    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

    /* ── Slate ──────────────────────────────────────────────────────────────
       The palette is bone on wet slate, and the split colors are artist pigment
       values (vermilion, cerulean, viridian) rather than framework defaults. The
       previous set mixed Flat UI and Tailwind stock colors, which is the single
       clearest tell that a palette was picked rather than chosen.

       Warm for push and cool for pull is not decorative: it encodes the motion,
       so the palette carries meaning the way competition plate colors do.

       Every hue drops roughly 25% in lightness for the light theme. Bright
       vermilion on warm paper only reaches about 3:1, which fails as text; the
       deepened value clears 5:1 and survives a badly lit gym. See the light
       block below, which restages the same names rather than inventing new ones. */
    :root {
      --bg:       #1A1D1C;
      --bg-card:  #232726;
      --bg-elev:  #2B2F2E;
      --bg-inp:   #2B2F2E;
      --accent:   #D5CFC0;
      /* Alpha tints. These are variables rather than inline rgba() so light
         mode can restage them: a tint mixed for near-black is far too weak to
         register over white, and carries the wrong hue. */
      --accent-t:  rgba(213,207,192,0.10);
      --accent-t2: rgba(213,207,192,0.22);
      --accent-bd: rgba(213,207,192,0.32);
      --danger-t:  rgba(232,80,58,0.12);
      --danger-t2: rgba(232,80,58,0.26);
      --warn-bd:   rgba(224,169,59,0.34);
      --warn-bd2:  rgba(224,169,59,0.22);
      /* Side-imbalance uses cerulean, not purple: the app now has exactly two
         alert colors, and neither may collide with a split hue. */
      --bal-bd:    rgba(42,147,206,0.36);
      --bal-bd2:   rgba(42,147,206,0.24);
      --camber-bd: rgba(224,169,59,0.32);
      --ok:        #1BA87B;
      --ok-t:      rgba(27,168,123,0.14);
      /* Text sitting ON a filled split color (calendar day pills). Dark mode's
         split hues are bright, so near-black reads on them; light mode's are
         deep, so it has to flip to white. */
      --on-split:  #16191A;
      --nav-on:   #D5CFC0;
      --push:     #E8503A;
      --push-d:   rgba(232,80,58,0.12);
      --pull:     #2A93CE;
      --pull-d:   rgba(42,147,206,0.12);
      --legs:     #1BA87B;
      --legs-d:   rgba(27,168,123,0.12);
      --rest:     #8A8A80;
      --rest-d:   rgba(138,138,128,0.12);
      /* Small-text variants of the split hues (the workout badge). On slate the
         bright pigments already clear 4.5:1 on their own tint, so ink and hue are
         the same value here and only light mode has to separate them. Defined
         anyway so the token exists in both themes and no rule can fall through
         to nothing. See the light block for why this split exists at all. */
      --push-ink: #E8503A;
      --pull-ink: #2A93CE;
      --legs-ink: #1BA87B;
      --rest-ink: #8A8A80;
      --cred:     #E8503A;
      --cred-d:   rgba(232,80,58,0.14);
      --cpurple:  #2A93CE;
      --cpurple-d:rgba(42,147,206,0.14);
      --camber:   #E0A93B;
      --camber-d: rgba(224,169,59,0.14);
      --cpink:    #C9736A;
      --cpink-d:  rgba(201,115,106,0.14);
      --text:      #F0EDE4;
      --text-soft: #B5B4AA;
      /* Tertiary text: section labels, dates, helper copy, placeholders. #555
         measured 2.66:1 on the page background, well under the 4.5 minimum, so
         labels faded into the black. #888 clears it at 5.58:1. The one place
         that genuinely wants to look faint (out-of-month calendar days) carries
         its own opacity: 0.35, so it stays distinct. */
      --text-muted:#9B9A90;
      --bdr:      rgba(240,237,228,0.11);
      --bdr2:     rgba(240,237,228,0.20);
      --bar-bg:   rgba(26,29,28,0.96);
      --warn:     #E0A93B;
      --danger:   #E8503A;
      /* Brand gold. Deliberately NOT one of the three split pigments, so it can
         mean exactly one thing wherever it appears: a personal best. It is the
         top bar of the app mark for the same reason. */
      --gold:     #D9A441;
      --gold-d:   rgba(217,164,65,0.13);
      --nav-h:    64px;
      --hdr-h:    56px;
      --safe-b:   env(safe-area-inset-bottom, 0px);
      --safe-t:   env(safe-area-inset-top, 0px);
      /* Radii drop hard. Slate builds structure from rules rather than rounded
         containers, and a uniform 14px radius on everything was part of what
         made the old UI read as generated. */
      --r:        3px;
      --rs:       2px;
      /* Display face. The serif is the whole signature of this direction, so it
         is a token rather than a hardcoded stack: headings, split names, big
         numerals and the clock all pull from here, and body copy stays sans.
         Georgia ships on every Apple platform, so there is no webfont to load,
         no CDN to block, and no silent fallback. */
      --serif: Georgia, 'Times New Roman', 'Iowan Old Style', serif;
      /* Serif for LIVE COUNTERS only (the stopwatch and the countdown).
         READ THE FONT TABLES BEFORE CHANGING THIS. A face is only safe here if
         it has a `tnum` feature OR its ten digits already share one advance
         width. Georgia has neither: its GSUB carries no numeral features at all
         (tnum, lnum and onum all absent), so `font-variant-numeric: tabular-nums`
         is a silent no-op on it, its advances stay proportional (377/2048 spread,
         the 1 nearly a third narrower than the 0), and its figures are old-style,
         so 3 4 5 7 9 hang below the baseline while 6 and 8 rise. Horizontal AND
         vertical jitter on every tick, unfixable in CSS because there is nothing
         to switch to. Georgia must therefore never appear in this chain.
         Charter is the chosen face: its digits are already equal-width (spread 0)
         so it needs no feature at all, and Matthew Carter drew it to survive
         coarse output, which is the same problem as reading a number mid-set.
         Every fallback below it is independently safe: New York carries tnum,
         and the system sans is tabular by default (it is what the iOS Clock
         app uses). Also ruled out when picking this: Didot (222 spread) and
         Hoefler Text (434), both without tnum. */
      --serif-num: Charter, 'Bitstream Charter', ui-serif, 'New York', -apple-system, BlinkMacSystemFont, sans-serif;
    }

    /* ── Light mode ─────────────────────────────────────────────
       Only colors change; layout/radius vars stay shared. The faint
       "-d" tint colors are alpha, so they work over white as-is. */
    :root[data-theme="light"] {
      /* Surfaces. White leads here: the page sits just off-white so
         white cards still read as raised, and the borders below do the rest of
         the separating. An earlier pass pushed the page to a heavy #E8EAEF gray,
         which bought contrast at the cost of looking dingy. */
      /* Warm paper, never white. Pure white behind a serif reads clinical, and
         this whole direction is built on print thinking. */
      --bg:       #F3F1EB;
      --bg-card:  #FAF9F5;
      --bg-elev:  #E7E4DB;
      --bg-inp:   #E7E4DB;
      --nav-on:   #333835;
      /* Hues are VIBRANT, not merely dark, and this has now been got wrong twice
         in the same direction, so read this before touching them.
         Forcing every hue to clear 4.5:1 as small text on paper is a bar that
         orange and green cannot meet without turning to mud: that is how --push
         ended up literally brown once, and how this set ended up dull enough to
         get rejected on sight a second time.
         The fix is not one value per hue, it is TWO. Split colors are used two
         very different ways, and only one of them is small text:
           --push        graphics: the 2px split rule, the equipment mark, filled
                         calendar days, the chart. Non-text, held to 3:1, so it
                         gets to stay saturated and bright (measured 3.3 to 3.4).
           --push-ink    the only small-text use: the workout badge, 12px bold on
                         a 10% tint. Held to the full 4.5:1 (measured ~4.7).
         So the app reads vibrant while the one thing that must stay legible does.
         Never collapse these back into a single token. */
      --accent:   #333835;
      --push:     #EB4932;
      --pull:     #218BC7;
      --legs:     #12946A;
      --rest:     #85857B;
      --push-ink: #C23C29;
      --pull-ink: #1B72A3;
      --legs-ink: #0F7A58;
      --rest-ink: #6B6B63;
      --cred:     #C33A24;
      --cpurple:  #1D6E9E;
      --camber:   #8A5E0C;
      --cpink:    #A6503F;
      --text:      #1E2220;
      --text-soft: #4C4F4B;
      /* Was #6E6D64, which measured 4.09:1 on --bg-elev and so failed on every
         inactive segmented-control label, the gym pill, the stall dates and the
         ghost buttons. The worst surface is bg-elev, not the page, so it is the
         one to tune against: this clears 4.61 there and 5.19 on paper, while
         staying plainly lighter than --text-soft so the hierarchy survives. */
      --text-muted:#66655C;
      /* Small text colors, held to the stricter 4.5:1 bar. Amber becomes ochre,
         because bright amber simply does not survive on paper. */
      --warn:     #8A5E0C;
      --danger:   #A8392A;
      --ok:       #0F7A57;
      /* Gold has to darken on paper like every other hue, or it turns to straw. */
      --gold:     #9A7118;
      --gold-d:   rgba(154,113,24,0.12);
      --bdr:      rgba(30,34,32,0.15);
      --bdr2:     rgba(30,34,32,0.26);
      --bar-bg:   rgba(243,241,235,0.94);
      /* Tints need more alpha over white than over near-black to read at all. */
      --accent-t:  rgba(51,56,53,0.08);
      --accent-t2: rgba(51,56,53,0.18);
      --accent-bd: rgba(51,56,53,0.34);
      --danger-t:  rgba(168,57,42,0.10);
      --danger-t2: rgba(168,57,42,0.22);
      --warn-bd:   rgba(138,94,12,0.40);
      --warn-bd2:  rgba(138,94,12,0.26);
      --bal-bd:    rgba(29,110,158,0.40);
      --bal-bd2:   rgba(29,110,158,0.26);
      --camber-bd: rgba(138,94,12,0.38);
      --ok-t:      rgba(15,122,87,0.12);
      /* Light mode's pigments are deep, so a filled calendar day flips to paper. */
      --on-split:  #F7F5F0;
      /* Tints restaged onto the vibrant hues above, or the wash sits under a
         badge whose text is a different color from the fill it is mixed from. */
      --push-d:    rgba(235,73,50,0.10);
      --pull-d:    rgba(33,139,199,0.10);
      --legs-d:    rgba(18,148,106,0.10);
      --rest-d:    rgba(133,133,123,0.12);
      --cred-d:    rgba(195,58,36,0.10);
      --cpurple-d: rgba(29,110,158,0.10);
      --camber-d:  rgba(138,94,12,0.11);
      --cpink-d:   rgba(166,80,63,0.10);
    }

    html, body {
      height: 100%; background: var(--bg); color: var(--text);
      font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', sans-serif;
      font-size: 16px; overflow: hidden;
      -webkit-tap-highlight-color: transparent;
      overscroll-behavior: none;
      /* Kill double-tap-to-zoom (and the 300ms tap delay) while keeping taps
         and scrolling fully responsive. Pinch zoom is blocked via the
         viewport meta + gesture handlers in the boot script. */
      touch-action: manipulation;
      -webkit-text-size-adjust: 100%; text-size-adjust: 100%;
    }

    #app {
      display: flex; flex-direction: column;
      height: 100dvh; max-width: 480px; margin: 0 auto;
    }

    /* ── Header ─────────────────── */
    #hdr {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: max(12px, var(--safe-t)) 16px 12px 16px;
      height: auto;
      min-height: 48px;
      background: var(--bar-bg);
      backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
      border-bottom: 1px solid var(--bdr);
      flex-shrink: 0;
      z-index: 10;
      box-sizing: border-box;
    }
    /* The wordmark is the serif at rest. Nothing else in the header competes. */
    #hdr h1 {
      font-family: var(--serif);
      font-size: 1.4rem;
      font-weight: 400;
      letter-spacing: 0.01em;
      flex: 1;
      margin: 0;
      padding: 0;
    }
    #hdr-act {
      display: flex;
      gap: 8px;
      align-items: center;
      height: 100%;
    }

    /* ── Main ────────────────────── */
    #main {
      flex: 1; overflow-y: auto; overflow-x: hidden;
      -webkit-overflow-scrolling: touch;
      overscroll-behavior-y: contain;
    }

    /* ── Bottom Nav ──────────────── */
    #nav {
      height: calc(var(--nav-h) + var(--safe-b));
      background: var(--bar-bg);
      backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
      border-top: 1px solid var(--bdr);
      display: flex; align-items: stretch;
      padding-bottom: var(--safe-b); flex-shrink: 0;
    }
    .nb {
      flex: 1; display: flex; flex-direction: column;
      align-items: center; justify-content: center; gap: 3px;
      background: none; border: none; color: var(--text-muted);
      cursor: pointer; font-size: 0.68rem; font-weight: 700;
      letter-spacing: 0.04em; text-transform: uppercase;
      transition: color 0.18s; padding: 8px 4px;
    }
    .nb svg { transition: transform 0.18s; }
    .nb.on { color: var(--nav-on); }
    .nb.on svg { transform: scale(1.12); }

    /* ── Buttons ─────────────────── */
    .btn {
      display: inline-flex; align-items: center; justify-content: center;
      gap: 7px; padding: 13px 18px; border-radius: var(--rs);
      font-size: 0.92rem; font-weight: 700; cursor: pointer; border: none;
      transition: opacity 0.12s, transform 0.12s;
      -webkit-tap-highlight-color: transparent; min-height: 48px; line-height: 1;
    }
    .btn:active { opacity: 0.8; transform: scale(0.975); }
    .btn-primary { background: var(--accent); color: var(--bg); }
    .btn-ghost   { background: var(--bg-elev); color: var(--text-soft); }
    .btn-danger  { background: var(--danger-t); color: var(--danger); }
    /* Sign in with Apple. Apple's guidelines allow the button to be black, white,
       or white with an outline, and nothing else, so it cannot use --accent like
       every other primary action. Painting it with --text on --bg lands on
       white-on-black in dark mode and black-on-white in light, which is exactly
       the pair Apple asks for and needs no theme-specific rule. */
    .btn-apple   { background: var(--text); color: var(--bg); }
    .btn-sm      { padding: 8px 12px; font-size: 0.82rem; min-height: 38px; }
    .btn-full    { width: 100%; }
    .btn-icon    { width: 38px; height: 38px; padding: 0; border-radius: var(--rs); flex-shrink: 0; }

    /* ── Cards ───────────────────── */
    .card { background: var(--bg-card); border-radius: var(--r); border: 1px solid var(--bdr); overflow: hidden; }

    /* ── Input ───────────────────── */
    .input {
      background: var(--bg-inp); border: 1.5px solid transparent;
      border-radius: var(--rs); color: var(--text);
      font-size: 1rem; padding: 12px 14px; width: 100%;
      outline: none; transition: border-color 0.18s;
      -webkit-appearance: none; appearance: none;
    }
    .input:focus { border-color: var(--accent); }
    .input::placeholder { color: var(--text-muted); }

    /* ── Badges / Dots ───────────── */
    .badge { padding: 4px 12px; border-radius: 50px; font-size: 0.75rem; font-weight: 800; letter-spacing: 0.05em; }
    /* Badge text takes the -ink variant, never the hue: 12px bold is normal-size
       text by WCAG, so it owes the full 4.5:1 that the vibrant hue does not pay. */
    .bp { background: var(--push-d); color: var(--push-ink); }
    .bl { background: var(--pull-d); color: var(--pull-ink); }
    .bg { background: var(--legs-d); color: var(--legs-ink); }
    .br { background: var(--rest-d); color: var(--rest-ink); }
    .s-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
    .dp { background: var(--push); } .dl { background: var(--pull); }
    .dg { background: var(--legs); } .dr { background: var(--rest); }

    /* ── Gym / Location ──────────── */
    .gym-bar {
      display: flex; align-items: center; gap: 10px;
      padding: 0 16px 14px;
    }
    .gym-bar-lbl {
      font-size: 0.68rem; font-weight: 800; text-transform: uppercase;
      letter-spacing: 0.1em; color: var(--text-muted);
    }
    .gym-pick {
      display: flex; align-items: center; gap: 6px;
      background: var(--bg-elev); border: 1px solid var(--bdr2);
      border-radius: 50px; padding: 7px 14px;
      color: var(--text); font-size: 0.85rem; font-weight: 700;
      cursor: pointer; transition: all 0.15s;
    }
    .gym-pick.none { color: var(--text-muted); }
    .gym-pick:active { opacity: 0.75; }
    .gym-badge {
      font-size: 0.72rem; font-weight: 800; letter-spacing: 0.04em;
      padding: 3px 10px; border-radius: 50px;
      background: var(--bg-elev); color: var(--text-soft);
    }

    /* ── Location / filter tabs ───── */
    .tabs-wrap {
      display: flex; gap: 6px; padding: 12px 16px 4px;
      overflow-x: auto; -webkit-overflow-scrolling: touch;
      scrollbar-width: none;
    }
    .tabs-wrap::-webkit-scrollbar { display: none; }
    .tab {
      flex-shrink: 0; padding: 7px 15px; border-radius: 50px;
      font-size: 0.8rem; font-weight: 700; cursor: pointer;
      background: var(--bg-elev); border: 1px solid transparent;
      color: var(--text-muted); transition: all 0.15s; white-space: nowrap;
    }
    .tab.on { background: var(--accent); color: var(--bg); }

    /* ── Type selector ───────────── */
    /* Splits are RULED ROWS, not cards. Four rounded cards stacked in a column is
       the default output shape of every assistant-built app, so the container is
       removed entirely and the split identifies itself with a 2px colored rule
       beneath it. Scanning the list, the rules read as a chart of your training
       balance without anyone having to draw a chart. */
    .type-grid { display: grid; gap: 0; padding: 4px 16px 8px; }
    .type-btn {
      display: flex; align-items: center; gap: 13px;
      padding: 15px 2px; border: 0; border-bottom: 2px solid var(--c);
      border-radius: 0; background: transparent;
      cursor: pointer; text-align: left;
      transition: background 0.16s; -webkit-tap-highlight-color: transparent;
    }
    /* No scale transform: it shifts layout on a row that has no card to move
       inside. A background wash reads as the press instead. */
    .type-btn:active { background: var(--cd); }
    /* The glyph is bare. A tinted rounded square behind every icon was the other
       half of the generic card, and the mark reads better without it. */
    .type-ico {
      width: 32px; height: 32px;
      display: flex; align-items: center; justify-content: center; flex-shrink: 0;
      background: transparent;
    }
    /* The SVG carries width/height attributes from the markup, so the size is
       forced here instead of threading a number through every call site. */
    .type-ico svg { width: 30px; height: 30px; }
    /* The color MUST be stated. Without it the label inherits the UA button
       color, which is pure black in Chrome (invisible on slate) and system blue
       in iOS WKWebView. Neither is a design decision, and the split already
       identifies itself by the rule beneath it and its mark, so the name reads
       as ordinary heading text. */
    .type-lbl { font-family: var(--serif); font-size: 1.32rem; font-weight: 400; letter-spacing: -0.01em; color: var(--text); }
    .type-sub { font-family: var(--serif); font-style: italic; font-size: 0.8rem; color: var(--text-muted); margin-top: 2px; }

    /* ── Active workout ──────────── */
    .wkt-hdr { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding: 14px 16px 0; }
    .wkt-date { font-size: 0.8rem; color: var(--text-muted); }
    .ex-list  { padding: 12px 16px 0; display: flex; flex-direction: column; gap: 12px; }

    /* Exercise card */
    .ex-card { background: var(--bg-card); border-radius: var(--r); border: 1px solid var(--bdr); }
    .ex-card-hdr {
      display: flex; align-items: center; gap: 10px;
      padding: 13px 14px; border-bottom: 1px solid var(--bdr);
    }
    .ex-num {
      width: 24px; height: 24px; border-radius: 50%;
      background: var(--bg-elev); color: var(--text-muted);
      font-size: 0.75rem; font-weight: 700;
      display: flex; align-items: center; justify-content: center; flex-shrink: 0;
    }
    .ex-title { flex: 1; font-size: 1rem; font-weight: 700; }

    /* Previous session */
    .prev { padding: 10px 14px; background: rgba(255,255,255,0.025); border-bottom: 1px solid var(--bdr); }
    .prev-lbl { font-size: 0.65rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 4px; }
    .prev-lbl-row { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; }
    .prev-lbl-row .prev-lbl { margin-bottom: 0; }
    /* Note buttons (write-to-self on an exercise) */
    .ex-note-btn {
      width: 30px; height: 30px; flex-shrink: 0;
      display: flex; align-items: center; justify-content: center;
      background: var(--bg-elev); border: none; border-radius: var(--rs);
      color: var(--text-muted); cursor: pointer; transition: transform 0.12s, background 0.15s, color 0.15s;
      -webkit-tap-highlight-color: transparent;
    }
    .ex-note-btn:active { transform: scale(0.9); }
    .ex-note-btn.has { color: var(--accent); background: var(--accent-t); }
    .prev-lbl-row .ex-note-btn { width: 26px; height: 26px; }
    .prev-date { font-size: 0.75rem; color: var(--text-muted); margin-bottom: 5px; }
    .prev-chips { display: flex; flex-wrap: wrap; gap: 5px; }
    .prev-chip { background: var(--bg-elev); border-radius: 6px; padding: 4px 9px; font-size: 0.78rem; color: var(--text-soft); }
    .prev-chip b { color: var(--text); }

    /* Sets table */
    .sets-wrap { padding: 10px 14px 4px; }
    .sets-hdr {
      display: grid; grid-template-columns: 26px 1fr 1fr 32px 32px;
      gap: 6px; padding-bottom: 6px;
      border-bottom: 1px solid var(--bdr); margin-bottom: 6px;
    }
    .sets-hdr span { font-size: 0.65rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted); text-align: center; }
    .sets-hdr span:first-child { text-align: left; }
    .set-row { display: grid; grid-template-columns: 26px 1fr 1fr 32px 32px; gap: 6px; margin-bottom: 6px; align-items: center; }
    .set-n { font-size: 0.82rem; font-weight: 700; color: var(--text-muted); text-align: center; }
    /* In-row "/" key for per-arm reps, always visible above the keyboard, never hidden */
    .rep-slash {
      height: 44px; width: 100%; border: none; border-radius: var(--rs);
      background: var(--bg-elev); color: var(--accent);
      font-size: 1.2rem; font-weight: 800; line-height: 1; cursor: pointer;
      display: flex; align-items: center; justify-content: center;
      -webkit-tap-highlight-color: transparent; padding: 0;
    }
    .rep-slash:active { background: var(--bg-inp); }
    .set-inp {
      background: var(--bg-inp); border: 1.5px solid transparent;
      border-radius: var(--rs); color: var(--text);
      font-size: 1rem; font-weight: 700; padding: 9px 6px;
      text-align: center; outline: none;
      transition: border-color 0.18s; -webkit-appearance: none;
      min-height: 44px; width: 100%;
    }
    .set-inp:focus { border-color: var(--accent); }
    .set-inp::placeholder { color: var(--text-muted); font-weight: 400; font-size: 0.82rem; }
    input[type=number]::-webkit-inner-spin-button,
    input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; }
    /* Reps cell with a built-in "/" key for per-arm reps (e.g. 7/6 = 7 left, 6 right) */
    .reps-cell { position: relative; display: flex; align-items: center; }
    .reps-cell .set-inp { padding-right: 26px; padding-left: 22px; }
    .slash-key {
      position: absolute; top: 50%; right: 4px; transform: translateY(-50%);
      width: 22px; height: 30px; border-radius: 6px;
      background: var(--bg-elev); border: 1px solid var(--bdr2);
      color: var(--text-soft); font-size: 1rem; font-weight: 800; line-height: 1;
      display: flex; align-items: center; justify-content: center;
      cursor: pointer; -webkit-tap-highlight-color: transparent; flex-shrink: 0;
      transition: background 0.12s, color 0.12s;
    }
    .slash-key:active { background: var(--accent); color: var(--bg); border-color: var(--accent); }
    .set-del {
      width: 36px; height: 36px; background: transparent; border: none;
      color: var(--text-muted); cursor: pointer;
      display: flex; align-items: center; justify-content: center;
      border-radius: var(--rs); transition: all 0.15s; flex-shrink: 0;
    }
    .set-del:active { color: var(--danger); background: var(--danger-t); }
    .ex-foot { padding: 4px 14px 12px; }
    .wkt-actions { padding: 14px 16px 8px; display: flex; flex-direction: column; gap: 8px; }

    /* ── Rest day ────────────────── */
    .rest-note {
      width: 100%; min-height: 130px; resize: none;
      background: var(--bg-inp); border: 1.5px solid transparent;
      border-radius: var(--r); color: var(--text);
      font-size: 1rem; line-height: 1.6; padding: 14px;
      outline: none; transition: border-color 0.18s;
      font-family: inherit; -webkit-appearance: none;
    }
    .rest-note:focus { border-color: var(--rest); }
    .rest-note::placeholder { color: var(--text-muted); }

    /* ── History ─────────────────── */
    .hist-list { padding: 6px 16px 12px; display: flex; flex-direction: column; gap: 8px; }
    .s-card { background: var(--bg-card); border-radius: var(--r); border: 1px solid var(--bdr); cursor: pointer; }
    .s-card-hdr { display: flex; align-items: center; gap: 12px; padding: 14px 16px; }
    .s-info { flex: 1; min-width: 0; }
    .s-info-top { font-size: 0.9rem; font-weight: 700; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
    .s-info-meta { font-size: 0.78rem; color: var(--text-muted); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .s-chev { color: var(--text-muted); transition: transform 0.2s; flex-shrink: 0; }
    .s-chev.open { transform: rotate(180deg); }
    .s-detail { display: none; padding: 0 16px 14px; border-top: 1px solid var(--bdr); }
    .s-detail.open { display: block; }
    .s-ex { margin-top: 11px; }
    .s-ex-name { font-size: 0.85rem; font-weight: 700; color: var(--text-soft); margin-bottom: 5px; }
    .s-sets { display: flex; flex-wrap: wrap; gap: 4px; }
    .s-chip { background: var(--bg-elev); border-radius: 6px; padding: 3px 8px; font-size: 0.75rem; color: var(--text-soft); }

    /* ── Progress ────────────────── */
    .stats-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; padding: 14px 16px 0; }
    .stat-card { background: var(--bg-card); border-radius: var(--r); border: 1px solid var(--bdr); padding: 16px; text-align: center; }
    .stat-val { font-family: var(--serif); font-size: 2.1rem; font-weight: 400; color: var(--text); letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
    .stat-lbl { font-size: 0.72rem; color: var(--text-muted); margin-top: 2px; font-weight: 600; }
    .prog-sec { padding: 14px 16px 0; }
    .prog-sec-lbl { font-size: 0.68rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-muted); margin-bottom: 8px; }
    /* Alert headings pair a drawn glyph with the count. The emoji that used to
       sit here rendered at a different weight and color from everything around
       it, which is exactly what makes emoji-as-icon look unconsidered. */
    .alert-lbl { display: flex; align-items: center; gap: 6px; }
    .alert-lbl svg { flex-shrink: 0; }
    .info-ico { display: flex; align-items: center; justify-content: center; margin-bottom: 10px; color: var(--text-muted); }
    .stall-card { background: var(--bg-card); border-radius: var(--r); border: 1px solid var(--warn-bd); padding: 14px; margin-bottom: 8px; }
    .stall-hdr { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
    .stall-name { font-size: 0.95rem; font-weight: 800; }
    .stall-cmp { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
    .stall-s { background: var(--bg-elev); border-radius: var(--rs); padding: 10px 12px; }
    .stall-s-lbl { font-size: 0.65rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); margin-bottom: 4px; }
    .stall-s-date { font-size: 0.75rem; color: var(--text-muted); margin-bottom: 4px; }
    .stall-s-sets { font-size: 0.8rem; color: var(--text-soft); line-height: 1.5; }
    .stall-note { font-size: 0.72rem; color: var(--warn); margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--warn-bd2); }
    /* Side imbalance deliberately breaks from the amber stall styling. Stacked on
       Progress, two amber-bordered sections read as one continuous block. Purple
       also fits the meaning better: an imbalance is something to look at, not a
       plateau to fix. */
    .bal-card { border-color: var(--bal-bd); }
    .bal-card .stall-note { color: var(--cpurple); border-top-color: var(--bal-bd2); }
    .lib-list { background: var(--bg-card); border-radius: var(--r); border: 1px solid var(--bdr); overflow: hidden; }
    .lib-item { display: flex; align-items: center; justify-content: space-between; padding: 4px 6px 4px 10px; border-bottom: 1px solid var(--bdr); gap: 6px; }
    .lib-item:last-child { border-bottom: none; }
    .lib-name { font-size: 0.88rem; }
    .lib-gym-set { flex: 1; display: flex; align-items: center; gap: 8px; background: none; border: none; color: var(--text); font-family: inherit; text-align: left; padding: 10px 4px; cursor: pointer; touch-action: manipulation; -webkit-tap-highlight-color: rgba(255,255,255,0.08); border-radius: var(--rs); }
    .lib-gym-set:active { background: var(--bg-elev); }
    .lib-del { background: var(--accent-t); border: none; color: var(--accent); cursor: pointer; font-size: 0.78rem; font-weight: 700; padding: 0 16px; height: 44px; border-radius: var(--rs); flex-shrink: 0; font-family: inherit; touch-action: manipulation; -webkit-tap-highlight-color: var(--accent-t2); }
    .lib-del:active { background: var(--accent-t2); }

    /* ── Modals / Sheets ─────────── */
    .overlay {
      position: fixed; inset: 0; background: rgba(0,0,0,0.72);
      z-index: 200; display: flex; align-items: flex-end;
      opacity: 0; pointer-events: none;
      transition: opacity 0.22s;
      backdrop-filter: blur(5px); -webkit-backdrop-filter: blur(5px);
    }
    .overlay.on { opacity: 1; pointer-events: all; }
    .sheet {
      background: var(--bg-card);
      border-radius: var(--r) var(--r) 0 0;
      padding: 20px 18px;
      padding-bottom: calc(20px + var(--safe-b));
      width: 100%; max-width: 480px; margin: 0 auto;
      transform: translateY(100%);
      transition: transform 0.28s cubic-bezier(0.34,1.4,0.64,1);
      border-top: 1px solid var(--bdr);
      max-height: 85vh; overflow-y: auto;
    }
    .overlay.on .sheet { transform: translateY(0); }
    .sheet-handle { width: 38px; height: 4px; background: var(--bdr2); border-radius: 2px; margin: -4px auto 18px; }
    .sheet-title  { font-size: 1.05rem; font-weight: 800; margin-bottom: 14px; }

    /* Centered dialog variant. Used for the one-time Announce Notifications
       prompt, which should read as a proper alert in the middle of the screen
       rather than a bottom sheet the lifter might mistake for a menu. */
    .overlay.centered { align-items: center; padding: 20px; }
    .overlay.centered .sheet {
      border-radius: var(--r);
      width: 100%; max-width: 400px;
      padding-bottom: 20px;
      transform: translateY(0) scale(0.94);
      opacity: 0;
      transition: transform 0.24s cubic-bezier(0.34,1.4,0.64,1), opacity 0.18s;
      border: 1px solid var(--bdr);
      max-height: calc(100vh - 40px);
    }
    .overlay.centered.on .sheet { transform: translateY(0) scale(1); opacity: 1; }

    /* Split editor rows */
    .split-row { display: flex; align-items: flex-start; gap: 10px; padding: 10px; background: var(--bg-elev); border-radius: var(--rs); margin-bottom: 8px; }
    .split-color { width: 34px; height: 34px; border-radius: 10px; border: none; flex-shrink: 0; cursor: pointer; margin-top: 2px; -webkit-tap-highlight-color: transparent; }
    .split-color:active { transform: scale(0.92); }
    .split-fields { flex: 1; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
    .split-fields .input { padding: 9px 11px; font-size: 0.9rem; }
    /* Rest: same swatch and layout as an editable split, but the name is static
       text rather than an input, and there is no delete control. The dotted rule
       above it separates "your splits" from "the box that is always there". */
    .split-row-fixed { border-top: 1px dashed var(--bdr2); border-radius: 0 0 var(--rs) var(--rs); margin-top: 2px; align-items: center; }
    .split-fixed-name { font-family: var(--serif); font-size: 0.95rem; font-weight: 700; color: var(--text); }
    .split-fixed-sub  { font-size: 0.74rem; color: var(--text-muted); margin-top: 2px; }

    /* ── Split color picker ─────── */
    /* Presets first, because most people want one of these and should not have
       to aim at a gradient to get a color the app already uses. */
    .cp-presets { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; }
    .cp-swatch {
      aspect-ratio: 1; border-radius: 50%; border: 2px solid transparent;
      cursor: pointer; padding: 0; -webkit-tap-highlight-color: transparent;
      box-shadow: inset 0 0 0 1px var(--bdr);
    }
    .cp-swatch:active { transform: scale(0.9); }
    /* The ring sits OUTSIDE the swatch (offset), so selection never changes the
       size of the color you are judging. */
    .cp-swatch.on { border-color: var(--accent); outline: 2px solid var(--bg); outline-offset: -4px; }
    .cp-custom-lbl {
      font-size: 0.68rem; font-weight: 800; text-transform: uppercase;
      letter-spacing: 0.1em; color: var(--text-muted); margin: 18px 0 8px;
    }
    /* Saturation runs left to right over the hue, brightness runs top to bottom
       over black. Two stacked gradients is the whole picker: no canvas, no
       image, nothing to load, and it stays sharp at any size. */
    .cp-field {
      position: relative; width: 100%; height: 150px; border-radius: var(--rs);
      background:
        linear-gradient(to top, #000, rgba(0,0,0,0)),
        linear-gradient(to right, #fff, var(--cp-hue, #E8503A));
      border: 1px solid var(--bdr);
      touch-action: none; cursor: crosshair;
    }
    .cp-hue {
      position: relative; width: 100%; height: 26px; margin-top: 12px;
      border-radius: 100px; border: 1px solid var(--bdr);
      background: linear-gradient(to right,
        #f00 0%, #ff0 16.66%, #0f0 33.33%, #0ff 50%, #00f 66.66%, #f0f 83.33%, #f00 100%);
      touch-action: none; cursor: pointer;
    }
    /* One handle style for both surfaces. The white ring plus the dark outline
       keeps it visible over a pure white corner and a pure black one alike. */
    .cp-handle {
      position: absolute; width: 22px; height: 22px; border-radius: 50%;
      border: 3px solid #fff; box-shadow: 0 0 0 1px rgba(0,0,0,0.55), 0 1px 4px rgba(0,0,0,0.4);
      transform: translate(-50%, -50%); pointer-events: none;
    }
    .cp-handle-hue { top: 50%; }
    .cp-foot { display: flex; align-items: center; gap: 12px; margin-top: 14px; }
    .cp-preview {
      width: 44px; height: 44px; border-radius: var(--rs);
      box-shadow: inset 0 0 0 1px var(--bdr); flex-shrink: 0;
    }
    .cp-hexlbl {
      font-family: var(--serif-num); font-size: 1rem; letter-spacing: 0.06em;
      color: var(--text-soft); font-variant-numeric: tabular-nums;
    }
    .split-sub-inp { font-size: 0.82rem !important; }
    .split-del { width: 34px; height: 34px; flex-shrink: 0; background: var(--danger-t); color: var(--danger); border: none; border-radius: 10px; font-size: 1.3rem; line-height: 1; cursor: pointer; margin-top: 2px; -webkit-tap-highlight-color: transparent; }
    .split-del:active { background: var(--danger-t2); }

    /* Exercise suggestions */
    .ex-sugg { background: var(--bg-elev); border-radius: var(--rs); margin-top: 8px; max-height: 220px; overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
    .sugg-item {
      display: block; width: 100%; text-align: left; background: transparent; border: none;
      padding: 14px 15px; cursor: pointer; font-size: 0.92rem; color: var(--text-soft);
      border-bottom: 1px solid var(--bdr); transition: background 0.12s;
      font-family: inherit; touch-action: manipulation; -webkit-tap-highlight-color: rgba(255,255,255,0.08);
      min-height: 48px;
    }
    .sugg-item:last-child { border-bottom: none; }
    .sugg-item:active { background: var(--bg-card); }
    .sugg-new { color: var(--accent); font-weight: 700; }

    /* ── Templates ───────────────── */
    .tmpl-item {
      display: flex; align-items: center; gap: 12px;
      width: 100%; text-align: left; background: var(--bg-elev);
      border: 1px solid var(--bdr); border-radius: var(--rs);
      padding: 14px 15px; cursor: pointer; margin-bottom: 8px;
      touch-action: manipulation; font-family: inherit;
      transition: background 0.15s; -webkit-tap-highlight-color: rgba(255,255,255,0.08);
    }
    .tmpl-item:active { background: var(--bg-inp); }
    .tmpl-info { flex: 1; min-width: 0; }
    .tmpl-name { font-size: 0.95rem; font-weight: 800; margin-bottom: 5px; }
    .tmpl-meta { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; flex-wrap: wrap; }
    .tmpl-exs { font-size: 0.75rem; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .load-tmpl-btn {
      width: 100%; padding: 16px; border-radius: var(--r);
      background: var(--bg-elev); border: 1.5px dashed var(--bdr2);
      color: var(--text-soft); font-size: 0.92rem; font-weight: 700;
      cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 8px;
      touch-action: manipulation; font-family: inherit;
      transition: all 0.15s; -webkit-tap-highlight-color: rgba(255,255,255,0.08);
      min-height: 52px;
    }
    .load-tmpl-btn:active { background: var(--bg-inp); border-color: var(--accent); color: var(--accent); }

    /* Gym location list */
    .gym-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
    .gym-item-row { display: flex; align-items: center; gap: 8px; }
    .gym-item {
      flex: 1; display: flex; align-items: center; gap: 12px;
      padding: 13px 15px; border-radius: var(--rs);
      background: var(--bg-elev); cursor: pointer;
      transition: background 0.15s; border: 1px solid transparent;
      font-family: inherit; text-align: left; color: var(--text);
      touch-action: manipulation; -webkit-tap-highlight-color: rgba(255,255,255,0.08);
    }
    .gym-item:active { background: var(--bg-inp); }
    .gym-item.on { background: var(--accent-t); border: 1px solid var(--accent-bd); }
    .gym-item-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-muted); flex-shrink: 0; }
    .gym-item.on .gym-item-dot { background: var(--accent); }
    .gym-item-name { flex: 1; font-size: 0.92rem; font-weight: 700; }
    .gym-item.on .gym-item-name { color: var(--accent); }
    .gym-item-del {
      background: var(--accent-t); border: none; color: var(--accent);
      cursor: pointer; font-size: 0.8rem; font-weight: 700; border-radius: var(--rs);
      flex-shrink: 0; width: 52px; height: 52px; display: flex; align-items: center;
      justify-content: center; font-family: inherit;
      touch-action: manipulation; -webkit-tap-highlight-color: var(--accent-t2);
    }
    .gym-item-del:active { background: var(--accent-t2); }

    /* ── Toast ───────────────────── */
    #toast {
      position: fixed;
      bottom: calc(var(--nav-h) + var(--safe-b) + 12px);
      left: 50%; transform: translateX(-50%) translateY(12px);
      background: var(--bg-elev); border: 1px solid var(--bdr2);
      color: var(--text); padding: 11px 20px; border-radius: 50px;
      font-size: 0.85rem; font-weight: 700; z-index: 500;
      opacity: 0; transition: opacity 0.18s, transform 0.18s;
      white-space: nowrap; pointer-events: none;
      max-width: calc(100% - 32px);
    }
    #toast.on { opacity: 1; transform: translateX(-50%) translateY(0); }

    /* ── Confirm dialog ──────────── */
    .conf-ov {
      position: fixed; inset: 0; background: rgba(0,0,0,0.82);
      z-index: 600; display: flex; align-items: center;
      justify-content: center; padding: 24px;
      backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
    }
    .conf-box { background: var(--bg-card); border-radius: var(--r); border: 1px solid var(--bdr); padding: 24px; width: 100%; max-width: 300px; }
    .conf-t   { font-size: 1.05rem; font-weight: 800; margin-bottom: 8px; }
    .conf-txt { font-size: 0.85rem; color: var(--text-soft); margin-bottom: 20px; line-height: 1.5; }
    .conf-acts { display: flex; gap: 10px; }
    .conf-acts .btn { flex: 1; }

    /* ── Celebration (post-workout) ── */
    .cel-ov {
      position: fixed; inset: 0; background: rgba(0,0,0,0.82);
      z-index: 650; display: flex; align-items: center; justify-content: center;
      padding: 24px; backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
      opacity: 0; transition: opacity 0.22s;
    }
    .cel-ov.on { opacity: 1; }
    .cel-box {
      background: var(--bg-card); border: 1px solid var(--bdr2);
      border-radius: 20px; padding: 28px 24px 24px; width: 100%; max-width: 330px;
      text-align: center; transform: scale(0.9); transition: transform 0.3s cubic-bezier(0.34,1.5,0.64,1);
    }
    .cel-ov.on .cel-box { transform: scale(1); }
    .cel-icon { margin-bottom: 12px; display: flex; justify-content: center; color: var(--warn); }
    .cel-title { font-size: 1.35rem; font-weight: 900; letter-spacing: -0.02em; margin-bottom: 8px; }
    .cel-msg { font-size: 0.88rem; color: var(--text-soft); line-height: 1.55; margin-bottom: 16px; }
    .cel-stats { display: flex; gap: 6px; margin-bottom: 16px; }
    .cel-stat { flex: 1; background: var(--bg-elev); border-radius: var(--rs); padding: 12px 6px; }
    /* Takes --warn, matching the trophy in .cel-icon directly above it. This was
       a literal #F5A623 (a stock orange that predates Slate), which does not
       restage for light mode: on --bg-elev it measured 1.59:1, failing even the
       3:1 large-text bar, and it read as a different hue from the trophy on the
       same card. Same bug class as the old `color:#fff on --accent`: a literal
       cannot invert with the theme, so a filled or colored value here must be a
       token, never a hex. */
    .cel-stat-v { font-size: 1.35rem; font-weight: 900; color: var(--warn); letter-spacing: -0.03em; line-height: 1; font-variant-numeric: tabular-nums; }
    .cel-stat-l { font-size: 0.62rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); margin-top: 5px; }
    .cel-pr {
      display: flex; align-items: center; gap: 8px; text-align: left;
      background: var(--camber-d); border: 1px solid var(--camber-bd);
      border-radius: var(--rs); padding: 11px 13px; margin-bottom: 16px;
    }
    .cel-pr svg { color: var(--camber); flex-shrink: 0; }
    .cel-pr-txt { font-size: 0.8rem; color: var(--text); line-height: 1.4; font-weight: 600; }
    .cel-pr-txt b { color: var(--camber); }

    /* ── Misc ────────────────────── */
    .sh { padding: 18px 16px 10px; }
    /* Screen headings carry the serif at a size where it can actually be seen.
       This is the one place the direction announces itself on every tab. */
    .sh-title { font-family: var(--serif); font-size: 1.85rem; font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; }
    .sh-sub   { font-size: 0.82rem; color: var(--text-muted); margin-top: 5px; }
    .log-date-row { position:relative; display:inline-flex; align-items:center; gap:5px; margin-top:5px; font-size:0.82rem; color:var(--accent); font-weight:600; cursor:pointer; background:none; border:none; font-family:inherit; padding:4px 0; -webkit-tap-highlight-color:transparent; }
    .log-date-row:active { opacity:0.7; }
    .empty { text-align: center; padding: 56px 24px; }
    .empty-ico { margin-bottom: 14px; display: flex; justify-content: center; color: var(--text-muted); }
    .empty-t { font-size: 1.05rem; font-weight: 800; margin-bottom: 7px; }
    .empty-s { font-size: 0.84rem; color: var(--text-muted); line-height: 1.55; }
    .info-card { background: var(--bg-card); border-radius: var(--r); border: 1px solid var(--bdr); padding: 20px; text-align: center; }
    .info-ico  { font-size: 1.6rem; margin-bottom: 9px; }
    .info-t    { font-weight: 800; margin-bottom: 5px; }
    .info-s    { font-size: 0.82rem; color: var(--text-muted); line-height: 1.5; }
    .recent { padding: 0 16px 20px; }
    .recent-lbl { font-size: 0.68rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-muted); margin-bottom: 8px; padding-top: 4px; }
    .recent-item { display: flex; align-items: center; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--bdr); }
    .recent-item:last-child { border-bottom: none; }
    .recent-info { flex: 1; font-size: 0.85rem; }

    /* ── View toggle ─────────────── */
    .view-toggle { display: flex; gap: 3px; background: var(--bg-elev); border-radius: var(--rs); padding: 3px; margin: 12px 16px 0; }
    .view-btn { flex: 1; padding: 8px; border: none; border-radius: 6px; font-size: 0.82rem; font-weight: 700; cursor: pointer; color: var(--text-muted); background: transparent; transition: all 0.15s; }
    .view-btn.on { background: var(--bg-card); color: var(--text); }

    /* ── Calendar ────────────────── */
    .cal-wrap { padding: 10px 12px 8px; }
    .cal-nav { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; }
    .cal-title { flex: 1; font-size: 1.05rem; font-weight: 800; text-align: center; letter-spacing: -0.01em; }
    .cal-nav-btn { background: var(--bg-elev); border: none; color: var(--text); cursor: pointer; border-radius: var(--rs); padding: 7px 10px; min-height: 36px; display: flex; align-items: center; justify-content: center; }
    .cal-today-btn { font-size: 0.78rem; font-weight: 700; padding: 7px 12px; color: var(--accent); }
    .cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); }
    .cal-dow { text-align: center; font-size: 0.7rem; font-weight: 700; color: var(--text-muted); padding: 2px 0 8px; }
    .cal-cell { display: flex; flex-direction: column; align-items: center; padding: 3px 1px; min-height: 50px; }
    .cal-cell.other .cal-day-n { color: var(--text-muted); opacity: 0.35; }
    .cal-cell.tappable { cursor: pointer; border-radius: var(--rs); touch-action: manipulation; -webkit-tap-highlight-color: rgba(255,255,255,0.06); }
    .cal-cell.tappable:active { background: var(--bg-elev); }
    .day-actions { display: flex; gap: 8px; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--bdr); }
    .day-act-btn { flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px; height: 44px; border-radius: var(--rs); border: 1px solid var(--bdr2); background: var(--bg-elev); color: var(--text); font-family: inherit; font-size: 0.85rem; font-weight: 700; cursor: pointer; touch-action: manipulation; -webkit-tap-highlight-color: rgba(255,255,255,0.08); }
    .day-act-btn:active { background: var(--bg-inp); }
    .day-act-btn.danger { color: var(--accent); border-color: var(--accent-bd); background: var(--accent-t); }
    .day-act-btn.danger:active { background: var(--accent-t2); }
    .cal-day-n {
      font-family: var(--serif); font-variant-numeric: tabular-nums;
      font-size: 0.95rem; font-weight: 400; color: var(--text-soft);
      width: 30px; height: 30px;
      display: flex; align-items: center; justify-content: center;
      border-radius: 50%; position: relative; z-index: 1;
      transition: background 0.15s;
    }
    .cal-cell.is-today .cal-day-n { box-shadow: 0 0 0 2px var(--accent); }
    .cal-cell.is-today:not(.has-sess) .cal-day-n { color: var(--accent); font-weight: 800; }
    .cal-dots { display: flex; gap: 3px; margin-top: 2px; justify-content: center; flex-wrap: wrap; max-width: 32px; }
    .cal-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
    .cal-legend { display: flex; gap: 14px; justify-content: center; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--bdr); flex-wrap: wrap; }
    .cal-leg-item { display: flex; align-items: center; gap: 5px; font-size: 0.73rem; color: var(--text-muted); }
    .cal-leg-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }

    /* ── Exercise progression picker ── */
    .ex-picker-wrap {
      position: relative; height: 220px; overflow: hidden;
    }
    .ex-picker-scroll {
      height: 100%; overflow-y: scroll; scroll-snap-type: y mandatory;
      -webkit-overflow-scrolling: touch; padding: 88px 0;
      scrollbar-width: none; box-sizing: border-box;
    }
    .ex-picker-scroll::-webkit-scrollbar { display: none; }
    .ex-picker-item {
      height: 44px; scroll-snap-align: center;
      display: flex; align-items: center; justify-content: center;
      font-size: 0.93rem; color: var(--text-muted); cursor: pointer;
      transition: color 0.12s, font-size 0.12s, font-weight 0.12s;
      padding: 0 20px; text-align: center;
      touch-action: manipulation; -webkit-tap-highlight-color: transparent;
    }
    .ex-picker-item.sel { color: var(--text); font-size: 1.05rem; font-weight: 600; }
    .ex-picker-wrap::before, .ex-picker-wrap::after {
      content: ''; position: absolute; left: 0; right: 0;
      height: 88px; pointer-events: none; z-index: 1;
    }
    .ex-picker-wrap::before { top: 0; background: linear-gradient(to bottom, var(--bg-elev) 20%, transparent); }
    .ex-picker-wrap::after  { bottom: 0; background: linear-gradient(to top, var(--bg-elev) 20%, transparent); }
    .ex-picker-sel-line {
      position: absolute; top: 88px; left: 16px; right: 16px; height: 44px;
      border-top: 1px solid var(--bdr); border-bottom: 1px solid var(--bdr);
      pointer-events: none; z-index: 2;
    }

    /* ── Progression chart: range chips, pinned axis, scrolling plot ── */
    .exr-row {
      display: flex; gap: 6px; padding-bottom: 10px;
      overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
    }
    .exr-row::-webkit-scrollbar { display: none; }
    .exr-chip {
      flex-shrink: 0; border: 1px solid var(--bdr2); background: var(--bg-elev);
      color: var(--text-soft); font: inherit; font-size: 0.72rem; font-weight: 700;
      padding: 6px 13px; border-radius: 999px; cursor: pointer;
      transition: background-color 0.15s, color 0.15s, border-color 0.15s;
      touch-action: manipulation; -webkit-tap-highlight-color: transparent;
    }
    .exr-chip.on { background: var(--accent); border-color: var(--accent); color: var(--bg); }

    /* The axis sits outside the scroller, so the weight scale holds still
       while the line scrolls under it. min-width:0 keeps the plot's intrinsic
       width from widening the card and scrolling the whole page sideways. */
    .exc-wrap { display: flex; align-items: flex-start; min-width: 0; }
    .exax { flex-shrink: 0; }
    .exc-scroll {
      flex: 1; min-width: 0; overflow-x: auto; overflow-y: hidden;
      -webkit-overflow-scrolling: touch; scrollbar-width: none;
      overscroll-behavior-x: contain;
    }
    .exc-scroll::-webkit-scrollbar { display: none; }
    .exhit { cursor: pointer; -webkit-tap-highlight-color: transparent; }

    .expt {
      text-align: center; margin-top: 8px; padding: 10px 8px 0;
      border-top: 1px solid var(--bdr);
    }
    .expt-d { font-size: 0.7rem; color: var(--text-muted); }
    .expt-w { font-family: var(--serif); font-size: 1.6rem; font-weight: 400; color: var(--text); margin-top: 2px; font-variant-numeric: tabular-nums; }
    .expt-w span { color: var(--text-muted); font-weight: 400; font-size: 1.1rem; }
    .expt-n { font-size: 0.72rem; color: var(--text-muted); margin-top: 3px; }
    .ex-foot { text-align: center; font-size: 0.75rem; color: var(--text-muted); margin-top: 6px; padding-bottom: 2px; }
    .ex-empty { text-align: center; color: var(--text-muted); font-size: 0.85rem; padding: 24px 8px; line-height: 1.6; }
    .ex-one { text-align: center; padding: 22px 8px; }
    .ex-one-w { font-size: 1.3rem; font-weight: 700; color: var(--text); margin-bottom: 4px; }
    .ex-one-w span { color: var(--text-muted); font-weight: 600; font-size: 1rem; }
    .ex-one-s { font-size: 0.8rem; color: var(--text-muted); line-height: 1.55; }

    /* ── Stopwatch ──────────────── */
    .clock-wrap {
      display: flex; flex-direction: column; align-items: center; justify-content: center;
      gap: 52px; padding: 24px;
      min-height: calc(100dvh - var(--hdr-h) - var(--nav-h) - var(--safe-b) - var(--safe-t));
    }
    /* The one screen where a single number owns everything, so the serif gets
       to be the whole design. This uses --serif-num, not --serif: these digits
       change ten times a second, and Georgia cannot hold a fixed advance (see
       the token). Negative letter-spacing is dropped too, because it reintroduces
       sub-pixel drift on a counter that must not move at all. */
    .clock-time {
      font-family: var(--serif-num);
      font-size: 4.6rem; font-weight: 400; letter-spacing: 0;
      font-variant-numeric: tabular-nums lining-nums; color: var(--text); line-height: 1;
      font-feature-settings: "tnum" 1, "lnum" 1;
    }
    .clock-btns { display: flex; gap: 28px; }
    .clock-btn {
      width: 90px; height: 90px; border-radius: 50%;
      font-size: 1rem; font-weight: 700; cursor: pointer; border: none;
      display: flex; align-items: center; justify-content: center;
      font-family: inherit; touch-action: manipulation;
      -webkit-tap-highlight-color: transparent;
      transition: opacity 0.12s, transform 0.1s;
    }
    .clock-btn:active { opacity: 0.75; transform: scale(0.94); }
    .clock-btn-action { background: var(--ok-t); color: var(--ok); font-size: 1.05rem; }
    .clock-btn-action.running { background: var(--accent-t); color: var(--accent); }
    .clock-btn-reset { background: var(--bg-elev); color: var(--text-soft); }

    /* ── Timer (countdown) ──────── */
    .clock-modes { margin: 12px 16px 0; }
    .clock-wrap { min-height: calc(100dvh - var(--hdr-h) - var(--nav-h) - var(--safe-b) - var(--safe-t) - 56px); }
    /* iOS-style scroll-wheel picker (minutes + 15-second steps) */
    .wheel-picker {
      position: relative; display: flex; align-items: center; justify-content: center;
      gap: 4px; height: 220px;
    }
    .wheel-band {
      position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
      width: 230px; height: 44px; border-radius: 10px; background: var(--bg-elev);
      pointer-events: none; z-index: 0;
    }
    .wheel {
      position: relative; z-index: 1; height: 220px; width: 92px; overflow-y: scroll;
      scroll-snap-type: y mandatory; -webkit-overflow-scrolling: touch;
      scrollbar-width: none; text-align: center;
      -webkit-mask-image: linear-gradient(transparent, #000 32%, #000 68%, transparent);
              mask-image: linear-gradient(transparent, #000 32%, #000 68%, transparent);
    }
    .wheel::-webkit-scrollbar { display: none; }
    .wheel-pad { height: 88px; }            /* (220 - 44) / 2 so first/last item can center */
    .wheel-item {
      height: 44px; display: flex; align-items: center; justify-content: center;
      scroll-snap-align: center; font-size: 2rem; font-weight: 500;
      font-variant-numeric: tabular-nums; color: var(--text); line-height: 1;
    }
    .wheel-unit {
      position: relative; z-index: 2; font-size: 0.95rem; font-weight: 700;
      color: var(--text-soft); margin: 0 2px;
    }
    .timer-presets {
      display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; max-width: 300px;
    }
    .timer-chip {
      padding: 8px 16px; border-radius: 100px; border: 1px solid var(--bdr);
      background: transparent; color: var(--text-muted);
      font-size: 1rem; font-weight: 400; font-family: var(--serif); cursor: pointer;
      font-variant-numeric: tabular-nums; touch-action: manipulation;
      -webkit-tap-highlight-color: transparent; transition: opacity 0.12s, transform 0.1s;
    }
    /* The ten rest lengths are a fixed, known set, so they get an explicit
       5-column grid rather than being left to wrap. Flex-wrap stranded 5:00
       alone on a third row, which read as a mistake; a grid also keeps every
       chip the same width, so the values line up as a table of durations. */
    .rest-lengths {
      display: grid; grid-template-columns: repeat(5, 1fr);
      gap: 8px; margin: 0; max-width: none;
    }
    .rest-lengths .timer-chip { padding: 8px 4px; text-align: center; }
    .timer-chip:active { opacity: 0.7; transform: scale(0.95); }
    /* The selected rest length fills solid rather than tinting, so it survives a
       glance mid-set with a bar in your hands. */
    .timer-chip.on { background: var(--accent); color: var(--bg); border-color: var(--accent); font-weight: 700; }
    .clock-time.timer-done { color: var(--accent); animation: timerPulse 0.9s ease-in-out infinite; }
    .timer-done-lbl { font-size: 1rem; font-weight: 800; letter-spacing: 0.04em; color: var(--accent); text-transform: uppercase; }
    @keyframes timerPulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
    @media (prefers-reduced-motion: reduce) { .clock-time.timer-done { animation: none; } }

    /* ── Trial banner & paywall lock ── */
    /* A ruled notice, not a tinted pill. It sits above the heading and must not
       compete with it, so it carries a top rule and no fill. Urgent is the one
       state allowed to pull real color, since by then it is the point. */
    .trial-banner {
      display: flex; align-items: center; justify-content: space-between; gap: 8px;
      margin: 12px 16px 0; padding: 9px 0 10px; border-radius: 0;
      background: transparent; border: 0; border-top: 1px solid var(--bdr2);
      font-size: 0.78rem; font-weight: 600; color: var(--text-soft);
    }
    .trial-banner .trial-days { font-family: var(--serif); font-weight: 400; font-size: 0.88rem; }
    .trial-banner.urgent { border-top-color: var(--accent-bd); color: var(--danger); }
    .trial-banner.urgent .trial-days { color: var(--danger); }
    /* The price carries both products, so it must never be the thing that
       truncates. The day count wraps instead when the row runs out of room. */
    .trial-banner .trial-days { min-width: 0; }
    .trial-banner .trial-price { font-weight: 600; opacity: 0.75; font-size: 0.72rem; white-space: nowrap; flex-shrink: 0; }
    .lock-screen {
      display: flex; flex-direction: column; align-items: center; text-align: center;
      max-width: 360px; margin: 0 auto; padding: 32px 28px;
      min-height: calc(100dvh - var(--hdr-h) - var(--safe-b) - var(--safe-t));
      justify-content: center; gap: 0;
    }
    /* The mark carries its own dark ground, so the radius here just rounds the
       corners of that square. Kept larger than --r because an app icon reads as
       an icon, not as a card. */
    .lock-logo { width: 76px; height: 76px; border-radius: 17px; margin-bottom: 24px; }
    .lock-title { font-family: var(--serif); font-size: 1.95rem; font-weight: 400; letter-spacing: -0.02em; color: var(--text); margin-bottom: 10px; line-height: 1.12; }
    .lock-sub { font-size: 0.92rem; line-height: 1.55; color: var(--text-soft); margin-bottom: 22px; }
    .lock-price { display: flex; flex-direction: column; align-items: center; margin-bottom: 20px; }
    .lock-amt { font-family: var(--serif); font-size: 2.8rem; font-weight: 400; letter-spacing: -0.03em; color: var(--gold); line-height: 1; font-variant-numeric: tabular-nums; }
    .lock-once { font-size: 0.78rem; color: var(--text-muted); margin-top: 4px; font-weight: 600; }
    .lock-list { list-style: none; text-align: left; margin-bottom: 26px; width: 100%; max-width: 260px; padding: 0; }
    .lock-list li {
      position: relative; font-size: 0.9rem; color: var(--text-soft); padding: 7px 0 7px 24px; font-weight: 500;
    }
    .lock-list li::before {
      content: ''; position: absolute; left: 4px; top: 50%; transform: translateY(-50%);
      width: 7px; height: 7px; border-radius: 50%; background: var(--gold);
    }
    /* Bullets in the cloud-sync offer sheet. Same dot as the paywall list, at the
       smaller size the sheet's supporting copy uses. Hanging indent keeps a
       wrapped line aligned under the first word rather than under the dot. */
    .sync-list { list-style: none; margin: 0; padding: 0; }
    .sync-list li {
      position: relative; font-size: 0.78rem; color: var(--text-soft);
      line-height: 1.55; padding: 4px 0 4px 16px;
    }
    .sync-list li::before {
      content: ''; position: absolute; left: 2px; top: 0.72em;
      width: 5px; height: 5px; border-radius: 50%; background: var(--gold);
    }
    /* Plan cards (paywall) */
    .lock-plans {
      display: flex; gap: 12px; width: 100%; margin-bottom: 20px;
    }
    .lock-plan {
      flex: 1; display: flex; flex-direction: column; align-items: center;
      gap: 4px; padding: 16px 10px; border-radius: var(--r); cursor: pointer;
      /* Was var(--bg2), which is not defined anywhere and resolved to nothing,
         so these cards had no background at all. */
      border: 1.5px solid var(--bdr2); background: var(--bg-card);
      font-family: inherit; transition: border-color 0.15s, background 0.15s;
      position: relative; -webkit-tap-highlight-color: transparent;
    }
    .lock-plan:active { opacity: 0.8; }
    /* Gold marks the better deal. It is the one hue in the app reserved for
       "this is the good one", which is exactly what a featured plan is. */
    .lock-plan-featured {
      border-color: var(--gold); background: var(--gold-d);
    }
    /* color takes --bg, never a literal. It was #1A1D1C, which happened to match
       --bg in dark and so looked correct, but could not invert on paper. Same
       class as the old `color:#fff on --accent` and the #F5A623 in .cel-stat-v:
       ANY color in a themed rule must be a token. Dark is unchanged at 7.55:1;
       light goes 3.84 to 3.91, still short of 4.5 for 10.4px, and that is
       accepted rather than fixed: the only lever left is darkening --gold, which
       also carries the logo and the personal-best meaning, so it is not worth
       moving for a decorative ribbon. */
    .lock-plan-badge {
      position: absolute; top: -10px; left: 50%; transform: translateX(-50%);
      background: var(--gold); color: var(--bg); font-size: 0.65rem; font-weight: 800;
      letter-spacing: 0.04em; padding: 2px 10px; border-radius: 99px;
      white-space: nowrap; text-transform: uppercase;
    }
    .lock-plan-name { font-size: 0.72rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.08em; }
    .lock-plan-price { font-family: var(--serif); font-size: 1.7rem; font-weight: 400; color: var(--text); letter-spacing: -0.02em; line-height: 1.1; font-variant-numeric: tabular-nums; }
    .lock-plan-price span { font-family: -apple-system, BlinkMacSystemFont, sans-serif; font-size: 0.72rem; font-weight: 600; color: var(--text-muted); }
    .lock-plan-note { font-size: 0.68rem; color: var(--text-muted); font-weight: 600; }
    .lock-plan-featured .lock-plan-price { color: var(--gold); }
    .lock-plan-featured .lock-plan-price span { color: var(--gold); opacity: 0.75; }
    .lock-plan-featured .lock-plan-note { color: var(--gold); opacity: 0.85; }
    .lock-export {
      background: none; border: none; color: var(--text-muted); font-size: 0.82rem; font-weight: 600;
      font-family: inherit; cursor: pointer; text-decoration: underline; text-underline-offset: 3px;
      -webkit-tap-highlight-color: transparent;
    }
    .lock-restore {
      background: none; border: none; color: var(--gold); font-size: 0.88rem; font-weight: 700;
      font-family: inherit; cursor: pointer; margin-bottom: 16px; padding: 6px 4px;
      -webkit-tap-highlight-color: transparent;
    }
    .lock-restore:active { opacity: 0.7; }
    .lock-legal {
      font-size: 0.7rem; line-height: 1.5; color: var(--text-muted);
      text-align: center; max-width: 320px; margin-bottom: 10px;
    }
    .lock-legal-links {
      display: flex; align-items: center; justify-content: center; gap: 8px;
      margin-bottom: 18px; font-size: 0.76rem;
    }
    .lock-legal-links a { color: var(--text-soft); text-decoration: underline; text-underline-offset: 2px; }
    .lock-legal-links span { color: var(--text-muted); }
    /* Subscription-check loading spinner */
    .billing-spin {
      width: 30px; height: 30px; margin-top: 22px; border-radius: 50%;
      border: 2px solid var(--bdr2); border-top-color: var(--accent);
      animation: billingSpin 0.8s linear infinite;
    }
    @keyframes billingSpin { to { transform: rotate(360deg); } }
    @media (prefers-reduced-motion: reduce) { .billing-spin { animation-duration: 2s; } }

    /* ── 1-Rep Max calculator ──── */
    .orm-card { background: var(--bg-card); border: 1px solid var(--bdr); border-radius: var(--r); padding: 16px; }
    .orm-inputs { display: flex; align-items: flex-start; justify-content: center; gap: 12px; }
    .orm-field { display: flex; flex-direction: column; align-items: center; gap: 6px; flex: 1; max-width: 130px; }
    .orm-input {
      width: 100%; padding: 12px 8px; text-align: center;
      font-size: 1.8rem; font-weight: 700; font-variant-numeric: tabular-nums;
      color: var(--text); background: var(--bg-inp); border: none; border-radius: var(--rs);
      font-family: inherit; -webkit-appearance: none; -moz-appearance: textfield;
    }
    .orm-input::-webkit-outer-spin-button, .orm-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
    .orm-input:focus { outline: 2px solid var(--nav-on); }
    .orm-unit { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); }
    .orm-x { font-size: 1.3rem; color: var(--text-muted); font-weight: 300; margin-top: 12px; }
    .orm-empty { text-align: center; font-size: 0.82rem; color: var(--text-muted); padding: 16px 8px 6px; line-height: 1.5; }
    .orm-result { text-align: center; padding: 16px 0 6px; }
    .orm-big { font-size: 2.6rem; font-weight: 800; letter-spacing: -0.03em; color: var(--nav-on); line-height: 1; }
    .orm-big span { font-size: 1.1rem; font-weight: 700; }
    .orm-big-lbl { font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); margin-top: 6px; }
    .orm-caveat { text-align: center; font-size: 0.72rem; color: var(--warn); margin: 8px 0 0; }
    .orm-table { margin-top: 14px; border-top: 1px solid var(--bdr); }
    .orm-row { display: grid; grid-template-columns: 1fr 1fr 1fr; align-items: center; padding: 9px 4px; font-size: 0.86rem; font-variant-numeric: tabular-nums; border-bottom: 1px solid var(--bdr); }
    .orm-row:last-child { border-bottom: none; }
    .orm-row .orm-pct { text-align: center; color: var(--text-muted); }
    .orm-row .orm-wt { text-align: right; font-weight: 700; color: var(--text); }
    .orm-head { font-size: 0.66rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); }
    .orm-head .orm-wt { color: var(--text-muted); font-weight: 800; }

    @media (min-width: 480px) {
      #app { border-left: 1px solid var(--bdr); border-right: 1px solid var(--bdr); }
    }
