/* Port of the supplied ShinyButton. Keep its mask geometry, paired animations,
   shimmer and hover behavior; only palette, typography and sizing use OpenGym. */
@property --og-shiny-angle{syntax:"<angle>";initial-value:0deg;inherits:false}
@property --og-shiny-offset{syntax:"<angle>";initial-value:0deg;inherits:false}
@property --og-shiny-percent{syntax:"<percentage>";initial-value:5%;inherits:false}
@property --og-shiny-shine{syntax:"<color>";initial-value:white;inherits:false}
.shiny-button{
  --shiny-bg:var(--ink);
  --shiny-bg-subtle:color-mix(in srgb,var(--on-ink) 8%,var(--ink));
  --shiny-fg:var(--on-ink);
  --shiny-highlight:color-mix(in srgb,var(--on-ink) 35%,transparent);
  --shiny-highlight-subtle:var(--on-ink);
  --og-shiny-shine:var(--on-ink);
  --shiny-animation:og-shiny-angle linear infinite;
  --shiny-play-state:running,paused;
  --shiny-duration:3s;
  --shiny-shadow-size:2px;
  --shiny-transition:800ms cubic-bezier(.25,1,.5,1);
  isolation:isolate;position:relative;overflow:hidden;display:inline-flex;align-items:center;justify-content:center;
  min-height:44px;padding:10px 16px;border:1px solid transparent;border-radius:var(--r-pill,999px);
  color:var(--shiny-fg);font:500 14px/1.35 var(--font);cursor:pointer;outline-offset:4px;
  background:linear-gradient(var(--shiny-bg),var(--shiny-bg)) padding-box,
    conic-gradient(from calc(var(--og-shiny-angle) - var(--og-shiny-offset)),transparent,
      var(--shiny-highlight) var(--og-shiny-percent),var(--og-shiny-shine) calc(var(--og-shiny-percent) * 2),
      var(--shiny-highlight) calc(var(--og-shiny-percent) * 3),transparent calc(var(--og-shiny-percent) * 4)) border-box;
  box-shadow:inset 0 0 0 1px var(--shiny-bg-subtle);
  transition:var(--shiny-transition);transition-property:--og-shiny-offset,--og-shiny-percent,--og-shiny-shine;
}
.shiny-button::before,.shiny-button::after,.shiny-button-content::before{
  content:"";pointer-events:none;position:absolute;inset-inline-start:50%;inset-block-start:50%;translate:-50% -50%;z-index:-1;
}
.shiny-button:active:not(:disabled){translate:0 1px}
/* Same sparse dot field and narrow moving conic mask as the supplied source. */
.shiny-button::before{
  --size:calc(100% - var(--shiny-shadow-size) * 3);--position:2px;--space:calc(var(--position) * 2);
  width:var(--size);height:var(--size);border-radius:inherit;opacity:.4;
  background:radial-gradient(circle at var(--position) var(--position),var(--shiny-fg) calc(var(--position) / 4),transparent 0) padding-box;
  background-size:var(--space) var(--space);background-repeat:space;
  mask-image:conic-gradient(from calc(var(--og-shiny-angle) + 45deg),#000,transparent 10% 90%,#000);
  -webkit-mask-image:conic-gradient(from calc(var(--og-shiny-angle) + 45deg),#000,transparent 10% 90%,#000);
}
.shiny-button::after{
  --shiny-animation:og-shiny-shimmer linear infinite;
  width:100%;aspect-ratio:1;
  background:linear-gradient(-50deg,transparent,var(--shiny-highlight),transparent);
  mask-image:radial-gradient(circle at bottom,transparent 40%,#000);
  -webkit-mask-image:radial-gradient(circle at bottom,transparent 40%,#000);opacity:.6;
}
.shiny-button-content{display:inline-flex;align-items:center;gap:12px;min-width:0;z-index:1}
.shiny-button-content::before{
  --size:calc(100% + 1rem);width:var(--size);height:var(--size);
  box-shadow:inset 0 -1ex 2rem 4px var(--shiny-highlight);opacity:0;
  transition:opacity var(--shiny-transition);animation:calc(var(--shiny-duration) * 1.5) og-shiny-breathe linear infinite;
}
.shiny-button,.shiny-button::before,.shiny-button::after{
  animation:var(--shiny-animation) var(--shiny-duration),var(--shiny-animation) calc(var(--shiny-duration) / .4) reverse paused;
  animation-composition:add;animation-play-state:var(--shiny-play-state);
}
.shiny-button:focus-visible{--shiny-play-state:running;outline:2px solid var(--ink);--og-shiny-percent:20%;--og-shiny-offset:95deg;--og-shiny-shine:var(--shiny-highlight-subtle)}
.shiny-button:focus-visible,.shiny-button:focus-visible::before,.shiny-button:focus-visible::after{animation-play-state:running}
.shiny-button:focus-visible .shiny-button-content::before{opacity:1}
@media(hover:hover) and (pointer:fine){
  .shiny-button:hover:not(:disabled){--shiny-play-state:running;--og-shiny-percent:20%;--og-shiny-offset:95deg;--og-shiny-shine:var(--shiny-highlight-subtle)}
  .shiny-button:hover:not(:disabled),.shiny-button:hover:not(:disabled)::before,.shiny-button:hover:not(:disabled)::after{animation-play-state:running}
  .shiny-button:hover:not(:disabled) .shiny-button-content::before{opacity:1}
}
.shiny-button:disabled{cursor:default;color:var(--text-3);animation:none}
.shiny-button:disabled::before,.shiny-button:disabled::after,.shiny-button:disabled .shiny-button-content::before{display:none;animation:none}
@keyframes og-shiny-angle{to{--og-shiny-angle:360deg}}
@keyframes og-shiny-shimmer{to{rotate:360deg}}
@keyframes og-shiny-breathe{from,to{scale:1}50%{scale:1.2}}
@media(prefers-reduced-motion:reduce){
  .shiny-button,.shiny-button::before,.shiny-button::after,.shiny-button-content::before{animation:none!important;transition:none}
  .shiny-button::before,.shiny-button::after,.shiny-button-content::before{display:none}
  .shiny-button:active:not(:disabled){translate:none}
}

.focus-view{display:grid;gap:12px}
.focus-superset-inline{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-bottom:12px;padding-bottom:12px;border-bottom:var(--hair) solid var(--sep);color:var(--ink);font-size:13px}
.focus-superset-inline strong{font-weight:600}
.focus-superset-inline span{color:var(--label-2)}
.focus-superset-inline .icn{font-size:14px}
.focus-superset-inline .btn{min-height:32px;padding-inline:8px;color:var(--ink)}
.focus-superset-nav{display:flex;margin-left:auto}
.focus-superset-nav button{display:grid;place-items:center;width:44px;height:44px;color:var(--label-2)}
.focus-superset-nav button:disabled{opacity:.3}
.focus-card{padding:16px;border-radius:var(--r-lg);background:var(--surface);box-shadow:inset 0 0 0 1.5px var(--control-line)}
.focus-card-header{display:flex;align-items:center;gap:6px;padding-bottom:12px;border-bottom:var(--hair) solid var(--sep)}
.focus-card-header h2{flex:1;font-size:20px;line-height:1.2;text-transform:capitalize}
.focus-warmup{font-size:16px}
/* The set on screen is taken to failure: the same purple "F" the set rows wear. */
.focus-failure{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 4px;border-radius:10px;background:var(--purple);color:#fff;font-size:12px;font-weight:700}
.focus-context{display:grid;gap:5px;margin-top:10px}
.focus-tags{display:flex;flex-wrap:wrap;gap:5px}
.focus-note,.focus-last,.focus-guidance{color:var(--label-2);font-size:12px;line-height:1.35}
.focus-note{padding-left:8px;border-left:var(--hair) solid var(--sep)}
.focus-note.pinned{color:var(--warning-fg);display:flex;gap:5px;align-items:flex-start}
.focus-note .icn{margin-top:1px;flex:none}
.focus-guidance{display:flex;align-items:center;gap:5px;width:max-content;text-align:left;color:var(--ink);font-weight:600}
.focus-guidance .icn{font-size:13px}
.focus-prescription{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:14px 0}
.focus-badge{display:inline-flex;align-items:center;gap:5px;max-width:100%;min-height:30px;padding:6px 11px;border-radius:99px;background:var(--surface-2);color:var(--label);font-size:14px;font-weight:500;line-height:1.2;white-space:nowrap}
.focus-badge .icn{font-size:13px;flex:none}
.focus-progress{padding-inline:12px;background:var(--ink);color:var(--on-ink);font-weight:600}
.focus-badge.plan{background:var(--control-tint);color:var(--ink);white-space:normal}
.focus-badge.warning{background:color-mix(in srgb,var(--orange) 14%,transparent);color:var(--warning-fg);white-space:normal}
.focus-badge .short{color:var(--warning-fg)}
.focus-badge-action{margin-inline-start:2px;color:inherit;font-size:13px;font-weight:700;text-decoration:underline;text-underline-offset:2px}
.focus-set>.stp-w,.focus-side>.stp-w{margin-top:12px}
.focus-set.complete .stp .num:disabled,.focus-set.locked .stp .num:disabled,.focus-set.complete .focus-timed strong,.focus-set.locked .focus-timed strong{color:color-mix(in srgb,var(--label) 48%,var(--surface))!important;-webkit-text-fill-color:color-mix(in srgb,var(--label) 48%,var(--surface))!important;opacity:1}
.focus-lock-note{margin:-4px 2px 2px;color:var(--label-2);font-size:12px;line-height:1.35}
.focus-effort{width:100%;margin-top:16px}
.focus-card>.btn.primary{margin-top:18px;min-height:48px}
.focus-secondary{display:grid;grid-template-columns:1fr 44px;gap:8px;margin-top:8px}
.focus-secondary>.iconbtn{width:44px;height:44px;border:1px solid var(--sep);border-radius:8px}
.focus-skip{display:flex;align-items:center;justify-content:center;gap:6px;min-height:44px;border:1px solid var(--sep);border-radius:8px;color:var(--label)}
.focus-pager{display:grid;grid-template-columns:44px 1fr 44px;align-items:center;gap:8px}
.focus-pager>button{display:grid;place-items:center;width:44px;height:44px;border:1px solid var(--sep);border-radius:50%;color:var(--label)}
.focus-pager>button:disabled{opacity:.3}
.focus-dots{display:flex;align-items:center;justify-content:center;gap:4px}
.focus-dots button{position:relative;width:44px;height:44px}
.focus-dots button::after{content:'';position:absolute;left:50%;top:50%;width:6px;height:6px;border-radius:50%;background:var(--label-3);transform:translate(-50%,-50%)}
.focus-dots button.active::after{width:9px;height:9px;background:var(--ink)}
.focus-dots button.done::after{box-shadow:0 0 0 2px var(--control-line)}
.focus-sides{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.focus-side{min-width:0;padding:10px;border-radius:var(--r);background:var(--surface-2)}
.focus-side-header{display:flex;align-items:center;justify-content:space-between}
.focus-side-check{display:grid;place-items:center;width:44px;height:44px;border-radius:50%;color:var(--label-2)}
.focus-side-check.done{background:var(--done);color:var(--on-ink)}
.focus-timed{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:12px;padding:12px;border-radius:var(--r);background:var(--surface-2)}
.focus-timed .btn{width:auto;min-width:120px}
.focus-extras{display:grid;gap:8px;margin-top:12px}
.focus-extra{display:grid;grid-template-columns:minmax(56px,auto) 1fr 1fr;align-items:end;gap:8px;padding:8px;border-radius:var(--r-sm);background:var(--surface-2)}
.focus-extra .stp-l{font-size:11px}
@media (max-width:400px){
  .focus-sides{grid-template-columns:1fr}
  .focus-extra{grid-template-columns:1fr 1fr}
  .focus-extra>span:first-child{grid-column:1/-1}
}

/* Admin dashboard — operator-facing, English-only. Sits on top of the app's tokens; nothing
   here is used outside views/Admin.jsx and views/AdminCoach.jsx. The page is looked at maybe
   twice a year, so every card says what it is for in a sentence and every state is a word, not
   a colour to decode. */

.adm-intro{color:var(--label-2);font-size:14px;line-height:1.45;margin:-6px 0 16px}

/* one sentence under a card heading that says what the card is for */
.adm-lead{color:var(--label-2);font-size:13px;line-height:1.45;margin:2px 0 12px}

/* status pill: a word and a colour, never a paragraph */
.adm-pill{
  display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:999px;
  font-size:12.5px;font-weight:600;letter-spacing:-.004em;line-height:1.5;white-space:nowrap;
  background:var(--surface-2);color:var(--label-2)
}
.adm-pill::before{content:'';width:7px;height:7px;border-radius:50%;background:currentColor;flex:none}
.adm-pill.ok{background:color-mix(in srgb,var(--green) 16%,transparent);color:var(--done-fg)}
.adm-pill.warn{background:color-mix(in srgb,var(--yellow) 18%,transparent);color:var(--warning-fg)}
.adm-pill.bad{background:color-mix(in srgb,var(--red) 16%,transparent);color:var(--danger-fg)}
.adm-pill.acc{background:var(--control-tint);color:var(--ink)}

/* the one-line "what state is this in" under the card title */
.adm-status{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:14px;color:var(--label-2);margin:4px 0 14px;line-height:1.4}

/* numbered setup steps: a <details> per step, so a finished step folds away */
.adm-step{border-top:var(--hair) solid var(--sep);padding:2px 0}
.adm-step:first-of-type{border-top:0}
.adm-step>summary{
  list-style:none;cursor:pointer;display:flex;align-items:center;gap:12px;min-height:50px;padding:6px 0;
  -webkit-tap-highlight-color:transparent
}
.adm-step>summary::-webkit-details-marker{display:none}
.adm-step>summary:active{opacity:.7}
.adm-num{
  width:26px;height:26px;border-radius:50%;flex:none;display:grid;place-items:center;
  font-size:13px;font-weight:700;background:var(--surface-3);color:var(--label)
}
.adm-step.done .adm-num{background:var(--ink);color:var(--on-ink)}
.adm-step.todo .adm-num{background:var(--surface-3);color:var(--label-2)}
.adm-step-t{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.adm-step-t b{font-size:16px;font-weight:600;letter-spacing:-.012em;line-height:1.25}
.adm-step-t span{font-size:13px;color:var(--label-2);line-height:1.3}
.adm-step>summary .chev{color:var(--label-2);font-size:14px;transition:transform .18s ease;flex:none}
.adm-step[open]>summary .chev{transform:rotate(90deg)}
.adm-step-b{padding:2px 0 14px 38px}
@media (max-width:380px){.adm-step-b{padding-left:0}}

/* a dim explainer that reads like a sentence, not a footnote */
.adm-hint{font-size:13px;color:var(--label-2);line-height:1.45;margin:6px 0 10px}
.adm-hint code{font-size:12px;background:var(--surface-2);padding:1px 5px;border-radius:5px}

/* provider chips grouped under a small heading */
.adm-group{margin:0 0 12px}
.adm-group-t{font-size:11.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--label-2);margin:0 0 7px}
.adm-chips{display:flex;flex-wrap:wrap;gap:8px}
.adm-chips .chip{min-height:38px;display:inline-flex;align-items:center;gap:7px}
.adm-chip-key{
  font-size:10.5px;font-weight:700;letter-spacing:.02em;padding:1px 6px;border-radius:999px;
  background:var(--control-tint);color:var(--ink)
}
.chip.on .adm-chip-key{background:rgba(0,0,0,.18);color:inherit}

/* label + control pairs inside a step */
.adm-field{display:flex;flex-direction:column;gap:6px;margin:0 0 10px}
.adm-field>label{font-size:13px;font-weight:600;color:var(--label-2)}
/* Inside a card the app's default field colour is the card's own colour, so the box was
   invisible and the placeholder floated in space. One shade up, and a size that is readable
   without iOS zooming into it. */
.adm-field .field{width:100%;background:var(--surface-2);font-size:16px;min-height:44px}
.adm-select{
  width:100%;min-height:44px;padding:10px 38px 10px 12px;border-radius:var(--r);border:0;
  background:var(--surface-2);color:var(--label);font-size:15px;appearance:none;-webkit-appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,var(--label-2) 50%),linear-gradient(135deg,var(--label-2) 50%,transparent 50%);
  background-position:calc(100% - 20px) 50%,calc(100% - 14px) 50%;background-size:6px 6px;background-repeat:no-repeat
}
.adm-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:6px}
.adm-actions .btn{min-height:44px}

/* inline result box under the Test button */
.adm-result{
  margin-top:10px;padding:10px 12px;border-radius:var(--r);font-size:13.5px;line-height:1.45;
  background:var(--surface-2);color:var(--label)
}
.adm-result.ok{background:color-mix(in srgb,var(--green) 14%,transparent)}
.adm-result.bad{background:color-mix(in srgb,var(--red) 14%,transparent)}
.adm-result b{display:block;margin-bottom:2px}

/* advanced / activity folds */
.adm-fold{border-top:var(--hair) solid var(--sep);margin-top:4px}
.adm-fold>summary{
  list-style:none;cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:10px;
  min-height:48px;padding:6px 0;font-size:15px;font-weight:600;letter-spacing:-.012em
}
.adm-fold>summary::-webkit-details-marker{display:none}
.adm-fold>summary .chev{color:var(--label-2);font-size:14px;transition:transform .18s ease}
.adm-fold[open]>summary .chev{transform:rotate(90deg)}
.adm-fold-b{padding:0 0 12px}

.adm-kv{display:flex;justify-content:space-between;gap:12px;padding:9px 0;border-bottom:var(--hair) solid var(--sep);font-size:14px}
.adm-kv:last-child{border-bottom:0}
.adm-kv .k{color:var(--label-2);flex:none}
.adm-kv .v{text-align:right;min-width:0;overflow-wrap:anywhere}
/* the two daily-limit numbers: a real field, not the browser's white default box */
.adm-kv .v input{
  width:84px;min-height:40px;padding:6px 10px;text-align:right;font-size:16px;font-weight:600;
  border:0;border-radius:10px;background:var(--surface-2);color:var(--label);outline:none;
  -moz-appearance:textfield;appearance:textfield
}
.adm-kv .v input::-webkit-outer-spin-button,.adm-kv .v input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.adm-kv .v input:focus{box-shadow:inset 0 0 0 2px var(--ink)}

.adm-log{display:flex;flex-direction:column}
.adm-log-row{display:flex;justify-content:space-between;gap:10px;padding:8px 0;border-bottom:var(--hair) solid var(--sep);font-size:13.5px}
.adm-log-row:last-child{border-bottom:0}
.adm-log-row .when{color:var(--label-2);font-size:12px;flex:none}

/* users list rows with a copy affordance for invite codes */
.adm-code{
  font-family:var(--font);font-weight:600;letter-spacing:.08em;
  background:var(--surface-2);padding:4px 9px;border-radius:8px;font-size:14px
}
.adm-iconbtn{width:44px;height:44px;border-radius:12px;font-size:17px}
.adm-empty{color:var(--label-2);font-size:13.5px;padding:10px 2px}

/* ---------- the Coach before setup: a pitch, not a form ---------- */
.adm-hero{display:flex;flex-direction:column;align-items:flex-start;gap:4px;padding:6px 2px 2px}
.adm-hero-av{
  width:52px;height:52px;border-radius:16px;display:grid;place-items:center;font-size:26px;
  background:var(--surface);
  color:var(--text);margin-bottom:8px;box-shadow:var(--shadow-card)
}
.adm-hero h2{margin:0 0 4px;font-size:22px;letter-spacing:-.022em}
.adm-hero p{margin:0 0 14px;font-size:14px;line-height:1.5;color:var(--label-2)}
.adm-hero-feats{display:grid;gap:10px;margin-bottom:18px}
.adm-hero-feats>div{display:flex;gap:11px;align-items:flex-start}
.adm-hero-feats .icn{color:var(--ink);font-size:18px;flex:none;margin-top:2px}
.adm-hero-feats span{font-size:13.5px;line-height:1.45;color:var(--label-2)}
.adm-hero-feats b{color:var(--label);font-weight:600}
.adm-hero .btn{width:100%}

/* ---------- setup progress ---------- */
.adm-progress{height:5px;border-radius:99px;background:var(--surface-2);overflow:hidden;margin:0 0 10px}
.adm-progress i{display:block;height:100%;border-radius:99px;background:var(--ink);transition:width var(--med) var(--ease)}

/* ---------- provider chips: clearly idle vs. clearly chosen ---------- */
.adm-chips .chip{
  background:var(--surface-2);border:1.5px solid transparent;color:var(--label);
  font-weight:500;text-transform:none
}
.adm-chips .chip.on{background:var(--control-tint);border-color:var(--ink);color:var(--ink);font-weight:600}
.adm-chips .chip:active{transform:scale(.97)}

/* a finished step's summary reads as a receipt, not a control */
.adm-step.done>summary .adm-step-t span{color:var(--ink)}

/* SwipeDecide — structure and motion only. Surfaces, type and colour come from the skin
   (the caller's className). Exposes --dx/--r/--p on the top card while it is dragged; --p runs
   -1 (fully toward "keep") to 1 (fully toward "take") so a skin can preview the outcome. */
.swd{position:fixed;inset:0;z-index:var(--z-sheet,300);background:var(--canvas)}
.swd-panel{height:100%;box-sizing:border-box;display:flex;flex-direction:column;gap:12px;padding:calc(12px + env(safe-area-inset-top)) 16px calc(16px + env(safe-area-inset-bottom));outline:none}
.swd-hd{display:grid;grid-template-columns:44px 1fr 44px;align-items:center}
.swd-hd .btn:disabled{background:transparent;box-shadow:none;color:var(--text-3)}
.swd-count{text-align:center;color:var(--text-2);font:600 14px/1.2 var(--font);font-variant-numeric:tabular-nums}
.swd-deck{position:relative;flex:1;min-height:0}
.swd-deck>.swd-card{position:absolute;inset:0 0 20px;box-sizing:border-box;overflow:auto;overscroll-behavior:contain}
.swd-top{z-index:3;touch-action:pan-y;cursor:grab;user-select:none;-webkit-user-select:none;
  transform:translateX(var(--dx,0px)) rotate(var(--r,0deg));transition:transform 320ms var(--spring,cubic-bezier(.32,.72,0,1)),opacity 220ms ease-out}
.swd-top[data-stale],.swd-summary{cursor:auto;user-select:auto;-webkit-user-select:auto}
.swd-top[data-dragging]{transition:none;cursor:grabbing}
.swd-behind{pointer-events:none;transform-origin:50% 100%;transition:transform 300ms var(--ease-out),opacity 300ms var(--ease-out)}
.swd-behind[data-n="1"]{z-index:2;transform:translateY(10px) scale(.95);opacity:.65}
.swd-behind[data-n="2"]{z-index:1;transform:translateY(20px) scale(.9);opacity:.3}
.swd-behind>*{opacity:0}
.swd-top[data-leaving="right"]{transform:translateX(135%) rotate(12deg);opacity:0;transition:transform 220ms var(--ease-in-exit,cubic-bezier(.4,0,1,1)),opacity 220ms var(--ease-in-exit,cubic-bezier(.4,0,1,1))}
.swd-top[data-leaving="left"]{transform:translateX(-135%) rotate(-12deg);opacity:0;transition:transform 220ms var(--ease-in-exit,cubic-bezier(.4,0,1,1)),opacity 220ms var(--ease-in-exit,cubic-bezier(.4,0,1,1))}
.swd-answers{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.swd-answers .btn{width:100%;height:56px;font-size:17px}
.swd-answers .swd-wide{grid-column:1/-1}

@keyframes swd-fade{from{opacity:0}}
@keyframes swd-rise{from{opacity:0;transform:translateY(16px) scale(.98)}}
.swd{animation:swd-fade 200ms var(--ease-out) backwards}
.swd-summary{animation:swd-rise 260ms var(--ease-out) backwards}

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

.swd-panel{max-width:680px;margin-inline:auto}
.swd{overflow:hidden}

/* Proof. One ink (non-photo blue, the editor's pencil), one serif for the Coach's voice,
   one signature: the numbered margin rule every mark hangs off. */
.pf{
  --pf-ink:oklch(.79 .105 232);
  --pf-ink-tint:color-mix(in oklch,var(--pf-ink) 15%,transparent);
  --pf-rule:color-mix(in oklch,var(--pf-ink) 34%,transparent);
  --pf-serif:ui-serif,"New York","Iowan Old Style",Charter,Georgia,serif;
  --pf-gutter:22px;
  position:relative;width:100%;box-sizing:border-box;padding:18px 18px 12px;
  border-radius:var(--r-card);background:var(--surface);box-shadow:var(--shadow-card);color:var(--text);
  font:400 15px/1.4 var(--font)
}
:root[data-theme="light"] .pf{--pf-ink:oklch(.47 .14 250);--pf-ink-tint:color-mix(in oklch,var(--pf-ink) 9%,transparent);--pf-rule:color-mix(in oklch,var(--pf-ink) 24%,transparent)}

.pf-hd{display:grid;gap:8px}
.pf-eyebrow{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px;margin:0;color:var(--text-2);font:500 11px/1.3 var(--font);letter-spacing:.07em;text-transform:uppercase}
.pf-rev{margin-inline-start:auto;padding:2px 6px;border:1px solid var(--pf-ink);border-radius:4px;color:var(--pf-ink);letter-spacing:.04em}
.pf-lede{margin:0;font:400 21px/1.28 var(--pf-serif);letter-spacing:-.005em;text-wrap:pretty;overflow-wrap:anywhere;font-kerning:normal}

.pf-marks,.pf-full{position:relative;margin-top:16px;display:grid;gap:14px}
.pf-lines{list-style:none;margin:0;padding:0;display:grid;gap:12px;position:relative}
/* The margin rule: every numbered mark hangs off it, the page's one recurring device. */
.pf-lines::before{content:"";position:absolute;top:2px;bottom:2px;inset-inline-start:calc(var(--pf-gutter) + 5px);width:1px;background:var(--pf-rule);pointer-events:none}

.pf-line,.pf-plain{display:grid;grid-template-columns:var(--pf-gutter) minmax(0,1fr) auto;column-gap:12px;align-items:start}
.pf-n{color:var(--pf-ink);font:600 11px/22px var(--font);font-variant-numeric:tabular-nums;text-align:end}
.pf-line{row-gap:6px}
.pf-gloss-row{grid-column:2/-1}
.pf-subject{min-width:0;margin:0;display:grid;gap:2px;line-height:1.35}
.pf-what{color:var(--text);font-weight:500;overflow-wrap:anywhere}
.pf-field{color:var(--text-2);font-weight:400}
.pf-edit{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
/* The strike is a background so it crosses every line of a wrapped name (an ::after only
   reaches the first fragment). shortcut: background-size is a paint, not a composite; fine for
   a handful of one-shot spans, move to per-line overlays if a page ever carries dozens. */
.pf-del{color:var(--text-3);text-decoration:none;
  background:linear-gradient(var(--pf-ink),var(--pf-ink)) no-repeat 0 56% / 100% 1.5px;
  -webkit-box-decoration-break:clone;box-decoration-break:clone;
  transition:background-size 200ms var(--ease-out)}
.pf-ins{color:var(--pf-ink);font-weight:600;text-decoration:none;padding:0 4px;margin-inline-start:-4px;border-radius:4px;background:var(--pf-ink-tint);
  -webkit-box-decoration-break:clone;box-decoration-break:clone;transition:opacity 180ms ease-out}
/* Swap and rename replace the whole line: old above, new beneath. */
.pf-edit[data-whole]{display:grid;gap:3px}
.pf-cell{min-width:0}

/* Stet: the strike lifts, the original stands, the insertion greys out. */
.pf-line[data-kept] .pf-del{color:var(--text)}
.pf-line[data-kept] .pf-del{background-size:0% 1.5px}
.pf-line[data-kept] .pf-ins{opacity:.42;background:transparent;text-decoration:line-through;text-decoration-thickness:1px;font-weight:500}
.pf-line[data-stale] .pf-n{color:var(--text-3)}
.pf-line[data-stale] .pf-what{color:var(--text-2)}

.pf-gloss{margin:0;max-width:60ch;color:var(--text-2);font:400 15px/1.45 var(--pf-serif);text-wrap:pretty}
.pf-gloss-solo{margin-top:2px}
.pf-gloss-stale{color:var(--warning-fg);font-family:var(--font);font-size:13px}
.pf-more{margin:0;margin-inline-start:calc(var(--pf-gutter) + 12px);color:var(--text-2);font:500 13px/1.3 var(--font)}

/* Take / Stet: one control, two faces, 44px target. */
.pf-stet{position:relative;display:inline-grid;min-width:72px;min-height:44px;margin-block-start:-8px;margin-inline-end:-6px;padding:0 2px;border:0;border-radius:999px;background:transparent;
  font:600 13px/1 var(--font);cursor:pointer;touch-action:manipulation;transition:transform var(--d-press) var(--ease-out)}
.pf-stet:active{transform:scale(.96)}
.pf-stet:focus-visible{outline:2px solid var(--text-2);outline-offset:2px}
.pf-stet-face{grid-area:1/1;display:inline-flex;align-items:center;justify-content:center;gap:4px;height:30px;align-self:center;padding:0 10px;border-radius:999px;
  transition:opacity 150ms ease-out,transform 150ms var(--ease-out)}
.pf-stet-face[data-face="take"]{background:var(--pf-ink-tint);color:var(--pf-ink)}
.pf-stet-face[data-face="stet"]{box-shadow:0 0 0 1px var(--hairline) inset;color:var(--text-2);opacity:0;transform:translateY(4px)}
.pf-stet:not([data-taken]) [data-face="take"]{opacity:0;transform:translateY(-4px)}
.pf-stet:not([data-taken]) [data-face="stet"]{opacity:1;transform:none}
.pf-verdict{align-self:center;color:var(--pf-ink);font:600 11px/1 var(--font);letter-spacing:.06em;text-transform:uppercase}
.pf-line[data-kept] .pf-verdict{color:var(--text-3)}

/* The full page: your routine, printed, marks in place. */
.pf-full{gap:22px;padding-top:4px}
.pf-sheet{display:grid;gap:10px}
.pf-sheet-h{display:flex;align-items:baseline;gap:8px;margin:0;color:var(--text-2);font:600 13px/1.3 var(--font);letter-spacing:.01em}
.pf-sheet-h .icn{align-self:center;font-size:14px}
.pf-sheet-t{min-width:0;overflow-wrap:anywhere;color:var(--text);font-size:15px}
.pf-meta{margin-inline-start:auto;color:var(--text-3);font-weight:500;font-variant-numeric:tabular-nums;white-space:nowrap}
.pf-plain{color:var(--text-2);font-size:14px;line-height:1.35;row-gap:2px}
.pf-plain-n{grid-column:2;grid-row:1;overflow-wrap:anywhere}
.pf-plain .pf-rx{grid-column:2;grid-row:2;color:var(--text-3);font-variant-numeric:tabular-nums;font-size:13px}
.pf-plain .pf-gloss{grid-column:2;grid-row:3;font-size:14px}
.pf-plain.is-new{color:var(--text)}
.pf-link{color:var(--pf-ink);font-weight:500}
.pf-nb .pf-gloss{padding-inline-start:calc(var(--pf-gutter) + 12px)}
.pf-foot{margin:0;padding-top:12px;border-top:1px solid var(--hairline);color:var(--text-3);font:400 12px/1.5 var(--font);font-variant-numeric:tabular-nums}

/* A plan: the week as boxed letters. */
.pf-week{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(7,1fr);gap:6px}
.pf-week li{display:grid;place-items:center;height:34px;border-radius:8px;color:var(--text-3);font:600 12px/1 var(--font)}
.pf-week li[data-on]{color:var(--pf-ink);box-shadow:0 0 0 1.5px var(--pf-ink) inset;background:var(--pf-ink-tint)}
.pf-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}

/* A debrief: the grade, circled. */
.pf-grade{display:flex;align-items:center;gap:16px}
.pf-circle{position:relative;flex:none;width:96px;height:80px;display:grid;place-items:center}
.pf-circle svg{position:absolute;inset:0;overflow:visible}
.pf-circle path{fill:none;stroke:var(--pf-ink);stroke-width:2.25;stroke-linecap:round;stroke-dasharray:1;stroke-dashoffset:0}
.pf-circle>span{font:400 34px/1 var(--pf-serif);font-variant-numeric:tabular-nums;color:var(--text)}
.pf-circle small{font-size:14px;color:var(--text-3)}
.pf-facts{flex:1;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 12px;margin:0}
.pf-facts div{display:grid;gap:2px}
.pf-facts dt{color:var(--text-3);font:500 11px/1.2 var(--font);letter-spacing:.06em;text-transform:uppercase}
.pf-facts dd{margin:0;font:600 17px/1.2 var(--font);font-variant-numeric:tabular-nums}
.pf-findings{display:grid;gap:6px}
.pf-findings[data-op="good"] .pf-sheet-h{color:var(--done-fg)}
.pf-findings[data-op="watch"] .pf-sheet-h{color:var(--warning-fg)}
.pf-findings[data-op="next"] .pf-sheet-h{color:var(--pf-ink)}

/* Sign-off. */
.pf-sign{display:grid;gap:12px;margin-top:18px;padding-top:12px;border-top:1px solid var(--hairline)}
.pf-sign[data-done]{grid-template-columns:1fr auto;align-items:center}
.pf-sig{display:flex;flex-wrap:wrap;align-items:center;gap:4px 8px;margin:0;color:var(--text-2);font:500 13px/1.3 var(--font)}
.pf-sign[data-done] .pf-sig{color:var(--text)}
.pf-sign[data-done] .pf-sig .icn{color:var(--done-fg)}
.pf[data-status="declined"] .pf-sign .pf-sig .icn{color:var(--text-2)}
.pf-caret{width:2px;height:16px;border-radius:1px;background:var(--pf-ink)}
.pf-expiry{color:var(--text-3);font-variant-numeric:tabular-nums}
.pf-expiry::before{content:"· "}
.pf-actions{display:flex;align-items:center;gap:8px}
.pf-actions>:last-child{margin-inline-start:auto}
.pf-actions .btn{width:auto;flex:none}

/* ------------------------------ motion ------------------------------ */
/* Arrival (pending only, once): the strikes draw, then the insertions write in, one mark at a time. */
@keyframes pf-strike{from{background-size:0% 1.5px}}
@keyframes pf-write{from{clip-path:inset(0 100% 0 0)}to{clip-path:inset(0 0 0 0)}}
@keyframes pf-arrive{from{opacity:0;transform:translateY(6px)}}
@keyframes pf-blink{50%{opacity:0}}
@keyframes pf-circle{from{clip-path:inset(0 100% 0 0)}to{clip-path:inset(0)}}
.pf[data-status="pending"]{animation:pf-arrive 260ms var(--ease-out) backwards}
.pf[data-status="pending"] .pf-del{animation:pf-strike 240ms var(--ease-out) backwards;animation-delay:calc(220ms + var(--i,0) * 90ms)}
.pf[data-status="pending"] .pf-ins{animation:pf-write 260ms var(--ease-out) backwards;animation-delay:calc(380ms + var(--i,0) * 90ms)}
.pf[data-status="pending"] .pf-week li[data-on]{animation:pf-arrive 220ms var(--ease-out) backwards;animation-delay:200ms}
.pf[data-status="pending"] .pf-circle path{animation:pf-circle 700ms var(--ease-out) backwards;animation-delay:180ms}
/* Waiting on you: the caret on the sign-off line, only while the card is on screen. */
.pf[data-live] .pf-caret{animation:pf-blink 1.1s steps(1) infinite}
/* Opening: the page prints in, sheet by sheet. */
.pf-full>*{animation:pf-arrive 220ms var(--ease-out) backwards}
.pf-full>:nth-child(2){animation-delay:40ms}.pf-full>:nth-child(3){animation-delay:80ms}.pf-full>:nth-child(n+4){animation-delay:120ms}
/* Answered: the sign-off line settles in. */
.pf-sign[data-done]{animation:pf-arrive 240ms var(--ease-out) backwards}

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

/* ------------------- swipe mode (SwipeDecide skin, suggestions only) ------------------- */
.pf-sw{
  --pf-ink:oklch(.79 .105 232);
  --pf-ink-tint:color-mix(in oklch,var(--pf-ink) 15%,transparent);
  --pf-rule:color-mix(in oklch,var(--pf-ink) 34%,transparent);
  --pf-serif:ui-serif,"New York","Iowan Old Style",Charter,Georgia,serif;
  --pf-gutter:22px
}
:root[data-theme="light"] .pf-sw{--pf-ink:oklch(.47 .14 250);--pf-ink-tint:color-mix(in oklch,var(--pf-ink) 9%,transparent);--pf-rule:color-mix(in oklch,var(--pf-ink) 24%,transparent)}
.pf-sw .swd-card{padding:22px 20px;border-radius:var(--r-card);background:var(--surface);
  box-shadow:var(--shadow-card),0 1px 2px rgb(0 0 0 / .06),0 10px 30px -14px rgb(0 0 0 / .22);display:flex;flex-direction:column;justify-content:safe center}
.pf-sw .swd-summary{justify-content:flex-start}

.pfc{position:relative;display:grid;gap:14px;min-width:0;color:var(--text);font:400 15px/1.4 var(--font)}
.pfc-top{display:flex;align-items:center;gap:8px}
.pfc-n{display:grid;place-items:center;width:24px;height:24px;border-radius:50%;box-shadow:0 0 0 1.5px var(--pf-ink) inset;color:var(--pf-ink);font:600 12px/1 var(--font);letter-spacing:0;font-variant-numeric:tabular-nums}
.pfc-what{margin:0;font:600 22px/1.25 var(--font);letter-spacing:-.015em;text-wrap:balance;overflow-wrap:anywhere}
.pfc-what .pf-field{font-weight:500}
.pfc-edit{margin:0;display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 10px;font:500 20px/1.35 var(--font);font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
.pfc-edit[data-whole]{display:grid;gap:6px}
.pfc-edit .pf-ins{font-weight:650}
.pfc-gloss{position:relative;padding-inline-start:14px;font-size:18px;line-height:1.5}
.pfc-gloss::before{content:"";position:absolute;inset-inline-start:0;top:5px;bottom:5px;width:1.5px;border-radius:1px;background:var(--pf-rule)}

/* The card previews its own outcome while dragged: toward "keep" the strike lifts off the
   original and the insertion fades; toward "take" the insertion's tint deepens. */
.pf-sw .swd-top .pf-del{background-size:calc(100% * (1 + min(0, var(--p,0)))) 1.5px;
  color:color-mix(in oklch,var(--text) calc(max(0, var(--p,0) * -1) * 100%),var(--text-3))}
.pf-sw .swd-top .pf-ins{opacity:calc(1 + min(0, var(--p,0)) * .55);
  background:color-mix(in oklch,var(--pf-ink) calc(15% + max(0, var(--p,0)) * 22%),transparent)}
.pf-sw .swd-top[data-dragging] *{transition:none}
.pfc-stamp{position:absolute;bottom:-6px;display:inline-flex;align-items:center;gap:4px;padding:6px 12px;border-radius:10px;font:700 15px/1 var(--font);letter-spacing:.06em;text-transform:uppercase;pointer-events:none;opacity:0}
.pfc-stamp[data-side="take"]{inset-inline-start:0;color:var(--pf-ink);box-shadow:0 0 0 2px var(--pf-ink) inset;transform:rotate(-6deg);opacity:var(--p,0)}
.pfc-stamp[data-side="stet"]{inset-inline-end:0;padding:4px 14px 7px;color:var(--text-2);box-shadow:0 0 0 2px var(--text-3) inset;transform:rotate(6deg);
  font:italic 400 24px/1 var(--pf-serif);letter-spacing:0;text-transform:none;opacity:calc(var(--p,0) * -1)}

/* Progress as the margin's own numbers: filled when taken, struck when kept. */
.pfc-pips{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;justify-content:center;gap:6px}
.pfc-pips li{display:grid;place-items:center;width:24px;height:24px;border-radius:50%;box-shadow:0 0 0 1px var(--hairline) inset;color:var(--text-3);
  font:600 11px/1 var(--font);font-variant-numeric:tabular-nums;transition:transform 200ms var(--ease-out)}
.pfc-pips li[data-at]{box-shadow:0 0 0 1.5px var(--pf-ink) inset;color:var(--pf-ink);transform:scale(1.12)}
.pfc-pips li[data-state="accepted"]{background:var(--pf-ink);color:var(--surface);box-shadow:none}
.pfc-pips li[data-state="declined"]{color:var(--text-3);text-decoration:line-through;box-shadow:0 0 0 1px var(--text-3) inset}
.pfc-pips li[data-state="stale"]{opacity:.45}
@keyframes pfc-pop{40%{transform:scale(1.28)}}
.pfc-pips li[data-state="accepted"],.pfc-pips li[data-state="declined"]{animation:pfc-pop 240ms var(--ease-out)}

/* Summary: one row per mark, each a way back to its card. */
.pfc-rows{list-style:none;margin:0;padding:0;display:grid}
.pfc-row{width:100%;display:grid;grid-template-columns:var(--pf-gutter) minmax(0,1fr) auto;gap:12px;align-items:center;min-height:48px;padding:6px 0;
  border:0;border-top:1px solid var(--hairline);background:none;color:var(--text);font:500 15px/1.3 var(--font);text-align:start;cursor:pointer;touch-action:manipulation}
.pfc-row-t{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pfc-row[data-v="stet"] .pfc-row-t,.pfc-row[data-v="lapsed"] .pfc-row-t{color:var(--text-2)}
.pfc-row[data-v="stet"] .pf-verdict,.pfc-row[data-v="lapsed"] .pf-verdict{color:var(--text-3)}
.pfc-row:focus-visible{outline:2px solid var(--text-2);outline-offset:2px;border-radius:6px}
@media (hover:hover) and (pointer:fine){.pfc-row:hover .pfc-row-t{color:var(--text)}}

.pf-schedule{display:flex;align-items:center;gap:12px;justify-content:space-between}
.pf-actions{flex-wrap:wrap}
.pf .pf-foot{margin-block-start:12px}
.pf-cell{overflow-wrap:anywhere;max-width:100%}
.pf-sign[data-done]{grid-template-columns:minmax(0,1fr) auto}

.pf .btn{min-height:44px}

/* Polish: the fine print is one block under one rule, and the sign-off follows it without a
   second rule. The answered line keeps its mark beside the words, never on a line of its own. */
.pf-fine{display:grid;gap:6px;margin-top:18px;padding-top:12px;border-top:1px solid var(--hairline)}
.pf .pf-fine .pf-foot{margin:0;padding:0;border:0}
.pf-fine+.pf-sign{margin-top:14px;padding-top:0;border-top:0}
.pf-sign[data-done] .pf-sig{flex-wrap:nowrap;align-items:flex-start}
.pf-sign[data-done] .pf-sig .icn{flex:none;margin-top:1px}
/* The sign-off line starts on the text's edge: the caret hangs in the margin like a mark's number. */
.pf-sig .pf-caret{margin-inline-start:-10px}

/* The Coach's two screens — the questionnaire and the conversation.
   Everything here sits on the app's tokens (index.css); nothing is redefined. */

/* ---------- onboarding ---------- */
.ob{display:flex;flex-direction:column;min-height:calc(100dvh - var(--sat) - 200px)}
.ob-top{display:flex;align-items:center;justify-content:space-between;margin:2px 0 26px;min-height:36px}
.ob-dots{display:flex;gap:6px;align-items:center}
.ob-dot{width:6px;height:6px;border-radius:99px;background:var(--label-4);transition:all var(--med) var(--ease)}
.ob-dot.on{background:var(--ink);width:18px}
.ob-dot.done{background:var(--ink);opacity:.55}
.ob-skip{background:none;color:var(--label-2);font-size:15px;padding:6px 2px}
.ob-body{flex:1;padding-bottom:150px}
.ob-eyebrow{color:var(--ink);font-size:13px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;margin-bottom:8px}
.ob-h{font-size:30px;line-height:1.12;font-weight:700;letter-spacing:-.026em;margin:0 0 8px}
.ob-p{color:var(--label-2);font-size:16px;line-height:1.45;margin:0 0 24px;letter-spacing:-.006em}
.ob-choices{display:flex;flex-direction:column;gap:10px}
.ob-choice{
  display:flex;align-items:center;gap:14px;width:100%;text-align:left;
  padding:16px 18px;border-radius:var(--r-lg);background:var(--surface);
  font-size:17px;letter-spacing:-.012em;color:var(--label);
  border:1.5px solid transparent;transition:border-color var(--fast),background var(--fast),transform var(--fast)
}
.ob-choice:active{transform:scale(.985);background:var(--surface-2)}
.ob-choice.on{border-color:var(--ink);background:var(--control-tint)}
.ob-choice .icn{font-size:22px;color:var(--ink);flex:none}
.ob-choice .ob-choice-t{flex:1}
.ob-choice .ob-choice-s{display:block;font-size:13px;color:var(--label-2);margin-top:2px}
.ob-choice .ob-k{color:var(--ink);font-size:18px;--icon-stroke:2.6;flex:none;opacity:0}
.ob-choice.on .ob-k{opacity:1}
.ob-days{display:grid;grid-template-columns:repeat(7,1fr);gap:8px;margin:6px 0 4px}
.ob-day{
  aspect-ratio:1;border-radius:99px;background:var(--surface);color:var(--label);
  font-size:20px;font-weight:600;display:flex;align-items:center;justify-content:center;
  border:1.5px solid transparent;transition:all var(--fast)
}
.ob-day.on{background:var(--ink);color:var(--on-ink);border-color:var(--ink)}
.ob-day:active{transform:scale(.94)}
.ob-week{display:grid;grid-template-columns:repeat(7,1fr);gap:6px;margin-top:6px}
.ob-wd{
  padding:10px 0 9px;border-radius:var(--r);background:var(--surface);text-align:center;
  font-size:13px;font-weight:600;color:var(--label-2);border:1.5px solid transparent;transition:all var(--fast)
}
.ob-wd.on{color:var(--ink);border-color:var(--ink);background:var(--control-tint)}
.ob-sub{font-size:15px;color:var(--label-2);margin:22px 0 10px;letter-spacing:-.006em}
.ob-time{
  display:flex;align-items:center;justify-content:center;gap:10px;
  background:var(--surface);border-radius:var(--r-xl);padding:26px 18px;margin-top:4px
}
.ob-time input[type=time]{
  font-size:44px;font-weight:600;letter-spacing:-.03em;background:none;border:none;color:var(--label);
  font-variant-numeric:tabular-nums;padding:0;outline:none;text-align:center;width:auto;min-width:180px;
  -webkit-appearance:none;appearance:none;color-scheme:dark
}
:root[data-theme="light"] .ob-time input[type=time]{color-scheme:light}
.ob-time input[type=time]::-webkit-calendar-picker-indicator{display:none}
.ob-time .ob-wheel{appearance:none;-webkit-appearance:none;background:transparent;border:0;color:var(--label);font-size:56px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.02em;padding:0 4px;text-align:center;min-width:1.6em}
.ob-time .ob-time-sep{font-size:56px;font-weight:700;color:var(--label);margin:0 -2px;transform:translateY(-4px)}
.ob-time .ob-time-l{font-size:15px;color:var(--label-2)}
.ob-quick{display:flex;gap:7px;justify-content:center;flex-wrap:wrap;margin-top:12px}
.ob-chips{display:flex;flex-wrap:wrap;gap:8px}
.ob-chips .chip{padding:10px 16px;font-size:15px;border:1.5px solid transparent}
.ob-chips .chip.on{background:var(--control-tint);color:var(--ink);border-color:var(--ink)}
.ob-field{margin-bottom:14px}
.ob-field .field{font-size:16px}
.ob-note{font-size:13px;line-height:1.45;color:var(--label-2);margin-top:10px}
.ob-note.warn{color:var(--warning-fg)}
.ob-consent{display:flex;flex-direction:column;gap:10px;margin-bottom:18px}
.ob-consent-row{display:flex;gap:12px;align-items:flex-start;background:var(--surface);border-radius:var(--r-lg);padding:13px 15px}
.ob-consent-row .icn{color:var(--ink);font-size:19px;flex:none;margin-top:2px}
.ob-consent-row b{display:block;font-size:15px;font-weight:600;margin-bottom:2px;letter-spacing:-.008em}
.ob-consent-row span{font-size:13px;color:var(--label-2);line-height:1.4}
.ob-fine{font-size:13px;color:var(--label-2);line-height:1.5;display:grid;gap:8px;margin-bottom:20px}
.ob-foot{position:sticky;bottom:calc(58px + var(--sab));padding:30px 0 14px;background:linear-gradient(to top,var(--bg) 58%,transparent);display:flex;gap:10px;margin-top:18px}
.ob-foot .btn{font-size:17px;padding:15px 18px;border-radius:var(--r-lg)}
.ob-hint{text-align:center;font-size:13px;color:var(--label-2);margin-top:8px}

/* ---------- chat ---------- */
.chat{padding-bottom:40px}
.chat-hdr{
  display:flex;align-items:center;gap:10px;
  /* Pinned like a messenger's title bar: it eats the app shell's top padding so the blur
     reaches the status bar, and gives it back as its own padding — below the connection
     indicator (--conn) when there is one. */
  position:sticky;top:0;z-index:40;
  margin:calc(-1 * (var(--sat) + var(--conn) + 8px)) calc(-1 * var(--pad)) 8px;
  padding:calc(var(--sat) + var(--conn) + 8px) var(--pad) 8px;
  background:var(--canvas);-webkit-backdrop-filter:none;backdrop-filter:none
}
.chat-hdr .chat-av{
  width:38px;height:38px;border-radius:99px;background:var(--ink);color:var(--on-ink);
  display:flex;align-items:center;justify-content:center;font-size:20px;flex:none
}
.chat-hdr h1{font-size:20px;font-weight:700;letter-spacing:-.02em;margin:0;line-height:1.1}
.chat-hdr .chat-st{font-size:13px;color:var(--label-2);margin-top:2px}
.chat-hdr .chat-st.live{color:var(--ink)}
.chat-hdr .grow{flex:1;min-width:0}
.msgs{display:flex;flex-direction:column;gap:10px}
.msg{display:flex;flex-direction:column;max-width:88%;animation:msg-in var(--med) var(--ease)}
.msg.coach{align-self:flex-start}
.msg.user{align-self:flex-end;align-items:flex-end}
.bub{
  padding:11px 15px;border-radius:20px;font-size:16px;line-height:1.42;letter-spacing:-.008em;
  background:var(--surface);color:var(--label);white-space:pre-wrap;word-break:break-word
}
.msg.coach .bub{border-bottom-left-radius:6px}
.msg.user .bub{background:var(--ink);color:var(--on-ink);border-bottom-right-radius:6px}
.bub.err{background:color-mix(in srgb,var(--red) 14%,var(--surface));color:var(--label)}
.bub.sys{background:none;color:var(--label-2);font-size:13px;text-align:center;padding:4px 8px;align-self:center;max-width:100%}
.msg.sys{align-self:center;max-width:100%;align-items:center}
.bub ul{margin:6px 0 0;padding-left:18px}
.bub li{margin:2px 0}
.msg-t{font-size:11px;color:var(--label-2);margin:4px 8px 0}
.typing{display:flex;align-items:center;gap:5px;padding:14px 16px;min-width:64px}
.typing i{width:8px;height:8px;border-radius:99px;background:var(--label-2);animation:typing 1.2s infinite ease-in-out}
.typing i:nth-child(2){animation-delay:.15s}
.typing i:nth-child(3){animation-delay:.3s}
.typing-eta{font-size:13px;color:var(--label-2);margin:6px 8px 0;line-height:1.4}
@keyframes typing{0%,80%,100%{transform:translateY(0);opacity:.45}40%{transform:translateY(-4px);opacity:1}}
@keyframes msg-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* composer */
.composer{
  position:fixed;left:0;right:0;bottom:0;z-index:40;
  padding:8px var(--pad) calc(10px + var(--sab));
  background:var(--canvas);-webkit-backdrop-filter:none;backdrop-filter:none
}
.composer-in{max-width:560px;margin:0 auto;display:flex;gap:8px;align-items:flex-end}
.composer textarea{
  flex:1;min-height:44px;max-height:120px;resize:none;border-radius:22px;padding:11px 16px;
  font-size:16px;line-height:1.35;background:var(--surface);color:var(--label);border:none;outline:none;
  font-family:inherit;letter-spacing:-.008em
}
.composer textarea:focus{box-shadow:inset 0 0 0 1.5px var(--ink)}
.composer textarea::placeholder{color:var(--label-3)}
.send{
  width:44px;height:44px;border-radius:99px;background:var(--ink);color:var(--on-ink);flex:none;
  display:flex;align-items:center;justify-content:center;font-size:20px;transition:transform var(--fast),opacity var(--fast)
}
.send:active{transform:scale(.92)}
.send:disabled{opacity:.3}
.composer-cap{max-width:560px;margin:4px auto 0;text-align:center;font-size:11px;color:var(--label-2)}

/* menu sheet rows reuse .lrow; the cadence sub-sheet reuses Section */
.chat-menu .lrow-t{font-size:17px}

/* ---------- quick actions above the composer ---------- */
.chips-row{max-width:560px;margin:0 auto 8px;display:flex;gap:6px;overflow-x:auto;scrollbar-width:none;padding:0 2px}
.chips-row::-webkit-scrollbar{display:none}
.qchip{
  flex:none;display:inline-flex;align-items:center;gap:6px;padding:8px 13px;border-radius:99px;
  background:var(--surface);color:var(--label);font-size:13px;font-weight:500;letter-spacing:-.006em;
  border:1px solid var(--sep-op);transition:transform var(--fast),background var(--fast)
}
.qchip .icn{font-size:14px;color:var(--ink)}
.qchip:active{transform:scale(.96);background:var(--surface-2)}
.chat-empty{font-size:14px;color:var(--label-2);line-height:1.45;padding:14px 4px}

/* ---------- the numbers behind a card ---------- */
.ins{padding:6px 18px 4px;display:grid;gap:10px;min-width:0}
.ins>*{min-width:0}
.ins-tiles{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}
.ins-tile{background:var(--surface-2);border-radius:14px;padding:10px 6px 9px;text-align:center;min-width:0}
.ins-tile-v{font-size:19px;font-weight:700;letter-spacing:-.03em;font-variant-numeric:tabular-nums;line-height:1.05;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ins-tile-l{font-size:10.5px;color:var(--label-2);margin-top:4px;letter-spacing:-.004em;line-height:1.15;overflow-wrap:anywhere}
.ins-block{background:var(--surface-2);border-radius:16px;padding:12px 14px 10px}
.ins-h{display:flex;justify-content:space-between;align-items:baseline;gap:8px;font-size:13px;font-weight:600;letter-spacing:-.008em;margin-bottom:6px;min-width:0}
.ins-h>span:first-child{flex:none}
.ins-h>span:last-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:right}
.ins-h .dim{font-weight:400;font-size:12px}
.ins-block .chart{margin:2px -4px 0}

/* ---------- you against the room ---------- */
.cmp{padding:8px 0;border-top:var(--hair) solid var(--sep)}
.cmp:first-of-type{border-top:none}
.cmp-h{display:flex;justify-content:space-between;font-size:13.5px;font-weight:500;text-transform:capitalize;margin-bottom:5px}
.cmp-h .dim{font-weight:400;font-size:12px;text-transform:none}
.cmp-bar{position:relative;height:22px;border-radius:7px;background:var(--surface-3);overflow:hidden;margin-top:4px}
.cmp-bar i{display:block;height:100%;border-radius:7px;background:var(--label-3);opacity:.55}
.cmp-bar.you i{background:var(--metric-volume);opacity:1}
.cmp-bar span{position:absolute;left:8px;top:0;line-height:22px;font-size:11.5px;font-weight:600;color:var(--label);font-variant-numeric:tabular-nums;text-shadow:0 0 6px var(--bg)}

/* Workspace: shared controls, assistant-ui composer and content-led proposal previews. */
/* Beat the shell's resting/native-keyboard padding in every stylesheet order. The
   transcript owns scrolling; padding on #app creates a second page below the composer. */
#root #app:has(>.coach-workspace){padding-bottom:0}
html:has(.coach-workspace),body:has(.coach-workspace){overflow:hidden;overscroll-behavior:none}
/* Size the pinned canvas directly, without a percentage-height clipping chain.
   Interactive chrome uses the separately measured visible bottom below. */
body:has(.coach-workspace){position:fixed;inset:0;width:100%;height:100vh;height:100lvh}
body:has(.coach-workspace) .staging-banner{position:fixed;inset-inline:0}
/* The menu sheet shares the room's visible bottom, including the PWA home-indicator area. */
body:has(.coach-workspace) #modal-root{bottom:auto;height:var(--coach-viewport-bottom,100dvh)}
/* Native sheets already subtract this inset with their own bottom rule. */
:root[data-native-kb] body:has(.coach-workspace) #modal-root{height:calc(var(--coach-viewport-bottom,100dvh) + var(--native-kb,0px))}
/* The workspace only shares tokens. Its header and room are sibling fixed layers;
   keyboard sizing never changes a header ancestor's box or transform. */
.chat.coach-workspace{position:static;display:block;height:0;min-height:0;padding:0;margin:0;max-width:none}
.coach-workspace .chat-hdr,.coach-workspace .coach-room{position:fixed;inset-inline:var(--pad);max-width:640px;margin-inline:auto;box-sizing:border-box}
.coach-workspace .chat-hdr{top:var(--coach-header-inset,calc(var(--sat) + var(--conn) + 14px));z-index:4;gap:12px;padding:8px 0 16px;background:none;backdrop-filter:none;pointer-events:none}
/* The room starts at the visual origin (header inset minus resting inset), so
   the transcript can paint throughout the header fade without moving the header.
   The transcript spans the room behind chrome. The intrinsic composer row stays
   independent; its observed border-box size only supplies transcript end clearance.
   No negative margins or measured size feeds back into the composer or header. */
.coach-workspace .coach-room{top:calc(var(--coach-header-inset,0px) - var(--coach-top,0px));height:max(0px,calc(var(--coach-room-bottom,var(--coach-viewport-bottom,100dvh)) - var(--coach-header-inset,0px) + var(--coach-top,0px)));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr) auto;min-height:0}
.coach-workspace .composer{grid-area:2 / 1 / 3 / 2}
/* Four overlapping, masked blur bands follow the tint toward the clear edge.
   Keep the backing layers separate from the fully opaque controls and transcript. */
.coach-chrome-backdrop{position:absolute;z-index:0;inset-inline:calc(-1 * var(--pad));pointer-events:none}
/* Keep Safari's backdrop surfaces in the nonnegative paint order. Controls sit
   above the material; the transcript remains behind both chrome containers. */
.coach-workspace .chat-hdr>:not(.coach-chrome-backdrop),.coach-workspace .composer>:not(.coach-chrome-backdrop){position:relative;z-index:1}
.coach-chrome-backdrop::after{content:"";position:absolute;inset:0;background:var(--coach-chrome-tint)}
.coach-blur-band{position:absolute;inset:0;-webkit-backdrop-filter:blur(var(--coach-blur-radius));backdrop-filter:blur(var(--coach-blur-radius));mask-image:linear-gradient(var(--coach-fade-direction),#000 0%,#000 var(--coach-blur-solid),transparent var(--coach-blur-clear));-webkit-mask-image:linear-gradient(var(--coach-fade-direction),#000 0%,#000 var(--coach-blur-solid),transparent var(--coach-blur-clear))}
.coach-blur-band:nth-child(1){--coach-blur-radius:2px;--coach-blur-solid:78%;--coach-blur-clear:100%}
.coach-blur-band:nth-child(2){--coach-blur-radius:4px;--coach-blur-solid:60%;--coach-blur-clear:88%}
.coach-blur-band:nth-child(3){--coach-blur-radius:8px;--coach-blur-solid:38%;--coach-blur-clear:70%}
.coach-blur-band:nth-child(4){--coach-blur-radius:12px;--coach-blur-solid:16%;--coach-blur-clear:50%}
.coach-workspace .chat-hdr>.coach-chrome-backdrop{top:calc(-1 * var(--coach-top,0px));bottom:-14px;--coach-fade-direction:to bottom;--coach-chrome-tint:linear-gradient(to bottom,color-mix(in srgb,var(--canvas) 78%,transparent) 0%,color-mix(in srgb,var(--canvas) 72%,transparent) 30%,color-mix(in srgb,var(--canvas) 52%,transparent) 55%,color-mix(in srgb,var(--canvas) 20%,transparent) 80%,transparent 100%)}
/* The shell's entrance animation must not transform these viewport-anchored layers. */
#root #app.vfade:has(>.coach-workspace),#root #app.vfade>.coach-workspace>*{animation:none}
.coach-workspace .chat-hdr button,.coach-workspace .coach-header-actions{pointer-events:auto}
.coach-workspace .chat-hdr h1{font:600 17px/1.25 var(--font);letter-spacing:-.015em;margin:0 0 3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.coach-workspace .chat-hdr .chat-st{font:400 12px/1.35 var(--font);color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.coach-workspace .chat-hdr>.coach-back{width:44px;height:44px;min-width:44px;padding:0;border:0;border-radius:50%}
.coach-workspace .chat-hdr .glass{background-color:var(--glass-fill);background-image:var(--glass-sheen);box-shadow:var(--glass-elevation);backdrop-filter:blur(12px) saturate(1.6);-webkit-backdrop-filter:blur(12px) saturate(1.6)}
.coach-header-actions{display:flex;flex:none;gap:0;padding:2px;border-radius:24px}
.coach-workspace .coach-header-actions>.btn{width:44px;height:44px;min-width:44px;padding:0;border-radius:22px;background:none;box-shadow:none;border:0}
.coach-workspace .coach-header-actions>.btn>.icn{width:20px;height:20px}
.coach-workspace .msgs{grid-area:1 / 1 / 3 / 2;position:relative;z-index:1;min-width:0;min-height:0;overflow-y:auto;overscroll-behavior:contain;gap:24px;margin:0;padding:calc(var(--coach-top,0px) + var(--coach-header-height,80px) + 12px) 2px calc(var(--coach-composer-height,172px) + 20px);scroll-padding-block:calc(var(--coach-top,0px) + var(--coach-header-height,80px) + 12px) calc(var(--coach-composer-height,172px) + 20px);scrollbar-width:thin;overflow-anchor:none}
.coach-workspace .msg{flex:none;animation:none;max-width:100%;min-width:0;user-select:text}
.coach-workspace .msg.user{max-width:86%;margin-bottom:4px}
.coach-workspace .bub{padding:0;background:none;border-radius:0;font:400 16px/1.65 var(--font);letter-spacing:0;white-space:pre-wrap;overflow-wrap:anywhere}
.coach-workspace .msg.user .bub{padding:13px 16px;background:color-mix(in srgb,var(--surface-2) 62%,transparent);border-radius:20px 20px 6px 20px;color:var(--text);line-height:1.5}
.coach-workspace .bub.err{padding:12px 14px;background:var(--danger-tint);border-radius:10px}
.coach-workspace .aui-md{min-width:0;max-width:100%;white-space:normal;overflow-wrap:anywhere}
.coach-workspace .coach-streaming .coach-streaming-text{padding:0;background:none;border:0;border-radius:0;box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none}
.coach-workspace .coach-streaming .aui-md>div>:last-child::after{content:'▋';display:inline;color:var(--info-fg);animation:coach-stream-caret 1s steps(1,end) infinite}
@keyframes coach-stream-caret{50%{opacity:0}}
.coach-workspace .aui-md p{margin:0 0 .75em}
.coach-workspace .aui-md :is(h1,h2,h3,h4,h5,h6){margin:1em 0 .4em;font:600 1em/1.4 var(--font);letter-spacing:-.015em}
.coach-workspace .aui-md h1{font-size:1.25em}
.coach-workspace .aui-md h2{font-size:1.125em}
.coach-workspace .aui-md :is(ul,ol){margin:.65em 0;padding-inline-start:1.5em}
.coach-workspace .aui-md li{margin:.25em 0}
.coach-workspace .aui-md li>p{margin:.3em 0}
.coach-workspace .aui-md strong{font-weight:600}
.coach-workspace .aui-md a{color:var(--info-fg);text-decoration:underline;text-underline-offset:3px}
.coach-workspace .aui-md code{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:.85em;background:var(--surface-2);border-radius:4px;padding:.15em .3em;box-decoration-break:clone;-webkit-box-decoration-break:clone}
.coach-workspace .aui-md pre{max-width:100%;min-width:0;box-sizing:border-box;overflow-x:auto;overscroll-behavior-x:contain;white-space:pre;margin:.75em 0;padding:14px;background:var(--surface-2);border:1px solid var(--sep);border-radius:12px;line-height:1.5;tab-size:2}
.coach-workspace .aui-md pre code{background:none;border-radius:0;padding:0;overflow-wrap:normal}
.coach-workspace .aui-md blockquote{margin:.75em 0;padding-inline-start:14px;border-inline-start:3px solid var(--sep);color:var(--text-2)}
.coach-workspace .aui-md hr{border:0;border-top:1px solid var(--sep);margin:1em 0}
.coach-workspace .aui-md-table-wrapper{max-width:100%;overflow-x:auto;overscroll-behavior-x:contain;margin:.75em 0}
.coach-workspace .aui-md table{border-collapse:collapse;font-size:.875em;font-variant-numeric:tabular-nums;width:100%}
.coach-workspace .aui-md :is(th,td){padding:8px 12px;border:1px solid var(--sep);text-align:start;min-width:6em}
.coach-workspace .aui-md th{background:var(--surface-2);font-weight:600}
.coach-workspace .aui-md>:first-child{margin-top:0}
.coach-workspace .aui-md>:last-child{margin-bottom:0}
.coach-workspace .aui-md :is(a,pre,.aui-md-table-wrapper):focus-visible{outline:2px solid var(--info-fg);outline-offset:3px}
.coach-workspace .msg-t{display:flex;align-items:center;gap:6px;min-height:28px;margin:4px 0 0;font:400 11px/1.4 var(--font);color:var(--text-2);font-variant-numeric:tabular-nums}
.coach-workspace .msg.user .msg-t{min-height:0;margin-top:6px}
/* A 28px copy button that still takes a 44px tap: the row stays a caption, not a toolbar. */
.coach-workspace .msg-t>.btn{position:relative;width:28px;height:28px;min-height:28px;min-width:28px;padding:0;margin-inline-start:-6px;color:var(--text-2);border-radius:8px}
.coach-workspace .msg-t>time+.btn{margin-inline-start:0}
.coach-workspace .msg-t>.btn::before{content:"";position:absolute;inset:-8px}
.coach-workspace .msg-t>.btn>.icn{width:15px;height:15px}
.coach-workspace .typing{display:flex;align-items:center;gap:10px;min-height:44px;padding:0;color:var(--text-2);font-size:14px}
.coach-workspace .typing canvas{display:block;flex:none}
.coach-workspace .typing-eta{margin:4px 0 0 42px;max-width:48ch;font-size:12px;line-height:1.5}
.coach-workspace .composer{position:relative;min-width:0;flex:none;inset-inline:0;bottom:auto;z-index:3;padding:10px 0 max(6px,var(--sab));background:none}
.coach-workspace[data-keyboard] .composer{padding-bottom:6px}
.coach-workspace .composer>.coach-chrome-backdrop{top:-28px;bottom:0;--coach-fade-direction:to top;--coach-chrome-tint:linear-gradient(to top,color-mix(in srgb,var(--canvas) 68%,transparent) 0%,color-mix(in srgb,var(--canvas) 52%,transparent) 38%,color-mix(in srgb,var(--canvas) 34%,transparent) 62%,color-mix(in srgb,var(--canvas) 12%,transparent) 84%,transparent 100%)}
.coach-workspace .composer-in{display:block;max-width:none;margin:0;padding:10px;background:var(--surface-2);border-radius:24px;cursor:text;border:0}
.coach-workspace .composer-in:focus-within{outline:1px solid var(--outline-input);outline-offset:0}
.coach-workspace .composer textarea{display:block;box-sizing:border-box;width:100%;min-height:52px;max-height:144px;resize:none;background:none;border:0;border-radius:0;padding:8px 8px 12px;font:400 16px/1.5 var(--font);color:var(--text);box-shadow:none;outline:none}
.coach-workspace .prompt-input-actions{display:flex;align-items:center;justify-content:space-between;gap:8px}
.coach-workspace .prompt-input-actions>.btn{width:auto;min-height:44px;padding:8px 10px;border-radius:14px;font-size:13px;color:var(--text-2)}
.coach-workspace .prompt-input-actions>.btn>.icn{width:16px;height:16px}
.coach-workspace .prompt-input-actions>.send{width:44px;height:44px;min-width:44px;padding:0;border-radius:50%;background:var(--ink);color:var(--on-ink);opacity:1}
.coach-workspace .prompt-input-actions>.send:disabled{background:var(--surface-3);color:var(--text-3)}
.coach-workspace .chips-row{margin:0 0 10px;gap:6px;scrollbar-width:thin}
.coach-workspace .chips-row>.btn{width:auto;min-height:44px;flex:none;padding:8px 12px;border-radius:12px;font-size:13px;box-shadow:none;background:none;border:1px solid var(--sep)}
.coach-workspace .composer-cap{margin-top:7px;font-size:11px;color:var(--text-2)}
.coach-context-list{margin:16px 0}.coach-context-list>div{display:flex;justify-content:space-between;gap:16px;padding:14px 0;border-bottom:var(--hair) solid var(--sep);font-size:15px}.coach-context-list span{color:var(--text-2)}
.coach-workspace .composer>.coach-latest.btn{position:absolute;z-index:2;bottom:calc(100% + 12px);inset-inline:0;margin-inline:auto;width:max-content;max-width:90%;min-height:44px;padding:8px 14px;background:var(--surface);box-shadow:var(--shadow-card);border-radius:22px;font-size:13px}
/* Statistics read as a table rather than nested cards. */
.chat-menu .ins{padding:12px 16px}
.chat-menu .ins-tiles{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:0;margin:8px 0 16px;background:none}
.chat-menu .ins-tile{padding:0 8px;background:none;border-radius:0;min-width:0;text-align:start}
.chat-menu .ins-tile:first-child{padding-inline-start:0}
.chat-menu .ins-tile+.ins-tile{border-inline-start:var(--hair) solid var(--sep)}
.chat-menu .ins-tile-v{font:600 clamp(16px,4.6vw,23px)/1.3 var(--font);font-variant-numeric:tabular-nums;letter-spacing:-.02em;margin-top:5px;overflow-wrap:anywhere}
.chat-menu .ins-tile-l{font-size:11px;line-height:1.4;color:var(--text-2);white-space:normal}
.chat-menu .ins-block{padding:16px 0 0;background:none;border-radius:0;border-top:var(--hair) solid var(--sep);margin-top:16px}
.chat-menu .ins-h{flex-wrap:wrap;gap:6px;font-size:13px;line-height:1.5}
@media(max-width:360px){
.chat-menu .ins-tiles{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 0}
.chat-menu .ins-tile:nth-child(3){border-inline-start:0;padding-inline-start:0}}
@media(prefers-reduced-transparency:reduce),(prefers-contrast:more){.coach-workspace .chat-hdr .glass{background:var(--surface);backdrop-filter:none;-webkit-backdrop-filter:none;box-shadow:0 0 0 1px var(--sep)}}

/* Page entrance animation must not move the header, transcript and composer independently. */
#root #app.vfade:has(>.coach-workspace),#root #app.vfade>.coach-workspace>*{animation:none}

#app.vfade:has(>.coach-workspace){animation:none}
/* Inline composer: the send control shares the input row instead of a second toolbar. */
.coach-workspace .composer-in{display:flex;align-items:flex-end;gap:6px;padding:5px 6px 5px 12px;border-radius:26px}
.coach-workspace .composer textarea{flex:1;min-width:0;width:auto;min-height:44px;padding:10px 2px;font-size:16px;line-height:24px}
.coach-workspace .composer textarea::placeholder{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.coach-workspace .composer-in>.send{width:44px;height:44px;min-width:44px;flex:none;padding:0;border-radius:50%;background:var(--ink);color:var(--on-ink)}
.coach-workspace .composer-in>.send:disabled{background:var(--surface-3);color:var(--text-3);opacity:1}

/* assistant-ui Elements: standalone Inline composer and horizontal follow-up suggestions.
   The Coach owns its job state; these source-adapted elements own presentation. */
.aui-composer{position:relative;width:100%;min-width:0}
.aui-composer-bar{width:100%;box-sizing:border-box}
.aui-composer-input{resize:none;overflow-y:auto;max-height:144px;caret-color:var(--ink)}
.aui-composer-send{display:grid;place-items:center;transition:background-color 150ms var(--ease-out),color 150ms var(--ease-out)}
.aui-composer-send .icn{width:18px;height:18px}
.aui-suggestions{display:block;width:100%;min-width:0;overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none;padding:4px 2px}
.aui-suggestions::-webkit-scrollbar{display:none}
.aui-suggestions-track{display:flex;align-items:center;gap:8px;width:max-content}
.aui-suggestion{display:flex;align-items:center;flex:none;min-height:44px;padding:8px 12px;border:1px solid var(--sep);border-radius:999px;background:transparent;box-shadow:none;font:400 13px/1.4 var(--font);color:var(--text);text-align:start;white-space:nowrap;transition:background-color 150ms var(--ease-out),border-color 150ms var(--ease-out)}
.aui-suggestion[aria-pressed="true"]{background:var(--ink);color:var(--on-ink)}
.aui-suggestion:disabled{color:var(--text-3);cursor:default}
.coach-suggestions{margin:0 0 12px;transition:opacity 160ms var(--ease-out)}
.coach-suggestions[data-hidden]{opacity:0;pointer-events:none;transition-duration:100ms}
.coach-workspace[data-keyboard] .coach-suggestions{display:none}
.coach-workspace[data-keyboard] .composer{padding-bottom:6px}
/* Native keyboard page padding is for document-scrolling pages; the Coach has its own
   measured transcript. Leaving that padding creates a second scroll area below the input. */
:root[data-native-kb] body #app:has(>.coach-workspace){padding-bottom:0}
@media(hover:hover){.aui-suggestion:hover:not(:disabled){background:var(--surface-2);border-color:var(--text-3)}}
.aui-suggestion:active:not(:disabled){background:var(--surface-2)}
.aui-suggestion:focus-visible,.aui-composer-send:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
@media(prefers-reduced-motion:reduce){.aui-suggestion{animation:none;transition:none}.aui-suggestion:hover,.aui-suggestion:active{transform:none}.aui-composer-send{transition:none}}
@media(prefers-reduced-transparency:reduce),(prefers-contrast:more){
  .coach-chrome-backdrop{background:var(--canvas)}
  .coach-blur-band,.coach-chrome-backdrop::after{display:none}
  .coach-workspace .chat-hdr>.coach-chrome-backdrop{bottom:0}
  .coach-workspace .composer>.coach-chrome-backdrop{top:0}
}

/* Pointer press feedback is immediate and reversible. Typing, focus movement, old
   messages and the floating chrome stay still; incoming replies use WAAPI once. */
.coach-workspace .aui-composer-send,.coach-workspace .aui-suggestion{transition:transform 120ms cubic-bezier(.32,.72,0,1),background-color 150ms ease,border-color 150ms ease}
.coach-workspace .aui-composer-send:active:not(:disabled),.coach-workspace .aui-suggestion:active:not(:disabled){transform:scale(.97)}
.coach-workspace .aui-composer-send:focus-visible:active,.coach-workspace .aui-suggestion:focus-visible:active{transform:none}
@media(prefers-reduced-motion:reduce){.coach-workspace .aui-composer-send,.coach-workspace .aui-suggestion{transition:none}.coach-workspace .aui-composer-send:active:not(:disabled),.coach-workspace .aui-suggestion:active:not(:disabled){transform:none}}

/* Animate navigation snapshots, never the measured live header/composer geometry. */
:root[data-vt="coach"]::view-transition-group(root){animation-duration:400ms}
/* The room opens out of the Coach button: the page you were on stays still underneath and the
   room's opaque circle grows over it, so the two never show through each other the way a
   crossfade does. coach-open-reveal is written by TabBar.jsx (revealFrom) with the button's
   pixels; without it (the button never pressed) the room still fades in. */
:root[data-vt="coach"]::view-transition-old(root){animation:none;mix-blend-mode:normal}
:root[data-vt="coach"]::view-transition-new(root){animation:coach-open-reveal 400ms cubic-bezier(.32,.72,0,1) both;mix-blend-mode:normal}
@keyframes coach-open-reveal{from{opacity:0}}
/* The tab bar is not its own layer here: it leaves the page a moment into the transition, and a
   captured element that stops rendering aborts the whole transition, which cut the circle off
   half open. It stays in the old page's picture instead, under the circle. */
:root[data-vt="coach"] #dock .tab-menus{view-transition-name:none}
@media(prefers-reduced-motion:reduce){:root[data-vt="coach"]::view-transition-group(*),:root[data-vt="coach"]::view-transition-old(*),:root[data-vt="coach"]::view-transition-new(*){animation:none!important}}

/* Bottom-of-screen backdrop behind both transcript and composer. The glow rises
   beyond the composer without changing layout or intercepting interactions. */
.coach-thinking-beam{position:absolute;inset-inline:calc(-1 * var(--pad));bottom:0;height:min(100%,452px);z-index:0;overflow:hidden;pointer-events:none;mask-image:linear-gradient(to bottom,transparent 0%,#000 28%,#000 100%);-webkit-mask-image:linear-gradient(to bottom,transparent 0%,#000 28%,#000 100%)}
#root #app.vfade>.coach-workspace>.coach-room>.coach-thinking-beam:not([data-thinking]){animation:coach-beam-descend 240ms var(--ease-out) both}
@keyframes coach-beam-descend{from{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(10px)}}
.coach-thinking-beam [data-voice-beam]{position:absolute;inset-inline:0;bottom:0;width:100%;height:100%;border-radius:0}
.coach-thinking-beam-host{width:100%;height:100%;min-height:0;border-radius:0}
@media(prefers-reduced-motion:reduce){.coach-thinking-beam{display:none;transition:none}}
.coach-thinking-beam [data-voice-beam][data-active],.coach-thinking-beam [data-voice-beam][data-fading]{animation-duration:240ms}

/* A restrained glass material on message surfaces; text remains fully opaque. */
.coach-workspace .msg.user .bub{
  backdrop-filter:blur(10px) saturate(1.15);-webkit-backdrop-filter:blur(10px) saturate(1.15);
}
.coach-workspace .msg.user .bub{box-shadow:inset 0 1px 0 color-mix(in srgb,var(--text) 6%,transparent)}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .coach-workspace .msg.user .bub{background:var(--surface-2)}
}
@media(prefers-reduced-transparency:reduce),(prefers-contrast:more){
.coach-workspace .msg.user .bub{backdrop-filter:none;-webkit-backdrop-filter:none;box-shadow:var(--shadow-card)}
  .coach-workspace .msg.user .bub{background:var(--surface-2)}
}

/* Chosen in the composer tuner: 65% fill, 35% transparency, 12px blur.
   Keep opacity on the material only so labels and controls stay fully legible. */
.coach-workspace{--coach-input-opacity:65%;--coach-input-blur:12px;--coach-input-sheen:rgb(255 255 255 / .045)}
:root[data-theme="light"] .coach-workspace{--coach-input-sheen:rgb(255 255 255 / .18)}
.coach-workspace .composer-in,.coach-workspace .aui-suggestion::before{
  position:relative;
  background:linear-gradient(145deg,var(--coach-input-sheen),transparent 38%,transparent 65%,var(--coach-input-sheen)),color-mix(in srgb,var(--surface-2) var(--coach-input-opacity),transparent);
  -webkit-backdrop-filter:blur(var(--coach-input-blur)) saturate(1.6);backdrop-filter:blur(var(--coach-input-blur)) saturate(1.6);
  box-shadow:inset 0 1px 0 color-mix(in srgb,var(--text) 12%,transparent),0 3px 10px rgb(0 0 0 / .07);
}
/* Anchor each absolute glass backing to its own pill, never to the composer. */
.coach-workspace .aui-suggestion{position:relative;isolation:isolate;min-height:44px;padding:4px 18px;border:0}
.coach-workspace .aui-suggestion::before{content:"";position:absolute;inset:5px 0;border-radius:inherit;z-index:-1;pointer-events:none;border:1px solid color-mix(in srgb,var(--text) 8%,transparent)}
.coach-workspace .aui-suggestion[aria-pressed="true"]::before{background:var(--ink);color:var(--on-ink)}
@media(hover:hover){.coach-workspace .aui-suggestion:hover:not(:disabled):not([aria-pressed="true"])::before{background-color:color-mix(in srgb,var(--surface-2) 80%,transparent)}}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .coach-workspace .composer-in,.coach-workspace .aui-suggestion::before{background:var(--surface-2)}
}
@media(prefers-reduced-transparency:reduce),(prefers-contrast:more){
  .coach-workspace .composer-in,.coach-workspace .aui-suggestion::before{background:var(--surface-2);-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:inset 0 0 0 1px var(--outline-input)}
  .coach-workspace .aui-suggestion[aria-pressed="true"]::before{background:var(--ink)}
}

.coach-workspace .aui-suggestion,.coach-workspace .aui-suggestion:hover:not(:disabled),.coach-workspace .aui-suggestion:active:not(:disabled),.coach-workspace .aui-suggestion[aria-pressed="true"]{background:none;box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none}
.coach-workspace .aui-suggestion[aria-pressed="true"]{color:var(--on-ink)}

/* inter-cyrillic-ext-wght-normal */
@font-face {
  font-family: 'Inter Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/ca157063339ac4ad.woff2) format('woff2-variations');
  unicode-range: U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F;
}

/* inter-cyrillic-wght-normal */
@font-face {
  font-family: 'Inter Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/71d5ee93cc1e9f1d.woff2) format('woff2-variations');
  unicode-range: U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;
}

/* inter-greek-ext-wght-normal */
@font-face {
  font-family: 'Inter Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/6e9e020a25f9b56d.woff2) format('woff2-variations');
  unicode-range: U+1F00-1FFF;
}

/* inter-greek-wght-normal */
@font-face {
  font-family: 'Inter Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/1be3448e292fbf05.woff2) format('woff2-variations');
  unicode-range: U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF;
}

/* inter-vietnamese-wght-normal */
@font-face {
  font-family: 'Inter Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/5c66f9e07e90c6d4.woff2) format('woff2-variations');
  unicode-range: U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB;
}

/* inter-latin-ext-wght-normal */
@font-face {
  font-family: 'Inter Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/34b9c504cab7a73e.woff2) format('woff2-variations');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* inter-latin-wght-normal */
@font-face {
  font-family: 'Inter Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/3100e775e8616cd2.woff2) format('woff2-variations');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
/* inter-cyrillic-ext-wght-italic */
@font-face {
  font-family: 'Inter Variable';
  font-style: italic;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/39689184132e9fba.woff2) format('woff2-variations');
  unicode-range: U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F;
}

/* inter-cyrillic-wght-italic */
@font-face {
  font-family: 'Inter Variable';
  font-style: italic;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/47d42151dff6d13f.woff2) format('woff2-variations');
  unicode-range: U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;
}

/* inter-greek-ext-wght-italic */
@font-face {
  font-family: 'Inter Variable';
  font-style: italic;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/787fc783f35c9133.woff2) format('woff2-variations');
  unicode-range: U+1F00-1FFF;
}

/* inter-greek-wght-italic */
@font-face {
  font-family: 'Inter Variable';
  font-style: italic;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/29e273a42cac8240.woff2) format('woff2-variations');
  unicode-range: U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF;
}

/* inter-vietnamese-wght-italic */
@font-face {
  font-family: 'Inter Variable';
  font-style: italic;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/1991ed5832eb07f7.woff2) format('woff2-variations');
  unicode-range: U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB;
}

/* inter-latin-ext-wght-italic */
@font-face {
  font-family: 'Inter Variable';
  font-style: italic;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/71254244ccb1ec21.woff2) format('woff2-variations');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* inter-latin-wght-italic */
@font-face {
  font-family: 'Inter Variable';
  font-style: italic;
  font-display: swap;
  font-weight: 100 900;
  src: url(../assets/7291b5970da22374.woff2) format('woff2-variations');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
/* ============================================================================
   openGym — design system
   ----------------------------------------------------------------------------
   Rebuilt around four rules, each aimed at a specific "generated" tell in the
   previous sheet:

   1. ONE TYPE SCALE, MOSTLY REGULAR WEIGHT. The old sheet set font-weight 700/800
      on nearly every element, which flattens hierarchy — when everything shouts,
      position is the only cue left. Here weight carries meaning: 600 for a title,
      400 for its content, and size does the rest.
   2. A NEUTRAL SURFACE RAMP. Cards are near-neutral greys a few points apart, not
      saturated blue-greys. Colour is spent only on the accent and on status.
   3. HAIRLINES, NOT BORDERS. Separators are sub-pixel and inset past the icon
      rail, so a list reads as one object instead of a stack of outlined boxes.
   4. MOTION THAT ACKNOWLEDGES, NOT ANIMATES. Presses scale ~2%, transitions run
      140–220ms on an ease-out curve. Nothing bounces or slides for decoration.
   ========================================================================== */

/* ---------------------------------------------------------------- tokens -- */
:root {
  --font:-apple-system,BlinkMacSystemFont,"SF Pro Text","SF Pro Display","Inter Variable",Inter,"Segoe UI",Roboto,system-ui,sans-serif;
  /* surfaces — dark is the default */
  --bg:        #000000;
  --bg-el:     #0e0e10;   /* elevated backdrop (sheets, bars) */
  --surface:   #1c1c1e;   /* card / grouped-list fill */
  --surface-2: #2c2c2e;   /* pressed + nested fill */
  --surface-3: #3a3a3c;   /* controls (segmented track, switch off) */

  /* text */
  --label:     #ffffff;
  --label-2:   rgba(235,235,245,.60);
  --label-3:   rgba(235,235,245,.32);
  --label-4:   rgba(235,235,245,.18);

  /* lines */
  --sep:       rgba(84,84,88,.60);
  --sep-op:    rgba(84,84,88,.34);   /* for edges sitting over blur */
  --hair:      .5px;

  /* system palette (iOS dark values) */
  --blue:#0a84ff; --green:#30d158; --red:#ff453a; --orange:#ff9f0a;
  --yellow:#ffd60a; --teal:#40c8e0; --indigo:#5e5ce6; --pink:#ff375f;
  --purple:#bf5af2; --mint:#63e6e2; --brown:#ac8e68; --grey:#8e8e93;

  /* accent (per-account, synced) */
  --acc:  var(--green);
  --acc-2:#248a3d;
  --on-acc:#000000;
  --acc-soft: color-mix(in srgb, var(--acc) 16%, transparent);
  --acc-line: color-mix(in srgb, var(--acc) 38%, transparent);

  /* geometry */
  --r-sm:8px; --r:12px; --r-lg:16px; --r-xl:22px; --r-card:14px;
  --pad:16px;
  --icon-stroke:2;

  /* motion */
  --ease:cubic-bezier(.32,.72,0,1);
  --fast:140ms; --med:220ms;

  /* The system bars the page is drawn under. env() is all a browser and the iOS app give; the
     Android WebView reports only the camera cutout there, and on Android 15, which draws the app
     under the status and navigation bars, the app passes the bars themselves as --native-sat and
     --native-sab (MainActivity.java). The larger one wins, so a WebView that learns to report
     the bars does not count them twice. */
  --sab:max(env(safe-area-inset-bottom,0px),var(--native-sab,0px));
  --sat:max(env(safe-area-inset-top,0px),var(--native-sat,0px));
  /* height of the connection indicator under the status bar, 0 while there is none — set by
     components/SyncBanner.jsx. Whatever starts at the top of the screen starts below it. */
  --conn:0px;
}

:root[data-theme="light"] {
  --bg:        #f2f2f7;
  --bg-el:     #f7f7fa;
  --surface:   #ffffff;
  --surface-2: #ececef;
  --surface-3: #e3e3e8;

  --label:     #000000;
  --label-2:   rgba(60,60,67,.60);
  --label-3:   rgba(60,60,67,.30);
  --label-4:   rgba(60,60,67,.16);

  --sep:       rgba(60,60,67,.29);
  --sep-op:    rgba(60,60,67,.20);

  --blue:#007aff; --green:#34c759; --red:#ff3b30; --orange:#ff9500;
  --yellow:#ffcc00; --teal:#30b0c7; --indigo:#5856d6; --pink:#ff2d55;
  --purple:#af52de; --mint:#00c7be; --brown:#a2845e; --grey:#8e8e93;
  --acc-2:#248a3d;
  --on-acc:#ffffff;
}

/* accents — Apple's system colours, so a recolour never looks off-system */
:root[data-accent="lime"]  { --acc:var(--green);  --acc-2:#248a3d; --on-acc:#000 }
:root[data-accent="sky"]   { --acc:var(--blue);   --acc-2:#0060df; --on-acc:#fff }
:root[data-accent="orange"]{ --acc:var(--orange); --acc-2:#c76b00; --on-acc:#000 }
:root[data-accent="violet"]{ --acc:var(--purple); --acc-2:#8944ab; --on-acc:#fff }
:root[data-accent="pink"]  { --acc:var(--pink);   --acc-2:#d70036; --on-acc:#fff }
:root[data-accent="red"]   { --acc:var(--red);    --acc-2:#d70015; --on-acc:#fff }
:root[data-accent="teal"]  { --acc:var(--teal);   --acc-2:#0071a4; --on-acc:#000 }
:root[data-accent="gold"]  { --acc:var(--yellow); --acc-2:#b25000; --on-acc:#000; --knob-ring:rgba(0,0,0,.28) }
/* Label colour on a filled accent button is picked per accent by measured contrast,
   not by taste. Button text is 17px/600, so the AA bar is 3:1 (large text). White on
   the light-theme green is 2.22:1 and on teal 2.57:1 — both fail, and green is the
   DEFAULT accent, so every primary button in light mode was failing. Black scores
   9.46 / 8.16 there. Blue, purple, pink and red keep white (3.5–4.1:1), which both
   passes and matches the platform convention. */
:root[data-theme="light"][data-accent="lime"],
:root[data-theme="light"][data-accent="teal"]  { --on-acc:#000 }
:root[data-theme="light"][data-accent="sky"],
:root[data-theme="light"][data-accent="violet"],
:root[data-theme="light"][data-accent="pink"],
:root[data-theme="light"][data-accent="red"]   { --on-acc:#fff }

/* ---------------------------------------------------------------- reset -- */
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html{
  font-size:16px;background:var(--bg);overscroll-behavior:none;overflow-x:clip;
  -webkit-text-size-adjust:100%;
}
body{
  background:var(--bg);color:var(--label);
  font-family:var(--font);
  font-size:17px;line-height:1.29;letter-spacing:-.01em;
  min-height:100vh;min-height:100dvh;overscroll-behavior-y:none;overflow-x:clip;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  touch-action:manipulation;
  font-variant-numeric:tabular-nums;
}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer;letter-spacing:inherit}
input,select,textarea{font:inherit;color:var(--label);letter-spacing:inherit}
img{max-width:100%}
a{color:var(--ink);text-decoration:none}
:focus{outline:none}
:focus-visible{outline:2.5px solid var(--ink);outline-offset:2px;border-radius:6px}
button,.chip,.tile,.item,.wday,.cal-d,.swatch,.hm-c,.lrow,.seg button,.stp button,.sld
{-webkit-user-select:none;user-select:none}

/* icons inherit colour and optical size from their context */
.icn{
  width:1em;height:1em;flex:none;display:block;
  fill:none;stroke:currentColor;stroke-width:var(--icon-stroke);
  stroke-linecap:round;stroke-linejoin:round;
}

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

/* ------------------------------------------------------------ type scale -- */
/* The nine .t-* classes that used to live here emitted from no JSX in the app, while the views
   typed their numbers inline (Home.jsx:223 is .t-title2 with a different weight). Deleted
   2026-09-22 rather than adopted, because adopting a scale means changing what four screens
   render, which is a design call and not a cleanup. `git log -- src/index.css` has them. */

.muted{color:var(--label-2)} .dim{color:var(--label-2)}
.small{font-size:13px;line-height:1.38}
.accent{color:var(--ink)}
.capitalize{text-transform:capitalize}
/* exercise names and body-part/equipment terms arrive lowercase from the dataset,
   so tags and chips capitalise by default. Anything that is a unit or a sentence opts
   back out — blanket-capitalising turned "60 kg" into "60 Kg" and a whole hint into
   Title Case. The compound selectors are needed: .tag/.chip come later in this file
   and would otherwise win on source order. */
.nocap,.tag.nocap,.chip.nocap{text-transform:none}

.staging-banner{position:sticky;top:0;z-index:1000;padding:6px 12px;background:#fcd34d;color:#1c1917;text-align:center;font-size:12px}

/* ---------------------------------------------------------------- layout -- */
#app{
  padding:calc(var(--sat) + var(--conn) + 8px) var(--pad) calc(88px + var(--sab));
  max-width:560px;margin:0 auto;
}
/* Android 15 with the keyboard up: room to scroll the last field on a page above the keys.
   The tab bar stays where it is, under the keyboard, rather than riding up on it. */
:root[data-native-kb] #app,:root[data-native-kb] body.resting #app,:root[data-native-kb] body.no-tabbar.resting #app{padding-bottom:calc(88px + var(--native-kb))}
/* Keep the last workout controls clear of the mobile overlays without adding a second
   screenful of blank scroll space. The stacked rest timer needs the larger reserve. */
body.resting #app{padding-bottom:calc(166px + var(--sab))}
/* The workout screen has no tab bar (App.jsx): only the docked rest bar, when it is there. */
body.no-tabbar #app{padding-bottom:calc(24px + var(--sab))}
body.no-tabbar.resting #app{padding-bottom:calc(96px + var(--sab))}
.workout-end-spacer{height:0}
@keyframes viewfade{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
#app.vfade{animation:viewfade var(--med) var(--ease)}

/* Connection indicator (components/SyncBanner.jsx): pinned under the status bar for as long as
   the app is not connected to a server. It carries the page's own ground and blur, like the
   pinned workout header, so rows scrolling under it read as under it; --conn is the height of
   its row, which #app and the pinned headers leave free. Above those headers (20, 40), below the
   tab bar (50), the timer and every sheet. The sentence is never cut: its last words are the ones
   that say the changes are kept, so a narrow phone gets a third line rather than an ellipsis. */
.conn-bar{
  position:fixed;inset-inline-start:0;inset-inline-end:0;top:0;z-index:45;
  padding:var(--sat) var(--pad) 0;
  background:color-mix(in srgb,var(--bg) 94%,transparent);
  -webkit-backdrop-filter:saturate(180%) blur(10px);backdrop-filter:saturate(180%) blur(10px);
}
.conn-row{max-width:560px;margin:0 auto;padding:6px 0}
.conn{
  display:flex;align-items:center;gap:9px;width:100%;text-align:start;min-height:34px;
  padding-block:6px;padding-inline:12px 8px;border-radius:var(--r);
  background:color-mix(in srgb,var(--yellow) 16%,var(--surface));color:var(--label);font-size:13px;line-height:1.3;
}
.conn .icn{flex:none;font-size:16px;color:var(--label-2)}
.conn-t{flex:1;min-width:0;overflow-wrap:break-word}
.conn-a{flex:none;padding:4px 10px;border-radius:99px;background:var(--surface-3);font-weight:600;white-space:nowrap}
button.conn:active{filter:brightness(1.12)}
.conn-bar.off .conn{background:color-mix(in srgb,var(--label-3) 18%,var(--surface))}
.conn-bar.bad .conn{background:color-mix(in srgb,var(--red) 16%,var(--surface))}
.conn-bar.bad .conn .icn{color:var(--red)}
/* a deliberate local setup: said, not flagged — one small line, no fill */
.conn-bar.quiet .conn-row{padding:2px 0 4px}
.conn-bar.quiet .conn{min-height:26px;padding-block:2px;padding-inline:4px 2px;background:none;color:var(--label-2);font-size:12px;gap:6px}
.conn-bar.quiet .conn .icn{font-size:13px;color:var(--label-2)}
.conn-bar.quiet .conn-a{padding:2px 9px;font-size:12px;color:var(--ink);background:var(--control-tint)}
/* its × (#454): beside the line, not inside its button, so hiding it never also connects */
.conn-bar.quiet .conn-row{display:flex;align-items:center;gap:2px}
.conn-x{flex:none;display:grid;place-items:center;width:26px;height:26px;border-radius:99px;color:var(--label-2);font-size:12px}
.conn-x:active{background:var(--surface-2)}
:root[data-theme="light"] .conn-bar:not(.quiet) .conn-a{background:var(--surface)}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .conn-bar{background:var(--bg)}
}
/* large title, the way a nav bar does it */
.hdr{display:flex;align-items:flex-end;justify-content:space-between;gap:12px;margin:8px 0 18px}
/* The title block gives way, the button on the right never does: a flex item will not shrink
   below its longest word, so "Упражнения" at 34px or "Hi Bartholomew_Jones" used to push the
   gear / "By muscle" past the screen edge. Two things follow from letting it shrink. Below 420px
   — every phone width we test — the title drops a step to 30px, because the 95 to 125px the
   Library button leaves the Polish and Russian titles is less than half of "Ćwiczenia" or
   "Упражнения" at 34px and they came apart into three lines; at 30px all 14 packs take two at
   most. And a word that still does not fit is broken with overflow-wrap:break-word, which moves
   the whole word to the next line first and breaks it only if it does not fit there either —
   `anywhere` broke "Bartholomew_Jones" mid-word even at 412px, where a line of its own was
   waiting for it. hyphens:auto goes with them: the hyphen costs a character's worth of width in
   a box this tight, and that is what turned "Упражнения" into "Упра / жнен / ия". */
.hdr>div{min-width:0}
.hdr>.btn{flex:none}
.hdr>.hdr-actions{display:flex;align-items:center;gap:8px;flex:none}
.hdr h1{font-size:34px;line-height:1.06;font-weight:700;letter-spacing:-.028em;overflow-wrap:break-word}
@media (max-width:420px){.hdr h1{font-size:30px}}
.hdr .sub{color:var(--label-2);font-size:15px;letter-spacing:-.006em;margin-top:4px}
/* Library: the count line runs under the title row at full width instead of beside the "By muscle"
   button, which left it ~200px on a phone: the catalogue count plus your own exercises stays one
   line in every language. The ellipsis is only the safety net (the strings are kept short), and
   text-overflow follows the text direction, so Arabic clips on its own end. */
.hdr.lib-hdr{flex-wrap:wrap;align-items:center;row-gap:0}
.hdr.lib-hdr>.sub.lib-count{flex:1 0 100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
@media (max-width:360px){.hdr.lib-hdr>.sub.lib-count{white-space:normal;overflow:visible;text-overflow:clip}}

.iconbtn{
  width:36px;height:36px;border-radius:50%;flex:none;
  background:var(--surface);color:var(--label);
  display:flex;align-items:center;justify-content:center;font-size:18px;
  transition:background var(--fast),transform var(--fast);
}
.iconbtn:active{background:var(--surface-2);transform:scale(.92)}
/* invisible hit-area extension: these look right at their size but fall short of a
   finger-sized target, so the pseudo element widens what the tap lands on without
   changing the painted box. Segmented buttons sit flush against each other, so they
   only grow vertically or the neighbour would steal the edge of the tap. */
.iconbtn,.chip,.seg button,.helpbtn{position:relative}
.iconbtn::before,.chip::before,.seg button::before,.helpbtn::before{content:'';position:absolute;inset:-6px}
.seg button::before{inset:-6px 0}
.iconbtn.on-ss{background:var(--control-tint);color:var(--ink)}
.iconbtn:disabled{opacity:.32}

h4.sec{
  font-size:13px;font-weight:400;letter-spacing:-.004em;color:var(--label-2);
  text-transform:none;margin:22px 0 8px;padding:0 4px;
}
.card h2{
  font-size:13px;font-weight:400;letter-spacing:-.004em;color:var(--label-2);
  text-transform:none;margin:0 0 12px;
}
.divider{height:var(--hair);background:var(--sep);margin:14px 0;border:0}
.row{display:flex;align-items:center;gap:12px}
.row.between{justify-content:space-between}
/* The body-weight card header (Home and Stats): title on the left, Goal + Log on the right. In
   German the title and the two buttons ("Ziel", "+ Eintragen") outgrow a 320px card by about
   55px, so the button pair may drop to a second line — still flush right, hence the auto margin. */
.bw-head{flex-wrap:wrap;row-gap:8px}
.bw-head>.row{margin-inline-start:auto}

/* ----------------------------------------------------------------- card -- */
.card{
  background:var(--surface);border-radius:var(--r-card);
  padding:16px;margin-bottom:12px;
}
.card .big{font-size:30px;font-weight:600;letter-spacing:-.026em;line-height:1.1}

/* ------------------------------------------------------ inset group list -- */
.sect{margin-bottom:22px}
.sect-t{
  font-size:13px;font-weight:400;color:var(--label-2);
  letter-spacing:-.004em;padding:0 4px 7px;display:block;
}
.sect-b{background:var(--surface);border-radius:var(--r-card);overflow:hidden}
.sect-f{font-size:13px;color:var(--label-2);padding:7px 4px 0;line-height:1.38}

.lrow{
  display:flex;align-items:center;gap:12px;width:100%;text-align: start;
  padding:11px 14px;min-height:46px;position:relative;color:var(--label);
  background:none;
}
/* hairline starts after the icon rail so the list reads as one object */
.lrow+.lrow::before{
  content:'';position:absolute;inset-inline-start:14px;inset-inline-end:0;top:0;height:var(--hair);background:var(--sep);
}
.lrow:has(.lrow-i)+.lrow:has(.lrow-i)::before{inset-inline-start:55px}
.lrow.tap:active{background:var(--surface-2)}
.lrow-i{
  width:29px;height:29px;border-radius:7px;flex:none;font-size:18px;
  display:flex;align-items:center;justify-content:center;
  background:var(--tint,var(--ink));color:#fff;
}
/* The title column never shrinks below its own longest word. With a basis of 0 and min-width:0 it
   only got what a capped value left over, and on a 320px phone "Progression" (96px) was painted over
   by "Linear progression" in a 37px box; min-width:auto — the flex default — is exactly the floor
   that case wants. A fixed 104px floor fixed that row and starved the rest: the backfill sheet's Date
   and Start-time rows have nothing but the title to give, so the floor shoved their fixed-width
   .timef off a 320px screen, and a short title like "Routine" (63px) took 104px away from the value
   beside it until "Freies Training" ellipsised. Asking only for the longest word takes nothing a row
   did not already owe the title. .lrow-t does not ellipsise on purpose — long settings titles wrap
   onto a second line — and the value next to it shrinks and ellipsises instead (below). */
.lrow-m{flex:1;min-width:auto;display:flex;flex-direction:column;gap:1px}
.lrow-t{font-size:17px;letter-spacing:-.012em;line-height:1.25}
.lrow-s{font-size:13px;color:var(--label-2);line-height:1.3}
/* Settings → Account ID: a machine string, so a machine face, small, and free to break anywhere
   rather than push the row past a phone's edge. */
.acct-id{font-family:var(--font);font-size:12px;overflow-wrap:anywhere}
/* flex:none would let a long value ("Follow the routine (Linear progression)") run straight
   through the title next to it, since the title's column only holds out for its longest word.
   Letting the value shrink and ellipsise instead keeps the two out of each other's way.
   The cap is max-width, not flex-basis: .lrow-m is flex:1, so its basis is 0 and it absorbs
   none of the shrink — a long value would otherwise take the whole row and squeeze the title
   to 21px. A basis of 45% fixes that but reserves the space even for "3", costing the title
   141px on the rows that need it most. A cap does neither. */
.lrow-v{color:var(--label-2);font-size:17px;letter-spacing:-.012em;flex:0 1 auto;max-width:55%;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align: end}
.lrow-c{color:var(--label);font-size:15px;flex:none;--icon-stroke:2.4}
.lrow-k{color:var(--ink);font-size:17px;flex:none;--icon-stroke:2.4}
.lrow.danger,.lrow.danger .lrow-t{color:var(--danger-fg)}
/* A warning under a settings row reads at subtitle size: a sentence, not a row title. */
.lrow.backup-lost .lrow-t{font-size:13px;line-height:1.3;color:var(--label-2);letter-spacing:0}
/* The Stats exercise name gets its own line so long names cannot run into the title.
   Two columns only — label/value on the left, chevron on the right — so this is for rows
   WITHOUT an icon. `.lrow-i` is not placed here; on a row that has one it would auto-place
   into the grid and push the layout around. Give it a leading column before using this
   anywhere else. */
.lrow.lrow-stack-value{
  display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-rows:auto auto;
}
.lrow.lrow-stack-value .lrow-m{grid-column:1;grid-row:1}
.lrow.lrow-stack-value .lrow-v{grid-column:1;grid-row:2;width:100%;max-width:none;text-align:start}
.lrow.lrow-stack-value .lrow-c{grid-column:2;grid-row:1 / span 2;align-self:center}
/* an (i) before a row's control: painted small and dim so the control stays the loud thing,
   but with a finger-sized target like everything else — the padding is the hit area and the
   vertical negative margin keeps it from making the row taller. The horizontal ones pull the
   hit area back under the row's own 12px gap instead of adding to it. */
.helpbtn{
  color:var(--label-2);font-size:16px;background:none;line-height:0;flex:none;
  margin-block:-11px;margin-inline:-4px -2px;padding:11px 4px;
}
.helpbtn:active{color:var(--label)}

/* -------------------------------------------------------------- buttons -- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:7px;width:100%;
  padding:14px 18px;border-radius:var(--r);font-size:17px;font-weight:600;
  letter-spacing:-.012em;background:var(--surface-2);color:var(--label);
  transition:transform var(--fast) var(--ease),background var(--fast),opacity var(--fast);
}
.btn .icn{font-size:19px}
.btn:active{transform:scale(.975)}
.btn.primary{background:var(--ink);color:var(--on-ink)}
.btn.primary:active{background:var(--ink)}
.btn.tinted{background:var(--control-tint);color:var(--ink)}
.btn.danger{background:color-mix(in srgb,var(--red) 15%,transparent);color:var(--danger-fg)}
.btn.ghost,.btn.plain{background:none;color:var(--ink);font-weight:400}
.btn.ghost:active,.btn.plain:active{background:var(--surface-2)}
.btn.sm{padding:8px 14px;width:auto;font-size:15px;border-radius:var(--r-sm);gap:5px}
.btn.sm .icn{font-size:16px}
.btn.xs{padding:5px 10px;width:auto;font-size:13px;border-radius:7px;gap:4px}
.btn:disabled{opacity:.32;pointer-events:none}
.weekly-volume-toggle{padding-block:0}
.weekly-volume-toggle .icn{transition:transform var(--fast) var(--ease)}
.weekly-volume-toggle[aria-expanded="true"] .icn{transform:rotate(180deg)}

/* ----------------------------------------------------------- tab bar ----- */
/* Nearly opaque, and deliberately so. At the old 72% the page read straight through the bar
   and the labels had to compete with whatever was scrolling behind them — nobody needs to read
   the content under a navigation bar. 94% keeps a hint of movement behind the glass without
   letting text through. The blur is also down from 24px to 10px: this is a fixed element, so
   the WebView recomposites the blurred region on every scroll frame, and on Android that is
   the single most expensive thing on the screen. See @supports below for the no-blur case. */
#tabbar{
  position:fixed;inset-inline-start:0;inset-inline-end:0;bottom:0;z-index:50;
  display:flex;justify-content:space-around;align-items:flex-end;
  padding:7px 6px calc(6px + var(--sab));
  background:color-mix(in srgb,var(--bg-el) 94%,transparent);
  -webkit-backdrop-filter:saturate(180%) blur(10px);backdrop-filter:saturate(180%) blur(10px);
  border-top:var(--hair) solid var(--sep-op);
}
:root[data-theme="light"] #tabbar{background:rgba(249,249,251,.94)}
#tabbar button{
  flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;
  color:var(--label-2);font-size:10px;font-weight:500;letter-spacing:.005em;padding-top:3px;
  transition:color var(--fast);
}
/* The inactive tint is semi-transparent, so wherever two strokes cross inside an
   icon (the calendar's hangers over its frame, the divider's caps on its sides)
   the alpha doubled up and the icon read as a stack of loose layers. Carrying the
   fade on the <svg> instead of in the stroke colour flattens the icon first and
   fades it as one shape — and it does that for every icon, not just this one. */
#tabbar button .icn{font-size:25px;--icon-stroke:1.65;color:var(--label)}
#tabbar button.on{color:var(--ink)}
#tabbar button.on .icn{--icon-stroke:2;color:inherit;opacity:1}
/* A connection problem while the banner is switched off (Settings → Show connection status):
   a dot on the Home tab and on the Settings gear. */
#tabbar .tab-ic{position:relative;display:inline-flex}
.tab-dot{
  position:absolute;top:-1px;right:-3px;width:8px;height:8px;border-radius:50%;
  background:var(--orange);box-shadow:0 0 0 2px var(--bg-el);pointer-events:none;
}
.iconbtn .tab-dot{top:5px;right:5px;box-shadow:0 0 0 2px var(--bg)}
#tabbar button.start{margin-top:-24px}
#tabbar button.start .cir{
  width:52px;height:52px;border-radius:50%;background:var(--ink);color:var(--on-ink);
  display:flex;align-items:center;justify-content:center;position:relative;
  box-shadow:0 6px 18px -4px color-mix(in srgb,var(--ink) 55%,transparent);
  transition:transform var(--fast) var(--ease);
}
#tabbar button.start:active .cir{transform:scale(.93)}
#tabbar button.start .cir .icn{font-size:26px;--icon-stroke:2;color:inherit;opacity:1}
#tabbar button.start span{color:var(--ink);font-weight:600}
#tabbar button.start .tab-time{font-variant-numeric:tabular-nums}
/* `.cir` is itself a <span>, so the label rules above and below reach it too and
   outrank the `.cir` block — which is how the running state ended up painting an
   orange play glyph onto an orange disc. Both states restate their own colour.
   The disc is orange in either theme, so its glyph is black, not `--on-acc`. */
#tabbar button.start .cir{color:var(--on-ink)}
#tabbar button.start.rec .cir{background:var(--orange);color:#000;box-shadow:0 6px 18px -4px color-mix(in srgb,var(--orange) 55%,transparent)}
#tabbar button.start.rec span{color:var(--warning-fg)}
#tabbar button.start.rec .cir::after{
  content:'';position:absolute;inset:0;border-radius:50%;
  border:2px solid var(--orange);animation:ping 1.9s var(--ease) infinite;
}
@keyframes ping{0%{transform:scale(1);opacity:.7}100%{transform:scale(1.45);opacity:0}}

/* NOTE on every backdrop-filter pair in this file: the -webkit- line comes first and the
   standard property last, which is the order a prefixed/standard pair wants — whichever is
   written last wins in the cascade, and that should be the standard name.

   Where backdrop-filter is genuinely unsupported there is no glass either — only the alpha,
   and the page shows through unblurred, which is the worst of both. Older Android WebViews
   never had it, and "reduce transparency" accessibility settings drop it. Those surfaces go
   fully opaque instead. Keep this in sync with the rules above. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  #tabbar{background:var(--bg-el)}
  :root[data-theme="light"] #tabbar{background:#f9f9fb}
  #timer{background:var(--surface)}
  #toast{background:var(--surface-2)}
}

/* ------------------------------------------------------------ week strip -- */
.week{display:flex;justify-content:space-between;gap:4px}
.wday{
  flex:1;text-align:center;padding:8px 2px 9px;border-radius:10px;
  background:none;border:none;transition:background var(--fast);
}
.wday .lbl{font-size:11px;color:var(--label-2);font-weight:500;text-transform:uppercase;letter-spacing:.03em}
.wday .num{font-size:17px;font-weight:400;margin:4px 0;letter-spacing:-.012em}
.wday .dot{width:5px;height:5px;border-radius:50%;background:transparent;margin:0 auto}
.wday .dot.plan{background:var(--label-3)}
.wday .dot.ovr{background:var(--orange)}
.wday .dot.done{background:var(--ink)}
/* a day off with a note on it (#261, lib/day-notes.js): the same colour on every calendar */
.wday .dot.noted{background:var(--indigo)}
.wday:active{background:var(--surface-2)}
.wday.today .num{
  background:var(--ink);color:var(--on-ink);font-weight:600;
  width:31px;height:31px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;margin:2px auto;
}

/* ----------------------------------------------------------------- list -- */
.list{display:flex;flex-direction:column;gap:8px}
.item{
  display:flex;align-items:center;gap:12px;background:var(--surface);
  border-radius:var(--r-card);padding:10px 12px;min-height:60px;
  transition:background var(--fast);text-align: start;width:100%;
}
.item:active{background:var(--surface-2)}
.routine-list{position:relative}
/* One column at every width (#277), whatever page it is on. The desktop layout puts the #app
   lists outside a .narrow page in two columns, and before the .narrow rule below won on
   specificity this list sat in that grid on a computer, while the reorder measures its rows top
   to bottom and draws the drop line across the whole list: an exercise dragged just below the
   next one in its column landed at the end. Supersets ("the exercise above") read as a column too. */
#app .list.routine-list{display:flex;flex-direction:column}
.routine-drag-row{touch-action:pan-y;-webkit-touch-callout:none;position:relative;transition:transform var(--fast) var(--ease)}
.routine-list.is-reordering{user-select:none;-webkit-user-select:none}
.routine-list.is-reordering .routine-drag-row{transition:none}
.routine-drag-row.is-dragging{z-index:2;pointer-events:none}
.routine-drag-row.is-dragging .item{box-shadow:var(--shadow-card);background:var(--surface-2)}
.routine-drop-indicator{
  position:absolute;left:6px;right:6px;height:3px;border-radius:99px;
  background:var(--ink);transform:translateY(-50%);pointer-events:none;z-index:3;
}
/* The drag handle (#277, #114). A long press anywhere on a row reorders it on every device,
   but nothing on screen said so, and with a mouse nobody holds a row to find out. So a pointer
   device gets the grip it looks for, with a grab cursor, and pressing it picks the row up at
   once (RoutineEdit.jsx). A touch screen keeps the long press and the row's full width. */
.routine-grip{
  display:none;flex:none;align-self:stretch;align-items:center;margin:-10px -6px -10px -4px;padding:0 4px;
  color:var(--label-2);font-size:16px;cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none;
}
@media (hover:hover) and (pointer:fine){
  .routine-grip{display:flex}
  .routine-grip:hover{color:var(--label-2)}
}
.routine-list.is-reordering,.routine-list.is-reordering *{cursor:grabbing}
.thumb{width:50px;height:50px;border-radius:9px;object-fit:cover;background:#fff;flex:none}
/* exercise pictures are decoration inside tappable rows/cards: no save-image callout on
   a long press and no drag ghost when a scroll starts on the picture */
.thumb,.exmedia img,.exmedia video{-webkit-touch-callout:none;-webkit-user-drag:none;user-select:none;-webkit-user-select:none}
.thumb-x{
  display:flex;align-items:center;justify-content:center;font-size:21px;
  background:var(--surface-2);color:var(--label-2);
}
.item .tt{font-size:16px;font-weight:400;line-height:1.25;letter-spacing:-.009em}
.item .ss{color:var(--label-2);font-size:13px;margin-top:2px}
.item .grow{flex:1;min-width:0}
/* A row's opener as a real button (the routine editor's exercise name), so a row holding other
   buttons is no button itself. Reads as the plain text it replaced. */
.item .item-open{display:flex;flex-direction:column;justify-content:center;align-self:stretch;text-align:start}
.item .item-open>span{display:block}
.chev{color:var(--label);flex:none;font-size:15px;--icon-stroke:2.4}
.tag{
  display:inline-flex;align-items:center;gap:3px;background:var(--surface-2);
  color:var(--label-2);border-radius:6px;padding:3px 7px;font-size:12px;
  font-weight:500;text-transform:capitalize;
}
.tag.acc{background:var(--control-tint);color:var(--ink)}
/* Left / Right on a per-side row: one width for both (#322). The two hidden words share the
   visible one's grid cell, so the pill is as wide as the longer word. */
.tag.sidepill{display:inline-grid;justify-items:center;flex:none}
.tag.sidepill>span,.tag.sidepill::before,.tag.sidepill::after{grid-area:1/1}
.tag.sidepill::before{content:attr(data-l);visibility:hidden}
.tag.sidepill::after{content:attr(data-r);visibility:hidden}
/* favourite marker (issue #6): a small yellow star glued to the exercise name — distinct from
   the accent "chosen" tag at the row's end, which means "already in a routine or the log" */
.fav-star{color:var(--yellow);font-size:12px;display:inline-block;margin-inline-end:5px;vertical-align:-1px}
.fav-btn{margin-top:-4px;flex:none}
/* One long word (a German custom name) wraps instead of pushing the star off the screen. */
.exdetail-name{min-width:0;overflow-wrap:anywhere}
.fav-btn.on{color:var(--yellow)}
/* Exercise cards (S.exerciseView 'cards', ExerciseViewToggle): the Library, the picker and the
   muscle explorer as a grid of pictures with the name underneath — two across on a phone, more
   as the page or sheet widens. The id-prefixed selectors outrank the desktop rules further down
   that make every #app list two columns and every sheet list one. The catalogue pictures are
   180px, which is why a card stays near that size instead of filling a phone's width. */
.list.ex-grid,#app .list.ex-grid,#modal-root .list.ex-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px}
.ex-grid .item{position:relative;flex-direction:column;align-items:stretch;gap:8px;padding:8px}
.ex-grid .item .thumb{width:100%;height:auto;aspect-ratio:1;border-radius:12px}
.ex-grid .item .thumb-x{font-size:36px}
.ex-grid .item .tt{font-size:15px}
/* The badges ride on the picture's top corners and "+ Plan" spans the foot of the card. The
   picker's "+" carries an inline padding/margin that widens its hit area in a row; on a card it
   sits on the picture, so those give way here. */
.ex-grid .item>.tag{position:absolute;top:14px;inset-inline-start:14px}
.ex-grid .item:not(.ex-new)>.chev{position:absolute;top:14px;inset-inline-end:14px;width:32px;height:32px;margin:0 !important;padding:7px !important;border-radius:50%;background:var(--surface)}
.ex-grid .item>.btn{width:100%}
/* "Create your own exercise" stays a row across the top of the grid */
.ex-grid .item.ex-new{grid-column:1/-1;flex-direction:row;align-items:center;gap:12px;padding:10px 12px}
.ex-grid .item.ex-new .thumb{width:50px;height:50px;border-radius:9px}
.ex-grid .item.ex-new .thumb-x{font-size:21px}
/* The list/cards button (ExerciseViewToggle) at the end of the search field, as tall as it and
   dressed like it; pressed while the cards are on. */
.search-row{display:flex;gap:8px}
.search-row>.search{flex:1;min-width:0}
.search-row>.ex-view-btn{width:46px;height:auto;border-radius:10px;background:var(--surface-2);font-size:20px}
:root[data-theme="light"] .search-row>.ex-view-btn{background:var(--control-tint)}
.search-row>.ex-view-btn.on,:root[data-theme="light"] .search-row>.ex-view-btn.on{background:var(--control-tint);color:var(--ink)}

/* ---------------------------------------------------------------- chips -- */
.chips{
  display:flex;gap:7px;overflow-x:auto;padding:4px 4px 6px;   /* room for a chip's focus outline inside a sheet (#162) */
  scrollbar-width:none;
}
.chips::-webkit-scrollbar{display:none}
/* horizontal strips: keep a sideways overscroll from chaining to the page and leave a
   margin when a chip is scrolled into view. The chip row also claims the horizontal axis
   (touch-action:pan-x): on a phone a slightly diagonal swipe along the chips used to hand
   the gesture to the page, which scrolled down instead. The row is 32px tall, so losing a
   vertical scroll that happens to start on it costs nothing; the ~130px heatmap wrap keeps
   both axes, there the trade-off goes the other way. The chips contain both axes: once a
   strip is at its end, a diagonal drag must not chain into the page either. */
.chips,.hm-wrap{overscroll-behavior-x:contain;scroll-padding-inline:16px}
.chips{touch-action:pan-x;overscroll-behavior:contain}
/* The chip hit-area (.chip::before, inset:-6px) must not poke out of the strip vertically:
   overflow-x:auto makes overflow-y auto as well, and that 6px of positioned overflow gave
   the 32px row a 36px scroll height — a diagonal swipe, wheel or drag then scrolled the
   whole row up by 4px and left it there. Vertical slop is clipped by the strip anyway. */
.chips .chip::before{top:0;bottom:0}
.chip{
  flex:none;padding:6px 13px;border-radius:99px;background:var(--surface);
  font-size:14px;font-weight:400;color:var(--label);text-transform:capitalize;
  letter-spacing:-.006em;transition:background var(--fast),color var(--fast);
}
.chip:active{background:var(--surface-2)}
.chip.on{background:var(--ink);color:var(--on-ink);font-weight:500}
.chip.on .dim{color:color-mix(in srgb,var(--on-ink) 62%,transparent)}
.chip .qstate{text-transform:none}
/* On a phone these rows scroll by swipe. On a pointer device lib/hchips.js lets you
   click-drag anywhere on the row to pull it along; a grab cursor on rows that actually
   overflow (data-xscroll, set by hchips.js on hover) is the hint. */
@media (hover:hover) and (pointer:fine){
  .chips[data-xscroll]{cursor:grab}
}
/* while a drag is in flight: no text selection, grabbing cursor everywhere (the `*` rule
   outweighs button{cursor:pointer} so it holds even over a chip) */
body.chips-dragging{cursor:grabbing;user-select:none;-webkit-user-select:none}
body.chips-dragging *{cursor:inherit}

/* =========================== CONTROLS ==================================== */

/* --- text field --- */
.field,.input{
  width:100%;background:var(--surface);border:none;border-radius:var(--r);
  padding:13px 15px;font-size:17px;letter-spacing:-.012em;outline:none;
  transition:box-shadow var(--fast);
}
.field::placeholder,.input::placeholder{color:var(--label-3)}
.field:focus,.input:focus{box-shadow:inset 0 0 0 2px var(--ink)}
.field.area,textarea.input{min-height:92px;resize:vertical;line-height:1.42}
.measure-date{display:block;margin-bottom:14px}
.measure-date>span,.measure-field>span:first-child{display:block;color:var(--label-2);font-size:13px;margin:0 2px 6px}
.measure-date .field{background:var(--surface-2)}
.measure-form{display:grid;grid-template-columns:1fr 1fr;gap:11px 10px}
.measure-field{min-width:0}
.measure-input{height:47px;background:var(--surface-2);border-radius:var(--r);display:flex;align-items:center;padding:0 12px;gap:6px}
.measure-input .num{width:100%;min-width:0;background:transparent;border:0;outline:none;font-size:18px;font-weight:500;color:var(--label);padding:0}
.measure-input i{font-style:normal;color:var(--label-2);font-size:13px}
.measure-options{margin:12px 0 16px}
.measure-select{margin-bottom:10px;background:var(--surface-2)}
.measure-preview{display:flex;flex-wrap:wrap;gap:6px 12px;margin-top:11px;padding-top:10px;border-top:1px solid var(--sep);font-size:12px;color:var(--label-2)}
.measure-preview b{color:var(--label);font-weight:500}
.measure-home-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.measure-home-grid button{background:var(--surface-2);border-radius:10px;padding:10px;text-align:left;min-width:0}
.measure-home-grid span,.measure-home-grid i{display:block;font-size:11px;color:var(--label-2);font-style:normal;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.measure-home-grid b{display:block;font-size:16px;margin:3px 0;white-space:nowrap}
.measure-empty{width:100%;display:flex;align-items:center;justify-content:space-between;text-align:left;color:var(--label-2);font-size:13px;gap:10px}
.measure-empty .icn{flex:none}
.exnote{
  background:var(--surface);border-radius:var(--r);padding:13px 15px;
  line-height:1.45;white-space:pre-wrap;font-size:15px;margin-bottom:10px;color:var(--label-2);
}

/* --- search field --- */
.searchf{position:relative;display:flex;align-items:center}
.searchf .lead{
  position:absolute;inset-inline-start:11px;font-size:16px;color:var(--label-2);
  pointer-events:none;--icon-stroke:2.1;z-index:1;
}
.searchf .field{padding-inline-start:35px;padding-inline-end:36px;background:var(--surface-2);border-radius:10px}
:root[data-theme="light"] .searchf .field{background:var(--control-tint)}
.searchf .clear{
  position:absolute;inset-inline-end:8px;width:22px;height:22px;border-radius:50%;
  background:var(--label-3);color:var(--bg);display:flex;align-items:center;
  justify-content:center;font-size:11px;--icon-stroke:3;
}
/* legacy .search wrapper */
.search{position:relative}
.search .input{padding-inline-start:35px;background:var(--surface-2);border-radius:10px}
:root[data-theme="light"] .search .input{background:var(--control-tint)}
.search>svg{
  position:absolute;inset-inline-start:11px;top:50%;transform:translateY(-50%);z-index:1;
  width:16px;height:16px;stroke:var(--label-3);fill:none;stroke-width:2.1;stroke-linecap:round;
}
/* The live result count (Library and the exercise picker, from GitLab !31): a pill at the end
   of the field while a search or filter narrows the list. The field makes room for it only while
   it is there, so a long placeholder is not cut short for nothing. */
.search.has-count .input{padding-inline-end:62px}
.search .search-count{
  position:absolute;inset-inline-end:9px;top:50%;transform:translateY(-50%);
  font-size:12px;font-weight:600;line-height:1.4;color:var(--label-2);
  background:var(--surface-3);padding:2px 8px;border-radius:99px;
  font-variant-numeric:tabular-nums;pointer-events:none;user-select:none;
}
/* The × that empties the search (Library and the exercise picker), the same round button as
   SearchField's, at the end of the field; the count moves in beside it while both show. */
.search .clear{
  position:absolute;inset-inline-end:8px;top:50%;transform:translateY(-50%);z-index:1;
  width:22px;height:22px;border-radius:50%;
  background:var(--label-3);color:var(--bg);display:flex;align-items:center;
  justify-content:center;font-size:11px;--icon-stroke:3;
}
.search.has-clear .input{padding-inline-end:36px}
.search.has-count.has-clear .input{padding-inline-end:90px}
.search.has-clear .search-count{inset-inline-end:36px}

/* --- switch --- */
.sw{
  width:51px;height:31px;border-radius:99px;background:var(--surface-3);
  flex:none;padding:2px;display:flex;align-items:center;
  transition:background var(--med) var(--ease);
}
.sw .knob{
  width:27px;height:27px;border-radius:50%;background:#fff;
  box-shadow:0 3px 8px rgba(0,0,0,.15),0 1px 1px rgba(0,0,0,.16);
  transition:transform var(--med) var(--ease),width var(--fast) var(--ease);
}
.sw.on{background:var(--ink)}
/* On an accent nearly as light as the knob (an own white or pale yellow, the gold preset) the
   knob gets a hairline ring so it does not vanish into the track. lib/accent.js sets --knob-ring
   for an own colour; it is transparent everywhere else. */
.sw.on .knob{box-shadow:0 0 0 1px var(--knob-ring,transparent),0 3px 8px rgba(0,0,0,.15),0 1px 1px rgba(0,0,0,.16)}
.sw.on .knob{transform:translateX(20px)}
.sw:active .knob{width:31px}
.sw.on:active .knob{transform:translateX(16px)}
.sw:disabled{opacity:.4}

/* --- segmented control --- */
/* flex, not grid: an absolutely-positioned child of a GRID container is placed
   into a grid area, so the sliding thumb resolved top/bottom against the wrong
   box and overflowed the track. A flex container leaves abspos children on the
   padding box, which is what the thumb needs. */
.seg{
  position:relative;display:flex;
  background:var(--surface-3);border-radius:9px;padding:2px;isolation:isolate;
}
.seg>button{flex:1 1 0;min-width:0}
:root[data-theme="light"] .seg{background:var(--control-tint)}
.seg-sel{
  position:absolute;z-index:0;top:2px;bottom:2px;inset-inline-start:2px;
  width:calc((100% - 4px)/var(--n));
  transform:translateX(calc(100% * var(--i)));
  background:var(--surface);border-radius:7px;
  box-shadow:0 3px 8px rgba(0,0,0,.12),0 1px 1px rgba(0,0,0,.06);
  transition:transform var(--med) var(--ease);
}
:root[data-theme="light"] .seg-sel{background:#fff}
.seg button{
  position:relative;z-index:1;padding:6px 8px;font-size:14px;font-weight:500;
  letter-spacing:-.006em;color:var(--label);display:flex;align-items:center;
  justify-content:center;gap:5px;min-height:30px;transition:opacity var(--fast);
}
.seg button .icn{font-size:16px}
.seg button:not(.on){color:var(--label-2);font-weight:400}
.seg button:active{opacity:.5}
/* sitting in a list row: shrink to content instead of filling the row. The control never
   shrinks below its labels, so a row whose title and control do not both fit — most translated
   packs at 390px: "Übungs-Animationen" against "Voll · Klein · Aus" — wraps the control onto its
   own line under the title instead of painting it over the title. */
.seg-inline{flex:none;min-width:132px;max-width:100%;margin-inline-start:auto}
.lrow:has(.seg-inline){flex-wrap:wrap}
.lrow:has(.seg-inline) .lrow-m{min-width:min(150px,100%)}
.seg-range{margin-bottom:10px}
/* Every segment as wide as the widest label (QA 10-05: with flex:1 1 0 the track was sized by the
   labels' sum but split evenly, so "Compact" / "Versteckt" got less than its own width and
   touched the segment's edge). A grid of equal 1fr columns sizes each to the widest one, so the
   thumb (100%/n) still lines up; the sliding thumb is absolutely positioned with no grid
   placement, so its box is the track's padding box, as in the flex version. */
.seg-inline{display:grid;grid-auto-flow:column;grid-auto-columns:1fr}
.seg-inline button{padding:5px 12px;font-size:13px;min-height:28px}
.seg-inline button span{white-space:nowrap}
.seg-inline button .icn{font-size:14px}

/* native time input, restyled to sit in a row like a value label */
.timef{
  background:var(--surface-2);border:none;border-radius:8px;padding:6px 10px;
  font-size:16px;color:var(--label);outline:none;font-variant-numeric:tabular-nums;
}
/* A date or time field is as wide as the browser draws it and will not give way, and neither will
   the title beside it once that is down to its longest word: the Polish "Godzina rozpoczęcia" plus
   the clock leaves a 320px row 17px short, and the field then hangs over the edge of the card with
   its picker icon. Such a row wraps the field onto a line of its own under the title instead, still
   flush right — the same way a row carrying an inline segmented control does. */
.lrow:has(.timef){flex-wrap:wrap}
.lrow>.timef{margin-inline-start:auto}
.timef::-webkit-calendar-picker-indicator{filter:invert(.5)}
:root[data-theme="light"] .timef::-webkit-calendar-picker-indicator{filter:none}

/* --- stepper --- */
.stp-w{display:flex;flex-direction:column;gap:6px;min-width:0}
.stp-l{font-size:13px;color:var(--label-2);text-align:center}
.stp{
  display:flex;align-items:center;background:var(--surface-2);
  border-radius:10px;overflow:hidden;min-width:0;
}
.stp button{
  width:40px;height:44px;flex:none;color:var(--label);font-size:16px;
  display:flex;align-items:center;justify-content:center;
  transition:background var(--fast);--icon-stroke:2.2;
}
.stp button:active{background:var(--surface-3)}
.stp .val{
  flex:1;min-width:0;display:flex;align-items:baseline;justify-content:center;gap:3px;padding:0 2px;
  align-self:stretch;
}
.stp .val i{font-style:normal;font-size:12px;color:var(--label-2);flex:none}
.stp .num{
  width:100%;min-width:0;text-align:center;background:none;border:none;outline:none;
  font-size:17px;font-weight:500;letter-spacing:-.012em;padding:0;
  -moz-appearance:textfield;appearance:textfield;
  /* the field is the whole height of the stepper, not just its 18px text line, so a tap
     anywhere between the two buttons focuses it */
  height:100%;min-height:40px;cursor:text;
}
.stp .num::-webkit-inner-spin-button{display:none}
.stp.invalid{box-shadow:inset 0 0 0 1px var(--red)}

/* --- slider --- */
.sld{position:relative;height:32px;display:flex;align-items:center;cursor:pointer;touch-action:none}
.sld-track{
  position:absolute;inset-inline-start:0;inset-inline-end:0;height:6px;border-radius:99px;
  background:var(--surface-3);overflow:hidden;
}
.sld-fill{display:block;height:100%;background:var(--ink);border-radius:99px}
.sld-knob{
  position:absolute;width:26px;height:26px;border-radius:50%;background:#fff;
  transform:translateX(-50%);
  box-shadow:0 4px 10px rgba(0,0,0,.22),0 1px 2px rgba(0,0,0,.16);
  transition:transform var(--fast) var(--ease);
}
.sld.dragging .sld-knob{transform:translateX(-50%) scale(1.14)}

/* --- checkbox --- */
.chk,.ck{
  width:30px;height:30px;border-radius:50%;flex:none;position:relative;
  display:flex;align-items:center;justify-content:center;
  background:none;box-shadow:inset 0 0 0 1.8px var(--label-4);color:transparent;
  transition:background var(--fast),box-shadow var(--fast),color var(--fast),transform var(--fast);
}
.chk .icn{font-size:16px;--icon-stroke:2.6}
/* 30px is the right look next to a stepper but a poor target: extend the tap area to 44px
   without painting it; the left side stays shorter so the stepper's + button keeps its edge */
.chk::before,.ck::before{content:'';position:absolute;inset:-7px -7px -7px -4px}
.chk.on{background:var(--ink);box-shadow:none;color:var(--on-ink)}
.chk:active,.ck:active{transform:scale(.9)}
.ck svg{
  width:16px;height:16px;stroke:transparent;fill:none;stroke-width:2.6;
  stroke-linecap:round;stroke-linejoin:round;transition:stroke var(--fast);
}
.ck.on{background:var(--ink);box-shadow:none}
.ck.on svg{stroke:var(--on-ink)}

/* ------------------------------------------------------------- workout --- */
/* Workout header. In list mode it is pinned: pulled up over #app's top padding so it sits flush
   with the screen edge from the first pixel, and given the page's own ground plus a light blur so
   the rows scrolling underneath read as underneath. The connection indicator, when there is
   one, sits over its top (--conn) and its content starts below it. */
.whdr.stick{
  position:sticky;top:0;z-index:20;
  margin:calc(-1 * (var(--sat) + var(--conn) + 8px)) calc(-1 * var(--pad)) 6px;
  padding:calc(var(--sat) + var(--conn) + 8px) var(--pad) 0;
  background:color-mix(in srgb,var(--bg) 94%,transparent);
  -webkit-backdrop-filter:saturate(180%) blur(10px);backdrop-filter:saturate(180%) blur(10px);
}
.whdr.stick .hdr{margin-bottom:12px}
.whdr.stick .wprog{margin-bottom:10px}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .whdr.stick{background:var(--bg)}
}
/* The workout's own header (v1.3.11): ⌄ (or the editor's ✕), the name with the clock and set
   count, ⋯, and a labelled Finish pill. The name block takes what is left and truncates; the pill
   never shrinks. */
.hdr.whdr-bar{align-items:center;gap:8px;margin:4px 0 12px}
.whdr-mid{flex:1;min-width:0;text-align:center}
.whdr-name{font-weight:600;font-size:16px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* The clock and set count may take a second line: in ru/uk the count is the long half and a
   one-line ellipsis cut exactly the 0/19 the line is there for. */
.whdr-mid .sub{font-size:13px;margin-top:1px;font-variant-numeric:tabular-nums;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;overflow-wrap:anywhere;text-wrap:balance}
.btn.pill.whdr-finish{width:auto;flex:none;padding:8px 16px;border-radius:99px;font-size:15px;max-width:40%}
/* Animations set to Small: the picture beside the exercise name, with an expand badge. */
.wthumb{position:relative;flex:none;width:48px;height:48px;border-radius:10px;overflow:hidden;padding:0}
.wthumb .thumb{width:48px;height:48px;border-radius:10px}
.wthumb .thumb-x{background:var(--surface-3)}
.wthumb-x{
  position:absolute;inset-inline-end:3px;bottom:3px;width:16px;height:16px;border-radius:5px;
  display:flex;align-items:center;justify-content:center;font-size:10px;
  background:rgba(0,0,0,.55);color:#fff;--icon-stroke:2.4;
}
.exhd{align-items:center}
.wprog{height:4px;background:var(--surface-2);border-radius:99px;overflow:hidden;margin-bottom:16px}
.wprog i{display:block;height:100%;background:var(--done);border-radius:99px;transition:width var(--med) var(--ease)}
.exmedia{position:relative;border-radius:var(--r-lg);overflow:hidden;background:#fff;margin-bottom:12px}
.exmedia img{width:100%;height:320px;object-fit:contain;display:block}
.exmedia .gifhint,.exmedia .giftoggle{
  position:absolute;bottom:9px;display:inline-flex;align-items:center;gap:4px;
  background:rgba(0,0,0,.45);color:#fff;border-radius:99px;padding:5px 11px;
  font-size:12px;font-weight:500;
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
}
.exmedia .gifhint{inset-inline-end:9px}
.exmedia .giftoggle{inset-inline-start:9px}
.exmedia .gifhint .icn,.exmedia .giftoggle .icn{font-size:13px}
/* superset: both exercises are on screen together, so the animations have to give way —
   at 180px you had to scroll a full screen between two exercises done back-to-back */
.exmedia.compact img{height:120px}
.exmedia.mini img{height:84px}
/* both the animation and the still failed to load: a neutral tile instead of the browser's
   broken-image glyph; same heights as the picture so the card does not jump. tap retries. */
.exmedia.broken{background:var(--surface-2)}
.exmedia-x{width:100%;height:320px;display:flex;align-items:center;justify-content:center;color:var(--label-2);font-size:34px}
.exmedia.compact .exmedia-x{height:120px}
.exmedia.mini .exmedia-x{height:84px}
/* a custom exercise's own video (components/CustomMedia.jsx): the same box as a picture, on black
   so a clip that does not fill it is letterboxed like any player */
.exmedia video{width:100%;height:320px;object-fit:contain;display:block;background:#000}
.exmedia.compact video{height:120px}
.exmedia.mini video{height:84px}
.exmedia:has(> video){background:#000}
/* a catalogue animation: drawn on white, like the stills next to it */
.exmedia video.catvid,.exmedia:has(> video.catvid){background:#fff}

/* the link to a video or a guide (#246): a quiet action tile under the picture, or in its place.
   A <button>, so the reset of the browser's button look comes first. */
.exlink-card{
  display:flex;align-items:center;gap:12px;width:100%;text-align:start;font:inherit;border:0;
  background:var(--surface);border-radius:var(--r-card);
  padding:10px 14px;margin-bottom:12px;
  cursor:pointer;color:var(--label);
  transition:background var(--fast),transform var(--fast);
  user-select:none;-webkit-user-select:none;
}
.exlink-card:active{background:var(--surface-2);transform:scale(.98)}
.exlink-icon{
  width:34px;height:34px;border-radius:9px;
  display:flex;align-items:center;justify-content:center;
  background:var(--surface-2);color:var(--label);font-size:18px;flex:none;
}
.exlink-meta{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.exlink-title{
  font-size:15px;font-weight:500;color:var(--label);line-height:1.25;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
/* a host name reads left to right in every language; text-align keeps it on the reading side */
.exlink-sub{
  font-size:12px;color:var(--label-2);line-height:1.2;text-align:start;unicode-bidi:plaintext;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.exlink-arr{color:var(--label-2);font-size:14px;flex:none}
.exlink-card.mini{padding:6px 12px;gap:10px}
.exlink-card.mini .exlink-icon{width:28px;height:28px;font-size:15px;border-radius:7px}
.exlink-card.mini .exlink-title{font-size:13px}

/* the editor's field (components/CustomMediaField.jsx): the row, a 36px thumb of the draft, the
   buttons beside it, the notes under it and the link input */
.cmf{margin-top:8px}
.cmf .lrow{padding-inline:4px}
.cmf-act{display:flex;align-items:center;gap:6px;flex:none}
.cmf-thumb .thumb{width:36px;height:36px;border-radius:8px}
.cmf-thumb .thumb-x{font-size:16px}
.cmf-sub{display:inline-flex;align-items:center;gap:4px}
.cmf-sub .icn{font-size:13px}
.cmf-note{margin:0 4px 6px;line-height:1.35}
.cmf-link{margin-top:4px}
/* A logged workout's photos and videos (WorkoutMedia.jsx): a grid of posters with an Add tile,
   and the full-screen viewer they open in. Logical properties only, so RTL mirrors by itself. */
.wmedia{margin:4px 0 12px}
.wmedia-h{margin:0 0 6px}
.wmedia-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(72px,1fr));gap:8px}
.wmedia-item,.wmedia-add{
  position:relative;aspect-ratio:1;border:0;padding:0;border-radius:10px;overflow:hidden;
  background:var(--surface-2);color:var(--label-2);cursor:pointer;font:inherit;
}
.wmedia-item .thumb{width:100%;height:100%;border-radius:0;display:block}
.wmedia-item .thumb-x{font-size:22px}
.wmedia-kind{
  position:absolute;inset-inline-end:5px;bottom:5px;width:22px;height:22px;border-radius:99px;
  display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.55);color:#fff;font-size:12px;
}
.wmedia-add{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;
  color:var(--ink);font-size:11px;line-height:1.2;text-align:center;padding:6px;
  border:1.5px dashed var(--sep)}
.wmedia-add .icn{font-size:20px}
.wmedia-add:disabled{opacity:.5;cursor:default}
.wmedia-note{margin:6px 2px 0;line-height:1.35}
.wrow-media{display:inline-flex;align-items:center;gap:3px;font-size:12px;color:var(--label-2);flex:none}

.pp-selected{outline:3px solid var(--ink);outline-offset:-3px}
.pp-check{
  position:absolute;inset-inline-end:5px;top:5px;width:20px;height:20px;border-radius:99px;
  display:flex;align-items:center;justify-content:center;background:var(--ink);color:var(--on-ink);font-size:11px;
}
.pp-cta{position:sticky;bottom:calc(var(--sab) + 10px);display:flex;justify-content:center;margin-top:14px}
.pp-compare{position:relative;flex:1;min-height:0;overflow:hidden;background:#000;touch-action:none}
.pp-img{
  position:absolute;inset:0;width:100%;height:100%;object-fit:contain;background:#000;
  -webkit-user-select:none;user-select:none;
}
.pp-handle{
  position:absolute;inset-block:0;transform:translateX(-50%);width:0;
  display:flex;align-items:center;justify-content:center;pointer-events:none;
}
.pp-handle::before{content:'';position:absolute;inset-block:0;width:2px;background:#fff;box-shadow:0 0 0 1px rgba(0,0,0,.3)}
.pp-grip{width:36px;height:36px;border-radius:99px;background:#fff;box-shadow:0 1px 6px rgba(0,0,0,.4)}
.pp-label{
  position:absolute;bottom:14px;font-size:12px;font-weight:600;color:#fff;
  background:rgba(0,0,0,.55);padding:4px 9px;border-radius:99px;pointer-events:none;
}
.pp-label-before{inset-inline-start:10px}
.pp-label-after{inset-inline-end:10px}
.wrow-media .icn{font-size:13px}
.mviewer{
  position:absolute;inset:0;background:#000;color:#fff;display:flex;flex-direction:column;
  padding:var(--sat) 0 var(--sab);animation:pop-fade .2s var(--ease);
}
@keyframes pop-fade{from{opacity:0}to{opacity:1}}
.mviewer-bar{display:flex;align-items:center;justify-content:space-between;padding:6px 8px;flex:none}
.mviewer .iconbtn{color:#fff;background:rgba(255,255,255,.12)}
.mviewer-count{font-size:14px;font-variant-numeric:tabular-nums;opacity:.85}
.mviewer-stage{flex:1;min-height:0;display:flex}
.exmedia.viewer{flex:1;min-width:0;margin:0;border-radius:0;background:#000;display:flex;align-items:center;justify-content:center}
.exmedia.viewer img,.exmedia.viewer video{width:100%;height:100%;max-height:100%;object-fit:contain;background:#000}
.exmedia.viewer .exmedia-x{height:100%;color:rgba(255,255,255,.5)}
.mviewer-nav{display:flex;justify-content:space-between;padding:8px 12px;flex:none}
[dir="rtl"] .mviewer-nav .icn{transform:scaleX(-1)}
.mviewer-ask{flex:none;padding:12px 16px;background:rgba(255,255,255,.08)}
.mviewer-ask-t{font-weight:600;margin-bottom:10px}
.mviewer-ask-b{display:flex;gap:8px;justify-content:flex-end}

.sethead{
  display:flex;align-items:center;gap:8px;padding:0 0 6px;
  font-size:11px;color:var(--label-2);font-weight:500;text-transform:uppercase;letter-spacing:.045em;
}
.sethead .n-sp{width:24px;flex:none}
.sethead .w-sp{flex:1.4;text-align:center}
.sethead .r-sp{flex:1;text-align:center}
.sethead .eff-sp{text-align:center}
.sethead .ck-sp{width:30px;flex:none}
.setrow{display:flex;align-items:center;gap:8px;padding:7px 0;position:relative}
.setrow+.setrow::before{
  content:'';position:absolute;inset-inline-start:32px;inset-inline-end:0;top:0;height:var(--hair);background:var(--sep);
}
.setph{margin:8px 0 2px;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--dim);display:flex;align-items:center;gap:10px}
.setph::after{content:'';flex:1;height:1px;background:var(--sep)}
.setsep{height:1px;background:var(--sep);margin:9px 0}
/* the per-side wrapper carries its own .n (the set number in front of the L/R rows) */
.setrow .n,.setrow-side>.n{
  width:24px;height:24px;border-radius:50%;background:var(--surface-2);color:var(--label-2);
  display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:500;flex:none;
  position:relative;padding:0;border:0;font-family:inherit;cursor:pointer;
  transition:background var(--fast),color var(--fast);
}
.setrow .stp.w{flex:1.4;min-width:0}
.setrow .stp.r{flex:1;min-width:0}
/* The number outranks the buttons in every set row, not only the ones with an effort column
   that #235 covered: a 320 px phone left 0–6 px for the reps number and showed 102.5 as "102",
   and the cardio row's 10.5 km/h read "10" at 368 px (QA C2, C21, C24). The field reserves the
   widest value it shows at its font — "227.5" kg, "100" reps or "10.5" km/h (`--num`, incl.
   the field's 4 px padding and 2 px against font rounding) — and the two buttons give up width
   first, down to an 18 px floor, before anything is clipped. The cell itself is never narrower
   than number + two floors, so the row's flex hands a starving cell width from the others
   instead of clipping its buttons. */
.setrow .stp button{width:32px;height:40px}
/* Only the weight/reps buttons: `.effcell-stp` is a `.stp` too, and its value is a `<button>`,
   so a rule on `.setrow .stp button` would outrank `.effcell-stp .val` and stop the value from
   filling the cell (it bunched left with dead space next to it at desktop widths). */
.setrow .stp.w button,.setrow .stp.r button{flex:0 1 auto;min-width:var(--btn-floor)}
.setrow .stp.w,.sethead .w-sp{--num:48px}
.setrow .stp.r,.sethead .r-sp{--num:39px}
.setrow .stp.w,.setrow .stp.r,.sethead .w-sp,.sethead .r-sp{--btn-floor:18px;min-width:calc(var(--num) + 2*var(--btn-floor))}
/* no buttons (Workout controls → steppers off): the number alone is the floor. The header
   carries the same `plain` so its columns freeze where the cells do. */
.setrow .stp.plain,.sethead.plain .w-sp,.sethead.plain .r-sp{--btn-floor:0px}
.setrow .stp.w .val,.setrow .stp.r .val{min-width:var(--num)}
/* A timed hold logs the seconds in the first column and the load in the second, so the two
   columns swap roles: the load carries "227.5" and needs the wider reserve and the bigger share,
   the seconds column "120". Without the swap the load input was 35 px for a 41.7 px "102.5" at
   368 and 412 px — "102.5 kg" read "102.!" — while the seconds column sat on 67 px for "120". */
.setrow.timed .stp.w,.sethead.timed .w-sp{flex:1;--num:39px}
.setrow.timed .stp.r,.sethead.timed .r-sp{flex:1.4;--num:48px}
/* The effort column is a single tap-to-pick button, not a stepper. It is a direct flex child
   of the row (like the .stp cells), carrying its own column width via flex. `align-self` and
   a fixed height stop the row from stretching it taller than the weight/reps cells; it is NOT
   inside `.stp`, so the stepper's 32px fixed button width (which wrapped "RIR") never applies. */
/* flex-basis:0 so the button's width comes from its flex share, not its text, and the column
   never jumps between an empty "RIR" and a logged "2". The unrated state uses `.is-empty`, not
   the generic `.empty` (which is a full-page empty-state with 44px padding — sharing that name
   inflated the cell to ~90px). */
.setrow .effcell,.sethead .eff-sp{flex:.8 1 0;min-width:0}
/* The whole effort column — empty cell, logged cell and header label alike, so the row does not
   jump when a rating is added and the label does not drift — never goes below what the logged
   stepper needs at its floor: 28 px value + two 16 px buttons + the 1.5 px borders. The row's
   flex hands the difference back to weight and reps, whose own buttons shrink for it. */
.setrow .effcell,.setrow .effcell-stp,.setrow.eff3 .effcell-stp,.sethead .eff-sp{min-width:64px}
.effcell{
  box-sizing:border-box;height:44px;border-radius:10px;
  background:var(--surface-2);border:1.5px solid transparent;
  color:var(--label);font-size:15px;font-weight:600;letter-spacing:-.01em;
  font-variant-numeric:tabular-nums;white-space:nowrap;line-height:1;
  display:flex;align-items:center;justify-content:center;
  transition:background var(--fast),transform var(--fast),border-color var(--fast);
}
.effcell:active{transform:scale(.94)}
.effcell.is-empty{color:var(--label-2);font-weight:500;font-size:12px;letter-spacing:.02em}
/* a logged rating becomes a −/value/+ stepper, tinted by its effort band: the band colour
   fills the cell at low opacity (set inline via color-mix) and borders it; the value uses ink.
   the +/− buttons step 0.5 on the profile's scale; the value opens the picker. it carries the
   same column flex as the plain .effcell so the row does not jump when a rating is added. */
.setrow .effcell-stp,.setrow.eff3 .effcell-stp{
  height:44px;border-radius:10px;border:1.5px solid transparent;
  transition:background var(--fast),border-color var(--fast);
}
.effcell-stp button{color:inherit}
.effcell-stp>button[aria-label="Decrease"],
.effcell-stp>button[aria-label="Increase"]{width:26px;height:44px;font-size:15px;opacity:.85;flex:0 1 auto;min-width:16px}
/* the value is the tap target for the picker, so it keeps a 28 px finger's width for "8.5" and
   the −/+ shrink first — on a 368 px phone it had collapsed to 4 px under its own digits, and a
   tap on the number stepped the rating instead of opening the picker (QA C22) */
.effcell-stp .val{
  flex:1;min-width:28px;display:flex;align-items:center;justify-content:center;
  font-size:15px;font-weight:600;letter-spacing:-.01em;
  font-variant-numeric:tabular-nums;line-height:1;align-self:stretch;color:inherit;
}
.effcell-stp .val:active{background:var(--surface-3)}
/* the effort cell needs less room now (one short value, no +/- buttons), so weight/reps keep
   more of the row on narrow phones than they did when three steppers had to share it */
.setrow .effcell-stp,.setrow.eff3 .effcell-stp{flex:.8 1 0}
.setrow.eff3 .effcell-stp{flex:.7 1 0}
.setrow.eff3,.sethead.eff3{gap:6px}
.setrow.eff3 .stp.w,.sethead.eff3 .w-sp{flex:1.4}
.setrow.eff3 .stp.r,.sethead.eff3 .r-sp{flex:1.1}
.setrow.eff3 .effcell,.sethead.eff3 .eff-sp{flex:.7 1 0}
.setrow.eff3 .stp.w button,.setrow.eff3 .stp.r button{width:26px}
.setrow.eff3 .stp .num{font-size:16px}
/* the same reserved widths as a plain row's, at the smaller font */
.setrow.eff3 .stp.w,.sethead.eff3 .w-sp{--num:41px}
.setrow.eff3 .stp.r,.sethead.eff3 .r-sp{--num:30px}
.setrow.eff3 .effcell-stp>button[aria-label="Decrease"],
.setrow.eff3 .effcell-stp>button[aria-label="Increase"]{width:22px}
.setrow.eff3 .effcell-stp .val{font-size:14px}
/* effort quick picker sheet: colour-coded preset buttons, hardest (purple) first */
/* effort picker: the ⋯-menu list with the value in the icon square, tinted per band; the
   exact-value row carries the same stepper as the logged cell in the set row. */
.effpick.menu-list .menu-item .effpick-n{
  background:color-mix(in srgb,var(--bc) 20%,var(--surface));color:var(--text);font-size:13px;font-weight:700;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;
}
.effpick .menu-item.on{background:color-mix(in srgb,var(--bc) 14%,var(--surface))}
.effpick .menu-on.is-on{color:var(--bc)}
.effpick .effpick-free{padding-inline-end:8px}
.effpick .effpick-free .stp{flex:none;width:148px}
.effpick .effpick-free .stp .num{font-size:17px;font-weight:600}
.effpick .effpick-free .stp .num::placeholder{color:var(--label-3);font-weight:500}
.setrow.done .n{background:var(--done);color:var(--on-ink)}
.setrow.done{opacity:.45}

/* Swipe on sets (v1.3.11, components/SwipeRow.jsx). The row slides over two panes: Copy at the
   start of the line, Delete at its end, each as wide as the swipe has gone and zero wide at rest.
   pan-y leaves vertical scroll to the browser and hands sideways moves to the row. */
.swrow{position:relative;overflow:hidden;border-radius:10px;touch-action:pan-y;-webkit-touch-callout:none}
.swrow.dragging{-webkit-user-select:none;user-select:none}
/* Plan's lists (v1.3.11): the row is a whole .item card, so the swipe clips to the card's corners */
.swrow.swrow-item{border-radius:var(--r-card)}
.swfront{position:relative;z-index:1;background:var(--surface)}
/* Its own layer only while it moves: on every row it was a layer per set (#431). */
.swrow.dragging .swfront,.swrow.go-del .swfront,.swrow.go-cp .swfront{will-change:transform}
.swpane{position:absolute;top:0;bottom:0;width:0;overflow:hidden;z-index:0}
.swpane.del{inset-inline-end:0;background:color-mix(in srgb,var(--red) 22%,var(--surface))}
.swpane.cp{inset-inline-start:0;background:var(--control-tint)}
.swpane button{position:absolute;top:0;bottom:0;width:76px;padding:0;color:#fff;transition:width .16s var(--ease)}
.swpane.del button{inset-inline-end:0;background:var(--red)}
.swpane.cp button{inset-inline-start:0;background:var(--ink);color:var(--on-ink)}
.swpane.armed button{width:100%}
.swpane .lab{position:absolute;top:0;bottom:0;width:76px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;font-size:12px}
.swpane.del .lab{inset-inline-start:0}
.swpane.cp .lab{inset-inline-end:0}
.swpane .lab .icn{font-size:21px;transform:scale(.8);transition:transform .16s var(--ease)}
.swpane .lab b{font-weight:500}
.swpane.armed .lab .icn{transform:scale(1)}
.swpane.armed .lab b{font-weight:800}
/* The last set cannot go: the delete side shows grey and never fills. */
.swpane.del.dis{background:var(--surface-2)}
.swpane.del.dis button{background:var(--surface-3);color:var(--label-3)}
.swpane.del.dis.armed button{width:76px}
.swrow.flash .swfront{animation:swflash .4s ease}
@keyframes swflash{0%,35%{background:color-mix(in srgb,var(--ink) 28%,var(--surface))}100%{background:var(--surface)}}
.swrow.flash-red .swfront{animation:swflashr .5s ease}
@keyframes swflashr{0%,35%{background:color-mix(in srgb,var(--red) 22%,var(--surface))}100%{background:var(--surface)}}
/* The first-use hint under the row it nudged. */
.swhint{display:flex;justify-content:center;padding:4px 0 6px}
.swhint button{display:inline-flex;align-items:center;gap:8px;background:var(--control-tint);color:var(--ink);border-radius:99px;padding:7px 12px;font-size:13px;font-weight:600;animation:swhintin .3s var(--ease);text-align:start}
.swhint .icn{font-size:15px;flex:none}
.swhint .icn:last-child{opacity:.7}
@keyframes swhintin{from{opacity:0;transform:translateY(-4px)}}
.vh{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* one-sided (unilateral) sets (issue #60): the set number sits beside a two-row L/R stack, each
   side its own weight/reps/effort + done tick. The two inner rows reuse .setrow so their columns
   line up with the header exactly like a straight set — only the leading .n circle is replaced by
   a small L/R badge of the same width. */
.setrow-side{display:flex;align-items:center;gap:8px;padding:4px 0;position:relative}
.setrow-side+.setrow-side::before{content:'';position:absolute;inset-inline-start:32px;inset-inline-end:0;top:0;height:var(--hair);background:var(--sep)}
.setrow-side>.n{align-self:center}
.setrow-side .side-rows{flex:1;min-width:0;display:flex;flex-direction:column}
/* inner side rows: no leading number circle (the badge takes its place), no top hairline between
   the two sides of the same set — they read as one unit. */
.setrow-side .setrow.side{padding:4px 0}
.setrow-side .setrow.side+.setrow.side::before{display:none}
.sidetag{
  width:24px;height:24px;border-radius:8px;background:var(--surface-2);color:var(--label-2);
  display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;flex:none;
}
/* A one-sided row with an effort column is the tightest line in the app: set number, L/R badge,
   two steppers, effort, tick. On a narrow phone the reps stepper's two buttons took all of its
   width and the number between them was gone (issue #235, 368 px). The number outranks the
   buttons here: slimmer buttons, tighter gaps, and reps gets the same share as the weight. */
.setrow-side .setrow.side.eff3{gap:4px}
.setrow-side .setrow.side.eff3 .stp.r{flex:1.4}
.setrow-side .setrow.side.eff3 .effcell,.setrow-side .setrow.side.eff3 .effcell-stp{flex:.6 1 0}
.setrow-side .setrow.side.eff3 .stp.w button,.setrow-side .setrow.side.eff3 .stp.r button{width:20px}
/* The header is laid out like a straight row, but in front of an L/R row's weight cell sit the
   set number, its gap AND the side badge, so over per-side rows the labels stood 17–23 px left
   of their cells (QA C5). `.per-side` (set by Workout.jsx) widens the number slot by the badge
   and takes the badge's gap as its own, so header and rows share one column track; with an
   effort column it also mirrors the side rows' own shares (reps 1.4, effort .6). */
.sethead.per-side .n-sp{width:56px}
.sethead.per-side.eff3{gap:4px}
.sethead.per-side.eff3 .r-sp{flex:1.4}
.sethead.per-side.eff3 .eff-sp{flex:.6 1 0}
@media (max-width:400px){
  /* the same squeeze on a plain row, where the list view's own inset costs the last pixels */
  .setrow.eff3 .stp.w button,.setrow.eff3 .stp.r button{width:21px}
  .setrow.eff3 .stp.r,.sethead.eff3 .r-sp{flex:1.25}
  .setrow-side{gap:5px}
  /* and on every L/R row, with or without an effort column — the default profile (no effort,
     buttons on) lost the per-side reps number the same way at 320 and 368 px (QA C2, C3) */
  .setrow-side .setrow.side{gap:4px}
  .setrow-side .setrow.side .sidetag{width:20px}
  .setrow-side .setrow.side .stp .num{font-size:16px}
  .setrow-side .setrow.side .stp.w,.sethead.per-side .w-sp{--num:41px}
  .setrow-side .setrow.side .stp.r,.sethead.per-side .r-sp{--num:30px}
  .setrow-side .side-rows .setrow.side .stp.w button,.setrow-side .side-rows .setrow.side .stp.r button{width:18px}
  /* number 24 + gap 5 + badge 20; the row's 4 px gap is the header's too */
  .sethead.per-side{gap:4px}
  .sethead.per-side .n-sp{width:49px}
}
/* The effort column steps down twice on the way to a narrow screen, not once. Its −/+ are gone
   below 360 px (see the 359 px query), and from 366 px an L/R row carries them at full size in a
   sets card two insets deep — in a list unit, or in a superset card. In between it could do
   neither: the 64 px the pill needs for a 28 px value and two 16 px button floors left the row
   6, 5, 4, 3, 2 and 1 px wider than its card's content box at 360–365 px, so its done tick sat
   in the card's side padding. The −/+ give way there too, to a 12 px floor — they are what the
   cell sheds first, a pixel further down they go altogether — and the row keeps everything that
   carries meaning: the rating stays a 28 px tap target, the weight and reps columns keep their
   numbers, their buttons and their floors, and the header keeps its single line ("WEIGHT (KG)"
   has 1.5 px to spare in a 77 px column and would wrap if the weight column paid instead).
   An L/R row in a superset in the list view has no −/+ to shrink below 430 px; the rule for it
   below is more specific and keeps the cell at 34 px. */
@media (min-width:360px) and (max-width:365px){
  .setrow.side .effcell,.setrow.side .effcell-stp,.sethead.per-side .eff-sp{min-width:56px}
  .setrow.side .effcell-stp>button[aria-label="Decrease"],
  .setrow.side .effcell-stp>button[aria-label="Increase"]{min-width:12px}
}
/* An L/R row with an effort column inside a superset in the list view sits behind three insets
   (unit, superset card, sets card). It used to drop the RIR −/+ here and hand the width to an
   oversized weight cell — but the rating is the field you reach for most on a unilateral set, so
   it keeps the same −/+ stepper a normal row has, just shrunk, and the weight cell pays for it
   instead. The effort cell reserves its 28 px value plus two 12 px button floors (≈54 px); the
   weight column gives up the matching width (a per-side weight is one limb's load, so its 48 px
   reserve was generous), so the row's total is unchanged and everything still fits at 412 px. */
@media (max-width:429px){
  .wl-unit .ss-card .setrow.side .effcell-stp>button[aria-label="Decrease"],
  .wl-unit .ss-card .setrow.side .effcell-stp>button[aria-label="Increase"]{min-width:12px}
  .wl-unit .ss-card .setrow.side .effcell,.wl-unit .ss-card .setrow.side .effcell-stp,.wl-unit .ss-card .sethead.per-side .eff-sp{min-width:54px}
  /* reclaim the +/-'s room from the weight column: a slimmer number reserve and tighter button
     floors, the same shape the 320 px step-down below already gives weight on these rows */
  .wl-unit .ss-card .setrow.side.eff3 .stp.w:not(.plain),.wl-unit .ss-card .sethead.per-side.eff3:not(.plain) .w-sp{--btn-floor:12px}
  .wl-unit .ss-card .setrow.side.eff3 .stp.w,.wl-unit .ss-card .sethead.per-side.eff3 .w-sp{--num:33px}
  .wl-unit .ss-card .setrow.side.eff3 .stp.w button{width:18px}
}
/* Below 360 px a row with an effort column cannot hold three numbers and six buttons: with the
   set number, tick and gaps gone a card leaves ~178 px, and 102.5 / 12 / 8.5 at their floors need
   ~197. The effort −/+ give way there on every row — the value stays (26 px for "8.5" plus the
   border), still opens the picker on tap, and the picker's exact row steps in halves as before;
   weight and reps keep their buttons. */
@media (max-width:359px){
  .setrow .effcell-stp>button[aria-label="Decrease"],.setrow .effcell-stp>button[aria-label="Increase"]{display:none}
  .setrow .effcell,.setrow .effcell-stp,.setrow.eff3 .effcell-stp,.sethead .eff-sp,
  .wl-unit .ss-card .setrow.side .effcell,.wl-unit .ss-card .setrow.side .effcell-stp,.wl-unit .ss-card .sethead.per-side .eff-sp{min-width:29px}
  .setrow .effcell-stp .val{min-width:26px}
  /* an L/R row with an effort column is still over by 14 px in a card at 320 px (badge 20, 77 + 66 +
     29 for the three cells, tick 30, four gaps): one notch further there — 16 px button floors
     and a 13 px number — and it fits with two pixels to spare. Not with the buttons off (`plain`),
     where the number alone is the floor. */
  .setrow-side .setrow.side.eff3 .stp.w:not(.plain),.setrow-side .setrow.side.eff3 .stp.r:not(.plain),.sethead.per-side.eff3:not(.plain) .w-sp,.sethead.per-side.eff3:not(.plain) .r-sp{--btn-floor:16px}
  .setrow-side .setrow.side.eff3 .stp .num{font-size:16px}
  .setrow-side .setrow.side.eff3 .stp.w,.sethead.per-side.eff3 .w-sp{--num:38px}
  .setrow-side .setrow.side.eff3 .stp.r,.sethead.per-side.eff3 .r-sp{--num:28px}
  /* A weighted timed hold has one control more than a straight row (the play button before the
     tick) and was 15 px over at 320 px with the full-size floors: seconds ("120") and the load
     ("102.5") at the 14 px size and 16 px button floors, as an effort row does. */
  .setrow.timed .stp .num{font-size:16px}
  .setrow.timed .stp.w,.sethead.timed .w-sp{--num:30px}
  .setrow.timed .stp.r,.sethead.timed .r-sp{--num:41px}
  .setrow.timed .stp.w:not(.plain),.setrow.timed .stp.r:not(.plain),.sethead.timed:not(.plain) .w-sp,.sethead.timed:not(.plain) .r-sp{--btn-floor:16px}
}
.setrow.side.done .sidetag{background:var(--done-tint);color:var(--done-fg)}
.setrow.side.done{opacity:.45}

/* drop-set drops / rest-pause bursts riding on a work row, editable like the row itself
   (issue: drop-sets & rest-pause) */
.subrow{display:flex;align-items:center;gap:6px;padding-block:3px;padding-inline:32px 0}
/* Under an L/R row the set number already sits outside the .side-rows box, so the indent that
   tucks a straight row's drops under its number would be paid twice — at 320 px both number
   fields of a per-side drop collapsed to 0 px (QA C3). The label starts under the badge instead. */
.setrow-side .side-rows .subrow{padding-inline-start:0}
.subrow .subn{font-size:11px;color:var(--label-2);flex:none;width:46px}
/* the number outranks the buttons here as in the row above: room for "227.5" (a drop's weight)
   or "100" (the second mini is always reps) at 13 px, and the buttons shrink to 16 px first */
.subrow .stp.mini{flex:1;--num:38px;min-width:calc(var(--num) + 32px)}
.subrow .stp.mini+.stp.mini{--num:28px}
.subrow .stp.mini button{width:26px;height:30px;flex:0 1 auto;min-width:16px}
.subrow .stp.mini .val{min-width:var(--num)}
.subrow .stp.mini .num{font-size:16px;min-height:30px}
.subrow .iconbtn{width:26px;height:26px;font-size:11px;flex:none}
/* label 46, two minis at their floors 70 + 60, the ✕ and three gaps: 252 px with the indent — the
   whole row at 320 px. The label starts under the number circle's inner edge there instead. */
@media (max-width:359px){
  .subrow,.plateline{padding-inline-start:24px}
}
/* Plate line under a set row (Workout.jsx loadLine): the stack for this row's weight, what is
   missing from the inventory, and what to strip/add from the row above. */
.plateline{display:flex;align-items:center;gap:6px;padding-block:0 5px;padding-inline:32px 0;font-size:12px;color:var(--dim);line-height:1.3}
.plateline .icn{font-size:12px;flex:none;opacity:.8}
.plateline .short{color:var(--warning-fg)}
.plateline .moves{margin-inline-start:auto;color:var(--label-2);font-variant-numeric:tabular-nums;white-space:nowrap}
/* The number is the set's menu (drop / burst / remove); a 24px circle needs a finger-sized hit area. */
.setrow .n::before{content:'';position:absolute;inset:-10px}
/* A set taken to failure: a small "F" on the number's corner, in the colour the effort scale
   gives "nothing left" (effort.js EFFORT_BANDS). */
.setrow .n .failmark,.setrow-side>.n .failmark{position:absolute;top:-5px;inset-inline-end:-6px;min-width:13px;height:13px;padding:0 2px;border-radius:7px;background:var(--danger-tint);color:var(--danger-fg);font-size:9px;font-weight:700;line-height:13px;text-align:center;pointer-events:none}
/* No +/- buttons: the number field takes the whole cell and is the tap target. */
.stp.plain{grid-template-columns:1fr}
.stp.plain .val{width:100%}
.stp.plain .num{width:100%;text-align:center}
/* --- menu sheet (the workout's "more" menus) --- */
.menu-list .menu-item{min-height:52px;padding:8px 12px}
.menu-list .menu-item .lrow-i{width:32px;height:32px;font-size:16px;background:var(--surface-2);color:var(--label)}
.menu-list .menu-item.danger .tt,.menu-list .menu-item.danger .lrow-i{color:var(--danger-fg)}
.menu-list .menu-item.disabled{opacity:.4;pointer-events:none}
.menu-on{color:transparent;font-size:16px;flex:none}
.menu-on.is-on{color:var(--ink)}
/* A grouped menu (menuSheet's `sections`): groups sit apart, each with a small header, so a long
   list reads as four short ones. */
.menu-group.grouped+.menu-group.grouped{margin-top:14px}
.menu-group.grouped .menu-list{gap:0;background:var(--surface);border-radius:var(--r-card);overflow:hidden}
.menu-group.grouped .menu-item{border-radius:0;position:relative}
.menu-group.grouped .menu-item+.menu-item::before{
  content:'';position:absolute;top:0;inset-inline-start:56px;inset-inline-end:0;height:var(--hair);background:var(--sep-op);
}
.menu-sec{font-size:13px;font-weight:600;color:var(--label-2);padding:0 6px 6px;letter-spacing:.005em}
.menu-list .menu-item.accent .lrow-i{background:var(--ink);color:var(--on-ink)}
.menu-chev{color:var(--label-2);font-size:14px;flex:none}
[dir="rtl"] .menu-chev{transform:scaleX(-1)}
.setextra{display:flex;flex-wrap:wrap;gap:6px;margin:2px 0 8px 32px}
.setextra .chip.add{display:inline-flex;align-items:center;gap:4px;color:var(--ink)}
.setextra .chip.add svg{width:13px;height:13px}
.setextra .chip.add:disabled{opacity:.35}
/* why the next target is what it is (issue #17) */
.progline{
  width:100%;display:flex;align-items:flex-start;gap:7px;margin:6px 0 2px;padding:0;
  text-align: start;font-size:13px;line-height:1.38;color:var(--ink);
}
.progline.warn{color:var(--warning-fg)}
.progline svg{flex:none;margin-top:2px}
/* "Last time" / "Best set" under the plan line (#173): a button that switches between the two,
   looking like the plain line it replaced, with a small icon to say it can be tapped. */
.refline{width:100%;display:flex;align-items:flex-start;gap:6px;margin-bottom:4px;padding:0;text-align:start}
.refline svg{flex:none;margin-top:2px;font-size:12px}
/* an exercise kept out of progression for this session, with its undo */
.noprog{display:flex;align-items:center;gap:7px;margin:0 0 6px;font-size:13px;line-height:1.38;color:var(--warning-fg)}
.noprog svg{flex:none}
.noprog .chip{margin-inline-start:auto;padding:3px 11px;font-size:13px;color:var(--warning-fg);background:color-mix(in srgb,var(--orange) 14%,transparent)}

/* start a timed set (issue #16) — sits where you'd otherwise reach for the checkbox */
.setrow .setgo{
  width:30px;height:30px;border-radius:50%;flex:none;
  display:flex;align-items:center;justify-content:center;
  background:var(--surface-2);color:var(--ink);font-size:14px;
  transition:background var(--fast),opacity var(--fast);
}
.setrow .setgo:disabled{opacity:.3;cursor:default}
.setrow .setgo:not(:disabled):active{background:var(--surface-3)}
/* exercise-config sheet: three steppers side by side on narrow phones */
.cfgrow{gap:8px}
.cfgrow>div{flex:1;min-width:0}
.cfgrow .stp button{width:30px}
.cfgrow .stp-l{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* The double-progression row holds four (Step / Reps from / Reps up to / Deload 1RM). Each stepper
   already spends 64px on its two buttons, so four abreast left the input 1px at 320 and 13px at
   368 — "1.25" showed as "1.2", "90" as "9(". Below 480px the row wraps into two pairs instead;
   from there up four abreast still leaves the input 40px or more. The basis is half the row minus
   half the gap, so each line takes exactly two. */
@media (max-width:479px){
  .cfgrow.cfgrow-4{flex-wrap:wrap}
  .cfgrow.cfgrow-4>div{flex-basis:calc(50% - 4px)}
}

/* --- rest timer --- */
/* One row: the clock (a button, tap to set the time left), then the controls; the progress is a
   thin line along the top edge, so it takes no width from them. On the workout screen, which has
   no tab bar (body.no-tabbar, App.jsx), the bar is docked to the bottom edge; anywhere else it
   sits just above the tab bar. */
#timer{
  position:fixed;inset-inline-start:12px;inset-inline-end:12px;bottom:calc(88px + var(--sab));z-index:60;
  /* nearly opaque: the set rows underneath were reading through the old 82% and made the
     clock hard to pick out mid-set. The blur stays, so it still sits above the page. */
  background:color-mix(in srgb,var(--surface) 97%,transparent);
  -webkit-backdrop-filter:saturate(180%) blur(10px);backdrop-filter:saturate(180%) blur(10px);
  border-radius:var(--r-lg);padding:12px 12px 10px;overflow:hidden;
  display:flex;align-items:center;gap:10px;
  box-shadow:var(--glass-elevation);
  animation:slideup var(--med) var(--ease);
}
@keyframes slideup{from{transform:translateY(16px);opacity:0}to{transform:none;opacity:1}}
#timer .bar{position:absolute;top:0;inset-inline-start:0;inset-inline-end:0;height:3px;background:var(--surface-3)}
#timer .bar i{display:block;height:100%;background:var(--ink);transition:width 1s linear}
/* The clock is what the bar is for, so it never gives up width: the buttons do (Skip is the one that
   gives: in a long language on a narrow phone it becomes an icon, RestTimer.jsx useSkipFits). The label under the
   clock fills the clock's width but does not widen it. */
#timer .tclock{flex:none;min-width:0;display:flex;flex-direction:column;align-items:flex-start;text-align:start;padding:2px 0}
#timer .t{font-size:28px;font-weight:600;line-height:1.1;letter-spacing:-.026em;font-variant-numeric:tabular-nums;white-space:nowrap}
/* The rest clock is as wide as the wider of its two faces, the time and Ready: the face not
   showing sits in a hidden zero-height line (data-alt), so turning Ready does not move the
   buttons beside it. */
#timer.rest .t{display:flex;flex-direction:column}
#timer.rest .t::after{content:attr(data-alt);height:0;overflow:hidden;visibility:hidden}
#timer .lbl{
  font-size:12px;color:var(--label-2);width:0;min-width:100%;margin-top:1px;
  display:inline-flex;align-items:center;gap:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
#timer .lbl .icn{font-size:10px;flex:none;opacity:.8}
#timer .acts{display:flex;align-items:center;justify-content:flex-end;gap:6px;flex:1 1 auto;min-width:0}
#timer .acts .btn{padding-top:11px;padding-bottom:11px}   /* sweaty hands, mid-set */
#timer .acts .adj{padding-inline:9px;gap:2px}
#timer .acts .btn.plain{background:var(--surface-2);color:var(--label)}
#timer .acts .btn.plain:active{background:var(--surface-3)}
#timer .acts .btn{flex:none}
#timer .acts .skip{min-width:min(70px,100%);flex:0 1 auto}
#timer .acts .skip > span{display:grid;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Skip and Dismiss stacked in one cell, the one not in use hidden, so the button keeps one width
   between counting and Ready; so does the pause slot, kept invisible once the rest is over. */
#timer .acts .skip > span > span{grid-area:1/1;min-width:0;overflow:hidden;text-overflow:ellipsis}
#timer .acts .skip .off,#timer .acts .pause-slot{visibility:hidden}
/* Hidden copies of both labels, at their natural width, that RestTimer measures to decide
   whether Skip shows its label or only its icon (skip-forward, or × once Ready). */
#timer .acts .skip{position:relative}
#timer .acts .skip > .skip-probe{position:absolute;inset-inline-start:0;top:0;visibility:hidden;pointer-events:none;display:block;overflow:visible;width:max-content}
#timer .acts .skip > .skip-probe > span{display:block;width:max-content;white-space:nowrap}
#timer .acts .skip.icon-only{min-width:0}
/* A paused rest reads as held: the clock and the bar step back until it runs again. */
#timer.rest.paused .t,#timer.rest.paused .bar{opacity:.5}
/* work timer (issue #16): the same bar doing the opposite job — outlined and tinted so a
   glance tells "you are holding this" apart from "you are recovering". */
#timer.working{box-shadow:inset 0 0 0 var(--hair) var(--ink),0 12px 34px -8px rgba(0,0,0,.55)}
#timer.working .t{color:var(--ink)}
/* The label is the exercise name, handed in already cased (exerciseNameText): a capitalize here
   would title-case German's own casing too. */
#timer.working .lbl{display:block}
/* A hold's label is the exercise name, so there the clock side takes the room and its two
   buttons keep theirs; the time itself still never shrinks (the label adds no minimum). */
#timer.working .tclock{flex:1 1 0;min-width:auto}
#timer.working .acts{flex:none}
/* Docked on the workout screen: edge to edge, flush with the bottom, the home indicator's inset
   inside it. */
body.no-tabbar #timer{
  inset-inline-start:0;inset-inline-end:0;bottom:0;
  border-radius:var(--r-xl) var(--r-xl) 0 0;padding:14px 14px calc(10px + var(--sab));
  box-shadow:0 -10px 30px -14px rgba(0,0,0,.55);
}
body.no-tabbar #timer.working{box-shadow:inset 0 var(--hair) 0 var(--ink),0 -10px 30px -14px rgba(0,0,0,.55)}
@media (max-width:399px){
  #timer .acts{gap:4px}
  #timer .acts .adj{padding-inline:6px;gap:1px}
  #timer .acts .pause,#timer .acts .pause-slot{padding-inline:10px}
  #timer .acts .skip{padding-inline:10px}
}
@media (max-width:359px){
  body.no-tabbar #timer,#timer{padding-inline:10px}
  #timer .t{font-size:25px}
  #timer .acts .skip{min-width:0}
}

/* ---------------------------------------------------------------- modal -- */
#modal-root{position:fixed;inset:0;z-index:100;display:none}
#modal-root.open{display:block}
.mback{
  position:absolute;inset:0;background:rgba(0,0,0,.4);
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);
  touch-action:none;overscroll-behavior:none;
}
.sheet{
  position:absolute;inset-inline-start:0;inset-inline-end:0;bottom:0;background:var(--bg-el);
  border-radius:var(--r-xl) var(--r-xl) 0 0;
  padding:8px 18px calc(20px + var(--sab));
  /* A tall sheet stops short of the status bar / Dynamic Island: every cap carries the top
     safe-area inset, which the layout viewport does not (viewport-fit=cover). */
  max-height:90vh;max-height:min(90vh,calc(100dvh - var(--sat) - 8px - var(--native-kb,0px)));
  overflow-y:auto;scroll-padding-bottom:calc(20px + var(--sab));
  animation:sheetup .34s var(--ease);
  overscroll-behavior:contain;touch-action:pan-y;will-change:transform;
}
.sheet:has(.picker-search){
  bottom:max(var(--picker-keyboard-bottom,0px),var(--native-kb,0px));
  /* with the keyboard up the sheet is capped by the visual viewport — which still starts
     under the notch, hence the inset here too */
  max-height:min(90vh,calc(100dvh - var(--sat) - 8px - var(--native-kb,0px)),calc(var(--picker-visual-height,100vh) - var(--sat) - 8px));
}
/* Android 15: the window is not resized for the soft keyboard, the app passes the height it
   covers as --native-kb instead (MainActivity.keyboardScript, lib/native-keyboard.js). Every
   sheet stands on the keyboard, and its foot drops the navigation-bar inset, which the keyboard
   already covers. Older Android versions resize the window and never set the variable. */
:root[data-native-kb] .sheet{
  bottom:max(var(--picker-keyboard-bottom,0px),var(--native-kb,0px));
  padding-bottom:20px;scroll-padding-bottom:20px;
}
:root[data-theme="light"] .sheet{background:var(--bg)}
@keyframes sheetup{from{transform:translateY(100%)}to{transform:none}}
.sheet .grab{width:36px;height:5px;border-radius:99px;background:var(--label-4);margin:6px auto 14px}
.sheet h3{font-size:20px;font-weight:600;letter-spacing:-.021em;margin-bottom:14px}
.picker-search{
  position:sticky;top:0;z-index:2;margin-bottom:0;padding-bottom:10px;
  background:var(--bg-el);
}
:root[data-theme="light"] .picker-search{background:var(--bg)}
.center{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(84vw,300px);background:var(--bg-el);border-radius:var(--r-lg);padding:20px;
  max-height:calc(100dvh - 2*var(--sat) - 24px);overflow-y:auto;
  box-shadow:none;
  animation:pop .28s var(--ease);
}
:root[data-theme="light"] .center{background:#fff}
/* a dialog with a field centres in what the Android 15 keyboard leaves */
:root[data-native-kb] .center{
  top:calc((100% - var(--native-kb)) / 2);
  max-height:calc(100dvh - var(--native-kb) - 2*var(--sat) - 24px);
}
@keyframes pop{from{transform:translate(-50%,-50%) scale(.94);opacity:0}to{transform:translate(-50%,-50%) scale(1);opacity:1}}

/* --- RIR/RPE conversion table (effort help sheet) ---
   The two scales only click when you see them side by side, so the numbers get fixed-width
   tabular columns you can read straight down, and the words take whatever is left. Built out
   of the same grouped-list parts as the rest of the app (surface fill, inset hairlines) rather
   than a real <table>, so it inherits the card look and wraps properly on a narrow phone. */
.efftbl{background:var(--surface);border-radius:var(--r-lg);overflow:hidden;margin:14px 0 12px}
.efftbl .r{display:flex;align-items:center;gap:10px;padding:10px 14px;position:relative}
.efftbl .r+.r::before{
  content:'';position:absolute;inset-inline-start:14px;inset-inline-end:0;top:0;height:var(--hair);background:var(--sep);
}
.efftbl .n{
  width:36px;flex:none;text-align:center;font-size:17px;font-weight:600;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums;
}
.efftbl .f{flex:1;min-width:0;font-size:15px;color:var(--label-2);line-height:1.3}
/* the header names the columns without competing with them */
.efftbl .hd{background:var(--surface-2);padding-top:8px;padding-bottom:8px}
.efftbl .hd .n,.efftbl .hd .f{
  font-size:11px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;
  color:var(--label-2);
}
/* the row a working set usually lands on — the anchor the others are read against */
.efftbl .r.on{background:var(--control-tint)}
.efftbl .r.on .n{color:var(--ink)}
.efftbl .r.on .f{color:var(--label)}

/* --- glyph picker (replaces the emoji grid) --- */
.glyph-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:9px}
.glyph-cell{
  aspect-ratio:1;border-radius:13px;background:var(--surface);
  display:flex;align-items:center;justify-content:center;font-size:24px;
  color:var(--label);transition:background var(--fast),color var(--fast),transform var(--fast);
}
.glyph-cell:active{transform:scale(.92)}
.glyph-cell.on{background:var(--ink);color:var(--on-ink)}

/* --- big weight readout --- */
.bwstep{display:flex;align-items:center;justify-content:center;gap:18px;margin:14px 0 6px}
.bw-pm{
  width:46px;height:46px;border-radius:50%;background:var(--surface);flex:none;
  color:var(--label);display:flex;align-items:center;justify-content:center;font-size:19px;
  transition:background var(--fast),transform var(--fast);--icon-stroke:2.2;
}
.bw-pm:active{background:var(--surface-2);transform:scale(.92)}
.bw-read{
  font-size:52px;font-weight:600;letter-spacing:-.035em;min-width:158px;text-align:center;
  font-variant-numeric:tabular-nums;line-height:1;
}
.bw-read .u{font-size:19px;color:var(--label-2);font-weight:400;letter-spacing:-.01em}
.bw-read .num{
  display:inline-block;vertical-align:baseline;background:none;border:none;outline:none;
  padding:0;margin:0;color:inherit;font:inherit;letter-spacing:inherit;
  font-variant-numeric:tabular-nums;text-align:center;cursor:text;
  -moz-appearance:textfield;appearance:textfield;
}

/* --------------------------------------------------------------- charts -- */
.chart{width:100%;overflow:hidden}
.chart svg{display:block;width:100%;height:auto}
.chart-i{position:relative;touch-action:pan-y}
/* left/top are written by LineChart after measuring the label, so it can never be
   pushed under the `.chart` clip at either edge — hence no offset here. */
.ctip{
  position:absolute;left:0;top:0;background:var(--surface-2);
  border-radius:8px;padding:4px 10px;font-size:12px;font-weight:500;white-space:nowrap;
  max-width:calc(100% - 8px);overflow:hidden;text-overflow:ellipsis;
  pointer-events:none;box-shadow:0 6px 18px -4px rgba(0,0,0,.4);
}

/* --- activity heatmap --- */
.hm-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;padding-bottom:2px}
.hm-wrap::-webkit-scrollbar{display:none}
.hm-months{display:flex;margin-inline-start:28px;margin-bottom:5px}
.hm-months span{flex:none;width:14px;font-size:11px;color:var(--label-2);white-space:nowrap;overflow:visible}
.hm-body{display:flex}
.hm-days{display:flex;flex-direction:column;gap:3px;flex:none;width:28px}
.hm-days span{height:11px;font-size:10px;color:var(--label-2);line-height:11px}
.hm-grid{display:flex;gap:3px}
.hm-col{display:flex;flex-direction:column;gap:3px}
.hm-c{width:11px;height:11px;border-radius:3px;background:var(--surface-2);flex:none}
.hm-c.l1{background:color-mix(in srgb,var(--acc) 30%,var(--surface-2))}
.hm-c.l2{background:color-mix(in srgb,var(--acc) 55%,var(--surface-2))}
.hm-c.l3{background:color-mix(in srgb,var(--acc) 78%,var(--surface-2))}
.hm-c.l4{background:var(--acc)}
.hm-c.today{box-shadow:0 0 0 1.5px var(--acc)}
.hm-c.future{opacity:.3}
.hm-c.noted{box-shadow:inset 0 0 0 1.5px var(--indigo)}
.hm-legend{
  display:flex;align-items:center;gap:4px;justify-content:flex-end;margin-top:9px;
  font-size:11px;color:var(--label-2);
}
.hm-legend .hm-c{width:10px;height:10px}

/* "Share as image" (#453): the card as it will be sent, at the sheet's width. The placeholder
   holds a portrait card's shape so nothing below it jumps when the picture lands. */
.share-card{margin:0 auto 14px;max-width:420px}
.share-card img{display:block;width:100%;max-height:56vh;object-fit:contain;border-radius:16px;box-shadow:var(--shadow-card)}
.share-card-ph{aspect-ratio:4/5;max-height:56vh;margin:0 auto;border-radius:16px;background:var(--surface-2);display:flex;align-items:center;justify-content:center;text-align:center;padding:16px}
/* --- muscle map --- */
/* Reuses the .hm-c level ramp above, so one accent scale means one thing app-wide. */
/* An untrained muscle is derived from the text colour rather than a fixed surface, so
   the body keeps the same contrast in both themes — pinned to --surface-2 it was all
   but invisible on a white card. */
.bodymap{
  display:flex;gap:6px;justify-content:center;align-items:flex-start;
  --bm-base:color-mix(in srgb,var(--label) 11%,var(--surface));
}
.bm-v{flex:1;min-width:0;height:auto;max-height:min(46vh,340px)}
.bm-ph{height:200px}                       /* holds the space while the geometry loads */
.bm-sil{fill:color-mix(in srgb,var(--label) 18%,var(--surface))}
.bm-m{fill:var(--bm-base);transition:fill var(--med) var(--ease)}
.bm-m.l1{fill:color-mix(in srgb,var(--acc) 32%,var(--bm-base))}
.bm-m.l2{fill:color-mix(in srgb,var(--acc) 56%,var(--bm-base))}
.bm-m.l3{fill:color-mix(in srgb,var(--acc) 78%,var(--bm-base))}
.bm-m.l4{fill:var(--acc)}
/* Semantic recovery bands: both ready levels share mint, recovering amber, fatigue coral. */
.hm-fatigue{--fatigue-ready:oklch(.72 .075 165);--fatigue-recovering:oklch(.78 .1 80);--fatigue-fatigued:oklch(.74 .12 28)}
:root[data-theme="light"] .hm-fatigue{--fatigue-ready:oklch(.57 .09 165);--fatigue-recovering:oklch(.64 .11 80);--fatigue-fatigued:oklch(.6 .15 28)}
.hm-fatigue .bm-m:is(.l0,.l1){fill:var(--fatigue-ready)}
.hm-fatigue .bm-m:is(.l2,.l3){fill:var(--fatigue-recovering)}
.hm-fatigue .bm-m.l4{fill:var(--fatigue-fatigued)}
.hm-fatigue .hm-c.l0{background:var(--fatigue-ready)}
.hm-fatigue .hm-c.l2{background:var(--fatigue-recovering)}
.hm-fatigue .hm-c.l4{background:var(--fatigue-fatigued)}
.hm-fatigue .fatigue-key{display:inline-flex;align-items:center;gap:5px}
.hm-legend.hm-fatigue{gap:12px;flex-wrap:wrap}
/* Strength view: top band pops gold (owner tweak 2026-08-06) */
.hm-strength .bm-m.l4{fill:var(--yellow);filter:drop-shadow(0 0 1.5px var(--yellow))}
.hm-strength .hm-c.l4{background:var(--yellow)}

.bm-m.sel{stroke:var(--label);stroke-width:7}
.bodymap.tappable .bm-m{cursor:pointer}
.bodymap.tappable .bm-m:focus-visible{outline:none;stroke:var(--label);stroke-width:7;filter:drop-shadow(0 0 2px var(--surface))}
/* A hairline in the surface colour separates neighbouring muscles; the artwork has no
   outline path of its own, so without this the body reads as one flat blob. */
.bm-v path{stroke:var(--surface);stroke-width:2.5;stroke-linejoin:round}

.mrow{display:flex;align-items:center;gap:9px;padding:5px 0}
.mrow .nm{flex:1;min-width:0;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mrow .bar{width:74px;height:5px;border-radius:3px;background:var(--surface-2);flex:none;overflow:hidden}
.mrow .bar i{display:block;height:100%;background:var(--acc);border-radius:3px}
.mrow .v{font-size:12px;color:var(--label-2);min-width:52px;text-align: end;flex:none}
/* A headline number inside a card — tile weight without a tile around it, for the pair of
   readings at the top of the effort card. */
.stat-v{font-size:26px;font-weight:600;letter-spacing:-.026em;line-height:1.1}
.mchips{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}
.mchip{font-size:12px;padding:4px 9px;border-radius:99px;background:var(--surface-2);color:var(--label-2)}
.mchip.miss{background:color-mix(in srgb,var(--orange) 16%,transparent);color:var(--warning-fg)}

/* --- stat tiles --- */
.tiles{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:12px}
.tile{background:var(--surface);border-radius:var(--r-card);padding:14px}
.tile .l{
  color:var(--label-2);font-size:13px;font-weight:400;letter-spacing:-.004em;
  text-transform:none;display:flex;align-items:center;gap:5px;
}
.tile .l .icn{font-size:14px;color:var(--label)}
.tile .v{font-size:26px;font-weight:600;letter-spacing:-.026em;margin-top:5px;line-height:1.1}
.tile.tappable:active{background:var(--surface-2)}

/* --- PR badge --- */
.pr{
  display:inline-flex;align-items:center;gap:4px;
  background:color-mix(in srgb,var(--yellow) 18%,transparent);color:var(--goal-fg);
  border-radius:6px;padding:3px 8px;font-size:12px;font-weight:500;
}
.pr .icn{font-size:13px}

/* --- toast --- */
#toast{
  position:fixed;left:50%;transform:translateX(-50%) translateY(6px);
  bottom:calc(96px + var(--sab));z-index:200;
  background:color-mix(in srgb,var(--surface-2) 88%,transparent);
  -webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px);
  /* 22px, not a pill radius: one line (about 41px high) still reads as a pill, and a toast that
     wraps to four lines is a rounded box instead of a circle over the page. */
  border-radius:var(--r-xl);padding:11px 20px;font-size:15px;font-weight:500;
  box-shadow:var(--shadow-float);
  opacity:0;pointer-events:none;transition:opacity var(--med),transform var(--med) var(--ease);
  /* As wide as its text up to 88vw. Without a width, left:50% left it half the screen to wrap
     in, so a long message stood as a narrow column. */
  width:max-content;max-width:88vw;text-align:center;
}
#toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
/* With an action (Undo): the message, then the button at the end, and the toast takes taps. */
#toast.has-action{pointer-events:auto;display:flex;align-items:center;gap:6px;padding:4px 6px 4px 18px;text-align:start}
#toast.has-action .toast-msg{flex:1;min-width:0;padding:7px 0}
#toast .toast-act{flex:none;display:inline-flex;align-items:center;gap:5px;color:var(--ink);font-weight:700;padding:8px 12px;border-radius:14px;min-height:36px}
#toast .toast-act:active{background:color-mix(in srgb,var(--label) 10%,transparent)}
#toast .toast-act .icn{font-size:16px}
body.no-tabbar #toast{bottom:calc(24px + var(--sab))}
body.no-tabbar.resting #toast{bottom:calc(100px + var(--sab))}

/* ---------------------------------------------------------------- misc --- */
.empty{text-align:center;color:var(--label-2);padding:44px 20px;font-size:15px;line-height:1.45}
.empty .ico{font-size:34px;color:var(--label-2);margin-bottom:12px;display:flex;justify-content:center}
.steps-list{
  padding-inline-start:18px;color:var(--label-2);font-size:15px;line-height:1.5;
  display:flex;flex-direction:column;gap:9px;
}
.steps-list::marker{color:var(--label-2)}

/* --- month calendar --- */
.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:5px;margin-top:10px}
.cal-h{text-align:center;font-size:11px;color:var(--label-2);font-weight:500;text-transform:uppercase;padding:2px 0}
.cal-d{
  aspect-ratio:1;border-radius:10px;background:var(--surface);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  font-weight:400;font-size:15px;color:var(--label);transition:background var(--fast);
}
.cal-d:active{background:var(--surface-2)}
.cal-d.has{background:var(--control-tint);color:var(--ink)}
.cal-d.today{box-shadow:inset 0 0 0 1.8px var(--ink)}
.cal-d i{width:5px;height:5px;border-radius:50%;background:transparent}
.cal-d i.done{background:var(--ink)}
.cal-d i.plan{background:var(--label-3)}
.cal-d i.ovr{background:var(--orange)}
.cal-d i.noted{background:var(--indigo)}
.cal-legend{display:flex;gap:14px;justify-content:center;margin-top:12px;font-size:12px;color:var(--label-2)}
.cal-legend i{display:inline-block;width:6px;height:6px;border-radius:50%;margin-inline-end:5px}

/* --- accent swatches --- */
.swatches{display:flex;gap:12px;flex-wrap:wrap}
.swatch{width:32px;height:32px;border-radius:50%;flex:none;position:relative;transition:transform var(--fast)}
.swatch:active{transform:scale(.9)}
/* The ring takes no taps: over the own colour it lay on the colour input, so the picker never opened. */
.swatch.on::after{content:'';position:absolute;inset:-4px;border-radius:50%;box-shadow:0 0 0 2px var(--label);pointer-events:none}
/* The user's own colour (Settings → Accent color): a rainbow ring until there is one, then filled
   with it. The native colour input lies over it, invisible, so the tap lands on the input itself. */
.swatch-own{display:inline-flex;align-items:center;justify-content:center;font-size:15px;--icon-stroke:2.4}
.swatch-own.unset{
  background:radial-gradient(circle,var(--surface) 0 52%,transparent 54%),
    conic-gradient(#ff453a,#ff9f0a,#ffd60a,#30d158,#40c8e0,#0a84ff,#bf5af2,#ff375f,#ff453a);
  color:var(--label-2);
}
.swatch-input{position:absolute;inset:0;width:100%;height:100%;opacity:0;border:0;padding:0;margin:0;border-radius:50%;cursor:pointer;-webkit-appearance:none;appearance:none}
.swatch-note{margin-top:-4px}

/* --- supersets --- */
.ss-label{
  font-size:12px;font-weight:600;letter-spacing:-.004em;text-transform:none;
  color:var(--ink);margin-block:8px 5px;margin-inline-start:4px;display:flex;align-items:center;gap:5px;
}
.ss-label .icn{font-size:13px}
/* The routine editor's label opens the superset's name and rest (#292). */
.ss-label-btn{background:none;border:0;padding:4px 6px;margin-inline-start:-2px;border-radius:8px;cursor:pointer;font:inherit;font-size:12px;font-weight:600;min-height:28px;max-width:100%}
.ss-label-btn:active{background:var(--surface-2)}
.ss-label-btn .ss-label-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ss-label-btn .dim{font-weight:500;white-space:nowrap}
/* A1, A2…: a member's place in the round (#293). */
.ss-pos{flex:none;min-width:26px;height:22px;padding:0 5px;border-radius:7px;display:inline-flex;align-items:center;justify-content:center;font-size:11.5px;font-weight:700;color:var(--ink);background:var(--control-tint, var(--surface-2))}
.item.in-ss{box-shadow:inset 3px 0 0 var(--ink)}
/* A past workout's detail: each exercise opens its history, and a superset's exercises share the
   routine editor's label and bar. */
.wd-ex{margin-bottom:12px;cursor:pointer;border-radius:10px}
.wd-ex>.grow{flex:1;min-width:0}
.wd-ex:active{background:var(--surface-2)}
.wd-ss{box-shadow:inset 3px 0 0 var(--ink);padding-inline-start:11px;margin-bottom:12px}
.wd-ss .ss-label{margin:0 0 8px}
.wd-ss .wd-ex:last-child{margin-bottom:0}
.ss-card{
  border-radius:var(--r-lg);padding:14px;
  background:var(--surface);box-shadow:inset 0 0 0 1.5px var(--control-line);
}
.workout-swipe-surface{touch-action:pan-y}
.workout-swipe-stack{position:relative;isolation:isolate;overflow:hidden}
.workout-swipe-stack>.workout-swipe-card,.workout-swipe-stack>.workout-swipe-preview{min-width:0}
.workout-swipe-card{position:relative;z-index:2;background:var(--bg)}
.workout-swipe-preview{position:absolute;z-index:1;top:0;inset-inline-start:0;width:100%;pointer-events:none;background:var(--bg)}
/* A superset nests a card inside the page's own gutter, so its inset is paid twice. On a
   narrow phone that left the weight and reps steppers too tight to show a three-digit
   number — reported as "the reps textbox becomes too small when superset on mobile". The
   card only gives up its own padding; the rows inside keep their spacing.
   The give-back runs to 404 px rather than 400, because it may not end before the full insets
   fit: at 401 px they snapped back to 16 + 14 + 14 per side and took 48 px off the row while the
   screen had gained one, so a plain row with an effort column in a superset in the list view —
   285 px of cells in a 281 px card — was 4, 3, 2 and 1 px wider than its card's content box at
   401–404 px and its done tick sat in the card's side padding. 405 px is the width where those
   285 px and the three full insets first add up to the screen, so that is where it ends. */
@media (max-width:404px){
  .ss-card{padding:10px 8px}
  /* The sets card nested in a superset card or a list unit pays a second inset, and in a superset
     in the list view a third; with an L/R row's set number, badge, two steppers, effort and tick
     it is the line that decides whether the numbers fit. 8 px each, and the superset card inside
     a unit keeps 4 (none below 360), so every set row has the same 256 px at 320 as in a plain
     card, and 296–304 at 368. */
  .wl-unit .card,.ss-card .card{padding-inline:8px}
  .wl-unit .ss-card{padding-inline:4px}
}
@media (max-width:359px){
  .wl-unit .ss-card{padding-inline:0}
}
.ss-hd{
  font-size:12px;font-weight:600;color:var(--ink);margin-bottom:12px;
  text-align:center;display:flex;align-items:center;justify-content:center;gap:5px;
}
.ss-ex{position:relative}
.ss-amp{text-align:center;font-size:15px;font-weight:600;color:var(--ink);margin:14px 0 8px}

/* --- workout list view: every unit stacked, the current one outlined --- */
/* minmax(0, …): a grid's default `auto` track is at least as wide as its widest content, so a set
   row whose cells have floors (see .setrow .stp) would widen the whole unit past the screen and
   push the ticks off it. Capped, a row that does not fit overflows its own card instead. */
.workout-list{display:grid;grid-template-columns:minmax(0,1fr);gap:14px}
.wl-unit{
  border-radius:var(--r-lg);padding:14px 14px 4px;
  background:var(--surface-2);
}
/* scrolled to when the list opens (#224): clear the sticky header above it. Workout.jsx
   measures the header (--whdr-h on .workout-list, safe area included) because it grows when
   the session name wraps; the fallback is the height of a one-line header. */
.wl-unit{scroll-margin-top:calc(var(--whdr-h, var(--sat) + var(--conn) + 80px) + 16px)}
.wl-unit.cur{box-shadow:inset 0 0 0 1.5px var(--control-line)}
.wl-hd{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}
.wl-summary{display:grid;gap:8px;padding-bottom:10px}
/* the folded unit is a button (a tap opens it again): full width, text where it always sat */
button.wl-summary{width:100%;padding:0 0 10px;text-align:start;border-radius:var(--r-sm)}

/* --- the chip per exercise at the top of a running workout (#323) --- */
/* One numbered chip per unit, filled as far as it is done: an outline waiting, half full started,
   full when every work set is ticked, so the state reads without the colour. The current one has
   the accent ring. Every chip is the same height whatever its state, and the row scrolls sideways
   (.chips), so nothing here can move the page while you type. 28px chips with the strip's own
   padding keep the row at about the height of the line it replaces. */
.chips.wchips{gap:6px;padding:4px 5px 5px;margin-bottom:2px}   /* room for the current chip's ring: the strip clips */
.wchip{
  flex:none;position:relative;display:inline-flex;align-items:center;justify-content:center;gap:2px;
  min-width:28px;height:28px;padding:0 8px;border-radius:99px;
  font-size:13px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--label-2);
  background:var(--surface);box-shadow:inset 0 0 0 1.5px var(--sep);
}
.wchip .icn{width:12px;height:12px}
.wchip.partial{background:linear-gradient(to top,color-mix(in srgb,var(--orange) 45%,var(--surface)) 50%,var(--surface) 50%);box-shadow:inset 0 0 0 1.5px var(--orange);color:var(--label)}
.wchip.done{background:color-mix(in srgb,var(--green) 70%,var(--surface));box-shadow:none;color:var(--label)}
.wchip.cur{box-shadow:0 0 0 2px var(--bg),0 0 0 3.5px var(--ink);color:var(--label)}
.wchip.partial.cur{box-shadow:inset 0 0 0 1.5px var(--orange),0 0 0 2px var(--bg),0 0 0 3.5px var(--ink)}
/* part of the give-back above — one edge for all three insets of a row in the list view */
@media (max-width:404px){
  .wl-unit{padding:10px 8px 2px}
}

/* --- home: today's session row --- */
.today-row{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  margin-top:12px;padding:12px 14px;border-radius:var(--r);background:var(--surface-2);
  transition:background var(--fast);width:100%;text-align: start;cursor:pointer;
}
.today-row:active{background:var(--surface-3)}
.today-row .lbl2{font-size:11px;font-weight:500;letter-spacing:.03em;text-transform:uppercase;color:var(--label-2)}
.today-row .ttl{
  font-weight:500;font-size:17px;line-height:1.25;text-transform:capitalize;
  letter-spacing:-.012em;margin-top:2px;
  /* two lines before the ellipsis: "Leg Day — in progress" grows past one line in hu/tr/th/pt-BR */
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;
}

/* Only where a pointer really hovers — on a phone :hover sticks to the row after the tap.
   Lighter than :active, which goes all the way to --surface-3, so the two stay distinct. */
@media (hover:hover){
  .today-row:hover{background:color-mix(in srgb,var(--surface-2),var(--surface-3) 60%)}
  :root[data-theme="light"] .today-row:hover{background:color-mix(in srgb,var(--surface-2),var(--surface-3) 85%)}
}

/* --------------------------------------------------- desktop (≥1000px) --- */
.cols{display:block}
@media (min-width:1000px){
  #app{max-width:1080px;padding-top:calc(var(--conn) + 32px);padding-bottom:calc(128px + var(--sab))}
  .conn-row{max-width:640px}   /* the width of the .narrow pages below it */
  body.resting #app{padding-bottom:calc(220px + var(--sab))}
  body.no-tabbar #app{padding-bottom:calc(40px + var(--sab))}
  body.no-tabbar.resting #app{padding-bottom:calc(130px + var(--sab))}
  .workout-end-spacer{height:40px}
  .cols{display:grid;grid-template-columns:1fr 1fr;gap:14px;align-items:start}
  .cols>*{min-width:0}
  /* Two columns on the full-width pages (Library, History, Stats, Plan, Muscles). A .narrow page
     is a single 640px column and keeps its lists in one too. The #app in that selector is what
     lets it win: `.narrow .list` alone lost to `#app .list` on specificity, so Home, Workout,
     Admin and the rest showed their lists two-up on a computer. Sheets live in #modal-root,
     outside #app, and are one column at every width. */
  #app .list{display:grid;grid-template-columns:1fr 1fr;gap:8px}
  #modal-root .list,#app .narrow .list{display:flex;flex-direction:column}
  .narrow{max-width:640px;margin:0 auto}
  .tiles{grid-template-columns:repeat(4,1fr)}
  .cols .tiles,.center .tiles{grid-template-columns:1fr 1fr}   /* a 300px dialog has no room for four */
  #tabbar{
    left:50%;right:auto;bottom:16px;transform:translateX(-50%);width:520px;
    border:var(--hair) solid var(--sep-op);border-radius:var(--r-xl);
    padding:7px 10px 9px;box-shadow:0 12px 40px -10px rgba(0,0,0,.5);
  }
  #tabbar button.start{margin-top:-26px}
  .sheet{left:50%;right:auto;margin-left:-320px;width:640px;border-radius:var(--r-xl) var(--r-xl) 0 0}
  .center{width:340px}
  #timer{left:50%;right:auto;margin-left:-260px;width:520px;bottom:112px}
  body.no-tabbar #timer{left:50%;right:auto;bottom:16px;border-radius:var(--r-xl);padding-bottom:10px;box-shadow:0 12px 40px -10px rgba(0,0,0,.5)}
  .exmedia img,.exmedia video{height:380px}
  .hm-wrap{display:flex;flex-direction:column;align-items:center}
}

/* ------------------------------------------------------- gym check-in -- */
/* Mobile-only feature (views/CheckIn.jsx): saved membership codes shown as QR, swiped
   through horizontally. The rail is a scroll-snap track — one card per viewport, no JS
   carousel — with a trailing "+" card to add another. */
.ci-rail{
  display:flex;gap:14px;overflow-x:auto;scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch;scrollbar-width:none;
  padding:4px 0 8px;margin:0 -16px;padding-left:16px;padding-right:16px;
}
.ci-rail::-webkit-scrollbar{display:none}
.ci-card{
  scroll-snap-align:center;flex:0 0 100%;box-sizing:border-box;
  background:var(--surface);border-radius:var(--r-xl);padding:22px 18px;
  display:flex;flex-direction:column;align-items:center;gap:14px;
  transition:transform var(--fast),box-shadow var(--fast),opacity var(--fast);
}
/* header row: edit — title — trash. The two icon buttons are equal fixed widths so the title,
   flexed between them, stays optically centered on the card no matter how long it is. */
.ci-card-hd{display:flex;align-items:center;gap:8px;width:100%}
.ci-card-btn{width:30px;height:30px;font-size:14px;flex:none}
.ci-card .ci-label{flex:1;min-width:0;font-size:19px;font-weight:600;letter-spacing:-.014em;text-align:center;overflow-wrap:anywhere}
.ci-card .ci-value{font-size:14px;color:var(--label-2);word-break:break-all;text-align:center;font-variant-numeric:tabular-nums}
/* reorder row under a card (only shown with >1 card): ◀ position ▶ to nudge the card one slot
   along the rail. A plain, reliable control — no drag gesture to fight the horizontal scroll. */
.ci-reorder{display:flex;align-items:center;justify-content:center;gap:14px;margin-top:2px}
.ci-reorder .ci-pos{font-size:13px;color:var(--label-2);font-variant-numeric:tabular-nums;min-width:44px;text-align:center}
.ci-reorder .iconbtn:disabled{opacity:.3;pointer-events:none}
/* The QR itself: lean-qr paints 1 module per pixel, so scale it up with the browser's
   nearest-neighbour so every module stays a crisp square instead of a blurred blob. White
   quiet-zone padding is baked in by the renderer; the plate underneath just frames it. */
.ci-qr-plate{background:#fff;border-radius:var(--r-lg);padding:16px}
.qr-canvas{display:block;image-rendering:pixelated;image-rendering:crisp-edges;transition:opacity var(--fast)}
/* the trailing add card — a big + on a dashed outline, same footprint as a real card */
.ci-add{
  scroll-snap-align:center;flex:0 0 100%;box-sizing:border-box;
  min-height:280px;border-radius:var(--r-xl);
  border:2px dashed var(--surface-3);background:none;color:var(--label-2);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;
}
.ci-add:active{background:var(--surface);transform:scale(.99)}
.ci-add .icn{font-size:40px;--icon-stroke:1.8}
.ci-add .ci-add-t{font-size:16px;font-weight:500}
/* dots under the rail — which card you're on. Purely a hint; the rail itself is the control. */
.ci-dots{display:flex;justify-content:center;gap:7px;margin-top:4px}
.ci-dot{width:7px;height:7px;border-radius:50%;background:var(--surface-3);transition:background var(--fast),transform var(--fast)}
.ci-dot.on{background:var(--ink);transform:scale(1.15)}
/* browser camera sheet (components/CameraScan.jsx): the video fills a portrait plate, a dashed
   square in the middle says "put the code here" — decoding reads the whole frame regardless. */
.cam-wrap{position:relative;width:100%;aspect-ratio:3/4;max-height:58vh;border-radius:var(--r-lg);overflow:hidden;background:#000}
.cam-wrap video{width:100%;height:100%;object-fit:cover;display:block}
.cam-frame{position:absolute;inset:0;margin:auto;width:62%;aspect-ratio:1;border:2px dashed rgba(255,255,255,.75);border-radius:14px;pointer-events:none}
/* ---------------------------------------------------------------- Plan -- */
/* Schedule | Routines (views/Plan.jsx). A settings-like page, one column at every width. */
.plan-views{margin-bottom:18px}
.plan-views button{min-height:34px;font-size:15px}
.plan .plan-mode .lrow-t{white-space:nowrap}
/* The control takes the rest of the row when it fits, and a full line of its own when it does
   not, rather than squeezing "Fixed Week" onto two lines. */
.plan-mode .seg-inline{flex:1 1 200px;min-width:0}
.plan-mode .seg-inline button{white-space:nowrap}
.plan-mode-locked{margin-inline-start:auto;text-align:end}
.plan-sec-h{margin:22px 0 8px;gap:8px;flex-wrap:wrap}
/* Long words (German "Hinzufügen") push the loop's buttons off a 320 px screen; they drop
   to their own line instead and stay on the trailing edge. */
.plan-sec-h>.plan-sec-acts{margin-inline-start:auto}
.plan-sec-h h4.sec{margin:0}
.plan-routines-bar{margin-top:0}
.plan-textbtn{color:var(--ink);font-size:16px;padding:6px 4px;position:relative}
.plan-textbtn::before{content:'';position:absolute;inset:-6px}
.plan .sect-f{margin:0 0 4px}
.plan .list+.sect-f{padding-top:8px}
/* a weekday: short day name, the routine's glyph (a moon on a rest day), what is on it */
.plan-day-n{min-width:30px;flex:none;white-space:nowrap;font-size:15px;font-weight:600;color:var(--label-2)}
.plan-day-n.today{color:var(--ink)}
/* Arabic names the whole day: one column wide enough for the longest keeps the glyphs aligned */
[dir="rtl"] .plan-day-n{min-width:88px}
.item .lrow-i.rest{background:var(--surface-3);color:var(--label-2)}
/* the loop: a numbered position, lit when up next, a tick once done this round */
.plan-order{
  width:24px;height:24px;border-radius:50%;flex:none;display:grid;place-items:center;
  font-size:13px;font-weight:600;color:var(--label-2);background:var(--surface-3);--icon-stroke:2.6;
}
.plan-order.next{background:var(--ink);color:var(--on-ink)}
.rotation-row.is-done .tt{color:var(--label-2)}
/* Edit mode, as on an iPhone: a red minus at the start, a handle at the end */
.plan-minus{
  width:24px;height:24px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:var(--red);color:#fff;font-size:14px;--icon-stroke:2.6;position:relative;
}
.plan-minus::before{content:'';position:absolute;inset:-10px}
.plan-handle{
  flex:none;align-self:stretch;display:flex;align-items:center;padding:0 6px;margin:-10px -6px -10px 0;
  color:var(--label-2);font-size:18px;cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none;
}
.plan-handle:active{cursor:grabbing;color:var(--label-2)}
.plan [data-reorder-row]{transition:transform var(--fast) var(--ease)}
.plan-link{margin-top:24px}
.plan-empty{padding:28px 20px}
/* Stats: the card Plan links to clears the sticky banners when it is scrolled to */
#weekly-volume{scroll-margin-top:calc(var(--sat) + var(--conn) + 96px)}

/* ------------------------------------------------- duration wheel picker -- */
/* components/DurationWheel.jsx: two scroll-snap wheels under one highlight band. --dw-item is
   WHEEL_ITEM there. The band sits behind the rows; the rows fade and lean back toward the edges
   (painted from JS while scrolling), and the mask softens the top and bottom rows further. */
.dw{--dw-item:40px;position:relative;display:flex;justify-content:center;height:calc(var(--dw-item) * 5);
  margin:4px auto 16px;max-width:320px;user-select:none;-webkit-user-select:none;touch-action:pan-y}
.dw-band{position:absolute;inset-inline:6px;top:calc(var(--dw-item) * 2);height:var(--dw-item);border-radius:10px;
  background:color-mix(in srgb,var(--label) 10%,transparent);pointer-events:none}
.dw-col{position:relative;flex:1;min-width:0;outline:none;border-radius:10px}
.dw-col:focus-visible::after{content:'';position:absolute;inset-inline:8px;top:calc(var(--dw-item) * 2);height:var(--dw-item);
  border-radius:10px;box-shadow:0 0 0 2px var(--ink);pointer-events:none}
.dw-scroll{height:100%;overflow-y:scroll;overflow-x:hidden;scroll-snap-type:y mandatory;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;scrollbar-width:none;perspective:420px;
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 34%,#000 66%,transparent 100%);
  mask-image:linear-gradient(to bottom,transparent 0,#000 34%,#000 66%,transparent 100%)}
.dw-scroll::-webkit-scrollbar{display:none}
.dw-pad{height:calc(var(--dw-item) * 2)}
.dw-it{height:var(--dw-item);scroll-snap-align:center;display:flex;align-items:center;justify-content:flex-end;
  padding-inline-end:calc(50% + 2px);font-size:22px;font-variant-numeric:tabular-nums;color:var(--label-2);
  cursor:pointer;transform-origin:50% 50%;will-change:transform,opacity}
.dw-it.on{color:var(--label);font-weight:600}
.dw-it.out{color:var(--label-4)}
.dw-unit{position:absolute;top:calc(var(--dw-item) * 2);height:var(--dw-item);display:flex;align-items:center;
  inset-inline-start:calc(50% + 8px);font-size:17px;font-weight:600;color:var(--label);pointer-events:none}
.dw-read{text-align:center;font-size:34px;font-weight:700;letter-spacing:-.02em;font-variant-numeric:tabular-nums;margin:-4px 0 2px}
.dw-foot{text-align:center;margin:-6px 0 14px;line-height:1.4}
@media (hover:hover){.dw-it:hover{color:var(--label)}}

/* ------------------------------------------------------- Settings (v1.3.11) -- */
/* A sub-page's nav bar: the back button names where it goes, the title sits in the middle.
   The back column is at least as wide as its label ("Einstellungen" stays whole), and the two
   side columns share what is left equally, so the title is centred whenever it can be and moves
   over when the label needs the room. Only a label past half the screen is cut. */
.sp-nav{display:grid;grid-template-columns:minmax(max-content,1fr) minmax(0,max-content) minmax(0,1fr);align-items:center;column-gap:6px;
  min-height:44px;margin:4px -6px 10px}
.sp-back{display:inline-flex;align-items:center;gap:2px;color:var(--ink);font-size:17px;padding:6px;border-radius:10px;
  min-width:0;max-width:50vw;justify-self:start}
.sp-back span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sp-back .icn{font-size:22px;--icon-stroke:2.2;flex:none}
/* A long title ("Alertas do temporizador", "Megjelenés és Kezdőlap") takes a second line rather
   than lose its end to an ellipsis next to a whole back label. */
.sp-title{text-align:center;font-weight:600;font-size:17px;line-height:1.2;margin:0;overflow:hidden;overflow-wrap:anywhere;-webkit-hyphens:auto;hyphens:auto;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;text-wrap:balance}
.sp-root-title{font-size:34px;line-height:1.06;font-weight:700;letter-spacing:-.028em;margin:2px 0 10px}
@media (max-width:420px){.sp-root-title{font-size:30px}}
.sp-search{margin-bottom:18px}
/* the account card on top of the root: a big round avatar, the name, one line under it */
.lrow.sp-acct{padding-block:12px;gap:14px}
.sp-avatar{width:56px;height:56px;border-radius:50%;flex:none;display:grid;place-items:center;font-size:30px;
  background:linear-gradient(160deg,var(--surface-3),var(--surface-2));color:var(--label-2)}
.sp-acct .lrow-t{font-size:19px;font-weight:600}
.sp-avatar.on{background:var(--control-tint);color:var(--ink);font-size:24px;font-weight:700}
.sp-version{text-align:center;margin-top:4px;line-height:1.6}
/* The root rows' previews ("2:00 de descanso · Tarjetas", "Som · Vibração") are two or three facts, and a
   one-line ellipsis cut all but the first. They wrap instead, up to three lines, and never below
   their longest word (min-content, since overflow:hidden would make auto mean 0). On the narrowest phones there is no room beside
   the title at all, so the preview moves under it, like a subtitle. */
.lrow.sp-root-row .lrow-v{white-space:normal;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;line-clamp:3;
  min-width:min-content;max-width:62%;line-height:1.25;text-wrap:balance}
@media (max-width:360px){
  .lrow.sp-root-row:has(.lrow-v){display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;column-gap:12px;row-gap:1px}
  .lrow.sp-root-row:has(.lrow-v) .lrow-i{grid-column:1;grid-row:1 / span 2}
  .lrow.sp-root-row:has(.lrow-v) .lrow-m{grid-column:2;grid-row:1}
  .lrow.sp-root-row .lrow-v{grid-column:2;grid-row:2;min-width:0;max-width:none;text-align:start;font-size:15px;-webkit-line-clamp:2;line-clamp:2}
  .lrow.sp-root-row:has(.lrow-v) .lrow-c{grid-column:3;grid-row:1 / span 2}
}
.lrow.dis .lrow-i,.lrow.dis .lrow-t,.lrow.dis .sw{opacity:.45}
/* a row a search result jumped to: a short accent wash that fades out */
.lrow.sp-flash,.btn.sp-flash{animation:spflash 1.8s ease}
@keyframes spflash{0%,45%{background:var(--control-tint)}100%{background:transparent}}
.sp-empty{color:var(--label-2);text-align:center;padding:28px 12px;line-height:1.4}

/* ----------------------------------------------------------- RTL (Arabic) -- */
/* Directional icons flip: back chevrons point right, trailing chevrons point left. */
[dir="rtl"] [data-icon="chevronLeft"],
[dir="rtl"] [data-icon="chevronRight"]{transform:scaleX(-1)}
/* Segmented control: flex order reverses, so the sliding indicator moves the other way. */
[dir="rtl"] .seg-sel{transform:translateX(calc(-100% * var(--i)))}
/* Numbers and dates inside Arabic text still read left-to-right. */
[dir="rtl"] .num,[dir="rtl"] input[type="number"]{direction:ltr}
/* Superset edge stripe points at the inline start (the right, in RTL). */
[dir="rtl"] .item.in-ss,[dir="rtl"] .wd-ss{box-shadow:inset -3px 0 0 var(--ink)}
/* Slider: the thumb is offset from inline-start, which is the right edge in RTL, so the
   half-width centering shift points the other way. */
[dir="rtl"] .sld-knob{transform:translateX(50%)}
[dir="rtl"] .sld.dragging .sld-knob{transform:translateX(50%) scale(1.14)}
/* Switch: the knob rests at inline-start (the right, in RTL), so "on" travels the other
   way — the physical +20px would push it out of the track. */
[dir="rtl"] .sw.on .knob{transform:translateX(-20px)}
[dir="rtl"] .sw.on:active .knob{transform:translateX(-16px)}
/* Chronological grids keep their left-to-right order: heatmap weeks and calendar
   weekdays would otherwise mirror. */
[dir="rtl"] .hm-wrap,[dir="rtl"] .cal-grid{direction:ltr}
/* Tight tracking is tuned for Latin; Arabic is a connected script and gets none. */
[dir="rtl"] *{letter-spacing:0}
.exfix-link{display:inline-flex;align-items:center;gap:5px;margin:14px 0 4px;color:var(--label-2);text-decoration:none}
.list .similar-label{margin:16px 2px 6px;grid-column:1/-1}

/* ============================================================================
   Liquid glass material — isolated so it can be swapped or dropped in one place.
   Ported from Evan's Momong (first-party), src/styles.css "Shared glass material",
   re-tokenised for the Bevel palette used by the reskin (no Momong brand tokens/fonts).

   Use: add class="glass" to a FLOATING element only (tab dock, Start, live bar, sheets,
   icon buttons). Content cards stay opaque. Add .glass-moving while the layer animates:
   it swaps to the flat composite fill instead of animating a large backdrop blur.
   ========================================================================== */
:root{
  --glass-fill:rgb(255 255 255 / .55);
  --glass-flat:#FAFAFA;
  --glass-light:oklch(1 0 0 / .55);
  --glass-dim:oklch(1 0 0 / .08);
  --glass-wash:oklch(1 0 0 / .30);
  --glass-depth:0 3px 10px rgb(0 0 0 / .10);
  --glass-sheen:linear-gradient(145deg,var(--glass-wash),transparent 38%,transparent 65%,var(--glass-wash));
  --glass-elevation:inset 0 1px 0 var(--glass-light),var(--glass-depth);
}
:root:not([data-theme="light"]){
  --glass-fill:rgb(28 28 28 / .55);
  --glass-flat:#202020;
  --glass-light:oklch(1 0 0 / .20);
  --glass-dim:oklch(1 0 0 / .03);
  --glass-wash:oklch(1 0 0 / .05);
  --glass-depth:0 3px 10px rgb(0 0 0 / .18);
}
.glass{
  position:relative;
  background-color:var(--glass-fill);
  background-image:var(--glass-sheen);
  -webkit-backdrop-filter:blur(24px) saturate(180%);
  backdrop-filter:blur(24px) saturate(180%);
  box-shadow:var(--glass-elevation);
}
/* the rim: 1px conic gradient ring, masked to the border box */
.glass::after{
  content:"";position:absolute;inset:0;border-radius:inherit;padding:1px;pointer-events:none;z-index:2;
  background:conic-gradient(from 135deg,var(--glass-light),var(--glass-dim) 18%,var(--glass-light) 46%,var(--glass-dim) 68%,var(--glass-light));
  -webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);
  mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;
}
/* while the layer moves: flat fill, no live blur (keeps iOS Safari at 60fps) */
.glass.glass-moving{background-color:var(--glass-flat);-webkit-backdrop-filter:none;backdrop-filter:none}
.glass:active{transition:transform 120ms cubic-bezier(.2,.8,.2,1)}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .glass{background:var(--surface)}
}
@media (prefers-reduced-transparency:reduce),(prefers-contrast:more){
  .glass{background:var(--surface);background-image:none;-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:0 0 0 1px var(--sep-op)}
  .glass::after{display:none}
}

/* Momong's shared floating material, scoped to the live session bar. */
.live-bar.glass{
  --glass-light:oklch(1 0 0 / .48);
  --glass-dim:oklch(1 0 0 / .08);
  --glass-shade:oklch(0 0 0 / .075);
  --glass-wash:oklch(1 0 0 / .28);
  --glass-fill:rgb(255 255 255 / .46);
  --glass-depth:0 2px 3px oklch(0 0 0 / .04),0 8px 24px -6px oklch(0 0 0 / .15);
  --glass-elevation:inset 0 1px 1px var(--glass-light),inset 0 -2px 3px var(--glass-shade),var(--glass-depth);
  -webkit-backdrop-filter:blur(12px) saturate(1.6);backdrop-filter:blur(12px) saturate(1.6);
}
:root:not([data-theme="light"]) .live-bar.glass{
  --glass-light:oklch(1 0 0 / .24);--glass-dim:oklch(1 0 0 / .025);
  --glass-shade:oklch(0 0 0 / .22);--glass-wash:oklch(1 0 0 / .045);
  --glass-fill:rgb(34 34 34 / .6);--glass-depth:0 0 0 1px oklch(1 0 0 / .1);
}
:root[data-vt] .live-bar.glass,body.wk-dragging .live-bar.glass,body.wk-settle .live-bar.glass{background-color:var(--glass-flat);-webkit-backdrop-filter:none;backdrop-filter:none}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){.live-bar.glass{background:var(--surface)}}
@media (prefers-reduced-transparency:reduce),(prefers-contrast:more){
  .live-bar.glass{background:var(--surface);-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:0 0 0 1px var(--sep-op)}
}

/* ============================================================================
   openGym — Bevel skin (reskin/bevel)
   ----------------------------------------------------------------------------
   Theme layer after index.css and glass.css. Owner's v6-A direction overrides the older
   palette/elevation spec: achromatic surfaces, near-black dark canvas, quiet cards and
   translucent floating chrome. Metric hues, geometry and motion tokens stay independent.
   ========================================================================== */

/* ---------------------------------------------------------------- tokens -- */
/* Theme-independent: type, spacing, radii, motion, layers. */
:root{
  --font:-apple-system,BlinkMacSystemFont,"SF Pro Text","SF Pro Display","Inter Variable",Inter,"Segoe UI",Roboto,system-ui,sans-serif;
  --t-hero:700 40px/1 var(--font);       /* hero metric, tracking -0.03em */
  --t-timer:700 34px/1.05 var(--font);   /* live timer, tabular */
  --t-title:700 30px/1.1 var(--font);    /* large title, -0.02em */
  --t-date:600 22px/1.2 var(--font);     /* "Today, 14 September" */
  --t-ring:600 22px/1 var(--font);
  --t-card:600 18px/1.25 var(--font);    /* card / exercise title */
  --t-section:600 17px/1.3 var(--font);  /* section header, sentence case */
  --t-body:400 17px/1.35 var(--font);
  --t-cell:600 17px/1 var(--font);       /* set value; unit uses 400 + --text-2 */
  --t-meta:400 15px/1.3 var(--font);
  --t-status:500 13px/1.2 var(--font);   /* "Normal range" in hue */
  --t-label:500 11px/1.2 var(--font);    /* tab label, axis, column caps (+0.06em) */
  /* `font: var(--t-*)` resets font-variant-numeric too: numbers re-add tabular-nums */

  --s-1:4px; --s-2:8px; --s-3:12px; --s-4:16px; --s-5:20px; --s-6:24px; --s-8:32px;
  --margin:20px;          /* screen side margin (measured) */
  --card-pad:16px;
  --card-gap:12px;
  --section-gap:28px;

  --r-card:24px;          /* measured 22–24 */
  --r-inner:12px;         /* 24 − 12 pad: set cells, inner tiles */
  --r-sheet:38px;
  --r-menu:22px;
  --r-pill:999px;
  --r-icon:8px;           /* 30px settings icon squircle */

  --ease-out:cubic-bezier(.32,.72,0,1);    /* enters, sheets */
  --ease-inout:cubic-bezier(.65,0,.35,1);  /* on-screen moves */
  --ease-in-exit:cubic-bezier(.4,0,1,1);   /* quiet exits only */
  --d-press:120ms; --d-hover:150ms; --d-pop:200ms; --d-sheet:320ms; --d-page:360ms;
  /* Springs in plain CSS (no motion library: the frontend stays dependency-light). Each is a
     damped spring sampled into linear() that settles at the end of the duration it runs for.
     --spring is critically damped (bounce 0), the default everywhere; --spring-bounce has
     bounce .15 and is only for a move a flick started (a released sheet). */
  --spring:linear(0,.017 2.1%,.073 4.8%,.209 9.2%,.467 17.1%,.611 22.4%,.724 27.7%,.815 33.6%,.887 40.4%,.94 48.9%,.976 61%,.996 82.6%,1);
  --spring-bounce:linear(0,.016 2.1%,.071 4.8%,.189 8.6%,.518 17.9%,.666 23%,.78 28%,.867 33.2%,.933 39.2%,.978 46.6%,1.002 57%,1.003 86.5%,1);
  --d-spring:400ms;       /* sheet open: spring {bounce:0, duration:.4} */
  --press:.97;            /* press any control: scale(.97) over --d-press, --ease-out */

  /* New components use this scale. The upstream layers (connection bar 45, tab bar 50, rest
     bar 60, modal root 100, toast 200) keep their own numbers until they move onto it. */
  --z-content:0; --z-sticky:10; --z-dock:20; --z-sheet:30; --z-menu:40; --z-toast:50;

  /* upstream geometry and motion names, pointed at the system */
  --pad:var(--margin);
  --r-sm:var(--r-icon); --r:var(--r-inner); --r-lg:16px; --r-xl:var(--r-menu);
  --ease:var(--ease-out);
  --fast:var(--d-press); --med:var(--d-pop);
}

/* Colour, dark. Dark stays the attribute-less default like upstream; App.jsx sets data-theme
   as soon as it runs. Accents are the light hues with ~20% less chroma: the pairs DESIGN-SYSTEM
   gives verbatim, the rest derived the same way in OKLCH (lightness kept, floor .7). */
:root{
  --canvas:#101010; --surface:#1C1C1C; --surface-2:#2A2A2A; --surface-sheet:#181818;
  --scrim:rgb(0 0 0 / .5);
  --text:#F2F2F2; --text-2:#A3A3A3; --text-3:#757575;
  --hairline:#2A2A2A;            /* dark borders solid, not glowing alpha */
  --outline-input:#454545;
  --ink:#F2F2F2; --on-ink:#161616;

  --strain:#E8935F; --strain-2:oklch(.819 .111 72);
  --recovery:#7CC447; --recovery-2:oklch(.859 .164 123.3);
  --sleep:#8486DE; --sleep-2:oklch(.711 .087 272.8);
  --stress:oklch(.85 .135 92.2); --stress-2:oklch(.747 .075 190.9);
  --done:#6DAF83; --danger:#D98368;
  --heart:oklch(.7 .151 38.9);
  --info:oklch(.7 .113 257.5);
  --protein:oklch(.7 .127 356.1); --carbs:oklch(.783 .113 70.5); --fat:oklch(.7 .113 279.9);
  --muscle-a:oklch(.85 .138 88.9); --muscle-b:oklch(.836 .14 129.9); --muscle-c:oklch(.724 .081 200.1);
  --done-tint:rgb(123 195 145 / .18); --danger-tint:rgb(224 131 97 / .18);
  --strain-tint:color-mix(in srgb,var(--strain) 18%,transparent);
  --recovery-tint:color-mix(in srgb,var(--recovery) 18%,transparent);
  --sleep-tint:color-mix(in srgb,var(--sleep) 18%,transparent);

  /* Foregrounds are independent of pastel strokes/fills; checked on solids and status tints. */
  --done-fg:#A3D9B3; --warning-fg:#F5BC89; --danger-fg:#FFB49E; --goal-fg:#E8D277;
  --info-fg:#A9C8FF; --bodyweight-fg:#C0BDF5; --measure-fg:#F1B0CC; --sets-fg:#99D5D8;

  --shadow-card:0 0 0 1px var(--hairline);
  --shadow-float:0 3px 10px rgb(0 0 0 / .18);
  --shadow-menu:var(--shadow-card);
}

/* Colour, light. Same specificity as index.css's light block, and later, so it wins. */
:root[data-theme="light"]{
  --canvas:#F7F7F7;  /* neutral off-white page */
  --surface:#FFFFFF;  /* cards */
  --surface-2:#EFEFEF;  /* inset: segmented track, input fill, chip bg */
  --surface-sheet:#F7F7F7;  /* sheet canvas */
  --scrim:rgb(0 0 0 / .28);
  --text:#111111;
  --text-2:#696969;  /* readable secondary ink */
  --text-3:#8A8A8A;  /* placeholder/disabled token (not opacity) */
  --hairline:rgb(0 0 0 / .08);
  --outline-input:rgb(0 0 0 / .12);
  --ink:#282828;  /* primary pill */
  --on-ink:#FFFFFF;

  /* metric accents (data only) */
  --strain:#F98C50; --strain-2:#FBB453; --strain-tint:#FEF1E6;
  --recovery:#6CCF2A; --recovery-2:#B7E51F; --recovery-tint:#EEF8E2;
  --sleep:#6C6CDB; --sleep-2:#8B9DE6; --sleep-tint:#ECEEFB;
  --stress:#F5C91E; --stress-2:#5DC0BB;
  --done:#7BC391; --done-tint:#E4F1E8;  /* completed set */
  --danger:#E08361; --danger-tint:#F7E0DA;  /* Finish / discard (coral, not red) */
  --heart:#F2622E;
  --info:#639FF5;
  --protein:#E46B9D; --carbs:#F1A744; --fat:#7275D3;
  --muscle-a:#FBC608; --muscle-b:#A3DF59; --muscle-c:#47B9BF;

  --done-fg:#28633B; --warning-fg:#7A461B; --danger-fg:#903E25; --goal-fg:#6B5400;
  --info-fg:#23589D; --bodyweight-fg:#50469A; --measure-fg:#8B3460; --sets-fg:#226569;

  /* Content stays flat; floating chrome gets one small shadow. */
  --shadow-card:0 1px 2px rgb(0 0 0 / .025);
  --shadow-float:0 3px 10px rgb(0 0 0 / .10);  /* tab bar, live bar */
  --shadow-menu:var(--shadow-card);
}

/* Upstream names → the system, in both themes. `:root[data-theme]` matches index.css's light
   block on specificity and comes later; `:root` covers the first paint, before data-theme.
   Greys mix in oklab: in oklch a near-neutral comes out with a `none` hue that paints as 0°,
   a visible red cast on graphite. */
:root,:root[data-theme]{
  --bg:var(--canvas); --bg-el:var(--surface-sheet);
  --surface-3:color-mix(in oklab,var(--surface-2),var(--text) 7%);   /* controls: one step past --surface-2 */
  --label:var(--text); --label-2:var(--text-2); --label-3:var(--text-3);
  --control-tint:color-mix(in srgb,var(--text) 8%,transparent);
  --control-line:var(--hairline);
  --label-4:color-mix(in oklab,var(--text) 16%,transparent);
  --sep:var(--hairline); --sep-op:var(--hairline);

  /* the iOS system palette, folded onto the pastels so every upstream status colour follows */
  --blue:var(--info); --green:var(--done); --red:var(--danger); --orange:var(--strain);
  --yellow:var(--stress); --teal:var(--stress-2); --indigo:var(--sleep); --purple:var(--sleep-2);
  --pink:var(--protein); --mint:var(--muscle-c); --grey:var(--text-2);

  /* One hue per metric. Charts take a metric (LineChart `metric`, a data-metric scope) and
     paint var(--metric-<name>); --chart is the neutral line for a chart that names none. */
  --metric-bodyweight:var(--sleep);   /* Bevel "Weight": a lavender-indigo line */
  --metric-measure:var(--protein);    /* waist, arms, body fat… */
  --metric-e1rm:var(--info);          /* strength: e1RM and top-set load (Bevel strength progression) */
  --metric-reps:var(--info);          /* rep bests ride the same strength line */
  --metric-time:var(--done);          /* minutes trained, holds, cardio */
  --metric-effort:var(--strain);      /* RPE / RIR and hard sets: Bevel strain/effort */
  --metric-volume:var(--muscle-a);    /* load lifted (Bevel "Total volume") */
  --metric-sets:var(--muscle-c);      /* sets per muscle: body map, muscle bars */
  --metric-bodyweight-fg:var(--bodyweight-fg); --metric-measure-fg:var(--measure-fg);
  --metric-e1rm-fg:var(--info-fg); --metric-reps-fg:var(--info-fg);
  --metric-time-fg:var(--done-fg); --metric-effort-fg:var(--warning-fg);
  --metric-volume-fg:var(--goal-fg); --metric-sets-fg:var(--sets-fg);
  --metric-status-fg:var(--text-2);
  --chart:var(--text-2);
}

/* Accent presets → their pastel twins, so the per-account accent setting keeps working. The
   default (lime) is the teal twin: the system has no neon lime. A custom accent is written
   inline by lib/accent.js and wins over all of this. */
:root[data-accent="lime"],:root[data-accent="teal"]{--acc:var(--stress-2)}
:root[data-accent="sky"]   { --acc:var(--info) }
:root[data-accent="orange"]{ --acc:var(--strain) }
:root[data-accent="violet"]{ --acc:var(--sleep) }
:root[data-accent="pink"]  { --acc:var(--protein) }
:root[data-accent="red"]   { --acc:var(--danger) }
:root[data-accent="gold"]  { --acc:var(--stress) }
:root[data-accent]{--acc-2:color-mix(in oklab,var(--acc),black 16%)}
/* every twin is a mid-light pastel in both themes, so its label is always near-black */
:root[data-accent],:root[data-theme][data-accent]{--on-acc:#161616}

/* ------------------------------------------------------------ typography -- */
body{letter-spacing:-.012em}
#app{padding:calc(var(--sat) + var(--conn) + 14px) var(--margin) calc(112px + var(--sab))}
body:has(#dock.has-live) #app{padding-bottom:calc(var(--live-bar-height,88px) + 104px + var(--sab))}
.hdr{margin:10px 0 22px;align-items:center}
.hdr h1{font:var(--t-title);letter-spacing:-.02em}
.hdr .sub{font:var(--t-meta);color:var(--text-2);margin-top:3px}
h4.sec{font:var(--t-section);letter-spacing:-.012em;color:var(--text);margin:var(--section-gap) 0 var(--s-2);padding:0 2px}
.sect-t{font:var(--t-section);letter-spacing:-.012em;color:var(--text);text-transform:none;padding:0 2px var(--s-2)}
.card h2{font:var(--t-card);letter-spacing:-.016em;color:var(--text-2);margin:0 0 10px}
.card .big,.big{font:var(--t-hero);letter-spacing:-.03em;font-variant-numeric:tabular-nums}
/* units are smaller and lighter than digits: ~60%, medium, secondary */
.card .big .muted,.big .muted,.big span{font-size:.6em!important;font-weight:500;letter-spacing:-.01em;color:var(--text-2)}
.stat-v{font-weight:700;letter-spacing:-.03em}
.muted{color:var(--text-2)}
.small{font-size:13px}
:focus-visible{outline-color:var(--ink)}   /* grey/ink focus ring, never the accent */

/* --------------------------------------------------------------- surfaces -- */
.card{
  border-radius:var(--r-card);padding:var(--card-pad);margin-bottom:var(--card-gap);background:var(--surface);
  box-shadow:var(--shadow-card);
  transition:transform 120ms cubic-bezier(.2,.8,.2,1);
}
.sect-b{border-radius:var(--r-card);box-shadow:var(--shadow-card)}
.sect{margin-bottom:var(--section-gap)}
.item{border-radius:var(--r-card);background:var(--surface);box-shadow:var(--shadow-card);padding:12px 14px;transition:transform var(--d-spring) var(--spring),background var(--d-hover)}
.list{gap:var(--card-gap)}
.tile{border-radius:var(--r-card);box-shadow:var(--shadow-card)}
.lrow{min-height:56px;padding:12px 16px}
.lrow+.lrow::before{inset-inline-start:16px}
.lrow:has(.lrow-i)+.lrow:has(.lrow-i)::before{inset-inline-start:58px}
/* Identity icons are chrome; metric graphics carry their own semantic hues. */
.lrow-i{
  width:30px;height:30px;border-radius:var(--r-icon);font-size:17px;
  background:var(--surface-2);color:var(--text-2);
}
.lrow-i .icn{--icon-stroke:2}
.thumb{border-radius:var(--r-inner);outline:1px solid rgb(0 0 0 / .1);outline-offset:-1px}
:root:not([data-theme="light"]) .thumb{outline-color:rgb(255 255 255 / .1)}
.divider{background:var(--sep)}

/* ---------------------------------------------------------------- chips -- */
.tag{border-radius:var(--r-pill);padding:3px 10px;font:var(--t-status);background:color-mix(in srgb,var(--text) 6%,transparent);color:var(--text-2)}
.tag.acc{background:var(--control-tint);color:var(--text)}
.chip{border-radius:var(--r-pill);background:var(--surface);box-shadow:var(--shadow-card);font-weight:500;min-height:32px;padding:0 14px}
.chip.on{background:var(--ink);color:var(--on-ink);box-shadow:none}

/* -------------------------------------------------------------- buttons -- */
.btn{border-radius:var(--r-pill);min-height:52px;padding:13px 20px;font-weight:600;background:var(--surface-2)}
.btn.primary{background:var(--ink);color:var(--on-ink)}
.btn.primary:active{background:var(--ink);opacity:.86}
.btn.tinted{background:var(--control-tint);color:var(--text)}
.btn.danger{background:var(--danger-tint);color:var(--danger-fg)}
.btn.sm{min-height:36px;padding:7px 14px;border-radius:var(--r-pill);font-size:15px;background:color-mix(in srgb,var(--text) 6%,transparent)}
.btn.sm.primary{background:var(--ink);color:var(--on-ink)}
.btn.xs{min-height:0;border-radius:var(--r-pill)}
.btn.ghost,.btn.plain{background:none;color:var(--text);font-weight:500}
.btn{transition:transform var(--d-spring) var(--spring),background var(--d-hover),opacity var(--d-hover)}
.btn:active{transform:scale(var(--press));transition-duration:var(--d-press);transition-timing-function:var(--ease-out)}
/* toolbar rounded-square (Bevel "+" top-right) */
.iconbtn{
  width:36px;height:36px;border-radius:var(--r-inner);background:var(--surface);font-size:17px;
  box-shadow:var(--shadow-card);
  transition:transform var(--d-spring) var(--spring),background var(--d-hover);
}
.iconbtn:active{transform:scale(var(--press));transition-duration:var(--d-press);transition-timing-function:var(--ease-out)}
.seg{border-radius:var(--r-pill);padding:3px}
.seg-sel{border-radius:var(--r-pill);box-shadow:0 1px 2px rgb(0 0 0 / .04)}
/* dark: the thumb has to be lighter than its track, or the selection all but disappears */
:root:not([data-theme="light"]) .seg{background:var(--surface-2)}
:root:not([data-theme="light"]) .seg-sel{background:var(--surface-3)}
.field,.input,.search .input,.searchf .field{border-radius:var(--r-inner)}
.sw.on{background:var(--ink)}
.sw.on .knob{background:var(--on-ink);box-shadow:none}

/* ---------------------------------------------------- week strip (Home) -- */
.wday{border-radius:var(--r-inner);padding:6px 0}
.wday .lbl{font:var(--t-label);color:var(--text-2)}
.wday .num{font-size:17px;font-weight:600}
.wday.today .num{background:var(--ink)!important;color:var(--on-ink)!important;box-shadow:none!important}
.wday .dot.done{background:var(--done)}
.wday .dot.ovr{background:var(--orange)}
.today-row{border-radius:var(--r-inner);background:var(--surface-2)!important;transition:transform var(--d-spring) var(--spring)}

/* ---------------------------------------------------------------- charts -- */
/* A line chart paints its metric's hue itself (LineChart `metric` → var(--metric-<name>), the
   caller's colour as fallback) and exposes it as --chart-hue; nothing here recolours a line. */
.chart svg>polyline{stroke-width:2}
.chart svg>defs stop:first-child{stop-opacity:.16}
/* latest point: the dot plus an 8px halo of its own hue at 20% */
.chart svg>circle:last-of-type{
  stroke:var(--chart-hue,currentColor);stroke-opacity:.2;stroke-width:8;
  paint-order:stroke;transform-box:fill-box;transform-origin:center;
}
.chart svg line{stroke-opacity:.5}
/* The activity heatmap, the body map and the muscle bars draw their ramps from --acc in
   index.css; in here that is the metric's hue instead of the account accent. */
.hm-wrap[data-metric="time"],.hm-legend[data-metric="time"]{--acc:var(--metric-time)}
.hm-wrap[data-metric="vol"],.hm-legend[data-metric="vol"]{--acc:var(--metric-volume)}
.bodymap,.bodymap+.hm-legend,.mrow,.ins-bar{--acc:var(--metric-sets)}
.bodymap.hm-strength,.hm-legend.hm-strength{--acc:var(--metric-e1rm)}

/* --------------------------------------------- dock: tab bar + Start + live bar -- */
#dock{
  position:fixed;z-index:50;inset-inline:max(16px,calc((100vw - 520px)/2));
  bottom:calc(8px + var(--sab));
  display:grid;grid-template-columns:minmax(0,1fr) 56px;column-gap:12px;row-gap:12px;align-items:center;
}
#dock #tabbar{
  position:relative;inset:auto;bottom:auto;grid-column:1 / -1;grid-row:2;
  display:flex;align-items:center;gap:10px;
  height:64px;padding:0;border:0;background:none;box-shadow:none;
  -webkit-backdrop-filter:none;backdrop-filter:none;
}
#dock .tab-menus{
  display:flex;align-items:center;flex:1;min-width:0;height:64px;padding:4px;
  border-radius:var(--r-pill);
  view-transition-name:dock;
}
#dock #tabbar .tab-menus button{flex:1;min-width:0;border-radius:var(--r-pill)}
#dock #tabbar .tab-menus button.on{background:color-mix(in srgb,var(--text) 8%,transparent)}
/* Tabs switch instantly; selection keeps the same icon stroke. */
#dock #tabbar button{gap:3px;padding-top:0;font:var(--t-label);color:var(--text-2);justify-content:center;height:100%}
#dock #tabbar button .icn{width:24px;height:24px;font-size:24px;--icon-stroke:2;color:var(--text-2)}
#dock #tabbar button.on{color:var(--text)}
#dock #tabbar button.on .icn{color:var(--text);--icon-stroke:2}
#dock #tabbar button:active .icn{transform:scale(var(--press));transition:transform var(--d-press) var(--ease-out)}
#dock #tabbar button.start{margin-top:0;flex:1;width:auto;border-radius:var(--r-pill)}
#dock #tabbar button.start .cir{display:grid;place-items:center;width:24px;height:24px;border-radius:0;background:none;box-shadow:none}
#dock #tabbar button.start .cir .icn{color:var(--text-2);fill:none;translate:1px 0}
#dock #tabbar button.start.on .cir .icn{color:var(--text)}
#dock #tabbar button.start .start-lbl{position:static;width:auto;height:auto;overflow:visible;clip-path:none;color:var(--text-2);font-weight:inherit}
#dock #tabbar button.start.rec .cir{background:none;box-shadow:none}
#dock #tabbar button.start.rec .cir::after{display:none}
#dock #tabbar button.start.rec .start-lbl{color:var(--info-fg)}
#dock #tabbar[data-labels="off"] button :is(.tab-label,.start-lbl){display:none}
#dock #tabbar[data-labels="off"] button .icn{width:26px;height:26px}
#dock #tabbar[data-labels="off"] .cir{width:26px;height:26px}
#dock .dock-coach-row{grid-column:2;grid-row:1;display:flex;justify-content:flex-end;pointer-events:none}
#dock>.live-bar{grid-column:1 / -1;grid-row:1;min-width:0}
#dock:has(.dock-coach)>.live-bar{grid-column:1}
#dock .dock-coach-surface{flex:none;width:56px;height:56px;border-radius:50%;pointer-events:auto}
#dock .dock-coach{display:grid;place-items:center;width:100%;height:100%;padding:0;border-radius:inherit}
#dock .dock-coach .icn{width:24px;height:24px;--icon-stroke:2}
#dock .dock-coach:active{transform:scale(var(--press))}
body:has(#dock .dock-coach) #app{padding-bottom:calc(180px + var(--sab))}
body:has(#dock.has-live .dock-coach) #app{padding-bottom:calc(var(--live-bar-height,64px) + 104px + var(--sab))}
@keyframes dockin{from{transform:translateY(24px)}}
#dock{animation:none}

/* the live bar */
.live-bar{
  border-radius:var(--r-card);min-height:60px;padding:8px 8px 8px 16px;cursor:pointer;
  display:block;overflow:hidden;
  animation:none;
}
@keyframes liveup{from{transform:translateY(40px) scale(.96);opacity:0}to{transform:none;opacity:1}}

.live-in{display:flex;align-items:center;gap:12px;min-height:44px}
@keyframes livein{from{opacity:0;transform:translateY(10px) scale(.98)}to{opacity:1;transform:none}}
.live-tx{flex:1;min-width:0}
.live-t{display:flex;align-items:baseline;gap:8px;min-width:0}
.live-name{font:var(--t-section);letter-spacing:-.02em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.live-s{font:var(--t-meta);color:var(--text-2);margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.live-time{font-size:17px;font-weight:600;font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.live-check{
  flex:none;width:44px;height:44px;border-radius:50%;display:grid;place-items:center;
  background:var(--ink);color:var(--on-ink);font-size:20px;
  transition:transform 120ms cubic-bezier(.2,.8,.2,1);
}
.live-check .icn{--icon-stroke:2}
.live-check:active{transform:scale(var(--press));transition:transform var(--d-press) var(--ease-out)}
.live-ring{flex:none;width:38px;height:38px;position:relative}
.live-ring svg{width:100%;height:100%;transform:rotate(-90deg)}
.live-ring circle{fill:none;stroke:var(--info);stroke-width:3.5;stroke-linecap:round;stroke-dasharray:1;stroke-dashoffset:calc(1 - var(--p));transition:stroke-dashoffset 1s linear}
.live-ring::before{content:'';position:absolute;inset:1.25px;border-radius:50%;border:3.5px solid color-mix(in srgb,var(--info) 18%,transparent);box-sizing:border-box}
.live-clock{display:inline-block;font:var(--t-card);letter-spacing:-.03em;font-variant-numeric:tabular-nums;color:var(--text)}
@keyframes tick{from{transform:translateY(-35%);opacity:.35}to{transform:none;opacity:1}}
.live-k{font:var(--t-status);color:var(--info-fg)}
.live-acts{display:flex;gap:6px;flex:none}
.live-pill{
  height:34px;min-width:44px;padding:0 10px;border-radius:var(--r-pill);font-size:14px;font-weight:600;
  background:color-mix(in srgb,var(--text) 8%,transparent);color:var(--text);
  transition:transform 120ms cubic-bezier(.2,.8,.2,1);
}
.live-pill.strong{background:var(--ink);color:var(--on-ink);padding:0 14px}
.live-pill:active{transform:scale(var(--press));transition:transform var(--d-press) var(--ease-out)}
.live-pill:disabled{color:var(--text-3)}
/* the docked rest bar stands down while the live bar shows the rest */
body:has(#dock.has-live) #timer.rest{display:none}
body.live-handoff #app{opacity:0}

/* the upstream rest/hold bar (workout screen) gets the same glass */
#timer{
  background-color:var(--glass-fill);background-image:var(--glass-sheen);
  -webkit-backdrop-filter:blur(24px) saturate(180%);backdrop-filter:blur(24px) saturate(180%);
  box-shadow:var(--glass-elevation);border-radius:var(--r-card);
  animation:liveup var(--d-spring) var(--spring) both;
}
#timer .bar i{background:var(--info)}
#timer .t{font-weight:700;letter-spacing:-.035em}
#timer .acts .btn{border-radius:var(--r-pill)}
/* Live log v2: on the workout screen the bar floats like the tab bar's dock (same insets), a
   rounded glass slab over the sets rather than a sheet edge flush with the bottom. The progress
   line runs inside its top edge, clear of the rounded corners. */
body.no-tabbar #timer{
  inset-inline:max(16px,calc((100vw - 520px)/2));bottom:calc(8px + var(--sab));
  border-radius:28px;padding:12px 12px 12px 18px;
  box-shadow:var(--glass-elevation),0 12px 32px -12px rgba(0,0,0,.55);
}
body.no-tabbar #timer .bar{inset-inline:22px;top:0;height:3px;border-radius:0 0 3px 3px;overflow:hidden}
body.no-tabbar #timer.working{box-shadow:inset 0 0 0 var(--hair) var(--ink),var(--glass-elevation)}

/* ------------------------------------------------------------- sheets -- */
/* Sheets are content, so they are opaque (glass is for floating controls only), which also
   keeps a large backdrop blur off the sheet's slide-up on iOS. */
.mback{background:var(--scrim);animation:fadein var(--d-sheet) var(--ease-out) both}
@keyframes fadein{from{opacity:0}to{opacity:1}}
.sheet{
  background:var(--surface-sheet);
  border-radius:var(--r-sheet) var(--r-sheet) 0 0;padding:8px 20px calc(22px + var(--sab));
  box-shadow:none;
  animation:sheetup var(--d-spring) var(--spring) both;
}
:root[data-theme="light"] .sheet{background:var(--surface-sheet)}
.sheet .grab{width:36px;height:5px;margin:4px auto 16px;background:var(--label-4)}
.sheet h3{font:var(--t-date);letter-spacing:-.02em}
.sheet .card,.sheet .sect-b,.sheet .item{background:var(--surface)}
.sheet:has(.start-sheet){view-transition-name:start-sheet}

@keyframes rowin{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

/* ------------------------------------------------------------- motion -- */
/* screen change: rise in (upstream keys #app on the route) */
@keyframes viewfade{from{opacity:0;transform:translateY(14px) scale(.99)}to{opacity:1;transform:none}}
#app.vfade{animation:viewfade var(--d-page) var(--ease-out)}
/* staggered reveal of a screen's blocks: 40ms apart, at most four steps */
@keyframes rise{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}
#app.vfade>.narrow>*,#app.vfade>div>.card,#app.vfade>div>.sect,#app.vfade>div>.list>*{animation:rise var(--d-page) var(--ease-out) both}
#app.vfade>.narrow>*:nth-child(2),#app.vfade .list>*:nth-child(2){animation-delay:40ms}
#app.vfade>.narrow>*:nth-child(3),#app.vfade .list>*:nth-child(3){animation-delay:80ms}
#app.vfade>.narrow>*:nth-child(4),#app.vfade .list>*:nth-child(4){animation-delay:120ms}
#app.vfade>.narrow>*:nth-child(n+5),#app.vfade .list>*:nth-child(n+5){animation-delay:160ms}
/* press scale on cards/rows (class from lib/motion.js on pointerdown) */
.pressed{transform:scale(var(--press))!important;transition:transform var(--d-press) var(--ease-out)!important}
.card.tappable,.item,.today-row{will-change:auto}
/* chart: the line draws on once, the area fades in, then the latest point settles in */
@keyframes draw{to{stroke-dashoffset:0}}
@keyframes areain{from{opacity:0}to{opacity:1}}
@keyframes dotin{from{transform:scale(0)}to{transform:none}}
.chart svg>polyline{stroke-dasharray:1;stroke-dashoffset:1;animation:draw 600ms var(--ease-out) 120ms forwards}
.chart svg>polygon{animation:areain 600ms var(--ease-out) 240ms both}
.chart svg>circle:last-of-type{animation:dotin var(--d-spring) var(--spring) 600ms both}
/* set check: ▶→✓ scales in from .8 */
@keyframes ckpop{from{transform:scale(.8)}to{transform:none}}
@keyframes ckin{from{opacity:0;transform:scale(.8)}to{opacity:1;transform:none}}
.chk.on,.ck.on{animation:ckpop var(--d-pop) var(--ease-out)}
.chk.on .icn,.ck.on svg{animation:ckin var(--d-pop) var(--ease-out) both}

/* Start → picker → live log, as one move (View Transitions; lib/motion.js) */
::view-transition-group(*){animation-duration:450ms;animation-timing-function:var(--spring)}
:root[data-vt="rise"]::view-transition-old(root){animation:vt-sink var(--d-page) var(--ease-out) both}
:root[data-vt="rise"]::view-transition-new(root){animation:vt-rise 450ms var(--spring) both}
:root[data-vt="rise"]::view-transition-old(dock){animation:vt-drop var(--d-sheet) var(--ease-in-exit) both}
:root[data-vt="rise"]::view-transition-old(start-sheet){animation:vt-drop var(--d-page) var(--ease-in-exit) both}
@keyframes vt-sink{to{opacity:0;transform:scale(.94)}}
@keyframes vt-rise{from{opacity:0;transform:translateY(60px) scale(.98)}to{opacity:1;transform:none}}
@keyframes vt-drop{to{opacity:0;transform:translateY(120%)}}

/* index.css already stops every element's animation and transition here; pseudo-elements and
   view transitions are not elements, and a line that never draws on must still be drawn. */
@media (prefers-reduced-motion:reduce){
  .chart svg>polyline{stroke-dasharray:none;stroke-dashoffset:0}
  .pressed{transform:none!important}
  #dock #tabbar button.start.rec .cir::before{animation:none}
  :root::view-transition-group(*),:root::view-transition-old(*),:root::view-transition-new(*){animation:none!important}
}

/* ID-scoped material rules must also yield to motion and opaque accessibility fallbacks. */
:root[data-vt] #dock .tab-menus,body.wk-dragging #dock .tab-menus,body.wk-settle #dock .tab-menus,
#dock .tab-menus.glass-moving,#timer.glass-moving,:root[data-vt] #timer,
body.wk-dragging #timer,body.wk-settle #timer{
  background-color:var(--glass-flat);-webkit-backdrop-filter:none;backdrop-filter:none;
}
#timer.working,body.no-tabbar #timer,body.no-tabbar #timer.working{box-shadow:var(--glass-elevation)}
/* Structural bars are solid: scrolling labels must never show through their titles. */
.conn-bar,.whdr.stick{background:var(--canvas);-webkit-backdrop-filter:none;backdrop-filter:none}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .glass,#dock .tab-menus,#timer{background:var(--surface)!important;box-shadow:var(--shadow-float)}
}
@media (prefers-reduced-transparency:reduce),(prefers-contrast:more){
  .glass,#dock .tab-menus,#timer{
    background:var(--surface)!important;-webkit-backdrop-filter:none!important;backdrop-filter:none!important;
    box-shadow:0 0 0 1px var(--outline-input);
  }
}

/* Keep all five destinations evenly spaced on compact phones. */
@media (max-width:360px){
  #dock{inset-inline:10px}
  #dock #tabbar{gap:8px}
  #dock #tabbar .tab-menus button{font-size:10px}
}
#dock #tabbar button:focus-visible,.live-expand:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
.live-expand{display:block;text-align:start;background:none;color:inherit;padding:0;min-height:44px;touch-action:pan-x}
.live-expand .live-t,.live-expand .live-s{display:flex}
.live-expand .live-s{display:block}


@media (prefers-reduced-transparency:reduce),(prefers-contrast:more){
  #dock #tabbar button.start .cir{background:var(--ink)!important;color:var(--on-ink)}
}

/* Selected Split: timer controls above, full exercise name below. All glyphs share
   the product's 24px grid and 2px round stroke; progress is not an action icon. */
#dock .live-bar .icn{width:24px;height:24px;font-size:24px;--icon-stroke:2;flex:none}
#dock .live-bar.is-rest{padding:0;border-radius:var(--r-card)}
.live-rest-top{display:flex;align-items:center;gap:8px;padding:12px 12px 8px}
.live-rest-toggle{display:flex;align-items:center;gap:8px;min-width:max-content;min-height:44px;flex:1;padding:0;background:none;color:var(--text);text-align:start}
.live-rest-clock{display:flex;flex-direction:column;gap:2px;min-width:0}
.live-rest-clock .live-clock{min-inline-size:5ch;white-space:nowrap;font-size:24px;font-weight:600;line-height:1.05;letter-spacing:-.035em}
.live-rest-clock .live-k{font:var(--t-meta);color:var(--text-2)}
.live-rest-toggle>.icn{color:var(--text-2)}
.live-rest-toggle>.icn[data-icon="play"]{translate:1px 0}
.live-rest .live-ring{width:28px;height:28px}
.live-rest .live-acts{gap:8px;flex:0 1 auto;min-width:0;max-width:calc(100% - 128px);flex-wrap:wrap;justify-content:flex-end}
.live-adjust{display:flex;gap:0;border-radius:var(--r-pill);background:color-mix(in srgb,var(--text) 5%,transparent)}
.live-rest .live-pill{height:44px;min-width:44px;padding:0 10px;font-size:14px;background:none}
.live-rest .live-pill.strong{background:var(--ink);color:var(--on-ink);padding:0 16px;max-width:100%;overflow-wrap:anywhere;height:auto;min-height:44px}
.live-rest .live-pill:disabled{color:var(--text-3);cursor:default}
.live-rest .live-pill:disabled:active{transform:none}
.live-next{display:flex;align-items:center;gap:12px;width:100%;padding:10px 16px 14px;min-height:64px;border-top:var(--hair) solid color-mix(in srgb,var(--text) 7%,transparent);color:var(--text)}
.live-next-copy{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}
.live-next-label{font:var(--t-meta);color:var(--text-2);font-variant-numeric:tabular-nums}
.live-next .live-name{font-size:14px;font-weight:500;line-height:1.4;white-space:normal;overflow-wrap:anywhere;letter-spacing:0}
.live-next>.icn{color:var(--text-2)}
.live-ex-icon{display:grid;place-items:center;width:28px;height:28px;flex:none;color:var(--text-2)}
.live-bar button{touch-action:manipulation}
.live-bar .live-expand{touch-action:pan-x}
.live-bar button:focus-visible{outline:2px solid var(--text);outline-offset:2px}
@media (max-width:360px){
  .live-rest-top{padding:12px 10px 8px;gap:6px}
  .live-rest-toggle{gap:6px}
  .live-rest .live-acts{gap:6px;max-width:calc(100% - 120px)}
  .live-rest .live-pill{padding:0 8px}
  .live-rest .live-pill.strong{padding:0 12px}
}
/* Compact logging shares a stable row with Coach in both work and rest states. */
#dock .live-bar.is-compact{height:64px;min-height:64px;padding:8px 8px 8px 16px;border-radius:var(--r-pill);box-sizing:border-box}
#dock .is-compact .live-in{gap:8px;height:48px}
#dock .is-compact .live-name{font-size:14px;line-height:20px}
#dock .is-compact .live-s{font-size:12px;line-height:18px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#dock .is-compact .live-expand{min-width:0;flex:1}
#dock .is-compact .live-rest-top{height:48px;padding:0;gap:8px}
#dock .is-compact .live-rest-top>.live-expand{display:flex;flex-direction:column;justify-content:center;height:44px;padding-inline-start:0}
#dock .is-compact .live-clock{font-size:20px;line-height:24px;min-inline-size:5ch}
#dock .is-compact .live-k{font-size:12px;line-height:18px;color:var(--text-2)}
#dock .is-compact .live-rest-toggle{display:grid;place-items:center;flex:none;min-width:44px;width:44px;height:44px;padding:0;border-radius:50%;background:color-mix(in srgb,var(--text) 6%,transparent)}

/* Notifications clear the full dock, including Coach and either live-bar height. */
body:has(#dock .dock-coach) #toast{bottom:calc(152px + var(--sab))}
body:has(#dock.has-live) #toast{bottom:calc(var(--live-bar-height,88px) + 96px + var(--sab))}
body:has(#dock.has-live .dock-coach) #toast{bottom:calc(var(--live-bar-height,64px) + 96px + var(--sab))}
body:has(#dock.dock-live-only.has-live) #toast{bottom:calc(var(--live-bar-height,88px) + 28px + var(--sab))}

/* Secondary pages retain the live workout bar, without tabs or the Start button. */
body:has(#dock.dock-live-only.has-live) #app{padding-bottom:calc(var(--live-bar-height,88px) + 24px + var(--sab))}
body:has(#dock.dock-live-only.has-live) #app:has(>.coach-workspace){padding-bottom:0}
body:has(#dock.dock-live-only.has-live) .coach-workspace{--coach-live-inset:calc(var(--live-bar-height,88px) + 20px + var(--sab))}
body:has(#dock.dock-live-only.has-live) .coach-workspace .coach-room{padding-bottom:var(--coach-live-inset)}

/* ============================================================================
   openGym — Bevel live workout (reskin/bevel, chunk 2)
   ----------------------------------------------------------------------------
   The live log as a full-height sheet: the parent recedes to a band above it, the sheet has a
   rounded top and a grabber, the header pins the big clock, the coral Finish and the ··· glass
   button. Exercises are Bevel cards; set rows are outlined cells that fill sage when logged, with
   the rest on the line between rows. The page still scrolls on the window (upstream relies on
   it): the band and the rounded top are a fixed cap (.wk-cap, App.jsx) the session scrolls under.
   Presentation only; refs/DESIGN-SYSTEM.md §2.7–2.10 and §3.
   ========================================================================== */

:root{
  --sheet-top:calc(max(var(--sat),12px) + var(--conn,0px) + 10px);
  --wk-parent:color-mix(in oklab,var(--canvas),#000 15%);   /* the parent, receded under a scrim */
  --wex-pad:var(--card-pad);
}
:root:not([data-theme="light"]){--wk-parent:#0B0B0B}

/* ---------------------------------------------------------------- sheet -- */
body:has(.wk-sheet){background:var(--wk-parent)}
body #app:has(.wk-sheet),body.no-tabbar #app:has(.wk-sheet),body.no-tabbar.resting #app:has(.wk-sheet){padding-top:var(--sheet-top);padding-bottom:0}
#app.vfade:has(.wk-sheet){animation:none}
.wk-sheet{
  position:relative;margin-inline:calc(-1 * var(--pad));padding:0 var(--pad) calc(24px + var(--sab));
  min-height:calc(100dvh - var(--sheet-top));
  background:var(--surface-sheet);border-radius:var(--r-sheet) var(--r-sheet) 0 0;
}
/* room for the floating rest bar: its height, the gap under it, and a breath above it */
body.resting .wk-sheet{padding-bottom:calc(var(--workout-timer-height,80px) + 20px + var(--sab))}
.wk-sheet #toast,.wk-sheet #toast.show,.wk-sheet #toast.has-action{
  position:relative;inset:auto;transform:none;width:100%;max-width:none;margin:8px 0;
}
.wk-sheet #toast:not(.show){display:none}
/* Without View Transitions the sheet still presents: it rises from the bottom (transform/opacity). */
@supports not (view-transition-name:none){
  .wk-sheet{animation:wk-rise 280ms cubic-bezier(0.32,0.72,0,1) backwards}
}
@keyframes wk-rise{from{transform:translateY(56px);opacity:0}}

/* The fixed cap: the receded parent above the sheet and the sheet's rounded top. It reaches a
   screen above itself so a dragged sheet never uncovers what scrolled off its top. */
.wk-cap{
  position:fixed;z-index:25;top:-100vh;inset-inline:0;pointer-events:none;overflow:hidden;
  height:calc(100vh + var(--sheet-top) + var(--r-sheet));
}
.wk-cap::after{
  content:'';position:absolute;top:calc(100vh + var(--sheet-top));left:50%;transform:translateX(-50%);
  width:min(100%,560px);height:calc(var(--r-sheet) * 2);
  border-radius:var(--r-sheet) var(--r-sheet) 0 0;box-shadow:0 0 0 100vmax var(--wk-parent);
}

/* The band above the sheet as a plain solid bar on the top edge (App.jsx .wk-bar): iOS 26 tints
   the status bar from a fixed element like this, and otherwise shows the session that scrolled
   up under the clock, blurred. Same colour as the cap, so it is invisible everywhere else. */
.wk-bar{position:fixed;z-index:26;top:0;inset-inline:0;height:var(--sheet-top);background-color:var(--wk-parent);pointer-events:none}

/* drag down on the grabber (components/SheetGrab.jsx): 1:1, then spring back or dismiss */
body.wk-dragging .wk-sheet,body.wk-dragging .wk-cap,body.wk-settle .wk-sheet,body.wk-settle .wk-cap{transform:translateY(var(--sheet-dy,0px))}
body.wk-dragging .wk-cap::after{transform:translateX(-50%)}
body.wk-settle .wk-sheet,body.wk-settle .wk-cap{transition:transform 280ms cubic-bezier(0.32,0.72,0,1)}
body.wk-dragging{-webkit-user-select:none;user-select:none}
/* glass goes flat while anything moves (iOS Safari keeps its frames) */
:root[data-vt] .glass,body.wk-dragging .glass,body.wk-settle .glass{background-color:var(--glass-flat);-webkit-backdrop-filter:none;backdrop-filter:none}

/* -------------------------------------------------------------- header -- */
.wk-top,.wk-top.stick{
  position:sticky;top:var(--sheet-top);z-index:20;
  margin:0 calc(-1 * var(--pad)) 10px;padding:0 var(--pad) 8px;
  background:var(--surface-sheet);-webkit-backdrop-filter:none;backdrop-filter:none;
  border-radius:var(--r-sheet) var(--r-sheet) 0 0;
  view-transition-name:live-sheet;
}
.wk-grab{
  display:flex;justify-content:center;align-items:flex-start;width:100%;height:44px;padding:7px 0 0;
  background:none;border:0;touch-action:none;cursor:grab;
}
.wk-grab i{display:block;width:36px;height:5px;border-radius:3px;background:var(--label-4)}
.wk-grab:focus-visible{outline:none}
.wk-grab:focus-visible i{outline:2px solid var(--ink);outline-offset:3px}
span.wk-grab{cursor:default}
.wk-top .hdr.whdr-bar{margin:0 0 10px;gap:10px;align-items:center}
.wk-top .whdr-mid{text-align:start}
.wk-clock{font:var(--t-timer);letter-spacing:-.03em;font-variant-numeric:tabular-nums;color:var(--text);white-space:nowrap}
.ticker>span{display:inline-block;animation:tick var(--d-sheet) cubic-bezier(0.32,0.72,0,1) both}
.wk-top .whdr-mid .sub{
  display:flex;align-items:baseline;gap:6px;margin-top:3px;
  font:var(--t-meta);font-variant-numeric:tabular-nums;color:var(--text-2);-webkit-line-clamp:none;line-clamp:none;
}
.wk-top .whdr-name{font:inherit;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.wk-count{flex:none}
.wk-count::before{content:'·';margin-inline-end:6px;color:var(--text-2)}
.btn.pill.whdr-finish{min-height:44px;padding:0 20px;font:var(--t-section);max-width:44%}
.btn.pill.whdr-finish.finish{background:var(--danger-tint);color:var(--danger-fg)}
.iconbtn.wk-more{
  width:44px;height:44px;border-radius:50%;font-size:20px;flex:none;color:var(--text);
  background-color:var(--glass-fill);background-image:var(--glass-sheen);box-shadow:var(--glass-elevation);
}
.wk-top .wprog{height:3px;margin-bottom:6px;background:var(--surface-2)}
/* the rail (components/WorkoutChips.jsx): one segment per exercise, filled as far as its work sets
   are ticked, the current one outlined; "2/6" beside it opens the whole session as a list */
.wrail{display:flex;align-items:center;gap:8px;margin:-6px 0 -4px}
.wrail .chips.wchips{flex:1;display:flex;gap:4px;margin:0;padding:0;overflow:visible;touch-action:auto}
.wrail .wchip{flex:1 1 0;min-width:0;height:44px;padding:0;border-radius:0;background:none;box-shadow:none}
.wrail .wchip i{display:block;width:100%;height:6px;border-radius:3px;overflow:hidden;background:var(--surface-2)}
.wrail .wchip b{display:block;height:100%;background:var(--done);transform-origin:left;transition:transform var(--d-sheet) var(--ease-out)}
[dir="rtl"] .wrail .wchip b{transform-origin:right}
.wrail .wchip.cur i{box-shadow:inset 0 0 0 1.5px var(--ink);background:color-mix(in oklab,var(--surface-2),var(--ink) 12%)}
.wrail .wchip.cur{box-shadow:none}
.wrail .wchip:focus-visible{outline:none}
.wrail .wchip:focus-visible i{outline:2px solid var(--ink);outline-offset:3px}
.wrail-n{flex:none;display:inline-flex;align-items:center;gap:3px;height:44px;padding:0 2px 0 8px;border:0;background:none;color:var(--text-2);font:600 15px/1 var(--font);font-variant-numeric:tabular-nums}
.wrail-n .icn{font-size:12px}
.wjump h3{margin:0 0 8px}
.wjump ol{list-style:none;margin:0;padding:0}
.wjump li+li{border-top:1px solid var(--hairline)}
.wjump button{display:grid;grid-template-columns:30px minmax(0,1fr) auto;gap:12px;align-items:center;width:100%;min-height:60px;padding:0;border:0;background:none;color:var(--text);text-align:start}
.wjump .nm{font:var(--t-section);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-transform:capitalize}
.wjump .ct{font:var(--t-status);color:var(--text-2);font-variant-numeric:tabular-nums}
.wjump [aria-current] .ct{color:var(--text);font-weight:600}
.wchip-n{width:30px;height:30px;border-radius:50%;display:grid;place-items:center;font:600 14px/1 var(--font);font-variant-numeric:tabular-nums;color:var(--text-2);box-shadow:inset 0 0 0 1.5px var(--outline-input)}
.wchip-n.partial{background:linear-gradient(to top,var(--done-tint) 50%,transparent 50%);color:var(--text)}
.wchip-n.done{background:var(--done-tint);color:var(--done-fg);box-shadow:none}
[aria-current]>.wchip-n{box-shadow:inset 0 0 0 2px var(--ink);color:var(--text)}

.wk-top .wprog i{background:var(--done)}
.wk-sheet .wl-unit{scroll-margin-top:calc(var(--whdr-h,110px) + var(--sheet-top) + 12px)}

/* ------------------------------------------------------- exercise card -- */
.wex{background:var(--surface);border-radius:var(--r-card);box-shadow:var(--shadow-card);padding:var(--wex-pad)}
@media (max-width:404px){.wex{--wex-pad:12px}}
.wex .exmedia{border-radius:var(--r-inner)}
.wk-sheet .exmedia img,.wk-sheet .exmedia video{height:96px;object-fit:contain}
.wk-sheet .exmedia.broken{display:none}
.wk-sheet .exmedia .giftoggle{display:none}
.wex .exhd{gap:12px;margin-bottom:10px}
.wex-title{flex:1;min-width:0}
.wex-name{font:var(--t-card);letter-spacing:-.02em}
.wex.compact .wex-name,.wex.dense .wex-name{font-size:17px}
.wex-sub{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 6px;margin-top:2px;font:var(--t-meta);color:var(--text-2)}
.wex-sub .tag{background:none;padding:0;border-radius:0;font:inherit;color:inherit}
.wex-sub>*+*::before{content:'·';margin-inline-end:6px;color:var(--text-2)}
.wex-n{font-variant-numeric:tabular-nums}
.wex-acts{gap:6px;flex:none}
.wex-acts .iconbtn{width:44px;height:44px;border-radius:var(--r-inner);background:var(--surface);box-shadow:inset 0 0 0 1px var(--outline-input);color:var(--text-2)}
.wex-sets{margin:4px -6px 0}
/* the set circle's ring overhangs its 24px box by 3px, and a swipe row clips: the table is 3px
   wider each side and its rows pad back in, so the columns stay where index.css puts them */
.wex .sethead,.wex .setrow:not(.side),.wex .setrow-side{padding-inline:6px}
.wex .sethead{font:var(--t-label);letter-spacing:.06em;color:var(--text-2)}
.wex .sethead .ck-sp{width:44px}

/* ------------------------------------------------------- set rows: a table -- */
/* Live log v2 (docs/dev/LIVE_LOG_V2.md): SET · LAST TIME · the fields · ✓. The number is plain, the
   reference sits in its own column, the fields are filled cells you type into (the +/- buttons are
   a setting, off by default), and a logged row tints sage as a whole. */
.wex .setrow,.wex .setrow-side{gap:6px;border-radius:12px;transition:background-color var(--d-pop) var(--ease-out)}
.wex .setrow{min-height:44px;padding-block:2px}
.wex .setrow.done,.wex .setrow-side.done,.wex .setrow-side .setrow.side.done{background:var(--done-tint)}
.wex .setrow-side .setrow.side.done{background:none}
.wex .setrow.done,.wex .setrow.side.done{opacity:1}
.wex .setrow+.setrow::before,.wex .setrow-side+.setrow-side::before{display:none}
.wex .sethead{gap:6px;min-height:22px;align-items:flex-end;font:var(--t-label);letter-spacing:.06em;text-transform:uppercase;color:var(--text-2)}
.wex .sethead .ck-sp{width:36px}
/* the set number: plain, a warm-up's W and a drop's D in their colours */
.wex .setrow .n,.wex .setrow-side>.n{
  background:none;color:var(--text);font-size:15px;font-weight:600;font-variant-numeric:tabular-nums;overflow:visible;min-height:44px;
  transition:color var(--d-pop) var(--ease-out);
}
.wex .setrow.done .n,.wex .setrow-side.done>.n{color:var(--done-fg);background:none}
.wex .n.k-w .n-num,.wex .n.k-d .n-num,.wex .n.k-f .n-num{display:none}
.wex .n .n-k,.wex .n .failmark{
  position:static;inset:auto;width:auto;height:auto;min-width:0;padding:0;margin:0;border-radius:0;
  background:none;box-shadow:none;font:inherit;font-weight:700;line-height:1;
}
.wex .n.k-w{color:var(--warning-fg)}
.wex .n.k-d{color:var(--info-fg)}
.wex .n.k-f,.wex .n.k-f .failmark{color:var(--danger-fg)}
.wex .n:not(.k-f) .failmark{display:none}
/* the reference column; its heading is the Last time / Best switch */
.wex .setrow .prev,.wex .sethead .p-sp{flex:1 1 0;min-width:0;text-align:start}
.wex .setrow .prev{font:var(--t-status);color:var(--text-3);font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.wex .setrow.done .prev{color:var(--done-fg);opacity:.75}
.wex .sethead .p-sp{position:relative;padding:0;font:inherit;letter-spacing:inherit;text-transform:inherit;color:inherit;background:none;border:0;cursor:pointer}
.wex .sethead .p-sp::after{content:'';position:absolute;inset:-11px 0}
/* the fields: filled cells; with the +/- buttons on they keep their stepper widths */
.wex .setrow .stp{
  min-height:40px;background:var(--surface-2);border-radius:10px;box-shadow:none;
  transition:background-color var(--d-pop) var(--ease-out);
}
.wex .setrow .stp.plain.w,.wex .sethead.plain .w-sp{flex:0 0 72px;min-width:0}
.wex .setrow .stp.plain.r,.wex .sethead.plain .r-sp{flex:0 0 56px;min-width:0}
.wex .setrow .stp:focus-within{box-shadow:inset 0 0 0 1.5px var(--ink)}
.wex .setrow.done .stp{background:transparent}
.wex .setrow .stp .num,.wex .subrow .stp .num{font-size:17px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--text);transition:color var(--d-pop)}
.wex .setrow.done .stp .num{color:var(--done-fg)}
.wex .setrow .stp button{height:40px;color:var(--text-2)}
.wex .setrow .effcell.is-empty{background:var(--surface-2);box-shadow:none}
/* ✓: an empty square that fills sage */
.wex .set-ck{position:relative;width:36px;height:36px;border-radius:10px;background:none;color:#fff;box-shadow:inset 0 0 0 1.5px var(--outline-input);transition:background-color var(--d-pop) var(--ease-out),box-shadow var(--d-pop)}
.wex .set-ck::after{content:'';position:absolute;inset:-4px}
.wex .set-ck .icn{position:absolute;transition:opacity var(--d-pop) var(--ease-out),transform var(--d-pop) var(--ease-out)}
.wex .set-ck .icn:first-child{display:none}
.wex .set-ck .icn:last-child{font-size:17px;opacity:0;transform:scale(.6)}
.wex .set-ck.on{background:var(--done);box-shadow:none}
.wex .set-ck.on .icn{animation:none}
.wex .set-ck.on .icn:last-child{opacity:1;transform:none}
.wex .setgo{width:36px;height:36px;border-radius:10px}
.wex .setrow.side .sidetag{background:none;color:var(--text-2)}
.wex .setrow.side.done .sidetag{color:var(--done-fg)}

/* ------------------------------------------------- rest on the row line -- */
/* Planned: the time, small on a hairline. Running: the time draining along the line, a tap sets it
   on the wheel; −15 / +15 / Skip are on the rest bar docked at the bottom (RestTimer). */
.rest-line{position:relative;display:flex;align-items:center;justify-content:center;height:18px;padding-inline-start:32px}
.rest-line::before{content:'';position:absolute;inset-inline:32px 40px;top:50%;height:1px;background:var(--hairline)}
.rest-chip{position:relative;padding:0 6px;background:var(--surface);font:600 11px/1 var(--font);font-variant-numeric:tabular-nums;color:var(--text-3)}
button.rest-chip::after{content:'';position:absolute;inset:-4px -8px}
.rest-line.is-on{height:28px}
.rest-line.is-on::before{display:none}
.rest-run{display:grid;grid-template-columns:1fr auto;gap:10px;align-items:center;width:100%;height:28px;padding:0 6px 0 0;background:none;color:var(--text)}
.rest-track{height:3px;border-radius:2px;background:var(--surface-2);overflow:hidden}
.rest-track i{display:block;height:100%;background:var(--ink);transform-origin:left;transition:transform 1s linear}
[dir="rtl"] .rest-track i{transform-origin:right}
.rest-t{display:inline-block;min-width:36px;text-align:end;font:700 13px/1 var(--font);font-variant-numeric:tabular-nums;animation:tick var(--d-sheet) cubic-bezier(0.32,0.72,0,1) both}
.rest-line.paused .rest-run{opacity:.55}

/* ------------------------------------------------------- the card's lines -- */
.wex .wex-sub .planline{font:inherit;color:inherit}
.wex .exnote{display:flex;gap:6px;align-items:flex-start;margin:0 0 4px;padding:0;background:none;border-radius:0;font:var(--t-status);color:var(--text-2);white-space:pre-wrap}
.wex .exnote .icn{flex:none;font-size:14px;margin-top:-1px}
.wex .exnote.pinned{color:var(--goal-fg)}
.wex .noprog{min-height:28px;margin:0 0 4px;font:var(--t-status)}
.wex .noprog .chip{min-height:32px;background:none;padding:0 4px;font-weight:600}
.wex .progline{align-items:flex-start;margin:0 0 4px;font:var(--t-status);color:var(--text-2)}
.wex .progline .icn{font-size:14px;color:var(--done-fg)}
.wex .progline.warn .icn{color:var(--warning-fg)}

/* ------------------------------------------------------------ footer -- */
.wex-foot{
  display:flex;justify-content:center;flex-wrap:wrap;gap:0 4px;
  margin:10px calc(-1 * var(--wex-pad)) calc(-1 * var(--wex-pad) + 2px);padding:2px var(--wex-pad);
  border-top:1px solid var(--hairline);
}
.wex-foot .btn.sm{width:auto;min-height:44px;padding:0 12px;background:none;color:var(--text-2);font-size:15px;font-weight:500}
.wex-foot .btn.sm .icn{font-size:15px}
.wex-foot .btn.sm:disabled{color:var(--text-3)}

/* Prev / Next say where they go; the session's quiet actions under them */
.wk-nav{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.wk-nav-b{display:flex;align-items:center;gap:6px;min-width:0;min-height:56px;padding:8px 12px;border:0;border-radius:16px;background:var(--surface);color:var(--text);text-align:start;transition:transform var(--d-press) var(--ease-out)}
.wk-nav-b:not(:disabled):active{transform:scale(var(--press))}
.wk-nav-b:disabled{visibility:hidden}
.wk-nav-b.next{justify-content:flex-end;text-align:end}
.wk-nav-b>.icn{flex:none;color:var(--text-2)}
.wk-nav-b span{display:grid;grid-template-columns:minmax(0,1fr);min-width:0}
.wk-nav-b small{font:var(--t-status);color:var(--text-2)}
.wk-nav-b b{font:600 15px/1.25 var(--font);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-transform:capitalize}
.wk-links{display:flex;justify-content:center;flex-wrap:wrap;gap:0 4px;margin-top:6px}
.wk-links button{display:inline-flex;align-items:center;gap:6px;min-height:44px;padding:0 12px;border:0;background:none;color:var(--text-2);font:500 15px/1 var(--font);transition:transform var(--d-press) var(--ease-out)}
.wk-links button:active{transform:scale(var(--press))}
.wk-links button.on{color:var(--text)}
.wk-links .icn{font-size:15px}
.btn.wk-finish-cta{margin-top:8px}

/* ------------------------------------------------------------ supersets -- */
/* each member is its own card; a round link chip on a hairline joins them */
.ss-card{background:none;box-shadow:none;padding:0;border-radius:0}
.ss-hd{justify-content:space-between;margin:0 4px 8px;color:var(--text-2);font:var(--t-status)}
.ss-hd .btn{color:var(--text-2)}
.ss-amp{position:relative;display:flex;align-items:center;justify-content:center;height:48px;margin:0;color:var(--text-2)}
.ss-amp::before{content:'';position:absolute;inset-inline:28px;top:50%;height:1px;background:var(--hairline)}
.ss-amp::after{content:'';position:absolute;left:50%;top:50%;width:40px;height:40px;margin:-20px 0 0 -20px;border-radius:50%;background:var(--surface);box-shadow:var(--shadow-card),inset 0 0 0 1px var(--hairline)}
.ss-amp .icn{position:relative;z-index:1;font-size:18px}

/* ------------------------------------------------------------ list view -- */
.wk-sheet .workout-list{gap:20px}
.wk-sheet .wl-unit,.wk-sheet .wl-unit.cur{background:none;padding:0;border-radius:0;box-shadow:none}
.wk-sheet .wl-unit.cur .wex{box-shadow:var(--shadow-card),0 0 0 1.5px color-mix(in oklab,var(--text) 20%,transparent)}
.wk-sheet .wl-hd{margin:0 4px 8px}
.wk-sheet button.wl-summary{background:var(--surface);border-radius:var(--r-card);box-shadow:var(--shadow-card);padding:14px 16px}
.wk-sheet .wl-summary .tag.acc{background:var(--done-tint);color:var(--done-fg)}
.wk-sheet .workout-swipe-card,.wk-sheet .workout-swipe-preview{background:var(--surface-sheet)}

/* ------------------------------------------- live bar ⇄ sheet (View Transitions) -- */
/* The live bar and the sheet's header share a name, so the bar grows into the header and the
   header shrinks back into the bar; the sheet body rises behind it, the parent sinks to .94. */
.live-bar{view-transition-name:live-sheet}
:root[data-vt^="live"]::view-transition-group(live-sheet){animation-duration:280ms;animation-timing-function:cubic-bezier(0.32,0.72,0,1)}
:root[data-vt^="live"]::view-transition-image-pair(live-sheet){overflow:clip;border-radius:var(--r-card)}
:root[data-vt^="live"]::view-transition-old(live-sheet),:root[data-vt^="live"]::view-transition-new(live-sheet){height:100%;object-fit:cover;object-position:50% 0}
:root[data-vt^="live"]::view-transition-old(live-sheet){animation:vt-out 220ms var(--ease-out) both}
:root[data-vt^="live"]::view-transition-new(live-sheet){animation:vt-in 220ms var(--ease-out) both}
:root[data-vt="live-open"]::view-transition-old(root){animation:vt-sink 280ms cubic-bezier(0.32,0.72,0,1) both}
:root[data-vt="live-open"]::view-transition-new(root){animation:vt-rise 280ms cubic-bezier(0.32,0.72,0,1) both}
:root[data-vt="live-open"]::view-transition-old(dock){animation:vt-drop var(--d-sheet) var(--ease-in-exit) both}
:root[data-vt="live-close"]::view-transition-old(root){animation:vt-sheet-down var(--d-sheet) var(--ease-in-exit) both}
:root[data-vt="live-close"]::view-transition-new(root){animation:vt-unsink 280ms cubic-bezier(0.32,0.72,0,1) both}
:root[data-vt="live-close"]::view-transition-new(dock){animation:vt-dock-in 280ms cubic-bezier(0.32,0.72,0,1) both}
@keyframes vt-out{to{opacity:0}}
@keyframes vt-in{from{opacity:0}}
@keyframes vt-unsink{from{opacity:0;transform:scale(.94)}}
@keyframes vt-sheet-down{to{opacity:0;transform:translateY(30%)}}
@keyframes vt-dock-in{from{opacity:0;transform:translateY(40px)}}
@media (prefers-reduced-motion:reduce){
  .ticker>span,.rest-t{animation:none}
  .wex .setrow,.wex .set-ck,.rest-track i,.wrail .wchip b{transition:none}
  body.wk-settle .wk-sheet,body.wk-settle .wk-cap{transition:none}
}
@media (prefers-reduced-transparency:reduce),(prefers-contrast:more){
  .iconbtn.wk-more{background:var(--surface);background-image:none;box-shadow:inset 0 0 0 1px var(--outline-input)}
}

/* Primary gym actions keep a full thumb target. */
body.no-tabbar #timer .btn,body.no-tabbar #timer .tclock{min-height:44px;min-width:44px}
.wk-sheet .swhint button,.wk-sheet #toast .toast-act{min-height:44px}

:root[data-vt="live-close"]::view-transition-group(live-sheet){animation-duration:220ms}

/* live log v2: the table's widths. Plain fields hug their numbers so the reference column keeps
   room; an effort column narrows them further. Headings stay on one line. */
.wex .sethead>span{line-height:1.15;overflow-wrap:anywhere}
.wex .sethead .p-sp{display:block;line-height:1.15;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.wex .setrow.eff3 .stp.plain.w,.wex .sethead.plain.eff3 .w-sp{flex-basis:64px}
.wex .setrow.eff3 .stp.plain.r,.wex .sethead.plain.eff3 .r-sp{flex-basis:48px}
.wex .setrow.eff3 .effcell,.wex .setrow.eff3 .effcell-stp,.wex .sethead.eff3 .eff-sp{flex:0 0 52px;min-width:0}
.wex .setrow .effcell.is-empty{background:none;box-shadow:inset 0 0 0 1px var(--hairline);color:var(--text-3);font-size:13px;min-height:40px;border-radius:10px}
.wex .setrow.done .effcell.is-empty{box-shadow:inset 0 0 0 1px color-mix(in oklab,var(--done-fg) 30%,transparent)}
.wex .sethead .p-sp{align-self:flex-end}

/* ============================================================================
   openGym — Bevel skin: the finish (reskin/bevel)
   ----------------------------------------------------------------------------
   Finish pill → confirm sheet (neutral Cancel, coral Finish, the discard set apart) → the summary,
   a full-height locked sheet (confetti once, hero numbers counting up, records, every exercise
   with its best set) → the effort dial (warm wash that deepens with the rating) → Save → Home.
   Markup: sheets.jsx FinishConfirm / FinishSummary, components/EffortDial, Confetti, CountUp.
   Only transform and opacity animate; under reduced motion nothing moves (index.css) and the
   confetti never renders.
   ========================================================================== */

/* -------------------------------------------------------- confirm sheet -- */
.fin-confirm h3{margin-bottom:8px}
.fin-warn{
  display:flex;align-items:flex-start;gap:10px;margin:0;padding:12px 14px;border-radius:var(--r-inner);
  background:var(--strain-tint);color:var(--text);font:var(--t-meta);text-wrap:pretty;
}
.fin-warn .icn{flex:none;font-size:18px;color:var(--strain);margin-top:1px}
.fin-acts{display:grid;grid-template-columns:minmax(0,1fr) max-content;gap:10px;margin-top:20px}
.fin-acts .btn{min-height:52px;padding:0 14px;border-radius:var(--r-pill);font:var(--t-section);letter-spacing:-.012em}
.fin-cancel{background:var(--surface);box-shadow:var(--shadow-card);color:var(--text)}
.fin-acts .fin-go{white-space:nowrap;padding-inline:12px}
.fin-go{background:var(--danger-tint);color:var(--danger-fg);gap:6px}
.fin-go .icn{font-size:17px}
.fin-discard{
  display:flex;align-items:center;justify-content:center;gap:6px;width:100%;min-height:44px;margin-top:14px;
  border-radius:var(--r-pill);font:var(--t-meta);font-weight:500;color:var(--danger-fg);
  transition:transform var(--d-spring) var(--spring);
}
.fin-discard .icn{font-size:16px}
.fin-discard:active{transform:scale(var(--press));transition-duration:var(--d-press);transition-timing-function:var(--ease-out)}

/* ------------------------------------------------- the sheet and its steps -- */
/* A full-height task sheet: the parent peeks above it. Locked, and nothing in it drags it. */
.sheet:has(>.fin){top:calc(var(--sat) + 12px);max-height:none;padding:0;overflow:hidden;display:flex;flex-direction:column}
.sheet:has(>.fin)>.grab{display:none}
.fin{
  flex:1;min-height:0;display:flex;flex-direction:column;position:relative;
  --pr:var(--stress);
}
:root[data-theme="light"] .fin{--pr:color-mix(in oklab,var(--stress),black 32%)}
.fin-pane{flex:1;min-height:0;display:flex;flex-direction:column;position:relative}
.fin-pane[hidden]{display:none}
.fin-body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:28px var(--margin) 24px;position:relative}
.fin-foot{flex:none;position:relative;padding:10px var(--margin) calc(12px + var(--sab));background:var(--surface-sheet)}
.fin-foot::before{
  content:'';position:absolute;inset-inline:0;bottom:100%;height:28px;pointer-events:none;
  background:linear-gradient(to bottom,transparent,var(--surface-sheet));
}
/* Continue / Back: a push, x 24px and a fade; back is the same path, quicker */
.fin[data-dir="1"] .fin-pane:not([hidden]){animation:fin-fwd var(--d-sheet) var(--ease-out) both}
.fin[data-dir="-1"] .fin-pane:not([hidden]){animation:fin-bwd 240ms var(--ease-out) both}
@keyframes fin-fwd{from{opacity:0;transform:translateX(24px)}to{opacity:1;transform:none}}
@keyframes fin-bwd{from{opacity:0;transform:translateX(-24px)}to{opacity:1;transform:none}}

/* --------------------------------------------------------------- summary -- */
.fin-hero{position:relative;z-index:2;text-align:center}
.fin-badge{
  width:64px;height:64px;margin:0 auto 14px;border-radius:50%;display:grid;place-items:center;font-size:30px;
  background:var(--strain-tint);color:var(--strain);
  animation:fin-pop 560ms var(--spring-bounce) 80ms both;
}
@keyframes fin-pop{from{opacity:0;transform:scale(.5)}to{opacity:1;transform:none}}
.sheet .fin-title{font:var(--t-title);letter-spacing:-.02em;margin:0;text-wrap:balance}
.fin-sub{font:var(--t-meta);color:var(--text-2);margin-top:4px}

.fin-pair{position:relative;z-index:2;display:grid;grid-template-columns:1fr 1fr;margin:26px 0 20px}
.fin-pair>div{text-align:center;padding:0 8px;min-width:0}
.fin-pair>div+div{border-inline-start:1px solid var(--hairline)}
.fin-big{
  font:var(--t-timer);font-size:clamp(26px,8.4vw,34px);letter-spacing:-.03em;
  font-variant-numeric:tabular-nums;white-space:nowrap;
}
.fin-unit{font-size:.55em;font-weight:500;letter-spacing:-.01em;color:var(--text-2);margin-inline-start:4px}
.fin-lbl{font:var(--t-meta);color:var(--text-2);margin-top:4px}

.fin-tiles{display:grid;grid-template-columns:1fr 1fr;gap:var(--card-gap);margin-bottom:var(--card-gap)}
.fin-tile{
  display:flex;align-items:center;gap:12px;min-width:0;padding:14px;border-radius:var(--r-card);
  background:var(--surface);box-shadow:var(--shadow-card);
}
.fin-tile[data-metric="sets"]{--tint:var(--metric-sets)}
.fin-tile[data-metric="pr"]{--tint:var(--pr)}
.fin-tile-i{
  width:44px;height:44px;flex:none;border-radius:var(--r-inner);display:grid;place-items:center;font-size:20px;
  background:color-mix(in srgb,var(--tint) 15%,transparent);color:var(--tint);
}
.fin-tile>div{min-width:0}
.fin-tile-v{font:700 22px/1.1 var(--font);letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.fin-tile .fin-lbl{margin-top:2px;font-size:14px;overflow-wrap:anywhere}

.fin-recs,.fin-ex{border-radius:var(--r-card);background:var(--surface);box-shadow:var(--shadow-card);overflow:hidden}
.fin-recs{margin-bottom:var(--card-gap)}
.fin-rec{position:relative;display:flex;align-items:center;gap:12px;min-height:52px;padding:10px 16px;font:var(--t-meta)}
.fin-rec+.fin-rec::before,.fin-ex-row+.fin-ex-row::before{content:'';position:absolute;top:0;inset-inline:58px 0;height:1px;background:var(--hairline)}
.fin-ex-row+.fin-ex-row::before{inset-inline-start:16px}
.fin-rec-i{
  width:30px;height:30px;flex:none;border-radius:var(--r-icon);display:grid;place-items:center;font-size:16px;
  background:color-mix(in srgb,var(--pr) 16%,transparent);color:var(--pr);
}
.fin-rec.e1 .fin-rec-i{background:color-mix(in srgb,var(--metric-e1rm) 16%,transparent);color:var(--metric-e1rm)}
.fin-rec b{font-weight:600}
.fin-rec-v{font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}

.fin-ex-row{
  position:relative;padding:12px 16px;
  animation:rowin var(--d-spring) var(--spring) both;animation-delay:calc(min(var(--i,0),4) * 40ms + 240ms);
}
.fin-ex-n{font:var(--t-section);letter-spacing:-.012em;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fin-ex-c{flex:none;font:var(--t-meta);color:var(--text-2);font-variant-numeric:tabular-nums}
.fin-ex-b{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;margin-top:3px;font:var(--t-meta);font-variant-numeric:tabular-nums}
.fin-ex-k{color:var(--text-2)}
.fin .pr{background:color-mix(in srgb,var(--pr) 16%,transparent);color:var(--goal-fg)}
.fin .pr.e1{background:color-mix(in srgb,var(--metric-e1rm) 16%,transparent);color:var(--metric-e1rm-fg)}

/* confetti: one burst from the badge, pastels of the metric palette */
.confetti{position:absolute;top:70px;left:50%;width:0;height:0;pointer-events:none;z-index:1}
.confetti i{position:absolute;left:0;top:0;animation:cf-x 1200ms cubic-bezier(.1,.6,.3,1) var(--d) both}
.confetti b{
  display:block;width:var(--w);height:var(--h);margin:calc(var(--h) / -2) 0 0 calc(var(--w) / -2);
  border-radius:2px;background:var(--c);animation:cf-y 1200ms var(--d) both;
}
@keyframes cf-x{from{transform:translateX(0)}to{transform:translateX(var(--x))}}
@keyframes cf-y{
  0%{opacity:0;transform:translateY(0) rotate(0deg) scale(.3);animation-timing-function:cubic-bezier(.2,.7,.35,1)}
  8%{opacity:1}
  32%{transform:translateY(var(--up)) rotate(calc(var(--r) * .35)) scale(1);animation-timing-function:cubic-bezier(.45,0,.85,.55)}
  78%{opacity:1}
  100%{opacity:0;transform:translateY(var(--fall)) rotate(var(--r)) scale(.9)}
}

/* ---------------------------------------------------------------- effort -- */
.fin-effort{isolation:isolate}
/* the warm wash: the effort hue rising from the foot, deeper with every step of the rating */
.fin-effort::before{
  content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:radial-gradient(130% 62% at 50% 100%,color-mix(in srgb,var(--metric-effort) 34%,transparent),transparent 72%);
  opacity:var(--e,0);transition:opacity 320ms var(--ease-out);
}
.fin-effort .fin-body{display:flex;flex-direction:column;align-items:center;text-align:center;padding-top:20px}
.fin-effort .fin-foot{background:none}
.fin-effort .fin-foot::before{display:none}
.fin-back{
  position:absolute;top:14px;inset-inline-start:14px;width:40px;height:40px;border-radius:50%;
  display:grid;place-items:center;font-size:18px;color:var(--text);background:var(--surface);box-shadow:var(--shadow-card);
  transition:transform var(--d-spring) var(--spring);
}
.fin-back::before{content:'';position:absolute;inset:-2px;border-radius:50%}
.fin-back:active{transform:scale(var(--press));transition-duration:var(--d-press);transition-timing-function:var(--ease-out)}
.sheet .fin-q{font:var(--t-date);letter-spacing:-.02em;margin:44px 0 20px}

.dial{
  position:relative;width:min(82vw,330px);aspect-ratio:300/272;flex:none;cursor:pointer;
  touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent;
  border-radius:40%;outline:none;
  --dial-from:color-mix(in oklab,var(--strain-2) 45%,var(--surface));
}
.dial:focus-visible{outline:none}
.dial-focus{fill:none;stroke:var(--ink);stroke-width:2;stroke-linecap:round;visibility:hidden}
.dial:focus-visible .dial-focus{visibility:visible}
.dial svg{display:block;width:100%;height:100%;overflow:visible}
.dial-track,.dial-fill{fill:none;stroke-width:24;stroke-linecap:round}
.dial-track{stroke:color-mix(in oklab,var(--text) 9%,transparent)}
.dial-fill{stroke-dasharray:1 1;transition:stroke-dashoffset 260ms var(--spring)}
.dial-tick{fill:var(--surface)}
.dial-tick.lit{fill:#fff;opacity:.9}
.dial-end{font:600 15px var(--font);fill:var(--text);text-anchor:middle;font-variant-numeric:tabular-nums}
.dial-knob{transform-box:view-box;transform-origin:150px 150px;transition:transform 260ms var(--spring)}
.dial-knob circle{fill:#fff;stroke:rgb(0 0 0 / .08);stroke-width:1}
.dial-knob .dial-knob-dot{fill:var(--metric-effort);stroke:none}
.dial-num{position:absolute;inset-inline:0;top:calc(150 / 272 * 100%);transform:translateY(-50%);text-align:center;pointer-events:none}
.dial-num span{
  display:inline-block;font:700 92px/1 var(--font);letter-spacing:-.04em;font-variant-numeric:tabular-nums;
  color:var(--metric-effort-fg);
  animation:dial-pop 220ms var(--spring) both;
}
.dial:not(.on) .dial-num span{color:var(--text-2);text-shadow:none}
@keyframes dial-pop{from{opacity:.4;transform:scale(.86)}to{opacity:1;transform:none}}
.fin-level{margin-top:22px;max-width:320px;min-height:100px}
.fin-level-n{font:var(--t-title);letter-spacing:-.02em;animation:fin-lvl 240ms var(--ease-out) both}
@keyframes fin-lvl{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.fin-level-d{font:var(--t-body);color:var(--text-2);margin-top:6px;text-wrap:pretty}

@media (prefers-reduced-motion:reduce){
  .confetti{display:none}
}

/* ============================================================================
   Home v2 (docs/dev/HOME_REDESIGN_V2.md)
   ----------------------------------------------------------------------------
   views/Home.jsx only, loaded after bevel.css. The atmosphere is one full-bleed wash in the
   hue of this week's pace (data-zone); cards stay flat. Ink is the one primary (Start).
   Motion: the hero arrives once per app session (.home-arrive), the header folds with
   scroll through --p (transforms and opacity only), and all of it stops under reduced motion.
   ========================================================================== */

.home{--p:0;--z:var(--sleep);--z-fg:var(--bodyweight-fg);position:relative;isolation:isolate;display:flex;flex-direction:column;gap:12px;padding-bottom:24px}
.home{--wash-top:color-mix(in oklab,var(--z) 70%,var(--canvas))}
:root[data-theme="light"] .home{--wash-top:color-mix(in oklab,var(--z) 46%,var(--canvas))}
.home[data-zone="above"]{--z:var(--strain);--z-fg:var(--warning-fg)}
.home[data-zone="on"]{--z:var(--recovery);--z-fg:var(--done-fg)}
.home[data-zone="below"]{--z:var(--info);--z-fg:var(--info-fg)}
.home [data-state="ready"]{--st:var(--recovery)}
.home [data-state="recovering"]{--st:var(--stress)}
.home [data-state="fatigued"]{--st:var(--danger)}
.home :is(button,[role="button"]){touch-action:manipulation}

/* ----------------------------------------------------------------- wash -- */
/* The zone hue fades to the canvas along an ease-out curve (ten stops, no banding), with a
   faint glow across the full top edge. No corner blob. */
.home-wash{position:absolute;z-index:-1;top:calc(-1 * (var(--sat) + 72px));left:50%;width:100vw;margin-inline-start:-50vw;height:700px;pointer-events:none;
  background:
    radial-gradient(140% 55% at 50% 0%,color-mix(in oklab,var(--z) 22%,transparent),transparent 70%),
    linear-gradient(180deg,
      var(--wash-top) 0%,color-mix(in oklab,var(--z) 64.4%,var(--canvas)) 10%,
      color-mix(in oklab,var(--z) 56%,var(--canvas)) 20%,color-mix(in oklab,var(--z) 46.2%,var(--canvas)) 30%,
      color-mix(in oklab,var(--z) 36.4%,var(--canvas)) 40%,color-mix(in oklab,var(--z) 27.3%,var(--canvas)) 50%,
      color-mix(in oklab,var(--z) 17.5%,var(--canvas)) 62%,color-mix(in oklab,var(--z) 9.1%,var(--canvas)) 75%,
      color-mix(in oklab,var(--z) 2.8%,var(--canvas)) 88%,var(--canvas) 100%);
  transform:translateY(calc(var(--p) * -140px));opacity:calc(1 - var(--p) * .55);will-change:transform}
:root[data-theme="light"] .home-wash{background:
    radial-gradient(140% 55% at 50% 0%,color-mix(in oklab,var(--z) 18%,transparent),transparent 70%),
    linear-gradient(180deg,
      var(--wash-top) 0%,color-mix(in oklab,var(--z) 42.3%,var(--canvas)) 10%,
      color-mix(in oklab,var(--z) 36.8%,var(--canvas)) 20%,color-mix(in oklab,var(--z) 30.4%,var(--canvas)) 30%,
      color-mix(in oklab,var(--z) 23.9%,var(--canvas)) 40%,color-mix(in oklab,var(--z) 17.9%,var(--canvas)) 50%,
      color-mix(in oklab,var(--z) 11.5%,var(--canvas)) 62%,color-mix(in oklab,var(--z) 6%,var(--canvas)) 75%,
      color-mix(in oklab,var(--z) 1.8%,var(--canvas)) 88%,var(--canvas) 100%)}
@media (prefers-contrast:more){.home-wash{display:none}}

/* After ~220px of scroll the number lives here. */
.home-tint-probe{position:absolute;width:0;height:0;overflow:hidden;visibility:hidden;color:var(--wash-top)}
.home-sticky{position:fixed;z-index:var(--z-dock);top:calc(var(--sat) + 10px);left:50%;display:flex;align-items:center;gap:6px;height:36px;padding:0 16px;border-radius:var(--r-pill);
  background:color-mix(in oklab,var(--z) 30%,var(--surface));box-shadow:var(--shadow-float);font:500 15px/1 var(--font);white-space:nowrap;pointer-events:none;
  opacity:calc((var(--p) - .7) * 3.4);transform:translate(-50%,calc((1 - var(--p)) * -10px))}
.home-sticky b{font-weight:700;font-variant-numeric:tabular-nums}

/* --------------------------------------------------------------- header -- */
.home-top{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:44px}
.home-date{display:inline-flex;align-items:center;gap:6px;min-height:44px;padding:0;font:600 15px/1.2 var(--font);color:var(--text);opacity:.85}
.home-date .icn{font-size:14px;--icon-stroke:2.6}
.home-avatar{position:relative;flex:none;width:44px;height:44px;border-radius:50%;display:grid;place-items:center;background:color-mix(in oklab,var(--surface) 70%,transparent);box-shadow:var(--shadow-card);font:600 17px/1 var(--font);color:var(--text)}
.home-avatar .tab-dot{top:2px;right:2px}

/* ----------------------------------------------------------------- hero -- */
.home-hero{display:flex;flex-direction:column;gap:12px;padding:14px 4px 4px}
.home-label{display:inline-flex;align-items:center;gap:6px;font:var(--t-label);letter-spacing:.08em;text-transform:uppercase;color:var(--text);opacity:.75}
.home-giant-row{display:flex;align-items:baseline;gap:8px;transform-origin:left bottom;transform:translateY(calc(var(--p) * -24px)) scale(calc(1 - var(--p) * .3));opacity:calc(1 - var(--p) * 1.3)}
.home-giant{font:700 96px/.9 var(--font);letter-spacing:-.045em;font-variant-numeric:tabular-nums}
.home-giant-u{font:600 22px/1 var(--font);opacity:.7}
.home-delta{align-self:flex-start;display:inline-flex;align-items:center;gap:4px;height:28px;margin-top:2px;padding:0 10px;border-radius:var(--r-pill);
  background:color-mix(in oklab,var(--z) 22%,transparent);font:600 14px/1 var(--font);font-variant-numeric:tabular-nums}
.home-delta .icn{font-size:12px}
.home-headline{margin:8px 0 0;font:700 24px/1.15 var(--font);letter-spacing:-.02em;text-wrap:balance}
.home-narr{margin:0;font:400 16px/1.42 var(--font);opacity:.85;text-wrap:pretty;max-width:60ch}

/* pace chart: lines in the text colour, the zone only on today's dot */
.home-chart{margin:10px 0 0;display:flex;flex-direction:column;gap:6px}
.home-chart svg{width:100%;height:auto;overflow:visible}
.home-chart .band{fill:color-mix(in oklab,var(--text) 10%,transparent)}
.home-chart .last{fill:none;stroke:color-mix(in oklab,var(--text) 45%,transparent);stroke-width:2;stroke-dasharray:4 5;stroke-linecap:round}
.home-chart .now{fill:none;stroke:var(--text);stroke-width:3;stroke-linejoin:round;stroke-linecap:round}
.home-chart .tip{fill:var(--z);stroke:var(--text);stroke-width:3}
.home-days{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;margin:0 -6px}
.home-days .wday{display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:2px;min-height:56px;padding:4px 0;background:none}
.home-days .wday .num{display:grid;place-items:center;width:30px;height:30px;margin:0;border-radius:50%;font-size:15px}
.home-day{display:flex;justify-content:center;font:var(--t-label);opacity:.7}
.home-day.today{opacity:1;font-weight:700}
.home-legend{display:flex;gap:14px;flex-wrap:wrap;font:500 13px/1 var(--font);opacity:.8}
.home-legend span{display:inline-flex;align-items:center;gap:6px}
.home-legend i{width:14px;height:3px;border-radius:2px;background:var(--text)}
.home-legend i.last{height:0;background:none;border-top:2px dashed color-mix(in oklab,var(--text) 55%,transparent)}
.home-legend i.band{height:10px;background:color-mix(in oklab,var(--text) 14%,transparent)}

/* -------------------------------------------------- today: the logbook -- */
.home-today{margin-top:10px;padding:18px 18px 14px;background:var(--surface);border-radius:var(--r-card);box-shadow:var(--shadow-card)}
.home-k{margin:0;font:var(--t-status);color:var(--text-2);font-variant-numeric:tabular-nums}
.home-today .ttl{margin:4px 0 12px;font:700 26px/1.1 var(--font);letter-spacing:-.02em;overflow-wrap:anywhere;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}
.home-ex{list-style:none;margin:0;padding:0}
.home-ex li{display:grid;grid-template-columns:30px 1fr auto;align-items:baseline;gap:8px;padding:12px 0;border-top:var(--hair) solid var(--hairline)}
.home-ex-n{font:500 13px/1 ui-monospace,"SF Mono",SFMono-Regular,Menlo,monospace;font-variant-numeric:tabular-nums;color:var(--text-3)}
.home-ex-n .icn{font-size:14px;color:var(--done-fg)}
.home-ex-name{display:flex;flex-direction:column;gap:3px;min-width:0;font:500 16px/1.3 var(--font)}
.home-ex-note{font:500 13px/1.2 var(--font);color:var(--warning-fg)}
.home-ex-note[data-state="fatigued"]{color:var(--danger-fg)}
.home-ex-p{font:600 16px/1 var(--font);font-variant-numeric:tabular-nums;white-space:nowrap}
.home-ex-p .x{margin:0 2px;font-weight:400;color:var(--text-3)}
.home-ex-more{display:flex;align-items:center;gap:4px;width:100%;min-height:44px;padding-inline-start:38px;border-top:var(--hair) solid var(--hairline);color:var(--text-2);font:500 15px/1 var(--font);text-align:start}
.home-ex-more .icn{font-size:12px;--icon-stroke:2.6}
.home-foot{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:2px;padding-top:14px;border-top:var(--hair) solid var(--hairline)}
.home-today[data-state="rest"] .home-foot{border-top:0;padding-top:0}
.home-sum{font:var(--t-meta);color:var(--text-2);font-variant-numeric:tabular-nums}
.home-sum b{font-weight:700;color:var(--text)}
.home-sum .arrow{color:var(--text-3)}
.home-go{flex:none;display:inline-flex;align-items:center;gap:6px;height:44px;padding:0 18px 0 14px;border-radius:var(--r-pill);background:var(--ink);color:var(--on-ink);font:600 16px/1 var(--font);
  transition:transform var(--d-press) var(--ease-out)}
.home-go:active{transform:scale(var(--press))}
.home-go.is-quiet{padding:0 16px;background:var(--surface-2);color:var(--text)}
.home-go>.icn{font-size:15px}
/* play → chevron on the way into the session */
.home-go-ic{position:relative;width:16px;height:16px}
.home-go-ic .icn{position:absolute;inset:0;font-size:15px;transition:transform 160ms var(--ease-out),opacity 160ms var(--ease-out)}
.home-go-ic .icn:first-child{margin-inline-start:2px}
.home-go-ic .icn:last-child{opacity:0;transform:translateX(-8px)}
.home-go[data-go] .home-go-ic .icn:first-child{opacity:0;transform:translateX(8px) scale(.6)}
.home-go[data-go] .home-go-ic .icn:last-child{opacity:1;transform:none}
.home-door{align-self:center;display:inline-flex;align-items:center;gap:6px;min-height:44px;padding:0 12px;color:var(--text-2);font:500 15px/1 var(--font)}
.home-door .icn{font-size:15px}
.home-queue{margin:0}
.home-queue.empty{font:var(--t-meta);color:var(--text-2)}
.home-welcome h2{margin:0 0 4px;font:700 22px/1.2 var(--font)}
.home-welcome p{margin:0 0 12px;font:var(--t-meta);color:var(--text-2)}

/* ------------------------------------------------------------- sections -- */
.home-sec{display:flex;align-items:baseline;justify-content:space-between;margin:14px 4px -2px}
.home-sec h3{margin:0;font:var(--t-section)}
.home-more{display:inline-flex;align-items:center;gap:2px;min-height:44px;margin:-14px 0;color:var(--text-2);font:500 15px/1 var(--font)}
.home-more .icn{font-size:13px}
.home .card{margin:0}
.home-empty{margin:8px 0 0;font:var(--t-meta);color:var(--text-2);text-wrap:pretty}

/* Recovery, after Bevel's muscle freshness: two columns of tiles, each the muscle cropped from
   the body map in its state colour, the name, the share recovered and ten pips. Filled pips sit
   a step back from the state colour, the last one in full, so the eye lands on the reading. */
.home-rec{display:grid;grid-template-columns:1fr 1fr;gap:20px 12px;width:100%;text-align:start;color:var(--text)}
.home-fr{--st-dim:color-mix(in oklch,var(--st) 42%,var(--surface));display:grid;grid-template-columns:44px minmax(0,1fr);grid-template-areas:"m n" "m s" "m p";column-gap:10px;row-gap:2px;align-items:center}
.home-fr .mt{grid-area:m;align-self:start;width:44px;height:44px}
.home-fr .n{grid-area:n;font:600 16px/1.2 var(--font);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.home-fr .s{grid-area:s;font:var(--t-status);color:var(--text-2);font-variant-numeric:tabular-nums;white-space:nowrap}
.home-fr .pips{grid-area:p;display:flex;gap:3px;margin-top:6px}
.home-fr .pips i{flex:1;max-width:10px;height:12px;border-radius:99px;background:var(--surface-2)}
.home-fr .pips i[data-on]{background:var(--st-dim)}
.home-fr .pips i[data-on="head"]{background:var(--st)}
.mt-sil,.mt-m{stroke:var(--surface);stroke-width:1.25px;vector-effect:non-scaling-stroke}
.mt-sil{fill:color-mix(in oklch,var(--text) 16%,var(--surface))}
.mt-m{fill:color-mix(in oklch,var(--text) 30%,var(--surface))}
.home-fr .mt-m.on{fill:var(--st)}
@media (max-width:360px){.home-rec{column-gap:8px}.home-fr{grid-template-columns:36px minmax(0,1fr);column-gap:8px}.home-fr .mt{width:36px;height:36px}}

/* Highlights and body weight share one row: highlights stack in the first column, body weight
   holds the second for their full height. Without body weight the highlights take the row. */
.home-hl{display:grid;gap:12px}
.home-hl[data-n="2"],.home-hl[data-n="3"],.home-hl[data-bw][data-n="1"],.home-hl[data-bw][data-n="2"]{grid-template-columns:1fr 1fr}
.home-hl[data-n="3"] .home-hl-c:first-child{grid-column:1 / -1}
.home-hl[data-bw] .home-hl-c{grid-column:1}
.home-hl[data-bw] .home-bw{grid-column:2;grid-row:1 / span 2}
.home-hl[data-bw][data-n="1"] .home-bw{grid-row:1}
.home-hl[data-bw][data-n="0"] .home-bw{grid-column:1 / -1;grid-row:auto}
.home-hl-c{display:flex;flex-direction:column;gap:4px;min-height:112px;width:100%;text-align:start;color:var(--text)}
.home-hl-c[data-hue="pr"]{--h:var(--goal-fg)}
.home-hl-c[data-hue="gap"]{--h:var(--sets-fg)}
.home-hl-c .e{display:inline-flex;align-items:center;gap:6px;margin-bottom:auto;font:600 13px/1.2 var(--font);color:var(--h)}
.home-hl-c .tt{font:var(--t-card);overflow-wrap:anywhere}
.home-hl-c .s{font:var(--t-meta);color:var(--text-2);font-variant-numeric:tabular-nums}

.home-bw{display:flex;flex-direction:column;min-width:0}
.home-bw-h{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:20px}
.home-bw-h h2{display:inline-flex;align-items:center;gap:6px;min-width:0;margin:0;font:600 13px/1.2 var(--font);color:var(--metric-bodyweight-fg);white-space:nowrap}
.home-bw-log{position:relative;display:grid;place-items:center;flex:none;width:28px;height:28px;margin:-4px -6px -4px 0;border-radius:99px;background:var(--surface-2);color:var(--text);transition:transform 150ms var(--ease-out)}
.home-bw-log::before{content:"";position:absolute;inset:-8px}
.home-bw-log:active{transform:scale(.92)}
.home-bw-log .icn{font-size:15px}
.home-bw-b{display:flex;flex-direction:column;gap:4px;flex:1;width:100%;margin-top:auto;padding-top:12px;text-align:start;color:var(--text)}
.home-bw-b .v{display:flex;align-items:baseline;gap:2px}
.home-bw-b .v b{font:700 34px/1 var(--font);letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.home-bw-b .u{margin-inline-start:3px;font:500 15px/1 var(--font);color:var(--text-2)}
.home-bw-b .d{font:var(--t-status);color:var(--text-2);font-variant-numeric:tabular-nums}
.home-bw-b .ch{margin-top:auto;padding-top:8px}
.home-bw-b .ch .spark{display:block;width:100%;height:auto}
.home-bw-b .g{font:var(--t-status);color:var(--text-2)}

/* ---------------------------------------------------------------- motion -- */
/* `backwards`, never `both`: once played, the scroll-linked transforms take over again. */
#app.vfade>.narrow.home>*{animation:none}
@keyframes home-wash{from{opacity:0}}
@keyframes home-rise{from{opacity:0;transform:translateY(8px)}}
@keyframes home-pop{from{opacity:0;transform:scale(.9)}}
@keyframes home-draw{from{stroke-dasharray:1;stroke-dashoffset:1}to{stroke-dasharray:1;stroke-dashoffset:0}}
.home-arrive .home-wash{animation:home-wash 600ms var(--ease-out) backwards}
.home-arrive .home-in{animation:home-rise 380ms var(--ease-out) backwards;animation-delay:calc(80ms + var(--d,0) * 60ms)}
.home-arrive .home-delta{animation:home-pop 320ms var(--spring) 420ms backwards}
.home-arrive .home-chart .now{animation:home-draw 700ms var(--ease-out) 200ms backwards}
.home-arrive .home-chart .tip{animation:home-pop 300ms var(--spring) 820ms backwards}
@media (prefers-reduced-motion:reduce){
  .home-arrive *{animation:none !important}
  .home-go-ic .icn{transition:none}
  .home-wash,.home-giant-row,.home-sticky{transform:none}
}

/* Stats and exercise progress (reskin/bevel): sparklines, hero numbers, banded line charts and
   records. The tabs and their cards are styles/stats-overview.css. Colour stays on the data, one hue
   per metric; the chrome around it is neutral. Motion is transform/opacity (plus the dash of a
   line or arc drawing on, once on mount); index.css stops all of it under reduced motion, and
   the rules at the end make sure what would have drawn on is simply drawn. */

/* --------------------------------------------------------------- sparkline -- */
.spark{flex:none;display:block;overflow:visible}
.spark-line{stroke-dasharray:1;stroke-dashoffset:1;animation:draw 700ms var(--ease-out) 150ms forwards}
.spark-band{animation:areain 500ms var(--ease-out) 300ms both}
.spark-dot{stroke:var(--chart-hue,currentColor);stroke-opacity:.22;stroke-width:7;paint-order:stroke;
  transform-box:fill-box;transform-origin:center;animation:dotin var(--d-spring) var(--spring) 750ms both}

/* -------------------------------------------------- hero over a chart -- */
.st-hero{margin:4px 0 12px;--hue:var(--chart)}
.st-hero .hv{font:700 34px/1.05 var(--font);letter-spacing:-.03em;font-variant-numeric:tabular-nums;color:var(--text)}
.st-hero .hv small{font-size:18px;font-weight:500;letter-spacing:0;color:var(--text-2);margin-inline-start:5px}
.st-hero .hs{display:flex;align-items:center;flex-wrap:wrap;gap:4px;margin-top:4px;font:var(--t-status);font-size:14px;
  font-variant-numeric:tabular-nums;color:var(--text)}
.st-hero .hs .icn{font-size:14px;--icon-stroke:2.4;color:var(--metric-status-fg)}
.st-hero .hs-dim{color:var(--text-2);font-weight:400}
.st-bw .st-hero,.st-bw{--hue:var(--metric-bodyweight);--metric-status-fg:var(--metric-bodyweight-fg)}
.st-ex,.st-ex .st-hero,.exh-hero .st-hero{--hue:var(--metric-e1rm);--metric-status-fg:var(--metric-e1rm-fg)}

/* ---------------------------------------------------- banded line chart -- */
.chart svg>.cband{animation:areain 600ms var(--ease-out) 200ms both}
.chart svg>.cavg{stroke-opacity:.75}
.chart svg>.cavg,.chart svg>.cavg-l{animation:areain 400ms var(--ease-out) 650ms both}
.chart svg>.cdot{animation:areain 300ms var(--ease-out) 600ms both}
.chart svg>.cbase{stroke-opacity:.9}
.chart+.seg-range{margin:10px 0 0}
.seg-range button{font-variant-numeric:tabular-nums}

/* ------------------------------------------------- records and history -- */
.st-recs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:2px 0 6px}
.st-rec{background:var(--surface-2);border-radius:var(--r-inner);padding:10px 12px;min-width:0}
.st-rec .rl{display:flex;align-items:center;gap:5px;font:var(--t-label);letter-spacing:.02em;color:var(--text-2);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.st-rec .rl .icn{font-size:12px;color:var(--stress);flex:none}
.st-rec b{display:block;margin-top:4px;font:var(--t-cell);font-variant-numeric:tabular-nums;color:var(--text)}
.st-rec b small{font-size:14px;font-weight:400;color:var(--text-2)}
.st-rec .rd{margin-top:3px;font:var(--t-label);color:var(--text-2)}

@media (prefers-reduced-motion:reduce){
  .spark-line{stroke-dasharray:none;stroke-dashoffset:0}
}

/* ============================================================================
   Stats v2 (docs/dev/STATS_REDESIGN_V2.md): the tab bar and the Overview tab
   (components/StatsOverview.jsx). Flat cards, colour only on the data: ink for the median,
   four lift hues checked for colour-blind separation, green up and orange down as small marks
   beside ink text. Motion: the charts arrive once per app session (.sto-arrive: lines draw,
   bars grow from their baseline), the muscle bars and their ticks move with an interruptible
   transform transition, a scrub follows the finger with none. index.css stops all of it under
   reduced motion.
   ========================================================================== */

.st-tabs{position:sticky;top:calc(var(--sat, 0px) + 8px);z-index:var(--z-sticky);margin:0 0 14px;
  background:color-mix(in oklab,var(--surface-2) 82%,transparent);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px)}
.st-pane{display:flex;flex-direction:column}
.st-pane>.card,.st-pane>.cols{margin-bottom:var(--card-gap)}

.sto{--c1:#4F8BE8;--c2:#E88A4F;--c3:#A87BE6;--c4:#7CC447;--up:var(--recovery);--down:var(--strain);--level:var(--text-3);--mus:var(--muscle-c);
  display:flex;flex-direction:column;gap:var(--card-gap)}
:root[data-theme="light"] .sto{--c1:#2F6FD6;--c2:#D9682A;--c3:#8A57D6;--c4:#4E9A1E}
.sto .card{margin:0}
.sto :is(button){touch-action:manipulation;-webkit-tap-highlight-color:transparent}
.sto-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
.sto-head h2{margin:0}
.sto-dim{font:var(--t-status);color:var(--text-2)}
.sto-axis{display:flex;justify-content:space-between;margin-top:6px;font:var(--t-label);letter-spacing:.04em;color:var(--text-3);font-variant-numeric:tabular-nums}

/* ------------------------------------------------------------------ hero -- */
.sto-hero{display:flex;flex-direction:column;gap:6px;padding:4px 0 2px;user-select:none;-webkit-user-select:none}
.sto-k{margin:0;font:var(--t-label);letter-spacing:.08em;text-transform:uppercase;color:var(--text-2);min-height:14px}
.sto-n{font:700 60px/1 var(--font);letter-spacing:-.035em;color:var(--text);font-variant-numeric:tabular-nums}
.sto-sub{margin:0;font:var(--t-meta);color:var(--text-2);text-wrap:pretty}
.sto-hint{color:var(--text-3)}
.sto-empty{display:flex;flex-direction:column;gap:6px;padding:8px 0 12px}
.sto-empty b{font:var(--t-card);color:var(--text)}
.sto-empty span{font:var(--t-meta);color:var(--text-2);max-width:36ch;text-wrap:pretty}
.sto-hero .seg-range{margin:8px 0 0}

.sto-chart{position:relative;margin-top:8px}
.sto-chart svg{display:block;width:100%;overflow:visible;touch-action:pan-y;cursor:ew-resize}
.sto-chart .base{stroke:var(--hairline);stroke-width:1;vector-effect:non-scaling-stroke}
.sto-chart .hair{stroke:var(--text);stroke-width:1;opacity:.45;vector-effect:non-scaling-stroke}
.sto-chart .ln{fill:none;stroke-width:2.5;stroke-linejoin:round;stroke-linecap:round;vector-effect:non-scaling-stroke}
.sto-chart .ln.back{stroke-width:1.5}
.sto-chart .area{stroke:none;opacity:.1}
.sto-chart .ink{stroke:var(--text);fill:var(--text)}
.sto-chart .c1{stroke:var(--c1);fill:var(--c1)}.sto-chart .c2{stroke:var(--c2);fill:var(--c2)}
.sto-chart .c3{stroke:var(--c3);fill:var(--c3)}.sto-chart .c4{stroke:var(--c4);fill:var(--c4)}
.sto-chart .ln{fill:none}
.sto-dot{position:absolute;width:12px;height:12px;margin:-6px 0 0 -6px;border-radius:50%;box-shadow:0 0 0 2px var(--canvas);pointer-events:none;background:var(--text)}
.sto-dot.c1{background:var(--c1)}.sto-dot.c2{background:var(--c2)}.sto-dot.c3{background:var(--c3)}.sto-dot.c4{background:var(--c4)}
.sto-base{position:absolute;left:0;transform:translateY(-130%);font:var(--t-label);letter-spacing:.04em;color:var(--text-3);pointer-events:none}

.sto-legend{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.sto-legend button{display:inline-flex;align-items:center;gap:6px;max-width:100%;min-height:36px;padding:0 12px;border:0;border-radius:var(--r-pill);
  background:var(--surface-2);font:500 13px/1 var(--font);color:var(--text-2);cursor:pointer;
  transition:background-color var(--d-hover) var(--ease-out),color var(--d-hover) var(--ease-out),transform var(--d-press) var(--ease-out)}
/* a 36px chip taps at 42, short of its 6px-gapped neighbours */
.sto-legend button{position:relative}
.sto-legend button::before{content:"";position:absolute;inset:-3px 0}
.sto-legend button span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:22ch}
.sto-legend button:active{transform:scale(var(--press))}
.sto-legend button[aria-pressed="true"]{background:var(--ink);color:var(--on-ink)}
.sto-legend i{flex:none;width:10px;height:3px;border-radius:2px;background:var(--text)}
.sto-legend button[aria-pressed="true"] i.ink{background:var(--on-ink)}
.sto-legend i.c1{background:var(--c1)}.sto-legend i.c2{background:var(--c2)}.sto-legend i.c3{background:var(--c3)}.sto-legend i.c4{background:var(--c4)}

/* ---------------------------------------------------------------- movers -- */
.sto-all{display:inline-flex;align-items:center;gap:2px;min-height:44px;margin:-12px -4px -12px 0;padding:0 4px;border:0;background:none;
  font:500 15px/1 var(--font);color:var(--text-2);cursor:pointer}
.sto-all .icn{font-size:14px}
.sto-cols,.sto-movers li button{display:grid;grid-template-columns:minmax(0,1fr) 56px 72px;gap:8px;align-items:center}
.sto-cols{margin-top:8px;padding-bottom:6px;font:var(--t-label);letter-spacing:.04em;color:var(--text-3)}
.sto-cols span:not(:first-child){text-align:end}
.sto-movers ul{list-style:none;margin:0;padding:0}
.sto-movers li{border-top:1px solid var(--hairline)}
.sto-movers li.sto-split{border-top-color:var(--outline-input)}
.sto-movers li button{width:100%;min-height:48px;padding:8px 0;border:0;background:none;color:var(--text);text-align:start;cursor:pointer;
  transition:transform var(--d-press) var(--ease-out)}
.sto-movers li button:active{transform:scale(var(--press))}
.sto-movers .nm{display:flex;flex-direction:column;gap:3px;min-width:0}
.sto-movers .nm b{font:500 15px/1.25 var(--font);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sto-movers .nm span{font:400 12px/1.2 var(--font);color:var(--text-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sto-movers .now{text-align:end;font:400 15px/1 var(--font);color:var(--text-2);font-variant-numeric:tabular-nums}
.sto-movers .ch{text-align:end;font:600 15px/1 var(--font);font-variant-numeric:tabular-nums;white-space:nowrap}
.sto-trend{display:inline-block;width:0;height:0;margin-inline-end:5px;vertical-align:1px;border:4px solid transparent}
.sto-trend.up{border-bottom:6px solid var(--up);border-top-width:0}
.sto-trend.down{border-top:6px solid var(--down);border-bottom-width:0}
.sto-trend.level{width:8px;height:2px;border:0;background:var(--level);vertical-align:3px}

/* --------------------------------------------------------- muscle groups -- */
.sto-muscles .seg{margin:12px 0 14px}
.sto-gbars{display:flex;flex-direction:column;gap:12px}
.sto-gbars .row{display:grid;grid-template-columns:84px minmax(0,1fr) 36px;gap:10px;align-items:center}
.sto-gbars .nm{font:var(--t-meta);color:var(--text)}
.sto-gbars .bar{position:relative;height:8px;border-radius:4px;background:var(--surface-2)}
.sto-gbars .bar>i{position:absolute;inset:0;border-radius:4px;background:var(--mus);transform-origin:left;transition:transform var(--d-sheet) var(--ease-out)}
/* the tick rides a full-width track so translateX(%) lands on the value */
.sto-gbars .tk{position:absolute;inset:-4px 0;pointer-events:none;transition:transform var(--d-sheet) var(--ease-out)}
.sto-gbars .tk b{position:absolute;left:-1px;top:0;bottom:0;width:2px;border-radius:1px;background:var(--text);box-shadow:0 0 0 2px var(--surface)}
.sto-gbars .v{text-align:end;font:600 15px/1 var(--font);font-variant-numeric:tabular-nums;color:var(--text)}
.sto-key{display:flex;flex-wrap:wrap;gap:6px 16px;margin-top:12px;font:var(--t-status);color:var(--text-2)}
.sto-key span{display:inline-flex;align-items:center;gap:6px}
.sto-key i.b{width:12px;height:6px;border-radius:3px;background:var(--mus)}
.sto-key i.t{width:2px;height:12px;border-radius:1px;background:var(--text)}
:dir(rtl) .sto-gbars .bar>i{transform-origin:right}

/* ----------------------------------------------------------- weekly sets -- */
.sto-bars{position:relative;display:grid;grid-template-columns:repeat(var(--n),minmax(0,1fr));gap:4px;height:96px;margin-top:22px}
.sto-bars .col{position:relative;display:flex;align-items:flex-end;justify-content:center;min-width:0}
.sto-bars .col i{display:block;width:min(100%,24px);border-radius:4px 4px 0 0;background:color-mix(in oklab,var(--text) 16%,transparent);transform-origin:bottom}
.sto-bars .col.on i{background:var(--text)}
.sto-bars .col em{position:absolute;margin-bottom:4px;font:600 12px/1 var(--font);font-style:normal;font-variant-numeric:tabular-nums;color:var(--text);white-space:nowrap}
.sto-bars .avg{position:absolute;left:0;right:0;height:0;border-top:1px solid var(--hairline);pointer-events:none}
.sto-bars .avg b{position:absolute;left:0;bottom:3px;font:var(--t-label);font-weight:500;color:var(--text-3);font-variant-numeric:tabular-nums}

/* --------------------------------------------------------------- arrival -- */
@keyframes sto-draw{from{stroke-dashoffset:1}}
@keyframes sto-fade{from{opacity:0}}
@keyframes sto-pop{from{opacity:0;transform:scale(.6)}}
@keyframes sto-grow{from{transform:scaleY(0)}}
@keyframes sto-growx{from{transform:scaleX(0)}}
@keyframes sto-rise{from{opacity:0;transform:translateY(8px)}}
.sto-arrive .sto-chart .ln{stroke-dasharray:1;animation:sto-draw 700ms var(--ease-out) backwards}
.sto-arrive .sto-chart .ln.back{animation-delay:80ms}
.sto-arrive .sto-chart .area{animation:sto-fade 400ms 300ms var(--ease-out) backwards}
.sto-arrive .sto-dot{animation:sto-pop 240ms 620ms var(--ease-out) backwards}
.sto-arrive>.card{animation:sto-rise 360ms var(--ease-out) backwards}
.sto-arrive>.card:nth-child(2){animation-delay:60ms}
.sto-arrive>.card:nth-child(3){animation-delay:120ms}
.sto-arrive>.card:nth-child(4){animation-delay:180ms}
.sto-arrive>.card:nth-child(5){animation-delay:240ms}
.sto-arrive .sto-gbars .bar>i{animation:sto-growx 520ms 200ms var(--spring) backwards}
.sto-arrive .sto-bars .col i{animation:sto-grow 480ms calc(260ms + var(--i) * 24ms) var(--spring) backwards}
@media (hover:hover) and (pointer:fine){
  .sto-legend button:not([aria-pressed="true"]):hover{color:var(--text)}
  .sto-all:hover{color:var(--text)}
}

/* =====================================================================================
   Strength, Muscles and Body (Stats v2, second pass): the old cards in the Overview's
   language. A head row (.sto-head) instead of inline styles, ink text with colour only on
   marks, one range vocabulary (1M 3M 6M 1Y All, Week where a week is the unit), no card that
   is only a link.
   ===================================================================================== */
.st-pane>.card h2,.st-sessions h2{margin:0}
.st-pane .sto-head{margin-bottom:12px}
.st-sub{margin:16px 0 8px;font:var(--t-label);letter-spacing:.06em;text-transform:uppercase;color:var(--text-2)}
.st-foot{margin:12px 0 0;font:var(--t-status);color:var(--text-2);text-wrap:pretty}

/* a way out to another screen: what it is, one line, Open */
.st-link,.st-body-head{display:flex;align-items:center;justify-content:space-between;gap:12px}
.st-link .tx,.st-body-head .tx{display:flex;flex-direction:column;gap:3px;min-width:0}
.st-link p{margin:0;font:var(--t-status);color:var(--text-2);text-wrap:pretty}
.st-link .btn,.st-body-head .btn{flex:none}

/* records sit in their own card; RecordGrid's heading reads as the card's */
.st-recs-card .sec{margin:0 0 12px;font:var(--t-section);letter-spacing:0;text-transform:none;color:var(--text)}

/* recent sessions: date, the sets as unbroken tokens, volume */
.st-sessions ul{list-style:none;margin:12px 0 0;padding:0}
.st-sessions li{display:grid;grid-template-columns:72px minmax(0,1fr) auto;gap:12px;align-items:baseline;padding:10px 0;border-top:1px solid var(--hairline);font:var(--t-status);font-variant-numeric:tabular-nums}
.st-sessions .d{color:var(--text-2);white-space:nowrap}
.st-sessions .s{display:flex;flex-wrap:wrap;gap:4px 10px;color:var(--text)}
.st-sessions .s>span{white-space:nowrap}
.st-sessions .v{color:var(--text-2);white-space:nowrap;text-align:end}

/* effort: one number, the rest under it */
.st-effort .seg-range{margin:0 0 14px}
.st-effort-n{font:700 34px/1.05 var(--font);letter-spacing:-.03em;color:var(--text)}
.st-effort-n small{margin-inline-start:5px;font-size:18px;font-weight:500;letter-spacing:0;color:var(--text-2)}
.st-effort-sub{margin:4px 0 0;font:var(--t-status);color:var(--text-2);font-variant-numeric:tabular-nums;text-wrap:pretty}
.st-effort-warn{margin:8px 0 0;font:var(--t-status);color:var(--text)}
.st-bins{display:flex;flex-direction:column;gap:10px}
.st-bins .row{display:grid;grid-template-columns:64px minmax(0,1fr) 64px;gap:10px;align-items:center}
.st-bins .nm{font:var(--t-status);color:var(--text-2);white-space:nowrap}
.st-bins .bar{position:relative;height:8px;border-radius:4px;background:var(--surface-2);overflow:hidden}
.st-bins .bar i{position:absolute;inset:0;border-radius:4px;background:var(--text-3);transform-origin:left}
.st-bins .hard .bar i{background:var(--metric-effort,var(--yellow))}
:dir(rtl) .st-bins .bar i{transform-origin:right}
.st-bins .v{text-align:end;font:600 14px/1 var(--font);font-variant-numeric:tabular-nums;color:var(--text)}
.st-bins .v small{margin-inline-start:6px;font-size:12px;font-weight:400;color:var(--text-3)}

/* muscles: one card, the switch first */
.st-muscles .st-view{margin:0 0 14px}
.st-mb-head{min-height:32px;align-items:center}
.st-muscles .seg-range{margin-bottom:6px}

/* body */
.st-acts{display:flex;gap:8px}
.st-bw .sto-head{align-items:center}
.st-bw-d{display:inline-flex;align-items:center;gap:6px}
.st-bw-d>i{width:8px;height:8px;border-radius:50%;background:var(--text-3)}
.st-more{display:flex;justify-content:flex-end;margin-top:4px}
.st-body-head{margin-bottom:0}
.st-body-empty{margin:10px 0 0;font:var(--t-status);color:var(--text-2);text-wrap:pretty}
.st-measure-rows{list-style:none;margin:12px 0 0;padding:0}
.st-measure-rows li{display:grid;grid-template-columns:minmax(0,1fr) 64px auto;gap:12px;align-items:center;min-height:48px;border-top:1px solid var(--hairline)}
.st-measure-rows .nm{font:var(--t-meta);color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.st-measure-rows .v{text-align:end;font:var(--t-status);color:var(--text-2);font-variant-numeric:tabular-nums;white-space:nowrap}
.st-measure-rows .v b{font:600 17px/1 var(--font);color:var(--text)}
.st-measure-rows .v small{display:block;margin-top:3px;font-size:12px;color:var(--text-3)}
.st-photo-row{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin-top:12px}
.st-photo{aspect-ratio:3/4;border-radius:var(--r-inner);overflow:hidden;background:var(--surface-2)}
.st-photo .thumb{display:block;width:100%;height:100%;object-fit:cover;border-radius:0;outline:1px solid rgb(0 0 0 / .1);outline-offset:-1px}
:root:not([data-theme="light"]) .st-photo .thumb{outline-color:rgb(255 255 255 / .1)}
.st-photo .thumb-x{display:grid;place-items:center;color:var(--text-3)}

/* ============================================================================
   Plan, routine editor, Start picker — Bevel (reskin/bevel, chunk 6)
   ----------------------------------------------------------------------------
   views/Plan.jsx, views/RoutineEdit.jsx, components/StartSheet.jsx and the exercise picker
   (sheets.jsx ExercisePicker), loaded after bevel.css. Routine cards are one recipe in Plan and
   the Start picker (components/RoutineCard.jsx): a neutral glyph tile, the name, what it holds
   and about how long it runs, three muscle chips at most. Chrome stays neutral: actions are
   quiet white pills, the one primary per view is the ink pill, and the only hues are data (a
   done step in the loop in sage, a superset in the link blue). Static lists are Bevel's inset
   groups with hairlines; lists you drag or swipe stay as cards. Transform/opacity motion only;
   index.css stops all of it under reduced motion. refs/DESIGN-SYSTEM.md §2.1, 2.4–2.6, 2.8, 2.11.
   ========================================================================== */

/* ------------------------------------------------------------ quiet pill -- */
/* DESIGN-SYSTEM 2.5 "Secondary": a white pill on the card shadow, ink label, grey glyph. */
.btn.quiet,.btn.sm.quiet{background:var(--surface);color:var(--text);box-shadow:var(--shadow-card);font-weight:600}
.btn.quiet .icn{color:var(--text-2)}
.btn.quiet:disabled{background:var(--surface-2);color:var(--text-3);box-shadow:none;opacity:1}
.btn.quiet:disabled .icn{color:var(--text-3)}

/* ---------------------------------------------------------- routine card -- */
.rc-sub{margin-top:3px;text-wrap:pretty;font:var(--t-meta);color:var(--text-2);font-variant-numeric:tabular-nums}
.rc-sub .ss{display:block;margin:0;font:inherit;color:inherit}
.rc-dur,.rc-sets{white-space:nowrap}
.rc-sets+.rc-dur::before{content:"\00a0· "}
/* Planned sets per muscle group (Plan v2): labelled bars against the biggest, one hue. */
.rc-vol{display:flex;flex-direction:column;gap:7px;margin-top:12px}
.rc-vol-row{display:grid;grid-template-columns:76px minmax(0,1fr) 28px;align-items:center;gap:10px}
.rc-vol-row .n{font:var(--t-status);color:var(--text-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rc-vol-row .b{height:6px;border-radius:3px;background:var(--surface-2);overflow:hidden}
.rc-vol-row .b i{display:block;height:100%;border-radius:3px;background:var(--muscle-c);transform-origin:left}
:dir(rtl) .rc-vol-row .b i{transform-origin:right}
.rc-vol-row .v{text-align:end;font:600 13px/1 var(--font);font-variant-numeric:tabular-nums;color:var(--text)}

/* ------------------------------------------------------------- this week -- */
/* Plan v2: the week above the tabs (components/PlanWeek.jsx). A column per day; the routine is
   its icon and first word, done is a check on a green tile, missed a struck-through icon. */
.plan-wk{display:flex;flex-direction:column;gap:6px;margin:4px 0 14px}
.plan-wk-k{margin:0;font:var(--t-label);letter-spacing:.08em;text-transform:uppercase;color:var(--text-2)}
.plan-wk-sum{margin:0 0 6px;font:var(--t-meta);color:var(--text);text-wrap:pretty}
.plan-wk-cols{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:2px}
.plan-wk-day{display:flex;flex-direction:column;align-items:center;gap:6px;min-width:0;padding:8px 0 6px;border:0;border-radius:14px;background:none;color:var(--text);cursor:pointer;
  touch-action:manipulation;-webkit-tap-highlight-color:transparent;transition:transform var(--d-press) var(--ease-out),background-color var(--d-hover) var(--ease-out)}
.plan-wk-day:active{transform:scale(var(--press));background:var(--surface-2)}
.plan-wk-day:focus-visible{outline:2.5px solid var(--ink);outline-offset:2px}
.plan-wk-day .l{font:var(--t-label);color:var(--text-3)}
.plan-wk-day .n{width:30px;height:30px;border-radius:50%;display:grid;place-items:center;font:600 15px/1 var(--font);font-variant-numeric:tabular-nums}
.plan-wk-day[data-today] .n{background:var(--ink);color:var(--on-ink)}
.plan-wk-day .g{position:relative;width:34px;height:34px;border-radius:11px;display:grid;place-items:center;font-size:17px;background:var(--surface)}
.plan-wk-day .g>i{width:5px;height:5px;border-radius:50%;background:var(--text-3)}
.plan-wk-day .w{max-width:100%;padding:0 2px;font:500 12px/1.2 var(--font);color:var(--text-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-height:1.2em}
.plan-wk-day[data-state="rest"] .g{background:transparent}
.plan-wk-day[data-state="done"] .g{background:color-mix(in oklab,var(--recovery) 28%,var(--surface))}
.plan-wk-day[data-state="today"] .g{background:var(--ink);color:var(--on-ink)}
.plan-wk-day[data-state="missed"] .g{background:transparent;box-shadow:inset 0 0 0 1.5px var(--hairline);color:var(--text-3)}
.plan-wk-day[data-state="missed"] .g::after{content:"";position:absolute;left:7px;right:7px;top:50%;height:1.5px;border-radius:1px;background:var(--text-2);transform:rotate(-45deg)}
.plan-wk-day[data-state="missed"] .w{text-decoration:line-through;text-decoration-color:var(--text-3)}

/* Arrival: the days and the volume bars, once per app session (useChartArrival). */
@keyframes plan-rise{from{opacity:0;transform:translateY(6px)}}
@keyframes plan-growx{from{transform:scaleX(0)}}
.plan-arrive .plan-wk-day{animation:plan-rise 320ms var(--ease-out) backwards;animation-delay:calc(var(--i, 0) * 30ms)}
.plan-arrive .rc-vol-row .b i{animation:plan-growx 480ms 120ms var(--ease-out) backwards}

/* ------------------------------------------------------------------ Plan -- */
/* Routine glyphs are identity, not data: a neutral tile everywhere on the page. */
.plan .item .lrow-i{--tint:var(--text)}
.plan-textbtn{color:var(--text);font:600 16px/1.2 var(--font);letter-spacing:-.012em}
.plan-textbtn:active{opacity:.6}

/* Routines: one card per routine */
.plan-cards{gap:var(--card-gap)}
.plan-routine.rc{align-items:flex-start;gap:14px;padding:16px 14px 16px 16px;min-height:0}
.plan-routine.rc .lrow-i{
  width:44px;height:44px;border-radius:calc(var(--r-card) - 16px);font-size:21px;flex:none;display:grid;place-items:center;
  background:var(--surface-2);color:var(--text);
}
.plan-routine.rc .tt{font:var(--t-card);letter-spacing:-.016em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.plan-routine.rc .chev{align-self:center;color:var(--text-2)}
.plan-routines.is-editing{gap:var(--s-2)}

/* Edit mode, Bevel's way: a coral outlined minus at the start, the grip at the end */
.plan-minus{background:none;color:var(--danger-fg);box-shadow:inset 0 0 0 1.5px var(--danger)}
.plan-minus:active{background:var(--danger-tint)}
.plan-handle{color:var(--text-2);font-size:20px}

/* Schedule: the week as one inset group, the day name in front, today in an ink pill */
.plan-week{gap:0;background:var(--surface);border-radius:var(--r-card);box-shadow:var(--shadow-card);overflow:hidden}
.plan-week>.item{position:relative;border-radius:0;box-shadow:none;background:none;min-height:60px;padding:10px 14px 10px 16px}
.plan-week>.item+.item::before{content:'';position:absolute;top:0;inset-inline:100px 0;height:var(--hair);background:var(--sep)}
.plan-week>.item:active{background:var(--surface-2)}
.plan-week>.item.pressed{transform:none!important}
.plan-week .tt{font:var(--t-body);letter-spacing:-.012em}
.plan-week .ss{font:var(--t-meta);color:var(--text-2)}
.plan-week .chev{color:var(--text-2)}
.plan-day-n{font:600 15px/1 var(--font);color:var(--text-2);text-align:center;padding:5px 0;border-radius:var(--r-pill)}
.plan-day-n.today{background:var(--ink);color:var(--on-ink)}

/* The loop stays cards (it is dragged and swiped): its position, ink when up next, sage once done */
.plan-loop{gap:var(--s-2)}
.plan-loop .tt{font:var(--t-section);letter-spacing:-.012em}
.plan-loop .ss{font:var(--t-meta);color:var(--text-2)}
.plan-order{background:var(--surface-2);color:var(--text-2);font-variant-numeric:tabular-nums}
.plan-order.next{background:var(--ink);color:var(--on-ink)}
.rotation-row.is-done .plan-order{background:var(--done-tint);color:var(--done-fg)}
.plan-loop-acts{gap:var(--s-2);margin-top:var(--s-2);flex-wrap:wrap}

/* A swipe row's card: the shadow on the clipping wrapper, so overflow:hidden doesn't cut it */
.plan .swrow.swrow-item,.re .swrow.swrow-item{box-shadow:var(--shadow-card)}
.plan .swrow.swrow-item .item,.re .swrow.swrow-item .item{box-shadow:none}

/* Empty: the same card footprint, an icon, the why, one specific action */
.plan .empty{background:var(--surface);border-radius:var(--r-card);box-shadow:var(--shadow-card);padding:32px 24px;color:var(--text-2);text-wrap:pretty}
.plan .empty .ico{color:var(--text-2)}
.plan-empty-act{display:flex;justify-content:center;margin-top:var(--s-4)}

/* ------------------------------------------------------- routine editor -- */
.hdr.re-bar{align-items:center;margin:4px 0 14px}
.re-bar .iconbtn{width:40px;height:40px;border-radius:50%;font-size:18px}
/* the name is the large title, edited in place */
.re-title{display:flex;align-items:center;gap:12px;cursor:text}
.re .re-name.input{
  flex:1;min-width:0;height:auto;min-height:0;padding:2px 0 4px;margin:0;border:0;border-radius:0;background:none;
  font:var(--t-title);letter-spacing:-.02em;color:var(--text);text-overflow:ellipsis;
  box-shadow:inset 0 -2px 0 transparent;transition:box-shadow var(--d-hover) var(--ease-out);
}
.re .re-name.input:focus{outline:none;border:0;background:none;box-shadow:inset 0 -2px 0 var(--ink)}
.re-pen{
  flex:none;width:36px;height:36px;border-radius:50%;display:grid;place-items:center;
  background:var(--surface-2);color:var(--text-2);font-size:16px;transition:opacity var(--d-hover) var(--ease-out);
}
.re-title:focus-within .re-pen{opacity:0}
.re-meta{
  font:var(--t-meta);color:var(--text-2);font-variant-numeric:tabular-nums;
  margin:4px 0 22px;padding-bottom:18px;border-bottom:var(--hair) solid var(--sep);
}

/* Exercise editor: one flat working list, not a stack of rounded cards. */
.re .routine-list{gap:0}
.re .routine-list .item{display:grid;grid-template-columns:44px minmax(0,1fr);align-items:start;gap:8px 12px;min-height:88px;padding:16px 0;background:none;border-radius:0;box-shadow:none;border-bottom:var(--hair) solid var(--sep)}
.re .routine-list .swrow.swrow-item{border-radius:0;box-shadow:none;background:none}
.re .routine-list .swrow.swrow-item .item{background:var(--bg)}
.re-ex-identity{grid-column:1;grid-row:1 / 3;display:flex;flex-direction:column;align-items:center;gap:8px}
.re .routine-list .thumb{width:44px;height:44px;border-radius:8px}
.re .routine-list .item-open{grid-column:2;min-width:0;align-self:start;min-height:44px}
.re .routine-list .item .tt{font:var(--t-section);letter-spacing:-.016em;overflow-wrap:anywhere;white-space:normal}
.re .routine-list .item .ss{font:400 14px/1.4 var(--font);color:var(--text-2);font-variant-numeric:tabular-nums;margin-top:4px}
.re-rest{white-space:nowrap}
.re-note{font:400 13px/1.5 var(--font);color:var(--text-2);margin-top:6px;max-width:60ch}
.re-warn{grid-column:2;justify-self:start;background:var(--strain-tint);color:var(--warning-fg)}
.re-ex-controls{grid-column:2;display:flex;align-items:center;justify-content:flex-end;gap:4px}
.re-link{flex:none;width:44px;height:44px;border-radius:8px;background:none;box-shadow:none;color:var(--text-2);font-size:18px}
.re-ex-controls .iconbtn::before{inset:0}
.re-link.on-ss{background:var(--surface-2);color:var(--info-fg)}
.re-move{flex:none;display:flex;gap:4px;background:none}
.re-move .iconbtn{width:44px;height:44px;border-radius:8px;background:none;box-shadow:none;color:var(--text-2);font-size:16px}
.re-move .iconbtn:disabled{color:var(--text-3);opacity:1}
.re-move .iconbtn:active,.re-link:active{transform:none;background:var(--surface-2)}
.re .routine-grip{margin:0;padding:0 8px;height:44px;font-size:18px;color:var(--text-2)}
/* A1/A2 carries sequence; one straight rule connects the superset rows. */
.re .ss-pos{height:22px;padding:0;min-width:0;border-radius:0;color:var(--info-fg);background:none;font-variant-numeric:tabular-nums}
.re .item.in-ss,.re .swrow.swrow-item .item.in-ss{box-shadow:none;border-inline-start:2px solid var(--info);padding-inline-start:12px}
[dir="rtl"] .re .item.in-ss,[dir="rtl"] .re .swrow.swrow-item .item.in-ss{box-shadow:none}
.re .ss-label{color:var(--info-fg);margin:20px 0 0;min-height:44px;padding:8px 0;border-radius:0}
.re .ss-label-btn .dim{white-space:normal;text-align:start}
/* picked up: the card lifts a little on the menu shadow; the drop line is ink */
.re .routine-drag-row.is-dragging .item{transform:scale(1.02)!important;background:var(--surface);box-shadow:var(--shadow-menu)}
.re .routine-drop-indicator{background:var(--ink)}

.re-hint{margin:14px 4px 0;gap:6px;align-items:flex-start;line-height:1.4;color:var(--text-2)}
.re-hint .icn{flex:none;font-size:13px;margin-top:2px}
/* the routine's own actions as one inset group, Delete on its own below */
.re-actions{display:flex;flex-direction:column;margin-top:var(--section-gap);background:var(--surface);border-radius:var(--r-card);box-shadow:var(--shadow-card);overflow:hidden}
.re-actions .btn,.btn.re-delete{
  position:relative;width:100%;justify-content:flex-start;gap:12px;min-height:56px;padding:0 16px;
  border-radius:0;background:none;box-shadow:none;font:var(--t-body);letter-spacing:-.012em;color:var(--text);
}
.re-actions .btn .icn{font-size:19px;color:var(--text-2)}
.re-actions .btn+.btn::before{content:'';position:absolute;top:0;inset-inline:47px 0;height:var(--hair);background:var(--sep)}
.re-actions .btn:disabled,.re-actions .btn:disabled .icn{color:var(--text-3);opacity:1}
.re-actions .btn:active,.btn.re-delete:active{transform:none;background:var(--surface-2)}
.btn.re-delete{margin-top:var(--card-gap);border-radius:var(--r-card);background:var(--surface);box-shadow:var(--shadow-card);color:var(--danger-fg)}
.btn.re-delete .icn{font-size:19px;color:var(--danger-fg)}

/* ---------------------------------------------------------- Start picker -- */

/* The sheet moves as one surface; rows have no stagger or press animation. */
.start-sheet{display:flex;flex-direction:column;flex:1;min-height:0}
.start-sheet>h3{flex:none;margin-bottom:20px}
.start-list{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:2px}
.start-row{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto 44px;gap:12px;align-items:center;min-height:68px;padding:10px 0;border-bottom:var(--hair) solid var(--sep)}
.start-row:last-child{border-bottom:0}
.start-tx{min-width:0;display:grid;gap:3px}
.start-tx h4{display:flex;align-items:center;gap:8px;min-width:0;margin:0;font:var(--t-section);letter-spacing:-.01em}
.start-tx h4>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.start-today{flex:none;padding:3px 6px;border-radius:6px;font:600 11px/1 var(--font);font-style:normal;background:var(--done-tint);color:var(--done-fg)}
.start-tx p{margin:0;font:var(--t-status);color:var(--text-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.start-mt{display:grid;gap:3px;text-align:end;font-variant-numeric:tabular-nums;white-space:nowrap}
.start-mt b{font:600 15px/1.2 var(--font)}
.start-mt span{font:var(--t-status);color:var(--text-2)}
/* one button per row, its target the whole row */
.start-row>.btn{position:static;width:44px;min-width:44px;height:44px;min-height:44px;padding:0;border-radius:50%}
.start-row>.btn::after{content:'';position:absolute;inset:0}
.start-row>.btn .icn{font-size:14px;margin-inline-start:2px}
.start-row>.btn.tinted{background:var(--surface-2);color:var(--text)}
.start-footer{flex:none;padding-top:16px}
.start-footer>.btn{width:100%}
@media(max-width:360px){.start-row{gap:8px}}
.start-sheet .start-list{padding-top:0}

/* -------------------------------------------------------- exercise picker -- */
.picker-hd{gap:12px;margin-bottom:12px}
.picker-hd h3{min-width:0}
.picker-hd .btn{flex:none}
.sheet .picker-search .search .input{background:var(--surface);box-shadow:var(--shadow-card);border-color:transparent;min-height:44px}
.sheet .search-row>.ex-view-btn{background:var(--surface);box-shadow:var(--shadow-card);border-radius:var(--r-inner);color:var(--text-2)}
:root .search-row>.ex-view-btn.on,:root[data-theme] .search-row>.ex-view-btn.on{background:var(--ink);color:var(--on-ink);box-shadow:none}
/* the list as one inset group (the card view keeps its tiles) */
.sheet .picker-list:not(.ex-grid){gap:0;background:var(--surface);border-radius:var(--r-card);box-shadow:var(--shadow-card);overflow:hidden}
.sheet .picker-list:not(.ex-grid)>.item{position:relative;border-radius:0;box-shadow:none;background:none;min-height:64px;padding:10px 14px 10px 16px;gap:12px}
.sheet .picker-list:not(.ex-grid)>.item+.item::before{content:'';position:absolute;top:0;inset-inline:72px 0;height:var(--hair);background:var(--sep)}
.sheet .picker-list:not(.ex-grid)>.item:active{background:var(--surface-2)}
.sheet .picker-list:not(.ex-grid)>.item.pressed{transform:none!important}
.sheet .picker-list:not(.ex-grid) .thumb{width:44px;height:44px;border-radius:var(--r-inner)}
.sheet .picker-list:not(.ex-grid) .item .tt{font:var(--t-section);letter-spacing:-.016em}
.sheet .picker-list:not(.ex-grid) .item .ss{font:var(--t-meta);color:var(--text-2)}
.sheet .picker-list:not(.ex-grid) .item>.iconbtn.chev{width:32px;height:32px;border-radius:50%;background:var(--surface-2);box-shadow:none;color:var(--text);font-size:15px}
.sheet .picker-list>.similar-label{margin:0;padding:16px 16px 6px;font:var(--t-meta);color:var(--text-2)}
.plan-routines-bar>.btn{box-shadow:none;background:none;border:0;width:auto;font-size:14px;padding:8px 0 8px 12px;gap:6px;border-radius:8px}
.plan-routines-bar>.btn>.icn{width:16px;height:16px;font-size:16px}
.plan-textbtn{min-height:44px}

/* ============================================================================
   History, Library, Muscles, Measurements, Settings (reskin/bevel).
   ----------------------------------------------------------------------------
   History is Hevy's month calendar inside a Bevel card, Library is Bevel's search + filter
   chips over an inset-grouped list, Muscles is the body map shaded by your own sets, Measurements
   are Bevel's Biology tiles over a banded chart, and Settings is Bevel's grouped list with the
   Appearance cards. Colour stays on data (dots, bars, values); the chrome is neutral and the
   selected state is ink. Motion is transform/opacity only; index.css stops every animation and
   transition under prefers-reduced-motion.
   ========================================================================== */

/* ------------------------------------------------------------- History -- */
.hi-stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--card-gap);margin-bottom:var(--card-gap)}
.hi-stats>.card{margin:0}
.hi-stat{display:flex;align-items:center;gap:12px;padding:14px var(--card-pad);min-width:0}
.hi-stat[data-metric="streak"]{--hue:var(--strain)}
.hi-stat[data-metric="rest"]{--hue:var(--sleep)}
.hi-ic{width:40px;height:40px;border-radius:50%;flex:none;display:grid;place-items:center;font-size:19px;
  background:color-mix(in srgb,var(--hue,var(--text-2)) 16%,transparent);color:var(--hue,var(--text-2))}
.hi-st{display:flex;flex-direction:column;gap:1px;min-width:0}
.hi-st b{font:700 22px/1.15 var(--font);letter-spacing:-.02em;font-variant-numeric:tabular-nums;color:var(--text);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hi-st b.hi-ago{font-size:17px;line-height:1.3;letter-spacing:-.012em}
.hi-st b.hi-ago::first-letter{text-transform:uppercase}
.hi-st>span{font:400 13px/1.3 var(--font);color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.hi-cal{padding:10px 10px 4px}
.hi-cal-head{display:flex;align-items:center;gap:6px;margin-bottom:6px}
.hi-month{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;text-align:center}
.hi-month b{font:var(--t-section);letter-spacing:-.012em;color:var(--text)}
.hi-month span{max-width:100%;margin-top:2px;font:400 13px/1.3 var(--font);font-variant-numeric:tabular-nums;color:var(--text-2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hi-nav{width:44px;height:44px;border-radius:50%;flex:none;display:grid;place-items:center;font-size:17px;color:var(--text);
  --icon-stroke:2.4;transition:transform var(--d-spring) var(--spring),background var(--d-hover)}
.hi-nav:active{background:var(--surface-2);transform:scale(.92);transition-duration:var(--d-press)}
.hi-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr))}
.hi-wd{text-align:center;font:var(--t-label);letter-spacing:.02em;color:var(--text-2);padding:2px 0 6px}
/* A day: the number in a 34px circle, the dot under it. Trained days get the done tint, today a
   ring, the picked day the ink fill (Bevel's selected state). */
.hi-d{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;height:48px;min-width:0;
  padding:3px 0 0;background:none;font:500 16px/1 var(--font);font-variant-numeric:tabular-nums;color:var(--text-2);
  -webkit-tap-highlight-color:transparent}
.hi-d span{width:34px;height:34px;border-radius:50%;display:grid;place-items:center;
  transition:background var(--d-hover),color var(--d-hover),transform var(--d-spring) var(--spring)}
.hi-d.fut{color:var(--text-2)}
.hi-d.has{color:var(--text);font-weight:600}
.hi-d.has span{background:var(--done-tint)}
.hi-d.today span{box-shadow:inset 0 0 0 1.5px var(--text)}
.hi-d.sel span{background:var(--ink);color:var(--on-ink);box-shadow:none}
.hi-d:active span{transform:scale(.88);transition-duration:var(--d-press)}
.hi-d:focus-visible{outline:none}
.hi-d:focus-visible span{outline:2px solid var(--text-2);outline-offset:2px}
.hi-d i{position:absolute;bottom:3px;width:5px;height:5px;border-radius:50%}
.hi-d i.done,.hi-legend i.done{background:var(--done)}
.hi-d i.plan,.hi-legend i.plan{background:var(--text-3)}
.hi-d i.ovr,.hi-legend i.ovr{background:var(--strain)}
.hi-d i.noted,.hi-legend i.noted{background:var(--sleep)}
/* paging a month slides the days in from the side it came from */
@keyframes hi-next{from{opacity:0;transform:translateX(16px)}}
@keyframes hi-prev{from{opacity:0;transform:translateX(-16px)}}
.hi-days[data-dir="1"]{animation:hi-next var(--d-sheet) var(--ease-out) both}
.hi-days[data-dir="-1"]{animation:hi-prev var(--d-sheet) var(--ease-out) both}
[dir="rtl"] .hi-grid{direction:ltr}
.hi-legend{display:flex;flex-wrap:wrap;justify-content:center;gap:4px 14px;margin:6px 0 4px;font:400 12px/1.3 var(--font);color:var(--text-2)}
.hi-legend span{display:inline-flex;align-items:center;gap:5px}
.hi-legend i{width:6px;height:6px;border-radius:50%}
/* the card's text action (DESIGN-SYSTEM 2.5): grey, centred, never a second primary */
.hi-foot{display:flex;justify-content:center;margin:4px -10px 0;padding-top:2px;border-top:.5px solid var(--hairline)}
.hi-foot .btn.ghost{color:var(--text-2);font-size:15px;font-weight:500;min-height:44px}
.hi-list-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;scroll-margin-top:calc(var(--sat) + 12px)}
.hi-list-head .btn.ghost{color:var(--text-2);flex:none}
.hi-none{display:flex;align-items:center;gap:12px;padding:12px 12px 12px var(--card-pad)}
.hi-none .hi-ic{--hue:var(--text-2)}
.hi-none-t{flex:1;min-width:0;font:var(--t-meta);color:var(--text-2)}
.hi-none .btn{flex:none}
.hi-list>.item{min-height:64px;padding:12px 14px}
.hi-list>.item:not(.day-note-row)>.lrow-i{background:var(--surface-2);color:var(--text-2)}
.hi-list .tt{font:var(--t-section)}
.hi-list .ss{font:var(--t-meta);color:var(--text-2)}

/* ------------------------------------------------------------- Library -- */
.hdr .btn.lib-pill{background:var(--surface);color:var(--text);box-shadow:var(--shadow-card);font-weight:500}
.hdr .btn.lib-pill .icn{color:var(--text-2)}
.chips.lib-bp{margin-bottom:6px}
/* Bevel's filter chip: what it filters by now, and a chevron for the sheet behind it */
.lib-filters{display:flex;flex-wrap:wrap;gap:8px;margin:2px 0 12px}
.fchip{display:inline-flex;align-items:center;gap:6px;min-height:44px;max-width:100%;padding:0 14px;border-radius:var(--r-pill);
  background:var(--surface);box-shadow:var(--shadow-card);color:var(--text);font:500 15px/1 var(--font);letter-spacing:-.01em;
  text-transform:capitalize;transition:transform var(--d-spring) var(--spring),background var(--d-hover)}
.fchip span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fchip .icn{flex:none;font-size:15px;color:var(--text-2);--icon-stroke:2.2}
.fchip .fchip-c{font-size:11px;--icon-stroke:2.8}
.fchip.on{background:var(--ink);color:var(--on-ink);box-shadow:none}
.fchip.on .icn{color:color-mix(in srgb,var(--on-ink) 70%,transparent)}
.fchip:active{transform:scale(var(--press));transition-duration:var(--d-press)}
/* the list: one inset-grouped card, rows split by hairlines that start at the text */
.lib-list:not(.ex-grid){gap:0;background:var(--surface);border-radius:var(--r-card);box-shadow:var(--shadow-card);overflow:hidden}
.lib-list:not(.ex-grid)>.item{position:relative;min-height:66px;padding:10px 12px 10px 14px;border-radius:0;background:none;box-shadow:none}
.lib-list:not(.ex-grid)>.item+.item::before{content:'';position:absolute;top:0;inset-inline:72px 0;height:var(--hair);background:var(--hairline)}
.lib-list:not(.ex-grid)>.item:active,.lib-list:not(.ex-grid)>.item.pressed{background:var(--surface-2);transform:none!important}
.lib-list:not(.ex-grid) .thumb{width:46px;height:46px;border-radius:var(--r-inner)}
.lib-list .item .tt{font:600 16px/1.25 var(--font);letter-spacing:-.012em}
.lib-list .item .ss{font:400 14px/1.3 var(--font);color:var(--text-2);margin-top:2px}
.lib-list .item .tag.acc{background:color-mix(in srgb,var(--metric-e1rm) 14%,transparent);
  color:var(--metric-e1rm-fg);font-variant-numeric:tabular-nums}
.lib-list .btn.lib-add{background:var(--surface-2);color:var(--text);min-height:44px;padding:5px 12px;font-size:14px;font-weight:600}
.lib-list .btn.lib-add .icn{--icon-stroke:2.4}
.lib-list:not(.ex-grid)>.similar-label{margin:0;padding:18px 16px 6px}
.lib-list:not(.ex-grid)>.empty{padding:28px 16px}

/* ------------------------------------------------------------- Muscles -- */
.mx-card{padding-top:12px}
.mx-range{margin:0 0 6px}
.mx-card .hm-legend{justify-content:center;margin:6px 0 2px}
.mx-list{margin:10px -4px 0;padding-top:4px;border-top:.5px solid var(--hairline)}
/* one row per muscle: name, a bar in the sets hue as strong as the map paints it, the sets */
.mx-row{display:grid;grid-template-columns:minmax(0,1fr) minmax(48px,32%) minmax(64px,auto);align-items:center;gap:12px;width:100%;
  min-height:44px;padding:6px 8px;border-radius:var(--r-inner);background:none;color:var(--text);text-align:start;
  transition:background var(--d-hover),transform var(--d-spring) var(--spring)}
.mx-row:active{transform:scale(var(--press));transition-duration:var(--d-press)}
.mx-row.on{background:var(--surface-2)}
.mx-row.on .mx-n{font-weight:600}
.mx-n{font:400 16px/1.25 var(--font);letter-spacing:-.012em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mx-row.l0 .mx-n{color:var(--text-2)}
.mx-bar{height:6px;border-radius:3px;background:var(--surface-2);overflow:hidden}
.mx-bar i{display:block;height:100%;border-radius:3px;background:var(--metric-sets);transform:scaleX(var(--w,0));transform-origin:0 50%;
  animation:mx-grow 600ms var(--ease-out) 120ms both}
[dir="rtl"] .mx-bar i{transform-origin:100% 50%}
.mx-row.l1 .mx-bar i{background:color-mix(in srgb,var(--metric-sets) 40%,var(--surface-2))}
.mx-row.l2 .mx-bar i{background:color-mix(in srgb,var(--metric-sets) 60%,var(--surface-2))}
.mx-row.l3 .mx-bar i{background:color-mix(in srgb,var(--metric-sets) 80%,var(--surface-2))}
@keyframes mx-grow{from{transform:scaleX(0)}}
.mx-v{font:400 14px/1.2 var(--font);font-variant-numeric:tabular-nums;color:var(--text-2);text-align:end;white-space:nowrap}

/* -------------------------------------------------------- Measurements -- */
.ms-hero{padding:16px var(--card-pad) 14px}
.ms-hero-top{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:6px}
.ms-hero-tx{min-width:0}
.ms-l{display:flex;align-items:center;gap:6px;font:500 15px/1.25 var(--font);color:var(--text-2)}
.ms-l .icn{flex:none;font-size:16px}
.ms-v{margin-top:8px;font:700 36px/1 var(--font);letter-spacing:-.03em;font-variant-numeric:tabular-nums;color:var(--text)}
.ms-v small{font-size:18px;font-weight:500;letter-spacing:-.01em;color:var(--text-2);margin-inline-start:4px}
.ms-d{display:flex;align-items:center;flex-wrap:wrap;gap:3px;margin-top:6px;font:500 14px/1.2 var(--font);font-variant-numeric:tabular-nums;
  color:var(--metric-measure-fg)}
.ms-d .icn{font-size:12px;--icon-stroke:2.6}
.ms-d span{color:var(--text-2);font-weight:400}
.ms-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--card-gap);margin-bottom:var(--card-gap)}
.ms-grid>.card{margin:0}
.ms-tile{display:flex;flex-direction:column;align-items:stretch;gap:6px;width:100%;min-width:0;padding:14px var(--card-pad);
  text-align:start;color:var(--text);transition:transform var(--d-spring) var(--spring),box-shadow var(--d-hover)}
.ms-tile:active{transform:scale(var(--press));transition-duration:var(--d-press)}
.ms-tile.on{box-shadow:var(--shadow-card),0 0 0 1.5px var(--text)}
.ms-tl{font:500 15px/1.25 var(--font);color:var(--text-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ms-tv{font:700 24px/1.1 var(--font);letter-spacing:-.025em;font-variant-numeric:tabular-nums;white-space:nowrap}
.ms-tv small{font-size:14px;font-weight:500;letter-spacing:0;color:var(--text-2);margin-inline-start:3px}
.ms-tr{display:flex;align-items:flex-end;justify-content:space-between;flex-wrap:wrap;gap:6px;min-height:24px}
.ms-td{display:inline-flex;align-items:center;gap:2px;font:var(--t-status);font-variant-numeric:tabular-nums;color:var(--text-2);white-space:nowrap}
.ms-td .icn{font-size:11px;--icon-stroke:2.6}
.ms-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px var(--card-pad);text-align:center;text-wrap:pretty}
.ms-empty-i{width:48px;height:48px;border-radius:50%;display:grid;place-items:center;font-size:22px;background:var(--surface-2);color:var(--text-2)}
.ms-empty .btn{align-self:stretch}
.ms .measure-history{padding:14px var(--card-pad)}
.ms .measure-history b{font-weight:600}
.ms .measure-history .iconbtn{width:36px;height:36px;border-radius:50%;background:var(--surface-2);box-shadow:none}
.ms .measure-preview{border-top:.5px solid var(--hairline);font-size:13px}
.ms .measure-preview b{font-weight:600;color:var(--text);font-variant-numeric:tabular-nums}
/* the log sheet: one stepper row per measurement, grouped like a settings list */
.ms-form{display:flex;flex-direction:column;background:var(--surface);border-radius:var(--r-card);box-shadow:var(--shadow-card);overflow:hidden}
.ms-step{position:relative;display:flex;align-items:center;gap:12px;min-height:60px;padding:8px 8px 8px var(--card-pad)}
.ms-step+.ms-step::before{content:'';position:absolute;top:0;inset-inline:var(--card-pad) 0;height:var(--hair);background:var(--hairline)}
.ms-step-l{flex:1;min-width:0;font:400 16px/1.25 var(--font);color:var(--text);overflow-wrap:anywhere}
.ms-step .stp{flex:0 0 176px;border-radius:var(--r-pill);background:var(--surface-2)}
.ms-step .stp button{width:44px;height:44px;border-radius:50%;transition:transform var(--d-spring) var(--spring),background var(--d-hover)}
.ms-step .stp button:active{transform:scale(.9);transition-duration:var(--d-press)}
.ms-step .stp .num{font:600 17px/1 var(--font);font-variant-numeric:tabular-nums;color:var(--text)}
.ms-step .stp .num::placeholder{color:var(--text-3);font-weight:500}
.ms-step .stp .val i{font-size:13px;color:var(--text-2)}
@media (max-width:360px){.ms-step{flex-wrap:wrap}.ms-step-l{flex-basis:100%}.ms-step .stp{flex:1}}

/* ------------------------------------------------------------- Settings -- */
/* neutral chrome: the back button, chevrons and checkmarks are ink and grey, never the accent */
.sp-page .sp-back{color:var(--text)}
.lrow-c{color:var(--text-2);font-size:14px}
.lrow-k{color:var(--text)}
.sp-root .sp-root-title{font:var(--t-title);letter-spacing:-.02em;margin:2px 0 14px}
.sp-page .sect-t{font:500 17px/1.3 var(--font);letter-spacing:-.012em;color:var(--text-2);padding:0 4px var(--s-2)}
.sp-page .sect-f{font-size:13px;color:var(--text-2);padding:8px 4px 0}
.sp-page .lrow{min-height:56px}
.sp-root .lrow.sp-acct .lrow-t{font:var(--t-card);letter-spacing:-.016em}
.sp-root .sp-avatar{width:52px;height:52px}
/* Settings v2, Hub (docs/dev/SETTINGS_V2.md): the hero card (who, where, how sync stands, Sync
   now), the three quick controls, one list of pages; the account page keeps the hero on top. */
.sp-hero .sect-t{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.sp-hero .lrow.sp-acct,.sp-hero .lrow.sp-id{padding-block:14px;gap:14px}
.sp-hero .sp-acct .lrow-t,.sp-hero .sp-id .lrow-t{font:var(--t-card);letter-spacing:-.016em}
.sp-avatar.lg,.sp-hero .sp-avatar{width:52px;height:52px}
.sp-avatar.on{background:var(--ink);color:var(--on-ink);font:600 21px/1 var(--font)}
.lrow.sp-sync{min-height:52px;padding-block:10px;gap:10px}
.lrow.sp-sync .lrow-t{font:var(--t-meta);color:var(--text)}
.lrow.sp-sync .lrow-s{font-size:13px}
.sp-dot{width:8px;height:8px;border-radius:50%;flex:none;margin-inline:3px 5px;background:var(--text-3)}
.sp-sync[data-tone="ok"] .sp-dot{background:var(--done)}
.sp-sync[data-tone="wait"] .sp-dot{background:var(--warning-fg)}
.sp-sync[data-tone="bad"] .sp-dot{background:var(--danger-fg)}
.lrow.sp-sync .btn.sp-sync-now{flex:none;width:auto;min-height:36px;padding:0 14px;border-radius:var(--r-pill);background:var(--surface-2);color:var(--text);font:600 14px/1 var(--font);position:relative}
.lrow.sp-sync .btn.sp-sync-now::before{content:'';position:absolute;inset:-4px 0}
.sp-quick{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:var(--section-gap)}
.sp-q{display:flex;flex-direction:column;gap:10px;min-width:0;padding:12px 14px;border-radius:var(--r-card);background:var(--surface);box-shadow:var(--shadow-card)}
.sp-q.wide{grid-column:1 / -1}
.sp-ql{font:var(--t-status);color:var(--text-2)}
.sp-q .seg{width:100%}
.sp-step{display:flex;align-items:center;justify-content:space-between;gap:4px}
.sp-step>button{display:grid;place-items:center;width:40px;height:40px;border-radius:50%;background:var(--surface-2);color:var(--text);font-size:16px;flex:none;
  transition:transform var(--d-press) var(--ease-out)}
.sp-step>button:active:not(:disabled){transform:scale(.96)}
.sp-step>button:disabled{color:var(--text-3)}
.sp-step>.sp-step-v{width:auto;min-width:0;flex:1;height:44px;border-radius:12px;background:none;font:var(--t-ring);letter-spacing:-.02em;font-variant-numeric:tabular-nums}
/* the pages' icons are a quiet rail, not tiles: the hero and the quick controls carry the weight */
.sp-root .sp-pages .lrow-i,.sp-account .lrow-i{background:none;width:24px;font-size:19px}
.sp-root .sp-pages .lrow:has(.lrow-i)+.lrow:has(.lrow-i)::before,.sp-account .lrow:has(.lrow-i)+.lrow:has(.lrow-i)::before{inset-inline-start:52px}
.sp-account .lrow.danger .lrow-i{color:var(--danger-fg)}
@media (prefers-reduced-motion:reduce){.sp-step>button:active:not(:disabled){transform:none}}

/* iOS switches are green; here the sage of a done set */
.sw.on{background:var(--done)}
/* Appearance: System / Light / Dark as preview cards (Bevel), the chosen one outlined in ink */
.lrow.ap-row{flex-wrap:wrap;row-gap:12px;padding-bottom:16px}
.ap-cards{flex:1 0 100%;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}
.ap-card{display:flex;flex-direction:column;min-width:0;padding:0;border-radius:calc(var(--r-card) - 16px);overflow:hidden;background:var(--surface);
  box-shadow:0 0 0 1px var(--hairline);color:var(--text-2);text-align:start;
  transition:transform var(--d-spring) var(--spring),box-shadow var(--d-hover),color var(--d-hover)}
.ap-card.on{box-shadow:0 0 0 2px var(--text);color:var(--text)}
.ap-card:active{transform:scale(var(--press));transition-duration:var(--d-press)}
.ap-prev{position:relative;display:block;aspect-ratio:1.1;padding:10px;
  --pv-bg:#F7F7F7;--pv-line:#DDDDDD;--pv-track:#E8E8E8;background:var(--pv-bg)}
.ap-card[data-look="dark"] .ap-prev{--pv-bg:#101010;--pv-line:#454545;--pv-track:#2A2A2A}
.ap-card[data-look="system"] .ap-prev{--pv-line:#9A9A9A;--pv-track:rgb(144 144 144 / .35);background:linear-gradient(90deg,#F7F7F7 50%,#101010 50%)}
.ap-tx{display:flex;flex-direction:column;gap:4px}
.ap-tx i{display:block;width:55%;height:5px;border-radius:3px;background:var(--pv-line)}
.ap-tx i+i{width:35%}
.ap-rings{position:absolute;inset-inline:10px;bottom:10px;display:flex;justify-content:space-between}
.ap-rings i{width:27%;aspect-ratio:1;border-radius:50%;border:3px solid var(--pv-track);transform:rotate(-45deg)}
.ap-rings .r1{border-top-color:var(--strain);border-right-color:var(--strain)}
.ap-rings .r2{border-top-color:var(--recovery);border-right-color:var(--recovery);border-bottom-color:var(--recovery)}
.ap-rings .r3{border-top-color:var(--sleep)}
.ap-lbl{display:flex;align-items:center;gap:6px;padding:9px 10px;border-top:1px solid var(--hairline);font:500 15px/1.2 var(--font);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ap-lbl .icn{flex:none;font-size:14px}

@media (prefers-reduced-motion:reduce){
  .mx-bar i{animation:none}
}

/* shadcn/ui Button variants translated to the project's plain CSS. The shared
   wrapper retains legacy layout classes, while these states have one owner. */
.shadcn-button[data-slot="button"]{
  display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;gap:8px;
  min-height:44px;padding:10px 16px;border:1px solid transparent;border-radius:12px;
  font:500 15px/1.25 var(--font);letter-spacing:-.01em;white-space:nowrap;
  background:var(--sb-bg);color:var(--sb-fg);box-shadow:none;position:relative;
  transition:background-color 150ms var(--ease-out),color 150ms var(--ease-out),transform 120ms var(--ease-out),box-shadow 150ms var(--ease-out);
  --sb-bg:var(--ink);--sb-fg:var(--on-ink);
}
.shadcn-button.sb-default{--sb-bg:var(--ink);--sb-fg:var(--on-ink)}
.shadcn-button.sb-secondary{--sb-bg:var(--surface-2);--sb-fg:var(--text)}
.shadcn-button.sb-outline{--sb-bg:var(--surface);--sb-fg:var(--text);border-color:var(--outline-input)}
.shadcn-button.sb-ghost,.shadcn-button.sb-link{--sb-bg:transparent;--sb-fg:var(--text)}
.shadcn-button.sb-destructive{--sb-bg:var(--danger-tint);--sb-fg:var(--danger-fg)}
.shadcn-button.sb-link{text-underline-offset:4px}
.shadcn-button[data-size="lg"]{min-height:48px;padding-inline:24px}
.shadcn-button[data-size="sm"],.shadcn-button[data-size="xs"]{min-height:44px;padding:8px 12px;font-size:14px;width:auto}
.shadcn-button[data-size^="icon"]{width:44px;min-width:44px;height:44px;padding:0;flex:none}
.shadcn-button[data-size="icon-lg"]{width:48px;height:48px}
.shadcn-button[data-slot="button"]>.icn{width:18px;height:18px;font-size:18px;flex-shrink:0;--icon-stroke:2;pointer-events:none}
@media(hover:hover){
  .shadcn-button[data-slot="button"]:hover:not(:disabled){background:color-mix(in oklch,var(--sb-bg) 88%,var(--sb-fg) 12%)}
  .shadcn-button.sb-ghost:hover:not(:disabled),.shadcn-button.sb-link:hover:not(:disabled){background:var(--surface-2)}
  .shadcn-button.sb-link:hover:not(:disabled){text-decoration:underline}
}
.shadcn-button[data-slot="button"]:active:not(:disabled){background:color-mix(in oklch,var(--sb-bg) 84%,var(--sb-fg) 16%);transform:scale(.98);opacity:1}
.shadcn-button.sb-ghost:active:not(:disabled){background:var(--surface-2)}
.shadcn-button[data-slot="button"]:focus-visible{outline:2px solid var(--ink);outline-offset:3px;box-shadow:0 0 0 4px var(--surface)}
.shadcn-button[data-slot="button"][aria-invalid="true"]{border-color:var(--danger-fg);outline-color:var(--danger-fg)}
.shadcn-button[data-slot="button"]:disabled{background:var(--surface-2);color:var(--text-3);border-color:transparent;box-shadow:none;opacity:1;pointer-events:none;transform:none}
.shadcn-button[aria-busy="true"]{cursor:progress}
.sb-loading-label{opacity:0;display:inline-flex;align-items:center;gap:8px}
.sb-spinner{position:absolute;width:18px;height:18px;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:sb-spin .7s linear infinite}
@keyframes sb-spin{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.shadcn-button[data-slot="button"]{transition:none}.shadcn-button[data-slot="button"]:active:not(:disabled){transform:none}.sb-spinner{animation:none;border-style:dotted}}
.shadcn-button[data-slot="button"][aria-busy="true"]{background:var(--sb-bg);color:var(--sb-fg)}
.shadcn-button[data-slot="button"] .sb-loading-label>.icn{width:18px;height:18px;font-size:18px;--icon-stroke:2}

/* The sheet owns the viewport; only its content pane scrolls. The action footer
   occupies its own flex row, so it can never float between exercise rows. */
.sheet:has(>.workout-detail){
  display:flex;flex-direction:column;overflow:hidden;
  bottom:max(var(--picker-keyboard-bottom,0px),var(--native-kb,0px));
  height:min(90dvh,calc(var(--picker-visual-height,100dvh) - var(--sat) - 12px));
  max-height:min(90dvh,calc(var(--picker-visual-height,100dvh) - var(--sat) - 12px));
}
.workout-detail{position:relative;display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden}
.wd-scroll{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;scroll-padding-block:12px 20px}
.wd-map{border-radius:20px;background:var(--surface-2);padding:16px;margin-bottom:20px;overflow:hidden}
.wd-map .bodymap{margin:0 auto;max-width:300px;gap:12px}
.wd-map .bm-v{height:240px;max-height:30dvh;width:auto}
.wd-map .bm-ph{height:240px;max-height:30dvh}
.wd-header{display:flex;align-items:center;gap:12px;margin-bottom:20px}
.wd-header .grow{flex:1;min-width:0}
.wd-header h3{font:600 24px/1.2 var(--font);letter-spacing:-.025em;margin:4px 0 0;overflow-wrap:anywhere}
.wd-summary{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin:0 0 28px}
.wd-summary>div{min-width:0}
.wd-summary dt{font:400 13px/1.4 var(--font);color:var(--text-2);margin-bottom:6px}
.wd-summary dd{font:600 18px/1.3 var(--font);font-variant-numeric:tabular-nums;letter-spacing:-.025em;margin:0;overflow-wrap:anywhere}
.wd-section-title{font:600 17px/1.3 var(--font);margin:0 0 12px}
.workout-detail .wd-ex{min-height:76px;padding-block:12px;border-bottom:1px solid var(--sep)}
.workout-detail .wd-ex .ss{margin-top:4px;line-height:1.4}
.workout-detail .wd-ex .thumb{width:48px;height:48px;border-radius:12px}
.wd-note{margin-top:20px;padding:16px 0;border-top:1px solid var(--sep)}
.wd-note summary{display:grid;grid-template-columns:minmax(0,1fr) 24px;gap:6px 12px;min-height:44px;cursor:pointer;list-style:none}
.wd-note summary::-webkit-details-marker{display:none}
.wd-note summary>.small{grid-column:1}
.wd-note-preview{grid-column:1;white-space:pre-wrap;overflow-wrap:anywhere;font:400 15px/1.5 var(--font)}
.wd-note summary>.icn{grid-column:2;grid-row:1 / 3;align-self:center;width:18px;height:18px;color:var(--text-2)}
.wd-note[open] .wd-note-preview{display:none}
.wd-note textarea{margin-top:12px}
.wd-note summary:focus-visible{outline:2px solid var(--ink);outline-offset:4px;border-radius:8px}
.wd-actions{display:grid;grid-template-columns:1fr 1fr;gap:12px;flex:none;padding:16px 0 0;border-top:1px solid var(--sep);background:var(--surface-sheet)}
.wd-actions .shadcn-button{white-space:normal;min-height:48px}
.menu-list button.menu-item{width:100%;text-align:start;font:inherit;color:var(--text)}
.menu-list button.menu-item:disabled{opacity:1;pointer-events:none;color:var(--text-3)}
@media(max-width:360px){.wd-summary{gap:8px}.wd-summary dd{font-size:16px}.wd-map .bm-v,.wd-map .bm-ph{height:200px}.wd-actions{gap:8px}}
.wd-note .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}

/* Sheet motion is owned by Modals' WAAPI lifecycle, including exits. Cancel an
   in-flight entrance before dragging; never let CSS keyframes override the finger. */
.sheet-layer{position:absolute;inset:0}
.sheet-layer[data-exiting]{pointer-events:none}
.sheet-layer>.sheet,.sheet-layer>.center,.sheet-layer>.mback{animation:none;transition:none}
.sheet-layer>.sheet{will-change:auto}
.sheet-layer>.sheet[data-expandable]{display:flex;flex-direction:column;height:60dvh;max-height:calc(100dvh - var(--sat) - 12px - var(--native-kb,0px));overflow:hidden}
.sheet-layer>.sheet[data-expanded]{height:calc(100dvh - var(--sat) - 12px - var(--native-kb,0px))}
.sheet>.sheet-grab{display:grid;place-items:center;flex:none;width:100%;height:44px;padding:0;margin:0 0 8px;border:0;border-radius:12px;background:none;touch-action:none;cursor:grab}
.sheet-grab>i{display:block;width:36px;height:5px;border-radius:99px;background:var(--label-4)}
.sheet-grab:active{cursor:grabbing}
.sheet-grab:focus-visible{outline:2px solid var(--text);outline-offset:2px}
.sheet:has(.start-sheet){view-transition-name:none}

html,body{overflow:hidden!important;scrollbar-width:none}*,*::before,*::after{animation:none!important;transition:none!important;caret-color:transparent!important}