
/* ============================================================
   WORKOUT
   ============================================================ */
.wk-h{ font-family:var(--head); font-size:23px; font-weight:600; letter-spacing:.03em; text-transform:uppercase; margin:2px 0 14px; }

/* ---------- goal selector ---------- */
.goalseg{ display:flex; background:var(--card); border:1px solid var(--line); border-radius:14px; overflow:hidden; margin-bottom:18px; }
.goalseg button{
  flex:1 1 0; min-width:0; display:flex; flex-direction:column; align-items:center; gap:8px;
  padding:16px 6px 14px; background:transparent; border:none; cursor:pointer; font:inherit;
  color:var(--muted); font-size:11.5px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  border-right:1px solid var(--line); transition:color .18s, background .18s;
}
.goalseg button:last-child{ border-right:none; }
.goalseg button span{ text-align:center; line-height:1.25; }
.goalseg__ic{ width:44px; height:44px; border-radius:50%; display:grid; place-items:center; background:transparent; transition:background .18s; }
.goalseg__ic svg{ width:28px; height:28px; }
.goalseg button.active{ color:var(--gold); background:linear-gradient(180deg,rgba(245,179,1,.10),transparent); box-shadow:inset 0 0 0 1.5px var(--gold); border-radius:13px; }
.goalseg button.active .goalseg__ic{ background:#000; }

/* ---------- plan hero card ---------- */
.plancard{ position:relative; overflow:hidden; background:var(--card); border:1px solid var(--line); border-radius:16px; padding:22px 20px 20px; }
/* Scrim over the photo's lower half. Measured positions inside the card:
   title 4-10%, blurb 18-28%, stat row 31.5-37%, Plan Overview from 40%.
   So the photo is left alone across the headline band and is damped out from
   ~24% down, which keeps the stat row readable whatever the artwork does —
   without it, "TIME / DAY" landed on a brightly lit shoulder. Copy and panels
   carry z-index:1, so they paint above this. */
.plancard::after{ content:''; position:absolute; inset:0; z-index:0; pointer-events:none;
  background:linear-gradient(to bottom,
    transparent 22%, rgba(20,21,24,.55) 32%, rgba(20,21,24,.92) 40%, var(--card) 48%); }
/* The photo sits in the TOP-RIGHT of the card and feathers away before it
   reaches the copy.
   Geometry matters here: the visible area must roughly match the art's aspect,
   or `cover` crops a tall sliver and you end up looking at the back of the
   athlete's head. A 60% x 56% box is ~0.67 against 3:4 art, so `cover` trims
   only a little and the whole subject reads.
   Capping the height at 56% also guarantees the stat row and the Plan Overview
   panel can never sit on top of the photo.
   The left feather is a CSS mask on the ELEMENT, so it is expressed in box
   percentages and cannot be thrown off by however `cover` decides to crop; the
   bottom edge is feathered in the art itself. */
.plancard__bg{ position:absolute; top:0; right:0; width:60%; height:56%;
  background-size:cover; background-position:center top; pointer-events:none;
  -webkit-mask-image:linear-gradient(90deg,
     transparent 22%, rgba(0,0,0,.16) 40%, rgba(0,0,0,.60) 58%, #000 78%);
          mask-image:linear-gradient(90deg,
     transparent 22%, rgba(0,0,0,.16) 40%, rgba(0,0,0,.60) 58%, #000 78%); }
.plancard > *:not(.plancard__bg){ position:relative; z-index:1; }
.plancard__t{ font-family:var(--head); font-size:32px; font-weight:700; letter-spacing:.02em; line-height:1; }
.plancard__s{ font-size:12.5px; font-weight:600; letter-spacing:.14em; color:var(--text-soft); text-transform:uppercase; margin-top:8px; }
.plancard__rule{ width:74px; height:4px; border-radius:2px; background:var(--gold); margin:14px 0 14px; }
.plancard__blurb{ font-size:14px; line-height:1.5; color:var(--muted); max-width:52%; }

/* Sized to content and spaced apart — NOT equal thirds. Forcing three equal
   columns left every block at exactly 102px, which "LEVEL / BEGINNER" already
   exceeded, so the longest label ("TIME / DAY") was clipped by the card's
   overflow:hidden. Now each block takes the width it needs and the leftover
   space goes into the gaps. */
.planstats{ display:flex; align-items:center; justify-content:space-between;
  gap:6px; margin:20px 0 18px; }
.planstats > div{ display:flex; align-items:center; gap:9px; flex:0 1 auto; min-width:0; }
.planstats__txt{ display:flex; flex-direction:column; min-width:0; }
.planstats__ic{ width:36px; height:36px; flex:0 0 36px; border-radius:11px; background:var(--field-2,var(--field)); border:1px solid var(--line); display:grid; place-items:center; }
.planstats__ic svg{ width:18px; height:18px; }
.planstats__k{ font-size:9px; line-height:1.2; letter-spacing:.07em; color:var(--muted); text-transform:uppercase; font-weight:600; white-space:nowrap; }
.planstats__v{ font-size:12.5px; line-height:1.25; font-weight:800; color:var(--gold); letter-spacing:.02em; margin-top:3px; white-space:nowrap; }
.planstats__sep{ width:1px; align-self:stretch; background:var(--line); flex:0 0 1px; }

.planov{ background:var(--card-2); border:1px solid var(--line); border-radius:14px; padding:14px 13px 4px; }
.planov__h{ font-family:var(--head); font-size:14px; font-weight:600; letter-spacing:.1em; text-transform:uppercase; margin-bottom:6px; }
.wkrow{ display:flex; align-items:center; gap:12px; width:100%; background:none; border:none; padding:11px 2px; cursor:pointer; font:inherit; color:inherit; text-align:left; border-top:1px solid var(--line); }
.planov .wkrow:first-of-type{ border-top:none; }
/* A ROUNDED RECT, not a circle. A circle is at its narrowest exactly where a
   stacked label sits: at 42px the ring offered ~20px of width where "WEEK"
   needs ~36px, so the caps ran straight through it. Fitting that as a circle
   means going back to ~51px — the size that read as zoomed-in. 10px corners
   keep most of the height straight, so the label fits at the smaller size. */
.wkbadge{ width:42px; height:42px; flex:0 0 42px; border-radius:8px; border:1.5px solid var(--gold); display:grid; place-items:center; line-height:1; }
.wkbadge b{ display:block; font-size:9px; line-height:1; letter-spacing:.02em; color:var(--gold); font-weight:700; }
.wkbadge i{ display:block; font-style:normal; font-family:var(--head); font-size:19px; line-height:1; font-weight:700; color:var(--gold); margin-top:3px; }
.wkrow__t{ flex:1 1 auto; min-width:0; }
.wkrow__t b{ display:block; font-size:14px; font-weight:700; }
.wkrow__t span{ display:block; font-size:12px; color:var(--muted); margin-top:3px; }
.wkrow svg{ width:18px; height:18px; color:var(--muted-2); flex:0 0 18px; }

.btn-gold{
  display:flex; align-items:center; justify-content:center; gap:8px; width:100%;
  margin-top:16px; padding:14px 16px; border:none; border-radius:13px; cursor:pointer;
  background:var(--gold); color:#111; font-family:var(--head); font-size:15px; font-weight:700;
  letter-spacing:.1em; text-transform:uppercase; transition:transform .12s, filter .15s;
}
.btn-gold:hover{ filter:brightness(1.05); }
.btn-gold:active{ transform:scale(.985); }
.btn-gold:disabled{ opacity:.55; cursor:default; }

/* ---------- plan detail ---------- */
.pd-head{ display:flex; align-items:flex-start; gap:12px; margin-bottom:14px; }
.pd-back{ width:34px; height:34px; flex:0 0 34px; margin-top:2px; display:grid; place-items:center; background:none; border:none; color:var(--text); cursor:pointer; padding:0; }
.pd-back svg{ width:22px; height:22px; }
.pd-title{ flex:1 1 auto; min-width:0; }
.pd-title h2{ font-family:var(--head); font-size:21px; font-weight:700; letter-spacing:.02em; text-transform:uppercase; line-height:1.15; margin:0; }
.pd-title p{ font-size:13.5px; color:var(--muted); margin:5px 0 0; }
.pd-prog{ flex:0 0 auto; display:flex; align-items:center; gap:11px; background:var(--card); border:1px solid var(--line); border-radius:12px; padding:10px 12px; }
.pd-prog__k{ font-size:9.5px; letter-spacing:.1em; color:var(--muted); text-transform:uppercase; font-weight:600; }
.pd-prog__v{ font-family:var(--head); font-size:19px; font-weight:700; color:var(--gold); margin-top:2px; }
.ring{ width:42px; height:42px; flex:0 0 42px; transform:rotate(-90deg); }
.ring__bg{ fill:none; stroke:var(--line-2); stroke-width:3.5; }
.ring__fg{ fill:none; stroke:var(--gold); stroke-width:3.5; stroke-linecap:round; transition:stroke-dashoffset .5s var(--ease); }

.pd-bar{ height:4px; border-radius:2px; background:var(--line); overflow:hidden; margin-bottom:16px; }
.pd-bar i{ display:block; height:100%; border-radius:2px; background:var(--gold); transition:width .5s var(--ease); }

.pd-stats{ display:flex; background:var(--card); border:1px solid var(--line); border-radius:14px; padding:16px 4px; margin-bottom:16px; }
.pd-stats > div{ flex:1 1 0; min-width:0; display:flex; flex-direction:column; align-items:center; gap:7px; padding:0 4px; border-right:1px solid var(--line); }
.pd-stats > div:last-child{ border-right:none; }
.pd-stats svg{ width:21px; height:21px; color:var(--text); }
.pd-stats b{ font-size:9px; letter-spacing:.07em; color:var(--muted); text-transform:uppercase; font-weight:600; text-align:center; }
.pd-stats i{ font-style:normal; font-size:12.5px; font-weight:800; color:var(--gold); letter-spacing:.02em; text-align:center; line-height:1.2; }

.wktabs{ display:flex; gap:8px; background:var(--card); border:1px solid var(--line); border-radius:13px; padding:8px; margin-bottom:6px; }
.wktab{ flex:1 1 0; min-width:0; position:relative; background:var(--card-2); border:1px solid var(--line); border-radius:10px; padding:11px 4px; cursor:pointer; font:inherit; color:var(--text-soft); text-align:center; transition:background .15s, color .15s; }
.wktab b{ display:block; font-family:var(--head); font-size:13px; font-weight:700; letter-spacing:.04em; text-transform:uppercase; }
.wktab span{ display:block; font-size:10.5px; color:var(--muted); margin-top:3px; }
.wktab.active{ background:var(--gold); border-color:var(--gold); color:#111; }
.wktab.active span{ color:rgba(0,0,0,.65); }
/* the little pointer under the selected week, as in the design */
.wktab.active::after{ content:''; position:absolute; left:50%; bottom:-7px; width:11px; height:11px; background:var(--gold); transform:translateX(-50%) rotate(45deg); border-radius:2px; }

.wkhead{ padding:18px 2px 2px; }
.wkhead h3{ font-family:var(--head); font-size:15px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; margin:0; }
.wkhead p{ font-size:13px; color:var(--muted); margin:6px 0 0; }

.daylist{ display:flex; flex-direction:column; gap:10px; margin-top:14px; }
.dayrow{ display:flex; align-items:center; gap:12px; background:var(--card); border:1px solid var(--line); border-radius:13px; padding:11px 12px 11px 11px; }
.dayrow--next{ border-color:var(--gold); box-shadow:0 0 0 1px rgba(245,179,1,.25); }
.dayrow--done{ border-color:rgba(45,166,100,.4); }
/* Matched to .wkbadge so the two read as one family. */
.daybadge{ width:46px; height:46px; flex:0 0 46px; border-radius:9px; border:1.5px solid var(--line-2); display:grid; place-items:center; line-height:1; }
.daybadge b{ display:block; font-size:9px; line-height:1; letter-spacing:.02em; color:var(--muted); font-weight:700; }
.daybadge i{ display:block; font-style:normal; font-family:var(--head); font-size:20px; line-height:1; font-weight:700; color:var(--text-soft); margin-top:3px; }
.dayrow--next .daybadge{ border-color:var(--gold); }
.dayrow--next .daybadge b,.dayrow--next .daybadge i{ color:var(--gold); }
.dayrow--done .daybadge{ border-color:rgba(45,166,100,.55); }
.dayrow--done .daybadge i,.dayrow--done .daybadge b{ color:var(--ok,#2da664); }
.daymain{ flex:1 1 auto; min-width:0; }
.daymain b{ display:block; font-size:14.5px; font-weight:700; line-height:1.25; }
.daymeta{ display:flex; align-items:center; gap:7px; margin-top:5px; font-size:12px; color:var(--muted); }
.daymeta svg{ width:13px; height:13px; flex:0 0 13px; }
.daymeta em{ font-style:normal; color:var(--line-2); }
.daygo{ flex:0 0 auto; border:none; cursor:pointer; font:inherit; }
.daygo--start{ background:var(--gold); color:#111; font-family:var(--head); font-size:12.5px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; padding:10px 16px; border-radius:22px; }
.daygo--lock,.daygo--done{ width:38px; height:38px; border-radius:50%; display:grid; place-items:center; background:var(--field); border:1px solid var(--line); color:var(--muted); }
.daygo--done{ color:var(--ok,#2da664); border-color:rgba(45,166,100,.45); }
.daygo--lock svg,.daygo--done svg{ width:18px; height:18px; }
.daygo:disabled{ cursor:default; }

/* ---------- day / session view ---------- */
.sess-block{ margin-top:18px; }
.sess-block__h{ display:flex; align-items:baseline; gap:9px; margin-bottom:10px; }
.sess-block__h b{ font-family:var(--head); font-size:14px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; }
.sess-block__h span{ font-size:12px; color:var(--muted); }
.exrow{ display:flex; align-items:center; gap:13px; background:var(--card); border:1px solid var(--line); border-radius:13px; padding:11px; width:100%; text-align:left; cursor:pointer; font:inherit; color:inherit; margin-bottom:9px; }
.exrow:last-child{ margin-bottom:0; }
.exthumb{ width:52px; height:52px; flex:0 0 52px; border-radius:11px; background:var(--field); border:1px solid var(--line); overflow:hidden; }
.exrow__t{ flex:1 1 auto; min-width:0; }
.exrow__t b{ display:block; font-size:14.5px; font-weight:700; }
.exrow__t span{ display:block; font-size:12.5px; color:var(--muted); margin-top:3px; }
.exrow__n{ flex:0 0 auto; font-size:13px; font-weight:800; color:var(--gold); letter-spacing:.02em; }

/* ---------- interactive player ---------- */
.player{ text-align:center; }
.player__stage{ width:min(260px,72vw); height:min(260px,72vw); margin:6px auto 4px; border-radius:20px; background:var(--card); border:1px solid var(--line); overflow:hidden; }
.player__name{ font-family:var(--head); font-size:22px; font-weight:700; letter-spacing:.02em; margin:14px 0 4px; }
.player__target{ font-size:13px; color:var(--muted); }
.player__count{ font-family:var(--head); font-size:52px; font-weight:700; color:var(--gold); line-height:1; margin:14px 0 2px; font-variant-numeric:tabular-nums; }
.player__sub{ font-size:12.5px; color:var(--muted); letter-spacing:.06em; text-transform:uppercase; }
.player__rest{ color:var(--brand); }
.cues{ text-align:left; background:var(--card-2); border:1px solid var(--line); border-radius:13px; padding:13px 15px; margin-top:18px; }
.cues b{ display:block; font-size:11px; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); margin-bottom:8px; }
.cues li{ font-size:13.5px; line-height:1.55; margin-left:16px; }
.cues li + li{ margin-top:5px; }
.player__bar{ display:flex; gap:10px; margin-top:18px; }
.player__bar .btn{ flex:1 1 0; padding:15px; font-size:14.5px; }
.player__dots{ display:flex; justify-content:center; gap:6px; margin-top:14px; flex-wrap:wrap; }
.player__dots i{ width:7px; height:7px; border-radius:50%; background:var(--line-2); display:block; }
.player__dots i.on{ background:var(--gold); }
.player__dots i.cur{ background:var(--gold); box-shadow:0 0 0 3px rgba(245,179,1,.22); }

/* ---------- home "today" card ---------- */
.todaycard{ display:flex; align-items:center; gap:13px; width:100%; text-align:left; background:var(--card); border:1px solid var(--line); border-radius:15px; padding:14px; cursor:pointer; font:inherit; color:inherit; margin-bottom:16px; }
.todaycard__ic{ width:48px; height:48px; flex:0 0 48px; border-radius:13px; background:rgba(245,179,1,.1); border:1px solid rgba(245,179,1,.32); display:grid; place-items:center; color:var(--gold); }
.todaycard__ic svg{ width:24px; height:24px; }
.todaycard__t{ flex:1 1 auto; min-width:0; }
.todaycard__t b{ display:block; font-size:15px; font-weight:700; }
.todaycard__t span{ display:block; font-size:12.5px; color:var(--muted); margin-top:3px; }
.todaycard__go{ color:var(--muted-2); flex:0 0 18px; }
.todaycard__go svg{ width:18px; height:18px; }

/* ============================================================
   Workout — exercise figures
   ============================================================
   Articulated SVG stick figures. Each exercise rotates a few joints with CSS
   keyframes, so a demo is a few hundred bytes, stays sharp at any size, works
   with no network, and needs no third-party media licence.
   ============================================================ */
.exfig{ width:100%; height:100%; display:block; }

/* WHY THE LIMBS ARE WEIGHTED, NOT UNIFORM
   Every limb used to be a 5px hairline and the head an unfilled ring, which is
   the definition of a stick figure: no mass, so nothing reads as a body and a
   rotating line reads as a rotating line. A real body is not one thickness —
   the trunk dominates, thighs outweigh arms, forearms and shins taper. Giving
   each segment its own weight (and a solid head) turns the SAME rig into a
   figure with volume, without touching a single one of the 29 animations,
   which all drive `transform` on the joints and are indifferent to stroke.
   Round caps do the rest: each segment becomes a capsule, so joints read as
   joints instead of corners. */
.exfig .j-fig line{ stroke:var(--gold); stroke-width:8; stroke-linecap:round; fill:none; }
/* `line.j-spine`, not `.j-spine`: the base rule above is (0,2,1) and a bare
   class is (0,2,0), so a class-only selector LOSES to it and the trunk quietly
   stayed a hairline — the one weight that matters most. */
.exfig .j-fig line.j-spine{ stroke-width:17; }                        /* the trunk carries the mass */
.exfig .j-armL > line, .exfig .j-armR > line{ stroke-width:8.5; }     /* upper arm */
.exfig .j-foreL > line, .exfig .j-foreR > line{ stroke-width:7; }     /* forearm tapers */
.exfig .j-legL > line, .exfig .j-legR > line{ stroke-width:11.5; }    /* thigh is the thickest limb */
.exfig .j-shinL > line, .exfig .j-shinR > line{ stroke-width:8.5; }   /* shin tapers */
.exfig .j-head{ fill:var(--gold); stroke:none; }                      /* solid, not a ring */
.exfig .j-floor{ stroke:var(--line-2); stroke-width:2; stroke-dasharray:3 6; stroke-linecap:round; }
.exfig .j-bell rect{ fill:var(--gold); stroke:none; }
/* transform-origin is expressed in viewBox units */
.exfig g,.exfig circle,.exfig line{ transform-box:view-box; }
.exfig .j-fig,.exfig .j-body{ transform-origin:60px 108px; }
.exfig .j-armL,.exfig .j-armR{ transform-origin:60px 38px; }
.exfig .j-foreL,.exfig .j-foreR{ transform-origin:60px 56px; }
.exfig .j-legL,.exfig .j-legR{ transform-origin:60px 62px; }
.exfig .j-shinL,.exfig .j-shinR{ transform-origin:60px 86px; }
.exfig .j-armR,.exfig .j-legR{ opacity:.5; }              /* far-side limb reads as depth */
.exfig .j-bell{ transform-origin:60px 73px; }

@media (prefers-reduced-motion:reduce){
  .exfig *{ animation:none !important; }
}

/* ============================================================
   Workout — the muscle map
   ============================================================
   Three states, and they have to be distinguishable at a glance and at 44px:
     rest       the body, quiet, low contrast — it is context, not content
     secondary  assisting muscle, gold at partial strength
     primary    the point of the exercise, full gold
   Colour alone is not enough (roughly 1 in 12 men has a colour vision
   deficiency, and this is a gym), so primary also gets a stroke outline —
   shape and edge carry the same message as the fill.
   ============================================================ */
.mmap{ display:flex; flex-direction:column; align-items:center; gap:12px; }
.mm__bodies{ display:flex; align-items:flex-end; justify-content:center; gap:18px; }
.mm__wrap{ position:relative; display:flex; flex-direction:column; align-items:center; gap:6px; }
.mm__view{ font-size:9.5px; letter-spacing:.14em; text-transform:uppercase; color:var(--muted-2,var(--muted)); font-weight:700; }
.mm{ width:74px; height:auto; display:block; overflow:visible; }

/* The resting body. Deliberately close to the card so the lit muscles are the
   only thing with contrast — a map where everything is visible highlights
   nothing. */
.mm__r{ fill:var(--line); stroke:none; transition:fill .25s ease, opacity .25s ease; }
.mm__m{ fill:var(--line-2); }
.mm__m[data-on="is-secondary"]{ fill:var(--gold); opacity:.42; }
.mm__m[data-on="is-primary"]{ fill:var(--gold); stroke:var(--gold-2); stroke-width:.8; }

/* Legend. Reads as a sentence of chips rather than a paragraph of grey text. */
.mm__legend{ display:flex; flex-wrap:wrap; justify-content:center; gap:6px; }
.mm__chip{ font-size:11px; font-weight:700; letter-spacing:.02em; padding:4px 10px; border-radius:999px; white-space:nowrap; }
.mm__chip--p{ background:rgba(245,179,1,.16); color:var(--gold-2); }
.mm__chip--s{ background:var(--field-2,var(--field)); color:var(--muted); }

/* Small inline map used on the exercise rows, where there is no room for a
   legend — just the lit body, at thumbnail size. */
.mm--mini{ width:34px; }
.mm--mini + .mm__view{ display:none; }

/* ---------- exercise info panel (player + detail modal) ----------
   Two stacked sections rather than one wall of text. "Muscles worked" comes
   FIRST because it answers the question a beginner has before they start
   moving; the cues answer the one they have while moving. */
.exinfo{ margin-top:18px; display:flex; flex-direction:column; gap:12px; }
.exinfo__sec{ background:var(--card-2); border:1px solid var(--line); border-radius:14px; padding:15px 16px; }
.exinfo__h{ display:block; font-family:var(--head); font-size:12px; font-weight:700; letter-spacing:.12em;
  text-transform:uppercase; color:var(--muted); margin-bottom:12px; text-align:left; }
.cuelist{ margin:0; padding:0; list-style:none; text-align:left; }
.cuelist li{ position:relative; padding-left:22px; font-size:14px; line-height:1.5; color:var(--text-soft); }
.cuelist li + li{ margin-top:10px; }
/* A gold tick rather than a bullet: these are things to DO, not a list of
   facts, and the mark should read as a checklist. */
.cuelist li::before{ content:''; position:absolute; left:2px; top:6px; width:9px; height:5px;
  border-left:2px solid var(--gold); border-bottom:2px solid var(--gold);
  transform:rotate(-45deg); border-radius:1px; }
html[data-theme="light"] .cuelist li::before{ border-color:var(--gold-3); }

/* squat */
@keyframes k-sqb{ 0%,100%{transform:translateY(0)} 50%{transform:translateY(15px)} }
@keyframes k-sqt{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(52deg)} }
@keyframes k-sqs{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(-52deg)} }
@keyframes k-sqa{ 0%,100%{transform:rotate(4deg)} 50%{transform:rotate(-78deg)} }
.ex-squat .j-fig{ animation:k-sqb 2.2s ease-in-out infinite }
.ex-squat .j-legL,.ex-squat .j-legR{ animation:k-sqt 2.2s ease-in-out infinite }
.ex-squat .j-shinL,.ex-squat .j-shinR{ animation:k-sqs 2.2s ease-in-out infinite }
.ex-squat .j-armL,.ex-squat .j-armR{ animation:k-sqa 2.2s ease-in-out infinite }

/* squat pulses — same shape, short fast range */
@keyframes k-pub{ 0%,100%{transform:translateY(11px)} 50%{transform:translateY(17px)} }
@keyframes k-put{ 0%,100%{transform:rotate(42deg)} 50%{transform:rotate(58deg)} }
@keyframes k-pus{ 0%,100%{transform:rotate(-42deg)} 50%{transform:rotate(-58deg)} }
.ex-pulse .j-fig{ animation:k-pub .7s ease-in-out infinite }
.ex-pulse .j-legL,.ex-pulse .j-legR{ animation:k-put .7s ease-in-out infinite }
.ex-pulse .j-shinL,.ex-pulse .j-shinR{ animation:k-pus .7s ease-in-out infinite }
.ex-pulse .j-armL,.ex-pulse .j-armR{ transform:rotate(-78deg) }

/* wall sit — held position, subtle breathing */
@keyframes k-wall{ 0%,100%{transform:translateY(15px)} 50%{transform:translateY(17px)} }
.ex-wall .j-fig{ animation:k-wall 3s ease-in-out infinite }
.ex-wall .j-legL,.ex-wall .j-legR{ transform:rotate(56deg) }
.ex-wall .j-shinL,.ex-wall .j-shinR{ transform:rotate(-56deg) }
.ex-wall .j-armL,.ex-wall .j-armR{ transform:rotate(-82deg) }

/* jumping jacks */
@keyframes k-jkb{ 0%,100%{transform:translateY(0)} 50%{transform:translateY(-7px)} }
@keyframes k-jka{ 0%,100%{transform:rotate(8deg)} 50%{transform:rotate(155deg)} }
@keyframes k-jkar{ 0%,100%{transform:rotate(-8deg)} 50%{transform:rotate(-155deg)} }
@keyframes k-jkl{ 0%,100%{transform:rotate(4deg)} 50%{transform:rotate(24deg)} }
@keyframes k-jklr{ 0%,100%{transform:rotate(-4deg)} 50%{transform:rotate(-24deg)} }
.ex-jack .j-fig{ animation:k-jkb .85s ease-in-out infinite }
.ex-jack .j-armL{ animation:k-jka .85s ease-in-out infinite }
.ex-jack .j-armR{ animation:k-jkar .85s ease-in-out infinite }
.ex-jack .j-legL{ animation:k-jkl .85s ease-in-out infinite }
.ex-jack .j-legR{ animation:k-jklr .85s ease-in-out infinite }

/* marching / high knees */
@keyframes k-mkl{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(-58deg)} }
@keyframes k-mks{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(64deg)} }
@keyframes k-mka{ 0%,100%{transform:rotate(-26deg)} 50%{transform:rotate(26deg)} }
.ex-march .j-legL{ animation:k-mkl 1.4s ease-in-out infinite }
.ex-march .j-shinL{ animation:k-mks 1.4s ease-in-out infinite }
.ex-march .j-legR{ animation:k-mkl 1.4s ease-in-out infinite .7s }
.ex-march .j-shinR{ animation:k-mks 1.4s ease-in-out infinite .7s }
.ex-march .j-armL{ animation:k-mka 1.4s ease-in-out infinite .7s }
.ex-march .j-armR{ animation:k-mka 1.4s ease-in-out infinite }
.ex-knees .j-legL{ animation:k-mkl .6s ease-in-out infinite }
.ex-knees .j-shinL{ animation:k-mks .6s ease-in-out infinite }
.ex-knees .j-legR{ animation:k-mkl .6s ease-in-out infinite .3s }
.ex-knees .j-shinR{ animation:k-mks .6s ease-in-out infinite .3s }
.ex-knees .j-armL{ animation:k-mka .6s ease-in-out infinite .3s }
.ex-knees .j-armR{ animation:k-mka .6s ease-in-out infinite }

/* lunges */
@keyframes k-lub{ 0%,100%{transform:translateY(0)} 50%{transform:translateY(13px)} }
@keyframes k-luf{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(-34deg)} }
@keyframes k-lufs{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(62deg)} }
@keyframes k-lur{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(26deg)} }
@keyframes k-lurs{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(-58deg)} }
.ex-lunge .j-fig{ animation:k-lub 2.4s ease-in-out infinite }
.ex-lunge .j-legL{ animation:k-luf 2.4s ease-in-out infinite }
.ex-lunge .j-shinL{ animation:k-lufs 2.4s ease-in-out infinite }
.ex-lunge .j-legR{ animation:k-lur 2.4s ease-in-out infinite }
.ex-lunge .j-shinR{ animation:k-lurs 2.4s ease-in-out infinite }

/* calf raises */
@keyframes k-calf{ 0%,100%{transform:translateY(0)} 50%{transform:translateY(-9px)} }
.ex-calf .j-fig{ animation:k-calf 1.4s ease-in-out infinite }

/* arm circles */
@keyframes k-circ{ from{transform:rotate(0)} to{transform:rotate(360deg)} }
.ex-circle .j-armL{ animation:k-circ 2s linear infinite }
.ex-circle .j-armR{ animation:k-circ 2s linear infinite reverse }

/* shoulder press / curl / row (dumbbell) */
@keyframes k-prs{ 0%,100%{transform:rotate(148deg)} 50%{transform:rotate(178deg)} }
@keyframes k-prf{ 0%,100%{transform:rotate(-52deg)} 50%{transform:rotate(0)} }
@keyframes k-prb{ 0%,100%{transform:translateY(-40px)} 50%{transform:translateY(-64px)} }
.ex-press .j-armL,.ex-press .j-armR{ animation:k-prs 1.9s ease-in-out infinite }
.ex-press .j-foreL,.ex-press .j-foreR{ animation:k-prf 1.9s ease-in-out infinite }
.ex-press .j-bell{ animation:k-prb 1.9s ease-in-out infinite }
@keyframes k-cur{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(-128deg)} }
@keyframes k-curb{ 0%,100%{transform:translateY(0)} 50%{transform:translateY(-26px)} }
.ex-curl .j-foreL,.ex-curl .j-foreR{ animation:k-cur 1.8s ease-in-out infinite }
.ex-curl .j-bell{ animation:k-curb 1.8s ease-in-out infinite }
@keyframes k-rowa{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(-16deg)} }
@keyframes k-rowf{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(-104deg)} }
@keyframes k-rowb{ 0%,100%{transform:translate(0,0)} 50%{transform:translate(0,-22px)} }
.ex-row .j-fig{ transform:rotate(-46deg); transform-origin:60px 62px }
.ex-row .j-armL,.ex-row .j-armR{ animation:k-rowa 1.9s ease-in-out infinite }
.ex-row .j-foreL,.ex-row .j-foreR{ animation:k-rowf 1.9s ease-in-out infinite }
.ex-row .j-bell{ animation:k-rowb 1.9s ease-in-out infinite }

