/* ═══════════════════════════════════════════════════════════════════════════
   ALLBRAD SHARED SHELL. 26 September 2026
   ═══════════════════════════════════════════════════════════════════════════
   The CSS that money.html, work.html, learn.html and car.html carried as the
   same block pasted four times: tokens, base, topbar and backbar, hero, tabs,
   sections and cards, clocks, steps, do/never, fragile items, table, buttons,
   overlay and sheet, form fields, empty, toast, the bottom nav, the tablet
   ladder, the rail and the presence. Each page links this file where that
   block used to start and keeps its own rules after the link, so the cascade
   order is what it was.

   Not every page uses every block (money has no hero, clock, step, do/never or
   fragile markup) but nothing here is defined differently on any of the four.
   Where a page needs a different value it overrides after the link: money's
   .tab has no minimum height and money's .ov and .sheet are its own.

   index.html still carries its own copy and is not touched by this file.
   boxing.html links it too since 26 September: it takes the rail, the
   presence and the base rules from here and keeps its own tokens (canvas,
   mat, rope, leather) with --bg, --s1, --s2 and --voice aliased to them in
   its own style block after the link, so the gym looks exactly as it did. */
/* ══════════════════════════════════════════════════════════════════════
   TOKENS. Two themes, one set of names.

   Every colour below is a ROLE, not a hue. The brand DNA is explicit that a
   colour is never chosen because a section needed to look different, so the
   semantic names are the real API and --purple, --blue and friends survive
   only as aliases so 226KB of existing markup keeps working. New code uses
   the role.

   Light values are not inversions. A dark theme carries meaning with
   luminous accents on near-black; inverting that gives pastel mush on white.
   Each accent was re-picked for contrast against a light surface and every
   pair is checked by test-theme.js against WCAG, in both themes.
   ══════════════════════════════════════════════════════════════════════ */
:root, [data-theme="dark"]{
  color-scheme: dark;
  --bg:#14100E;--s1:#1D1815;--s2:#272019;--s3:#312821;
  --border:#ffeee212;--border2:#ffeee21f;--border3:#ffeee230;
  --text:#F5EDE4;--muted:#A89B90;--muted2:#9A8E84;--muted3:#54493F;

  /* The seven roles. */
  --voice:#F2704F;      /* ALLBRAD speaking: brief, command mode, AI output */
  --earned:#EE9A5E;     /* progress you worked for: camp, streaks, ranks */
  --measured:#CDBFAF;   /* machine truth: WHOOP, body, charts */
  --good:#9DBE72;       /* complete, healthy, positive delta */
  --watch:#E8B96B;      /* pending, partial, middle of a range */
  --attention:#F0566B;  /* deficit, overspend, missed */

  --shadow:0 8px 32px rgba(8,5,3,.55);
  --blur-bg:rgba(20,16,14,.9);

  /* One family, aliased. See the token comment in index.html. */
  --font:'Hanken Grotesk',-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;
  /* Ray speaks in a serif, ALLBRAD reports in a sans. Brand DNA v4. */
  --font-voice:'Newsreader',Georgia,'Times New Roman',serif;
  --font-d:var(--font);
  --mono:var(--font);

  /* Radius, four values plus pill. The app had ten. */
  --r-xs:8px;--r-sm:12px;--r-md:16px;--r-lg:20px;--r-pill:999px;

  /* Type, five sizes across six roles. The app had twenty-one. */
  --t-label:11px;--t-meta:13px;--t-body:15px;--t-read:17px;--t-title:20px;--t-display:28px;

  /* Motion. Three durations, used for state changes (tabs, nav), the pane
     fade and the sheet settling back. Figures never animate: money does not
     animate, and envelope bars draw at their value with no transition. */
  --m-state:150ms;--m-entry:250ms;--m-progress:400ms;
}

[data-theme="light"]{
  color-scheme: light;
  /* Warm off-white rather than pure white: #fff next to Clash Display at 800
     weight glares, and this is read outdoors on a phone. */
  --bg:#F0E4DC;--s1:#FBF5F0;--s2:#F5ECE5;--s3:#E6D8CE;
  --border:#1f17141a;--border2:#1f171429;--border3:#1f17143d;
  --text:#1F1714;--muted:#5E5149;--muted2:#68594F;--muted3:#B8A89C;

  /* Darkened so each still passes against #ffffff. The dark-theme values are
     luminous by design and would sit at 1.4:1 here. */
  --voice:#A83A1E;
  --earned:#9A4E14;
  --measured:#6E5C4E;
  --good:#4F6B2A;
  --watch:#77530E;
  --attention:#B8303F;

  --shadow:0 6px 24px rgba(60,35,20,.10);
  --blur-bg:rgba(251,245,240,.92);
}

