:root{
  /* THE WHITE FLASH (measured 2026-08-03, w27). Without this declaration the browser treats the
     document as light-scheme no matter what prefers-color-scheme says, so every surface the UA
     paints ITSELF stays white: the root canvas underneath our background, the overscroll region,
     scrollbars, form controls. Probe on a dark-mode page confirmed Canvas = rgb(255,255,255)
     while our own html background was rgb(13,14,16). A tab swap collapses the document by ~17,800px
     (Library 19,438 -> Today 1,650) and Chrome re-rasters the root scroller; for a frame the
     newly-exposed region is UA-white. That is the "light white/blue flash" - it was never the
     pane transition, which is why four fixes to the pane transition all missed it.
     `light dark` (not `dark`) because this app genuinely ships both themes.
     Bonus: this is also the documented fix for the UA CanvasText-in-dialogs bug. */
  color-scheme:light dark;
  --page:#F4F0E7;--ink-1:#F4F0E7;--ink-2:#F4F0E7;
  --cream:#211C17;--cream-dim:#4A443C;--taupe:#665F54;--faint:#6E675E;
  --amber:#E06E1F;--amber-soft:#EF8A3D;--amber-deep:#9A480A;--on-amber:#211C17;
  --teal:#0B6E77;--teal-ink-on:#FFFFFF;
  --glass:rgba(20,15,8,.03);--glass-2:rgba(20,15,8,.06);
  --hair:rgba(20,15,8,.12);--hair-bright:rgba(20,15,8,.22);
  --glass-tint:linear-gradient(180deg,rgba(255,253,248,.72),rgba(250,246,238,.82));
  --glass-edge:inset 0 1px 0 rgba(255,255,255,.75);--glass-solid:#FBF7EF;
  --card-bg:linear-gradient(180deg,rgba(255,255,255,.66),rgba(255,255,255,.40));
  --card-hair:rgba(20,15,8,.12);--card-edge:rgba(255,255,255,.85);--card-solid:#FCFAF4;
  --shadow:0 18px 40px -22px rgba(60,45,25,.30),0 4px 12px -6px rgba(60,45,25,.18);
  --danger:#aa463c;--danger-soft:#f6e2df;
  --r0:0;--r1:4px;--r2:10px;--radius:10px;--radius-sm:4px;--ease:cubic-bezier(.16,1,.3,1);
  --glass-blur:blur(30px) saturate(1.6);
  --bloom-amber:224,110,31;--bloom-teal:11,110,119;--bloom-op:.10;
  --nav-height:56px;/* permanently compact (Mark 2026-08-02): the bar never grows, labels never show */
}
@media(prefers-color-scheme:dark){:root{
  --page:#0D0E10;--ink-1:#121316;--ink-2:#1A1D21;
  /* --faint is calibrated against the TRANSLUCENT card gradient (the darkest surface it lands on),
     not the flat card colour: #6B7178 was 3.25:1 and #7E858C 4.29:1 — both AA fails at 11px. */
  --cream:#F4F1EA;--cream-dim:#C2C7CB;--taupe:#8A9097;--faint:#868D94;
  --amber:#FF8A3D;--amber-soft:#FFB070;--amber-deep:#FFB070;--on-amber:#211C17;
  --teal:#2EC5E0;--teal-ink-on:#0D0E10;
  --glass:rgba(255,255,255,.045);--glass-2:rgba(255,255,255,.08);
  --hair:rgba(255,255,255,.10);--hair-bright:rgba(255,255,255,.20);
  --glass-tint:linear-gradient(180deg,rgba(31,24,16,.82),rgba(16,12,7,.90));
  --glass-edge:inset 0 1px 0 rgba(255,247,235,.14);--glass-solid:#1a140d;
  --card-bg:linear-gradient(180deg,rgba(255,251,244,.14),rgba(255,251,244,.085));
  --card-hair:rgba(255,255,255,.16);--card-edge:rgba(255,250,242,.20);--card-solid:#161A1D;
  --shadow:0 14px 30px -16px rgba(0,0,0,.92),0 3px 8px -3px rgba(0,0,0,.8);
  --danger:#e79086;--danger-soft:rgba(231,144,134,.14);
  --bloom-amber:255,138,61;--bloom-teal:46,197,224;--bloom-op:.16;
}}
*{box-sizing:border-box;min-width:0}
html{background:var(--page);scroll-behavior:smooth;max-width:100%;overflow-x:clip}
body{margin:0;background:var(--page);color:var(--cream);font:500 15px/1.45 -apple-system,BlinkMacSystemFont,'SF Pro Text','Segoe UI Variable','Segoe UI',system-ui,sans-serif;min-height:100vh;max-width:100%;overflow-x:clip;-webkit-font-smoothing:antialiased}
/* v2 (Instrument): the two ambient blooms are GONE. Surfaces now carry their own light — an inset
   top-light plus one soft cast shadow (see the v2 token block at the end of this file) — instead of
   a page-level glow. The --bloom-amber / --bloom-teal RGB tokens STAY: they are the theme-aware
   amber/teal channels used by the nav cursor, rest pulse, adopt-last, bar marks and trend line.
   overflow-x:clip on html/body above still kills a stuck horizontal scroll offset. */
button,input,select,textarea{font:inherit;color:inherit}
button{cursor:pointer}
button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{outline:3px solid rgba(224,110,31,.35);outline-offset:2px}
/* ============================================================================================
   PROTOTYPE SOURCE - extracted verbatim from Mark's "Gym v2 Standalone.html", never authored here.
   Regenerate with the extractor; the checked-in copy is design/extracted/tokens.css.

   Mark, 2026-08-04: "dont guess it, just literally apply the same thing." So the design's own
   tokens and utilities now live in this file rather than being translated into ours. Verified
   before adding: the only three names that exist in both systems (--amber, --teal, --danger) hold
   IDENTICAL values in BOTH schemes, and NO atomic class name collides with any class token in our
   markup - so this block is purely additive and cannot restyle anything that already exists.

   The prototype is 68% inline-styled and every inline style references these vars, which is why one
   set of ported markup serves light AND dark: the theme lives entirely in the token override below.
   ============================================================================================ */
:root{
  /* The design's page gutter, read from its scroll container: padding 76px 20px 96px. */
  --gutter:20px;
  --w:20,15,8;--sh:224,214,194;--am:224,110,31;--tl:11,110,119;--dg:170,70,60;--sf:239,138,61;--bg:#F4F0E7;
  --desk:#E7E0D2;--desk2:#F6F2E9;--ink:#211C17;--ink2:#4A443C;--ink3:#5A5348;--mut:#665F54;--mut2:#6E675E;
  --mut3:#7C7466;--mut4:#8B8372;--mut5:#9A9280;--amber2:#C85F14;--acc:#9A480A;--soft:#EF8A3D;--hi:#F7B57C;
  --warm:#9A480A;--onAmber:#211C17;--teal2:#0B6E77;--c1:#FFFFFF;--c2:#FBF7EF;--c3:#FFFFFF;--c4:#FAF6EC;
  --c5:#FFFFFF;--c6:#FDFAF3;--sheet:#FBF7EF;--receipt:#FCFAF4;--confirm:#FBF7EF;--segOn:#FFFFFF;
  --chrome:rgba(251,247,239,.74);--chrome2:rgba(251,247,239,.84);--navBg:rgba(251,247,239,.62);
  --restBg:rgba(251,247,239,.9);--toast:rgba(251,247,239,.96);--scrim:rgba(60,45,25,.34);
  --scrim2:rgba(60,45,25,.42);
}
@media(prefers-color-scheme:dark){:root{
  --w:255,255,255;--sh:0,0,0;--am:255,138,61;--tl:46,197,224;--dg:231,144,134;--sf:255,176,112;--bg:#0B0C0D;
  --desk:#08090a;--desk2:#111315;--ink:#F4F1EA;--ink2:#C2C7CB;--ink3:#A7AEB5;--mut:#8A9097;--mut2:#7d848b;
  --mut3:#6b7279;--mut4:#5f666d;--mut5:#4f565c;--amber2:#FF7A24;--acc:#FFB070;--soft:#FFB070;--hi:#FFC98A;
  --warm:#FFC48A;--onAmber:#1a1206;--teal2:#4FD6EC;--c1:#1a1d20;--c2:#141618;--c3:#1c2023;--c4:#14171a;
  --c5:#1e2225;--c6:#1c1f22;--sheet:#121417;--receipt:#141719;--confirm:#161a1c;--segOn:#2b2f33;
  --chrome:rgba(11,12,13,.72);--chrome2:rgba(11,12,13,.82);--navBg:rgba(26,20,13,.58);--restBg:rgba(20,22,24,.86);
  --toast:rgba(28,31,34,.94);--scrim:rgba(6,7,8,.62);--scrim2:rgba(6,7,8,.7);
}}

/* The design's 45 atomic utilities, verbatim. Low specificity on purpose: ported screen rules and
   the elements' own inline styles both win over these. */
.fx { display: flex; }
.col { display: flex; flex-direction: column; }
.grid { display: grid; }
.ac { align-items: center; }
.jc { justify-content: center; }
.jb { justify-content: space-between; }
.f1 { flex: 1 1 0%; }
.noshrink { flex-shrink: 0; }
.wrap { flex-wrap: wrap; }
.fw5 { font-weight: 500; }
.fw6 { font-weight: 600; }
.fw7 { font-weight: 700; }
.fw8 { font-weight: 800; }
.fs11 { font-size: 11px; }
.fs12 { font-size: 12px; }
.fs13 { font-size: 13px; }
.fs14 { font-size: 14px; }
.fs15 { font-size: 15px; }
.fs16 { font-size: 16px; }
.fs20 { font-size: 20px; }
.fs22 { font-size: 22px; }
.upper { text-transform: uppercase; }
.tc { text-align: center; }
.nowrap { white-space: nowrap; }
.gap8 { gap: 8px; }
.gap10 { gap: 10px; }
.gap12 { gap: 12px; }
.gap16 { gap: 16px; }
.gap24 { gap: 24px; }
.m0 { margin: 0px; }
.mt8 { margin-top: 8px; }
.mt12 { margin-top: 12px; }
.mt16 { margin-top: 16px; }
.mb8 { margin-bottom: 8px; }
.mb12 { margin-bottom: 12px; }
.mb16 { margin-bottom: 16px; }
.posrel { position: relative; }
.posabs { position: absolute; }
.round { border-radius: 50%; }
.ohide { overflow: hidden; }
.bbox { box-sizing: border-box; }
.pointer { cursor: pointer; }
.w100 { width: 100%; }
.b0 { border-width: medium; border-style: none; border-color: currentcolor; border-image: none; }
.gs { scrollbar-width: none; }

.app-shell{width:100%;max-width:760px;min-height:100vh;margin:0 auto;padding:0 var(--gutter) calc(var(--nav-height) + 42px + env(safe-area-inset-bottom))}
.app-header{position:sticky;top:0;z-index:15;height:60px;display:flex;align-items:center;justify-content:space-between;margin:0 calc(var(--gutter)*-1);padding:0 18px;background:var(--chrome);-webkit-backdrop-filter:blur(26px) saturate(1.6);backdrop-filter:blur(26px) saturate(1.6);border-bottom:1px solid var(--hair);box-shadow:var(--glass-edge)}
/* Design: gap 9, 17px, min-height 44, --ink. */
.brand{display:flex;align-items:center;gap:9px;min-height:44px;border:0;background:transparent;padding:0;color:var(--ink);font-weight:800;font-size:17px;letter-spacing:-.02em}
.brand span{width:36px;height:36px;display:grid;place-items:center;border-radius:var(--r2);background:var(--amber);color:var(--on-amber);font-size:16px;font-weight:800}
/* Design: 44x44, r14, 1px rgba(var(--w),.09) on rgba(var(--w),.05), 15px/800, --ink2, ls 2px. */
.icon-button{width:44px;height:44px;border:1px solid rgba(var(--w),.09);border-radius:14px;background:rgba(var(--w),.05);color:var(--ink2);font-weight:800;font-size:15px;letter-spacing:2px}
.view{display:none}.view.active{display:block}#main:focus{outline:none}
/* MOTION MATCHED TO THE DESIGN (2026-08-04). The prototype animates the PANE as one with its own
   `gvIn` - opacity 0->1 plus translateY(10px), 0.34s cubic-bezier(.16,1,.3,1) - and does NOT stagger
   children. Ours ran `rise` on every direct child with delays to .2s, which is a different feel.
   Our --ease is already cubic-bezier(.16,1,.3,1), i.e. identical to the design's curve.
   On the opacity: it was banned here after the w25 curtain bug, but BOTH of that ban's reasons are
   gone - the animated bloom layers were deleted in w28, and the flash was root-caused in w47 as the
   UA tap highlight. A blend needs TWO panes painted at once; the swap gate still asserts exactly one
   is, so an entrance fade on the incoming pane cannot reproduce it. */
