/* Brain -- shared shell styles (design tokens, page background, header, primary nav, components).
   Linked by every page; each page keeps only its page-specific CSS inline. The mobile (iPhone)
   fixes live HERE so they apply everywhere at once. The rules this sheet is built to are in
   DESIGN.md at the repo root: read it before adding a screen or a colour. */

/* THE TYPEFACES, declared once for every page (BR-PERSONAL-4-1 B1-28). Each page used to carry
   its own three <link> tags for Inter; the owner's design uses Barlow Condensed for display type
   and Manrope for everything else, and one @import here means a new page gets them by linking
   this sheet and nothing else. */
@import url("https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@500;600;700&family=Manrope:wght@400;500;600;700&display=swap");

:root{
  /* THE OWNER'S LOOK, from his Claude Design export of 2026-09-24 ("Momentum, green"): graphite,
     gold and a little green. One palette, no light variant: his design has none, and inventing
     one would be deciding a look he did not pick. These are the canonical names; new code uses
     them. */
  --bg:#161616; --bg-bar:#141414; --surface-solid:#201F1D;
  --gold:#E3BE6A; --gold-text:#E3BE6A; --green:#4FC97E;
  --text:#F5F2EA; --text-2:#C2BDB2; --text-3:#8B877E;
  --hairline:rgba(255,255,255,.1); --hairline-strong:rgba(255,255,255,.2);
  --surface-accent:rgba(227,190,106,.07);
  --input-bg:rgba(255,255,255,.05); --input-line:rgba(255,255,255,.12);
  --btn-gold:var(--gold);      /* B1-37: his flat gold; the old sheen band sat still and read as a stripe */
  --font-display:"Barlow Condensed",system-ui,sans-serif;
  --font-body:Manrope,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",sans-serif;

  /* THE OLD NAMES, kept as aliases so every page's own sheet follows without being rewritten.
     Each one says what it means now; DESIGN.md carries the same table. */
  --paper:var(--bg); --paper-bar:var(--bg-bar); --surface:var(--surface-solid);
  --ink:var(--text); --ink-soft:var(--text-3); --line:var(--hairline);
  --accent:var(--gold); --accent-deep:var(--gold-text); --on-accent:#141414;
  --warn:#F0857A; --amber:#E0A94B;
  --sans:var(--font-body);
  --shadow:0 10px 30px rgba(0,0,0,.35);

  /* TYPE SCALE. Five steps, and the gaps between them are the point.
     Before this, a task title and its 900-character description rendered at nearly
     the same weight, so the eye had nothing to catch on and the page read as one
     grey mass. --t-md is body, --t-sm is supporting detail, --t-xs is metadata that
     should be legible but never competes. */
  --t-xs:.68rem; --t-sm:.78rem; --t-md:.88rem; --t-lg:1.05rem; --t-xl:1.3rem;

  --r-sm:6px; --r-md:8px; --r-lg:8px;   /* his design: 8px cards, 6px buttons and fields */

  /* THE BOTTOM BAR, as one number. Under 720px .tabbar is fixed to the bottom of the viewport,
     so three separate things have to clear it: the page's own last row, the chat composer, and
     any future fixed footer. Each used to carry its own literal, and they disagreed -- the body
     cleared 64px for a 48px bar, on every page, including ones with no bar at all.
     --tabbar-h is the 1px top border + a 58px tab (icon, gap, label), measured in a browser at
     390px and not assumed. --tabbar-space adds the iOS home-indicator inset, so anything clearing
     the bar adds --tabbar-space and never env() a second time. */
  --tabbar-h:59px;
  --tabbar-space:calc(var(--tabbar-h) + env(safe-area-inset-bottom));
}

/* touch-action:manipulation on EVERY element, not on html alone. It is not inherited, and the
   effective value stops at the nearest scroll container, so a rule on html would not reach the chat
   log or any other box that scrolls. It keeps pan and pinch and removes only double-tap zoom, which
   is what the owner's screen recording showed: a quick second tap on a button zoomed the page
   (BR-PERSONAL-4-1 B1-25). */