/* Aliases. Existing markup refers to hues; these keep it working and let the
   theme swap reach every one of them. Do not use these in new code. */
:root,[data-theme="dark"],[data-theme="light"]{
  --purple:var(--voice);--orange:var(--earned);--gold:var(--earned);
  --blue:var(--measured);--green:var(--good);--yellow:var(--watch);
  --red:var(--attention);
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
body{background:var(--bg);color:var(--text);font-family:var(--font);line-height:1.55;
  -webkit-font-smoothing:antialiased;padding-bottom:calc(90px + env(safe-area-inset-bottom,0px))}
.app{max-width:520px;margin:0 auto}
@media (prefers-reduced-motion: reduce){*,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}}

/* topbar */
.topbar{display:flex;align-items:center;justify-content:space-between;padding:14px calc(env(safe-area-inset-right,0px) + 20px) 0 calc(env(safe-area-inset-left,0px) + 20px)}
/* Was a 13px muted text link in the top right corner, which is neither where a
   back control belongs nor a size a thumb aims at. Same component as
   boxing.html now, and it carries the status-bar inset for the page. */
.backbar{position:sticky;top:0;z-index:40;max-width:520px;margin:0 auto;
  padding:calc(env(safe-area-inset-top,0px) + 8px) calc(env(safe-area-inset-left,0px) + 20px) 8px;
  background:color-mix(in srgb,var(--bg) 92%,transparent);backdrop-filter:blur(10px)}
.backbar a{display:inline-flex;align-items:center;gap:7px;min-height:36px;
  padding:0 14px 0 10px;border-radius:var(--r-pill);background:var(--s1);
  border:1px solid var(--border2);color:var(--muted);font-size:var(--t-meta);
  font-weight:600;text-decoration:none}
.backbar a:active{background:var(--s2)}
.backbar .chev{font-size:1.05rem;line-height:1;margin-top:-2px}
h1{font-family:var(--font-d);font-size:var(--t-title);font-weight:700;letter-spacing:-.4px}
.tb-sub{font-family:var(--mono);font-size:var(--t-label);color:var(--muted2);letter-spacing:normal;margin-top:2px}

/* hero */
.hero{margin:16px 20px 0;padding:18px;border-radius:var(--r-lg);
  background:linear-gradient(140deg,color-mix(in srgb,var(--measured) 12%,var(--s1)),var(--s1) 60%);border:1px solid color-mix(in srgb,var(--measured) 18%,transparent)}
.hero-top{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:12px}
.hero-model{font-family:var(--font-d);font-size:var(--t-title);font-weight:700;letter-spacing:-.7px}
.hero-spec{font-family:var(--mono);font-size:var(--t-label);color:var(--muted);letter-spacing:normal;line-height:1.7}
.hero-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:14px;padding-top:14px;border-top:1px solid var(--border)}
.hg-l{font-family:var(--mono);font-size:var(--t-label);color:var(--muted2);letter-spacing:normal;margin-bottom:4px}
.hg-v{font-family:var(--font-d);font-size:var(--t-title);font-weight:700;letter-spacing:-.3px;font-variant-numeric:tabular-nums}
.hg-s{font-family:var(--mono);font-size:var(--t-label);color:var(--muted);margin-top:2px}

/* tabs */
/* 14px under the row: with 0 the first card in a pane sat 2px below the pills
   and read as touching (Brad's feedback, learn, 27 September). The ::after is
   the right-hand gutter: a scrolling flex row ignores its own right padding,
   so the last pill ran into the screen edge. Pills never shrink. */
.tabs{display:flex;gap:6px;padding:16px 20px 14px;overflow-x:auto;scrollbar-width:none}
.tabs::after{content:'';flex:0 0 14px}
.tabs .tab{flex-shrink:0}
.tabs::-webkit-scrollbar{display:none}
.tab{padding:7px 14px;min-height:44px;border-radius:var(--r-pill);font-size:var(--t-body);font-weight:600;cursor:pointer;border:none;
  white-space:nowrap;background:var(--s2);color:var(--muted);flex-shrink:0;transition:all .15s;font-family:var(--font)}