/* burpee — condensed squat/plank/jump cycle */
@keyframes k-brb{ 0%,100%{transform:translateY(0)} 30%{transform:translateY(16px)} 60%{transform:translateY(30px)} 80%{transform:translateY(-8px)} }
@keyframes k-brl{ 0%,100%{transform:rotate(0)} 30%{transform:rotate(54deg)} 60%{transform:rotate(84deg)} }
@keyframes k-brs{ 0%,100%{transform:rotate(0)} 30%{transform:rotate(-54deg)} 60%{transform:rotate(-84deg)} }
@keyframes k-bra{ 0%,100%{transform:rotate(6deg)} 45%{transform:rotate(-96deg)} 80%{transform:rotate(168deg)} }
.ex-burpee .j-fig{ animation:k-brb 2.2s ease-in-out infinite }
.ex-burpee .j-legL,.ex-burpee .j-legR{ animation:k-brl 2.2s ease-in-out infinite }
.ex-burpee .j-shinL,.ex-burpee .j-shinR{ animation:k-brs 2.2s ease-in-out infinite }
.ex-burpee .j-armL,.ex-burpee .j-armR{ animation:k-bra 2.2s ease-in-out infinite }

/* stretches */
@keyframes k-str{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(56deg)} }
.ex-stretch .j-fig{ animation:k-str 3s ease-in-out infinite; transform-origin:60px 62px }
@keyframes k-qs{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(112deg)} }
.ex-quadstretch .j-shinL{ animation:k-qs 3s ease-in-out infinite }
.ex-quadstretch .j-armL{ transform:rotate(-24deg) }

