@the-portland-company/shell 0.68.1 → 0.70.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +4 -1
  3. package/dist/FormColumn-DsNP6NVG.d.cts +21 -0
  4. package/dist/FormColumn-DsNP6NVG.d.ts +21 -0
  5. package/dist/app-chrome.cjs +477 -236
  6. package/dist/app-chrome.cjs.map +1 -1
  7. package/dist/app-chrome.d.cts +24 -12
  8. package/dist/app-chrome.d.ts +24 -12
  9. package/dist/app-chrome.js +115 -50
  10. package/dist/app-chrome.js.map +1 -1
  11. package/dist/app-icons.cjs +6 -10
  12. package/dist/app-icons.cjs.map +1 -1
  13. package/dist/app-icons.d.cts +6 -6
  14. package/dist/app-icons.d.ts +6 -6
  15. package/dist/app-icons.js +6 -10
  16. package/dist/app-icons.js.map +1 -1
  17. package/dist/{chunk-6UHJV2FH.js → chunk-7YVJ7HQG.js} +41 -3
  18. package/dist/chunk-7YVJ7HQG.js.map +1 -0
  19. package/dist/{chunk-2UTIX3LI.js → chunk-CZI66JVG.js} +278 -167
  20. package/dist/chunk-CZI66JVG.js.map +1 -0
  21. package/dist/chunk-LPSBSAF3.js +26 -0
  22. package/dist/chunk-LPSBSAF3.js.map +1 -0
  23. package/dist/index.cjs +68 -37
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +30 -9
  26. package/dist/index.d.ts +30 -9
  27. package/dist/index.js +59 -45
  28. package/dist/index.js.map +1 -1
  29. package/dist/native.cjs +343 -165
  30. package/dist/native.cjs.map +1 -1
  31. package/dist/native.d.cts +69 -31
  32. package/dist/native.d.ts +69 -31
  33. package/dist/native.js +3 -1
  34. package/dist/nav-preference.cjs +44 -0
  35. package/dist/nav-preference.cjs.map +1 -1
  36. package/dist/nav-preference.d.cts +8 -1
  37. package/dist/nav-preference.d.ts +8 -1
  38. package/dist/nav-preference.js +1 -1
  39. package/package.json +1 -1
  40. package/dist/chunk-2UTIX3LI.js.map +0 -1
  41. package/dist/chunk-6UHJV2FH.js.map +0 -1
@@ -7,6 +7,7 @@ var fi = require('react-icons/fi');
7
7
  var reactDom = require('react-dom');
8
8
  var jsxRuntime = require('react/jsx-runtime');
9
9
  var devnotes = require('@the-portland-company/devnotes');
10
+ var lu = require('react-icons/lu');
10
11
 
11
12
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
13
 
@@ -59,6 +60,21 @@ function resolveBrandGlyph(name) {
59
60
  return GLYPHS[name.trim().toLowerCase()] ?? null;
60
61
  }
61
62
 
63
+ // src/lib/deprecation.ts
64
+ var warned = /* @__PURE__ */ new Set();
65
+ function isDev() {
66
+ try {
67
+ return typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
68
+ } catch {
69
+ return false;
70
+ }
71
+ }
72
+ function warnDeprecated(key, message) {
73
+ if (!isDev() || warned.has(key)) return;
74
+ warned.add(key);
75
+ console.warn(`[@the-portland-company/shell] ${message}`);
76
+ }
77
+
62
78
  // src/native/orgFilter.ts
63
79
  var ORG_FILTER_THRESHOLD = 8;