.tab.on{background:color-mix(in srgb,var(--measured) 16%,transparent);color:var(--blue);border:1px solid color-mix(in srgb,var(--measured) 30%,transparent)}
.pane{display:none;padding:0 20px}
.pane.on{display:block;animation:fade .15s ease}
@keyframes fade{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}

/* section */
.sec{margin-top:20px}
.sec-h{font-family:var(--mono);font-size:var(--t-label);color:var(--muted2);
  letter-spacing:normal;margin-bottom:10px;display:flex;align-items:center;gap:7px}
.sec-h::before{content:'';width:5px;height:5px;border-radius:50%;background:var(--muted2)}
.sec-h.gold::before{background:var(--gold)}
.sec-h.blue::before{background:var(--blue)}
.sec-h.red::before{background:var(--red)}
.card{background:var(--s1);border:1px solid var(--border);border-radius:var(--r-md);padding:16px;margin-bottom:10px}

/* clocks */
.clock{display:flex;align-items:center;gap:12px;background:var(--s1);border:1px solid var(--border);
  border-radius:var(--r-md);padding:13px 15px;margin-bottom:8px}
.clock-bar{width:3px;align-self:stretch;border-radius:var(--r-pill);flex-shrink:0}
.clock-b{flex:1;min-width:0}
.clock-l{font-size:var(--t-body);font-weight:650}
.clock-s{font-family:var(--mono);font-size:var(--t-label);color:var(--muted);margin-top:3px}
.clock-r{text-align:right;flex-shrink:0}
.clock-v{font-family:var(--font-d);font-size:var(--t-title);font-weight:700;letter-spacing:-.3px;font-variant-numeric:tabular-nums;line-height:1.1}
.clock-u{font-family:var(--mono);font-size:var(--t-label);color:var(--muted2);letter-spacing:normal}
.pill{display:inline-block;font-family:var(--mono);font-size:var(--t-label);padding:2px 7px;border-radius:var(--r-pill);
  letter-spacing:normal;margin-left:6px;vertical-align:1px}
.pill-mp{background:color-mix(in srgb,var(--good) 12%,transparent);color:var(--green);border:1px solid color-mix(in srgb,var(--good) 24%,transparent)}

/* steps */
.step{display:flex;gap:12px;margin-bottom:14px}
.step-n{font-family:var(--mono);font-size:var(--t-meta);color:var(--gold);width:18px;flex-shrink:0;padding-top:2px}
.step-b{flex:1}
.step-t{font-size:var(--t-body);font-weight:650;margin-bottom:3px}
.step-d{font-size:var(--t-body);color:var(--muted);line-height:1.55}

/* do / never */
.dn{display:grid;grid-template-columns:1fr;gap:8px;margin-top:10px}
.dn-box{border-radius:var(--r-sm);padding:11px 13px;border:1px solid var(--border)}
.dn-box.do{border-color:color-mix(in srgb,var(--good) 18%,transparent)}
.dn-box.no{border-color:color-mix(in srgb,var(--attention) 18%,transparent)}
.dn-h{font-family:var(--mono);font-size:var(--t-label);letter-spacing:normal;margin-bottom:6px}
.dn-box.do .dn-h{color:var(--green)}.dn-box.no .dn-h{color:var(--red)}
.dn-box ul{list-style:none;margin:0}
.dn-box li{font-size:var(--t-body);color:var(--muted);padding-left:12px;position:relative;margin-bottom:4px;line-height:1.5}
.dn-box li::before{content:'';position:absolute;left:0;top:8px;width:3px;height:3px;border-radius:50%;background:var(--muted2)}

/* fragile item */
.frag{background:var(--s1);border:1px solid var(--border);border-radius:var(--r-md);padding:15px;margin-bottom:10px}
.frag-top{display:flex;align-items:baseline;gap:9px;margin-bottom:6px}
.frag-code{font-family:var(--mono);font-size:var(--t-label);color:var(--gold);background:color-mix(in srgb,var(--earned) 10%,transparent);
  border:1px solid color-mix(in srgb,var(--earned) 22%,transparent);padding:2px 7px;border-radius:var(--r-xs);flex-shrink:0}
.frag-n{font-size:var(--t-body);font-weight:700;letter-spacing:-.2px}
.frag-w{font-size:var(--t-body);color:var(--muted);line-height:1.55}

