:root {
  --bg: #0e1116; --panel: #171c24; --panel2: #1f2630; --line: #2a323d;
  --fg: #e8edf3; --muted: #93a1b0; --accent: #28c76f; --accent2: #1f9bcf;
  --warn: #ff9f43; --bad: #ea5455;
}
* { box-sizing: border-box; }
html { height: 100%; }
/* min-height (not height:100%) so the page grows with its content and the document
   itself scrolls — a height:100% body is only one viewport tall, which collapses the
   sticky header's containing block and lets it scroll away after one screenful. */
body { margin: 0; min-height: 100%; background: var(--bg); color: var(--fg);
  font: 15px/1.45 -apple-system, system-ui, "Segoe UI", Roboto, sans-serif; }
a { color: inherit; text-decoration: none; }

.wrap { max-width: 760px; margin: 0 auto; padding: 16px; }
header.top { position: sticky; top: 0; background: var(--bg); padding: 14px 16px 8px;
  border-bottom: 1px solid var(--line); z-index: 5; }
h1 { font-size: 18px; margin: 0 0 10px; }
.sub { color: var(--muted); font-size: 13px; }

input.search { width: 100%; padding: 11px 13px; border-radius: 10px; border: 1px solid var(--line);
  background: var(--panel); color: var(--fg); font-size: 15px; }
/* Unified multi-select filter bar (toggle tags; no redundant "All"). */
.chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 10px; }
.chip { padding: 5px 11px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--panel); color: var(--muted); font-size: 12px; cursor: pointer;
  transition: background .12s, color .12s, border-color .12s; }
