/* ══════════════════════════════════════════════════════════════════════════
   app-ui.css — the app, rebuilt in HTML.

   THE SOURCE IS THE SOURCE. Every number below was read out of the React
   Native it replicates, not measured off a screenshot. Screenshots go stale
   the day someone ships; the components do not. Each block names the file it
   came from so the next person can diff it rather than guess.

     lib/theme.ts             minimalistLightTheme  (the app ships light)
     lib/accent.ts            DEFAULT_ACCENT_KEY = 'violet'  → #6D28D9
     lib/viz.ts               MACRO_RING, scoreColor
     components/GlassCard     the card: radius 16, 1px border, top highlight
     components/FloatingTabBar the dock
     components/DateSwitcher   Fuel / Train / Habits date control
     components/DateTimeline   the dashboard's scrubbable day rail
     components/dashboard/VitalsHero  the recovery plate
     components/SleepStrip + SleepMoonHero
     components/FuelFlowHero   the glass tube
     components/TopProgramPill the program card
     app/(tabs)/{index,macros,workouts,mind}.tsx, app/ai-chat.tsx

   Authored at 1 CSS px = 1 iOS pt inside a 402 × 874 canvas (iPhone 16/17
   Pro), then scaled by `--s` on the frame — so every value here is directly
   comparable to the RN style it was copied from. Don't "improve" a number;
   change the app and copy it again.
   ══════════════════════════════════════════════════════════════════════════ */

/* ⚠️ SUBSCRIPT WITHOUT A LINE-HEIGHT JUMP. <sub> raises the line box by
   default, which pushes a one-line label off its own baseline — the health
   cards are 9px labels and it showed. */
.ap sub { font-size: .72em; line-height: 0; vertical-align: -.18em }

.ap {
  /* ── lib/theme.ts · minimalistLightTheme ───────────────────────────── */
  --bg:             #F3F1ED;
  --raised:         #FFFFFF;
  --surface:        rgba(0, 0, 0, .04);
  --surface-strong: rgba(0, 0, 0, .08);
  --track:          rgba(0, 0, 0, .10);
  --track-strong:   rgba(0, 0, 0, .15);
  --line:           rgba(0, 0, 0, .10);
  --line-strong:    rgba(0, 0, 0, .22);
  --ink:            #000000;
  --sub:            rgba(0, 0, 0, .65);
  --mut:            rgba(0, 0, 0, .45);
  --coral:          #FF3B30;
  --coral-bg:       rgba(255, 59, 48, .08);

  /* ── lib/accent.ts · violet ────────────────────────────────────────── */
  --acc:      #6D28D9;
  --acc-ink:  #FFFFFF;
  --acc-10:   rgba(109, 40, 217, .10);
  --acc-12:   rgba(109, 40, 217, .12);
  --acc-14:   rgba(109, 40, 217, .14);
  --acc-25:   rgba(109, 40, 217, .25);
  --acc-40:   rgba(109, 40, 217, .40);
  --acc-45:   rgba(109, 40, 217, .45);

  /* ── lib/viz.ts ────────────────────────────────────────────────────── */
  --m-protein: #F4795B;
  --m-carbs:   #46B4D6;
  --m-fat:     #F2B33D;
  /* scoreColor(s, light): 100 → #1C8F46 · 86 → #4B8532 */
  --score-100: #1C8F46;
  --score-86:  #4B8532;
  /* nightScoreTone(72) — the sleep chartreuse */
  --night-72:  rgb(184, 204, 111);

  --r-card: 16px;   /* radius.lg — GlassCard's default */

  font-family: -apple-system, "SF Pro Text", system-ui, "Segoe UI", Roboto, sans-serif;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  /* The page around a replica may be centred; the app never is. */
  text-align: left;
  font-synthesis-weight: none;
}

/* Every measurement below is a BORDER box, the way a React Native style is —
   `padding: 16` there never grows the view. The replicas carry their own rule
   so they behave identically on a page that has no reset (the harness) and on
   one that does (site.css). */
.ap, .ap *, .ph, .ph * { box-sizing: border-box }
/* ⚠️ AN <svg> WITH NO SIZE IS 300 × 150. Every icon here is an inline
   `<svg><use href="#i-…"/></svg>` sized by a CSS rule, and the moment one of
   those rules goes missing the glyph does not shrink or vanish — it inflates
   to the SVG default and shoves the card apart. That is not a subtle bug to
   look at, but it is an easy one to ship, because the markup stays valid and
   nothing errors. This is the floor: 1em square unless a rule says otherwise,
   so a missing rule costs a slightly-wrong icon instead of a broken screen. */
:where(.ap) svg:where(:not([width])) { width: 1em; height: 1em; flex: none }

/* ⚠️ NO BARE CLASS NAMES INSIDE A REPLICA. These screens were authored
   against app-ui.css alone and then dropped into a page that also loads
   app-v2.css, where `.hero`, `.band`, `.nav`, `.tier`, `.foot` and `.sr` are
   all real site-level classes. The site's `.hero` — 40px of padding and two
   620px blurred accent clouds — landed on the steps card's number row; its
   `.band` (a full page section) inflated the sleep schedule card; its `.nav`
   (position: sticky, backdrop-filter) turned the cycle month's two chevrons
   into a full-width blurred bar. Every one of them is prefixed `p-` now.
   Anything added here takes a screen prefix (`t-`, `s-`, `z-`, `y-`, `k-`, …)
   or a `p` prefix — never a word the site might also want. */
/* `:where()` on BOTH halves is the point: it contributes no specificity, so
   this sits at (0,0,1) and every real icon rule in this file — however loosely
   written — still wins. A floor that outranked the rules it backs up would
   shrink the status bar and the back chevron instead of saving them. */

/* Numerals are tabular everywhere a value can change (fontVariant in RN). */
.ap b, .ap strong, .ap .num, .ap .tab { font-variant-numeric: tabular-nums }
/* A unit suffix inside a display numeral keeps normal tracking — a headline's
   negative letter-spacing turns "min" into "mn". */
.ap b i, .ap b span, .ap .big i { letter-spacing: normal }

/* ── The phone ───────────────────────────────────────────────────────────
   True iPhone 16/17 Pro proportions. `--s` scales the whole canvas; the
   inner surface always thinks it is 402 × 874 pt. */
.ph {
  --s: 1;
  --w: 402; --h: 874;
  /* How far the back plate stands proud of the glass, in canvas points. */
  --depth: 7px;

  /* ── THE METAL ────────────────────────────────────────────────────────
     Graphite by default, because the replicas were authored on paper and a
     dark handset is what reads there. The site swaps these six stops for a
     brushed silver under its dark theme — a black phone on a black page is a
     silhouette with a screen floating in it. Every band is a variable so the
     swap is six values, not two rewritten gradients. */
  --rail-lit:   #4C515C;   /* the chamfer that catches the light */
  --rail-hi:    #464B56;
  --rail-mid:   #1B1E25;
  --rail-low:   #0C0E12;   /* the darkest face */
  --rail-back:  #1C1F27;
  --wall-lit:   #575D69;   /* the side wall's own top highlight */
  --wall-dark:  #0A0C11;
  --bezel-ink:  rgba(255, 255, 255, .17);   /* inner chamfer over the screen */
  --bezel-top:  rgba(255, 255, 255, .24);
  /* Strength of the plate's top facet. Graphite can take a strong one; a pale
     metal cannot — see the dark-theme override in app-v2.css. */
  --facet:      .30;

  position: relative;
  /* +8 = the bezel. --w / --h stay the SCREEN's size so every number inside
     is still 1px = 1pt against the RN canvas. */
  width: calc((var(--w) + 8) * var(--s) * 1px);
  height: calc((var(--h) + 8) * var(--s) * 1px);
  flex: none;
}
/* ── THICKNESS ───────────────────────────────────────────────────────────
   NO 3D TRANSFORM. Two earlier attempts went the other way and both failed
   in the same place:

     1. `transform-style: preserve-3d` on the frame with a translateZ on the
        screen dragged the whole replica — every card, every shader canvas —
        into the 3D pipeline, and Chrome dropped tiles out of it: the page
        showed THROUGH the handset in pale rectangles.
     2. Keeping the plate alone in Z and cancelling the perspective shrink
        with `scale(1.035)` made the rim UNEVEN. 3.5% of 410 is 14px; 3.5% of
        882 is 31px. The plate peeked out twice as far along the top and
        bottom as it did along the sides, which is what read as a broken
        strip down the left edge.

   So the thickness is drawn, not projected: a rounded plate inset by a fixed
   number of points on all four sides — uniform by construction, at any --s —
   carrying a gradient that is lit on the left and shadowed on the right, the
   way a machined band catches a window. */
.ph::before {
  content: ""; position: absolute; z-index: 0;
  inset: calc(var(--depth) * var(--s) * -1);
  border-radius: calc(61px * var(--s));
  background:
    /* A second, tighter highlight band across the upper third — one gradient
       reads as a tube, two read as a milled edge with a facet on it. */
    linear-gradient(178deg,
      rgba(255, 255, 255, var(--facet)) 0%,
      rgba(255, 255, 255, calc(var(--facet) * .18)) calc(11px * var(--s)),
      rgba(255, 255, 255, 0) calc(20px * var(--s)),
      rgba(0, 0, 0, 0) calc(100% - 22px * var(--s)),
      rgba(0, 0, 0, .28) 100%),
    linear-gradient(96deg,
      var(--wall-lit) 0%, var(--rail-mid) 14%, var(--wall-dark) 46%,
      var(--wall-dark) 66%, var(--rail-back) 88%, var(--rail-lit) 100%);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, .07) inset,
    0 calc(30px * var(--s)) calc(56px * var(--s)) calc(-20px * var(--s)) rgba(6, 8, 14, .72);
}
/* The contact shadow the plate casts on the page — soft, wide, and shifted
   down rather than sideways, so it reads as a slab resting on something. */
.ph::after {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  left: 6%; right: 6%; bottom: calc(-18px * var(--s)); height: calc(40px * var(--s));
  border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(4, 7, 12, .55), transparent 72%);
  filter: blur(calc(12px * var(--s)));
}
.ph-body {
  position: absolute; inset: 0; z-index: 1;
  width: calc((var(--w) + 8) * 1px); height: calc((var(--h) + 8) * 1px);
  transform: scale(var(--s));
  transform-origin: 0 0;
  border-radius: 54px;
  padding: 4px;
  /* A machined rail, not a flat rectangle: a lit top edge, a dark face, and
     a bright chamfer all the way round. */
  background:
    linear-gradient(160deg,
      var(--rail-hi) 0%, var(--rail-mid) 15%, var(--rail-low) 50%,
      var(--rail-back) 85%, var(--rail-lit) 100%);
  box-shadow:
    0 0 0 1.5px var(--bezel-ink) inset,
    0 1px 0 var(--bezel-top) inset,
    0 8px 18px -6px rgba(6, 8, 14, .5);
}
/* The volume rocker and the side button — machined INTO the plate, so they
   are children of the frame rather than of the body: as children of the body
   they hung in the air off a rounded corner with no side wall to sit on. */
.ph-btn {
  position: absolute; z-index: 0;
  width: calc(var(--depth) * var(--s));
  border-radius: calc(2px * var(--s));
  background: linear-gradient(180deg, var(--wall-lit), var(--rail-mid) 55%, var(--rail-low));
  box-shadow: 0 0 0 .5px rgba(0, 0, 0, .5);
}
.ph-btn--vol-up   { left: calc(var(--depth) * var(--s) * -1); top: calc(172px * var(--s)); height: calc(58px * var(--s)) }
.ph-btn--vol-down { left: calc(var(--depth) * var(--s) * -1); top: calc(242px * var(--s)); height: calc(58px * var(--s)) }
.ph-btn--power    { right: calc(var(--depth) * var(--s) * -1); top: calc(214px * var(--s)); height: calc(92px * var(--s)) }
/* The action button, above the rocker — the detail that dates the handset. */
.ph-btn--action   { left: calc(var(--depth) * var(--s) * -1); top: calc(126px * var(--s)); height: calc(30px * var(--s)) }
/* One soft diagonal reflection across the glass. A child of the FRAME, not
   of the screen: the screen's contents are replaced wholesale every time
   somebody switches tab. */
.ph-glass {
  position: absolute; inset: 4px; z-index: 3; pointer-events: none;
  border-radius: 50px;
  background: linear-gradient(122deg,
    rgba(255, 255, 255, .17) 0%,
    rgba(255, 255, 255, .05) 17%,
    rgba(255, 255, 255, 0) 36%,
    rgba(255, 255, 255, 0) 74%,
    rgba(255, 255, 255, .06) 100%);
}
.ph-screen {
  position: relative; z-index: 2; width: 100%; height: 100%;
  border-radius: 50px; overflow: hidden;
  background: var(--bg);
  display: flex; flex-direction: column;
}
.ph--tilt { transform: rotateY(-7deg) rotateX(2.5deg) }
.ph--tilt-r { transform: rotateY(7deg) rotateX(2.5deg) }

.ph--flat .ph-body { background: none; padding: 0; box-shadow: none; border-radius: 34px }
.ph--flat .ph-screen { border-radius: 34px; box-shadow: 0 24px 60px -26px rgba(8, 10, 16, .5) }
.ph--crop { --h: 560 }

/* ── A loose card, outside a phone ───────────────────────────────────────
   Some surfaces read better on the site as the single card they are, without
   a phone around them. `zoom` (not transform) so the card's real height still
   drives the layout around it. */
.slab { zoom: var(--z, 1); width: 370px }
@media (max-width: 900px) { .slab { --z: 1 !important } }
@media (max-width: 430px) { .slab { --z: .88 !important } }
@media (max-width: 390px) { .slab { --z: .82 !important } }

.shot {
  width: var(--sw, 420px); max-width: 100%; margin-inline: auto;
  border-radius: 22px; overflow: hidden; border: 1px solid rgba(255, 255, 255, .12);
  box-shadow: 0 26px 60px -34px rgba(0, 0, 0, .7);
  background: #fff;
}
.shot img { width: 100%; height: auto }

/* ── Status bar ──────────────────────────────────────────────────────────
   62pt — the real top safe-area inset on a 402 × 874 device. Everything
   under it is what SafeAreaView edges={['top']} hands the screen. */
.ap-status {
  position: relative; flex: none; height: 62px;
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 34px 0;
  font-size: 16px; font-weight: 650; letter-spacing: -.2px;
}
.ap-status .island {
  position: absolute; left: 50%; top: 13px; transform: translateX(-50%);
  width: 126px; height: 37px; border-radius: 999px; background: #000;
}
.ap-status .sig { display: flex; align-items: center; gap: 6px }
.ap-status .sig svg { display: block }

/* ── Scroll body ─────────────────────────────────────────────────────────
   contentContainerStyle={{ padding: 20, gap: N }} on every tab screen.
   Content runs UNDER the floating dock — that is the app's own behaviour,
   so the replica clips rather than reserving a dead band. */
.ap-scroll {
  flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden;
  padding: 20px 20px 0;
  display: flex; flex-direction: column;
  gap: 12px;                      /* index.tsx */
}
.ap-scroll--14 { gap: 14px }      /* macros.tsx, workouts.tsx */
.ap-scroll--flush { padding-left: 0; padding-right: 0 }
/* A ScrollView's children keep their natural height and the column runs off
   the bottom. Without this, flexbox SHRINKS the tallest card instead — which
   reads as a broken card rather than as a screen you have not scrolled yet. */
.ap-scroll > *, .m-scroll > *, .c-thread > * { flex: none }

/* ── The replicas actually SCROLL ────────────────────────────────────────
   Not a picture of a screen: a screen. iOS shows no persistent scrollbar,
   so neither do these, and the gesture is contained so a flick inside the
   phone never drags the page out from under it. */
.ap-scroll, .m-scroll, .c-thread {
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.ap-scroll::-webkit-scrollbar,
.m-scroll::-webkit-scrollbar,
.c-thread::-webkit-scrollbar { width: 0; height: 0 }
/* The screen fills the frame under the status bar. */
.ap-view { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column }

/* Everything the finger can hit answers it. RN's Pressable drops to ~0.7–0.85
   opacity on press; these are the same feel, plus a real cursor. */
.ap .tap { cursor: pointer; -webkit-tap-highlight-color: transparent }
.ap .tap:active { opacity: .72 }
/* Anything that routes is pressable, whether or not it also carries .tap —
   the Today cards and the header chevrons both go through [data-go]. */
.ap [data-go] { cursor: pointer; -webkit-tap-highlight-color: transparent }
.ap [data-go]:active { opacity: .78 }
.ap-head .back { padding: 2px; margin: -2px }   /* a chevron needs a hit area */
.ap-dock .tb, .ap-dock .fab { cursor: pointer; -webkit-tap-highlight-color: transparent }
.ap-dock .tb:active, .ap-dock .fab:active { opacity: .6 }
.ap-dock .fab:active { transform: scale(.94) }
.ap-dock .tb, .ap-dock .fab, .ap-dock .tb.on { transition: background-color .16s ease, opacity .12s ease }
@media (prefers-reduced-motion: reduce) { .ap-dock .tb, .ap-dock .fab { transition: none } }

/* ── The card — components/GlassCard ─────────────────────────────────────
   radius.lg, flat bgRaised fill, ONE 1px top-edge highlight, hairline
   border, tight neutral shadow. No gradients, no accent stripe. */
.ap-card {
  position: relative;
  background: var(--raised);
  border-radius: var(--r-card);
  border: 1px solid var(--line);
  box-shadow: 0 3px 8px rgba(0, 0, 0, .08);
  overflow: hidden;
}
.ap-card::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: rgba(255, 255, 255, .65); pointer-events: none; z-index: 2;
}
.ap-card--pad { padding: 16px }
.ap-card--r20 { border-radius: 20px }

/* ── Shared type ─────────────────────────────────────────────────────────
   The app has exactly one small-label convention: 10pt / 800 / caps. */
.ap-eyebrow {
  font-size: 10px; font-weight: 800; letter-spacing: .8px;
  text-transform: uppercase; color: var(--mut);
}
.ap-title { font-size: 24px; font-weight: 700; letter-spacing: -.5px; line-height: 30px }
.ap-h     { font-size: 17px; font-weight: 600; letter-spacing: -.2px; line-height: 22px }

/* 36 × 36, radius 12, surface + hairline — the "options" button that sits at
   the right of the Today and Train mastheads. */
.ap-opt {
  position: relative; flex: none;
  width: 36px; height: 36px; border-radius: 12px;
  background: var(--surface); border: 1px solid var(--line);
  display: grid; place-items: center; color: var(--ink);
}
.ap-opt svg { width: 16px; height: 16px }

/* ══ THE DOCK — components/FloatingTabBar ════════════════════════════════
   Absolute, centred, bottom = max(insets.bottom, 12) + 6 → 40 on this
   device. Raised pill, hairline border, 6pt padding, 3pt gap. Inactive tabs
   are 42 × 42 icon-only in muted ink; the focused one grows a surface chip
   with its label. The FAB is the companion PNG at 44pt — no disc. */
