/* ===========================================================
   ELITE TRACKER — "The Coach's Ledger"
   Dark navy ledger surface, brass gold earned sparingly,
   weathered clay for attention. See DESIGN.md for the spec.
   =========================================================== */
:root{
  --ink:#0b1426;
  --page-bg:var(--ink);
  --surface-1:#111d34;
  --surface-2:#17233f;
  --hairline:#26324c;
  --hairline-soft:#1c2946;

  --bone:#efe9db;
  --bone-muted:#a7afc2;
  --bone-faint:#8996b0;

  --gold:#b8934c;
  --gold-rgb:184,147,76;
  --gold-dim:#8f7038;
  --gold-tint:rgba(184,147,76,.14);
  --gold-ink:var(--gold);

  --clay:#cc7d61;
  --clay-dim:#8a4a37;
  --clay-tint:rgba(195,114,86,.16);
  --clay-ink:var(--clay);

  /* ---------- Fibonacci spacing scale ----------
     Every gap, pad and margin in the app resolves to one of these.
     Before this there were 24 distinct spacing values in the stylesheet
     (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,20,22,24,26,34,38,44px),
     most of them one-off guesses a few pixels from a neighbour — which
     is why the rhythm read as arbitrary and why cards in a grid ended
     up closer together than the padding inside them.

     Fibonacci works here because the ratio between consecutive steps
     approaches the golden ratio, so each step is visibly distinct from
     the last without the gaps between big values becoming huge. Two
     spacings either look the same or they look deliberate; there is no
     "is that 14 or 16px?" middle ground left.

     s-1  2px   hairline nudges, icon optical alignment
     s-2  3px   tight inline gaps
     s-3  5px   inside a control
     s-4  8px   label to field, icon to text
     s-5  13px  between rows, between controls
     s-6  21px  card padding, card to card
     s-7  34px  section breaks
     s-8  55px  page-level separation
     -------------------------------------------------- */
  --s-1:2px;
  --s-2:3px;
  --s-3:5px;
  --s-4:8px;
  --s-5:13px;
  --s-6:21px;
  --s-7:34px;
  --s-8:55px;

  --radius-sm:10px;
  --radius-lg:18px;
  --radius-pill:999px;

  --shadow-resting:0 1px 2px rgba(4,7,14,.4);
  --shadow-floating:0 2px 4px rgba(4,7,14,.35), 0 16px 32px -8px rgba(4,7,14,.6);

  --glass-blur:blur(20px) saturate(1.6);
  --glass-blur-sm:blur(14px) saturate(1.5);
  --glass-1:rgba(17,29,52,.55);
  --glass-2:rgba(23,35,63,.6);
  --glass-chrome:rgba(11,20,38,.72);
  --glass-sheet:rgba(15,25,45,.82);
  --glass-sheen:inset 0 1px 0 rgba(255,255,255,.07);

  --page-wash:
    radial-gradient(120% 70% at 12% -10%, rgba(184,147,76,.12), transparent 55%),
    radial-gradient(100% 70% at 100% 0%, rgba(204,125,97,.10), transparent 50%);

  --display:'Fraunces', Georgia, serif;
  --headline:'Fraunces', Georgia, serif;
  --sans:'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono:'IBM Plex Mono', ui-monospace, 'SFMono-Regular', monospace;

  /* legacy token aliases — old traffic-light names now resolve through
     the three-color system (gold = positive, clay = attention) */
  --serif:var(--display);
  --navy:var(--ink);
  --green:var(--gold-ink);
  --red:var(--clay-ink);
  --amber:var(--clay-ink);
  --muted:var(--bone-faint);
  --muted-2:var(--bone-faint);

  /* Genuine traffic-light tones, distinct from --green/--amber/--red
     above (which are deliberately just gold/clay aliases everywhere
     else in the app). Scoped to the funnel/pace dashboard only, where
     an at-a-glance red/orange/green read is the whole point. */
  --pace-green:#5fae7c;
  --pace-amber:#dc9a45;
  --pace-red:var(--clay-ink);

  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
}

/* ---------- Light theme — same three-color identity, inverted ledger ---------- */
[data-theme="light"]{
  --page-bg:#f1f2f6;
  --surface-1:#ffffff;
  --surface-2:#e7e9f0;
  --hairline:#d7dae2;
  --hairline-soft:#e5e7ee;

  --bone:#182238;
  --bone-muted:#4c5568;
  --bone-faint:#5c6478;

  /* --gold/--clay are FILL colors (buttons, pills, bars) — tuned so ink
     text on top stays >=4.5:1. --gold-ink/--clay-ink are for gold/clay
     rendered AS text or icon color directly on a surface — tuned darker
     since the light page has far less headroom than the dark one. */
  --gold:#a67b2c;
  --gold-rgb:166,123,44;
  --gold-dim:#7a5a1f;
  --gold-tint:rgba(166,123,44,.12);
  --gold-ink:#7a5a1d;

  --clay:#c06f4a;
  --clay-dim:#8a4a2e;
  --clay-tint:rgba(192,111,74,.12);
  --clay-ink:#a24a2e;

  --pace-green:#3f8f5e;
  --pace-amber:#b97a2a;
  --pace-red:var(--clay-ink);

  --shadow-resting:0 1px 2px rgba(20,25,40,.06);
  --shadow-floating:0 2px 6px rgba(20,25,40,.08), 0 16px 32px -8px rgba(20,25,40,.16);

  --glass-1:rgba(255,255,255,.55);
  --glass-2:rgba(231,233,240,.6);
  --glass-chrome:rgba(241,242,246,.72);
  --glass-sheet:rgba(255,255,255,.82);
  --glass-sheen:inset 0 1px 0 rgba(255,255,255,.7);

  --page-wash:
    radial-gradient(120% 70% at 12% -10%, rgba(166,123,44,.10), transparent 55%),
    radial-gradient(100% 70% at 100% 0%, rgba(192,111,74,.09), transparent 50%);
}

/* No backdrop-filter support: raise glass opacity so panels stay legible flat */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))){
  :root{
    --glass-1:rgba(17,29,52,.94);
    --glass-2:rgba(23,35,63,.94);
    --glass-chrome:rgba(11,20,38,.97);
    --glass-sheet:rgba(15,25,45,.98);
  }
  [data-theme="light"]{
    --glass-1:rgba(255,255,255,.95);
    --glass-2:rgba(231,233,240,.96);
    --glass-chrome:rgba(241,242,246,.97);
    --glass-sheet:rgba(255,255,255,.98);
  }
}

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;padding:0;overscroll-behavior:none}
body{
  font-family:var(--sans);
  font-size:14.5px;
  color:var(--bone);
  background:var(--page-wash), var(--page-bg);
  background-attachment:fixed;
  -webkit-font-smoothing:antialiased;
}
button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit;touch-action:manipulation}
input,select,textarea{font-family:inherit;font-size:16px}
a{color:inherit}
svg{display:block}
svg.flip{transform:scaleX(-1)}

/* ---------- App shell ---------- */
#app{max-width:520px;margin:0 auto;min-height:100vh;position:relative;background:transparent}

/* ---------- Vertical rhythm ----------
   One gap between every stacked block on a screen, whatever the block
   is — a card, a grid of cards, a row of buttons, a lone button.

   This used to live on `.card{margin-top}`, which only spaced cards
   against each other. Anything else between two cards (a .grid2, a
   .btn-row, a standalone button) contributed nothing, so the rhythm
   collapsed wherever the page wasn't a plain run of cards — and each
   time that looked wrong somebody zeroed the card's margin inline or
   gave the other block a one-off margin, which is how the dashboard
   ended up with cards touching.

   The owl selector puts the gap between siblings instead of on them,
   so it cannot be forgotten by a new block type and there is nothing
   to zero out on the first child. `.stack` opts a nested wrapper in —
   the student screen's tab body and the forecast body both render a
   run of cards inside a container rather than directly on the screen. */