64
80
  function filterOrgs(orgs, query) {
@@ -73,13 +89,111 @@ function normalize(s) {
73
89
  return s.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().trim();
74
90
  }
75
91
 
92
+ // src/nav-preference.ts
93
+ var NAV_DISPLAY_STORAGE_KEY = "politogy_nav_display";
94
+ var NAV_DISPLAY_COOKIE = "politogy_nav_display";
95
+ var LEGACY_NAV_DISPLAY_KEY = "vrm.navDisplay";
96
+ var NAV_DISPLAY_DEFAULT = "both";
97
+ var VALID = ["menu", "tabs", "both"];
98
+ function isNavDisplayPreference(v) {
99
+ return typeof v === "string" && VALID.includes(v);
100
+ }
101
+ function readNavDisplayCookie() {
102
+ if (typeof document === "undefined") return null;
103
+ try {
104
+ const m = document.cookie.match(
105
+ new RegExp(`(?:^|;\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)`)
106
+ );
107
+ const v = m ? decodeURIComponent(m[1]) : null;
108
+ return isNavDisplayPreference(v) ? v : null;
109
+ } catch {
110
+ return null;
111
+ }
112
+ }
113
+ function writeNavDisplayCookie(pref) {
114
+ if (typeof document === "undefined" || typeof window === "undefined") return;
115
+ const host = window.location.hostname;
116
+ const domainAttr = /(^|\.)politogyvrm\.com$/i.test(host) ? "; Domain=.politogyvrm.com" : "";
117
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
118
+ document.cookie = `${NAV_DISPLAY_COOKIE}=${encodeURIComponent(
119
+ pref
120
+ )}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`;
121
+ }
122
+ function readNavDisplayLocal() {
123
+ if (typeof localStorage === "undefined") return null;
124
+ try {
125
+ const current = localStorage.getItem(NAV_DISPLAY_STORAGE_KEY);
126
+ if (isNavDisplayPreference(current)) return current;
127
+ const legacy = localStorage.getItem(LEGACY_NAV_DISPLAY_KEY);
128
+ return isNavDisplayPreference(legacy) ? legacy : null;
129
+ } catch {
130
+ return null;
131
+ }
132
+ }
133
+ function writeNavDisplayLocal(pref) {
134
+ if (typeof localStorage === "undefined") return;
135
+ try {
136
+ localStorage.setItem(NAV_DISPLAY_STORAGE_KEY, pref);
137
+ } catch {
138
+ }
139
+ }
140
+ function resolveNavDisplay() {
141
+ return readNavDisplayCookie() ?? readNavDisplayLocal() ?? NAV_DISPLAY_DEFAULT;
142
+ }
143
+ `(function(){try{
144
+ var KEY=${JSON.stringify(NAV_DISPLAY_STORAGE_KEY)};
145
+ var VALID=["menu","tabs","both"];
146
+ function fromCookie(){try{var m=document.cookie.match(/(?:^|;\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)/);return m?decodeURIComponent(m[1]):null;}catch(e){return null;}}
147
+ var cookie=fromCookie();
148
+ if(cookie&&VALID.indexOf(cookie)!==-1){var ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}
149
+ if(cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}}
150
+ }catch(e){}})();`;
151
+ var RAIL_STORAGE_KEY = "politogy_rail";
152
+ var RAIL_COOKIE = "politogy_rail";
153
+ var RAIL_DEFAULT = "collapsed";
154
+ function isRailPreference(v) {
155
+ return v === "expanded" || v === "collapsed";
156
+ }
157
+ function readRailPreference() {
158
+ if (typeof document !== "undefined") {
159
+ try {
160
+ const m = document.cookie.match(new RegExp(`(?:^|;\\s*)${RAIL_COOKIE}=([^;]+)`));
161
+ const v = m ? decodeURIComponent(m[1]) : null;
162
+ if (isRailPreference(v)) return v;
163
+ } catch {
164
+ }
165
+ }
166
+ if (typeof localStorage !== "undefined") {
167
+ try {
168
+ const v = localStorage.getItem(RAIL_STORAGE_KEY);
169
+ if (isRailPreference(v)) return v;
170
+ } catch {
171
+ }
172
+ }
173
+ return RAIL_DEFAULT;
174
+ }
175
+ function writeRailPreference(pref) {
176
+ if (typeof document === "undefined" || typeof window === "undefined") return;
177
+ const host = window.location.hostname;
178
+ const domainAttr = /(^|\.)politogyvrm\.com$/i.test(host) ? "; Domain=.politogyvrm.com" : "";
179
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
180
+ try {
181
+ document.cookie = `${RAIL_COOKIE}=${pref}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`;
182
+ } catch {
183
+ }
184
+ try {
185
+ localStorage.setItem(RAIL_STORAGE_KEY, pref);
186
+ } catch {
187
+ }
188
+ }
189
+
76
190
  // src/theme-preference.ts
77
191
  var THEME_STORAGE_KEY = "politogy_theme";
78
192
  var THEME_COOKIE = "politogy_theme";
79
193
  var THEME_PENDING_COOKIE = "politogy_theme_pending";
80
- var VALID = ["light", "dark", "system"];
194
+ var VALID2 = ["light", "dark", "system"];
81
195
  function isThemePreference(v) {
82
- return typeof v === "string" && VALID.includes(v);
196
+ return typeof v === "string" && VALID2.includes(v);
83
197
  }
84
198
  function readThemeCookie() {
85
199
  if (typeof document === "undefined") return null;
@@ -1832,7 +1946,6 @@ var PHONEBANK_ORIGIN = "https://phonebank.politogyvrm.com/";
1832
1946
  var CANVASS_ORIGIN = "https://canvass.politogyvrm.com/";
1833
1947
  var SIGNS_ORIGIN = "https://signs.politogyvrm.com/";
1834
1948
  var POLLS_ORIGIN = "https://polls.politogyvrm.com/";
1835
- var CONTACTS_TRIBES = "https://contacts.politogyvrm.com/tribes";
1836
1949
  var PETITION_MODE_ORIGIN = "https://petition-mode.politogyvrm.com/";
1837
1950
  function applyHiddenItems(items, hidden) {
1838
1951
  if (!hidden || hidden.length === 0) return items;
@@ -1902,10 +2015,6 @@ var APP_POLLS_CHILDREN = [
1902
2015
  { label: "Command Center", icon: "grid", href: "https://polls.politogyvrm.com/" },
1903
2016
  { label: "New Poll", icon: "edit", href: "https://polls.politogyvrm.com/polls/new" }
1904
2017
  ];
1905
- var APP_CTAS_CHILDREN = [
1906
- { label: "CTAs", icon: "list", href: "https://ctas.politogyvrm.com/" },
1907
- { label: "Canvas", icon: "edit", href: "https://ctas.politogyvrm.com/?tab=canvas" }
1908
- ];
1909
2018
  var APP_A2P_CHILDREN = [
1910
2019
  { label: "Dashboard", icon: "grid", path: "dashboard" },
1911
2020
  { label: "Compose", icon: "edit", path: "compose" },
@@ -1953,16 +2062,27 @@ function standardPolitogyNav(opts) {
1953
2062
  return { label: c.label, icon: icon(c.icon), href: withOrg(withMode) };
1954
2063
  });
1955
2064
  };
2065
+ const accountRows = () => [
2066
+ { kind: "section", label: "Account" },
2067
+ // My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).
2068
+ { label: "My profile", icon: icon("circleUser"), href: withOrg(abs("/my-profile")) },
2069
+ {
2070
+ label: "Organization settings",
2071
+ icon: icon("settings"),
2072
+ href: withOrg(abs("/organization-settings")),
2073
+ children: branches(ORG_SETTINGS_CHILDREN)
2074
+ }
2075
+ ];
1956
2076
  const buildRelationship = () => {
1957
2077
  const contacts = opts.contactsItem ? {
1958
2078
  label: "Contacts",
1959
- icon: icon("users"),
2079
+ icon: icon("usersRound"),
1960
2080
  href: opts.contactsItem.href,
1961
2081
  children: opts.contactsItem.children,
1962
2082
  badge: opts.contactsItem.count ?? void 0
1963
2083
  } : {
1964
2084
  label: "Contacts",
1965
- icon: icon("users"),
2085
+ icon: icon("usersRound"),
1966
2086
  href: withOrg(`${CONTACTS_APP}/`),
1967
2087
  children: APP_CONTACTS_CHILDREN.map((c) => ({
1968
2088
  label: c.label,
@@ -1972,7 +2092,7 @@ function standardPolitogyNav(opts) {
1972
2092
  };
1973
2093
  return [
1974
2094
  { kind: "section", label: "Relationship" },
1975
- { label: "Dashboard", icon: icon("home"), href: withOrg(abs("/relationship/dashboard")) },
2095
+ { label: "Dashboard", icon: icon("layoutDashboard"), href: withOrg(abs("/relationship/dashboard")) },
1976
2096
  contacts,
1977
2097
  {
1978
2098
  label: "Email broadcast",
@@ -1995,40 +2115,20 @@ function standardPolitogyNav(opts) {
1995
2115
  },
1996
2116
  { kind: "section", label: "Collect" },
1997
2117
  // Carries no top-level href in VRM core (parent row only toggles).
1998
- { label: "Calls to action", icon: icon("layout"), children: leaves(CTA_CHILDREN) },
2118
+ { label: "Calls to action", icon: icon("mousePointerClick"), children: leaves(CTA_CHILDREN) },
1999
2119
  {
2000
2120
  label: "Forms",
2001
- icon: icon("activity"),
2121
+ icon: icon("fileText"),
2002
2122
  href: withOrg("https://forms.politogyvrm.com/"),
2003
2123
  children: APP_FORMS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
2004
2124
  },
2005
2125
  {
2006
2126
  label: "Surveys",
2007
- icon: icon("fileText"),
2127
+ icon: icon("clipboardList"),
2008
2128
  href: withOrg("https://surveys.politogyvrm.com/surveys"),
2009
2129
  children: APP_SURVEYS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
2010
2130
  },
2011
- {
2012
- label: "Polls",
2013
- icon: icon("barChart"),
2014
- href: withOrg("https://polls.politogyvrm.com/"),
2015
- children: APP_POLLS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
2016
- },
2017
- {
2018
- label: "CTAs",
2019
- icon: icon("layout"),
2020
- href: withOrg("https://ctas.politogyvrm.com/"),
2021
- children: APP_CTAS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
2022
- },
2023
- { kind: "section", label: "Account" },
2024
- // My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).
2025
- { label: "My profile", icon: icon("user"), href: withOrg(abs("/my-profile")) },
2026
- {
2027
- label: "Organization settings",
2028
- icon: icon("settings"),
2029
- href: withOrg(abs("/organization-settings")),
2030
- children: branches(ORG_SETTINGS_CHILDREN)
2031
- }
2131
+ ...accountRows()
2032
2132
  ];
2033
2133
  };
2034
2134
  const buildCampaign = () => {
@@ -2037,40 +2137,57 @@ function standardPolitogyNav(opts) {
2037
2137
  ...opts.campaignAvailability
2038
2138
  };
2039
2139
  const rows = [
2040
- { label: "Dashboard", icon: icon("home"), href: withOrg(abs("/campaign/dashboard")) },
2041
- { label: "Voter Contact", icon: icon("target"), href: withOrg(abs("/campaign/campaigns")) },
2140
+ // Left-Navigation §9.2: Race data -> Research -> GOTV -> Account.
2141
+ // Battleground is the Campaign landing page; there is no Campaign
2142
+ // Dashboard row, and Voter Contact and Tribes have no row.
2143
+ { kind: "section", label: "Race data" },
2144
+ { label: "Battleground", icon: icon("crosshair"), href: withOrg(abs("/campaign/battleground")) },
2145
+ { label: "District data", icon: icon("landmark"), href: withOrg(abs("/campaign/districts")) },
2146
+ { kind: "section", label: "Research" },
2042
2147
  {
2043
- label: "A2P",
2044
- icon: icon("messageSquare"),
2045
- href: withOrg(A2P_ORIGIN),
2046
- children: appLeaves(A2P_ORIGIN, APP_A2P_CHILDREN),
2047
- flag: "a2p"
2148
+ label: "Polling",
2149
+ icon: icon("chartNoAxes"),
2150
+ href: withOrg(POLLS_ORIGIN),
2151
+ children: APP_POLLS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) })),
2152
+ flag: "polling"
2153
+ },
2154
+ { kind: "section", label: "GOTV" },
2155
+ {
2156
+ label: "Field canvassing",
2157
+ icon: icon("doorOpen"),
2158
+ href: withOrg(CANVASS_ORIGIN),
2159
+ children: appLeaves(CANVASS_ORIGIN, APP_CANVASS_CHILDREN),
2160
+ flag: "canvass"
2048
2161
  },
2049
2162
  {
2050
- label: "Phone Banking",
2163
+ label: "Phone banking",
2051
2164
  icon: icon("phone"),
2052
2165
  href: withOrg(PHONEBANK_ORIGIN),
2053
2166
  children: appLeaves(PHONEBANK_ORIGIN, APP_PHONEBANK_CHILDREN),
2054
2167
  flag: "phonebank"
2055
2168
  },
2056
2169
  {
2057
- label: "Field Canvassing",
2058
- icon: icon("map"),
2059
- href: withOrg(CANVASS_ORIGIN),
2060
- children: appLeaves(CANVASS_ORIGIN, APP_CANVASS_CHILDREN),
2061
- flag: "canvass"
2170
+ label: "A2P texting",
2171
+ icon: icon("messageSquare"),
2172
+ href: withOrg(A2P_ORIGIN),
2173
+ children: appLeaves(A2P_ORIGIN, APP_A2P_CHILDREN),
2174
+ flag: "a2p"
2062
2175
  },
2063
2176
  {
2064
- label: "Sign Mapping",
2065
- icon: icon("mapPin"),
2177
+ label: "Sign mapping",
2178
+ icon: icon("signpost"),
2066
2179
  href: withOrg(SIGNS_ORIGIN),
2067
2180
  children: appLeaves(SIGNS_ORIGIN, APP_SIGNS_CHILDREN),
2068
2181
  flag: "signs"
2069
2182
  },
2070
- { label: "Tribes", icon: icon("users"), href: withOrg(CONTACTS_TRIBES), flag: "tribes" },
2071
- { label: "Polling Engine", icon: icon("barChart"), href: withOrg(POLLS_ORIGIN), flag: "polling" }
2183
+ ...accountRows()
2072
2184
  ];
2073
- return rows.filter((r) => !r.flag || avail[r.flag]).map(({ flag: _flag, ...item }) => item);
2185
+ const kept = rows.filter((r) => !r.flag || avail[r.flag]).map(({ flag: _flag, ...item }) => item);
2186
+ return kept.filter((item, idx) => {
2187
+ if (item.kind !== "section") return true;
2188
+ const next = kept[idx + 1];
2189
+ return !!next && next.kind !== "section";
2190
+ });
2074
2191
  };
2075
2192
  const buildPetition = () => [
2076
2193
  opts.petitionsItem ? {
@@ -2150,6 +2267,24 @@ function envChipClasses(label) {
2150
2267
  return "bg-[rgba(107,114,128,0.16)] text-[#6b7280]";
2151
2268
  }
2152
2269
  var ORG_PILL_DEFAULT = "var(--color-accent)";
2270
+ var RailCollapsibleContext = react.createContext(false);
2271
+ function useRailCollapse() {
2272
+ const collapsible = react.useContext(RailCollapsibleContext);
2273
+ return (cls) => collapsible ? cls : "";
2274
+ }
2275
+ function OrgIconMark({ org, logoSrc }) {
2276
+ const rc = useRailCollapse();
2277
+ const src = resolveOrgLogoUrl(org.iconUrl) ?? logoSrc;
2278
+ return /* @__PURE__ */ jsxRuntime.jsx(
2279
+ "span",
2280
+ {
2281
+ "aria-hidden": true,
2282
+ "data-rail-org-mark": "",
2283
+ className: `hidden h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-[5px] bg-[#FFFFFF] text-[11px] font-bold text-neutral-800 ${rc("max-md:flex")}`,
2284
+ children: src ? /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt: "", className: "max-h-full max-w-full object-contain" }) : (org.name ?? "Org").slice(0, 2).toUpperCase()
2285
+ }
2286
+ );
2287
+ }
2153
2288
  function NavSidebar({
2154
2289
  pathname,
2155
2290
  brand,
@@ -2159,9 +2294,13 @@ function NavSidebar({
2159
2294
  footer,
2160
2295
  linkComponent,
2161
2296
  open,
2162
- onClose
2297
+ onClose,
2298
+ onOpen,
2299
+ onNavigate
2163
2300
  }) {
2164
2301
  const Link = linkComponent ?? DefaultLink;
2302
+ const collapsible = !open;
2303
+ const rc = (cls) => collapsible ? cls : "";
2165
2304
  const asideRef = react.useRef(null);
2166
2305
  const closeButtonRef = react.useRef(null);
2167
2306
  const previouslyFocusedRef = react.useRef(null);
@@ -2228,12 +2367,12 @@ function NavSidebar({
2228
2367
  setOpenGroup(activeGroupKey);
2229
2368
  }, [activeGroupKey]);
2230
2369
  const toggleGroup = (key) => setOpenGroup((prev) => prev === key ? null : key);
2231
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2370
+ return /* @__PURE__ */ jsxRuntime.jsxs(RailCollapsibleContext.Provider, { value: collapsible, children: [
2232
2371
  open ? /* @__PURE__ */ jsxRuntime.jsx(
2233
2372
  "div",
2234
2373
  {
2235
2374
  "aria-hidden": true,
2236
- className: "fixed inset-0 z-40 bg-black/40 lg:hidden",
2375
+ className: "fixed inset-0 z-40 bg-black/40 md:hidden",
2237
2376
  onClick: onClose
2238
2377
  }
2239
2378
  ) : null,
@@ -2246,13 +2385,15 @@ function NavSidebar({
2246
2385
  "aria-modal": open ? "true" : void 0,
2247
2386
  "aria-label": open ? "Navigation" : void 0,
2248
2387
  className: clsx__default.default(
2249
- "fixed inset-y-0 left-0 w-[var(--sidebar-width,236px)] flex-col border-r border-[color:var(--sidebar-line,var(--line))] bg-[color:var(--sidebar-bg,var(--nav-surface))] lg:flex",
2250
- open ? "flex z-50" : "hidden z-30"
2388
+ "fixed inset-y-0 left-0 flex flex-col border-r border-[color:var(--sidebar-line,var(--line))] bg-[color:var(--sidebar-bg,var(--nav-surface))]",
2389
+ // Never hidden: the 64px icon rail below `md`, the full rail from
2390
+ // `md` up, and the full rail as a drawer when expanded below `md`.
2391
+ open ? "z-50 w-[var(--sidebar-width,236px)]" : "z-30 w-[var(--sidebar-collapsed-width,64px)] md:w-[var(--sidebar-width,236px)]"
2251
2392
  ),
2252
2393
  style: { fontFamily: 'var(--font-family, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif)' },
2253
2394
  onKeyDown: trapTab,
2254
2395
  onClick: (e) => {
2255
- if (open && e.target.closest("a[href]")) onClose?.();
2396
+ if (open && e.target.closest("a[href]")) (onNavigate ?? onClose)?.();
2256
2397
  },
2257
2398
  children: [
2258
2399
  open ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -2261,37 +2402,75 @@ function NavSidebar({
2261
2402
  type: "button",
2262
2403
  ref: closeButtonRef,
2263
2404
  onClick: onClose,
2264
- "aria-label": "Close menu",
2265
- className: "absolute right-3 top-3 flex h-8 w-8 items-center justify-center rounded-full text-[color:var(--muted)] transition hover:bg-[color:var(--panel-elevated)] hover:text-[color:var(--foreground)] lg:hidden",
2405
+ "aria-label": "Collapse navigation",
2406
+ className: "absolute right-3 top-3 flex h-8 w-8 items-center justify-center rounded-full text-[color:var(--muted)] transition hover:bg-[color:var(--panel-elevated)] hover:text-[color:var(--foreground)] md:hidden",
2266
2407
  children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
2267
2408
  }
2268
2409
  ) : null,
2269
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 flex-col gap-[14px] border-b border-[color:var(--sidebar-line,var(--line))] px-[18px] py-4", children: [
2270
- /* @__PURE__ */ jsxRuntime.jsx(
2410
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-shrink-0 flex-col gap-[14px] border-b border-[color:var(--sidebar-line,var(--line))] px-[18px] py-4 ${rc("max-md:items-center max-md:px-[10px]")}`, children: [
2411
+ onOpen ? /* @__PURE__ */ jsxRuntime.jsx(
2412
+ "button",
2413
+ {
2414
+ type: "button",
2415
+ onClick: onOpen,
2416
+ "aria-label": "Expand navigation",
2417
+ "aria-expanded": open ?? false,
2418
+ "data-rail-toggle": "expand",
2419
+ className: `hidden h-8 w-8 items-center justify-center rounded-lg ${rc("max-md:flex")}`,
2420
+ children: brand.logoSquareSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: brand.logoSquareSrc, alt: "", draggable: false, className: "h-8 w-8 object-contain" }) : brand.logoPending ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "block h-8 w-8" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-8 w-8 items-center justify-center rounded-xl bg-[color:var(--color-accent)] text-sm font-black text-[#FFFFFF]", children: brand.badgeLabel })
2421
+ }
2422
+ ) : null,
2423
+ /* @__PURE__ */ jsxRuntime.jsxs(
2271
2424
  Link,
2272
2425
  {
2273
2426
  href: brand.homeHref ?? "/",
2274
- className: "flex items-center gap-2.5",
2275
- children: brand.logoSrc ? /* @__PURE__ */ jsxRuntime.jsx(
2276
- "img",
2277
- {
2278
- src: brand.logoSrc,
2279
- alt: brand.logoAlt ?? brand.title,
2280
- draggable: false,
2281
- className: "h-[var(--sidebar-brand-logo-height,24px)] w-auto object-contain"
2282
- }
2283
- ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2284
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-9 w-9 items-center justify-center rounded-xl bg-[color:var(--color-accent)] text-base font-black text-[#FFFFFF] shadow-sm", children: brand.badgeLabel }),
2285
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-col leading-tight", children: [
2286
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-extrabold tracking-[-0.01em] text-[color:var(--color-accent)]", children: brand.title }),
2287
- brand.subtitle ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-semibold uppercase tracking-[0.16em] text-[color:var(--muted)]", children: brand.subtitle }) : null
2427
+ "aria-label": brand.logoAlt ?? brand.title,
2428
+ className: `flex items-center gap-2.5 ${rc("max-md:justify-center")} ${onOpen ? rc("max-md:hidden") : ""}`,
2429
+ children: [
2430
+ brand.logoSquareSrc ? /* @__PURE__ */ jsxRuntime.jsx(
2431
+ "img",
2432
+ {
2433
+ src: brand.logoSquareSrc,
2434
+ alt: "",
2435
+ draggable: false,
2436
+ "data-rail-logo": "square",
2437
+ className: `hidden h-8 w-8 object-contain ${rc("max-md:block")}`
2438
+ }
2439
+ ) : brand.logoPending ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: `hidden h-8 w-8 ${rc("max-md:block")}` }) : null,
2440
+ brand.logoSrc ? /* @__PURE__ */ jsxRuntime.jsx(
2441
+ "img",
2442
+ {
2443
+ src: brand.logoSrc,
2444
+ alt: brand.logoAlt ?? brand.title,
2445
+ draggable: false,
2446
+ "data-rail-logo": "horizontal",
2447
+ className: `h-[var(--sidebar-brand-logo-height,24px)] w-auto object-contain ${rc("max-md:hidden")}`
2448
+ }
2449
+ ) : brand.logoPending ? /* @__PURE__ */ jsxRuntime.jsx(
2450
+ "span",
2451
+ {
2452
+ "aria-hidden": true,
2453
+ className: `block h-[var(--sidebar-brand-logo-height,24px)] ${rc("max-md:hidden")}`
2454
+ }
2455
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2456
+ /* @__PURE__ */ jsxRuntime.jsx(
2457
+ "span",
2458
+ {
2459
+ className: `flex h-9 w-9 items-center justify-center rounded-xl bg-[color:var(--color-accent)] text-base font-black text-[#FFFFFF] shadow-sm ${brand.logoSquareSrc ? rc("max-md:hidden") : ""}`,
2460
+ children: brand.badgeLabel
2461
+ }
2462
+ ),
2463
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `flex flex-col leading-tight ${rc("max-md:hidden")}`, children: [
2464
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-extrabold tracking-[-0.01em] text-[color:var(--color-accent)]", children: brand.title }),
2465
+ brand.subtitle ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-semibold uppercase tracking-[0.16em] text-[color:var(--muted)]", children: brand.subtitle }) : null
2466
+ ] })
2288
2467
  ] })
2289
- ] })
2468
+ ]
2290
2469
  }
2291
2470
  ),
2292
- org ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2293
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-[7px] flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: NAV_EYEBROW_CLASS, children: "Organization" }) }),
2294
- org.loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-2.5 rounded-md border border-[color:var(--line)] bg-[color:var(--panel-elevated)] px-2.5 py-2 shadow-sm", children: [
2471
+ org ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: rc("max-md:flex max-md:justify-center"), children: [
2472
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `mb-[7px] flex items-center justify-between ${rc("max-md:hidden")}`, children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: NAV_EYEBROW_CLASS, children: "Organization" }) }),
2473
+ org.loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex w-full items-center gap-2.5 rounded-md border border-[color:var(--line)] bg-[color:var(--panel-elevated)] px-2.5 py-2 shadow-sm ${rc("max-md:w-auto max-md:border-0 max-md:bg-transparent max-md:p-0 max-md:shadow-none")}`, children: [
2295
2474
  /* @__PURE__ */ jsxRuntime.jsx(
2296
2475
  "span",
2297
2476
  {
@@ -2303,7 +2482,7 @@ function NavSidebar({
2303
2482
  "span",
2304
2483
  {
2305
2484
  "aria-hidden": true,
2306
- className: "h-4 flex-1 animate-pulse rounded bg-[color:var(--panel)]"
2485
+ className: `h-4 flex-1 animate-pulse rounded bg-[color:var(--panel)] ${rc("max-md:hidden")}`
2307
2486
  }
2308
2487
  ),
2309
2488
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading organization" })
@@ -2312,9 +2491,11 @@ function NavSidebar({
2312
2491
  "summary",
2313
2492
  {
2314
2493
  style: orgCardStyle,
2315
- className: "flex w-full cursor-pointer list-none flex-col overflow-hidden rounded-[5px] border border-[color:var(--sidebar-card-border,var(--sidebar-line,var(--line)))] bg-[color:var(--sidebar-card-bg,var(--panel-elevated))] text-left text-[color:var(--sidebar-text,var(--foreground))] transition hover:bg-[color:var(--sidebar-row-hover-bg,var(--panel))] [&::-webkit-details-marker]:hidden",
2494
+ title: org.name ?? void 0,
2495
+ className: `flex w-full cursor-pointer list-none flex-col overflow-hidden rounded-[5px] border border-[color:var(--sidebar-card-border,var(--sidebar-line,var(--line)))] bg-[color:var(--sidebar-card-bg,var(--panel-elevated))] text-left text-[color:var(--sidebar-text,var(--foreground))] transition hover:bg-[color:var(--sidebar-row-hover-bg,var(--panel))] [&::-webkit-details-marker]:hidden ${rc("max-md:w-auto max-md:items-center max-md:overflow-visible max-md:border-0 max-md:bg-transparent")}`,
2316
2496
  children: [
2317
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-[var(--sidebar-org-band-height,48px)] w-full items-center justify-center bg-[#FFFFFF] px-3 py-[7px]", children: [
2497
+ /* @__PURE__ */ jsxRuntime.jsx(OrgIconMark, { org, logoSrc: orgLogoSrc }),
2498
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `relative flex h-[var(--sidebar-org-band-height,48px)] w-full items-center justify-center bg-[#FFFFFF] px-3 py-[7px] ${rc("max-md:hidden")}`, children: [
2318
2499
  orgLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: orgLogoSrc, alt: "", className: "max-h-full max-w-[132px] object-contain" }) : org.canUploadLogo ? /* @__PURE__ */ jsxRuntime.jsx(
2319
2500
  "a",
2320
2501
  {
@@ -2326,7 +2507,7 @@ function NavSidebar({
2326
2507
  ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-semibold text-neutral-800", children: org.name ?? "Organization" }),
2327
2508
  /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute inset-x-0 bottom-0 h-[3px]", style: { backgroundImage: orgGradient } })
2328
2509
  ] }),
2329
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex w-full min-w-0 items-center justify-between gap-[9px] px-[10px] py-2", children: [
2510
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `flex w-full min-w-0 items-center justify-between gap-[9px] px-[10px] py-2 ${rc("max-md:hidden")}`, children: [
2330
2511
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
2331
2512
  /* @__PURE__ */ jsxRuntime.jsx(
2332
2513
  "span",
@@ -2343,7 +2524,7 @@ function NavSidebar({
2343
2524
  ]
2344
2525
  }
2345
2526
  ),
2346
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-0 right-0 z-40 mt-1 max-h-[min(60vh,520px)] overflow-y-auto rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]", children: [
2527
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `absolute left-0 right-0 z-40 mt-1 max-h-[min(60vh,520px)] overflow-y-auto rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)] ${rc("max-md:right-auto max-md:w-[236px]")}`, children: [
2347
2528
  shouldShowOrgFilter(org.organizations.length) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10 bg-[color:var(--panel-elevated)] px-2 pb-1 pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(
2348
2529
  "input",
2349
2530
  {
@@ -2412,9 +2593,11 @@ function NavSidebar({
2412
2593
  type: "button",
2413
2594
  onClick: org.onClick,
2414
2595
  style: orgCardStyle,
2415
- className: "flex w-full flex-col overflow-hidden rounded-[5px] border border-[color:var(--sidebar-card-border,var(--sidebar-line,var(--line)))] bg-[color:var(--sidebar-card-bg,var(--panel-elevated))] text-left text-[color:var(--sidebar-text,var(--foreground))] transition hover:bg-[color:var(--sidebar-row-hover-bg,var(--panel))]",
2596
+ title: org.name ?? void 0,
2597
+ className: `flex w-full flex-col overflow-hidden rounded-[5px] border border-[color:var(--sidebar-card-border,var(--sidebar-line,var(--line)))] bg-[color:var(--sidebar-card-bg,var(--panel-elevated))] text-left text-[color:var(--sidebar-text,var(--foreground))] transition hover:bg-[color:var(--sidebar-row-hover-bg,var(--panel))] ${rc("max-md:w-auto max-md:items-center max-md:overflow-visible max-md:border-0 max-md:bg-transparent")}`,
2416
2598
  children: [
2417
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-[var(--sidebar-org-band-height,48px)] w-full items-center justify-center bg-[#FFFFFF] px-3 py-[7px]", children: [
2599
+ /* @__PURE__ */ jsxRuntime.jsx(OrgIconMark, { org, logoSrc: orgLogoSrc }),
2600
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `relative flex h-[var(--sidebar-org-band-height,48px)] w-full items-center justify-center bg-[#FFFFFF] px-3 py-[7px] ${rc("max-md:hidden")}`, children: [
2418
2601
  orgLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: orgLogoSrc, alt: "", className: "max-h-full max-w-[132px] object-contain" }) : org.canUploadLogo ? /* @__PURE__ */ jsxRuntime.jsx(
2419
2602
  "a",
2420
2603
  {
@@ -2426,7 +2609,7 @@ function NavSidebar({
2426
2609
  ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-semibold text-neutral-800", children: org.name ?? "Organization" }),
2427
2610
  /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute inset-x-0 bottom-0 h-[3px]", style: { backgroundImage: orgGradient } })
2428
2611
  ] }),
2429
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex w-full min-w-0 items-center justify-between gap-[9px] px-[10px] py-2", children: [
2612
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `flex w-full min-w-0 items-center justify-between gap-[9px] px-[10px] py-2 ${rc("max-md:hidden")}`, children: [
2430
2613
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
2431
2614
  /* @__PURE__ */ jsxRuntime.jsx(
2432
2615
  "span",
@@ -2444,13 +2627,13 @@ function NavSidebar({
2444
2627
  }
2445
2628
  )
2446
2629
  ] }) : null,
2447
- mode ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2630
+ mode ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: rc("max-md:w-full"), children: [
2448
2631
  /* @__PURE__ */ jsxRuntime.jsx(
2449
2632
  "div",
2450
2633
  {
2451
2634
  role: "radiogroup",
2452
2635
  "aria-label": "Mode",
2453
- className: "flex w-full items-center gap-1 rounded-lg border border-[color:var(--border-inverse,var(--sidebar-line,var(--line)))] bg-[color:var(--mode-track-bg,var(--panel-elevated))] p-[3px]",
2636
+ className: `flex w-full items-center gap-1 rounded-lg border border-[color:var(--border-inverse,var(--sidebar-line,var(--line)))] bg-[color:var(--mode-track-bg,var(--panel-elevated))] p-[3px] ${rc("max-md:flex-col max-md:items-stretch")}`,
2454
2637
  children: (mode.options && mode.options.length > 0 ? mode.options : [{ id: mode.label, label: mode.label, icon: ModeIcon }]).map(
2455
2638
  (opt) => {
2456
2639
  const selected = opt.label === mode.label;
@@ -2482,11 +2665,11 @@ function NavSidebar({
2482
2665
  )
2483
2666
  }
2484
2667
  ),
2485
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1.5 text-left text-[11px] leading-[1.2] text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))]", children: modeCaption(mode.label) })
2668
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: `mt-1.5 text-left text-[11px] leading-[1.2] text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))] ${rc("max-md:hidden")}`, children: modeCaption(mode.label) })
2486
2669
  ] }) : null
2487
2670
  ] }),