/* table */
.tbl{width:100%;border-collapse:collapse;font-size:var(--t-body)}
.tbl th{text-align:left;font-family:var(--mono);font-size:var(--t-label);letter-spacing:normal;
  color:var(--muted2);padding:7px 8px;border-bottom:1px solid var(--border2);font-weight:500}
.tbl td{padding:9px 8px;border-bottom:1px solid var(--border);color:var(--muted);vertical-align:top}
.tbl td:first-child{color:var(--text);font-weight:600}
.tbl tr:last-child td{border-bottom:none}
.tbl .num{font-family:var(--mono);font-size:var(--t-meta);white-space:nowrap;color:var(--text)}
.scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}

/* buttons */
.row-btn{display:flex;gap:8px;margin-top:12px}
.btn{flex:1;padding:11px;border-radius:var(--r-sm);border:none;font-family:var(--font);font-size:var(--t-body);
  font-weight:700;cursor:pointer;transition:opacity .15s}
.btn-g{background:var(--earned);color:var(--bg)}
.btn-s{background:var(--s3);color:var(--text);border:1px solid var(--border2)}
.btn:active{opacity:.75}

/* overlay */
.ov{position:fixed;inset:0;background:color-mix(in srgb,var(--bg) 78%,transparent);backdrop-filter:blur(8px);display:none;
  align-items:flex-end;justify-content:center;z-index:500}
.ov.on{display:flex}
.sheet{background:var(--s1);border:1px solid var(--border2);border-radius:var(--r-lg) 20px 0 0;padding:0 20px 40px;
  width:100%;max-width:520px;max-height:92vh;overflow-y:auto}
.sh-handle{width:36px;height:4px;background:var(--s3);border-radius:var(--r-pill);margin:12px auto 18px}
.sheet h3{font-family:var(--font-d);font-size:var(--t-title);font-weight:700;margin-bottom:16px}
.f{margin-bottom:12px}
.f label{display:block;font-family:var(--mono);font-size:var(--t-label);color:var(--muted);
  letter-spacing:normal;margin-bottom:5px}
.f input,.f select,.f textarea{width:100%;background:var(--s2);border:1px solid var(--border2);border-radius:var(--r-sm);
  padding:11px 13px;color:var(--text);font-family:var(--font);font-size:var(--t-body);outline:none;-webkit-appearance:none}
.f input:focus,.f select:focus{border-color:var(--blue)}
.f-row{display:grid;grid-template-columns:1fr 1fr;gap:10px}

.empty{font-family:var(--mono);font-size:var(--t-meta);color:var(--muted);text-align:center;padding:20px 10px;line-height:1.7}
.toast{position:fixed;bottom:100px;left:50%;transform:translateX(-50%) translateY(20px);background:var(--s3);
  border:1px solid var(--border2);border-radius:var(--r-pill);padding:9px 18px;font-size:var(--t-body);opacity:0;
  transition:all .2s;z-index:900;pointer-events:none}
.toast.on{opacity:1;transform:translateX(-50%) translateY(0)}

/* ── APP NAV ──────────────────────────────────────────────────────────────
   The same five items as Home, in the same stroke icons. Finance, Habits and
   More are panes inside index.html, so from here they are links carrying a
   hash that index applies once it is unlocked.

   index.html has its own copy of this block; the four pages that link this
   file share this one. Learn, Work and Car are not in the five: they live
   under More, which is why More is the item lit there. */
.nav{position:fixed;bottom:0;left:50%;transform:translateX(-50%);width:100%;max-width:520px;
  background:var(--s1);border-top:1px solid var(--border);display:flex;z-index:200;
  padding-bottom:env(safe-area-inset-bottom,0px)}
.nav-item{flex:1;display:flex;flex-direction:column;align-items:center;padding:10px 4px 8px;
  cursor:pointer;border:none;background:none;color:var(--muted);text-decoration:none;transition:all .15s}
.nav-item .ni{display:flex;align-items:center;justify-content:center;height:22px;margin-bottom:4px;
  transition:transform var(--m-state) ease}
.nav-item .nl{font-size:var(--t-label);font-family:var(--mono);letter-spacing:normal;line-height:1.2}
.nav-item.active{color:var(--text)}
.nav-item.active .ni{transform:translateY(-1px)}
.nav-item .ic{width:22px;height:22px;flex:none;fill:none;stroke:currentColor;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round;display:block}