*{ box-sizing:border-box; scrollbar-width:thin; scrollbar-color:var(--line) transparent;
   touch-action:manipulation }
html,body{ min-height:100%; margin:0 }
html{ color-scheme:dark; background:var(--bg) }
body{ font-family:var(--font-body); color:var(--text); font-size:16px; line-height:1.45;
  background:var(--bg); -webkit-font-smoothing:antialiased;
  -webkit-tap-highlight-color:transparent; }
/* The depth of his design: a faint gold light top left, a faint green one bottom right, over
   graphite. Pinned to the viewport so it stays put at any page length or scroll. STATIC on
   purpose: the mockup drifts and breathes these layers, and every animated full-screen layer is
   one more compositing layer for iOS to drop, which is the failure B1-25 found in the old bar. */
body::before{ content:""; position:fixed; inset:0; z-index:-1; pointer-events:none;
  background:
    radial-gradient(ellipse 70% 45% at 15% 0%, rgba(227,190,106,.13), transparent 70%),
    radial-gradient(ellipse 70% 50% at 100% 100%, rgba(79,201,126,.12), transparent 70%),
    linear-gradient(180deg, #1A1A1A, #121212); }

/* THE THREE MOVING ELEMENTS OF HIS DESIGN, INSIDE THE APP ONLY (BR-PERSONAL-4-2 B2-03 to B2-05).
   Every rule below sits under html.in-app, which nav.js (and login.html's one line) sets only when the
   user agent carries the Brain app's marker. The Home Screen icon and every browser keep the static
   look until he has seen these on his phone (B2-27); B2-06 then widens them in one commit.
   - The glow: the depth above breathes, and a gold-and-green light drifts behind everything. .glow is a
     child of body and a SIBLING of .app, never an ancestor of the tab bar (never-do 2). The body goes
     transparent here because its own background otherwise paints over the fixed layers (measured in
     B2-02: the static depth above has never been visible in a browser for exactly that reason).
   - The shine: his gold gradient, three widths wide, swept every 12 seconds.
   - The mark: its gold light breathes from 6px to 24px every 4 seconds.
   No backdrop-filter anywhere (never-do 1), and all of it stops under Reduce Motion. */
.glow{ display:none }
html.in-app body{ background:transparent }
html.in-app body::before{ animation:bgbreathe 7s ease-in-out infinite }
html.in-app .glow{ display:block; position:fixed; inset:-40%; z-index:-1; pointer-events:none;
  background:
    radial-gradient(circle at 30% 35%, rgba(227,190,106,.10), transparent 28%),
    radial-gradient(circle at 72% 68%, rgba(79,201,126,.10), transparent 28%);
  animation:drift 30s ease-in-out infinite alternate, bgbreathe 9s ease-in-out infinite }
html.in-app .btn, html.in-app .loginbox button{
  background:linear-gradient(100deg, #DDB65E 0%, #DDB65E 40%, #F1D690 50%, #DDB65E 60%, #DDB65E 100%);
  background-size:300% 100%; animation:sheen 12s ease-in-out infinite }
html.in-app .brand .logo, html.in-app .loginbox .logo{ animation:breathe 4s ease-in-out infinite }
@keyframes bgbreathe{ 0%,100%{ opacity:.6; transform:scale(1) } 50%{ opacity:1; transform:scale(1.05) } }
@keyframes drift{ from{ transform:translate(-4%,-3%) rotate(0deg) } to{ transform:translate(4%,3%) rotate(6deg) } }
@keyframes sheen{ 0%,70%,100%{ background-position:100% 0 } 85%{ background-position:0% 0 } }
@keyframes breathe{ 0%,100%{ filter:drop-shadow(0 0 6px rgba(227,190,106,.25)) }
                    50%{ filter:drop-shadow(0 0 24px rgba(227,190,106,.75)) } }
@media (prefers-reduced-motion:reduce){
  html.in-app body::before, html.in-app .glow, html.in-app .btn, html.in-app .loginbox button,
  html.in-app .brand .logo, html.in-app .loginbox .logo{ animation:none }
}

a{ color:var(--gold-text) }

/* refined scrollbars (the primary nav keeps its hidden bar via its own rules below) */
::-webkit-scrollbar{ width:10px; height:10px }
::-webkit-scrollbar-track{ background:transparent }
::-webkit-scrollbar-thumb{ background:var(--line); border-radius:999px;
  border:3px solid transparent; background-clip:content-box }
::-webkit-scrollbar-thumb:hover{ background:var(--ink-soft); background-clip:content-box }

/* keyboard-only focus ring + gold-tinted text selection */
:focus-visible{ outline:2px solid var(--gold); outline-offset:2px }
::selection{ background:color-mix(in srgb, var(--gold) 32%, transparent); color:var(--text) }

/* subtle page-load reveal -- his design's "rise"; respects reduced motion */
@keyframes appear{ from{ opacity:0; transform:translateY(12px) } to{ opacity:1; transform:none } }
main{ animation:appear .5s ease both }
@media (prefers-reduced-motion:reduce){ main{ animation:none } }

/* svh (small viewport, mobile toolbar SHOWING) rather than dvh. dvh is the height of a viewport
   whose toolbar has collapsed, so a page sized to it grows when the toolbar hides, which makes the
   document exceed the viewport, which brings the toolbar back. The owner's words: "the navigation
   glitches in and out". svh is the one unit that cannot start that loop. */
.app{ max-width:760px; margin:0 auto; min-height:100vh; min-height:100svh;
      display:flex; flex-direction:column }

/* THE HEADER: his brain mark, the section's name in display type, and Log out in gold. It scrolls
   with the page and is not blurred: a translucent, blurred bar is the thing iOS failed to paint
   (B1-25), and the header has no reason to take that risk. The top padding clears the notch in
   standalone mode. */
.bar{ display:flex; align-items:flex-end; justify-content:space-between; gap:12px;
      padding:calc(18px + env(safe-area-inset-top)) 20px 10px;
      border-bottom:1px solid var(--line); background:transparent; position:relative; z-index:5 }
.brand{ display:flex; align-items:center; gap:10px; min-width:0 }
.brand .logo{ flex:none; height:30px; width:30px; display:block }
.brand h1{ font-family:var(--font-display); font-weight:600; font-size:28px; line-height:1;
           text-transform:uppercase; letter-spacing:.01em; margin:0; white-space:nowrap }
.brand .sub{ font-size:var(--t-sm); color:var(--ink-soft);
             overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.actions{ display:flex; align-items:center; gap:.5rem; flex:none }
.iconbtn{ position:relative; display:inline-grid; place-items:center; width:40px; height:40px;
          border:1px solid var(--hairline-strong); border-radius:var(--r-sm); color:var(--gold-text);
          text-decoration:none; background:transparent;
          transition:border-color .2s ease, background-color .2s ease, transform .1s ease }
.iconbtn:hover{ border-color:var(--gold) }
.iconbtn:active{ transform:scale(.96) }
.iconbtn svg{ width:17px; height:17px }
.iconbtn.active{ background:var(--gold); color:var(--on-accent); border-color:transparent }
.badge{ position:absolute; top:-2px; right:-2px; min-width:9px; height:9px; border-radius:999px;
        background:var(--warn); border:2px solid var(--bg) }
.badge[hidden]{ display:none }
.logout{ flex:none; display:inline-flex; align-items:center; gap:.4rem; cursor:pointer;
         font:inherit; font-size:13px; font-weight:600; color:var(--gold-text); background:transparent;
         border:0; padding:0 6px; min-height:44px; white-space:nowrap;
         transition:opacity .2s ease, transform .1s ease }
.logout:hover{ opacity:.8 }
.logout:active{ transform:scale(.96) }
.logout svg{ display:none }

/* primary nav -- ONE row on a wide screen (the phone layout is the bottom bar further down). */
.nav{ display:flex; gap:.2rem; padding:10px 20px 0; flex-wrap:nowrap;
      overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none }
.nav::-webkit-scrollbar{ display:none }
.nav a{ flex:none; position:relative; display:inline-flex; align-items:center; gap:.45rem;
        white-space:nowrap; text-decoration:none; font-family:var(--font-display);
        font-size:15px; font-weight:600; letter-spacing:.1em; text-transform:uppercase;
        color:var(--text-3); padding:.5rem .8rem;
        transition:color .15s ease, transform .1s ease }
.nav a .ico{ width:20px; height:20px; flex:none; display:block }
.nav a img.ico{ filter:grayscale(1); opacity:.6 }
.nav a.active{ color:var(--gold-text) }
.nav a.active img.ico{ filter:none; opacity:1 }
/* The gold rule over the active tab, with his glow. A child of the bar, never a layer of its own
   with a backdrop, so it cannot take the bar's paint with it. */
.nav a.active::before{ content:""; position:absolute; left:20%; right:20%; bottom:0; height:2px;
        background:var(--gold);
        box-shadow:0 0 10px 1px var(--gold), 0 8px 22px 6px rgba(227,190,106,.35) }
.nav a:active{ transform:scale(.97) }

/* phone: free up header space + force 16px form text so iOS doesn't zoom on focus (app-wide).
   B1-41: every field he can type in, typed or not (a script-built <input> often has no type), and
   !important so no page rule can take one under 16px again. Pinch zoom is untouched. */
@media (max-width:560px){
  .brand .sub{ display:none }
  .bar{ gap:8px }
  input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=range]):not([type=color]):not([type=button]):not([type=submit]):not([type=reset]):not([type=image]):not([type=hidden]),
  textarea,select{ font-size:16px !important }
}

/* DESKTOP: the app is phone-first; on a wide screen, use the room -- a roomier centered column, the
   whole tab row laid out, and hover feedback a pointer can use. Pages that pin their own .app width
   (e.g. the chat) keep it; lists/boards widen. */
@media (min-width:900px){
  .app{ max-width:940px }
  .bar{ padding-left:30px; padding-right:30px }
  .nav{ padding:12px 30px 0; overflow:visible; flex-wrap:wrap }
  .nav a:hover{ color:var(--text) }
  .nav a.active:hover{ color:var(--gold-text) }
  button:not(:disabled):hover, .iconbtn:hover, a.iconbtn:hover{ filter:brightness(1.06); cursor:pointer }
}

[aria-disabled="true"]{ opacity:.55 }

/* Form fields, his design's: a faint lift on graphite, a hairline, 6px corners. Pages may size
   and lay out their own fields; the surface is shared so no page ships a white box. */
input[type=text],input[type=password],input[type=email],input[type=search],input[type=number],
input[type=date],input[type=time],input[type=datetime-local],input[type=url],input[type=tel],
textarea,select{ background:var(--input-bg); color:var(--text); border:1px solid var(--input-line);
  border-radius:var(--r-sm) }
input::placeholder,textarea::placeholder{ color:var(--text-3) }
input[type=checkbox],input[type=radio]{ accent-color:var(--gold) }

/* ============================================================================
   COMPONENTS -- defined here, ONCE, and nowhere else.

   Measured before this section existed: `.card` was defined on 11 of 11 pages and
   0 times in this file. `.empty` on 9, `.lead` on 8, `.pill` and `.save` on 7,
   `.savebar` on 6. 850 lines of per-page CSS against 121 shared.

   That is not untidiness, it is the mechanism the drift ran on. Every page owned a
   private copy of the same component, so a change to one was a change to exactly
   one, and after enough edits no two pages agreed what a card looked like. The
   reconciliation is visible in the numbers: `.empty` arrived here with three
   different font sizes and three paddings, `.savebar` with four margin-tops, `.card`
   with two radii. Each is now one value.

   tests/test_design_system.py fails the moment a page redefines any of these.
   ============================================================================ */

/* --- surfaces ------------------------------------------------------------- */
/* The horizontal padding lives on the CARD, not the row. That is the convention ten
   pages already followed, and it is the one that lets a row's separator run the full
   inner width instead of stopping short at each end. Solid, not translucent: a card
   holds menus and editors, and nothing behind one should show through. */
.card{ background:var(--surface); border:1px solid rgba(255,255,255,.07); border-radius:var(--r-lg);
       box-shadow:var(--shadow); padding:4px 16px }
.card + .card{ margin-top:10px }
/* A card that holds nothing but rows wants no padding of its own. */
.card.flush{ padding:0; overflow:hidden }
/* The gold-edged card his design uses for anything waiting on his yes. */
.card.accent{ background:color-mix(in srgb, var(--gold) 7%, var(--surface)); border-color:var(--gold) }

/* A row inside a card. The separator is a top border rather than a bottom one, so the
   first row never draws a line immediately under the card's own edge. */
.row{ display:flex; align-items:center; justify-content:space-between; gap:12px;
      padding:14px 0; min-height:56px; border-top:1px solid var(--line) }
.row:first-child{ border-top:0 }
/* Lists of things rather than label/value pairs: top-aligned, left-packed, tighter. */
.row.item{ align-items:flex-start; justify-content:flex-start; gap:.6rem; padding:.62rem 0; min-height:0 }

/* --- headings ------------------------------------------------------------- */
/* Nine pages each defined this identical uppercase section label as a bare `h2`, with
   three different margins between them. It slipped past the component guard because an
   element selector is not a class -- so it is stated once here, and .sec-h below is the
   same thing for markup that wants it explicitly. His design: display type, gold, wide
   tracking. */
main h2{ font-family:var(--font-display); font-size:var(--t-xs); font-weight:600;
         text-transform:uppercase; letter-spacing:.18em; color:var(--gold-text);
         margin:1.4rem 0 .5rem }
main h2:first-of-type{ margin-top:.4rem }
/* A page TITLE, which is a different thing from a section label and had been sharing the
   `h2` element with one. mfa and plaid use it. */
.pagetitle{ font-family:var(--font-display); font-size:var(--t-xl); font-weight:600;
            letter-spacing:.01em; text-transform:uppercase; color:var(--text); margin:.2rem 0 .1rem }
.sec-h{ font-family:var(--font-display); font-size:var(--t-xs); font-weight:600;
        text-transform:uppercase; letter-spacing:.18em; color:var(--gold-text);
        margin:1.4rem 0 .5rem; display:flex; align-items:baseline; gap:.5rem }
.sec-h .n{ font-size:var(--t-xs); font-weight:600; letter-spacing:.18em; color:var(--text-3);
           margin-left:auto }
.lead{ color:var(--text-2); font-size:var(--t-md); margin:.15rem 0 .75rem;
       max-width:64ch; line-height:1.45 }

/* --- text ----------------------------------------------------------------- */
.meta{ font-size:var(--t-sm); color:var(--ink-soft) }
.empty{ color:var(--ink-soft); font-size:var(--t-md); padding:.9rem .1rem }

/* One line, then an ellipsis. The Worklist rendered a 900-character description on
   load, which pushed everything else off the screen. `.clamp.open` releases it. */
.clamp{ display:-webkit-box; -webkit-line-clamp:1; line-clamp:1;
        -webkit-box-orient:vertical; overflow:hidden }
.clamp.open{ display:block; -webkit-line-clamp:unset; line-clamp:unset }

/* --- buttons -------------------------------------------------------------- */
/* Primary: his gold. The mockup sweeps a sheen across it every 12 seconds; that is left out,
   because an always-running animation on every primary button costs battery and repaint for
   no information. */
.btn{ cursor:pointer; font:inherit; font-size:var(--t-md); font-weight:700; letter-spacing:.03em;
      color:var(--on-accent); background:var(--btn-gold); border:1px solid transparent;
      border-radius:var(--r-sm); padding:.55rem 1.1rem;
      transition:filter .15s ease, transform .1s ease }
.btn:active{ transform:scale(.97) }
.btn:disabled{ cursor:default; opacity:.55 }
/* Secondary: a hairline box on graphite. */
.btn-quiet{ cursor:pointer; font:inherit; font-size:var(--t-sm); font-weight:600;
            color:var(--text); background:rgba(255,255,255,.04);
            border:1px solid var(--hairline-strong); border-radius:var(--r-sm); padding:.45rem .85rem;
            transition:border-color .15s ease, transform .1s ease }
.btn-quiet:hover{ border-color:var(--gold) }
.btn-quiet:active{ transform:scale(.97) }
.btn-danger{ cursor:pointer; font:inherit; font-size:var(--t-sm); font-weight:600;
             color:var(--warn); background:transparent;
             border:1px solid color-mix(in srgb, var(--warn) 40%, transparent);
             border-radius:var(--r-sm); padding:.45rem .85rem }
.pill{ display:inline-flex; align-items:center; gap:.4rem; cursor:pointer; font:inherit;
       font-size:var(--t-sm); font-weight:600; color:var(--gold-text);
       background:transparent; border:1px solid var(--hairline-strong); border-radius:var(--r-sm);
       padding:.32rem .7rem; transition:border-color .15s ease }
.pill:hover{ border-color:var(--gold) }
.savebar{ display:flex; align-items:center; gap:.7rem; margin-top:.85rem }

/* --- tags and status ------------------------------------------------------ */
/* `.badge` is taken (the notification dot on .iconbtn), so chips are `.tag`. His "Repeats"
   marker: gold hairline, small caps. */
.tag{ flex:none; font-size:var(--t-xs); font-weight:600; letter-spacing:.12em;
      text-transform:uppercase; color:var(--gold-text);
      background:transparent; border:1px solid color-mix(in srgb, var(--gold) 70%, transparent);
      border-radius:3px; padding:.08rem .38rem }
/* The other person's rows. Green so "not mine" registers without reading it. */
.tag-who{ color:var(--green); border-color:color-mix(in srgb, var(--green) 60%, transparent) }
.due{ flex:none; font-size:var(--t-sm); font-weight:600; color:var(--ink-soft);
      white-space:nowrap }
.due-late{ color:var(--warn) }

/* --- disclosure ----------------------------------------------------------- */
/* "Show 4 more" instead of a wall. */
.fold{ display:block; width:100%; text-align:left; cursor:pointer; font:inherit;
       font-size:var(--t-sm); font-weight:600; color:var(--gold-text);
       background:transparent; border:0; border-top:1px solid var(--line);
       padding:.55rem .8rem }

/* --- tiles (the Brain and Settings lists) ---------------------------------- */
/* His design draws these as rows in a card with a gold chevron, not as a grid of boxes, so the
   tiles stack into one column and each carries the chevron. */
.tiles{ display:grid; grid-template-columns:1fr; gap:0; background:var(--surface);
        border:1px solid rgba(255,255,255,.07); border-radius:var(--r-lg); box-shadow:var(--shadow);
        padding:0 16px }
.tile{ position:relative; display:flex; flex-direction:column; justify-content:center; gap:.1rem;
       min-height:64px; text-decoration:none; color:inherit; background:transparent;
       border:0; border-top:1px solid var(--line); border-radius:0; padding:10px 28px 10px 0;
       transition:opacity .15s ease }
.tile:first-child{ border-top:0 }
.tile::after{ content:"\203A"; position:absolute; right:2px; top:50%; transform:translateY(-52%);
              color:var(--gold); font-size:22px; line-height:1 }
.tile:hover{ opacity:.85 }
.tile:active{ opacity:.7 }
.tile .nm{ font-size:var(--t-md); font-weight:600 }
.tile .st{ font-size:var(--t-sm); color:var(--ink-soft) }
.tile .st b{ color:var(--gold-text); font-weight:700 }
.tile.wide{ grid-column:1 / -1 }

/* --- the segmented control is GONE, deliberately -----------------------------
   `.seg` was written here for the Board's "whose tasks" switch, which then shipped with its own
   `.whofilter` / `.whobtn` (work.html) and never adopted it. It had zero consumers in any page's
   markup -- and one accidental consumer in chat.html's script, which named every streamed text
   block "seg". `display:inline-flex` turned each rendered markdown block into a flex ITEM laid
   out in a ROW, so a reply with nine blocks rendered as nine one-word vertical columns.

   Deleted rather than left dead. A shared sheet is only trustworthy if what is in it is in use;
   an unused component that silently claims a common word is worse than no component. If a real
   segmented control is ever needed, it comes back with a page using it in the same commit. */

/* THE BAR IS SOLID (BR-PERSONAL-4-1 B1-02). It was translucent with backdrop-filter:blur, and the
   owner's screen recording (B1-25) showed iOS keeping the blur while dropping the bar's own
   background and labels on Work, and dropping the whole bar on Chat and Brain with its space still
   reserved. An opaque bar with no backdrop layer has nothing of that kind to lose. */

/* --- the primary tab bar --------------------------------------------------
   Desktop keeps a top row. On a phone it becomes a fixed bottom bar, because the
   app is INSTALLED (display:standalone) on both home screens and top tabs sit at the
   far end of a one-handed thumb arc.

   env(safe-area-inset-bottom) is not optional here: in standalone mode iOS draws the
   page under the home indicator, and without the inset the last tab is unpressable. */
.tabbar{ }
@media (max-width:720px){
  .tabbar{ position:fixed; left:0; right:0; bottom:0; z-index:6;
           display:grid; grid-template-columns:repeat(4,1fr); gap:0;
           padding:0 12px env(safe-area-inset-bottom);
           margin:0; overflow:visible;
           /* solid, no backdrop-filter: iOS dropped the translucent bar's paint (B1-25) */
           background:var(--paper-bar);
           border-top:1px solid var(--line) }
  /* 44px is the documented minimum for a finger; each tab is 58px, his design's height. The icon
     sits over its label, and the gold rule marks the tab you are on from the top edge. */
  .tabbar a{ flex-direction:column; justify-content:center; gap:5px;
             min-height:44px; height:58px; padding:0 .2rem;
             font-size:11px; letter-spacing:.1em }
  .tabbar a .ico{ width:24px; height:24px }
  .tabbar a.active::before{ top:-1px; bottom:auto }

  /* CLEAR THE BAR -- but only where there IS one, and never on a shell that is already exactly
     one viewport tall.

     This used to be a flat `body{ padding-bottom }` on every page under 720px, and it did two
     kinds of damage. On /login, /mfa, /plaid and /review, which have no tab bar at all, it was
     64px of dead space under the content. On /chat it was worse: that page's .app is a
     FIXED-HEIGHT shell, so 100svh of shell plus 64px of body padding made the document taller
     than the viewport on a page that scrolls nothing. Scrolling that overflow collapsed the
     mobile toolbar, which changed the viewport height, which re-laid-out the shell. That is the
     glitching the owner reported, and it was 64 pixels of padding causing it.

     `:has(#nav)` is the honest test: #nav is in the static markup of exactly the pages nav.js
     turns into a tab bar, so this can never drift from where the bar actually is. */
  body:has(#nav):not(.shell-fixed){ padding-bottom:var(--tabbar-space) }

  /* A PHONE STEP-UP FOR THE TYPE SCALE.
     The scale was tuned on a desktop: --t-md is .88rem, so body copy rendered at 14.08px and
     metadata at 10.88px on the screen this app is actually used on. The owner: "I have to zoom
     in a lot." Body copy goes to 16px, which is also the size iOS will not zoom a form field at,
     and every other step moves with it. The RATIOS are preserved -- this is the same scale one
     size larger, not a different hierarchy. */
  :root{ --t-xs:.78rem; --t-sm:.86rem; --t-md:1rem; --t-lg:1.18rem; --t-xl:1.45rem }

  /* Shared controls reach 44px too. Written as min-height so a control that is already taller
     (a wrapped button, a text field) is left exactly as it was. */
  .btn, .btn-quiet, .btn-danger, .pill, .logout, .fold{ min-height:44px }
  .iconbtn{ width:44px; height:44px }
}
