@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.
package/dist/chrome.css CHANGED
@@ -155,7 +155,7 @@
155
155
  --sidebar-border: #E2E8F0;
156
156
  --sidebar-brand-logo-height: 24px;
157
157
  --sidebar-org-logo-max-height: 34px;
158
- --sidebar-org-band-height: 48px;
158
+ --sidebar-org-band-height: 70px;
159
159
  --sidebar-item-radius: 8px;
160
160
  --sidebar-item-padding-x: 16px;
161
161
  --sidebar-item-padding-y: 10px;
@@ -447,7 +447,7 @@
447
447
  display: inline-flex !important;
448
448
  align-items: center !important;
449
449
  justify-content: center !important;
450
- border: 1px solid var(--line) !important;
450
+ border: 1px solid transparent !important;
451
451
  border-radius: var(--topbar-icon-button-radius, 5px) !important;
452
452
  background: transparent !important;
453
453
  color: var(--topbar-icon-color, var(--muted)) !important;
@@ -57,7 +57,45 @@ var cookie=fromCookie();
57
57
  if(cookie&&VALID.indexOf(cookie)!==-1){var ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}
58
58
  if(cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}}
59
59
  }catch(e){}})();`;
60
+ var RAIL_STORAGE_KEY = "politogy_rail";
61
+ var RAIL_COOKIE = "politogy_rail";
62
+ var RAIL_DEFAULT = "collapsed";
63
+ function isRailPreference(v) {
64
+ return v === "expanded" || v === "collapsed";
65
+ }
66
+ function readRailPreference() {
67
+ if (typeof document !== "undefined") {
68
+ try {
69
+ const m = document.cookie.match(new RegExp(`(?:^|;\\s*)${RAIL_COOKIE}=([^;]+)`));
70
+ const v = m ? decodeURIComponent(m[1]) : null;
71
+ if (isRailPreference(v)) return v;
72
+ } catch {
73
+ }
74
+ }
75
+ if (typeof localStorage !== "undefined") {
76
+ try {
77
+ const v = localStorage.getItem(RAIL_STORAGE_KEY);
78
+ if (isRailPreference(v)) return v;
79
+ } catch {
80
+ }
81
+ }
82
+ return RAIL_DEFAULT;
83
+ }
84
+ function writeRailPreference(pref) {
85
+ if (typeof document === "undefined" || typeof window === "undefined") return;
86
+ const host = window.location.hostname;
87
+ const domainAttr = /(^|\.)politogyvrm\.com$/i.test(host) ? "; Domain=.politogyvrm.com" : "";
88
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
89
+ try {
90
+ document.cookie = `${RAIL_COOKIE}=${pref}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`;
91
+ } catch {
92
+ }
93
+ try {
94
+ localStorage.setItem(RAIL_STORAGE_KEY, pref);
95
+ } catch {
96
+ }
97
+ }
60
98
 
61
- export { LEGACY_NAV_DISPLAY_KEY, NAV_DISPLAY_COOKIE, NAV_DISPLAY_DEFAULT, NAV_DISPLAY_PREPAINT_SCRIPT, NAV_DISPLAY_STORAGE_KEY, isNavDisplayPreference, readNavDisplayCookie, readNavDisplayLocal, resolveNavDisplay, writeNavDisplayCookie, writeNavDisplayLocal };
62
- //# sourceMappingURL=chunk-6UHJV2FH.js.map
63
- //# sourceMappingURL=chunk-6UHJV2FH.js.map
99
+ export { LEGACY_NAV_DISPLAY_KEY, NAV_DISPLAY_COOKIE, NAV_DISPLAY_DEFAULT, NAV_DISPLAY_PREPAINT_SCRIPT, NAV_DISPLAY_STORAGE_KEY, RAIL_COOKIE, RAIL_DEFAULT, RAIL_STORAGE_KEY, isNavDisplayPreference, isRailPreference, readNavDisplayCookie, readNavDisplayLocal, readRailPreference, resolveNavDisplay, writeNavDisplayCookie, writeNavDisplayLocal, writeRailPreference };
100
+ //# sourceMappingURL=chunk-7YVJ7HQG.js.map
101
+ //# sourceMappingURL=chunk-7YVJ7HQG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/nav-preference.ts"],"names":[],"mappings":"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","file":"chunk-7YVJ7HQG.js","sourcesContent":["// Universal navigation-display preference — the same cross-app contract as the\n// theme (see ./theme-preference, which this deliberately mirrors).\n//\n// The user's choice of how navigation renders (Menu / Tabs / Both) follows the\n// authenticated user across every Politogy app + subdomain. Three layers:\n// 1. VRM Core `profiles.nav_display_preference` — source of truth, persisted\n// via the chrome API (`PATCH me/preferences { navDisplay }`) and read back\n// from `GET me` (`navDisplay`).\n// 2. `.politogyvrm.com` cookie `politogy_nav_display` — the cross-subdomain\n// vehicle (app session cookies are host-only, and so is localStorage).\n// 3. localStorage — same-app fast reads and cross-tab `storage` events.\n//\n// Before this existed the preference lived ONLY in localStorage under\n// `vrm.navDisplay`, which is per-ORIGIN: every app subdomain kept its own copy\n// and a freshly opened app booted the default, so the setting appeared not to\n// hold when moving between apps. The legacy key is still read as a fallback so\n// an existing local choice survives the upgrade.\n//\n// Server-safe (no 'use client'): layouts may import NAV_DISPLAY_PREPAINT_SCRIPT.\n\nexport type NavDisplayPreference = 'menu' | 'tabs' | 'both'\n\n// One key for BOTH the localStorage store and the cross-subdomain cookie, so a\n// choice in one app is the same key in the next.\nexport const NAV_DISPLAY_STORAGE_KEY = 'politogy_nav_display'\nexport const NAV_DISPLAY_COOKIE = 'politogy_nav_display'\n\n/** Pre-0.37 host-only key. Read for migration; never written. */\nexport const LEGACY_NAV_DISPLAY_KEY = 'vrm.navDisplay'\n\nexport const NAV_DISPLAY_DEFAULT: NavDisplayPreference = 'both'\n\nconst VALID: readonly NavDisplayPreference[] = ['menu', 'tabs', 'both']\n\nexport function isNavDisplayPreference(v: unknown): v is NavDisplayPreference {\n return typeof v === 'string' && (VALID as readonly string[]).includes(v)\n}\n\n/** Read the shared cookie (browser only; null on the server or when unset). */\nexport function readNavDisplayCookie(): NavDisplayPreference | null {\n if (typeof document === 'undefined') return null\n try {\n const m = document.cookie.match(\n new RegExp(`(?:^|;\\\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)`),\n )\n const v = m ? decodeURIComponent(m[1]) : null\n return isNavDisplayPreference(v) ? v : null\n } catch {\n return null\n }\n}\n\n// Same host-aware scoping as the theme cookie: parent domain on\n// *.politogyvrm.com so every app subdomain reads it, host-only elsewhere\n// (localhost, *.pages.dev preview) because browsers silently drop a mismatched\n// Domain attribute. 1-year, SameSite=Lax, Secure on https.\nexport function writeNavDisplayCookie(pref: NavDisplayPreference): void {\n if (typeof document === 'undefined' || typeof window === 'undefined') return\n const host = window.location.hostname\n const domainAttr = /(^|\\.)politogyvrm\\.com$/i.test(host) ? '; Domain=.politogyvrm.com' : ''\n const secure = window.location.protocol === 'https:' ? '; Secure' : ''\n document.cookie = `${NAV_DISPLAY_COOKIE}=${encodeURIComponent(\n pref,\n )}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`\n}\n\n/** Read the local store, falling back to the legacy host-only key. */\nexport function readNavDisplayLocal(): NavDisplayPreference | null {\n if (typeof localStorage === 'undefined') return null\n try {\n const current = localStorage.getItem(NAV_DISPLAY_STORAGE_KEY)\n if (isNavDisplayPreference(current)) return current\n const legacy = localStorage.getItem(LEGACY_NAV_DISPLAY_KEY)\n return isNavDisplayPreference(legacy) ? legacy : null\n } catch {\n return null\n }\n}\n\nexport function writeNavDisplayLocal(pref: NavDisplayPreference): void {\n if (typeof localStorage === 'undefined') return\n try {\n localStorage.setItem(NAV_DISPLAY_STORAGE_KEY, pref)\n } catch {\n /* storage unavailable */\n }\n}\n\n/** Boot precedence: cookie → localStorage (incl. legacy) → default. */\nexport function resolveNavDisplay(): NavDisplayPreference {\n return readNavDisplayCookie() ?? readNavDisplayLocal() ?? NAV_DISPLAY_DEFAULT\n}\n\n// Inline pre-paint script — optional, and the mirror of THEME_PREPAINT_SCRIPT.\n// Nav display has no paint-blocking visual (the frame is client-rendered), but\n// seeding localStorage from the cookie before hydration keeps the first render\n// on the synced value instead of the default. Self-contained and silent.\nexport const NAV_DISPLAY_PREPAINT_SCRIPT = `(function(){try{\nvar KEY=${JSON.stringify(NAV_DISPLAY_STORAGE_KEY)};\nvar VALID=[\"menu\",\"tabs\",\"both\"];\nfunction fromCookie(){try{var m=document.cookie.match(/(?:^|;\\\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)/);return m?decodeURIComponent(m[1]):null;}catch(e){return null;}}\nvar cookie=fromCookie();\nif(cookie&&VALID.indexOf(cookie)!==-1){var ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}\nif(cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}}\n}catch(e){}})();`\n\n// ---------------------------------------------------------------------------\n// Rail expand preference — Left-Navigation §11.6: below `md` the rail\n// collapses to the 64px icon rail; \"the user can also collapse and expand it;\n// the choice is remembered per user\". Same cookie + localStorage layers as the\n// nav-display preference above (no server column yet), so the choice follows\n// the user across every app subdomain and survives reloads. Only an explicit\n// Expand / Collapse writes it; a route change that closes the overlay does not.\n// ---------------------------------------------------------------------------\n\nexport type RailPreference = 'expanded' | 'collapsed'\n\nexport const RAIL_STORAGE_KEY = 'politogy_rail'\nexport const RAIL_COOKIE = 'politogy_rail'\nexport const RAIL_DEFAULT: RailPreference = 'collapsed'\n\nexport function isRailPreference(v: unknown): v is RailPreference {\n return v === 'expanded' || v === 'collapsed'\n}\n\nexport function readRailPreference(): RailPreference {\n if (typeof document !== 'undefined') {\n try {\n const m = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${RAIL_COOKIE}=([^;]+)`))\n const v = m ? decodeURIComponent(m[1]) : null\n if (isRailPreference(v)) return v\n } catch {\n /* ignore */\n }\n }\n if (typeof localStorage !== 'undefined') {\n try {\n const v = localStorage.getItem(RAIL_STORAGE_KEY)\n if (isRailPreference(v)) return v\n } catch {\n /* ignore */\n }\n }\n return RAIL_DEFAULT\n}\n\nexport function writeRailPreference(pref: RailPreference): void {\n if (typeof document === 'undefined' || typeof window === 'undefined') return\n const host = window.location.hostname\n const domainAttr = /(^|\\.)politogyvrm\\.com$/i.test(host) ? '; Domain=.politogyvrm.com' : ''\n const secure = window.location.protocol === 'https:' ? '; Secure' : ''\n try {\n document.cookie = `${RAIL_COOKIE}=${pref}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`\n } catch {\n /* ignore */\n }\n try {\n localStorage.setItem(RAIL_STORAGE_KEY, pref)\n } catch {\n /* storage unavailable */\n }\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  import { warnDeprecated } from './chunk-LPSBSAF3.js';
2
2
  import { readThemeCookie, THEME_STORAGE_KEY, isThemePreference, applyThemePreference, readPendingThemeChoice, writeThemeCookie, clearPendingThemeChoice, markThemeChoicePending } from './chunk-NHBNM5P3.js';
3
- import { createContext, useRef, useState, useEffect, useContext, useCallback, useMemo, useSyncExternalStore } from 'react';
3
+ import { readRailPreference, writeRailPreference } from './chunk-7YVJ7HQG.js';
4
+ import { createContext, useRef, useState, useEffect, useContext, useCallback, useMemo, Fragment as Fragment$1, useSyncExternalStore } from 'react';
4
5
  import clsx from 'clsx';
5
6
  import { FiUser, FiSettings, FiMessageSquare, FiMail, FiInfo, FiSun, FiMoon, FiHelpCircle, FiLifeBuoy, FiAlertCircle, FiAlertTriangle, FiBell, FiGrid, FiZap, FiBatteryCharging, FiBattery } from 'react-icons/fi';
6
7
  import { createPortal } from 'react-dom';
@@ -90,7 +91,7 @@ function topBarIconButtonClass(tone = "default") {
90
91
  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)]";
91
92
  return [
92
93
  // `group/tbtip` powers the shared <TopBarTooltip> rendered inside the trigger.
93
- "group/tbtip relative flex items-center justify-center rounded-[var(--topbar-icon-button-radius,5px)] border border-[color:var(--line)] transition",
94
+ "group/tbtip relative flex items-center justify-center rounded-[var(--topbar-icon-button-radius,5px)] border border-transparent transition",
94
95
  "h-[var(--topbar-icon-button-size,34px)] w-[var(--topbar-icon-button-size,34px)]",
95
96
  toneClass
96
97
  ].join(" ");
@@ -1763,7 +1764,6 @@ var PHONEBANK_ORIGIN = "https://phonebank.politogyvrm.com/";
1763
1764
  var CANVASS_ORIGIN = "https://canvass.politogyvrm.com/";
1764
1765
  var SIGNS_ORIGIN = "https://signs.politogyvrm.com/";
1765
1766
  var POLLS_ORIGIN = "https://polls.politogyvrm.com/";
1766
- var CONTACTS_TRIBES = "https://contacts.politogyvrm.com/tribes";
1767
1767
  var PETITION_MODE_ORIGIN = "https://petition-mode.politogyvrm.com/";
1768
1768
  function applyHiddenItems(items, hidden) {
1769
1769
  if (!hidden || hidden.length === 0) return items;
@@ -1833,10 +1833,6 @@ var APP_POLLS_CHILDREN = [
1833
1833
  { label: "Command Center", icon: "grid", href: "https://polls.politogyvrm.com/" },
1834
1834
  { label: "New Poll", icon: "edit", href: "https://polls.politogyvrm.com/polls/new" }
1835
1835
  ];
1836
- var APP_CTAS_CHILDREN = [
1837
- { label: "CTAs", icon: "list", href: "https://ctas.politogyvrm.com/" },
1838
- { label: "Canvas", icon: "edit", href: "https://ctas.politogyvrm.com/?tab=canvas" }
1839
- ];
1840
1836
  var APP_A2P_CHILDREN = [
1841
1837
  { label: "Dashboard", icon: "grid", path: "dashboard" },
1842
1838
  { label: "Compose", icon: "edit", path: "compose" },
@@ -1884,16 +1880,27 @@ function standardPolitogyNav(opts) {
1884
1880
  return { label: c.label, icon: icon(c.icon), href: withOrg(withMode) };
1885
1881
  });
1886
1882
  };
1883
+ const accountRows = () => [
1884
+ { kind: "section", label: "Account" },
1885
+ // My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).
1886
+ { label: "My profile", icon: icon("circleUser"), href: withOrg(abs("/my-profile")) },
1887
+ {
1888
+ label: "Organization settings",
1889
+ icon: icon("settings"),
1890
+ href: withOrg(abs("/organization-settings")),
1891
+ children: branches(ORG_SETTINGS_CHILDREN)
1892
+ }
1893
+ ];
1887
1894
  const buildRelationship = () => {
1888
1895
  const contacts = opts.contactsItem ? {
1889
1896
  label: "Contacts",
1890
- icon: icon("users"),
1897
+ icon: icon("usersRound"),
1891
1898
  href: opts.contactsItem.href,
1892
1899
  children: opts.contactsItem.children,
1893
1900
  badge: opts.contactsItem.count ?? void 0
1894
1901
  } : {
1895
1902
  label: "Contacts",
1896
- icon: icon("users"),
1903
+ icon: icon("usersRound"),
1897
1904
  href: withOrg(`${CONTACTS_APP}/`),
1898
1905
  children: APP_CONTACTS_CHILDREN.map((c) => ({
1899
1906
  label: c.label,
@@ -1903,7 +1910,7 @@ function standardPolitogyNav(opts) {
1903
1910
  };
1904
1911
  return [
1905
1912
  { kind: "section", label: "Relationship" },
1906
- { label: "Dashboard", icon: icon("home"), href: withOrg(abs("/relationship/dashboard")) },
1913
+ { label: "Dashboard", icon: icon("layoutDashboard"), href: withOrg(abs("/relationship/dashboard")) },
1907
1914
  contacts,
1908
1915
  {
1909
1916
  label: "Email broadcast",
@@ -1926,40 +1933,20 @@ function standardPolitogyNav(opts) {
1926
1933
  },
1927
1934
  { kind: "section", label: "Collect" },
1928
1935
  // Carries no top-level href in VRM core (parent row only toggles).
1929
- { label: "Calls to action", icon: icon("layout"), children: leaves(CTA_CHILDREN) },
1936
+ { label: "Calls to action", icon: icon("mousePointerClick"), children: leaves(CTA_CHILDREN) },
1930
1937
  {
1931
1938
  label: "Forms",
1932
- icon: icon("activity"),
1939
+ icon: icon("fileText"),
1933
1940
  href: withOrg("https://forms.politogyvrm.com/"),
1934
1941
  children: APP_FORMS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
1935
1942
  },
1936
1943
  {
1937
1944
  label: "Surveys",
1938
- icon: icon("fileText"),
1945
+ icon: icon("clipboardList"),
1939
1946
  href: withOrg("https://surveys.politogyvrm.com/surveys"),
1940
1947
  children: APP_SURVEYS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
1941
1948
  },
1942
- {
1943
- label: "Polls",
1944
- icon: icon("barChart"),
1945
- href: withOrg("https://polls.politogyvrm.com/"),
1946
- children: APP_POLLS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
1947
- },
1948
- {
1949
- label: "CTAs",
1950
- icon: icon("layout"),
1951
- href: withOrg("https://ctas.politogyvrm.com/"),
1952
- children: APP_CTAS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
1953
- },
1954
- { kind: "section", label: "Account" },
1955
- // My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).
1956
- { label: "My profile", icon: icon("user"), href: withOrg(abs("/my-profile")) },
1957
- {
1958
- label: "Organization settings",
1959
- icon: icon("settings"),
1960
- href: withOrg(abs("/organization-settings")),
1961
- children: branches(ORG_SETTINGS_CHILDREN)
1962
- }
1949
+ ...accountRows()
1963
1950
  ];
1964
1951
  };
1965
1952
  const buildCampaign = () => {
@@ -1968,40 +1955,57 @@ function standardPolitogyNav(opts) {
1968
1955
  ...opts.campaignAvailability
1969
1956
  };
1970
1957
  const rows = [
1971
- { label: "Dashboard", icon: icon("home"), href: withOrg(abs("/campaign/dashboard")) },
1972
- { label: "Voter Contact", icon: icon("target"), href: withOrg(abs("/campaign/campaigns")) },
1958
+ // Left-Navigation §9.2: Race data -> Research -> GOTV -> Account.
1959
+ // Battleground is the Campaign landing page; there is no Campaign
1960
+ // Dashboard row, and Voter Contact and Tribes have no row.
1961
+ { kind: "section", label: "Race data" },
1962
+ { label: "Battleground", icon: icon("crosshair"), href: withOrg(abs("/campaign/battleground")) },
1963
+ { label: "District data", icon: icon("landmark"), href: withOrg(abs("/campaign/districts")) },
1964
+ { kind: "section", label: "Research" },
1973
1965
  {
1974
- label: "A2P",
1975
- icon: icon("messageSquare"),
1976
- href: withOrg(A2P_ORIGIN),
1977
- children: appLeaves(A2P_ORIGIN, APP_A2P_CHILDREN),
1978
- flag: "a2p"
1966
+ label: "Polling",
1967
+ icon: icon("chartNoAxes"),
1968
+ href: withOrg(POLLS_ORIGIN),
1969
+ children: APP_POLLS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) })),
1970
+ flag: "polling"
1971
+ },
1972
+ { kind: "section", label: "GOTV" },
1973
+ {
1974
+ label: "Field canvassing",
1975
+ icon: icon("doorOpen"),
1976
+ href: withOrg(CANVASS_ORIGIN),
1977
+ children: appLeaves(CANVASS_ORIGIN, APP_CANVASS_CHILDREN),
1978
+ flag: "canvass"
1979
1979
  },
1980
1980
  {
1981
- label: "Phone Banking",
1981
+ label: "Phone banking",
1982
1982
  icon: icon("phone"),
1983
1983
  href: withOrg(PHONEBANK_ORIGIN),
1984
1984
  children: appLeaves(PHONEBANK_ORIGIN, APP_PHONEBANK_CHILDREN),
1985
1985
  flag: "phonebank"
1986
1986
  },
1987
1987
  {
1988
- label: "Field Canvassing",
1989
- icon: icon("map"),
1990
- href: withOrg(CANVASS_ORIGIN),
1991
- children: appLeaves(CANVASS_ORIGIN, APP_CANVASS_CHILDREN),
1992
- flag: "canvass"
1988
+ label: "A2P texting",
1989
+ icon: icon("messageSquare"),
1990
+ href: withOrg(A2P_ORIGIN),
1991
+ children: appLeaves(A2P_ORIGIN, APP_A2P_CHILDREN),
1992
+ flag: "a2p"
1993
1993
  },
1994
1994
  {
1995
- label: "Sign Mapping",
1996
- icon: icon("mapPin"),
1995
+ label: "Sign mapping",
1996
+ icon: icon("signpost"),
1997
1997
  href: withOrg(SIGNS_ORIGIN),
1998
1998
  children: appLeaves(SIGNS_ORIGIN, APP_SIGNS_CHILDREN),
1999
1999
  flag: "signs"
2000
2000
  },
2001
- { label: "Tribes", icon: icon("users"), href: withOrg(CONTACTS_TRIBES), flag: "tribes" },
2002
- { label: "Polling Engine", icon: icon("barChart"), href: withOrg(POLLS_ORIGIN), flag: "polling" }
2001
+ ...accountRows()
2003
2002
  ];
2004
- return rows.filter((r) => !r.flag || avail[r.flag]).map(({ flag: _flag, ...item }) => item);
2003
+ const kept = rows.filter((r) => !r.flag || avail[r.flag]).map(({ flag: _flag, ...item }) => item);
2004
+ return kept.filter((item, idx) => {
2005
+ if (item.kind !== "section") return true;
2006
+ const next = kept[idx + 1];
2007
+ return !!next && next.kind !== "section";
2008
+ });
2005
2009
  };
2006
2010
  const buildPetition = () => [
2007
2011
  opts.petitionsItem ? {
@@ -2108,7 +2112,9 @@ function NavSidebar({
2108
2112
  footer,
2109
2113
  linkComponent,
2110
2114
  open,
2111
- onClose
2115
+ onClose,
2116
+ onOpen,
2117
+ onNavigate
2112
2118
  }) {
2113
2119
  const Link = linkComponent ?? DefaultLink;
2114
2120
  const collapsible = !open;
@@ -2205,7 +2211,7 @@ function NavSidebar({
2205
2211
  style: { fontFamily: 'var(--font-family, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif)' },
2206
2212
  onKeyDown: trapTab,
2207
2213
  onClick: (e) => {
2208
- if (open && e.target.closest("a[href]")) onClose?.();
2214
+ if (open && e.target.closest("a[href]")) (onNavigate ?? onClose)?.();
2209
2215
  },
2210
2216
  children: [
2211
2217
  open ? /* @__PURE__ */ jsx(
@@ -2214,18 +2220,30 @@ function NavSidebar({
2214
2220
  type: "button",
2215
2221
  ref: closeButtonRef,
2216
2222
  onClick: onClose,
2217
- "aria-label": "Close menu",
2223
+ "aria-label": "Collapse navigation",
2218
2224
  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",
2219
2225
  children: /* @__PURE__ */ jsx(CloseIcon, {})
2220
2226
  }
2221
2227
  ) : null,
2222
2228
  /* @__PURE__ */ 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: [
2229
+ onOpen ? /* @__PURE__ */ jsx(
2230
+ "button",
2231
+ {
2232
+ type: "button",
2233
+ onClick: onOpen,
2234
+ "aria-label": "Expand navigation",
2235
+ "aria-expanded": open ?? false,
2236
+ "data-rail-toggle": "expand",
2237
+ className: `hidden h-8 w-8 items-center justify-center rounded-lg ${rc("max-md:flex")}`,
2238
+ children: brand.logoSquareSrc ? /* @__PURE__ */ jsx("img", { src: brand.logoSquareSrc, alt: "", draggable: false, className: "h-8 w-8 object-contain" }) : brand.logoPending ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "block h-8 w-8" }) : /* @__PURE__ */ 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 })
2239
+ }
2240
+ ) : null,
2223
2241
  /* @__PURE__ */ jsxs(
2224
2242
  Link,
2225
2243
  {
2226
2244
  href: brand.homeHref ?? "/",
2227
2245
  "aria-label": brand.logoAlt ?? brand.title,
2228
- className: `flex items-center gap-2.5 ${rc("max-md:justify-center")}`,
2246
+ className: `flex items-center gap-2.5 ${rc("max-md:justify-center")} ${onOpen ? rc("max-md:hidden") : ""}`,
2229
2247
  children: [
2230
2248
  brand.logoSquareSrc ? /* @__PURE__ */ jsx(
2231
2249
  "img",
@@ -2269,7 +2287,7 @@ function NavSidebar({
2269
2287
  }
2270
2288
  ),
2271
2289
  org ? /* @__PURE__ */ jsxs("div", { className: rc("max-md:flex max-md:justify-center"), children: [
2272
- /* @__PURE__ */ jsx("div", { className: `mb-[7px] flex items-center justify-between ${rc("max-md:hidden")}`, children: /* @__PURE__ */ jsx("p", { className: NAV_EYEBROW_CLASS, children: "Organization" }) }),
2290
+ /* @__PURE__ */ jsx("div", { className: `mb-[7px] mt-[7px] flex items-center justify-between ${rc("max-md:hidden")}`, children: /* @__PURE__ */ jsx("p", { className: NAV_EYEBROW_CLASS, children: "Organization" }) }),
2273
2291
  org.loading ? /* @__PURE__ */ 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: [
2274
2292
  /* @__PURE__ */ jsx(
2275
2293
  "span",
@@ -2295,7 +2313,7 @@ function NavSidebar({
2295
2313
  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")}`,
2296
2314
  children: [
2297
2315
  /* @__PURE__ */ jsx(OrgIconMark, { org, logoSrc: orgLogoSrc }),
2298
- /* @__PURE__ */ 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: [
2316
+ /* @__PURE__ */ 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: [
2299
2317
  orgLogoSrc ? /* @__PURE__ */ jsx("img", { src: orgLogoSrc, alt: "", className: "max-h-full max-w-[132px] object-contain" }) : org.canUploadLogo ? /* @__PURE__ */ jsx(
2300
2318
  "a",
2301
2319
  {
@@ -2307,7 +2325,7 @@ function NavSidebar({
2307
2325
  ) : /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-semibold text-neutral-800", children: org.name ?? "Organization" }),
2308
2326
  /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "absolute inset-x-0 bottom-0 h-[3px]", style: { backgroundImage: orgGradient } })
2309
2327
  ] }),
2310
- /* @__PURE__ */ jsxs("span", { className: `flex w-full min-w-0 items-center justify-between gap-[9px] px-[10px] py-2 ${rc("max-md:hidden")}`, children: [
2328
+ /* @__PURE__ */ jsxs("span", { className: `flex w-full min-w-0 items-center justify-between gap-[9px] px-[10px] py-[10px] ${rc("max-md:hidden")}`, children: [
2311
2329
  /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
2312
2330
  /* @__PURE__ */ jsx(
2313
2331
  "span",
@@ -2397,7 +2415,7 @@ function NavSidebar({
2397
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))] ${rc("max-md:w-auto max-md:items-center max-md:overflow-visible max-md:border-0 max-md:bg-transparent")}`,
2398
2416
  children: [
2399
2417
  /* @__PURE__ */ jsx(OrgIconMark, { org, logoSrc: orgLogoSrc }),
2400
- /* @__PURE__ */ 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
+ /* @__PURE__ */ 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: [
2401
2419
  orgLogoSrc ? /* @__PURE__ */ jsx("img", { src: orgLogoSrc, alt: "", className: "max-h-full max-w-[132px] object-contain" }) : org.canUploadLogo ? /* @__PURE__ */ jsx(
2402
2420
  "a",
2403
2421
  {
@@ -2409,7 +2427,7 @@ function NavSidebar({
2409
2427
  ) : /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-semibold text-neutral-800", children: org.name ?? "Organization" }),
2410
2428
  /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "absolute inset-x-0 bottom-0 h-[3px]", style: { backgroundImage: orgGradient } })
2411
2429
  ] }),
2412
- /* @__PURE__ */ 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
+ /* @__PURE__ */ jsxs("span", { className: `flex w-full min-w-0 items-center justify-between gap-[9px] px-[10px] py-[10px] ${rc("max-md:hidden")}`, children: [
2413
2431
  /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
2414
2432
  /* @__PURE__ */ jsx(
2415
2433
  "span",
@@ -2454,7 +2472,7 @@ function NavSidebar({
2454
2472
  },
2455
2473
  disabled: !available,
2456
2474
  className: [
2457
- "flex flex-1 items-center justify-center rounded-[5px] px-[9px] py-[6px] transition",
2475
+ `flex flex-none items-center justify-center rounded-[5px] px-[9px] py-[6px] transition ${rc("max-md:flex-1")}`,
2458
2476
  !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))]"
2459
2477
  ].join(" "),
2460
2478
  children: OptIcon ? /* @__PURE__ */ jsx(OptIcon, { size: 15, className: "shrink-0" }) : null
@@ -2544,15 +2562,17 @@ function NavSidebar({
2544
2562
  onSignOut: footer.onSignOut
2545
2563
  }
2546
2564
  ) : null,
2547
- footer.links && footer.links.length > 0 ? /* @__PURE__ */ 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__ */ jsx(
2548
- "a",
2549
- {
2550
- href: safeHref(l.href),
2551
- className: "text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))] hover:text-[color:var(--sidebar-text,var(--foreground))] hover:underline",
2552
- children: l.label
2553
- },
2554
- l.label
2555
- )) }) : null,
2565
+ footer.links && footer.links.length > 0 ? /* @__PURE__ */ 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__ */ jsxs(Fragment$1, { children: [
2566
+ i > 0 ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))]", children: "\xB7" }) : null,
2567
+ /* @__PURE__ */ jsx(
2568
+ "a",
2569
+ {
2570
+ href: safeHref(l.href),
2571
+ className: "text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))] hover:text-[color:var(--sidebar-text,var(--foreground))] hover:underline",
2572
+ children: l.label
2573
+ }
2574
+ )
2575
+ ] }, l.label)) }) : null,
2556
2576
  footer.envLabel && footer.envLabel.trim().toLowerCase() !== "production" ? /* @__PURE__ */ jsxs(
2557
2577
  "div",
2558
2578
  {
@@ -2999,7 +3019,7 @@ function NavTopBar({
2999
3019
  const initials = (hasRealName ? rawName : user?.email ?? "P").slice(0, 2).toUpperCase();
3000
3020
  const secondary = hasRealName ? user?.email || [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member" : [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member";
3001
3021
  return /* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-20", children: [
3002
- /* @__PURE__ */ 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: [
3022
+ /* @__PURE__ */ 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: [
3003
3023
  onOpenNav ? /* @__PURE__ */ jsx(
3004
3024
  "button",
3005
3025
  {
@@ -3012,7 +3032,7 @@ function NavTopBar({
3012
3032
  children: /* @__PURE__ */ jsx(HamburgerIcon, {})
3013
3033
  }
3014
3034
  ) : null,
3015
- /* @__PURE__ */ jsxs("label", { className: "relative flex h-9 w-[320px] max-w-full shrink-0 items-center", children: [
3035
+ /* @__PURE__ */ jsxs("label", { className: "relative flex h-9 w-[320px] min-w-0 max-w-full shrink items-center md:shrink-0", children: [
3016
3036
  /* @__PURE__ */ jsx(SearchIcon, { className: "pointer-events-none absolute left-[10px] h-[15px] w-[15px] text-[color:var(--muted)]" }),
3017
3037
  /* @__PURE__ */ jsx(
3018
3038
  "input",
@@ -3032,13 +3052,13 @@ function NavTopBar({
3032
3052
  "kbd",
3033
3053
  {
3034
3054
  "aria-hidden": true,
3035
- 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)]",
3055
+ 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)]",
3036
3056
  children: "/"
3037
3057
  }
3038
3058
  )
3039
3059
  ] }),
3040
3060
  /* @__PURE__ */ jsxs("div", { className: "relative ml-auto flex shrink-0 items-center gap-[var(--topbar-icon-gap,8px)]", children: [
3041
- /* @__PURE__ */ jsxs(
3061
+ buildNotes ? /* @__PURE__ */ jsxs(
3042
3062
  "button",
3043
3063
  {
3044
3064
  type: "button",
@@ -3049,7 +3069,7 @@ function NavTopBar({
3049
3069
  buildNotes?.label ?? "Build notes"
3050
3070
  ]
3051
3071
  }
3052
- ),
3072
+ ) : null,
3053
3073
  actionsList && actionsList.length > 0 ? actionsList.map((action) => /* @__PURE__ */ jsx(NavTopBarActionButton, { action }, action.key)) : null,
3054
3074
  actions,
3055
3075
  themeToggle,
@@ -3624,9 +3644,22 @@ function NavAppShell({
3624
3644
  );
3625
3645
  }
3626
3646
  const [navOpen, setNavOpen] = useState(false);
3647
+ const expandRail = () => {
3648
+ writeRailPreference("expanded");
3649
+ setNavOpen(true);
3650
+ };
3651
+ const collapseRail = () => {
3652
+ writeRailPreference("collapsed");
3653
+ setNavOpen(false);
3654
+ };
3627
3655
  useEffect(() => {
3628
3656
  setNavOpen(false);
3629
3657
  }, [sidebar.pathname]);
3658
+ useEffect(() => {
3659
+ if (readRailPreference() !== "expanded") return;
3660
+ const narrow = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(max-width: 767.98px)").matches : false;
3661
+ if (narrow) setNavOpen(true);
3662
+ }, []);
3630
3663
  useEffect(() => {
3631
3664
  if (!navOpen) return;
3632
3665
  const previous = document.body.style.overflow;
@@ -3647,15 +3680,23 @@ function NavAppShell({
3647
3680
  "data-politogy-mode": modeId,
3648
3681
  className: "min-h-screen bg-[color:var(--background)] text-[color:var(--foreground)]",
3649
3682
  children: [
3650
- /* @__PURE__ */ jsx(NavSidebar, { ...sidebar, footer: sidebarFooter, open: navOpen, onClose: () => setNavOpen(false) }),
3683
+ /* @__PURE__ */ jsx(
3684
+ NavSidebar,
3685
+ {
3686
+ ...sidebar,
3687
+ footer: sidebarFooter,
3688
+ open: navOpen,
3689
+ onClose: collapseRail,
3690
+ onOpen: expandRail,
3691
+ onNavigate: () => setNavOpen(false)
3692
+ }
3693
+ ),
3651
3694
  /* @__PURE__ */ jsxs("div", { className: "pl-[var(--sidebar-collapsed-width,64px)] md:pl-[var(--sidebar-width,236px)]", children: [
3652
3695
  /* @__PURE__ */ jsx(
3653
3696
  NavTopBar,
3654
3697
  {
3655
3698
  ...topBar,
3656
- accountMenu: topBar.accountMenu ?? (accountMenuPlacement === "sidebar" ? "sidebar" : "topbar"),
3657
- onOpenNav: () => setNavOpen(true),
3658
- navOpen
3699
+ accountMenu: topBar.accountMenu ?? (accountMenuPlacement === "sidebar" ? "sidebar" : "topbar")
3659
3700
  }
3660
3701
  ),
3661
3702
  betaBanner ? /* @__PURE__ */ jsx(NavBetaBanner, { ...betaBanner }) : null,
@@ -3684,5 +3725,5 @@ function NavAppShell({
3684
3725
  }
3685
3726
 
3686
3727
  export { BETA_BANNER_DISMISS_KEY, CAMPAIGN_FEATURE_AVAILABILITY, CORE_APP_ORIGIN, CORE_BILLING_PATH, FuelAction, NavAppShell, NavBetaBanner, NavChromeProvider, NavDisplayAction, NavSidebar, NavTabStrip, NavThemeControl, NavTopBar, NotificationsAction, SPECS_ORIGIN, SpecOverlayAction, SupportAction, TopBarCountBadge, TopBarPanelArrow, TopBarPopover, TopBarTooltip, TopBarWidgetSlot, clearBetaBannerDismissal, envChipClasses, isNavItemActive, resolveOrgLogoUrl, standardPolitogyNav, topBarIconButtonClass, useChromeMe, useChromeOrgs, useNavChromeFetcher, useThemePreference };
3687
- //# sourceMappingURL=chunk-WFUWFMCA.js.map
3688
- //# sourceMappingURL=chunk-WFUWFMCA.js.map
3728
+ //# sourceMappingURL=chunk-B2AQL37X.js.map
3729
+ //# sourceMappingURL=chunk-B2AQL37X.js.map