2488
2671
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-col overflow-y-auto px-[10px] py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("nav", { className: "flex flex-col gap-0.5", children: [
2489
- nav.groupLabel ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: `${NAV_EYEBROW_CLASS} px-2 pb-1.5 pt-1`, children: nav.groupLabel }) : null,
2672
+ nav.groupLabel ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: `${NAV_EYEBROW_CLASS} px-2 pb-1.5 pt-1 ${rc("max-md:hidden")}`, children: nav.groupLabel }) : null,
2490
2673
  nav.items.map((item, idx) => {
2491
2674
  if (item.kind === "section") {
2492
2675
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -2552,7 +2735,7 @@ function NavSidebar({
2552
2735
  );
2553
2736
  })
2554
2737
  ] }) }),
2555
- footer ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-shrink-0 border-t border-[color:var(--sidebar-line,var(--line))] px-[14px] py-3", children: [
2738
+ footer ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative flex-shrink-0 border-t border-[color:var(--sidebar-line,var(--line))] px-[14px] py-3 ${rc("max-md:px-[10px]")}`, children: [
2556
2739
  footer.user ? /* @__PURE__ */ jsxRuntime.jsx(
2557
2740
  NavSidebarUserCard,
2558
2741
  {
@@ -2561,7 +2744,7 @@ function NavSidebar({
2561
2744
  onSignOut: footer.onSignOut
2562
2745
  }
2563
2746
  ) : null,
2564
- footer.links && footer.links.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex flex-wrap items-center gap-[10px] text-[11px] leading-[1.2] ${footer.user ? "mt-3" : ""}`, children: footer.links.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
2747
+ footer.links && footer.links.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex flex-wrap items-center gap-[10px] text-[11px] leading-[1.2] ${footer.user ? "mt-3" : ""} ${rc("max-md:hidden")}`, children: footer.links.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
2565
2748
  "a",
2566
2749
  {
2567
2750
  href: safeHref(l.href),
@@ -2574,7 +2757,7 @@ function NavSidebar({
2574
2757
  "div",
2575
2758
  {
2576
2759
  "data-shell-meta": true,
2577
- className: "mt-1.5 flex flex-col items-start gap-0.5 font-[family-name:var(--font-plex-mono)] text-[10px] text-[color:var(--sidebar-meta-text,var(--sidebar-text))]",
2760
+ className: `mt-1.5 flex flex-col items-start gap-0.5 font-[family-name:var(--font-plex-mono)] text-[10px] text-[color:var(--sidebar-meta-text,var(--sidebar-text))] ${rc("max-md:hidden")}`,
2578
2761
  children: [
2579
2762
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
2580
2763
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2737,21 +2920,27 @@ function NavActiveRail() {
2737
2920
  );
2738
2921
  }
2739
2922
  function NavRowBadge({ value }) {
2923
+ const rc = useRailCollapse();
2740
2924
  if (value === void 0 || value === null || value === "") return null;
2741
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto shrink-0 font-[family-name:var(--font-plex-mono,ui-monospace,monospace)] text-[11px] font-semibold leading-none text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))]", children: value });
2925
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `ml-auto shrink-0 font-[family-name:var(--font-plex-mono,ui-monospace,monospace)] text-[11px] font-semibold leading-none text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))] ${rc("max-md:hidden")}`, children: value });
2742
2926
  }
2743
2927
  function NavSectionRow({
2744
2928
  label,
2745
2929
  first,
2746
2930
  variant = "top"
2747
2931
  }) {
2932
+ const rc = useRailCollapse();
2933
+ const collapsed = variant === "sub" ? "" : first ? rc("max-md:sr-only") : rc(
2934
+ "max-md:mx-2 max-md:my-2 max-md:h-px max-md:overflow-hidden max-md:bg-[color:var(--sidebar-line,var(--line))] max-md:p-0 max-md:text-transparent"
2935
+ );
2748
2936
  return /* @__PURE__ */ jsxRuntime.jsx(
2749
2937
  "p",
2750
2938
  {
2751
2939
  className: [
2752
2940
  NAV_EYEBROW_CLASS,
2753
2941
  variant === "sub" ? "px-3 pb-0.5" : "px-2 pb-1.5 pt-1",
2754
- first ? "" : variant === "sub" ? "mt-3" : "mt-[14px]"
2942
+ first ? "" : variant === "sub" ? "mt-3" : "mt-[14px]",
2943
+ collapsed
2755
2944
  ].join(" "),
2756
2945
  children: label
2757
2946
  }
@@ -2763,6 +2952,7 @@ function NavRow({
2763
2952
  Link,
2764
2953
  variant = "top"
2765
2954
  }) {
2955
+ const rc = useRailCollapse();
2766
2956
  const Icon = item.icon;
2767
2957
  const isSub = variant === "sub";
2768
2958
  const washActive = variant !== "top";
@@ -2788,9 +2978,12 @@ function NavRow({
2788
2978
  }
2789
2979
  ) : null
2790
2980
  ) : /* @__PURE__ */ jsxRuntime.jsx(NavActiveRail, {}),
2791
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `relative z-10 flex items-center ${rowPadding}`, children: [
2792
- Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: iconSize, className: `shrink-0 ${iconClass}` }) : null,
2793
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: item.label }),
2981
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `relative z-10 flex items-center ${rowPadding} ${rc("max-md:justify-center max-md:px-0")}`, children: [
2982
+ Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: iconSize, className: `shrink-0 ${iconClass}` }) : (
2983
+ // A row with no glyph still needs something on the icon rail.
2984
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: `hidden text-[11px] font-semibold uppercase ${rc("max-md:inline")}`, children: item.label.slice(0, 2) })
2985
+ ),
2986
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `min-w-0 flex-1 truncate ${rc("max-md:hidden")}`, children: item.label }),
2794
2987
  /* @__PURE__ */ jsxRuntime.jsx(NavRowBadge, { value: item.badge })
2795
2988
  ] })
2796
2989
  ] });
@@ -2799,20 +2992,30 @@ function NavRow({
2799
2992
  "span",
2800
2993
  {
2801
2994
  "aria-disabled": "true",
2802
- title: item.disabledTitle,
2995
+ title: item.disabledTitle ?? item.label,
2803
2996
  className: `${wrapperClasses} cursor-not-allowed opacity-50`,
2804
2997
  children: inner
2805
2998
  }
2806
2999
  );
2807
3000
  }
2808
3001
  if (item.onClick && !item.href) {
2809
- return /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: item.onClick, className: `w-full text-left ${wrapperClasses}`, children: inner });
3002
+ return /* @__PURE__ */ jsxRuntime.jsx(
3003
+ "button",
3004
+ {
3005
+ type: "button",
3006
+ onClick: item.onClick,
3007
+ title: item.label,
3008
+ className: `w-full text-left ${wrapperClasses}`,
3009
+ children: inner
3010
+ }
3011
+ );
2810
3012
  }
2811
3013
  return /* @__PURE__ */ jsxRuntime.jsx(
2812
3014
  Link,
2813
3015
  {
2814
3016
  href: item.href ?? "#",
2815
3017
  "aria-current": active ? "page" : void 0,
3018
+ title: item.label,
2816
3019
  className: wrapperClasses,
2817
3020
  children: inner
2818
3021
  }
@@ -2827,6 +3030,7 @@ function NavGroup({
2827
3030
  activeFn,
2828
3031
  Link
2829
3032
  }) {
3033
+ const rc = useRailCollapse();
2830
3034
  const Icon = item.icon;
2831
3035
  const headerClasses = [
2832
3036
  "group relative block w-full overflow-hidden text-left transition",
@@ -2843,19 +3047,21 @@ function NavGroup({
2843
3047
  item.onClick?.();
2844
3048
  },
2845
3049
  "aria-expanded": open,
3050
+ title: item.label,
2846
3051
  className: headerClasses,
2847
3052
  children: [
2848
3053
  active ? /* @__PURE__ */ jsxRuntime.jsx(NavActiveRail, {}) : null,
2849
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `relative z-10 flex items-center ${NAV_TOP_ROW_CLASS(active)}`, children: [
3054
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `relative z-10 flex items-center ${NAV_TOP_ROW_CLASS(active)} ${rc("max-md:justify-center max-md:px-0")}`, children: [
2850
3055
  Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: NAV_TOP_ICON_SIZE, className: "shrink-0 text-current" }) : null,
2851
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: item.label }),
3056
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `min-w-0 flex-1 truncate ${rc("max-md:hidden")}`, children: item.label }),
2852
3057
  /* @__PURE__ */ jsxRuntime.jsx(NavRowBadge, { value: item.badge }),
2853
3058
  /* @__PURE__ */ jsxRuntime.jsx(
2854
3059
  ChevronDown,
2855
3060
  {
2856
3061
  className: [
2857
3062
  "shrink-0 opacity-80 transition-transform duration-200",
2858
- open ? "rotate-180" : ""
3063
+ open ? "rotate-180" : "",
3064
+ rc("max-md:hidden")
2859
3065
  ].join(" ")
2860
3066
  }
2861
3067
  )
@@ -2863,7 +3069,7 @@ function NavGroup({
2863
3069
  ]
2864
3070
  }
2865
3071
  ),
2866
- open ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-b-md bg-[color:var(--nav-submenu-bg)] p-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-0.5", children: item.children.map((child, i) => {
3072
+ open ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: `overflow-hidden rounded-b-md bg-[color:var(--nav-submenu-bg)] p-1 ${rc("max-md:hidden")}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-0.5", children: item.children.map((child, i) => {
2867
3073
  if (child.kind === "section") {
2868
3074
  return /* @__PURE__ */ jsxRuntime.jsx(
2869
3075
  NavSectionRow,
@@ -2993,7 +3199,7 @@ function NavTopBar({
2993
3199
  const initials = (hasRealName ? rawName : user?.email ?? "P").slice(0, 2).toUpperCase();
2994
3200
  const secondary = hasRealName ? user?.email || [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member" : [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member";
2995
3201
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-0 z-20", children: [
2996
- /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex h-[var(--topbar-height,60px)] items-center justify-between gap-[14px] border-b border-[color:var(--line)] bg-[color:var(--panel)] px-[var(--topbar-padding-x,20px)]", children: [
3202
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex min-w-0 h-[var(--topbar-height,60px)] items-center justify-between gap-[8px] md:gap-[14px] border-b border-[color:var(--line)] bg-[color:var(--panel)] px-[var(--topbar-padding-x,20px)]", children: [
2997
3203
  onOpenNav ? /* @__PURE__ */ jsxRuntime.jsx(
2998
3204
  "button",
2999
3205
  {
@@ -3002,11 +3208,11 @@ function NavTopBar({
3002
3208
  "aria-label": "Open menu",
3003
3209
  "aria-expanded": navOpen ?? false,
3004
3210
  "aria-controls": "politogy-nav-drawer",
3005
- className: `${topBarIconButtonClass("default")} mr-1 shrink-0 lg:hidden`,
3211
+ className: `${topBarIconButtonClass("default")} mr-1 shrink-0 md:hidden`,
3006
3212
  children: /* @__PURE__ */ jsxRuntime.jsx(HamburgerIcon, {})
3007
3213
  }
3008
3214
  ) : null,
3009
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "relative flex h-9 w-[320px] max-w-full shrink-0 items-center", children: [
3215
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "relative flex h-9 w-[320px] min-w-0 max-w-full shrink items-center md:shrink-0", children: [
3010
3216
  /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { className: "pointer-events-none absolute left-[10px] h-[15px] w-[15px] text-[color:var(--muted)]" }),
3011
3217
  /* @__PURE__ */ jsxRuntime.jsx(
3012
3218
  "input",
@@ -3026,13 +3232,13 @@ function NavTopBar({
3026
3232
  "kbd",
3027
3233
  {
3028
3234
  "aria-hidden": true,
3029
- className: "pointer-events-none absolute right-[10px] rounded-[3px] border border-[color:var(--line)] px-[5px] py-px font-[family-name:var(--font-plex-mono,ui-monospace,monospace)] text-[12px] leading-[1.2] text-[color:var(--muted)]",
3235
+ className: "pointer-events-none absolute right-[10px] hidden md:block rounded-[3px] border border-[color:var(--line)] px-[5px] py-px font-[family-name:var(--font-plex-mono,ui-monospace,monospace)] text-[12px] leading-[1.2] text-[color:var(--muted)]",
3030
3236
  children: "/"
3031
3237
  }
3032
3238
  )
3033
3239
  ] }),
3034
3240
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative ml-auto flex shrink-0 items-center gap-[var(--topbar-icon-gap,8px)]", children: [
3035
- /* @__PURE__ */ jsxRuntime.jsxs(
3241
+ buildNotes ? /* @__PURE__ */ jsxRuntime.jsxs(
3036
3242
  "button",
3037
3243
  {
3038
3244
  type: "button",
@@ -3043,7 +3249,7 @@ function NavTopBar({
3043
3249
  buildNotes?.label ?? "Build notes"
3044
3250
  ]
3045
3251
  }
3046
- ),
3252
+ ) : null,
3047
3253
  actionsList && actionsList.length > 0 ? actionsList.map((action) => /* @__PURE__ */ jsxRuntime.jsx(NavTopBarActionButton, { action }, action.key)) : null,
3048
3254
  actions,
3049
3255
  themeToggle,
@@ -3100,7 +3306,8 @@ function NavAccountMenuPanel({
3100
3306
  onSignOut,
3101
3307
  placement
3102
3308
  }) {
3103
- const wrapper = placement === "above" ? "absolute bottom-full left-0 right-0 z-40 mb-2 flex max-h-[calc(100vh-5rem)] flex-col overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 text-[color:var(--foreground)] shadow-[var(--shadow-soft)]" : "absolute right-0 z-30 mt-2 flex max-h-[calc(100vh-5rem)] w-72 flex-col overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]";
3309
+ const rc = useRailCollapse();
3310
+ const wrapper = placement === "above" ? rc("max-md:right-auto max-md:w-64") + " absolute bottom-full left-0 right-0 z-40 mb-2 flex max-h-[calc(100vh-5rem)] flex-col overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 text-[color:var(--foreground)] shadow-[var(--shadow-soft)]" : "absolute right-0 z-30 mt-2 flex max-h-[calc(100vh-5rem)] w-72 flex-col overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]";
3104
3311
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: wrapper, children: [
3105
3312
  placement === "below" ? /* @__PURE__ */ jsxRuntime.jsx(TopBarPanelArrow, {}) : null,
3106
3313
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto overscroll-contain", children: [
@@ -3252,19 +3459,20 @@ function NavSidebarUserCard({
3252
3459
  const displayName = hasRealName ? rawName : user.email ?? "Signed in";
3253
3460
  const initials = (hasRealName ? rawName : user.email ?? "P").slice(0, 2).toUpperCase();
3254
3461
  const secondary = hasRealName ? user.email || [user.tier, user.role].filter(Boolean).join(" \xB7 ") || "member" : [user.tier, user.role].filter(Boolean).join(" \xB7 ") || "member";
3462
+ const rc = useRailCollapse();
3255
3463
  return /* @__PURE__ */ jsxRuntime.jsxs("details", { "data-nav-details": true, className: "group/acct relative", children: [
3256
3464
  /* @__PURE__ */ jsxRuntime.jsxs(
3257
3465
  "summary",
3258
3466
  {
3259
3467
  "aria-label": "My Account",
3260
- className: "flex w-full cursor-pointer list-none items-center gap-[9px] rounded-[5px] px-1 py-1 text-left transition hover:bg-[color:var(--sidebar-row-hover-bg,var(--panel-elevated))] [&::-webkit-details-marker]:hidden",
3468
+ className: `flex w-full cursor-pointer list-none items-center gap-[9px] rounded-[5px] px-1 py-1 text-left transition hover:bg-[color:var(--sidebar-row-hover-bg,var(--panel-elevated))] [&::-webkit-details-marker]:hidden ${rc("max-md:justify-center max-md:px-0")}`,
3261
3469
  children: [
3262
3470
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-full bg-[color:var(--sidebar-avatar-bg,var(--color-accent))] text-[11px] font-bold text-[#FFFFFF]", children: user.avatarUrl || user.memojiUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: user.avatarUrl || user.memojiUrl, alt: "", className: "h-full w-full object-cover" }) : initials }),
3263
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [
3471
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `flex min-w-0 flex-1 flex-col ${rc("max-md:hidden")}`, children: [
3264
3472
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[12px] font-semibold leading-[1.2] text-[color:var(--sidebar-text,var(--foreground))]", children: displayName }),
3265
3473
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[11px] leading-[1.3] text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))]", children: secondary })
3266
3474
  ] }),
3267
- /* @__PURE__ */ jsxRuntime.jsx(ChevronDown, { size: 14, className: "shrink-0 rotate-180 text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))] transition group-open/acct:rotate-0" })
3475
+ /* @__PURE__ */ jsxRuntime.jsx(ChevronDown, { size: 14, className: `shrink-0 rotate-180 text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))] transition group-open/acct:rotate-0 ${rc("max-md:hidden")}` })
3268
3476
  ]
3269
3477
  }
3270
3478
  ),
@@ -3525,10 +3733,29 @@ function NavAppShell({
3525
3733
  children
3526
3734
  }) {
3527
3735
  useCloseNavDetailsOnOutsideClick();
3736
+ if (contentWrapper === "bare") {
3737
+ warnDeprecated(
3738
+ "contentWrapper",
3739
+ "`contentWrapper: 'bare'` is deprecated: the frame's <main> is fluid and apps must not emit their own page container. Remove the app's PageContainer and drop the prop."
3740
+ );
3741
+ }
3528
3742
  const [navOpen, setNavOpen] = react.useState(false);
3743
+ const expandRail = () => {
3744
+ writeRailPreference("expanded");
3745
+ setNavOpen(true);
3746
+ };
3747
+ const collapseRail = () => {
3748
+ writeRailPreference("collapsed");
3749
+ setNavOpen(false);
3750
+ };
3529
3751
  react.useEffect(() => {
3530
3752
  setNavOpen(false);
3531
3753
  }, [sidebar.pathname]);
3754
+ react.useEffect(() => {
3755
+ if (readRailPreference() !== "expanded") return;
3756
+ const narrow = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(max-width: 767.98px)").matches : false;
3757
+ if (narrow) setNavOpen(true);
3758
+ }, []);
3532
3759
  react.useEffect(() => {
3533
3760
  if (!navOpen) return;
3534
3761
  const previous = document.body.style.overflow;
@@ -3549,31 +3776,41 @@ function NavAppShell({
3549
3776
  "data-politogy-mode": modeId,
3550
3777
  className: "min-h-screen bg-[color:var(--background)] text-[color:var(--foreground)]",
3551
3778
  children: [
3552
- /* @__PURE__ */ jsxRuntime.jsx(NavSidebar, { ...sidebar, footer: sidebarFooter, open: navOpen, onClose: () => setNavOpen(false) }),
3553
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lg:pl-[var(--sidebar-width,236px)]", children: [
3779
+ /* @__PURE__ */ jsxRuntime.jsx(
3780
+ NavSidebar,
3781
+ {
3782
+ ...sidebar,
3783
+ footer: sidebarFooter,
3784
+ open: navOpen,
3785
+ onClose: collapseRail,
3786
+ onOpen: expandRail,
3787
+ onNavigate: () => setNavOpen(false)
3788
+ }
3789
+ ),
3790
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pl-[var(--sidebar-collapsed-width,64px)] md:pl-[var(--sidebar-width,236px)]", children: [
3554
3791
  /* @__PURE__ */ jsxRuntime.jsx(
3555
3792
  NavTopBar,
3556
3793
  {
3557
3794
  ...topBar,
3558
- accountMenu: topBar.accountMenu ?? (accountMenuPlacement === "sidebar" ? "sidebar" : "topbar"),
3559
- onOpenNav: () => setNavOpen(true),
3560
- navOpen
3795
+ accountMenu: topBar.accountMenu ?? (accountMenuPlacement === "sidebar" ? "sidebar" : "topbar")
3561
3796
  }
3562
3797
  ),
3563
3798
  betaBanner ? /* @__PURE__ */ jsxRuntime.jsx(NavBetaBanner, { ...betaBanner }) : null,
3564
- topBar.title ? /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "px-6 pt-7 text-xl font-semibold text-[color:var(--foreground)]", children: topBar.title }) : null,
3799
+ topBar.title ? /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "px-4 pt-7 text-xl font-semibold text-[color:var(--foreground)] md:px-6", children: topBar.title }) : null,
3565
3800
  contentWrapper === "bare" ? /* @__PURE__ */ jsxRuntime.jsx("div", { "data-shell-content": "", className: topBar.title ? "mt-[22px]" : void 0, children }) : (
3566
- // Claude Design: "a rounded, inset frame on a light-grey page
3567
- // background" — the shell owns the page background and the
3568
- // gutter; it does not draw a hard border/box around the content
3569
- // (that reads as a second frame on top of the page header). An
3570
- // app's own cards are its own furniture and stay app-owned.
3801
+ // Brand guidelines "Content width is fluid" + "Content body
3802
+ // padding": `<main>` fills the space beside the rail with ONE
3803
+ // gutter — 24px, or 16px below `md`, horizontally and vertically —
3804
+ // and has no max-width and no centered container. Form and settings
3805
+ // pages constrain themselves with <FormColumn> (960px, left-aligned).
3806
+ // The shell owns the page background and the gutter; an app's own
3807
+ // cards are its own furniture and stay app-owned.
3571
3808
  /* @__PURE__ */ jsxRuntime.jsx(
3572
3809
  "main",
3573
3810
  {
3574
3811
  "data-shell-content": "",
3575
- className: `min-h-[calc(100vh-63px)] bg-[color:var(--chrome-page-bg,#F4F5F7)] px-6 ${topBar.title ? "pb-7 pt-[22px]" : "py-7"}`,
3576
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto max-w-7xl", children })
3812
+ className: `min-h-[calc(100vh-63px)] bg-[color:var(--chrome-page-bg,#F4F5F7)] px-4 pb-4 md:px-6 md:pb-6 ${topBar.title ? "pt-[22px]" : "pt-4 md:pt-6"}`,
3813
+ children
3577
3814
  }
3578
3815
  )
3579
3816
  )
@@ -3630,66 +3867,6 @@ function resolveActiveOrg(search) {
3630
3867
  return readActiveOrgCookie();
3631
3868
  }
3632
3869
 
3633
- // src/nav-preference.ts
3634
- var NAV_DISPLAY_STORAGE_KEY = "politogy_nav_display";
3635
- var NAV_DISPLAY_COOKIE = "politogy_nav_display";
3636
- var LEGACY_NAV_DISPLAY_KEY = "vrm.navDisplay";
3637
- var NAV_DISPLAY_DEFAULT = "both";
3638
- var VALID2 = ["menu", "tabs", "both"];
3639
- function isNavDisplayPreference(v) {
3640
- return typeof v === "string" && VALID2.includes(v);
3641
- }
3642
- function readNavDisplayCookie() {
3643
- if (typeof document === "undefined") return null;
3644
- try {
3645
- const m = document.cookie.match(
3646
- new RegExp(`(?:^|;\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)`)
3647
- );
3648
- const v = m ? decodeURIComponent(m[1]) : null;
3649
- return isNavDisplayPreference(v) ? v : null;
3650
- } catch {
3651
- return null;
3652
- }
3653
- }
3654
- function writeNavDisplayCookie(pref) {
3655
- if (typeof document === "undefined" || typeof window === "undefined") return;
3656
- const host = window.location.hostname;
3657
- const domainAttr = /(^|\.)politogyvrm\.com$/i.test(host) ? "; Domain=.politogyvrm.com" : "";
3658
- const secure = window.location.protocol === "https:" ? "; Secure" : "";
3659
- document.cookie = `${NAV_DISPLAY_COOKIE}=${encodeURIComponent(
3660
- pref
3661
- )}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`;
3662
- }
3663
- function readNavDisplayLocal() {
3664
- if (typeof localStorage === "undefined") return null;
3665
- try {
3666
- const current = localStorage.getItem(NAV_DISPLAY_STORAGE_KEY);
3667
- if (isNavDisplayPreference(current)) return current;
3668
- const legacy = localStorage.getItem(LEGACY_NAV_DISPLAY_KEY);
3669
- return isNavDisplayPreference(legacy) ? legacy : null;
3670
- } catch {
3671
- return null;
3672
- }
3673
- }
3674
- function writeNavDisplayLocal(pref) {
3675
- if (typeof localStorage === "undefined") return;
3676
- try {
3677
- localStorage.setItem(NAV_DISPLAY_STORAGE_KEY, pref);
3678
- } catch {
3679
- }
3680
- }
3681
- function resolveNavDisplay() {
3682
- return readNavDisplayCookie() ?? readNavDisplayLocal() ?? NAV_DISPLAY_DEFAULT;
3683
- }
3684
- `(function(){try{
3685
- var KEY=${JSON.stringify(NAV_DISPLAY_STORAGE_KEY)};
3686
- var VALID=["menu","tabs","both"];
3687
- function fromCookie(){try{var m=document.cookie.match(/(?:^|;\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)/);return m?decodeURIComponent(m[1]):null;}catch(e){return null;}}
3688
- var cookie=fromCookie();
3689
- if(cookie&&VALID.indexOf(cookie)!==-1){var ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}
3690
- if(cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}}
3691
- }catch(e){}})();`;
3692
-
3693
3870
  // src/lib/breadcrumbs.ts
3694
3871
  function deriveBreadcrumbs(items, pathname, opts) {
3695
3872
  const search = opts?.search ?? (typeof window !== "undefined" ? window.location.search : "");
@@ -4228,13 +4405,54 @@ function LoadingScreen({
4228
4405
  }
4229
4406
  );
4230
4407
  }
4408
+ function parseCssUrl(value) {
4409
+ if (!value) return null;
4410
+ const m = /^url\(\s*(['"]?)(.*?)\1\s*\)$/i.exec(value.trim());
4411
+ const url = m?.[2]?.trim();
4412
+ return url && /^https:\/\//i.test(url) ? url : null;
4413
+ }
4414
+ function readBrandAsset(kind) {
4415
+ if (typeof document === "undefined") return null;
4416
+ try {
4417
+ return parseCssUrl(
4418
+ window.getComputedStyle(document.documentElement).getPropertyValue(`--asset-${kind}`)
4419
+ );
4420
+ } catch {
4421
+ return null;
4422
+ }
4423
+ }
4424
+ var EMPTY = { logoHorizontal: null, logoSquare: null };
4425
+ var RETRY_MS = [0, 250, 1e3, 3e3];
4426
+ function useBrandAssets() {
4427
+ const [assets, setAssets] = react.useState(EMPTY);
4428
+ react.useEffect(() => {
4429
+ let done = false;
4430
+ const read = () => {
4431
+ if (done) return;
4432
+ const next = {
4433
+ logoHorizontal: readBrandAsset("logo-horizontal"),
4434
+ logoSquare: readBrandAsset("logo-square")
4435
+ };
4436
+ setAssets(
4437
+ (prev) => prev.logoHorizontal === next.logoHorizontal && prev.logoSquare === next.logoSquare ? prev : next
4438
+ );
4439
+ };
4440
+ const links = Array.from(
4441
+ document.querySelectorAll('link[rel="stylesheet"][href*="api/tokens"]')
4442
+ );
4443
+ links.forEach((l) => l.addEventListener("load", read));
4444
+ const timers = RETRY_MS.map((ms) => window.setTimeout(read, ms));
4445
+ read();
4446
+ return () => {
4447
+ done = true;
4448
+ links.forEach((l) => l.removeEventListener("load", read));
4449
+ timers.forEach((t) => window.clearTimeout(t));
4450
+ };
4451
+ }, []);
4452
+ return assets;
4453
+ }
4231
4454
  var CORE_APP = "vrm";
4232
4455
  var DEFAULT_SIGN_OUT_URL = "/auth/signout";
4233
- var DEFAULT_BRAND_LOGO = "/brand/logos/relationship-mode-logo.png";
4234
- var MODE_BRAND_LOGOS = {
4235
- petition: "/brand/logos/petition-mode-logo.svg"
4236
- };
4237
- var modeBrandLogo = (mode) => mode && MODE_BRAND_LOGOS[mode] || DEFAULT_BRAND_LOGO;
4238
4456
  var POLITOGY_APPS = {
4239
4457
  vrm: { title: "Politogy VRM", origin: "https://app.politogyvrm.com", storagePrefix: "vrm" },
4240
4458
  contacts: {
@@ -4252,13 +4470,12 @@ var POLITOGY_APPS = {
4252
4470
  origin: "https://petition-mode.politogyvrm.com",
4253
4471
  storagePrefix: "petitions",
4254
4472
  mode: "petition",
4255
- // Petitions wraps every page in its own PageContainer (which emits its own
4256
- // <main>), and its adjudication case is addressed per sheet and per line —
4257
- // a trail derived from the nav tree reads "Dashboard › Adjudication" on
4258
- // every one of those URLs and cannot name the record you are actually on.
4259
- // 'title' for the same reason: its pages have real names ("Batches"),
4260
- // where the registry can only say "Petitions".
4261
- grants: ["contentWrapper", "breadcrumbs", "title"],
4473
+ // Its adjudication case is addressed per sheet and per line — a trail
4474
+ // derived from the nav tree reads "Dashboard › Adjudication" on every one
4475
+ // of those URLs and cannot name the record you are actually on. 'title'
4476
+ // for the same reason: its pages have real names ("Batches"), where the
4477
+ // registry can only say "Petitions".
4478
+ grants: ["breadcrumbs", "title"],
4262
4479
  navShape: "flat",
4263
4480
  beta: false
4264
4481
  },
@@ -4350,6 +4567,19 @@ function FrameBody({
4350
4567
  }) {
4351
4568
  const meta = POLITOGY_APPS[app];
4352
4569
  const chrome = useChromeState();
4570
+ const brandAssets = useBrandAssets();
4571
+ if (data?.frame?.contentWrapper !== void 0) {
4572
+ warnDeprecated(
4573
+ "frame.contentWrapper",
4574
+ "`data.frame.contentWrapper` is retired and ignored: the frame's <main> is fluid. Remove the app's own page container and drop the prop."
4575
+ );
4576
+ }
4577
+ if (data?.core?.brandLogoSrc !== void 0) {
4578
+ warnDeprecated(
4579
+ "core.brandLogoSrc",
4580
+ "`data.core.brandLogoSrc` is ignored: the rail logo is read at runtime from Brand `assets.logoHorizontal`."
4581
+ );
4582
+ }
4353
4583
  const bootAppMode = meta.mode;
4354
4584
  const bootOrgId = chrome?.orgId ?? null;
4355
4585
  const [bootVisible, setBootVisible] = react.useState(true);
@@ -4488,7 +4718,11 @@ function FrameBody({
4488
4718
  sidebar: {
4489
4719
  pathname,
4490
4720
  brand: {
4491
- logoSrc: core?.brandLogoSrc ?? modeBrandLogo(appMode),
4721
+ logoSrc: brandAssets.logoHorizontal ?? void 0,
4722
+ logoSquareSrc: brandAssets.logoSquare ?? void 0,
4723
+ // Reserve the logo's box while the token sheet loads; never draw a
4724
+ // stand-in.
4725
+ logoPending: true,
4492
4726
  logoAlt: "Politogy",
4493
4727
  badgeLabel: "P",
4494
4728
  title: "Politogy"
@@ -4520,7 +4754,7 @@ function FrameBody({
4520
4754
  },
4521
4755
  betaBanner: meta.beta === true ? {} : void 0,
4522
4756
  modeId: appMode,
4523
- contentWrapper: core?.contentWrapper ?? granted("contentWrapper"),
4757
+ contentWrapper: core?.contentWrapper,
4524
4758
  topBar: {
4525
4759
  // Core's pages publish their own identity; every other app is one
4526
4760
  // product surface and takes its registry title.
@@ -4541,10 +4775,7 @@ function FrameBody({
4541
4775
  // search yet, so this stays decorative (`NavTopBarProps.search` — "an
4542
4776
  // app that has not wired search yet still gets the correct chrome").
4543
4777
  search: { placeholder: data?.searchPlaceholder ?? DEFAULT_SEARCH_PLACEHOLDER[app] ?? "Search" },
4544
- // "Build notes" — a quiet text button that starts the right-hand
4545
- // group. The spec names the element and its position but not its
4546
- // destination content; `onOpen` is left unset until that is defined.
4547
- buildNotes: {},
4778
+ // No Build notes control (Reference/UI-Platform, decided 2026-10-03).
4548
4779
  // The action cluster is IDENTICAL everywhere — core included. Page
4549
4780
  // actions sit BEFORE it, never inside it, so the Alerts bell keeps its
4550
4781
  // required position: farthest right, immediately before My Account.
@@ -4559,33 +4790,43 @@ function FrameBody({
4559
4790
  ] });
4560
4791
  }
4561
4792
  var standardNavIcons = {
4562
- home: fi.FiHome,
4563
- users: fi.FiUsers,
4564
- mail: fi.FiMail,
4565
- messageSquare: fi.FiMessageSquare,
4566
- layout: fi.FiLayout,
4567
- activity: fi.FiActivity,
4568
- lifeBuoy: fi.FiLifeBuoy,
4569
- grid: fi.FiGrid,
4570
- list: fi.FiList,
4571
- upload: fi.FiUpload,
4572
- edit: fi.FiEdit3,
4573
- fileText: fi.FiFileText,
4574
- send: fi.FiSend,
4575
- clock: fi.FiClock,
4576
- user: fi.FiUser,
4577
- barChart: fi.FiBarChart2,
4578
- briefcase: fi.FiBriefcase,
4579
- settings: fi.FiSettings,
4580
- creditCard: fi.FiCreditCard,
4581
- dollarSign: fi.FiDollarSign,
4582
- share: fi.FiShare2,
4793
+ home: lu.LuHouse,
4794
+ users: lu.LuUsers,
4795
+ mail: lu.LuMail,
4796
+ messageSquare: lu.LuMessageSquare,
4797
+ layout: lu.LuLayoutDashboard,
4798
+ activity: lu.LuActivity,
4799
+ lifeBuoy: lu.LuLifeBuoy,
4800
+ grid: lu.LuLayoutGrid,
4801
+ list: lu.LuList,
4802
+ upload: lu.LuUpload,
4803
+ edit: lu.LuPencil,
4804
+ fileText: lu.LuFileText,
4805
+ send: lu.LuSend,
4806
+ clock: lu.LuClock,
4807
+ user: lu.LuUser,
4808
+ barChart: lu.LuChartColumn,
4809
+ briefcase: lu.LuBriefcase,
4810
+ settings: lu.LuSettings,
4811
+ creditCard: lu.LuCreditCard,
4812
+ dollarSign: lu.LuDollarSign,
4813
+ share: lu.LuShare2,
4583
4814
  // Campaign / Petition mode slots.
4584
- phone: fi.FiPhone,
4585
- map: fi.FiMap,
4586
- mapPin: fi.FiMapPin,
4587
- target: fi.FiTarget,
4588
- flag: fi.FiFlag
4815
+ phone: lu.LuPhone,
4816
+ map: lu.LuMap,
4817
+ mapPin: lu.LuMapPin,
4818
+ target: lu.LuTarget,
4819
+ flag: lu.LuFlag,
4820
+ layoutDashboard: lu.LuLayoutDashboard,
4821
+ usersRound: lu.LuUsersRound,
4822
+ mousePointerClick: lu.LuMousePointerClick,
4823
+ clipboardList: lu.LuClipboardList,
4824
+ circleUser: lu.LuCircleUser,
4825
+ crosshair: lu.LuCrosshair,
4826
+ landmark: lu.LuLandmark,
4827
+ chartNoAxes: lu.LuChartNoAxesColumn,
4828
+ doorOpen: lu.LuDoorOpen,
4829
+ signpost: lu.LuSignpost
4589
4830
  };
4590
4831
  var ORG_STORAGE_KEY = "vrm.activeOrg";
4591
4832
  var MODE_STORAGE_KEY = "vrm.activeMode";
@@ -5012,14 +5253,14 @@ var MODE_DEFS = [
5012
5253
  {
5013
5254
  id: "relationship",
5014
5255
  label: "Relationship Mode",
5015
- icon: fi.FiUsers,
5256
+ icon: lu.LuContactRound,
5016
5257
  href: `${CORE_BASE_URL}/relationship/dashboard`,
5017
5258
  orgQuery: true
5018
5259
  },
5019
5260
  {
5020
5261
  id: "campaign",
5021
5262
  label: "Campaign Mode",
5022
- icon: fi.FiBarChart2,
5263
+ icon: lu.LuMegaphone,
5023
5264
  href: `${CORE_BASE_URL}/campaign/dashboard`,
5024
5265
  orgQuery: true
5025
5266
  },
@@ -5028,7 +5269,7 @@ var MODE_DEFS = [
5028
5269
  // petitions repo deploys production to petition-mode.politogyvrm.com.
5029
5270
  id: "petition",
5030
5271
  label: "Petition Mode",
5031
- icon: fi.FiFlag,
5272
+ icon: lu.LuFilePenLine,
5032
5273
  href: "https://petition-mode.politogyvrm.com/",
5033
5274
  orgQuery: true
5034
5275
  }