@the-portland-company/shell 0.58.0 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/breadcrumbs.ts","../src/lib/identity.ts","../src/mode-preference.ts","../src/app-chrome/loading-screen.tsx","../src/app-chrome/frame.tsx","../src/app-chrome/index.tsx"],"names":["trail","jsx","useState","useRef","useEffect","useMemo","jsxs","useCallback","Fragment"],"mappings":"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","file":"app-chrome.js","sourcesContent":["// Breadcrumb derivation — pure, dependency-free logic (no React, no DevNotes),\n// so it is importable from a server module and testable in isolation.\n//\n// The standard is Dashboard > Sub > Item (HITL 2026-07-23), derived from the\n// same nav tree the sidebar renders. Apps previously hand-built their own\n// trails and disagreed: forms rendered \"Forms > Dashboard\" while polls rendered\n// a lone \"Polls\" crumb under a \"Polls\" title (\"Polls / Polls\").\n\nimport type { NavBreadcrumb, NavItem } from '../native/index'\n\nexport function deriveBreadcrumbs(\n items: NavItem[],\n pathname: string,\n opts?: { search?: string; origin?: string },\n): NavBreadcrumb[] {\n const search = opts?.search ?? (typeof window !== 'undefined' ? window.location.search : '')\n const origin = opts?.origin ?? (typeof window !== 'undefined' ? window.location.origin : '')\n\n // Same-origin comparison: cross-app hrefs are absolute, local ones relative.\n const matches = (href?: string): boolean => {\n if (!href) return false\n let path = href\n let query = ''\n if (/^https?:\\/\\//i.test(href)) {\n try {\n const u = new URL(href)\n if (origin && u.origin !== origin) return false\n path = u.pathname\n query = u.search\n } catch {\n return false\n }\n } else {\n const qi = href.indexOf('?')\n if (qi >= 0) {\n path = href.slice(0, qi) || '/'\n query = href.slice(qi)\n }\n }\n if (path !== pathname) return false\n if (!query) return true\n const want = new URLSearchParams(query)\n const have = new URLSearchParams(search)\n for (const [k, v] of want) if (have.get(k) !== v) return false\n return true\n }\n\n // Depth-first walk for the deepest item owning the current route.\n const walk = (nodes: NavItem[], trail: NavItem[]): NavItem[] | null => {\n for (const node of nodes) {\n const here = [...trail, node]\n if (node.children?.length) {\n const deeper = walk(node.children, here)\n if (deeper) return deeper\n }\n if (matches(node.href)) return here\n }\n return null\n }\n\n const trail = walk(items, [])\n // Always anchored at Dashboard; the last crumb is the current location and\n // carries no href (the shell marks it aria-current=\"page\").\n const dashboard = items.find((i) => i.label === 'Dashboard')\n const crumbs: NavBreadcrumb[] = [{ label: 'Dashboard', href: dashboard?.href }]\n if (!trail) return crumbs\n for (const node of trail) {\n if (node.label === 'Dashboard') continue\n crumbs.push({ label: node.label, href: node.href })\n }\n const last = crumbs[crumbs.length - 1]\n if (last) delete (last as { href?: string }).href\n return crumbs\n}\n","// Identity resolution — pure logic, shared by the chrome hook.\n//\n// The chrome API (VRM-core profile) is the AUTHORITY for a user's display name;\n// what an app knows from its own session token is a pre-hydration fallback. An\n// email is never a name: forms passed `user.name ?? user.email`, so a user with\n// no name set had their email rendered as their name in the top bar and the\n// shell's \"add your name\" affordance never fired (HITL 2026-07-23).\n\nexport type ResolvedIdentity = {\n userName: string | null\n email: string | null\n avatarUrl: string | null\n loaded: boolean\n}\n\n/** True when a \"name\" is really just an email address. */\nexport function looksLikeEmail(value: string | null | undefined): boolean {\n return typeof value === 'string' && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value.trim())\n}\n\nexport function resolveIdentity(input: {\n apiName?: string | null\n fallbackName?: string | null\n email?: string | null\n avatarUrl?: string | null\n loaded?: boolean\n}): ResolvedIdentity {\n const apiName = looksLikeEmail(input.apiName) ? null : input.apiName ?? null\n const fallbackName = looksLikeEmail(input.fallbackName) ? null : input.fallbackName ?? null\n return {\n userName: apiName ?? fallbackName,\n email: input.email ?? null,\n avatarUrl: input.avatarUrl ?? null,\n loaded: input.loaded ?? false,\n }\n}\n","// Active-mode continuity — the cross-app \"which mode am I in\" contract.\n//\n// A DUAL-MODE app (today: a2p, Specs/A2P — \"the SMS/MMS delivery engine for\n// Relationship Mode and Campaign Mode\") has no single registry `mode`: its\n// nav tree and Mode pill must follow the user's LAST-SELECTED mode instead of\n// a fixed value. The resolution order, cheapest/most-explicit first:\n// 1. `?mode=` query param on the current URL (an explicit cross-app link,\n// e.g. the Relationship tree's SMS/MMS Blast row linking into a2p).\n// 2. `politogy_active_mode` cookie — the same cross-subdomain pattern as\n// `politogy_theme` / `politogy_active_org` (see theme-preference.ts):\n// `.politogyvrm.com` on a *.politogyvrm.com host, host-only elsewhere.\n// 3. The dual app's own configured default mode.\n//\n// Every PINNED app (one with a fixed `meta.mode`, e.g. petitions/email) and\n// core (`vrm`, whose mode switches client-side) write this cookie whenever\n// their resolved mode is known/changes, so arriving at a dual app later\n// resolves to whatever mode the user was last actually in.\n\nimport type { StandardNavMode } from './native/standardNav'\n\nexport const ACTIVE_MODE_COOKIE = 'politogy_active_mode'\n\nconst VALID_MODES: readonly StandardNavMode[] = ['relationship', 'campaign', 'petition']\n\nexport function isStandardNavMode(v: unknown): v is StandardNavMode {\n return typeof v === 'string' && (VALID_MODES as readonly string[]).includes(v)\n}\n\n/** Read the shared cookie (browser only; null on the server or when unset). */\nexport function readActiveModeCookie(): StandardNavMode | null {\n if (typeof document === 'undefined') return null\n try {\n const m = document.cookie.match(\n new RegExp(`(?:^|;\\\\s*)${ACTIVE_MODE_COOKIE}=([^;]+)`),\n )\n const v = m ? decodeURIComponent(m[1]) : null\n return isStandardNavMode(v) ? v : null\n } catch {\n return null\n }\n}\n\n/**\n * Write the cross-subdomain cookie with the same scoping rules as the theme\n * cookie (parent domain on *.politogyvrm.com, host-only elsewhere). 1-year,\n * SameSite=Lax, Secure on https. No-op on the server.\n */\nexport function writeActiveModeCookie(mode: StandardNavMode): void {\n if (typeof document === 'undefined' || typeof window === 'undefined') return\n const host = window.location.hostname\n const domainAttr = /(^|\\.)politogyvrm\\.com$/i.test(host) ? '; Domain=.politogyvrm.com' : ''\n const secure = window.location.protocol === 'https:' ? '; Secure' : ''\n document.cookie = `${ACTIVE_MODE_COOKIE}=${encodeURIComponent(\n mode,\n )}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`\n}\n\n/** Read `?mode=` from a query string (`search`, with or without a leading `?`). */\nfunction modeFromSearch(search: string | undefined): string | null {\n if (!search) return null\n try {\n const params = new URLSearchParams(search.startsWith('?') ? search.slice(1) : search)\n return params.get('mode')\n } catch {\n return null\n }\n}\n\n/**\n * Resolve a dual-mode app's effective mode: `?mode=` query param (must be one\n * of `modes`) → `politogy_active_mode` cookie (must be one of `modes`) →\n * `defaultMode`. Client-side only; on the server (or when nothing resolves)\n * this simply falls through to `defaultMode`.\n */\nexport function resolveActiveMode({\n search,\n modes,\n defaultMode,\n}: {\n search?: string\n modes: readonly StandardNavMode[]\n defaultMode: StandardNavMode\n}): StandardNavMode {\n const fromQuery = modeFromSearch(search)\n if (fromQuery && isStandardNavMode(fromQuery) && modes.includes(fromQuery)) {\n return fromQuery\n }\n const fromCookie = readActiveModeCookie()\n if (fromCookie && modes.includes(fromCookie)) {\n return fromCookie\n }\n return defaultMode\n}\n","// ---------------------------------------------------------------------------\n// LoadingScreen — the platform's boot handshake (Specs/Loading-Screen).\n//\n// Mounted once by PolitogyAppFrame (see frame.tsx), never hand-rolled per app\n// (Global-Rules \"Boot Screen Exception\": one screen, one owner). It renders on\n// the four triggers that replace the account context wholesale — cold start,\n// hard reload, organization switch, mode switch — and never for an in-page\n// fetch or plain navigation, which stay on scoped skeletons.\n//\n// Progress is a REPORT, not an animation (spec §4): determinate, monotonic,\n// weighted across boot stages. An app that has real pipeline signals passes\n// `bootProgress`; an app that does not (V1: every consumer but core's own\n// pipeline work is still to come) gets a synthetic two-stage report driven by\n// the same chrome-state signal FrameBody already computes (org list resolved),\n// so the screen still tells the truth — it just has fewer stages to report —\n// and no consumer app can regress to a spinner or a hand-rolled splash.\n// ---------------------------------------------------------------------------\n\n'use client'\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\n\n/** One stage in the boot pipeline (spec §7). */\nexport type BootStageId =\n | 's0_session'\n | 's1_org'\n | 's2_uvp_connect'\n | 's3_district'\n | 's4_universe'\n | 's5_layers'\n | 's6_verified'\n | 's7_tribes'\n | 's8_intelligence'\n | 's9_shell'\n\nexport type BootPhase = 'booting' | 'slow' | 'error' | 'done'\n\n/**\n * The boot pipeline weight table (spec §7). Stages run in catalog order;\n * weights sum to 100 for a full cold boot. \"Waits on\" documents the real\n * signal a caller must have before it may claim the stage is progressing or\n * complete — the status line may not claim a stage the client isn't actually\n * waiting on.\n */\nexport const BOOT_STAGE_TABLE: readonly {\n id: BootStageId\n weight: number\n critical: boolean\n waitsOn: string\n}[] = [\n { id: 's0_session', weight: 5, critical: true, waitsOn: 'Politogy ID session resolution' },\n { id: 's1_org', weight: 10, critical: true, waitsOn: 'Chrome API /api/chrome/me + orgs' },\n { id: 's2_uvp_connect', weight: 10, critical: true, waitsOn: 'UVP data layer connection' },\n { id: 's3_district', weight: 5, critical: true, waitsOn: 'uvp_geo_entitlements / uvp_boundaries scope' },\n { id: 's4_universe', weight: 25, critical: true, waitsOn: 'UVP universe load + total count' },\n { id: 's5_layers', weight: 15, critical: false, waitsOn: 'UVP enrichment layer joins' },\n { id: 's6_verified', weight: 10, critical: false, waitsOn: 'VRM Verified tier computation' },\n { id: 's7_tribes', weight: 10, critical: false, waitsOn: 'Tribes member_count + Hot Tribes warm-up' },\n { id: 's8_intelligence', weight: 5, critical: false, waitsOn: 'Mode intelligence signals (Polling/Relationship/Petition)' },\n { id: 's9_shell', weight: 5, critical: true, waitsOn: 'Shell paint-ready handoff' },\n]\n\nconst BOOT_STAGE_ORDER: readonly BootStageId[] = BOOT_STAGE_TABLE.map((s) => s.id)\nconst BOOT_STAGE_WEIGHTS: Record<BootStageId, number> = Object.fromEntries(\n BOOT_STAGE_TABLE.map((s) => [s.id, s.weight]),\n) as Record<BootStageId, number>\n\n/**\n * Weighted, monotonic, redistributing progress (spec §4.1 principles 3 & 5).\n * `completedStageIds` are fully done (their full weight counts); `skippedStageIds`\n * don't apply to this account/mode and have their weight redistributed\n * proportionally across the stages that DO apply; `currentStageId` is in\n * flight and contributes `currentStageProgress` (0–1) of its own weight.\n * Pure function — no fake motion, no timers.\n */\nexport function computeWeightedPct(args: {\n completedStageIds: readonly BootStageId[]\n skippedStageIds?: readonly BootStageId[]\n currentStageId?: BootStageId\n currentStageProgress?: number\n}): number {\n const skipped = new Set(args.skippedStageIds ?? [])\n const applicable = BOOT_STAGE_ORDER.filter((id) => !skipped.has(id))\n const applicableWeightTotal = applicable.reduce((sum, id) => sum + BOOT_STAGE_WEIGHTS[id], 0)\n if (applicableWeightTotal <= 0) return 100\n // Redistribute each skipped stage's weight proportionally across the\n // remaining applicable stages so the bar still ends at 100.\n const redistributionFactor = 100 / applicableWeightTotal\n\n const completed = new Set(args.completedStageIds)\n let pct = 0\n for (const id of applicable) {\n const effectiveWeight = BOOT_STAGE_WEIGHTS[id] * redistributionFactor\n if (completed.has(id)) {\n pct += effectiveWeight\n } else if (id === args.currentStageId) {\n const progress = Math.min(1, Math.max(0, args.currentStageProgress ?? 0))\n pct += effectiveWeight * progress\n }\n }\n return Math.min(100, pct)\n}\n\n/**\n * The progress-reporting contract (spec §14, Shell package integration\n * point). An app with a real pipeline drives this; the shape is intentionally\n * small so a future per-app pipeline can report into it without a shell\n * release.\n */\nexport type BootProgress = {\n stageId: BootStageId\n /**\n * 0–100, real, monotonic. Callers that already know the weighted value\n * (e.g. by calling `computeWeightedPct` themselves) pass it directly here;\n * callers that only know stage completion/skip state may omit `pct` and\n * pass `completedStageIds`/`skippedStageIds`/`currentStageProgress`\n * instead, and the screen computes the weighted value itself.\n */\n pct?: number\n /** Stages fully completed so far this boot (spec §7 weight table). */\n completedStageIds?: readonly BootStageId[]\n /** Stages that don't apply to this account/mode; their weight redistributes\n * proportionally across the remaining stages (spec §4.1 principle 5). */\n skippedStageIds?: readonly BootStageId[]\n /** 0–1 sub-stage progress within `stageId`, for stages that stream a real\n * counter (S4 universe records, S7 Tribes warmed) (spec §4.1 principle 4). */\n currentStageProgress?: number\n /** The account's own status line for this stage (spec §8; tokens already\n * filled, fallback already applied by the caller). */\n label: string\n phase: BootPhase\n /** Critical-stage failure: Retry / Sign out (spec §9.1). */\n onRetry?: () => void\n onSignOut?: () => void\n /** Footer (spec §6, §14 `version.ts` + deploy environment). */\n version?: string\n region?: string\n}\n\n/** Default synthetic pipeline used when no app supplies `bootProgress` yet.\n * UNCHANGED from the shipped V1 behavior — do not alter without a spec\n * amendment; consumers that haven't wired the real pipeline must keep seeing\n * exactly this. */\nconst SYNTHETIC_STAGES: readonly { pct: number; label: string }[] = [\n { pct: 20, label: 'Connecting to your organization…' },\n { pct: 100, label: 'Ready.' },\n]\n\n/** Spec §11: announcements throttled to one per 1.5s so a fast boot doesn't\n * read five lines at once; \"Ready.\" is always announced regardless. */\nconst ANNOUNCE_THROTTLE_MS = 1500\n/** Spec §4.1 principle 7: minimum dwell time per status line. */\nconst MIN_DWELL_MS = 450\n/** Spec §10: exit transition timings. */\nconst FILL_EASE_MS = 380\nconst HOLD_MS = 240\nconst FADE_MS = 300\n\nfunction usePrefersReducedMotion(): boolean {\n const [reduced, setReduced] = useState(false)\n useEffect(() => {\n if (typeof window === 'undefined' || !window.matchMedia) return\n const mq = window.matchMedia('(prefers-reduced-motion: reduce)')\n setReduced(mq.matches)\n const onChange = () => setReduced(mq.matches)\n mq.addEventListener('change', onChange)\n return () => mq.removeEventListener('change', onChange)\n }, [])\n return reduced\n}\n\n/**\n * Announces `label` on an `aria-live=\"polite\"` cadence: never more than once\n * per ANNOUNCE_THROTTLE_MS, except the terminal \"Ready.\" line, which always\n * gets announced (spec §11).\n */\nfunction useThrottledAnnouncement(label: string, isFinal: boolean): string {\n const [announced, setAnnounced] = useState(label)\n const lastAtRef = useRef(0)\n useEffect(() => {\n const now = Date.now()\n if (isFinal || now - lastAtRef.current >= ANNOUNCE_THROTTLE_MS) {\n lastAtRef.current = now\n setAnnounced(label)\n return\n }\n const wait = ANNOUNCE_THROTTLE_MS - (now - lastAtRef.current)\n const t = setTimeout(() => {\n lastAtRef.current = Date.now()\n setAnnounced(label)\n }, wait)\n return () => clearTimeout(t)\n }, [label, isFinal])\n return announced\n}\n\n/**\n * Enforces the minimum-dwell floor on the DISPLAYED label only — the bar\n * itself is never delayed (spec §4.1 \"the copy is throttled; the bar is not\").\n */\nfunction useDwelledLabel(label: string): string {\n const [displayed, setDisplayed] = useState(label)\n const shownAtRef = useRef(0)\n const pendingRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n useEffect(() => {\n if (label === displayed) return\n const elapsed = Date.now() - shownAtRef.current\n if (pendingRef.current) clearTimeout(pendingRef.current)\n if (elapsed >= MIN_DWELL_MS) {\n shownAtRef.current = Date.now()\n setDisplayed(label)\n } else {\n pendingRef.current = setTimeout(() => {\n shownAtRef.current = Date.now()\n setDisplayed(label)\n }, MIN_DWELL_MS - elapsed)\n }\n return () => {\n if (pendingRef.current) clearTimeout(pendingRef.current)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [label])\n return displayed\n}\n\nexport type LoadingScreenProps = {\n /** Real pipeline progress, when the host app has one wired. */\n bootProgress?: BootProgress\n /**\n * Fallback completion signal used when `bootProgress` is absent: the\n * screen dismisses once this flips true. Callers pass the same \"org list\n * resolved\" signal FrameBody already computes, so a consumer that never\n * wires the full contract still gets a truthful (if coarse) boot report\n * instead of a spinner.\n */\n syntheticReady?: boolean\n /** True while the screen should be mounted at all (trigger gate lives in\n * frame.tsx; this component only renders its own exit transition). */\n visible: boolean\n /** Called after the fade-out completes and the DOM node should unmount. */\n onExitComplete: () => void\n}\n\nexport function LoadingScreen({\n bootProgress,\n syntheticReady,\n visible,\n onExitComplete,\n}: LoadingScreenProps) {\n const reducedMotion = usePrefersReducedMotion()\n\n const synthetic = useMemo(() => {\n const stage = syntheticReady ? SYNTHETIC_STAGES[1] : SYNTHETIC_STAGES[0]\n return {\n pct: stage.pct,\n label: stage.label,\n phase: (syntheticReady ? 'done' : 'booting') as BootPhase,\n }\n }, [syntheticReady])\n\n const weightedPct = useMemo(() => {\n if (!bootProgress) return undefined\n if (typeof bootProgress.pct === 'number') return bootProgress.pct\n if (!bootProgress.completedStageIds && !bootProgress.skippedStageIds) return undefined\n return computeWeightedPct({\n completedStageIds: bootProgress.completedStageIds ?? [],\n skippedStageIds: bootProgress.skippedStageIds,\n currentStageId: bootProgress.stageId,\n currentStageProgress: bootProgress.currentStageProgress,\n })\n }, [\n bootProgress,\n bootProgress?.pct,\n bootProgress?.completedStageIds,\n bootProgress?.skippedStageIds,\n bootProgress?.stageId,\n bootProgress?.currentStageProgress,\n ])\n\n const pct = weightedPct ?? synthetic.pct\n const rawLabel = bootProgress?.label ?? synthetic.label\n const phase = bootProgress?.phase ?? synthetic.phase\n const isFinal = phase === 'done' && pct >= 100\n\n // Monotonic clamp: a re-render can never show a lower value than the last\n // one painted, even if a caller's own state briefly regresses.\n const highWaterRef = useRef(0)\n const clampedPct = Math.max(pct, highWaterRef.current)\n useEffect(() => {\n highWaterRef.current = clampedPct\n }, [clampedPct])\n\n const displayedLabel = useDwelledLabel(rawLabel)\n const announced = useThrottledAnnouncement(displayedLabel, isFinal)\n\n // Exit transition: hold at 100 for HOLD_MS, then fade, then unmount.\n const [fading, setFading] = useState(false)\n useEffect(() => {\n if (!isFinal) return\n const holdMs = reducedMotion ? 0 : HOLD_MS\n const fadeMs = reducedMotion ? 0 : FADE_MS\n const holdTimer = setTimeout(() => {\n setFading(true)\n const fadeTimer = setTimeout(onExitComplete, fadeMs)\n return () => clearTimeout(fadeTimer)\n }, holdMs)\n return () => clearTimeout(holdTimer)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isFinal, reducedMotion])\n\n if (!visible) return null\n\n const isError = phase === 'error'\n\n return (\n <div\n data-testid=\"politogy-loading-screen\"\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 2147483000,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '2rem',\n background: 'var(--color-ink-900, #0a0a0c)',\n color: '#fff',\n opacity: fading ? 0 : 1,\n transition: reducedMotion ? undefined : `opacity ${FADE_MS}ms ease-out`,\n }}\n >\n {/*\n Inline lockup, not an <img>: the screen mounts in every consumer app and\n none of them serves a shared asset at a fixed path, so an asset URL\n rendered as a broken image (the alt text) on every boot. Inline markup\n needs no network and cannot 404.\n */}\n <div\n aria-label=\"Politogy\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '0.6rem',\n fontFamily: 'var(--font-sans, ui-sans-serif, system-ui, sans-serif)',\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 34,\n height: 26,\n borderRadius: 6,\n background: '#fff',\n color: 'var(--color-ink-900, #0a0a0c)',\n fontSize: '0.8125rem',\n fontWeight: 800,\n letterSpacing: '-0.02em',\n }}\n >\n vrm\n </span>\n <span style={{ fontSize: '1.375rem', fontWeight: 700, letterSpacing: '-0.02em' }}>Politogy</span>\n </div>\n <div style={{ width: 320, maxWidth: '80vw' }}>\n <div\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(clampedPct)}\n aria-label=\"Loading your workspace\"\n style={{\n height: 3,\n width: '100%',\n borderRadius: 2,\n background: 'rgba(255,255,255,0.12)',\n overflow: 'hidden',\n }}\n >\n <div\n style={{\n height: '100%',\n width: `${clampedPct}%`,\n background:\n 'linear-gradient(90deg, var(--color-race-blue, #1d4ed8), var(--color-race-red, #dc2626))',\n transition: reducedMotion ? undefined : `width ${FILL_EASE_MS}ms ease-out`,\n }}\n />\n </div>\n <div\n role=\"status\"\n aria-live=\"polite\"\n style={{\n marginTop: '0.75rem',\n fontFamily: 'var(--font-mono, ui-monospace, monospace)',\n fontSize: '0.8125rem',\n color: isError ? 'var(--color-race-red, #dc2626)' : 'rgba(255,255,255,0.72)',\n textAlign: 'center',\n }}\n >\n {announced}\n </div>\n {isError && (bootProgress?.onRetry || bootProgress?.onSignOut) && (\n <div\n style={{\n marginTop: '1.25rem',\n display: 'flex',\n flexDirection: 'column',\n gap: '0.75rem',\n alignItems: 'center',\n }}\n >\n {bootProgress?.onRetry && (\n <button\n type=\"button\"\n onClick={bootProgress.onRetry}\n style={{\n height: 40,\n padding: '0 1.25rem',\n borderRadius: 'var(--radius-md, 8px)',\n border: 'none',\n background: 'var(--color-race-red, #dc2626)',\n color: '#fff',\n fontFamily: 'var(--font-sans, ui-sans-serif, system-ui, sans-serif)',\n fontSize: '0.875rem',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n Retry\n </button>\n )}\n {bootProgress?.onSignOut && (\n <button\n type=\"button\"\n onClick={bootProgress.onSignOut}\n style={{\n height: 'auto',\n padding: 0,\n border: 'none',\n background: 'transparent',\n color: 'rgba(255,255,255,0.38)',\n fontFamily: 'var(--font-sans, ui-sans-serif, system-ui, sans-serif)',\n fontSize: '12.5px',\n textDecoration: 'underline',\n cursor: 'pointer',\n }}\n >\n Sign out\n </button>\n )}\n </div>\n )}\n </div>\n <div\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n bottom: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '0 32px 30px',\n fontFamily: 'var(--font-sans, ui-sans-serif, system-ui, sans-serif)',\n fontSize: '12.5px',\n color: 'rgba(255,255,255,0.38)',\n }}\n >\n <span>Politogy VRM. Built for the long game.</span>\n <span style={{ fontFamily: 'var(--font-mono, ui-monospace, monospace)', letterSpacing: '0.04em' }}>\n {(bootProgress?.version ?? 'v—') + ' · ' + (bootProgress?.region ?? '—')}\n </span>\n </div>\n </div>\n )\n}\n","// ---------------------------------------------------------------------------\n// PolitogyAppFrame — ONE component that renders the entire app frame.\n//\n// Why this exists (HITL directive 2026-07-23): shipping the same npm package at\n// the same version is necessary but NOT sufficient. The package exposed\n// PRIMITIVES (NavAppShell + a dozen hooks) and every app hand-assembled them in\n// its own ~150-line Shell.tsx. Identical inputs were never guaranteed, so the\n// outputs diverged — measured on production: forms rendered its user's EMAIL as\n// their name, polls' breadcrumb read \"Polls / Polls\", forms and surveys pinned\n// the mode pill to a hardcoded \"relationship\", and each app declared its own\n// chrome CSS variables (surveys' accent was #C8102E where everyone else was\n// #E63946).\n//\n// The fix is to stop exporting assembly as an app responsibility. An app now\n// renders:\n//\n// <PolitogyAppFrame app=\"forms\" pathname={pathname} linkComponent={Link}\n// session={{ userId, email, role, accountName, accountId }}\n// onSignOut={signOut}>\n// {children}\n// </PolitogyAppFrame>\n//\n// and passes NOTHING about the chrome: no nav, no breadcrumbs, no title, no\n// mode, no user menu, no footer, no theme. Those are derived here, identically,\n// for every app. Anything an app cannot pass is something it cannot drift on.\n// ---------------------------------------------------------------------------\n\n'use client'\n\nimport { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'\n\nimport { broadcastLogout, watchLogout } from '../logout-signal'\nimport { resolveActiveMode, writeActiveModeCookie } from '../mode-preference'\nimport { clearBetaBannerDismissal } from '../native/index'\nimport { LoadingScreen, type BootProgress } from './loading-screen'\nimport {\n NavAppShell,\n standardPolitogyNav,\n type NavLinkComponent,\n} from '../native/index'\nimport {\n ChromeTopBarActions,\n PolitogyAppChrome,\n standardNavIcons,\n useChromeFooter,\n useChromeIdentity,\n useChromeMode,\n useChromeState,\n useChromeUserMenu,\n type ChromeDevNotesConfig,\n type ControlledOrgState,\n} from './index'\nimport type {\n NavBreadcrumb,\n NavChromeFetcher,\n NavItem,\n NavMode,\n NavUserMenu,\n} from '../native/index'\nimport type { StandardNavMode } from '../native/standardNav'\nimport { deriveBreadcrumbs } from '../lib/breadcrumbs'\n\n/**\n * The core app — the one that OWNS the canonical nav tree and routes in-app.\n * `PolitogyFrameData.core` is honored for this key and no other.\n */\nconst CORE_APP: PolitogyAppKey = 'vrm'\n\n/**\n * Template A convention: every feature app exposes GET /auth/signout, which\n * clears its session cookie and 302s to the IdP's end_session endpoint. Apps\n * that route sign-out elsewhere (core: /api/auth/logout) pass `signOutUrl`.\n */\nconst DEFAULT_SIGN_OUT_URL = '/auth/signout'\n\n/** Every app that renders the shared chrome. Keyed by its subdomain. */\nexport type PolitogyAppKey =\n | 'vrm'\n | 'contacts'\n | 'forms'\n | 'surveys'\n | 'polls'\n | 'petitions'\n // Relationship Mode standalone apps.\n | 'email'\n // Campaign Mode standalone apps.\n | 'a2p'\n | 'phonebank'\n | 'canvass'\n | 'signs'\n // Relationship Mode CTAs (Specs/CTAs) — the new standalone acquisition app,\n // same \"forms./surveys./polls.\" pattern (unscoped, own subdomain).\n | 'ctas'\n\n/**\n * The operating Mode an app is scoped to, if any. It drives two things,\n * BOTH derived here from app identity so no app passes chrome config:\n * 1. the standardPolitogyNav tree the sidebar renders, and\n * 2. the static Mode pill the app shows (a campaign app shows a Campaign\n * pill, never Relationship).\n * An UNSCOPED app (no `mode`) keeps its prior behavior exactly: the\n * Relationship tree + an entitlement-driven Mode pill.\n */\nexport type PolitogyAppMode = StandardNavMode\n\n/** The wordmark every unscoped app renders — Politogy's default lockup. */\nconst DEFAULT_BRAND_LOGO = '/brand/logos/relationship-mode-logo.png'\n\n/**\n * Mode-specific brand lockups, by Mode. Same idea as the per-Mode accent: the\n * wordmark is Mode identity, resolved from the REGISTRY, not passed by an app.\n *\n * Only a Mode with its own shipped lockup appears here. Everything else falls\n * back to the default, so this is additive.\n *\n * Why it needs fixing: `brandLogoSrc` became core-only in 0.43, so every\n * MODE-SCOPED app started rendering the Relationship lockup — a red wordmark\n * on a purple \"vrm\" badge — regardless of the Mode it is scoped to. Petition\n * Mode shipped a green Petition lockup in V1 and lost it in that migration,\n * which is the \"migration may not drop a shipped element\" rule.\n *\n * The path is app-relative: each app serves the asset from its own `public/`\n * (petitions already ships `petition-mode-logo.svg`). A Mode added here without\n * the asset in place would 404 to a broken image, so add the file first.\n */\nconst MODE_BRAND_LOGOS: Partial<Record<PolitogyAppMode, string>> = {\n petition: '/brand/logos/petition-mode-logo.svg',\n}\n\nconst modeBrandLogo = (mode?: PolitogyAppMode) =>\n (mode && MODE_BRAND_LOGOS[mode]) || DEFAULT_BRAND_LOGO\n\n/**\n * A frame input a feature app is allowed to supply, because the answer is a\n * fact only the app has — not a styling choice.\n *\n * The grant list is the COMPLETE set of exceptions to \"an app never passes\n * chrome configuration\", and it lives here, in the shell, in one greppable\n * table. That is what keeps the no-drift guarantee: an app cannot grant itself,\n * so widening the surface takes a shell release and a review by whoever owns\n * the shell.\n *\n * Never add a grant for a visual input. `contentWrapper` qualifies because the\n * app either does or does not already emit its own `<main>`; `breadcrumbs`\n * qualifies because only the app knows which record a deep link points at.\n * \"Petitions wants a wider box\" would not qualify — that is a look, and looks\n * come from tokens.\n */\nexport type PolitogyFrameGrant = 'contentWrapper' | 'breadcrumbs' | 'title'\n\n/**\n * The per-app registry — the ONLY place app identity lives. A new app adds a\n * row here and inherits every chrome behavior; it never re-derives one.\n */\nexport const POLITOGY_APPS: Record<\n PolitogyAppKey,\n {\n title: string\n origin: string\n storagePrefix: string\n mode?: PolitogyAppMode\n /**\n * DUAL-MODE apps (today: a2p — Specs/A2P: \"the SMS/MMS delivery engine\n * for Relationship Mode and Campaign Mode\") have no single fixed mode.\n * `mode` above stays the fallback/default identity for any code that\n * still reads `meta.mode` directly; FrameBody instead resolves the\n * EFFECTIVE mode via `resolveActiveMode` (?mode= query → the\n * `politogy_active_mode` cookie → `defaultMode`) and uses that for the\n * nav tree, the Mode pill, and the brand lockup.\n */\n dual?: { modes: readonly StandardNavMode[]; defaultMode: StandardNavMode }\n /** See PolitogyFrameGrant. Omitted => the app may pass no frame input. */\n grants?: readonly PolitogyFrameGrant[]\n /**\n * 'flat': the app's whole tree nests under one standard entry, and the rail\n * renders that entry's CHILDREN at the root — no parent header row, no\n * accordion (see NavSidebar nav.flatten). V1's petition rail was flat;\n * the parent row duplicated its first child's route.\n */\n navShape?: 'flat'\n /**\n * false: this app does not render the Beta banner strip. A registry\n * declaration, not an app prop, for the same reason as grants — whether a\n * product shows the platform's Beta notice is a platform decision.\n */\n beta?: boolean\n }\n> = {\n vrm: { title: 'Politogy VRM', origin: 'https://app.politogyvrm.com', storagePrefix: 'vrm' },\n contacts: { title: 'Contacts', origin: 'https://contacts.politogyvrm.com', storagePrefix: 'contacts' },\n forms: { title: 'Forms', origin: 'https://forms.politogyvrm.com', storagePrefix: 'forms' },\n surveys: { title: 'Surveys', origin: 'https://surveys.politogyvrm.com', storagePrefix: 'surveys' },\n polls: { title: 'Polls', origin: 'https://polls.politogyvrm.com', storagePrefix: 'polls' },\n ctas: { title: 'CTAs', origin: 'https://ctas.politogyvrm.com', storagePrefix: 'ctas' },\n petitions: {\n title: 'Petitions',\n origin: 'https://petition-mode.politogyvrm.com',\n storagePrefix: 'petitions',\n mode: 'petition',\n // Petitions wraps every page in its own PageContainer (which emits its own\n // <main>), and its adjudication case is addressed per sheet and per line —\n // a trail derived from the nav tree reads \"Dashboard › Adjudication\" on\n // every one of those URLs and cannot name the record you are actually on.\n // 'title' for the same reason: its pages have real names (\"Batches\"),\n // where the registry can only say \"Petitions\".\n grants: ['contentWrapper', 'breadcrumbs', 'title'],\n navShape: 'flat',\n beta: false,\n },\n // Relationship Mode Email Engine (Specs/Email-Engine) — the V2 standalone\n // app, running in parallel to VRM core's V1 Email Broadcast.\n email: { title: 'Email', origin: 'https://email.politogyvrm.com', storagePrefix: 'email', mode: 'relationship' },\n // Campaign Mode apps — each scoped to Campaign, so they render the Campaign\n // tree and a static Campaign pill. Not yet deployed; hidden from the Campaign\n // nav by CAMPAIGN_FEATURE_AVAILABILITY until their launch flips the flag.\n // Dual-mode: a2p is the SMS/MMS delivery engine for BOTH Relationship Mode\n // and Campaign Mode (Specs/A2P). `mode: 'campaign'` stays the fallback for\n // anything reading `meta.mode` directly; the effective mode a user sees is\n // resolved per-visit (see `dual`, resolveActiveMode).\n a2p: {\n title: 'A2P Messaging',\n origin: 'https://a2p.politogyvrm.com',\n storagePrefix: 'a2p',\n mode: 'campaign',\n dual: { modes: ['relationship', 'campaign'], defaultMode: 'campaign' },\n },\n phonebank: { title: 'Phone Banking', origin: 'https://phonebank.politogyvrm.com', storagePrefix: 'phonebank', mode: 'campaign' },\n canvass: { title: 'Field Canvassing', origin: 'https://canvass.politogyvrm.com', storagePrefix: 'canvass', mode: 'campaign' },\n signs: { title: 'Sign Mapping', origin: 'https://signs.politogyvrm.com', storagePrefix: 'signs', mode: 'campaign' },\n}\n\nexport type PolitogyAppSession = {\n /** Stable IdP subject (`sub`). */\n userId: string\n email: string | null\n /** The app's own role string — feeds DevNotes admin gating. */\n role: string\n /** The app's own workspace label, used only until core orgs resolve. */\n accountName: string\n accountId: string\n /**\n * Pre-hydration display name ONLY. The chrome API is the authority; an email\n * passed here is discarded rather than rendered as a name.\n */\n userName?: string | null\n}\n\n/**\n * Optional DATA plumbing for apps whose session/auth differs — never styling.\n *\n * Everything here is about WHERE data comes from (which fetcher, which org\n * state, which routes an app owns), not what the chrome looks like. Adding a\n * visual option to this type would re-open the drift this component exists to\n * close.\n */\nexport type PolitogyFrameData = {\n /** Chrome-API fetcher override for apps that authenticate client-side. */\n fetchJson?: NavChromeFetcher\n /** DevNotes wiring override for those same direct-auth apps. */\n devNotes?: ChromeDevNotesConfig\n /** Controlled org state for apps that own active-org + switching. */\n org?: ControlledOrgState\n /** App-owned children for a standard nav entry this app owns (Contacts). */\n contactsItem?: { href?: string; children?: NavItem[] }\n /** Petitions app: nest its own routes under the Petition-mode entry. */\n petitionsItem?: { href?: string; children?: NavItem[] }\n /** Avatar fallback when the profile has no uploaded photo (memoji, default). */\n fallbackAvatarUrl?: string | null\n /**\n * Frame inputs this app has been GRANTED in the registry.\n *\n * Each field is honored only when the app's `POLITOGY_APPS` row lists it in\n * `grants`; an undeclared field is dropped before it reaches the chrome, so\n * passing one has no effect rather than a silent effect. Nothing here is\n * styling — see PolitogyFrameGrant for what qualifies.\n *\n * This is deliberately NOT a widening of the `app === CORE_APP` gate below.\n * That gate makes core's props inert for every other app; this makes a named\n * input live for a named app, listed in one place the shell owns.\n */\n frame?: PolitogyGrantedFrame\n /**\n * CORE-ONLY frame inputs. **Honored only when `app` is the core app (`vrm`)\n * — silently ignored for every other app**, which is what keeps the\n * no-drift guarantee intact: a feature app cannot re-specify a chrome\n * element even by passing this, so the props are inert for it.\n *\n * Core is genuinely different, and pretending otherwise would have meant\n * REMOVING shipped behavior from app.politogyvrm.com to satisfy packaging —\n * which Reference/UI-Platform forbids (\"migration may not drop a shipped\n * element … extend the shell first, then migrate\"). Specifically, core:\n * - owns the canonical nav tree AND decorates it with live entitlement\n * state a static tree cannot express (10DLC gating, contact/group\n * counts, org-lock),\n * - routes in-app (react-router), so its rows must be app-relative paths,\n * not the absolute cross-app URLs `standardPolitogyNav` emits,\n * - publishes per-page title/breadcrumbs from 66 page components,\n * - switches Mode client-side rather than by full-page navigation,\n * - owns real linked-account switching (with its own modals).\n *\n * Everything here is still DATA or app-owned STATE. There is no styling\n * input, no ordering input, and no way to change the top-bar action cluster\n * — those stay identical for every app, core included.\n */\n core?: PolitogyCoreFrame\n}\n\n/** See `PolitogyFrameData.frame` — honored per the app's registry `grants`. */\nexport type PolitogyGrantedFrame = {\n /**\n * How the frame wraps page content. `'bare'` for an app that already emits\n * its own `<main>` + container, which the default otherwise nests inside\n * `mx-auto max-w-7xl` — producing a doubled gutter and, strictly, invalid\n * HTML (a `<main>` inside a `<main>`).\n */\n contentWrapper?: 'padded' | 'bare'\n /**\n * The trail for pages whose location is finer-grained than their nav row —\n * a specific record, not a section. For an app granted 'breadcrumbs' the\n * published trail REPLACES the derived one entirely: a page that publishes\n * none shows none, exactly as core's pages do. (Falling back to the derived\n * trail put \"Dashboard › Batches\" under the title of every list page — a\n * parent nobody chose, on apps whose pages already say where they are.)\n */\n breadcrumbs?: NavBreadcrumb[]\n /** The page's own name for the top bar (\"Batches\"), not the app's. */\n title?: string\n}\n\n/** See `PolitogyFrameData.core` — core app (`vrm`) only. */\nexport type PolitogyCoreFrame = {\n /** The canonical nav tree, decorated with core's live entitlement state. */\n nav?: NavItem[]\n /** Per-page identity published by core's own pages. */\n page?: { title?: string; breadcrumbs?: NavBreadcrumb[]; actions?: ReactNode }\n /** Client-side Mode switching (core navigates in-app, not cross-origin). */\n mode?: NavMode\n /** Real linked-account switching + core's theme persistence. */\n userMenu?: NavUserMenu\n /** Mode-specific brand wordmark (core swaps it per operating Mode). */\n brandLogoSrc?: string\n /** Core wraps every page in PageContainer, which emits its own <main>. */\n contentWrapper?: 'padded' | 'bare'\n}\n\nexport type PolitogyBuildMeta = {\n envLabel?: string\n version?: string\n commit?: string\n commitDate?: string\n commitAuthor?: string\n}\n\nexport function PolitogyAppFrame({\n app,\n pathname,\n search,\n linkComponent,\n session,\n onSignOut,\n signOutUrl = DEFAULT_SIGN_OUT_URL,\n buildMeta,\n data,\n bootProgress,\n appReady,\n children,\n}: {\n app: PolitogyAppKey\n /** Current path from the app's router (Next: usePathname()). */\n pathname: string\n /** Current query string, when the app routes by query (forms' ?tab=). */\n search?: string\n /** The app's routing primitive (Next: <Link>). */\n linkComponent: NavLinkComponent\n session: PolitogyAppSession\n onSignOut: () => void\n /**\n * The app's sign-out ROUTE — a GET endpoint that clears the session cookie\n * and redirects to RP-initiated logout at the IdP. Defaults to the Template A\n * convention; core overrides it. This, not `onSignOut`, is what actually\n * signs the user out (see handleSignOut).\n */\n signOutUrl?: string\n buildMeta?: PolitogyBuildMeta\n /** Optional DATA plumbing (never styling) — see PolitogyFrameData. */\n data?: PolitogyFrameData\n /**\n * Real boot-pipeline progress (Specs/Loading-Screen §14 contract). Absent\n * for apps that have not wired their own pipeline yet — the frame then\n * reports a truthful but coarse two-stage boot instead of a spinner.\n */\n bootProgress?: BootProgress\n /**\n * Explicit \"the host app is ready to be shown\" signal. When omitted (every\n * app today), the Loading Screen dismisses itself once the chrome's own\n * org/nav state resolves, so none of the 14 consumer apps has to opt in to\n * keep working.\n */\n appReady?: boolean\n children: ReactNode\n}) {\n const meta = POLITOGY_APPS[app]\n return (\n <PolitogyAppChrome\n storagePrefix={meta.storagePrefix}\n fetchJson={data?.fetchJson}\n devNotes={data?.devNotes}\n org={data?.org}\n identity={{\n userId: session.userId,\n userName: session.userName ?? null,\n email: session.email,\n role: session.role,\n }}\n >\n <FrameBody\n app={app}\n pathname={pathname}\n search={search}\n linkComponent={linkComponent}\n session={session}\n onSignOut={onSignOut}\n signOutUrl={signOutUrl}\n buildMeta={buildMeta}\n data={data}\n bootProgress={bootProgress}\n appReady={appReady}\n >\n {children}\n </FrameBody>\n </PolitogyAppChrome>\n )\n}\n\nfunction FrameBody({\n app,\n pathname,\n search,\n linkComponent,\n session,\n onSignOut,\n signOutUrl,\n buildMeta,\n data,\n bootProgress,\n appReady,\n children,\n}: {\n app: PolitogyAppKey\n pathname: string\n search?: string\n linkComponent: NavLinkComponent\n session: PolitogyAppSession\n onSignOut: () => void\n signOutUrl: string\n buildMeta?: PolitogyBuildMeta\n data?: PolitogyFrameData\n bootProgress?: BootProgress\n appReady?: boolean\n children: ReactNode\n}) {\n const meta = POLITOGY_APPS[app]\n const chrome = useChromeState()\n\n // Loading Screen trigger gate (Specs/Loading-Screen §5, Global-Rules \"Boot\n // Screen Exception\"): shown on mount (cold start / hard reload both remount\n // this component fresh) and re-shown on organization switch or mode switch —\n // the two events that replace the account context after mount. A plain\n // route change never touches these refs, so it never re-arms the screen.\n const bootAppMode = meta.mode\n const bootOrgId = chrome?.orgId ?? null\n const [bootVisible, setBootVisible] = useState(true)\n // Remounts LoadingScreen on every new trigger so its internal monotonic\n // high-water mark and exit-transition state start clean for the new boot.\n const [bootGeneration, setBootGeneration] = useState(0)\n const seenOrgRef = useRef(bootOrgId)\n const seenModeRef = useRef(bootAppMode)\n useEffect(() => {\n if (seenOrgRef.current !== null && seenOrgRef.current !== bootOrgId) {\n setBootVisible(true)\n setBootGeneration((g) => g + 1)\n }\n seenOrgRef.current = bootOrgId\n }, [bootOrgId])\n useEffect(() => {\n if (seenModeRef.current !== undefined && seenModeRef.current !== bootAppMode) {\n setBootVisible(true)\n setBootGeneration((g) => g + 1)\n }\n seenModeRef.current = bootAppMode\n }, [bootAppMode])\n // Default dismiss signal when the app has not wired a real pipeline: the\n // chrome's own org list has resolved, i.e. the same state FrameBody already\n // needed to render the sidebar/org switcher truthfully. `chrome` is null\n // for an app rendered without a chrome/org provider at all (no org state to\n // wait on), which must count as resolved — otherwise the screen never\n // dismisses and blocks the app forever.\n const chromeResolved = chrome == null || !chrome.orgsLoading\n\n // Sign-out is a PLATFORM event, not an app event. Each app holds its own\n // host-only session cookie with a long sliding window, so without this a user\n // who signed out in one tab stayed fully signed in in every other open tab\n // and on every other subdomain. Announce the sign-out to all of them, then\n // run the app's own sign-out.\n //\n // Every app reaches sign-out through this frame, so wiring it here covers the\n // whole estate without an app having to opt in — the same guarantee the rest\n // of the chrome relies on.\n const signOutRef = useRef(onSignOut)\n signOutRef.current = onSignOut\n // This tab started the sign-out, so its own watcher must not also fire and\n // run the app's sign-out a second time concurrently.\n const signingOutRef = useRef(false)\n\n const handleSignOut = useCallback(() => {\n signingOutRef.current = true\n // Re-arm the Beta banner so it reappears at the next login rather than\n // staying hidden across an in-tab logout→login (sessionStorage survives it).\n clearBetaBannerDismissal()\n broadcastLogout()\n // Navigate to the app's sign-out ROUTE. Apps also pass an onSignOut\n // handler, but it cannot be relied on: they wire it as\n // `onSignOut={() => { void signOutAction(); }}`, and a server action\n // invoked outside a transition can never have its redirect() applied by\n // the client. Measured against production 2026-07-25: clicking Sign out\n // left the user signed in, and an app they had never opened authenticated\n // with no credentials — the IdP session was still alive because the\n // browser never reached its end-session endpoint.\n //\n // A plain navigation to a GET route cannot fail that way: the route drops\n // the session cookie and 302s to RP-initiated logout at the IdP.\n signOutRef.current()\n window.location.assign(signOutUrl)\n }, [signOutUrl])\n\n useEffect(\n () =>\n // A tab that learns of a sign-out elsewhere ends its own session for\n // real, by navigating to the same sign-out route.\n //\n // Measured against production before this landed: calling the app's\n // handler did nothing at all. Apps wire it as\n // `onSignOut={() => { void signOutAction(); }}` — a server action invoked\n // outside a transition, so the `redirect()` inside it can never be\n // applied by the client and the tab just sits there. Building cross-tab\n // logout on that path made the whole feature a no-op.\n //\n // A hard navigation cannot fail that way, and it hands the decision to\n // the authority rather than guessing: the app's middleware sees a session\n // whose auth_time predates `politogy_logout_at`, treats it as revoked,\n // and redirects to Politogy ID. Server-side truth decides; the client\n // only forces the request. No re-broadcast — the signal that woke us is\n // already on record for every tab.\n watchLogout(() => {\n if (signingOutRef.current) return\n clearBetaBannerDismissal()\n window.location.assign(signOutUrl)\n }),\n [signOutUrl],\n )\n // Core-only inputs are read through this ONE gate. For every other app it is\n // undefined no matter what the app passed, so the \"an app cannot re-specify a\n // chrome element\" guarantee holds by construction, not by convention.\n const core = app === CORE_APP ? data?.core : undefined\n\n // Registry-granted inputs run through the SAME shape of gate, one field at a\n // time: the registry decides, the app only supplies. An app that passes\n // `frame.breadcrumbs` without the grant gets `undefined` here, so the failure\n // mode is \"no effect\", never \"an app quietly re-specified the chrome\".\n const grants = meta.grants\n const granted = <K extends keyof PolitogyGrantedFrame>(\n key: K & PolitogyFrameGrant,\n ): PolitogyGrantedFrame[K] | undefined =>\n grants?.includes(key) ? data?.frame?.[key] : undefined\n\n // Identity: chrome API wins, app claims are a fallback, an email is never a\n // name (that is what forms was rendering in the top right).\n const identity = useChromeIdentity({ userName: session.userName, email: session.email })\n const derivedUserMenu = useChromeUserMenu({\n userId: session.userId,\n userName: identity.userName,\n email: identity.email,\n })\n const userMenu = core?.userMenu ?? derivedUserMenu\n const footer = useChromeFooter(buildMeta ?? {})\n // A mode-scoped app (Campaign apps, Petitions) pins its pill to its own mode;\n // an unscoped app stays entitlement + user-selection driven. Either way no\n // app passes a mode — it is read from the registry (app identity).\n //\n // A DUAL-MODE app (a2p — Specs/A2P) has no single fixed mode: its EFFECTIVE\n // mode is resolved per-visit, ?mode= query → politogy_active_mode cookie →\n // the app's own default, and that resolved value stands in for `meta.mode`\n // everywhere below (nav tree, Mode pill, brand lockup). Every other app is\n // unaffected — `appMode` is exactly `meta.mode`, as before.\n const resolvedDualMode = meta.dual\n ? resolveActiveMode({\n search: search ?? (typeof window !== 'undefined' ? window.location.search : undefined),\n modes: meta.dual.modes,\n defaultMode: meta.dual.defaultMode,\n })\n : undefined\n const appMode = resolvedDualMode ?? meta.mode\n const derivedMode = useChromeMode(appMode ? { pinnedModeId: appMode } : undefined)\n // Core switches Mode client-side; every other app jumps to the mode's home.\n const mode = core?.mode ?? derivedMode\n\n // PINNED apps (a fixed `meta.mode`, no `dual`) write their own mode to the\n // shared cookie whenever it is known, so a dual app visited next (a2p)\n // resolves to it instead of its own default — that is what makes \"SMS/MMS\n // Blast\" clicked from Relationship Mode land on the Relationship tree in\n // a2p even without a `?mode=` link.\n //\n // Core (`vrm`) has no `meta.mode` — it switches mode client-side via\n // in-app routing, not the registry — so its live mode is read from its own\n // route namespace (`/relationship/...` vs `/campaign/...`, the same split\n // `standardPolitogyNav`'s trees use) rather than `core?.mode` (a `NavMode`\n // describing the PILL's label/options, not which mode is currently active).\n // Re-runs on every pathname change, so switching mode in-app (a route\n // change, not a remount) still updates the cookie.\n const coreLiveMode: StandardNavMode | undefined =\n app === CORE_APP\n ? pathname.startsWith('/campaign')\n ? 'campaign'\n : pathname.startsWith('/relationship')\n ? 'relationship'\n : undefined\n : undefined\n const cookieMode = coreLiveMode ?? (meta.dual ? undefined : meta.mode)\n useEffect(() => {\n if (cookieMode) writeActiveModeCookie(cookieMode)\n }, [cookieMode])\n\n const coreOrgs = chrome?.orgs ?? []\n const activeCoreOrg = coreOrgs.find((o) => o.id === chrome?.orgId) ?? null\n const navDisplay = chrome?.navDisplay ?? 'both'\n\n // The nav tree follows the app's OWN mode (registry), not the live pill\n // selection — so it is deterministic from app identity. Unscoped apps render\n // Relationship exactly as before. Cross-app links in the Campaign/Petition\n // trees carry the active org the way the switcher/account menu do.\n const navMode: StandardNavMode = appMode ?? 'relationship'\n const activeOrgId = chrome?.orgId ?? null\n const derivedNavItems = useMemo(\n () =>\n standardPolitogyNav({\n coreBaseUrl: POLITOGY_APPS.vrm.origin,\n icons: standardNavIcons,\n // An app that OWNS a standard nav entry (Contacts) nests its own routes\n // under it. This is routing data, not chrome configuration.\n contactsItem: data?.contactsItem,\n petitionsItem: data?.petitionsItem,\n mode: navMode,\n activeOrgId,\n }),\n [data?.contactsItem, data?.petitionsItem, navMode, activeOrgId],\n )\n // Core supplies the canonical tree already decorated with its live gating\n // state (and with app-relative hrefs so its router handles them in-app).\n const navItems = core?.nav ?? derivedNavItems\n\n // Dashboard › Sub › Item, derived from the same tree the sidebar renders.\n // Core publishes its trail from the page itself, because a core page's\n // location is finer-grained than its nav row (e.g. a contact detail view).\n const derivedBreadcrumbs = useMemo(\n () => deriveBreadcrumbs(navItems, pathname, { search, origin: meta.origin }),\n [navItems, pathname, search, meta.origin],\n )\n // An app granted 'breadcrumbs' behaves like core: the page's published\n // trail IS the trail, and a page that publishes nothing shows nothing.\n // (First cut fell back to the derived trail, which put \"Dashboard › Batches\"\n // under every list-page title — a parent nobody chose.) Ungranted apps keep\n // the derived trail exactly as before.\n const breadcrumbs = core\n ? core.page?.breadcrumbs\n : grants?.includes('breadcrumbs')\n ? granted('breadcrumbs')\n : derivedBreadcrumbs\n\n return (\n <>\n <LoadingScreen\n key={bootGeneration}\n visible={bootVisible}\n bootProgress={bootProgress}\n syntheticReady={appReady ?? chromeResolved}\n onExitComplete={() => setBootVisible(false)}\n />\n <NavAppShell\n sidebar={{\n pathname,\n brand: {\n logoSrc: core?.brandLogoSrc ?? modeBrandLogo(appMode),\n logoAlt: 'Politogy',\n badgeLabel: 'P',\n title: 'Politogy',\n },\n nav: {\n // A flat rail's sub-menu IS the nav, so the 'tabs only' preference\n // (which strips children) would leave one childless parent row —\n // flat apps ignore the stripping.\n items:\n navDisplay === 'tabs' && meta.navShape !== 'flat'\n ? navItems.map(({ children: _sub, ...item }) => item)\n : navItems,\n flatten: meta.navShape === 'flat',\n },\n // The app's own workspace is NOT the organization — it is a per-app\n // bootstrap account with a different id in every app. Showing it while\n // the chrome API resolves flashed the wrong org on every load (\"not\n // connected to the account\"). Shimmer while in flight; only fall back\n // to the app label once the chrome lookup has actually failed.\n org: activeCoreOrg\n ? {\n name: activeCoreOrg.name,\n id: activeCoreOrg.id,\n logoUrl: activeCoreOrg.logoUrl,\n brandColor: activeCoreOrg.brandColor,\n organizations: coreOrgs,\n onSwitch: chrome?.setOrgId,\n }\n : chrome?.orgsLoading\n ? { name: null, id: null, loading: true }\n : { name: session.accountName, id: session.accountId },\n mode,\n footer,\n linkComponent,\n }}\n betaBanner={meta.beta === false ? undefined : {}}\n // Mode identity, straight from the registry — this is what lets the Brand\n // API's per-Mode chrome tokens target this frame. Not app-supplied: an app\n // still cannot pick its own accent, it inherits its Mode's.\n modeId={appMode}\n contentWrapper={core?.contentWrapper ?? granted('contentWrapper')}\n topBar={{\n // Core's pages publish their own identity; every other app is one\n // product surface and takes its registry title.\n title: core?.page?.title ?? (grants?.includes('title') ? data?.frame?.title : undefined) ?? meta.title,\n breadcrumbs,\n user: {\n name: identity.userName,\n email: identity.email,\n // The chrome API's avatar wins; the app may supply a fallback chain\n // (e.g. a stored memoji) for users with no uploaded photo.\n avatarUrl: identity.avatarUrl ?? data?.fallbackAvatarUrl ?? null,\n role: session.role,\n },\n userMenu,\n onSignOut: handleSignOut,\n // The action cluster is IDENTICAL everywhere — core included. Page\n // actions sit BEFORE it, never inside it, so the Alerts bell keeps its\n // required position: farthest right, immediately before My Account.\n actions: (\n <>\n {core?.page?.actions}\n <ChromeTopBarActions />\n </>\n ),\n }}\n >\n {children}\n </NavAppShell>\n </>\n )\n}\n","// ---------------------------------------------------------------------------\n// App chrome wiring — the ONE shared implementation of the per-app glue that\n// previously lived as a copied ChromeWidgets.tsx in every Next.js feature app\n// (forms / surveys / polls / contacts). Copies drifted (org dropdown, badges);\n// this module makes that class of drift impossible: apps configure, never\n// re-implement (Reference/UI-Platform: consume via npm, never vendored).\n//\n// Provides:\n// <PolitogyAppChrome> — NavChromeProvider (same-origin proxy fetcher) +\n// chrome state (active core org, nav display) +\n// DevNotes provider, in one wrapper.\n// <ChromeTopBarActions> — the canonical top-bar cluster, in canonical order\n// (Fuel · Nav display · DevNotes · Support · Alerts\n// LAST, immediately left of My Account).\n// useChromeState / useChromeUserMenu / useIsSuperAdmin / useChromeFooter.\n//\n// The app still owns: its session (the /api/chrome proxy), page frames, build\n// metadata (env/commit/version), tab strips, and its own icons.\n// ---------------------------------------------------------------------------\n\n'use client'\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react'\nimport {\n NavChromeProvider,\n FuelAction,\n NotificationsAction,\n SupportAction,\n SpecOverlayAction,\n NavDisplayAction,\n TopBarWidgetSlot,\n useChromeOrgs,\n useThemePreference,\n type NavChromeFetcher,\n type NavDisplayMode,\n type NavOrgOption,\n type NavUserMenu,\n type NavFooter,\n type NavFooterLink,\n} from '../native/index'\nimport {\n DevNotesProvider,\n DevNotesMenu,\n DevNotesOverlay,\n DevNotesTaskListModal,\n createDevNotesClient,\n type DevNotesConfig,\n} from '@the-portland-company/devnotes'\nimport {\n FiActivity,\n FiBarChart2,\n FiBriefcase,\n FiClock,\n FiCreditCard,\n FiDollarSign,\n FiEdit3,\n FiFileText,\n FiFlag,\n FiGrid,\n FiHome,\n FiLayout,\n FiLifeBuoy,\n FiList,\n FiMail,\n FiMap,\n FiMapPin,\n FiMessageSquare,\n FiPhone,\n FiSend,\n FiSettings,\n FiShare2,\n FiTarget,\n FiUpload,\n FiUser,\n FiUsers,\n} from 'react-icons/fi'\nimport { useChromeMe, useNavChromeFetcher } from '../native/index'\nimport {\n ACTIVE_ORG_QUERY_PARAM,\n isOrgId,\n readActiveOrgCookie,\n resolveActiveOrg,\n writeActiveOrgCookie,\n} from '../active-org'\nimport {\n NAV_DISPLAY_DEFAULT,\n NAV_DISPLAY_STORAGE_KEY,\n isNavDisplayPreference,\n readNavDisplayCookie,\n resolveNavDisplay,\n writeNavDisplayCookie,\n writeNavDisplayLocal,\n} from '../nav-preference'\nimport type { StandardNavIconKey } from '../native/standardNav'\nimport type { NavBreadcrumb, NavIcon, NavItem, NavMode } from '../native/index'\n\n/**\n * The canonical icon map for standardPolitogyNav — ONE definition so every\n * app renders identical glyphs (including the Organization Settings branch:\n * briefcase / settings / creditCard / dollarSign / share).\n */\nexport const standardNavIcons: Record<StandardNavIconKey, NavIcon> = {\n home: FiHome,\n users: FiUsers,\n mail: FiMail,\n messageSquare: FiMessageSquare,\n layout: FiLayout,\n activity: FiActivity,\n lifeBuoy: FiLifeBuoy,\n grid: FiGrid,\n list: FiList,\n upload: FiUpload,\n edit: FiEdit3,\n fileText: FiFileText,\n send: FiSend,\n clock: FiClock,\n user: FiUser,\n barChart: FiBarChart2,\n briefcase: FiBriefcase,\n settings: FiSettings,\n creditCard: FiCreditCard,\n dollarSign: FiDollarSign,\n share: FiShare2,\n // Campaign / Petition mode slots.\n phone: FiPhone,\n map: FiMap,\n mapPin: FiMapPin,\n target: FiTarget,\n flag: FiFlag,\n}\n\nconst ORG_STORAGE_KEY = 'vrm.activeOrg'\n// The user's mode choice, shared by every app on the origin's localStorage.\nconst MODE_STORAGE_KEY = 'vrm.activeMode'\nconst CORE_BASE_URL = 'https://app.politogyvrm.com'\nconst CORE_BASE_URL_STAGING = 'https://staging-app.politogyvrm.com'\n\n/**\n * VRM-core base for the CURRENT environment, resolved at call time from the\n * host. A staging app (e.g. `surveys-staging.politogyvrm.com`,\n * `staging-app.politogyvrm.com`) targets the staging core, so cross-app links\n * into core — My Profile, Organization Settings, Add Account, the mode\n * dashboards — stay in staging instead of bouncing the user to production.\n * Everything else (prod hosts, localhost, previews) keeps the production core.\n *\n * Runtime, not build-time: the shell is one shared bundle consumed by every\n * app, so the environment can only be known from the host it runs on.\n */\nfunction getCoreBaseUrl(): string {\n if (typeof window !== 'undefined') {\n if (window.location.hostname.toLowerCase().includes('staging')) {\n return CORE_BASE_URL_STAGING\n }\n }\n return CORE_BASE_URL\n}\n\nexport type ChromeIdentity = {\n userId: string\n userName: string | null\n email: string | null\n /** The APP's own role string (any casing) — feeds DevNotes admin gating. */\n role: string\n}\n\ntype ChromeState = {\n orgId: string | null\n setOrgId: (id: string) => void\n orgs: (NavOrgOption & { rawRole?: string | null })[]\n /**\n * The org list is still in flight. Consumers must render a skeleton rather\n * than fall back to the app's own workspace label, which is a DIFFERENT\n * account and flashes as the wrong organization.\n */\n orgsLoading: boolean\n navDisplay: NavDisplayMode\n setNavDisplay: (m: NavDisplayMode) => void\n}\n\nconst ChromeStateContext = createContext<ChromeState | null>(null)\n\nexport function useChromeState(): ChromeState | null {\n return useContext(ChromeStateContext)\n}\n\nexport type ControlledOrgState = {\n orgId: string | null\n onSwitch: (id: string) => void\n /** Override the org list (e.g. the app's own session-scoped list). */\n orgs?: (NavOrgOption & { rawRole?: string | null })[]\n /**\n * Applied for EXTERNAL org changes (another tab/app switched the shared\n * cookie, or the profile preference was adopted at boot). Unlike `onSwitch`\n * (a user gesture), this fires on tab focus — wire it WITHOUT navigation\n * side effects (e.g. vrm/core's switch without the dashboard redirect).\n * Falls back to `onSwitch` when absent.\n */\n onExternalSwitch?: (id: string) => void\n}\n\nfunction ChromeStateProvider({\n controlledOrg,\n children,\n}: {\n controlledOrg?: ControlledOrgState\n children: ReactNode\n}) {\n const { orgs, loading: orgsFetching, error: orgsError } = useChromeOrgs()\n const chromeMe = useChromeMe()\n const chromeFetch = useNavChromeFetcher()\n const [orgId, setOrgIdState] = useState<string | null>(null)\n const [navDisplay, setNavDisplayState] = useState<NavDisplayMode>(NAV_DISPLAY_DEFAULT)\n const navReconciled = useRef(false)\n const orgReconciled = useRef(false)\n // Whether boot found an explicit selector (URL `?org=` or the shared cookie).\n // The mirror effect writes the cookie right after first resolve, so a later\n // `resolveActiveOrg()` read is a false positive — this ref is the only\n // reliable \"was there a pre-existing selector?\" signal for the profile tier.\n const hadBootSelector = useRef(false)\n\n // Boot: restore persisted choices. The cross-app active org (URL `?org=` or\n // the `.politogyvrm.com` cookie) wins over host-only localStorage so every\n // app + subdomain resolves the SAME org instead of each defaulting to its own\n // earliest-joined org. Nav display follows the same cross-subdomain contract\n // as theme (cookie → localStorage → default) — it used to be localStorage\n // only, which is per-origin, so it reset on every app the user opened.\n useEffect(() => {\n try {\n const selector = resolveActiveOrg()\n if (selector) hadBootSelector.current = true\n const storedOrg = selector ?? localStorage.getItem(ORG_STORAGE_KEY)\n if (storedOrg) setOrgIdState(storedOrg)\n } catch {\n /* storage unavailable */\n }\n setNavDisplayState(resolveNavDisplay())\n }, [])\n\n // Once per session: converge on the profile's saved choice (authoritative),\n // reusing the provider's single `me` fetch — the theme reconcile pattern.\n useEffect(() => {\n if (navReconciled.current || !chromeMe.me) return\n const pref = chromeMe.me.navDisplay\n if (!isNavDisplayPreference(pref)) return\n navReconciled.current = true\n setNavDisplayState(pref)\n writeNavDisplayCookie(pref)\n writeNavDisplayLocal(pref)\n }, [chromeMe])\n\n // Live sync: `storage` events for same-app tabs, cookie re-reads on\n // focus/visibility for tabs on OTHER app subdomains.\n useEffect(() => {\n const onStorage = (e: StorageEvent) => {\n if (e.key === NAV_DISPLAY_STORAGE_KEY && isNavDisplayPreference(e.newValue)) {\n setNavDisplayState(e.newValue)\n }\n }\n const onWake = () => {\n const cookie = readNavDisplayCookie()\n if (cookie) setNavDisplayState(cookie)\n }\n window.addEventListener('storage', onStorage)\n window.addEventListener('focus', onWake)\n document.addEventListener('visibilitychange', onWake)\n return () => {\n window.removeEventListener('storage', onStorage)\n window.removeEventListener('focus', onWake)\n document.removeEventListener('visibilitychange', onWake)\n }\n }, [])\n\n // Once orgs resolve: validate the stored org, default to the first.\n useEffect(() => {\n if (!orgs || orgs.length === 0) return\n setOrgIdState((prev) => (prev && orgs.some((o) => o.id === prev) ? prev : orgs[0].id))\n }, [orgs])\n\n // Refs for the live-sync wake handler: registered once (theme/nav precedent)\n // but acting on CURRENT state, so listeners never re-subscribe per render.\n const activeOrgRef = useRef<string | null>(null)\n const memberOrgsRef = useRef<{ id: string }[]>([])\n const controlledOrgRef = useRef<ControlledOrgState | undefined>(controlledOrg)\n controlledOrgRef.current = controlledOrg\n\n // Apply an EXTERNAL org change (another tab/app, or the adopted profile\n // preference). Membership-guarded and change-guarded; silent fall-through\n // otherwise — a non-member cookie value is normal, not an error.\n const applyExternalOrg = useCallback((next: string | null) => {\n if (!isOrgId(next)) return\n const members = memberOrgsRef.current\n if (members.length === 0) return\n if (!members.some((o) => o.id === next)) return\n if (next === activeOrgRef.current) return\n const controlled = controlledOrgRef.current\n if (controlled) (controlled.onExternalSwitch ?? controlled.onSwitch)(next as string)\n else setOrgIdState(next as string)\n }, [])\n\n // Live org sync: `storage` events for same-origin tabs, cookie re-reads on\n // focus/visibility for tabs on OTHER app subdomains — the same two channels\n // theme and nav display use. A user switching orgs in one app re-scopes\n // every other open tab the moment it regains focus.\n useEffect(() => {\n const onStorage = (e: StorageEvent) => {\n if (e.key === ORG_STORAGE_KEY) applyExternalOrg(e.newValue)\n }\n const onWake = () => {\n applyExternalOrg(readActiveOrgCookie())\n }\n window.addEventListener('storage', onStorage)\n window.addEventListener('focus', onWake)\n document.addEventListener('visibilitychange', onWake)\n return () => {\n window.removeEventListener('storage', onStorage)\n window.removeEventListener('focus', onWake)\n document.removeEventListener('visibilitychange', onWake)\n }\n }, [applyExternalOrg])\n\n // Once per session: adopt the profile's saved org (me.activeOrg) — but ONLY\n // when this load carried no explicit selector. Precedence is URL → cookie →\n // profile → default; theme's unconditional adopt is wrong for org because an\n // explicit per-request selector must always win.\n //\n // Membership is judged against the FETCHED chrome-API org list, not the\n // controlled app's list: controlled apps seed a provisional single-org list\n // (their session default) before their real fetch settles, and judging the\n // preference against that dropped it every time (verified live 2026-08-07).\n useEffect(() => {\n if (orgReconciled.current || !chromeMe.me) return\n if (hadBootSelector.current) {\n orgReconciled.current = true\n return\n }\n const pref = (chromeMe.me as { activeOrg?: string | null }).activeOrg\n if (!isOrgId(pref)) {\n orgReconciled.current = true\n return\n }\n // Wait until the chrome-API org fetch settles (success or error) — do NOT\n // latch while it is in flight, or the preference is silently dropped.\n if (!orgs && !orgsError) return\n orgReconciled.current = true\n const members = [...(orgs ?? []), ...(controlledOrg?.orgs ?? [])]\n if (!members.some((o) => o.id === pref)) return\n const controlled = controlledOrgRef.current\n if (controlled) (controlled.onExternalSwitch ?? controlled.onSwitch)(pref as string)\n else setOrgIdState(pref as string)\n }, [chromeMe.me, orgs, orgsError, controlledOrg])\n\n const setOrgId = useCallback((id: string) => {\n setOrgIdState(id)\n try {\n localStorage.setItem(ORG_STORAGE_KEY, id)\n } catch {\n /* best effort */\n }\n // Remember the choice cross-subdomain so the next app opens on the same org.\n writeActiveOrgCookie(id)\n }, [])\n\n const setNavDisplay = useCallback(\n (m: NavDisplayMode) => {\n setNavDisplayState(m)\n writeNavDisplayLocal(m)\n // Cross-subdomain, so the next app opens on the same choice.\n writeNavDisplayCookie(m)\n // Best-effort durable persistence on the user's profile — a nav toggle\n // never errors, and the cookie already carries the choice meanwhile.\n chromeFetch?.('me/preferences', {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ navDisplay: m }),\n })?.catch(() => {})\n },\n [chromeFetch],\n )\n\n const value = useMemo<ChromeState>(() => {\n // CONTROLLED mode (Contacts): the APP owns the active org + switching —\n // its switch does a full session re-scope. The shared widgets read the\n // app's state so there is exactly one org truth (unification directive).\n if (controlledOrg) {\n return {\n orgId: controlledOrg.orgId,\n setOrgId: controlledOrg.onSwitch,\n orgs:\n controlledOrg.orgs ??\n (orgs ?? []).map((o) => ({\n id: o.id,\n name: o.name,\n logoUrl: o.logoUrl,\n brandColor: o.brandColor,\n role: o.role,\n rawRole: o.rawRole ?? null,\n })),\n orgsLoading: false,\n navDisplay,\n setNavDisplay,\n }\n }\n return {\n orgId,\n setOrgId,\n orgs: (orgs ?? []).map((o) => ({\n id: o.id,\n name: o.name,\n logoUrl: o.logoUrl,\n brandColor: o.brandColor,\n role: o.role,\n rawRole: o.rawRole ?? null,\n })),\n // Loading until the fetch settles. On error we stop loading so the frame\n // falls back to the app label rather than shimmering forever.\n orgsLoading: orgsFetching && !orgsError && !orgs,\n navDisplay,\n setNavDisplay,\n }\n }, [controlledOrg, orgId, setOrgId, orgs, orgsFetching, orgsError, navDisplay, setNavDisplay])\n\n // Keep the shared cookie + address-bar `?org=` in sync with the ACTIVE org —\n // whichever path owns it, controlled (Contacts) or uncontrolled (feature\n // apps) — so every app + tab resolves the same org and every URL is\n // bookmarkable/shareable with its org context. Idempotent; no-op on server.\n const activeOrgId = value.orgId\n activeOrgRef.current = activeOrgId\n memberOrgsRef.current = value.orgs\n const lastPatchedOrg = useRef<string | null>(null)\n useEffect(() => {\n if (!isOrgId(activeOrgId)) return\n writeActiveOrgCookie(activeOrgId as string)\n try {\n // Same-origin storage channel for OTHER tabs of this app (the cookie\n // write emits no event) — mirrors the choice whichever branch owns it.\n localStorage.setItem(ORG_STORAGE_KEY, activeOrgId as string)\n } catch {\n /* best effort */\n }\n try {\n const url = new URL(window.location.href)\n if (url.searchParams.get(ACTIVE_ORG_QUERY_PARAM) !== activeOrgId) {\n url.searchParams.set(ACTIVE_ORG_QUERY_PARAM, activeOrgId as string)\n window.history.replaceState(window.history.state, '', url.toString())\n }\n } catch {\n /* SSR / no window */\n }\n // Durable profile write (the theme/nav pattern): one call site covers both\n // the controlled and uncontrolled branches. Best-effort, deduped against\n // the profile's known value and our own last write; a fresh browser with\n // no cookie then boots on this org via the profile tier.\n //\n // GATED on the reconcile having resolved: before that, activeOrgId is the\n // app's boot DEFAULT, and patching it overwrote the user's stored\n // preference with the default on every fresh session (verified live\n // 2026-08-07 — the preference lasted exactly one login).\n const known = (chromeMe.me as { activeOrg?: string | null } | null)?.activeOrg ?? null\n if (\n orgReconciled.current &&\n chromeMe.me &&\n activeOrgId !== known &&\n activeOrgId !== lastPatchedOrg.current\n ) {\n lastPatchedOrg.current = activeOrgId as string\n chromeFetch?.('me/preferences', {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ activeOrg: activeOrgId }),\n })?.catch(() => {})\n }\n }, [activeOrgId, chromeMe.me, chromeFetch])\n\n return <ChromeStateContext.Provider value={value}>{children}</ChromeStateContext.Provider>\n}\n\nexport type ChromeDevNotesConfig = {\n /** Override the DevNotes API base (default: `${proxyBasePath}/devnotes`). */\n basePath?: string\n /** Client-side token supplier (default: empty — same-origin proxy injects). */\n getAuthToken?: () => Promise<string> | string\n /** Custom fetch (e.g. credentials:'include' against a cross-origin API). */\n fetch?: typeof globalThis.fetch\n /**\n * The app already mounts its own `<DevNotesProvider>` ABOVE this chrome, so\n * the chrome must not mount a second one (VRM core, whose provider carries\n * capabilities the generic client has no equivalent for — user stories, its\n * own role gating). The working SURFACE still comes from here, so the\n * launcher, the overlay and the task modal behave identically everywhere;\n * only the data adapter is the app's.\n */\n providedByApp?: boolean\n}\n\nfunction AppDevNotes({\n storagePrefix,\n proxyBasePath,\n devNotes,\n identity,\n children,\n}: {\n storagePrefix: string\n proxyBasePath: string\n devNotes?: ChromeDevNotesConfig\n identity: ChromeIdentity\n children: ReactNode\n}) {\n const adapter = useMemo(\n () =>\n createDevNotesClient({\n basePath: devNotes?.basePath ?? `${proxyBasePath}/devnotes`,\n // Default: the same-origin proxy attaches the session's Bearer.\n getAuthToken: devNotes?.getAuthToken ?? (async () => ''),\n ...(devNotes?.fetch ? { fetch: devNotes.fetch } : {}),\n }),\n [proxyBasePath, devNotes?.basePath, devNotes?.getAuthToken, devNotes?.fetch],\n )\n\n const user = useMemo(\n () => ({\n id: identity.userId,\n email: identity.email ?? '',\n fullName: identity.userName ?? undefined,\n }),\n [identity.userId, identity.email, identity.userName],\n )\n\n const config = useMemo<DevNotesConfig>(\n () => ({\n storagePrefix,\n role: identity.role.toLowerCase() === 'admin' ? 'admin' : 'reporter',\n disableAi: true,\n getPagePath: () => window.location.pathname,\n }),\n [storagePrefix, identity.role],\n )\n\n // `<DevNotesProvider>` hydrates tasks/task-types/task-lists/collaborators/\n // app-link/capabilities unconditionally on mount — 5-6 requests, one 6.8s\n // cold, even when the panel is never opened (nav-latency-report.md Table 2).\n // Gate those specific adapter methods behind the panel's FIRST open; the\n // launcher button (`ChromeDevNotesMenu` below) still renders and responds\n // instantly, it just flips `activate()` on pointerdown before its own click\n // handler runs. `fetchUnreadCounts` (the launcher badge count) is exempt\n // from the open-gate — it still needs a number before the user opens\n // anything — but its first call is pushed off the boot path onto\n // requestIdleCallback so it never competes with first paint.\n const activatedRef = useRef(false)\n const activationWaitersRef = useRef<Array<() => void>>([])\n const activate = useCallback(() => {\n if (activatedRef.current) return\n activatedRef.current = true\n const waiters = activationWaitersRef.current\n activationWaitersRef.current = []\n waiters.forEach((resolve) => resolve())\n }, [])\n const waitForActivation = useCallback((): Promise<void> => {\n if (activatedRef.current) return Promise.resolve()\n return new Promise((resolve) => {\n activationWaitersRef.current.push(resolve)\n })\n }, [])\n\n const lazyAdapter = useMemo<typeof adapter>(() => {\n const GATED_METHODS = [\n 'fetchTasks',\n 'fetchTaskTypes',\n 'fetchTaskLists',\n 'fetchCollaborators',\n 'fetchCapabilities',\n 'getAppLinkStatus',\n 'fetchBugReports',\n 'fetchBugReportTypes',\n ] as const\n const wrapped: Record<string, unknown> = { ...adapter }\n for (const method of GATED_METHODS) {\n const original = (adapter[method] as (...args: unknown[]) => Promise<unknown>).bind(adapter)\n wrapped[method] = (...args: unknown[]) => waitForActivation().then(() => original(...args))\n }\n let idleScheduled = false\n const originalUnreadCounts = adapter.fetchUnreadCounts.bind(adapter)\n wrapped.fetchUnreadCounts = () => {\n if (idleScheduled || typeof window === 'undefined') return originalUnreadCounts()\n idleScheduled = true\n return new Promise((resolve, reject) => {\n const run = () => originalUnreadCounts().then(resolve, reject)\n const ric = (window as { requestIdleCallback?: (cb: () => void) => number })\n .requestIdleCallback\n if (ric) ric(run)\n else setTimeout(run, 0)\n })\n }\n return wrapped as unknown as typeof adapter\n }, [adapter, waitForActivation])\n\n // The app brought its own provider — mount only the surface, so a second\n // DevNotesProvider never shadows the app's adapter. (The app's own adapter\n // is out of this chrome's control, so the open-gate above does not apply.)\n if (devNotes?.providedByApp) return <DevNotesSurface activate={activate}>{children}</DevNotesSurface>\n\n return (\n <DevNotesProvider adapter={lazyAdapter} user={user} config={config}>\n <DevNotesSurface activate={activate}>{children}</DevNotesSurface>\n </DevNotesProvider>\n )\n}\n\n// \"View All Tasks\" is triggered from the menu in the top bar but the modal has\n// to render at the chrome ROOT, or it would be trapped inside the top bar's\n// stacking/blur context. The menu publishes the request through this context.\nconst DevNotesTasksContext = createContext<{\n ready: boolean\n openTasks: () => void\n activate: () => void\n}>({\n ready: false,\n openTasks: () => {},\n activate: () => {},\n})\n\n/**\n * The DevNotes working surface, mounted once at the chrome root.\n *\n * `<DevNotesMenu>` only TOGGLES creation mode — `<DevNotesOverlay>` is what\n * renders the click-to-place capture layer, the report dots and the report\n * form. The shell shipped the provider and the menu but never the overlay, so\n * on every app that used this chrome (forms / surveys / polls) \"Create Task\"\n * closed the menu and did nothing at all: the mode flipped on with nothing\n * listening (HITL bug report 2026-07-23). Contacts didn't hit it only because\n * it still had its own hand-rolled surface.\n */\nfunction DevNotesSurface({\n activate,\n children,\n}: {\n /** Flips the DevNotes data adapter open for the first time (no-op after). */\n activate: () => void\n children: ReactNode\n}) {\n const [tasksOpen, setTasksOpen] = useState(false)\n const openTasks = useCallback(() => {\n activate()\n setTasksOpen(true)\n }, [activate])\n const tasksCtx = useMemo(() => ({ ready: true, openTasks, activate }), [openTasks, activate])\n\n return (\n <DevNotesTasksContext.Provider value={tasksCtx}>\n {children}\n {/* Mounted only while open: the modal loads data on mount regardless of\n its `open` prop, so keeping it unmounted avoids fetching every user's\n tasks before they ask for them. */}\n {tasksOpen ? <DevNotesTaskListModal open onClose={() => setTasksOpen(false)} /> : null}\n <DevNotesOverlay />\n </DevNotesTasksContext.Provider>\n )\n}\n\n/**\n * The app-chrome root. Wrap the authenticated frame once:\n *\n * <PolitogyAppChrome storagePrefix=\"forms\" identity={{userId, userName, email, role}}>\n * <ShellFrame …/>\n * </PolitogyAppChrome>\n */\nexport function PolitogyAppChrome({\n storagePrefix,\n proxyBasePath = '/api/chrome',\n fetchJson: fetchJsonOverride,\n devNotes,\n org,\n identity,\n children,\n}: {\n storagePrefix: string\n proxyBasePath?: string\n /**\n * Override the same-origin proxy fetcher for apps that talk to the chrome\n * API directly with their own auth (Contacts sends a client-side Bearer).\n * Paths stay relative ('orgs', 'me', …) — the override owns base + auth.\n */\n fetchJson?: NavChromeFetcher\n /** DevNotes wiring override for direct-auth apps (Contacts). */\n devNotes?: ChromeDevNotesConfig\n /** Controlled org state — the app owns active-org + switching (Contacts). */\n org?: ControlledOrgState\n identity: ChromeIdentity\n children: ReactNode\n}) {\n const proxyFetchJson = useMemo<NavChromeFetcher>(\n () =>\n async (path, init) => {\n const res = await fetch(`${proxyBasePath}/${path}`, {\n method: init?.method ?? 'GET',\n headers: init?.headers,\n body: init?.body,\n })\n if (!res.ok) throw new Error(`chrome ${path}: ${res.status}`)\n if (res.status === 204) return null\n const text = await res.text()\n return text ? JSON.parse(text) : null\n },\n [proxyBasePath],\n )\n const fetchJson = fetchJsonOverride ?? proxyFetchJson\n\n return (\n <NavChromeProvider fetchJson={fetchJson}>\n <ChromeStateProvider controlledOrg={org}>\n <AppDevNotes\n storagePrefix={storagePrefix}\n proxyBasePath={proxyBasePath}\n devNotes={devNotes}\n identity={identity}\n >\n {children}\n </AppDevNotes>\n </ChromeStateProvider>\n </NavChromeProvider>\n )\n}\n\n/** The standard top-bar action cluster. The Alerts bell renders LAST so it\n * sits farthest right, immediately left of the My Account badge. */\nexport function ChromeTopBarActions() {\n const state = useChromeState()\n if (!state) return null\n return (\n <>\n <FuelAction orgId={state.orgId} />\n <NavDisplayAction value={state.navDisplay} onChange={state.setNavDisplay} />\n <TopBarWidgetSlot\n title=\"DevNotes\"\n description=\"Capture bugs and notes, filed straight to Forge.\"\n >\n <ChromeDevNotesMenu />\n </TopBarWidgetSlot>\n <SpecOverlayAction orgId={state.orgId} />\n <SupportAction orgId={state.orgId} />\n <NotificationsAction orgId={state.orgId} />\n </>\n )\n}\n\n/**\n * The DevNotes launcher. Renders nothing until the surface above is mounted, so\n * it never touches DevNotes context before the provider exists, and forwards\n * \"View All Tasks\" to the root-level modal.\n */\nfunction ChromeDevNotesMenu() {\n const { ready, openTasks, activate } = useContext(DevNotesTasksContext)\n if (!ready) return null\n // `onPointerDownCapture` fires before DevNotesMenu's own click handler, so\n // the adapter is already unblocked by the time the menu's first \"Create\n // Task\" click reaches it. `display: contents` keeps the wrapper out of\n // layout entirely — the launcher renders exactly as before.\n return (\n <span style={{ display: 'contents' }} onPointerDownCapture={activate} onFocusCapture={activate} onKeyDownCapture={activate}>\n <DevNotesMenu position=\"top-right\" onViewTasks={openTasks} />\n </span>\n )\n}\n\n/** True when any core-org membership carries a super-admin tier. */\nexport function useIsSuperAdmin(): boolean {\n const state = useChromeState()\n return (state?.orgs ?? []).some((o) => /super/i.test(o.rawRole ?? ''))\n}\n\nconst FOOTER_LINKS: NavFooterLink[] = [\n { label: 'Privacy', href: `${CORE_BASE_URL}/privacy-policy`, external: true },\n { label: 'Terms', href: `${CORE_BASE_URL}/terms-and-conditions`, external: true },\n {\n label: 'Subscriptions',\n href: 'https://politogyvrm.com/subscription-cancellation-policy',\n external: true,\n },\n]\n\n/**\n * Sidebar footer: legal links AND build metadata (env / commit / version /\n * date / author) for every user. Reference/UI-Platform \"Left bar — required\n * elements\" lists Meta unconditionally — it carries no Super Administrator\n * gate. Gating it here (pre-2026-09-30) silently dropped the whole Meta row\n * for every non-admin viewer, which is exactly the \"Left Nav not adhering to\n * UI/UX rules\" violation DevNotes 83a4713 filed against Contacts. Pass the\n * app's build-time metadata in; it now always reaches the rail.\n */\nexport function useChromeFooter(meta: {\n envLabel?: string\n version?: string\n commit?: string\n commitDate?: string\n commitAuthor?: string\n}): NavFooter {\n return useMemo<NavFooter>(\n () => ({ links: FOOTER_LINKS, ...meta }),\n [meta.envLabel, meta.version, meta.commit, meta.commitDate, meta.commitAuthor],\n )\n}\n\n// ---------------------------------------------------------------------------\n// Identity — resolved by the PACKAGE, from the chrome API.\n//\n// Apps used to pass a display name straight from their own session claims, and\n// forms passed `user.name ?? user.email` — so a user with no name set had their\n// EMAIL rendered as their name, and the chrome API's real profile name could\n// never win (HITL 2026-07-23). The chrome API is the authority; what the app\n// passes is a pre-hydration fallback only, and an email is never a name.\n// ---------------------------------------------------------------------------\n\nexport function useChromeIdentity(fallback?: {\n userName?: string | null\n email?: string | null\n}): ResolvedIdentity {\n const { me, loaded } = useChromeMe()\n return resolveIdentity({\n apiName: me?.userName,\n fallbackName: fallback?.userName,\n email: fallback?.email,\n avatarUrl: me?.avatarUrl,\n loaded,\n })\n}\n\n// Breadcrumbs live in ../lib/breadcrumbs (pure, dependency-free) and are\n// re-exported here so apps keep a single import surface.\nexport { deriveBreadcrumbs } from '../lib/breadcrumbs'\nexport { looksLikeEmail, resolveIdentity, type ResolvedIdentity } from '../lib/identity'\nimport { resolveIdentity, type ResolvedIdentity } from '../lib/identity'\n\n// ---------------------------------------------------------------------------\n// Breadcrumbs — derived by the PACKAGE from the nav tree + the current path.\n//\n// Every app hand-built its own trail, so they disagreed: forms rendered\n// \"Forms › Dashboard\" while polls rendered \"Polls\" under a \"Polls\" title\n// (\"Polls / Polls\"). The standard is Dashboard › Sub › Item (HITL 2026-07-23),\n// derived from the same nav tree the sidebar renders, so no app can drift.\n// ---------------------------------------------------------------------------\n\n/**\n * The My Account menu config — profile/org links into VRM core, real roles\n * from the user's core organizations, the signed-in account, and the shared\n * Light/System/Dark theme control (auth-derived, cross-app).\n */\nexport function useChromeUserMenu({\n userId,\n userName,\n email,\n}: {\n userId: string\n userName: string | null\n email: string | null\n}): NavUserMenu {\n const state = useChromeState()\n const theme = useThemePreference()\n const activeOrg = state?.orgs.find((o) => o.id === state.orgId) ?? null\n const orgSuffix = activeOrg ? `?org=${activeOrg.id}` : ''\n // Environment-aware: on a staging app these must point at the staging core,\n // not production (HITL: editing Profile from a staging app redirected to prod).\n const coreBase = getCoreBaseUrl()\n return {\n // My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).\n myProfileHref: `${coreBase}/my-profile`,\n organizationSettingsHref: `${coreBase}/organization-settings${orgSuffix}`,\n roles: (state?.orgs ?? [])\n .filter((o) => o.rawRole || o.role)\n .map((o) => ({ role: (o.rawRole ?? o.role) as string, orgName: o.name })),\n accounts: [{ id: userId, name: userName, email, avatarUrl: null, active: true }],\n addAccountHref: `${coreBase}/my-profile#accounts`,\n theme: { value: theme.value, onChange: theme.setValue },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Mode selector — entitlement-driven (HITL 2026-07-23: an org with multiple\n// active modes selects them from the left nav). Entitlements come from the\n// chrome API: GET me with the active org header → modes booleans\n// {relationship, campaign, petition, polling}. Selecting a mode navigates to\n// that mode's VRM-core dashboard carrying the active org.\n// ---------------------------------------------------------------------------\n\nconst MODE_DEFS: {\n id: string\n label: string\n icon: NavIcon\n /** Absolute destination, or a VRM-core path prefixed with CORE_BASE_URL. */\n href: string\n orgQuery: boolean\n}[] = [\n {\n id: 'relationship',\n label: 'Relationship Mode',\n icon: FiUsers,\n href: `${CORE_BASE_URL}/relationship/dashboard`,\n orgQuery: true,\n },\n {\n id: 'campaign',\n label: 'Campaign Mode',\n icon: FiBarChart2,\n href: `${CORE_BASE_URL}/campaign/dashboard`,\n orgQuery: true,\n },\n {\n // Petition Mode lives in its own standalone app on its own subdomain — the\n // petitions repo deploys production to petition-mode.politogyvrm.com.\n id: 'petition',\n label: 'Petition Mode',\n icon: FiFlag,\n href: 'https://petition-mode.politogyvrm.com/',\n orgQuery: true,\n },\n]\n\ntype ModeId = 'relationship' | 'campaign' | 'petition'\n\ntype UseChromeModeArg =\n | ModeId\n | {\n /** Pre-entitlement fallback for first paint (default 'relationship'). */\n fallbackModeId?: ModeId\n /**\n * Registry-pinned mode for a MODE-SCOPED app (e.g. the Campaign apps\n * a2p / phonebank / canvass / signs, from `POLITOGY_APPS[app].mode`). The\n * pill DISPLAYS this mode regardless of the cross-app selection, so a\n * campaign app never shows a Relationship pill. The switcher still appears\n * when the active org is entitled to more than one mode, so the user can\n * jump out to another mode's home.\n */\n pinnedModeId?: ModeId\n }\n\n/**\n * The active mode pill / selector.\n *\n * For an UNSCOPED app the current mode is the USER'S OWN SELECTION (persisted\n * cross-app in localStorage under `vrm.activeMode`), narrowed to what the active\n * org is entitled to — never a literal an app hardcodes. Apps used to call\n * `useChromeMode('relationship')`, which pinned the pill to Relationship even\n * for an org entitled to Campaign or Petition (HITL 2026-07-23); the string\n * argument now only supplies the pre-entitlement fallback for first paint.\n *\n * A MODE-SCOPED app passes `{ pinnedModeId }` so its pill displays that mode\n * (its own mode from the app registry) rather than the cross-app selection —\n * while a multi-mode org still gets the switcher to leave.\n */\nexport function useChromeMode(arg: UseChromeModeArg = {}): NavMode {\n const { fallbackModeId = 'relationship', pinnedModeId } =\n typeof arg === 'string' ? { fallbackModeId: arg, pinnedModeId: undefined } : arg\n const ctx = useContext(ChromeStateContext)\n const nav = useNavChromeFetcher()\n const orgId = ctx?.orgId ?? null\n const [entitled, setEntitled] = useState<Record<string, boolean> | null>(null)\n const [selectedModeId, setSelectedModeId] = useState<string | null>(null)\n\n // Restore the user's last mode choice (shared key across every app).\n useEffect(() => {\n try {\n const stored = localStorage.getItem(MODE_STORAGE_KEY)\n if (stored && MODE_DEFS.some((m) => m.id === stored)) setSelectedModeId(stored)\n } catch {\n /* storage unavailable */\n }\n }, [])\n\n useEffect(() => {\n if (!nav || !orgId) return\n let cancelled = false\n nav('me', { headers: { 'x-contacts-org': orgId } })\n .then((data) => {\n if (cancelled) return\n const modes = (data as { modes?: Record<string, boolean> | null })?.modes ?? null\n setEntitled(modes)\n })\n .catch(() => {\n /* entitlements unavailable — single-mode pill stands */\n })\n return () => {\n cancelled = true\n }\n }, [nav, orgId])\n\n const options = MODE_DEFS.filter((m) => entitled?.[m.id])\n // Resolution order: a registry pin (mode-scoped app) wins outright → then the\n // user's selection (if the org is still entitled to it) → the first entitled\n // mode → the app's fallback. Entitlements are async, so before they land the\n // pin/fallback holds the pill's shape (no layout shift).\n const pinned = pinnedModeId ? MODE_DEFS.find((m) => m.id === pinnedModeId) ?? null : null\n const selected = selectedModeId\n ? options.find((m) => m.id === selectedModeId) ?? null\n : null\n const current =\n pinned ??\n selected ??\n options[0] ??\n MODE_DEFS.find((m) => m.id === fallbackModeId) ??\n MODE_DEFS[0]\n const suffix = orgId ? `?org=${orgId}` : ''\n\n return {\n label: current.label,\n icon: current.icon,\n options:\n options.length > 1\n ? options.map((o) => ({ id: o.id, label: o.label, icon: o.icon }))\n : undefined,\n onSelect:\n options.length > 1\n ? (id: string) => {\n const def = MODE_DEFS.find((m) => m.id === id)\n if (!def) return\n // Remember the choice BEFORE navigating so the destination app —\n // and every app after it — opens in the mode the user picked.\n setSelectedModeId(id)\n try {\n localStorage.setItem(MODE_STORAGE_KEY, id)\n } catch {\n /* storage unavailable */\n }\n // Env-aware: the two VRM-core dashboards are baked with the prod\n // base at module load; on a staging app rewrite it to the staging\n // core so a mode switch stays in staging (petition mode is a fully\n // absolute URL and is left untouched by the replace).\n const href = def.href.replace(CORE_BASE_URL, getCoreBaseUrl())\n const sep = href.includes('?') ? '&' : '?'\n window.location.assign(\n def.orgQuery && suffix ? `${href}${sep}${suffix.slice(1)}` : href,\n )\n }\n : undefined,\n }\n}\n\n// The one-component app frame (see ./frame.tsx). Re-exported here so apps have\n// a single import surface: `@the-portland-company/shell/app-chrome`.\nexport {\n PolitogyAppFrame,\n POLITOGY_APPS,\n type PolitogyAppKey,\n type PolitogyAppMode,\n type PolitogyAppSession,\n type PolitogyBuildMeta,\n type PolitogyFrameData,\n type PolitogyFrameGrant,\n type PolitogyGrantedFrame,\n} from './frame'\n\n// The boot-screen surface (Specs/Loading-Screen), mounted by PolitogyAppFrame.\n// Re-exported so an app with a real pipeline can type its `bootProgress` prop.\nexport { LoadingScreen, type BootProgress, type BootStageId, type BootPhase } from './loading-screen'\n"]}
1
+ {"version":3,"sources":["../src/lib/breadcrumbs.ts","../src/lib/identity.ts","../src/mode-preference.ts","../src/app-chrome/loading-screen.tsx","../src/app-chrome/frame.tsx","../src/app-chrome/index.tsx"],"names":["trail","jsx","useState","useRef","useEffect","useMemo","pathname","jsxs","useCallback","Fragment"],"mappings":"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","file":"app-chrome.js","sourcesContent":["// Breadcrumb derivation — pure, dependency-free logic (no React, no DevNotes),\n// so it is importable from a server module and testable in isolation.\n//\n// The standard is Dashboard > Sub > Item (HITL 2026-07-23), derived from the\n// same nav tree the sidebar renders. Apps previously hand-built their own\n// trails and disagreed: forms rendered \"Forms > Dashboard\" while polls rendered\n// a lone \"Polls\" crumb under a \"Polls\" title (\"Polls / Polls\").\n\nimport type { NavBreadcrumb, NavItem } from '../native/index'\n\nexport function deriveBreadcrumbs(\n items: NavItem[],\n pathname: string,\n opts?: { search?: string; origin?: string },\n): NavBreadcrumb[] {\n const search = opts?.search ?? (typeof window !== 'undefined' ? window.location.search : '')\n const origin = opts?.origin ?? (typeof window !== 'undefined' ? window.location.origin : '')\n\n // Same-origin comparison: cross-app hrefs are absolute, local ones relative.\n const matches = (href?: string): boolean => {\n if (!href) return false\n let path = href\n let query = ''\n if (/^https?:\\/\\//i.test(href)) {\n try {\n const u = new URL(href)\n if (origin && u.origin !== origin) return false\n path = u.pathname\n query = u.search\n } catch {\n return false\n }\n } else {\n const qi = href.indexOf('?')\n if (qi >= 0) {\n path = href.slice(0, qi) || '/'\n query = href.slice(qi)\n }\n }\n if (path !== pathname) return false\n if (!query) return true\n const want = new URLSearchParams(query)\n const have = new URLSearchParams(search)\n for (const [k, v] of want) if (have.get(k) !== v) return false\n return true\n }\n\n // Depth-first walk for the deepest item owning the current route.\n const walk = (nodes: NavItem[], trail: NavItem[]): NavItem[] | null => {\n for (const node of nodes) {\n const here = [...trail, node]\n if (node.children?.length) {\n const deeper = walk(node.children, here)\n if (deeper) return deeper\n }\n if (matches(node.href)) return here\n }\n return null\n }\n\n const trail = walk(items, [])\n // Always anchored at Dashboard; the last crumb is the current location and\n // carries no href (the shell marks it aria-current=\"page\").\n const dashboard = items.find((i) => i.label === 'Dashboard')\n const crumbs: NavBreadcrumb[] = [{ label: 'Dashboard', href: dashboard?.href }]\n if (!trail) return crumbs\n for (const node of trail) {\n if (node.label === 'Dashboard') continue\n crumbs.push({ label: node.label, href: node.href })\n }\n const last = crumbs[crumbs.length - 1]\n if (last) delete (last as { href?: string }).href\n return crumbs\n}\n","// Identity resolution — pure logic, shared by the chrome hook.\n//\n// The chrome API (VRM-core profile) is the AUTHORITY for a user's display name;\n// what an app knows from its own session token is a pre-hydration fallback. An\n// email is never a name: forms passed `user.name ?? user.email`, so a user with\n// no name set had their email rendered as their name in the top bar and the\n// shell's \"add your name\" affordance never fired (HITL 2026-07-23).\n\nexport type ResolvedIdentity = {\n userName: string | null\n email: string | null\n avatarUrl: string | null\n loaded: boolean\n}\n\n/** True when a \"name\" is really just an email address. */\nexport function looksLikeEmail(value: string | null | undefined): boolean {\n return typeof value === 'string' && /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value.trim())\n}\n\nexport function resolveIdentity(input: {\n apiName?: string | null\n fallbackName?: string | null\n email?: string | null\n avatarUrl?: string | null\n loaded?: boolean\n}): ResolvedIdentity {\n const apiName = looksLikeEmail(input.apiName) ? null : input.apiName ?? null\n const fallbackName = looksLikeEmail(input.fallbackName) ? null : input.fallbackName ?? null\n return {\n userName: apiName ?? fallbackName,\n email: input.email ?? null,\n avatarUrl: input.avatarUrl ?? null,\n loaded: input.loaded ?? false,\n }\n}\n","// Active-mode continuity — the cross-app \"which mode am I in\" contract.\n//\n// A DUAL-MODE app (today: a2p, Specs/A2P — \"the SMS/MMS delivery engine for\n// Relationship Mode and Campaign Mode\") has no single registry `mode`: its\n// nav tree and Mode pill must follow the user's LAST-SELECTED mode instead of\n// a fixed value. The resolution order, cheapest/most-explicit first:\n// 1. `?mode=` query param on the current URL (an explicit cross-app link,\n// e.g. the Relationship tree's SMS/MMS Blast row linking into a2p).\n// 2. `politogy_active_mode` cookie — the same cross-subdomain pattern as\n// `politogy_theme` / `politogy_active_org` (see theme-preference.ts):\n// `.politogyvrm.com` on a *.politogyvrm.com host, host-only elsewhere.\n// 3. The dual app's own configured default mode.\n//\n// Every PINNED app (one with a fixed `meta.mode`, e.g. petitions/email) and\n// core (`vrm`, whose mode switches client-side) write this cookie whenever\n// their resolved mode is known/changes, so arriving at a dual app later\n// resolves to whatever mode the user was last actually in.\n\nimport type { StandardNavMode } from './native/standardNav'\n\nexport const ACTIVE_MODE_COOKIE = 'politogy_active_mode'\n\nconst VALID_MODES: readonly StandardNavMode[] = ['relationship', 'campaign', 'petition']\n\nexport function isStandardNavMode(v: unknown): v is StandardNavMode {\n return typeof v === 'string' && (VALID_MODES as readonly string[]).includes(v)\n}\n\n/** Read the shared cookie (browser only; null on the server or when unset). */\nexport function readActiveModeCookie(): StandardNavMode | null {\n if (typeof document === 'undefined') return null\n try {\n const m = document.cookie.match(\n new RegExp(`(?:^|;\\\\s*)${ACTIVE_MODE_COOKIE}=([^;]+)`),\n )\n const v = m ? decodeURIComponent(m[1]) : null\n return isStandardNavMode(v) ? v : null\n } catch {\n return null\n }\n}\n\n/**\n * Write the cross-subdomain cookie with the same scoping rules as the theme\n * cookie (parent domain on *.politogyvrm.com, host-only elsewhere). 1-year,\n * SameSite=Lax, Secure on https. No-op on the server.\n */\nexport function writeActiveModeCookie(mode: StandardNavMode): void {\n if (typeof document === 'undefined' || typeof window === 'undefined') return\n const host = window.location.hostname\n const domainAttr = /(^|\\.)politogyvrm\\.com$/i.test(host) ? '; Domain=.politogyvrm.com' : ''\n const secure = window.location.protocol === 'https:' ? '; Secure' : ''\n document.cookie = `${ACTIVE_MODE_COOKIE}=${encodeURIComponent(\n mode,\n )}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`\n}\n\n/** Read `?mode=` from a query string (`search`, with or without a leading `?`). */\nfunction modeFromSearch(search: string | undefined): string | null {\n if (!search) return null\n try {\n const params = new URLSearchParams(search.startsWith('?') ? search.slice(1) : search)\n return params.get('mode')\n } catch {\n return null\n }\n}\n\n/**\n * Resolve a dual-mode app's effective mode: `?mode=` query param (must be one\n * of `modes`) → `politogy_active_mode` cookie (must be one of `modes`) →\n * `defaultMode`. Client-side only; on the server (or when nothing resolves)\n * this simply falls through to `defaultMode`.\n */\nexport function resolveActiveMode({\n search,\n modes,\n defaultMode,\n}: {\n search?: string\n modes: readonly StandardNavMode[]\n defaultMode: StandardNavMode\n}): StandardNavMode {\n const fromQuery = modeFromSearch(search)\n if (fromQuery && isStandardNavMode(fromQuery) && modes.includes(fromQuery)) {\n return fromQuery\n }\n const fromCookie = readActiveModeCookie()\n if (fromCookie && modes.includes(fromCookie)) {\n return fromCookie\n }\n return defaultMode\n}\n","// ---------------------------------------------------------------------------\n// LoadingScreen — the platform's boot handshake (Specs/Loading-Screen).\n//\n// Mounted once by PolitogyAppFrame (see frame.tsx), never hand-rolled per app\n// (Global-Rules \"Boot Screen Exception\": one screen, one owner). It renders on\n// the four triggers that replace the account context wholesale — cold start,\n// hard reload, organization switch, mode switch — and never for an in-page\n// fetch or plain navigation, which stay on scoped skeletons.\n//\n// Progress is a REPORT, not an animation (spec §4): determinate, monotonic,\n// weighted across boot stages. An app that has real pipeline signals passes\n// `bootProgress`; an app that does not (V1: every consumer but core's own\n// pipeline work is still to come) gets a synthetic two-stage report driven by\n// the same chrome-state signal FrameBody already computes (org list resolved),\n// so the screen still tells the truth — it just has fewer stages to report —\n// and no consumer app can regress to a spinner or a hand-rolled splash.\n// ---------------------------------------------------------------------------\n\n'use client'\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\n\n/** One stage in the boot pipeline (spec §7). */\nexport type BootStageId =\n | 's0_session'\n | 's1_org'\n | 's2_uvp_connect'\n | 's3_district'\n | 's4_universe'\n | 's5_layers'\n | 's6_verified'\n | 's7_tribes'\n | 's8_intelligence'\n | 's9_shell'\n\nexport type BootPhase = 'booting' | 'slow' | 'error' | 'done'\n\n/**\n * The boot pipeline weight table (spec §7). Stages run in catalog order;\n * weights sum to 100 for a full cold boot. \"Waits on\" documents the real\n * signal a caller must have before it may claim the stage is progressing or\n * complete — the status line may not claim a stage the client isn't actually\n * waiting on.\n */\nexport const BOOT_STAGE_TABLE: readonly {\n id: BootStageId\n weight: number\n critical: boolean\n waitsOn: string\n}[] = [\n { id: 's0_session', weight: 5, critical: true, waitsOn: 'Politogy ID session resolution' },\n { id: 's1_org', weight: 10, critical: true, waitsOn: 'Chrome API /api/chrome/me + orgs' },\n { id: 's2_uvp_connect', weight: 10, critical: true, waitsOn: 'UVP data layer connection' },\n { id: 's3_district', weight: 5, critical: true, waitsOn: 'uvp_geo_entitlements / uvp_boundaries scope' },\n { id: 's4_universe', weight: 25, critical: true, waitsOn: 'UVP universe load + total count' },\n { id: 's5_layers', weight: 15, critical: false, waitsOn: 'UVP enrichment layer joins' },\n { id: 's6_verified', weight: 10, critical: false, waitsOn: 'VRM Verified tier computation' },\n { id: 's7_tribes', weight: 10, critical: false, waitsOn: 'Tribes member_count + Hot Tribes warm-up' },\n { id: 's8_intelligence', weight: 5, critical: false, waitsOn: 'Mode intelligence signals (Polling/Relationship/Petition)' },\n { id: 's9_shell', weight: 5, critical: true, waitsOn: 'Shell paint-ready handoff' },\n]\n\nconst BOOT_STAGE_ORDER: readonly BootStageId[] = BOOT_STAGE_TABLE.map((s) => s.id)\nconst BOOT_STAGE_WEIGHTS: Record<BootStageId, number> = Object.fromEntries(\n BOOT_STAGE_TABLE.map((s) => [s.id, s.weight]),\n) as Record<BootStageId, number>\n\n/**\n * Weighted, monotonic, redistributing progress (spec §4.1 principles 3 & 5).\n * `completedStageIds` are fully done (their full weight counts); `skippedStageIds`\n * don't apply to this account/mode and have their weight redistributed\n * proportionally across the stages that DO apply; `currentStageId` is in\n * flight and contributes `currentStageProgress` (0–1) of its own weight.\n * Pure function — no fake motion, no timers.\n */\nexport function computeWeightedPct(args: {\n completedStageIds: readonly BootStageId[]\n skippedStageIds?: readonly BootStageId[]\n currentStageId?: BootStageId\n currentStageProgress?: number\n}): number {\n const skipped = new Set(args.skippedStageIds ?? [])\n const applicable = BOOT_STAGE_ORDER.filter((id) => !skipped.has(id))\n const applicableWeightTotal = applicable.reduce((sum, id) => sum + BOOT_STAGE_WEIGHTS[id], 0)\n if (applicableWeightTotal <= 0) return 100\n // Redistribute each skipped stage's weight proportionally across the\n // remaining applicable stages so the bar still ends at 100.\n const redistributionFactor = 100 / applicableWeightTotal\n\n const completed = new Set(args.completedStageIds)\n let pct = 0\n for (const id of applicable) {\n const effectiveWeight = BOOT_STAGE_WEIGHTS[id] * redistributionFactor\n if (completed.has(id)) {\n pct += effectiveWeight\n } else if (id === args.currentStageId) {\n const progress = Math.min(1, Math.max(0, args.currentStageProgress ?? 0))\n pct += effectiveWeight * progress\n }\n }\n return Math.min(100, pct)\n}\n\n/**\n * The progress-reporting contract (spec §14, Shell package integration\n * point). An app with a real pipeline drives this; the shape is intentionally\n * small so a future per-app pipeline can report into it without a shell\n * release.\n */\nexport type BootProgress = {\n stageId: BootStageId\n /**\n * 0–100, real, monotonic. Callers that already know the weighted value\n * (e.g. by calling `computeWeightedPct` themselves) pass it directly here;\n * callers that only know stage completion/skip state may omit `pct` and\n * pass `completedStageIds`/`skippedStageIds`/`currentStageProgress`\n * instead, and the screen computes the weighted value itself.\n */\n pct?: number\n /** Stages fully completed so far this boot (spec §7 weight table). */\n completedStageIds?: readonly BootStageId[]\n /** Stages that don't apply to this account/mode; their weight redistributes\n * proportionally across the remaining stages (spec §4.1 principle 5). */\n skippedStageIds?: readonly BootStageId[]\n /** 0–1 sub-stage progress within `stageId`, for stages that stream a real\n * counter (S4 universe records, S7 Tribes warmed) (spec §4.1 principle 4). */\n currentStageProgress?: number\n /** The account's own status line for this stage (spec §8; tokens already\n * filled, fallback already applied by the caller). */\n label: string\n phase: BootPhase\n /** Critical-stage failure: Retry / Sign out (spec §9.1). */\n onRetry?: () => void\n onSignOut?: () => void\n /** Footer (spec §6, §14 `version.ts` + deploy environment). */\n version?: string\n region?: string\n}\n\n/** Default synthetic pipeline used when no app supplies `bootProgress` yet.\n * UNCHANGED from the shipped V1 behavior — do not alter without a spec\n * amendment; consumers that haven't wired the real pipeline must keep seeing\n * exactly this. */\nconst SYNTHETIC_STAGES: readonly { pct: number; label: string }[] = [\n { pct: 20, label: 'Connecting to your organization…' },\n { pct: 100, label: 'Ready.' },\n]\n\n/** Spec §11: announcements throttled to one per 1.5s so a fast boot doesn't\n * read five lines at once; \"Ready.\" is always announced regardless. */\nconst ANNOUNCE_THROTTLE_MS = 1500\n/** Spec §4.1 principle 7: minimum dwell time per status line. */\nconst MIN_DWELL_MS = 450\n/** Spec §10: exit transition timings. */\nconst FILL_EASE_MS = 380\nconst HOLD_MS = 240\nconst FADE_MS = 300\n\nfunction usePrefersReducedMotion(): boolean {\n const [reduced, setReduced] = useState(false)\n useEffect(() => {\n if (typeof window === 'undefined' || !window.matchMedia) return\n const mq = window.matchMedia('(prefers-reduced-motion: reduce)')\n setReduced(mq.matches)\n const onChange = () => setReduced(mq.matches)\n mq.addEventListener('change', onChange)\n return () => mq.removeEventListener('change', onChange)\n }, [])\n return reduced\n}\n\n/**\n * Announces `label` on an `aria-live=\"polite\"` cadence: never more than once\n * per ANNOUNCE_THROTTLE_MS, except the terminal \"Ready.\" line, which always\n * gets announced (spec §11).\n */\nfunction useThrottledAnnouncement(label: string, isFinal: boolean): string {\n const [announced, setAnnounced] = useState(label)\n const lastAtRef = useRef(0)\n useEffect(() => {\n const now = Date.now()\n if (isFinal || now - lastAtRef.current >= ANNOUNCE_THROTTLE_MS) {\n lastAtRef.current = now\n setAnnounced(label)\n return\n }\n const wait = ANNOUNCE_THROTTLE_MS - (now - lastAtRef.current)\n const t = setTimeout(() => {\n lastAtRef.current = Date.now()\n setAnnounced(label)\n }, wait)\n return () => clearTimeout(t)\n }, [label, isFinal])\n return announced\n}\n\n/**\n * Enforces the minimum-dwell floor on the DISPLAYED label only — the bar\n * itself is never delayed (spec §4.1 \"the copy is throttled; the bar is not\").\n */\nfunction useDwelledLabel(label: string): string {\n const [displayed, setDisplayed] = useState(label)\n const shownAtRef = useRef(0)\n const pendingRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n useEffect(() => {\n if (label === displayed) return\n const elapsed = Date.now() - shownAtRef.current\n if (pendingRef.current) clearTimeout(pendingRef.current)\n if (elapsed >= MIN_DWELL_MS) {\n shownAtRef.current = Date.now()\n setDisplayed(label)\n } else {\n pendingRef.current = setTimeout(() => {\n shownAtRef.current = Date.now()\n setDisplayed(label)\n }, MIN_DWELL_MS - elapsed)\n }\n return () => {\n if (pendingRef.current) clearTimeout(pendingRef.current)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [label])\n return displayed\n}\n\nexport type LoadingScreenProps = {\n /** Real pipeline progress, when the host app has one wired. */\n bootProgress?: BootProgress\n /**\n * Fallback completion signal used when `bootProgress` is absent: the\n * screen dismisses once this flips true. Callers pass the same \"org list\n * resolved\" signal FrameBody already computes, so a consumer that never\n * wires the full contract still gets a truthful (if coarse) boot report\n * instead of a spinner.\n */\n syntheticReady?: boolean\n /** True while the screen should be mounted at all (trigger gate lives in\n * frame.tsx; this component only renders its own exit transition). */\n visible: boolean\n /** Called after the fade-out completes and the DOM node should unmount. */\n onExitComplete: () => void\n}\n\nexport function LoadingScreen({\n bootProgress,\n syntheticReady,\n visible,\n onExitComplete,\n}: LoadingScreenProps) {\n const reducedMotion = usePrefersReducedMotion()\n\n const synthetic = useMemo(() => {\n const stage = syntheticReady ? SYNTHETIC_STAGES[1] : SYNTHETIC_STAGES[0]\n return {\n pct: stage.pct,\n label: stage.label,\n phase: (syntheticReady ? 'done' : 'booting') as BootPhase,\n }\n }, [syntheticReady])\n\n const weightedPct = useMemo(() => {\n if (!bootProgress) return undefined\n if (typeof bootProgress.pct === 'number') return bootProgress.pct\n if (!bootProgress.completedStageIds && !bootProgress.skippedStageIds) return undefined\n return computeWeightedPct({\n completedStageIds: bootProgress.completedStageIds ?? [],\n skippedStageIds: bootProgress.skippedStageIds,\n currentStageId: bootProgress.stageId,\n currentStageProgress: bootProgress.currentStageProgress,\n })\n }, [\n bootProgress,\n bootProgress?.pct,\n bootProgress?.completedStageIds,\n bootProgress?.skippedStageIds,\n bootProgress?.stageId,\n bootProgress?.currentStageProgress,\n ])\n\n const pct = weightedPct ?? synthetic.pct\n const rawLabel = bootProgress?.label ?? synthetic.label\n const phase = bootProgress?.phase ?? synthetic.phase\n const isFinal = phase === 'done' && pct >= 100\n\n // Monotonic clamp: a re-render can never show a lower value than the last\n // one painted, even if a caller's own state briefly regresses.\n const highWaterRef = useRef(0)\n const clampedPct = Math.max(pct, highWaterRef.current)\n useEffect(() => {\n highWaterRef.current = clampedPct\n }, [clampedPct])\n\n const displayedLabel = useDwelledLabel(rawLabel)\n const announced = useThrottledAnnouncement(displayedLabel, isFinal)\n\n // Exit transition: hold at 100 for HOLD_MS, then fade, then unmount.\n const [fading, setFading] = useState(false)\n useEffect(() => {\n if (!isFinal) return\n const holdMs = reducedMotion ? 0 : HOLD_MS\n const fadeMs = reducedMotion ? 0 : FADE_MS\n const holdTimer = setTimeout(() => {\n setFading(true)\n const fadeTimer = setTimeout(onExitComplete, fadeMs)\n return () => clearTimeout(fadeTimer)\n }, holdMs)\n return () => clearTimeout(holdTimer)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isFinal, reducedMotion])\n\n if (!visible) return null\n\n const isError = phase === 'error'\n\n return (\n <div\n data-testid=\"politogy-loading-screen\"\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 2147483000,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '2rem',\n background: 'var(--color-ink-900, #0a0a0c)',\n color: '#fff',\n opacity: fading ? 0 : 1,\n transition: reducedMotion ? undefined : `opacity ${FADE_MS}ms ease-out`,\n }}\n >\n {/*\n Inline lockup, not an <img>: the screen mounts in every consumer app and\n none of them serves a shared asset at a fixed path, so an asset URL\n rendered as a broken image (the alt text) on every boot. Inline markup\n needs no network and cannot 404.\n */}\n <div\n aria-label=\"Politogy\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '0.6rem',\n fontFamily: 'var(--font-sans, ui-sans-serif, system-ui, sans-serif)',\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 34,\n height: 26,\n borderRadius: 6,\n background: '#fff',\n color: 'var(--color-ink-900, #0a0a0c)',\n fontSize: '0.8125rem',\n fontWeight: 800,\n letterSpacing: '-0.02em',\n }}\n >\n vrm\n </span>\n <span style={{ fontSize: '1.375rem', fontWeight: 700, letterSpacing: '-0.02em' }}>Politogy</span>\n </div>\n <div style={{ width: 320, maxWidth: '80vw' }}>\n <div\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(clampedPct)}\n aria-label=\"Loading your workspace\"\n style={{\n height: 3,\n width: '100%',\n borderRadius: 2,\n background: 'rgba(255,255,255,0.12)',\n overflow: 'hidden',\n }}\n >\n <div\n style={{\n height: '100%',\n width: `${clampedPct}%`,\n background:\n 'linear-gradient(90deg, var(--color-race-blue, #1d4ed8), var(--color-race-red, #dc2626))',\n transition: reducedMotion ? undefined : `width ${FILL_EASE_MS}ms ease-out`,\n }}\n />\n </div>\n <div\n role=\"status\"\n aria-live=\"polite\"\n style={{\n marginTop: '0.75rem',\n fontFamily: 'var(--font-mono, ui-monospace, monospace)',\n fontSize: '0.8125rem',\n color: isError ? 'var(--color-race-red, #dc2626)' : 'rgba(255,255,255,0.72)',\n textAlign: 'center',\n }}\n >\n {announced}\n </div>\n {isError && (bootProgress?.onRetry || bootProgress?.onSignOut) && (\n <div\n style={{\n marginTop: '1.25rem',\n display: 'flex',\n flexDirection: 'column',\n gap: '0.75rem',\n alignItems: 'center',\n }}\n >\n {bootProgress?.onRetry && (\n <button\n type=\"button\"\n onClick={bootProgress.onRetry}\n style={{\n height: 40,\n padding: '0 1.25rem',\n borderRadius: 'var(--radius-md, 8px)',\n border: 'none',\n background: 'var(--color-race-red, #dc2626)',\n color: '#fff',\n fontFamily: 'var(--font-sans, ui-sans-serif, system-ui, sans-serif)',\n fontSize: '0.875rem',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n Retry\n </button>\n )}\n {bootProgress?.onSignOut && (\n <button\n type=\"button\"\n onClick={bootProgress.onSignOut}\n style={{\n height: 'auto',\n padding: 0,\n border: 'none',\n background: 'transparent',\n color: 'rgba(255,255,255,0.38)',\n fontFamily: 'var(--font-sans, ui-sans-serif, system-ui, sans-serif)',\n fontSize: '12.5px',\n textDecoration: 'underline',\n cursor: 'pointer',\n }}\n >\n Sign out\n </button>\n )}\n </div>\n )}\n </div>\n <div\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n bottom: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '0 32px 30px',\n fontFamily: 'var(--font-sans, ui-sans-serif, system-ui, sans-serif)',\n fontSize: '12.5px',\n color: 'rgba(255,255,255,0.38)',\n }}\n >\n <span>Politogy VRM. Built for the long game.</span>\n <span style={{ fontFamily: 'var(--font-mono, ui-monospace, monospace)', letterSpacing: '0.04em' }}>\n {(bootProgress?.version ?? 'v—') + ' · ' + (bootProgress?.region ?? '—')}\n </span>\n </div>\n </div>\n )\n}\n","// ---------------------------------------------------------------------------\n// PolitogyAppFrame — ONE component that renders the entire app frame.\n//\n// Why this exists (HITL directive 2026-07-23): shipping the same npm package at\n// the same version is necessary but NOT sufficient. The package exposed\n// PRIMITIVES (NavAppShell + a dozen hooks) and every app hand-assembled them in\n// its own ~150-line Shell.tsx. Identical inputs were never guaranteed, so the\n// outputs diverged — measured on production: forms rendered its user's EMAIL as\n// their name, polls' breadcrumb read \"Polls / Polls\", forms and surveys pinned\n// the mode pill to a hardcoded \"relationship\", and each app declared its own\n// chrome CSS variables (surveys' accent was #C8102E where everyone else was\n// #E63946).\n//\n// The fix is to stop exporting assembly as an app responsibility. An app now\n// renders:\n//\n// <PolitogyAppFrame app=\"forms\" pathname={pathname} linkComponent={Link}\n// session={{ userId, email, role, accountName, accountId }}\n// onSignOut={signOut}>\n// {children}\n// </PolitogyAppFrame>\n//\n// and passes NOTHING about the chrome: no nav, no breadcrumbs, no title, no\n// mode, no user menu, no footer, no theme. Those are derived here, identically,\n// for every app. Anything an app cannot pass is something it cannot drift on.\n// ---------------------------------------------------------------------------\n\n'use client'\n\nimport { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'\n\nimport { broadcastLogout, watchLogout } from '../logout-signal'\nimport { resolveActiveMode, writeActiveModeCookie } from '../mode-preference'\nimport { clearBetaBannerDismissal, isNavItemActive } from '../native/index'\nimport { LoadingScreen, type BootProgress } from './loading-screen'\nimport {\n NavAppShell,\n standardPolitogyNav,\n type NavLinkComponent,\n} from '../native/index'\nimport {\n ChromeTopBarActions,\n PolitogyAppChrome,\n standardNavIcons,\n useChromeFooter,\n useChromeIdentity,\n useChromeMode,\n useChromeState,\n useChromeUserMenu,\n type ChromeDevNotesConfig,\n type ControlledOrgState,\n} from './index'\nimport type {\n NavBreadcrumb,\n NavChromeFetcher,\n NavItem,\n NavMode,\n NavUserMenu,\n} from '../native/index'\nimport type { StandardNavMode } from '../native/standardNav'\nimport { deriveBreadcrumbs } from '../lib/breadcrumbs'\n\n/**\n * The core app — the one that OWNS the canonical nav tree and routes in-app.\n * `PolitogyFrameData.core` is honored for this key and no other.\n */\nconst CORE_APP: PolitogyAppKey = 'vrm'\n\n/**\n * Template A convention: every feature app exposes GET /auth/signout, which\n * clears its session cookie and 302s to the IdP's end_session endpoint. Apps\n * that route sign-out elsewhere (core: /api/auth/logout) pass `signOutUrl`.\n */\nconst DEFAULT_SIGN_OUT_URL = '/auth/signout'\n\n/** Every app that renders the shared chrome. Keyed by its subdomain. */\nexport type PolitogyAppKey =\n | 'vrm'\n | 'contacts'\n | 'forms'\n | 'surveys'\n | 'polls'\n | 'petitions'\n // Relationship Mode standalone apps.\n | 'email'\n // Campaign Mode standalone apps.\n | 'a2p'\n | 'phonebank'\n | 'canvass'\n | 'signs'\n // Relationship Mode CTAs (Specs/CTAs) — the new standalone acquisition app,\n // same \"forms./surveys./polls.\" pattern (unscoped, own subdomain).\n | 'ctas'\n\n/**\n * The operating Mode an app is scoped to, if any. It drives two things,\n * BOTH derived here from app identity so no app passes chrome config:\n * 1. the standardPolitogyNav tree the sidebar renders, and\n * 2. the static Mode pill the app shows (a campaign app shows a Campaign\n * pill, never Relationship).\n * An UNSCOPED app (no `mode`) keeps its prior behavior exactly: the\n * Relationship tree + an entitlement-driven Mode pill.\n */\nexport type PolitogyAppMode = StandardNavMode\n\n/** The wordmark every unscoped app renders — Politogy's default lockup. */\nconst DEFAULT_BRAND_LOGO = '/brand/logos/relationship-mode-logo.png'\n\n/**\n * Mode-specific brand lockups, by Mode. Same idea as the per-Mode accent: the\n * wordmark is Mode identity, resolved from the REGISTRY, not passed by an app.\n *\n * Only a Mode with its own shipped lockup appears here. Everything else falls\n * back to the default, so this is additive.\n *\n * Why it needs fixing: `brandLogoSrc` became core-only in 0.43, so every\n * MODE-SCOPED app started rendering the Relationship lockup — a red wordmark\n * on a purple \"vrm\" badge — regardless of the Mode it is scoped to. Petition\n * Mode shipped a green Petition lockup in V1 and lost it in that migration,\n * which is the \"migration may not drop a shipped element\" rule.\n *\n * The path is app-relative: each app serves the asset from its own `public/`\n * (petitions already ships `petition-mode-logo.svg`). A Mode added here without\n * the asset in place would 404 to a broken image, so add the file first.\n */\nconst MODE_BRAND_LOGOS: Partial<Record<PolitogyAppMode, string>> = {\n petition: '/brand/logos/petition-mode-logo.svg',\n}\n\nconst modeBrandLogo = (mode?: PolitogyAppMode) =>\n (mode && MODE_BRAND_LOGOS[mode]) || DEFAULT_BRAND_LOGO\n\n/**\n * A frame input a feature app is allowed to supply, because the answer is a\n * fact only the app has — not a styling choice.\n *\n * The grant list is the COMPLETE set of exceptions to \"an app never passes\n * chrome configuration\", and it lives here, in the shell, in one greppable\n * table. That is what keeps the no-drift guarantee: an app cannot grant itself,\n * so widening the surface takes a shell release and a review by whoever owns\n * the shell.\n *\n * Never add a grant for a visual input. `contentWrapper` qualifies because the\n * app either does or does not already emit its own `<main>`; `breadcrumbs`\n * qualifies because only the app knows which record a deep link points at.\n * \"Petitions wants a wider box\" would not qualify — that is a look, and looks\n * come from tokens.\n */\nexport type PolitogyFrameGrant = 'contentWrapper' | 'breadcrumbs' | 'title'\n\n/**\n * The per-app registry — the ONLY place app identity lives. A new app adds a\n * row here and inherits every chrome behavior; it never re-derives one.\n */\nexport const POLITOGY_APPS: Record<\n PolitogyAppKey,\n {\n title: string\n origin: string\n storagePrefix: string\n mode?: PolitogyAppMode\n /**\n * DUAL-MODE apps (today: a2p — Specs/A2P: \"the SMS/MMS delivery engine\n * for Relationship Mode and Campaign Mode\") have no single fixed mode.\n * `mode` above stays the fallback/default identity for any code that\n * still reads `meta.mode` directly; FrameBody instead resolves the\n * EFFECTIVE mode via `resolveActiveMode` (?mode= query → the\n * `politogy_active_mode` cookie → `defaultMode`) and uses that for the\n * nav tree, the Mode pill, and the brand lockup.\n */\n dual?: { modes: readonly StandardNavMode[]; defaultMode: StandardNavMode }\n /** See PolitogyFrameGrant. Omitted => the app may pass no frame input. */\n grants?: readonly PolitogyFrameGrant[]\n /**\n * 'flat': the app's whole tree nests under one standard entry, and the rail\n * renders that entry's CHILDREN at the root — no parent header row, no\n * accordion (see NavSidebar nav.flatten). V1's petition rail was flat;\n * the parent row duplicated its first child's route.\n */\n navShape?: 'flat'\n /**\n * false: this app does not render the Beta banner strip. A registry\n * declaration, not an app prop, for the same reason as grants — whether a\n * product shows the platform's Beta notice is a platform decision.\n */\n beta?: boolean\n }\n> = {\n vrm: { title: 'Politogy VRM', origin: 'https://app.politogyvrm.com', storagePrefix: 'vrm' },\n contacts: { title: 'Contacts', origin: 'https://contacts.politogyvrm.com', storagePrefix: 'contacts' },\n forms: { title: 'Forms', origin: 'https://forms.politogyvrm.com', storagePrefix: 'forms' },\n surveys: { title: 'Surveys', origin: 'https://surveys.politogyvrm.com', storagePrefix: 'surveys' },\n polls: { title: 'Polls', origin: 'https://polls.politogyvrm.com', storagePrefix: 'polls' },\n ctas: { title: 'CTAs', origin: 'https://ctas.politogyvrm.com', storagePrefix: 'ctas' },\n petitions: {\n title: 'Petitions',\n origin: 'https://petition-mode.politogyvrm.com',\n storagePrefix: 'petitions',\n mode: 'petition',\n // Petitions wraps every page in its own PageContainer (which emits its own\n // <main>), and its adjudication case is addressed per sheet and per line —\n // a trail derived from the nav tree reads \"Dashboard › Adjudication\" on\n // every one of those URLs and cannot name the record you are actually on.\n // 'title' for the same reason: its pages have real names (\"Batches\"),\n // where the registry can only say \"Petitions\".\n grants: ['contentWrapper', 'breadcrumbs', 'title'],\n navShape: 'flat',\n beta: false,\n },\n // Relationship Mode Email Engine (Specs/Email-Engine) — the V2 standalone\n // app, running in parallel to VRM core's V1 Email Broadcast.\n email: { title: 'Email', origin: 'https://email.politogyvrm.com', storagePrefix: 'email', mode: 'relationship' },\n // Campaign Mode apps — each scoped to Campaign, so they render the Campaign\n // tree and a static Campaign pill. Not yet deployed; hidden from the Campaign\n // nav by CAMPAIGN_FEATURE_AVAILABILITY until their launch flips the flag.\n // Dual-mode: a2p is the SMS/MMS delivery engine for BOTH Relationship Mode\n // and Campaign Mode (Specs/A2P). `mode: 'campaign'` stays the fallback for\n // anything reading `meta.mode` directly; the effective mode a user sees is\n // resolved per-visit (see `dual`, resolveActiveMode).\n a2p: {\n title: 'A2P Messaging',\n origin: 'https://a2p.politogyvrm.com',\n storagePrefix: 'a2p',\n mode: 'campaign',\n dual: { modes: ['relationship', 'campaign'], defaultMode: 'campaign' },\n },\n phonebank: { title: 'Phone Banking', origin: 'https://phonebank.politogyvrm.com', storagePrefix: 'phonebank', mode: 'campaign' },\n canvass: { title: 'Field Canvassing', origin: 'https://canvass.politogyvrm.com', storagePrefix: 'canvass', mode: 'campaign' },\n signs: { title: 'Sign Mapping', origin: 'https://signs.politogyvrm.com', storagePrefix: 'signs', mode: 'campaign' },\n}\n\nexport type PolitogyAppSession = {\n /** Stable IdP subject (`sub`). */\n userId: string\n email: string | null\n /** The app's own role string — feeds DevNotes admin gating. */\n role: string\n /** The app's own workspace label, used only until core orgs resolve. */\n accountName: string\n accountId: string\n /**\n * Pre-hydration display name ONLY. The chrome API is the authority; an email\n * passed here is discarded rather than rendered as a name.\n */\n userName?: string | null\n}\n\n/**\n * Optional DATA plumbing for apps whose session/auth differs — never styling.\n *\n * Everything here is about WHERE data comes from (which fetcher, which org\n * state, which routes an app owns), not what the chrome looks like. Adding a\n * visual option to this type would re-open the drift this component exists to\n * close.\n */\nexport type PolitogyFrameData = {\n /** Chrome-API fetcher override for apps that authenticate client-side. */\n fetchJson?: NavChromeFetcher\n /** DevNotes wiring override for those same direct-auth apps. */\n devNotes?: ChromeDevNotesConfig\n /** Controlled org state for apps that own active-org + switching. */\n org?: ControlledOrgState\n /** App-owned children for a standard nav entry this app owns (Contacts). */\n contactsItem?: { href?: string; children?: NavItem[] }\n /** Petitions app: nest its own routes under the Petition-mode entry. */\n petitionsItem?: { href?: string; children?: NavItem[] }\n /** Avatar fallback when the profile has no uploaded photo (memoji, default). */\n fallbackAvatarUrl?: string | null\n /**\n * Frame inputs this app has been GRANTED in the registry.\n *\n * Each field is honored only when the app's `POLITOGY_APPS` row lists it in\n * `grants`; an undeclared field is dropped before it reaches the chrome, so\n * passing one has no effect rather than a silent effect. Nothing here is\n * styling — see PolitogyFrameGrant for what qualifies.\n *\n * This is deliberately NOT a widening of the `app === CORE_APP` gate below.\n * That gate makes core's props inert for every other app; this makes a named\n * input live for a named app, listed in one place the shell owns.\n */\n frame?: PolitogyGrantedFrame\n /**\n * CORE-ONLY frame inputs. **Honored only when `app` is the core app (`vrm`)\n * — silently ignored for every other app**, which is what keeps the\n * no-drift guarantee intact: a feature app cannot re-specify a chrome\n * element even by passing this, so the props are inert for it.\n *\n * Core is genuinely different, and pretending otherwise would have meant\n * REMOVING shipped behavior from app.politogyvrm.com to satisfy packaging —\n * which Reference/UI-Platform forbids (\"migration may not drop a shipped\n * element … extend the shell first, then migrate\"). Specifically, core:\n * - owns the canonical nav tree AND decorates it with live entitlement\n * state a static tree cannot express (10DLC gating, contact/group\n * counts, org-lock),\n * - routes in-app (react-router), so its rows must be app-relative paths,\n * not the absolute cross-app URLs `standardPolitogyNav` emits,\n * - publishes per-page title/breadcrumbs from 66 page components,\n * - switches Mode client-side rather than by full-page navigation,\n * - owns real linked-account switching (with its own modals).\n *\n * Everything here is still DATA or app-owned STATE. There is no styling\n * input, no ordering input, and no way to change the top-bar action cluster\n * — those stay identical for every app, core included.\n */\n core?: PolitogyCoreFrame\n}\n\n/** See `PolitogyFrameData.frame` — honored per the app's registry `grants`. */\nexport type PolitogyGrantedFrame = {\n /**\n * How the frame wraps page content. `'bare'` for an app that already emits\n * its own `<main>` + container, which the default otherwise nests inside\n * `mx-auto max-w-7xl` — producing a doubled gutter and, strictly, invalid\n * HTML (a `<main>` inside a `<main>`).\n */\n contentWrapper?: 'padded' | 'bare'\n /**\n * The trail for pages whose location is finer-grained than their nav row —\n * a specific record, not a section. For an app granted 'breadcrumbs' the\n * published trail REPLACES the derived one entirely: a page that publishes\n * none shows none, exactly as core's pages do. (Falling back to the derived\n * trail put \"Dashboard › Batches\" under the title of every list page — a\n * parent nobody chose, on apps whose pages already say where they are.)\n */\n breadcrumbs?: NavBreadcrumb[]\n /** The page's own name for the top bar (\"Batches\"), not the app's. */\n title?: string\n}\n\n/** See `PolitogyFrameData.core` — core app (`vrm`) only. */\nexport type PolitogyCoreFrame = {\n /** The canonical nav tree, decorated with core's live entitlement state. */\n nav?: NavItem[]\n /** Per-page identity published by core's own pages. */\n page?: { title?: string; breadcrumbs?: NavBreadcrumb[]; actions?: ReactNode }\n /** Client-side Mode switching (core navigates in-app, not cross-origin). */\n mode?: NavMode\n /** Real linked-account switching + core's theme persistence. */\n userMenu?: NavUserMenu\n /** Mode-specific brand wordmark (core swaps it per operating Mode). */\n brandLogoSrc?: string\n /** Core wraps every page in PageContainer, which emits its own <main>. */\n contentWrapper?: 'padded' | 'bare'\n}\n\nexport type PolitogyBuildMeta = {\n envLabel?: string\n version?: string\n commit?: string\n commitDate?: string\n commitAuthor?: string\n}\n\nexport function PolitogyAppFrame({\n app,\n pathname,\n search,\n linkComponent,\n session,\n onSignOut,\n signOutUrl = DEFAULT_SIGN_OUT_URL,\n buildMeta,\n data,\n bootProgress,\n appReady,\n children,\n}: {\n app: PolitogyAppKey\n /** Current path from the app's router (Next: usePathname()). */\n pathname: string\n /** Current query string, when the app routes by query (forms' ?tab=). */\n search?: string\n /** The app's routing primitive (Next: <Link>). */\n linkComponent: NavLinkComponent\n session: PolitogyAppSession\n onSignOut: () => void\n /**\n * The app's sign-out ROUTE — a GET endpoint that clears the session cookie\n * and redirects to RP-initiated logout at the IdP. Defaults to the Template A\n * convention; core overrides it. This, not `onSignOut`, is what actually\n * signs the user out (see handleSignOut).\n */\n signOutUrl?: string\n buildMeta?: PolitogyBuildMeta\n /** Optional DATA plumbing (never styling) — see PolitogyFrameData. */\n data?: PolitogyFrameData\n /**\n * Real boot-pipeline progress (Specs/Loading-Screen §14 contract). Absent\n * for apps that have not wired their own pipeline yet — the frame then\n * reports a truthful but coarse two-stage boot instead of a spinner.\n */\n bootProgress?: BootProgress\n /**\n * Explicit \"the host app is ready to be shown\" signal. When omitted (every\n * app today), the Loading Screen dismisses itself once the chrome's own\n * org/nav state resolves, so none of the 14 consumer apps has to opt in to\n * keep working.\n */\n appReady?: boolean\n children: ReactNode\n}) {\n const meta = POLITOGY_APPS[app]\n return (\n <PolitogyAppChrome\n storagePrefix={meta.storagePrefix}\n fetchJson={data?.fetchJson}\n devNotes={data?.devNotes}\n org={data?.org}\n identity={{\n userId: session.userId,\n userName: session.userName ?? null,\n email: session.email,\n role: session.role,\n }}\n >\n <FrameBody\n app={app}\n pathname={pathname}\n search={search}\n linkComponent={linkComponent}\n session={session}\n onSignOut={onSignOut}\n signOutUrl={signOutUrl}\n buildMeta={buildMeta}\n data={data}\n bootProgress={bootProgress}\n appReady={appReady}\n >\n {children}\n </FrameBody>\n </PolitogyAppChrome>\n )\n}\n\nfunction FrameBody({\n app,\n pathname,\n search,\n linkComponent,\n session,\n onSignOut,\n signOutUrl,\n buildMeta,\n data,\n bootProgress,\n appReady,\n children,\n}: {\n app: PolitogyAppKey\n pathname: string\n search?: string\n linkComponent: NavLinkComponent\n session: PolitogyAppSession\n onSignOut: () => void\n signOutUrl: string\n buildMeta?: PolitogyBuildMeta\n data?: PolitogyFrameData\n bootProgress?: BootProgress\n appReady?: boolean\n children: ReactNode\n}) {\n const meta = POLITOGY_APPS[app]\n const chrome = useChromeState()\n\n // Loading Screen trigger gate (Specs/Loading-Screen §5, Global-Rules \"Boot\n // Screen Exception\"): shown on mount (cold start / hard reload both remount\n // this component fresh) and re-shown on organization switch or mode switch —\n // the two events that replace the account context after mount. A plain\n // route change never touches these refs, so it never re-arms the screen.\n const bootAppMode = meta.mode\n const bootOrgId = chrome?.orgId ?? null\n const [bootVisible, setBootVisible] = useState(true)\n // Remounts LoadingScreen on every new trigger so its internal monotonic\n // high-water mark and exit-transition state start clean for the new boot.\n const [bootGeneration, setBootGeneration] = useState(0)\n const seenOrgRef = useRef(bootOrgId)\n const seenModeRef = useRef(bootAppMode)\n useEffect(() => {\n if (seenOrgRef.current !== null && seenOrgRef.current !== bootOrgId) {\n setBootVisible(true)\n setBootGeneration((g) => g + 1)\n }\n seenOrgRef.current = bootOrgId\n }, [bootOrgId])\n useEffect(() => {\n if (seenModeRef.current !== undefined && seenModeRef.current !== bootAppMode) {\n setBootVisible(true)\n setBootGeneration((g) => g + 1)\n }\n seenModeRef.current = bootAppMode\n }, [bootAppMode])\n // Default dismiss signal when the app has not wired a real pipeline: the\n // chrome's own org list has resolved, i.e. the same state FrameBody already\n // needed to render the sidebar/org switcher truthfully. `chrome` is null\n // for an app rendered without a chrome/org provider at all (no org state to\n // wait on), which must count as resolved — otherwise the screen never\n // dismisses and blocks the app forever.\n const chromeResolved = chrome == null || !chrome.orgsLoading\n\n // Sign-out is a PLATFORM event, not an app event. Each app holds its own\n // host-only session cookie with a long sliding window, so without this a user\n // who signed out in one tab stayed fully signed in in every other open tab\n // and on every other subdomain. Announce the sign-out to all of them, then\n // run the app's own sign-out.\n //\n // Every app reaches sign-out through this frame, so wiring it here covers the\n // whole estate without an app having to opt in — the same guarantee the rest\n // of the chrome relies on.\n const signOutRef = useRef(onSignOut)\n signOutRef.current = onSignOut\n // This tab started the sign-out, so its own watcher must not also fire and\n // run the app's sign-out a second time concurrently.\n const signingOutRef = useRef(false)\n\n const handleSignOut = useCallback(() => {\n signingOutRef.current = true\n // Re-arm the Beta banner so it reappears at the next login rather than\n // staying hidden across an in-tab logout→login (sessionStorage survives it).\n clearBetaBannerDismissal()\n broadcastLogout()\n // Navigate to the app's sign-out ROUTE. Apps also pass an onSignOut\n // handler, but it cannot be relied on: they wire it as\n // `onSignOut={() => { void signOutAction(); }}`, and a server action\n // invoked outside a transition can never have its redirect() applied by\n // the client. Measured against production 2026-07-25: clicking Sign out\n // left the user signed in, and an app they had never opened authenticated\n // with no credentials — the IdP session was still alive because the\n // browser never reached its end-session endpoint.\n //\n // A plain navigation to a GET route cannot fail that way: the route drops\n // the session cookie and 302s to RP-initiated logout at the IdP.\n signOutRef.current()\n window.location.assign(signOutUrl)\n }, [signOutUrl])\n\n useEffect(\n () =>\n // A tab that learns of a sign-out elsewhere ends its own session for\n // real, by navigating to the same sign-out route.\n //\n // Measured against production before this landed: calling the app's\n // handler did nothing at all. Apps wire it as\n // `onSignOut={() => { void signOutAction(); }}` — a server action invoked\n // outside a transition, so the `redirect()` inside it can never be\n // applied by the client and the tab just sits there. Building cross-tab\n // logout on that path made the whole feature a no-op.\n //\n // A hard navigation cannot fail that way, and it hands the decision to\n // the authority rather than guessing: the app's middleware sees a session\n // whose auth_time predates `politogy_logout_at`, treats it as revoked,\n // and redirects to Politogy ID. Server-side truth decides; the client\n // only forces the request. No re-broadcast — the signal that woke us is\n // already on record for every tab.\n watchLogout(() => {\n if (signingOutRef.current) return\n clearBetaBannerDismissal()\n window.location.assign(signOutUrl)\n }),\n [signOutUrl],\n )\n // Core-only inputs are read through this ONE gate. For every other app it is\n // undefined no matter what the app passed, so the \"an app cannot re-specify a\n // chrome element\" guarantee holds by construction, not by convention.\n const core = app === CORE_APP ? data?.core : undefined\n\n // Registry-granted inputs run through the SAME shape of gate, one field at a\n // time: the registry decides, the app only supplies. An app that passes\n // `frame.breadcrumbs` without the grant gets `undefined` here, so the failure\n // mode is \"no effect\", never \"an app quietly re-specified the chrome\".\n const grants = meta.grants\n const granted = <K extends keyof PolitogyGrantedFrame>(\n key: K & PolitogyFrameGrant,\n ): PolitogyGrantedFrame[K] | undefined =>\n grants?.includes(key) ? data?.frame?.[key] : undefined\n\n // Identity: chrome API wins, app claims are a fallback, an email is never a\n // name (that is what forms was rendering in the top right).\n const identity = useChromeIdentity({ userName: session.userName, email: session.email })\n const derivedUserMenu = useChromeUserMenu({\n userId: session.userId,\n userName: identity.userName,\n email: identity.email,\n })\n const userMenu = core?.userMenu ?? derivedUserMenu\n const footer = useChromeFooter(buildMeta ?? {})\n // A mode-scoped app (Campaign apps, Petitions) pins its pill to its own mode;\n // an unscoped app stays entitlement + user-selection driven. Either way no\n // app passes a mode — it is read from the registry (app identity).\n //\n // A DUAL-MODE app (a2p — Specs/A2P) has no single fixed mode: its EFFECTIVE\n // mode is resolved per-visit, ?mode= query → politogy_active_mode cookie →\n // the app's own default, and that resolved value stands in for `meta.mode`\n // everywhere below (nav tree, Mode pill, brand lockup). Every other app is\n // unaffected — `appMode` is exactly `meta.mode`, as before.\n const resolvedDualMode = meta.dual\n ? resolveActiveMode({\n search: search ?? (typeof window !== 'undefined' ? window.location.search : undefined),\n modes: meta.dual.modes,\n defaultMode: meta.dual.defaultMode,\n })\n : undefined\n const appMode = resolvedDualMode ?? meta.mode\n const derivedMode = useChromeMode(appMode ? { pinnedModeId: appMode } : undefined)\n // Core switches Mode client-side; every other app jumps to the mode's home.\n const mode = core?.mode ?? derivedMode\n\n // PINNED apps (a fixed `meta.mode`, no `dual`) write their own mode to the\n // shared cookie whenever it is known, so a dual app visited next (a2p)\n // resolves to it instead of its own default — that is what makes \"SMS/MMS\n // Blast\" clicked from Relationship Mode land on the Relationship tree in\n // a2p even without a `?mode=` link.\n //\n // Core (`vrm`) has no `meta.mode` — it switches mode client-side via\n // in-app routing, not the registry — so its live mode is read from its own\n // route namespace (`/relationship/...` vs `/campaign/...`, the same split\n // `standardPolitogyNav`'s trees use) rather than `core?.mode` (a `NavMode`\n // describing the PILL's label/options, not which mode is currently active).\n // Re-runs on every pathname change, so switching mode in-app (a route\n // change, not a remount) still updates the cookie.\n const coreLiveMode: StandardNavMode | undefined =\n app === CORE_APP\n ? pathname.startsWith('/campaign')\n ? 'campaign'\n : pathname.startsWith('/relationship')\n ? 'relationship'\n : undefined\n : undefined\n const cookieMode = coreLiveMode ?? (meta.dual ? undefined : meta.mode)\n useEffect(() => {\n if (cookieMode) writeActiveModeCookie(cookieMode)\n }, [cookieMode])\n\n const coreOrgs = chrome?.orgs ?? []\n const activeCoreOrg = coreOrgs.find((o) => o.id === chrome?.orgId) ?? null\n const navDisplay = chrome?.navDisplay ?? 'both'\n\n // The nav tree follows the app's OWN mode (registry), not the live pill\n // selection — so it is deterministic from app identity. Unscoped apps render\n // Relationship exactly as before. Cross-app links in the Campaign/Petition\n // trees carry the active org the way the switcher/account menu do.\n const navMode: StandardNavMode = appMode ?? 'relationship'\n const activeOrgId = chrome?.orgId ?? null\n const derivedNavItems = useMemo(\n () =>\n standardPolitogyNav({\n coreBaseUrl: POLITOGY_APPS.vrm.origin,\n icons: standardNavIcons,\n // An app that OWNS a standard nav entry (Contacts) nests its own routes\n // under it. This is routing data, not chrome configuration.\n contactsItem: data?.contactsItem,\n petitionsItem: data?.petitionsItem,\n mode: navMode,\n activeOrgId,\n }),\n [data?.contactsItem, data?.petitionsItem, navMode, activeOrgId],\n )\n // Core supplies the canonical tree already decorated with its live gating\n // state (and with app-relative hrefs so its router handles them in-app).\n const navItems = core?.nav ?? derivedNavItems\n\n // Left-Navigation §11.3: a row is active when the current route belongs to\n // its feature, by route prefix, never by exact URL — so a parent whose\n // OWN route is \"/\" still lights up on every child route it owns. The\n // 'tabs' display strips `children` before handing rows to the sidebar\n // (below), which would otherwise leave `isNavItemActive` with nothing to\n // prefix-match against and no row active on a child page (DevNotes\n // ebb036a1: Contacts' rail row went dark on /tribes, /import, /fields…).\n // Built from the UNSTRIPPED tree so the parent's activeness still reflects\n // routes its children (and grandchildren) own, independent of stripping.\n const navIsActive = useMemo(() => {\n const childHrefs = new Map<string, string[]>()\n for (const item of navItems) {\n if (!item.href || !item.children?.length) continue\n const hrefs: string[] = []\n for (const child of item.children) {\n if (child.href) hrefs.push(child.href)\n for (const leaf of child.children ?? []) {\n if (leaf.href) hrefs.push(leaf.href)\n }\n }\n childHrefs.set(item.href, hrefs)\n }\n return (pathname: string, href: string) =>\n isNavItemActive(pathname, href) ||\n (childHrefs.get(href) ?? []).some((h) => isNavItemActive(pathname, h))\n }, [navItems])\n\n // Dashboard › Sub › Item, derived from the same tree the sidebar renders.\n // Core publishes its trail from the page itself, because a core page's\n // location is finer-grained than its nav row (e.g. a contact detail view).\n const derivedBreadcrumbs = useMemo(\n () => deriveBreadcrumbs(navItems, pathname, { search, origin: meta.origin }),\n [navItems, pathname, search, meta.origin],\n )\n // An app granted 'breadcrumbs' behaves like core: the page's published\n // trail IS the trail, and a page that publishes nothing shows nothing.\n // (First cut fell back to the derived trail, which put \"Dashboard › Batches\"\n // under every list-page title — a parent nobody chose.) Ungranted apps keep\n // the derived trail exactly as before.\n const breadcrumbs = core\n ? core.page?.breadcrumbs\n : grants?.includes('breadcrumbs')\n ? granted('breadcrumbs')\n : derivedBreadcrumbs\n\n return (\n <>\n <LoadingScreen\n key={bootGeneration}\n visible={bootVisible}\n bootProgress={bootProgress}\n syntheticReady={appReady ?? chromeResolved}\n onExitComplete={() => setBootVisible(false)}\n />\n <NavAppShell\n sidebar={{\n pathname,\n brand: {\n logoSrc: core?.brandLogoSrc ?? modeBrandLogo(appMode),\n logoAlt: 'Politogy',\n badgeLabel: 'P',\n title: 'Politogy',\n },\n nav: {\n // A flat rail's sub-menu IS the nav, so the 'tabs only' preference\n // (which strips children) would leave one childless parent row —\n // flat apps ignore the stripping.\n items:\n navDisplay === 'tabs' && meta.navShape !== 'flat'\n ? navItems.map(({ children: _sub, ...item }) => item)\n : navItems,\n isActive: navIsActive,\n flatten: meta.navShape === 'flat',\n },\n // The app's own workspace is NOT the organization — it is a per-app\n // bootstrap account with a different id in every app. Showing it while\n // the chrome API resolves flashed the wrong org on every load (\"not\n // connected to the account\"). Shimmer while in flight; only fall back\n // to the app label once the chrome lookup has actually failed.\n org: activeCoreOrg\n ? {\n name: activeCoreOrg.name,\n id: activeCoreOrg.id,\n logoUrl: activeCoreOrg.logoUrl,\n brandColor: activeCoreOrg.brandColor,\n organizations: coreOrgs,\n onSwitch: chrome?.setOrgId,\n }\n : chrome?.orgsLoading\n ? { name: null, id: null, loading: true }\n : { name: session.accountName, id: session.accountId },\n mode,\n footer,\n linkComponent,\n }}\n betaBanner={meta.beta === false ? undefined : {}}\n // Mode identity, straight from the registry — this is what lets the Brand\n // API's per-Mode chrome tokens target this frame. Not app-supplied: an app\n // still cannot pick its own accent, it inherits its Mode's.\n modeId={appMode}\n contentWrapper={core?.contentWrapper ?? granted('contentWrapper')}\n topBar={{\n // Core's pages publish their own identity; every other app is one\n // product surface and takes its registry title.\n title: core?.page?.title ?? (grants?.includes('title') ? data?.frame?.title : undefined) ?? meta.title,\n breadcrumbs,\n user: {\n name: identity.userName,\n email: identity.email,\n // The chrome API's avatar wins; the app may supply a fallback chain\n // (e.g. a stored memoji) for users with no uploaded photo.\n avatarUrl: identity.avatarUrl ?? data?.fallbackAvatarUrl ?? null,\n role: session.role,\n },\n userMenu,\n onSignOut: handleSignOut,\n // The action cluster is IDENTICAL everywhere — core included. Page\n // actions sit BEFORE it, never inside it, so the Alerts bell keeps its\n // required position: farthest right, immediately before My Account.\n actions: (\n <>\n {core?.page?.actions}\n <ChromeTopBarActions />\n </>\n ),\n }}\n >\n {children}\n </NavAppShell>\n </>\n )\n}\n","// ---------------------------------------------------------------------------\n// App chrome wiring — the ONE shared implementation of the per-app glue that\n// previously lived as a copied ChromeWidgets.tsx in every Next.js feature app\n// (forms / surveys / polls / contacts). Copies drifted (org dropdown, badges);\n// this module makes that class of drift impossible: apps configure, never\n// re-implement (Reference/UI-Platform: consume via npm, never vendored).\n//\n// Provides:\n// <PolitogyAppChrome> — NavChromeProvider (same-origin proxy fetcher) +\n// chrome state (active core org, nav display) +\n// DevNotes provider, in one wrapper.\n// <ChromeTopBarActions> — the canonical top-bar cluster, in canonical order\n// (Fuel · Nav display · DevNotes · Support · Alerts\n// LAST, immediately left of My Account).\n// useChromeState / useChromeUserMenu / useIsSuperAdmin / useChromeFooter.\n//\n// The app still owns: its session (the /api/chrome proxy), page frames, build\n// metadata (env/commit/version), tab strips, and its own icons.\n// ---------------------------------------------------------------------------\n\n'use client'\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react'\nimport {\n NavChromeProvider,\n FuelAction,\n NotificationsAction,\n SupportAction,\n SpecOverlayAction,\n NavDisplayAction,\n TopBarWidgetSlot,\n useChromeOrgs,\n useThemePreference,\n type NavChromeFetcher,\n type NavDisplayMode,\n type NavOrgOption,\n type NavUserMenu,\n type NavFooter,\n type NavFooterLink,\n} from '../native/index'\nimport {\n DevNotesProvider,\n DevNotesMenu,\n DevNotesOverlay,\n DevNotesTaskListModal,\n createDevNotesClient,\n type DevNotesConfig,\n} from '@the-portland-company/devnotes'\nimport {\n FiActivity,\n FiBarChart2,\n FiBriefcase,\n FiClock,\n FiCreditCard,\n FiDollarSign,\n FiEdit3,\n FiFileText,\n FiFlag,\n FiGrid,\n FiHome,\n FiLayout,\n FiLifeBuoy,\n FiList,\n FiMail,\n FiMap,\n FiMapPin,\n FiMessageSquare,\n FiPhone,\n FiSend,\n FiSettings,\n FiShare2,\n FiTarget,\n FiUpload,\n FiUser,\n FiUsers,\n} from 'react-icons/fi'\nimport { useChromeMe, useNavChromeFetcher } from '../native/index'\nimport {\n ACTIVE_ORG_QUERY_PARAM,\n isOrgId,\n readActiveOrgCookie,\n resolveActiveOrg,\n writeActiveOrgCookie,\n} from '../active-org'\nimport {\n NAV_DISPLAY_DEFAULT,\n NAV_DISPLAY_STORAGE_KEY,\n isNavDisplayPreference,\n readNavDisplayCookie,\n resolveNavDisplay,\n writeNavDisplayCookie,\n writeNavDisplayLocal,\n} from '../nav-preference'\nimport type { StandardNavIconKey } from '../native/standardNav'\nimport type { NavBreadcrumb, NavIcon, NavItem, NavMode } from '../native/index'\n\n/**\n * The canonical icon map for standardPolitogyNav — ONE definition so every\n * app renders identical glyphs (including the Organization Settings branch:\n * briefcase / settings / creditCard / dollarSign / share).\n */\nexport const standardNavIcons: Record<StandardNavIconKey, NavIcon> = {\n home: FiHome,\n users: FiUsers,\n mail: FiMail,\n messageSquare: FiMessageSquare,\n layout: FiLayout,\n activity: FiActivity,\n lifeBuoy: FiLifeBuoy,\n grid: FiGrid,\n list: FiList,\n upload: FiUpload,\n edit: FiEdit3,\n fileText: FiFileText,\n send: FiSend,\n clock: FiClock,\n user: FiUser,\n barChart: FiBarChart2,\n briefcase: FiBriefcase,\n settings: FiSettings,\n creditCard: FiCreditCard,\n dollarSign: FiDollarSign,\n share: FiShare2,\n // Campaign / Petition mode slots.\n phone: FiPhone,\n map: FiMap,\n mapPin: FiMapPin,\n target: FiTarget,\n flag: FiFlag,\n}\n\nconst ORG_STORAGE_KEY = 'vrm.activeOrg'\n// The user's mode choice, shared by every app on the origin's localStorage.\nconst MODE_STORAGE_KEY = 'vrm.activeMode'\nconst CORE_BASE_URL = 'https://app.politogyvrm.com'\nconst CORE_BASE_URL_STAGING = 'https://staging-app.politogyvrm.com'\n\n/**\n * VRM-core base for the CURRENT environment, resolved at call time from the\n * host. A staging app (e.g. `surveys-staging.politogyvrm.com`,\n * `staging-app.politogyvrm.com`) targets the staging core, so cross-app links\n * into core — My Profile, Organization Settings, Add Account, the mode\n * dashboards — stay in staging instead of bouncing the user to production.\n * Everything else (prod hosts, localhost, previews) keeps the production core.\n *\n * Runtime, not build-time: the shell is one shared bundle consumed by every\n * app, so the environment can only be known from the host it runs on.\n */\nfunction getCoreBaseUrl(): string {\n if (typeof window !== 'undefined') {\n if (window.location.hostname.toLowerCase().includes('staging')) {\n return CORE_BASE_URL_STAGING\n }\n }\n return CORE_BASE_URL\n}\n\nexport type ChromeIdentity = {\n userId: string\n userName: string | null\n email: string | null\n /** The APP's own role string (any casing) — feeds DevNotes admin gating. */\n role: string\n}\n\ntype ChromeState = {\n orgId: string | null\n setOrgId: (id: string) => void\n orgs: (NavOrgOption & { rawRole?: string | null })[]\n /**\n * The org list is still in flight. Consumers must render a skeleton rather\n * than fall back to the app's own workspace label, which is a DIFFERENT\n * account and flashes as the wrong organization.\n */\n orgsLoading: boolean\n navDisplay: NavDisplayMode\n setNavDisplay: (m: NavDisplayMode) => void\n}\n\nconst ChromeStateContext = createContext<ChromeState | null>(null)\n\nexport function useChromeState(): ChromeState | null {\n return useContext(ChromeStateContext)\n}\n\nexport type ControlledOrgState = {\n orgId: string | null\n onSwitch: (id: string) => void\n /** Override the org list (e.g. the app's own session-scoped list). */\n orgs?: (NavOrgOption & { rawRole?: string | null })[]\n /**\n * Applied for EXTERNAL org changes (another tab/app switched the shared\n * cookie, or the profile preference was adopted at boot). Unlike `onSwitch`\n * (a user gesture), this fires on tab focus — wire it WITHOUT navigation\n * side effects (e.g. vrm/core's switch without the dashboard redirect).\n * Falls back to `onSwitch` when absent.\n */\n onExternalSwitch?: (id: string) => void\n}\n\nfunction ChromeStateProvider({\n controlledOrg,\n children,\n}: {\n controlledOrg?: ControlledOrgState\n children: ReactNode\n}) {\n const { orgs, loading: orgsFetching, error: orgsError } = useChromeOrgs()\n const chromeMe = useChromeMe()\n const chromeFetch = useNavChromeFetcher()\n const [orgId, setOrgIdState] = useState<string | null>(null)\n const [navDisplay, setNavDisplayState] = useState<NavDisplayMode>(NAV_DISPLAY_DEFAULT)\n const navReconciled = useRef(false)\n const orgReconciled = useRef(false)\n // Whether boot found an explicit selector (URL `?org=` or the shared cookie).\n // The mirror effect writes the cookie right after first resolve, so a later\n // `resolveActiveOrg()` read is a false positive — this ref is the only\n // reliable \"was there a pre-existing selector?\" signal for the profile tier.\n const hadBootSelector = useRef(false)\n\n // Boot: restore persisted choices. The cross-app active org (URL `?org=` or\n // the `.politogyvrm.com` cookie) wins over host-only localStorage so every\n // app + subdomain resolves the SAME org instead of each defaulting to its own\n // earliest-joined org. Nav display follows the same cross-subdomain contract\n // as theme (cookie → localStorage → default) — it used to be localStorage\n // only, which is per-origin, so it reset on every app the user opened.\n useEffect(() => {\n try {\n const selector = resolveActiveOrg()\n if (selector) hadBootSelector.current = true\n const storedOrg = selector ?? localStorage.getItem(ORG_STORAGE_KEY)\n if (storedOrg) setOrgIdState(storedOrg)\n } catch {\n /* storage unavailable */\n }\n setNavDisplayState(resolveNavDisplay())\n }, [])\n\n // Once per session: converge on the profile's saved choice (authoritative),\n // reusing the provider's single `me` fetch — the theme reconcile pattern.\n useEffect(() => {\n if (navReconciled.current || !chromeMe.me) return\n const pref = chromeMe.me.navDisplay\n if (!isNavDisplayPreference(pref)) return\n navReconciled.current = true\n setNavDisplayState(pref)\n writeNavDisplayCookie(pref)\n writeNavDisplayLocal(pref)\n }, [chromeMe])\n\n // Live sync: `storage` events for same-app tabs, cookie re-reads on\n // focus/visibility for tabs on OTHER app subdomains.\n useEffect(() => {\n const onStorage = (e: StorageEvent) => {\n if (e.key === NAV_DISPLAY_STORAGE_KEY && isNavDisplayPreference(e.newValue)) {\n setNavDisplayState(e.newValue)\n }\n }\n const onWake = () => {\n const cookie = readNavDisplayCookie()\n if (cookie) setNavDisplayState(cookie)\n }\n window.addEventListener('storage', onStorage)\n window.addEventListener('focus', onWake)\n document.addEventListener('visibilitychange', onWake)\n return () => {\n window.removeEventListener('storage', onStorage)\n window.removeEventListener('focus', onWake)\n document.removeEventListener('visibilitychange', onWake)\n }\n }, [])\n\n // Once orgs resolve: validate the stored org, default to the first.\n useEffect(() => {\n if (!orgs || orgs.length === 0) return\n setOrgIdState((prev) => (prev && orgs.some((o) => o.id === prev) ? prev : orgs[0].id))\n }, [orgs])\n\n // Refs for the live-sync wake handler: registered once (theme/nav precedent)\n // but acting on CURRENT state, so listeners never re-subscribe per render.\n const activeOrgRef = useRef<string | null>(null)\n const memberOrgsRef = useRef<{ id: string }[]>([])\n const controlledOrgRef = useRef<ControlledOrgState | undefined>(controlledOrg)\n controlledOrgRef.current = controlledOrg\n\n // Apply an EXTERNAL org change (another tab/app, or the adopted profile\n // preference). Membership-guarded and change-guarded; silent fall-through\n // otherwise — a non-member cookie value is normal, not an error.\n const applyExternalOrg = useCallback((next: string | null) => {\n if (!isOrgId(next)) return\n const members = memberOrgsRef.current\n if (members.length === 0) return\n if (!members.some((o) => o.id === next)) return\n if (next === activeOrgRef.current) return\n const controlled = controlledOrgRef.current\n if (controlled) (controlled.onExternalSwitch ?? controlled.onSwitch)(next as string)\n else setOrgIdState(next as string)\n }, [])\n\n // Live org sync: `storage` events for same-origin tabs, cookie re-reads on\n // focus/visibility for tabs on OTHER app subdomains — the same two channels\n // theme and nav display use. A user switching orgs in one app re-scopes\n // every other open tab the moment it regains focus.\n useEffect(() => {\n const onStorage = (e: StorageEvent) => {\n if (e.key === ORG_STORAGE_KEY) applyExternalOrg(e.newValue)\n }\n const onWake = () => {\n applyExternalOrg(readActiveOrgCookie())\n }\n window.addEventListener('storage', onStorage)\n window.addEventListener('focus', onWake)\n document.addEventListener('visibilitychange', onWake)\n return () => {\n window.removeEventListener('storage', onStorage)\n window.removeEventListener('focus', onWake)\n document.removeEventListener('visibilitychange', onWake)\n }\n }, [applyExternalOrg])\n\n // Once per session: adopt the profile's saved org (me.activeOrg) — but ONLY\n // when this load carried no explicit selector. Precedence is URL → cookie →\n // profile → default; theme's unconditional adopt is wrong for org because an\n // explicit per-request selector must always win.\n //\n // Membership is judged against the FETCHED chrome-API org list, not the\n // controlled app's list: controlled apps seed a provisional single-org list\n // (their session default) before their real fetch settles, and judging the\n // preference against that dropped it every time (verified live 2026-08-07).\n useEffect(() => {\n if (orgReconciled.current || !chromeMe.me) return\n if (hadBootSelector.current) {\n orgReconciled.current = true\n return\n }\n const pref = (chromeMe.me as { activeOrg?: string | null }).activeOrg\n if (!isOrgId(pref)) {\n orgReconciled.current = true\n return\n }\n // Wait until the chrome-API org fetch settles (success or error) — do NOT\n // latch while it is in flight, or the preference is silently dropped.\n if (!orgs && !orgsError) return\n orgReconciled.current = true\n const members = [...(orgs ?? []), ...(controlledOrg?.orgs ?? [])]\n if (!members.some((o) => o.id === pref)) return\n const controlled = controlledOrgRef.current\n if (controlled) (controlled.onExternalSwitch ?? controlled.onSwitch)(pref as string)\n else setOrgIdState(pref as string)\n }, [chromeMe.me, orgs, orgsError, controlledOrg])\n\n const setOrgId = useCallback((id: string) => {\n setOrgIdState(id)\n try {\n localStorage.setItem(ORG_STORAGE_KEY, id)\n } catch {\n /* best effort */\n }\n // Remember the choice cross-subdomain so the next app opens on the same org.\n writeActiveOrgCookie(id)\n }, [])\n\n const setNavDisplay = useCallback(\n (m: NavDisplayMode) => {\n setNavDisplayState(m)\n writeNavDisplayLocal(m)\n // Cross-subdomain, so the next app opens on the same choice.\n writeNavDisplayCookie(m)\n // Best-effort durable persistence on the user's profile — a nav toggle\n // never errors, and the cookie already carries the choice meanwhile.\n chromeFetch?.('me/preferences', {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ navDisplay: m }),\n })?.catch(() => {})\n },\n [chromeFetch],\n )\n\n const value = useMemo<ChromeState>(() => {\n // CONTROLLED mode (Contacts): the APP owns the active org + switching —\n // its switch does a full session re-scope. The shared widgets read the\n // app's state so there is exactly one org truth (unification directive).\n if (controlledOrg) {\n return {\n orgId: controlledOrg.orgId,\n setOrgId: controlledOrg.onSwitch,\n orgs:\n controlledOrg.orgs ??\n (orgs ?? []).map((o) => ({\n id: o.id,\n name: o.name,\n logoUrl: o.logoUrl,\n brandColor: o.brandColor,\n role: o.role,\n rawRole: o.rawRole ?? null,\n })),\n orgsLoading: false,\n navDisplay,\n setNavDisplay,\n }\n }\n return {\n orgId,\n setOrgId,\n orgs: (orgs ?? []).map((o) => ({\n id: o.id,\n name: o.name,\n logoUrl: o.logoUrl,\n brandColor: o.brandColor,\n role: o.role,\n rawRole: o.rawRole ?? null,\n })),\n // Loading until the fetch settles. On error we stop loading so the frame\n // falls back to the app label rather than shimmering forever.\n orgsLoading: orgsFetching && !orgsError && !orgs,\n navDisplay,\n setNavDisplay,\n }\n }, [controlledOrg, orgId, setOrgId, orgs, orgsFetching, orgsError, navDisplay, setNavDisplay])\n\n // Keep the shared cookie + address-bar `?org=` in sync with the ACTIVE org —\n // whichever path owns it, controlled (Contacts) or uncontrolled (feature\n // apps) — so every app + tab resolves the same org and every URL is\n // bookmarkable/shareable with its org context. Idempotent; no-op on server.\n const activeOrgId = value.orgId\n activeOrgRef.current = activeOrgId\n memberOrgsRef.current = value.orgs\n const lastPatchedOrg = useRef<string | null>(null)\n useEffect(() => {\n if (!isOrgId(activeOrgId)) return\n writeActiveOrgCookie(activeOrgId as string)\n try {\n // Same-origin storage channel for OTHER tabs of this app (the cookie\n // write emits no event) — mirrors the choice whichever branch owns it.\n localStorage.setItem(ORG_STORAGE_KEY, activeOrgId as string)\n } catch {\n /* best effort */\n }\n try {\n const url = new URL(window.location.href)\n if (url.searchParams.get(ACTIVE_ORG_QUERY_PARAM) !== activeOrgId) {\n url.searchParams.set(ACTIVE_ORG_QUERY_PARAM, activeOrgId as string)\n window.history.replaceState(window.history.state, '', url.toString())\n }\n } catch {\n /* SSR / no window */\n }\n // Durable profile write (the theme/nav pattern): one call site covers both\n // the controlled and uncontrolled branches. Best-effort, deduped against\n // the profile's known value and our own last write; a fresh browser with\n // no cookie then boots on this org via the profile tier.\n //\n // GATED on the reconcile having resolved: before that, activeOrgId is the\n // app's boot DEFAULT, and patching it overwrote the user's stored\n // preference with the default on every fresh session (verified live\n // 2026-08-07 — the preference lasted exactly one login).\n const known = (chromeMe.me as { activeOrg?: string | null } | null)?.activeOrg ?? null\n if (\n orgReconciled.current &&\n chromeMe.me &&\n activeOrgId !== known &&\n activeOrgId !== lastPatchedOrg.current\n ) {\n lastPatchedOrg.current = activeOrgId as string\n chromeFetch?.('me/preferences', {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ activeOrg: activeOrgId }),\n })?.catch(() => {})\n }\n }, [activeOrgId, chromeMe.me, chromeFetch])\n\n return <ChromeStateContext.Provider value={value}>{children}</ChromeStateContext.Provider>\n}\n\nexport type ChromeDevNotesConfig = {\n /** Override the DevNotes API base (default: `${proxyBasePath}/devnotes`). */\n basePath?: string\n /** Client-side token supplier (default: empty — same-origin proxy injects). */\n getAuthToken?: () => Promise<string> | string\n /** Custom fetch (e.g. credentials:'include' against a cross-origin API). */\n fetch?: typeof globalThis.fetch\n /**\n * The app already mounts its own `<DevNotesProvider>` ABOVE this chrome, so\n * the chrome must not mount a second one (VRM core, whose provider carries\n * capabilities the generic client has no equivalent for — user stories, its\n * own role gating). The working SURFACE still comes from here, so the\n * launcher, the overlay and the task modal behave identically everywhere;\n * only the data adapter is the app's.\n */\n providedByApp?: boolean\n}\n\nfunction AppDevNotes({\n storagePrefix,\n proxyBasePath,\n devNotes,\n identity,\n children,\n}: {\n storagePrefix: string\n proxyBasePath: string\n devNotes?: ChromeDevNotesConfig\n identity: ChromeIdentity\n children: ReactNode\n}) {\n const adapter = useMemo(\n () =>\n createDevNotesClient({\n basePath: devNotes?.basePath ?? `${proxyBasePath}/devnotes`,\n // Default: the same-origin proxy attaches the session's Bearer.\n getAuthToken: devNotes?.getAuthToken ?? (async () => ''),\n ...(devNotes?.fetch ? { fetch: devNotes.fetch } : {}),\n }),\n [proxyBasePath, devNotes?.basePath, devNotes?.getAuthToken, devNotes?.fetch],\n )\n\n const user = useMemo(\n () => ({\n id: identity.userId,\n email: identity.email ?? '',\n fullName: identity.userName ?? undefined,\n }),\n [identity.userId, identity.email, identity.userName],\n )\n\n const config = useMemo<DevNotesConfig>(\n () => ({\n storagePrefix,\n role: identity.role.toLowerCase() === 'admin' ? 'admin' : 'reporter',\n disableAi: true,\n getPagePath: () => window.location.pathname,\n }),\n [storagePrefix, identity.role],\n )\n\n // `<DevNotesProvider>` hydrates tasks/task-types/task-lists/collaborators/\n // app-link/capabilities unconditionally on mount — 5-6 requests, one 6.8s\n // cold, even when the panel is never opened (nav-latency-report.md Table 2).\n // Gate those specific adapter methods behind the panel's FIRST open; the\n // launcher button (`ChromeDevNotesMenu` below) still renders and responds\n // instantly, it just flips `activate()` on pointerdown before its own click\n // handler runs. `fetchUnreadCounts` (the launcher badge count) is exempt\n // from the open-gate — it still needs a number before the user opens\n // anything — but its first call is pushed off the boot path onto\n // requestIdleCallback so it never competes with first paint.\n const activatedRef = useRef(false)\n const activationWaitersRef = useRef<Array<() => void>>([])\n const activate = useCallback(() => {\n if (activatedRef.current) return\n activatedRef.current = true\n const waiters = activationWaitersRef.current\n activationWaitersRef.current = []\n waiters.forEach((resolve) => resolve())\n }, [])\n const waitForActivation = useCallback((): Promise<void> => {\n if (activatedRef.current) return Promise.resolve()\n return new Promise((resolve) => {\n activationWaitersRef.current.push(resolve)\n })\n }, [])\n\n const lazyAdapter = useMemo<typeof adapter>(() => {\n const GATED_METHODS = [\n 'fetchTasks',\n 'fetchTaskTypes',\n 'fetchTaskLists',\n 'fetchCollaborators',\n 'fetchCapabilities',\n 'getAppLinkStatus',\n 'fetchBugReports',\n 'fetchBugReportTypes',\n ] as const\n const wrapped: Record<string, unknown> = { ...adapter }\n for (const method of GATED_METHODS) {\n const original = (adapter[method] as (...args: unknown[]) => Promise<unknown>).bind(adapter)\n wrapped[method] = (...args: unknown[]) => waitForActivation().then(() => original(...args))\n }\n let idleScheduled = false\n const originalUnreadCounts = adapter.fetchUnreadCounts.bind(adapter)\n wrapped.fetchUnreadCounts = () => {\n if (idleScheduled || typeof window === 'undefined') return originalUnreadCounts()\n idleScheduled = true\n return new Promise((resolve, reject) => {\n const run = () => originalUnreadCounts().then(resolve, reject)\n const ric = (window as { requestIdleCallback?: (cb: () => void) => number })\n .requestIdleCallback\n if (ric) ric(run)\n else setTimeout(run, 0)\n })\n }\n return wrapped as unknown as typeof adapter\n }, [adapter, waitForActivation])\n\n // The app brought its own provider — mount only the surface, so a second\n // DevNotesProvider never shadows the app's adapter. (The app's own adapter\n // is out of this chrome's control, so the open-gate above does not apply.)\n if (devNotes?.providedByApp) return <DevNotesSurface activate={activate}>{children}</DevNotesSurface>\n\n return (\n <DevNotesProvider adapter={lazyAdapter} user={user} config={config}>\n <DevNotesSurface activate={activate}>{children}</DevNotesSurface>\n </DevNotesProvider>\n )\n}\n\n// \"View All Tasks\" is triggered from the menu in the top bar but the modal has\n// to render at the chrome ROOT, or it would be trapped inside the top bar's\n// stacking/blur context. The menu publishes the request through this context.\nconst DevNotesTasksContext = createContext<{\n ready: boolean\n openTasks: () => void\n activate: () => void\n}>({\n ready: false,\n openTasks: () => {},\n activate: () => {},\n})\n\n/**\n * The DevNotes working surface, mounted once at the chrome root.\n *\n * `<DevNotesMenu>` only TOGGLES creation mode — `<DevNotesOverlay>` is what\n * renders the click-to-place capture layer, the report dots and the report\n * form. The shell shipped the provider and the menu but never the overlay, so\n * on every app that used this chrome (forms / surveys / polls) \"Create Task\"\n * closed the menu and did nothing at all: the mode flipped on with nothing\n * listening (HITL bug report 2026-07-23). Contacts didn't hit it only because\n * it still had its own hand-rolled surface.\n */\nfunction DevNotesSurface({\n activate,\n children,\n}: {\n /** Flips the DevNotes data adapter open for the first time (no-op after). */\n activate: () => void\n children: ReactNode\n}) {\n const [tasksOpen, setTasksOpen] = useState(false)\n const openTasks = useCallback(() => {\n activate()\n setTasksOpen(true)\n }, [activate])\n const tasksCtx = useMemo(() => ({ ready: true, openTasks, activate }), [openTasks, activate])\n\n return (\n <DevNotesTasksContext.Provider value={tasksCtx}>\n {children}\n {/* Mounted only while open: the modal loads data on mount regardless of\n its `open` prop, so keeping it unmounted avoids fetching every user's\n tasks before they ask for them. */}\n {tasksOpen ? <DevNotesTaskListModal open onClose={() => setTasksOpen(false)} /> : null}\n <DevNotesOverlay />\n </DevNotesTasksContext.Provider>\n )\n}\n\n/**\n * The app-chrome root. Wrap the authenticated frame once:\n *\n * <PolitogyAppChrome storagePrefix=\"forms\" identity={{userId, userName, email, role}}>\n * <ShellFrame …/>\n * </PolitogyAppChrome>\n */\nexport function PolitogyAppChrome({\n storagePrefix,\n proxyBasePath = '/api/chrome',\n fetchJson: fetchJsonOverride,\n devNotes,\n org,\n identity,\n children,\n}: {\n storagePrefix: string\n proxyBasePath?: string\n /**\n * Override the same-origin proxy fetcher for apps that talk to the chrome\n * API directly with their own auth (Contacts sends a client-side Bearer).\n * Paths stay relative ('orgs', 'me', …) — the override owns base + auth.\n */\n fetchJson?: NavChromeFetcher\n /** DevNotes wiring override for direct-auth apps (Contacts). */\n devNotes?: ChromeDevNotesConfig\n /** Controlled org state — the app owns active-org + switching (Contacts). */\n org?: ControlledOrgState\n identity: ChromeIdentity\n children: ReactNode\n}) {\n const proxyFetchJson = useMemo<NavChromeFetcher>(\n () =>\n async (path, init) => {\n const res = await fetch(`${proxyBasePath}/${path}`, {\n method: init?.method ?? 'GET',\n headers: init?.headers,\n body: init?.body,\n })\n if (!res.ok) throw new Error(`chrome ${path}: ${res.status}`)\n if (res.status === 204) return null\n const text = await res.text()\n return text ? JSON.parse(text) : null\n },\n [proxyBasePath],\n )\n const fetchJson = fetchJsonOverride ?? proxyFetchJson\n\n return (\n <NavChromeProvider fetchJson={fetchJson}>\n <ChromeStateProvider controlledOrg={org}>\n <AppDevNotes\n storagePrefix={storagePrefix}\n proxyBasePath={proxyBasePath}\n devNotes={devNotes}\n identity={identity}\n >\n {children}\n </AppDevNotes>\n </ChromeStateProvider>\n </NavChromeProvider>\n )\n}\n\n/** The standard top-bar action cluster. The Alerts bell renders LAST so it\n * sits farthest right, immediately left of the My Account badge. */\nexport function ChromeTopBarActions() {\n const state = useChromeState()\n if (!state) return null\n return (\n <>\n <FuelAction orgId={state.orgId} />\n <NavDisplayAction value={state.navDisplay} onChange={state.setNavDisplay} />\n <TopBarWidgetSlot\n title=\"DevNotes\"\n description=\"Capture bugs and notes, filed straight to Forge.\"\n >\n <ChromeDevNotesMenu />\n </TopBarWidgetSlot>\n <SpecOverlayAction orgId={state.orgId} />\n <SupportAction orgId={state.orgId} />\n <NotificationsAction orgId={state.orgId} />\n </>\n )\n}\n\n/**\n * The DevNotes launcher. Renders nothing until the surface above is mounted, so\n * it never touches DevNotes context before the provider exists, and forwards\n * \"View All Tasks\" to the root-level modal.\n */\nfunction ChromeDevNotesMenu() {\n const { ready, openTasks, activate } = useContext(DevNotesTasksContext)\n if (!ready) return null\n // `onPointerDownCapture` fires before DevNotesMenu's own click handler, so\n // the adapter is already unblocked by the time the menu's first \"Create\n // Task\" click reaches it. `display: contents` keeps the wrapper out of\n // layout entirely — the launcher renders exactly as before.\n return (\n <span style={{ display: 'contents' }} onPointerDownCapture={activate} onFocusCapture={activate} onKeyDownCapture={activate}>\n <DevNotesMenu position=\"top-right\" onViewTasks={openTasks} />\n </span>\n )\n}\n\n/** True when any core-org membership carries a super-admin tier. */\nexport function useIsSuperAdmin(): boolean {\n const state = useChromeState()\n return (state?.orgs ?? []).some((o) => /super/i.test(o.rawRole ?? ''))\n}\n\nconst FOOTER_LINKS: NavFooterLink[] = [\n { label: 'Privacy', href: `${CORE_BASE_URL}/privacy-policy`, external: true },\n { label: 'Terms', href: `${CORE_BASE_URL}/terms-and-conditions`, external: true },\n {\n label: 'Subscriptions',\n href: 'https://politogyvrm.com/subscription-cancellation-policy',\n external: true,\n },\n]\n\n/**\n * Sidebar footer: legal links AND build metadata (env / commit / version /\n * date / author) for every user. Reference/UI-Platform \"Left bar — required\n * elements\" lists Meta unconditionally — it carries no Super Administrator\n * gate. Gating it here (pre-2026-09-30) silently dropped the whole Meta row\n * for every non-admin viewer, which is exactly the \"Left Nav not adhering to\n * UI/UX rules\" violation DevNotes 83a4713 filed against Contacts. Pass the\n * app's build-time metadata in; it now always reaches the rail.\n */\nexport function useChromeFooter(meta: {\n envLabel?: string\n version?: string\n commit?: string\n commitDate?: string\n commitAuthor?: string\n}): NavFooter {\n return useMemo<NavFooter>(\n () => ({ links: FOOTER_LINKS, ...meta }),\n [meta.envLabel, meta.version, meta.commit, meta.commitDate, meta.commitAuthor],\n )\n}\n\n// ---------------------------------------------------------------------------\n// Identity — resolved by the PACKAGE, from the chrome API.\n//\n// Apps used to pass a display name straight from their own session claims, and\n// forms passed `user.name ?? user.email` — so a user with no name set had their\n// EMAIL rendered as their name, and the chrome API's real profile name could\n// never win (HITL 2026-07-23). The chrome API is the authority; what the app\n// passes is a pre-hydration fallback only, and an email is never a name.\n// ---------------------------------------------------------------------------\n\nexport function useChromeIdentity(fallback?: {\n userName?: string | null\n email?: string | null\n}): ResolvedIdentity {\n const { me, loaded } = useChromeMe()\n return resolveIdentity({\n apiName: me?.userName,\n fallbackName: fallback?.userName,\n email: fallback?.email,\n avatarUrl: me?.avatarUrl,\n loaded,\n })\n}\n\n// Breadcrumbs live in ../lib/breadcrumbs (pure, dependency-free) and are\n// re-exported here so apps keep a single import surface.\nexport { deriveBreadcrumbs } from '../lib/breadcrumbs'\nexport { looksLikeEmail, resolveIdentity, type ResolvedIdentity } from '../lib/identity'\nimport { resolveIdentity, type ResolvedIdentity } from '../lib/identity'\n\n// ---------------------------------------------------------------------------\n// Breadcrumbs — derived by the PACKAGE from the nav tree + the current path.\n//\n// Every app hand-built its own trail, so they disagreed: forms rendered\n// \"Forms › Dashboard\" while polls rendered \"Polls\" under a \"Polls\" title\n// (\"Polls / Polls\"). The standard is Dashboard › Sub › Item (HITL 2026-07-23),\n// derived from the same nav tree the sidebar renders, so no app can drift.\n// ---------------------------------------------------------------------------\n\n/**\n * The My Account menu config — profile/org links into VRM core, real roles\n * from the user's core organizations, the signed-in account, and the shared\n * Light/System/Dark theme control (auth-derived, cross-app).\n */\nexport function useChromeUserMenu({\n userId,\n userName,\n email,\n}: {\n userId: string\n userName: string | null\n email: string | null\n}): NavUserMenu {\n const state = useChromeState()\n const theme = useThemePreference()\n const activeOrg = state?.orgs.find((o) => o.id === state.orgId) ?? null\n const orgSuffix = activeOrg ? `?org=${activeOrg.id}` : ''\n // Environment-aware: on a staging app these must point at the staging core,\n // not production (HITL: editing Profile from a staging app redirected to prod).\n const coreBase = getCoreBaseUrl()\n return {\n // My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).\n myProfileHref: `${coreBase}/my-profile`,\n organizationSettingsHref: `${coreBase}/organization-settings${orgSuffix}`,\n roles: (state?.orgs ?? [])\n .filter((o) => o.rawRole || o.role)\n .map((o) => ({ role: (o.rawRole ?? o.role) as string, orgName: o.name })),\n accounts: [{ id: userId, name: userName, email, avatarUrl: null, active: true }],\n addAccountHref: `${coreBase}/my-profile#accounts`,\n theme: { value: theme.value, onChange: theme.setValue },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Mode selector — entitlement-driven (HITL 2026-07-23: an org with multiple\n// active modes selects them from the left nav). Entitlements come from the\n// chrome API: GET me with the active org header → modes booleans\n// {relationship, campaign, petition, polling}. Selecting a mode navigates to\n// that mode's VRM-core dashboard carrying the active org.\n// ---------------------------------------------------------------------------\n\nconst MODE_DEFS: {\n id: string\n label: string\n icon: NavIcon\n /** Absolute destination, or a VRM-core path prefixed with CORE_BASE_URL. */\n href: string\n orgQuery: boolean\n}[] = [\n {\n id: 'relationship',\n label: 'Relationship Mode',\n icon: FiUsers,\n href: `${CORE_BASE_URL}/relationship/dashboard`,\n orgQuery: true,\n },\n {\n id: 'campaign',\n label: 'Campaign Mode',\n icon: FiBarChart2,\n href: `${CORE_BASE_URL}/campaign/dashboard`,\n orgQuery: true,\n },\n {\n // Petition Mode lives in its own standalone app on its own subdomain — the\n // petitions repo deploys production to petition-mode.politogyvrm.com.\n id: 'petition',\n label: 'Petition Mode',\n icon: FiFlag,\n href: 'https://petition-mode.politogyvrm.com/',\n orgQuery: true,\n },\n]\n\ntype ModeId = 'relationship' | 'campaign' | 'petition'\n\ntype UseChromeModeArg =\n | ModeId\n | {\n /** Pre-entitlement fallback for first paint (default 'relationship'). */\n fallbackModeId?: ModeId\n /**\n * Registry-pinned mode for a MODE-SCOPED app (e.g. the Campaign apps\n * a2p / phonebank / canvass / signs, from `POLITOGY_APPS[app].mode`). The\n * pill DISPLAYS this mode regardless of the cross-app selection, so a\n * campaign app never shows a Relationship pill. The switcher still appears\n * when the active org is entitled to more than one mode, so the user can\n * jump out to another mode's home.\n */\n pinnedModeId?: ModeId\n }\n\n/**\n * The active mode pill / selector.\n *\n * For an UNSCOPED app the current mode is the USER'S OWN SELECTION (persisted\n * cross-app in localStorage under `vrm.activeMode`), narrowed to what the active\n * org is entitled to — never a literal an app hardcodes. Apps used to call\n * `useChromeMode('relationship')`, which pinned the pill to Relationship even\n * for an org entitled to Campaign or Petition (HITL 2026-07-23); the string\n * argument now only supplies the pre-entitlement fallback for first paint.\n *\n * A MODE-SCOPED app passes `{ pinnedModeId }` so its pill displays that mode\n * (its own mode from the app registry) rather than the cross-app selection —\n * while a multi-mode org still gets the switcher to leave.\n */\nexport function useChromeMode(arg: UseChromeModeArg = {}): NavMode {\n const { fallbackModeId = 'relationship', pinnedModeId } =\n typeof arg === 'string' ? { fallbackModeId: arg, pinnedModeId: undefined } : arg\n const ctx = useContext(ChromeStateContext)\n const nav = useNavChromeFetcher()\n const orgId = ctx?.orgId ?? null\n const [entitled, setEntitled] = useState<Record<string, boolean> | null>(null)\n const [selectedModeId, setSelectedModeId] = useState<string | null>(null)\n\n // Restore the user's last mode choice (shared key across every app).\n useEffect(() => {\n try {\n const stored = localStorage.getItem(MODE_STORAGE_KEY)\n if (stored && MODE_DEFS.some((m) => m.id === stored)) setSelectedModeId(stored)\n } catch {\n /* storage unavailable */\n }\n }, [])\n\n useEffect(() => {\n if (!nav || !orgId) return\n let cancelled = false\n nav('me', { headers: { 'x-contacts-org': orgId } })\n .then((data) => {\n if (cancelled) return\n const modes = (data as { modes?: Record<string, boolean> | null })?.modes ?? null\n setEntitled(modes)\n })\n .catch(() => {\n /* entitlements unavailable — single-mode pill stands */\n })\n return () => {\n cancelled = true\n }\n }, [nav, orgId])\n\n const options = MODE_DEFS.filter((m) => entitled?.[m.id])\n // Resolution order: a registry pin (mode-scoped app) wins outright → then the\n // user's selection (if the org is still entitled to it) → the first entitled\n // mode → the app's fallback. Entitlements are async, so before they land the\n // pin/fallback holds the pill's shape (no layout shift).\n const pinned = pinnedModeId ? MODE_DEFS.find((m) => m.id === pinnedModeId) ?? null : null\n const selected = selectedModeId\n ? options.find((m) => m.id === selectedModeId) ?? null\n : null\n const current =\n pinned ??\n selected ??\n options[0] ??\n MODE_DEFS.find((m) => m.id === fallbackModeId) ??\n MODE_DEFS[0]\n const suffix = orgId ? `?org=${orgId}` : ''\n\n return {\n label: current.label,\n icon: current.icon,\n options:\n options.length > 1\n ? options.map((o) => ({ id: o.id, label: o.label, icon: o.icon }))\n : undefined,\n onSelect:\n options.length > 1\n ? (id: string) => {\n const def = MODE_DEFS.find((m) => m.id === id)\n if (!def) return\n // Remember the choice BEFORE navigating so the destination app —\n // and every app after it — opens in the mode the user picked.\n setSelectedModeId(id)\n try {\n localStorage.setItem(MODE_STORAGE_KEY, id)\n } catch {\n /* storage unavailable */\n }\n // Env-aware: the two VRM-core dashboards are baked with the prod\n // base at module load; on a staging app rewrite it to the staging\n // core so a mode switch stays in staging (petition mode is a fully\n // absolute URL and is left untouched by the replace).\n const href = def.href.replace(CORE_BASE_URL, getCoreBaseUrl())\n const sep = href.includes('?') ? '&' : '?'\n window.location.assign(\n def.orgQuery && suffix ? `${href}${sep}${suffix.slice(1)}` : href,\n )\n }\n : undefined,\n }\n}\n\n// The one-component app frame (see ./frame.tsx). Re-exported here so apps have\n// a single import surface: `@the-portland-company/shell/app-chrome`.\nexport {\n PolitogyAppFrame,\n POLITOGY_APPS,\n type PolitogyAppKey,\n type PolitogyAppMode,\n type PolitogyAppSession,\n type PolitogyBuildMeta,\n type PolitogyFrameData,\n type PolitogyFrameGrant,\n type PolitogyGrantedFrame,\n} from './frame'\n\n// The boot-screen surface (Specs/Loading-Screen), mounted by PolitogyAppFrame.\n// Re-exported so an app with a real pipeline can type its `bootProgress` prop.\nexport { LoadingScreen, type BootProgress, type BootStageId, type BootPhase } from './loading-screen'\n"]}