/* prone family: plank / push-up / climber / superman / bird dog / child's pose */
@keyframes k-push{ 0%,100%{transform:translateY(0)} 50%{transform:translateY(13px)} }
.ex-push .j-body{ animation:k-push 1.9s ease-in-out infinite; transform-origin:98px 100px }
@keyframes k-hold{ 0%,100%{transform:translateY(0)} 50%{transform:translateY(2px)} }
.ex-plank .j-body{ animation:k-hold 3.2s ease-in-out infinite }
@keyframes k-clk{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(-52deg)} }
.ex-climb .j-legL{ animation:k-clk .62s ease-in-out infinite; transform-origin:86px 76px }
@keyframes k-sup{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(-9deg)} }
.ex-super .j-body{ animation:k-sup 2.4s ease-in-out infinite; transform-origin:62px 72px }
@keyframes k-bird{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(34deg)} }
.ex-bird .j-legL{ animation:k-bird 2.6s ease-in-out infinite; transform-origin:86px 76px }
.ex-bird .j-armL{ animation:k-bird 2.6s ease-in-out infinite reverse; transform-origin:42px 67px }
@keyframes k-child{ 0%,100%{transform:translateX(0)} 50%{transform:translateX(-5px)} }
.ex-child .j-body{ animation:k-child 4s ease-in-out infinite }

