@the-portland-company/shell 0.69.0 → 0.71.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.
@@ -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
 
@@ -88,13 +89,111 @@ function normalize(s) {
88
89
  return s.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().trim();
89
90
  }
90
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
+
91
190
  // src/theme-preference.ts
92
191
  var THEME_STORAGE_KEY = "politogy_theme";
93
192
  var THEME_COOKIE = "politogy_theme";
94
193
  var THEME_PENDING_COOKIE = "politogy_theme_pending";
95
- var VALID = ["light", "dark", "system"];
194
+ var VALID2 = ["light", "dark", "system"];
96
195
  function isThemePreference(v) {
97
- return typeof v === "string" && VALID.includes(v);
196
+ return typeof v === "string" && VALID2.includes(v);
98
197
  }
99
198
  function readThemeCookie() {
100
199
  if (typeof document === "undefined") return null;
@@ -206,7 +305,7 @@ function topBarIconButtonClass(tone = "default") {
206
305
  const toneClass = tone === "danger" || tone === "warning" ? "text-[color:var(--chrome-danger)] hover:text-[color:var(--chrome-danger)]" : "text-[color:var(--topbar-icon-color,var(--muted))] hover:text-[color:var(--topbar-icon-hover-color,var(--foreground))] hover:bg-[color:var(--topbar-icon-hover-bg,transparent)]";
207
306
  return [
208
307
  // `group/tbtip` powers the shared <TopBarTooltip> rendered inside the trigger.
209
- "group/tbtip relative flex items-center justify-center rounded-[var(--topbar-icon-button-radius,5px)] border border-[color:var(--line)] transition",
308
+ "group/tbtip relative flex items-center justify-center rounded-[var(--topbar-icon-button-radius,5px)] border border-transparent transition",
210
309
  "h-[var(--topbar-icon-button-size,34px)] w-[var(--topbar-icon-button-size,34px)]",
211
310
  toneClass
212
311
  ].join(" ");
@@ -1847,7 +1946,6 @@ var PHONEBANK_ORIGIN = "https://phonebank.politogyvrm.com/";
1847
1946
  var CANVASS_ORIGIN = "https://canvass.politogyvrm.com/";
1848
1947
  var SIGNS_ORIGIN = "https://signs.politogyvrm.com/";
1849
1948
  var POLLS_ORIGIN = "https://polls.politogyvrm.com/";
1850
- var CONTACTS_TRIBES = "https://contacts.politogyvrm.com/tribes";
1851
1949
  var PETITION_MODE_ORIGIN = "https://petition-mode.politogyvrm.com/";
1852
1950
  function applyHiddenItems(items, hidden) {
1853
1951
  if (!hidden || hidden.length === 0) return items;
@@ -1917,10 +2015,6 @@ var APP_POLLS_CHILDREN = [
1917
2015
  { label: "Command Center", icon: "grid", href: "https://polls.politogyvrm.com/" },
1918
2016
  { label: "New Poll", icon: "edit", href: "https://polls.politogyvrm.com/polls/new" }
1919
2017
  ];
1920
- var APP_CTAS_CHILDREN = [
1921
- { label: "CTAs", icon: "list", href: "https://ctas.politogyvrm.com/" },
1922
- { label: "Canvas", icon: "edit", href: "https://ctas.politogyvrm.com/?tab=canvas" }
1923
- ];
1924
2018
  var APP_A2P_CHILDREN = [
1925
2019
  { label: "Dashboard", icon: "grid", path: "dashboard" },
1926
2020
  { label: "Compose", icon: "edit", path: "compose" },
@@ -1968,16 +2062,27 @@ function standardPolitogyNav(opts) {
1968
2062
  return { label: c.label, icon: icon(c.icon), href: withOrg(withMode) };
1969
2063
  });
1970
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
+ ];
1971
2076
  const buildRelationship = () => {
1972
2077
  const contacts = opts.contactsItem ? {
1973
2078
  label: "Contacts",
1974
- icon: icon("users"),
2079
+ icon: icon("usersRound"),
1975
2080
  href: opts.contactsItem.href,
1976
2081
  children: opts.contactsItem.children,
1977
2082
  badge: opts.contactsItem.count ?? void 0
1978
2083
  } : {
1979
2084
  label: "Contacts",
1980
- icon: icon("users"),
2085
+ icon: icon("usersRound"),
1981
2086
  href: withOrg(`${CONTACTS_APP}/`),
1982
2087
  children: APP_CONTACTS_CHILDREN.map((c) => ({
1983
2088
  label: c.label,
@@ -1987,7 +2092,7 @@ function standardPolitogyNav(opts) {
1987
2092
  };
1988
2093
  return [
1989
2094
  { kind: "section", label: "Relationship" },
1990
- { label: "Dashboard", icon: icon("home"), href: withOrg(abs("/relationship/dashboard")) },
2095
+ { label: "Dashboard", icon: icon("layoutDashboard"), href: withOrg(abs("/relationship/dashboard")) },
1991
2096
  contacts,
1992
2097
  {
1993
2098
  label: "Email broadcast",
@@ -2010,40 +2115,20 @@ function standardPolitogyNav(opts) {
2010
2115
  },
2011
2116
  { kind: "section", label: "Collect" },
2012
2117
  // Carries no top-level href in VRM core (parent row only toggles).
2013
- { label: "Calls to action", icon: icon("layout"), children: leaves(CTA_CHILDREN) },
2118
+ { label: "Calls to action", icon: icon("mousePointerClick"), children: leaves(CTA_CHILDREN) },
2014
2119
  {
2015
2120
  label: "Forms",
2016
- icon: icon("activity"),
2121
+ icon: icon("fileText"),
2017
2122
  href: withOrg("https://forms.politogyvrm.com/"),
2018
2123
  children: APP_FORMS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
2019
2124
  },
2020
2125
  {
2021
2126
  label: "Surveys",
2022
- icon: icon("fileText"),
2127
+ icon: icon("clipboardList"),
2023
2128
  href: withOrg("https://surveys.politogyvrm.com/surveys"),
2024
2129
  children: APP_SURVEYS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
2025
2130
  },
2026
- {
2027
- label: "Polls",
2028
- icon: icon("barChart"),
2029
- href: withOrg("https://polls.politogyvrm.com/"),
2030
- children: APP_POLLS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
2031
- },
2032
- {
2033
- label: "CTAs",
2034
- icon: icon("layout"),
2035
- href: withOrg("https://ctas.politogyvrm.com/"),
2036
- children: APP_CTAS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
2037
- },
2038
- { kind: "section", label: "Account" },
2039
- // My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).
2040
- { label: "My profile", icon: icon("user"), href: withOrg(abs("/my-profile")) },
2041
- {
2042
- label: "Organization settings",
2043
- icon: icon("settings"),
2044
- href: withOrg(abs("/organization-settings")),
2045
- children: branches(ORG_SETTINGS_CHILDREN)
2046
- }
2131
+ ...accountRows()
2047
2132
  ];
2048
2133
  };
2049
2134
  const buildCampaign = () => {
@@ -2052,40 +2137,57 @@ function standardPolitogyNav(opts) {
2052
2137
  ...opts.campaignAvailability
2053
2138
  };
2054
2139
  const rows = [
2055
- { label: "Dashboard", icon: icon("home"), href: withOrg(abs("/campaign/dashboard")) },
2056
- { 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" },
2057
2147
  {
2058
- label: "A2P",
2059
- icon: icon("messageSquare"),
2060
- href: withOrg(A2P_ORIGIN),
2061
- children: appLeaves(A2P_ORIGIN, APP_A2P_CHILDREN),
2062
- 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"
2063
2153
  },
2154
+ { kind: "section", label: "GOTV" },
2064
2155
  {
2065
- label: "Phone Banking",
2156
+ label: "Field canvassing",
2157
+ icon: icon("doorOpen"),
2158
+ href: withOrg(CANVASS_ORIGIN),
2159
+ children: appLeaves(CANVASS_ORIGIN, APP_CANVASS_CHILDREN),
2160
+ flag: "canvass"
2161
+ },
2162
+ {
2163
+ label: "Phone banking",
2066
2164
  icon: icon("phone"),
2067
2165
  href: withOrg(PHONEBANK_ORIGIN),
2068
2166
  children: appLeaves(PHONEBANK_ORIGIN, APP_PHONEBANK_CHILDREN),
2069
2167
  flag: "phonebank"
2070
2168
  },
2071
2169
  {
2072
- label: "Field Canvassing",
2073
- icon: icon("map"),
2074
- href: withOrg(CANVASS_ORIGIN),
2075
- children: appLeaves(CANVASS_ORIGIN, APP_CANVASS_CHILDREN),
2076
- 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"
2077
2175
  },
2078
2176
  {
2079
- label: "Sign Mapping",
2080
- icon: icon("mapPin"),
2177
+ label: "Sign mapping",
2178
+ icon: icon("signpost"),
2081
2179
  href: withOrg(SIGNS_ORIGIN),
2082
2180
  children: appLeaves(SIGNS_ORIGIN, APP_SIGNS_CHILDREN),
2083
2181
  flag: "signs"
2084
2182
  },
2085
- { label: "Tribes", icon: icon("users"), href: withOrg(CONTACTS_TRIBES), flag: "tribes" },
2086
- { label: "Polling Engine", icon: icon("barChart"), href: withOrg(POLLS_ORIGIN), flag: "polling" }
2183
+ ...accountRows()
2087
2184
  ];
2088
- 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
+ });
2089
2191
  };
2090
2192
  const buildPetition = () => [
2091
2193
  opts.petitionsItem ? {
@@ -2192,7 +2294,9 @@ function NavSidebar({
2192
2294
  footer,
2193
2295
  linkComponent,
2194
2296
  open,
2195
- onClose
2297
+ onClose,
2298
+ onOpen,
2299
+ onNavigate
2196
2300
  }) {
2197
2301
  const Link = linkComponent ?? DefaultLink;
2198
2302
  const collapsible = !open;
@@ -2289,7 +2393,7 @@ function NavSidebar({
2289
2393
  style: { fontFamily: 'var(--font-family, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif)' },
2290
2394
  onKeyDown: trapTab,
2291
2395
  onClick: (e) => {
2292
- if (open && e.target.closest("a[href]")) onClose?.();
2396
+ if (open && e.target.closest("a[href]")) (onNavigate ?? onClose)?.();
2293
2397
  },
2294
2398
  children: [
2295
2399
  open ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -2298,18 +2402,30 @@ function NavSidebar({
2298
2402
  type: "button",
2299
2403
  ref: closeButtonRef,
2300
2404
  onClick: onClose,
2301
- "aria-label": "Close menu",
2405
+ "aria-label": "Collapse navigation",
2302
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",
2303
2407
  children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
2304
2408
  }
2305
2409
  ) : null,
2306
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,
2307
2423
  /* @__PURE__ */ jsxRuntime.jsxs(
2308
2424
  Link,
2309
2425
  {
2310
2426
  href: brand.homeHref ?? "/",
2311
2427
  "aria-label": brand.logoAlt ?? brand.title,
2312
- className: `flex items-center gap-2.5 ${rc("max-md:justify-center")}`,
2428
+ className: `flex items-center gap-2.5 ${rc("max-md:justify-center")} ${onOpen ? rc("max-md:hidden") : ""}`,
2313
2429
  children: [
2314
2430
  brand.logoSquareSrc ? /* @__PURE__ */ jsxRuntime.jsx(
2315
2431
  "img",
@@ -2353,7 +2469,7 @@ function NavSidebar({
2353
2469
  }
2354
2470
  ),
2355
2471
  org ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: rc("max-md:flex max-md:justify-center"), children: [
2356
- /* @__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" }) }),
2472
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `mb-[7px] mt-[7px] flex items-center justify-between ${rc("max-md:hidden")}`, children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: NAV_EYEBROW_CLASS, children: "Organization" }) }),
2357
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: [
2358
2474
  /* @__PURE__ */ jsxRuntime.jsx(
2359
2475
  "span",
@@ -2379,7 +2495,7 @@ function NavSidebar({
2379
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")}`,
2380
2496
  children: [
2381
2497
  /* @__PURE__ */ jsxRuntime.jsx(OrgIconMark, { org, logoSrc: orgLogoSrc }),
2382
- /* @__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: [
2498
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `relative flex h-[var(--sidebar-org-band-height,70px)] w-full items-center justify-center bg-[#FFFFFF] px-3 py-[7px] ${rc("max-md:hidden")}`, children: [
2383
2499
  orgLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: orgLogoSrc, alt: "", className: "max-h-full max-w-[132px] object-contain" }) : org.canUploadLogo ? /* @__PURE__ */ jsxRuntime.jsx(
2384
2500
  "a",
2385
2501
  {
@@ -2391,7 +2507,7 @@ function NavSidebar({
2391
2507
  ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-semibold text-neutral-800", children: org.name ?? "Organization" }),
2392
2508
  /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute inset-x-0 bottom-0 h-[3px]", style: { backgroundImage: orgGradient } })
2393
2509
  ] }),
2394
- /* @__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: [
2510
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `flex w-full min-w-0 items-center justify-between gap-[9px] px-[10px] py-[10px] ${rc("max-md:hidden")}`, children: [
2395
2511
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
2396
2512
  /* @__PURE__ */ jsxRuntime.jsx(
2397
2513
  "span",
@@ -2481,7 +2597,7 @@ function NavSidebar({
2481
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")}`,
2482
2598
  children: [
2483
2599
  /* @__PURE__ */ jsxRuntime.jsx(OrgIconMark, { org, logoSrc: orgLogoSrc }),
2484
- /* @__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: [
2600
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `relative flex h-[var(--sidebar-org-band-height,70px)] w-full items-center justify-center bg-[#FFFFFF] px-3 py-[7px] ${rc("max-md:hidden")}`, children: [
2485
2601
  orgLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: orgLogoSrc, alt: "", className: "max-h-full max-w-[132px] object-contain" }) : org.canUploadLogo ? /* @__PURE__ */ jsxRuntime.jsx(
2486
2602
  "a",
2487
2603
  {
@@ -2493,7 +2609,7 @@ function NavSidebar({
2493
2609
  ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-semibold text-neutral-800", children: org.name ?? "Organization" }),
2494
2610
  /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute inset-x-0 bottom-0 h-[3px]", style: { backgroundImage: orgGradient } })
2495
2611
  ] }),
2496
- /* @__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: [
2612
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `flex w-full min-w-0 items-center justify-between gap-[9px] px-[10px] py-[10px] ${rc("max-md:hidden")}`, children: [
2497
2613
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
2498
2614
  /* @__PURE__ */ jsxRuntime.jsx(
2499
2615
  "span",
@@ -2538,7 +2654,7 @@ function NavSidebar({
2538
2654
  },
2539
2655
  disabled: !available,
2540
2656
  className: [
2541
- "flex flex-1 items-center justify-center rounded-[5px] px-[9px] py-[6px] transition",
2657
+ `flex flex-none items-center justify-center rounded-[5px] px-[9px] py-[6px] transition ${rc("max-md:flex-1")}`,
2542
2658
  !available ? "cursor-not-allowed text-[color:var(--sidebar-text-muted,var(--muted))] opacity-35" : selected ? "bg-[color:var(--sidebar-mode-selected-bg,var(--mode-accent,var(--color-accent)))] text-[color:var(--mode-on-accent,white)]" : "text-[color:var(--sidebar-text-muted,var(--muted))] hover:bg-[#FFFFFF]/5 hover:text-[color:var(--sidebar-text,var(--foreground))]"
2543
2659
  ].join(" "),
2544
2660
  children: OptIcon ? /* @__PURE__ */ jsxRuntime.jsx(OptIcon, { size: 15, className: "shrink-0" }) : null
@@ -2628,15 +2744,17 @@ function NavSidebar({
2628
2744
  onSignOut: footer.onSignOut
2629
2745
  }
2630
2746
  ) : null,
2631
- 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(
2632
- "a",
2633
- {
2634
- href: safeHref(l.href),
2635
- className: "text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))] hover:text-[color:var(--sidebar-text,var(--foreground))] hover:underline",
2636
- children: l.label
2637
- },
2638
- l.label
2639
- )) }) : null,
2747
+ footer.links && footer.links.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex flex-wrap items-center justify-center gap-[6px] text-[11px] leading-[1.2] ${footer.user ? "mt-3" : ""} ${rc("max-md:hidden")}`, children: footer.links.map((l, i) => /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
2748
+ i > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))]", children: "\xB7" }) : null,
2749
+ /* @__PURE__ */ jsxRuntime.jsx(
2750
+ "a",
2751
+ {
2752
+ href: safeHref(l.href),
2753
+ className: "text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))] hover:text-[color:var(--sidebar-text,var(--foreground))] hover:underline",
2754
+ children: l.label
2755
+ }
2756
+ )
2757
+ ] }, l.label)) }) : null,
2640
2758
  footer.envLabel && footer.envLabel.trim().toLowerCase() !== "production" ? /* @__PURE__ */ jsxRuntime.jsxs(
2641
2759
  "div",
2642
2760
  {
@@ -3083,7 +3201,7 @@ function NavTopBar({
3083
3201
  const initials = (hasRealName ? rawName : user?.email ?? "P").slice(0, 2).toUpperCase();
3084
3202
  const secondary = hasRealName ? user?.email || [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member" : [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member";
3085
3203
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-0 z-20", children: [
3086
- /* @__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: [
3204
+ /* @__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: [
3087
3205
  onOpenNav ? /* @__PURE__ */ jsxRuntime.jsx(
3088
3206
  "button",
3089
3207
  {
@@ -3096,7 +3214,7 @@ function NavTopBar({
3096
3214
  children: /* @__PURE__ */ jsxRuntime.jsx(HamburgerIcon, {})
3097
3215
  }
3098
3216
  ) : null,
3099
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "relative flex h-9 w-[320px] max-w-full shrink-0 items-center", children: [
3217
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "relative flex h-9 w-[320px] min-w-0 max-w-full shrink items-center md:shrink-0", children: [
3100
3218
  /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { className: "pointer-events-none absolute left-[10px] h-[15px] w-[15px] text-[color:var(--muted)]" }),
3101
3219
  /* @__PURE__ */ jsxRuntime.jsx(
3102
3220
  "input",
@@ -3116,13 +3234,13 @@ function NavTopBar({
3116
3234
  "kbd",
3117
3235
  {
3118
3236
  "aria-hidden": true,
3119
- 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)]",
3237
+ 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)]",
3120
3238
  children: "/"
3121
3239
  }
3122
3240
  )
3123
3241
  ] }),
3124
3242
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative ml-auto flex shrink-0 items-center gap-[var(--topbar-icon-gap,8px)]", children: [
3125
- /* @__PURE__ */ jsxRuntime.jsxs(
3243
+ buildNotes ? /* @__PURE__ */ jsxRuntime.jsxs(
3126
3244
  "button",
3127
3245
  {
3128
3246
  type: "button",
@@ -3133,7 +3251,7 @@ function NavTopBar({
3133
3251
  buildNotes?.label ?? "Build notes"
3134
3252
  ]
3135
3253
  }
3136
- ),
3254
+ ) : null,
3137
3255
  actionsList && actionsList.length > 0 ? actionsList.map((action) => /* @__PURE__ */ jsxRuntime.jsx(NavTopBarActionButton, { action }, action.key)) : null,
3138
3256
  actions,
3139
3257
  themeToggle,
@@ -3624,9 +3742,22 @@ function NavAppShell({
3624
3742
  );
3625
3743
  }
3626
3744
  const [navOpen, setNavOpen] = react.useState(false);
3745
+ const expandRail = () => {
3746
+ writeRailPreference("expanded");
3747
+ setNavOpen(true);
3748
+ };
3749
+ const collapseRail = () => {
3750
+ writeRailPreference("collapsed");
3751
+ setNavOpen(false);
3752
+ };
3627
3753
  react.useEffect(() => {
3628
3754
  setNavOpen(false);
3629
3755
  }, [sidebar.pathname]);
3756
+ react.useEffect(() => {
3757
+ if (readRailPreference() !== "expanded") return;
3758
+ const narrow = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(max-width: 767.98px)").matches : false;
3759
+ if (narrow) setNavOpen(true);
3760
+ }, []);
3630
3761
  react.useEffect(() => {
3631
3762
  if (!navOpen) return;
3632
3763
  const previous = document.body.style.overflow;
@@ -3647,15 +3778,23 @@ function NavAppShell({
3647
3778
  "data-politogy-mode": modeId,
3648
3779
  className: "min-h-screen bg-[color:var(--background)] text-[color:var(--foreground)]",
3649
3780
  children: [
3650
- /* @__PURE__ */ jsxRuntime.jsx(NavSidebar, { ...sidebar, footer: sidebarFooter, open: navOpen, onClose: () => setNavOpen(false) }),
3781
+ /* @__PURE__ */ jsxRuntime.jsx(
3782
+ NavSidebar,
3783
+ {
3784
+ ...sidebar,
3785
+ footer: sidebarFooter,
3786
+ open: navOpen,
3787
+ onClose: collapseRail,
3788
+ onOpen: expandRail,
3789
+ onNavigate: () => setNavOpen(false)
3790
+ }
3791
+ ),
3651
3792
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pl-[var(--sidebar-collapsed-width,64px)] md:pl-[var(--sidebar-width,236px)]", children: [
3652
3793
  /* @__PURE__ */ jsxRuntime.jsx(
3653
3794
  NavTopBar,
3654
3795
  {
3655
3796
  ...topBar,
3656
- accountMenu: topBar.accountMenu ?? (accountMenuPlacement === "sidebar" ? "sidebar" : "topbar"),
3657
- onOpenNav: () => setNavOpen(true),
3658
- navOpen
3797
+ accountMenu: topBar.accountMenu ?? (accountMenuPlacement === "sidebar" ? "sidebar" : "topbar")
3659
3798
  }
3660
3799
  ),
3661
3800
  betaBanner ? /* @__PURE__ */ jsxRuntime.jsx(NavBetaBanner, { ...betaBanner }) : null,
@@ -3730,66 +3869,6 @@ function resolveActiveOrg(search) {
3730
3869
  return readActiveOrgCookie();
3731
3870
  }
3732
3871
 
3733
- // src/nav-preference.ts
3734
- var NAV_DISPLAY_STORAGE_KEY = "politogy_nav_display";
3735
- var NAV_DISPLAY_COOKIE = "politogy_nav_display";
3736
- var LEGACY_NAV_DISPLAY_KEY = "vrm.navDisplay";
3737
- var NAV_DISPLAY_DEFAULT = "both";
3738
- var VALID2 = ["menu", "tabs", "both"];
3739
- function isNavDisplayPreference(v) {
3740
- return typeof v === "string" && VALID2.includes(v);
3741
- }
3742
- function readNavDisplayCookie() {
3743
- if (typeof document === "undefined") return null;
3744
- try {
3745
- const m = document.cookie.match(
3746
- new RegExp(`(?:^|;\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)`)
3747
- );
3748
- const v = m ? decodeURIComponent(m[1]) : null;
3749
- return isNavDisplayPreference(v) ? v : null;
3750
- } catch {
3751
- return null;
3752
- }
3753
- }
3754
- function writeNavDisplayCookie(pref) {
3755
- if (typeof document === "undefined" || typeof window === "undefined") return;
3756
- const host = window.location.hostname;
3757
- const domainAttr = /(^|\.)politogyvrm\.com$/i.test(host) ? "; Domain=.politogyvrm.com" : "";
3758
- const secure = window.location.protocol === "https:" ? "; Secure" : "";
3759
- document.cookie = `${NAV_DISPLAY_COOKIE}=${encodeURIComponent(
3760
- pref
3761
- )}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`;
3762
- }
3763
- function readNavDisplayLocal() {
3764
- if (typeof localStorage === "undefined") return null;
3765
- try {
3766
- const current = localStorage.getItem(NAV_DISPLAY_STORAGE_KEY);
3767
- if (isNavDisplayPreference(current)) return current;
3768
- const legacy = localStorage.getItem(LEGACY_NAV_DISPLAY_KEY);
3769
- return isNavDisplayPreference(legacy) ? legacy : null;
3770
- } catch {
3771
- return null;
3772
- }
3773
- }
3774
- function writeNavDisplayLocal(pref) {
3775
- if (typeof localStorage === "undefined") return;
3776
- try {
3777
- localStorage.setItem(NAV_DISPLAY_STORAGE_KEY, pref);
3778
- } catch {
3779
- }
3780
- }
3781
- function resolveNavDisplay() {
3782
- return readNavDisplayCookie() ?? readNavDisplayLocal() ?? NAV_DISPLAY_DEFAULT;
3783
- }
3784
- `(function(){try{
3785
- var KEY=${JSON.stringify(NAV_DISPLAY_STORAGE_KEY)};
3786
- var VALID=["menu","tabs","both"];
3787
- function fromCookie(){try{var m=document.cookie.match(/(?:^|;\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)/);return m?decodeURIComponent(m[1]):null;}catch(e){return null;}}
3788
- var cookie=fromCookie();
3789
- if(cookie&&VALID.indexOf(cookie)!==-1){var ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}
3790
- if(cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}}
3791
- }catch(e){}})();`;
3792
-
3793
3872
  // src/lib/breadcrumbs.ts
3794
3873
  function deriveBreadcrumbs(items, pathname, opts) {
3795
3874
  const search = opts?.search ?? (typeof window !== "undefined" ? window.location.search : "");
@@ -4698,10 +4777,7 @@ function FrameBody({
4698
4777
  // search yet, so this stays decorative (`NavTopBarProps.search` — "an
4699
4778
  // app that has not wired search yet still gets the correct chrome").
4700
4779
  search: { placeholder: data?.searchPlaceholder ?? DEFAULT_SEARCH_PLACEHOLDER[app] ?? "Search" },
4701
- // "Build notes" — a quiet text button that starts the right-hand
4702
- // group. The spec names the element and its position but not its
4703
- // destination content; `onOpen` is left unset until that is defined.
4704
- buildNotes: {},
4780
+ // No Build notes control (Reference/UI-Platform, decided 2026-10-03).
4705
4781
  // The action cluster is IDENTICAL everywhere — core included. Page
4706
4782
  // actions sit BEFORE it, never inside it, so the Alerts bell keeps its
4707
4783
  // required position: farthest right, immediately before My Account.
@@ -4716,33 +4792,43 @@ function FrameBody({
4716
4792
  ] });
4717
4793
  }
4718
4794
  var standardNavIcons = {
4719
- home: fi.FiHome,
4720
- users: fi.FiUsers,
4721
- mail: fi.FiMail,
4722
- messageSquare: fi.FiMessageSquare,
4723
- layout: fi.FiLayout,
4724
- activity: fi.FiActivity,
4725
- lifeBuoy: fi.FiLifeBuoy,
4726
- grid: fi.FiGrid,
4727
- list: fi.FiList,
4728
- upload: fi.FiUpload,
4729
- edit: fi.FiEdit3,
4730
- fileText: fi.FiFileText,
4731
- send: fi.FiSend,
4732
- clock: fi.FiClock,
4733
- user: fi.FiUser,
4734
- barChart: fi.FiBarChart2,
4735
- briefcase: fi.FiBriefcase,
4736
- settings: fi.FiSettings,
4737
- creditCard: fi.FiCreditCard,
4738
- dollarSign: fi.FiDollarSign,
4739
- share: fi.FiShare2,
4795
+ home: lu.LuHouse,
4796
+ users: lu.LuUsers,
4797
+ mail: lu.LuMail,
4798
+ messageSquare: lu.LuMessageSquare,
4799
+ layout: lu.LuLayoutDashboard,
4800
+ activity: lu.LuActivity,
4801
+ lifeBuoy: lu.LuLifeBuoy,
4802
+ grid: lu.LuLayoutGrid,
4803
+ list: lu.LuList,
4804
+ upload: lu.LuUpload,
4805
+ edit: lu.LuPencil,
4806
+ fileText: lu.LuFileText,
4807
+ send: lu.LuSend,
4808
+ clock: lu.LuClock,
4809
+ user: lu.LuUser,
4810
+ barChart: lu.LuChartColumn,
4811
+ briefcase: lu.LuBriefcase,
4812
+ settings: lu.LuSettings,
4813
+ creditCard: lu.LuCreditCard,
4814
+ dollarSign: lu.LuDollarSign,
4815
+ share: lu.LuShare2,
4740
4816
  // Campaign / Petition mode slots.
4741
- phone: fi.FiPhone,
4742
- map: fi.FiMap,
4743
- mapPin: fi.FiMapPin,
4744
- target: fi.FiTarget,
4745
- flag: fi.FiFlag
4817
+ phone: lu.LuPhone,
4818
+ map: lu.LuMap,
4819
+ mapPin: lu.LuMapPin,
4820
+ target: lu.LuTarget,
4821
+ flag: lu.LuFlag,
4822
+ layoutDashboard: lu.LuLayoutDashboard,
4823
+ usersRound: lu.LuUsersRound,
4824
+ mousePointerClick: lu.LuMousePointerClick,
4825
+ clipboardList: lu.LuClipboardList,
4826
+ circleUser: lu.LuCircleUser,
4827
+ crosshair: lu.LuCrosshair,
4828
+ landmark: lu.LuLandmark,
4829
+ chartNoAxes: lu.LuChartNoAxesColumn,
4830
+ doorOpen: lu.LuDoorOpen,
4831
+ signpost: lu.LuSignpost
4746
4832
  };
4747
4833
  var ORG_STORAGE_KEY = "vrm.activeOrg";
4748
4834
  var MODE_STORAGE_KEY = "vrm.activeMode";
@@ -5113,7 +5199,7 @@ function ChromeTopBarActions() {
5113
5199
  function ChromeDevNotesMenu() {
5114
5200
  const { ready, openTasks, activate } = react.useContext(DevNotesTasksContext);
5115
5201
  if (!ready) return null;
5116
- return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { display: "contents" }, onPointerDownCapture: activate, onFocusCapture: activate, onKeyDownCapture: activate, children: /* @__PURE__ */ jsxRuntime.jsx(devnotes.DevNotesMenu, { position: "top-right", onViewTasks: openTasks }) });
5202
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { display: "contents" }, onPointerDownCapture: activate, onFocusCapture: activate, onKeyDownCapture: activate, children: /* @__PURE__ */ jsxRuntime.jsx(devnotes.DevNotesMenu, { position: "top-right", icon: lu.LuNotebookPen, onViewTasks: openTasks }) });
5117
5203
  }
5118
5204
  function useIsSuperAdmin() {
5119
5205
  const state = useChromeState();
@@ -5169,14 +5255,14 @@ var MODE_DEFS = [
5169
5255
  {
5170
5256
  id: "relationship",
5171
5257
  label: "Relationship Mode",
5172
- icon: fi.FiUsers,
5258
+ icon: lu.LuContactRound,
5173
5259
  href: `${CORE_BASE_URL}/relationship/dashboard`,
5174
5260
  orgQuery: true
5175
5261
  },
5176
5262
  {
5177
5263
  id: "campaign",
5178
5264
  label: "Campaign Mode",
5179
- icon: fi.FiBarChart2,
5265
+ icon: lu.LuMegaphone,
5180
5266
  href: `${CORE_BASE_URL}/campaign/dashboard`,
5181
5267
  orgQuery: true
5182
5268
  },
@@ -5185,7 +5271,7 @@ var MODE_DEFS = [
5185
5271
  // petitions repo deploys production to petition-mode.politogyvrm.com.
5186
5272
  id: "petition",
5187
5273
  label: "Petition Mode",
5188
- icon: fi.FiFlag,
5274
+ icon: lu.LuFilePenLine,
5189
5275
  href: "https://petition-mode.politogyvrm.com/",
5190
5276
  orgQuery: true
5191
5277
  }