@keyframes gvIn{0%{opacity:0;transform:translateY(10px)}100%{opacity:1;transform:none}}
.view.active{animation:gvIn .34s cubic-bezier(.16,1,.3,1) both}
.view.active>*{animation:none}
/* child stagger removed: the design animates the pane once, not each child */
.workout-view.active>*{animation-duration:.3s}
@keyframes rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.page-lead{margin:14px 0 28px}.compact-lead{margin-bottom:20px}.page-lead h1{font-weight:800;font-size:clamp(32px,9vw,48px);line-height:1.02;letter-spacing:-.035em;margin:6px 0 3px;text-wrap:balance}.page-lead p:last-child{margin:0;max-width:550px;color:var(--taupe);font-size:16px}.kicker{margin:0;color:var(--amber-deep);font-size:11px;font-weight:800;letter-spacing:1.35px}
.section-heading{position:relative;display:flex;align-items:end;justify-content:space-between;gap:16px;margin:30px 2px 12px;padding-bottom:9px;border-bottom:1px solid var(--hair)}.section-heading::after{content:'';position:absolute;left:0;bottom:-1px;width:10px;height:2px;background:var(--amber)}.section-heading h2{font-weight:800;font-size:21px;letter-spacing:-.02em;margin:3px 0 0}.text-button{border:0;background:transparent;color:var(--amber-deep);min-height:44px;padding:0;font-weight:800}
.primary-button,.secondary-button,.finish-button{border:0;min-height:50px;border-radius:var(--radius);font-weight:800;transition:transform .12s var(--ease)}.primary-button{background:var(--amber);color:var(--on-amber);box-shadow:none}.primary-button:active,.secondary-button:active,.routine-start:active,.finish-button:active{transform:scale(.98)}.secondary-button{background:var(--glass-2);border:1px solid var(--hair);color:var(--cream)}.full-button{width:100%}.big-button{width:100%;display:flex;align-items:center;text-align:left;gap:14px;padding:16px 20px;margin:18px 0 4px;border-radius:var(--radius)}.big-button>span{font-size:24px}.big-button strong,.big-button small{display:block}.big-button small{opacity:.8;font-weight:500;margin-top:2px}
.stack{display:grid;gap:10px}.card,.routine-card,.history-card,.week-card,.chart-card{background:var(--card-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border:1px solid var(--card-hair);border-radius:var(--radius);box-shadow:var(--glass-edge),var(--shadow)}
.empty-card{padding:28px 20px;text-align:center;color:var(--taupe)}.empty-card strong{display:block;color:var(--cream);font-weight:800;font-size:18px;margin-bottom:4px}
.week-card{display:flex;justify-content:space-between;align-items:center;gap:18px;padding:17px 18px}.week-card-copy span,.week-card-copy strong,.week-card-copy small{display:block}.week-card-copy span{color:var(--taupe);font-size:12px}.week-card-copy strong{font-weight:800;font-size:20px;font-variant-numeric:tabular-nums lining-nums;margin:2px 0}.week-card-copy small{color:var(--taupe)}
.activity-card{background:var(--card-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border:1px solid var(--card-hair);color:var(--cream);border-radius:var(--radius);padding:18px;box-shadow:var(--glass-edge),var(--shadow);overflow:hidden}.activity-heading{display:flex;align-items:start;justify-content:space-between;gap:12px}.activity-heading .kicker{color:var(--amber-deep)}.activity-heading h2{font-weight:800;font-size:23px;letter-spacing:-.025em;margin:3px 0 0}.activity-detail{margin:4px 0 0;color:var(--taupe);font-size:12px}.activity-info{width:44px;height:44px;flex:none;border-radius:var(--radius-sm);border:1px solid var(--hair);background:var(--glass-2);color:var(--cream);font-weight:800;letter-spacing:2px}
.activity-layout{margin:14px 0 12px}
.activity-rings{display:flex;justify-content:space-around;gap:8px}
.arc-gauge{flex:1;display:flex;flex-direction:column;align-items:center;gap:6px;min-width:0}
.arc-gauge svg{display:block;width:100%;max-width:96px;height:auto;overflow:visible}
.arc-track,.arc-fill{fill:none;stroke-width:9;stroke-linecap:round}
.arc-track{stroke:var(--hair-bright)}
.arc-fill{transition:stroke-dashoffset .8s var(--ease)}
.arc-fill-workouts{stroke:var(--amber)}.arc-fill-sets{stroke:var(--teal)}.arc-fill-volume{stroke:var(--cream-dim)}
.arc-value{text-align:center;line-height:1.05}.arc-value strong{display:block;font-weight:800;font-size:24px;letter-spacing:-.02em;font-variant-numeric:tabular-nums lining-nums}.arc-value b{font-weight:600;font-size:11px;color:var(--taupe);font-variant-numeric:tabular-nums lining-nums}
.arc-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.7px;color:var(--taupe)}
.activity-legend{display:none}
.week-dots-wide{justify-content:space-between;padding-top:13px;margin-top:2px;border-top:1px solid var(--hair)}
.week-dots{display:flex;gap:5px}.day-dot{display:grid;justify-items:center;gap:5px}.day-dot i{display:block;width:11px;height:34px;border-radius:2px;background:var(--glass-2)}.day-dot.done i{background:var(--amber)}.day-dot.today i{box-shadow:0 0 0 2px var(--card-solid),0 0 0 3px var(--amber)}.day-dot small{font-size:9px;color:var(--taupe)}
.resume-card{margin-bottom:12px;padding:18px;background:var(--card-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border:1px solid var(--card-hair);color:var(--cream);border-radius:var(--radius);box-shadow:var(--glass-edge),var(--shadow)}.resume-card strong{font-weight:800;font-size:18px}.resume-card p{margin:2px 0 16px;color:var(--taupe)}.resume-card button{background:var(--amber);color:var(--on-amber);border:0;border-radius:var(--radius);min-height:48px;width:100%;font-weight:800}
.routine-card{display:grid;grid-template-columns:1fr auto;align-items:center;gap:12px;padding:15px 15px 15px 18px}.routine-card h3{margin:0;font-weight:800;font-size:17px}.routine-card p{margin:4px 0 0;color:var(--taupe);font-size:12px}.routine-actions{display:flex;gap:7px}.routine-menu,.routine-start{min-width:44px;height:44px;border-radius:var(--radius)}.routine-menu{border:1px solid var(--hair);background:var(--glass-2);color:var(--cream);font-weight:800;border-radius:var(--r1)}.routine-start{border:0;background:var(--amber);color:var(--on-amber);padding:0 15px;font-weight:800}
.history-card{padding:16px 18px;width:100%;text-align:left;transition:transform .14s var(--ease)}.history-card:active{transform:scale(.985)}.exercise-row{transition:transform .14s var(--ease)}.exercise-row:active{transform:scale(.985)}.history-top{display:flex;justify-content:space-between;gap:12px;align-items:start}.history-card h3{font-weight:800;font-size:16px;margin:0}.history-card time{font-size:11px;color:var(--taupe);font-variant-numeric:tabular-nums lining-nums}.history-meta{display:flex;gap:6px;flex-wrap:wrap;margin-top:12px}/* The chip's own --glass-2 fill lifts the background, which drops --taupe to 3.86:1 in dark. Ink
   for this surface is one step brighter so the pair passes in BOTH modes (audit 2026-07-22). */
.history-meta span{background:var(--glass-2);border-radius:var(--r1);padding:5px 8px;color:var(--cream-dim);font-size:11px;font-variant-numeric:tabular-nums lining-nums}.pr-badge{color:var(--amber-deep)!important;background:rgba(224,110,31,.14)!important;font-weight:800}
.template-grid{display:grid;grid-template-columns:1fr 1fr;gap:13px}.template-card{min-height:118px;border:1px solid var(--card-hair);border-radius:var(--radius);background:var(--card-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);box-shadow:var(--glass-edge),var(--shadow);padding:18px;text-align:left;color:var(--cream);transition:transform .14s var(--ease)}.template-card:active{transform:scale(.975)}.template-card span{display:block;color:var(--amber-deep);font-size:11px;font-weight:800;letter-spacing:1px}.template-card strong{display:block;font-weight:800;font-size:18px;margin:8px 0 5px;line-height:1.15}.template-card small{color:var(--taupe);display:block;line-height:1.4}
.search-wrap{display:flex;align-items:center;gap:10px;background:var(--glass-tint);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border:1px solid var(--hair);border-radius:var(--radius);padding:0 14px;height:52px;position:sticky;top:72px;z-index:5;box-shadow:var(--glass-edge)}.search-wrap span{font-size:22px;color:var(--taupe)}.search-wrap input{width:100%;border:0;outline:0;background:transparent;font-size:16px}.filter-row{display:flex;overflow-x:auto;gap:7px;margin:13px -18px 4px;padding:0 32px 0 18px;scrollbar-width:none;-webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 28px),transparent);mask-image:linear-gradient(90deg,#000 calc(100% - 28px),transparent)}.filter-row::-webkit-scrollbar{display:none}/* Design: r13, 1px rgba(var(--w),.08) on rgba(var(--w),.05), --ink2, 11px/800. */
.filter-chip{flex:none;white-space:nowrap;display:inline-flex;align-items:center;min-height:44px;border:1px solid rgba(var(--w),.08);border-radius:13px;background:rgba(var(--w),.05);color:var(--ink2);padding:0 14px;font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;transition:transform .12s var(--ease),background .15s var(--ease)}.filter-chip:active{transform:scale(.94)}.filter-chip.active{background:var(--amber);color:var(--on-amber);border-color:var(--amber)}.result-count{color:var(--taupe);font-size:12px;margin:12px 2px 8px}.exercise-list{display:grid;gap:8px;margin-bottom:16px}.exercise-row{display:flex;align-items:center;justify-content:space-between;gap:10px;border:1px solid var(--card-hair);border-radius:var(--radius);background:var(--card-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);box-shadow:var(--glass-edge),var(--shadow);padding:13px 13px 13px 16px}.exercise-row strong{display:block}.exercise-row small{display:block;margin-top:3px;color:var(--taupe);font-size:11px}
.metric-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:9px}.metric{position:relative;min-height:102px;background:var(--card-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border:1px solid var(--card-hair);border-radius:var(--radius);box-shadow:var(--glass-edge),var(--shadow);padding:16px 14px 14px}.metric::before{content:'';position:absolute;top:0;left:14px;right:14px;height:1px;background:var(--hair)}.metric::after{content:'';position:absolute;top:0;left:14px;width:10px;height:2px;background:var(--amber)}.metric strong{display:block;font-weight:800;font-size:28px;letter-spacing:-.02em;font-variant-numeric:tabular-nums lining-nums}.metric span{display:block;color:var(--taupe);font-size:11px;margin-top:6px}.chart-card{height:170px;padding:20px 14px 14px;display:flex;gap:8px;align-items:end}.bar-col{flex:1;height:100%;display:flex;flex-direction:column;justify-content:end;align-items:center;gap:6px}.bar-col i{width:100%;max-width:34px;min-height:4px;border-radius:2px;background:rgba(224,110,31,.22)}.bar-col.active i{background:var(--amber)}.bar-col small{font-size:9px;color:var(--taupe);font-variant-numeric:tabular-nums lining-nums}
.workout-view{padding-bottom:132px}/* room for the fixed rest pill - 96px still let it sit on the last card's +Add set row (audit 2026-08-02) */body.workout-active .app-header,body.workout-active .bottom-nav{display:none}body.workout-active .app-shell{padding-top:0;padding-bottom:30px}.workout-header{position:sticky;top:0;z-index:10;background:var(--glass-tint);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);display:flex;align-items:center;justify-content:space-between;margin:0 calc(var(--gutter)*-1);padding:14px var(--gutter) 12px;border-bottom:1px solid var(--hair);box-shadow:var(--glass-edge)}.workout-header h1{font-weight:800;font-size:12px;letter-spacing:1px;text-transform:uppercase;color:var(--taupe);margin:0}.workout-clock{margin:2px 0 0;color:var(--amber-deep);font-size:34px;font-weight:800;letter-spacing:0;line-height:1;font-variant-numeric:tabular-nums lining-nums}.workout-context{margin:8px 0 0;color:var(--taupe);font-size:12px;font-variant-numeric:tabular-nums lining-nums}/* Design: 44px tall, r15, the 135deg CTA gradient, --onAmber ink, 14px/800, inset top-light.
   NB its 18px is BUTTON padding, not the page gutter - the --gutter sweep wrongly caught it. */
.finish-button{height:44px;padding:0 18px;border-radius:15px;background:var(--cta-grad);color:var(--cta-ink);font-size:14px;font-weight:800;box-shadow:inset 0 1px 0 rgba(255,255,255,.35)}.live-metrics{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin:12px 0}.live-metric{position:relative;padding:12px 8px 10px;border-radius:var(--radius);background:var(--glass-2);border:1px solid var(--hair)}.live-metric::before{content:'';position:absolute;top:0;left:10px;right:10px;height:1px;background:var(--hair)}.live-metric::after{content:'';position:absolute;top:0;left:10px;width:10px;height:2px;background:var(--amber)}.live-metric strong,.live-metric small{display:block}.live-metric strong{font-weight:800;font-size:18px;letter-spacing:-.03em;font-variant-numeric:tabular-nums lining-nums}/* Design: 9.5px / 800 / uppercase / .09em. Ink stays --taupe (its --mut fails AA here). */
.live-metric small{font-size:9.5px;font-weight:800;color:var(--taupe);text-transform:uppercase;letter-spacing:.09em}.workout-exercises{display:grid;gap:12px}.workout-exercise{background:var(--card-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border:1px solid var(--card-hair);border-radius:var(--radius);overflow:hidden;box-shadow:var(--glass-edge),var(--shadow)}.exercise-head{display:flex;justify-content:space-between;align-items:start;padding:16px 16px 10px}.exercise-head h2{font-weight:800;font-size:18px;margin:0}.exercise-head p{color:var(--taupe);font-size:11px;margin:3px 0 0}.exercise-more{border:0;background:transparent;color:var(--cream);min-width:44px;height:44px;font-weight:800}.previous-strip{margin:0 14px 10px;padding:9px 10px;border-radius:var(--r2);background:rgba(11,110,119,.1);color:var(--teal);font-size:11px;font-variant-numeric:tabular-nums lining-nums}.set-grid{display:grid;grid-template-columns:34px 1fr 1fr 48px;gap:7px;align-items:center;padding:5px 14px}.set-grid.header{font-size:9px;color:var(--taupe);text-transform:uppercase;letter-spacing:.7px;padding-top:0;padding-bottom:7px;border-bottom:1px solid var(--hair)}.set-row{position:relative;margin:2px 8px;padding:7px 6px;border-radius:var(--r1);transition:background .16s var(--ease),box-shadow .16s var(--ease)}.set-row.completed{background:rgba(224,110,31,.13);box-shadow:inset 4px 0 0 var(--amber)}.set-row.notched{box-shadow:inset 3px 0 0 var(--amber);border:1px solid rgba(224,110,31,.4)}
@keyframes settleDone{0%{transform:translateX(0) scaleY(1)}30%{transform:translateX(3px) scaleY(1)}60%{transform:translateX(0) scaleY(.94) translateY(-1px);opacity:.85}100%{transform:none;opacity:1}}
.set-row.just-done{animation:settleDone .28s var(--ease)}
.set-row.just-done::after{content:'';position:absolute;inset:0;border-radius:var(--r1);box-shadow:0 0 0 2px var(--amber);opacity:0;animation:afterimage .42s var(--ease);pointer-events:none}
@keyframes afterimage{0%{opacity:.5}100%{opacity:0}}.set-row.completed .set-number{color:var(--amber-deep)}.set-row.completed .set-input{background:var(--card-solid);border-color:var(--amber-soft)}.set-number{text-align:center;color:var(--taupe);font-weight:800;font-variant-numeric:tabular-nums lining-nums}.set-input{width:100%;height:44px;border:1px solid var(--hair);border-radius:var(--r2);background:var(--glass);color:var(--cream);text-align:center;font-weight:700;font-size:16px;font-variant-numeric:tabular-nums lining-nums}.set-done{width:48px;height:48px;border:1px solid var(--hair);border-radius:var(--radius-sm);background:var(--glass-2);color:var(--taupe);font-size:18px;transition:transform .15s var(--ease),background .15s var(--ease)}.set-done.done{background:var(--amber);border-color:var(--amber);color:var(--on-amber);transform:scale(1.06)}/* Design: h46, r15, 1px rgba(var(--w),.07) on rgba(var(--w),.05), --acc ink, 14px/800. */
.add-set{width:calc(100% - 28px);margin:8px 14px 14px;height:46px;border:1px solid rgba(var(--w),.07);border-radius:15px;background:rgba(var(--w),.05);color:var(--acc);font-weight:800;font-size:14px}.add-exercise-button{margin-top:14px}.danger-link{display:block;margin:20px auto 0;border:0;background:transparent;color:var(--danger);height:44px;font-weight:700}
.bottom-nav{position:fixed;z-index:20;bottom:max(10px,env(safe-area-inset-bottom));left:50%;transform:translateX(-50%);width:calc(100vw - 24px);max-width:736px;height:var(--nav-height);padding:7px;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));background:var(--glass-tint);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border:1px solid var(--hair);border-radius:var(--radius);box-shadow:var(--glass-edge),var(--shadow)}.bottom-nav button{position:relative;z-index:1;border:0;border-radius:var(--r1);background:transparent;color:var(--taupe);display:grid;place-content:center;gap:2px}.bottom-nav button span{font-size:19px;line-height:1}.bottom-nav button small{font-size:10px;font-weight:700}.bottom-nav button.active{color:var(--amber-deep)}
.rest-pill{display:none;position:fixed;z-index:40;right:14px;bottom:14px;align-items:center;gap:9px;border:1px solid var(--hair);border-radius:var(--radius-sm);background:var(--glass-tint);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);color:var(--cream);padding:10px 13px;box-shadow:var(--glass-edge),var(--shadow)}.rest-pill.show{display:flex}.rest-pill span,.rest-pill small{font-size:10px;color:var(--amber-deep);font-weight:700}.rest-pill strong{font-weight:800;font-size:16px;font-variant-numeric:tabular-nums lining-nums}
dialog{color:var(--cream)}dialog:not([open]){display:none!important}dialog::backdrop{background:rgba(7,18,36,.48);backdrop-filter:blur(2px)}.sheet{width:min(100vw,760px);max-width:none;max-height:min(88vh,88dvh);margin:auto 0 0;border:0;border-radius:10px 10px 0 0;padding:0;background:var(--glass-solid);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);overflow:hidden}.sheet[open]{display:flex;flex-direction:column}.sheet-scroll{min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:8px 18px max(22px,env(safe-area-inset-bottom))}.sheet[open]{animation:sheetUp .22s var(--ease) both}@keyframes sheetUp{from{transform:translateY(30px);opacity:.6}}.sheet-handle{width:28px;height:3px;border-radius:0;background:var(--hair-bright);margin:2px auto 14px}.sheet-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:16px}.sheet-head h2{font-weight:800;font-size:24px;letter-spacing:-.02em;margin:0}.close-button{width:44px;height:44px;border:1px solid var(--hair);border-radius:var(--radius-sm);background:var(--glass-2);color:var(--cream);font-size:20px}.field{display:grid;gap:6px;margin-bottom:14px}.field label{font-size:10px;font-weight:800;letter-spacing:1px;color:var(--taupe)}.field input,.field select,.field textarea{width:100%;min-height:50px;border:1px solid var(--hair);border-radius:var(--r2);background:var(--glass);color:var(--cream);padding:0 13px;font-size:16px}.field textarea{padding:12px;resize:vertical}.picker-search{position:sticky;top:0;margin-bottom:10px}.picker-filters{margin-top:0;margin-bottom:4px}
.cue-strip{margin:0 14px 8px;padding:9px 10px;border-radius:var(--r2);background:rgba(224,110,31,.1);color:var(--amber-deep);font-size:12px;font-weight:600}
.cue-strip small{display:block;margin-top:3px;font-weight:600;font-size:9px;letter-spacing:.5px;text-transform:uppercase;opacity:.75}
.confirmed-line{display:block;margin-top:5px;padding-top:5px;border-top:1px solid rgba(11,110,119,.18);font-weight:600}.selected-list{display:grid;gap:8px;margin:10px 0}.selected-row{display:flex;justify-content:space-between;align-items:center;border:1px solid var(--hair);border-radius:var(--r2);background:var(--glass);padding:11px 12px}.selected-row button{border:0;background:transparent;color:var(--danger);min-width:44px;height:44px}.sheet-actions{display:flex;gap:8px;margin-top:18px}.sheet-actions>*{flex:1}.confirm-dialog{width:min(calc(100vw - 36px),420px);max-width:none;max-height:min(88vh,88dvh);border:0;border-radius:var(--r2);padding:0;overflow:hidden;background:var(--glass-solid);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);color:var(--cream)}.confirm-dialog[open]{display:flex;flex-direction:column}.confirm-dialog>.dialog-scroll{min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:20px}.confirm-dialog h2{font-weight:800;font-size:23px;margin:0 0 7px}.confirm-dialog p{color:var(--taupe)}.confirm-actions{display:flex;gap:8px;margin-top:18px}.confirm-actions button{flex:1}.toast{position:fixed;z-index:80;top:18px;left:50%;transform:translate(-50%,-20px);opacity:0;pointer-events:none;background:var(--glass-solid);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border:1px solid var(--hair);color:var(--cream);border-radius:var(--r1);overflow:hidden;padding:10px 15px;font-weight:700;box-shadow:var(--glass-edge),var(--shadow);transition:.2s}.toast.show{opacity:1;transform:translate(-50%,0)}
.bottom-nav button svg,.brand svg{width:22px;height:22px;display:block}
.brand strong{font-weight:800}   /* UA bold resolved to 900; the design's brand label is 800 */.brand span svg{width:20px;height:20px}
.search-wrap .search-glyph{display:grid;place-items:center;color:var(--taupe)}.search-wrap .search-glyph svg{width:19px;height:19px;display:block}
@keyframes setPop{0%{transform:scale(1)}40%{transform:scale(1.12)}100%{transform:scale(1.06)}}
.set-done.done{animation:setPop .3s var(--ease) both}
.toast.pr{background:var(--amber);color:var(--on-amber);border-color:var(--amber);font-weight:800}
@keyframes prGlow{0%{box-shadow:0 0 0 0 rgba(224,110,31,.5)}100%{box-shadow:0 0 0 22px rgba(224,110,31,0)}}
.toast.pr.show{animation:prGlow .9s var(--ease) 2}
.checkin-card{margin-bottom:12px;padding:15px 16px;border:1px solid var(--card-hair);border-radius:var(--radius);background:var(--card-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);box-shadow:var(--glass-edge),var(--shadow)}
.checkin-card p{margin:0 0 10px;font-weight:700;font-size:13px}.checkin-card p small{display:block;font-weight:500;color:var(--taupe);margin-top:2px}
.checkin-scale{display:flex;gap:5px}.checkin-scale button{flex:1;min-width:0;height:44px;border:1px solid var(--hair);border-radius:var(--r1);background:var(--glass-2);color:var(--cream);font-weight:700;font-size:12px;font-variant-numeric:tabular-nums;transition:transform .12s var(--ease)}.checkin-scale button:active{transform:scale(.92)}.checkin-scale button.picked{background:var(--teal);border-color:var(--teal);color:var(--teal-ink-on)}
.checkin-row{display:flex;gap:7px;margin-top:9px}.checkin-row button{flex:1;min-height:44px;border:1px solid var(--hair);border-radius:var(--radius-sm);background:var(--glass-2);color:var(--cream);font-weight:700;font-size:13px}.checkin-row button.picked{background:var(--teal);border-color:var(--teal);color:var(--teal-ink-on)}
.checkin-skip{border:0;background:transparent;color:var(--taupe);font-weight:700;font-size:12px;min-height:44px;padding:0 4px}
.set-number{border:0;background:transparent;padding:0;position:relative}
.set-number em{font-style:normal;position:absolute;top:-4px;right:-1px;font-size:8px;font-weight:800;color:var(--teal);letter-spacing:.5px}
.trend-card{padding:18px 16px 12px;background:var(--card-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border:1px solid var(--card-hair);border-radius:var(--radius);box-shadow:var(--glass-edge),var(--shadow)}
.trend-head{display:flex;justify-content:space-between;align-items:baseline;gap:10px;margin-bottom:4px}.trend-head strong{font-weight:800;font-size:16px}.trend-head span{color:var(--taupe);font-size:11px;font-variant-numeric:tabular-nums}
.trend-svg{display:block;width:100%;height:auto}
.trend-line{fill:none;stroke:var(--amber);stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}
.trend-area{fill:url(#trendFade);opacity:.9}
.trend-dot{fill:var(--amber);stroke:var(--card-solid);stroke-width:2}
.trend-grid-line{stroke:var(--hair);stroke-width:1}
.trend-tick{font-size:9px;fill:var(--taupe);font-weight:600}
.trend-picker{display:flex;overflow-x:auto;gap:7px;margin:0 calc(var(--gutter)*-1) 12px;padding:0 var(--gutter);scrollbar-width:none}.trend-picker::-webkit-scrollbar{display:none}
.locked-card{padding:22px 20px;text-align:center;color:var(--taupe);border-style:dashed;background:var(--glass)}
.locked-card strong{display:block;color:var(--cream);font-weight:800;font-size:16px;margin-bottom:4px}
.locked-card .lock-progress{display:flex;justify-content:center;gap:6px;margin-top:12px}.locked-card .lock-progress i{width:26px;height:6px;border-radius:2px;background:var(--glass-2);border:1px solid var(--hair)}.locked-card .lock-progress i.full{background:var(--amber);border-color:var(--amber)}
.pr-feed{display:grid;gap:8px}
.pr-row{position:relative;display:flex;align-items:center;gap:12px;border:1px solid var(--card-hair);border-radius:var(--radius);background:var(--card-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);box-shadow:var(--glass-edge),var(--shadow);padding:12px 14px}
.pr-row .pr-mark{width:38px;height:38px;flex:none;display:grid;place-items:center;border-radius:var(--r1);background:rgba(224,110,31,.14);color:var(--amber-deep);font-weight:800;font-size:11px}
.pr-row strong{display:block;font-weight:800;font-size:14px}.pr-row small{display:block;color:var(--taupe);font-size:11px;margin-top:2px;font-variant-numeric:tabular-nums}
.pr-row time{margin-left:auto;color:var(--taupe);font-size:11px;font-variant-numeric:tabular-nums;flex:none}
.confirm-feel{margin:14px 0 2px}.confirm-feel p{margin:0 0 8px;font-size:12px;font-weight:700;color:var(--taupe)}
/* Coach surface (Today) */
.coach-card{margin-bottom:12px;padding:18px}
.coach-top{display:flex;align-items:center;justify-content:space-between;gap:10px}
.coach-top .kicker{color:var(--amber-deep)}
.coach-flag{background:var(--teal);color:var(--teal-ink-on);font-size:10px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;padding:4px 9px 4px 8px}
.coach-card h2{font-weight:800;font-size:21px;letter-spacing:-.02em;margin:4px 0 8px}
.coach-superseded{margin:0 0 10px;padding:9px 11px;border-radius:var(--r2);background:rgba(224,110,31,.12);color:var(--amber-deep);font-size:12px;font-weight:700}
.coach-list{list-style:none;margin:0 0 10px;padding:0;display:grid;gap:5px}
.coach-list li{font-size:13px;color:var(--cream);font-variant-numeric:tabular-nums lining-nums;padding-left:12px;position:relative}
.coach-list li::before{content:'';position:absolute;left:0;top:8px;width:5px;height:5px;border-radius:0;background:var(--amber)}
.coach-list li.coach-skip{color:var(--taupe)}.coach-list li.coach-skip::before{background:var(--taupe)}
/* The design's single note line: margin 13px 0 0, 12px. DELIBERATE DEVIATION, contrast: the design's
   --mut2 measures 4.47:1 on this card in DARK - three hundredths under AA - so the ink is --faint,
   the value already calibrated against this exact surface. */
.coach-prov{margin:13px 0 0;color:var(--faint);font-size:12px}


.beighton-toggle{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-top:14px;padding:13px 14px;border:1px solid var(--hair);border-radius:var(--r2);background:var(--glass)}
.beighton-toggle strong{display:block;font-weight:800;font-size:14px}
.beighton-toggle small{display:block;margin-top:3px;color:var(--taupe);font-size:11px;line-height:1.4}
.beighton-toggle input{width:22px;height:22px;flex:none;accent-color:var(--teal)}
/* Load-notch motif — reserved for active set, PR marks, session receipt only */
.notched{clip-path:polygon(0 0,calc(100% - 14px) 0,100% 14px,100% 100%,0 100%)}
.notched-left{clip-path:polygon(14px 0,100% 0,100% 100%,0 100%,0 14px)}
/* Number roll — transform-only, gated on reduced-motion in JS */
.roll-mask{display:inline-block;overflow:hidden;vertical-align:bottom;position:relative}
.roll-mask>span{display:block;transition:transform .24s var(--ease)}
.roll-mask .roll-new{position:absolute;left:0;top:0;transform:translateY(100%)}
.roll-mask.go .roll-old{transform:translateY(-100%)}
.roll-mask.go .roll-new{transform:translateY(0)}
/* Session receipt overlay */
.receipt-overlay[hidden]{display:none}
.receipt-overlay{position:fixed;inset:0;z-index:100;display:grid;align-items:end;justify-items:center;background:rgba(7,10,14,.55);opacity:0;transition:opacity .3s var(--ease);padding:0 12px}
.receipt-overlay.show{opacity:1}
.receipt-card{position:relative;overflow-y:auto;overflow-x:hidden;max-height:min(85vh,85dvh);width:min(100%,520px);margin-bottom:max(18px,env(safe-area-inset-bottom));background:var(--card-solid);border:1px solid var(--card-hair);border-radius:var(--r2);box-shadow:var(--shadow);padding:24px 22px 20px;transform:translateY(24px);opacity:.6;transition:transform .35s var(--ease),opacity .35s var(--ease)}
.receipt-overlay.show .receipt-card{transform:none;opacity:1}
.receipt-card h2{font-weight:800;font-size:24px;letter-spacing:-.02em;margin:3px 0 0}
.receipt-date{margin:2px 0 10px;color:var(--taupe);font-size:12px;font-variant-numeric:tabular-nums lining-nums}
.receipt-sweep{position:absolute;top:0;left:0;height:2px;width:100%;background:var(--amber);transform:translateX(-100%);animation:sweep .7s var(--ease) .1s both}
@keyframes sweep{to{transform:translateX(100%)}}
.receipt-line{display:flex;justify-content:space-between;align-items:baseline;gap:12px;padding:12px 0;border-top:1px solid var(--hair);opacity:1;animation:receiptIn .4s var(--ease) both;animation-delay:calc(var(--i)*60ms + .15s)}
.receipt-line span{color:var(--taupe);font-size:11px;text-transform:uppercase;letter-spacing:1px;font-weight:800}
.receipt-line strong{font-weight:800;font-size:28px;font-variant-numeric:tabular-nums lining-nums}
@keyframes receiptIn{from{opacity:0;transform:translateY(8px)}}
.receipt-prs{margin-top:12px}
.receipt-pr{padding:10px 12px;margin-top:8px;background:rgba(224,110,31,.14);color:var(--amber-deep)}
.receipt-pr strong{display:block;font-weight:800;font-size:14px}
.receipt-pr small{font-size:11px;font-variant-numeric:tabular-nums lining-nums}
.receipt-card .primary-button{margin-top:18px}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .app-header,.search-wrap,.workout-header,.bottom-nav,.rest-pill{background:var(--glass-solid)}
  .card,.routine-card,.history-card,.week-card,.chart-card,.activity-card,.resume-card,.template-card,.exercise-row,.metric,.workout-exercise,.trend-card,.pr-row,.checkin-card,.coach-card{background:var(--card-solid)}
  .sheet,.confirm-dialog,.toast{background:var(--glass-solid)}
}
@media(min-width:650px){.app-shell{padding-left:28px;padding-right:28px}.template-grid{grid-template-columns:repeat(3,1fr)}.sheet{left:50%;transform:translateX(-50%);border-radius:10px 10px 0 0}.sheet[open]{animation:none}.metric-grid{gap:12px}}
@media(max-width:390px){.page-lead h1{font-size:33px}/* design: 33px flat, not a step-down */.week-dots{gap:3px}.day-dot i{width:9px}.metric{padding:12px 10px}.metric strong{font-size:20px}.template-grid{grid-template-columns:1fr}#workoutList{grid-template-columns:1fr 1fr;gap:10px}.routine-card{grid-template-columns:1fr}.routine-actions{justify-content:flex-end}.set-grid{grid-template-columns:36px 1fr 1fr 48px;padding-left:7px;padding-right:7px}.arc-value strong{font-size:19px}}
/* ---- Exercise catalogue picker (council 2026-07-19): Quick Picks + one muscle row + Filters control + stable list ---- */
.quick-picks:not(:empty){margin:6px 0 4px}
.quick-kicker{margin:0 2px 8px;color:var(--amber-deep)}
.quick-row{display:flex;gap:8px;overflow-x:auto;margin:0 calc(var(--gutter)*-1);padding:0 var(--gutter) 2px;scrollbar-width:none}
.quick-row::-webkit-scrollbar{display:none}
.quick-chip{flex:none;display:inline-flex;align-items:center;gap:6px;min-height:44px;max-width:210px;overflow:hidden;padding:0 14px;border:1px solid var(--card-hair);border-radius:var(--r1);background:var(--card-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);box-shadow:var(--glass-edge);color:var(--cream);font-weight:700;font-size:13px;transition:transform .12s var(--ease)}
.quick-chip:active{transform:scale(.96)}
.quick-chip>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.quick-star{flex:none;color:var(--amber-deep);font-size:12px;line-height:1}
/* Council 2026-07-22: rail full-width with an edge fade; Filters is a QUIET text-weight control
   docked on the results-count row (zero vertical cost) — amber + numeric badge only when active. */
.count-row{display:flex;align-items:center;justify-content:space-between;gap:12px}
.count-row .result-count{margin:0 0 0 2px}
.filters-button{position:relative;flex:none;display:inline-flex;align-items:center;gap:6px;min-height:44px;padding:0 2px;border:0;background:transparent;color:var(--taupe);font-size:12px;font-weight:600;transition:transform .12s var(--ease),color .15s var(--ease)}
.filters-button:active{transform:scale(.95)}
.filters-button svg{width:15px;height:15px;display:block}
.filters-button.has-active{color:var(--amber-deep);font-weight:800}
.filters-badge{min-width:18px;height:18px;padding:0 5px;border-radius:var(--r1);background:var(--amber);color:var(--on-amber);font-size:10px;font-weight:800;display:grid;place-items:center;font-variant-numeric:tabular-nums lining-nums}
.filters-badge[hidden]{display:none}
/* Row: big tappable name area (adds by exact id) + a ≥44px star toggle (filled vs outline shape — not colour-only) */
.exercise-row{padding:0;overflow:hidden}
.exercise-pick{flex:1;display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:60px;padding:12px 4px 12px 16px;border:0;background:transparent;color:inherit;text-align:left}
.exercise-info{min-width:0}
.exercise-info strong,/* Design: the Library equipment sub-line is 11.5px (ink stays --faint; its --mut2 fails AA). */
.exercise-info small{font-size:11.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.exercise-plus{flex:none;width:30px;text-align:center;color:var(--amber-deep);font-size:21px;font-weight:800;line-height:1}
.exercise-star{flex:none;align-self:stretch;width:54px;min-height:44px;border:0;border-left:1px solid var(--card-hair);background:transparent;display:grid;place-items:center}
.exercise-star svg{width:23px;height:23px;fill:none;stroke:var(--taupe);stroke-width:1.7;transition:fill .15s var(--ease),stroke .15s var(--ease),transform .15s var(--ease)}
.exercise-star.on svg{fill:var(--amber);stroke:var(--amber)}
.exercise-star:active svg{transform:scale(.85)}
/* Filters sheet: multi-select facet chips (fill = selected, matches the muscle chip idiom) */
.filter-group{margin-bottom:20px}
.filter-group .kicker{margin:0 0 10px;color:var(--amber-deep)}
.chip-wrap{display:flex;flex-wrap:wrap;gap:8px}
.facet-chip{display:inline-flex;align-items:center;min-height:44px;padding:0 15px;border:1px solid var(--hair);border-radius:var(--r1);background:var(--glass-2);color:var(--cream);font-weight:700;font-size:13px;transition:transform .12s var(--ease),background .15s var(--ease)}
.facet-chip:active{transform:scale(.95)}
.facet-chip.on{background:var(--amber);color:var(--on-amber);border-color:var(--amber)}
#filterClearBtn:disabled{opacity:.45}
/* Buttons set their own background AND colour, so the browser's built-in disabled dimming never
   lands — a dead button looked pixel-identical to a live one (audit 2026-07-22). Alpha + cursor,
   not hue, so the cue survives any colour-vision deficiency. */
button:disabled,button[disabled]{opacity:.38;cursor:default;box-shadow:none;filter:saturate(.5)}
@keyframes catFade{from{opacity:.35;transform:translateY(4px)}to{opacity:1;transform:none}}
/* ---- Track B: local profiles ---- */
.header-actions{display:flex;align-items:center;gap:8px}
/* Design: same 44x44 r14 control as .icon-button, ink --ink, 15px. */
.profile-chip{width:44px;height:44px;flex:none;border:1px solid rgba(var(--w),.09);border-radius:14px;background:rgba(var(--w),.05);color:var(--ink);font-weight:800;font-size:15px;display:grid;place-items:center;font-variant-numeric:tabular-nums;position:relative}
.profile-chip>span{line-height:1}
.profile-chip.is-locked::after{content:'';position:absolute;right:-2px;bottom:-2px;width:12px;height:12px;border-radius:50%;background:var(--teal);border:2px solid var(--page)}
.coach-empty{padding:20px}.coach-empty h2{font-weight:800;font-size:20px;letter-spacing:-.02em;margin:6px 0 4px}.coach-empty-detail{color:var(--taupe);font-size:13px;margin:0 0 16px}
.first-run-sub,.pin-sub{color:var(--taupe);font-size:13px;margin:-4px 0 16px;line-height:1.45}
.profile-rows{display:grid;gap:8px;margin:4px 0 6px}
.profile-row{display:flex;align-items:center;gap:13px;width:100%;min-height:60px;text-align:left;border:1px solid var(--card-hair);border-radius:var(--radius);background:var(--card-bg);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);box-shadow:var(--glass-edge),var(--shadow);padding:11px 15px;color:var(--cream);transition:transform .12s var(--ease)}
.profile-row:active{transform:scale(.985)}
.profile-row.active{border-color:var(--amber);box-shadow:var(--glass-edge),var(--shadow),inset 3px 0 0 var(--amber)}
.profile-ini{width:40px;height:40px;flex:none;display:grid;place-items:center;border-radius:var(--r2);background:var(--glass-2);border:1px solid var(--hair);font-weight:800;font-size:17px}
.profile-ini.add{background:rgba(224,110,31,.14);color:var(--amber-deep);border-color:transparent;font-size:22px}
.profile-name{flex:1;min-width:0;display:grid}.profile-name strong{font-weight:800;font-size:16px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.profile-name small{color:var(--taupe);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.6px;margin-top:2px}
.profile-mark{flex:none;color:var(--amber-deep);font-weight:800;font-size:16px}
.pin-dots{display:flex;justify-content:center;gap:16px;margin:6px 0 22px}
.pin-dot{width:15px;height:15px;border-radius:50%;border:2px solid var(--hair-bright);background:transparent;transition:background .12s var(--ease),border-color .12s var(--ease)}
.pin-dot.on{background:var(--amber);border-color:var(--amber)}
.pin-dots.shake{animation:pinShake .38s var(--ease)}
@keyframes pinShake{0%,100%{transform:translateX(0)}20%{transform:translateX(-8px)}40%{transform:translateX(7px)}60%{transform:translateX(-5px)}80%{transform:translateX(3px)}}
.pin-pad{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;max-width:300px;margin:0 auto}
.pin-key{height:60px;border:1px solid var(--hair);border-radius:var(--radius);background:var(--glass-2);color:var(--cream);font-weight:700;font-size:24px;font-variant-numeric:tabular-nums;transition:transform .1s var(--ease),background .12s var(--ease)}
.pin-key:active{transform:scale(.95);background:var(--glass-2)}
.pin-key.ghost{border:0;background:transparent;pointer-events:none}
.pin-key.pin-back{font-size:20px;color:var(--amber-deep)}
.pin-switch{display:block;margin:18px auto 4px}
/* Carry-forward: a prefilled (not-yet-confirmed) set reads muted AND italic/lighter — a non-colour cue too (Mark is colour-blind). */
.set-row.prefilled .set-input{color:var(--taupe);font-style:italic;font-weight:500}
/* Explicit set-1 adoption action. Theme-aware amber tint via the bloom RGB token, not a hardcoded literal. */
.adopt-last{display:block;width:calc(100% - 28px);margin:0 14px 8px;min-height:44px;border:1px solid var(--amber);border-radius:var(--r1);background:rgba(var(--bloom-amber),.12);color:var(--amber-deep);font-weight:800;font-size:13px;font-variant-numeric:tabular-nums lining-nums}
/* Rest-end progression: one-time amber pulse on the already-notched next set. */
@keyframes restNext{0%{box-shadow:inset 3px 0 0 var(--amber),0 0 0 0 rgba(var(--bloom-amber),.55)}100%{box-shadow:inset 3px 0 0 var(--amber),0 0 0 12px rgba(var(--bloom-amber),0)}}
.set-row.rest-next{animation:restNext .9s var(--ease)}
/* Rest pill → two thumb zones (+30s / Skip), both 44px. */
.rest-info{display:flex;flex-direction:column;line-height:1.1}
.rest-act{min-height:44px;min-width:44px;padding:0 12px;border:1px solid var(--hair);border-radius:var(--r1);background:var(--glass-2);color:var(--amber-deep);font-weight:800;font-size:12px;font-variant-numeric:tabular-nums lining-nums}
.rest-skip{color:var(--cream)}
/* Numeric pad sheet. */
.pad-value{display:flex;align-items:baseline;justify-content:center;gap:8px;margin:6px 0 16px}
.pad-value strong{font-weight:800;font-size:56px;letter-spacing:-.02em;font-variant-numeric:tabular-nums lining-nums}
.pad-value small{color:var(--taupe);font-size:14px;font-weight:700}
.pad-steps{display:flex;gap:7px;margin-bottom:14px}
.pad-step{flex:1;min-height:44px;border:1px solid var(--hair);border-radius:var(--r1);background:var(--glass-2);color:var(--cream);font-weight:800;font-size:13px;font-variant-numeric:tabular-nums lining-nums}
.pad-step.on{background:var(--amber);border-color:var(--amber);color:var(--on-amber)}
.pad-controls{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:6px}
.pad-adjust{height:72px;border:1px solid var(--hair);border-radius:var(--r2);background:var(--glass-2);color:var(--amber-deep);font-size:32px;font-weight:800;user-select:none;-webkit-user-select:none;touch-action:manipulation}
.pad-adjust:active{background:rgba(var(--bloom-amber),.14)}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}

/* ============================================================
   FORGED pass (council 2026-07-20) — composition over effects.
   Glass is chrome-only; cards are solid sculpted surfaces;
   data-viz gets gradient light; nav gets a glowing indicator
   with fixed geometry + material-only scroll response.
   Rollback: delete everything below this banner.
   ============================================================ */
:root{
  --radius:16px;--r2:13px;--r1:9px;--radius-sm:10px;
  --card-bg:linear-gradient(180deg,#FFFFFF 0%,#FCF9F2 55%,#F7F2E8 100%);
  --shadow:0 1px 2px rgba(60,45,25,.06),0 10px 24px -12px rgba(60,45,25,.22),0 24px 56px -28px rgba(60,45,25,.28);
  --nav-radius:26px;
}
@media(prefers-color-scheme:dark){:root{
  --card-bg:linear-gradient(180deg,#1D2228 0%,#171B20 60%,#131619 100%);
  --shadow:0 1px 0 rgba(255,255,255,.03),0 12px 28px -14px rgba(0,0,0,.85),0 28px 60px -30px rgba(0,0,0,.9);
}}
/* Cards go solid — blur stays only on chrome (header, nav, search, rest pill, sheets). */
.card,.routine-card,.history-card,.week-card,.chart-card,.activity-card,.resume-card,.template-card,.exercise-row,.metric,.workout-exercise,.trend-card,.pr-row,.checkin-card,.coach-card,.profile-row,.quick-chip{-webkit-backdrop-filter:none;backdrop-filter:none;background:var(--card-bg)}
.live-metric{background:var(--card-bg);border-color:var(--card-hair);box-shadow:var(--glass-edge),var(--shadow)}
/* Bars scale to 72% max so the count label + day label never force flex-shrink distortion (Codex verify 2026-07-20). */
/* Nav: floating pill, contained selection indicator, geometry fixed. */
.bottom-nav{border-radius:var(--nav-radius);padding:8px;box-shadow:var(--glass-edge),var(--shadow),0 -1px 0 rgba(255,255,255,.04)}

.bottom-nav button{transition:color .2s var(--ease)}
.bottom-nav button svg{transition:transform .3s cubic-bezier(.3,1.6,.4,1)}
.bottom-nav button.active svg{transform:translateY(-1px) scale(1.12)}
.bottom-nav button.active{color:var(--amber-deep)}
.bottom-nav button.active small{font-weight:700}   /* design: 700 */
/* Material-only scroll response: chrome deepens, nothing moves (council: geometry fixed). */
.app-header{transition:box-shadow .25s var(--ease),border-color .25s var(--ease)}
body.scrolled .app-header{border-bottom-color:var(--hair-bright);box-shadow:var(--glass-edge),0 8px 24px -12px rgba(0,0,0,.18)}
body.scrolled .bottom-nav{box-shadow:var(--glass-edge),var(--shadow),0 0 0 1px var(--hair)}
/* View entrance lives in ONE place: the tab-swap rule near the end of this file. Two competing
   grammars (this crossfade-scale + the directional slide) is exactly what read as unclean. */
/* Rings: gradient-lit arcs with an ambient glow per channel. */
.arc-fill{stroke-width:10}
.arc-track{stroke-width:10}
.arc-fill-workouts{stroke:url(#ringGradWorkouts);filter:none}
.arc-fill-sets{stroke:url(#ringGradSets);filter:drop-shadow(0 0 5px rgba(var(--bloom-teal),.5))}
.arc-fill-volume{stroke:url(#ringGradVolume)}
.arc-value strong{font-size:26px;letter-spacing:-.03em}
/* Consistency chart: sculpted bars with gradient light + live count on the current week. */
.chart-card{height:186px;padding:22px 16px 14px}
.bar-col i{max-width:36px;border-radius:7px 7px 3px 3px;background:linear-gradient(180deg,rgba(var(--bloom-amber),.38),rgba(var(--bloom-amber),.16));transition:height .5s var(--ease)}
.bar-col.active i{background:linear-gradient(180deg,var(--amber-soft),var(--amber));box-shadow:none}
.bar-col b{font-size:10px;font-weight:800;color:var(--amber-deep);font-variant-numeric:tabular-nums lining-nums;min-height:12px;line-height:1}
.bar-col b:empty{visibility:hidden}
/* Strength trend: line gets light; latest point pulses once. */
.trend-line{filter:none}
.trend-dot:last-of-type{animation:dotPulse 1.4s var(--ease) .4s 2}
@keyframes dotPulse{0%,100%{r:3.5}50%{r:5.5}}
/* Metrics read like instruments. */
.metric strong{font-size:31px;letter-spacing:-.03em}
/* Receipt: the app's one cinematic moment. */
.receipt-card{border-radius:var(--radius) var(--radius) 0 0;padding:26px 24px 22px}
.receipt-sweep{height:3px;background:linear-gradient(90deg,transparent,var(--amber),var(--amber-soft),transparent)}
.receipt-line strong{font-size:34px}
.receipt-card h2{font-size:27px;letter-spacing:-.03em}
.receipt-overlay{background:rgba(7,10,14,.62);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
/* Sheets keep the softer language. */
.sheet{border-radius:var(--radius) var(--radius) 0 0}
.sheet-handle{width:34px;height:4px;border-radius:3px}
/* Solid fallback parity for the new material split. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .receipt-overlay{background:rgba(7,10,14,.78)}
}

/* ============================================================
   COMPOSITION pass (council 2026-07-20) — per-screen identity.
   Each tab gets its own first-fold hero + a quiet dashboard below.
   Eyebrow system, live tinted cards, hero numerals, per-tab heroes.
   Extends the FORGED layer; token-paired both schemes.
   Rollback: delete everything below this banner.
   ============================================================ */

/* --- Eyebrow: quiet by default (taupe), amber reserved for the hero/active surface only. --- */
.kicker{color:var(--taupe);font-size:10px;font-weight:700;letter-spacing:.2em;text-transform:uppercase}
.kicker.accent{color:var(--amber-deep)}

/* Hero numeral: crisp in both themes; amber does not cast light onto the page. */
.hero-num{font-variant-numeric:tabular-nums lining-nums;letter-spacing:-.03em}
@media(prefers-color-scheme:dark){.hero-num{text-shadow:none}}

/* --- Premium tinted LIVE card: radial amber from top-right + amber border + inset amber top-light.
   --card-bg is already token-paired, so this reads as soft cream-amber on white / amber ember on #1D2228. --- */
/* NEUTRALISED 2026-08-04. Mark: "these boxes dont match up. the current one have a orange fade on
   them and the shape and feel off them is just different." He was right, and the cause was not a
   mis-ported token - it was the opposite. `--card-bg` is ALREADY byte-identical to the prototype's
   card in both schemes (light #FFFFFF->#FBF7EF, dark #1a1d20->#141618, measured off the running
   prototype). This rule then painted an invented amber radial wash ON TOP of a value that was already
   correct, plus an amber border and an amber inset. The design has no tinted "live" card at all.
   So the whole tint is gone and a live card is now simply a card. The class stays because four
   surfaces reference it; it just no longer repaints them. */
.card-live{position:relative;overflow:hidden}

/* Live dot — CSS-only pulse; covered by the global reduced-motion kill-switch. */
.live-dot{display:inline-block;width:9px;height:9px;border-radius:50%;background:var(--amber);margin-right:9px;vertical-align:baseline;box-shadow:0 0 0 0 rgba(var(--bloom-amber),.5);animation:livePulse 1.8s var(--ease) infinite}
@keyframes livePulse{0%{box-shadow:0 0 0 0 rgba(var(--bloom-amber),.5)}70%{box-shadow:0 0 0 9px rgba(var(--bloom-amber),0)}100%{box-shadow:0 0 0 0 rgba(var(--bloom-amber),0)}}

/* --- Below-fold wrapper: quiet dashboard with its own gentle stagger (not the pane rise, no double-animate). --- */
.view.active>.fold-2{animation:none}
.fold-2>*{animation:foldUp .5s var(--ease) both}
.fold-2>:nth-child(2){animation-delay:.05s}
.fold-2>:nth-child(3){animation-delay:.09s}
.fold-2>:nth-child(4){animation-delay:.12s}
.fold-2>:nth-child(n+5){animation-delay:.15s}
@keyframes foldUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}

/* ---- TODAY ---- */
/* Resume: top live card with a pulsing dot. */
.resume-card.card-live strong{display:flex;align-items:center}
/* Hero activity numerals. */
.activity-card.card-live .arc-value strong{font-size:27px}
/* Routines become a horizontal start strip. */
.routine-strip{display:flex;gap:11px;overflow-x:auto;margin:0 calc(var(--gutter)*-1);padding:2px var(--gutter) 8px;scrollbar-width:none}
.routine-strip::-webkit-scrollbar{display:none}
.routine-strip-card{flex:none;width:204px;display:flex;flex-direction:column;gap:12px;min-height:126px;padding:16px 16px 15px;border:1px solid var(--card-hair);border-radius:var(--radius);background:var(--card-bg);box-shadow:var(--glass-edge),var(--shadow)}
.routine-strip-card .rs-top{display:flex;align-items:start;justify-content:space-between;gap:8px}
.routine-strip-card h3{margin:0;font-weight:800;font-size:16px;line-height:1.2;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.routine-strip-card p{margin:0;color:var(--taupe);font-size:11px;flex:1}
.routine-strip-card .routine-menu{min-width:44px;height:44px;flex:none}
.routine-strip-card .rs-start{margin-top:auto;align-self:stretch;min-height:44px;border:0;border-radius:var(--r1);background:var(--amber);color:var(--on-amber);font-weight:800}

/* ---- TRAIN ---- */
.train-hero{position:relative;overflow:hidden;display:flex;align-items:center;gap:16px;width:100%;text-align:left;margin:2px 0 6px;padding:24px 22px;border:0;border-radius:var(--radius);color:var(--on-amber);
  background:linear-gradient(135deg,var(--amber-soft),var(--amber) 72%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.32)}
.train-hero>span{flex:none;width:52px;height:52px;display:grid;place-items:center;border-radius:15px;background:rgba(0,0,0,.14);color:var(--on-amber)}
.train-hero>span svg{width:26px;height:26px}
.train-hero strong{display:block;font-size:26px;font-weight:800;letter-spacing:-.02em;line-height:1.05}
.train-hero small{display:block;margin-top:4px;font-weight:600;font-size:13px;opacity:.85}
/* Plans read as posters: radial tint + bolder title. */
.plan-card{position:relative;overflow:hidden;background:radial-gradient(120% 80% at 100% 0,rgba(var(--bloom-amber),.12),transparent 55%),var(--card-bg)}
.plan-card strong{font-size:20px}

/* ---- LIBRARY: search-first cockpit ---- */
#view-library .page-lead h1{font-size:28px}
#view-library .search-wrap{height:56px}
#view-library .search-wrap input{font-size:17px}
#libraryQuickPicks{margin-top:12px}
/* Leading muscle "plate" on each exercise row. */
.ex-plate{flex:none;width:40px;height:40px;display:grid;place-items:center;border-radius:11px;background:var(--glass-2);color:var(--taupe);font-weight:800;font-size:15px;text-transform:uppercase;font-variant-numeric:tabular-nums}
.ex-plate.match{background:rgba(var(--bloom-amber),.16);color:var(--amber-deep)}
.exercise-pick{padding-left:13px;gap:12px}

/* ---- PROGRESS: strength hero first ---- */
.strength-hero{display:flex;align-items:baseline;gap:11px;flex-wrap:wrap;margin:2px 0 14px;padding:0 2px}
.strength-hero .sh-num{font-weight:800;font-size:clamp(46px,15vw,64px);line-height:.92;color:var(--amber-deep)}
.strength-hero .sh-unit{font-weight:700;font-size:15px;color:var(--taupe)}
.strength-hero .sh-delta{margin-left:auto;align-self:center;padding:6px 11px;border-radius:var(--r1);font-weight:800;font-size:13px;font-variant-numeric:tabular-nums lining-nums;background:rgba(var(--bloom-amber),.14);color:var(--amber-deep)}
.strength-hero .sh-delta.down{background:var(--glass-2);color:var(--taupe)}
/* PR feed: a connected timeline rail with amber node dots. */
.pr-feed:has(.pr-row){position:relative;padding-left:20px}
.pr-feed:has(.pr-row)::before{content:'';position:absolute;left:6px;top:16px;bottom:16px;width:2px;background:linear-gradient(180deg,var(--amber),rgba(var(--bloom-amber),.22))}
.pr-feed:has(.pr-row) .pr-row::before{content:'';position:absolute;left:-15px;top:50%;transform:translateY(-50%);width:9px;height:9px;border-radius:50%;background:var(--amber);box-shadow:0 0 0 3px var(--card-solid)}

/* "Done this week" on a routine card — same cream-on-glass recipe the PAUSED chip passes with. */
.done-badge{display:inline-block;padding:2px 8px;border-radius:var(--r1);background:var(--glass-2);border:1px solid var(--hair);color:var(--cream);font-size:11px;font-weight:800;letter-spacing:.4px}

/* ---- WORKOUT: cockpit ---- */
.workout-clock{font-size:44px}
/* Pause sits beside Finish: quiet secondary weight, same 50px target height. */
.workout-actions{display:flex;align-items:center;gap:8px}
/* Design: h44, r15, 1px rgba(var(--w),.09) on rgba(var(--w),.05), --ink ink, 13.5px/700. */
.pause-button{padding:0 14px;height:44px;min-height:44px;border-radius:15px;font-weight:700;font-size:13.5px;background:rgba(var(--w),.05);border:1px solid rgba(var(--w),.09);color:var(--ink);transition:transform .12s var(--ease)}
.pause-button:active{transform:scale(.98)}
/* Cream, not taupe: at 11px the muted ink measured 4.48:1 on glass-2 in dark — under the 4.5 bar. */
/* :not([hidden]) — a bare `display` would beat the UA hidden rule and leave a phantom chip laid out. */
.paused-flag:not([hidden]){display:inline-block;margin-left:10px;padding:4px 9px;border-radius:var(--r1);background:var(--glass-2);border:1px solid var(--hair);color:var(--cream);font-size:11px;font-weight:800;letter-spacing:1px;vertical-align:middle}
.workout-view.paused .workout-clock{color:var(--taupe)}
/* Live metrics: the design uses THREE SEPARATE r18 TILES, not one joined strip with dividers.
   Measured from design/extracted/workout.html - container grid repeat(3,1fr) gap 8px margin 14px 0,
   each tile r18 on linear-gradient(180deg,var(--c3),var(--c4)) with a 1px rgba(var(--w),.08)
   hairline and 13px 14px padding. Our previous comment literally said "not three boxes", which is
   exactly what the design is. */
.live-metrics{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:14px 0;background:none;border:0;border-radius:0;box-shadow:none;overflow:visible}
.live-metric{border-radius:18px;background:linear-gradient(180deg,var(--c3),var(--c4));border:1px solid rgba(var(--w),.08);box-shadow:none;padding:13px 14px}
.live-metric::before,.live-metric::after{display:none}
.live-metric+.live-metric{border-left:1px solid rgba(var(--w),.08)}
/* The design accents exactly one tile - the volume metric - with an amber radial wash and an amber
   hairline. This is where that wash BELONGS; it was previously painted on the UP NEXT card, which
   the design keeps neutral. Measured: radial-gradient(130% 100% at 100% 0,rgba(var(--am),.12),
   transparent 60%) over the same --c3/--c4 base, border rgba(var(--am),.22). */
.live-metric:nth-child(2){background:radial-gradient(130% 100% at 100% 0,rgba(var(--am),.12),transparent 60%),linear-gradient(180deg,var(--c3),var(--c4));border-color:rgba(var(--am),.22)}
.live-metric strong{font-size:22px}
/* Thin amber progress rail on the exercise card's left edge (fraction of sets done via --done). */
.workout-exercise{position:relative}
.workout-exercise::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--hair)}
.workout-exercise::after{content:'';position:absolute;left:0;top:0;width:3px;height:calc(var(--done,0)*100%);background:linear-gradient(180deg,var(--amber-soft),var(--amber));box-shadow:none;transition:height .4s var(--ease)}

/* ---- Muscle volume board: two parallel tracks per muscle, NEVER one joined bar (council two-ledger model). */
.mv-board{display:grid;gap:8px}
.mv-row{display:grid;grid-template-columns:92px 1fr auto;gap:12px;align-items:center;text-align:left;border:1px solid var(--card-hair);border-radius:var(--radius);background:var(--card-bg);box-shadow:var(--glass-edge),var(--shadow);padding:13px 15px;color:var(--cream);min-height:56px;transition:transform .12s var(--ease)}
button.mv-row:active{transform:scale(.985)}
.mv-name{font-weight:800;font-size:14px;display:grid;gap:2px;min-width:0}
.mv-range{font-weight:700;font-size:10px;color:var(--taupe);white-space:nowrap}
.mv-range.in{color:var(--teal)}
.mv-range.over{color:var(--danger)}
.mv-tracks{display:grid;gap:4px;min-width:0;align-content:center}
.mv-tracks i{display:block;height:9px;border-radius:5px;background:linear-gradient(90deg,var(--amber-soft),var(--amber));min-width:3px;transition:width .5s var(--ease)}
.mv-tracks .mv-assist{height:4px;background:var(--hair-bright)}
.mv-nums{font-size:11px;color:var(--taupe);font-variant-numeric:tabular-nums lining-nums;white-space:nowrap;text-align:right}
.mv-nums strong{font-weight:800;font-size:17px;color:var(--cream)}
.mv-note{margin:0 0 10px;color:var(--taupe);font-size:12px}
.mv-count{color:var(--taupe);font-size:12px;font-variant-numeric:tabular-nums lining-nums;flex:none}
.mv-static{box-shadow:none;background:var(--glass);border-color:var(--hair)}
@media(max-width:390px){.mv-row{grid-template-columns:78px 1fr auto;padding:12px 13px}.mv-nums{font-size:10px}.mv-nums strong{font-size:15px}}

/* ---- Set footer: add-set + drop-set side by side. */
.set-footer{display:flex;gap:8px;margin:8px 14px 14px}
.set-footer .add-set{flex:1;width:auto;margin:0}
/* Design: h46, r15, NO border, rgba(var(--tl),.09) fill, --teal2 ink, 14px/800. */
.add-drop{flex:none;min-width:84px;height:46px;border:1px solid rgba(var(--tl),.35);border-radius:15px;background:rgba(var(--tl),.09);color:var(--teal2);font-weight:800;font-size:14px}
/* Drop-set rows: teal down-arrow number + tint; a shape+glyph cue, never colour-only. */
.set-row.drop-set{background:rgba(var(--bloom-teal),.07)}
.set-row.drop-set .set-number{color:var(--teal);font-size:15px}
.set-row.drop-set.completed{background:rgba(var(--bloom-teal),.14);box-shadow:inset 4px 0 0 var(--teal)}
.set-row.drop-set.completed .set-input{border-color:var(--teal)}
/* Superset connector between paired exercise cards. */
.ss-link{display:flex;justify-content:center;margin:-6px 0}
.ss-link span{position:relative;z-index:2;padding:5px 12px;border-radius:999px;border:1px solid rgba(var(--bloom-teal),.5);background:var(--card-solid);color:var(--teal);font-size:10px;font-weight:800;letter-spacing:1px;text-transform:uppercase;box-shadow:var(--shadow)}
/* 8-week muscle spark chart inside the detail sheet. */
.mv-spark{height:128px;padding:14px 10px 10px}
/* Plate math line under the pad numeral. */
.pad-plates{margin:-8px 0 14px;text-align:center;color:var(--teal);font-size:13px;font-weight:700;font-variant-numeric:tabular-nums lining-nums;min-height:18px}
/* Nav is compact ALWAYS (Mark 2026-08-02): 56px icon bar, stable geometry, nothing to transition.
   Labels stay in the DOM for screen readers but never paint. */
.bottom-nav{transition:box-shadow .25s var(--ease)}
.bottom-nav button small{opacity:0;transform:translateY(8px);position:absolute;pointer-events:none}
.bottom-nav button svg{width:24px;height:24px}
/* Soul: a slow light sheen across the Train hero (killed by the global reduced-motion rule). */
.train-hero::after{content:'';position:absolute;inset:0;pointer-events:none;background:linear-gradient(115deg,transparent 32%,rgba(255,255,255,.22) 46%,transparent 60%);background-size:260% 100%;background-position:180% 0;animation:sheen 7s var(--ease) 1.2s infinite}
@keyframes sheen{0%,55%{background-position:180% 0}100%{background-position:-80% 0}}

/* Solid fallback: the tinted live surfaces keep their gradient (drop only blur, per @supports rule above). */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .routine-strip-card,.live-metrics{background:var(--card-solid)}
}

/* ========================================================================
   WAVES 1–3 (council 2026-07-20): progression loop, evidence surfaces, depth.
   All colours are token-paired (flip with the scheme). Motion is auto-killed
   by the global prefers-reduced-motion rule above.
   ======================================================================== */

/* ---- Update-ready pill (release truth). Chrome glass, persistent + tappable, slides up. ---- */
.update-pill{position:fixed;left:50%;bottom:calc(var(--nav-height) + 14px + env(safe-area-inset-bottom));transform:translate(-50%,140%);z-index:60;display:inline-flex;align-items:center;gap:9px;min-height:44px;padding:0 18px  /* pill padding, not the page gutter */;border:1px solid var(--amber);border-radius:999px;background:var(--glass-solid);color:var(--cream);font-weight:800;font-size:13px;box-shadow:var(--shadow),var(--glass-edge);transition:transform .4s var(--ease),opacity .3s var(--ease);opacity:0}
.update-pill[hidden]{display:none}
.update-pill.show{transform:translate(-50%,0);opacity:1}
.update-pill .update-dot{width:9px;height:9px;border-radius:50%;background:var(--amber);box-shadow:0 0 0 3px rgba(var(--bloom-amber),.22)}
body.workout-active .update-pill{bottom:calc(14px + env(safe-area-inset-bottom))}

/* ---- Wave 1: progression target line under "Last time". Fades/slides in after the previous-strip. ---- */
.target-line{display:flex;align-items:center;gap:7px;margin-top:6px;font-size:13px;color:var(--cream);animation:targetIn .34s var(--ease) both;animation-delay:.06s}
.target-line b{color:var(--amber-deep);font-weight:800}
.target-line .target-lead{color:var(--taupe);font-weight:700}
.target-line strong{font-weight:800;font-variant-numeric:tabular-nums lining-nums}
.target-line.blocked{color:var(--danger)}
.target-line.blocked b,.target-line.blocked strong{color:var(--danger)}
.why-target{border:0;background:transparent;color:var(--amber-deep);font-weight:800;font-size:12px;text-decoration:underline;text-underline-offset:2px;min-height:44px;padding:0 4px;margin-left:auto}
@keyframes targetIn{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}

/* ---- Wave 1: RIR capture chips + collapsed note. Chips pop in with a spring. ---- */
.rir-row{display:flex;flex-direction:column;gap:8px;margin:4px 14px 0;padding:12px 0 2px;border-top:1px dashed var(--hair);animation:rirIn .3s var(--ease) both}
.rir-label{font-size:12px;font-weight:800;color:var(--taupe)}
.rir-help{display:block;margin-top:2px;font-size:11px;font-weight:600;color:var(--faint);letter-spacing:0}
.rir-chips{display:flex;gap:7px;flex-wrap:wrap}
.rir-chip{min-width:44px;min-height:44px;padding:0 12px;border:1px solid var(--hair);border-radius:var(--r1);background:var(--glass-2);color:var(--cream);font-weight:800;font-size:14px;transition:transform .12s var(--ease),background .15s var(--ease)}
.rir-chip:active{transform:scale(.92);background:var(--amber);color:var(--on-amber);border-color:var(--amber)}
.rir-note{display:inline-flex;align-items:baseline;gap:8px;margin:6px 14px 0;min-height:44px;padding:0 12px;border:1px solid rgba(var(--bloom-amber),.5);border-radius:var(--r1);background:rgba(var(--bloom-amber),.1);color:var(--amber-deep);font-weight:800;font-size:13px}
.rir-note small{color:var(--taupe);font-weight:700;font-size:11px}
@keyframes rirIn{from{opacity:0;transform:translateY(6px) scale(.97)}60%{transform:translateY(-1px) scale(1.01)}to{opacity:1;transform:none}}

/* ---- Wave 1: "why this target" sheet. ---- */
.why-evidence{margin:2px 0 8px;color:var(--taupe);font-size:13px;font-variant-numeric:tabular-nums lining-nums}
.why-sentence{margin:0 0 8px;color:var(--cream);font-size:15px;line-height:1.5}
.why-foot{margin:14px 0 4px;color:var(--faint);font-size:11px}
.why-block{display:flex;gap:12px;align-items:flex-start;padding:16px;border-radius:var(--radius);border:1px solid var(--danger);background:var(--danger-soft);color:var(--danger)}
.why-block-glyph{flex:none;width:26px;height:26px;display:grid;place-items:center;border-radius:50%;border:2px solid var(--danger);font-weight:800}
.why-block p{margin:0;font-weight:700;font-size:14px;line-height:1.5}

/* ---- Wave 1: receipt NEXT SESSION block. Rows stagger in like the receipt lines. ---- */
.receipt-next{margin-top:16px;padding-top:4px}
.receipt-next .kicker{color:var(--amber-deep)}
.receipt-next-rows{margin-top:8px}
.receipt-next-row{display:flex;justify-content:space-between;align-items:baseline;gap:12px;padding:11px 0;border-top:1px solid var(--hair);animation:receiptIn .4s var(--ease) both;animation-delay:calc(var(--i)*55ms + .3s)}
.receipt-next-row span{color:var(--taupe);font-size:13px;font-weight:700}
.receipt-next-row strong{font-weight:800;font-variant-numeric:tabular-nums lining-nums;text-align:right}
.receipt-next-row strong em{font-style:normal;font-weight:800;font-size:10px;text-transform:uppercase;letter-spacing:.6px;color:var(--amber-deep)}

/* ---- Wave 2: exercise detail sheet. ---- */
.exercise-title{cursor:pointer}
.detail-equip{margin:-2px 0 12px;color:var(--taupe);font-size:13px}
.detail-stat{display:flex;align-items:baseline;gap:10px;margin:4px 0 6px}
.detail-stat strong{font-size:34px;font-weight:800;color:var(--amber-deep);line-height:1}
.detail-stat span{color:var(--taupe);font-size:11px;font-weight:800;letter-spacing:1px}
.rr-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(64px,1fr));gap:8px}
.rr-cell{border:1px solid var(--card-hair);border-radius:var(--radius);background:var(--card-bg);box-shadow:var(--glass-edge),var(--shadow);padding:11px 8px;text-align:center}
.rr-cell strong{display:block;font-weight:800;font-size:19px;font-variant-numeric:tabular-nums lining-nums}
.rr-cell small{display:block;margin-top:2px;color:var(--taupe);font-size:11px}

/* ---- Wave 2: weekly recap card + honest accumulation state. ---- */
.recap-card{padding:18px;margin:14px 0}
.recap-card .kicker{color:var(--amber-deep)}
.recap-locked strong{display:block;margin:6px 0 4px;font-weight:800;font-size:18px;color:var(--cream)}
.recap-locked p{margin:0;color:var(--taupe);font-size:13px}
.recap-locked .lock-progress{display:flex;gap:6px;margin-top:12px}
.recap-locked .lock-progress i{width:26px;height:6px;border-radius:2px;background:var(--glass-2);border:1px solid var(--hair)}
.recap-locked .lock-progress i.full{background:var(--amber);border-color:var(--amber)}
.rc-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px;margin-top:12px}
.rc-stat{display:flex;flex-direction:column;gap:2px}
.rc-stat>span{color:var(--taupe);font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:1px}
.rc-stat>strong{font-weight:800;font-size:24px;font-variant-numeric:tabular-nums lining-nums;line-height:1.05}
/* Deltas render inside an uppercased parent: a "4.7k" must stay lowercase like every other compact number. */
.rc-delta{font-size:11px;font-weight:800;font-variant-numeric:tabular-nums lining-nums;text-transform:none}
.rc-delta.up{color:var(--teal)}
.rc-delta.down{color:var(--danger)}
.rc-delta.flat{color:var(--taupe);text-transform:uppercase}
.rc-insights{margin-top:14px;padding-top:12px;border-top:1px solid var(--hair)}
.rc-insights p{margin:0 0 4px;color:var(--cream);font-size:13px}
.rc-pain{margin:8px 0 0;color:var(--taupe);font-size:12px}

/* ---- Wave 2: L/R balance board. Mirrored bars from a center axis, shared scale. ---- */
.bal-board{display:grid;gap:10px}
.bal-row{border:1px solid var(--card-hair);border-radius:var(--radius);background:var(--card-bg);box-shadow:var(--glass-edge),var(--shadow);padding:13px 15px}
.bal-name{display:flex;align-items:center;gap:8px;font-weight:800;font-size:14px;margin-bottom:9px}
.bal-flag{font-size:11px;font-weight:800;color:var(--danger)}
.bal-bars{display:grid;grid-template-columns:1fr 2px 1fr;align-items:center;gap:0}
.bal-side{display:flex;align-items:center;gap:8px;min-width:0}
.bal-side i{display:block;height:10px;border-radius:5px;background:linear-gradient(90deg,var(--amber-soft),var(--amber));min-width:3px;transition:width .5s var(--ease)}
.bal-side b{font-size:11px;font-weight:800;color:var(--taupe);font-variant-numeric:tabular-nums lining-nums;white-space:nowrap}
.bal-left{flex-direction:row-reverse;justify-content:flex-start}
.bal-left i{transform-origin:right}
.bal-right{justify-content:flex-start}
.bal-axis{width:2px;align-self:stretch;background:var(--hair-bright)}
.bal-gap{margin-top:8px;color:var(--taupe);font-size:11px;font-weight:700;font-variant-numeric:tabular-nums lining-nums}
/* One-sided partial rows: dashed, honest, no gap % (Codex P3). */
.bal-partial{border-style:dashed;background:var(--glass)}
.bal-partial .bal-name{margin-bottom:4px}
.bal-partial-line{color:var(--taupe);font-size:12px;font-variant-numeric:tabular-nums lining-nums}

/* ---- Wave 3: pain trend bars (teal, value labels). ---- */
.pain-bars{height:120px;padding:14px 10px 10px;display:flex;align-items:flex-end;gap:6px}
.pain-col{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;height:100%}
.pain-col b{font-size:11px;font-weight:800;color:var(--cream);font-variant-numeric:tabular-nums lining-nums;margin-bottom:4px}
.pain-col i{display:block;width:70%;max-width:22px;border-radius:4px 4px 0 0;background:linear-gradient(180deg,var(--teal),rgba(var(--bloom-teal),.5))}
.pain-col small{margin-top:5px;color:var(--taupe);font-size:10px}

/* ---- Wave 3: bodyweight card. ---- */
.bw-card{padding:16px}
.bw-head{display:flex;align-items:baseline;gap:10px;margin-bottom:8px}
.bw-head strong{font-size:34px;font-weight:800;color:var(--amber-deep);line-height:1}
.bw-head span{color:var(--taupe);font-size:12px;font-variant-numeric:tabular-nums lining-nums}

/* ---- Wave 3: rep-range distribution line in the muscle detail sheet. ---- */
.rep-dist{margin:8px 0 2px;color:var(--cream);font-size:13px;font-weight:700;font-variant-numeric:tabular-nums lining-nums}

/* ============================================================
   POLISH pass (council 2026-07-20, build w4) — interaction physics,
   sheet spring+drag, depth tokens, restrained PR moment.
   ONE press-timing family (--press-ease/--press-ms); three press roles
   (control / card / primary); depth as a token scale; token-paired both
   schemes. All motion is auto-killed by the global prefers-reduced-motion
   rule above (it wins via !important regardless of source order).
   Rollback: delete everything below this banner + revert the app.js
   "POLISH pass" block (dismissDialog / attachSheetDrag / celebratePR).
   ============================================================ */
:root{
  --press-ease:cubic-bezier(.34,1.3,.5,1);--press-ms:140ms;
  --press-veil:rgba(20,15,8,.07);
  --top-light:inset 0 1px 0 rgba(255,255,255,.28);
  --elev-1:var(--shadow);           /* standard raised card — == resting look, unchanged */
  --elev-0:0 1px 2px rgba(60,45,25,.10); /* pressed: ambient only, key shadow compressed away */
}
@media(prefers-color-scheme:dark){:root{
  --press-veil:rgba(255,255,255,.10);
  --top-light:inset 0 1px 0 rgba(255,247,235,.16);
  --elev-0:0 1px 2px rgba(0,0,0,.6);
}}

/* ---- Tap hygiene: kill the 300ms delay / double-tap zoom on every control. ---- */
button,[role="button"],.filter-chip,.facet-chip,.quick-chip,.rir-chip,.pin-key,input[type="checkbox"],label.beighton-toggle,select{touch-action:manipulation}
/* NOTE: overscroll-behavior-y:contain on <body> locked touch scrolling on Android Chrome (body is a
   nested scroll container via overflow-x, and contain on it froze finger-pans while taps still fired).
   Removed 2026-07-20. Keep overscroll containment scoped to dialogs only, which scroll internally. */
dialog{overscroll-behavior:contain}

/* ---- Press role CONTROL — no scale; background highlight (inset veil) + opacity dip. ---- */
.icon-button,.text-button,.close-button,.routine-menu,.activity-info,.exercise-more,.filters-button,.filter-chip,.facet-chip,.quick-chip,.rir-chip,.pad-step,.rest-act,.why-target,.exercise-star,.pin-key,.checkin-scale button,.checkin-row button,.bottom-nav button,.add-set,.add-drop,.adopt-last{transition:box-shadow var(--press-ms) var(--press-ease),opacity var(--press-ms) var(--press-ease),background var(--press-ms) var(--press-ease)}
.icon-button:active,.text-button:active,.close-button:active,.routine-menu:active,.activity-info:active,.exercise-more:active,.filters-button:active,.filter-chip:active,.facet-chip:active,.quick-chip:active,.rir-chip:active,.pad-step:active,.rest-act:active,.why-target:active,.exercise-star:active,.pin-key:active,.checkin-scale button:active,.checkin-row button:active,.bottom-nav button:active,.add-set:active,.add-drop:active,.adopt-last:active{transform:none;opacity:.9;box-shadow:inset 0 0 0 99px var(--press-veil)}
.exercise-star:active svg{transform:none} /* star keeps its own fill-toggle, no press-scale */

/* ---- Press role CARD — scale(.985) + shadow compresses one step (drop the outer key shadow).
   Scoped to elements that ARE the interactive control (buttons), never container wrappers —
   a wrapper scaling while its child button presses reads as compound motion (Codex P2). ---- */
button.history-card,button.template-card,button.plan-card,button.profile-row,button.mv-row,.exercise-row{transition:transform var(--press-ms) var(--press-ease),box-shadow var(--press-ms) var(--press-ease)}
button.history-card:active,button.template-card:active,button.plan-card:active,button.profile-row:active,button.mv-row:active{transform:scale(.985);box-shadow:var(--glass-edge),var(--elev-0)}
/* Container wrappers (article: exercise-row / routine-card / routine-strip-card) never press as a whole —
   their child buttons carry their own role. Also overrides the legacy base .exercise-row:active scale. */
.exercise-row:active,.routine-card:active,.routine-strip-card:active{transform:none;box-shadow:var(--glass-edge),var(--shadow)}
/* Deliberate exception: the exercise row's MAIN tap surface (.exercise-pick spans the row) presses the
   row card — the star toggle alongside it never drags the row with it. */
.exercise-row:has(>.exercise-pick:active){transform:scale(.985);box-shadow:var(--glass-edge),var(--elev-0)}

/* ---- Press role PRIMARY — scale(.97) + stronger compression + brightness(.98). ---- */
.primary-button,.secondary-button,.finish-button,.routine-start,.rs-start,.big-button,.train-hero,.resume-card button{transition:transform var(--press-ms) var(--press-ease),box-shadow var(--press-ms) var(--press-ease),filter var(--press-ms) var(--press-ease)}
.primary-button:active,.secondary-button:active,.finish-button:active,.routine-start:active,.rs-start:active,.big-button:active,.train-hero:active,.resume-card button:active{transform:scale(.97);filter:brightness(.98);box-shadow:var(--top-light),var(--elev-0)}

/* ---- Depth: 3-layer light. Button CTAs were missing the inset top-light — add it (paired). ---- */
.primary-button,.finish-button,.routine-start,.rs-start{box-shadow:var(--top-light)}
.secondary-button{box-shadow:var(--top-light),var(--elev-0)}
/* train-hero + big-button already carry their own inset top-light — left untouched. */

/* ---- Sheet spring-open (transform-only overshoot) + real exit animation. ---- */
@keyframes sheetSpring{0%{transform:translateY(46px)}70%{transform:translateY(-5px)}100%{transform:translateY(0)}}
.sheet[open]{animation:sheetSpring .34s var(--press-ease) both}
@keyframes sheetDown{to{transform:translateY(102%)}}
@keyframes backdropOut{to{opacity:0}}
@keyframes dialogOut{to{opacity:0;transform:translateY(10px) scale(.98)}}
.sheet.closing{animation:sheetDown .18s var(--ease) both}
.sheet.closing::backdrop,.confirm-dialog.closing::backdrop{animation:backdropOut .18s var(--ease) both}
.confirm-dialog.closing{animation:dialogOut .16s var(--ease) both}
/* Drag-to-dismiss from the handle (JS drives --drag). Spring/transition off while dragging. */
.sheet.dragging{animation:none;transition:none;transform:translateY(var(--drag,0))}
.sheet.settle{transition:transform .28s var(--press-ease);transform:translateY(var(--drag,0))}
/* Handle: 44px invisible hit zone (visually unchanged), owns its own gesture. */
.sheet-handle{position:relative;touch-action:none;cursor:grab}
.sheet-handle::before{content:'';position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:140px;height:44px}
/* visualViewport-aware height: JS sets --vvh ONLY while the keyboard is up (a real positive px),
   so a focused field is never covered; otherwise the normal 88vh cap applies. Never collapses. */
.sheet{max-height:var(--vvh,min(88vh,88dvh))}
/* Desktop: sheet is centered (translateX) — keep centering through drag/close, fade instead of slide. */
@media(min-width:650px){
  .sheet[open]{animation:none}
  .sheet.dragging,.sheet.settle{transform:translate(-50%,var(--drag,0))}
  @keyframes fadeOut{to{opacity:0}}
  .sheet.closing{animation:fadeOut .15s var(--ease) both}
}

/* ---- PR moment (restrained, spatially earned): row compress + value roll up +
   a thin amber light sweep travelling UP the exercise card's left rail. No bursts. ---- */
@keyframes prCompress{0%{transform:scaleY(1)}35%{transform:scaleY(.9)}100%{transform:scaleY(1)}}
.set-row.pr-hit{animation:prCompress .42s var(--press-ease);transform-origin:center}
.pr-spark{position:absolute;left:0;bottom:0;width:3px;height:34%;border-radius:2px;pointer-events:none;z-index:4;background:linear-gradient(180deg,rgba(var(--bloom-amber),0),var(--amber-soft),var(--amber));box-shadow:none;animation:prRail .6s var(--ease)}
@keyframes prRail{0%{transform:translateY(0);opacity:0}20%{opacity:1}100%{transform:translateY(-300%);opacity:0}}

/* ---- Declared goals (2026-07-22) -----------------------------------------------------------
   Same sculpted-card language as the rest of the app: solid surface, hairline top rule, amber
   accent tick. Progress is stated three ways — filled bar, percentage, and a sentence — so it
   never relies on colour alone. The achieved state adds a glyph and a glow, not just a hue. */
.goal-card{padding:16px 18px 14px;position:relative;overflow:hidden}
.goal-card::before{content:'';position:absolute;top:0;left:18px;right:18px;height:1px;background:var(--hair)}
.goal-card::after{content:'';position:absolute;top:0;left:18px;width:14px;height:2px;background:var(--amber)}
.goal-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.goal-more{border:0;background:transparent;color:var(--cream);min-width:44px;height:44px;margin:-10px -12px -10px 0;font-weight:800}
.goal-card h3{margin:2px 0 0;font-weight:800;font-size:19px;letter-spacing:-.02em}
.goal-nums{display:flex;align-items:baseline;gap:6px;margin:8px 0 10px}
.goal-nums strong{font-weight:800;font-size:30px;line-height:1;letter-spacing:-.02em;font-variant-numeric:tabular-nums lining-nums}
.goal-nums span{color:var(--taupe);font-size:13px;font-weight:700;font-variant-numeric:tabular-nums lining-nums}
.goal-tick{margin-left:auto;color:var(--amber-deep);font-weight:800;font-size:18px}
.goal-bar{position:relative;height:8px;border-radius:4px;background:var(--glass-2);overflow:hidden;box-shadow:inset 0 1px 2px rgba(0,0,0,.18)}
.goal-bar i{display:block;height:100%;width:calc(var(--p,0)*100%);border-radius:4px;
  background:linear-gradient(90deg,var(--amber-deep),var(--amber),var(--amber-soft));
  box-shadow:none;transition:width .5s var(--ease)}
.goal-foot{display:flex;justify-content:space-between;gap:10px;margin:8px 0 0;color:var(--taupe);font-size:12px}
.goal-pct{color:var(--amber-deep);font-weight:800;font-variant-numeric:tabular-nums lining-nums}
.goal-card.achieved{border-color:rgba(var(--bloom-amber),.5)}
.goal-card.achieved .goal-bar i,.goal-card.met .goal-bar i{background:linear-gradient(90deg,var(--amber),var(--amber-soft))}
.goal-done{margin-top:4px}
.goal-done summary{cursor:pointer;color:var(--taupe);font-size:12px;font-weight:800;letter-spacing:.6px;text-transform:uppercase;padding:10px 2px;min-height:44px;display:flex;align-items:center}
.goal-done .goal-card{margin-top:8px}
.goal-help{margin:10px 0 0;color:var(--taupe);font-size:12px;line-height:1.45}
/* Goal type picker in the new-goal sheet */
.goal-types{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-bottom:14px}
.goal-type{min-height:44px;padding:0 8px;border:1px solid var(--hair);border-radius:var(--r2);background:var(--glass);color:var(--cream);font-weight:700;font-size:13px}
.goal-type.on{background:var(--amber);border-color:var(--amber);color:var(--on-amber);font-weight:800}
/* Today's single nearest goal — a reminder of why you're here, not a list */
.goal-strip{display:block;width:100%;text-align:left;padding:14px 16px;border:1px solid var(--card-hair);border-radius:var(--radius);background:var(--card-bg);box-shadow:var(--glass-edge),var(--shadow);color:var(--cream)}
.goal-strip-top{display:flex;align-items:center;justify-content:space-between;gap:10px}
.goal-strip strong{display:block;font-weight:800;font-size:17px;letter-spacing:-.02em;margin:4px 0 8px}
.goal-strip .goal-bar{display:block;margin-bottom:7px}
.goal-strip small{color:var(--taupe);font-size:12px}
.sync-advanced summary{cursor:pointer;color:var(--taupe);font-size:12px;font-weight:800;letter-spacing:.6px;text-transform:uppercase;min-height:44px;display:flex;align-items:center}

/* ================================================================================================
   APPLE PASS — council 2026-07-23 (brain/decisions/2026-07-23-council-gym-apple-design-language.md)
   Verdict in one line: colour communicates STATE and MEANING; material, type, geometry and motion
   carry IDENTITY. Amber was doing nine jobs at once (eyebrows, rules, borders, timer, buttons,
   completion, all chart ink, links, badges) — when everything is accent, nothing is.

   Semantic families:  amber = training/effort · teal = recovery/secondary · neutral = structure+nav
   Rollback: delete from this banner to EOF.
   ============================================================================================== */

/* --- 1. Concentric radius scale (Codex: nested children must be TIGHTER than their parent, so
   corners read as machined rather than merely rounded). The FORGED pass had drifted to an
   arbitrary 9/13/16/10 — which is exactly why the radius guard was already failing on a 16px
   sheet before this session. One scale now, chosen to KEEP the 16px card look Mark already
   signed off rather than tightening it:   control 8 → row 12 → card 16 → sheet 20.
   Enforced end-to-end by tests/layout-check.mjs (allowed values AND parent > child nesting). --- */
:root{--r1:8px;--r2:12px;--radius:16px;--radius-sm:8px;--r-card:16px;--r-sheet:20px}
.card,.routine-card,.history-card,.week-card,.chart-card,.activity-card,.resume-card,.template-card,
.exercise-row,.metric,.workout-exercise,.trend-card,.checkin-card,.coach-card,.recap-card,.goal-card,
.mv-card,.mv-row,.bal-card,.pr-row,.empty-card,.locked-card,.goal-strip,.receipt-card{border-radius:var(--r-card)}
.sheet{border-radius:var(--r-sheet) var(--r-sheet) 0 0}
.confirm-dialog{border-radius:var(--r-sheet)}
@media(min-width:650px){.sheet{border-radius:var(--r-sheet) var(--r-sheet) 0 0}}

/* --- 2. STRUCTURE GOES NEUTRAL. Eyebrows, section rules and decorative ticks carried accent for
   no informational reason — they only raised the noise floor. Identity now comes from the
   material and the type, so the real amber signals can rise above it. --- */
.kicker,.kicker.accent,.activity-heading .kicker,.coach-top .kicker,.quick-kicker,
.filter-group .kicker,.receipt-next .kicker,.recap-card .kicker{color:var(--taupe)}
.section-heading::after,.metric::after,.live-metric::after,.goal-card::after{background:var(--hair-bright)}
.coach-list li::before{background:var(--taupe)}
/* Decorative amber card borders → neutral. The recap card is a REPORT, not a live control. */
.recap-card.card-live{border-color:var(--card-hair)}

/* --- 3. COMPLETION COLLAPSES INTO CALM (Codex). One state, one mark: a filled tick plus a faint
   tint. The inset amber bar and amber-outlined cells were four extra shouts for the same fact,
   and they left the pending row looking as "done" as the finished one. --- */
.set-row.completed{background:rgba(var(--bloom-amber),.10);box-shadow:none}
.set-row.completed .set-input{background:var(--card-solid);border-color:var(--hair)}
.set-row.completed .set-number{color:var(--taupe)}
/* Tick flashes on completion, then settles so Finish stays the dominant amber on screen. */
.set-done.done{transform:none;background:var(--amber-soft);border-color:var(--amber-soft)}
.set-done.done{animation:tickSettle .5s var(--ease) both}
@keyframes tickSettle{0%{transform:scale(1)}35%{transform:scale(1.14);background:var(--amber)}100%{transform:scale(1)}}
/* "Next up" is guidance, not effort — neutral marker, never a second amber row. */
.set-row.notched{box-shadow:inset 3px 0 0 var(--hair-bright);border:1px solid var(--hair)}

/* --- 4. One accent per intent inside the workout. "+ Add set" is the action; "+ Drop" is a
   variant of it, so it stops competing as a second coloured button. --- */
/* REMOVED: this flattened .add-drop to a bare outline with !important, overriding the design's
   teal-tinted pill above. The design keeps the tint; contrast is verified by the guard. */

/* --- 5. Section heading must never wrap into its action (real collision: "What you're working
   toward" + "New goal" both wrapped and overlapped on Progress). Heading may shrink; the action
   holds its line, always. --- */
.section-heading>div:first-child{min-width:0;flex:1}
.section-heading .text-button{flex:none;white-space:nowrap}

/* --- 6. Empty and locked states join the same left axis as every other card. Centred text was
   the only thing on these screens not aligned to the page's spine. --- */
.empty-card,.locked-card,.recap-locked{text-align:left}
.locked-card .lock-progress,.recap-locked .lock-progress{justify-content:flex-start}

/* --- 7. Charts: history stays ALIVE in low-chroma amber (Codex — neutralising it made past work
   feel inert); today carries full chroma plus its label. Gridlines/axis stay structural. --- */
.bar-col i{background:rgba(var(--bloom-amber),.28)}
.bar-col.active i{background:var(--amber)}

/* --- 8. Rest is RECOVERY (teal), and becomes an action (amber) for the last 10 seconds. The pill
   changes hue AND wording weight, never hue alone — Mark is colour-blind. --- */
.rest-pill span,.rest-pill small{color:var(--teal)}
.rest-pill strong{color:var(--cream)}
.rest-pill.ending{border-color:var(--amber)}
.rest-pill.ending span,.rest-pill.ending small,.rest-pill.ending strong{color:var(--amber-deep)}
.rest-act{color:var(--cream)}

/* --- 9. Richness re-spent on MATERIAL, not pigment (the council's named risk, mitigated).
   A live card already announces itself with a radial amber wash and an inner amber top-light —
   the amber OUTLINE on top of that was a third statement of the same fact, and with two live
   cards stacked on Today it stopped distinguishing anything. Border goes structural; the wash
   and the light (the expensive-looking part) stay. --- */
.card-live{border-color:var(--card-hair)}

/* ================================================================================================
   BOOKENDS + COACH REASONING + DESK RESET: 2026-07-28
   Three new surfaces, because the Apple pass proved a pigment change is invisible: if the app is to
   FEEL different it has to gain surfaces, not re-tint the ones it has (Mark, 2026-07-28).
   Semantic families unchanged (amber = training/effort · teal = recovery/secondary · neutral =
   structure). All three of these are recovery/advisory work, so they are teal, and each one states
   its meaning in WORDS as well as hue: hue is never the only signal ([[user-mark-colourblind]]).
   Concentric scale respected: card 16 → inner panel 12 → control 12.
   Rollback: delete from this banner to EOF.
   ============================================================================================== */

/* Deload advisory. Never blocks anything, so it stays a quiet panel rather than an alert. */
.deload-card{padding:15px 18px;margin-bottom:12px;border-left:3px solid var(--teal)}
.deload-card .kicker{color:var(--teal)}
.deload-card p:last-child{margin:5px 0 0;color:var(--cream-dim);font-size:13px;line-height:1.45}

/* Desk Reset: Start to run it, ••• to see it as a plan and add it to your routines. Row shape, not
   a hero, so it never outranks the coach. The bottom margin is load-bearing: without it the row sat
   flush against the activity card below and the two read as one broken surface (Mark, 2026-07-28).
   Matches the routine card's ••• + Start layout, because it IS the same kind of object. */
.desk-card{display:grid;grid-template-columns:1fr auto;align-items:center;gap:12px;
  margin:12px 0;padding:15px 15px 15px 18px;border-left:3px solid var(--teal)}
.desk-text{border:0;background:transparent;color:inherit;font:inherit;text-align:left;padding:0;min-width:0}
.desk-text strong{display:block;font-weight:800;font-size:16px}
.desk-text small{display:block;margin-top:3px;color:var(--taupe);font-size:12px}
.desk-actions{display:flex;gap:7px}
.desk-start{min-height:44px;border-radius:var(--r1);font-weight:800}

.desk-start{padding:0 15px;border:0;background:var(--teal);color:var(--teal-ink-on);transition:transform .12s var(--ease)}
.desk-start:active{transform:scale(.98)}

/* Warm-up / cool-down strip inside the workout. Sits above the exercises, disappears once taken. */
.bookend-strip{display:flex;align-items:center;justify-content:space-between;gap:14px;
  margin-bottom:12px;padding:13px 15px;border-radius:var(--r-card);
  border:1px dashed var(--hair-bright);background:var(--glass)}
.bookend-strip .kicker{color:var(--teal)}
.bookend-strip small{display:block;margin-top:3px;color:var(--cream-dim);font-size:12px;line-height:1.4}
.bookend-strip button{min-height:44px;padding:0 15px;border-radius:var(--r2);flex:none}

/* The coach's REASONING. It shipped in every plan and was rendered nowhere: numbers with no why. */
.coach-cue{display:block;margin-top:3px;color:var(--taupe);font-size:12px;line-height:1.4;font-weight:500}
.coach-notes{margin:12px 0 0;border-radius:var(--r2);background:var(--glass);border:1px solid var(--hair)}
.coach-notes summary{padding:11px 14px;font-size:12px;font-weight:800;letter-spacing:.6px;
  text-transform:uppercase;color:var(--teal);cursor:pointer;min-height:44px;display:flex;align-items:center}
.coach-notes ul{margin:0;padding:0 14px 12px 30px}
.coach-notes li{color:var(--cream-dim);font-size:12.5px;line-height:1.5;margin-bottom:6px}

/* The routine name is a tap target for the options sheet, not just decoration. Editing a routine
   was reachable only through an unlabelled ••• and went unfound for weeks (Mark, 2026-07-28). */
.routine-open{border:0;background:transparent;padding:0;margin:0;text-align:left;color:inherit;
  min-width:0;font:inherit;transition:opacity .12s var(--ease)}
.routine-open:active{opacity:.65}
.routine-open h3{margin:0;font-weight:800;font-size:17px}
.routine-open p{margin:4px 0 0;color:var(--taupe);font-size:12px}

/* ================================================================================================
   BILLION-DOLLAR PASS - council 2026-07-28 (brain/decisions/2026-07-28-council-gym-billion-dollar-pass.md)
   The receipt gains its verdict layer: what changed TODAY, computed from evidence. Semantic
   families hold: amber = advance (effort won), teal = recovery/backed-off, neutral = held/baseline.
   Words always carry the meaning; hue never stands alone. Rollback: delete from this banner to EOF.
   ============================================================================================== */
.receipt-verdict{margin:14px 0 4px;padding:13px 15px;border-radius:var(--r2);background:var(--glass-2);
  border-left:3px solid var(--taupe)}
.receipt-verdict strong{display:block;font-weight:800;font-size:22px;letter-spacing:-.02em}
.receipt-verdict small{display:block;margin-top:4px;color:var(--cream-dim);font-size:12.5px;
  font-variant-numeric:tabular-nums lining-nums}
.receipt-verdict-advanced{border-left-color:var(--amber)}
.receipt-verdict-advanced strong{color:var(--amber-deep)}
.receipt-verdict-backed-off{border-left-color:var(--teal)}
.receipt-verdict-backed-off strong{color:var(--teal)}

/* One shared cue under the coach list, replacing six identical rows of it. */
.coach-cue-shared{margin-top:10px;padding-top:10px;border-top:1px solid var(--hair)}

/* ================================================================================================
   NAV MOTION GRAMMAR - council 2026-07-28 round 2 (same decision note as the billion-dollar pass).
   Codex verdict accepted: immediate response + invariant frame pacing beats cinematic transitions.
   Incoming view only, pure CSS, no snapshots, no JS handlers. Direction = spatial tab order.
   Rollback: delete from this banner to EOF.
   ============================================================================================== */
/* The cursor is now a LIT surface, not a flat wash: gradient fill, inner top-light, soft amber
   under-glow, and a light spring overshoot on the slide (Codex: heavy overshoot reads rubbery). */

/* Active icon: colour + 1px lift, without an ambient glow. Stroke weight stays stable. */
.bottom-nav button.active svg{filter:none}
.bottom-nav button{transition:color .2s var(--ease),transform .12s var(--ease)}
.bottom-nav button:active{transform:scale(.97)}
/* The w22 tab-swap grammar (`view-in`, a 200ms fade + 8px rise) was DELETED 2026-08-03 rather than
   shadowed by the SLICE PANE block at the end of this file. Two rules animating the same element is
   the exact bug that made the swap feel unclean in the first place; leaving a dead one behind for a
   later reader to resurrect would repeat it. The cross-dissolve is now the only pane grammar. */

/* Starter rows (council 2026-07-28): a module with no evidence keeps its address but compresses to
   one quiet line - it stops impersonating valuable content before any exists. Actionable ones are
   real buttons with the chevron; density returns the moment real data arrives. */
.starter-row{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;
  padding:13px 16px;text-align:left;min-height:52px}
.starter-row span{min-width:0}
.starter-row strong{display:block;font-size:14px;margin:0;color:var(--cream)}
.starter-row small{display:block;margin-top:2px;color:var(--taupe);font-size:12px;line-height:1.35}
.starter-row b{flex:none;color:var(--taupe);font-size:19px;font-weight:700;line-height:1}

/* Return chip (2026-07-28): the always-there way back to a live session, replacing the confirm()
   dialog that fired on every mid-workout tab switch. Rides above the nav on every tab; amber dot
   pulses while the clock runs, goes still + labelled when paused (never hue alone). */
.return-chip{position:fixed;z-index:19;left:50%;transform:translateX(-50%);
  bottom:calc(max(10px,env(safe-area-inset-bottom)) + var(--nav-height) + 8px);
  width:calc(100vw - 24px);max-width:736px;min-height:52px;
  display:flex;align-items:center;gap:11px;padding:9px 15px;text-align:left;
  border:1px solid var(--card-hair);border-radius:var(--r2);color:var(--cream);
  background:var(--glass-tint);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);
  box-shadow:var(--glass-edge),var(--shadow);transition:transform .12s var(--ease)}
.return-chip:active{transform:translateX(-50%) scale(.98)}
.return-chip[hidden]{display:none}
.rc-dot{flex:none;width:9px;height:9px;border-radius:50%;background:var(--amber);
  box-shadow:none}
@media (prefers-reduced-motion: no-preference){.rc-dot{animation:rc-pulse 1.6s ease-in-out infinite}}
.rc-dot.rc-paused{background:var(--taupe);box-shadow:none;animation:none}
.rc-text{flex:1;min-width:0}
.rc-text strong{display:block;font-weight:800;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rc-text small{display:block;margin-top:1px;color:var(--taupe);font-size:11.5px;font-variant-numeric:tabular-nums lining-nums}
.return-chip b{flex:none;color:var(--taupe);font-size:19px;font-weight:700;line-height:1}
@keyframes rc-pulse{0%,100%{opacity:1}50%{opacity:.45}}

/* Drag to reorder (2026-08-01). The grip is the ONLY drag surface: touch-action:none is scoped to it
   so the card body keeps its taps and the page keeps its scroll. Neutral ink, never a hue signal. */
.exercise-head{gap:4px}
.exercise-head>div{flex:1;min-width:0}
.exercise-grip{flex:none;width:44px;height:44px;margin:-6px 0 0 -10px;display:grid;place-content:center;
  border:0;border-radius:var(--r1);background:transparent;color:var(--taupe);touch-action:none}
.exercise-grip svg{width:10px;height:16px;display:block;fill:currentColor}
body.reordering{-webkit-user-select:none;user-select:none}
.workout-exercise.drag-lift{z-index:30;transition:none;box-shadow:var(--glass-edge),0 22px 44px -14px rgba(0,0,0,.55)}
/* Slight overshoot on the settle: --ease has no bounce, and a dead-stop drop reads as a glitch. */
.workout-exercise.drag-settle{transition:transform .22s cubic-bezier(.2,1.12,.34,1)}

/* ---- Curated workouts (council 2026-08-01) ----
   Card = one surface, two targets: the body opens the detail sheet, the amber pill starts it in one
   tap. Amber is effort (Start); the goal tag, blurb and meta line stay neutral structure. */
/* Compact workout cards (Mark 2026-08-02): goal + name + meta only, Start as a 44px corner glyph.
   Two columns even on small phones - the whole point is less scrolling. */
.workout-card{position:relative;display:block;min-height:0;padding:0;overflow:hidden}
.workout-open{width:100%;text-align:left;color:inherit;background:transparent;border:0;padding:13px 50px 12px 14px}
/* Design: the row's play control is a 44x44 r15 TILE tinted rgba(var(--am),.15) with --acc ink - it
   is not a bare glyph. This rule had flattened it to transparent. */
.workout-card .workout-start{position:absolute;top:6px;right:6px;width:44px;height:44px;margin:0;display:grid;place-items:center;border:0;border-radius:15px;background:rgba(var(--am),.15);color:var(--acc);font-size:11px}
.workout-card .workout-start svg{width:20px;height:20px}
/* Plans ride a horizontal shelf: one row of swipeable posters instead of a stack of full cards. */
#planList{grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:min(76%,290px);overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;margin:0 calc(var(--gutter)*-1);padding:2px var(--gutter) 6px}
#planList::-webkit-scrollbar{display:none}
#planList .plan-card{scroll-snap-align:start;min-height:118px}
/* Design: 11.5px, regular weight, no uppercasing - it reads 'strength - 55 min - 5 lifts'. Ink is
   --faint not the design's --mut2, which measures 4.47:1 (documented AA deviation). */
.workout-meta{margin-top:7px;color:var(--faint);font-size:11.5px;font-weight:400;text-transform:none;font-variant-numeric:tabular-nums lining-nums}
.workout-mins{margin:6px 0 10px;color:var(--taupe);font-size:12px;font-weight:700;font-variant-numeric:tabular-nums lining-nums}
/* Quiet, permanent, never a warning: structure copy, not a disclaimer banner. */
.workout-disclaimer{margin:14px 0 0;color:var(--taupe);font-size:11px;line-height:1.5}
/* The plan restated inside the teal previous-strip - neutral ink so it never reads as a target. */
.plan-line{display:block;margin-top:5px;padding-top:5px;border-top:1px solid rgba(11,110,119,.18);color:var(--cream-dim);font-weight:600}
/* Three fixed segments, no scroll: the row does not need the edge bleed or the fade mask. */
.vol-seg{margin:10px 0 4px;padding:0;-webkit-mask-image:none;mask-image:none}

/* ============================================================
   SLICE NAV pass (2026-08-02) - Mark: "the slice co bottom nav
   bar is a million times better... exact copy".
   Ported 1:1 from the LIVE sliceco.app tabbar (VPS
   /var/www/sliceco/app.html, style#slice-glass-p01, read
   2026-08-02): floating inset 999px capsule, glass sheen +
   blur/saturate/brightness, per-tab concentric pill that springs
   in (NOT a sliding cursor), icon spring + stroke thickening,
   labels fade only, transform-only minimise on scroll-down.
   Pigment is the ONLY substitution: SliceCo lime -> gym amber,
   because the semantic families (amber = training/effort) and
   Mark's CVD-safety rule outrank an exact hue copy. Every
   geometry, duration, easing curve and cue is SliceCo's.
   Rollback: delete everything below this banner.
   ============================================================ */
:root{
  --nav-height:58px;                       /* SliceCo --tabbar-h, fixed: minimise is transform-only */
  /* Every bottom-anchored surface reads this ONE token, and the probe in app.js
     re-writes it on the root when env() lies. Fallback keeps CSS-only correct. */
  --sai-bottom:env(safe-area-inset-bottom,0px);
  --nav-inset:calc(10px + var(--sai-bottom));
  --nav-sheen:linear-gradient(to bottom,rgba(255,255,255,.30),rgba(255,255,255,.04) 55%);
  --nav-rim:rgba(255,255,255,.70);
  --nav-edge:rgba(20,15,8,.10);
  --nav-glass-shadow:0 8px 32px rgba(60,45,25,.14),0 2px 8px rgba(60,45,25,.07);
  --nav-spring:cubic-bezier(.34,1.56,.64,1);
  /* The MATERIAL, and the reason this is glass rather than a lozenge: the bar must be
     translucent or the backdrop-filter has nothing to refract. --glass-solid (#FBF7EF /
     #1a140d) is opaque, which read as a flat brown capsule on the first render - content
     stopped dead at its edge. SliceCo's alphas, gym's own base hues. --nav-lumin lifts
     what is behind light glass and leaves dark glass neutral, so it never darkens
     already-dark content. */
  --nav-glass:rgba(251,247,239,.55);
  --nav-lumin:1.06;
}
@media(prefers-color-scheme:dark){:root{
  --nav-sheen:linear-gradient(to bottom,rgba(255,255,255,.09),rgba(255,255,255,.02) 55%);
  --nav-rim:rgba(255,255,255,.16);
  --nav-edge:rgba(255,255,255,.09);
  --nav-glass-shadow:0 8px 32px rgba(0,0,0,.55),0 2px 8px rgba(0,0,0,.35);
  --nav-glass:rgba(26,20,13,.58);
  --nav-lumin:1;
}}
/* The capsule. left/right insets + margin-inline:auto keeps it centred at max-width
   WITHOUT a translateX, so transform is free for the minimise (SliceCo relies on the
   same thing; its bar is absolute inside .device). */
.bottom-nav{
  left:14px;right:14px;width:auto;max-width:736px;margin-inline:auto;
  bottom:var(--nav-inset);
  height:var(--nav-height);
  padding:0 6px;
  display:flex;align-items:center;justify-content:space-around;
  border:0.5px solid var(--nav-edge);
  border-radius:999px;
  background-image:var(--nav-sheen);
  background-color:var(--nav-glass);
  -webkit-backdrop-filter:blur(24px) saturate(180%) brightness(var(--nav-lumin));
  backdrop-filter:blur(24px) saturate(180%) brightness(var(--nav-lumin));
  box-shadow:inset 0 1px 0 var(--nav-rim),var(--nav-glass-shadow);
  overflow:hidden;
  transform:none;
  transform-origin:50% 100%;
  will-change:transform;
  transition:transform 360ms var(--nav-spring),box-shadow .3s ease;
}
/* Minimise: transform ONLY, so layout never shifts and no clearance ever churns. */
body.nav-min .bottom-nav{transform:scale(.80) translateY(6px)}

.bottom-nav button{
  flex:1 1 0;min-width:0;height:100%;
  padding:0 8px;gap:3px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  position:relative;isolation:isolate;           /* REQUIRED: z-index:-1 pill vs the blurred bar */
  border-radius:999px;
  /* Matched to the design (design/extracted/today.html): its nav buttons carry NO font of their own,
     so they compute to the UA button default and the 10px/700 <small> sets the label size; and the
     idle ink is --mut2, not --mut. Ours inherited 15px/500 from the global button rule. */
  font-size:13.3333px;font-weight:400;color:var(--mut2);
  transition:color 200ms,transform 120ms var(--nav-spring),opacity 150ms ease;
}
/* Concentric glass pill behind the active tab (capsule-in-capsule). Active keeps THREE
   non-colour cues - pill shape, thicker stroke, icon scale - so amber is never the only signal. */
.bottom-nav button::before{
  content:"";position:absolute;inset:7px 3px;z-index:-1;
  border-radius:999px;
  background:rgba(var(--bloom-amber),.14);
  box-shadow:inset 0 1px 0 var(--nav-rim),inset 0 0 0 0.5px var(--nav-edge);
  opacity:0;transform:scale(.7);transform-origin:center center;
  transition:opacity 200ms,transform 320ms var(--nav-spring);
}
.bottom-nav button.active::before{opacity:1;transform:scale(1)}
body.nav-min .bottom-nav button::before{inset:10px 6px}
.bottom-nav button span{display:flex}
.bottom-nav button svg{width:24px;height:24px;transition:transform 320ms var(--nav-spring)}
.bottom-nav button.active svg{transform:scale(1.10);stroke-width:2.2;filter:none}
/* Labels come BACK (SliceCo shows them at rest) and never move - fade only. */
.bottom-nav button small{position:static;opacity:1;transform:none;pointer-events:none;font-size:10px;font-weight:700;line-height:1;transition:opacity 180ms ease}
body.nav-min .bottom-nav button small{opacity:0}
body.nav-min .bottom-nav button svg{transform:translateY(7px)}
body.nav-min .bottom-nav button.active svg{transform:translateY(7px) scale(1.10)}
/* Press (SliceCo): light depress + opacity tick + icon dip. Overrides the 3-role veil press. */
.bottom-nav button:active{transform:scale(.97);opacity:.72;box-shadow:none}
.bottom-nav button.active:active{opacity:.9}
.bottom-nav button:active svg{transform:scale(.86)}
.bottom-nav button.active:active svg{transform:scale(.96)}
/* Things anchored above the bar follow the new inset. */
#returnChip{bottom:calc(var(--nav-inset) + var(--nav-height) + 8px)}
.update-pill{bottom:calc(var(--nav-inset) + var(--nav-height) + 14px)}
.app-shell{padding-bottom:calc(var(--nav-height) + 44px + var(--sai-bottom))}
/* The other bottom-anchored surfaces, moved off raw env() for the same reason: on a
   standalone Android PWA env() reports 0 and they sit under the system nav buttons. */
body.workout-active .update-pill{bottom:calc(14px + var(--sai-bottom))}
.sheet-scroll{padding-bottom:max(22px,var(--sai-bottom))}
.receipt-card{margin-bottom:max(18px,var(--sai-bottom))}
/* The rest pill only shows mid-workout, where the nav is hidden - it needs the
   system-bar clearance, NOT nav clearance. */
.rest-pill{bottom:max(14px,var(--sai-bottom))}
/* Without backdrop-filter, translucency has nothing behind it but raw content - the
   earlier @supports fallback said so, but this block comes later and would have won.
   Restated here so the no-blur path stays opaque and legible. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .bottom-nav{background-color:var(--glass-solid);background-image:none}
}
@media(prefers-reduced-motion:reduce){
  body.nav-min .bottom-nav{transform:none}
  .bottom-nav,.bottom-nav button,.bottom-nav button::before,.bottom-nav button svg,.bottom-nav button small{transition:none}
}

/* ============================================================
   SLICE PANE pass (2026-08-03) - Mark: "there's still a weird
   flash when I swap tabs... a block around the section... the
   SliceCo one feels so much smoother, why?"
   Because of two things this block deletes.
   1. `.view.active>*{animation:rise .35s both}` (line ~56) ran a
      SEPARATE entrance on every direct child, staggered out to a
      0.2s delay. Fill-mode `both` pins each child at opacity 0
      through its delay, so a swap was 550ms of rectangles punching
      in one at a time - the "blocks". The w22 pass killed two
      fighting PARENT animations and never saw this child rule,
      which is why it survived every previous cleanup.
   2. The incoming view was hard-swapped out of display:none with
      nothing covering the gap - one bare frame, read as a flash.
   REWRITTEN 2026-08-03 (council, Codex's design won): the first
   port copied SliceCo's crossfade mechanism but not the conditions
   that make it invisible there. With BOTH panes semi-transparent
   over the page for ~200ms, two text-heavy screens whose headlines
   sit in the same spot blended into legible text-over-text - Mark's
   screenshot caught Library's search bar readable through Train's
   cards. And because this app scrolls the PAGE (SliceCo scrolls an
   inner container), a leaver pinned to top:0 teleported to its own
   top when navigate() reset the scroll - a flash of content you
   were not even looking at.
   THE CURTAIN WAS ALSO WRONG, and it was mine (measured
   2026-08-03, w25 -> w26). It painted flat `var(--page)` =
   rgb(13,14,16). But this app's real background is that colour
   PLUS two fixed radial blooms at z-index -1 (amber at 16%
   opacity). So an opaque curtain HID THE BLOOM, and fading it out
   washed a 16% amber tint back across the entire screen over
   160ms. Every tab tap changed the whole background. That was the
   flash Mark kept seeing, on the website as well as the PWA.
   ANY opaque full-screen overlay is incompatible with a
   translucent-content-over-bloom design. So there is no overlay.
   The swap is now what the fuel app does and what Mark says feels
   smooth: a plain synchronous display swap, no leaving element at
   all, plus a 14px directional slide on the incoming pane. The
   w24 premise that a hard swap leaves a bare frame was simply
   false - display:none -> block inside one tick paints ONE
   complete frame, there is no gap to cover.
   Kept from the SliceCo port: the slide distance/curve, and the
   "water droplet" pressRing (scale .6 to 1.4, fade, 550ms, fired
   on pointerdown) on the nav tabs.
   Rollback: delete everything below this banner.
   ============================================================ */
:root{--ease-ios:cubic-bezier(.22,1,.36,1)}
/* Children never carry their own entrance - one object moves, not N. */
.view.active>*{animation:none}
/* The DIRECTIONAL slide is gone (2026-08-04). The prototype has no left/right pane grammar at all -
   its only view animation is `gvIn`, one entrance regardless of direction. Keeping both meant two
   rules animating .view.active again, which is the precise shape of the w22 "doesn't look clean"
   bug. One grammar, and it is the design's. `gvIn` is declared with the other view rules above. */
@media (prefers-reduced-motion: reduce){.view.active{animation:none!important}}
/* The water droplet. SliceCo's pressRing verbatim (keyframes + .55s + fire-on-pointerdown);
   ring is element-centred like SliceCo's, inset to hug the tab's pill. --ease IS SliceCo's
   --ease-out curve (.16,1,.3,1) - same numbers, pre-existing token. The bar's overflow:hidden
   clips the ring at the capsule edge exactly as SliceCo's tabbar does. */
.bottom-nav button::after{
  content:"";position:absolute;inset:5px 1px;z-index:-1;
  border-radius:999px;border:1.5px solid var(--amber);
  opacity:0;transform:scale(.6);pointer-events:none;
}
.bottom-nav button.ring::after{animation:pressRing .55s var(--ease) forwards}
@keyframes pressRing{0%{transform:scale(.6);opacity:.55}100%{transform:scale(1.4);opacity:0}}
@media (prefers-reduced-motion: reduce){.bottom-nav button.ring::after{animation:none}}

/* ============================================================
   v2 "INSTRUMENT" TOKEN BLOCK (design/HANDOFF.md §1, ported 2026-08-03)
   Appended last so it wins over every earlier :root layer, matching this
   file's established convention. Rollback: delete everything below this banner.

   Polarity note: HANDOFF authors dark-first with a `prefers-color-scheme: light`
   override. This stylesheet is light-first with a dark override, and flipping it
   would fight the documented `color-scheme:light dark` white-flash fix at the top
   of this file for zero visual gain. Both schemes stay fully token-paired, which
   is what the rule is actually protecting. Values below are HANDOFF's, assigned
   to whichever side of the existing split they belong to.

   TWO DELIBERATE DEVIATIONS FROM HANDOFF, both because a machine gate disagrees
   with it and the gate is measurably right:

   1. --faint STAYS #868D94. HANDOFF proposes a 3-step quiet scale
      (#7d848b / #6b7279 / #5f666d) claiming "all >=4.5:1 on the new surfaces".
      Measured against the new OPAQUE card, worst realistic surface being the
      group inset over a card (#1c1e20):
          #7d848b 4.42:1   #6b7279 3.43:1   #5f666d 2.87:1   #868D94 4.98:1
      The first three are AA failures for normal text - the same failures this
      file already documents at line ~33 (#7E858C 4.29:1, #6B7178 3.25:1). The
      brief's own verification rule says "stay at or above #868D94", so the quiet
      hierarchy is expressed from the BRIGHT end (--cream-dim > --taupe > --faint)
      rather than by sinking below the AA floor. Enforced by tests/contrast-guard.mjs.

   2. Radius scale is snapped to the concentric law {0,8,12,16,20} that
      tests/layout-check.mjs enforces (council 2026-07-23). HANDOFF asks for
      22 cards / 20 groups / 16 buttons / 15 controls / 13 chips; 22, 15 and 13 are
      off that scale. HANDOFF's RELATIVE hierarchy is kept, snapped to the sanctioned
      steps: card 20 > group/button 16 > control/chip 12. Cards still get visibly
      rounder (16 -> 20), which is the design intent.
      TODO(design): if 22/15/13 are load-bearing rather than approximate, the
      concentric scale itself needs a council decision - it is enforced end-to-end,
      so widening it is not a CSS-only change.
   ============================================================ */
:root{
  /* Light scheme (this file's base). Paired 1:1 with the dark block below. */
  --card-bg:linear-gradient(180deg,#FFFFFF,#FBF7EF);
  --card-hair:rgba(20,15,8,.10);
  /* Primary CTA, read straight out of the running prototype in BOTH schemes (2026-08-04). The design's
     CTA is a 135deg amber gradient with an inset white top-light and NO drop shadow; ours was flat
     var(--amber) with a 20px cast, which is what made it read as a different button. */
  --cta-grad:linear-gradient(135deg,#EF8A3D,#C85F14);
  --cta-ink:#211C17;
  --group-bg:rgba(20,15,8,.035);
  --hair:rgba(20,15,8,.09);
  /* One soft cast + a top light, replacing the old 3-layer stack. Shadow alphas in
     HANDOFF are authored for dark (.85-.95); light gets the warm near-surface tint
     (--sh 224,214,194) instead of black so the page stays airy. */
  --shadow:0 18px 40px -20px rgba(140,122,92,.28),inset 0 1px 0 rgba(255,255,255,.90);
  --r-card:20px;--r-group:16px;--r-control:12px;--r-chip:12px;
  /* Teal twin of the existing --amber-deep: an OUTLINE control tints its own background, and
     --teal (#0B6E77) on that tint measures 4.29:1 in light - an AA fail the contrast guard caught.
     Same trick the amber pair already uses: the fill stays --teal, the INK goes darker. 5.53:1. */
  --teal-deep:#095C63;
  --chip-bg:rgba(20,15,8,.05);   /* UP NEXT chip fill, measured off the prototype (dark .055) */
  /* Third ink step (the prototype's --ink3): quieter than --cream-dim, but legible on the AMBER-TINTED
     set rows where --faint/--taupe fail. Worst surface is the PR row's 20%% amber wash:
     light #5A5348 = 6.09:1, dark #A7AEB5 = 5.27:1. Used by the hung unit labels. */
  --ink-quiet:#5A5348;
}
@media(prefers-color-scheme:dark){:root{
  --page:#0B0C0D;
  --card-bg:linear-gradient(180deg,#1a1d20,#141618);
  --card-hair:rgba(255,255,255,.07);
  --cta-grad:linear-gradient(135deg,#FFB070,#FF7A24);
  --cta-ink:#1A1206;
  --group-bg:rgba(255,255,255,.035);
  --hair:rgba(255,255,255,.06);
  --shadow:0 18px 40px -20px rgba(0,0,0,.9),inset 0 1px 0 rgba(255,255,255,.08);
  --teal-deep:#2EC5E0;   /* dark scheme: the bright teal already measures 7.49:1 on its own tint */
  --chip-bg:rgba(255,255,255,.055);
  --ink-quiet:#A7AEB5;
}}

/* ============================================================
   v2 TODAY — charge ring, UP NEXT card, grouped inset list
   (design/HANDOFF.md §2 "Today"). Rollback: delete to the next banner.
   All motion here is transform/opacity or stroke-dashoffset only and is killed
   by the global prefers-reduced-motion rule (line ~281, !important).
   ============================================================ */

/* ---- One charge ring replaces the three arc gauges ----
   Outer arc = sessions + volume, inner = completed sets, centre = the average.
   Strokes reuse the gradients already declared in index.html <defs>, so this
   introduces no hardcoded colour. Sized in vw with a hard cap so the ring can
   never out-grow its scroller. */
.charge-ring{position:relative;width:min(250px,72vw);aspect-ratio:1;margin:2px auto 0}
.charge-ring svg{width:100%;height:100%;display:block;transform:rotate(-90deg)}
.cr-track{fill:none;stroke:var(--hair);stroke-width:10}
.cr-track-in{stroke-width:4.5}
.cr-arc{fill:none;stroke-linecap:round;transition:stroke-dashoffset 1.1s var(--ease)}
.cr-out{stroke:url(#ringGradWorkouts);stroke-width:10;filter:none}
.cr-in{stroke:url(#ringGradSets);stroke-width:4.5;transition-delay:.1s;filter:drop-shadow(0 0 6px rgba(var(--bloom-teal),.42))}
.cr-centre{position:absolute;inset:0;display:grid;place-content:center;gap:1px;
  border:0;background:transparent;color:inherit;cursor:pointer;padding:0}
.cr-centre .hero-num{font-size:clamp(38px,14vw,54px);font-weight:800;letter-spacing:-.05em;line-height:1;
  font-variant-numeric:tabular-nums lining-nums}
.cr-centre .cr-pct{font-size:23px;font-weight:800;letter-spacing:-.02em;margin-left:1px}
.cr-num{display:flex;align-items:baseline;justify-content:center;gap:1px}
.cr-centre>small{display:block;margin-top:5px;font-size:10.5px;font-weight:700;letter-spacing:.13em;color:var(--taupe)}
/* Legend: each entry names its metric and prints its numbers, so the two arcs are
   never told apart by colour alone (CVD rule). Shapes differ too - thick vs thin. */
.activity-legend{display:flex;flex-wrap:wrap;justify-content:center;gap:8px 18px;margin-top:10px}
.cr-key{display:flex;align-items:center;gap:7px;font-size:11.5px;font-weight:600;color:var(--taupe)}
.cr-key i{width:9px;height:9px;flex:none;border-radius:50%;display:block}
.cr-key-out i{background:var(--amber)}
.cr-key-in i{width:9px;height:4px;border-radius:2px;background:var(--teal)}

/* ---- UP NEXT card: exercise chips + one full-width CTA ---- */
/* The design's UP NEXT card, measured: 350x264, radius 22, a 1px rgba(var(--w),.07) hairline and the
   --c1 -> --c2 vertical gradient. 22 is the design's own number, not our old concentric 20. */
.up-next{padding:0;overflow:hidden;border-radius:22px;
  background:linear-gradient(180deg,var(--c1),var(--c2));border:1px solid rgba(var(--w),.07)}
.up-next-body{padding:18px 18px 14px}
.up-next .coach-top{display:flex;align-items:baseline;gap:10px}
.up-next-src{margin-left:auto;color:var(--faint);font-size:11px;font-weight:600}
.up-next h2{margin:8px 0 0;font-size:21px;font-weight:800;letter-spacing:-.028em}
.next-chips{display:flex;gap:6px;margin-top:12px;flex-wrap:wrap}
.next-chip{display:inline-flex;align-items:baseline;gap:5px;padding:5px 10px;border-radius:var(--r-chip);
  background:var(--group-bg);border:1px solid var(--card-hair);color:var(--cream-dim);font-size:11.5px;font-weight:600}
.next-chip b{color:var(--taupe);font-weight:700;font-variant-numeric:tabular-nums lining-nums}
/* Missing-from-library reads as italic + muted + the word "skipped" (in the name), never colour. */
.next-chip-skip{font-style:italic;color:var(--faint)}
.next-chip-more{color:var(--faint)}
.up-next .coach-cue{display:block;margin-top:10px;color:var(--faint);font-size:12px;line-height:1.5}
/* The design's CTA is a 135deg gradient with an inset white top-light and NO drop shadow, full-bleed
   at the bottom of the card so the card's own radius clips it (hence border-radius:0). Values read
   from the running prototype in both schemes, not inferred. */
.up-next-cta{display:block;width:100%;min-height:56px;border:0;border-radius:0;font-size:16.5px;font-weight:800;letter-spacing:-.01em;
  background:var(--cta-grad);color:var(--cta-ink);box-shadow:inset 0 1px 0 rgba(255,255,255,.35)}
.up-next 

/* ---- Grouped inset list (Desk Reset + last session) ---- */
.group{border-radius:var(--r-group);background:var(--group-bg);border:1px solid var(--card-hair);overflow:hidden}
.group[hidden]{display:none}
.group>div:not(:last-child) .group-row{border-bottom:1px solid var(--hair)}
/* The design's group rows are padding:14px 16px (design/extracted/today.html). */
.group-row{display:flex;width:100%;align-items:center;gap:12px;min-height:56px;padding:14px 16px;
  border:0;background:transparent;color:var(--cream);text-align:left;font:inherit}
.row-glyph{width:34px;height:34px;flex:none;border-radius:var(--r-control);display:grid;place-items:center;
  font-size:14px;font-weight:800;font-style:normal}
.row-glyph-teal{background:rgba(var(--bloom-teal),.14);color:var(--teal-deep)}
.row-glyph-amber{background:rgba(var(--bloom-amber),.14);color:var(--amber-deep)}
.row-text,.desk-text{flex:1;min-width:0;display:block}
.row-text strong,.desk-text strong{display:block;font-size:14.5px;font-weight:700;letter-spacing:-.01em}
.row-text small,.desk-text small{display:block;margin-top:2px;color:var(--faint);font-size:11.5px;line-height:1.35}
.row-chev{color:var(--taupe);font-size:18px;flex:none}
.group-row-empty{color:var(--faint)}
/* Both actions keep a full 44px target even though the ••• glyph is small. */


/* Geometry verbatim from the design (14px radius, 44x64 minimums, its rgba(var(--tl),...) fill).
   DELIBERATE DEVIATION, contrast: the design's own --teal ink on that 10% tint measures 4.28:1 in
   LIGHT mode, under AA. Mark is colour-blind and the contrast rule does not bend for a mockup, so the
   ink is the paired --teal-deep. Dark mode is unaffected: --teal-deep is #2EC5E0 there, which IS the
   design's --teal, so dark is byte-identical to the prototype. */
.desk-start{min-width:64px;min-height:44px;padding:0 14px;border-radius:14px;
  border:1px solid rgba(var(--tl),.4);background:rgba(var(--tl),.1);color:var(--teal-deep);font-size:13px;font-weight:800}
/* The group IS the Desk Reset surface in v2, so it wears `.desk-card` (browser-flow's selector).
   Neutralise that class's old standalone-card geometry, keep only its clearance margin. */
.group.desk-card{display:block;grid-template-columns:none;padding:0;border-left:0;margin:12px 0}
/* A history row inside the group is a row, not a card: drop the card background/radius it
   inherits from the shared card rules above. */
.group .history-card{background:transparent;border-radius:0;box-shadow:none;border:0}

/* ============================================================
   v2 WORKOUT COCKPIT (design/HANDOFF.md section 2 "Workout").
   The screen you stare at for hours, so it carries the most life: the current
   exercise is lit, everything finished recedes to a calm done row.
   Every state is shape + word + colour (done = tick + amber fill, next = ring +
   the word NOW, prefilled = italic + muted, drop = DROP, beat = PR, paused =
   the word PAUSED). All motion is transform/opacity/stroke and dies under the
   global prefers-reduced-motion rule. Rollback: delete to the next banner.
   ============================================================ */

/* ---- Sticky header: clock + live volume + session progress + sets-left ---- */
.workout-header{display:block}
.wh-top{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
.wh-id{min-width:0;flex:1}
.wh-name-row{display:flex;align-items:center;gap:8px;min-width:0}
.wh-minimise{width:44px;min-width:44px;height:44px;flex:none;margin:-11px -4px -11px -10px;
  border:0;background:transparent;color:var(--taupe);display:grid;place-items:center;border-radius:var(--r-control)}
.wh-minimise svg{width:16px;height:16px;display:block}
.workout-header h1#workoutTitle{margin:0;min-width:0;font-size:11px;font-weight:800;letter-spacing:.11em;
  text-transform:uppercase;color:var(--taupe);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.workout-clock{margin:2px 0 0;display:flex;align-items:baseline;gap:9px;font-size:36px;font-weight:800;
  line-height:1;letter-spacing:-.03em;font-variant-numeric:tabular-nums lining-nums;color:var(--amber-deep)}
.workout-clock small{flex:none;font-size:12px;font-weight:800;color:var(--taupe);letter-spacing:0;white-space:nowrap}
.wh-progress{display:flex;align-items:center;gap:10px;margin-top:12px}
.wh-progress i{flex:1;height:5px;border-radius:3px;background:var(--hair);position:relative;display:block;overflow:hidden}
.wh-progress i b{position:absolute;left:0;top:0;bottom:0;width:0;border-radius:3px;
  background:linear-gradient(90deg,var(--amber-soft),var(--amber));transition:width .6s var(--ease)}
.wh-progress small{color:var(--cream-dim);font-size:11.5px;font-weight:800;font-variant-numeric:tabular-nums lining-nums}

/* ---- Exercise cards: the active one is lit, the rest recede ---- */
.workout-exercise{position:relative;overflow:hidden;transition:opacity .3s var(--ease),border-color .3s var(--ease)}
/* Receding must NOT be done with opacity: fading the whole card fades its text against the page
   too, and every muted ink inside dropped to ~3.3:1 in BOTH schemes (contrast-guard, 27 failures).
   The hierarchy comes from the lit card GAINING (amber wash, amber border, elevation) while the
   others sit flat and shadowless. Text stays at full strength everywhere. */
.workout-exercise:not(.lit):not(.done-card){box-shadow:none;border-color:var(--hair)}
.workout-exercise.lit{border-color:rgba(var(--bloom-amber),.34);
  background:radial-gradient(130% 90% at 100% 0,rgba(var(--bloom-amber),.13),transparent 58%),var(--card-bg);
  box-shadow:var(--shadow),0 0 0 1px rgba(var(--bloom-amber),.10)}
.exercise-head{display:flex;align-items:flex-start;gap:9px;padding:14px 12px 10px}
.exercise-grip{width:44px;min-width:44px;height:44px;flex:none;display:grid;place-items:center;
  border:0;background:transparent;color:var(--taupe);border-radius:var(--r-control);touch-action:none}
/* Design: 28x28, r9, rgba(var(--am),.18) fill with --acc ink, NO border, 11px/800 tabular. */
/* Design: the UNLIT badge is neutral - r9 on rgba(var(--w),.06) with --mut-family ink (ours stays
   --taupe, the AA-passing equivalent). Only the ACTIVE exercise's badge goes amber: rgba(var(--am),
   .18) with --acc, which measures 6.86:1 on its own fill. My first cut applied the amber to ALL
   badges and the unlit card's grey-ink override landed on an amber fill at 3.83:1 - the guard
   caught it before it shipped. */
.ex-index{width:28px;height:28px;border-radius:9px;background:rgba(var(--w),.06);
  border:0;display:grid;place-items:center;font-size:11px;font-weight:800;
  font-variant-numeric:tabular-nums lining-nums;color:var(--ink3)}  /* design's --mut = 4.42:1 on this fill; --ink3 = 6.35:1, nearest passing step */
.workout-exercise.lit .ex-index{background:rgba(var(--am),.18);color:var(--acc)}
.ex-id{min-width:0;flex:1}
.ex-id h2.exercise-title{margin:0;font-size:19px;font-weight:800;letter-spacing:-.028em;line-height:1.15}
.ex-id p{margin:3px 0 0;color:var(--faint);font-size:12px}
.exercise-more{width:44px;height:44px;flex:none;border:0;border-radius:var(--r-control);
  background:var(--group-bg);color:var(--taupe);font-weight:800;letter-spacing:1.5px;font-size:13px;display:grid;place-items:center}
.ex-rail{position:relative;margin:0 16px 6px;height:4px;border-radius:2px;background:var(--hair);overflow:hidden}
.ex-rail i{position:absolute;left:0;top:0;bottom:0;border-radius:2px;display:block;
  background:linear-gradient(90deg,var(--amber-soft),var(--amber));transition:width .55s var(--ease)}
.ex-count{margin:0 16px 12px;color:var(--faint);font-size:11px;font-weight:700;
  letter-spacing:.06em;font-variant-numeric:tabular-nums lining-nums}

/* ---- Finished exercise collapses to a calm done row ---- */
.workout-exercise.done-card{opacity:1}
.done-row{width:100%;display:flex;align-items:center;gap:12px;min-height:56px;padding:13px 14px;
  border:0;background:transparent;color:var(--cream);text-align:left;font:inherit;touch-action:none}
.done-mark{width:34px;height:34px;flex:none;border-radius:var(--r-control);display:grid;place-items:center;
  font-size:16px;font-weight:800;background:linear-gradient(135deg,var(--amber-soft),var(--amber));color:var(--on-amber)}
.done-row .row-text strong{font-size:15.5px;font-weight:800;letter-spacing:-.02em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.done-row .row-text small{color:var(--taupe);font-variant-numeric:tabular-nums lining-nums}
.done-edit{flex:none;color:var(--faint);font-size:12px;font-weight:700}

/* ---- last-to-target strip, with its delta chip ---- */
.target-strip{margin:0 14px 12px;padding:13px 14px;border-radius:var(--r-group);
  background:linear-gradient(135deg,rgba(var(--bloom-teal),.10),rgba(var(--bloom-teal),.035));
  border:1px solid rgba(var(--bloom-teal),.22)}
.ts-top{display:flex;align-items:center;justify-content:space-between;gap:10px}
.ts-last{color:var(--teal-deep);font-size:12px;font-weight:600;font-variant-numeric:tabular-nums lining-nums}
.ts-delta{flex:none;padding:4px 8px;border-radius:var(--r-chip);background:rgba(var(--bloom-amber),.16);
  color:var(--amber-deep);font-size:10.5px;font-weight:800;letter-spacing:.03em;font-variant-numeric:tabular-nums lining-nums}
.ts-bottom{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:11px;
  padding-top:11px;border-top:1px solid rgba(var(--bloom-teal),.2)}
.ts-today{display:flex;align-items:baseline;gap:8px;min-width:0}
.ts-today small{color:var(--taupe);font-size:10.5px;font-weight:800;letter-spacing:.11em}
.ts-today b{color:var(--amber-deep);font-weight:800;font-size:20px;letter-spacing:-.025em;font-variant-numeric:tabular-nums lining-nums}
.target-strip.blocked{background:var(--danger-soft);border-color:var(--danger)}
.target-strip.blocked .ts-today b{color:var(--danger)}
.why-target{flex:none;min-width:56px;min-height:44px;padding:0 12px;border:1px solid var(--card-hair);
  border-radius:var(--r-control);background:var(--group-bg);color:var(--cream-dim);font-size:12px;font-weight:700}

/* ---- Set rows: 52px values, hung units, one NOW row, 52px done circles ---- */
.set-grid{display:grid;grid-template-columns:38px 1fr 1fr 52px;gap:8px;align-items:center}
.set-grid.header{padding:0 14px 8px;font-size:9.5px;color:var(--faint);text-transform:uppercase;
  letter-spacing:.1em;font-weight:800}
.set-grid.header span:first-child,.set-grid.header span:last-child{text-align:center}
.set-row{position:relative;margin:0 8px 5px;padding:6px;border-radius:var(--r-group);background:transparent;
  transition:background .3s var(--ease),box-shadow .3s var(--ease)}
/* The column is 38px to keep the prototype's rhythm, but the TARGET must be 44. The button is 44
   wide and overhangs 3px into the 8px gutter on each side, so it never reaches the value cell. */
.set-number{display:grid;justify-items:center;align-content:center;gap:2px;border:0;background:transparent;
  color:var(--taupe);width:44px;margin:0 -3px;min-height:44px;border-radius:var(--r-control);padding:0}
.set-number b{font-size:14px;font-weight:800;font-variant-numeric:tabular-nums lining-nums;line-height:1}
.set-number em{font-style:normal;font-size:9px;font-weight:800;color:var(--teal-deep)}
.set-tag{font-size:9px;font-weight:800;letter-spacing:.04em;line-height:1;color:var(--faint)}
.set-cell{position:relative;display:block}
.set-input{width:100%;height:52px;border:1px solid var(--card-hair);border-radius:var(--r-control);
  background:var(--group-bg);color:var(--cream);text-align:center;font-size:20px;font-weight:800;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums lining-nums;padding:0 14px 0 0;
  -moz-appearance:textfield;transition:border-color .25s,background .25s,color .25s}
.set-input::-webkit-outer-spin-button,.set-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
/* The unit hangs to the right of the number so the digits stay optically centred in the cell. */
.set-unit{position:absolute;right:8px;bottom:15px;font-size:10px;font-weight:700;line-height:1;color:var(--ink-quiet);pointer-events:none}
.set-row.prefilled .set-input{font-style:italic;color:var(--faint)}
.set-row.now{background:rgba(var(--bloom-amber),.09);box-shadow:inset 3px 0 0 var(--amber)}
.set-row.now .set-input{border-color:rgba(var(--bloom-amber),.45)}
.set-row.now .set-tag{color:var(--amber-deep)}
.set-row.completed{background:rgba(var(--bloom-amber),.13)}
.set-row.completed .set-input{border-color:rgba(var(--bloom-amber),.28);color:var(--cream)}
.set-row.beats{background:rgba(var(--bloom-amber),.2)}
.set-row.beats .set-tag{color:var(--amber-deep)}
.set-row.drop-set .set-tag{color:var(--teal-deep)}
.set-done{width:52px;height:52px;justify-self:center;border:1.5px solid var(--card-hair);border-radius:50%;
  background:var(--group-bg);color:var(--taupe);font-size:20px;font-weight:800;display:grid;place-items:center;
  transition:background .25s,border-color .25s,transform .18s cubic-bezier(.34,1.56,.64,1)}
.set-done:active{transform:scale(.92)}
.set-done.done{background:linear-gradient(135deg,var(--amber-soft),var(--amber));border-color:transparent;
  color:var(--on-amber);box-shadow:none}
.set-footer{display:flex;gap:8px;padding:12px 14px 16px}
/* v2 rules, now carrying the design's values so the earlier block cannot be silently undone:
   both h46 r15; Add set on rgba(var(--w),.05)+.07 edge with --acc; Drop teal-tinted, borderless. */
.add-set{flex:1;min-height:46px;border:1px solid rgba(var(--w),.07);border-radius:15px;
  background:rgba(var(--w),.05);color:var(--acc);font-weight:800;font-size:14px}
.add-drop{flex:none;padding:0 16px;min-height:46px;border:1px solid rgba(var(--tl),.35);border-radius:15px;
  background:rgba(var(--tl),.09);color:var(--teal2);font-weight:800;font-size:14px}

/* ---- RIR row: 0 to 4+ AND Skip, each a full 44px target ---- */
.rir-row{margin:10px 14px 0;padding:13px 14px;border-radius:var(--r-group);
  background:linear-gradient(135deg,rgba(var(--bloom-amber),.16),rgba(var(--bloom-amber),.05));
  border:1px solid rgba(var(--bloom-amber),.3)}
.rir-label{display:block;font-size:12.5px;font-weight:700;color:var(--amber-deep)}
.rir-help{display:block;margin-top:3px;color:var(--taupe);font-size:11px;font-weight:600}
.rir-chips{display:flex;gap:6px;margin-top:10px}
.rir-chip{flex:1;min-height:44px;border:1px solid var(--card-hair);border-radius:var(--r-control);
  background:var(--group-bg);color:var(--cream);font-size:14px;font-weight:800;
  font-variant-numeric:tabular-nums lining-nums}
.rir-note{display:flex;flex-direction:column;gap:2px;margin:10px 14px 0;min-height:44px;padding:8px 14px;
  border:1px solid var(--card-hair);border-radius:var(--r-control);background:var(--group-bg);
  color:var(--cream-dim);font-size:12.5px;font-weight:700;text-align:left}
.rir-note small{color:var(--faint);font-size:11px;font-weight:600}

/* ---- Swap note in the picker sheet ---- */
.swap-note{margin:0 0 10px;color:var(--taupe);font-size:12.5px}
.swap-note strong{color:var(--cream)}

/* ---- Rest: full-width pill with a countdown ring ---- */
/* NB: no `display` here. The pill is display:none until .show is added (line ~102); setting
   display:flex in this rule made it permanently visible and it ate the bottom-nav taps. */
.rest-pill{left:14px;right:14px;width:auto;align-items:center;gap:12px;padding:11px 12px 11px 14px;
  border-radius:20px;border:1px solid rgba(var(--bloom-amber),.3)}
.rest-ring{width:42px;height:42px;flex:none;transform:rotate(-90deg)}
.rr-track{fill:none;stroke:var(--hair);stroke-width:4}
.rr-arc{fill:none;stroke:var(--amber);stroke-width:4;stroke-linecap:round;transition:stroke-dashoffset 1s linear}
.rest-info{flex:1;display:flex;flex-direction:column;line-height:1.15;min-width:0}
.rest-info span{font-size:10px;font-weight:800;letter-spacing:.1em;color:var(--amber-deep);text-transform:uppercase}
.rest-info strong{font-size:22px;font-weight:800;letter-spacing:-.02em;font-variant-numeric:tabular-nums lining-nums}
.rest-act{min-height:44px;padding:0 13px;border-radius:var(--r-control);border:1px solid var(--card-hair);
  background:var(--group-bg);color:var(--amber-deep);font-weight:800;font-size:12.5px;
  font-variant-numeric:tabular-nums lining-nums}
.rest-skip{border:0;background:linear-gradient(135deg,var(--amber-soft),var(--amber));color:var(--on-amber)}

/* ============================================================
   v2 TRAIN + LIBRARY (design/HANDOFF.md section 2).
   Train has ONE order: plan hero, your routines, the session library, the plan
   shelf. The grid of boxes is gone; rows live in grouped inset lists.
   Rollback: delete to the next banner.
   ============================================================ */

/* ---- Plan hero ---- */
.plan-hero{display:block;width:100%;text-align:left;border:0;border-radius:var(--r-card);padding:20px;
  background:linear-gradient(135deg,var(--amber-soft),var(--amber) 78%);color:var(--on-amber);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.35)}
.ph-kicker{font-size:10.5px;font-weight:800;letter-spacing:.11em;opacity:.75}
.plan-hero strong{display:block;margin-top:8px;font-size:23px;font-weight:800;letter-spacing:-.03em;line-height:1.06}
.plan-hero small{display:block;margin-top:6px;font-size:12.5px;font-weight:600;opacity:.8}
.ph-progress{display:flex;align-items:center;gap:9px;margin-top:14px}
.ph-progress i{flex:1;height:5px;border-radius:3px;background:rgba(20,15,8,.22);position:relative;display:block;overflow:hidden}
.ph-progress i b{position:absolute;left:0;top:0;bottom:0;background:var(--on-amber);border-radius:3px;display:block}
.ph-progress small{margin:0;font-size:11px;font-weight:800;opacity:1}
/* The no-plan variant is a quiet surface, not an amber shout: it is a fallback, not the main act. */
.plan-hero-empty{background:var(--card-bg);border:1px solid var(--card-hair);color:var(--cream);box-shadow:var(--shadow)}
.plan-hero-empty .ph-kicker{color:var(--faint);opacity:1}
.plan-hero-empty small{color:var(--taupe);opacity:1}

.section-count{color:var(--faint);font-size:11px;font-weight:700;font-variant-numeric:tabular-nums lining-nums}

/* ---- Routine + session rows inside a grouped list ---- */
#routineList.group,#workoutList.group{margin:0 0 4px}
.routine-card.group-row,.workout-card.group-row{background:transparent;border:0;border-radius:0;
  box-shadow:none;padding:0;gap:0;min-height:0;display:flex;align-items:center}
.group>.routine-card:not(:last-child),.group>.workout-card:not(:last-child){border-bottom:1px solid var(--hair)}
.routine-open,.workout-open{flex:1;min-width:0;min-height:56px;display:flex;flex-direction:column;
  justify-content:center;gap:2px;border:0;background:transparent;color:var(--cream);text-align:left;padding:12px 0 12px 16px}
.routine-open strong,.workout-open strong{display:block;font-size:14.5px;font-weight:700;letter-spacing:-.01em}
.routine-open small,.workout-open small{display:block;color:var(--faint);font-size:11.5px;line-height:1.35;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.routine-actions{display:flex;align-items:center;gap:6px;flex:none;padding-right:10px}
.routine-menu{min-width:44px;min-height:44px;border:0;background:transparent;color:var(--taupe);
  border-radius:var(--r-control);font-size:15px;letter-spacing:.06em}
.routine-start{min-width:64px;min-height:44px;padding:0 14px;border:0;border-radius:var(--r-control);
  background:rgba(var(--bloom-amber),.15);color:var(--amber-deep);font-size:13px;font-weight:800}
.workout-start{width:44px;height:44px;flex:none;margin-right:12px;border:0;border-radius:15px;
  background:rgba(var(--bloom-amber),.15);color:var(--amber-deep);display:grid;place-items:center}
.workout-start svg{width:14px;height:14px}

/* ---- Plan shelf: horizontal, not a grid ---- */
.plan-shelf{display:flex;gap:11px;overflow-x:auto;margin:0 calc(var(--gutter)*-1);padding:2px var(--gutter) 8px;scrollbar-width:none}
.plan-shelf::-webkit-scrollbar{display:none}
.plan-shelf-card{flex:none;width:178px;text-align:left;padding:16px;border-radius:var(--r-card);
  border:1px solid var(--card-hair);color:var(--cream);
  background:radial-gradient(120% 80% at 100% 0,rgba(var(--bloom-amber),.12),transparent 58%),var(--card-bg);
  box-shadow:var(--shadow)}
.plan-shelf-card span{color:var(--amber-deep);font-size:10px;font-weight:800;letter-spacing:.11em}
.plan-shelf-card strong{display:block;margin:9px 0 5px;font-size:17.5px;font-weight:800;letter-spacing:-.025em;line-height:1.12}
.plan-shelf-card small{display:block;color:var(--faint);font-size:11.5px;line-height:1.4}

/* ---- Plan detail: days expand to reveal their exercises ---- */
.plan-day{border-bottom:1px solid var(--hair)}
.plan-day:last-of-type{border-bottom:0}
.plan-day summary{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:52px;
  padding:10px 2px;cursor:pointer;list-style:none}
.plan-day summary::-webkit-details-marker{display:none}
.pd-name{font-size:14.5px;font-weight:700}
/* The chevron is a SHAPE cue, and it rotates on open - never colour alone. */
.pd-count{flex:none;display:flex;align-items:center;gap:8px;color:var(--faint);font-size:11.5px;font-weight:600}
.pd-count::after{content:'\203A';font-size:17px;line-height:1;transform:rotate(90deg);transition:transform .2s var(--ease)}
.plan-day[open] .pd-count::after{transform:rotate(-90deg)}
.pd-list{margin:0 0 12px;padding:0 0 0 18px;color:var(--taupe);font-size:12.5px;line-height:1.6}
/* A plan day carrying a real scheme (Mark's chain, 2026-08-03). Diffed against the prototype's Train
   tab: every list of things there is a GROUPED INSET block (rounded, tinted, hairline dividers) and
   every startable row is name-left / 44px amber play-right. The first cut was a bare indented <ul>
   with the play button on the LEFT beside a label - a grammar that appears nowhere else in the app or
   in the design. Same tokens as .exercise-list below, so this is reuse, not a new component. */
.pd-scheme{list-style:none;margin:0 0 10px;padding:0;border-radius:var(--r-group);
  background:var(--group-bg);border:1px solid var(--card-hair);overflow:hidden}
.pd-scheme li{display:flex;align-items:center;justify-content:space-between;gap:12px;
  min-height:44px;padding:9px 14px;color:var(--cream);font-size:13.5px;line-height:1.35}
.pd-scheme li:not(:last-child){border-bottom:1px solid var(--hair)}
.pd-dose{flex:none;color:var(--faint);font-size:11.5px;font-weight:600;font-variant-numeric:tabular-nums}
.pd-note{margin:0 0 10px;color:var(--faint);font-size:12px;line-height:1.55}
/* The day's start row: the same shape as the prototype's routine and session rows. */
.pd-start-row{display:flex;width:100%;align-items:center;gap:12px;min-height:56px;
  padding:6px 6px 6px 14px;margin:0 0 6px;border:0;background:transparent;color:var(--cream);
  text-align:left;font:inherit;border-radius:var(--r-group)}
.pd-start-copy{flex:1;min-width:0}
.pd-start-copy strong{display:block;font-size:14.5px;font-weight:700}
.pd-start-copy small{display:block;margin-top:2px;color:var(--faint);font-size:11.5px}
/* .workout-start carries a 12px right margin for its Train-card context; inside this row the row's
   own padding does that job, so zero it or the glyph floats 18px off the edge. */
.pd-start-row .workout-start{margin-right:0}


/* NAV YIELD. While the floating nav genuinely overlaps the primary CTA (measured from live rects in
   app.js, never a hardcoded offset) it steps aside so the button underneath is reachable. It fades
   and lifts rather than vanishing, and pointer-events go with it so the CTA receives the tap - the
   nav is one scroll gesture away and returns the moment the overlap clears. Chrome only: nothing
   about the card, CTA, ring, gutter, spacing or paint moves, so the ported design is untouched. */
/* GEOMETRY-STABLE ON PURPOSE. An earlier version also applied transform:translateY(8px) scale(.98),
   which MOVES the nav's bounding rect - so the next scroll measured the displaced rect, found no
   overlap, released the yield, and the nav sprang back into the collision. Codex named the failure:
   a feedback oscillation that flickers the bar and can eat taps. opacity and pointer-events do not
   affect layout, so the rect the collision test reads is identical whether yielded or not, and the
   loop cannot form. Do not add transform, margin, inset or display here. */
body.nav-yield .bottom-nav{opacity:0;pointer-events:none}
@media(prefers-reduced-motion:reduce){body.nav-yield .bottom-nav{transition:none}}

/* Cockpit footer actions, matched to the design (design/extracted/workout.html):
   "+ Add exercise" is a 52px DASHED r18 ghost button on transparent, --ink, 14px/800;
   "Save as routine" is the same shape on a quiet rgba(var(--w),.04) fill at 13.5px;
   "Discard workout" is a 13.5px text link. Ours were 15px filled secondary buttons at r16. */
.workout-view .add-exercise-button{height:52px;min-height:52px;margin-top:14px;border:1px dashed rgba(var(--w),.16);border-radius:18px;background:transparent;color:var(--ink);font-weight:800;font-size:14px;box-shadow:none}
.workout-view .full-button:not(.add-exercise-button){height:52px;min-height:52px;margin-top:10px;border:1px solid rgba(var(--w),.08);border-radius:18px;background:rgba(var(--w),.04);color:var(--ink);font-weight:700;font-size:13.5px;box-shadow:none}  /* design: 700 */
.workout-view .danger-link{font-size:13.5px}

/* Library's "+ Add custom exercise", verbatim from the design: h50, r16, 1px rgba(var(--w),.09) on
   rgba(var(--w),.05), --ink, 14px/800. */
#view-library .full-button{height:50px;min-height:50px;margin-top:14px;border:1px solid rgba(var(--w),.09);border-radius:16px;background:rgba(var(--w),.05);color:var(--ink);font-weight:800;font-size:14px;box-shadow:none}

/* ---- Library: the row list becomes a grouped inset list ---- */
.exercise-list{border-radius:var(--r-group);background:var(--group-bg);border:1px solid var(--card-hair);overflow:hidden}
.exercise-row{background:transparent;border:0;border-radius:0;box-shadow:none;display:flex;align-items:center}
.exercise-list>.exercise-row:not(:last-child){border-bottom:1px solid var(--hair)}
.exercise-pick{flex:1;min-width:0;min-height:56px;display:flex;align-items:center;gap:12px;
  border:0;background:transparent;color:var(--cream);text-align:left;padding:10px 0 10px 14px}
.exercise-info{flex:1;min-width:0}
.exercise-info strong{display:block;font-size:14.5px;font-weight:700;letter-spacing:-.01em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.exercise-info small{display:block;margin-top:2px;color:var(--faint);font-size:11.5px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* The hero keeps .train-hero/.big-button because browser-flow clicks '#view-train .big-button',
   but those classes were written for the OLD icon+text row: `.train-hero>span` makes any span a
   52px icon box and `.big-button` makes the button a flex row, so the v2 kicker rendered at 24px
   and overlapped the title. These reset that geometry at equal specificity, declared later. */
.plan-hero.train-hero,.plan-hero.big-button{display:block;gap:0;align-items:stretch;
  padding:20px;margin:2px 0 6px;border-radius:var(--r-card)}
.plan-hero>.ph-kicker{display:block;width:auto;height:auto;flex:none;place-items:start;
  background:none;border-radius:0;font-size:10.5px;font-weight:800;letter-spacing:.11em;color:inherit;
  /* No fade: at .75 this measured 4.27:1 on the hero gradient in light mode. Hierarchy here comes
     from size, weight and letter-spacing, not from thinning the ink. */
  opacity:1}
.plan-hero>.ph-progress{display:flex;width:auto;height:auto;flex:none;place-items:center;
  background:none;border-radius:0;font-size:inherit}
.plan-hero>strong{font-size:23px;line-height:1.06}
/* No sheen on the v2 hero: the prototype has none, and that keyframe animates background-position
   rather than transform/opacity. */
.plan-hero::after{display:none;content:none;animation:none}
.plan-hero-empty>.ph-kicker{opacity:1}

/* Rows are single-line: a wrapped title turns a list into a stack of blocks. */
.routine-open strong,.workout-open strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Reset the raised-card glow the old routine-start carried; in a row it is a flat tinted chip. */
.group .routine-start{box-shadow:none}

/* ============================================================
   v2 PROGRESS: Week / Trends / Records segments + the calisthenics ledger.
   Rollback: delete to the next banner.
   ============================================================ */

/* ---- Segmented control. The selected tab carries a filled chip AND aria-selected,
   never colour alone. The chip is 30px tall inside a 44px tap area. ---- */
/* Design: the segmented track is r15 on rgba(var(--w),.055); its buttons stay r12. */
.segmented{display:flex;gap:4px;margin:2px 0 16px;padding:4px;border-radius:15px;
  background:rgba(var(--w),.055);border:0}   /* design: .055 fill, borderless (third duplicate-declaration catch) */
/* Design: 12.5px / 700. NB this rule used to declare font-size TWICE - a prepended 12.5px followed
   by the original 13px later in the SAME block, and the later declaration silently won. */
.seg-button{flex:1;min-height:44px;border:0;border-radius:12px;background:transparent;
  color:var(--taupe);font-size:12.5px;font-weight:700;letter-spacing:.01em;
  transition:background .2s var(--ease),color .2s var(--ease)}
.seg-button.on{background:var(--card-solid);color:var(--cream);box-shadow:var(--shadow)}
.prog-group[hidden]{display:none}

/* ---- Calisthenics ledger ---- */
.cali-card{padding:16px 16px 14px;border-radius:var(--r-card);border:1px solid var(--card-hair);
  background:var(--card-bg);box-shadow:var(--shadow)}
.cali-head{margin:0 0 10px;color:var(--taupe);font-size:10px;font-weight:800;letter-spacing:.11em}
.cali-row+.cali-head{margin-top:18px}
.cali-row{margin-bottom:14px}
.cali-top{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.cali-name{font-size:13.5px;font-weight:700;color:var(--cream);min-width:0}
.cali-name b{font-weight:700;color:var(--amber-deep);font-size:11.5px}
.cali-val{flex:none;font-size:18px;font-weight:800;color:var(--cream);
  font-variant-numeric:tabular-nums lining-nums;letter-spacing:-.02em}
.cali-val small{font-size:11px;font-weight:700;color:var(--taupe)}
/* The bar: a ghost fill for the previous best BEHIND the current fill, plus a tick at the old
   mark, so a gained rep is visible as a gap rather than asserted in words alone. */
.cali-bar{position:relative;height:10px;margin-top:7px;border-radius:5px;background:var(--hair);overflow:hidden}
.cali-bar i{position:absolute;left:0;top:0;bottom:0;border-radius:5px;display:block}
.cali-ghost{background:var(--hair-bright)}
.cali-fill{background:linear-gradient(90deg,var(--amber-soft),var(--amber))}
.cali-fill.teal{background:linear-gradient(90deg,var(--teal),var(--teal))}
.cali-tick{position:absolute;top:-2px;bottom:-2px;width:2px;background:var(--cream-dim);
  border-radius:1px;display:block;transform:translateX(-1px)}
.cali-note{display:block;margin-top:5px;color:var(--faint);font-size:11px;font-weight:600}
.cali-unlock{margin-top:16px;padding:12px 14px;border-radius:var(--r-group);
  background:rgba(var(--bloom-amber),.10);border:1px solid rgba(var(--bloom-amber),.28)}
.cali-unlock .kicker{margin:0 0 4px;color:var(--amber-deep)}
.cali-unlock p:last-child{margin:0;color:var(--cream-dim);font-size:12.5px;line-height:1.45}

/* The previous-best tick paints above the fill (see renderCalisthenics). */
.cali-tick{z-index:2}
.cali-bar{overflow:visible;border-radius:5px}
.cali-bar i{max-width:100%}

/* ============================================================
   v2 SETTINGS: segmented controls, switches, unchanged sync block.
   Rollback: delete to the end of file.
   ============================================================ */

/* A switch is 50x30 of VISUAL inside a 44px row, so the small glyph never shrinks the target.
   State is carried by the knob's POSITION (and the native checked state that assistive tech
   reads), not by hue alone. */
.switch-row{display:flex;align-items:center;justify-content:space-between;gap:14px;min-height:44px;
  padding:12px 0;border-bottom:1px solid var(--hair)}
.switch-row>span{flex:1;min-width:0}
.switch-row strong{display:block;font-size:14.5px;font-weight:700}
.switch-row small{display:block;margin-top:3px;color:var(--faint);font-size:11.5px;line-height:1.4}
/* The ELEMENT is 50x44 (the tap area); the 50x30 track is drawn inside it by ::before, so the
   visual stays small without shrinking the target. */
.switch{flex:none;appearance:none;-webkit-appearance:none;position:relative;width:50px;height:44px;
  margin:0;background:transparent;border:0}
.switch::before{content:'';position:absolute;top:7px;left:0;width:50px;height:30px;border-radius:999px;
  background:var(--hair-bright);border:1px solid var(--card-hair);box-sizing:border-box;
  transition:background .2s var(--ease)}
.switch::after{content:'';position:absolute;top:11px;left:4px;width:22px;height:22px;border-radius:50%;
  background:var(--cream);transition:transform .2s var(--ease)}
.switch:checked::before{background:var(--amber);border-color:transparent}
.switch:checked::after{transform:translateX(20px);background:var(--on-amber)}

.settings-note{color:var(--taupe);font-size:12px;margin-top:18px}
.build-footer{color:var(--faint);font-size:11px;margin-top:6px}
/* The settings segmented control sits under its own label, so it needs no extra top margin. */
.field .segmented{margin:0}

/* A long sheet title (e.g. "Return Ramp · Day A · Squat pattern") squeezed the close button to
   34.7px: it declares width:44px but sits in a flex row, where flex-shrink:1 is the default.
   One fix at the shared rule, so every sheet keeps its 44px target. */
.close-button{flex:none}
.sheet-head h2{min-width:0;overflow-wrap:anywhere}

/* ============================================================
   v2 FIDELITY PASS — measured against Mark's standalone prototype
   ("Gym v2 Standalone.html"), not inferred. Every value below was read out of
   the running prototype with getComputedStyle, screen by screen.
   Rollback: delete to the end of file.
   ============================================================ */

/* ---- The charge ring sits ON THE PAGE, not in a card ----
   Measured: the ring's whole ancestor chain is border:0, background:transparent.
   Ours wrapped it in a bordered .activity-card with a "THIS WEEK / Momentum
   started." heading the prototype does not have. That was the "extra border".
   The heading elements stay in the DOM (renderActivityRings writes to them by
   id) but are not painted. */
.activity-card{background:none;border:0;box-shadow:none;padding:0;border-radius:0;margin:2px 0 0}
.activity-card::before,.activity-card::after{display:none;content:none}
.activity-heading{display:none}
.activity-card.card-live,.activity-card.complete{background:none;border:0;box-shadow:none}
.activity-layout{display:block}

/* Ring: 250px, and the concentric guide rings the prototype draws behind it. */
.charge-ring{width:min(250px,72vw);margin:6px auto 0}
/* These two rules had drifted OFF the design and, being later in the file, were overriding the
   correct values above (2026-08-04). Measured in the prototype: the number is 54px flat, the label
   is 10.5px/700 at .13em in --mut2. 15vw resolved to 58px at 390 wide, and .14em was a guess. */
.cr-centre .hero-num{font-size:clamp(38px,14vw,54px)}
.cr-centre>small{color:var(--mut2);letter-spacing:.13em}
/* The design's ring button carries NO font declarations, so it computes to the UA button default and
   every visible glyph inside it sets its own size. Ours inherits the app's 15px/500 from the global
   button rule, so it is pinned back to what the design actually renders. */
.cr-centre{font-size:13.3333px;font-weight:400}

/* Legend: two entries, centred, 11.5px. */
.activity-legend{gap:8px 22px;margin-top:14px}

/* ---- Week strip: full-width pill tracks (measured 46x8, radius 4) ---- */
.week-dots{display:flex;gap:6px;margin-top:18px}
.week-dots .day-dot{flex:1;display:flex;flex-direction:column;align-items:center;gap:7px;background:none;border:0;padding:0}
.week-dots .day-dot i{width:100%;height:8px;border-radius:4px;background:var(--hair);display:block;
  transition:background .4s var(--ease)}
.week-dots .day-dot.done i{background:linear-gradient(90deg,var(--amber-soft),var(--amber));
  box-shadow:none}
/* Today is marked by an OUTLINE as well as fill, so it is never colour alone. */
.week-dots .day-dot.today i{box-shadow:0 0 0 2px rgba(var(--bloom-amber),.55)}
.week-dots .day-dot small{font-size:10px;font-weight:600;color:var(--faint)}
.week-dots .day-dot.today small{color:var(--cream)}

/* ---- UP NEXT chips: NO border, radius 9, name only (measured) ---- */
.next-chip{border:0;border-radius:9px;background:var(--chip-bg);color:var(--cream-dim);
  padding:5px 10px;font-size:11.5px;font-weight:600}
.next-chip b{display:none}
.next-chips{gap:6px}

/* ---- Section headings are KICKERS ONLY. The prototype has zero <h2> on Train. ---- */
.section-heading h2{display:none}
.section-heading .kicker{font-size:11px;font-weight:700;letter-spacing:.1em;color:var(--taupe);margin:0}
/* Design's section action ('New', 'Manage'): 13px/700, --acc, 44x56 minimum, right aligned. */
.section-heading .text-button{min-height:44px;min-width:56px;font-size:13px;font-weight:700;text-align:right}
.section-heading{align-items:baseline;margin:22px 0 10px}   /* design: 22px 0 10px */
/* Train/Library/Progress lead with a plain h1; only Today keeps its date kicker. */
#view-train .page-lead>.kicker,#view-library .page-lead>.kicker,#view-progress .page-lead>.kicker{display:none}
#view-train .page-lead h1,#view-library .page-lead h1,#view-progress .page-lead h1{font-size:32px;font-weight:800;letter-spacing:-.035em}

/* ---- Routine + session rows: one 44px amber play square (measured 44x44, r15,
   bg rgba(255,138,61,.15), ink #FFB070). The row NAME opens options. ---- */
.routine-start,.workout-start{width:44px;height:44px;min-width:44px;flex:none;margin-right:12px;padding:0;
  border:0;border-radius:15px;background:rgba(var(--bloom-amber),.15);color:var(--amber-deep);
  display:grid;place-items:center;font-size:0}
.routine-start svg,.workout-start svg{width:14px;height:14px;display:block}
.routine-actions{padding-right:0;gap:0}

/* ---- The grouped list matches the prototype exactly: bg .035, hairline .06, r20 ---- */
.group,.exercise-list{border-radius:20px;background:var(--group-bg);border:1px solid var(--hair)}

/* The week strip had a border-top divider (.week-dots-wide) the prototype does not draw. */
.week-dots-wide{border-top:0;padding-top:0}
/* UP NEXT reads amber. The prototype uses raw --amber, which measures 2.88:1 on cream in LIGHT
   mode; --amber-deep is the app token for amber TEXT and resolves to #FFB070 in dark, which is the
   prototype's own accent colour anyway. Same look in dark, legible in light. */
/* The design's UP NEXT kicker: var(--amber), 11px, .1em. Measured on its own card - DARK #FF8A3D is
   7.22:1 so dark matches the design EXACTLY; LIGHT #E06E1F is 3.27:1 which fails AA, so light alone
   keeps --amber-deep (6.35:1). Deviate only in the scheme that forces it, never in both.
   NB this selector is (0,3,0): a lower-specificity attempt higher in the file silently lost to it. */
.up-next .coach-top .kicker{color:var(--amber-deep);font-size:11px;letter-spacing:.1em}
@media(prefers-color-scheme:dark){.up-next .coach-top .kicker{color:var(--amber)}}

/* Prototype gives its section actions min-width:56px; shortening "+ New" to "New" had ours at 33px. */
.section-heading .text-button{min-width:56px;min-height:44px}

/* ---- Library rows, ported verbatim from the prototype (getComputedStyle-measured) ----
   Row = flex container with a 1px hairline underneath. Left button = name + equipment.
   Then the MUSCLE in caps. Then a divided star column. No plate glyph, no "+" glyph:
   the design has neither. */
.exercise-row{display:flex;align-items:center;border-bottom:1px solid var(--hair);
  background:transparent;border-radius:0;box-shadow:none;padding:0}
.exercise-list>.exercise-row:last-child{border-bottom:0}
.exercise-pick{flex:1;min-width:0;display:flex;align-items:center;gap:10px;
  padding:12px 4px 12px 16px;border:0;background:transparent;color:var(--cream);text-align:left;min-height:54px}
.exercise-info strong{display:block;font-size:14.5px;font-weight:700;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.exercise-info small{display:block;margin-top:2px;color:var(--faint);font-size:11.5px;   /* design: 11.5px */
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ex-muscle{flex:none;color:var(--cream-dim);font-size:11px;font-weight:800;letter-spacing:.06em;
  text-transform:uppercase;padding:0 10px;white-space:nowrap}
/* The star sits in its own column behind a divider, and keeps a full 44px target. */
.exercise-star{flex:none;width:64px;min-height:54px;display:grid;place-items:center;
  border:0;border-left:1px solid var(--hair);border-radius:0;background:transparent;color:var(--faint)}
.exercise-star svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.6}
.exercise-star.on{color:var(--amber-deep)}
.exercise-star.on svg{fill:currentColor;stroke:currentColor}
.count-row{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:0 0 10px}
.result-count,.fav-count{color:var(--faint);font-size:11.5px;font-weight:600}
/* The design's Library has no quick-picks strip and no Filters button in the count row.
   Both stay in the DOM (their handlers and the filter sheet still work) but are not painted.
   TODO(design): Mark - your Library has no Filters entry point at all. Say the word and I will
   put it back somewhere, or leave it hidden to stay identical. */
#libraryQuickPicks{display:none}
#libraryFiltersBtn{display:none}

/* ---- Brand mark: Mark's pyramid bench-press logo, lifted from the prototype along with its
   32px gradient tile (150deg #FFC98A -> #FF7A24, r11, inset top-light + amber cast). ---- */
.brand>span{position:relative;width:32px;height:32px;display:grid;place-items:center;border-radius:11px;
  /* HARDCODED ON PURPOSE (2026-08-04). Measured in the prototype in BOTH schemes: this tile is
     linear-gradient(150deg,#FFC98A,#FF7A24) in light AND dark - it does not follow the theme. These
     were var(--hi,#FFC98A)/var(--amber2,#FF7A24), which was safe only while those tokens did NOT
     exist. Adopting the design's token block DEFINED them, killing the fallbacks and silently
     recolouring the logo in light mode. Codex named this exact mechanism: a newly defined inherited
     custom property changes any existing var(--x, fallback) consumer by replacing its fallback. */
  background:linear-gradient(150deg,#FFC98A,#FF7A24);color:var(--on-amber);
  overflow:hidden;box-shadow:inset 0 1px 0 rgba(255,255,255,.45)}
.brand>span svg{width:22px;height:22px;display:block}

/* ---- Progress > WEEK, ported from the prototype ---- */
.wk-kicker{margin:22px 0 0;color:var(--taupe);font-size:11px;font-weight:700;letter-spacing:.1em}   /* design: 22px 0 0 */
.wk-kicker-2{margin-top:26px}
/* Design: number 56px/800/-.05em line-height 1 tabular; unit 15px/700; row margin-top 2px. */
.wk-hero{display:flex;align-items:baseline;gap:8px;margin:2px 0 14px}
.wk-hero strong{font-size:56px;font-weight:800;letter-spacing:-.05em;line-height:1;font-variant-numeric:tabular-nums lining-nums}
.wk-hero strong{font-size:54px;font-weight:800;letter-spacing:-.05em;line-height:1;
  font-variant-numeric:tabular-nums lining-nums}
.wk-hero small{font-size:15px;font-weight:700;color:var(--taupe)}   /* design: 15px */
.wk-delta{margin-left:auto;font-size:12.5px;font-weight:800;font-variant-numeric:tabular-nums lining-nums}
.wk-delta.up{color:var(--teal-deep)}
.wk-delta.down{color:var(--danger)}
.wk-delta.flat{color:var(--faint);font-weight:600}
.wk-chart{width:100%;height:110px;display:block;margin:0 0 18px;overflow:visible}
.wk-area{fill:rgba(var(--bloom-amber),.20);stroke:none}
.wk-line{fill:none;stroke:var(--amber);stroke-width:1.6;vector-effect:non-scaling-stroke;
  stroke-linecap:round;stroke-linejoin:round}
.wk-dot{fill:var(--amber)}
.wk-empty{color:var(--faint);font-size:12.5px;margin:0 0 18px}
.wk-stats{margin-bottom:4px}
/* Design: stat-list labels are 13.5px/600. */
.wk-row>span:first-child{font-size:13.5px;font-weight:600}
.wk-row{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:56px;
  padding:12px 16px;font-size:14.5px;font-weight:700;color:var(--cream)}
.wk-stats .wk-row+.wk-row{border-top:1px solid var(--hair)}
.wk-val{display:flex;align-items:baseline;gap:8px;font-size:17px;font-weight:800;
  font-variant-numeric:tabular-nums lining-nums}
.wk-val .wk-delta{margin-left:0;font-size:11.5px}
.wk-muscle{display:flex;align-items:center;gap:12px;margin-bottom:14px}
.wk-mname{flex:none;width:88px;font-size:13.5px;font-weight:700;color:var(--cream);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wk-mbar{flex:1;height:9px;border-radius:5px;background:var(--hair);overflow:hidden;display:block}
.wk-mbar i{display:block;height:100%;border-radius:5px;
  background:linear-gradient(90deg,var(--amber-soft),var(--amber))}
.wk-mval{flex:none;min-width:22px;text-align:right;font-size:13.5px;font-weight:800;
  color:var(--cream-dim);font-variant-numeric:tabular-nums lining-nums}
/* The design's Week pane is these four blocks. The app's older modules stay in the DOM (their
   renderers still run and Goals is still reachable) but are not painted here.
   TODO(design): Mark - your Week pane has no Goals board. Say if you want it back below. */
.prog-group[data-seg="week"] .section-heading,
.prog-group[data-seg="week"] #progressStats,
.prog-group[data-seg="week"] #weeklyRecap,
.prog-group[data-seg="week"] #muscleVolume,
.prog-group[data-seg="week"] #goalBoard{display:none}

/* Mark: "i dont wanna zoom in and out off the app". The viewport meta stops pinch-zoom; these stop
   the two other ways a phone zooms a web app: a double-tap, and iOS auto-zooming any input whose
   font-size is under 16px when it gains focus. */
html{touch-action:manipulation;-webkit-text-size-adjust:100%;text-size-adjust:100%}
input,select,textarea{font-size:16px}

/* ---- Calisthenics rows, matched to the prototype ----
   value + delta chip on the right of the number; bar with the previous-best tick; then
   "| was N" bottom-left and "next tier N" bottom-right. */
.cali-val{display:flex;align-items:baseline;gap:7px}
.cali-chip{font-size:12px;font-weight:800;font-variant-numeric:tabular-nums lining-nums}
.cali-chip.up{color:var(--teal-deep)}
.cali-chip.down{color:var(--danger)}
.cali-foot{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-top:5px}
.cali-foot small{color:var(--faint);font-size:11px;font-weight:600}
.cali-gain{color:var(--amber-deep);font-weight:800}
.cali-name{font-size:14.5px}

/* ---- Progress > Trends strength card, ported from the prototype ----
   name 13/700 + teal gain on one row, est. 1RM at 46px, then a clean area chart:
   no grid lines, no axis ticks, no per-point dots - the design has none of them. */
.st-card{padding:16px 16px 6px;border-radius:var(--r-card);border:1px solid var(--card-hair);
  background:var(--card-bg);box-shadow:var(--shadow);margin-bottom:12px}
.st-top{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.st-name{font-size:13px;font-weight:700;color:var(--cream)}
.st-delta{font-size:12px;font-weight:800;color:var(--teal-deep);font-variant-numeric:tabular-nums lining-nums}
.st-delta.down{color:var(--danger)}
.st-hero{display:flex;align-items:baseline;gap:7px;margin-top:4px}
.st-hero .hero-num{font-size:46px;font-weight:800;letter-spacing:-.05em;line-height:1.05;
  font-variant-numeric:tabular-nums lining-nums}
.st-hero small{font-size:16px;font-weight:700;color:var(--taupe)}
.st-card .trend-grid-line,.st-card .trend-tick,.st-card .trend-dot{display:none}
.st-card .trend-line{stroke-width:2.8px}
.st-card .trend-svg{width:100%;height:92px;display:block;margin-top:2px}
/* The picker chips sit BELOW the card in the design. */
.trend-picker{display:flex;gap:7px;overflow-x:auto;margin:0 calc(var(--gutter)*-1) 4px;padding:2px var(--gutter) 8px;scrollbar-width:none}
.trend-picker::-webkit-scrollbar{display:none}
.trend-picker .filter-chip{flex:none;white-space:nowrap;min-height:44px;padding:0 14px;border-radius:13px;
  border:1px solid var(--card-hair);background:var(--group-bg);color:var(--cream-dim);font-size:11.5px;font-weight:800}
.trend-picker .filter-chip.active{border-color:var(--amber);background:var(--amber);color:var(--on-amber)}

/* ---- Progress > RECORDS, ported from the prototype ----
   Two grouped lists: PERSONAL RECORDS then ALL WORKOUTS. The design has no consistency
   chart on this pane, so it and its heading are not painted (renderer still runs). */
.prog-group[data-seg="records"] .section-heading:first-of-type,
.prog-group[data-seg="records"] #weekChart{display:none}
.pr-feed.group .pr-row{display:flex;align-items:center;gap:12px;min-height:64px;padding:12px 16px;
  background:transparent;border:0;border-radius:0;box-shadow:none}
.pr-feed.group .pr-row+.pr-row{border-top:1px solid var(--hair)}
.pr-row .pr-mark{width:50px;height:50px;flex:none;display:grid;place-items:center;border-radius:14px;
  background:rgba(var(--bloom-amber),.14);color:var(--amber-deep);font-size:12px;font-weight:800;letter-spacing:.04em}
.pr-row>span:not(.pr-mark){flex:1;min-width:0}
.pr-row strong{display:block;font-size:15px;font-weight:700;letter-spacing:-.01em}
.pr-row small{display:block;margin-top:2px;color:var(--faint);font-size:12px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pr-row time{flex:none;color:var(--faint);font-size:12px;white-space:nowrap}
/* ALL WORKOUTS rows carry no leading glyph in the design - name, meta, chevron. */
#historyList .history-card .row-glyph{display:none}
#historyList .history-card{min-height:64px;padding:12px 16px}
/* The PR timeline rail + dots (lines 430-432) are not in the design's Records pane, and the
   badge is a rounded square there, not the notched octagon. */
.pr-feed.group{display:block;padding-left:0;position:static}
.pr-feed.group::before{content:none;display:none}
.pr-feed.group .pr-row::before{content:none;display:none}
.pr-feed.group .pr-row .pr-mark{clip-path:none;-webkit-clip-path:none;border-radius:14px;width:50px;height:50px;font-size:12px}
/* The design has no "Use last" adopt bar - its set cells are pre-filled with the target, which
   ours are too, so the bar was redundant duplication. Kept in the DOM (adoptLast() still works if
   called) but not painted.
   TODO(design): Mark - say if you want the one-tap "Use last" back; the design omits it. */
.adopt-last{display:none}
/* The NOW row's done circle carries an amber ring in the design. */
.set-row.now .set-done{border-color:var(--amber);color:var(--amber-deep)}

/* ---- Number pad keypad, ported from the prototype ---- */
.pad-keys{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin:12px 0 14px}
.pad-key{min-height:56px;border:1px solid var(--card-hair);border-radius:var(--r-control);
  background:var(--group-bg);color:var(--cream);font-size:22px;font-weight:800;
  font-variant-numeric:tabular-nums lining-nums}
.pad-key:active{background:rgba(var(--bloom-amber),.14)}
.pad-back{color:var(--amber-deep);font-size:20px}
.pad-key-gap{display:block;min-height:56px}
.pad-value+.pad-plates{margin-top:4px}

/* ---- Exercise options sheet action rows, ported from the prototype ---- */
.opt-row{display:flex;width:100%;align-items:center;gap:14px;min-height:72px;padding:14px 16px;
  margin-bottom:10px;text-align:left;border:1px solid var(--card-hair);border-radius:var(--r-group);
  background:var(--group-bg);color:var(--cream)}
.opt-icon{width:44px;height:44px;flex:none;display:grid;place-items:center;border-radius:14px;
  background:rgba(var(--bloom-amber),.16);color:var(--amber-deep);font-size:19px;font-weight:800}
.opt-danger .opt-icon{background:var(--danger-soft);color:var(--danger)}
.opt-danger{border-color:var(--danger)}
.opt-text{flex:1;min-width:0}
.opt-text strong{display:block;font-size:15.5px;font-weight:700;letter-spacing:-.01em}
.opt-text small{display:block;margin-top:2px;color:var(--faint);font-size:12px;line-height:1.35}

/* ---- why? evidence list, ported from the prototype ---- */
.why-list{margin:14px 0 12px}
.why-row{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:56px;padding:12px 16px}
.why-row+.why-row{border-top:1px solid var(--hair)}
.why-row span{color:var(--taupe);font-size:14px}
.why-row b{font-size:14.5px;font-weight:800;color:var(--cream);
  font-variant-numeric:tabular-nums lining-nums;text-align:right}
.why-row b.why-teal{color:var(--teal-deep)}
.why-row b.why-amber{color:var(--amber-deep)}

/* ---- Long-press to reorder (Mark: finished rows moved too easily, unfinished ones were hard) ----
   The whole header of an open card and the whole finished row are now long-press handles, so any
   exercise is grabbable, not just a 44px badge. They keep touch-action:pan-y so the list scrolls
   normally under a finger; only the small numbered grip stays touch-action:none for an instant,
   precise drag. `drag-pending` is the 360ms "I felt that" cue: the card sinks slightly and lifts
   its shadow, transform/opacity only, so it dies under the reduced-motion kill-switch. */
.exercise-head{touch-action:pan-y}
.done-row{touch-action:pan-y}
.workout-exercise.drag-pending{transform:scale(.985);box-shadow:var(--shadow),0 0 0 1px rgba(var(--bloom-amber),.35);
  transition:transform .36s var(--ease),box-shadow .36s var(--ease)}
.workout-exercise.drag-lift{transform:scale(1.03)}

/* ---- Drag handles that actually work on a finger ----
   touch-action:pan-y hands vertical panning to the browser, so on a real phone the micro-movement
   of a held finger makes Chrome claim the gesture and fire pointercancel - the drag "flashes and
   nothing happens". A drag surface must therefore be touch-action:none, which means it has to be a
   HANDLE rather than the whole card, or the list could never be scrolled. So: every exercise, open
   or finished, carries its own visible grip; you scroll anywhere else. */
.exercise-head{touch-action:auto}
.done-row{touch-action:auto}
.grip-dots{display:block;width:14px;height:10px;opacity:.75;
  background-image:radial-gradient(currentColor 1.4px,transparent 1.5px);
  background-size:5px 5px;background-position:0 0}
.exercise-grip{flex-direction:column;gap:4px;align-content:center}
.workout-exercise.lit .exercise-grip{color:var(--amber-deep)}
/* The finished row keeps its own grip on the right, so the row itself is only a tap-to-reopen. */
.workout-exercise.done-card{display:flex;align-items:center}
.done-card .done-row{flex:1;min-width:0}
.done-grip{width:44px;height:44px;flex:none;margin-right:8px;display:grid;place-items:center;
  border:0;background:transparent;color:var(--taupe);border-radius:var(--r-control);touch-action:none}

/* ---- Train filter rail spacing, measured against the prototype ----
   Ours inherited .filter-row's `13px -18px 4px` margin, so the sessions list sat 4px under the
   chips instead of 12px, and the chips carried a 13px top margin the design does not have.
   Prototype: margin 0 -20px 12px / padding 0 20px (our page gutter is 18px, so -18/18). */
#workoutGoals{margin:0 calc(var(--gutter)*-1) 12px;padding:0 var(--gutter);gap:7px}

/* ============================================================
   THE TAB-SWAP FLASH, SOLVED 2026-08-03 (w23-w27 + w28-w46 all missed it).
   Mark's photo showed a BLUE RECTANGLE around the tapped nav button - not a
   white pane flash. That is Android Chrome's DEFAULT -webkit-tap-highlight-color,
   which this app never declared. Fuel (which never flashed) sets it transparent
   on `*`; SliceCo (whose nav Mark says feels better) sets it transparent three
   times. Gym never did, so every tap painted a translucent blue box.

   Why six builds missed it: the tap highlight only renders for REAL TOUCH input.
   Every gate in this repo drives synthetic events in headless Chrome with
   --disable-gpu, so no test here can ever reproduce it. It is a UA behaviour, not
   app state, which is why it happened on the website AND the installed PWA and
   predated the redesign.

   The app already draws its own press feedback (pressRing on the nav, --press-veil
   on controls), so removing the UA highlight loses nothing.
   ============================================================ */
*{-webkit-tap-highlight-color:transparent}
/* Belt and braces on the surfaces that are tapped hardest mid-set. */
.bottom-nav button,.set-done,.set-input,.exercise-grip,.done-grip,.pad-key,.rir-chip,
.filter-chip,.seg-button,button,a{-webkit-tap-highlight-color:transparent}

/* ============================================================
   w60 pass - 2026-08-05 (Mark + Ty's report)
   Five things: honest volume copy, a keyboard model that works
   everywhere, sheet action groups that are not one cramped block,
   preview-before-start on the plan hero, and weekly volume drawn
   as bars instead of a 42px smoothed sliver.
   Rollback: delete from this banner to EOF.
   ============================================================ */

/* ---- Keyboard, app-wide -------------------------------------------------
   --kb is the keyboard's height, set by JS only while it is actually up.
   Every scroll container adds it to its bottom padding, so the last row can
   always be brought clear of the keys. The viewport meta already shrinks the
   layout viewport (interactive-widget=resizes-content); this covers the
   scroll geometry that the meta does not. */
.sheet-scroll{padding-bottom:calc(max(22px,env(safe-area-inset-bottom)) + var(--kb,0px))}
body.kb-open{padding-bottom:var(--kb,0px)}
/* A sticky field over a scrolling list has to be OPAQUE or the rows slide
   through it and you cannot read what you typed. --glass-tint is translucent
   by design, so the picker's copy of it gets a solid backing plate. */
/* The halo is a spread-only shadow in the sheet's own colour, so it plugs the gap either side of
   the pill WITHOUT squaring off its corners the way a backing rectangle would. */
.picker-search{position:sticky;top:0;z-index:6;background:var(--glass-solid);
  box-shadow:0 0 0 10px var(--glass-solid),0 10px 14px -12px rgba(0,0,0,.55)}
/* The keyboard can be up while the sheet is short; never let it collapse. */
.sheet{min-height:180px}

/* ---- Sheet action groups ------------------------------------------------
   Three full-width buttons stacked with no gap read as one block you cannot
   parse at a glance (Mark, on the workout history sheet). Group them, give
   them real air, and keep the destructive one apart behind a rule. */
.sheet-stack{display:grid;gap:10px;margin-top:18px}
.sheet-stack .full-button{margin:0}
.sheet-stack-danger{margin-top:22px;padding-top:18px;border-top:1px solid var(--hair)}
.danger-button{color:var(--danger);border-color:rgba(170,70,60,.34)}
.danger-button:active{background:var(--danger-soft)}

/* ---- Volume honesty ----------------------------------------------------- */
.vol-note{margin:12px 0 0;color:var(--taupe);font-size:12.5px;line-height:1.45}
.vol-note strong{color:var(--cream);font-weight:800}
.vol-gap{margin:10px 0 0;padding:12px 14px;border-radius:var(--r2,12px);
  border:1px solid rgba(var(--bloom-amber),.34);background:rgba(var(--bloom-amber),.09);
  color:var(--cream);font-size:12.5px;line-height:1.5}
.vol-gap strong{display:block;color:var(--amber-deep);font-weight:800;margin-bottom:2px}
/* A flagged row is marked by a WORD in its own line plus a rail, never by hue
   alone - Mark is colour-blind and the rule holds for every state in this app. */
.selected-row.row-gap{position:relative;padding-left:12px}
.selected-row.row-gap::before{content:'';position:absolute;left:0;top:8px;bottom:8px;width:3px;
  border-radius:2px;background:var(--amber-deep)}
.receipt-gap{margin:14px 0 0;padding:13px 15px;border-radius:var(--r2,12px);
  border:1px solid rgba(var(--bloom-amber),.34);background:rgba(var(--bloom-amber),.09);text-align:left}
.receipt-gap strong{display:block;color:var(--amber-deep);font-weight:800;font-size:13.5px}
.receipt-gap small{display:block;margin-top:3px;color:var(--taupe);font-size:11.5px;line-height:1.5}

/* ---- Preview sheets + list capping -------------------------------------- */
.preview-count{margin:-6px 0 10px;color:var(--faint);font-size:12px;font-weight:700;
  letter-spacing:.02em;font-variant-numeric:tabular-nums lining-nums}
.list-more{width:100%;min-height:48px;border:0;border-top:1px solid var(--hair);
  background:transparent;color:var(--amber-deep);font-size:13px;font-weight:800;letter-spacing:.01em}
.list-more:active{background:rgba(var(--bloom-amber),.08)}

/* ---- Plan hero: body previews, play square starts ------------------------ */
/* MEASURED, not assumed: `.plan-hero.train-hero` (two classes) sets display:block + padding:20px,
   so a single-class `.plan-hero` rule here loses on specificity no matter how late it appears.
   Matching the selector is the fix - the first attempt read display:block in the probe and dropped
   the play button onto its own line. */
.plan-hero.train-hero,.plan-hero.big-button{display:flex;align-items:center;gap:12px;padding:0}
.plan-hero-empty.train-hero,.plan-hero-empty.big-button{display:block;padding:20px}
.ph-open{flex:1;min-width:0;text-align:left;border:0;background:transparent;
  color:inherit;padding:20px 0 20px 20px}
.plan-hero .ph-start{flex:none;margin-right:16px;background:rgba(20,15,8,.18);color:var(--on-amber)}
.plan-hero .ph-start svg{width:16px;height:16px}
/* The kicker's reset lived on `.plan-hero>.ph-kicker`, which stopped matching once the copy moved
   inside .ph-open. Its opacity:1 was a deliberate contrast decision (at .75 it measures 4.27:1 on
   the hero gradient in light mode), so it is re-attached here rather than lost. */
.plan-hero .ph-kicker{display:block;width:auto;height:auto;flex:none;background:none;border-radius:0;
  font-size:10.5px;font-weight:800;letter-spacing:.11em;color:inherit;opacity:1}
.plan-hero .ph-progress{display:flex;width:auto;height:auto;flex:none;background:none;border-radius:0}
.plan-hero-empty .ph-kicker{color:var(--faint)}

/* ---- Weekly volume as bars ----------------------------------------------
   Weekly totals are discrete, so they get discrete marks. Bars are readable
   one week at a time, carry their own labels, and stay legible for a
   colour-blind reader because THIS week is set apart by fill weight and by
   its label ("now"), not by hue. The average rule is what makes any single
   bar mean something. */
.wk-bars{position:relative;display:flex;align-items:flex-end;gap:5px;height:150px;
  margin:14px 0 0;padding:0 0 22px;border-bottom:1px solid var(--hair)}
.wkb{flex:1;min-width:0;height:100%;display:flex;flex-direction:column;justify-content:flex-end;position:relative}
/* A week with no training is a 2px stub, NOT an empty full-height track: the first draft drew a
   track behind every bar and a zero week read as a FULL one (caught by looking at the shot, not by
   any gate). Nothing is drawn behind a bar now - the baseline rule is the only reference. */
.wkb i{display:block;width:100%;min-height:2px;border-radius:4px 4px 0 0;background:var(--cream-dim);
  transition:height .5s var(--ease)}
.wkb-now i{background:linear-gradient(180deg,var(--amber-soft),var(--amber));
  box-shadow:none}
.wkb small{position:absolute;left:0;right:0;top:100%;padding-top:6px;text-align:center;color:var(--faint);
  font-size:9.5px;font-weight:700;letter-spacing:.02em;font-variant-numeric:tabular-nums lining-nums;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wkb-now small{color:var(--amber-deep);font-weight:800}
/* --r is the average as a fraction of the tallest bar, so the rule is on the SAME scale as the bars
   and can never disagree with them. (100% - 22px) is the plot area above the label strip. */
.wk-avg{position:absolute;left:0;right:0;height:0;bottom:calc(22px + var(--r,0) * (100% - 22px));
  border-top:1px dashed var(--hair-bright);pointer-events:none;z-index:1}
.wk-avg em{position:absolute;right:0;top:-13px;font-style:normal;color:var(--faint);
  font-size:9.5px;font-weight:700;letter-spacing:.03em}
.wk-rank{margin:12px 0 0;color:var(--taupe);font-size:12.5px;font-weight:600}
@media(prefers-reduced-motion:reduce){.wkb i{transition:none}}

/* ---- Work axes (2026-08-05) ---------------------------------------------
   Kilograms, reps and seconds are different quantities and are never summed.
   This block states the parts of a session the kg headline cannot carry, so
   calisthenics stops reading as "you did nothing". */
.work-axes{display:grid;gap:6px;margin:12px 0 0}
.work-axes span{color:var(--taupe);font-size:12.5px;line-height:1.45}
.work-axes strong{color:var(--cream);font-weight:800}
.bw-prompt{width:100%;min-height:48px;margin-top:10px;border:1px solid rgba(var(--bloom-amber),.34);
  border-radius:var(--r2,12px);background:rgba(var(--bloom-amber),.09);color:var(--amber-deep);
  font-size:13px;font-weight:800;text-align:center}
.bw-prompt:active{background:rgba(var(--bloom-amber),.16)}
/* The backfill decision is reversible, so it says so where every other data decision lives. */
.settings-note{margin:14px 0 0;color:var(--taupe);font-size:12px;line-height:1.5}
.settings-note strong{color:var(--cream);font-weight:800}

/* ============================================================
   w63 pass - 2026-08-05. Whole-app review (Claude + Codex).
   Rollback: delete from this banner to EOF.
   ============================================================ */

/* ---- The rest pill covered the RIR chips by a measured 50px --------------
   The pill is fixed to the bottom; the RIR question renders inline in the
   exercise card at the same moment the timer starts. scroll-margin-bottom
   reserves the pill's height (plus the safe-area token every bottom-anchored
   surface in this app reads) so scrollIntoView can never land it underneath. */
.rir-row{scroll-margin-bottom:calc(96px + var(--sai-bottom, 0px))}

/* ---- Library scope: Yours / All -----------------------------------------
   The catalogue is a reference; your own short list is the thing you reach
   for in a gym. Same segmented control as Progress, so there is one grammar
   for "which slice am I looking at" across the app. */
/* :not([hidden]) is load-bearing: a bare `display:flex` beats the UA [hidden]{display:none} rule,
   so the scope row would still be laid out while hidden for a lifter with no exercises of their own.
   Exactly the phantom-element class browser-flow caught on .paused-flag in July - the gate found it
   again here within a minute of the CSS being written. */
.seg-row:not([hidden]){display:flex}
.seg-row{gap:6px;margin:12px 0 4px;padding:4px;border-radius:var(--r-card);
  background:var(--glass-2);border:1px solid var(--hair)}
.seg-row .seg-button{flex:1;min-height:40px;border:0;border-radius:12px;background:transparent;
  color:var(--taupe);font-size:13px;font-weight:800;letter-spacing:.01em}
.seg-row .seg-button.on{background:var(--card-bg);color:var(--cream);box-shadow:var(--elev-0)}
/* Names and equipment truncated mid-word ("Assisted Pistol Sq...", "band o...").
   Two lines is enough for every entry in the catalogue and reads as a sentence. */
.exercise-info strong{white-space:normal;overflow:visible;text-overflow:clip;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.exercise-info small{white-space:normal;overflow:visible;text-overflow:clip;line-height:1.35;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.exercise-pick{align-items:flex-start;padding-top:12px;padding-bottom:12px}

/* ---- Today: one dominant action ----------------------------------------
   The ring reported an abstract percentage and nothing to do about it. It
   keeps its place, but the next thing to do now sits directly under it. */
.today-cta{display:flex;align-items:center;gap:12px;width:100%;margin:14px 0 0;padding:14px 14px 14px 18px;
  border:0;border-radius:var(--r-card);text-align:left;color:var(--on-amber);
  background:linear-gradient(135deg,var(--amber-soft),var(--amber) 78%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3)}
.today-cta-copy{flex:1;min-width:0}
.today-cta-copy small{display:block;font-size:10.5px;font-weight:800;letter-spacing:.11em;opacity:.95}
.today-cta-copy strong{display:block;margin-top:3px;font-size:19px;font-weight:800;letter-spacing:-.02em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.today-cta .workout-start{background:rgba(20,15,8,.18);color:var(--on-amber);margin:0;flex:none}
.today-cta .workout-start svg{width:16px;height:16px}
/* Rest is a training decision, so it gets a real state instead of a blank space. Quiet surface on
   purpose: nothing here should read as urgent. */
.today-rest{margin:14px 0 0;padding:16px 18px;border-radius:var(--r-card);
  border:1px solid var(--card-hair);background:var(--card-bg);box-shadow:var(--shadow)}
.today-rest .kicker{color:var(--teal)}
.today-rest strong{display:block;margin-top:6px;font-size:19px;font-weight:800;letter-spacing:-.02em}
.today-rest small{display:block;margin-top:5px;color:var(--taupe);font-size:12.5px;line-height:1.5}
.today-rest-actions{display:flex;align-items:center;gap:10px;margin-top:12px}
.today-rest-actions .secondary-button{flex:1;margin:0}

/* ---- Cockpit: exercise memory ------------------------------------------
   Collapsed by default - the card is a logging surface first. Open, it is
   the last three exposures, the best set on record, and a note that
   survives to next session. */
.ex-memory{margin:10px 0 0;border-top:1px solid var(--hair)}
.ex-memory summary{list-style:none;cursor:pointer;min-height:44px;display:flex;align-items:center;
  gap:6px;color:var(--taupe);font-size:11.5px;font-weight:800;letter-spacing:.05em;text-transform:uppercase}
.ex-memory summary::-webkit-details-marker{display:none}
.ex-memory summary::after{content:'›';margin-left:auto;font-size:16px;transition:transform .18s var(--ease)}
.ex-memory[open] summary::after{transform:rotate(90deg)}
.mem-body{padding:2px 0 10px}
.mem-row{display:flex;align-items:baseline;gap:10px;padding:6px 0;border-bottom:1px solid var(--hair)}
.mem-when{flex:none;width:78px;color:var(--faint);font-size:11px;font-weight:700}
.mem-sets{flex:1;min-width:0;color:var(--cream);font-size:12.5px;font-variant-numeric:tabular-nums lining-nums}
.mem-best{display:flex;justify-content:space-between;align-items:baseline;gap:10px;padding:9px 0 2px}
.mem-best span{color:var(--faint);font-size:11px;font-weight:800;letter-spacing:.05em;text-transform:uppercase}
.mem-best strong{color:var(--amber-deep);font-size:13.5px;font-weight:800;font-variant-numeric:tabular-nums lining-nums}
.mem-note{display:block;margin-top:8px}
.mem-note span{display:block;margin-bottom:4px;color:var(--faint);font-size:10px;font-weight:800;letter-spacing:1px;text-transform:uppercase}
.mem-note textarea{width:100%;border:1px solid var(--hair);border-radius:var(--r2,12px);
  background:var(--glass);color:var(--cream);padding:10px 12px;font-size:16px;resize:vertical}

/* ---- Warm-ups + plates per side ---------------------------------------- */
.add-warmup{border:0;background:transparent;color:var(--teal);font-size:12.5px;font-weight:800;min-height:44px;padding:0 10px}
/* A warm-up row is marked by the WORD "WARM" in its set-number cell plus a lighter rail - never by
   hue alone, which is the standing rule in this app. */
.set-row.warmup-set .set-number{opacity:.85}
.set-row.warmup-set .set-tag{color:var(--teal)}
.plate-hint{margin:-2px 0 8px;padding:0 4px 0 56px;color:var(--faint);font-size:11.5px;
  font-variant-numeric:tabular-nums lining-nums}
.plate-hint strong{color:var(--cream);font-weight:800}
/* ---- The ring earns less room -------------------------------------------
   It was 250px wide inside a 348px block: 27% of the page for one blended
   percentage nobody can act on. Reduced, with the counts and the next action
   taking the space it gives back. The prototype's proportions are kept - only
   the scale changes - so it still reads as the same object. */
.charge-ring{width:min(168px,46vw);margin:2px auto 0}
.cr-centre .hero-num{font-size:clamp(30px,10vw,38px)}
.activity-legend{margin-top:10px}
.week-dots{margin-top:12px}

/* ============================================================
   w64 LANDING - 2026-08-05. Council: Claude + Codex, converged.
   The "% WEEK CHARGED" ring is gone. It averaged three ratios,
   displayed two of them, and its owner could not name it when
   shown his own screen. What replaces it: the session you can
   start, then what your body actually got this week.
   Rollback: delete from this banner to EOF.
   ============================================================ */

/* ---- Hero: the executable next session ---------------------------------- */
.today-hero{margin:14px 0 0;padding:18px;border-radius:var(--r-card);
  background:linear-gradient(135deg,var(--amber-soft),var(--amber) 80%);color:var(--on-amber);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.32)}
.th-copy small{display:block;font-size:10.5px;font-weight:800;letter-spacing:.11em;opacity:1}
.th-copy strong{display:block;margin-top:4px;font-size:25px;font-weight:800;letter-spacing:-.03em;line-height:1.05}
.th-copy em{display:block;margin-top:5px;font-style:normal;font-size:12.5px;font-weight:700;opacity:.85}
/* The prescription. Hairlines rather than cards: this is a manifest, not six more surfaces. */
.th-list{list-style:none;margin:14px 0 0;padding:0;border-top:1px solid rgba(20,15,8,.18)}
.th-list li{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding:9px 0;border-bottom:1px solid rgba(20,15,8,.14)}
.th-lift{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:700}
.th-dose{flex:none;font-size:13.5px;font-weight:800;font-variant-numeric:tabular-nums lining-nums}
.th-more{margin:8px 0 0;font-size:12px;font-weight:700;opacity:.8}
.th-actions{display:flex;align-items:center;gap:10px;margin-top:14px}
.th-actions .primary-button{flex:1;margin:0;background:rgba(20,15,8,.22);color:var(--on-amber);
  border:1px solid rgba(20,15,8,.14)}
.th-actions .text-button{flex:none;color:var(--on-amber);opacity:.9;font-weight:800}
/* The no-plan variant is a quiet surface: it is a fallback, not the main act. */
.today-hero-empty{display:flex;align-items:center;gap:12px;width:100%;text-align:left;
  background:var(--card-bg);border:1px solid var(--card-hair);color:var(--cream);box-shadow:var(--shadow)}
.today-hero-empty .th-copy{flex:1;min-width:0}
.today-hero-empty .th-copy small{color:var(--faint)}
.today-hero-empty .th-copy em{color:var(--taupe)}
.today-hero-empty .workout-start{flex:none;margin:0}

/* ---- Weekly muscle dose: the signature visual ---------------------------
   Ranked by EXCEPTION, never by volume. Direct vs assisting is carried by
   fill PATTERN and by a written count, so it survives monochrome and
   colour-blindness; the notch marks the minimum weekly dose. */
.dose-board{display:grid;gap:2px;margin:14px 0 0}
.dose-row{display:flex;align-items:center;gap:12px;width:100%;min-height:46px;padding:8px 0;
  border:0;border-bottom:1px solid var(--hair);background:transparent;color:var(--cream);text-align:left}
.dose-row:last-of-type{border-bottom:0}
.dose-name{flex:none;width:74px;font-size:13px;font-weight:700;letter-spacing:-.01em}
.dose-track{position:relative;flex:1;min-width:0;height:14px;border-radius:4px;background:var(--glass-2);
  overflow:hidden;display:flex;align-items:stretch}
.dose-direct{display:block;height:100%;border-radius:4px 0 0 4px;background:var(--amber);min-width:2px}
/* Assisting sets are HATCHED, not merely a different colour - the distinction has to survive a
   greyscale print and a colour-blind reader. */
.dose-assist{display:block;height:100%;background:repeating-linear-gradient(115deg,
  var(--cream-dim) 0 3px,transparent 3px 7px);opacity:.75}
/* The minimum-dose notch: 10 direct sets/week (Schoenfeld 2017 dose-response meta-analysis). */
.dose-min{position:absolute;top:-2px;bottom:-2px;width:2px;background:var(--cream);opacity:.55;border-radius:1px}
.dose-nums{flex:none;width:74px;text-align:right;font-size:12px;color:var(--taupe);
  font-variant-numeric:tabular-nums lining-nums}
.dose-nums strong{color:var(--cream);font-weight:800;font-size:14px}
.dose-nums small{display:block;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase}
.dose-under .dose-nums small{color:var(--amber-deep)}
.dose-over .dose-nums small{color:var(--teal)}
.dose-all{width:100%;min-height:44px;margin-top:4px;border:0;border-top:1px solid var(--hair);
  background:transparent;color:var(--amber-deep);font-size:12.5px;font-weight:800}
.dose-empty{margin:14px 0 0;color:var(--taupe);font-size:12.5px}
/* The card is a plain section again now that the ring has gone. */
.activity-card .activity-heading h2{font-size:19px}
/* The heading was display:none for the v2 ring layout, which owned its own centre label. With the
   ring gone it is the only place the plain counts can live, so it comes back - and it carries the
   two numbers that replace "41%": each one traceable to exactly one thing. */
.activity-card .activity-heading{display:flex}
.activity-card .activity-heading h2{font-size:22px;font-weight:800;letter-spacing:-.025em;margin:3px 0 0}
.activity-card .activity-detail{margin:3px 0 0;color:var(--taupe);font-size:13px;font-weight:600}
/* A new user should not meet a scoreboard of zeroes through the onboarding blur. Nothing about the
   week is worth reporting before there is a week. */
body.first-run-open .activity-card,
body.first-run-open #weekDots,
body.first-run-open #todayHero{visibility:hidden}

/* ---- Editing a logged workout (2026-08-05) ------------------------------
   A finished session used to be immutable: a wrong number was wrong for
   good, and the only "fix" was deleting it and re-logging from memory,
   which destroys the timestamps and the PRs. */
.he-live{margin:-4px 0 0;color:var(--taupe);font-size:13px;font-variant-numeric:tabular-nums lining-nums}
.he-live strong{color:var(--cream);font-weight:800;font-size:16px}
.he-help{margin:8px 0 0;color:var(--taupe);font-size:12.5px;line-height:1.5}
.he-list{margin-top:12px}
.he-ex{padding:12px 0;border-bottom:1px solid var(--hair)}
.he-ex>strong{display:block;margin-bottom:8px;font-size:14.5px;font-weight:700;letter-spacing:-.01em}
.he-set{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:8px}
.he-n{flex:none;width:20px;color:var(--faint);font-size:12px;font-weight:800;
  font-variant-numeric:tabular-nums lining-nums}
.he-in{flex:1;min-width:0;min-height:48px;border:1px solid var(--hair);border-radius:var(--r2,12px);
  background:var(--glass);color:var(--cream);padding:0 12px;font-size:16px;
  font-variant-numeric:tabular-nums lining-nums}
.he-del{flex:none;width:44px;height:44px;border:1px solid var(--hair);border-radius:var(--r2,12px);
  background:transparent;color:var(--taupe);font-size:18px}
.he-del:active{color:var(--danger);border-color:rgba(170,70,60,.34)}
/* The warning names the problem in WORDS on its own line - it is the whole point of the screen,
   and it must read the same to a colour-blind lifter as to anyone else. */
.he-warn{flex-basis:100%;font-style:normal;color:var(--amber-deep);font-size:11.5px;font-weight:800;
  letter-spacing:.02em;padding-left:28px}
.he-undone .he-in{opacity:.75}
.he-add{min-height:44px;border:0;background:transparent;color:var(--amber-deep);
  font-size:12.5px;font-weight:800;padding:0}