/* supine family: crunch / bridge / dead bug / leg raise */
@keyframes k-crn{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(-22deg)} }
.ex-crunch .j-body{ animation:k-crn 1.9s ease-in-out infinite; transform-origin:74px 96px }
@keyframes k-brg{ 0%,100%{transform:translateY(0)} 50%{transform:translateY(-13px)} }
.ex-bridge .j-spine{ animation:k-brg 2.1s ease-in-out infinite; transform-origin:56px 93px }
@keyframes k-db{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(-30deg)} }
.ex-deadbug .j-legL{ animation:k-db 2.4s ease-in-out infinite; transform-origin:74px 96px }
.ex-deadbug .j-armL{ animation:k-db 2.4s ease-in-out infinite reverse; transform-origin:42px 91px }
@keyframes k-lr{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(-56deg)} }
.ex-legraise .j-legL{ animation:k-lr 2.2s ease-in-out infinite; transform-origin:74px 96px }

/* side plank */
@keyframes k-sp{ 0%,100%{transform:rotate(0)} 50%{transform:rotate(-4deg)} }
.ex-sideplank .j-body{ animation:k-sp 3s ease-in-out infinite; transform-origin:40px 66px }

/* light theme: the figures need a darker gold to stay legible on white */
html[data-theme="light"] .exfig .j-fig line{ stroke:var(--gold-3); }
/* The head is a SOLID shape now, not a ring, so it takes a fill and must not
   also carry a stroke — a stroked fill reads as a fatter, blurrier head. */