.screen > * + *,
.stack > * + *{margin-top:var(--s-6)}
/* Bottom padding clears the nav rather than guessing at it: the bar
   is at most 71px of content and carries the home indicator in its
   own padding, so 89px plus the same inset leaves a comfortable gap
   without the dead scroll the old flat 128px left behind. */
.screen{display:none;padding:calc(var(--safe-top) + var(--s-3)) var(--s-6) calc(89px + var(--safe-bottom))}
.screen.active{display:block;animation:fade .25s ease}
.screen.active.no-anim{animation:none}
@keyframes fade{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* ---------- Top bar (frosted glass — content scrolls beneath it) ---------- */
.topbar{
  position:sticky;top:0;z-index:40;
  display:flex;align-items:center;justify-content:space-between;
  padding:calc(var(--safe-top) + var(--s-6)) var(--s-6) var(--s-5);
  background:var(--glass-chrome);
  -webkit-backdrop-filter:var(--glass-blur-sm);
  backdrop-filter:var(--glass-blur-sm);
  border-bottom:1px solid var(--hairline-soft);
}
.topbar h1{font-family:var(--headline);font-weight:480;font-size:21px;margin:0;letter-spacing:-.005em;color:var(--bone)}
.icon-btn{width:36px;height:36px;border-radius:var(--radius-sm);background:var(--surface-2);color:var(--bone-muted);display:flex;align-items:center;justify-content:center;flex:0 0 auto}
.sync-badge{position:absolute;top:5px;right:5px;width:8px;height:8px;border-radius:50%;background:var(--clay);border:1.5px solid var(--surface-2)}
.icon-btn:active{background:var(--hairline)}

/* ---------- Hero (daily greeting — flows into the page, no card chrome) ---------- */
.hero{padding:var(--s-6) var(--s-2) var(--s-3) 0;position:relative}
.hero h2{font-family:var(--display);font-weight:340;font-size:clamp(1.6rem,7vw,2.1rem);line-height:1.05;letter-spacing:-.01em;margin:0 0 var(--s-4);color:var(--bone)}
.hero .meta{font-size:12.5px;color:var(--bone-faint);display:flex;gap:var(--s-4);flex-wrap:wrap;align-items:center}
.hero .meta .streak{color:var(--gold-ink);font-weight:600}
.hero-stats{display:flex;gap:var(--s-6);margin-top:var(--s-6);align-items:center}
.hero-stat .k{font-family:var(--sans);font-size:11px;color:var(--bone-faint);font-weight:600}
.hero-stat .v{font-family:var(--mono);font-size:24px;font-weight:500;margin-top:var(--s-2);color:var(--bone)}
.hero-stat .v.gold{color:var(--gold-ink)}
.ring{margin-left:auto;margin-right:calc(-1 * var(--s-3))}

/* ---------- Cards (frosted glass) ---------- */
.card{
  background:var(--glass-1);
  -webkit-backdrop-filter:var(--glass-blur);
  backdrop-filter:var(--glass-blur);
  border:1px solid var(--hairline-soft);
  border-radius:var(--radius-lg);
  padding:var(--s-6) var(--s-6) var(--s-6);
  box-shadow:var(--glass-sheen), var(--shadow-resting);
}
.card.dark{background:var(--glass-2);border-color:var(--hairline)}
.card h3{font-family:var(--headline);font-size:17px;font-weight:480;margin:0 0 var(--s-5);display:flex;align-items:center;justify-content:space-between;color:var(--bone)}
.card h3 .pill{font-family:var(--mono);font-size:11px;color:var(--bone-faint);font-weight:500}
/* Count badge for outstanding items (unheard voice notes) — the one
   place a pill is a live number rather than a quiet caption. */
.card h3 .pill.gold{background:var(--gold);color:var(--ink);padding:var(--s-1) var(--s-4);border-radius:var(--radius-pill);font-weight:600}
.section-title{font-family:var(--sans);font-size:12.5px;color:var(--bone-muted);margin:var(--s-1) 0 var(--s-5);font-weight:600}
.subtle{color:var(--bone-faint);font-size:13px;line-height:1.5}
.hr{height:1px;background:var(--hairline);margin:var(--s-6) 0}

/* ---------- Focus / to-do ---------- */
.focus-item{display:flex;align-items:center;gap:var(--s-5);padding:var(--s-5) 0;border-bottom:1px solid var(--hairline-soft)}
.focus-item:last-child{border-bottom:none}
.check{width:22px;height:22px;border-radius:var(--radius-pill);border:1.5px solid var(--gold-dim);flex:0 0 auto;display:flex;align-items:center;justify-content:center;color:var(--ink);transition:.15s}
.check.done{background:var(--gold);border-color:var(--gold)}
.check svg{width:12px;height:12px}
.focus-item .txt{flex:1;font-size:14.5px;color:var(--bone)}
.focus-item.done .txt{color:var(--bone-faint);text-decoration:line-through}
.focus-item .time{font-family:var(--mono);font-size:12px;color:var(--bone-faint)}

/* ---------- Number logging ---------- */
.num-row{display:flex;align-items:center;gap:var(--s-5);padding:var(--s-5) 0;border-bottom:1px solid var(--hairline-soft)}
.num-row:last-child{border-bottom:none}
.num-row .label{flex:1}
.num-row .label .l{font-size:14px;font-weight:600;color:var(--bone)}
.num-row .track{height:4px;background:var(--surface-2);border-radius:2px;margin-top:var(--s-4);overflow:hidden;max-width:150px}
.num-row .track .fill{height:100%;background:var(--gold);border-radius:2px;transition:width .3s}
.num-row .track .fill.over{background:var(--gold)}
.stepper{display:flex;align-items:center;gap:var(--s-4)}
.stepper button{width:30px;height:30px;border-radius:var(--radius-sm);background:var(--surface-2);color:var(--bone);display:flex;align-items:center;justify-content:center;border:1px solid var(--hairline)}
.stepper button svg{width:14px;height:14px}
.stepper button.minus{color:var(--bone-muted)}
.stepper .val{min-width:50px;text-align:center;font-family:var(--mono);font-size:14px;font-weight:500;color:var(--bone)}
.stepper .val .t{color:var(--bone-faint);font-weight:400;font-size:12px}
/* In the annual-progress rows the percentage is the headline and the
   raw figures sit under it, rather than trailing on the same line. */
/* Value and target read as one figure — "0 / 20" on a single line.
   nowrap matters: the mono digits plus the target were wrapping inside
   the stepper's fixed width, which stacked them into two rows. */
.stepper .val{white-space:nowrap}
.stepper .val .t{margin-left:var(--s-2)}

/* .stacked went with the annual-progress card, which was the only
   thing that opted into it. Keeping the note because the bug is easy
   to reintroduce: this was once written as `.t:only-child`, which also
   caught every "0 / 20" number row — the target span IS the only
   element child there, since the count itself is a bare text node — and
   split every row on the tracker into two lines. */

/* Log today's numbers — bigger, rounder +/- targets than the compact
   stepper used elsewhere (outcome sheet, Laser Focus item rows), where
   the small size still suits a tighter modal/list layout. */
.num-row .stepper{gap:var(--s-5)}
.num-row .stepper button{width:40px;height:40px;border-radius:var(--radius-pill)}
.num-row .stepper .val{min-width:72px;font-size:15px}

/* ---------- Coach message ---------- */
.coach-msg{display:flex;gap:var(--s-5)}
.avatar{width:34px;height:34px;border-radius:var(--radius-pill);background:var(--gold);color:var(--ink);font-weight:700;display:flex;align-items:center;justify-content:center;font-size:13px;flex:0 0 auto}
.avatar.lg{width:44px;height:44px;font-size:15px}
.coach-msg .who{font-size:13px;font-weight:600;color:var(--bone)}
.coach-msg .when{font-family:var(--mono);font-size:11px;color:var(--bone-faint)}
.coach-msg .quote{font-family:var(--headline);font-style:italic;font-weight:400;font-size:15px;color:var(--bone);margin-top:var(--s-4);line-height:1.45}

/* ---------- Buttons ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--s-4);background:var(--surface-2);color:var(--bone);border:1px solid var(--hairline);border-radius:var(--radius-pill);padding:var(--s-5) var(--s-6);font-weight:600;font-size:14px;width:100%}
.btn svg{width:16px;height:16px;flex:0 0 auto}
.btn.gold{background:var(--gold);color:var(--ink);border-color:var(--gold)}
.btn.gold:active{background:var(--gold-dim)}
.btn.ghost{background:transparent;color:var(--bone-muted);border:none;border-radius:var(--radius-lg)}
.btn.outline{background:transparent;border:1.5px solid var(--hairline);color:var(--bone);border-radius:var(--radius-lg)}
.btn.sm{padding:var(--s-4) var(--s-5);font-size:13px;width:auto}
.btn.danger{background:var(--clay-tint);color:var(--clay-ink);border-color:transparent;border-radius:var(--radius-lg)}
.btn:active{transform:translateY(1px)}
.btn:focus-visible{outline:1.5px solid var(--bone);outline-offset:2px}
.btn-row{display:flex;gap:var(--s-5)}
.btn-row .btn{flex:1}

/* Google's own brand guidelines call for a fixed white/neutral button,
   not a themed one — it must stay recognizable regardless of app theme. */
.btn-google{display:flex;align-items:center;justify-content:center;gap:var(--s-5);width:100%;background:#fff;color:#1f1f1f;border:1px solid #d6d6d6;border-radius:var(--radius-pill);padding:var(--s-5) var(--s-6);font-weight:600;font-size:14px;font-family:var(--sans)}
.btn-google:active{background:#f3f3f3}
.btn-google:focus-visible{outline:1.5px solid var(--gold);outline-offset:2px}

.divider{display:flex;align-items:center;gap:var(--s-5);margin:var(--s-6) 0;color:var(--bone-faint);font-size:12px}
.divider::before,.divider::after{content:'';flex:1;height:1px;background:var(--hairline)}

/* ---------- Bars chart ---------- */
.bars{display:flex;align-items:flex-end;gap:var(--s-5);height:120px;margin-top:var(--s-5)}
.bars .bar{flex:1;display:flex;flex-direction:column;align-items:center;height:100%}
.bars .bar .track{flex:1;min-height:0;width:100%;display:flex;flex-direction:column;align-items:center;justify-content:flex-end}
.bars .bar .col{width:100%;max-width:28px;background:var(--gold);border-radius:2px 2px 0 0;transition:height .4s;position:relative}
.bars .bar .col.under{background:var(--clay)}
.bars .bar .col.over{background:var(--gold)}
.bars .bar .n{font-family:var(--mono);font-size:11px;color:var(--bone-faint);margin-bottom:var(--s-3)}
.bars .bar .lbl{flex:0 0 auto;font-size:10.5px;line-height:1.25;color:var(--bone-faint);margin-top:var(--s-4);height:calc(10.5px * 1.25 * 2);overflow:hidden}

/* ---------- Sales funnel — a continuous tapering silhouette (shape
   column, clip-path trapezoids sharing edges between stages) paired
   with a legend column, traffic-light colored by pace ---------- */
.funnel2{display:flex;gap:var(--s-6);margin-top:var(--s-5)}
.funnel2-shape{flex:0 0 34%;display:flex;flex-direction:column}
.funnel2-seg{height:44px;transition:clip-path .4s,background .3s}
.funnel2-legend{flex:1;min-width:0;display:flex;flex-direction:column}
.funnel2-row{height:44px;display:flex;align-items:center;gap:var(--s-4);border-bottom:1px solid var(--hairline-soft)}
.funnel2-row:last-child{border-bottom:none}
.funnel2-dot{width:8px;height:8px;border-radius:50%;flex:0 0 auto}
.funnel2-label{font-weight:500;color:var(--bone-muted);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px}
.funnel2-count{font-family:var(--mono);font-size:13px;color:var(--bone-faint)}
.funnel2-pace{font-family:var(--mono);font-weight:600;font-size:12px;min-width:36px;text-align:right}
/* Revenue sits under the funnel, not in it. It is what the five stages
   produce rather than a stage of its own, and as a segment it would
   wreck the shape — a dollar figure against counts makes every other
   band collapse to the 10% floor. So: same row layout, below a rule,
   reading as the outcome the taper arrives at. Mirrors where REVENUE /
   $$$ sits on Harry's own sheet. */
.funnel2-outcome{margin-top:var(--s-4);padding-top:var(--s-4);border-top:1px solid var(--hairline)}
.funnel2-outcome .funnel2-row{border-bottom:none}
.funnel2-outcome .funnel2-label{color:var(--bone);font-weight:600}
.funnel2-outcome .funnel2-count{color:var(--bone);font-weight:600}

/* ---------- Pipeline / list rows ---------- */
.lrow{display:flex;align-items:center;gap:var(--s-5);padding:var(--s-5) 0;border-bottom:1px solid var(--hairline-soft)}
.lrow:last-child{border-bottom:none}
.lrow .mono{width:36px;height:36px;border-radius:var(--radius-sm);background:var(--surface-2);color:var(--bone-muted);font-family:var(--mono);font-size:11px;display:flex;align-items:center;justify-content:center;flex:0 0 auto}
.lrow .main{flex:1;min-width:0}
.lrow .main .t{font-size:14px;font-weight:600;color:var(--bone);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.lrow .main .s{font-size:12px;color:var(--bone-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.lrow .right{text-align:right;flex:0 0 auto}
/* The Students tab card. Avatar, sparkline and status tag are all fixed
   width, so laid out in one row on a phone they left the name about 54px
   and it wrapped mid-word. The sparkline sits over the tag instead, the
   way .lrow's .right column stacks the tag over the pace figure. */
.student-card{display:flex;align-items:center;gap:var(--s-5)}
.student-card-b{flex:1;min-width:0}
.student-card-b .t{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.student-card-b .s{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.student-card-r{flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;gap:var(--s-3)}
.tag{display:inline-block;font-size:10.5px;font-weight:600;padding:var(--s-2) var(--s-5);border-radius:var(--radius-pill);background:var(--surface-2);color:var(--bone-muted);white-space:nowrap}
.tag.green{background:var(--gold-tint);color:var(--gold-ink)}
.tag.gold{background:var(--gold-tint);color:var(--gold-ink)}
.tag.red{background:var(--clay-tint);color:var(--clay-ink)}
.tag.amber{background:var(--clay-tint);color:var(--clay-ink)}
.tag.navy{background:var(--ink);color:var(--bone);border:1px solid var(--hairline)}


/* ---------- Stat trio ---------- */
.stat3{display:flex;gap:var(--s-5)}
.stat3 .s{flex:1;background:var(--glass-1);-webkit-backdrop-filter:var(--glass-blur-sm);backdrop-filter:var(--glass-blur-sm);border:1px solid var(--hairline-soft);border-radius:var(--radius-lg);padding:var(--s-5) var(--s-5);text-align:center;box-shadow:var(--glass-sheen)}
.stat3 .s .v{font-family:var(--mono);font-size:19px;font-weight:500;color:var(--bone)}
.stat3 .s .k{font-size:10px;color:var(--bone-faint);margin-top:var(--s-2)}
.stat3 .s.red .v{color:var(--clay-ink)}
.stat3 .s.gold .v{color:var(--gold-ink)}

/* ---------- Tabs ---------- */
/* A segmented control, so it spans its container the way the search
   input above it and the sort select below it do. As an inline-flex
   strip it shrink-wrapped to its labels and stopped short of the right
   edge, which read as a broken row rather than a deliberate one.
   Buttons share the line proportionally rather than at equal widths,
   so "All" doesn't get the same slab as "On track". Wrapping stays:
   five long period labels won't fit one phone line, and each wrapped
   line fills in turn. */
.tabs{display:flex;flex-wrap:wrap;background:var(--surface-2);border-radius:var(--radius-pill);padding:var(--s-2);margin-bottom:var(--s-3)}
.tabs button{flex:1 1 auto;min-width:0;font-size:12.5px;font-weight:600;padding:var(--s-4) var(--s-5);border-radius:var(--radius-pill);color:var(--bone-faint)}
.tabs button.on{background:var(--gold);color:var(--ink)}

/* Loose chips — shortcuts that fill a field in, not a selection state
   (the milestone due-date presets). They borrowed .tabs for its pill
   look, but they are the one case that must not stretch: a trailing
   chip widened across its own row would read as the selected one, and
   none of them is ever selected. So they size to their labels and sit
   as separate pills rather than inside a shared track. */
.chips{display:flex;flex-wrap:wrap;gap:var(--s-3)}
.chips button{
  font-size:12.5px;font-weight:600;padding:var(--s-4) var(--s-5);
  border-radius:var(--radius-pill);background:var(--surface-2);color:var(--bone-faint);
}
.chips button:active{background:rgba(var(--gold-rgb),.18);color:var(--gold-ink)}

/* ---------- Bottom nav ---------- */
/* Trimmed down: 13px of padding above and below a 47px stack came to
   well over 100px of permanent chrome once a phone's home indicator was
   added underneath, for a bar carrying three words. Padding is a step
   down the scale and the icon pill is shorter, but the button holds an
   explicit 44px so the tap target does not shrink along with the bar. */
.bottomnav{
  position:fixed;left:50%;transform:translateX(-50%);bottom:0;width:100%;max-width:520px;z-index:50;
  display:flex;justify-content:space-around;
  background:var(--glass-chrome);
  -webkit-backdrop-filter:var(--glass-blur-sm);
  backdrop-filter:var(--glass-blur-sm);
  padding:var(--s-4) var(--s-3) calc(var(--s-4) + var(--safe-bottom));border-top:1px solid var(--hairline-soft);
}
.bottomnav button{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--s-2);min-height:44px;color:var(--bone-faint);font-size:10px;font-weight:600;padding:0 var(--s-3);flex:1}
.bottomnav button .ic{position:relative;width:34px;height:21px;display:flex;align-items:center;justify-content:center;border-radius:var(--radius-pill);transition:background .15s}
.bottomnav button .ic svg{width:17px;height:17px}
.bottomnav button.on{color:var(--gold-ink)}
.bottomnav button.on .ic{background:var(--gold-tint)}

/* The alert count, worn on the icon the way an app badge sits on a
   home-screen tile rather than printed under the caption, where it
   read as a second line of the label and made the bar taller still.
   Anchored to the glyph, not to the tint pill behind it: that pill is
   wider than the icon, so pinning to its corner would leave the badge
   adrift whenever the tab wasn't the active one. Half the glyph's
   width is 8.5px, so --s-4 puts the badge's left edge on the bell's
   right shoulder and --s-3 lifts it to overlap the top. Ringed in the
   page colour, the way the voice button is, so it reads as sitting
   above the icon rather than beside it. */
.bottomnav .nav-badge{
  position:absolute;left:50%;top:0;
  transform:translate(var(--s-4), calc(-1 * var(--s-3)));
  min-width:16px;height:16px;padding:0 var(--s-2);
  display:flex;align-items:center;justify-content:center;
  background:var(--clay);color:var(--ink);
  border-width:1.5px;border-style:solid;border-color:var(--page-bg);border-radius:var(--radius-pill);
  font-size:9px;font-weight:700;line-height:1;
  pointer-events:none;
}

/* Voice Log — a raised, central action rather than a plain tab, to
   encourage actually using the recorder instead of it hiding in a card.
   Sized on the Fibonacci sequence, same as the rest of the app's scale
   (button/icon were already ~55/~21 — bumped to the next step, 89/34). */
.bottomnav .voicebtn{flex:0 0 auto;display:flex;align-items:center;justify-content:center;padding:0;gap:0;width:89px;height:89px;border-radius:50%;background:var(--gold);margin-top:calc(-1 * var(--s-7));box-shadow:var(--shadow-floating);border:3px solid var(--page-bg)}
.bottomnav .voicebtn .ic{width:auto;height:auto;display:flex;align-items:center;justify-content:center}
.bottomnav .voicebtn .ic svg{width:34px;height:34px;color:var(--ink);display:block}
.bottomnav .voicebtn:active{background:var(--gold-dim)}

/* ---------- Forms ---------- */
.field{margin-bottom:var(--s-6)}
.field label{display:block;font-size:12px;font-weight:600;color:var(--bone-faint);margin-bottom:var(--s-3)}
.input,.textarea,select.input{
  width:100%;background:var(--surface-2);border:1.5px solid var(--hairline);border-radius:var(--radius-lg);padding:var(--s-5);font-size:16px;color:var(--bone);
}
.textarea{min-height:84px;resize:vertical;line-height:1.45}
/* Every dropdown in the app is a native <select class="input">. Left
   at the browser default it draws the platform's own control — on iOS
   a pair of stacked arrows in a system font — which reads as a
   different kind of thing from the text field it shares a card with.
   These rules give it the same field shape as .input, one chevron, and
   the 44px tap target the rest of the app uses.

   The chevron is drawn in CSS rather than an <img>: the deployed
   page's CSP blocks external images, and a data URI keeps it one file.
   A URL cannot interpolate a custom property, so the light theme gets
   its own copy rather than leaving the dark slate showing through. */
select.input{
  -webkit-appearance:none;appearance:none;cursor:pointer;
  min-height:44px;padding-right:var(--s-7);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238996b0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:right var(--s-5) center;
}
[data-theme="light"] select.input{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235c6478' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E")}

.input::placeholder,.textarea::placeholder{color:var(--bone-faint)}
.input:focus,.textarea:focus{outline:none;border-color:var(--gold)}
/* Password field with a show/hide eye. The button sits inside the
   input's own padding rather than beside it, so the field keeps its
   full width and nothing reflows when the icon swaps. 44px hit area
   per standard mobile tap-target sizing (see PRODUCT.md), while the
   glyph itself stays 17px. */
.pw-wrap{position:relative;display:flex;align-items:center}
.pw-wrap .input{padding-right:var(--s-8)}
.pw-eye{
  position:absolute;right:4px;top:50%;transform:translateY(-50%);
  width:44px;height:44px;display:flex;align-items:center;justify-content:center;
  background:none;border:none;color:var(--bone-faint);cursor:pointer;border-radius:var(--radius-sm);
}
.pw-eye:hover,.pw-eye:focus-visible{color:var(--bone)}
.pw-eye:focus-visible{outline:2px solid var(--gold);outline-offset:-2px}

/* Free-form money entry — the one metric that isn't a counter. Sized
   to sit in the same column as the +/- stepper so the seven rows of
   "Log today's numbers" keep a single alignment down the right edge. */
.money-field{display:flex;align-items:center;gap:var(--s-2);flex:0 0 auto}
.money-field .cur{font-family:var(--mono);font-size:14px;color:var(--bone-faint)}
.money-field .input.money{
  width:88px;padding:var(--s-4) var(--s-5);text-align:right;font-family:var(--mono);font-size:15px;
  -moz-appearance:textfield;appearance:textfield;
}
.money-field .input.money::-webkit-outer-spin-button,
.money-field .input.money::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.money-field .t{font-family:var(--mono);font-size:12px;color:var(--bone-faint);white-space:nowrap}

.field-icon{position:relative;display:flex;align-items:center}
.field-icon svg{position:absolute;left:var(--s-5);color:var(--bone-faint);pointer-events:none}
.field-icon .input{padding-left:var(--s-7)}

/* ---------- Choice cards ---------- */
.choice{display:block;width:100%;text-align:left;background:var(--glass-1);-webkit-backdrop-filter:var(--glass-blur-sm);backdrop-filter:var(--glass-blur-sm);border:1.5px solid var(--hairline);border-radius:var(--radius-lg);padding:var(--s-6);margin-bottom:var(--s-5);transition:.15s;box-shadow:var(--glass-sheen)}
.choice.on{border-color:var(--gold);background:var(--surface-2)}
.choice .ct{font-family:var(--headline);font-size:16px;font-weight:480;color:var(--bone)}
.choice .cs{font-size:13px;color:var(--bone-faint);margin-top:var(--s-2);line-height:1.4}

/* ---------- Menu tile grid (square, compact — replaces long lists of
   full-width rows for the settings/menu sheet) ---------- */
.tile-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(84px,1fr));gap:var(--s-5)}
.tile{
  aspect-ratio:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--s-3);
  background:var(--glass-1);-webkit-backdrop-filter:var(--glass-blur-sm);backdrop-filter:var(--glass-blur-sm);
  border:1.5px solid var(--hairline);border-radius:var(--radius-lg);padding:var(--s-5) var(--s-3);
  text-align:center;text-decoration:none;cursor:pointer;transition:.15s;box-shadow:var(--glass-sheen)
}
.tile:active{background:var(--surface-2)}
.tile.static{cursor:default}
.tile svg{color:var(--gold-ink)}
.tile .tl{font-size:12.5px;font-weight:500;color:var(--bone);line-height:1.25}
.tile .ts2{font-size:10.5px;color:var(--bone-faint);line-height:1.2}

/* ---------- Onboarding ---------- */
.onb{min-height:100vh;display:flex;flex-direction:column;justify-content:center;padding:var(--s-7) var(--s-6) calc(var(--s-7) + var(--safe-bottom));background:transparent;color:var(--bone)}
.onb .brand{display:flex;align-items:center;gap:var(--s-4);justify-content:center;margin-bottom:var(--s-5)}
.onb .brand .dia{width:13px;height:13px;background:var(--gold);transform:rotate(45deg);border-radius:2px}
.onb .brand .nm{font-family:var(--display);font-size:21px;letter-spacing:3px;font-weight:480}
.onb .brand .tk{font-size:9px;letter-spacing:3px;color:var(--bone-faint);align-self:center}
.onb h2{font-family:var(--display);font-weight:340;font-size:clamp(1.7rem,8vw,2.3rem);text-align:center;margin:var(--s-5) 0 var(--s-4);letter-spacing:-.01em}
.onb p.lead{text-align:center;color:var(--bone-muted);font-size:14px;margin:0 auto var(--s-6);max-width:340px;line-height:1.55}
.onb .card-light{background:var(--glass-1);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border:1px solid var(--hairline-soft);border-radius:var(--radius-lg);padding:var(--s-6);box-shadow:var(--glass-sheen)}
.onb .choice{background:var(--surface-1);border-color:var(--hairline)}
.onb .choice.on{border-color:var(--gold);background:var(--surface-2)}
.onb .field label{color:var(--bone-faint)}
.dots{display:flex;gap:var(--s-3);justify-content:center;margin:var(--s-6) 0}
.dots .d{width:6px;height:6px;border-radius:var(--radius-pill);background:var(--hairline)}
.dots .d.on{background:var(--gold);width:22px}
.step-actions{display:flex;gap:var(--s-5);margin-top:var(--s-6)}
.step-actions .btn{flex:1}

/* ---------- Ring (svg) ---------- */
.ringwrap{position:relative;width:62px;height:62px}
.ringwrap .rt{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center}
.ringwrap .rt .p{font-family:var(--mono);font-size:14px;font-weight:500;color:var(--bone)}
.ringwrap .rt .l{font-size:8px;letter-spacing:.6px;color:var(--bone-faint)}

/* ---------- Misc ---------- */
.empty{text-align:center;color:var(--bone-faint);padding:var(--s-7) var(--s-5);font-size:13.5px}
.empty svg{width:28px;height:28px;margin:0 auto var(--s-5);color:var(--bone-faint)}
.fab{position:fixed;right:calc(50% - 260px + 18px);bottom:calc(90px + var(--safe-bottom));width:52px;height:52px;border-radius:var(--radius-pill);background:var(--gold);color:var(--ink);display:flex;align-items:center;justify-content:center;box-shadow:var(--shadow-floating);z-index:45}
.fab svg{width:22px;height:22px}
@media(max-width:552px){.fab{right:20px}}
/* No outer margin of its own — on a screen the container spaces it
   (see Vertical rhythm). Nested inside a card, sheet or the onboarding
   column there is no owl to do it, so those get an explicit gap. */
.callout{background:var(--glass-2);-webkit-backdrop-filter:var(--glass-blur-sm);backdrop-filter:var(--glass-blur-sm);border-radius:var(--radius-lg);padding:var(--s-5) var(--s-5);font-size:13px;line-height:1.5;color:var(--bone-muted);display:flex;gap:var(--s-4);align-items:flex-start}
.card .callout,.sheet .callout,.onb .callout{margin-top:var(--s-5)}
.callout svg{width:15px;height:15px;flex:0 0 auto;margin-top:var(--s-1);color:var(--gold-ink)}
.callout.green{background:var(--gold-tint);color:var(--bone)}
.callout.green svg{color:var(--gold-ink)}
.callout.red{background:var(--clay-tint);color:var(--bone)}
.callout.red svg{color:var(--clay-ink)}
.list-plain{list-style:none;padding:0;margin:0}
.list-plain li{padding:var(--s-5) 0;border-bottom:1px solid var(--hairline-soft);font-size:13.5px;display:flex;gap:var(--s-5);align-items:flex-start;color:var(--bone-muted)}
.list-plain li:last-child{border-bottom:none}
.list-plain li .mk{color:var(--gold-ink);flex:0 0 auto;display:flex;align-items:center}
.list-plain li .mk svg{width:14px;height:14px}
.list-plain li .mk.warn{color:var(--clay-ink)}

/* ---------- Modal / sheet ---------- */
.sheet-backdrop{position:fixed;inset:0;background:rgba(4,7,14,.6);z-index:60;display:none;align-items:flex-end;justify-content:center}
.sheet-backdrop.open{display:flex;animation:fade .2s}
.sheet{width:100%;max-width:520px;background:var(--glass-sheet);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border-radius:var(--radius-lg) var(--radius-lg) 0 0;padding:var(--s-6) var(--s-6) calc(var(--s-6) + var(--safe-bottom));max-height:90vh;overflow:auto;box-shadow:var(--glass-sheen), var(--shadow-floating);animation:up .28s cubic-bezier(.2,.8,.2,1)}
@keyframes up{from{transform:translateY(100%)}to{transform:none}}
.sheet .grab{width:36px;height:4px;background:var(--hairline);border-radius:var(--radius-pill);margin:0 auto var(--s-6)}
.sheet h3{font-family:var(--headline);font-size:20px;margin:0 0 var(--s-6);font-weight:480;color:var(--bone)}

.rec-dot{width:9px;height:9px;border-radius:var(--radius-pill);background:var(--clay);display:inline-block;animation:pulse 1s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.3}}
.vn{display:flex;align-items:center;gap:var(--s-5);padding:var(--s-5) 0;border-bottom:1px solid var(--hairline-soft)}
.vn:last-child{border-bottom:none}
.vn .play{width:36px;height:36px;border-radius:var(--radius-pill);background:var(--gold);color:var(--ink);display:flex;align-items:center;justify-content:center;flex:0 0 auto}
.vn .play svg{width:14px;height:14px}
.vn .play{cursor:pointer}

/* An unheard note is marked by a dot rather than by weight or colour
   alone, so it survives the muted palette and reads at a glance. */
.unread-dot{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--gold);margin-right:var(--s-3);vertical-align:middle}
.vn.listened .play{background:var(--surface-2);color:var(--bone-muted);border:1px solid var(--hairline)}

/* ---------- Coach: one student's screen ---------- */
/* Replaced a bottom sheet of stacked, differently-styled buttons. The
   rules here exist to enforce the two things that sheet lacked: a
   single alignment edge, and one button style per group. */
.student-head{display:flex;align-items:center;gap:var(--s-5)}
.student-head-b{flex:1;min-width:0}
.student-head-b h2{font-family:var(--display);font-weight:340;font-size:clamp(1.4rem,6vw,1.8rem);line-height:1.1;margin:0 0 var(--s-3);color:var(--bone)}
.student-head-meta{display:flex;align-items:center;gap:var(--s-4);flex-wrap:wrap;font-size:12.5px;color:var(--bone-faint)}

/* Sub-navigation within one student. Scrolls sideways rather than
   wrapping to a second line, so the header height never jumps as you
   move between tabs. */
.subtabs{
  display:flex;gap:var(--s-3);
  overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;
}
.subtabs::-webkit-scrollbar{display:none}
.subtabs button{
  flex:0 0 auto;font-size:13px;font-weight:600;padding:var(--s-4) var(--s-5);
  border-radius:var(--radius-pill);color:var(--bone-faint);background:var(--surface-2);
  border:1px solid var(--hairline-soft);white-space:nowrap;
}
.subtabs button.on{background:var(--gold);color:var(--ink);border-color:transparent}

/* Every action in a card is full width in one column. This is the rule
   that fixes "the buttons are just stacked centrally and all designed
   differently" — one column, one alignment, consistent spacing. */
.action-stack{display:flex;flex-direction:column;gap:var(--s-4)}
.action-stack .btn{width:100%;justify-content:flex-start;text-align:left}
.action-stack .btn svg{flex:0 0 auto}

/* Period picker. A native select so it stays one line at any width and
   gets the platform's own wheel on iOS, with the icon sitting inside
   the field the way .field-icon does elsewhere. */
.period-picker{position:relative;display:flex;align-items:center}
.period-picker svg{position:absolute;left:var(--s-5);color:var(--bone-faint);pointer-events:none}
/* Only the left inset for the calendar icon is specific to this one;
   the chevron, tap target and field shape come from select.input. */
.period-picker select{padding-left:var(--s-7);font-weight:600}

/* ---------- Forecast ---------- */
.fc-row{padding:var(--s-5) 0;border-bottom:1px solid var(--hairline-soft)}
.fc-row:last-child{border-bottom:none}
.fc-head{display:flex;align-items:center;justify-content:space-between;gap:var(--s-4);margin-bottom:var(--s-4)}
.fc-t{font-size:14px;font-weight:600;color:var(--bone)}
.fc-row .track{height:4px;background:var(--surface-2);border-radius:2px;overflow:hidden}
.fc-row .track .fill{height:100%;border-radius:2px;transition:width .3s}
.fc-sub{font-size:12.5px;color:var(--bone-muted);margin-top:var(--s-4);line-height:1.5}
.fc-need{font-size:12.5px;color:var(--gold-ink);margin-top:var(--s-2);line-height:1.5;font-weight:600}
@media (prefers-reduced-motion: reduce){ .fc-row .track .fill{transition:none} }

/* Date and time inputs. Both already open the platform's own picker on
   iOS and Android — the wheel for a date, the wheel for a time — and
   every date and time field in the app is one of these rather than
   anything hand-built. What made them not *look* native was the styling
   around them: iOS renders the control at its own intrinsic width and
   left-aligns it inside a box sized for text, so it read as a text
   field that happened to open a wheel. Resetting the appearance and
   giving it a real tap height lets the platform control fill the field.

   type="time" gets identical treatment to type="date", because the two
   sit side by side in the coaching-session sheet and a time field an
   inch shorter than the date field beside it is the exact mismatch
   these rules exist to remove.

   16px on the font is not cosmetic: iOS zooms the page when a field
   under 16px takes focus. */
input[type="date"],
input[type="time"]{
  -webkit-appearance:none;appearance:none;
  min-height:44px;width:100%;
  font-family:var(--sans);font-size:16px;color:var(--bone);
}
input[type="date"]::-webkit-date-and-time-value,
input[type="time"]::-webkit-date-and-time-value{text-align:left;margin:0}
/* WebKit draws the little calendar/clock glyph as a dark shape, which
   needs inverting on the dark theme and must NOT be inverted on the
   light one — inverted, it goes pale grey on a pale field and all but
   disappears. Dark is the default here, so light opts back out. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator{
  filter:invert(.75);opacity:.8;cursor:pointer;padding:var(--s-3);
}
[data-theme="light"] input[type="date"]::-webkit-calendar-picker-indicator,
[data-theme="light"] input[type="time"]::-webkit-calendar-picker-indicator{
  filter:none;opacity:.55;
}

/* Goals table — goal, actual, variance, left to go, one row per metric.
   A grid rather than a <table> so the label can take the slack while
   the four number columns stay aligned; on a narrow phone the numbers
   are what must not wrap, so they are fixed and the label truncates. */
.gtable{display:flex;flex-direction:column}
.gt-head,.gt-row{display:grid;grid-template-columns:minmax(0,1fr) repeat(4,44px);gap:var(--s-3);align-items:center}
.gt-head{font-size:10px;font-weight:600;color:var(--bone-faint);letter-spacing:.04em;padding-bottom:var(--s-3);border-bottom:1px solid var(--hairline)}
.gt-head span:not(:first-child),.gt-row .gt-n{text-align:right}
.gt-row{padding:var(--s-4) 0;border-bottom:1px solid var(--hairline-soft)}
.gt-row:last-child{border-bottom:none}
.gt-l{font-size:13px;color:var(--bone);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gt-n{font-family:var(--mono);font-size:12px;color:var(--bone-muted);white-space:nowrap}
.gt-n.gt-a{color:var(--bone);font-weight:600}
@media(max-width:380px){
  .gt-head,.gt-row{grid-template-columns:minmax(0,1fr) repeat(4,38px);gap:var(--s-2)}
  .gt-n{font-size:11px}
}

/* Targets table — the coach's own spreadsheet, in the app. One row per
   category: the number he is aiming at, and what that demands per
   month, week and working day once a date is on it.

   Same grid idea as .gtable, but the goal column holds a real input —
   84px fits six digits and a dollar sign, which is what a revenue
   target actually is. The whole thing scrolls sideways rather than
   squeezing: five columns of numbers on a 390px phone is genuinely
   tight, and a number half-hidden is worse than one scrolled to. */
/* Wide enough for an eight-character figure ("$108,222") in every rate
   column: at 44px they ran into each other on a phone. Below the min-width
   the wrap scrolls sideways rather than the cells overlapping. */
.ttable{display:flex;flex-direction:column;min-width:344px}
.ttable-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;margin:0 calc(var(--s-5) * -1);padding:0 var(--s-5)}
.tt-head,.tt-row{display:grid;grid-template-columns:minmax(74px,1fr) 76px repeat(3,58px);gap:var(--s-3);align-items:center}
.tt-head{font-size:9.5px;font-weight:600;color:var(--bone-faint);letter-spacing:.04em;text-transform:uppercase;padding-bottom:var(--s-3);border-bottom:1px solid var(--hairline)}
.tt-head span:not(:first-child){text-align:right}
.tt-row{padding:var(--s-3) 0;border-bottom:1px solid var(--hairline-soft)}
.tt-row:last-child{border-bottom:none}
.tt-l{font-size:12.5px;color:var(--bone);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tt-n{font-family:var(--mono);font-size:11.5px;color:var(--bone-muted);text-align:right;white-space:nowrap}
/* The input is styled down to sit in a table row rather than look like
   a form field stacked in a column — it is a cell that happens to be
   typeable, which is how it reads in his spreadsheet. */
.tt-in{width:100%;box-sizing:border-box;padding:var(--s-2) var(--s-3);text-align:right;
  font-family:var(--mono);font-size:12px;color:var(--bone);
  background:var(--surface-2);border:1px solid var(--hairline);border-radius:var(--r-2)}
.tt-in:focus{outline:none;border-color:var(--gold);background:var(--surface-1)}
/* A row Harry has typed over is his, not the funnel's, and says so —
   otherwise "reset to baseline" has no visible meaning. */
.tt-row.over .tt-in{border-color:var(--gold);color:var(--gold-ink);font-weight:600}
.tt-row.over .tt-l::after{content:'·';color:var(--gold-ink);font-weight:700;margin-left:4px}
@media(max-width:380px){
  /* On a phone the rate columns keep their width and the label gives
     way instead, wrapping to a second line rather than truncating —
     "Conversa…" next to a number is worse than two short lines. */
  .ttable{min-width:300px}
  .tt-head,.tt-row{grid-template-columns:minmax(76px,1fr) 68px repeat(3,52px);gap:var(--s-2)}
  .tt-l{white-space:normal;line-height:1.25}
  .tt-n{font-size:11px}
}

/* A mission's promises, as the coach reads them back — numbered,
   because that is how they are written in the chat, and struck through
   once kept so a glance says what is outstanding today. */
.mission-items{margin:var(--s-4) 0 0;padding-left:calc(var(--s-6) + 2px);display:flex;flex-direction:column;gap:var(--s-2)}
.mission-items li{font-size:13px;line-height:1.5;color:var(--bone-muted)}
/* Which promises repeat, said once per line instead of once per
   mission — a fortnight can hold "thirty calls every day" and "call
   every dormant account" at the same time. */
.daily-tag{display:inline-block;margin-left:var(--s-3);padding:1px 6px;border-radius:999px;
  background:var(--surface-2);color:var(--bone-faint);font-size:10px;font-weight:600;
  letter-spacing:.02em;vertical-align:middle;white-space:nowrap}
.mission-items li.done{color:var(--bone-faint);text-decoration:line-through}

/* Coach's journal — entries grouped into a collapsible day.

   An accordion rather than a flat list because the thing a coach comes
   back for is one particular conversation, and forty entries in a row
   turns that into a scroll instead of a lookup. The newest day opens on
   its own so the tab lands on the last call, not on history. */
.jr-day{border-bottom:1px solid var(--hairline-soft)}
.jr-day:last-child{border-bottom:none}
.jr-head{display:flex;align-items:center;gap:var(--s-4);width:100%;
  padding:var(--s-5) 0;background:none;border:0;cursor:pointer;text-align:left;
  font:inherit;color:var(--bone);min-height:44px}
.jr-head svg{flex:0 0 auto;color:var(--bone-faint);transition:transform .2s}
.jr-day.open .jr-head svg{transform:rotate(90deg)}
.jr-date{flex:1;min-width:0;font-size:13.5px;font-weight:600;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* The count is what makes a collapsed day worth anything — it says
   whether there is one line in there or a whole session. */
.jr-count{flex:0 0 auto;font-family:var(--mono);font-size:11px;color:var(--bone-faint);
  background:var(--surface-2);border-radius:999px;padding:2px 8px}
.jr-entries{display:none;padding:0 0 var(--s-5) calc(14px + var(--s-4))}
.jr-day.open .jr-entries{display:block}
.jr-entry{padding:var(--s-4) 0;border-top:1px solid var(--hairline-soft)}
.jr-entry:first-child{border-top:none}
.jr-meta{display:flex;align-items:center;gap:var(--s-3)}
.jr-time{font-family:var(--mono);font-size:11px;color:var(--bone-faint);flex:0 0 auto}
.jr-edited{font-size:10.5px;color:var(--bone-faint);font-style:italic}
/* The two buttons sit to the right of the timestamp, pushed out by this
   spacer so they line up down the column whatever the time reads. */
.jr-meta .icon-btn{margin-left:auto}
.jr-meta .icon-btn + .icon-btn{margin-left:0}
/* white-space:pre-wrap so a coach's own line breaks survive — a journal
   entry is written in paragraphs, not one run-on line. */
.jr-body{margin-top:var(--s-3);font-size:13.5px;line-height:1.6;color:var(--bone);white-space:pre-wrap;word-break:break-word}
@media (prefers-reduced-motion: reduce){ .jr-head svg{transition:none} }

/* ---------- Milestones ---------- */
.ms-row{padding:var(--s-5) 0;border-bottom:1px solid var(--hairline-soft)}
.ms-row:last-child{border-bottom:none}
.ms-row.done .ms-t{color:var(--bone-faint);text-decoration:line-through}
.ms-head{display:flex;align-items:center;gap:var(--s-4)}
.ms-head .check{flex:0 0 auto}
.ms-t{flex:1;min-width:0;font-size:14px;font-weight:600;color:var(--bone)}
.ms-bar{display:flex;align-items:center;gap:var(--s-4);margin-top:var(--s-4);padding-left:calc(22px + var(--s-4))}
.ms-bar .track{flex:1;height:4px;background:var(--surface-2);border-radius:2px;overflow:hidden}
.ms-bar .track .fill{height:100%;border-radius:2px;transition:width .3s}
.ms-n{font-family:var(--mono);font-size:11px;color:var(--bone-muted);white-space:nowrap}
.ms-pct{color:var(--bone-faint)}
/* What a dated goal demands from here — the sentence that saves a
   student doing the division. The month figure leads because that is
   the horizon a target twelve months out is actually planned in; the
   week and day sit under it, quieter, for the ones who work that way. */
.ms-rate{font-size:12.5px;color:var(--gold-ink);font-weight:600;margin-top:var(--s-4);line-height:1.5}
.ms-rate-alt{display:block;font-size:11px;color:var(--bone-faint);font-weight:500;margin-top:var(--s-2)}
.ms-note{font-size:12.5px;color:var(--bone-faint);margin-top:var(--s-4);padding-left:calc(22px + var(--s-4));line-height:1.5}
@media (prefers-reduced-motion: reduce){ .ms-bar .track .fill{transition:none} }

/* ---------- Onboard-a-student steps ---------- */
.onb-step{display:flex;gap:var(--s-5);padding:var(--s-5) 0;border-bottom:1px solid var(--hairline-soft)}
.onb-step:last-of-type{border-bottom:none}
.onb-step-n{
  flex:0 0 auto;width:26px;height:26px;border-radius:var(--radius-pill);
  background:var(--gold-tint);color:var(--gold-ink);
  display:flex;align-items:center;justify-content:center;
  font-family:var(--mono);font-size:12px;font-weight:600;
}
.onb-step-b{flex:1;min-width:0}
.onb-step-t{font-size:14px;font-weight:600;color:var(--bone)}

/* ---------- Onboarding guide ---------- */
/* The getting-started card is the first thing a new student sees, so
   it gets a gold edge to separate it from the ordinary cards below
   without shouting. It removes itself once complete. */
.guide-card{border-color:var(--gold-dim)}
.guide-card .focus-item{cursor:default}

.guide-icon{
  width:52px;height:52px;margin:0 auto;border-radius:var(--radius-pill);
  background:var(--gold);color:var(--ink);
  display:flex;align-items:center;justify-content:center;
}
.guide-dots{display:flex;gap:var(--s-3);justify-content:center;margin-top:var(--s-6)}
.guide-dots span{width:6px;height:6px;border-radius:50%;background:var(--hairline);transition:.2s}
.guide-dots span.on{background:var(--gold);width:18px;border-radius:3px}
@media (prefers-reduced-motion: reduce){ .guide-dots span{transition:none} }

/* ---------- Voice note player ----------
   Mounts inside whichever note is playing. Hidden (zero height) until
   the player renders into it, so a list of notes doesn't carry a row
   of empty control strips. */
.vnp-host:empty{display:none}
.vnp{margin-top:var(--s-5)}
.vnp-row{display:flex;align-items:center;gap:var(--s-4)}
.vnp-btn{
  width:34px;height:34px;flex:0 0 auto;border-radius:var(--radius-pill);
  background:var(--gold);color:var(--ink);border:none;
  display:flex;align-items:center;justify-content:center;cursor:pointer;position:relative;
}
.vnp-btn.ghost{background:var(--surface-2);color:var(--bone-muted);border:1px solid var(--hairline)}
.vnp-btn:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.vnp-btn .vnp-skip{
  position:absolute;font-family:var(--mono);font-size:8px;font-weight:500;
  left:0;right:0;top:calc(50% + 1px);transform:translateY(-50%);text-align:center;pointer-events:none;
}
.vnp-rate{width:auto;padding:0 var(--s-5);font-family:var(--mono);font-size:12px;font-weight:500}
.vnp-time{font-family:var(--mono);font-size:11px;color:var(--bone-faint);flex:0 0 auto;white-space:nowrap}

/* Range input needs its track and thumb styled per-engine; without
   this it renders as the OS default slider, which looks nothing like
   the rest of the app. */
.vnp-seek{
  flex:1;min-width:60px;height:4px;-webkit-appearance:none;appearance:none;
  background:var(--surface-2);border-radius:2px;outline:none;cursor:pointer;
}
.vnp-seek::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;width:13px;height:13px;border-radius:50%;
  background:var(--gold);cursor:pointer;border:none;
}
.vnp-seek::-moz-range-thumb{
  width:13px;height:13px;border-radius:50%;background:var(--gold);cursor:pointer;border:none;
}
.vnp-seek:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

@media (prefers-reduced-motion: reduce){
  .vnp-seek,.vnp-btn{transition:none}
}
.toast{position:fixed;left:50%;transform:translateX(-50%);bottom:calc(100px + var(--safe-bottom));background:var(--surface-2);border:1px solid var(--hairline);color:var(--bone);padding:var(--s-5) var(--s-6);border-radius:var(--radius-pill);font-size:13px;font-weight:500;z-index:80;box-shadow:var(--shadow-floating);opacity:0;transition:opacity .25s, transform .25s;pointer-events:none;display:flex;align-items:center;gap:var(--s-5)}
.toast.show{opacity:1;transform:translateX(-50%) translateY(-4px)}
.toast.undo.show{pointer-events:auto}
.toast-undo{background:none;border:none;color:var(--gold);font-weight:700;font-size:13px;padding:var(--s-1);cursor:pointer;flex:0 0 auto}

.kv{display:flex;justify-content:space-between;padding:var(--s-4) 0;border-bottom:1px solid var(--hairline-soft);font-size:13.5px}
.kv:last-child{border-bottom:none}
.kv .k{color:var(--bone-faint)}
.kv .v{font-family:var(--mono);font-weight:500;color:var(--bone)}
/* Gap matches the padding inside the cards it separates (--s-6). A gap
   smaller than that padding is what made these four read as touching. */
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:var(--s-6)}
.goalcard{background:var(--glass-2);-webkit-backdrop-filter:var(--glass-blur-sm);backdrop-filter:var(--glass-blur-sm);border-radius:var(--radius-lg);padding:var(--s-5);box-shadow:var(--glass-sheen)}
.goalcard .cat{display:inline-block;font-size:10px;padding:var(--s-2) var(--s-4);border-radius:var(--radius-pill);background:var(--surface-1);color:var(--bone-muted);font-weight:600}
.goalcard .ti{font-family:var(--headline);font-size:15px;font-weight:480;margin-top:var(--s-3);color:var(--bone)}
.goalcard .de{font-size:11.5px;color:var(--bone-faint);margin-top:var(--s-2)}
.switch{display:inline-flex;align-items:center;gap:var(--s-4);font-size:12px;color:var(--bone-faint);font-weight:600}
.toggle{width:40px;height:23px;border-radius:var(--radius-pill);background:var(--hairline);position:relative;transition:.2s;flex:0 0 auto}
.toggle .knob{width:17px;height:17px;border-radius:var(--radius-pill);background:var(--bone);position:absolute;top:3px;left:3px;transition:.2s}
.toggle.on{background:var(--gold)}
.toggle.on .knob{left:20px;background:var(--ink)}

/* ---------- print (report export) ----------
   Reuses the on-screen report markup as-is rather than building a
   separate export template — "Download PDF" just forces the light
   theme's flat, opaque values (glass/blur effects don't rasterize
   reliably to print) and hides everything that isn't the report
   itself, then calls window.print(). Every browser's print dialog
   offers "Save as PDF" natively, so no PDF library is needed. */
@media print{
  :root{
    --page-bg:#fff; --surface-1:#fff; --surface-2:#f3f4f7;
    --hairline:#d7dae2; --hairline-soft:#e5e7ee;
    --bone:#182238; --bone-muted:#4c5568; --bone-faint:#5c6478;
    --gold-ink:#7a5a1d; --clay-ink:#a24a2e;
    --glass-1:#fff; --glass-2:#f3f4f7; --glass-sheen:none;
    --page-wash:none; --shadow-resting:none; --shadow-floating:none;
  }
  body{background:#fff}
  #topbar, #bottomnav, .tabs, .btn-row, #sheet-backdrop, .toast, #onboarding{display:none !important}
  #app{max-width:none}
  #main{display:block !important}
  .card{-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:none;border:1px solid var(--hairline);break-inside:avoid}
  .screen{padding-bottom:0}
}