/* ── The floating companion ──────────────────────────────────────────────
   ⚠️ NOT DECORATION, AND NOT PART OF ANY SCREEN. HealaCompanion is mounted
   above the navigator in app/_layout.tsx and its preference defaults ON
   (`scoped == null ? true`), so a new account meets it on every product
   surface — everything except /ai-chat, the camera flows and settings. The
   replicas drew the pet only in the dock, which made the site a picture of
   an app with one mascot where the real one has two.

   Every number here is the app's, from lib/companion-overlay-geometry.ts:
   COMPANION_MASCOT_SIZE 84, COMPANION_EDGE_GUTTER 8, COMPANION_DOCK_GAP 12,
   and defaultCompanionPosition() = {x: maxX, y: maxY} — the bottom-right
   corner. Do not round them to something tidier; they are what the handset
   actually shows. */
.ap-buddy {
  position: absolute; right: 8px; bottom: 12px; z-index: 6;
  --hp-size: 84px; display: block;
  /* It is draggable in the app. Here it is a picture of one, and it must
     never eat a tap meant for the card underneath it. */
  pointer-events: none;
  filter: drop-shadow(0 10px 18px rgba(12, 16, 28, .22));
}
/* Above the bar, not on it: the dock sits 40px up, its pill is ~44px tall,
   and COMPANION_DOCK_GAP is 12. */
.ap-buddy--dock { bottom: 96px }

.ap-dock {
  position: absolute; left: 16px; right: 16px; bottom: 40px;
  display: flex; justify-content: center; z-index: 5;
}
.ap-dock .bar {
  display: flex; align-items: center; gap: 3px;
  padding: 6px; border-radius: 999px;
  background: var(--raised);
  border: 1px solid var(--line);
  box-shadow: 0 8px 20px rgba(0, 0, 0, .18);
}
.ap-dock .tb {
  width: 42px; height: 42px; border-radius: 999px;
  display: flex; align-items: center; justify-content: center;
  color: var(--mut); flex: none;
}
.ap-dock .tb svg { width: 22px; height: 22px }
.ap-dock .tb.on {
  width: auto; min-width: 64px; padding: 0 14px; gap: 6px;
  background: var(--surface); color: var(--ink);
}
.ap-dock .tb.on svg { width: 20px; height: 20px }
.ap-dock .tb.on b { font-size: 13px; font-weight: 800; letter-spacing: .3px }
.ap-dock .fab {
  width: 46px; height: 46px; margin: 0 4px; flex: none;
  display: grid; place-items: center;
}
.ap-dock .fab img { width: 44px; height: 44px }

/* ══ THE DATE SWITCHER — components/DateSwitcher ══════════════════════════
   Fuel, Train and Habits all carry this exact control: two 30 × 30 chevron
   boxes around a 34pt pill. Neutral on today; accent-tinted when the user is
   back-logging a past day (which the replicas never are). */
.ap-dsw { display: flex; align-items: center; gap: 6px; align-self: flex-start }
.ap-dsw .pnav {
  width: 30px; height: 30px; border-radius: 10px;
  background: var(--surface); border: 1px solid var(--line);
  display: grid; place-items: center; color: var(--ink); flex: none;
}
.ap-dsw .pnav svg { width: 16px; height: 16px }
.ap-dsw .pnav.off { opacity: .32 }
.ap-dsw .pill {
  display: flex; align-items: center; gap: 7px;
  height: 34px; padding: 0 12px; border-radius: 16px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 13px; font-weight: 800; letter-spacing: -.2px;
}
.ap-dsw .pill .cal { width: 13px; height: 13px; color: var(--mut) }
.ap-dsw .pill .dn  { width: 12px; height: 12px; color: var(--mut) }

/* ══════════════════════════════════════════════════════════════════════════
   TODAY — app/(tabs)/index.tsx
   ══════════════════════════════════════════════════════════════════════════ */

/* Masthead. Avatar is a 48pt ROUNDED SQUARE (borderRadius 10) with an
   accent-tinted shadow — not a circle. */
