    :root {
      color-scheme: light;
      --purple:        #5b3a99;
      --purple-dark:   #3c2566;
      --purple-darker: #2c1a4d;
      --purple-light:  #f5f2fb;
      --purple-pale:   #ede6f8;
      --border:        #e2dbf1;
      --ink:           #211c2e;
      --muted:         #6c6579;
      --surface:       #ffffff;
      --ground-top:    #f5f2fb;
      --ground-bottom: #ffffff;
      --on-accent:     #ffffff;
      --danger:        #b3261e;
      --danger-bg:     #fdecea;
      --danger-border: #f3c6c2;
      --success:       #1c7a3d;
      --success-bg:    #e6f6ec;
      --success-border:#bfe3cd;
      --radius:        12px;
      --radius-sm:     8px;
      --shadow:        0 1px 2px rgba(44, 26, 77, 0.06),
                       0 4px 14px rgba(44, 26, 77, 0.08);
    }

    /* Dark keeps the purple identity rather than inverting to grey. The
       accent lifts because #5b3a99 has too little contrast on a dark
       ground, and button text goes dark against it for the same reason. */
    @media (prefers-color-scheme: dark) {
      :root:not([data-theme="light"]) {
        color-scheme: dark;
        --purple:        #a78bda;
        --purple-dark:   #bda6e8;
        --purple-darker: #d9cdf0;
        --purple-light:  #221b34;
        --purple-pale:   #2a2140;
        --border:        #332a4a;
        --ink:           #ece9f3;
        --muted:         #a49db5;
        --surface:       #1e1930;
        --ground-top:    #191327;
        --ground-bottom: #15111f;
        --on-accent:     #171226;
        --danger:        #f2b8b5;
        --danger-bg:     #3b1a17;
        --danger-border: #5c2b26;
        --success:       #8fd3a8;
        --success-bg:    #15301f;
        --success-border:#27523a;
        --shadow:        0 1px 2px rgba(0, 0, 0, 0.4),
                         0 4px 14px rgba(0, 0, 0, 0.35);
      }
    }

    :root[data-theme="dark"] {
      color-scheme: dark;
      --purple:        #a78bda;
      --purple-dark:   #bda6e8;
      --purple-darker: #d9cdf0;
      --purple-light:  #221b34;
      --purple-pale:   #2a2140;
      --border:        #332a4a;
      --ink:           #ece9f3;
      --muted:         #a49db5;
      --surface:       #1e1930;
      --ground-top:    #191327;
      --ground-bottom: #15111f;
      --on-accent:     #171226;
      --danger:        #f2b8b5;
      --danger-bg:     #3b1a17;
      --danger-border: #5c2b26;
      --success:       #8fd3a8;
      --success-bg:    #15301f;
      --success-border:#27523a;
      --shadow:        0 1px 2px rgba(0, 0, 0, 0.4),
                       0 4px 14px rgba(0, 0, 0, 0.35);
    }

    * { box-sizing: border-box; }
    html { overflow-x: hidden; }

    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui,
                   sans-serif;
      margin: 0;
      padding: 0 0 4rem;
      min-height: 100vh;
      background: var(--ground-bottom)
                  linear-gradient(180deg, var(--ground-top) 0,
                                  var(--ground-bottom) 320px) no-repeat;
      color: var(--ink);
      line-height: 1.55;
      font-size: 15px;
      overflow-x: hidden;
    }

    /* An address is one unbreakable token, and these pages put addresses in
       headings and prose constantly. Without this a real address reached
       395px inside a 375px viewport. `anywhere` breaks only what could not
       otherwise fit, so ordinary prose is untouched. */
    h1, h2, h3, a, code, p, strong, li, label { overflow-wrap: anywhere; }

    h1 {
      font-size: 1.7rem;
      letter-spacing: -0.01em;
      margin: 0 0 0.35rem;
      color: var(--purple-darker);
      text-align: center;
      text-wrap: balance;
    }
    h2 { font-size: 1.2rem; margin: 1.6rem 0 0.5rem; color: var(--purple-darker); }
    p { margin: 0 0 0.85rem; }
    a { color: var(--purple); text-decoration: none; }
    a:hover { text-decoration: underline; }
    a:focus-visible, button:focus-visible, select:focus-visible {
      outline: 2px solid var(--purple);
      outline-offset: 2px;
    }
    ::selection { background: var(--purple-pale); color: var(--purple-darker); }

    .topbar {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 0.6rem;
      padding: 0.85rem 1.25rem;
      background: linear-gradient(120deg, #5b3a99 0%, #3c2566 100%);
      color: #fff;
      box-shadow: var(--shadow);
      margin-bottom: 1.75rem;
    }
    .brand { display: flex; align-items: baseline; gap: 0.45rem; min-width: 0; }
    .brand-name { font-weight: 700; font-size: 1.05rem; letter-spacing: -0.01em; }
    .brand-tag {
      font-size: 0.75rem;
      opacity: 0.85;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .theme-wrap {
      display: flex;
      align-items: center;
      gap: 2px;
      flex: none;
      padding: 2px;
      border: 1px solid rgba(255, 255, 255, 0.3);
      border-radius: 999px;
      background: rgba(255, 255, 255, 0.1);
    }
    .theme-wrap button {
      width: auto;
      margin: 0;
      padding: 0.15rem 0.55rem;
      font-size: 0.72rem;
      font-weight: 600;
      color: #fff;
      background: transparent;
      border: 0;
      border-radius: 999px;
      transition: background-color 0.12s ease;
    }
    .theme-wrap button:hover { background: rgba(255, 255, 255, 0.16); }
    .theme-wrap button[aria-pressed="true"] { background: #fff; color: #3c2566; }

    /* Groups the theme toggle and sign-out on the topbar's right side so
       `.topbar`'s own `justify-content: space-between` still has exactly
       two children -- three would spread theme-wrap into the middle of
       the bar instead of keeping it tight against sign-out. */
    .topbar-actions {
      display: flex;
      align-items: center;
      gap: 0.75rem;
      flex: none;
    }

    /* A plain link, not a script-revealed control -- works with no JS and
       under the CSP unconditionally, unlike .theme-wrap (DESIGN §5.3.1).
       Shown on every page regardless of sign-in state; a visitor with no
       active session still lands safely on /sign-out's own "you are not
       signed in" page (sign_in_pages.dart's signOutPage). */
    .topbar-signout {
      color: #fff;
      font-size: 0.82rem;
      font-weight: 600;
      opacity: 0.9;
      white-space: nowrap;
    }
    .topbar-signout:hover { opacity: 1; text-decoration: underline; }

    .shell { max-width: 26rem; margin: 0 auto; padding: 0 1.25rem; }
    .shell-wide { max-width: 34rem; }

    .card {
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: 1.1rem 1.25rem 1.3rem;
      background: var(--surface);
      box-shadow: var(--shadow);
      margin: 0.75rem 0 1.25rem;
    }

    form { margin: 0; }
    label {
      display: block;
      margin-top: 0.85rem;
      font-weight: 600;
      font-size: 0.88rem;
      color: var(--ink);
    }
    label:first-of-type { margin-top: 0; }

    /* max-width alongside width: a dropdown sizes to its widest option
       unless capped, and width:100% alone does not stop it outgrowing the
       card at 375px. */
    input, select, textarea {
      width: 100%;
      max-width: 100%;
      padding: 0.5rem 0.65rem;
      margin-top: 0.3rem;
      border: 1px solid var(--border);
      border-radius: var(--radius-sm);
      font: inherit;
      background: var(--surface);
      color: var(--ink);
    }
    textarea { min-height: 6rem; }
    .shown-secret, .wrap-any { overflow-wrap: anywhere; }
    input:focus, select:focus, textarea:focus {
      outline: 2px solid var(--purple);
      outline-offset: 1px;
      border-color: var(--purple);
    }

    /* A checkbox is not a stacked field. The previous shell made every
       label a grid, which put the box on its own row, centred and detached
       from the words it labels. */
    .check {
      display: flex;
      align-items: flex-start;
      gap: 0.55rem;
      font-weight: 400;
      line-height: 1.45;
    }
    .check input[type=checkbox] {
      width: auto;
      max-width: none;
      margin: 0.2rem 0 0;
      flex: none;
      accent-color: var(--purple);
    }

    /* border: transparent rather than 0 — .btn-outline overrides only the
       colour, so a solid and an outline button side by side reserve the
       same 1.5px and end up the same size. */
    .btn, button {
      display: inline-block;
      width: 100%;
      margin-top: 1rem;
      padding: 0.65rem 1.4rem;
      background: var(--purple);
      color: var(--on-accent);
      border: 1.5px solid transparent;
      border-radius: var(--radius-sm);
      font: inherit;
      font-weight: 700;
      text-align: center;
      text-decoration: none;
      cursor: pointer;
      transition: background-color 0.12s ease, transform 0.05s ease;
    }
    .btn:hover, button:hover { background: var(--purple-dark); text-decoration: none; }
    button:active, .btn:active { transform: translateY(1px); }
    button:disabled { background: var(--border); color: var(--muted); cursor: not-allowed; }
    button:disabled:hover { background: var(--border); }
    .btn-outline {
      background: var(--surface);
      color: var(--purple);
      border-color: var(--purple);
    }
    .btn-outline:hover { background: var(--purple-light); color: var(--purple-dark); }
    .btn-row { display: grid; gap: 0.6rem; }
    .btn-row .btn, .btn-row button { margin-top: 0; }

    .divider {
      display: flex;
      align-items: center;
      gap: 0.75rem;
      margin: 1.25rem 0;
      color: var(--muted);
      font-size: 0.82rem;
    }
    .divider::before, .divider::after {
      content: "";
      flex: 1;
      height: 1px;
      background: var(--border);
    }

    /* Errors are a bordered box, not bare red text: colour alone is not a
       state signal, and #b3261e on the page ground fails contrast in dark. */
    .error, .notice, .success {
      border-radius: var(--radius-sm);
      padding: 0.6rem 0.85rem;
      font-size: 0.88rem;
      margin: 0 0 0.85rem;
    }
    .error {
      background: var(--danger-bg);
      border: 1px solid var(--danger-border);
      color: var(--danger);
    }
    .notice {
      background: var(--purple-light);
      border: 1px solid var(--border);
      color: var(--ink);
    }
    .success {
      background: var(--success-bg);
      border: 1px solid var(--success-border);
      color: var(--success);
    }

    /* `white-space: nowrap` plus resetting the inherited `overflow-wrap:
       anywhere` (h1/h2/h3/a/code/p/strong/li/label, above) is load-bearing,
       not tidiness. A badge sitting inside a flex row (`.address-row` at
       48rem+) is an inline-flex box whose own text is an anonymous flex
       item; `overflow-wrap: anywhere` shrinks that item's min-content width
       to a single glyph, so a tight flex row collapses "Recovery" into one
       letter per line instead of just wrapping the row. Short fixed
       vocabulary like a badge's label should never wrap at all. */
    .badge {
      display: inline-flex;
      align-items: center;
      background: var(--purple-pale);
      color: var(--purple-darker);
      border-radius: 999px;
      padding: 0.2rem 0.7rem;
      font-size: 0.76rem;
      font-weight: 700;
      white-space: nowrap;
      overflow-wrap: normal;
    }

    /* Per-field errors, for a form that has two problems at once. Same
       reasoning as the banner above: not bare red text. The rule down the
       left edge and the field's own border carry the state for anyone the
       colour does not reach. */
    .field-error {
      color: var(--danger);
      background: var(--danger-bg);
      border-left: 3px solid var(--danger-border);
      border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
      font-size: 0.8rem;
      font-weight: 600;
      margin: 0.35rem 0 0;
      padding: 0.35rem 0.6rem;
    }
    label + .field-error { margin-top: 0.35rem; }
    input[aria-invalid="true"] { border-color: var(--danger-border); }

    .hint { color: var(--muted); font-size: 0.78rem; margin-top: 0.25rem; font-weight: 400; }
    .muted { color: var(--muted); }
    .lede { color: var(--muted); margin-bottom: 1rem; }
    .center { text-align: center; }
    .foot { text-align: center; font-size: 0.9rem; margin: 0; }
    .foot + .foot { margin-top: 0.4rem; }

    .site-foot {
      max-width: 26rem;
      margin: 2.5rem auto 0;
      padding: 1.1rem 1.25rem 0;
      border-top: 1px solid var(--border);
      text-align: center;
      font-size: 0.78rem;
      color: var(--muted);
    }
    .site-foot p { margin: 0 0 0.3rem; }
    .site-foot a { color: var(--muted); text-decoration: underline; }
    .site-foot a:hover { color: var(--purple); }
    .site-foot-links span { padding: 0 0.35rem; }
    .site-foot-build {
      font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
      font-size: 0.7rem;
      opacity: 0.75;
    }

    /* Scrolls sideways rather than wrapping to two rows at 375px: a bar
       that changes height between pages makes the content below it jump.
       The base five items are short enough to fit on a phone without it;
       staff-admin accounts get a sixth ("Staff") that does not always
       fit, and that is fine -- `overflow-x` is exactly for that case,
       and `tool/responsive_check.js` excludes a scrollable ancestor's
       content from its overflow check on purpose. */
    .account-nav {
      margin: -1.75rem 0 1.75rem;
      background: var(--surface);
      border-bottom: 1px solid var(--border);
      overflow-x: auto;
    }
    .account-nav-inner {
      display: flex;
      align-items: center;
      gap: 0.15rem;
      max-width: 46rem;
      margin: 0 auto;
      padding: 0 0.75rem;
      white-space: nowrap;
    }
    .account-nav a, .account-nav-here {
      display: inline-block;
      padding: 0.7rem 0.7rem;
      font-size: 0.86rem;
      font-weight: 600;
      color: var(--muted);
      border-bottom: 2px solid transparent;
    }
    .account-nav a:hover { color: var(--purple); text-decoration: none; }
    .account-nav-here {
      color: var(--purple-darker);
      border-bottom-color: var(--purple);
    }

    /* The quick-glance row of apps above the account overview's own
       content (`_appStrip`, account_pages.dart). Horizontal scroll at
       any width rather than wrapping, the same reasoning .account-nav
       already uses -- a row that changes height between loads makes the
       content below it jump. */
    .app-strip { overflow-x: auto; margin: 0 0 1.5rem; }
    .app-strip-inner { display: flex; gap: 1rem; padding: 0.25rem 0.1rem; }
    .app-tile {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 0.4rem;
      width: 4.5rem;
      flex: none;
      color: var(--ink);
      text-decoration: none;
      text-align: center;
    }
    a.app-tile:hover .app-tile-name { color: var(--purple); text-decoration: underline; }
    .app-tile-icon {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 3rem;
      height: 3rem;
      border-radius: var(--radius-sm);
      overflow: hidden;
      background: var(--surface);
      border: 1px solid var(--border);
      box-shadow: var(--shadow);
    }
    .app-tile-icon img { width: 100%; height: 100%; object-fit: cover; display: block; }
    /* The ghost: a placeholder for an app with no icon set yet, not a
       blank box. Dashed border and the app's own first letter, so it
       reads as "nothing configured" rather than as broken rendering. */
    .app-tile-icon-ghost {
      border-style: dashed;
      box-shadow: none;
      background: var(--purple-light);
      color: var(--muted);
      font-weight: 700;
      font-size: 1.1rem;
    }
    .app-tile-name {
      font-size: 0.76rem;
      font-weight: 600;
      line-height: 1.25;
      overflow-wrap: anywhere;
    }

    /* The white ground is the QR's own, painted inside the SVG: an
       inverted QR defeats a good share of readers, so this one block does
       not follow the theme. The border keeps it from floating on a white
       card in light mode. */
    .qr {
      width: min(15rem, 100%);
      margin: 0.25rem auto 0.75rem;
      padding: 0.6rem;
      background: #ffffff;
      border: 1px solid var(--border);
      border-radius: var(--radius-sm);
    }
    .qr svg { display: block; width: 100%; height: auto; }

    .reveal { margin: 0.9rem 0 0.35rem; }
    .reveal > summary {
      cursor: pointer;
      color: var(--purple);
      font-size: 0.88rem;
      font-weight: 600;
    }
    .reveal > summary:focus-visible {
      outline: 2px solid var(--purple);
      outline-offset: 2px;
    }

    /* A "no thanks" that does not outweigh the thing being offered. A
       full-width outline button below two real actions is the widest
       control in the card, which reads as the recommended one. */
    .quiet-action { margin-top: 0.9rem; text-align: center; }
    .quiet-action button {
      width: auto;
      margin: 0;
      padding: 0.25rem 0.5rem;
      background: none;
      border: 0;
      color: var(--muted);
      font-size: 0.85rem;
      font-weight: 600;
      text-decoration: underline;
    }
    .quiet-action button:hover { background: none; color: var(--purple); }

    .secret-key {
      background: var(--purple-pale);
      border: 1px solid var(--border);
      border-radius: 8px;
      padding: 0.7rem 0.9rem;
      margin: 0.75rem 0 0.35rem;
      text-align: center;
    }
    .secret-key code {
      font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
      font-size: 1rem;
      letter-spacing: 0.14em;
      color: var(--purple-darker);
      user-select: all;
    }

    .address-row { padding: 0.9rem 0; border-top: 1px solid var(--border); }
    .address-row:first-of-type { border-top: 0; }
    .address-row > p { margin: 0 0 0.35rem; }
    .address-row .badge { margin-left: 0.35rem; }
    .address-row .hint { margin: 0 0 0.5rem; }

    /* One line where there is room, wrapping as a unit at phone width. The
       label is a flex item with a basis rather than a block, or it takes the
       full row and pushes every button onto its own line. */
    .row-actions, .row-actions > form {
      display: flex;
      flex-wrap: wrap;
      gap: 0.5rem;
      align-items: flex-end;
    }
    .row-actions > form { flex: 1 1 auto; }
    .row-actions label {
      margin: 0;
      flex: 1 1 10rem;
      min-width: 8rem;
      font-size: 0.76rem;
      font-weight: 400;
      color: var(--muted);
    }
    .row-actions input { width: 100%; margin-top: 0.15rem; }
    .row-actions button, .row-actions .btn {
      width: auto;
      margin: 0;
      flex: none;
      padding: 0.5rem 1rem;
      font-size: 0.88rem;
    }

    [hidden] { display: none !important; }

    @media (prefers-reduced-motion: reduce) {
      * { transition: none !important; }
    }

    /* A strict style-src cannot allow `style="..."` attributes (Q4) — a
       handful of one-off spacing tweaks used that instead of a class.
       Named by what they do, not by the value, so a future one reuses
       the closest fit rather than growing a sixth. */
    .stack-tight { margin-top: 0.5rem; }
    .stack { margin-top: 0.75rem; }
    .stack-loose { margin-top: 0.9rem; }
    .stack-wide { margin-top: 1.25rem; }
    .stack-below { margin-bottom: 1rem; }

    /* Responsive breakpoints (docs/design/bs-auth-responsive-design.md).
       375px is a floor, not the only width considered. Everything below
       is additive -- nothing above this comment changes at any width. */
    @media (min-width: 30rem) {
      .card { padding: 1.5rem 1.75rem 1.75rem; }
      .shell, .site-foot { padding-left: 1.5rem; padding-right: 1.5rem; }
    }

    @media (min-width: 48rem) {
      .account-nav { overflow-x: visible; }
      .account-nav-inner { justify-content: center; white-space: normal; }

      /* Every list of addresses/credentials -- account emails, account
         security, staff search results, staff account detail, the
         deletion checklist -- shares this row shape. */
      .address-row {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
      }
      .address-row > p:first-child { margin: 0; flex: 1 1 auto; }
      .address-row .row-actions { flex: none; }

      .shell-wide { max-width: 40rem; }
    }

    /* Below 1024px the brand pane is not rendered
       (bs-auth-responsive-design.md §4.1). The markup is on every auth
       page; without this it is an ordinary block, so "Backspot" and the
       product name sit under the card. The 64rem rule turns it into the
       side panel. */
    .auth-split-brand { display: none; }

    @media (min-width: 64rem) {
      /* Auth/recovery: a second, decorative pane next to the card.
         Emitted only when `htmlPage(authSplit: true)` is set. */
      .auth-split {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        align-items: stretch;
        gap: 2.5rem;
        max-width: 64rem;
        margin: 0 auto;
        padding: 0 1.5rem;
      }
      .auth-split > .shell { padding: 0; margin: 0; }
      /* Hardcoded, not `var(--purple-dark)`/`var(--purple-darker)` --
         those tokens flip to light lavender in dark mode (correct for
         *text* on a dark ground, wrong for a panel that must stay a
         purple-on-white block regardless of theme). Matches `.topbar`,
         the one other element with this same requirement, which hardcodes
         the identical gradient for the identical reason. */
      .auth-split-brand {
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: var(--radius);
        padding: 3rem 2.5rem;
        background: linear-gradient(160deg, #5b3a99 0%, #3c2566 100%);
        color: #fff;
        box-shadow: var(--shadow);
      }
      .auth-split-brand-inner { max-width: 22rem; text-align: center; }
      .auth-split-brand-name {
        font-size: 2rem;
        font-weight: 700;
        letter-spacing: -0.01em;
        margin: 0 0 0.5rem;
      }
      .auth-split-brand-tag { font-size: 1.05rem; opacity: 0.85; margin: 0; }

      /* Account settings: the tab bar becomes a persistent sidebar.
         Scoped to `body.has-account-nav`, emitted only when a page passes
         `currentAccountPath` -- the auth/recovery shapes are untouched by
         this rule. The staff console passes it too (2026-09-15): "Staff"
         used to be the one sidebar item that made the whole sidebar
         disappear on arrival, unlike every other item, which was the
         actual bug this decision closed -- not a deliberate exclusion, a
         gap nobody had pointed at yet. */
      /* `align-content: start` is load-bearing, not tidiness. `body`
         already carries `min-height: 100vh` (every page, so a short one
         still fills the screen) -- harmless in normal flow, but a grid's
         default `align-content: normal` computes as `stretch`, so with
         three `auto` rows shorter than the viewport the leftover height
         gets distributed across all three as invisible padding: real
         space, no visible box, pushing the nav/main row and the footer
         down by however far short of a full screen the content fell.
         That is the reported "invisible band" -- confirmed by measuring
         `body`'s own grid-template-rows against each row's actual
         content height in a live signed-in session, not guessed at. */
      body.has-account-nav {
        display: grid;
        grid-template-columns: 14rem minmax(0, 1fr);
        grid-template-areas:
          "header header"
          "nav    main"
          "footer footer";
        align-items: start;
        align-content: start;
      }
      /* `margin-bottom` deliberately not zeroed here, unlike every other
         override in this block: `.topbar` is the sole occupant of the
         "header" grid row, so its own margin is what pushes the "nav"/
         "main" row down -- the same spacing every non-sidebar page
         already gets from this exact rule, not a second number invented
         to approximate it. Giving nav or main their own top padding on
         top of this would double the gap; giving neither leaves them
         flush against the topbar with nothing pushing either down. */
      body.has-account-nav > .topbar { grid-area: header; }
      body.has-account-nav > .account-nav {
        grid-area: nav;
        margin: 0;
        border-bottom: 0;
        border-right: 1px solid var(--border);
        min-height: 100%;
      }
      body.has-account-nav > .account-nav .account-nav-inner {
        flex-direction: column;
        align-items: stretch;
        max-width: none;
        padding: 0 1rem 1.5rem;
        gap: 0.15rem;
      }
      body.has-account-nav > .account-nav a,
      body.has-account-nav > .account-nav .account-nav-here {
        border-bottom: 0;
        border-left: 2px solid transparent;
        border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
        padding: 0.55rem 0.75rem;
      }
      body.has-account-nav > .account-nav .account-nav-here {
        border-left-color: var(--purple);
        background: var(--purple-light);
      }
      body.has-account-nav > main.shell {
        grid-area: main;
        max-width: 46rem;
        margin: 0;
        padding: 0 2rem;
      }
      body.has-account-nav > .site-foot { grid-area: footer; max-width: none; }

      /* Staff console: the account-detail page's card sequence becomes
         two columns. `break-inside: avoid-column` keeps a card whole. */
      .staff-detail-grid { column-count: 2; column-gap: 1.25rem; }
      .staff-detail-grid > .card { break-inside: avoid-column; }
    }
    .g-signin {
      display: block;
      width: 180px;
      max-width: 100%;
      margin: 0 auto;
      line-height: 0;
    }
    .g-signin img { width: 100%; height: auto; }
    .g-signin:focus-visible {
      outline: 2px solid var(--purple);
      outline-offset: 3px;
      border-radius: 4px;
    }
    .g-signin-dark { display: none; }

    @media (prefers-color-scheme: dark) {
      :root:not([data-theme="light"]) .g-signin-light { display: none; }
      :root:not([data-theme="light"]) .g-signin-dark { display: block; }
    }
    :root[data-theme="dark"] .g-signin-light { display: none; }
    :root[data-theme="dark"] .g-signin-dark { display: block; }
    :root[data-theme="light"] .g-signin-light { display: block; }
    .fb-signin {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 0.6rem;
      width: 180px;
      max-width: 100%;
      height: 40px;
      margin: 0 auto;
      padding: 0 12px;
      border-radius: 4px;
      background: #0866FF;
      color: #FFFFFF;
      font-size: 0.875rem;
      font-weight: 600;
      text-decoration: none;
    }
    .fb-signin:hover { background: #0055E0; text-decoration: none; }
    .fb-signin:focus-visible {
      outline: 2px solid var(--purple);
      outline-offset: 3px;
    }
    /* 20px keeps it above Meta's 16px floor, and the 5px gap either side is
       the quarter-of-the-width clear space their guidelines ask for. */
    .fb-signin img { width: 20px; height: 20px; display: block; }
    .fb-signin span { white-space: nowrap; }
    .provider-row {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 0.6rem;
    }