html[data-theme="light"] .exfig .j-head{ stroke:none; }
html[data-theme="light"] .exfig .j-bell rect{ fill:var(--gold-3); }

/* Same problem across the whole Workout tab: --gold is #f5b301, which is only
   ~1.8:1 on a white card. Everything that paints gold TEXT or a gold HAIRLINE
   switches to the darker --gold-3 in light mode. Gold FILLS (the week tab, the
   START pill, the progress bar) keep the bright gold because they carry dark
   text on top and already have plenty of contrast. */
html[data-theme="light"] .planstats__v,
html[data-theme="light"] .pd-prog__v,
html[data-theme="light"] .pd-stats i,
html[data-theme="light"] .exrow__n,
html[data-theme="light"] .player__count,
html[data-theme="light"] .wkbadge b,
html[data-theme="light"] .wkbadge i,
html[data-theme="light"] .goalseg button.active,
html[data-theme="light"] .dayrow--next .daybadge b,
html[data-theme="light"] .dayrow--next .daybadge i{ color:var(--gold-3); }
html[data-theme="light"] .wkbadge,
html[data-theme="light"] .dayrow--next .daybadge{ border-color:var(--gold-3); }
html[data-theme="light"] .ring__fg{ stroke:var(--gold-3); }
html[data-theme="light"] .goalseg button.active{ box-shadow:inset 0 0 0 1.5px var(--gold-3); }
html[data-theme="light"] .plancard__rule{ background:var(--gold-3); }