.t-mast { display: flex; align-items: center; gap: 12px; margin-top: 4px; padding: 2px 0 }
.t-avatar {
  width: 48px; height: 48px; border-radius: 10px; flex: none;
  object-fit: cover; background: var(--acc-14);
  box-shadow: 0 4px 10px rgba(109, 40, 217, .35);
  display: grid; place-items: center;
  font-size: 21px; font-weight: 800; color: var(--acc);
}
.t-mast .who { flex: 1; min-width: 0 }
.t-mast .who .eye {
  font-size: 10px; font-weight: 800; letter-spacing: 1px;
  text-transform: uppercase; color: var(--mut);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.t-mast .who h2 {
  margin: 2px 0 0; font-size: 21px; line-height: 24px;
  font-weight: 800; letter-spacing: -.5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ── The day rail — components/DateTimeline ──────────────────────────────
   Header (month eyebrow 9pt over the friendly day, 13pt/800) then 46 × N
   cells, gap 5. Today is a raised cell with a 1.5px ink border; past days
   are a dashed muted hairline; the selected day is a solid accent fill. */
.t-rail-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; padding: 0 4px;
}
.t-rail-head .lab { flex: 1; min-width: 0 }
.t-rail-head .lab span {
  display: block; font-size: 9px; font-weight: 800; letter-spacing: .6px;
  text-transform: uppercase; color: var(--mut);
}
.t-rail-head .lab b { display: block; margin-top: 1px; font-size: 13px; font-weight: 800 }
.t-rail-head .cal {
  width: 28px; height: 26px; border-radius: 8px; background: var(--surface);
  display: grid; place-items: center; color: var(--ink); flex: none;
}
.t-rail-head .cal svg { width: 13px; height: 13px }

.t-rail { display: flex; gap: 5px; margin-top: 6px; overflow: hidden }
.t-rail .d {
  width: 46px; flex: none; padding: 7px 0; border-radius: 12px;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  background: var(--surface);
  border: 1px dashed rgba(0, 0, 0, .24);
}
.t-rail .d i {
  font-style: normal; font-size: 9px; font-weight: 800; letter-spacing: .4px;
  color: var(--mut);
}
.t-rail .d b { font-size: 16px; line-height: 19px; font-weight: 900 }
.t-rail .d em { width: 4px; height: 4px; border-radius: 2px; background: transparent }
.t-rail .d.today { background: var(--raised); border: 1.5px solid var(--ink); border-style: solid }
.t-rail .d.on {
  background: var(--acc); border: 1px solid transparent; border-style: solid;
}
.t-rail .d.on i, .t-rail .d.on b { color: var(--acc-ink) }
.t-rail .d.on em { background: var(--acc-ink) }
.t-rail .d.mark em { background: var(--acc) }
.t-rail .d.future { opacity: .7; border-color: var(--line) }

/* ── The four vitals — GlanceStrip / MiniArcGauge ────────────────────────
   48pt gauge, 4.5 stroke, 270° arc with the gap parked at the bottom.
   Value 11/900 inside; label 10/800 caps, 4pt under. */
.t-glance {
  display: flex; justify-content: space-between;
  padding: 2px 4px;
}
.t-vital { width: 72px; display: flex; flex-direction: column; align-items: center; gap: 4px }
.t-gauge {
  position: relative; width: 48px; height: 48px;
  display: grid; place-items: center;
}
.t-gauge svg { position: absolute; inset: 0; width: 48px; height: 48px }
.t-gauge .val {
  position: relative; font-size: 11px; font-weight: 900; letter-spacing: -.3px;
  line-height: 13px; font-variant-numeric: tabular-nums;
}
.t-gauge.empty .val { color: var(--mut) }
.t-vital .lab {
  font-size: 10px; font-weight: 800; letter-spacing: .8px; line-height: 12px;
  text-transform: uppercase; color: var(--mut);
}

/* ── Recovery — components/dashboard/VitalsHero ──────────────────────────
   The card's BORDER carries the tone (50% of the score colour, 1.5px and a
   halo once the score clears 80). Inside: a diagonal 20%→0 tone wash, the
   eyebrow row with the morning-reading badge, then the orb beside the mood
   stamp and headline, then a hairline 7-day band. */
.t-rec { border-color: var(--tone, var(--score-100)) !important; border-width: 1.5px !important }
.t-rec.glow { box-shadow: 0 4px 22px rgba(28, 143, 70, .32) }
.t-rec.glow.caution { box-shadow: 0 4px 22px rgba(187, 107, 3, .30) }
.t-rec.caution .top { background: linear-gradient(135deg, rgba(187,107,3,.2), rgba(187,107,3,0)) }
.t-rec.caution .t-morning { background: rgba(187,107,3,.14); border-color: rgba(187,107,3,.34) }
.t-rec .top {
  padding: 16px 16px 18px;
  display: flex; flex-direction: column; gap: 14px;
  background: linear-gradient(135deg, var(--wash, rgba(28,143,70,.2)), rgba(28, 143, 70, 0));
}
.t-rec .hdr { display: flex; align-items: center; gap: 8px }
.t-rec .hdr .eye { font-size: 10px; font-weight: 800; letter-spacing: .8px; text-transform: uppercase; color: var(--mut) }
.t-rec .hdr .spacer { flex: 1 }
.t-rec .hdr .chev { width: 14px; height: 14px; color: var(--mut) }
/* MorningReadingBadge, compact */
.t-morning {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 7px; border-radius: 999px;
  background: rgba(28, 143, 70, .14); border: 1px solid rgba(28, 143, 70, .34);
  color: var(--tone, var(--score-100));
  font-size: 9px; font-weight: 900; letter-spacing: .6px; line-height: 11px;
  text-transform: uppercase; white-space: nowrap;
}
.t-morning svg { width: 10px; height: 10px }

.t-rec .body { display: flex; align-items: center; gap: 10px }
/* RecoveryOrb — size 118 inside a 160-wide field. RecoveryOrb's own PAD is
   22, so the canvas is 162 tall; VitalsHero pulls it -26 vertically and -18
   into the left padding so the light spills past the card's edge. */
.t-orb {
  position: relative; width: 160px; height: 162px;
  margin: -26px 0 -26px -18px; flex: none;
}
.t-orb > svg { position: absolute; inset: 0; width: 100%; height: 100% }
/* The numeral is size × 0.30 / 900, submerged ink once the liquid is past
   where the digits start (app-shaders.js sets the colour). */
.t-orb .orb-num {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-weight: 900; letter-spacing: -1.6px;
  font-variant-numeric: tabular-nums;
  /* ⚠️ THE NUMERAL SITS ON A WebGL CANVAS, AND DOM ORDER IS NOT ENOUGH.
     iOS Safari promotes a WebGL canvas to its own compositing layer, and a
     plain sibling that merely comes later in the document can lose the paint
     order to it intermittently — the number goes see-through or vanishes and
     comes back on the next scroll. Giving the numeral its own layer with an
     explicit z-index takes the decision away from the compositor. */
  z-index: 2;
  transform: translateZ(0);
}
.t-rec .say { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 9px }
.t-stamp {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  padding: 5px 9px; border-radius: 6px;
  border: 1px solid rgba(28, 143, 70, .5); background: rgba(28, 143, 70, .1);
  color: var(--tone, var(--score-100));
  font-size: 11px; font-weight: 900; letter-spacing: 1.4px; line-height: 14px;
  text-transform: uppercase;
}
.t-stamp svg { width: 13px; height: 13px }
/* Same amber as the /recovery hero — scoreColor(52) on the light stops. */
.t-stamp.caution { --tone: #BB6B03; border-color: rgba(187, 107, 3, .5); background: rgba(187, 107, 3, .1) }
.t-rec .say h3 {
  margin: 0; font-size: 21px; font-weight: 900; line-height: 26px; letter-spacing: -.5px;
}

.t-band { border-top: 1px solid var(--line); padding: 12px 16px; display: flex; flex-direction: column; gap: 9px }
.t-band .hd { display: flex; align-items: flex-end; justify-content: space-between }
.t-band .hd span { font-size: 9px; font-weight: 800; letter-spacing: .8px; text-transform: uppercase; color: var(--mut) }
.t-band .hd b { font-size: 12px; font-weight: 900; letter-spacing: -.2px; line-height: 14px }
.t-band .hd b i {
  font-style: normal; margin-left: 4px; font-size: 9px; font-weight: 800;
  color: var(--mut); letter-spacing: .6px; text-transform: uppercase;
}
/* 36pt columns on a hairline baseline. Sharp 2px corners — instrument bars,
   not pills. Today is wider (13 vs 10) and carries full ink. */
.t-cols { position: relative; height: 36px; display: flex; align-items: flex-end }
.t-cols::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: var(--line) }
.t-cols i { flex: 1; display: flex; justify-content: center }
.t-cols i span { width: 10px; border-radius: 2px; background: rgba(75, 133, 50, .62) }
.t-cols i.on span { width: 13px; background: var(--tone, var(--score-100)) }
.t-days { display: flex; margin-top: 6px }
.t-days span {
  flex: 1; text-align: center; font-size: 9px; font-weight: 700; letter-spacing: .4px;
  text-transform: uppercase; color: var(--mut); line-height: 11px;
}
.t-days span.on { font-weight: 900; color: var(--ink) }

/* ── Sleep — components/SleepStrip + SleepMoonHero (compact) ─────────────
   The card is padded 14, gap 10: a tone eyebrow row, the 118pt night well,
   the bed→wake line, then duration-vs-need on a hairline. */
.t-sleep { padding: 14px; display: flex; flex-direction: column; gap: 10px }
.t-sleep .hdr { display: flex; align-items: center; justify-content: space-between }
.t-sleep .hdr .l { display: flex; align-items: center; gap: 6px; color: var(--night-72) }
.t-sleep .hdr svg { width: 13px; height: 13px }
.t-sleep .hdr span {
  font-size: 10px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase;
}
.t-sleep .hdr .chev { width: 14px; height: 14px; color: var(--mut) }
.t-moon {
  position: relative; height: 118px; border-radius: 18px; overflow: hidden;
  background: linear-gradient(180deg, #232B4D 0%, #141A33 55%, #0B0E1F 100%);
}
/* The sky stays CSS; the moon, its stars, halo and any murk are the shader.
   `.gl` means the GPU took it — the CSS stand-in steps aside. */
.t-moon.gl .disc { display: none }
.t-moon .rd { z-index: 1 }
.f-well.gl > svg { display: none }
/* The moon itself — the shader draws a lit disc with a terminator; a radial
   plus an offset shadow disc is the honest still of it. */
.t-moon .disc {
  position: absolute; right: 18px; top: 50%; transform: translateY(-50%);
  width: 86px; height: 86px; border-radius: 50%;
  background:
    radial-gradient(circle at 36% 30%, #FDFCF6 0%, #EDE9DC 40%, #C6C1B0 70%, #9A9686 100%);
  box-shadow: 0 0 40px 12px rgba(226, 232, 197, .16);
}
/* The terminator — a soft sweep across the disc, the way the shader animates
   the phase in. Never a hard bite. */
.t-moon .disc::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: linear-gradient(102deg,
    rgba(11, 14, 31, 0) 34%, rgba(11, 14, 31, .55) 58%, rgba(11, 14, 31, .88) 84%);
}
.t-moon .rd { position: absolute; left: 14px; top: 0; bottom: 0; display: flex; flex-direction: column; justify-content: center }
.t-moon .rd b {
  font-size: 34px; font-weight: 900; letter-spacing: -2px; line-height: 37px;
  color: var(--night-72);
}
.t-moon .rd .word {
  margin-top: 3px; font-size: 9.5px; font-weight: 900; letter-spacing: 1.6px; line-height: 12px;
  text-transform: uppercase; color: var(--night-72);
}
.t-moon .rd .meta {
  margin-top: 3px; font-size: 8.5px; font-weight: 800; letter-spacing: 1.1px; line-height: 11px;
  text-transform: uppercase; color: rgba(255, 255, 255, .66);
}
.t-sleep .clock { font-size: 10px; font-weight: 500; color: var(--sub) }
.t-need { padding-top: 10px; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: 6px }
.t-need .bar { position: relative; height: 8px; border-radius: 4px; background: var(--surface) }
.t-need .bar i { display: block; height: 100%; border-radius: 4px; background: var(--night-72) }
.t-need .bar .tick {
  position: absolute; top: -2px; width: 2px; height: 12px; border-radius: 1px;
  background: var(--line-strong);
}
.t-need .row { display: flex; align-items: center; justify-content: space-between }
.t-need .row span { font-size: 10px; font-weight: 700; color: var(--mut) }
.t-need .row b { font-size: 10px; font-weight: 800 }

/* ══════════════════════════════════════════════════════════════════════════
   FUEL — app/(tabs)/macros.tsx
   ══════════════════════════════════════════════════════════════════════════ */

.f-head { display: flex; align-items: center; gap: 8px }
.f-head h2 { margin: 0; font-size: 24px; font-weight: 700; letter-spacing: -.5px; line-height: 30px }
/* StreakFlame, size 24 */
.f-flame { display: inline-flex; align-items: center; gap: 3px; color: #E8853A; font-size: 13px; font-weight: 900 }
.f-flame svg { width: 17px; height: 17px }

/* ── The glass tube — components/FuelFlowHero ────────────────────────────
   A 238pt well. The arc is a "C" (open at the bottom), radius 86, 9pt wide,
   and the day runs through it as three ENERGY bands — protein, then carbs,
   then fat, each as long as the calories it contributed. The numerals live
   in the hollow; the "left" pill parks in the gap. */
.f-well { position: relative; height: 238px; overflow: hidden; background: var(--raised) }
.f-well svg { position: absolute; inset: 0; width: 100%; height: 100% }
.f-read {
  position: absolute; left: 0; right: 0; top: calc(238px * .495 - 44px); height: 88px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  pointer-events: none;
}
.f-read .eye {
  font-size: 9px; font-weight: 900; letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--mut);
}
.f-read b {
  margin-top: 4px; font-size: 40px; font-weight: 900; letter-spacing: -1.8px; line-height: 44px;
}
.f-read .goal { margin-top: 4px; font-size: 10px; font-weight: 700; color: var(--mut) }
.f-left {
  position: absolute; left: 0; right: 0; top: calc(238px * .495 + 86px * .90 - 13px);
  display: flex; justify-content: center; pointer-events: none;
}
.f-left span {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px 5px 8px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 11px; font-weight: 900; letter-spacing: .1px; line-height: 14px;
}
.f-left i { width: 6px; height: 6px; border-radius: 3px; background: var(--m-fat); flex: none }

/* Under the tube: the legend row, the coach nudge, the flip affordance. */
.f-under { padding: 13px 16px 15px; display: flex; flex-direction: column; gap: 11px }
.f-cells { display: flex; gap: 7px }
/* MacroFuelCell — an OPAQUE raised chip, never a surface wash. */
.f-cell {
  flex: 1; min-width: 0; padding: 8px; border-radius: 11px;
  background: var(--raised); border: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 3px;
}
.f-cell .k { display: flex; align-items: center; gap: 4px }
.f-cell .k i { width: 6px; height: 6px; border-radius: 2px; flex: none }
.f-cell .k span {
  font-size: 8px; font-weight: 900; letter-spacing: 1px; text-transform: uppercase;
  color: var(--sub); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.f-cell .v { display: flex; align-items: baseline }
.f-cell .v b { font-size: 13px; font-weight: 900; letter-spacing: -.4px; line-height: 16px }
.f-cell .v span { margin-left: 2px; font-size: 9.5px; font-weight: 700; color: var(--mut); line-height: 13px }

.f-tip {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 12px; background: var(--surface);
}
.f-tip .ic {
  width: 28px; height: 28px; border-radius: 9px; flex: none;
  background: var(--acc-14); display: grid; place-items: center; color: var(--acc);
}
.f-tip .ic svg { width: 15px; height: 15px }
.f-tip .tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px }
.f-tip .tx span {
  font-size: 8.5px; font-weight: 800; letter-spacing: 1px; text-transform: uppercase;
  color: var(--mut);
}
.f-tip .tx b { font-size: 12px; font-weight: 700; line-height: 16px }
.f-flip {
  display: flex; align-items: center; justify-content: center; gap: 4px;
  color: var(--mut); font-size: 10px; font-weight: 800; letter-spacing: .6px;
  text-transform: uppercase;
}
.f-flip svg { width: 10px; height: 10px }

/* ── Hydration — FuelWaterCard ───────────────────────────────────────────
   radius 20, padding 15, gap 13. A real 54 × 74 glass on the left. */
.f-water { border-radius: 20px; padding: 15px; display: flex; flex-direction: column; gap: 13px }
.f-water .row { display: flex; align-items: center; gap: 14px }
.f-glass {
  position: relative; width: 54px; height: 74px; flex: none;
  border: 2px solid rgba(0, 0, 0, .18);
  border-top: none;
  border-radius: 5px 5px 12px 12px;
  overflow: hidden; background: rgba(0, 0, 0, .02);
}
.f-glass::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: var(--fill, 38%);
  background: linear-gradient(180deg, #5CD5F0, #22C3E6);
}
.f-water .rd { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px }
.f-water .rd .eye {
  font-size: 9.5px; font-weight: 900; letter-spacing: 1.2px; text-transform: uppercase;
  color: var(--mut);
}
.f-water .rd .v { display: flex; align-items: baseline }
.f-water .rd .v b { font-size: 26px; font-weight: 900; letter-spacing: -1.1px; line-height: 30px }
.f-water .rd .v span { margin-left: 3px; font-size: 12px; font-weight: 800; color: var(--mut) }
.f-water .rd em { font-style: normal; font-size: 10.5px; font-weight: 700; color: var(--mut) }
.f-water .go {
  width: 32px; height: 32px; border-radius: 12px; flex: none;
  background: var(--surface); display: grid; place-items: center; color: var(--mut);
}
.f-water .go svg { width: 15px; height: 15px }
.f-water .quick { display: flex; gap: 8px }
.f-water .quick b {
  flex: 1; height: 42px; border-radius: 13px;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 11.5px; font-weight: 900;
}
.f-water .quick b svg { width: 14px; height: 14px; color: #22C3E6 }

/* ── The log deck ────────────────────────────────────────────────────────
   Search stays the quickest typed flow; every visual capture mode lives in
   one camera-first hub below it, then three compact precision launchers. */
.f-deck { display: flex; flex-direction: column; gap: 8px }
.f-search {
  display: flex; align-items: center; gap: 10px;
  height: 52px; padding-left: 16px; padding-right: 10px; border-radius: 26px;
  background: var(--raised); border: 1px solid var(--line);
  color: var(--mut); font-size: 14px; font-weight: 600;
}
.f-search .mag { width: 17px; height: 17px; flex: none }
.f-search .add {
  margin-left: auto; width: 34px; height: 34px; border-radius: 17px; flex: none;
  background: var(--acc); color: var(--acc-ink); display: grid; place-items: center;
}
.f-search .add svg { width: 19px; height: 19px }
.f-scan {
  min-height: 64px; padding: 0 14px; border-radius: 20px;
  display: flex; align-items: center; gap: 12px;
  background: var(--acc); border: 1px solid rgba(255, 255, 255, .18);
  color: var(--acc-ink);
}
.f-scan .ic {
  width: 42px; height: 42px; border-radius: 15px; flex: none;
  background: rgba(255, 255, 255, .15); display: grid; place-items: center;
}
.f-scan .ic svg { width: 21px; height: 21px }
.f-scan .tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px }
.f-scan .tx b { font-size: 16px; line-height: 20px; font-weight: 900 }
.f-scan .tx span {
  font-size: 10.5px; line-height: 14px; font-weight: 700;
  color: rgba(255, 255, 255, .72); white-space: nowrap;
}
.f-scan .cam { width: 20px; height: 20px; flex: none }
.f-tiles { display: flex; gap: 8px }
.f-tiles span {
  flex: 1; min-height: 74px; padding: 11px 6px; border-radius: 16px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 7px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 11px; line-height: 14px; font-weight: 800;
}
.f-tiles span i {
  width: 30px; height: 30px; border-radius: 10px;
  background: var(--raised); display: grid; place-items: center; color: var(--mut);
}
.f-tiles span i svg { width: 15px; height: 15px }
.f-tiles span.acc {
  background: rgba(109, 40, 217, .08); border-color: rgba(109, 40, 217, .32); font-weight: 900;
}
.f-tiles span.acc i { background: var(--acc); color: var(--acc-ink) }

/* ══════════════════════════════════════════════════════════════════════════
   TRAIN — app/(tabs)/workouts.tsx
   ══════════════════════════════════════════════════════════════════════════ */

.w-head { display: flex; align-items: center; justify-content: space-between }
.w-head .eye { font-size: 10px; font-weight: 800; letter-spacing: .8px; text-transform: uppercase; color: var(--mut) }
.w-head h2 { margin: 2px 0 0; font-size: 24px; font-weight: 700; letter-spacing: -.5px; line-height: 30px }

/* TrainingWeekHero — seven 38pt slots, then the program day rail, then one
   quiet summary line. Rendered bare: no card chrome. */
.w-week { padding: 6px 0 2px; display: flex; flex-direction: column; gap: 10px }
.w-week .days { display: flex; justify-content: space-between }
.w-week .day { width: 38px; display: flex; flex-direction: column; align-items: center; gap: 6px }
.w-week .day i {
  font-style: normal; font-size: 10px; font-weight: 700; letter-spacing: .6px;
  text-transform: uppercase; color: var(--mut);
}
.w-week .day.now i { font-weight: 900; color: var(--acc) }
.w-week .day .slot {
  width: 34px; height: 34px; border-radius: 17px;
  display: grid; place-items: center; border: 0 solid transparent;
}
.w-week .day.now .slot { border: 1.5px solid var(--acc-45) }
.w-week .day .dash { width: 10px; height: 2px; border-radius: 1px; background: rgba(0, 0, 0, .16) }
.w-week .day .tick {
  width: 26px; height: 26px; border-radius: 13px; background: var(--acc);
  display: grid; place-items: center; color: var(--acc-ink);
}
.w-week .day .tick svg { width: 14px; height: 14px }
.w-week .rail { display: flex; gap: 5px; flex-wrap: wrap }
.w-week .rail span {
  flex: 1 1 40px; display: flex; align-items: center; justify-content: center; gap: 4px;
  padding: 6px; border-radius: 999px; border: 1px solid var(--line);
  font-size: 10px; font-weight: 700; line-height: 13px; color: var(--mut);
}
.w-week .rail span.next {
  background: var(--acc-12); border-color: rgba(109, 40, 217, .7);
  color: var(--acc); font-weight: 900;
}
.w-week .rail span svg { width: 10px; height: 10px; color: var(--acc) }
.w-week .sum { font-size: 11.5px; font-weight: 600; text-align: center; color: var(--sub) }

/* TopProgramPill — radius 20, three stacked blocks on hairlines. */
.w-prog { border-radius: 20px }
.w-prog .hd { padding: 14px 16px 12px; display: flex; align-items: center; gap: 10px }
.w-prog .hd .ic {
  width: 34px; height: 34px; border-radius: 11px; flex: none;
  background: var(--acc-14); display: grid; place-items: center; color: var(--acc);
}
.w-prog .hd .ic svg { width: 15px; height: 15px }
.w-prog .hd .tx { flex: 1; min-width: 0 }
.w-prog .hd .tx span {
  display: block; font-size: 9.5px; font-weight: 800; letter-spacing: 1.1px;
  text-transform: uppercase; color: var(--acc);
}
.w-prog .hd .tx b {
  display: block; margin-top: 1px; font-size: 16px; font-weight: 900;
  letter-spacing: -.3px; line-height: 20px;
}
.w-prog .hd .manage {
  display: inline-flex; align-items: center; gap: 4px; flex: none;
  padding: 6px 10px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 9.5px; font-weight: 700; letter-spacing: .4px;
  text-transform: uppercase; color: var(--mut);
}
.w-prog .hd .manage svg { width: 10px; height: 10px }
.w-prog .strip { padding: 0 12px 12px; display: flex; gap: 4px; flex-wrap: wrap }
.w-prog .strip span {
  flex: 1 1 36px; padding: 8px 0; border-radius: 10px;
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  border: 1px solid transparent;
}
.w-prog .strip span i {
  font-style: normal; font-size: 9.5px; font-weight: 700; letter-spacing: .4px;
  line-height: 12px; color: var(--mut);
}
.w-prog .strip span em { height: 12px; display: grid; place-items: center }
.w-prog .strip span em b { width: 6px; height: 6px; border-radius: 3px; background: rgba(109, 40, 217, .55) }
.w-prog .strip span em svg { width: 12px; height: 12px; color: var(--mut) }
.w-prog .strip span.on { background: var(--acc-12); border-color: rgba(109, 40, 217, .85) }
.w-prog .strip span.on i { color: var(--acc); font-weight: 900 }
.w-prog .strip span.on em b { background: var(--acc) }
.w-prog .strip span.done em svg { color: var(--acc) }
.w-prog .next { border-top: 1px solid var(--line); padding: 13px 16px 16px; display: flex; flex-direction: column; gap: 10px }
.w-prog .next .eye {
  font-size: 10px; font-weight: 800; letter-spacing: 1.2px; text-transform: uppercase;
  color: var(--acc);
}
.w-prog .next h4 { margin: 3px 0 0; font-size: 20px; font-weight: 900; letter-spacing: -.4px; line-height: 25px }
.w-prog .chips { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 6px }
.w-prog .chips .m {
  padding: 3px 8px; border-radius: 999px;
  background: var(--acc-10); border: 1px solid var(--acc-25);
  font-size: 10px; font-weight: 800; letter-spacing: .3px; color: var(--acc);
}
.w-prog .chips .t {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 10px; font-weight: 700; color: var(--mut);
}
.w-prog .chips .t svg { width: 10px; height: 10px }
.w-prog .count { font-size: 10.5px; font-weight: 600; color: var(--sub); margin-top: 4px }
.w-ex { display: flex; align-items: center; gap: 10px; padding: 5px 4px; border-radius: 10px }
.w-ex .n {
  width: 32px; height: 32px; border-radius: 9px; flex: none;
  background: var(--surface); border: 1px solid var(--line);
  display: grid; place-items: center;
  font-size: 12px; font-weight: 900; color: var(--acc);
}
.w-ex .nm { flex: 1; min-width: 0; font-size: 13px; font-weight: 700; letter-spacing: -.2px; line-height: 17px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
.w-ex .psr { font-size: 11px; font-weight: 700; color: var(--sub); flex: none }
/* StartButton — the page's one loud element. */
.w-start {
  margin-top: 8px; border-radius: 14px; padding: 14px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  background: var(--acc); color: var(--acc-ink);
  box-shadow: 0 4px 10px rgba(109, 40, 217, .22);
  font-size: 13.5px; font-weight: 900; letter-spacing: .6px; text-transform: uppercase;
}
.w-start svg { width: 15px; height: 15px }

/* StatTileShell — a FIXED 148pt pair so the two always sit flush. */
/* Two half-width slots of the reorderable grid. ReorderableCardList lays its
   items out with flex-wrap + space-between and gives a half `width: '48.5%'`
   — NOT a flex child sized by its content, which is what this was, and why
   the four tiles came out ragged. */
.w-pair { display: flex; justify-content: space-between }
.w-pair > .w-act { width: 48.5%; min-width: 0 }
.w-tile {
  position: relative; flex: 1; height: 148px; padding: 14px; border-radius: 16px;
  background: var(--raised); border: 1px solid var(--line);
  display: flex; flex-direction: column; overflow: hidden;
}
.w-tile.lit { border-color: rgba(232, 133, 58, .5); box-shadow: 0 3px 10px rgba(232, 133, 58, .22) }
.w-tile.lit::before {
  content: ""; position: absolute; inset: 0; background: rgba(232, 133, 58, .09); pointer-events: none;
}
.w-tile .hd { display: flex; align-items: center; gap: 6px; position: relative }
.w-tile .hd .ic { width: 22px; height: 22px; border-radius: 8px; display: grid; place-items: center; flex: none }
.w-tile .hd .ic svg { width: 12px; height: 12px }
.w-tile .hd span {
  flex: 1; font-size: 10px; font-weight: 800; letter-spacing: .8px;
  text-transform: uppercase; color: var(--mut);
}
.w-tile .v { display: flex; align-items: baseline; gap: 5px; margin-top: 9px; position: relative }
.w-tile .v b {
  font-size: 28px; line-height: 32px; font-weight: 900; letter-spacing: -.8px;
  white-space: nowrap; min-width: 0;
}
.w-tile .v.v6 b { font-size: 24px; line-height: 28px }
.w-tile .v.v7 b { font-size: 21px; line-height: 25px }
.w-tile .v span { font-size: 11px; font-weight: 600; color: var(--mut) }
.w-tile .cx { margin-top: 3px; font-size: 10.5px; font-weight: 600; line-height: 14px; color: var(--sub); position: relative }
.w-tile .pfoot { margin-top: auto; padding-top: 8px; position: relative }
/* The week bars share one baseline, so the day letters line up under them
   instead of floating at whatever height each bar happens to end. */
.w-tile .spark { display: flex; gap: 3px; align-items: flex-end; min-height: 30px }
.w-tile .spark i {
  flex: 1; display: flex; flex-direction: column; justify-content: flex-end;
  align-items: center; gap: 2px;
}
.w-tile .spark i u { display: block; align-self: stretch; border-radius: 2px; text-decoration: none }
.w-tile .spark i em { font-style: normal; font-size: 7.5px; font-weight: 800; color: var(--mut) }
.w-tile .spark i.now em { color: var(--acc) }
.w-tile .segs { display: flex; gap: 3px; align-items: center }
.w-tile .segs i { flex: 1; height: 7px; border-radius: 4px; background: rgba(0, 0, 0, .09) }
.w-tile .segs i.on { background: #E8853A }
.w-tile .edit {
  position: absolute; top: 10px; right: 10px;
  display: inline-flex; align-items: center; gap: 3px;
  padding: 4px 8px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 9.5px; font-weight: 800; color: var(--sub);
}
.w-tile .edit svg { width: 10px; height: 10px }

/* PrimaryAction — the full-bleed accent bar. */
.w-cta {
  min-height: 60px; border-radius: 16px; padding: 0 18px;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  background: linear-gradient(180deg, var(--acc), rgba(109, 40, 217, .86));
  color: var(--acc-ink); font-size: 16px; font-weight: 800; letter-spacing: .2px;
  box-shadow: 0 4px 10px rgba(109, 40, 217, .18);
}
.w-cta svg { width: 20px; height: 20px }
.w-logpast {
  align-self: center; margin-top: 8px;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 14px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 12.5px; font-weight: 800;
}
.w-logpast svg { width: 14px; height: 14px; color: var(--mut) }

/* ActionTile — the half-width destinations. */
.w-act {
  min-height: 64px; padding: 14px 12px; border-radius: 16px;
  background: var(--raised); border: 1px solid var(--line);
  display: flex; align-items: center; gap: 8px;
}
.w-act .ic {
  width: 32px; height: 32px; border-radius: 10px; flex: none;
  background: var(--surface); display: grid; place-items: center;
}
.w-act .ic svg { width: 16px; height: 16px }
.w-act b {
  flex: 1; min-width: 0; font-size: 13px; font-weight: 700;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;   /* numberOfLines={1} */
}
.w-act .go { width: 13px; height: 13px; color: var(--mut); flex: none }

/* ══════════════════════════════════════════════════════════════════════════
   HABITS — app/(tabs)/mind.tsx
   Note this screen does NOT use the 20pt scroll padding: its header and rows
   are laid out at 16 with their own gaps.
   ══════════════════════════════════════════════════════════════════════════ */

.m-head { display: flex; align-items: center; gap: 8px; padding: 4px 16px 6px }
.m-head h2 { flex: 1; margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -.2px; line-height: 22px }
.m-head .chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 7px 12px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 11px; font-weight: 700; letter-spacing: 1.2px;
}
.m-head .chip svg { width: 15px; height: 15px }
.m-dsw { padding: 0 16px 8px }
.m-scroll {
  flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden;
  padding-top: 8px; display: flex; flex-direction: column; gap: 20px;
}

/* Momentum hero — receipt numeral, ring, then a hairline stat strip. */
.m-hero {
  margin: 6px 16px 0; border-radius: 20px; overflow: hidden;
  background: var(--raised); border: 1px solid var(--line);
}
.m-hero .top { display: flex; align-items: center }
.m-hero .top .l { flex: 1; min-width: 0; padding: 14px 0 14px 16px }
.m-hero .top .l .n { display: flex; align-items: baseline }
.m-hero .top .l .n b { font-size: 40px; line-height: 44px; font-weight: 900; letter-spacing: -2px }
.m-hero .top .l .n span { font-size: 19px; font-weight: 900; color: var(--mut) }
.m-hero .top .l .p {
  margin-top: 3px; font-size: 8.5px; font-weight: 900; letter-spacing: 1.6px;
  text-transform: uppercase; color: var(--mut);
}
.m-ring { position: relative; width: 62px; height: 62px; margin-right: 16px; flex: none; display: grid; place-items: center }
.m-ring svg { position: absolute; inset: 0; width: 62px; height: 62px }
.m-ring .rd { position: relative; display: flex; flex-direction: column; align-items: center }
.m-ring .rd b { font-size: 18px; font-weight: 900; letter-spacing: -.5px; line-height: 21px }
.m-ring .rd span { font-size: 9.5px; font-weight: 800; color: var(--mut); line-height: 12px }
.m-stats { display: flex; border-top: 1px solid var(--line); background: var(--surface) }
.m-stats div { flex: 1; min-width: 0; padding: 10px 12px; border-left: 1px solid var(--line) }
.m-stats div:first-child { border-left: 0 }
.m-stats b { font-size: 16px; line-height: 21px; font-weight: 900 }
.m-stats b span { font-size: 9.5px; font-weight: 800; color: var(--mut) }
.m-stats i {
  display: block; margin-top: 2px; font-style: normal;
  font-size: 8px; font-weight: 900; letter-spacing: .9px; text-transform: uppercase; color: var(--mut);
}

/* Time-of-day group: a bare header row, then ONE grouped card of rows. */
.m-group { display: flex; flex-direction: column; gap: 8px }
.m-group .gh { display: flex; align-items: center; gap: 8px; padding: 0 20px }
.m-group .gh svg { width: 13px; height: 13px; color: var(--mut); flex: none }
.m-group .gh .lab {
  font-size: 10px; font-weight: 800; letter-spacing: 1.2px; text-transform: uppercase;
  color: var(--mut);
}
.m-group .gh .meter { flex: 1; display: flex; justify-content: flex-end; gap: 3px }
.m-group .gh .meter i { width: 13px; height: 4px; border-radius: 2px; background: var(--surface-strong) }
.m-group .gh .meter i.on { background: var(--acc) }
.m-group .gh .cnt {
  font-size: 11px; font-weight: 800; line-height: 14px; color: var(--mut); flex: none;
}
.m-group.done .gh svg, .m-group.done .gh .lab, .m-group.done .gh .cnt { color: var(--acc) }
.m-list {
  margin: 0 16px; border-radius: 16px; overflow: hidden;
  background: var(--raised); border: 1px solid var(--line);
}
.m-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px; border-top: 1px solid var(--line);
}
.m-row:first-child { border-top: 0 }
.m-row .ic {
  width: 36px; height: 36px; border-radius: 12px; flex: none;
  background: var(--surface); display: grid; place-items: center; color: var(--sub);
}
.m-row.on .ic { background: var(--acc-12); color: var(--acc) }
.m-row .ic svg { width: 17px; height: 17px }
.m-row .tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px }
.m-row .tx b { font-size: 14.5px; font-weight: 700;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
.m-row.on .tx b { color: var(--mut) }
.m-row .tx span { font-size: 11px; font-weight: 600; line-height: 14px; color: var(--mut) }
.m-row .pen { width: 28px; height: 28px; border-radius: 9px; display: grid; place-items: center; opacity: .58; flex: none }
.m-row .pen svg { width: 13px; height: 13px; color: var(--sub) }
.m-row .flame { display: flex; align-items: center; gap: 3px; flex: none; color: var(--mut) }
.m-row .flame svg { width: 13px; height: 13px }
.m-row .flame b { font-size: 12px; font-weight: 800; line-height: 15px; color: var(--sub) }
.m-row.on .flame, .m-row.on .flame b { color: var(--acc) }
/* CheckDisc — 30pt ring, 2pt stroke; filled accent disc + tick when met. */
.m-disc {
  position: relative; width: 30px; height: 30px; border-radius: 15px; flex: none;
  border: 2px solid var(--line-strong); box-sizing: border-box;
  display: grid; place-items: center;
}
.m-disc.late { border-color: rgba(255, 59, 48, .55) }
.m-disc.on { border-color: transparent; background: var(--acc); color: var(--acc-ink) }
.m-disc.on svg { width: 16px; height: 16px }
.m-disc svg { display: none }
.m-disc.on svg { display: block }

.m-add { display: flex; gap: 8px; padding: 0 16px }
.m-add span {
  flex: 1; height: 42px; border-radius: 999px;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 12.5px; font-weight: 800;
}
.m-add span svg { width: 14px; height: 14px; color: var(--mut) }

/* ══════════════════════════════════════════════════════════════════════════
   COACH — app/ai-chat.tsx
   A bottom sheet, not a tab: grab handle, header, hairline, transcript,
   the adaptive prompt strip, the composer, the disclaimer.
   ══════════════════════════════════════════════════════════════════════════ */

.c-sheet { background: var(--bg); padding-top: 12px }
.c-grab { width: 40px; height: 5px; border-radius: 3px; background: var(--line); margin: 6px auto 8px }
.c-head { display: flex; align-items: center; gap: 8px; padding: 2px 12px 10px }
.c-head .x { width: 34px; height: 34px; border-radius: 17px; display: grid; place-items: center; flex: none; color: var(--sub) }
.c-head .x svg { width: 20px; height: 20px }
.c-head .mark { width: 40px; height: 40px; flex: none }
.c-head .mark img { width: 39px; height: 39px }
.c-head .tx { flex: 1; min-width: 0 }
.c-head .tx b { display: block; font-size: 16px; font-weight: 900; letter-spacing: -.4px; line-height: 19px }
.c-head .tx .st {
  display: inline-flex; align-items: center; gap: 5px; margin-top: 3px;
  padding: 3px 8px; border-radius: 999px;
  background: var(--acc-10); border: 1px solid var(--acc-25);
  font-size: 10px; font-weight: 800; color: var(--acc); letter-spacing: .2px;
}
.c-head .st i { width: 6px; height: 6px; border-radius: 3px; background: var(--acc) }
.c-head .act { width: 36px; height: 36px; border-radius: 18px; display: grid; place-items: center; flex: none; color: var(--sub) }
.c-head .act svg { width: 19px; height: 19px }
.c-rule { height: 1px; background: var(--line); margin: 0 16px }

.c-thread {
  flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden;
  padding: 16px 16px 12px; display: flex; flex-direction: column; gap: 14px;
}
/* User turn — an accent-washed bubble with a squared bottom-right corner. */
.c-me {
  align-self: flex-end; max-width: 84%;
  padding: 11px 15px; border-radius: 16px 16px 6px 16px;
  background: var(--acc-14); border: 1px solid var(--acc-40);
  color: #3B1580; font-size: 15px; line-height: 21px;
}
/* Assistant turn — avatar, a 2pt accent spine, then FLAT text. Not a bubble:
   the app deliberately stopped drawing grey speech blobs. */
.c-them { display: flex; gap: 10px; padding-right: 6px }
.c-them .av { width: 28px; height: 28px; margin-top: 1px; flex: none }
.c-them .av img { width: 28px; height: 28px }
.c-them .spine { width: 2px; border-radius: 1px; background: rgba(109, 40, 217, .35); flex: none }
.c-them .bd { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px }
.c-them .bd p { margin: 0; font-size: 15px; line-height: 22px }
.c-them .bd p b { font-weight: 800 }
/* A tool receipt — what the coach actually did, as its own card. */
.c-tool {
  border-radius: 12px; padding: 11px 12px;
  background: var(--acc-10); border: 1px solid var(--acc-25);
  display: flex; flex-direction: column; gap: 8px;
}
.c-tool .hd { display: flex; align-items: center; gap: 6px; color: var(--acc) }
.c-tool .hd svg { width: 12px; height: 12px }
.c-tool .hd span { font-size: 9.5px; font-weight: 900; letter-spacing: 1.1px; text-transform: uppercase }
.c-tool b { font-size: 13.5px; font-weight: 800 }
.c-tool .mm { display: flex; gap: 14px }
.c-tool .mm i { font-style: normal; display: flex; flex-direction: column; gap: 1px }
.c-tool .mm i span { font-size: 8.5px; font-weight: 900; letter-spacing: .8px; text-transform: uppercase; color: var(--acc) }
.c-tool .mm i b { font-size: 13px; font-weight: 900 }

.c-sugg {
  display: flex; gap: 8px; padding: 8px 18px;
  overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
}
.c-sugg::-webkit-scrollbar { height: 0 }
.c-sugg span {
  flex: none; display: inline-flex; align-items: center; gap: 5px;
  padding: 8px 14px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 12px; font-weight: 600; white-space: nowrap;
}
.c-sugg span.hot {
  background: rgba(109, 40, 217, .13); border-color: rgba(109, 40, 217, .5);
  color: var(--acc); font-weight: 800;
}
.c-sugg span.hot svg { width: 11px; height: 11px }

.c-bar {
  padding: 8px 12px 42px; border-top: 1px solid var(--line); background: var(--bg);
}
.c-compose { display: flex; align-items: flex-end; gap: 8px }
.c-field {
  flex: 1; min-height: 44px; border-radius: 22px;
  background: var(--raised); border: 1px solid var(--line);
  display: flex; align-items: center;
}
.c-field .ib { width: 36px; height: 36px; border-radius: 18px; margin-left: 4px; display: grid; place-items: center; flex: none }
.c-field .ib svg { width: 20px; height: 20px; color: var(--mut) }
/* NOT `.ph` — that is the phone frame, and a placeholder inheriting a
   410 × 882 handset is a very confusing five minutes. */
.c-field .hint { flex: 1; padding: 0 4px; font-size: 15px; line-height: 20px; color: var(--mut) }
.c-send {
  width: 42px; height: 42px; border-radius: 21px; flex: none;
  display: grid; place-items: center; color: var(--acc-ink);
  background: linear-gradient(180deg, #8442E4, #5F23BE);
  box-shadow: 0 3px 8px rgba(109, 40, 217, .35);
}
.c-send svg { width: 19px; height: 19px }
.c-legal {
  margin: 8px 0 0; padding: 0 8px; text-align: center;
  font-size: 10.5px; line-height: 14px; color: var(--mut);
}

/* ══════════════════════════════════════════════════════════════════════════
   TODAY, BELOW THE FOLD — the rest of the reorderable stack.
   DEFAULT_SECTION_ORDER: recovery · strain · sleep · macrohero · vitals ·
   water-card · training · … · health(steps)
   ══════════════════════════════════════════════════════════════════════════ */

/* components/StrainMiniCard — the orb is frameless: its field spreads wider
   than the body and fades into the card. StrainOrb size 104 in a 128 field,
   AURA_PAD 34 → a 172 canvas, pulled -18 / -14 so it bleeds into the padding. */
.t-strain { padding: 12px 16px; display: flex; flex-direction: column; gap: 6px }
.t-strain .top { display: flex; align-items: center; gap: 10px }
.t-strain .orb {
  position: relative; width: 128px; height: 128px; flex: none;
  margin: -18px 0 -18px -14px;
}
.t-strain .orb .fld { position: absolute; left: 0; top: -22px; width: 128px; height: 172px }
/* The centre numeral: size × 0.25 at 900, with a quiet /21 on the same
   baseline — StrainRing draws no geometric ring in live-field mode, the
   morphing silhouette carries the progress. */
.t-strain .orb .val { position: absolute; inset: 0; z-index: 2; display: grid; place-items: center }
.t-strain .orb .val .n { display: flex; align-items: flex-end; gap: 4px }
.t-strain .orb .val b { font-size: 26px; font-weight: 900; letter-spacing: -1.5px; line-height: 28px }
.t-strain .orb .val span {
  font-size: 11px; font-weight: 800; color: var(--mut); line-height: 15px; margin-bottom: 4px;
}
.t-strain .rd { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px }
.t-strain .rd .hd { display: flex; align-items: center; gap: 6px }
.t-strain .rd .hd .eye {
  font-size: 9.5px; font-weight: 800; letter-spacing: .8px; text-transform: uppercase; color: var(--mut);
}
.t-strain .rd .hd .dl { display: flex; align-items: center; gap: 2px; color: var(--mut); font-size: 10px; font-weight: 800 }
.t-strain .rd .hd .dl svg { width: 10px; height: 10px }
.t-strain .rd .hd .sp { flex: 1 }
.t-strain .rd .hd .chev { width: 14px; height: 14px; color: var(--mut) }
.t-strain .rd h3 { margin: 0; font-size: 16px; font-weight: 900; line-height: 20px }
.t-strain .rd p { font-size: 11px; line-height: 15px; color: var(--sub) }
/* FlowSparkline — today's strain as it accumulated, a curve and not a bar
   chart: a shape you can read at 34pt. */
.t-strain .spark { height: 34px }
.t-strain .spark svg { width: 100%; height: 100%; display: block }
.t-strain .burn {
  display: flex; align-items: center; gap: 5px; margin-top: 2px;
  padding-top: 8px; border-top: 1px solid var(--line);
  font-size: 10.5px; font-weight: 600; color: var(--mut);
}
.t-strain .burn svg { width: 12px; height: 12px; color: #8B5CF6 }
.t-strain .burn b { font-size: 11.5px; font-weight: 800; color: var(--ink) }
.t-strain .burn b.q { color: var(--mut); margin-left: 6px }
.t-strain .burn .lite {
  margin-left: auto; padding: 2px 6px; border-radius: 6px; background: var(--surface);
  font-size: 8.5px; font-weight: 900; letter-spacing: .6px; color: var(--mut);
}

/* TodaysWorkoutCard — a 4pt accent bar down the left, then the plan. */
.t-work { display: flex }
.t-work .bar { width: 4px; background: var(--acc); flex: none }
.t-work .in { flex: 1; min-width: 0; padding: 18px; display: flex; align-items: center; gap: 12px }
.t-work .tx { flex: 1; min-width: 0 }
.t-work .tx .eye {
  font-size: 10px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; color: var(--mut);
}
.t-work .tx h3 { margin: 4px 0 0; font-size: 17px; font-weight: 600; letter-spacing: -.2px; line-height: 22px }
.t-work .pills { display: flex; gap: 12px; margin-top: 8px }
.t-work .pills span {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 8px; border-radius: 999px; background: var(--surface);
  font-size: 10px; font-weight: 700; color: var(--mut);
}
.t-work .pills span svg { width: 11px; height: 11px }
.t-work .go {
  width: 44px; height: 44px; border-radius: 8px; flex: none;
  background: var(--acc); color: var(--acc-ink); display: grid; place-items: center;
  box-shadow: 0 4px 8px rgba(109, 40, 217, .3);
}
.t-work .go svg { width: 18px; height: 18px }

/* ── Steps — components/StepsCard ────────────────────────────────────────
   The day as a lap of a circuit. Header chip + TODAY + freshness, then the
   count against a track whose fill is how far round the goal you are, then
   the pace pill, the verdict and the week. */
.t-steps { padding: 14px 16px 16px; display: flex; flex-direction: column; gap: 12px }
.t-steps .hd { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px }
.t-steps .hd .l { flex: 1; min-width: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 9px }
.t-steps .hd .ic {
  width: 30px; height: 30px; border-radius: 15px; flex: none;
  background: var(--acc-14); display: grid; place-items: center; color: var(--acc);
}
.t-steps .hd .ic svg { width: 14px; height: 14px }
.t-steps .hd .day { font-size: 11px; font-weight: 900; letter-spacing: 1px; text-transform: uppercase }
.t-steps .hd .ago { font-size: 10px; font-weight: 700; color: var(--sub) }
.t-steps .hd .streak {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 3px 7px; border-radius: 999px; background: var(--acc-14); color: var(--acc);
  font-size: 10.5px; font-weight: 900; line-height: 13px;
}
.t-steps .hd .streak svg { width: 10px; height: 10px }
.t-steps .hd .ref {
  width: 30px; height: 30px; border-radius: 15px; flex: none;
  background: var(--surface); border: 1px solid var(--line);
  display: grid; place-items: center; color: var(--mut);
}
.t-steps .hd .ref svg { width: 13px; height: 13px }
.t-steps .phero { display: flex; align-items: center; gap: 8px }
.t-steps .phero .l { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px }
.t-steps .phero b { font-size: 40px; font-weight: 900; letter-spacing: -1.6px; line-height: 44px }
.t-steps .phero .unit {
  font-size: 11px; font-weight: 800; letter-spacing: 1.6px; text-transform: uppercase; color: var(--sub);
}
.t-steps .phero .pct { display: flex; align-items: baseline; gap: 5px; margin-top: 6px }
.t-steps .phero .pct em { font-style: normal; font-size: 19px; font-weight: 900; line-height: 23px; color: var(--acc) }
.t-steps .phero .pct span { font-size: 12px; font-weight: 700; color: var(--sub) }
/* THE RACE CIRCUIT — the polyline from components/StepsCard.tsx, not an
   approximation of it. The dash fill is the lap walked so far and the marble
   rides its leading edge. The track box is 150 × 112 exactly. */
.t-steps .track { width: 150px; height: 112px; flex: none }
.t-steps .track svg { width: 150px; height: 112px; display: block }
.t-steps .pills { display: flex; align-items: center; justify-content: space-between; gap: 8px }
.t-steps .pace {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 12px; border-radius: 999px;
  background: var(--acc-14); border: 1px solid rgba(109, 40, 217, .35); color: var(--acc);
  font-size: 11px; font-weight: 900; letter-spacing: 1px; text-transform: uppercase; line-height: 13px;
}
.t-steps .pace svg { width: 12px; height: 12px }
.t-steps .kcal {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 7px 11px; border-radius: 999px;
  background: rgba(232, 133, 58, .13); border: 1px solid rgba(232, 133, 58, .32); color: #C46A1E;
  font-size: 11.5px; font-weight: 900; line-height: 13px;
}
.t-steps .kcal svg { width: 12px; height: 12px }
.t-steps .verdict { font-size: 13px; line-height: 17px; font-weight: 600; color: var(--sub) }
/* PaceBars — components/StepsCard.tsx. WEEK_CHART_H is 52, the gap is 8, and
   every bar is a rounded 7 pill rather than a column with square shoulders. */
.t-steps .week { display: flex; flex-direction: column; gap: 8px }
.t-steps .week .wk-hd { display: flex; align-items: center; justify-content: space-between }
.t-steps .week .wk-hd > span {
  font-size: 10px; font-weight: 800; letter-spacing: 1.2px; text-transform: uppercase; color: var(--mut);
}
/* The whole card opens the history sheet; nothing SAID so. This is the
   invitation. */
.t-steps .week .chip {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 4px 9px; border-radius: 999px;
  background: var(--acc-14); color: var(--acc) !important;
  letter-spacing: .4px !important;
}
.t-steps .week .chip svg { width: 10px; height: 10px }
.t-steps .week .rule { height: 1px; background: var(--line) }
.t-steps .week .bars { display: flex; align-items: flex-end; gap: 8px; height: 52px; margin-top: 2px }
/* Only the last bar carries the pace colour. Six inked bars is a rainbow;
   one is a reading. */
.t-steps .week .bars i { flex: 1; border-radius: 7px; background: var(--surface) }
.t-steps .week .bars i.on { background: var(--acc) }
.t-steps .week .days { display: flex; gap: 8px }
.t-steps .week .days b {
  flex: 1; text-align: center; font-size: 10.5px; font-weight: 700; line-height: 13px;
  text-transform: uppercase; color: var(--mut);
}
.t-steps .week .days b.on { font-weight: 900; color: var(--acc) }
.t-steps .goal {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-radius: 14px;
  background: var(--surface); border: 1px solid var(--line);
}
.t-steps .goal .l { display: flex; align-items: center; gap: 8px; font-size: 13.5px; font-weight: 800 }
.t-steps .goal .l svg { width: 13px; height: 13px; color: #C46A1E }
.t-steps .goal .r { display: flex; align-items: center; gap: 3px; font-size: 12.5px; font-weight: 700; color: var(--sub) }
.t-steps .goal .r svg { width: 13px; height: 13px; color: var(--mut) }

/* ── Vitals — components/HealthMiniCard ──────────────────────────────────
   Four live readings, each in its own colour and with its own week. Not four
   numbers over one shared line: that is a summary of one metric pretending
   to be a summary of four. */
.t-vitals { padding: 16px }
.t-vitals .hd { display: flex; align-items: center; gap: 5px; margin-bottom: 12px }
.t-vitals .hd > svg { width: 13px; height: 13px; color: var(--acc); flex: none }
.t-vitals .hd .lab {
  flex: 1; font-size: 9.5px; font-weight: 900; letter-spacing: .8px;
  text-transform: uppercase; color: var(--mut); line-height: 12px;
}
.t-vitals .hd .open { font-size: 10px; font-weight: 800; color: var(--sub) }
.t-vitals .hd .chev { width: 12px; height: 12px; color: var(--sub); flex: none }
.t-vitals .cols { display: flex; gap: 8px }
.t-vitals .col { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px }
.t-vitals .col .k { display: flex; align-items: center; gap: 3px }
.t-vitals .col .k svg { width: 9px; height: 9px; flex: none }
.t-vitals .col .k span {
  flex: 1; min-width: 0; font-size: 7.5px; font-weight: 900; letter-spacing: .4px;
  text-transform: uppercase; color: var(--mut); line-height: 9px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.t-vitals .col .v { display: flex; align-items: baseline; gap: 2px }
.t-vitals .col .v b { font-size: 16px; font-weight: 900; letter-spacing: -.4px; line-height: 19px }
.t-vitals .col .v span { font-size: 8px; font-weight: 800; color: var(--sub) }
.t-vitals .col .sp { height: 22px }
.t-vitals .col .sp svg { width: 100%; height: 100%; display: block }

/* ══ FUEL, BELOW THE FOLD ═════════════════════════════════════════════════
   components/macros/DayTimeline — the log grouped by meal, on a hairline
   rail: a dot per group, then 38pt rows. */
.f-log { display: flex; flex-direction: column }
.f-meal { display: flex }
.f-meal .rail { width: 22px; display: flex; flex-direction: column; align-items: center; flex: none }
.f-meal .rail i {
  width: 11px; height: 11px; border-radius: 6px; margin-top: 6px;
  background: var(--line-strong); border: 2px solid var(--bg); box-sizing: content-box;
}
.f-meal .rail u { flex: 1; width: 1px; margin-top: 3px; background: var(--line); text-decoration: none }
.f-meal .grp { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; padding-bottom: 18px }
.f-meal.last .grp { padding-bottom: 0 }
.f-meal .gh { display: flex; align-items: center; gap: 6px; min-height: 22px }
.f-meal .gh svg { width: 12px; height: 12px; color: var(--mut) }
.f-meal .gh .lab {
  font-size: 10.5px; font-weight: 800; letter-spacing: 1px; text-transform: uppercase; color: var(--mut);
}
.f-meal .gh .kcal {
  margin-left: auto; padding: 3px 8px; border-radius: 999px; background: var(--surface);
  font-size: 10.5px; font-weight: 800; color: var(--sub);
}
.f-rows { display: flex; flex-direction: column; gap: 6px }
.f-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 14px;
  background: var(--raised); border: 1px solid var(--line);
}
.f-row .thumb {
  width: 38px; height: 38px; border-radius: 10px; flex: none;
  background: var(--surface); display: grid; place-items: center; font-size: 19px;
}
.f-row .tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px }
.f-row .tx b {
  font-size: 13px; font-weight: 800; letter-spacing: -.2px; line-height: 16px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.f-row .meta { display: flex; align-items: center; gap: 8px }
.f-row .meta .time { display: flex; align-items: center; gap: 3px; color: var(--mut); font-size: 10px; font-weight: 700 }
.f-row .meta .time svg { width: 9px; height: 9px }
.f-row .meta .trio { display: flex; align-items: center; gap: 3px; font-size: 9.5px; font-weight: 700; color: var(--sub) }
.f-row .meta .trio i { width: 5px; height: 5px; border-radius: 3px }
.f-row .kc { text-align: right; flex: none }
.f-row .kc b { display: block; font-size: 15px; font-weight: 900; letter-spacing: -.3px; line-height: 18px }
.f-row .kc span { font-size: 9.5px; font-weight: 700; letter-spacing: .5px; color: var(--mut) }

/* The stats pill under the log. */
.f-stats {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 14px; border-radius: 16px;
  background: var(--raised); border: 1px solid var(--line);
}
.f-stats .ic {
  width: 36px; height: 36px; border-radius: 12px; flex: none;
  background: var(--surface); display: grid; place-items: center; color: var(--acc);
}
.f-stats .ic svg { width: 18px; height: 18px }
.f-stats .tx { flex: 1; min-width: 0 }
.f-stats .tx b { display: block; font-size: 14px; font-weight: 900; letter-spacing: -.2px }
.f-stats .tx span { font-size: 11px; font-weight: 600; color: var(--sub) }
.f-stats .chev { width: 14px; height: 14px; color: var(--mut); flex: none }

/* ══ TRAIN, BELOW THE FOLD ════════════════════════════════════════════════
   components/CardioCard — its own layout tokens: radius 22, inset 18. */
.w-cardio {
  border-radius: 22px; padding: 18px; display: flex; flex-direction: column; gap: 17px;
  background: var(--raised); border: 1px solid var(--line);
}
.w-cardio .hd { display: flex; align-items: center; gap: 11px }
.w-cardio .hd .ic {
  width: 42px; height: 42px; border-radius: 14px; flex: none;
  background: var(--surface); border: 1px solid var(--line);
  display: grid; place-items: center; color: var(--acc);
}
.w-cardio .hd .ic svg { width: 20px; height: 20px }
.w-cardio .hd .tx { flex: 1; min-width: 0 }
.w-cardio .hd .tx b { display: block; font-size: 18px; line-height: 22px; font-weight: 800 }
.w-cardio .hd .tx span { display: block; margin-top: 2px; font-size: 12px; line-height: 17px; font-weight: 600; color: var(--mut) }
.w-cardio .mid { display: flex; align-items: flex-end; min-height: 70px }
.w-cardio .mid .l { flex: 1; min-width: 0 }
.w-cardio .mid .big { display: flex; align-items: baseline; gap: 5px }
.w-cardio .mid .big b { font-size: 42px; line-height: 46px; font-weight: 800; letter-spacing: -1.6px }
.w-cardio .mid .big span { font-size: 12px; font-weight: 700; color: var(--mut) }
.w-cardio .mid .sub { display: flex; align-items: center; margin-top: 8px; font-size: 12px; font-weight: 700; color: var(--sub) }
.w-cardio .mid .sub u { width: 1px; height: 12px; background: var(--line); margin: 0 9px; text-decoration: none }
.w-cardio .bars { display: flex; align-items: flex-end; gap: 5px; height: 45px }
.w-cardio .bars i { width: 8px; border-radius: 3px; background: var(--track) }
.w-cardio .bars i.on { background: var(--acc) }
.w-cardio .go {
  min-height: 52px; border-radius: 16px; padding: 0 16px;
  display: flex; align-items: center; justify-content: center; gap: 9px;
  background: var(--acc); color: var(--acc-ink); font-size: 15px; font-weight: 800;
}
.w-cardio .go svg { width: 17px; height: 17px }

/* The history header — a collapsed month section. */
.w-hist {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px; border-radius: 16px;
  background: var(--raised); border: 1px solid var(--line);
}
.w-hist .ic { width: 30px; height: 30px; border-radius: 10px; background: var(--surface); display: grid; place-items: center; color: var(--mut); flex: none }
.w-hist .ic svg { width: 15px; height: 15px }
.w-hist b { flex: 1; font-size: 13px; font-weight: 800 }
.w-hist .n { font-size: 11px; font-weight: 800; color: var(--mut) }
.w-hist .chev { width: 14px; height: 14px; color: var(--mut) }

/* ══ HABITS — the weekly heat ledger ══════════════════════════════════════ */
.m-week { display: flex; flex-direction: column; gap: 8px }
.m-week .eye { display: flex; align-items: center; gap: 8px; padding: 0 20px }
.m-week .eye svg { width: 13px; height: 13px; color: var(--mut) }
.m-week .eye span { font-size: 10px; font-weight: 800; letter-spacing: 1.2px; text-transform: uppercase; color: var(--mut) }
.m-ledger {
  margin: 0 16px; border-radius: 16px; overflow: hidden;
  background: var(--raised); border: 1px solid var(--line);
}
.m-ledger .lh { display: flex; align-items: center; gap: 10px; padding: 9px 14px 3px }
.m-ledger .lh .pad { width: 26px; flex: none }
.m-ledger .lh .fill { flex: 1 }
.m-ledger .lh .days { display: flex; gap: 3px }
.m-ledger .lh .days span { width: 13px; text-align: center; font-size: 8px; font-weight: 900; color: var(--mut) }
.m-ledger .lh .tail { width: 36px; flex: none }
.m-lrow {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 14px; border-top: 1px solid var(--line);
}
.m-lrow .ic { width: 26px; height: 26px; border-radius: 9px; background: var(--surface); display: grid; place-items: center; color: var(--sub); flex: none }
.m-lrow .ic svg { width: 13px; height: 13px }
.m-lrow .nm { flex: 1; min-width: 0; font-size: 13px; font-weight: 600; color: var(--sub);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
.m-lrow .cells { display: flex; gap: 3px; flex: none }
.m-lrow .cells i { width: 13px; height: 13px; border-radius: 4px; background: var(--surface) }
.m-lrow .cells i.met { background: var(--acc) }
.m-lrow .cells i.part { background: rgba(109, 40, 217, .32) }
.m-lrow .cells i.today { border: 1px solid var(--line-strong) }
.m-lrow .pc { width: 36px; text-align: right; font-size: 12px; font-weight: 900; line-height: 15px; flex: none }
.m-lrow .pc.on { color: var(--acc) }

/* ══════════════════════════════════════════════════════════════════════════
   THE REST OF THE APP
   Every screen the site shows, at the same 1px = 1pt fidelity.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── A pushed page's header — chevron, one word, controls ───────────────── */
.ap-head {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 16px 10px; flex: none;
}
.ap-head .back { width: 22px; height: 22px; flex: none; color: var(--ink) }
.ap-head h2 { margin: 0; font-size: 20px; font-weight: 800; letter-spacing: -.4px }
.ap-head .sp { flex: 1 }
.ap-head .ic { width: 18px; height: 18px; color: var(--sub); flex: none }
.ap-head .eye {
  display: block; font-size: 10px; font-weight: 800; letter-spacing: .8px;
  text-transform: uppercase; color: var(--mut);
}
/* The 7d / 30d / 90d segmented control. */
.ap-seg {
  display: flex; padding: 2px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line); flex: none;
}
.ap-seg span {
  padding: 4px 10px; border-radius: 999px;
  font-size: 10.5px; font-weight: 900; color: var(--sub);
}
.ap-seg span.on { background: var(--acc); color: var(--acc-ink) }

/* ══ HEALTH HUB — app/health.tsx ══════════════════════════════════════════
   One full-width heart composition, then a two-column board where a MEASURED
   tile (sparkline, delta chip) and a SCORE tile (chevron, no sparkline) look
   different on purpose — nobody should mistake Heala's opinion for a reading. */
.h-scroll { padding: 0 16px; gap: 12px }
.h-heart { padding: 16px; display: flex; flex-direction: column; gap: 12px }
.h-heart .hd { display: flex; align-items: center; gap: 6px }
.h-heart .hd .ic { width: 18px; height: 18px; border-radius: 6px; display: grid; place-items: center; flex: none }
.h-heart .hd .ic svg { width: 11px; height: 11px }
.h-heart .hd span {
  flex: 1; font-size: 9px; font-weight: 900; letter-spacing: .8px;
  text-transform: uppercase; color: var(--mut);
}
.h-heart .v { display: flex; align-items: baseline; gap: 4px }
.h-heart .v b { font-size: 34px; font-weight: 900; letter-spacing: -1.4px; line-height: 38px }
.h-heart .v span { font-size: 12px; font-weight: 800; color: var(--sub) }
.h-heart .chart { height: 76px }
.h-heart .chart svg { width: 100%; height: 100%; display: block; overflow: visible }
.h-heart .legend { display: flex; gap: 14px }
.h-heart .legend i {
  font-style: normal; display: flex; align-items: center; gap: 5px;
  font-size: 10px; font-weight: 800; color: var(--mut);
}
.h-heart .legend i u { width: 12px; height: 2px; border-radius: 1px; text-decoration: none }

/* THE BOARD. Two columns of 48.5% halves with space-between — the same
   geometry ReorderableCardList gives every half-width slot, so the tiles pair
   into rows the way they do in the app. */
.h-grid { display: flex; flex-wrap: wrap; justify-content: space-between; row-gap: 14px }
.h-tile {
  width: 48.5%; min-width: 0; padding: 12px; border-radius: 18px;
  background: var(--raised); border: 1px solid var(--line);
  display: flex; flex-direction: column;
}
.h-tile .hd { display: flex; align-items: center; gap: 5px; margin-bottom: 8px }
/* The glyph carries the identity; the label stays quiet. A tinted LABEL
   would make ten tiles shout at once. */
.h-tile .ic { width: 18px; height: 18px; border-radius: 6px; display: grid; place-items: center; flex: none }
.h-tile .ic svg { width: 11px; height: 11px }
.h-tile .hd > span:nth-child(2) {
  flex: 1; min-width: 0; font-size: 9px; font-weight: 900; letter-spacing: .8px;
  text-transform: uppercase; color: var(--mut); line-height: 11px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.h-tile .chev { width: 11px; height: 11px; color: var(--sub); flex: none }
.h-tile .v { display: flex; align-items: baseline; gap: 3px }
.h-tile .v b { font-size: 24px; line-height: 28px; font-weight: 900; letter-spacing: -.8px; font-variant-numeric: tabular-nums }
.h-tile .v span { font-size: 10.5px; font-weight: 800; color: var(--sub) }
.h-tile .avg {
  margin-top: 2px; font-size: 8.5px; font-weight: 800; letter-spacing: .5px;
  text-transform: uppercase; color: var(--mut); line-height: 11px; font-variant-numeric: tabular-nums;
}
/* The tile chart, with enough scale to be read: a two-value y axis, the
   first and last date, a ring on every reading, and a dashed rule at the
   window mean — the number the AVG caption refers to, drawn instead of
   asserted. 54 tall, insets 5/4/11/21. */
.h-tile .sp { display: block; width: 100%; height: 54px; margin-top: 6px }
.h-tile .sp .ax { font-size: 7.5px; font-weight: 700; fill: rgba(0,0,0,.45) }
/* A score tile has no chart, so it pads out to its neighbour's height
   instead of leaving a ragged row. */
.h-score { justify-content: flex-start }
.h-score .avg { margin-top: auto; padding-top: 12px }

/* ══ BANDS — app/settings/integrations.tsx ════════════════════════════════
   Logo first, zero paragraph copy: brand mark + name + one action. */
.b-card { border-radius: 16px; overflow: hidden }
.b-row {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 14px; border-top: 1px solid var(--line);
}
.b-row:first-child { border-top: 0 }
.b-mark {
  width: 38px; height: 38px; border-radius: 10px; flex: none;
  overflow: hidden; background: var(--surface);
  display: grid; place-items: center;
}
.b-mark img { width: 100%; height: 100%; object-fit: cover }
.b-row .tx { flex: 1; min-width: 0 }
.b-row .tx .nm { display: flex; align-items: center; gap: 6px }
.b-row .tx b { font-size: 15px; font-weight: 800; letter-spacing: -.2px }
.b-row .tx .dot { width: 7px; height: 7px; border-radius: 4px; background: var(--acc); flex: none }
.b-row .tx span {
  display: block; margin-top: 2px; font-size: 10.5px; font-weight: 500; color: var(--sub);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.b-connect {
  padding: 8px 15px; border-radius: 999px; flex: none;
  background: var(--acc); color: var(--acc-ink); font-size: 12px; font-weight: 800;
}
.b-off {
  display: inline-flex; align-items: center; gap: 5px; flex: none;
  padding: 7px 11px; border-radius: 999px;
  border: 1px solid rgba(255, 59, 48, .4); color: var(--coral);
  font-size: 12px; font-weight: 800;
}
.b-off svg { width: 13px; height: 13px }
.b-sync {
  min-height: 46px; display: flex; align-items: center; justify-content: center; gap: 7px;
  border-top: 1px solid var(--line); color: var(--acc); font-size: 13px; font-weight: 800;
}
.b-sync svg { width: 14px; height: 14px }
.b-soon {
  display: inline-flex; align-items: center; padding: 3px 8px; border-radius: 999px;
  background: var(--surface); font-size: 9.5px; font-weight: 900;
  letter-spacing: .6px; text-transform: uppercase; color: var(--mut); flex: none;
}

/* ══ RECOVERY — app/recovery.tsx ══════════════════════════════════════════ */
.r-hero {
  border-radius: 24px; overflow: hidden;
  background: var(--raised);
  border: 1px solid rgba(28, 143, 70, .45);
  box-shadow: 0 3px 8px rgba(0, 0, 0, .06);
}
.r-hero .top {
  padding: 20px; display: flex; flex-direction: column; gap: 18px;
  background: linear-gradient(135deg, rgba(28, 143, 70, .16), rgba(28, 143, 70, 0));
}
.r-hero .hd { display: flex; align-items: center; justify-content: space-between; gap: 12px }
.r-hero .hd .l { flex: 1; display: flex; flex-direction: column; gap: 6px }
.r-hero .hd .eye {
  font-size: 10.5px; font-weight: 800; letter-spacing: 1.1px;
  text-transform: uppercase; color: var(--mut);
}
.r-hero .mood {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  padding: 6px 10px; border-radius: 999px;
  background: rgba(28, 143, 70, .12); border: 1px solid rgba(28, 143, 70, .26);
  color: var(--score-100);
  font-size: 10.5px; font-weight: 900; letter-spacing: .8px; text-transform: uppercase;
}
.r-hero .mood svg { width: 13px; height: 13px }
.r-hero .hint { margin-top: -10px; font-size: 10px; line-height: 13px; color: var(--mut) }
.r-hero .cell { display: flex; flex-direction: column; align-items: center; gap: 2px }
/* RecoveryOrb size 196, PAD 22 → a 240 canvas, pulled -14 vertically. */
.r-orb { position: relative; width: 100%; height: 240px; margin: -14px 0 }
.r-orb .num {
  position: absolute; inset: 0; z-index: 2; display: flex; flex-direction: column;
  align-items: center; justify-content: center;
}
.r-orb .num b { font-size: 59px; font-weight: 900; letter-spacing: -2.6px; line-height: 62px }
.r-orb .num span {
  margin-top: 2px; font-size: 9px; font-weight: 800; letter-spacing: .6px;
  text-transform: uppercase; color: var(--mut);
}
.r-hero h3 { margin: 0; font-size: 24px; font-weight: 900; line-height: 28px; letter-spacing: -.65px; text-align: center }
.r-hero .coach {
  padding: 16px 20px; border-top: 1px solid var(--line);
  font-size: 13.5px; line-height: 20px; font-weight: 600; color: var(--sub);
}
/* The signal rows under the hero. */
.r-sig { padding: 16px; display: flex; flex-direction: column; gap: 14px }
.r-sig .row { display: flex; align-items: center; gap: 10px }
.r-sig .row > svg { width: 13px; height: 13px; flex: none }
.r-sig .bd { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px }
.r-sig .bd .t { display: flex; justify-content: space-between }
.r-sig .bd .t span {
  font-size: 11px; font-weight: 700; letter-spacing: .5px;
  text-transform: uppercase; color: var(--mut);
}
.r-sig .bd .t b { font-size: 11px; font-weight: 700 }
.r-sig .bar { height: 5px; border-radius: 3px; background: var(--surface-strong); overflow: hidden }
.r-sig .bar i { display: block; height: 100% }

/* ══ STRAIN — app/strain.tsx ══════════════════════════════════════════════ */
/* ══════════════════════════════════════════════════════════════════════════
   STRAIN — app/strain.tsx
   The hero is radius 16 (not 24), borders in the tier hue at 45%, and its
   wash runs TOP→BOTTOM at 20% / 5% / 0 — a vertical gradient reads as light
   falling on a surface; a diagonal one reads as an accident of the shape.
   ══════════════════════════════════════════════════════════════════════════ */
.s-hero {
  border-radius: 16px; overflow: hidden;
  background: var(--raised); border: 1px solid rgba(139, 92, 246, .45);
  box-shadow: 0 4px 14px -6px rgba(139, 92, 246, .5);
}
.s-hero .top {
  padding: 16px; display: flex; flex-direction: column; gap: 14px;
  background: linear-gradient(180deg, rgba(139,92,246,.20) 0%, rgba(139,92,246,.05) 55%, rgba(139,92,246,0) 100%);
}
.s-hero .eyerow { display: flex; align-items: center; justify-content: space-between }
.s-hero .eye { font-size: 10px; font-weight: 800; letter-spacing: .8px; text-transform: uppercase; color: var(--mut) }
/* Zone stamp — a flame and a word in the tier's hue, NOT a pill. */
.s-hero .ptier {
  display: inline-flex; align-items: center; gap: 5px;
  color: #8B5CF6; font-size: 10px; font-weight: 900; letter-spacing: 1.2px;
  line-height: 13px; text-transform: uppercase;
}
.s-hero .ptier svg { width: 12px; height: 12px }
/* The orb field bleeds the full card width — no panel, no box: the card's
   own rounded clip contains it. StrainOrb size 208, AURA_PAD 34 → 276. */
.s-orb { position: relative; width: calc(100% + 32px); margin: -6px -16px; height: 276px }
.s-orb .num { position: absolute; inset: 0; z-index: 2; display: grid; place-items: center }
.s-orb .num .n { display: flex; align-items: flex-end; gap: 5px }
/* The score is theme.text; only the "/21" denominator is muted. `.num span`
   also matches the `.n` wrapper, which is how the whole numeral inherited
   45% ink and rendered grey. */
.s-orb .num b { font-size: 52px; font-weight: 900; letter-spacing: -1.5px; line-height: 56px; color: var(--ink) }
.s-orb .num .n > span { font-size: 16px; font-weight: 800; color: var(--mut); margin-bottom: 7px }
.s-hero .verdict {
  font-size: 15px; font-weight: 800; line-height: 20px; letter-spacing: -.2px; text-align: center;
}
.s-row {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 16px; border-top: 1px solid var(--line);
}
.s-row span { flex: 1; font-size: 11px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; color: var(--sub) }
.s-row b { font-size: 15px; font-weight: 900; letter-spacing: -.3px; font-variant-numeric: tabular-nums }

/* Energy burned today. */
.s-burn { padding: 14px }
.s-burn .hd { display: flex; align-items: center; gap: 6px }
.s-burn .hd b { flex: 1; font-size: 12px; font-weight: 800; letter-spacing: .8px; text-transform: uppercase; color: var(--mut) }
.s-burn .src {
  padding: 3px 7px; border-radius: 7px; background: var(--surface);
  font-size: 9px; font-weight: 900; letter-spacing: .6px; color: var(--mut);
}
.s-burn .figs { display: flex; align-items: flex-end; gap: 18px; margin-top: 10px }
.s-burn .figs .sp { flex: 1 }
.s-burn .figs b { display: block; font-size: 26px; line-height: 30px; font-weight: 900; font-variant-numeric: tabular-nums }
.s-burn .figs span { display: block; font-size: 11px; font-weight: 600; color: var(--mut) }
.s-burn .act b { color: var(--acc) }
.s-burn .bmr { text-align: right }
.s-burn .bmr b { font-size: 13px; line-height: 17px; font-weight: 800; color: var(--mut) }
.s-burn .bmr span { font-size: 10px }

/* Today's flow — the all-day accumulation curve. */
.s-flow { padding: 14px; display: flex; flex-direction: column; gap: 12px }
.s-flow .hd { display: flex; align-items: flex-start; gap: 10px }
.s-flow .tx { flex: 1; min-width: 0 }
.s-flow .tx b { display: block; font-size: 14px; font-weight: 900 }
.s-flow .tx span { display: block; margin-top: 3px; font-size: 11px; line-height: 15px; color: var(--mut) }
.s-flow .badge {
  flex: none; padding: 3px 7px; border-radius: 6px; background: rgba(139,92,246,.14);
  font-size: 9px; font-weight: 900; letter-spacing: .8px; color: #8B5CF6;
}
.s-flow .curve { display: block; width: 100%; height: 86px }
.s-flow .split { display: flex; gap: 16px }
.s-flow .split span { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 800; color: var(--sub) }
.s-flow .split i { width: 8px; height: 8px; border-radius: 3px }
.s-flow .split .c i { background: #38BDF8 }
.s-flow .split .m i { background: #8B5CF6 }

/* Heart-rate zones today. */
.s-zones { padding: 14px; display: flex; flex-direction: column; gap: 10px }
.s-zones .hd { font-size: 14px; font-weight: 900 }
.s-zones .z { display: flex; align-items: center; gap: 10px }
.s-zones .lb { width: 22px; font-size: 10.5px; font-weight: 900; font-variant-numeric: tabular-nums }
.s-zones .bar { flex: 1; height: 7px; border-radius: 4px; background: var(--surface); overflow: hidden }
.s-zones .bar i { display: block; height: 100%; border-radius: 4px }
.s-zones .mi { width: 52px; text-align: right; font-size: 10.5px; font-weight: 800; color: var(--mut); font-variant-numeric: tabular-nums }

/* 14-day column chart — thin rounded columns, tier-inked, the readout in
   its own row above the plot so a value can never collide with a column. */
.s-week { padding: 14px; display: flex; flex-direction: column; gap: 12px }
.s-week .hd { display: flex; align-items: baseline; justify-content: space-between }
.s-week .hd b { font-size: 14px; font-weight: 900 }
.s-week .read { font-size: 11px; font-weight: 700; color: var(--mut) }
.s-week .read em { font-style: normal; font-weight: 900; color: var(--ink); font-variant-numeric: tabular-nums }
.s-week .cols { display: flex; align-items: flex-end; gap: 4px; height: 84px }
.s-week .cols i {
  flex: 1; height: var(--h); border-radius: 3px; background: var(--c); opacity: .5;
}
.s-week .cols i.on { opacity: 1; box-shadow: 0 0 0 2px rgba(139,92,246,.2) }
.s-week .legend { display: flex; flex-wrap: wrap; gap: 6px }
.s-week .legend span {
  display: inline-flex; align-items: center; gap: 5px; padding: 4px 8px; border-radius: 999px;
  background: var(--surface); font-size: 9.5px; font-weight: 800; color: var(--sub);
}
.s-week .legend i { width: 7px; height: 7px; border-radius: 99px }

/* Sources + recent sessions — receipt rows. */
.s-src, .s-recent { padding: 14px; display: flex; flex-direction: column; gap: 10px }
.s-src .hd, .s-recent .hd { font-size: 14px; font-weight: 900 }
.s-src .d { display: flex; align-items: center; gap: 10px }
.s-src .k { flex: 1; display: inline-flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 700; color: var(--sub) }
.s-src .k i { width: 8px; height: 8px; border-radius: 3px; flex: none }
.s-src .d b { font-size: 14px; font-weight: 900; font-variant-numeric: tabular-nums }
.s-recent .rw {
  display: flex; align-items: center; gap: 10px; padding-top: 10px; border-top: 1px solid var(--line);
}
.s-recent .rw:first-of-type { padding-top: 0; border-top: 0 }
.s-recent .dt { width: 30px; font-size: 10.5px; font-weight: 900; letter-spacing: .6px; text-transform: uppercase; color: var(--mut) }
.s-recent .nm { flex: 1; min-width: 0; font-size: 13px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
.s-recent .mn { font-size: 11px; font-weight: 700; color: var(--mut); font-variant-numeric: tabular-nums }
.s-recent .rw b { width: 34px; text-align: right; font-size: 14px; font-weight: 900; font-variant-numeric: tabular-nums }

/* ══════════════════════════════════════════════════════════════════════════
   SLEEP — app/sleep.tsx
   Stage colours are the LIGHT set from `stageColors()`: awake #D97A1F,
   light #2E7CD6, rem #7C4DD6, deep #3148C9. (An earlier pass had this page
   in olive, which is nowhere in the app.)
   ══════════════════════════════════════════════════════════════════════════ */
.z-hero {
  border-radius: 16px; overflow: hidden; padding: 16px;
  display: flex; flex-direction: column; gap: 14px;
  /* ringTone = mixHex(nightScoreTone(72), theme.text, .14) = #9EAF5F. Every
     piece of this card's chrome derives from the night's own score, not from
     the app accent — a bad night is a red card and a good one is green. */
  background: linear-gradient(135deg, rgba(158,175,95,.20), rgba(158,175,95,.07) 50%, var(--raised));
  border: 1px solid rgba(158,175,95,.45);
}
.z-hero .eyerow { display: flex; align-items: center; justify-content: space-between }
.z-hero .eye { font-size: 10px; font-weight: 800; letter-spacing: .8px; text-transform: uppercase; color: var(--mut) }
.z-hero .tone {
  display: inline-flex; align-items: center; gap: 5px;
  color: #9EAF5F; font-size: 10px; font-weight: 900; letter-spacing: 1.2px;
  line-height: 13px; text-transform: uppercase;
}
.z-hero .tone svg { width: 12px; height: 12px }
.z-hero .tone .cv { width: 11px; height: 11px; color: var(--mut) }

/* The moon — the score as a phase inside its own night-sky well. */
.z-moon {
  height: 210px; border-radius: 18px; overflow: hidden; position: relative;
  background: linear-gradient(180deg, #232B4D 0%, #141A33 55%, #0B0E1F 100%);
}
.z-moon .rd {
  position: absolute; left: 20px; top: 0; bottom: 0; z-index: 1;
  display: flex; flex-direction: column; justify-content: center;
}
.z-moon .rd b { font-size: 46px; font-weight: 900; letter-spacing: -1.6px; line-height: 50px; color: #B8CC6F }
.z-moon .rd .word { margin-top: 2px; font-size: 15px; font-weight: 800; color: #B8CC6F }
.z-moon .rd .meta { margin-top: 5px; font-size: 10.5px; font-weight: 700; letter-spacing: .6px;
  text-transform: uppercase; color: rgba(255,255,255,.5) }
/* SVG fallback disc, replaced by the WebGL moon when it mounts. */
.z-moon .disc {
  position: absolute; right: 26px; top: 50%; width: 116px; height: 116px; margin-top: -58px;
  border-radius: 50%; background: radial-gradient(circle at 34% 30%, #F4F1E4, #C9C4AE 62%, #8A8674);
  box-shadow: 0 0 46px rgba(226,222,200,.34);
}

/* Duration numeral + clock line + vs-goal chip. */
.z-dur .n { display: flex; align-items: flex-end }
.z-dur .n b { font-size: 42px; line-height: 44px; font-weight: 900; letter-spacing: -1.8px; font-variant-numeric: tabular-nums }
.z-dur .n i { font-style: normal; font-size: 18px; line-height: 44px; font-weight: 800; color: var(--mut) }
.z-dur .n i:first-of-type { margin-right: 6px }
.z-dur .sub { margin-top: 8px; font-size: 10.5px; line-height: 14px; letter-spacing: .15px; color: var(--sub); font-variant-numeric: tabular-nums }
.z-dur .delta {
  display: inline-flex; align-items: center; gap: 4px; margin-top: 8px;
  height: 20px; padding: 0 8px; border-radius: 999px;
  /* deltaTone: 6h57m against an 8h goal is a 0.87 ratio — warm amber, not
     the accent. The chip is only accent-green at ≥0.9. */
  background: rgba(200,138,26,.10); border: 1px solid rgba(200,138,26,.30);
  color: #C88A1A; font-size: 11px; font-weight: 800; line-height: 13px; font-variant-numeric: tabular-nums;
}
.z-dur .delta svg { width: 10px; height: 10px }

/* Shared card header: uppercase label left, a tabular figure right. */
.z-stages, .z-river, .z-avg, .z-sched, .z-hrv { padding: 14px }
.z-stages .hd, .z-river .hd, .z-sched .hd, .z-hrv .hd {
  display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 10px;
}
.z-stages .hd span, .z-river .hd span, .z-sched .hd span, .z-hrv .hd span {
  font-size: 10px; font-weight: 800; letter-spacing: .8px; text-transform: uppercase; color: var(--mut);
}
.z-stages .hd em, .z-river .hd em, .z-sched .hd em, .z-hrv .hd em {
  font-style: normal; font-size: 11px; font-weight: 800; color: #3148C9; font-variant-numeric: tabular-nums;
}   /* sc.deep — the restorative figure is inked in the deep-stage colour */
.z-river .hd em, .z-sched .hd em { color: var(--mut) }

/* One stacked bar, 2px surface gaps between segments. */
.z-stages .bar { height: 14px; border-radius: 7px; overflow: hidden; display: flex; gap: 2px; background: var(--surface) }
.z-stages .bar i { border-radius: 2px }
.z-stages .legend { margin-top: 12px; display: flex; flex-direction: column; gap: 7px }
.z-stages .legend div { display: flex; align-items: center; gap: 10px }
.z-stages .legend i { width: 10px; height: 10px; border-radius: 3px; flex: none }
.z-stages .legend span { flex: 1; font-size: 12px; font-weight: 700 }
.z-stages .legend em { width: 40px; text-align: right; font-style: normal; font-size: 11px; font-weight: 800; color: var(--sub); font-variant-numeric: tabular-nums }
.z-stages .legend b { width: 50px; text-align: right; font-size: 11px; font-weight: 700; color: var(--mut); font-variant-numeric: tabular-nums }

/* Night river — the hypnogram as a depth ribbon. */
.z-river { position: relative }
.z-river svg { display: block; width: 100%; height: 104px }
/* ⚠️ 48px IS THE AWAKE LINE, NOT A GUESS. The dots mark real awakenings, so
   they have to sit ON the curve. The svg renders at exactly its 104-unit
   viewBox height, so one unit is one px: the awake depth is 8 + 0.06*(104-16)
   = 13.3 from the svg's top, the svg starts 38px down the card, and the 7px
   dot is centred on 51.3. The old 46px was tuned to the staircase's y=20
   plateau and left them floating five pixels clear of the new peaks. */
.z-river .wakes { position: absolute; left: 14px; right: 14px; top: 48px; height: 0 }
.z-river .wakes i {
  position: absolute; width: 7px; height: 7px; margin-left: -3.5px; border-radius: 50%;
  background: #E9B949; box-shadow: 0 0 0 2px var(--raised);
}
.z-river .tm, .z-sched .tm {
  display: flex; justify-content: space-between; margin-top: 8px;
  font-size: 9.5px; font-weight: 700; color: var(--mut); font-variant-numeric: tabular-nums;
}
.z-river .tm i, .z-sched .tm i { font-style: normal }

/* Tonight's bedtime. */
.z-rec { padding: 16px; display: flex; align-items: center; gap: 12px }
.z-rec .ic { width: 36px; height: 36px; border-radius: 12px; flex: none;
  background: var(--acc-14); display: grid; place-items: center; color: var(--acc) }
.z-rec .ic svg { width: 18px; height: 18px }
.z-rec .tx { flex: 1; min-width: 0 }
.z-rec .tx b { display: block; font-size: 13.5px; font-weight: 800 }
.z-rec .tx span { display: block; margin-top: 2px; font-size: 11.5px; line-height: 16px; color: var(--sub) }

/* Score averages. */
.z-avg .row { display: flex; gap: 22px }
.z-avg .row b { display: block; font-size: 24px; line-height: 28px; font-weight: 900; font-variant-numeric: tabular-nums }
.z-avg .row span { display: block; margin-top: 1px; font-size: 10px; font-weight: 800; letter-spacing: .6px; text-transform: uppercase; color: var(--mut) }
.z-avg .debt { margin-left: auto; text-align: right }
.z-avg .debt b { font-size: 18px; line-height: 28px; color: #D97A1F }
.z-avg .spark { display: flex; align-items: flex-end; gap: 5px; height: 42px; margin-top: 12px }
.z-avg .spark i { flex: 1; height: var(--h); border-radius: 3px; background: rgba(49,72,201,.28) }
.z-avg .spark i.on { background: #3148C9 }

/* Sleep schedule — one lane per night, bedtime → wake. */
/* ⚠️ COLUMNS, MATCHING app/sleep.tsx. --a and --b keep their meaning — the
   start and end of the night as a percentage of the 22:00→08:00 window — they
   are simply read down the bar now instead of across it. */
.z-sched .pband {
  position: relative; display: flex; align-items: stretch;
  gap: 6px; height: 104px; padding-left: 34px;
}
/* The time axis, down the left. Four labels spread over the same window the
   bars are measured against, so a bar's top edge can be read off it. */
.z-sched .pband .ax {
  position: absolute; left: 0; top: 0; bottom: 0; width: 30px;
  display: flex; flex-direction: column; justify-content: space-between;
  font-style: normal; font-size: 8px; font-weight: 700;
  color: var(--mut); font-variant-numeric: tabular-nums;
}
.z-sched .pband .ax b { font-weight: 700; line-height: 1; }
/* Hour rules behind the bars — the thing that makes a level run READ as
   level rather than merely look it. */
.z-sched .pband::before {
  content: ""; position: absolute; left: 34px; right: 0; top: 0; bottom: 0;
  background: repeating-linear-gradient(180deg,
    var(--line) 0 1px, transparent 1px calc(100% / 3));
  pointer-events: none;
}
/* The slot stays full width so the seven nights are evenly spaced; the BAR
   inside it is narrower, the way app/sleep.tsx sizes it (barW = slot * 0.5).
   A bar as wide as its slot reads as a stacked area chart rather than as
   seven separate nights. */
.z-sched .lane { position: relative; flex: 1; min-width: 0; background: none }
.z-sched .lane::after {
  content: ""; position: absolute; left: 18%; right: 18%; top: var(--a); bottom: calc(100% - var(--b));
  border-radius: 6px; background: linear-gradient(180deg, #3148C9, #7C4DD6);
}
/* The weekday row is a per-column label now, so each initial sits under the
   night it belongs to rather than being spread edge to edge. */
.z-sched .tm { padding-left: 34px }
.z-sched .tm i { flex: 1; text-align: center }

/* Overnight HRV. */
.z-hrv .fig { display: flex; align-items: flex-end; gap: 10px }
.z-hrv .fig b { font-size: 34px; line-height: 36px; font-weight: 900; letter-spacing: -1.2px; font-variant-numeric: tabular-nums }
.z-hrv .fig i { font-style: normal; font-size: 13px; font-weight: 800; color: var(--mut); line-height: 36px }
.z-hrv .fig svg { flex: 1; height: 34px; margin-left: 6px }
.z-hrv .hd em { color: #0E7C86 }
.z-hrv p { margin: 10px 0 0; font-size: 11.5px; line-height: 16px; color: var(--sub) }

/* ══ CYCLE — components/cycle/CycleHero.tsx ═══════════════════════════════
   The Rose Orrery has its OWN palette, decoupled from the app accent. */
.y-hero {
  --rose: #D81E68; --rose-soft: rgba(216, 30, 104, .10);
  background: var(--raised); border-radius: 22px; padding: 16px;
  display: flex; flex-direction: column; gap: 14px;
  border: 1px solid var(--line);
}
.y-top { display: flex; align-items: center; gap: 15px }
.y-ring { position: relative; width: 122px; height: 122px; flex: none; display: grid; place-items: center }
.y-ring svg { position: absolute; inset: 0; width: 122px; height: 122px }
.y-ring .rd { position: relative; display: flex; flex-direction: column; align-items: center }
.y-ring .rd .k { font-size: 9px; font-weight: 900; letter-spacing: 1px; text-transform: uppercase; color: var(--rose) }
.y-ring .rd b { font-size: 34px; font-weight: 900; letter-spacing: -1.4px; line-height: 38px }
.y-ring .rd span { font-size: 9.5px; font-weight: 800; color: var(--mut) }
.y-top .tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 7px }
.y-top .tx h3 { margin: 0; font-size: 17px; font-weight: 900; letter-spacing: -.3px; line-height: 21px; color: var(--rose) }
.y-top .tx p { font-size: 12px; line-height: 17px; font-weight: 600; color: var(--sub) }
.y-conf {
  display: inline-flex; align-items: center; gap: 5px; align-self: flex-start;
  padding: 3px 8px; border-radius: 999px; background: var(--rose-soft);
  font-size: 9.5px; font-weight: 900; letter-spacing: .6px; text-transform: uppercase; color: var(--rose);
}
.y-strip { display: flex; gap: 4px }
.y-cell {
  flex: 1; min-width: 0; padding: 7px 0 6px; border-radius: 12px;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  background: var(--surface); border: 1px solid transparent;
}
.y-cell i { font-style: normal; font-size: 9px; font-weight: 800; color: var(--mut) }
.y-cell b { font-size: 14px; font-weight: 900; line-height: 17px }
.y-cell em { width: 5px; height: 5px; border-radius: 3px; background: transparent }
.y-cell.on { border-color: var(--rose); background: var(--rose-soft) }
.y-cell.on b, .y-cell.on i { color: var(--rose) }
.y-acts { display: flex; gap: 8px }
.y-acts span {
  flex: 1; height: 42px; border-radius: 14px;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  font-size: 12.5px; font-weight: 800;
}
.y-acts .go { background: var(--rose); color: #fff }
.y-acts .ghost { background: var(--surface); border: 1px solid var(--line); color: var(--sub) }
.y-acts span svg { width: 15px; height: 15px }

/* ══ CARDIO LIVE — components/cardio/session/CardioLiveExperience.tsx ══════
   Outdoor: the map IS the canvas, full bleed, no inset frame. */
.k-live { position: absolute; inset: 0 }
/* Outdoor: the map owns the whole canvas — edge to edge, no inset frame.
   surfaceStrong sits under it so a tile that has not landed yet is a grey
   plate rather than a white hole. */
.k-map { position: absolute; inset: 0; overflow: hidden; background: rgba(0,0,0,.08) }

/* Floating chrome over the map. The app fills these with bgRaised at 94%
   (`withAlpha(theme.bgRaised, 0.94)`), which is opaque enough to read a
   glyph against a road and translucent enough to show the map moving. */
.k-glass {
  background: rgba(255,255,255,.94); border: 1px solid var(--line);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.k-chrome {
  position: absolute; top: 59px; left: 0; right: 0; height: 62px; padding: 0 16px;
  display: flex; align-items: center; justify-content: space-between; gap: 8px; z-index: 2;
}
.k-x {
  width: 46px; height: 46px; border-radius: 16px; display: grid; place-items: center; flex: none;
}
.k-x svg { width: 22px; height: 22px }
.k-status {
  min-height: 34px; padding: 0 12px; border-radius: 999px;
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 10px; font-weight: 900; letter-spacing: 1.1px; text-transform: uppercase;
}
/* statusColor = accent while recording, muted when paused, warning on
   auto-pause. Recording is the state worth drawing. */
.k-status i { width: 8px; height: 8px; border-radius: 99px; background: var(--acc); flex: none }

.k-acts { display: flex; align-items: center; gap: 6px }
.k-3d {
  height: 42px; padding: 0 12px; border-radius: 14px; display: grid; place-items: center;
  background: var(--acc); border: 1px solid var(--acc); color: #fff;
  font-size: 11.5px; font-weight: 900; letter-spacing: .6px;
}
.k-ic { width: 42px; height: 42px; border-radius: 14px; display: grid; place-items: center; flex: none }
.k-ic svg { width: 20px; height: 20px; color: rgba(0,0,0,.65) }

/* ── The console sheet ──────────────────────────────────────────────────
   OPAQUE bgRaised, not glass — only the header floats. 28pt top radii, a
   hairline top border, and the dock inset below it. */
.k-sheet {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  background: var(--raised);
  border-radius: 28px 28px 0 0; border-top: 1px solid var(--line);
  padding-bottom: 40px;
}
.k-grab {
  display: block; width: 36px; height: 4px; border-radius: 2px;
  background: rgba(0,0,0,.08); margin: 9px auto 0;
}

/* Status line — GPS / activity / heart rate. */
.k-line {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 18px 0;
}
.k-line > span { display: inline-flex; align-items: center; gap: 5px; min-width: 0 }
.k-line svg { width: 11px; height: 11px; flex: none }
.k-line .gps {
  color: #32A66A; font-size: 9.5px; font-weight: 900; letter-spacing: .8px; text-transform: uppercase;
}
.k-line .act {
  color: var(--mut); font-size: 9.5px; font-weight: 900; letter-spacing: .8px;
  text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.k-line .hr svg { width: 12px; height: 12px; color: #F05D6F }
.k-line .hr b { font-size: 11px; font-weight: 900; font-variant-numeric: tabular-nums }
.k-line .hr em { font-style: normal; font-size: 9px; font-weight: 800; color: var(--mut) }

/* Hero — the clock, with the lead metric as co-hero. */
.k-hero {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 12px;
  padding: 4px 20px 11px;
}
.k-hero .t { min-width: 0 }
.k-hero .t b {
  display: block; font-size: 52px; line-height: 58px; font-weight: 900;
  letter-spacing: -2.8px; font-variant-numeric: tabular-nums;
}
.k-hero .t span {
  display: block; margin-top: 1px; color: var(--mut);
  font-size: 8.5px; font-weight: 900; letter-spacing: 1.8px; text-transform: uppercase;
}
.k-hero .s { text-align: right; padding-bottom: 4px; flex: none }
.k-hero .s b {
  display: block; color: var(--acc); font-size: 24px; line-height: 28px;
  font-weight: 900; letter-spacing: -1px; font-variant-numeric: tabular-nums;
}
.k-hero .s b i { font-style: normal; font-size: 11px; font-weight: 800; color: var(--mut) }
.k-hero .s b i::before { content: " " }
.k-hero .s span {
  display: block; margin-top: 1px; color: var(--mut);
  font-size: 8.5px; font-weight: 900; letter-spacing: 1.4px; text-transform: uppercase;
}

/* Stat strip — hairline receipt cells, no gaps, dividers between. */
.k-strip { display: flex; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line) }
.k-strip .c { flex: 1; min-width: 0; padding: 11px 12px }
.k-strip .c + .c { border-left: 1px solid var(--line) }
.k-strip .c b {
  display: block; font-size: 17px; line-height: 22px; font-weight: 900;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.k-strip .c b i { font-style: normal; font-size: 10px; font-weight: 800; color: var(--mut) }
.k-strip .c b i::before { content: " " }
.k-strip .c span {
  display: block; margin-top: 2px; color: var(--mut);
  font-size: 8.5px; font-weight: 900; letter-spacing: 1px; text-transform: uppercase;
}
.k-strip .c em {
  display: block; margin-top: 1px; font-style: normal;
  font-size: 9px; line-height: 12px; font-weight: 800; color: var(--sub);
}

/* Controls — Pause is quiet, Finish is the accent and 1.18× as wide. */
.k-dock { display: flex; gap: 8px; padding: 12px 16px 0 }
.k-dock .b {
  min-height: 54px; border-radius: 17px;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-size: 13px; font-weight: 900;
}
.k-dock .b svg { width: 17px; height: 17px }
.k-dock .pause { flex: 1; background: var(--surface); border: 1px solid var(--line) }
.k-dock .fin { flex: 1.18; background: var(--acc); color: #fff }
.k-dock .fin svg { width: 16px; height: 16px }

/* ══ THE CARDIO RECAP — the app's share export ════════════════════════════
   A full-bleed basemap, the brand and the date across the top, what the
   session WAS in the upper third, and the three numbers on a white bar at
   the bottom. Nothing else: it has to survive being 200px wide in a feed. */
.g-recap { position: absolute; inset: 0; overflow: hidden; background: #E8E6E1 }
.g-map { position: absolute; inset: 0 }
.g-recap .lmap-route .lmap-halo { stroke: rgba(16, 20, 26, .16); stroke-width: 20 }
.g-recap .lmap-route .lmap-line { stroke: #12161C; stroke-width: 7 }
.g-recap .lmap-route .lmap-start { fill: #22C55E; stroke: #fff; stroke-width: 3 }
.g-recap .lmap-route .lmap-head { fill: #12161C; stroke: #fff; stroke-width: 4 }
.g-recap .lmap-zoom, .g-recap .lmap-credit { display: none }
.g-top {
  position: absolute; z-index: 3; left: 24px; right: 24px; top: 62px;
  display: flex; align-items: center; justify-content: space-between;
}
.g-brand {
  display: inline-flex; align-items: center; gap: 11px;
  font-size: 15px; font-weight: 900; letter-spacing: 3.4px; color: #0B1017;
}
.g-brand img { width: 30px; height: 30px; border-radius: 9px }
.g-date { font-size: 13px; font-weight: 800; color: #0B1017; letter-spacing: -.2px }
.g-title { position: absolute; z-index: 3; left: 24px; top: 126px }
.g-eye {
  display: block; font-size: 13px; font-weight: 900; letter-spacing: 3.2px;
  text-transform: uppercase; color: #1668C7;
}
.g-title h3 {
  margin: 4px 0 0; font-size: 54px; font-weight: 900; letter-spacing: -2.6px;
  line-height: 58px; color: #05080C;
}
.g-stats {
  position: absolute; z-index: 3; left: 18px; right: 18px; bottom: 82px;
  display: flex; border-radius: 22px; overflow: hidden;
  background: rgba(248, 251, 255, .95);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  box-shadow: 0 10px 28px -12px rgba(8, 16, 28, .38);
}
.g-stats .c { flex: 1; min-width: 0; padding: 16px 8px 17px 16px; border-left: 1px solid rgba(11, 16, 23, .12) }
.g-stats .c:first-child { border-left: 0 }
.g-stats .k {
  display: block; font-size: 10px; font-weight: 900; letter-spacing: 1.6px;
  text-transform: uppercase; color: #5C6673;
}
.g-stats b { display: block; margin-top: 5px; font-size: 26px; font-weight: 900; letter-spacing: -1.2px; line-height: 28px; color: #05080C }
.g-stats b i { font-style: normal; font-size: 12px; font-weight: 800; color: #5C6673; letter-spacing: 0 }
.g-foot {
  position: absolute; z-index: 3; left: 26px; bottom: 44px;
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 14px; font-weight: 700; color: #0B1017;
}
.g-foot i { width: 9px; height: 9px; border-radius: 5px; background: #1668C7 }

/* ══ FRIEND MAP — app/friends/map.tsx ═════════════════════════════════════ */
.p-map { position: absolute; inset: 0; overflow: hidden }
.p-pin { position: absolute; display: flex; flex-direction: column; align-items: center; z-index: 2; width: 48px }
.p-pin .av {
  width: 48px; height: 48px; border-radius: 24px; padding: 2.5px;
  box-shadow: 0 3px 6px rgba(0, 0, 0, .35);
}
.p-pin .av img, .p-pin .av .mono {
  width: 100%; height: 100%; border-radius: 22px; object-fit: cover; display: grid; place-items: center;
  font-size: 18px; font-weight: 800; color: #fff;
}
.p-pin .tail {
  width: 0; height: 0; margin-top: -2px;
  border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 7px solid;
}
.p-pin .when {
  margin-top: 3px; padding: 2px 6px; border-radius: 999px;
  background: var(--raised); border: 1px solid var(--line);
  font-size: 9px; line-height: 12px; font-weight: 800; color: var(--mut); white-space: nowrap;
}
/* The friend map's header — app/friends/map.tsx gives it a chevron and one
   word, and floats it over the map like the rest of that screen's chrome. */
.p-head {
  position: absolute; top: 59px; left: 0; right: 0; z-index: 3;
  height: 44px; padding: 0 12px; display: flex; align-items: center; gap: 10px;
}
.p-head .back { width: 22px; height: 22px; flex: none; padding: 4px; margin: -4px; box-sizing: content-box }
.p-head b {
  font-size: 16px; font-weight: 800; letter-spacing: -.2px;
  text-shadow: 0 1px 10px rgba(255,255,255,.75);
}
.p-ghost {
  position: absolute; top: 116px; left: 50%; transform: translateX(-50%); z-index: 3;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 14px; border-radius: 999px;
  border: 1px solid var(--acc-45);
  background: rgba(255, 255, 255, .7); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  font-size: 12px; font-weight: 800; white-space: nowrap;
}
.p-ghost svg { width: 14px; height: 14px; color: var(--acc) }
.p-sheet {
  position: absolute; left: 12px; right: 12px; bottom: 34px; z-index: 3;
  border-radius: 24px; padding: 14px; display: flex; flex-direction: column; gap: 12px;
  box-shadow: 0 18px 44px -18px rgba(0, 0, 0, .45);
}
.p-sheet .hd { display: flex; align-items: center; gap: 8px }
.p-sheet .hd b { flex: 1; font-size: 15px; font-weight: 900; letter-spacing: -.2px }
.p-sheet .hd .n { font-size: 11px; font-weight: 800; color: var(--mut) }
.p-faces { display: flex; gap: 8px }
.p-faces span {
  width: 38px; height: 38px; border-radius: 19px; flex: none;
  display: grid; place-items: center; color: #fff; font-size: 14px; font-weight: 800;
  border: 2px solid var(--raised);
}
.p-acts { display: flex; gap: 8px }
.p-acts span {
  flex: 1; padding: 13px 0; border-radius: 14px;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  font-size: 12.5px; font-weight: 800;
}
.p-acts .acc { background: var(--acc-12); border: 1px solid rgba(109, 40, 217, .34); color: var(--acc) }
.p-acts .ghost { background: var(--surface); border: 1px solid var(--line); color: var(--mut) }
.p-acts span svg { width: 15px; height: 15px }

/* ══ THE LIVE MAP — map-live.js ═══════════════════════════════════════════
   A real slippy map on the same key-less CARTO raster the app falls back to
   (lib/map-tiles.ts), upgrading to Mapbox Streets the moment a token exists.
   Drag to pan, ⌘/ctrl-scroll or the buttons to zoom, pinch on touch. */
.lmap { position: absolute; inset: 0; overflow: hidden; touch-action: none; cursor: grab; background: #E8E6E1 }
.lmap.is-drag { cursor: grabbing }
.lmap-tiles { position: absolute; inset: 0 }
/* The label service is a transparent overlay: it has to sit on the base, and
   under the route. */
.lmap-labels { pointer-events: none }
.lmap-tiles img {
  position: absolute; top: 0; left: 0; width: 256px; height: 256px;
  user-select: none; -webkit-user-drag: none;
}
.lmap-route { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none }
.lmap-halo  { fill: none; stroke: var(--acc); stroke-opacity: .2; stroke-width: 22; stroke-linecap: round; stroke-linejoin: round }
.lmap-line  { fill: none; stroke: var(--acc); stroke-width: 8; stroke-linecap: round; stroke-linejoin: round }
.lmap-start { fill: #fff; stroke: var(--acc); stroke-width: 4 }
.lmap-head  { fill: var(--acc); stroke: #fff; stroke-width: 4 }
/* The live puck — the app gets this from the OS via showUserLocation, so it
   is the system blue, not the app accent. */
.lmap-puck { fill: #1E7BF0; stroke: #fff; stroke-width: 4 }
.lmap-puck-halo { fill: rgba(30,123,240,.16); stroke: none; animation: lmap-breathe 2.6s ease-in-out infinite }
@keyframes lmap-breathe {
  0%, 100% { r: 18; opacity: .55 }
  50%      { r: 27; opacity: .22 }
}
@media (prefers-reduced-motion: reduce) { .lmap-puck-halo { animation: none } }
.lmap-pins { position: absolute; inset: 0; pointer-events: none }
.lmap-pins .p-pin { position: absolute; top: 0; left: 0; width: 48px }
.lmap-zoom {
  position: absolute; right: 12px; bottom: 12px; z-index: 4;
  display: flex; flex-direction: column; gap: 1px; border-radius: 12px; overflow: hidden;
  box-shadow: 0 4px 12px rgba(0, 0, 0, .22);
}
.lmap-zoom button {
  width: 34px; height: 34px; border: 0; cursor: pointer;
  background: rgba(255, 255, 255, .94); color: #101418;
  font-size: 19px; font-weight: 600; line-height: 1;
  display: grid; place-items: center;
}
.lmap-zoom button:hover { background: #fff }
.lmap-credit {
  position: absolute; left: 8px; bottom: 8px; z-index: 4;
  padding: 3px 7px; border-radius: 6px;
  background: rgba(255, 255, 255, .78);
  font-size: 8.5px; font-weight: 600; color: #33383F; letter-spacing: .1px;
}

/* Inside a handset the sheet owns the bottom of the screen, so the map's own
   controls move up out of its way. */
/* CardioLiveMap draws at strokeWidth 4 with a halo — thinner than the recap
   card's 7, because a live map is zoomed in and a fat line hides the street
   you are about to turn down. */
.k-live .lmap-halo { stroke-width: 13; stroke-opacity: .16 }
.k-live .lmap-line { stroke-width: 5 }
.k-live .lmap-start { r: 5 }
.k-live .lmap-zoom, .p-map .lmap-zoom { top: 124px; bottom: auto }
.k-live .lmap-credit, .p-map .lmap-credit { bottom: 6px; left: 6px; font-size: 8px }

/* ── Recovery: "Why this score?" + the signal explorer ──────────────────── */
.r-why { display: flex; align-items: center; gap: 12px; min-height: 58px; padding: 0 16px }
.r-why .ic { width: 36px; height: 36px; border-radius: 12px; background: var(--acc-10); display: grid; place-items: center; color: var(--acc); flex: none }
.r-why .ic svg { width: 17px; height: 17px }
.r-why b { flex: 1; font-size: 14px; font-weight: 800 }
.r-why .chev { width: 17px; height: 17px; color: var(--mut); flex: none }

.r-explorer { padding: 18px 0 18px; display: flex; flex-direction: column; gap: 16px }
.r-explorer .hd { padding: 0 18px; display: flex; flex-direction: column; gap: 3px }
.r-explorer .hd h4 { margin: 0; font-size: 18px; line-height: 22px; font-weight: 900; letter-spacing: -.35px }
.r-explorer .hd p { font-size: 12px; line-height: 17px; color: var(--sub) }
.r-explorer .chips { display: flex; gap: 10px; padding: 0 18px; overflow: hidden }
.r-explorer .chips > span {
  flex: 0 0 auto; min-width: 116px; padding: 11px 13px; border-radius: 16px;
  background: var(--surface); border: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 2px;
}
.r-explorer .chips > span.on { background: var(--acc-10); border-color: rgba(109, 40, 217, .45) }
.r-explorer .chips i { font-style: normal; font-size: 9px; font-weight: 800; letter-spacing: .2px; color: var(--mut) }
.r-explorer .chips b { font-size: 21px; font-weight: 900; letter-spacing: -.8px; line-height: 25px }
.r-explorer .chips b em { font-style: normal; font-size: 12px; font-weight: 800; color: var(--mut) }
.r-explorer .chips > span > span { font-size: 11px; font-weight: 700; color: var(--sub) }
.r-explorer .lead { display: flex; align-items: flex-start; gap: 8px; padding: 0 18px }
.r-explorer .lead .ic { width: 34px; height: 34px; border-radius: 11px; background: var(--acc-10); display: grid; place-items: center; color: var(--acc); flex: none }
.r-explorer .lead .ic svg { width: 16px; height: 16px }
.r-explorer .lead .tx { flex: 1; min-width: 0 }
.r-explorer .lead .tx b { display: block; font-size: 14px; line-height: 18px; font-weight: 800 }
.r-explorer .lead .tx span { font-size: 11px; line-height: 15px; color: var(--sub) }
.r-explorer .lead .goal { flex: none; padding: 5px 9px; border-radius: 999px; background: var(--surface); font-size: 10px; font-weight: 800; color: var(--sub) }
.r-explorer .chart { position: relative; height: 150px; margin: 0 18px }
.r-explorer .chart svg { width: 100%; height: 100%; display: block }
.r-explorer .chart .ax { position: absolute; right: 0; font-size: 9px; font-weight: 800; color: var(--mut) }
.r-explorer .chart .ax.hi { top: -2px }
.r-explorer .chart .ax.lo { bottom: -2px }

/* ── Strain: what the number was made of ────────────────────────────────── */
.s-row b i { font-style: normal; font-size: 11px; font-weight: 800; color: var(--mut) }
.s-drivers { display: flex; flex-direction: column; gap: 11px }
.s-drivers .d { display: flex; align-items: center; gap: 10px }
.s-drivers .k { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; font-size: 12.5px; font-weight: 700; color: var(--sub) }
.s-drivers .k i { width: 8px; height: 8px; border-radius: 4px; flex: none }
.s-drivers b { font-size: 15px; font-weight: 900; letter-spacing: -.3px }

/* ── Sleep: the hypnogram, with the axis that makes it readable ─────────── */
.z-hyp { position: relative; height: 110px; padding-left: 42px }
.z-hyp svg { width: 100%; height: 92px; display: block }
.z-hyp .lv { position: absolute; left: 0; top: 0; height: 92px; width: 38px;
  display: flex; flex-direction: column; justify-content: space-between }
.z-hyp .lv i { font-style: normal; font-size: 8px; font-weight: 800; letter-spacing: .3px;
  text-transform: uppercase; color: var(--mut); line-height: 9px }
.z-hyp .tm { display: flex; justify-content: space-between; margin-top: 5px }
.z-hyp .tm i { font-style: normal; font-size: 9px; font-weight: 700; color: var(--mut) }

/* ── Cycle: symptoms, the cycle's own numbers, and why it matters here ──── */
.y-sym { padding: 16px; display: flex; flex-direction: column; gap: 12px }
.y-sym .tags { display: flex; flex-wrap: wrap; gap: 7px }
.y-sym .tags span {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 7px 11px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 11.5px; font-weight: 700; color: var(--sub);
}
.y-sym .tags span svg { width: 12px; height: 12px }
.y-sym .tags span.on { background: rgba(216, 30, 104, .10); border-color: rgba(216, 30, 104, .35); color: #D81E68 }
.y-stats { display: flex }
.y-stats div { flex: 1; min-width: 0; padding: 14px 16px; border-left: 1px solid var(--line) }
.y-stats div:first-child { border-left: 0 }
.y-stats b { font-size: 22px; font-weight: 900; letter-spacing: -.9px; line-height: 26px }
.y-stats b span { font-size: 11px; font-weight: 800; color: var(--mut) }
.y-stats i { display: block; margin-top: 2px; font-style: normal; font-size: 9px; font-weight: 900;
  letter-spacing: .9px; text-transform: uppercase; color: var(--mut) }
.y-note { padding: 14px 16px; display: flex; align-items: flex-start; gap: 12px }
.y-note .ic { width: 34px; height: 34px; border-radius: 11px; flex: none;
  background: rgba(216, 30, 104, .10); display: grid; place-items: center; color: #D81E68 }
.y-note .ic svg { width: 16px; height: 16px }
.y-note span { flex: 1; min-width: 0; font-size: 11.5px; line-height: 16px; color: var(--sub) }
.y-note span b { display: block; font-size: 13.5px; font-weight: 800; color: var(--ink); margin-bottom: 2px }

/* ══ FLYOVER ══════════════════════════════════════════════════════════════
   The exported flyover, played back in the handset. It is CONTAINED, not
   covered: the render is 9:16 and the screen is ≈9:19.5, so `cover` crops
   the sides — and the sides are where the encoder burned the run's own stat
   bar. Letterboxing shows the file as it will be posted.
   ══════════════════════════════════════════════════════════════════════════ */
.v-fly { position: relative; height: 100%; background: #05070C; overflow: hidden }
.v-vid {
  position: absolute; left: 0; right: 0; top: 0; bottom: 96px;
  width: 100%; height: calc(100% - 96px); object-fit: contain; display: block;
}

.v-foot {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; height: 96px;
  padding: 0 18px 34px; display: flex; flex-direction: column; justify-content: flex-end; gap: 11px;
}
.v-chip {
  align-self: flex-start; padding: 5px 10px; border-radius: 999px;
  background: rgba(255,255,255,.10); border: 1px solid rgba(255,255,255,.18);
  font-size: 10px; font-weight: 800; letter-spacing: .5px; color: rgba(255,255,255,.72);
}
.v-bar { height: 3px; border-radius: 2px; background: rgba(255,255,255,.20); overflow: hidden }
.v-bar i { display: block; height: 100%; width: 38%; border-radius: 2px; background: #fff;
  animation: v-play 16.7s linear infinite }
@keyframes v-play { from { width: 3% } to { width: 100% } }
@media (prefers-reduced-motion: reduce) { .v-bar i { animation: none } }

.v-acts { display: flex; align-items: center; gap: 8px }
.v-acts .save {
  flex: 1; height: 42px; border-radius: 14px; display: inline-flex; align-items: center;
  justify-content: center; gap: 8px; background: #fff; color: #0B0E14;
  font-size: 13px; font-weight: 800;
}
.v-acts .save svg { width: 15px; height: 15px }
.v-acts .share {
  width: 42px; height: 42px; border-radius: 14px; display: grid; place-items: center; flex: none;
  background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.2); color: #fff;
}
.v-acts .share svg { width: 17px; height: 17px }

/* ── Recovery: check-in, muscle readiness, the CTA ─────────────────────────
   components/MorningCheckinCard.tsx + MuscleReadinessStrip.tsx. Both are
   14-padded, 10-gap GlassCards with a 13.5/900 title row. */
/* Fatigued hero. The green is hardcoded three times up in .r-hero because
   the replica only ever showed a good day; the tone now drives all of them
   from one custom property, and #BB6B03 is scoreColor(52) on the light stops
   rather than a warning colour chosen by eye. */
.r-hero.caution { --tone: #BB6B03; border-color: rgba(187, 107, 3, .45) }
.r-hero.caution .top { background: linear-gradient(135deg, rgba(187, 107, 3, .16), rgba(187, 107, 3, 0)) }
.r-hero.caution .mood { background: rgba(187, 107, 3, .12); border-color: rgba(187, 107, 3, .30); color: var(--tone) }
.r-hero.caution .t-morning { background: rgba(187, 107, 3, .14); border-color: rgba(187, 107, 3, .34) }

/* Why this score, expanded — components/RecoveryExplainerCard.tsx.
   Colour carries the verdict (coral against you, green for you, muted
   neutral) so no row needs a sentence explaining itself. The points column
   is tabular and right-aligned because the reader is meant to add it up. */
.r-why.open .chev { color: var(--acc) }
.r-explain { padding: 16px; display: flex; flex-direction: column }
.r-explain .hd { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; color: var(--acc) }
.r-explain .hd svg { width: 14px; height: 14px; flex: none }
.r-explain .hd span { font-size: 10px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase }
.r-explain .ax { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-top: 1px solid var(--line) }
.r-explain .ax:first-of-type { border-top: 0 }
.r-explain .ax svg { width: 15px; height: 15px; flex: none }
.r-explain .ax b { font-size: 13px; font-weight: 700; white-space: nowrap }
.r-explain .ax span { flex: 1; min-width: 0; font-size: 11px; font-weight: 600; color: var(--mut);
  font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.r-explain .ax em { font-style: normal; font-size: 12px; font-weight: 900; letter-spacing: -.2px;
  font-variant-numeric: tabular-nums; min-width: 34px; text-align: right; flex: none }
.r-explain .ax.neg svg, .r-explain .ax.neg em { color: var(--coral) }
.r-explain .ax.pos svg, .r-explain .ax.pos em { color: #34D399 }
/* Base and total exist so the arithmetic is checkable. Without both ends the
   card is a column of signed numbers asking to be taken on faith. */
.r-explain .sum { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 4px }
.r-explain .s { display: flex; align-items: center; gap: 8px }
.r-explain .s span { flex: 1; font-size: 11px; font-weight: 700; color: var(--mut) }
.r-explain .s em { font-style: normal; font-size: 12px; font-weight: 800; color: var(--mut);
  font-variant-numeric: tabular-nums; min-width: 34px; text-align: right }
.r-explain .s.tot span { font-size: 12px; font-weight: 900; color: var(--ink) }
.r-explain .s.tot em { font-size: 13px; font-weight: 900; color: var(--ink) }
.r-method { display: flex; gap: 8px; padding: 0 6px; color: var(--mut) }
.r-method svg { width: 15px; height: 15px; flex: none; margin-top: 1px }
.r-method span { flex: 1; font-size: 11.5px; line-height: 17px; font-weight: 500 }

.r-checkin, .r-muscle { padding: 14px; display: flex; flex-direction: column; gap: 10px }
.r-checkin .hd, .r-muscle .hd { display: flex; align-items: center; gap: 8px }
.r-checkin .hd b, .r-muscle .hd b { font-size: 13.5px; font-weight: 900 }
.r-checkin .hd svg { width: 16px; height: 16px; color: var(--mut) }
.r-checkin .hd .ok { color: var(--acc) }      /* every axis answered */
.r-muscle .hd svg { width: 15px; height: 15px; color: var(--mut) }

.r-checkin .ax { display: flex; align-items: center; gap: 10px }
.r-checkin .ax > svg { width: 18px; height: 15px; color: var(--mut); flex: none }
.r-checkin .ax > span { width: 86px; font-size: 12px; font-weight: 700 }
.r-checkin .dots { display: flex; gap: 6px; flex: 1; justify-content: flex-end }
.r-checkin .dots i {
  width: 22px; height: 22px; border-radius: 11px; display: grid; place-items: center;
  background: var(--surface); border: 1px solid var(--line);
}
.r-checkin .dots i::after {
  content: ""; width: 8px; height: 8px; border-radius: 4px; background: var(--line);
}
/* Energy/mood fill toward the accent (more = better); soreness and stress
   toward coral (more = worse). */
.r-checkin .dots i.on { background: rgba(109,40,217,.18); border-color: rgba(109,40,217,.55) }
.r-checkin .dots i.on::after { background: var(--acc) }
.r-checkin .dots.bad i.on { background: rgba(255,59,48,.18); border-color: rgba(255,59,48,.55) }
.r-checkin .dots.bad i.on::after { background: #FF3B30 }

/* The strip scrolls horizontally in the app; here it runs off the card edge
   the same way, with the untrained groups last. */
.r-muscle .strip { display: flex; gap: 8px; overflow-x: auto; margin: 0 -14px; padding: 0 14px }
.r-muscle .strip::-webkit-scrollbar { display: none }
.r-muscle .strip > span {
  flex: none; min-width: 74px; padding: 7px 10px; border-radius: 10px;
  display: flex; flex-direction: column; gap: 2px;
}
.r-muscle .strip b { font-size: 11.5px; font-weight: 900; text-transform: capitalize }
.r-muscle .strip > span > span { font-size: 10px; font-weight: 700 }
.r-muscle .fresh { background: rgba(109,40,217,.12); border: 1px solid rgba(109,40,217,.4) }
.r-muscle .fresh > span { color: var(--acc) }
.r-muscle .rep { background: rgba(200,142,58,.12); border: 1px solid rgba(200,142,58,.4) }
.r-muscle .rep > span { color: #C88E3A }
.r-muscle .rec { background: rgba(255,59,48,.12); border: 1px solid rgba(255,59,48,.4) }
.r-muscle .rec > span { color: #FF3B30 }
.r-muscle .due { background: rgba(0,0,0,.06); border: 1px solid rgba(0,0,0,.16) }
.r-muscle .due > span { color: var(--mut) }

.r-cta { padding: 14px; display: flex; align-items: center; gap: 12px }
.r-cta .ic {
  width: 38px; height: 38px; border-radius: 12px; flex: none;
  background: var(--surface); display: grid; place-items: center;
}
.r-cta .ic svg { width: 17px; height: 17px }
.r-cta .tx { flex: 1; min-width: 0 }
.r-cta .tx b { display: block; font-size: 14px; font-weight: 900; line-height: 18px }
.r-cta .tx span {
  display: block; margin-top: 2px; font-size: 11px; line-height: 14px; color: var(--sub);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.r-cta .chev { width: 16px; height: 16px; color: var(--mut); flex: none }

/* HealthNote — the estimate disclaimer under every derived score. */
.ap-note {
  display: flex; align-items: flex-start; gap: 8px; margin: 2px 6px 0;
  font-size: 11.5px; line-height: 17px; color: var(--sub);
}
.ap-note svg { width: 15px; height: 15px; color: var(--mut); flex: none; margin-top: 1px }

/* ── Cycle: the month grid + the phase guide ───────────────────────────────
   components/cycle/CycleMonthCard.tsx. Square cells (aspect-ratio 1) with a
   2px gutter, a filled day for what happened and a dashed outline for what
   is predicted. */
.y-month { padding: 14px; border-radius: 22px }
.y-month .hd { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px }
.y-month .hd b { font-size: 14.5px; font-weight: 800 }
.y-month .pnav {
  width: 30px; height: 30px; padding: 8px; border-radius: 15px; flex: none;
  background: var(--surface); color: var(--sub); box-sizing: border-box;
}
.y-month .dow { display: flex; margin-bottom: 4px }
.y-month .dow i {
  flex: 1; text-align: center; font-style: normal;
  font-size: 9px; font-weight: 800; letter-spacing: .5px; color: var(--mut);
}
.y-month .wks { display: flex; flex-direction: column }
.y-month .wk { display: flex }
.y-month .wk i {
  flex: 1; aspect-ratio: 1; margin: 2px; border-radius: 8px;
  display: grid; place-items: center; font-style: normal;
  font-size: 12.5px; font-weight: 600; line-height: 16px; font-variant-numeric: tabular-nums;
  border: 0 solid transparent;
}
.y-month .wk i.fill { font-weight: 700 }
.y-month .wk i.pred { border-width: 1px; border-style: dashed }
.y-month .wk i.today { border-width: 1.25px; border-style: solid; border-color: rgba(0,0,0,.55); font-weight: 800 }
.y-month .key { display: flex; flex-wrap: wrap; gap: 6px 12px; margin-top: 12px }
.y-month .key span { display: inline-flex; align-items: center; gap: 6px; font-size: 10.5px; font-weight: 700; color: var(--sub) }
.y-month .key i { width: 8px; height: 8px; border-radius: 3px }

.y-guide { padding: 14px; display: flex; align-items: center; gap: 12px }
.y-guide .ic {
  width: 36px; height: 36px; border-radius: 12px; flex: none; display: grid; place-items: center;
  background: rgba(200,138,26,.14); color: #C88A1A;
}
.y-guide .ic svg { width: 17px; height: 17px }
.y-guide .tx { flex: 1; min-width: 0 }
.y-guide .tx b { display: block; font-size: 13.5px; font-weight: 800 }
.y-guide .tx span { display: block; margin-top: 2px; font-size: 11.5px; line-height: 16px; color: var(--sub) }
.y-guide .chev { width: 16px; height: 16px; color: var(--mut); flex: none }

/* ══ THE BODY TWIN — app/body-scan.tsx ════════════════════════════════════
   The stage is a dark well so the scan's own lighting has something to sit
   against; body-twin.js drops a canvas in and starts turning it. */
.bt-stage { padding: 0; overflow: hidden }
.bt-view {
  --bt-rim: #6D28D9;
  position: relative; height: 400px; touch-action: none; cursor: grab;
  background:
    radial-gradient(120% 80% at 50% 12%, rgba(109,40,217,.16), transparent 62%),
    linear-gradient(180deg, #1B1830 0%, #131024 58%, #0D0B18 100%);
}
.bt-view:active { cursor: grabbing }
.bt-view .bt-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block }
/* A floor, so the figure is standing rather than floating. */
.bt-view::after {
  content: ""; position: absolute; left: 22%; right: 22%; bottom: 26px; height: 22px;
  border-radius: 50%; background: radial-gradient(ellipse at center, rgba(0,0,0,.55), transparent 72%);
  pointer-events: none;
}
.bt-hint {
  position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%); z-index: 2;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: 999px;
  background: rgba(255,255,255,.10); border: 1px solid rgba(255,255,255,.18);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  font-size: 11px; font-weight: 700; color: rgba(255,255,255,.82); white-space: nowrap;
  transition: opacity .4s ease;
}
.bt-hint svg { width: 12px; height: 12px }
/* The invitation retires once the model is actually turning under a finger. */
.bt-view:active .bt-hint { opacity: 0 }

.bt-meta { display: flex; gap: 8px; padding: 12px 14px }
.bt-meta .chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 11px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 11px; font-weight: 700; color: var(--sub);
}
.bt-meta .chip svg { width: 12px; height: 12px }

.bt-set { padding: 14px }
.bt-rows { display: flex; flex-direction: column; margin-top: 10px }
.bt-rows > div {
  display: flex; align-items: baseline; gap: 10px;
  padding: 10px 0; border-top: 1px solid var(--line);
}
.bt-rows > div:first-child { border-top: 0; padding-top: 2px }
.bt-rows span { flex: 1; font-size: 13px; font-weight: 700 }
.bt-rows b { font-size: 15px; font-weight: 900; font-variant-numeric: tabular-nums }
.bt-rows b i { font-style: normal; font-size: 10.5px; font-weight: 800; color: var(--mut); margin-left: 2px }
.bt-rows em {
  width: 42px; text-align: right; font-style: normal;
  font-size: 11.5px; font-weight: 800; color: var(--mut); font-variant-numeric: tabular-nums;
}
/* Down is good on a waist and bad on an arm, so neither direction is tinted
   green or red — the app does not editorialise a circumference either. */
.bt-rows em.up, .bt-rows em.dn { color: var(--sub) }
