/* StepFlow - salsa & bachata trainer
 *
 * Theming: every colour in this file comes from a token below. To add a theme,
 * copy one block and override the tokens - no other rule needs to change.
 */

html[data-theme="havana"],
html[data-theme="system"] {
  color-scheme: dark;
  --bg: #14110f;
  --bg-tint: #2a221c;
  --bg2: #1b1714;
  --panel: #201b18;
  --panel2: #272119;
  --line: #372f28;
  --line2: #4a4038;
  --text: #f6efe6;
  --text2: #ded4ca;
  --muted: #a1948a;
  --faint: #6b6058;
  --faint2: #574d46;
  --accent: #f0a93c;
  --accent-dim: #8a6224;
  --accent-ink: #221a10;
  --accent-soft: rgba(240, 169, 60, .13);
  --accent2: #35bfae;
  --accent2-dim: #1f4a45;
  --accent2-ink: #06231f;
  --accent2-soft: rgba(53, 191, 174, .35);
  --danger: #e0533f;
  --danger-dim: #5a2d24;
  --ok: #74c46a;
  --ok-dim: #2f4a2c;
  --cell: #1a1613;
  --cell-beat: #221d19;
  --topbar: rgba(20, 17, 15, .72);
  --tapbeat-on: #3a3128;
  --shadow-c: rgba(0, 0, 0, .22);
  --cloth-m: #3d3d48;
  --cloth-f: #e05046;
}

/* Shared, palette-independent tokens. Skin, hair and shoes are the same in
   every theme - only the clothing follows the accents, which is what tells the
   two roles apart. */
:root {
  --radius: 12px;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  --skin: #e6b088;
  --hair: #35281e;
  --shoe: #2b2521;
  --cloth-m: #24242b;
  --cloth-f: #c62828;
}

/* Cool, low-light. Good for sensual bachata playlists at 1am. */
html[data-theme="noche"] {
  color-scheme: dark;
  --bg: #0d0f16;
  --bg-tint: #1d2133;
  --bg2: #141824;
  --panel: #171b28;
  --panel2: #1e2333;
  --line: #2a3043;
  --line2: #3a4257;
  --text: #eef1f8;
  --text2: #ccd2e2;
  --muted: #8e97b0;
  --faint: #5d657e;
  --faint2: #4a5168;
  --accent: #8b7bf5;
  --accent-dim: #4a3f96;
  --accent-ink: #100c26;
  --accent-soft: rgba(139, 123, 245, .16);
  --accent2: #4fd1c5;
  --accent2-dim: #1e4a4a;
  --accent2-ink: #05231f;
  --accent2-soft: rgba(79, 209, 197, .35);
  --danger: #f26d6d;
  --danger-dim: #5b2b2f;
  --ok: #6ed49a;
  --ok-dim: #23492f;
  --cell: #12151f;
  --cell-beat: #191d2b;
  --topbar: rgba(13, 15, 22, .74);
  --tapbeat-on: #2b3145;
  --shadow-c: rgba(0, 0, 0, .22);
  --cloth-m: #3d3d48;
  --cloth-f: #e05046;
}

/* High-contrast club palette. */
html[data-theme="neon"] {
  color-scheme: dark;
  --bg: #08080c;
  --bg-tint: #1a1030;
  --bg2: #101018;
  --panel: #14141d;
  --panel2: #1c1c28;
  --line: #2b2b3d;
  --line2: #3e3e55;
  --text: #ffffff;
  --text2: #dcdcea;
  --muted: #9494ae;
  --faint: #62627d;
  --faint2: #4d4d64;
  --accent: #ff2e88;
  --accent-dim: #8c1349;
  --accent-ink: #ffffff;
  --accent-soft: rgba(255, 46, 136, .18);
  --accent2: #00e5ff;
  --accent2-dim: #0a5c66;
  --accent2-ink: #002229;
  --accent2-soft: rgba(0, 229, 255, .4);
  --danger: #ff5252;
  --danger-dim: #6b1f1f;
  --ok: #4afa70;
  --ok-dim: #1f4a22;
  --cell: #0d0d14;
  --cell-beat: #16161f;
  --topbar: rgba(8, 8, 12, .78);
  --tapbeat-on: #2a2a3a;
  --shadow-c: rgba(0, 0, 0, .22);
  --cloth-m: #3d3d48;
  --cloth-f: #e05046;
}

/* Warm paper - the default. Readable in a bright studio or in daylight. */
:root,
html[data-theme="sala"] {
  color-scheme: light;
  --bg: #f7f2e9;
  --bg-tint: #ffffff;
  --bg2: #efe7d9;
  --panel: #fffcf6;
  --panel2: #f3ece0;
  --line: #e0d5c2;
  --line2: #cbbda4;
  --text: #241d15;
  --text2: #43382a;
  --muted: #7a6c58;
  --faint: #9c8e79;
  --faint2: #b3a591;
  --accent: #c47816;
  --accent-dim: #f0d5a8;
  --accent-ink: #fffaf2;
  --accent-soft: rgba(196, 120, 22, .13);
  --accent2: #10796e;
  --accent2-dim: #b7ded8;
  --accent2-ink: #f0fffd;
  --accent2-soft: rgba(16, 121, 110, .35);
  --danger: #b4331f;
  --danger-dim: #f0c4bb;
  --ok: #3d7d33;
  --ok-dim: #c3ddbd;
  --cell: #ece3d3;
  --cell-beat: #e0d4bd;
  --topbar: rgba(247, 242, 233, .82);
  --tapbeat-on: #e5d7bc;
  --shadow-c: rgba(90, 70, 40, .18);
}

/* Maximum contrast, minimum decoration. */
html[data-theme="mono"] {
  color-scheme: dark;
  --bg: #000000;
  --bg-tint: #161616;
  --bg2: #0d0d0d;
  --panel: #121212;
  --panel2: #1c1c1c;
  --line: #333333;
  --line2: #4f4f4f;
  --text: #ffffff;
  --text2: #e2e2e2;
  --muted: #b0b0b0;
  --faint: #8a8a8a;
  --faint2: #6e6e6e;
  --accent: #ffffff;
  --accent-dim: #575757;
  --accent-ink: #000000;
  --accent-soft: rgba(255, 255, 255, .16);
  --accent2: #ffd400;
  --accent2-dim: #6b5a00;
  --accent2-ink: #1a1500;
  --accent2-soft: rgba(255, 212, 0, .4);
  --danger: #ff6b6b;
  --danger-dim: #5c2020;
  --ok: #6ee36e;
  --ok-dim: #1f4a1f;
  --cell: #0a0a0a;
  --cell-beat: #1a1a1a;
  --topbar: rgba(0, 0, 0, .8);
  --tapbeat-on: #2e2e2e;
  --shadow-c: rgba(0, 0, 0, .22);
  --cloth-m: #3d3d48;
  --cloth-f: #e05046;
}

/* "System" follows the OS: it takes the dark palette above, and this swaps
   it for the light one when the OS asks for light. */
@media (prefers-color-scheme: light) {
  html[data-theme="system"] {
    color-scheme: light;
    --bg: #f7f2e9; --bg-tint: #ffffff; --bg2: #efe7d9;
    --panel: #fffcf6; --panel2: #f3ece0;
    --line: #e0d5c2; --line2: #cbbda4;
    --text: #241d15; --text2: #43382a; --muted: #7a6c58;
    --faint: #9c8e79; --faint2: #b3a591;
    --accent: #c47816; --accent-dim: #f0d5a8; --accent-ink: #fffaf2;
    --accent-soft: rgba(196, 120, 22, .13);
    --accent2: #10796e; --accent2-dim: #b7ded8; --accent2-ink: #f0fffd;
    --accent2-soft: rgba(16, 121, 110, .35);
    --danger: #b4331f; --danger-dim: #f0c4bb;
    --ok: #3d7d33; --ok-dim: #c3ddbd;
    --cell: #ece3d3; --cell-beat: #e0d4bd;
    --topbar: rgba(247, 242, 233, .82); --tapbeat-on: #e5d7bc;
    --shadow-c: rgba(90, 70, 40, .18);
  }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  background: var(--bg);
  background-image: radial-gradient(1200px 700px at 20% -10%, var(--bg-tint) 0%, var(--bg) 60%);
  background-attachment: fixed;
  color: var(--text);
  font: 15px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  min-height: 100%;
}