/* ============================================================
   Light mode — the plan card
   ============================================================
   THE BUG: .plancard::after damps the photo down to the card colour so the
   stat row stays readable. Its stops were hardcoded rgba(20,21,24,…) — a DARK
   scrim — with no light-mode counterpart. In light mode that painted a dark
   band underneath dark text, and "DURATION / LEVEL / TIME / DAY" measured
   2.90:1 against it. That is the washed-out row in the screenshots.
   The scrim has to fade to whatever the card actually is, so here it fades to
   white and the same labels measure 5.35:1.
   ============================================================ */
html[data-theme="light"] .plancard::after{
  background:linear-gradient(to bottom,
    transparent 22%, rgba(255,255,255,.60) 32%, rgba(255,255,255,.93) 40%, var(--card) 48%);
}
/* The photo is bright artwork on a white card, so it needs a floor of its own
   or the athlete dissolves into the background. */
html[data-theme="light"] .plancard__bg{ opacity:.88; }

/* --gold-3 is 4.48:1 on white — a hair under the 4.5 floor for normal text.
   Every gold VALUE on the workout screens therefore steps down to --gold-4
   (6.51:1). Measured, not guessed. */
html[data-theme="light"] .planstats__v,
html[data-theme="light"] .pd-prog__v,
html[data-theme="light"] .exrow__n,
html[data-theme="light"] .mm__chip--p{ color:var(--gold-4); }