.chip:hover { border-color: var(--accent); color: var(--fg); }
.chip.on { background: var(--accent); color: #06210f; border-color: var(--accent); font-weight: 600; }
.chip.clear { background: transparent; color: var(--bad); border-color: var(--bad); }
.chip.clear:hover { background: rgba(234,84,85,.12); color: var(--bad); }
.chip-sep { width: 1px; align-self: stretch; min-height: 18px; background: var(--line); margin: 0 4px; }

.list { display: grid; gap: 10px; padding: 12px 0 48px; }
.card { display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 14px;
  background: var(--panel); border: 1px solid var(--line); cursor: pointer;
  transition: border-color .12s, background .12s, transform .06s; }
.card:hover { border-color: var(--accent); }
.card:active { background: var(--panel2); transform: scale(.995); }
.card .name { font-weight: 700; font-size: 15.5px; }
.card .meta { color: var(--muted); font-size: 12px; margin-top: 3px; }
.card .chev { flex: 0 0 auto; color: var(--muted); font-size: 22px; line-height: 1; }
/* Non-trackable exercises: launchable into a camera MIRROR (no rep counting), but kept
   visually distinct from auto-counted ones — dashed border + slightly dimmed. */
.card.untracked { opacity: .85; border-style: dashed; }
.card.untracked:hover { border-color: var(--accent2); }

/* Badge row lives INSIDE the card body (left), wrapping under the name. */
.badges { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 9px; }
.badge { font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 999px;
  border: 1px solid var(--line); color: var(--muted); white-space: nowrap;
  display: inline-flex; align-items: center; gap: 3px; }
.badge.cat { color: var(--fg); background: var(--panel2); border-color: var(--line); }
.badge.track { color: var(--accent); border-color: var(--accent); background: rgba(40,199,111,.10); }
.badge.side { color: var(--accent2); border-color: var(--accent2); }
.badge.front { color: var(--accent2); border-color: var(--accent2); }
/* format badges — distinct class names so they don't collide with the session
   HUD's `.reps` rep-counter (which sets font-size:44px). */
.badge.fmt-reps { color: var(--accent); border-color: var(--accent); }
.badge.fmt-timed { color: var(--accent2); border-color: var(--accent2); }
.badge.warmup { color: var(--warn); border-color: var(--warn); background: rgba(255,159,67,.10); }
.badge.untracked { color: var(--muted); border-style: dashed; }
.grow { flex: 1; min-width: 0; }
.rel { font-size: 12px; color: var(--muted); }
.rel.reliable { color: var(--accent); }
.rel.experimental, .rel.marginal { color: var(--warn); }
.empty { color: var(--muted); text-align: center; padding: 40px 0; }

/* session page */
.stage { position: fixed; inset: 0; background: #000; overflow: hidden; }
/* cover so the camera fills the screen (natural full-bleed camera look). The
   stream's aspect is requested to match the screen orientation (see session.js),
   so cover fills without big letterbox bars on phone or desktop. The overlay
   canvas uses the same object-fit + intrinsic size, so the skeleton stays aligned.
   (Display mode is cosmetic — MediaPipe always processes the full video frame.) */
video#cam { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
canvas#overlay { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Mirror only the front (selfie) camera — toggled by session.js per facingMode.
   The rear camera must NOT be mirrored. */
video#cam.mirrored, canvas#overlay.mirrored { transform: scaleX(-1); }

/* Front/back camera toggle — a translucent FAB on the right edge, over the camera.
   A sibling of (not inside) the .hud, with its own pointer events enabled. */
.cam-flip { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); z-index: 7;
  width: 46px; height: 46px; border-radius: 50%; border: 1px solid rgba(255,255,255,.28);
  background: rgba(0,0,0,.55); color: #fff; font-size: 22px; line-height: 1; cursor: pointer;
  pointer-events: auto; backdrop-filter: blur(4px); display: flex; align-items: center;
  justify-content: center; }
.cam-flip:active { background: rgba(0,0,0,.75); }
.cam-flip[hidden] { display: none; }
/* Phone-angle guide — a slim plumb "spirit level" pinned to the left edge (display-only).
   The bubble rides a vertical vial and turns green inside the center band when the phone
   is upright (~90°). Small edge footprint instead of a center dial. */
.level { position: absolute; left: calc(10px + env(safe-area-inset-left)); top: 50%; z-index: 6;
  transform: translateY(-50%); width: 16px; height: 150px; border-radius: 999px;
  background: rgba(0,0,0,.5); border: 1px solid rgba(255,255,255,.22);
  backdrop-filter: blur(4px); pointer-events: none; }
.level[hidden] { display: none; }
/* center "you're level" band — its half-height matches the ±tolerance in level.js */
.level-zone { position: absolute; left: 0; right: 0; top: 50%; height: 48px; transform: translateY(-50%);
  border-top: 1px solid rgba(255,255,255,.35); border-bottom: 1px solid rgba(255,255,255,.35); }
.level.ok .level-zone { background: rgba(40,199,111,.28); border-color: var(--accent); }
.level-bubble { position: absolute; left: 50%; top: 50%; width: 12px; height: 12px; margin: -6px 0 0 -6px;
  border-radius: 50%; background: var(--warn); box-shadow: 0 0 8px rgba(0,0,0,.55);
  transition: transform .08s linear, background .15s; }
.level-bubble.ok { background: var(--accent); }

.hud { position: absolute; inset: 0; pointer-events: none; display: flex; flex-direction: column;
  justify-content: space-between; padding: 16px; }
.hud .top, .hud .bottom { display: flex; gap: 10px; align-items: flex-start; }
.hud .pill { background: rgba(0,0,0,.55); border: 1px solid rgba(255,255,255,.14);
  border-radius: 12px; padding: 8px 12px; backdrop-filter: blur(4px); }
.reps { font-size: 44px; font-weight: 800; line-height: 1; }
.reps small { font-size: 16px; color: var(--muted); font-weight: 600; }
/* Countdown for a timed run, sits above the rep count in the same pill. */
.countdown { font-size: 22px; font-weight: 800; line-height: 1; color: var(--accent2);
  font-variant-numeric: tabular-nums; margin-bottom: 6px; }
.countdown[hidden] { display: none; }
.angle-hint { color: var(--accent2); font-weight: 700; }
.form-ok { color: var(--accent); } .form-bad { color: var(--bad); }
.state-bar { height: 6px; border-radius: 3px; background: rgba(255,255,255,.15); overflow: hidden; margin-top: 8px; }
.state-bar > i { display: block; height: 100%; background: var(--accent); width: 0%; }

/* Mirror mode (non-trackable exercises): camera as a plain self-view — name pill on
   top, a big centered timer, a Done button at the bottom. Sits above the (hidden) rep
   HUD; only the button takes pointer events so the flip/level FABs stay reachable. */
.mirror-hud { position: absolute; inset: 0; z-index: 5; pointer-events: none;
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  padding: 16px; padding-top: calc(16px + env(safe-area-inset-top));
  padding-bottom: calc(20px + env(safe-area-inset-bottom)); }
.mirror-hud[hidden] { display: none; }
.mirror-name { text-align: center; max-width: 70%; }
.mirror-mid { flex: 1; display: flex; align-items: center; justify-content: center; }
.mirror-timer { font-size: 56px; font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums;
  padding: 12px 24px; border-radius: 16px; background: rgba(0,0,0,.5);
  border: 1px solid rgba(255,255,255,.14); backdrop-filter: blur(4px); }
.mirror-done { pointer-events: auto; min-width: 160px; padding: 16px 28px; font-size: 17px; }

.center { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  flex-direction: column; gap: 14px; text-align: center; padding: 24px; pointer-events: auto; }
/* The intro doubles as the "tap to start" gesture target (see session.js boot()). */
.center.tap { cursor: pointer; }
button.go { pointer-events: auto; background: var(--accent); color: #06210f; border: 0; font-weight: 700;
  padding: 14px 22px; border-radius: 12px; font-size: 16px; }
button.ghost { background: transparent; color: var(--fg); border: 1px solid var(--line);
  padding: 10px 16px; border-radius: 10px; }
.banner { position: absolute; left: 0; right: 0; top: 0; text-align: center; padding: 10px;
  background: var(--accent); color: #06210f; font-weight: 700; transform: translateY(-100%);
  transition: transform .3s; }
.banner.show { transform: translateY(0); }
.toast { position: absolute; left: 50%; bottom: 24px; transform: translateX(-50%);
  background: rgba(0,0,0,.7); border: 1px solid var(--line); padding: 8px 14px; border-radius: 10px;
  color: var(--fg); font-size: 13px; }

/* tutorial picture-in-picture (bottom-right, over the camera) */
.pip { position: absolute; right: 12px; bottom: 12px; width: 34%; max-width: 200px;
  aspect-ratio: 4 / 3; border-radius: 10px; overflow: hidden; z-index: 6;
  border: 1px solid rgba(255,255,255,.28); background: #000;
  box-shadow: 0 4px 16px rgba(0,0,0,.55); }
.pip.big { width: 62%; max-width: 360px; }
.pip video { width: 100%; height: 100%; object-fit: cover; display: block; }
.pip-label { position: absolute; left: 6px; top: 5px; font-size: 10px; color: #fff;
  background: rgba(0,0,0,.5); padding: 1px 6px; border-radius: 6px; pointer-events: none; }
.pip-close { position: absolute; right: 3px; top: 3px; width: 22px; height: 22px; border: 0;
  border-radius: 50%; background: rgba(0,0,0,.6); color: #fff; font-size: 15px; line-height: 1;
  cursor: pointer; padding: 0; }
.pip-fallback { position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 4px; background: #11161d;
  color: var(--muted); font-size: 12px; }
/* The `hidden` attribute must beat `display:flex` above (equal specificity would
   otherwise keep this opaque panel covering the playing tutorial video). */
.pip-fallback[hidden] { display: none; }
.pip-fallback-icon { font-size: 22px; color: var(--accent); }

/* completion page */
.done-screen { position: fixed; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 14px; text-align: center;
  padding: 24px; background: var(--bg); }
.spinner { width: 54px; height: 54px; border-radius: 50%;
  border: 5px solid var(--line); border-top-color: var(--accent);
  animation: spin 0.9s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.done-title { font-size: 22px; font-weight: 800; }
.done-sub { font-size: 32px; font-weight: 800; color: var(--accent); }

/* ── dev/test parameter panel (off-production only; see js/devpanel.js) ───────── */
/* Lives on the exercise list only: a per-card gear opens this right-side drawer. */
.dp-backdrop { position: fixed; inset: 0; z-index: 90; background: rgba(0,0,0,.45); }
.dp-drawer { position: fixed; top: 0; bottom: 0; right: 0; z-index: 91; width: min(360px, 88vw);
  display: flex; flex-direction: column; background: var(--panel); border-left: 1px solid var(--line);
  box-shadow: 0 0 32px rgba(0,0,0,.6); transform: translateX(102%); transition: transform .2s ease;
  padding-top: env(safe-area-inset-top); }
.dp-drawer.open { transform: translateX(0); }
.dp-head { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px;
  border-bottom: 1px solid var(--line); font-size: 15px; }
/* per-card gear on the exercise list (off-production only) */
.dp-card-gear { flex: 0 0 auto; width: 34px; height: 34px; border-radius: 9px; padding: 0;
  border: 1px solid var(--line); background: var(--panel2); color: var(--muted); font-size: 16px;
  line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; }
.dp-card-gear:hover, .dp-card-gear:active { color: var(--accent); border-color: var(--accent); }
/* read-only "what am I configuring" banner shown when opened from a card */
.dp-ctx { padding: 11px 16px; border-bottom: 1px solid var(--line); background: var(--panel2); }
.dp-ctx[hidden] { display: none; }
.dp-ctx-name { font-weight: 700; font-size: 14px; }
.dp-ctx-meta { color: var(--muted); font-size: 12px; margin-top: 2px; }
.dp-x { background: transparent; border: 0; color: var(--muted); font-size: 24px; line-height: 1;
  cursor: pointer; padding: 0 4px; }
.dp-body { flex: 1; overflow-y: auto; padding: 8px 16px 16px; -webkit-overflow-scrolling: touch; }
.dp-group { margin-top: 16px; }
.dp-group-title { font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); margin-bottom: 8px; }
.dp-field { display: flex; flex-direction: column; gap: 3px; margin-bottom: 12px; }
.dp-key { font-size: 12px; font-weight: 600; color: var(--fg); font-family: ui-monospace, Menlo, monospace; }
.dp-input { width: 100%; padding: 9px 11px; border-radius: 9px; border: 1px solid var(--line);
  background: var(--panel2); color: var(--fg); font-size: 14px; }
select.dp-input { appearance: none; }
.dp-help { font-size: 11px; color: var(--muted); line-height: 1.35; }
/* A goal field that doesn't apply to the chosen exercise (reps for a timed exercise,
   or seconds for a rep one) is disabled + dimmed. */
.dp-field.dp-disabled { opacity: .4; }
.dp-input:disabled { cursor: not-allowed; }
.dp-foot { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding: 12px 16px;
  border-top: 1px solid var(--line); padding-bottom: calc(12px + env(safe-area-inset-bottom)); }
.dp-btn { flex: 1; min-width: 88px; padding: 10px 12px; border-radius: 9px; border: 1px solid var(--line);
  background: var(--panel2); color: var(--fg); font-size: 13px; font-weight: 600; cursor: pointer; }
.dp-apply { background: var(--accent); color: #06210f; border-color: var(--accent); }
.dp-ghost { flex: 0 0 auto; min-width: 0; }
.dp-off { flex-basis: 100%; text-align: center; color: var(--muted); font-size: 12px;
  text-decoration: underline; margin-top: 2px; }
.dp-toast { position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 12px); z-index: 95;
  background: rgba(0,0,0,.82); border: 1px solid var(--line); color: var(--fg); font-size: 13px;
  padding: 8px 14px; border-radius: 10px; opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s; }
.dp-toast.show { opacity: 1; transform: translate(-50%, 0); }
