/* ==========================================================================
 * THE SHELL LAYER — one file, one content-hashed path, both hosts (#6220).
 *
 * GENERATED by scripts/build-shell-static.ts — do not hand-edit. Sources, in order:
 *   - apps/groups/public/fonts/core.css
 *   - packages/core/src/ui/shell-tokens.css
 *   - packages/shell/src/styles.css
 *
 * Served immutable from ONE origin so a hop between the admin and member hosts
 * re-uses a single cache entry (the baseline this replaces: planning/shell/baseline-2026-09.md).
 * `@font-face` URLs are root-relative on purpose: they resolve against THIS sheet's
 * origin, so the same bytes work on the static origin and on an app origin in dev.
 *
 * Everything is inside `@layer shell` so an unlayered host rule wins an equal-specificity
 * tie regardless of where this <link> lands in <head> — the cascade both apps already had
 * when they imported this sheet first, now independent of link order.
 * ========================================================================== */
@layer shell {
  /* Shell type pair (#6205), both hosts: Bricolage Grotesque (display) + Hanken Grotesk (body), variable.
   * GENERATED by scripts/fetch-self-hosted-fonts.mjs — do not hand-edit.
   * Source: https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400..800&family=Hanken+Grotesk:wght@400..800&display=swap
   * Files are the exact fonts.gstatic.com binaries, served same-origin. */

  /* vietnamese */
  @font-face {
    font-family: 'Bricolage Grotesque';
    font-style: normal;
    font-weight: 400 800;
    font-stretch: 100%;
    font-display: swap;
    src: url(/fonts/files/bricolagegrotesque-v9-3y9K6as8bTXq_nANBjzKo3IeZx8z6up5BeSl9D4dj_x9PpZBMlGHInHWVyNJtvI.woff2) format('woff2');
    unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
  }
  /* latin-ext */
  @font-face {
    font-family: 'Bricolage Grotesque';
    font-style: normal;
    font-weight: 400 800;
    font-stretch: 100%;
    font-display: swap;
    src: url(/fonts/files/bricolagegrotesque-v9-3y9K6as8bTXq_nANBjzKo3IeZx8z6up5BeSl9D4dj_x9PpZBMlGGInHWVyNJtvI.woff2) format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
  }
  /* latin */
  @font-face {
    font-family: 'Bricolage Grotesque';
    font-style: normal;
    font-weight: 400 800;
    font-stretch: 100%;
    font-display: swap;
    src: url(/fonts/files/bricolagegrotesque-v9-3y9K6as8bTXq_nANBjzKo3IeZx8z6up5BeSl9D4dj_x9PpZBMlGIInHWVyNJ.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  /* cyrillic-ext */
  @font-face {
    font-family: 'Hanken Grotesk';
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url(/fonts/files/hankengrotesk-v12-ieVn2YZDLWuGJpnzaiwFXS9tYtpQ59CxCis4UvI.woff2) format('woff2');
    unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
  }
  /* vietnamese */
  @font-face {
    font-family: 'Hanken Grotesk';
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url(/fonts/files/hankengrotesk-v12-ieVn2YZDLWuGJpnzaiwFXS9tYtpS59CxCis4UvI.woff2) format('woff2');
    unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
  }
  /* latin-ext */
  @font-face {
    font-family: 'Hanken Grotesk';
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url(/fonts/files/hankengrotesk-v12-ieVn2YZDLWuGJpnzaiwFXS9tYtpT59CxCis4UvI.woff2) format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
  }
  /* latin */
  @font-face {
    font-family: 'Hanken Grotesk';
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url(/fonts/files/hankengrotesk-v12-ieVn2YZDLWuGJpnzaiwFXS9tYtpd59CxCis4.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }

  /* ============================================================================
   * SHELL TOKENS — the ONE chrome palette both hats read (epic #6203 §2.1, story #6206).
   *
   * Imported, byte-identical, by the admin app (`apps/admin/app/globals.css`) and the
   * member surfaces (`apps/groups/app/member-shell.css`, `portal/portal.css`, `you/you.css`).
   * Each of those sheets used to carry its own copy of these names with values that had
   * drifted apart; now they carry none, so the two hats cannot repaint the frame when a
   * person switches between them.
   *
   * Light values are the admin warm-neutral set (the one the admin-ux-consistency pass has
   * been ratcheting toward). Status literals keep the WCAG ratios #3303/#3313 measured:
   * --c-ok #1a7d51 5.13:1 on #fff · --c-warn #8f5b0e 5.72:1 · --c-danger #c33a32 (fill).
   *
   * `--accent` is the SINGLE brand slot. Default is Golbi blue; the derived ramp is a
   * `color-mix` off it, so a preset (#6211/#6212) re-skins both hats by setting one name.
   * `--brand` and its ramp are ALIASES of `--accent` for one release so nothing repaints;
   * `scripts/brand-alias-readers-ledger.json` lists the remaining `var(--brand…)` readers
   * and may only shrink.
   *
   * Dark: the `[data-theme="dark"]` block is admin's, verbatim, with a dark value for every
   * colour above (radii need none). The member surfaces still flip on their own signals
   * (`.site[data-mode="dark"]`, `prefers-color-scheme`); folding those onto this block is
   * #6212 / #3396, not this file.
   *
   * ⚠️ Add a name here ONLY after deleting it from every consumer's own `:root`/`.pweb`/
   * `.you-app` block: a consumer's later declaration of the same name would override the
   * dark value below (this sheet loads FIRST) and put the light colour back in dark mode.
   * ========================================================================== */

  :root {
    /* — the accent slot + its derived ramp — */
    --accent: #3457D5;
    --accent-ink: #ffffff;
    --accent-50:  color-mix(in oklab, var(--accent) 8%,  #fff);
    --accent-100: color-mix(in oklab, var(--accent) 14%, #fff);
    --accent-200: color-mix(in oklab, var(--accent) 26%, #fff);
    --accent-300: color-mix(in oklab, var(--accent) 45%, #fff);
    --accent-600: color-mix(in oklab, var(--accent) 84%, #000);
    --accent-700: color-mix(in oklab, var(--accent) 68%, #000);
    --accent-soft:   color-mix(in oklab, var(--accent) 10%, var(--c-surface));
    --accent-softer: color-mix(in oklab, var(--accent) 6%,  var(--c-surface));

    /* — `--brand` alias, one release (#6206) —
       The ramp is mixed off `--brand` itself, NOT aliased step-for-step to `--accent-*`:
       admin's AppShell / template gallery still set `--brand` inline for a branded org, and
       the tints must keep following that override exactly as they did on admin's own :root.
       When the alias retires, those call sites set `--accent` and this block goes. */
    --brand:        var(--accent);
    --brand-ink:    var(--accent-ink);
    --brand-50:     color-mix(in oklab, var(--brand) 8%,  #fff);
    --brand-100:    color-mix(in oklab, var(--brand) 14%, #fff);
    --brand-200:    color-mix(in oklab, var(--brand) 26%, #fff);
    --brand-300:    color-mix(in oklab, var(--brand) 45%, #fff);
    --brand-600:    color-mix(in oklab, var(--brand) 84%, #000);
    --brand-700:    color-mix(in oklab, var(--brand) 68%, #000);
    --brand-soft:   color-mix(in oklab, var(--brand) 10%, var(--c-surface));
    --brand-softer: color-mix(in oklab, var(--brand) 6%,  var(--c-surface));

    /* — chrome neutrals — */
    --c-bg:            #f4f2ec;
    --c-surface:       #ffffff;
    --c-surface-2:     #faf8f3;
    --c-surface-3:     #f0ede5;
    --c-border:        #e7e2d6;
    --c-border-2:      #d9d3c4;
    --c-border-strong: #c7c0ad;
    --c-text:     #24262b;
    --c-text-2:   #595c63;
    --c-text-3:   #6d6a60;
    --c-text-inv: #ffffff;

    /* — status — */
    /* #167a4f, not #1a7d51. The old value measured 4.36:1 on `--ok-bg` (its own 12% tint),
       which is the ground it is used on in eight admin rules — a status colour failing AA on
       its own chip. Moved by `adjustForContrast`: same hue, the smallest step that clears
       4.5 (it lands at 4.54). Found by `check:contrast-pairs`. */
    --c-ok:     #167a4f;
    --c-warn:   #8f5b0e;
    --c-danger: #c33a32;

    /* — radii — */
    --r-xs: 5px; --r-sm: 7px; --r-md: 10px; --r-lg: 14px; --r-xl: 20px; --r-pill: 999px;

    /* — elevation — */
    --sh-xs: 0 1px 2px rgba(40,36,28,.05);
    --sh-sm: 0 1px 2px rgba(40,36,28,.05), 0 2px 6px rgba(40,36,28,.05);
    --sh-md: 0 2px 4px rgba(40,36,28,.05), 0 8px 22px rgba(40,36,28,.09);
    --sh-lg: 0 6px 14px rgba(40,36,28,.08), 0 24px 48px rgba(40,36,28,.14);
    --sh-pop: 0 8px 28px rgba(40,36,28,.16);
  }

  [data-theme="dark"] {
    --accent-ink: #ffffff;
    --accent-soft:   color-mix(in oklab, var(--accent) 22%, var(--c-surface));
    --accent-softer: color-mix(in oklab, var(--accent) 14%, var(--c-surface));
    --accent-50:  color-mix(in oklab, var(--accent) 16%, var(--c-surface));
    --accent-100: color-mix(in oklab, var(--accent) 24%, var(--c-surface));
    --accent-200: color-mix(in oklab, var(--accent) 38%, var(--c-surface));
    --accent-300: color-mix(in oklab, var(--accent) 58%, #fff);
    --brand-soft:   color-mix(in oklab, var(--brand) 22%, var(--c-surface));
    --brand-softer: color-mix(in oklab, var(--brand) 14%, var(--c-surface));
    --brand-50:  color-mix(in oklab, var(--brand) 16%, var(--c-surface));
    --brand-100: color-mix(in oklab, var(--brand) 24%, var(--c-surface));
    --brand-200: color-mix(in oklab, var(--brand) 38%, var(--c-surface));
    --brand-300: color-mix(in oklab, var(--brand) 58%, #fff);

    --c-bg:            #131419;
    --c-surface:       #1b1d23;
    --c-surface-2:     #212430;
    --c-surface-3:     #2a2d39;
    --c-border:        #2d3039;
    --c-border-2:      #383c47;
    --c-border-strong: #474c59;
    --c-text:   #ecedf1;
    --c-text-2: #a9adb8;
    --c-text-3: #8f95a2;

    --c-ok:     #3bbd84;
    --c-warn:   #e1a13f;
    --c-danger: #ef6a61;

    --sh-xs: 0 1px 2px rgba(0,0,0,.3);
    --sh-sm: 0 1px 2px rgba(0,0,0,.3), 0 2px 6px rgba(0,0,0,.25);
    --sh-md: 0 2px 6px rgba(0,0,0,.35), 0 10px 24px rgba(0,0,0,.4);
    --sh-lg: 0 10px 26px rgba(0,0,0,.45), 0 28px 56px rgba(0,0,0,.55);
    --sh-pop: 0 10px 34px rgba(0,0,0,.55);
  }


  .shell-sr {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  .shell-rail-row,
  .shell-tab,
  .shell-button,
  .shell-mode-toggle,
  .shell-org-chip,
  .shell-chip,
  .shell-list-row {
    appearance: none;
    box-sizing: border-box;
    font: inherit;
    letter-spacing: 0;
    text-decoration: none;
    border: 1px solid transparent;
    cursor: pointer;
    color: var(--c-text);
    -webkit-tap-highlight-color: transparent;
  }

  .shell-rail-row:disabled,
  .shell-tab:disabled,
  .shell-button:disabled,
  .shell-mode-toggle:disabled,
  .shell-org-chip:disabled,
  .shell-chip:disabled,
  .shell-list-row:disabled {
    cursor: not-allowed;
    opacity: .56;
  }

  .shell-action-icon,
  .shell-action-trailing,
  .shell-badge,
  .shell-notification-dot {
    flex: none;
  }

  .shell-action-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
  }

  .shell-action-label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /*
   * ALWAYS A CIRCLE, whatever the count.
   *
   * This was `min-width: 22px; height: 22px; padding: 0 8px`, which is a circle at one digit
   * and an oval at two or three — and "99+" (what every host caps at: see `app-shell.tsx`
   * and `portal-tabbar.tsx`) was the widest, so the badge changed shape exactly when it was
   * most prominent. `aspect-ratio: 1` with a free height is what holds the shape: wider
   * content grows the box in BOTH axes instead of stretching it into a pill, so a 3-glyph
   * badge is simply a larger circle. A fixed width would have clipped the glyphs instead.
   */
  .shell-badge {
    min-width: 22px;
    min-height: 22px;
    height: auto;
    aspect-ratio: 1;
    padding: 0 4px;
    border-radius: var(--r-pill);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--accent-700);
    background: var(--accent-100);
    font-size: 12px;
    font-weight: 700;
    line-height: 1;
  }

  .shell-notification-dot {
    width: 8px;
    height: 8px;
    border-radius: var(--r-pill);
    background: var(--c-danger);
    box-shadow: 0 0 0 2px var(--c-surface);
  }

  .shell-rail-row,
  .shell-list-row {
    width: 100%;
    min-height: 44px;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 12px;
    border-radius: var(--r-md);
    background: transparent;
  }

  @media (hover: hover) {
    .shell-rail-row:hover,
    .shell-list-row:hover {
      background: var(--c-surface-2);
    }
  }

  .shell-rail-row[data-active="true"],
  .shell-list-row[data-active="true"] {
    color: var(--accent-700);
    background: var(--accent-50);
    border-color: var(--accent-200);
  }

  .shell-tab {
    min-height: 56px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 0 14px;
    border-radius: var(--r-md);
    background: transparent;
    color: var(--c-text-2);
    position: relative;
  }

  .shell-tab[data-active="true"] {
    color: var(--accent-700);
  }

  .shell-tab[data-active="true"]::after {
    content: "";
    position: absolute;
    left: 14px;
    right: 14px;
    bottom: 6px;
    height: 3px;
    border-radius: var(--r-pill);
    background: var(--accent);
  }

  .shell-button,
  .shell-mode-toggle {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 0 14px;
    border-radius: var(--r-md);
    font-weight: 700;
  }

  .shell-button-sm {
    min-height: 44px;
    padding: 0 11px;
    font-size: 13px;
  }

  .shell-button-default,
  .shell-mode-toggle {
    background: var(--c-surface);
    border-color: var(--c-border);
    box-shadow: var(--sh-xs);
  }

  .shell-button-primary {
    color: var(--accent-ink);
    background: var(--accent);
    border-color: var(--accent);
    box-shadow: var(--sh-sm);
  }

  .shell-button-ghost {
    background: transparent;
    color: var(--c-text-2);
  }

  .shell-mode-toggle[data-pressed="true"] {
    color: var(--accent-700);
    background: var(--accent-50);
    border-color: var(--accent-200);
  }

  /* #7552: dark mode redefines `--accent-50` as a dark tint but not `--accent-700`, so the
     light rule above measured ~1.3:1 there. The pressed hat goes solid instead: the accent
     with its own ink, a pair every ramp already contrast-checks (`accentRamp`), and one that
     does not depend on which surface a preset's tints were mixed toward. Light is unchanged. */
  [data-theme="dark"] .shell-mode-toggle[data-pressed="true"] {
    color: var(--accent-ink);
    background: var(--accent);
    border-color: var(--accent);
  }

  .shell-org-chip,
  .shell-chip {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    border-radius: var(--r-pill);
    color: var(--c-text);
    background: rgba(255,255,255,.58);
    border-color: rgba(255,255,255,.64);
    backdrop-filter: blur(12px);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.3), var(--sh-xs);
  }

  /*
   * THE CHIP IS WHAT GIVES WAY in a crowded bar. It is the only item there with content that
   * can reflow — its label already carries `min-width: 0` and an ellipsis — so it, not the
   * fixed-size icon buttons or the search pill, should absorb the squeeze. A flex item's
   * default `min-width: auto` floors it at its own min-content, which left the admin's top
   * bar overflowing by 20px at a ~920px viewport (the avatar clipped off the right edge)
   * while the chip sat at its full 301px refusing to give. `0` lets the ellipsis do its job.
   */
  /* #7565: the white glass wash above is a light-mode ground. Left on in dark it put the
     light dark-mode text on a near-white pill (~2.2:1). Same glass, dark-tinted. */
  [data-theme="dark"] .shell-org-chip,
  [data-theme="dark"] .shell-chip {
    background: rgba(255,255,255,.08);
    border-color: rgba(255,255,255,.14);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.06), var(--sh-xs);
  }

  .shell-org-chip {
    min-width: 0;
    padding: 4px 12px 4px 5px;
  }

  .shell-chip {
    padding: 0 14px;
  }

  .shell-org-chip[data-active="true"],
  .shell-chip[data-active="true"],
  .shell-chip-accent {
    color: var(--accent-700);
    background: color-mix(in oklab, var(--accent) 16%, rgba(255,255,255,.66));
    border-color: color-mix(in oklab, var(--accent) 28%, rgba(255,255,255,.72));
  }

  .shell-chip-danger {
    color: var(--c-text);
  }

  .shell-org-chip-avatar {
    /* MUST NOT SHRINK. The declared box is square and `border-radius: 50%` makes it a circle
     * — but this is a flex ITEM sitting next to a long org name, and the default
     * `flex-shrink: 1` let the row steal width from it: measured 24x32 in the top-bar chip
     * and 24.5x32 in the switcher panel, i.e. an egg, not a crest. A circle only stays a
     * circle if the box cannot be compressed on one axis, so the sibling label is what gives
     * (it already carries `min-width: 0` + ellipsis for exactly that). Same reason the
     * `.shell-action-icon` / `.shell-badge` group above is `flex: none`. */
    flex: none;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    object-fit: cover;
    color: var(--accent-ink);
    background: var(--accent);
    font-size: 12px;
    font-weight: 800;
  }

  .shell-chip-row {
    display: flex;
    flex-wrap: nowrap;
    gap: 8px;
    overflow-x: auto;
    scrollbar-width: thin;
  }

  .shell-list-row-copy {
    min-width: 0;
    display: grid;
    gap: 2px;
    flex: 1 1 auto;
    text-align: left;
  }

  .shell-list-row-title {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--c-text);
    font-weight: 700;
  }

  .shell-list-row-body {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--c-text-2);
    font-size: 13px;
  }

  .shell-card {
    box-sizing: border-box;
    border: 1px solid var(--c-border);
    border-radius: var(--r-sm);
    background: var(--c-surface);
    color: var(--c-text);
    box-shadow: var(--sh-sm);
    padding: 16px;
  }

  .shell-card-interactive {
    transition: border-color .16s ease, box-shadow .16s ease, transform .16s ease;
  }

  @media (hover: hover) {
    .shell-card-interactive:hover {
      border-color: var(--accent-200);
      box-shadow: var(--sh-md);
      transform: translateY(-1px);
    }
  }

  /* ============================================================================
   * THE CHROME CONTAINERS (#6209, epic #6203 §2.3): rail, top bar, app bar, tab bar.
   *
   * Neutral by default — the surface tokens for the ground, `--accent` for the active
   * state — so the frame is the same on both hats until a preset (#6211/#6212) sets
   * `--accent`. The host paints NO chrome of its own: it mounts these, hands them rows and
   * chips, and keeps its content column beside/below them.
   *
   * Hosts clear `--shell-tab-bar-height` (64px) + `--shell-tab-bar-float` (16px) + the
   * bottom safe area under their scrollers. A host may set the height on its frame.
   * ========================================================================== */

  .shell-rail {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    /* `--shell-rail-width` is the second number shared with the host, for ONE reason: a host
       may collapse its rail to an icon column (the admin's `data-nav="rail"` state). A state
       the host declares by setting the token, never by redeclaring the rail. */
    width: var(--shell-rail-width, 258px);
    flex: none;
    padding: 14px 12px;
    height: 100vh;
    height: 100svh;
    height: 100dvh;
    position: relative;
    z-index: 2;
    color: var(--c-text);
    /* `--shell-rail-ground`: the rail's ground, so a host that wants a brand-tinted column
       (the admin's) sets ONE token instead of carrying a second rail rule (#6271). */
    background: var(--shell-rail-ground, var(--c-surface));
    border-right: 1px solid var(--c-border);
  }

  .shell-rail-header {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 2px 0 12px;
  }

  .shell-rail-header .shell-org-chip {
    width: 100%;
    justify-content: flex-start;
  }

  .shell-rail-nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    /* The rail owns its own scroll: reaching its end must NOT chain the gesture to an
       ancestor scroller, which dragged the whole admin frame off-screen in #4200. Declared
       here now that both hats scroll through this element. */
    overscroll-behavior: contain;
    scrollbar-width: none;
  }

  .shell-rail-nav::-webkit-scrollbar {
    display: none;
  }

  .shell-rail-group-label {
    padding: 0 12px;
    margin: 14px 0 4px;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--c-text-3);
  }

  .shell-rail-sub {
    display: flex;
    flex-direction: column;
    gap: 1px;
    margin: 1px 0 3px 14px;
    padding-left: 8px;
    border-left: 1px solid var(--c-border);
  }

  .shell-rail-sub .shell-rail-row {
    min-height: 40px;
    padding: 7px 12px;
    font-size: 13.5px;
  }

  /* A collapsible group row: the host marks it `data-open`; the chevron turns. */
  .shell-rail-chevron {
    display: inline-flex;
    opacity: .7;
    transition: transform .16s;
  }

  .shell-rail-group[data-open="true"] .shell-rail-chevron {
    transform: rotate(90deg);
  }

  .shell-rail-footer {
    margin-top: auto;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 4px 2px;
    border-top: 1px solid var(--c-border);
  }

  .shell-top-bar,
  .shell-appbar {
    box-sizing: border-box;
    display: flex;
    align-items: center;
    gap: 12px;
    flex: none;
    position: sticky;
    top: 0;
    color: var(--c-text);
    background: var(--c-surface);
    border-bottom: 1px solid var(--c-border);
  }

  .shell-top-bar {
    padding: 10px 24px;
    z-index: 5;
  }

  .shell-top-bar-title {
    margin: 0;
    font-weight: 800;
    font-size: 18px;
    letter-spacing: -.01em;
    line-height: 1.2;
    color: var(--c-text);
  }

  .shell-bar-spacer {
    flex: 1;
  }

  /* viewport-fit=cover: the top inset clears the status bar / notch; left and right clear the
     rounded corners and the landscape notch, so the chip and the buttons never slide under
     them. `max(12px, …)` keeps the base gutter on a non-notched viewport. */
  .shell-appbar {
    display: none;
    z-index: 30;
    padding: calc(16px + env(safe-area-inset-top, 0px)) max(12px, env(safe-area-inset-right, 0px)) 8px max(12px, env(safe-area-inset-left, 0px));
  }

  /* AUTO-HIDE (`<AppBar autoHide>`): the bar OVERLAYS its frame's scroller instead of sitting
     above it in the flex column, so leaving and returning is a pure `transform` on the
     compositor. Collapsing it in flow (height / margin) reflows the whole page under the
     finger on every frame, which is the stutter this replaces. The host pads its scroller by
     `--shell-appbar-h` (published on the bar's parent by the component). The frame must be a
     containing block — `.pweb` is `position: fixed` at this width. */
  @media (max-width: 859.98px) {
    .shell-appbar[data-autohide] {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      transform: translate3d(0, 0, 0);
      will-change: transform;
      border-bottom-color: transparent;
      /* Returning eases OUT (fast start — the reader asked for it); leaving eases IN below. */
      transition: transform .3s cubic-bezier(.2, .8, .2, 1), border-color .2s ease, box-shadow .2s ease;
    }
    /* The hairline and lift only once content is actually underneath it. */
    .shell-appbar[data-autohide][data-scrolled] {
      border-bottom-color: var(--c-border);
      box-shadow: 0 1px 12px rgb(15 23 42 / .06);
    }
    .shell-appbar[data-autohide][data-hidden],
    /* #7884: the keyboard is up in a chat composer — every pixel above it is the conversation. */
    :root[data-gb-chat-composing] .shell-appbar[data-autohide] {
      transform: translate3d(0, calc(-100% - 12px), 0);
      box-shadow: none;
      transition: transform .24s cubic-bezier(.4, 0, .7, .2), box-shadow .2s ease;
    }
    /* A keyboard user tabbing into a hidden bar gets it back (the component also shows it on
       focusin); `:focus-visible` rather than `:focus-within` so a tapped chip that keeps focus
       does not pin the bar open forever. */
    .shell-appbar[data-autohide]:has(:focus-visible) { transform: translate3d(0, 0, 0); }
  }
  @media (max-width: 859.98px) and (prefers-reduced-motion: reduce) {
    .shell-appbar[data-autohide],
    .shell-appbar[data-autohide][data-hidden] { transition: none; }
  }

  /* A short read-only context word beside the chip ("Member", "Guardian"). */
  .shell-appbar-context {
    flex: none;
    font-size: 12px;
    font-weight: 700;
    color: var(--c-text-3);
  }

  /* E-4a (#6852): the Member relationship line. The role word keeps its exact look; "through
     Maya" stacks under it at the same size, lighter weight, so a 320px bar keeps the child's name
     readable instead of ellipsizing "Member t…". Like the role word it does not shrink (the
     org chip ellipsizes instead) but is capped; past the cap the names ellipsize and the full
     sentence stays in the DOM and in the title. */
  .shell-appbar-context--relationship {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    flex: none;
    max-width: 42%;
    line-height: 1.2;
  }

  .shell-appbar-context--relationship > span {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .shell-appbar-context-through {
    font-weight: 600;
  }

  .shell-icon-button {
    appearance: none;
    box-sizing: border-box;
    width: 44px;
    height: 44px;
    padding: 0;
    flex: none;
    display: inline-grid;
    place-items: center;
    position: relative;
    border-radius: var(--r-md);
    border: 1px solid transparent;
    background: transparent;
    color: var(--c-text-2);
    font: inherit;
    text-decoration: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }

  @media (hover: hover) {
    .shell-icon-button:hover {
      background: var(--c-surface-2);
      color: var(--c-text);
    }
  }

  .shell-icon-button[data-active="true"] {
    color: var(--accent-700);
    background: var(--accent-50);
    border-color: var(--accent-200);
  }

  .shell-icon-button .shell-notification-dot {
    position: absolute;
    top: 9px;
    right: 9px;
  }

  .shell-icon-button .shell-badge {
    position: absolute;
    top: 2px;
    right: 0;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    font-size: 10.5px;
  }

  /* Glass lives on a sibling layer: filtering the nav would trap the water lens's backdrop. */
  .shell-tab-bar {
    --shell-tab-bar-float: 16px;
    --dl: .55s; --wl: .16s; --dr: .38s; --wr: 0s;
    box-sizing: border-box;
    display: none;
    position: fixed;
    isolation: auto;
    bottom: calc(var(--shell-tab-bar-float) + env(safe-area-inset-bottom, 0px));
    left: calc(16px + env(safe-area-inset-left, 0px));
    right: calc(16px + env(safe-area-inset-right, 0px));
    z-index: 40;
    height: var(--shell-tab-bar-height, 64px);
    padding: 0 8px;
    border-radius: 24px;
  }

  .shell-tab-bar::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    z-index: -1;
    pointer-events: none;
    /* Uniform translucent fill lets scrolling content show through the frost. */
    background: color-mix(in srgb, var(--c-surface) 60%, transparent);
    -webkit-backdrop-filter: blur(24px) saturate(220%) brightness(1.08);
    backdrop-filter: blur(24px) saturate(220%) brightness(1.08);
    border: 1px solid rgb(255 255 255 / .55);
    box-shadow: inset 0 1px 0 rgb(255 255 255 / .9), inset 0 -1px 0 rgb(255 255 255 / .25), inset 0 0 0 .5px rgb(15 23 42 / .06), 0 18px 40px rgb(15 23 42 / .22), 0 2px 6px rgb(15 23 42 / .08);
  }

  /* Dark mode needs a little more frost when white content scrolls underneath. */
  [data-theme="dark"] .shell-tab-bar::before {
    background: color-mix(in srgb, var(--c-surface) 70%, transparent);
  }

  .shell-tab-bar-indicator {
    position: absolute;
    pointer-events: none;
    top: 6px;
    height: calc(100% - 12px);
    /* One slot wide, parked at slot 0 and moved by transform so the slide composites on the GPU
       instead of laying out every frame (#7924). translateX's % is the indicator's own width = one slot. */
    left: 8px;
    width: calc((100% - 16px) / var(--tab-count));
    transform: translateX(calc(var(--tab-index) * 100%));
    /* Snap to whole pixels where round() is supported: a fractional offset re-rasterizes the lens
       highlight under the label and drops the active label below AA (nav-layout-7546). */
    transform: translateX(round(calc(var(--tab-index) * 100%), 1px));
    border-radius: 24px;
    box-sizing: border-box;
    /* Keep the refracting crown translucent, but give the small white label an AA ground. */
    background:
      linear-gradient(180deg, transparent 40%, color-mix(in srgb, var(--accent) 65%, #000) 72%),
      radial-gradient(60% 45% at 30% 20%, rgb(255 255 255 / .75) 0%, rgb(255 255 255 / .18) 35%, transparent 60%),
      radial-gradient(50% 30% at 62% 92%, rgb(255 255 255 / .45) 0%, transparent 70%),
      radial-gradient(130% 130% at 50% 40%, color-mix(in srgb, var(--accent) 55%, transparent) 0%, color-mix(in srgb, var(--accent) 77%, transparent) 70%, color-mix(in srgb, var(--accent) 90%, transparent) 100%);
    border: 1px solid rgb(255 255 255 / .7);
    box-shadow: inset 0 1.5px 0 rgb(255 255 255 / .95), inset 0 -1px 0 rgb(255 255 255 / .5), inset 0 -10px 14px -6px rgb(10 20 40 / .28), inset 0 10px 16px -8px rgb(255 255 255 / .55), inset 6px 0 10px -6px rgb(255 255 255 / .35), inset -6px 0 10px -6px rgb(10 20 40 / .18), 0 8px 14px -4px rgb(10 20 40 / .25);
    -webkit-backdrop-filter: blur(1px) saturate(190%) brightness(1.12);
    backdrop-filter: blur(1px) saturate(190%) brightness(1.12);
  }

  /* URL filters are a progressive enhancement; unsupported engines retain the blur above. */
  /* WebKit accepts URL syntax but can discard the painted layer; Gecko has no lens support. */
  @supports (backdrop-filter: url(#shell-water-lens) blur(.6px)) and (not (-webkit-backdrop-filter: blur(1px))) and (not (-moz-appearance: none)) {
    .shell-tab-bar-indicator { backdrop-filter: var(--shell-water-lens) blur(.6px) saturate(190%) brightness(1.12); }
  }

  /* Indicator treatments share the geometry and movement rules below. */
  .shell-tab-bar[data-active-style="inset"] .shell-tab-bar-indicator {
    /* `--accent-indicator` (from `accentRamp`) darkens the bottom stop for a bright accent so the
       white label keeps AA (#7606); without a ramp it is the original 90% mix. */
    background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 75%, #142037), var(--accent-indicator, color-mix(in srgb, var(--accent) 90%, #142037)));
    border: 1px solid rgb(15 23 42 / .15);
    box-shadow: inset 0 3px 7px rgb(10 20 40 / .4), inset 0 1px 2px rgb(10 20 40 / .35), inset 0 -1px 0 rgb(255 255 255 / .45), 0 1px 0 rgb(255 255 255 / .6);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .shell-tab-bar[data-active-style="soft"] .shell-tab-bar-indicator {
    background: color-mix(in srgb, var(--accent) 80%, #142037);
    border: 1px solid rgb(255 255 255 / .3);
    box-shadow: inset 0 1px 0 rgb(255 255 255 / .2), 0 2px 5px rgb(10 20 40 / .12);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  .shell-tab-bar[data-ready="true"] .shell-tab-bar-indicator {
    transition: transform .55s cubic-bezier(.5,0,.2,1.35), border-radius .4s ease;
  }
  .shell-tab-bar[data-ready="true"][data-moving="true"] .shell-tab-bar-indicator {
    border-radius: 26px;
    animation: shell-drop-squish .8s cubic-bezier(.34,1.45,.5,1);
  }
  @keyframes shell-drop-squish {
    0% { scale: 1 1; }
    30% { scale: .86 .7; }
    55% { scale: 1 .62; }
    80% { scale: 1 1.08; }
    100% { scale: 1 1; }
  }

  .shell-tab-bar-item {
    position: relative;
    z-index: 1;
    min-height: 44px;
    appearance: none;
    box-sizing: border-box;
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    /* The translucent ground needs primary ink over both light and dark content. */
    color: var(--c-text);
    font: inherit;
    font-size: 10.5px;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }

  .shell-tab-bar-item[data-active="true"] {
    color: #fff;
    font-weight: 800;
  }
  .shell-tab-bar[data-ready="true"] .shell-tab-bar-item .shell-action-label { transition: color .35s ease .05s; }
  .shell-tab-bar[data-ready="true"] .shell-tab-bar-item .shell-action-icon { transition: transform .55s cubic-bezier(.34,1.56,.64,1); }
  .shell-tab-bar-item[data-active="true"] .shell-action-icon { transform: translateY(-1px) scale(1.12); }
  /* #7675: lift the active label 3.5px (gap 3px -> 0 is 1.5px, plus a 2px nudge) so its
     line box stays inside the indicator's rounded bottom corners; pill size, radius and colours
     are unchanged. */
  .shell-tab-bar-item[data-active="true"] { gap: 0; }
  .shell-tab-bar-item[data-active="true"] .shell-action-label { transform: translateY(-2px); }
  .shell-tab-bar-item[data-active="true"] .shell-action-icon svg { stroke: var(--shell-tab-active-icon, currentColor); }

  .shell-tab-bar-item-icon {
    position: relative;
    display: inline-flex;
    width: 24px;
    height: 24px;
    align-items: center;
    justify-content: center;
  }

  .shell-tab-bar-item-icon .shell-badge {
    position: absolute;
    top: -5px;
    right: -9px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    font-size: 10px;
  }

  .shell-tab-bar-item-icon .shell-notification-dot {
    position: absolute;
    top: -2px;
    right: -3px;
  }

  /* THE ONE SWAP. Below this edge the rail and the top bar stand down and the app bar and
     the tab bar take over. Declared here and nowhere else, so the two hats change shape at
     the same width and a host cannot carry a second copy that drifts. */
  @media (max-width: 859.98px) {
    .shell-rail { display: none; }
    .shell-top-bar { display: none; }
    .shell-appbar { display: flex; }
    .shell-tab-bar { display: flex; }
    /* #7884: a chat composer has focus (attribute set by chat-ui on <html>) — the keyboard
       owns the bottom of the screen, so the tab bar steps aside rather than riding above it. */
    :root[data-gb-chat-composing] .shell-tab-bar { display: none; }
  }

  .shell-preview {
    display: grid;
    gap: 18px;
    padding: 18px;
    background: var(--c-bg);
  }

  .shell-preview-grid {
    display: grid;
    gap: 12px;
    padding: 16px;
    background: var(--c-surface-2);
    color: var(--c-text);
  }

  /* The preview mounts the fixed/sticky chrome INSIDE a box rather than against the viewport. */
  .shell-preview-chrome {
    position: relative;
    display: grid;
    gap: 12px;
  }

  .shell-preview-chrome .shell-rail,
  .shell-preview-chrome .shell-tab-bar,
  .shell-preview-chrome .shell-appbar {
    position: static;
    display: flex;
    height: auto;
    width: auto;
  }

  .shell-preview-chrome .shell-tab-bar { position: relative; height: var(--shell-tab-bar-height, 64px); inset: auto; }

  /* ──────────────────────────────────────────────────────────────────────────────────────
   * THE ORG-AND-MODE SWITCHER (#6210, epic #6203 §2.4).
   *
   * The chip is the trigger; the rows live in the shared `Sheet`'s card, so the overlay,
   * the dim and the enter/exit transition stay the host's `.gb-sheet` rule and only the
   * card's own contents are described here. Nothing below names a host class.
   * ────────────────────────────────────────────────────────────────────────────────────── */
  .shell-org-switcher-chevron {
    /* MUST stay a block. It is a bare <span>, so as an inline box width/height are
     * ignored and the 9x9 chevron collapses to its 2px border-right — which renders
     * next to the org name as a stray vertical bar, not a caret. */
    display: block;
    width: 9px;
    height: 9px;
    border-right: 2px solid var(--c-text-3);
    border-bottom: 2px solid var(--c-text-3);
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform 0.15s ease;
  }

  /* Open: the caret points UP, the standard dropdown affordance. Driven off the trigger's
     own `aria-expanded`, so the state the assistive tech reads and the state the eye reads
     are the same attribute and cannot drift apart. */
  .shell-org-switcher[aria-expanded="true"] .shell-org-switcher-chevron {
    transform: rotate(225deg) translate(-2px, -2px);
  }

  @media (prefers-reduced-motion: reduce) {
    .shell-org-switcher-chevron { transition: none; }
    .shell-tab-bar[data-ready="true"] .shell-tab-bar-indicator,
    .shell-tab-bar[data-ready="true"] .shell-tab-bar-item .shell-action-label,
    .shell-tab-bar[data-ready="true"] .shell-tab-bar-item .shell-action-icon { transition: none; }
    .shell-tab-bar[data-ready="true"][data-moving="true"] .shell-tab-bar-indicator { animation: none; }
    .shell-tab-bar-item[data-active="true"] .shell-action-icon { transform: none; }
  }

  /* The dropdown is a menu-shaped surface: rows run edge to edge and the panel's own
     padding is the only gutter. The bottom sheet keeps the roomier row rhythm. */
  .shell-switcher-card--dropdown .shell-switcher-intro { display: none; }

  .shell-switcher-card--dropdown .shell-switcher-row {
    min-height: 44px;
    padding: 9px 12px;
  }

  /* ONE line per label, truncating — the nav's own label behaviour (`.shell-action-label`
   * is `nowrap` + ellipsis). This briefly clamped to two lines, which kept a long club name
   * whole but made the row 57px against the nav's 36px beside it: the row read as a card,
   * not a list item. A wrapped name is the one thing that cannot be reconciled with a nav
   * row, so the name truncates and the panel is widened to keep the truncation rare.
   *
   * `overflow-wrap: normal` still matters: the inherited `anywhere` breaks mid-word, which
   * is right for a phone-width sheet and wrong at this measure. */
  .shell-switcher-card--dropdown .shell-switcher-title,
  .shell-switcher-card--dropdown .shell-switcher-meta {
    overflow: hidden;
    overflow-wrap: normal;
    white-space: nowrap;
    text-overflow: ellipsis;
  }

  /* Breathing room between the rows and the trailing "Join or create" action, which is a
     button rather than a row and was sitting hard against the last one. */
  .shell-switcher-card--dropdown .shell-switcher-rows { gap: 2px; }

  .shell-switcher-intro {
    margin: 0 0 12px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--c-text-2);
  }

  .shell-switcher-rows {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 0;
    padding: 0;
    list-style: none;
  }

  /*
   * THE SWITCHER ROW IS A NAV ROW. Same geometry as `.shell-rail-row` / `.shell-list-row`
   * above — same min-height, same padding, same radius, same 10px gap — because it is the
   * same kind of object: a full-width list item with leading art, a label and optional
   * trailing control. It had drifted into its own idiom (46px tall, `--r-md` against the
   * nav's radius, a 13.5px/700 title against the nav's inherited 14.5px/400), which is three
   * independent axes of difference and why the panel read as a different component family
   * rather than the same list in a smaller box. A host that makes its nav denser (admin's
   * `.app-rail-row`) restates that density for these rows too, so the pair stays matched
   * inside each host rather than matching only in the package's defaults.
   */
  .shell-switcher-row {
    display: flex;
    align-items: center;
    /* #7565: at 200% text the fixed `Member | Manage` segment wraps under the name instead of
       squeezing it to one letter per line. At 100% everything still fits on one line. */
    flex-wrap: wrap;
    gap: 10px;
    min-height: 44px;
    padding: 9px 12px;
    border-radius: var(--r-md);
  }

  /* The leading crest takes the nav's 24px icon slot (`.shell-action-icon`), not the 32px of
     the top-bar chip: in a list it is a row's icon, not the bar's identity badge. */
  .shell-switcher-row .shell-org-chip-avatar {
    width: 24px;
    height: 24px;
    font-size: 10px;
  }

  .shell-switcher-name {
    display: flex;
    align-items: center;
    gap: 9px;
    flex: 1;
    min-width: min(100%, 8em);
    color: var(--c-text);
    text-decoration: none;
  }

  .shell-switcher-copy,
  .shell-switcher-link {
    display: flex;
    flex-direction: column;
    min-width: 0;
    /* MUST be restated. `.shell-switcher-link` is also a `.shell-switcher-name`, which sets
       `align-items: center` for its ROW axis — but this rule turns the axis vertical, so that
       centre becomes a HORIZONTAL centre and the "Your home" row rendered centred while every
       org row beside it was left-aligned. `stretch` also gives the title its full width, which
       is what the dropdown's ellipsis truncation measures against. */
    align-items: stretch;
    text-align: start;
  }

  /* #7565: the Home link fills its row's height (41px of text inside 9px row padding measured
     41px tall). Taking the padding inside the link makes the whole row the target; the row's
     size is unchanged. */
  .shell-switcher-link {
    padding-block: 9px;
    margin-block: -9px;
  }

  /* Inherited size and weight — the nav's label vocabulary. The row sets `font: inherit`
     via the shared reset, so naming nothing here IS the match; a bolder, smaller title was
     the single loudest difference between this panel and the nav beside it. */
  .shell-switcher-title {
    overflow-wrap: anywhere;
  }

  .shell-switcher-meta {
    font-size: 12px;
    color: var(--c-text-3);
    overflow-wrap: anywhere;
  }

  /* The `Member | Manage` segmented control: two 44px targets that read as one object. */
  .shell-mode-seg {
    display: inline-flex;
    flex: none;
    gap: 2px;
    padding: 2px;
    border-radius: var(--r-pill);
    background: var(--c-surface-2);
  }

  /* 44px stays the floor on both hats — a segment is a phone target like any other. */
  .shell-mode-seg-item {
    min-height: 44px;
    padding: 0 12px;
    font-size: 12.5px;
    border-radius: var(--r-pill);
    text-decoration: none;
  }

  .shell-switcher-join {
    width: 100%;
    margin-top: 12px;
    text-decoration: none;
  }


  /* ──────────────────────────────────────────────────────────────────────────────────────
   * OVERFLOW MENU (`overflow-menu.tsx`) — the default dress for hosts that do not bring
   * their own. A host may pass its own class names (chat does, so its stylesheet keeps
   * owning those pixels); these are what a host gets for free.
   * ────────────────────────────────────────────────────────────────────────────────────── */
  .shell-overflow-trigger {
    flex: none;
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--r-sm);
    border: 1px solid var(--c-border-2);
    background: var(--c-surface);
    color: var(--c-text-2);
    cursor: pointer;
  }
  @media (hover: hover) {
    .shell-overflow-trigger:hover { background: var(--c-surface-2); border-color: var(--c-border-strong); }
  }
  .shell-overflow-trigger[aria-expanded="true"] { background: var(--c-surface-2); }

  .shell-overflow-title {
    margin: 4px 4px 8px;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--c-text-2);
  }

  /*
   * THE BOTTOM SHEET'S HEAD (#6313) — grab handle, title, explicit Close. Rendered only on
   * the phone presentation; the dropdown has no head at all.
   *
   * These are plain classes rather than more inline style, and they may be: the unlayered
   * `.gb-sheet` reset the file header warns about targets the `dialog` ELEMENT — its box,
   * its position, its background — and nothing inside it. The card's own geometry still has
   * to be inline for that reason; its contents do not.
   *
   * The shape follows the member portal's own sheets (`.pweb .sheet-grip` / `.sheet-head`):
   * a 40x4 pill and a 44px round close. Matching the pixels rather than borrowing the
   * selectors is deliberate — `.pweb .overlay`/`.sheet` are portal-scoped, reached by
   * portalling into `#sheet-root`, and bottom-dock at every width (centering into a 420px
   * modal at >=860). This control must stay an anchored dropdown at >=860 and works in two
   * other hosts that have no `.pweb` at all.
   */
  .shell-overflow-sheet-head { display: block; }
  .shell-overflow-grip {
    width: 40px;
    height: 4px;
    margin: 2px auto 6px;
    border-radius: var(--r-pill);
    background: var(--c-border-strong);
  }
  .shell-overflow-headrow { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
  .shell-overflow-headrow .shell-overflow-title { margin: 0 0 0 4px; font-size: 15px; color: var(--c-text); }
  .shell-overflow-close {
    flex: none;
    width: 44px;
    height: 44px;
    padding: 0;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 50%;
    background: var(--c-surface-2);
    color: var(--c-text-2);
    cursor: pointer;
  }
  @media (hover: hover) {
    .shell-overflow-close:hover { background: var(--c-border-2); }
  }

  /*
   * ⚠️ THE CARD SETS ITS OWN INK. `Sheet` portals the dialog to `<body>`, so this surface is
   * NOT a DOM descendant of the host's themed wrapper and does not inherit its tokens: in the
   * member portal `--site-text` is bridged to a dark ink inside `.pweb` and is a near-white
   * (`rgb(237,238,255)`, meant for dark chrome) outside it. The card inherited that white and
   * every host control that draws its label with `var(--site-text)` rendered white-on-white.
   * `--c-text` is declared on `:root` in `shell-tokens.css`, so it is correct everywhere —
   * stating it here is what stops the surface depending on where it happens to be mounted.
   */
  .shell-overflow-card { color: var(--c-text); }

  /*
   * Every item reads as ONE menu row, whatever the host passed — a link, a <details>
   * summary, a server-action form's button, a segmented control. Hosts hand their own
   * chrome to this slot (`btn`, `portal-btn`, a filled toggle), and side by side those
   * rendered as a bare underlined link, a dark full-width bar and four outlined pills
   * stacked on each other. A menu whose rows disagree about what a row looks like does not
   * read as a menu.
   *
   * The reset is scoped to this card and neutralises only SURFACE (fill, border, radius,
   * shadow, alignment) — never behaviour and never the control's own disabled/pressed
   * state, which is how the notify segment keeps showing which level is active.
   */
  .shell-overflow-items { display: grid; gap: 2px; }
  .shell-overflow-items > * { width: 100%; min-width: 0; }
  .shell-overflow-items :is(button, a, summary) {
    display: flex;
    width: 100%;
    align-items: center;
    gap: 10px;
    justify-content: flex-start;
    text-align: left;
    min-height: 42px;
    padding: 8px 10px;
    border: 0;
    border-radius: var(--r-sm);
    background: transparent;
    box-shadow: none;
    color: inherit;
    font-size: 14px;
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
  }
  @media (hover: hover) {
    .shell-overflow-items :is(button, a, summary):hover { background: var(--c-surface-2); }
  }

  /*
   * PHONE ROWS ARE TALLER (#6313). 42px is a pointer row; a docked sheet is thumb-driven and
   * its rows are 52px with the whole row as the target. The class is added by the component
   * on the phone presentation, NOT by a media query here — the surface is chosen in JS
   * (`useIsPhone`), and a second threshold in CSS is a second place for it to be wrong.
   */
  .shell-overflow-sheet-items { gap: 0; }
  .shell-overflow-sheet-items :is(button, a, summary) { min-height: 52px; padding: 10px 12px; font-size: 15px; }
  .shell-overflow-items summary { list-style: none; }
  .shell-overflow-items summary::-webkit-details-marker { display: none; }

  /* The notify segment is a GROUP, not a row: its three options stay side by side so the
     active one is legible as a choice among three rather than as three separate rows. */

  /* Go to search (E-2a, #6869): the hosts' own text-field treatment (`.input-suffix`:
     `--c-border-2`, `--r-sm`, accent focus ring), sized to the 44px row floor. Shown only
     above ORG_SEARCH_THRESHOLD organizations, so the default menu is pixel-identical. */
  .shell-switcher-search { margin: 0 0 8px; }
  .shell-switcher-search-input {
    width: 100%;
    min-height: 44px;
    padding: 0 12px;
    font: inherit;
    /* 16px, not the console's 14px: iOS Safari zooms the page on focusing a smaller field. */
    font-size: 16px;
    color: var(--c-text);
    background: var(--c-surface);
    border: 1px solid var(--c-border-2);
    border-radius: var(--r-sm);
    outline: none;
    box-sizing: border-box;
  }
  .shell-switcher-search-input:focus-visible {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 16%, transparent);
  }

  /* ── Context-change arrival notice (E-9b, #6885) ── page content, not app-bar chrome. */
  .shell-context-change__live {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }
  .shell-context-change__notice {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    margin: 12px 16px 0;
    padding: 10px 12px;
    border: 1px solid var(--c-border);
    border-radius: var(--r-md, 10px);
    background: var(--c-surface-2);
    color: var(--c-text, inherit);
    font-size: 14px;
  }
  .shell-context-change__text {
    flex: 1 1 220px;
    margin: 0;
  }
  .shell-context-change__home,
  .shell-context-change__dismiss {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 12px;
    border-radius: var(--r-sm, 8px);
    font: inherit;
    font-weight: 600;
  }
  .shell-context-change__home {
    color: inherit;
    text-decoration: underline;
  }
  .shell-context-change__dismiss {
    border: 1px solid var(--c-border);
    background: var(--c-surface);
    color: inherit;
    cursor: pointer;
  }
  .shell-context-change__home:focus-visible,
  .shell-context-change__dismiss:focus-visible {
    outline: 2px solid var(--accent, currentColor);
    outline-offset: 2px;
  }

  /* ── In-shell access recovery (E-7b, #6884) ── page content inside the authorized chrome. */
  .shell-access-recovery {
    max-width: 560px;
    margin: 32px auto;
    padding: 0 16px;
    color: var(--c-text, inherit);
  }
  .shell-access-recovery__title {
    margin: 0 0 8px;
    font-size: 22px;
    line-height: 1.25;
  }
  .shell-access-recovery__title:focus {
    outline: none;
  }
  .shell-access-recovery__title:focus-visible {
    outline: 2px solid var(--accent, currentColor);
    outline-offset: 2px;
  }
  .shell-access-recovery__body {
    margin: 0 0 16px;
    font-size: 16px;
    line-height: 1.5;
    color: var(--c-text-2, inherit);
  }
  .shell-access-recovery__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
  }
  .shell-access-recovery__action {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 16px;
    border: 1px solid var(--c-border);
    border-radius: var(--r-sm, 8px);
    background: var(--c-surface);
    color: inherit;
    font: inherit;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
  }
  .shell-access-recovery__action--primary {
    border-color: transparent;
    background: var(--accent);
    color: var(--accent-ink, #fff);
  }
  .shell-access-recovery__action:focus-visible {
    outline: 2px solid var(--accent, currentColor);
    outline-offset: 2px;
  }

  /* ── AccountChip: the person, on the right of the phone app bar ─────────────────────────
   * Deliberately NOT `.shell-org-chip-avatar` (accent on accent-ink = the ORG's colour): the
   * person's mark is the neutral surface + border, so the coloured circle in a bar always
   * means "organization" and the outlined one always means "you". 32px mark inside a 44px
   * target (2.5.5 / 2.5.8). `flex: none` so a long sibling org name cannot squash it. */
  .shell-account-chip {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    cursor: pointer;
  }

  .shell-account-chip-mark {
    flex: none;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 800;
    color: var(--c-text);
    background: var(--c-surface);
    border: 1.5px solid var(--c-border-2);
  }

  @media (hover: hover) {
    .shell-account-chip:hover .shell-account-chip-mark {
      border-color: var(--accent);
    }
  }

  .shell-account-chip[aria-expanded="true"] .shell-account-chip-mark {
    border-color: var(--accent);
  }

  .shell-account-chip:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 50%;
  }
}