/* The resting body must stay visible on white without competing with the lit
   muscles: --line is nearly white in light mode, which would erase it. */
html[data-theme="light"] .mm__r{ fill:#dcdce3; }
html[data-theme="light"] .mm__m{ fill:#c6c6d0; }
html[data-theme="light"] .mm__m[data-on="is-secondary"]{ fill:var(--gold-3); opacity:.5; }
html[data-theme="light"] .mm__m[data-on="is-primary"]{ fill:var(--gold-3); stroke:var(--gold-4); }
html[data-theme="light"] .mm__chip--p{ background:#fdf3d9; }

/* The figure is gold-on-white here; --gold-3 keeps it from glaring. */
html[data-theme="light"] .exfig .j-head{ fill:var(--gold-3); }

/* ============================================================
   Exercise media — the box a demonstration is played in
   ============================================================
   The stage geometry is unchanged (.player__stage / .exthumb keep their sizes);
   only what goes INSIDE it moved from an inline SVG to whatever PAI.EXMEDIA
   resolved. These rules exist so a video, a poster and the legacy diagram all
   fill the same box identically, and so swapping between them never shifts the
   layout — the box is sized by its parent, never by its contents.
   ============================================================ */
.exmedia{ position:relative; display:block; }
.exmedia > video,
.exmedia > img,
.exmedia > svg{
  display:block; width:100%; height:100%;
  /* `contain`, never `cover`: these clips are framed to keep the whole body in
     shot, and cropping one to fill a square would cut the feet off exactly the
     movements where footwork is the point. */
  object-fit:contain;
}
/* Alpha video carries its own transparency, so the card behind it shows through
   and the clip sits on the app's surface rather than a black rectangle. */
.exmedia__v{ background:transparent; }
/* Promote to its own layer: the decoder output is composited by the GPU instead
   of repainting the card underneath it on every frame. */
.exmedia__v,
.exmedia__i{ will-change:transform; transform:translateZ(0); }
/* A thumbnail is a still; give it a little breathing room in its 52px box. */
.exmedia--thumb{ padding:3px; }

/* Equipment / difficulty. Two facts, stated plainly, under the name. */
.exfacts{ display:flex; justify-content:center; flex-wrap:wrap; gap:8px; margin:10px 0 2px; }
.exfacts__i{
  font-size:11px; font-weight:600; letter-spacing:.04em; text-transform:uppercase;
  color:var(--muted); background:var(--field-2,var(--field));
  border:1px solid var(--line); border-radius:999px; padding:5px 11px;
}

/* Primary / secondary muscles, labelled.
   The map legend already colours them; this names which group is which, for the
   places where there is no diagram beside it to infer it from. Same chip
   classes, so the two can never drift apart. */
.mchips{ display:flex; flex-direction:column; gap:8px; margin:12px 0 2px; }
.mchips__row{ display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; }
.mchips__k{
  flex:0 0 auto; min-width:68px;
  font-size:10px; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--muted-2);
}
.mchips__v{ display:flex; flex-wrap:wrap; gap:6px; min-width:0; }

/* Reduced motion is handled in JS as well (a poster is served instead of a
   clip), but if a video is already mounted when the preference changes, stop it
   moving rather than wait for a re-render. */
@media (prefers-reduced-motion: reduce){
  .exmedia__v{ animation:none !important; }
}