/* ── tablet ───────────────────────────────────────────────────────────────
   This page had no breakpoint of any kind, so on an iPad it rendered as a
   520px strip down the middle of a 1194px screen with more than half the
   display empty, while the home page adapted. Same ladder as home, and the
   nav tracks the content so the bar is identical on every page. */
@media (min-width:760px){
  .app,.backbar{max-width:720px}
  .nav{max-width:720px}
}
@media (min-width:820px){
  .app,.backbar{max-width:840px}
  .nav{max-width:840px}
}
/* ══════════════════════════════════════════════════════════════════════════
   TABLET AND UP: A RAIL, NOT A BOTTOM BAR - 18 September 2026
   ══════════════════════════════════════════════════════════════════════════
   Below 820px nothing here applies and the bottom bar is exactly as it was.
   At 820 and above the bar is replaced by a fixed left rail, because a phone
   bar holds five things and this app has fourteen places to go.

   Revised the same day after an audit against docs/brand-dna.html, which the
   first version had not been read against. It had reintroduced the exact
   defect v2 of the brand doc was written to remove: uppercase, letter-spacing
   and the decorative grey, all at once, on the smallest text in the rail.
   Group headings are now sentence case at 13px in --muted. Spacing is back on
   the 4px scale, icons on the 24px grid, motion on the 150ms state duration,
   touch targets at 44px, and every item has a visible focus ring. */
:root{--rail-w:64px}
:root[data-rail="open"]{--rail-w:224px}

.rail{display:none}