h1, h2, h3 { margin: 0 0 6px; line-height: 1.2; font-weight: 650; letter-spacing: -0.01em; }
h1 { font-size: 22px; }
h2 { font-size: 17px; }
p { margin: 0 0 10px; }
kbd {
  font: 12px var(--mono); background: var(--panel2); border: 1px solid var(--line2);
  border-bottom-width: 2px; border-radius: 5px; padding: 1px 6px;
}

/* ---------- layout ---------- */
.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  flex-wrap: wrap; padding: 16px 26px;
  border-bottom: 1px solid var(--line); background: var(--topbar);
  backdrop-filter: blur(8px); position: sticky; top: 0; z-index: 20;
}
.brand { display: flex; align-items: center; gap: 14px; }
svg.logo { width: 40px; height: 40px; display: block; flex: 0 0 40px; }
.lg-ring { fill: none; stroke: var(--accent); stroke-width: 1.5; opacity: .5; }
.lg-ink { fill: var(--accent); }
.lg-ink .lg-limb { fill: none; stroke: var(--accent); stroke-width: 2.2; stroke-linecap: round; }
.tag { margin: 0; color: var(--muted); font-size: 12.5px; }
/* `.topright` was declared here when the header was one wide row. Every property
   it set is re-declared by the band layout further down, so it is laid out there
   and only there. */

.tabs { display: flex; gap: 4px; background: var(--panel); padding: 4px; border-radius: 10px; border: 1px solid var(--line); }
.tabs button {
  background: none; border: 0; color: var(--muted); padding: 8px 16px; border-radius: 7px;
  font: inherit; font-weight: 550; cursor: pointer;
}
.tabs button:hover { color: var(--text); }
.tabs button.active { background: var(--accent); color: var(--accent-ink); }

.themepick { display: flex; align-items: center; gap: 7px; }
.themepick label { font-size: 12px; color: var(--muted); }
.themepick select { padding: 6px 9px; font-size: 13px; }

.view { display: none; max-width: 1180px; margin: 0 auto; padding: 22px 26px 10px; }
.view.active { display: block; }

.panel {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 18px 20px; margin-bottom: 18px;
}
.cols { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; align-items: start; }
@media (max-width: 900px) { .cols { grid-template-columns: 1fr; } }

.row { display: flex; align-items: center; }
.row.gap { gap: 12px; }
.row.between { justify-content: space-between; }
.row.wrap { flex-wrap: wrap; gap: 12px; }
.sub, .hint { color: var(--muted); font-size: 13px; }
.hint { margin: 6px 0 0; }