@media (min-width:820px){
  body{padding-left:var(--rail-w);transition:padding-left var(--m-state,150ms) ease}
  .nav{display:none}
  /* The floating Ask button lived at the bottom right. With content held to a
     reading column on the left it floated in empty space. It is a rail item. */
  .fab{display:none}

  .rail{display:flex;flex-direction:column;position:fixed;top:0;bottom:0;left:0;
        width:var(--rail-w);background:var(--s1);border-right:1px solid var(--border);
        z-index:400;overflow:hidden;transition:width var(--m-state,150ms) ease;
        padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}

  /* Left aligned, not centred: the rail is the left edge now. Capped at 900 so
     cards stay readable rather than stretching into a spreadsheet. */
  .app,.backbar{max-width:900px;margin-left:0;margin-right:auto}

  .rail-brand{display:flex;align-items:center;gap:12px;height:52px;flex:none;
              padding:0 12px;border-bottom:1px solid var(--border)}
  .rail-mark{width:28px;height:28px;border-radius:var(--r-xs);background:var(--text);
             color:var(--bg);display:flex;align-items:center;justify-content:center;
             flex:none;font-size:var(--t-label);font-weight:700}
  .rail-word{font-size:var(--t-meta);color:var(--muted)}

  .rail-scroll{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px;scrollbar-width:thin}
  /* On a short screen (an iPad in landscape is 834 tall) fourteen destinations
     do not fit, so the list scrolls. It used to scroll with no sign that it
     could: whole groups sat hidden above or below with nothing cut in half to
     hint at them. Scroll shadows, the local/scroll background pair: the covers
     move with the content and hide each shadow once you reach that end. */
  .rail-scroll{overscroll-behavior:contain;background:
      linear-gradient(var(--s1) 30%,transparent) center top/100% 32px no-repeat local,
      linear-gradient(transparent,var(--s1) 70%) center bottom/100% 32px no-repeat local,
      linear-gradient(color-mix(in srgb,var(--bg) 90%,#000),transparent) center top/100% 14px no-repeat scroll,
      linear-gradient(transparent,color-mix(in srgb,var(--bg) 90%,#000)) center bottom/100% 14px no-repeat scroll}
  /* Short screens get back 70px by tightening group spacing, which is enough
     for the whole list on a 1024x768 rail, while items keep their 44px target. */
  @media (max-height:900px){
    .rail .rail-h{padding-top:12px}
    .rail .rail-item{margin:0}
  }
  .rail-h{font-size:var(--t-meta);color:var(--muted);padding:16px 12px 4px;white-space:nowrap}
  .rail-item{display:flex;align-items:center;gap:12px;width:100%;min-height:44px;
             padding:8px 12px;margin:2px 0;border:none;background:none;color:var(--muted);
             border-radius:var(--r-sm);cursor:pointer;text-decoration:none;text-align:left;
             font-family:var(--font);font-size:var(--t-body);white-space:nowrap}
  /* The satellite pages scope their stroke styling to .nav-item .ic, so every
     symbol the rail brought with it rendered as a filled black block. The rail
     carries its own, which also keeps it identical on all six pages. */
  .rail .ic{fill:none;stroke:currentColor;stroke-width:1.6;
            stroke-linecap:round;stroke-linejoin:round;display:block}
  .rail-item .ic{flex:none;width:24px;height:24px}
  .rail-item:hover{background:var(--s2);color:var(--text)}
  .rail-item.active{background:var(--s3);color:var(--text);font-weight:650}
  /* The audit found seventeen interactive elements with no visible focus at
     all, in a file whose only focus-visible rule was on .habit-row. */
  .rail-item:focus-visible{outline:2px solid var(--voice);outline-offset:2px}
  .rail-ask{color:var(--voice)}
  .rail-ask:hover{background:color-mix(in srgb,var(--voice) 12%,transparent);color:var(--voice)}
  .rail-foot{flex:none;border-top:1px solid var(--border);padding:8px}
  .rail-lb{overflow:hidden;transition:opacity var(--m-state,150ms) ease}

  /* Collapsed. Labels fade rather than reflow, and a group heading becomes the
     hairline it was standing in for. */
  :root:not([data-rail="open"]) .rail-lb{opacity:0;pointer-events:none}
  :root:not([data-rail="open"]) .rail-h{height:1px;padding:0;margin:8px 12px;
      font-size:0;color:transparent;background:var(--border);overflow:hidden}
  :root[data-rail="open"] .rail-toggle .ic{transform:scaleX(-1)}
}

/* ══ THE PRESENCE. Brand DNA v4, 21 September 2026 ═══════════════════════
   Ray's mark is a light, not a logo. Four states on one element:
   resting (almost out), attending (breathing, the default), speaking (it has
   something for you), insisting (shifts toward the warning red, rare).
   Screen blend in the dark theme so it adds light rather than a coloured
   film; normal blend on paper. Under reduced motion it HOLDS at its current
   brightness rather than switching off: presence is a state, not decoration. */
.presence{--pa:40%;--pb:12%;position:fixed;left:50%;top:0;width:min(620px,150vw);height:230px;
  transform:translateX(-50%);pointer-events:none;z-index:150;
  background:radial-gradient(ellipse 62% 100% at 50% 0%,
    color-mix(in srgb,var(--voice) var(--pa),transparent),
    color-mix(in srgb,var(--voice) var(--pb),transparent) 44%,transparent 78%);
  mix-blend-mode:screen;opacity:.7;transition:opacity var(--m-entry,250ms) ease}
/* On paper a light is a warm cast, not a glow: same states, a third the strength. */
[data-theme="light"] .presence{mix-blend-mode:multiply;--pa:22%;--pb:6%}
.presence[data-state="resting"]{opacity:.14}
.presence[data-state="attending"]{animation:presence-breathe 7s ease-in-out infinite}
.presence[data-state="speaking"]{opacity:.95}
.presence[data-state="insisting"]{opacity:1;background:radial-gradient(ellipse 62% 100% at 50% 0%,
    color-mix(in srgb,var(--attention) 52%,transparent),
    color-mix(in srgb,var(--attention) 16%,transparent) 44%,transparent 78%)}
@keyframes presence-breathe{0%,100%{opacity:.5}50%{opacity:.8}}
@media (prefers-reduced-motion:reduce){.presence{animation:none!important;transition:none}}

/* ══ SKELETON. 26 September 2026 ═══════════════════════════════════════════
   A loading line that looks like loading, so a hero or a list never says
   "Loading" in the same type as a real reading. One line per value it stands
   in for, width set inline (style="width:60%") so the block has the shape of
   what is coming. The renderer replaces it by writing innerHTML.

   Same name and same look as the copy car.html still carries after its link,
   so that copy wins there for now and can simply be deleted later. Under
   reduced motion the line holds flat in --s2 rather than freezing mid-sweep:
   the shimmer is the signal, the shape is the information. */
.skel{height:14px;border-radius:var(--r-pill);margin:6px 0;
  background:linear-gradient(90deg,var(--s2) 25%,var(--s3) 50%,var(--s2) 75%);background-size:200% 100%;
  animation:skel 1.2s linear infinite}
@keyframes skel{from{background-position:200% 0}to{background-position:-200% 0}}
@media (prefers-reduced-motion:reduce){.skel{animation:none;background:var(--s2)}}