/* ---------- controls ---------- */
button {
  font: inherit; cursor: pointer; border-radius: 9px; border: 1px solid var(--line2);
  background: var(--panel2); color: var(--text); padding: 8px 14px;
  transition: background .12s, border-color .12s, color .12s;
}
button:hover { border-color: var(--accent); }
button.primary { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); font-weight: 650; }
button.primary:hover { filter: brightness(1.08); }
button.primary.on { background: var(--danger); border-color: var(--danger); color: #fff; }
button.ghost { background: transparent; }
button.big { padding: 11px 22px; font-size: 15px; }
button.small { padding: 5px 11px; font-size: 13px; }
button:disabled { opacity: .4; cursor: not-allowed; }

.styleswitch { display: inline-flex; background: var(--bg2); border: 1px solid var(--line); border-radius: 9px; padding: 3px; }
.styleswitch button { background: none; border: 0; color: var(--muted); padding: 7px 14px; border-radius: 7px; font-size: 13.5px; }
.styleswitch button.active { background: var(--panel2); color: var(--text); box-shadow: inset 0 0 0 1px var(--line2); }

input[type=search], select, input[type=file] {
  font: inherit; background: var(--bg2); color: var(--text);
  border: 1px solid var(--line2); border-radius: 9px; padding: 8px 12px;
}
input[type=search] { min-width: 200px; }
input[type=range] { accent-color: var(--accent); width: 150px; }
.bpmbox { display: flex; align-items: center; gap: 9px; font-size: 13px; color: var(--muted); }
.bpmbox output { font: 13px var(--mono); color: var(--accent); min-width: 72px; }
.field { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; flex-wrap: wrap; }
.field label { font-size: 13px; color: var(--muted); }
.check { display: inline-flex; align-items: center; gap: 7px; font-size: 13.5px; color: var(--muted); cursor: pointer; }
.check input { accent-color: var(--accent); }
.pill {
  font: 12px var(--mono); background: var(--bg2); border: 1px solid var(--line);
  color: var(--muted); padding: 3px 9px; border-radius: 20px;
}

/* ---------- the counter ---------- */
.counter { display: grid; grid-template-columns: repeat(8, 1fr); gap: 8px; margin: 18px 0 8px; }
.counter .beat {
  position: relative; aspect-ratio: 1 / .78; border-radius: 10px;
  background: var(--bg2); border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
  font: 600 30px/1 var(--mono); color: var(--faint);
  transition: background .06s, color .06s, border-color .06s, transform .06s;
}
.counter .beat.tapbeat { color: var(--faint2); }
.counter .beat small {
  position: absolute; bottom: 6px; left: 0; right: 0; text-align: center;
  font: 10px/1 system-ui; letter-spacing: .08em; text-transform: uppercase; color: var(--faint2);
}
.counter .beat.on { background: var(--accent-dim); border-color: var(--accent); color: var(--text); transform: translateY(-2px); }
.counter .beat.on.one { background: var(--accent); color: var(--accent-ink); }
.counter .beat.on.tapbeat { background: var(--tapbeat-on); border-color: var(--line2); color: var(--muted); transform: none; }
.counter.hiddenmode .beat { color: transparent; }
.counter.hiddenmode .beat small { color: transparent; }
.counter.hiddenmode .beat.on { background: var(--bg2); border-color: var(--line); transform: none; }
.counter.small .beat { aspect-ratio: 1 / .5; font-size: 20px; }
.counter-caption { color: var(--muted); font-size: 12.5px; margin: 0; }

/* ---------- mixer ---------- */
.mixer { list-style: none; margin: 0; padding: 0; }
.mixer li {
  display: flex; align-items: flex-start; gap: 11px; padding: 9px 0;
  border-top: 1px solid var(--line);
}
.mixer li:first-child { border-top: 0; }
.mixer .name { font-weight: 600; font-size: 14px; }
.mixer .why { color: var(--muted); font-size: 12.5px; }
.mixer .grow { flex: 1; min-width: 0; }
.mixer .solo {
  font: 600 11px/1 system-ui; letter-spacing: .06em; padding: 5px 9px; border-radius: 6px;
  background: transparent; border: 1px solid var(--line2); color: var(--muted);
}
.mixer .solo.on { background: var(--accent2); border-color: var(--accent2); color: var(--accent2-ink); }
.mixer input[type=checkbox] { margin-top: 4px; accent-color: var(--accent); width: 16px; height: 16px; }

/* ---------- rhythm grid ---------- */
.grid-wrap { overflow-x: auto; }
.grid { display: grid; gap: 3px; min-width: 520px; }
.grid .grow { display: grid; grid-template-columns: 92px repeat(32, 1fr); gap: 3px; align-items: center; }
.grid .glabel { font-size: 11.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.grid .cell { height: 17px; border-radius: 3px; background: var(--cell); border: 1px solid transparent; }
.grid .cell.beat { background: var(--cell-beat); }
.grid .cell.hit { background: var(--accent); }
.grid .cell.hit.soft { background: var(--accent-dim); }
.grid .cell.now { border-color: var(--accent2); }
.grid .head .cell {
  height: auto; background: none; font: 10px/1.4 var(--mono); color: var(--faint); text-align: center;
}
.grid .head .cell.beat { color: var(--text); }

/* ---------- drill modes / scoring ---------- */
.modes { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }
.modes button { padding: 7px 13px; font-size: 13.5px; }
.modes button.active { background: var(--accent2); border-color: var(--accent2); color: var(--accent2-ink); font-weight: 600; }

.tapzone {
  margin: 14px 0; padding: 16px; border-radius: 10px; text-align: center;
  border: 1px dashed var(--line2); background: var(--bg2); cursor: pointer;
  transition: background .08s, border-color .08s;
}
.tapzone.flash { background: var(--accent-dim); border-color: var(--accent); }
.tapzone-key { font: 600 12px var(--mono); letter-spacing: .2em; color: var(--muted); }
.tapzone-text { font-size: 15px; margin-top: 4px; }

.score { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.score > div { display: flex; flex-direction: column; }
.score-num { font: 600 22px var(--mono); color: var(--accent); }
.score-lbl { font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.feedback { margin-top: 12px; min-height: 44px; font-size: 14px; }
.feedback .good { color: var(--ok); }
.feedback .near { color: var(--accent); }
.feedback .bad { color: var(--danger); }
.feedback .meter { height: 6px; background: var(--bg2); border-radius: 4px; margin-top: 8px; position: relative; overflow: hidden; }
.feedback .meter i { position: absolute; top: 0; bottom: 0; width: 3px; background: var(--accent2); }
.feedback .meter b { position: absolute; top: 0; bottom: 0; left: 50%; width: 1px; background: var(--line2); }

.earguide h3 { font-size: 13.5px; margin: 14px 0 3px; color: var(--accent); }
.earguide h3:first-child { margin-top: 0; }
.earguide p { font-size: 13.5px; color: var(--text2); margin: 0 0 6px; }

.steps { margin: 12px 0; padding-left: 0; list-style: none; font-size: 13.5px; color: var(--text2); }
.steps li { margin-bottom: 7px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* ---------- move visuals ---------- */
.viz { display: block; width: 100%; height: auto; }
.viz .floor { fill: var(--bg2); stroke: var(--line); }
.viz .path { fill: none; stroke-width: 2; stroke-dasharray: 5 4; }
.viz .path.l { stroke: var(--accent); }
.viz .path.f { stroke: var(--accent2); }
.viz .fig-l { fill: var(--accent); }
.viz .fig-f { fill: var(--accent2); }
.viz .fig-x { fill: var(--muted); }
.viz .ghost { opacity: .3; }
.viz .ink-l { fill: var(--accent-ink); font: 600 11px var(--mono); }
.viz .ink-f { fill: var(--accent2-ink); font: 600 11px var(--mono); }
.viz .ink-x { fill: var(--bg); font: 600 11px var(--mono); }
.viz .hand { fill: none; stroke: var(--text2); stroke-width: 1.5; stroke-dasharray: 2 3; }
.viz .lbl { fill: var(--muted); font: 9.5px system-ui; letter-spacing: .04em; }
.viz .spin { fill: none; stroke-width: 1.8; }
.viz .spin.f { stroke: var(--accent2); }
.viz .spin.l { stroke: var(--accent); }

.vizbox { background: var(--bg2); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; }
.vizbox .vizcap { color: var(--muted); font-size: 12.5px; margin: 8px 0 0; }
.vizgrid { display: grid; grid-template-columns: 1.15fr 1fr; gap: 14px; align-items: start; }
@media (max-width: 720px) { .vizgrid { grid-template-columns: 1fr; } }

/* foot timeline */
.feet { display: grid; grid-template-columns: 46px repeat(8, 1fr); gap: 4px; align-items: center; }
.feet .rlabel { font: 600 10px system-ui; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.feet .fcell {
  border-radius: 6px; background: var(--cell); border: 1px solid var(--line);
  text-align: center; padding: 7px 0 6px; font: 600 12px var(--mono); color: var(--faint);
  position: relative;
}
.feet .fcell.L { background: var(--accent-dim); color: var(--text); border-color: var(--accent); }
.feet .fcell.R { background: var(--accent2-dim); color: var(--text); border-color: var(--accent2); }
.feet .fcell.tap { background: var(--cell-beat); color: var(--muted); border-style: dashed; }
.feet .fcell.now { outline: 2px solid var(--accent); outline-offset: 1px; }
.feet .num { font: 10px var(--mono); color: var(--faint); text-align: center; }
.feetkey { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 9px; font-size: 11.5px; color: var(--muted); }
.feetkey span { display: inline-flex; align-items: center; gap: 5px; }
.feetkey i { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }
.feetkey i.l { background: var(--accent-dim); border: 1px solid var(--accent); }
.feetkey i.r { background: var(--accent2-dim); border: 1px solid var(--accent2); }
.feetkey i.t { background: var(--cell-beat); border: 1px dashed var(--line2); }

/* ---------- move library ---------- */
/* min-width:0 so a wide child cannot force the column - and therefore the page
   - to grow. Grid items default to min-width:auto, which means "at least as wide
   as my content", and that is how one oversized canvas drags the whole layout. */
.library { display: grid; grid-template-columns: 340px minmax(0, 1fr); gap: 18px; align-items: start; }
/* The filter belongs to the list, so it lives with it - but on a wide screen it
   still reads as a bar across the top of both columns. The browse strip above it
   is the library's own header and spans the same way. */
#movesFilter, .browsebar { grid-column: 1 / -1; }
.library > * { min-width: 0; }
/* A tablet is not a big phone. Everything that folds this app into one column
   used to key off 900px, which swallowed every tablet in portrait: at 768 the
   list was hidden behind a button and the detail ran down a single narrow
   column with 340px of the screen doing nothing. Two columns fit comfortably
   at 768 - they just need a narrower list. The fold now begins at 720, which is
   where a phone in landscape gives out. */
@media (max-width: 1000px) and (min-width: 721px) {
  .library { grid-template-columns: 264px minmax(0, 1fr); gap: 14px; }
  .movelist { max-height: 62vh; }
}
@media (max-width: 720px) { .library { grid-template-columns: 1fr; } }
.movelist { display: flex; flex-direction: column; gap: 8px; max-height: 78vh; overflow-y: auto; padding-right: 4px; }
.movecard {
  text-align: left; width: 100%; background: var(--panel); border: 1px solid var(--line);
  border-radius: 10px; padding: 12px 14px; display: flex; gap: 12px; align-items: flex-start;
}
.movecard:hover { border-color: var(--accent-dim); }
.movecard.active { border-color: var(--accent); background: var(--panel2); }
.movecard .mc-body { flex: 1; min-width: 0; }
.movecard .mc-thumb { width: 92px; flex: 0 0 92px; }
.movecard .mc-top { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.movecard .mc-name { font-weight: 640; font-size: 14.5px; }
.movecard .mc-sum { color: var(--muted); font-size: 12.5px; margin-top: 3px; }
.badge {
  font: 600 10px system-ui; letter-spacing: .05em; text-transform: uppercase;
  padding: 3px 7px; border-radius: 5px; background: var(--bg2); color: var(--muted); border: 1px solid var(--line);
  white-space: nowrap;
}
.badge.l1 { color: var(--ok); border-color: var(--ok-dim); }
.badge.l2 { color: var(--accent); border-color: var(--accent-dim); }
.badge.l3 { color: var(--danger); border-color: var(--danger-dim); }
.badge.concept { color: var(--accent2); border-color: var(--accent2-dim); }

.movedetail { min-height: 300px; }
.movedetail .md-head { border-bottom: 1px solid var(--line); padding-bottom: 12px; margin-bottom: 14px; }
.movedetail .md-aka { color: var(--muted); font-size: 13px; font-style: italic; }

/* ---- the three views read as one numbered flow, not three apps ---- */
.tabs button { display: inline-flex; align-items: baseline; gap: 7px; }
.tabs button b {
  display: inline-flex; align-items: center; justify-content: center;
  width: 17px; height: 17px; border-radius: 50%;
  background: var(--line); color: var(--bg);
  font-size: 10px; font-weight: 700;
}
.tabs button.active b { background: var(--accent); color: var(--bg); }
.tabs button span { font-size: 11px; color: var(--muted); font-weight: 400; }
.tabs button.active span { color: inherit; opacity: .7; }

/* the dance you are working on is the top-level choice */
.stylepick select { font-weight: 600; }

.nowdancing { display: flex; align-items: center; gap: 10px; }
.nowdancing strong { font-size: 15px; }

/* where to go next, from a move */
.handoff { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 4px; }

.linkish { cursor: pointer; }
.linkish:hover { color: var(--accent); text-decoration: underline; }

.scrubread {
  font-variant-numeric: tabular-nums;
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-size: 12px;
  white-space: nowrap;
  cursor: pointer;
  border-bottom: 1px dotted var(--line);
}
.scrubread:hover { color: var(--accent); }
.scrubread.copied { color: var(--accent); border-bottom-color: transparent; }

/* Two kinds of switch on the viz control row: how you are shown the move
   (sound, cues) and how the move itself is danced (circle, travelling). */
.ctlgroup { display: inline-flex; align-items: center; gap: 10px; }
.ctlgroup + .ctlgroup { margin-left: 4px; padding-left: 14px; border-left: 1px solid var(--line); }
.ctlgroup.dancegrp .check { color: var(--accent); }

/* say-it-out-loud button, sitting on the move name */
.movedetail h2 .sayname {
  margin-left: 10px;
  padding: 0;
  width: 24px; height: 24px;
  line-height: 1;
  font-size: 10px;
  vertical-align: 3px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--cell);
  color: var(--accent);
  cursor: pointer;
  transition: background .15s, color .15s, transform .15s;
}
.movedetail h2 .sayname:hover { background: var(--accent); color: var(--bg); }
.movedetail h2 .sayname.saying { background: var(--accent); color: var(--bg); transform: scale(1.15); }
.movedetail .md-phon { margin-top: 2px; font-size: 13px; }
.movedetail .md-phon .phon {
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: .02em;
  color: var(--ink);
}
.movedetail .md-phon .phonnote { margin-left: 8px; color: var(--muted); font-size: 12px; }

/* the missing-voice notice, with the fix folded up behind it */
.movedetail .md-phon .fixlink {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: 12px;
  color: var(--muted);
  cursor: pointer;
  text-decoration: underline dotted;
  text-underline-offset: 3px;
}
.movedetail .md-phon .fixlink:hover,
.movedetail .md-phon .fixlink.open { color: var(--accent); }
.voicefix {
  margin: 8px 0 2px;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 8px;
  background: var(--cell);
  max-width: 620px;
}
.voicefix strong { display: block; font-size: 13px; margin-bottom: 6px; }
.voicefix ol { margin: 0 0 8px; padding-left: 20px; font-size: 13px; color: var(--text2); }
.voicefix ol li { margin-bottom: 4px; }
.voicefix .tryfirst { margin: 6px 0 0; font-size: 12.5px; color: var(--muted); }
.movedetail .md-meta { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 9px; }
.movedetail h3 { font-size: 13px; text-transform: uppercase; letter-spacing: .07em; color: var(--accent); margin: 20px 0 8px; }
.movedetail p { font-size: 14px; color: var(--text2); }
.movedetail ul { margin: 0; padding-left: 18px; font-size: 13.5px; color: var(--text2); }
.movedetail ul li { margin-bottom: 5px; }
.movedetail .placeholder { color: var(--muted); text-align: center; padding: 60px 20px; }

.counttable { width: 100%; border-collapse: collapse; font-size: 13px; margin-bottom: 14px; }
.counttable th { text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); padding: 5px 8px; font-weight: 600; }
.counttable td { padding: 6px 8px; border-top: 1px solid var(--line); vertical-align: top; color: var(--text2); }
.counttable td.n { font: 600 15px var(--mono); color: var(--accent); width: 34px; }
.counttable tr.tap td.n { color: var(--muted); }
.counttable tr.tap td { color: var(--muted); }
.counttable tr.now td { background: var(--accent-soft); }
.phrase-label { font: 600 12px system-ui; color: var(--accent2); text-transform: uppercase; letter-spacing: .06em; margin: 14px 0 4px; }

.md-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 16px; align-items: center; }
a.link { color: var(--accent2); font-size: 13px; text-decoration: none; border-bottom: 1px solid var(--accent2-soft); }
a.link:hover { border-bottom-color: var(--accent2); }

/* ---------- drill ---------- */
.chips { display: flex; flex-wrap: wrap; gap: 7px; min-height: 34px; align-items: center; }
.chips .empty { color: var(--muted); font-size: 13px; }
.chip {
  display: inline-flex; align-items: center; gap: 7px; background: var(--panel2);
  border: 1px solid var(--line2); border-radius: 20px; padding: 5px 6px 5px 13px; font-size: 13px;
}
.chip.on { border-color: var(--accent); background: var(--accent-dim); }
.chip button { background: none; border: 0; color: var(--muted); padding: 0 5px; font-size: 15px; line-height: 1; }
.chip button:hover { color: var(--danger); }

.picker { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); }
.picker button { padding: 6px 12px; font-size: 13px; }

.drillstage { background: linear-gradient(160deg, var(--panel2), var(--panel)); }
.stage-label { font: 600 11px system-ui; letter-spacing: .09em; text-transform: uppercase; color: var(--muted); margin: 0 0 2px; }
.stage-move { font-size: 27px; margin: 0; }
.stage-next { font-size: 18px; margin: 0; color: var(--muted); text-align: right; }
.stage-sub { color: var(--accent2); font-size: 12.5px; margin: 4px 0 0; }
.stagegrid { display: grid; grid-template-columns: 330px minmax(0, 1fr); gap: 16px; align-items: start; }
.stagegrid > * { min-width: 0; }
@media (max-width: 820px) { .stagegrid { grid-template-columns: 1fr; } }
.cues { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.cues.single { grid-template-columns: 1fr; }
.cue { background: var(--bg2); border: 1px solid var(--line); border-radius: 10px; padding: 14px 16px; min-height: 92px; }
.cue .role { font: 600 11px system-ui; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-bottom: 6px; }
.cue .text { font-size: 19px; line-height: 1.35; }
.cue .text.tapline { color: var(--muted); }


/* ---------- move viz panel ---------- */
.vizpanel { margin-bottom: 16px; }
.viztabs { display: flex; gap: 6px; margin-bottom: 10px; flex-wrap: wrap; align-items: center; }
.viztabs button { padding: 6px 12px; font-size: 13px; }
.viztabs button.active { background: var(--accent2); border-color: var(--accent2); color: var(--accent2-ink); font-weight: 600; }
.viztabs .spacer { flex: 1; }
.vizstage { background: var(--bg2); border: 1px solid var(--line); border-radius: 10px; padding: 10px; }
.vizstage .viz { max-height: 300px; }
.vizcap { color: var(--muted); font-size: 12.5px; margin: 9px 2px 0; }
.vizphrase { font: 600 11px system-ui; letter-spacing: .06em; text-transform: uppercase; color: var(--accent2); margin: 0 0 7px; }

.strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
@media (max-width: 560px) { .strip { grid-template-columns: repeat(2, 1fr); } }
.stillcell { background: var(--cell); border: 1px solid var(--line); border-radius: 8px; padding: 4px; }
.stillcell.tap { border-style: dashed; opacity: .82; }
.stillnum { font: 600 10px var(--mono); color: var(--muted); text-align: center; padding: 2px 0 3px; }

.movecard .mc-thumb .viz { height: 52px; }
.movecard .mc-thumb .floor { fill: var(--cell); }

.drillviz { background: var(--bg2); border: 1px solid var(--line); border-radius: 10px; padding: 8px; }
.drillviz .viz { max-height: 200px; }


/* ---------- 3D stage ---------- */
.orbit { cursor: grab; touch-action: none; user-select: none; }
.orbit:active { cursor: grabbing; }
.vizstage, .drillviz { position: relative; overflow: hidden; }
canvas.stage3d { display: block; width: 100%; max-width: 100%; height: auto; border-radius: 8px; }

/* cue labels ride on top of the canvas, positioned by projecting their 3D anchor */
.cuelayer { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.cue3d {
  position: absolute; transform: translate(-50%, -100%); white-space: nowrap;
  font: 700 11px system-ui; letter-spacing: .03em; padding: 2px 8px; border-radius: 20px;
  background: var(--panel); border: 1px solid var(--line2); color: var(--text);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .25);
  transform-origin: 50% 100%;
}
.cue3d.badge { font-size: 10px; padding: 1px 6px; font-weight: 800; }
/* Colour says WHOSE cue it is. Colouring by kind made a leader's "tap" show up
   in the follower's colour, which reads as the cue belonging to her. */
.cue3d.role-l { color: var(--accent); border-color: var(--accent-dim); }
.cue3d.role-f { color: var(--accent2); border-color: var(--accent2-dim); }
.cue3d i { font-style: normal; font-weight: 800; margin-right: 5px; opacity: .95; }
.cue3d.role-l i { color: var(--accent); }
.cue3d.role-f i { color: var(--accent2); }
.cue3d.tap { font-weight: 800; }
.cue3d.hold { opacity: .85; }
.cue3d.hands { color: var(--text2); border-color: var(--line2); font-weight: 650; }

.filternote {
  width: 100%; text-align: left; font-size: 12.5px; color: var(--muted);
  background: var(--accent-soft); border: 1px solid var(--accent-dim);
  border-radius: 8px; padding: 7px 11px;
}
.filternote strong { color: var(--accent); }
.filternote:hover { border-color: var(--accent); color: var(--text); }

.stillcell img.still { display: block; width: 100%; height: auto; border-radius: 6px; }
.movecard .mc-thumb img { display: block; width: 100%; height: auto; border-radius: 6px; }
.camrow { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 9px; }
.camrow button { padding: 4px 10px; font-size: 12px; }
.camhint { color: var(--muted); font-size: 11.5px; margin-left: auto; }

.vizstage .viz.people { max-height: 340px; }
.drillviz .viz.people { max-height: 250px; }
.movecard .mc-thumb .viz.people { height: 64px; }

/* ---------- scrub bar ---------- */
.scrubrow { display: flex; align-items: center; gap: 12px; margin-top: 10px; }
.scrubrow .scrub { flex: 1; width: auto; accent-color: var(--accent); cursor: grab; }
.scrubrow .scrub:active { cursor: grabbing; }
.scrubread {
  font: 600 12px var(--mono); color: var(--muted); min-width: 118px; text-align: right;
}


/* ============================================================================
   SMALL SCREENS

   The layout was built for a desktop and broke in three distinct ways on a
   phone, all of which needed different fixes rather than one blanket rule:

   1. Things that must SHRINK - paddings, type, the top bar - because a desktop
      header ate a third of an 812px screen before any content appeared.
   2. Things that must STACK - the two-column panels - which mostly already had
      breakpoints, except their children could still force the column wider than
      the screen. Grid and flex children default to min-width:auto, meaning "at
      least as wide as my content", so one wide table drags the page sideways.
   3. Things that CANNOT shrink and must SCROLL instead - the 32-step rhythm
      grid, the eight-count tables. Squeezing a 32-column grid into 375px makes
      it unreadable; letting it scroll inside its own box keeps it usable and
      keeps the page from scrolling sideways.
   ========================================================================= */

/* Nothing may push the page wider than the screen. */
html, body { max-width: 100%; overflow-x: hidden; }
.view, .panel, .cols, .library, .stagegrid, .vizgrid { min-width: 0; }
.view > *, .cols > *, .library > *, .stagegrid > *, .vizgrid > *, .panel > * { min-width: 0; }

/* Wide, dense things scroll inside themselves rather than stretching the page. */
.counttable-wrap, #vizFeet, #drillFeet { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* Tablets and small laptops: the desktop bar still fits horizontally but wraps
   into three rows and takes 197px of height. It only needs tightening, not the
   full phone treatment - the tab sub-labels are still useful here. */
@media (max-width: 900px) {
  .topbar { padding: 10px 16px; gap: 10px 14px; }
  .tag { display: none; }
  .brand h1 { font-size: 21px; }
  svg.logo { width: 32px; height: 32px; flex-basis: 32px; }
  .themepick label { font-size: 11px; }
  .themepick select { padding: 6px 8px; font-size: 12.5px; }
}

@media (max-width: 860px) {
  .stagegrid { grid-template-columns: 1fr; }
  .view { padding: 16px 16px 10px; }
}

@media (max-width: 680px) {
  /* --- top bar: three tight rows instead of one wide one --- */
  .topbar {
    padding: 10px 14px; gap: 10px;
    flex-direction: column; align-items: stretch;
  }
  .brand { gap: 10px; }
  .brand h1 { font-size: 20px; }
  svg.logo { width: 30px; height: 30px; flex-basis: 30px; }
  .tag { display: none; }              /* the strapline is the first thing to go */

  /* `.topright` is laid out once, further down, for every width - see there. */
  .tabs { width: 100%; justify-content: space-between; }
  .tabs button { flex: 1 1 0; padding: 9px 4px; justify-content: center; font-size: 13px; }
  .tabs button span { display: none; }  /* "rhythm lab" etc - the number and word carry it */
  /* Stacking the label above the select made sense when the label was a WORD.
     It is a glyph now, and a glyph floating over a dropdown reads as a stray
     mark rather than as that control's icon - so it sits beside the select, on
     the same line, where an icon belongs. */
  .themepick { flex-direction: row; align-items: center; gap: 8px; }
  .themepick label { font-size: 10.5px; }
  .themepick select { width: 100%; min-width: 0; padding: 8px 9px; font-size: 13px; }

  /* --- content --- */
  .view { padding: 14px 12px 10px; }
  .panel { padding: 14px; }
  .cols { gap: 14px; }

  .counter { gap: 5px; margin: 12px 0 6px; }
  .counter .beat { font-size: 17px; border-radius: 7px; aspect-ratio: 1 / .92; }
  .counter.small .beat { font-size: 14px; aspect-ratio: 1 / .7; }
  /* The "THE ONE" / "TAP" tags are absolutely positioned at the bottom of a
     cell, and once the cell is phone-sized they land on top of the number. The
     caption under the row already says what 1, 4 and 8 mean. */
  .counter .beat small { display: none; }

  /* the eight-count table is genuinely wide; let it scroll */
  .counttable { font-size: 12px; min-width: 460px; }
  .counttable td, .counttable th { padding: 5px 6px; }

  .feet { min-width: 420px; }

  /* controls wrap instead of squeezing, and stay thumb-sized */
  .viztabs, .row.gap { flex-wrap: wrap; }
  /* Thumb-sized controls - but NOT every button. A move card is a <button> too,
     and as a flex-column child a min-height plus the default flex-shrink
     squashed 96px cards down to 38px with the text spilling out of them. */
  .tabs button, .styleswitch button, .viztabs button, select,
  .ghost, .primary, button.small { min-height: 38px; }
  .movecard { flex-shrink: 0; min-height: 0; }

  /* Two controls stayed too small for a fingertip: the SOLO buttons on each
     mixer row, and the little x that removes a move from a drill. */
  .mixrow .solo, .solo { min-height: 32px; padding-inline: 12px; }
  .chip button { min-width: 30px; min-height: 30px; font-size: 16px; }

  /* the level filter scrolls rather than being clipped */
  .styleswitch { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .styleswitch button { white-space: nowrap; flex: 0 0 auto; }
  .ctlgroup + .ctlgroup { margin-left: 0; padding-left: 10px; }

  .bpmbox input[type=range] { width: 100% !important; }
  .bpmbox { flex: 1 1 100%; }

  /* Grid and flex children size to their content unless told otherwise, which
     is how an eight-cell counter ends up wider than the panel holding it. */
  .counter .beat, .grid .cell, .grid .glabel, .feet > * { min-width: 0; }
  .counter { grid-template-columns: repeat(8, minmax(0, 1fr)); }

  /* The header scrolls away on a phone instead of holding the top of the
     screen - there is not enough of it to give a third away permanently. */
  .topbar { position: static; }

  .movelist { max-height: 46vh; }
  .movedetail { min-height: 0; }
  .voicefix { max-width: 100%; }
}

@media (max-width: 420px) {
  .tabs button b { display: none; }     /* just Listen / Learn / Practise */
  .tabs button { font-size: 12.5px; padding: 9px 2px; }
  .view { padding: 12px 10px 10px; }
  .panel { padding: 12px; }
  h2 { font-size: 20px; }
  /* NB the pickers stay two-up here. Stacking them one per row was tried and
     made the header TALLER than the desktop one - 369px of a 812px screen
     before any content - which is the opposite of the point. */
}

/* Touch: the stage owns its gestures, so the page must not also pan while you
   are orbiting the camera. */
.vizstage, .drillviz { touch-action: none; }

/* A queued pair that does not actually join up. Worth saying out loud, but it is
   a caution rather than an error - the figures themselves are still correct. */
.seqnote {
  margin-top: 10px; padding: 10px 12px;
  border: 1px solid var(--warn-line, #7a5b1e); border-radius: 8px;
  background: rgba(190, 140, 40, .09);
  font-size: 13px; line-height: 1.45;
}
.seqnote strong { display: block; margin-bottom: 4px; color: var(--warn, #e0b25c); }
.seqnote ul { margin: 0 0 6px; padding-left: 18px; }
.seqnote li { margin: 2px 0; }
.seqnote p { margin: 0; opacity: .75; }

/* ---------------------------------------------------------------------------
   The move list on a phone

   Stacked, the list came first and filled the screen, so the Learn tab opened
   on a wall of moves with no sign that a visualisation existed below it. The
   list is how you CHOOSE; the move itself is what you came to look at. So on a
   narrow screen the list folds away behind a button that names the move you are
   on, and the detail - visualisation first - starts at the top of the screen.

   Desktop is a two-column layout where both fit at once, and is left alone. */
/* The inside of the toggle is the same at every width - an eyebrow over a name,
   sized to match the sequence bar's head exactly, so Learn and Practise present
   the identical object rather than two bars of different heights. Only the
   border and the accent-coloured invitation are mobile-only: on a wide screen
   the list is already visible, so there is nothing to invite you into. */
.listtoggle {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; padding: 12px 14px; text-align: left;
  background: none; border: 0; color: var(--ink);
}
.listtoggle .lt-now { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.listtoggle .lt-eyebrow {
  font-size: 9.5px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  opacity: .55;
}
.listtoggle .lt-label {
  font-size: 14px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

@media (max-width: 720px) {
  /* Folded away, the toggle has to read as a CONTROL rather than a caption: a
     name and a chevron alone looked like a heading that happened to have a mark
     after it, with nothing to say that more moves were behind it or how many. */
  .listtoggle {
    border: 1px solid var(--line); border-radius: 10px;
    background: var(--panel);
    box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
  }
  .listtoggle .lt-label { font-size: 15px; font-weight: 700; }
  /* the invitation: coloured, boxed, and counted, so it is plainly a button */
  .listtoggle .lt-cta {
    flex: 0 0 auto; display: flex; align-items: center; gap: 7px;
    padding: 6px 10px; border-radius: 999px;
    background: var(--accent-soft, rgba(176, 122, 44, .13));
    color: var(--accent, #b07a2c);
    font-size: 12.5px; font-weight: 700; white-space: nowrap;
  }
  /* a chevron that turns to point the way the list will move */
  .listtoggle .lt-mark {
    flex: 0 0 auto; width: 7px; height: 7px;
    border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform .18s ease;
  }
  .library.browsing .listtoggle .lt-mark { transform: rotate(-135deg) translate(-1px, -1px); }
  .library.browsing .listtoggle { border-color: var(--accent, #b07a2c); }

  /* Folded away by default: the move you are looking at gets the screen. */
  .library .movelist { display: none; }
  .library.browsing .movelist { display: flex; max-height: 62vh; }
  /* while browsing, the detail is out of the way rather than pushed down the page */
  .library.browsing .movedetail { display: none; }
}

@media (max-width: 720px) {
  /* Levels and search are for finding a move, so they appear with the list they
     filter - and BELOW the button that opens it. Opening a panel above the thing
     you just tapped pushes it down the screen, so the control moves out from
     under your finger just as you look at it. */
  /* `align-items: start` is right for the desktop grid, where the two columns
     should not stretch to the tallest of them. Carried into this flex column it
     means every child shrinks to its own content instead of filling the width -
     which is why the browse strip stood 80px narrower than the panels under it. */
  .library { display: flex; flex-direction: column; align-items: stretch; }
  #moveListToggle { order: 0; }
  #movesFilter { order: 1; display: none; }
  #moveList { order: 2; }
  #moveDetail { order: 3; }
  .library.browsing #movesFilter { display: block; }

  /* Inside the visualisation panel the controls came first, which put the stage
     itself off the bottom of the screen: you arrived at a row of buttons with
     no sign of what they drove. The picture goes first and the controls sit
     under it, where a caption belongs. */
  .vizpanel { display: flex; flex-direction: column; }
  .vizpanel #vizStage { order: -1; margin-bottom: 10px; }

  /* The previous/next-move links are navigation, not content: useful at the
     bottom of a move, wasteful above its title. */
  .md-head .handoff { order: 2; margin-top: 12px; }
  .md-head { display: flex; flex-direction: column; }

  /* On a phone the picture comes before the write-up. The name, pronunciation
     and badges are worth having, but they are not worth a screenful ahead of
     the thing you opened the move to see - and the button directly above the
     panel already says which move this is, so nothing is lost by reading the
     title after the shape. */
  #moveDetail { display: flex; flex-direction: column; }
  #moveDetail .vizpanel { order: -1; margin-bottom: 4px; }
}

/* The hold, given its own line rather than a fourth grey badge. */
.md-hold {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line);
  font-size: 14px;
}
.md-hold .mh-key {
  font-size: 10px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  opacity: .55;
}
.md-hold .mh-val { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.md-hold .mh-arrow { opacity: .5; }

/* The written position, alongside the modelled one - it carries detail the
   geometry does not, like which hands are joined. */
.md-hold .mh-note { opacity: .6; font-size: 12.5px; }
.md-hold .mh-note::before { content: "·"; margin-right: 8px; opacity: .7; }

/* The saved combinations, which now vary by style rather than being three
   fixed buttons. */
.presetlist { display: inline-flex; flex-wrap: wrap; gap: 8px; }

/* ---------------------------------------------------------------------------
   The drill's sequence panel

   Building a sequence is something you do once; running it is what you do for
   the next twenty minutes. Chips, seven preset buttons and the whole move
   picker was a screenful before you reached the thing you came to watch, and on
   a phone it WAS the screen. So it folds, and the head carries a summary - how
   many moves, how many eights, the first few names - because folded should
   still tell you what is in there.
   ------------------------------------------------------------------------ */
.seqpanel { padding: 0; overflow: hidden; }
.seqhead {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; padding: 12px 14px; text-align: left;
  background: none; border: 0; border-radius: 0; color: var(--ink);
}
.seqhead .sq-now { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.seqhead .sq-eyebrow {
  font-size: 9.5px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  opacity: .55;
}
.seqhead .sq-label {
  font-size: 14px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.seqhead .sq-now { gap: 2px; }
.seqhead .sq-cta {
  flex: 0 0 auto; display: flex; align-items: center; gap: 7px;
  padding: 6px 10px; border-radius: 999px;
  background: var(--accent-soft, rgba(176, 122, 44, .13));
  color: var(--accent, #b07a2c);
  font-size: 12.5px; font-weight: 700; white-space: nowrap;
}
.seqhead .sq-mark {
  width: 7px; height: 7px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .18s ease;
}
.seqpanel.open .seqhead .sq-mark { transform: rotate(-135deg) translate(-1px, -1px); }
.seqbody { display: none; padding: 0 14px 14px; }
.seqpanel.open .seqbody { display: block; }
.seqpanel .seqnote { margin: 0 14px 14px; }

/* The drill's scrub bar sits under the stage controls, like the library's. */
#drillScrubRow { margin: 6px 0 10px; }

@media (max-width: 720px) {
  /* On a phone the drill reads top to bottom: what you are dancing, the count
     you are on, then the figures. The option switches and the scrub bar are
     things you reach for between runs, not while dancing, so they sit under the
     picture rather than pushing it off the bottom of the screen. */
  .drillstage { display: flex; flex-direction: column; }
  .drillstage .stagegrid { order: 1; }
  .drillstage #drillOptions { order: 2; }
  .drillstage #drillScrubRow { order: 3; margin-top: 4px; }
}

/* The "you can move this" hint, sitting on the stage rather than under it.
   Shown for a moment when the stage appears and again on hover, so it teaches
   once and then stays out of the way. */
.vizstage, .drillviz { position: relative; }
.camtip {
  position: absolute; left: 50%; bottom: 10px; transform: translateX(-50%) translateY(4px);
  padding: 5px 11px; border-radius: 999px;
  background: rgba(20, 14, 8, .62); color: #fff;
  font-size: 11.5px; letter-spacing: .01em; white-space: nowrap;
  pointer-events: none; opacity: 0;
  transition: opacity .35s ease, transform .35s ease;
}
.camtip.on { opacity: 1; transform: translateX(-50%) translateY(0); }
@media (max-width: 680px) { .camtip { font-size: 10.5px; padding: 4px 9px; } }
@media (prefers-reduced-motion: reduce) { .camtip { transition: none; } }


/* Visually hidden but read aloud, so every control keeps a real name. */
.vh {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* The theme is a whole-page setting, so it sits at the page's own corner,
   pushed away from the controls that belong to the picture. */
.themecorner { margin-left: auto; }

/* ---------------------------------------------------------------------------
   The browse bar

   The dance you are doing and the move you are looking at are one decision made
   in two steps, so they sit in one strip: pick the dance, then pick the figure.
   ------------------------------------------------------------------------ */
/* superseded below: the three bars share one rule, with no gap */
.browsebar .listtoggle { flex: 1 1 auto; }
.browsebar .dancepick {
  flex: 0 0 auto; display: flex; align-items: center; gap: 7px;
  padding: 8px 12px; border: 1px solid var(--line); border-radius: 10px;
  background: var(--panel);
}
.browsebar .dancepick select { border: 0; background: none; padding: 4px 2px; font-weight: 600; }
.browsebar .dancepick label { opacity: .55; }

/* On a wide screen the browse bar is the library's own header, so the toggle
   inside it shows even though the list is not folded away. */
@media (min-width: 721px) {
  .browsebar .listtoggle { display: flex; }
  .browsebar .listtoggle .lt-cta { display: none; }
  .browsebar .listtoggle { pointer-events: none; }
}
@media (max-width: 720px) {
  .browsebar { flex-wrap: wrap; }
  .browsebar .dancepick { flex: 1 1 100%; justify-content: flex-start; }
}


/* ===========================================================================
   Header

   Three bands rather than one crowded row. The brand line carries the name and,
   at the far right of the page, the theme - a whole-page choice belongs at the
   page's own corner. Under it the numbered tabs. Under those, the two controls
   that describe the PICTURE rather than the page: how the figures are drawn and
   where they are standing.
   ======================================================================== */
/* The base rule is a wrapping row with space-between, which is what the single
   crowded row used to need. As a COLUMN both are wrong: wrap turns into
   wrapping columns, and space-between silently redistributes the row gaps the
   moment anything gives the header a height. Neither shows today - which is
   exactly why they are worth removing rather than leaving armed. */
.topbar {
  flex-direction: column; align-items: stretch;
  flex-wrap: nowrap; justify-content: flex-start; gap: 10px;
}
.brand { display: flex; align-items: center; gap: 14px; }
.brand > div { flex: 1 1 auto; min-width: 0; }
/* Has to out-specify `.brand > div` above, which is a class plus a type and so
   beats a bare class. It did not, so the theme box grew to fill the brand row
   and its `margin-left: auto` had no free space left to push against - the
   control sat two thirds of the way across with 365px of dead space to its
   right, looking centred rather than cornered. */
.brand > .themecorner { flex: 0 0 auto; margin-left: auto; }

/* The only live layout for `.topright`, at every width. It is unmediated and
   comes after the phone and tablet blocks, so it beat them wherever they said
   something different - which is how a `display: grid` two-up rule up there sat
   dead for so long without anything looking wrong: `.picrow` wraps by itself,
   so the pickers paired up regardless. `flex-wrap` has to be said here too,
   because the base rule sets it for a ROW and nothing since has cleared it. */
.topright {
  display: flex; flex-direction: column; align-items: stretch;
  flex-wrap: nowrap; gap: 8px;
}
.picrow { display: flex; gap: 10px; flex-wrap: wrap; }

/* Both bands under the brand line hug their contents instead of being stretched
   the width of the page. Stretched, the tab pill drew a 1213px rounded box with
   three tabs sitting in the left third of it, which reads as a layout mistake
   rather than as a segmented control. Phones keep the full-width version, where
   the tabs divide the row between them and filling it is the point. */
@media (min-width: 681px) {
  /* The three bands are peers, so they sit on one rhythm. `.topright` groups the
     last two for layout only, and its own 8px gap made the header read as 10
     then 8 down the page. Phones keep the tighter 8, where the tabs and the
     pickers are stacked tight rather than spaced as bands. */
  .topright { align-items: flex-start; gap: 10px; }
  .tabs, .picrow { max-width: 100%; }
}

/* Icon labels: the word is kept for screen readers and on hover. */
.themepick label svg {
  width: 15px; height: 15px; display: block;
  fill: none; stroke: currentColor; stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
}
.themepick label svg .fill { fill: currentColor; stroke: none; }
.themepick label { opacity: .62; cursor: help; }
.themepick:focus-within label, .themepick:hover label { opacity: 1; }
.vh {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ===========================================================================
   The browse element

   The dance and the figure are one choice in two steps, so they are one object:
   a single bordered strip with the dance on the left, a hairline, and the
   figure you are showing filling the rest.
   ======================================================================== */
.browsebar, .seqpanel, .rhythmbar {
  display: flex; align-items: stretch;
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--panel); overflow: hidden;
  padding: 0; gap: 0;
}
/* The slot is a marker for where the dance picker gets moved to, never a box of
   its own. Left as a flex item it took a share of the strip's gap, which put a
   10px indent on two of the three bars and thirty pixels of height on them once
   the strip wrapped on a phone - a difference you cannot name but can see the
   moment you switch tabs. */
.danceslot { display: none; }
.browsebar .dancepick, .seqpanel .dancepick {
  flex: 0 0 auto; display: flex; align-items: center; gap: 8px;
  padding: 10px 14px; border: 0; background: none; border-radius: 0;
}
.browsebar .dancepick select, .seqpanel .dancepick select {
  border: 0; background: none; padding: 3px 2px; font-weight: 700; font-size: 14px;
}
.browsedivider { flex: 0 0 1px; background: var(--line); margin: 8px 0; }
.browsebar .listtoggle, .seqpanel .seqhead {
  flex: 1 1 auto; border: 0; border-radius: 0; background: none; box-shadow: none;
}
.seqpanel { flex-direction: row; align-items: stretch; padding: 0; }
.seqpanel .seqbody, .seqpanel .seqnote { display: none; }
.seqpanel.open { flex-wrap: wrap; }
.seqpanel.open .seqbody { display: block; flex: 1 1 100%; padding: 0 14px 14px; }
.seqpanel.open .seqnote { display: block; flex: 1 1 100%; margin: 0 14px 14px; }

/* On a wide screen the list is always visible, so the browse half is a label
   rather than a control. */
@media (min-width: 721px) {
  .browsebar .listtoggle { pointer-events: none; }
  .browsebar .listtoggle .lt-cta { display: none; }
}

@media (max-width: 720px) {
  .browsebar, .seqpanel { flex-wrap: wrap; }
  .browsebar .dancepick, .seqpanel .dancepick { flex: 1 1 100%; }
  .browsedivider { flex: 1 1 100%; height: 1px; margin: 0; }
}

@media (max-width: 680px) {
  .brand h1 { font-size: 19px; }
  .picrow .themepick { flex: 1 1 0; min-width: 0; }
  .picrow .themepick select { width: 100%; }
}

@media (max-width: 680px) {
  .dancepick select { width: auto !important; flex: 1 1 auto; }
}

@media (max-width: 1000px) and (min-width: 721px) {
  /* The tablet list column is narrower than the desktop one, so the cards give
     up their thumbnail before they give up a readable name. */
  .movecard { gap: 8px; padding: 8px 10px; }
  .movecard .mc-thumb { width: 52px; flex: 0 0 52px; }
  .movecard .mc-name { font-size: 13.5px; }
  .movecard .mc-sum { font-size: 11.5px; }
}

/* The Rhythm Lab's copy of the shared bar. Same object as Learn's and
   Practise's: the dance on the left, a hairline, then what this view has to say
   about it. */
.rhythmbar { margin-bottom: 16px; }
.rhythmbar .nowdancing {
  flex: 1 1 auto; display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 12px 14px; min-width: 0;
}
.rhythmbar .nd-stack { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rhythmbar .nd-eyebrow {
  font-size: 9.5px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  opacity: .55;
}
.rhythmbar .nd-what {
  font-size: 14px; font-weight: 600; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 720px) {
  /* One row, not three: the stack and the way onward stay side by side so this
     bar is the same height as the other two views' on a phone as well. */
  .rhythmbar .nowdancing { flex: 1 1 100%; flex-wrap: nowrap; gap: 10px; }
}

/* ---------------------------------------------------------------------------
   One bar, three views

   Listen, Learn and Practise each carry the same strip, so it has to BE the same
   strip: the same padding, the same two-line stack, the same minimum height.
   They had drifted a few pixels apart - different padding here, an extra border
   there - which is the kind of difference you cannot name but can see the moment
   you switch tabs. Practise's is the one being matched.
   ------------------------------------------------------------------------ */
.listtoggle,
.seqpanel .seqhead,
.rhythmbar .nowdancing {
  min-height: 62px; padding: 12px 14px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.listtoggle .lt-now,
.seqpanel .seqhead .sq-now,
.rhythmbar .nd-stack { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

.listtoggle .lt-eyebrow,
.seqpanel .seqhead .sq-eyebrow,
.rhythmbar .nd-eyebrow {
  font-size: 9.5px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  opacity: .55; line-height: 1.2;
}
.listtoggle .lt-label,
.seqpanel .seqhead .sq-label,
.rhythmbar .nd-what {
  font-size: 14px; font-weight: 600; line-height: 1.35;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* The dance half is the same width in all three, so the hairline falls in the
   same place whichever tab you are on. */
.browsebar .dancepick,
.seqpanel .dancepick,
.rhythmbar .dancepick {
  flex: 0 0 auto; min-width: 168px; padding: 12px 14px; gap: 8px;
}

@media (max-width: 720px) {
  .browsebar .dancepick,
  .seqpanel .dancepick,
  .rhythmbar .dancepick { flex: 1 1 100%; min-width: 0; }
  /* Inside a bordered strip the toggle needs no border of its own - it had one
     from when it stood alone, which drew a box inside a box. */
  .browsebar .listtoggle { border: 0; box-shadow: none; background: none; }
}

/* ======================== tunes to practise to ==========================
   A tempo-ordered reading list. The BPM is set in the leading column and
   given its own weight, because the number is what you are scanning for -
   the list is sorted by it, and which end of the range a track sits at is
   the whole reason it is here. */
.songlist { display: flex; flex-direction: column; gap: 2px; }
.songrow {
  display: flex; align-items: center; gap: 14px;
  padding: 10px 12px; border-radius: 10px;
  border: 1px solid transparent;
}
.songrow:nth-child(odd) { background: var(--panel); }
.songrow:hover { border-color: var(--line); }
.songbpm {
  flex: 0 0 46px; text-align: center; line-height: 1.05;
  display: flex; flex-direction: column; align-items: center;
}
.songbpm b { font-size: 17px; font-variant-numeric: tabular-nums; color: var(--accent); }
.songbpm span { font-size: 9.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--muted); }
.songmeta { flex: 1 1 auto; min-width: 0; }
.songtitle { font-weight: 600; font-size: 14px; }
.songby { font-weight: 400; color: var(--muted); font-size: 12.5px; margin-left: 8px; }
.songnote { color: var(--muted); font-size: 12.5px; margin-top: 2px; }
.songrow > button { flex: 0 0 auto; }

@media (max-width: 680px) {
  /* The note is the first thing to go: on a phone the title, the tempo and a
     way to hear it are what the row is for. */
  .songrow { gap: 10px; padding: 9px 8px; }
  .songnote { display: none; }
  .songby { display: block; margin-left: 0; }
}

/* The spoken count sits with the transport, not with the mixer: it is a way of
   hearing the beat, like the metronome, rather than an instrument in the kit. */
.countvoice { display: inline-flex; align-items: center; gap: 8px; }
.countvoice > span { font-size: 12px; color: var(--muted); }
.countvoice select { padding: 6px 9px; font-size: 13px; }
.countvoice select:disabled { opacity: .5; cursor: not-allowed; }
.songgo { text-decoration: none; display: inline-flex; align-items: center; }
@media (max-width: 680px) {
  .countvoice { margin-top: 8px; }
}

/* The out-of-copyright shelf is a footnote to the list above, not a rival to
   it: same rows, quieter frame, set off by a rule rather than a panel of its
   own so it reads as "and also these" rather than as a second catalogue. */
.freeaudio { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.fahead {
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); font-weight: 650;
}
.fanote { margin: 4px 0 8px; color: var(--muted); font-size: 12.5px; max-width: 62ch; }
.farow:nth-child(odd) { background: none; }
.farow { background: none; }
