/* Keys, PURE BLACK (2026-08-29). True black ground, no filled panels, one
   raised band, structure carried by hairlines. Single committed look; every
   colour explicit, nothing inherits the OS theme.
   Measured on #000000: ink 17.73:1, muted 5.87:1, accent 9.88:1,
   urgent 13.82:1, wrong 9.37:1, white on the accent fill 6.34:1,
   ink on the band #131915 15.06:1, muted on the band 4.99:1.
   Verified by design-2026-08/palette-check.mjs and test/check.mjs. */

/* Display face (10th council: identity used SPARINGLY: brand, song titles,
   big results numbers; controls stay in the system face). Self-hosted OFL
   variable font, no network fonts. */
@font-face {
  font-family: 'Fraunces';
  src: url('fonts/Fraunces.ttf') format('truetype');
  font-weight: 100 900;
  font-display: swap;
}

/* CANON ISOLATION, 2026-08-29. Everything below is in the `app` layer, and
   nothing else on the page is, which is the whole point.

   The canon markup reuses the app's ids so the app's handlers can find its
   controls. That also means the app's own stylesheet reaches INTO the design
   and restyles it. It already did: `#lesson-keys { margin-top: 8px }` pushed
   the lesson keyboard 8px down, and the same 8px then displaced every element
   below it on three screens. The design was correct, the port was correct, and
   the app's CSS quietly moved it anyway.

   A layered rule always loses to an unlayered one, whatever its specificity, so
   the single unlayered rule at the bottom of this file rolls the whole app
   layer back inside a canon subtree. Inline styles are not in a layer, so the
   design's own styles survive untouched, and custom properties are not touched
   by `all` so tokens still resolve. */
@layer app {

:root {
  color-scheme: dark;

  /* PURE BLACK, 2026-08-29. Mark, looking at the first attempt: "theres too
     much of this colour, theres more this then the black". He was right and it
     was measured: the raised tone covered 67.5% of the rendered screen. So the
     ground is now true black (his panel is OLED, those pixels switch off) and
     surfaces stop being fills. Structure comes from --line hairlines, which are
     now load-bearing: every panel rule in this file already carried a border,
     which is why the fills could be removed safely. */
  --bg: #000000;
  --panel: #000000;
  --panel-2: #131915;   /* the ONE raised band, L*8, for chips and the recommendation */
  --ink: #e9ede7;
  --muted: #788c82;
  --line: #253129;

  /* ☠️ --right and --left are the HANDS, not chrome. falls.mjs paints every
     right-hand note with #f0a832 and every left-hand note with the cyan, and
     score.mjs picks the right/left tokens per note. They are deliberately
     NOT swapped to the new green: this is the surface Mark watches while he
     plays, and amber-vs-cyan sits on the blue-yellow axis, which is the safest
     pair there is for red-green colour blindness. Green-vs-cyan would be worse
     for him. Chrome uses --accent instead. Do not merge these two ideas again. */
  --right: #f0a832;
  --left: #5ec8f2;

  /* Chrome accent. Solved, not chosen: every value below was measured against
     the surface it actually sits on, and the four state colours were solved
     JOINTLY because lifting any one of them collapses another. See
     design-2026-08/PALETTE.md and palette-solve.mjs. */
  --accent: #82bf9c;        /* accent text, rules, active markers      9.88:1 on black */
  --accent-fill: #2e6b47;   /* the one filled button    white on it =  6.34:1 */
  --urgent: #efce81;        /* decaying, needs attention              13.82:1 on black */
  --wrong: #d4a19b;         /* wrong note                              9.37:1 on black */
  --good: #82bf9c;          /* banked, done, passed                    9.88:1 on black */
  --score-ink: #e8e4da;
  --score-line: #4a5160;
  --score-passive: #5a6270;
  --score-played: #7d8694;
  --score-finger: #a8b0ba;
  --score-cur-bar: rgba(240, 168, 50, 0.10);
  --score-next-bar: rgba(232, 228, 218, 0.05);
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
html, body { margin: 0; height: 100%; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: 'Segoe UI', system-ui, sans-serif;
  display: flex; flex-direction: column;
}

.topbar {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 16px; border-bottom: 1px solid var(--line);
  background: var(--panel);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
/* tabular numerals wherever numbers sit in rows (stats, HUD, tempo) */
.hud, .song-card .stats, #tempo-val, .met-num, .echo-status { font-variant-numeric: tabular-nums; }
.now-playing { flex: 1; font-weight: 600; }
.midi-status {
  font-size: 13px; padding: 5px 12px; border-radius: 999px;
  background: var(--panel-2); color: var(--muted); border: 1px solid var(--line);
}
.midi-status[data-connected="true"] { color: #14171d; background: var(--good); border-color: var(--good); font-weight: 600; }

.screen { flex: 1; display: flex; flex-direction: column; padding: 18px 22px; overflow: auto; min-height: 0; }
.brand { font-family: 'Fraunces', Georgia, serif; font-weight: 650; font-size: 46px; margin: 8px 0 0; letter-spacing: 0.5px; }
.tagline { color: var(--muted); margin: 4px 0 18px; }
.streak { color: var(--accent); font-weight: 600; margin-bottom: 14px; min-height: 20px; }

.song-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; }
.song-card {
  position: relative;
  background: rgba(255,255,255,0.03);   /* flat, same ruling: no fade on the card ground */
  border: 1px solid var(--line); border-radius: 14px; padding: 16px 18px;
  cursor: pointer; text-align: left; color: var(--ink); font: inherit;
  transition: transform .12s ease, border-color .12s ease;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04); /* lacquer top edge */
}
.song-card:hover { transform: translateY(-2px); border-color: var(--accent); }
.song-card:active { transform: translateY(0) scale(0.985); }
.song-card h3 { font-family: 'Fraunces', Georgia, serif; font-weight: 560; margin: 0 0 2px; font-size: 20px; padding-right: 84px; }
/* sheet-label chip: monochrome monogram on cream, identity by shape and type
   never hue (10th council; scaled to a chip so 19 cards don't go beige) */
.sheet-chip {
  /* engraved dark glass (cinema 08-25): the cream label pulled light off the
     titles; identity stays shape + type, just unlit until it matters */
  position: absolute; top: 12px; right: 12px; width: 44px;
  display: flex; flex-direction: column; align-items: center; gap: 0;
  background: rgba(255, 255, 255, 0.04); color: var(--ink); border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.13);
  padding: 5px 4px 4px;
  pointer-events: none;
}
.sheet-chip b { font-family: 'Fraunces', Georgia, serif; font-weight: 640; font-size: 20px; line-height: 1; }
.sheet-chip span { font-size: 10.5px; font-weight: 600; letter-spacing: 0.3px; color: var(--muted); border-top: 1px solid rgba(255, 255, 255, 0.14); margin-top: 3px; padding-top: 2px; width: 100%; text-align: center; font-variant-numeric: tabular-nums; }
.song-card .composer { color: var(--muted); font-size: 13px; }
.song-card .stats { margin-top: 10px; font-size: 13px; color: var(--muted); display: flex; gap: 14px; }
.song-card .levels { margin-top: 10px; display: flex; gap: 8px; }
.level-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 12px; border-radius: 8px; font-size: 13px; font-weight: 600;
  background: var(--panel); border: 1px solid var(--line); color: var(--ink);
  cursor: pointer; min-height: 34px;
}
.level-btn:hover { border-color: var(--accent); }
.song-card .stats b { color: var(--ink); }
.song-card .learned { color: var(--good); font-weight: 600; }

/* rows in the library column must NEVER shrink: a squeezed row lets its
   fixed-height children bleed over the neighbours (shipped bug, 08-24) */
/* ---- library v2 (council 2026-08-28): one lit action, disclosed sections ---- */
.next-action {
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  width: 100%; max-width: 560px; margin: 0 0 18px; padding: 14px 18px;
  /* was a full-width amber gradient slab with an amber border. That slab IS
     what Mark meant by "theres too much of this colour". It is now the one
     raised band in the app, L*8, held by a hairline, hugging its content. */
  background: var(--panel-2);
  border: 1px solid var(--line); border-radius: 12px;
  width: fit-content;
  color: var(--ink); cursor: pointer; text-align: left; flex: none;
  transition: transform 0.2s ease, border-color 0.2s ease;
}
.next-action:hover { transform: translateY(-1px); border-color: var(--accent); }
.next-action:active { transform: translateY(0) scale(0.99); }
.next-action-label { font-family: 'Fraunces', Georgia, serif; font-size: 20px; font-weight: 600; color: var(--accent); }
.next-action-reason { font-size: 13px; color: var(--muted); }

.path-playable { color: var(--accent); font-weight: 600; font-size: 14px; margin-top: 6px; font-variant-numeric: tabular-nums; }

/* ---- gamification (14th council): value-anchored XP, chosen quests ---- */
.game-row { display: flex; align-items: center; gap: 16px; margin-bottom: 12px; flex: none; flex-wrap: wrap; }
.game-level { display: flex; align-items: center; gap: 8px; font: 700 12px 'Segoe UI', system-ui, sans-serif; letter-spacing: 1px; color: var(--muted); }
.game-level b { font-family: 'Fraunces', Georgia, serif; font-size: 20px; color: var(--ink); }
.xp-bar { display: inline-block; width: 110px; height: 6px; background: var(--panel-2); border: 1px solid var(--line); border-radius: 999px; overflow: hidden; }
.xp-bar i { display: block; height: 100%; background: var(--accent); border-radius: 999px; }
.xp-num { font-variant-numeric: tabular-nums; font-weight: 600; }
.rhythm-chip { color: var(--accent); font-weight: 600; font-size: 13px; font-variant-numeric: tabular-nums; }
.freeze-offer {
  flex: none; margin-bottom: 12px; padding: 10px 14px; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--line); font-size: 14px;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.quest-row, .weekly-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex: none; flex-wrap: wrap; }
.quest-tag { font: 700 11px 'Segoe UI', system-ui, sans-serif; letter-spacing: 1.2px; text-transform: uppercase; color: var(--muted); min-width: 52px; }
.quest {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 999px;
  color: var(--ink); padding: 6px 12px; font-size: 13px; cursor: pointer;
  transition: border-color 0.2s ease;
}
.quest:hover { border-color: var(--accent); }
.quest.on { border-color: var(--accent); background: rgba(130, 191, 156, 0.10); }
.quest.done { border-style: dashed; color: var(--muted); }
.quest.done i { color: var(--good); }
.quest i { font-style: normal; }
.q-xp { color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.weekly-live { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--ink); }
.weekly-live i { font-style: normal; color: var(--accent); }

/* results: assessment leads, arcade is subordinate and labelled */
#results-stats .lead b { font-size: 26px; }
#results-stats .verdict b { font-family: 'Fraunces', Georgia, serif; font-size: 18px; }
#results-stats .arcade { display: block; width: 100%; color: var(--muted); font-size: 12px; letter-spacing: 0.4px; margin-top: 6px; }
.verdict-word { color: var(--muted); }

/* trophies: the evidence cabinet */
.trophy-list { display: flex; flex-direction: column; gap: 8px; flex: none; }
.trophy {
  display: grid; grid-template-columns: 34px minmax(140px, auto) 1fr; gap: 10px;
  align-items: baseline; background: var(--panel); border: 1px solid var(--line);
  border-radius: 10px; padding: 10px 14px;
}
.t-shape { font-size: 20px; }
.t-word { font-weight: 700; }
.t-arc { font-style: normal; font-size: 10px; letter-spacing: 1px; color: var(--muted); border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; margin-left: 6px; }
.t-ev { color: var(--muted); font-size: 12.5px; }
.arcade-badge { border-style: dashed; }
.xp-log { flex: none; }
.xp-row { padding: 5px 2px; border-bottom: 1px solid var(--line); font-size: 13px; }
.xp-row b { color: var(--accent); font-variant-numeric: tabular-nums; }

/* journey strip (goal gradient) */
.journey-strip {
  flex: none; display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 8px 4px; font-size: 12.5px;
}
.j-step { display: inline-flex; align-items: center; gap: 4px; color: var(--muted); white-space: nowrap; }
.j-step i { font-style: normal; }
.j-step.done { color: var(--good); }
.j-step.now { color: var(--accent); font-weight: 700; }
.j-link { width: 14px; height: 1px; background: var(--line); }
.j-done { color: var(--accent); font-weight: 700; }
#j-go { margin-left: auto; padding: 5px 12px; font-size: 12.5px; }

/* first run */
.firstrun {
  position: fixed; inset: 0; z-index: 40; display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 3, 0.88);
}
.firstrun-card {
  max-width: 420px; margin: 20px; padding: 28px 30px; border-radius: 16px;
  background: var(--panel); border: 1px solid var(--line); box-shadow: 0 24px 80px rgba(0, 0, 0, 0.7);
}
.firstrun-card h2 { font-family: 'Fraunces', Georgia, serif; font-size: 34px; margin: 0 0 8px; }
.firstrun-card p { color: var(--muted); }

.lib-sec { flex: none; margin-bottom: 6px; }
.lib-head-row { display: flex; align-items: center; gap: 8px; }
.lib-head {
  display: flex; align-items: center; gap: 8px;
  background: none; border: 0; color: var(--ink); cursor: pointer;
  font: 600 15px 'Segoe UI', system-ui, sans-serif; letter-spacing: 0.4px;
  padding: 10px 2px; text-transform: uppercase;
}
.lib-caret { display: inline-block; transition: transform 0.2s ease; color: var(--muted); }
.lib-sec.open .lib-caret { transform: rotate(90deg); }
.lib-count {
  font-size: 12px; color: var(--muted); background: var(--panel-2);
  border: 1px solid var(--line); border-radius: 999px; padding: 1px 8px;
  font-variant-numeric: tabular-nums;
}
.lib-body { display: none; opacity: 0; transition: opacity 0.2s ease; padding: 2px 0 10px; }
.lib-sec.open .lib-body { display: block; opacity: 1; }
.lib-search { margin-left: auto; display: flex; align-items: center; gap: 6px; }
#explore-search {
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
  color: var(--ink); padding: 6px 10px; font-size: 14px; width: 200px;
}
#explore-search:focus { outline: none; border-color: var(--accent); }

.song-rows { display: flex; flex-direction: column; }
/* ---- cover plates (15th council): beside text, never behind ----
   The ring is load-bearing, not decoration. The border pixels of all 26 real
   sleeves were measured: six have an edge median below L*10 and would have NO
   visible boundary on a black page. Star Wars is 95% of its border below L*10,
   Hotel California 99%, Piano Man 100%, Still D.R.E. 100%. The old ring was
   rgba(255,255,255,0.10), which composites to roughly L*10 on black and would
   have left exactly those six invisible. --line is L*19. It goes on all 26, not
   only the six, so the sleeves read as one consistent family. */
.cover-plate {
  border-radius: 10px; border: 1px solid var(--line);
  background: var(--bg); flex: none;
  transition: filter 0.32s ease, transform 0.32s ease;
}
button:hover > .cover-plate, .song-card:hover .cover-plate, .song-row:hover .cover-plate {
  filter: brightness(1.3) saturate(1.15); transform: translateY(-1px);
}
@media (prefers-reduced-motion: reduce) {
  .cover-plate { transition: opacity 0.12s ease; }
  button:hover > .cover-plate, .song-card:hover .cover-plate, .song-row:hover .cover-plate { filter: none; transform: none; }
}
.cover-64 { position: absolute; top: 12px; right: 12px; width: 64px; height: 64px; }
.cover-40 { width: 40px; height: 40px; border-radius: 8px; align-self: center; }
.cover-96 { width: 96px; height: 96px; border-radius: 12px; }
.cover-160 {
  position: absolute; top: 118px; right: 26px; width: 160px; height: 160px;
  border-radius: 14px; z-index: 5; opacity: 1; transition: opacity 0.24s ease;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6);
}
.cover-160.fade { opacity: 0; }
#screen-play { position: relative; }
.next-action { flex-direction: row; align-items: center; gap: 16px; }
.next-action-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }

.song-row {
  display: grid; grid-template-columns: auto minmax(140px, 1.3fr) 1fr auto auto auto;
  gap: 12px; align-items: baseline;
  background: none; border: 0; border-bottom: 1px solid var(--line);
  color: var(--ink); cursor: pointer; text-align: left;
  padding: 9px 4px; font-size: 14px;
}
.song-row:hover { background: rgba(255, 255, 255, 0.04); }
.row-title { font-weight: 600; }
.row-meta { color: var(--muted); font-size: 13px; }
.row-tiers { display: flex; gap: 4px; }
.row-tier {
  font-style: normal; font-size: 11px; font-weight: 700; color: var(--muted);
  border: 1px solid var(--line); border-radius: 5px; padding: 1px 6px; cursor: pointer;
}
.row-tier:hover { color: var(--ink); border-color: var(--accent); }
.row-stars { color: var(--accent); font-size: 12px; }
.row-diff { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.sort-toggle { font-size: 12px; font-variant-numeric: tabular-nums; padding: 4px 10px; border: 1px solid var(--line); border-radius: 8px; }
.sort-toggle:hover { border-color: var(--accent); color: var(--ink); }

.rail {
  position: sticky; bottom: 0; margin-top: auto; flex: none;
  display: flex; gap: 8px; padding: 10px 0 2px;
  background: linear-gradient(180deg, transparent, var(--bg) 35%);
}
.rail-btn {
  flex: 1; max-width: 180px; padding: 10px 0; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--line); color: var(--muted);
  font: 600 13px 'Segoe UI', system-ui, sans-serif; letter-spacing: 1.2px;
  text-transform: uppercase; cursor: pointer;
}
.rail-btn.on { color: var(--ink); border-color: var(--accent); }
.rail-sheet {
  flex: none; margin-top: auto;
  display: flex; flex-wrap: wrap; gap: 10px; padding: 12px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.6);
}
.rail-sheet:not([hidden]) ~ .rail { margin-top: 0; }
.session-label { color: var(--muted); font-size: 14px; font-weight: 600; }
.practice-chart {
  display: flex; align-items: flex-end; gap: 4px; margin: 2px 0 16px;
  height: 44px; flex: none; overflow: hidden;
}
.practice-chart .hint { margin-right: 10px; align-self: center; white-space: nowrap; }
.pbar {
  width: 12px; height: 36px; display: inline-flex; align-items: flex-end;
  background: transparent; border: 1px solid var(--line); border-radius: 3px; flex: none;
}
.pbar i { display: block; width: 100%; background: var(--accent); border-radius: 2px; }
.met-row { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; margin: 10px 0 20px; }
.theory-body { font-size: 16px; line-height: 1.55; color: var(--ink); max-width: 720px; }
.lesson-list { display: flex; flex-direction: column; gap: 8px; max-width: 560px; }
/* numbered curriculum spine (10th council): sequential shape+word states */
.lesson-list { position: relative; padding-left: 6px; }
.lesson-card {
  display: flex; align-items: center; gap: 12px; text-align: left;
  background: var(--panel-2); color: var(--ink); border: 1px solid var(--line);
  border-radius: 10px; padding: 13px 16px; font: inherit; font-weight: 600;
  cursor: pointer; min-height: 48px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
.lesson-card:hover:not(:disabled) { border-color: var(--accent); }
.lesson-card:active:not(:disabled) { transform: scale(0.99); }
.lesson-card.done { color: var(--muted); }
/* locked rows stay READABLE: opacity dimming measured 2.61:1 (below AA), so
   state is carried by the dashed edge + the ○ shape + the word "Locked",
   never by near-invisibility (contrast law, 2026-08-25) */
.lesson-card.locked {
  cursor: default; background: var(--bg); border-style: dashed;
  color: var(--muted); box-shadow: none;
  opacity: 1; /* beats button:disabled's 0.35, which re-dimmed it to 2.6:1 */
}
.lesson-card.locked .spine-num, .lesson-card.locked .spine-title, .lesson-card.locked .spine-state { color: var(--muted); }
.spine-num {
  font-family: 'Fraunces', Georgia, serif; font-weight: 620; font-size: 17px;
  color: var(--muted); width: 30px; flex: none; text-align: right;
  font-variant-numeric: tabular-nums;
}
.spine-title { flex: 1; }
.spine-state {
  flex: none; display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.4px;
  color: var(--muted); border: 1px solid var(--line); border-radius: 999px;
  padding: 3px 10px;
}
.spine-state i { font-style: normal; }
.spine-state.done { color: var(--good); border-color: var(--good); }
.spine-state.ready { color: #14171d; background: var(--accent); border-color: var(--accent); }
.spine-star { color: var(--accent); flex: none; }
.spine-badge { flex: none; }
.lesson-banner {
  flex: none; font-weight: 700; font-size: 14.5px; color: #14171d;
  background: var(--accent); border-radius: 10px; padding: 10px 14px;
  margin: 4px 0 10px; max-width: 720px;
}
.lesson-steps { max-width: 720px; margin: 6px 0; padding-left: 24px; flex: none; }
.lesson-steps li { font-size: 15.5px; line-height: 1.55; margin: 7px 0; }
.lesson-video { flex: none; }
.lesson-video a { color: var(--accent); font-weight: 600; }
/* id selector on purpose: .falls (flex:1, min-height:0) would collapse this
   canvas to 0px in the lesson flex column (the shipped shrink-bleed class) */
#lesson-keys { flex: none; height: 140px; margin-top: 8px; }
.lesson-stave {
  background: #f5f1e6; border-radius: 12px; padding: 6px 0; margin: 14px 0;
  width: fit-content; min-width: 320px; overflow: hidden;
  /* flex none or the screen's flex column crushes this to a sliver: its
     overflow:hidden zeroes the automatic minimum size (shipped bug class) */
  flex: none;
  --score-ink: #23282f; --score-line: #9a948a; --score-finger: #6b6558;
  --score-cur-bar: transparent; --score-next-bar: transparent;
  --score-passive: #23282f; --score-played: #23282f;
}
.rhythm-blocks {
  position: relative; height: 64px; margin: 14px 0;
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
}
.rblock {
  position: absolute; top: 12px; width: 26px; height: 40px; border-radius: 6px;
  background: var(--accent); box-shadow: 0 0 14px rgba(130, 191, 156, 0.45);
  margin-left: 12px;
}
.rblock.hit { background: var(--good); box-shadow: 0 0 14px rgba(130, 191, 156, 0.5); }
.rblock.miss { background: transparent; border: 2px dashed var(--wrong); box-shadow: none; }
.rtick { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--line); margin-left: 12px; }
.rhythm-blocks { height: 88px; }
.count-row b {
  position: absolute; bottom: 4px; margin-left: 12px; width: 26px; text-align: center;
  font-size: 13px; font-weight: 800; color: var(--ink);
}
.count-row b.rest { color: var(--muted); font-weight: 400; font-size: 11px; }
button:disabled { opacity: 0.35; cursor: default; }
.met-beat { font-size: 42px; letter-spacing: 8px; color: var(--accent); min-height: 60px; }
.met-num {
  width: 76px; background: var(--panel); color: var(--ink); border: 1px solid var(--line);
  border-radius: 8px; padding: 9px 10px; font: inherit; font-weight: 600; min-height: 42px;
}
.echo-status { display: flex; gap: 22px; font-size: 15px; margin: 6px 0; }
.echo-status span:not(.hint) { font-weight: 600; }
.echo-msg { font-size: 17px; min-height: 26px; margin: 10px 0; color: var(--accent); font-weight: 600; }
.echo-actions { display: flex; gap: 10px; margin-bottom: 14px; }
.delta-up { color: var(--good); font-weight: 600; }
.delta-down { color: var(--muted); }

.tools { margin-top: 22px; display: flex; gap: 10px; }
.tool {
  background: var(--panel-2); color: var(--ink); border: 1px solid var(--line);
  border-radius: 10px; padding: 12px 18px; font: inherit; font-weight: 600; cursor: pointer;
  min-height: 44px;
}
.tool:hover { border-color: var(--accent); }
.tool:active:not(:disabled), .level-btn:active, .ghost:active, .seg-btn:active { transform: scale(0.97); }
.tool.accent { background: var(--accent); color: #14171d; border-color: var(--accent); }
.ghost {
  background: transparent; color: var(--muted); border: 1px solid var(--line);
  border-radius: 10px; padding: 8px 14px; font: inherit; cursor: pointer; min-height: 40px;
}
.ghost:hover { color: var(--ink); border-color: var(--muted); }
.ghost.training { color: #14171d; background: var(--accent); border-color: var(--accent); font-weight: 700; }
.hint { color: var(--muted); font-size: 13.5px; }

.play-controls {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  padding: 8px 0 12px;
}
.seg { display: flex; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.seg-btn {
  background: var(--panel); color: var(--muted); border: 0; padding: 9px 15px;
  font: inherit; font-weight: 600; cursor: pointer; min-height: 42px;
}
.seg-btn[data-on="true"] { background: var(--accent); color: #14171d; }
.ctl { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 14px; }
.ctl input[type=range] { accent-color: var(--accent); }
.ctl.chk input { width: 18px; height: 18px; accent-color: var(--accent); }
.ctl-select {
  background: var(--panel); color: var(--ink); border: 1px solid var(--line);
  border-radius: 8px; padding: 9px 10px; font: inherit; min-height: 42px;
}
#tempo-val { min-width: 44px; color: var(--ink); font-weight: 600; }

/* the stage bezel (10th council): dark lacquer + hairline cream inlay, all
   box-shadow so it costs ZERO layout pixels; the canvas stays sovereign, 
   no DOM ambience, spectacle lives at note contact only */
.falls {
  flex: 1; width: 100%; min-height: 0; border-radius: 10px;
  box-shadow:
    inset 0 0 0 1px rgba(245, 241, 230, 0.14),
    0 0 0 3px var(--panel-2),   /* was #1a1610, a warm brown that now fought the green family */
    0 0 0 4px rgba(245, 241, 230, 0.10),
    0 10px 30px rgba(0, 0, 0, 0.55);
}
/* the engraved control rail */
.play-controls {
  background: linear-gradient(180deg, var(--panel), var(--panel-2));
  border: 1px solid var(--line); border-radius: 10px;
  padding: 8px 12px; margin-bottom: 10px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
/* level rail + fixed slot ledger (shape + word, never hue alone) */
.lvl-rail { display: inline-flex; align-items: baseline; gap: 10px; }
.lvl-rail b { font-variant-numeric: tabular-nums; letter-spacing: 1px; font-size: 13px; color: var(--accent); }
.lvl-rail em { font-style: normal; font-weight: 700; color: var(--ink); }
.lvl-mode { color: var(--muted); font-size: 12.5px; border: 1px solid var(--line); border-radius: 999px; padding: 2px 9px; }
.slot-row { display: inline-flex; align-items: center; gap: 7px; margin-right: 12px; }
.slot { display: inline-block; width: 13px; height: 13px; border-radius: 50%; border: 2px solid var(--line); background: transparent; }
.slot.now { border-color: var(--ink); }
.slot.clean { background: var(--accent); border-color: var(--accent); }
.slot.recov { border-radius: 3px; transform: rotate(45deg); width: 11px; height: 11px; border-color: var(--accent); background: var(--panel-2); }
.slot-need { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--ink); font-size: 13px; }
.freeplay { max-height: 40vh; }
.stars { color: var(--accent); font-size: 0.8em; letter-spacing: 2px; }
.stars.big { font-size: 1em; }

.combo-flash {
  position: absolute; left: 50%; top: 26%; transform: translateX(-50%);
  font-size: 34px; font-weight: 800; letter-spacing: 3px;
  color: var(--accent); text-shadow: 0 0 24px rgba(130, 191, 156, 0.8);
  opacity: 0; pointer-events: none;
}
.combo-flash.go { animation: combo-pop 1.4s ease-out forwards; }
@keyframes combo-pop {
  0% { opacity: 0; transform: translateX(-50%) scale(0.6); }
  15% { opacity: 1; transform: translateX(-50%) scale(1.15); }
  30% { transform: translateX(-50%) scale(1); }
  75% { opacity: 1; }
  100% { opacity: 0; transform: translateX(-50%) scale(1.04); }
}
#screen-play { position: relative; }

.hud { display: flex; gap: 18px; padding: 8px 2px 2px; color: var(--muted); font-size: 14px; min-height: 28px; align-items: center; }
.pace { display: inline-flex; align-items: center; gap: 8px; margin-left: auto; }
.pace-meter {
  position: relative; width: 110px; height: 12px; border-radius: 6px;
  background: var(--panel-2); border: 1px solid var(--line); overflow: hidden; display: inline-block;
}
.pace-meter i { display: block; height: 100%; background: var(--accent); border-radius: 6px; }
.pace-good .pace-meter i { background: var(--good); }
.pace-notch { position: absolute; left: 50%; top: -2px; bottom: -2px; width: 2px; background: var(--ink); opacity: 0.7; }
.pace-label { font-weight: 700; color: var(--ink); font-size: 13px; min-width: 110px; }
.pace-good .pace-label { color: var(--good); }
.hud b { color: var(--ink); }
.hud .h-wrong b { color: var(--wrong); }

.freeplay-log { padding: 12px 4px; font-size: 22px; min-height: 40px; letter-spacing: 2px; }
.freeplay-log .vel { color: var(--muted); font-size: 13px; }

.cal-canvas { width: 100%; height: 300px; border-radius: 10px; }
.cal-status { padding: 12px 2px; font-size: 16px; }
.cal-status b { color: var(--accent); }

.results {
  position: fixed; inset: 0; background: rgba(10, 12, 16, 0.7);
  display: flex; align-items: center; justify-content: center;
}
.results-card {
  background: var(--panel); border: 1px solid var(--line); border-radius: 16px;
  padding: 26px 30px; width: min(440px, 90vw);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 18px 50px rgba(0, 0, 0, 0.5);
  animation: card-in 0.28s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
@keyframes card-in {
  from { opacity: 0; transform: scale(0.93) translateY(8px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}
.results-stats { display: flex; gap: 20px; margin: 12px 0 6px; font-size: 15px; }
.results-stats b { font-family: 'Fraunces', Georgia, serif; font-weight: 620; font-size: 28px; display: block; font-variant-numeric: tabular-nums; }
.results-actions { display: flex; gap: 10px; margin-top: 16px; flex-wrap: wrap; }

/* performance run */
.perf-banner {
  flex: none; text-align: center; font-weight: 800; letter-spacing: 2px;
  color: #14171d; background: var(--accent); border-radius: 8px;
  padding: 6px 10px; margin-bottom: 6px;
}

/* improv playground */
.improv-chord { font-size: 26px; font-weight: 800; color: var(--ink); min-width: 220px; }

/* 12-key ladder grid */
.keys12-grid-wrap { max-width: 900px; }
.keys12-row-title { margin: 14px 0 8px; color: var(--muted); font-size: 15px; }
.keys12-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 8px; }
.key-cell {
  display: flex; flex-direction: column; gap: 4px; align-items: center;
  background: var(--panel-2); color: var(--ink); border: 1px solid var(--line);
  border-radius: 10px; padding: 12px 8px; font: inherit; font-weight: 800; font-size: 18px;
  cursor: pointer; min-height: 60px;
}
.key-cell:hover { border-color: var(--accent); }
.key-cell.passed { border-color: var(--good); }
.key-cell .key-state { font-size: 12px; font-weight: 600; color: var(--muted); }
.key-cell.passed .key-state { color: var(--good); }
.tools { flex-wrap: wrap; }

/* memory ladder: the score surface dims as cues are removed */
.echo-modes { margin-bottom: 10px; width: fit-content; flex: none; }

/* takes shelf */
.takes-list { display: flex; flex-direction: column; gap: 8px; max-width: 760px; margin-bottom: 14px; flex: none; }
.take-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 14px;
}
.take-row .take-name { flex: 1; font-size: 14px; color: var(--muted); min-width: 220px; }
.take-row .take-name b { color: var(--ink); }

/* filmed self-review card (pull, never nag) */
.form-card {
  background: var(--panel);   /* flat, 2026-09-09: Mark, "i dont like the colour fade we have going on in the background"; the hairline carries the edge */
  border: 1px solid var(--accent); border-radius: 14px;
  padding: 16px 18px; margin-bottom: 16px; max-width: 720px; flex: none;
}
.form-card h3 { margin: 0 0 6px; }
.form-checks { display: flex; flex-direction: column; gap: 6px; margin: 10px 0; }
.form-check { display: flex; align-items: center; justify-content: space-between; gap: 14px; font-size: 14.5px; font-weight: 600; }
.form-check .ctl-select { min-height: 34px; padding: 4px 8px; font-size: 13px; }
.form-teacher { font-weight: 600; color: var(--ink); }

/* touch diagnostic: the ask is huge and unmissable */
.touch-ask { display: flex; align-items: baseline; gap: 20px; margin: 18px 0 6px; }
.touch-dyn { font-size: 40px; font-weight: 800; letter-spacing: 2px; color: var(--accent); }
.touch-key { font-size: 56px; font-weight: 800; color: var(--ink); }

/* results analysis: pedal, articulation, voicing sentences */
.results-analysis { list-style: none; margin: 10px 0 0; padding: 0; font-size: 14px; color: var(--ink); }
.results-analysis li { margin: 6px 0; line-height: 1.45; }

/* pedal state: shape + words carry it, fill is garnish (colour-blind law) */
.pedal-ind { font-weight: 700; font-size: 13px; color: var(--ink); border: 1px solid var(--line); border-radius: 8px; padding: 2px 10px; }
.pedal-ind.down { background: var(--accent); color: #14171d; border-color: var(--accent); }

/* same shrink-bleed class fix for every fixed-height row in a flex column */
.tools, .play-controls, .hud, .echo-status, .echo-actions, .met-row, .rhythm-blocks, .touch-ask { flex: none; }

@media (max-width: 700px) {
  .screen { padding: 12px; }
  .brand { font-size: 32px; }
  .play-controls { gap: 8px; }
}

/* ---- Teacher Loop v1 (11th council 2026-08-25) ---- */
.path-h { font-family: 'Fraunces', Georgia, serif; font-weight: 600; font-size: 30px; margin: 6px 0 2px; }
.path-sub { font-family: 'Fraunces', Georgia, serif; font-weight: 600; font-size: 18px; margin: 20px 0 8px; color: var(--ink); }

/* the library teaser: one line that always says what is next */
.path-teaser {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap; flex: none;
  background: var(--panel);   /* flat, 2026-09-09: Mark, "i dont like the colour fade we have going on in the background"; the hairline carries the edge */
  border: 1px solid var(--accent); border-radius: 14px; padding: 14px 16px; margin-bottom: 16px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.teaser-tag {
  font-size: 11px; font-weight: 800; letter-spacing: 1.2px; text-transform: uppercase;
  color: #14171d; background: var(--accent); border-radius: 999px; padding: 3px 10px; flex: none;
}
.teaser-reason { flex: 1; font-weight: 600; min-width: 200px; }

/* the prescription card: reason on top, evidence underneath, never bare */
.path-next {
  flex: none; background: var(--panel);   /* flat, 2026-09-09: Mark, "i dont like the colour fade we have going on in the background"; the hairline carries the edge */
  border: 1px solid var(--line); border-radius: 14px; padding: 16px 18px; margin: 10px 0 6px;
  max-width: 760px; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.path-next-head {
  font-size: 11px; font-weight: 800; letter-spacing: 1.4px; text-transform: uppercase; color: var(--accent);
}
.path-reason { font-size: 19px; font-weight: 600; margin: 6px 0 4px; line-height: 1.4; }
.path-evidence { color: var(--muted); font-size: 13.5px; margin-bottom: 12px; font-variant-numeric: tabular-nums; }

/* skill map: stage is shape + word, never hue alone (colour-blind law) */
.path-skills, .path-lessons { max-width: 760px; flex: none; }
.skill-row {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  border-bottom: 1px solid var(--line); padding: 9px 2px;
}
.skill-name { font-weight: 600; min-width: 200px; flex: none; }
.skill-rule { color: var(--muted); font-size: 12.5px; flex: 1; min-width: 180px; }
.stage-chip {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  font-size: 12px; font-weight: 700; border: 1px solid var(--line); border-radius: 999px;
  padding: 3px 10px; color: var(--muted);
}
.stage-chip i { font-style: normal; }
.stage-chip.s-guided { color: var(--ink); border-color: var(--muted); }
.stage-chip.s-independent { color: #14171d; background: var(--accent); border-color: var(--accent); }
.stage-chip.s-retained { color: #14171d; background: var(--good); border-color: var(--good); }
.path-lessons .lesson-card { width: 100%; margin-bottom: 8px; }

/* task screen */
.task-teach { max-width: 760px; flex: none; }
.task-stage { flex: none; max-width: 760px; margin: 8px 0; }
.task-badge {
  display: inline-block; font-size: 11.5px; font-weight: 800; letter-spacing: 1.1px;
  color: var(--ink); border: 1px dashed var(--line); border-radius: 999px; padding: 4px 12px; margin-bottom: 10px;
}
.task-prompt { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; margin: 4px 0 10px; }
.big-sym { font-family: 'Fraunces', Georgia, serif; font-weight: 640; font-size: 54px; line-height: 1; color: var(--accent); }
.sym-sub { color: var(--muted); font-size: 14.5px; }
#task-keys { flex: none; height: 150px; margin-top: 8px; width: 100%; }

/* lead sheet: chord symbols above bars, the way working musicians read */
.lead-sheet {
  display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0 14px;
  background: #f5f1e6; border-radius: 10px; padding: 12px 14px; width: fit-content; max-width: 100%;
}
.ls-bar {
  min-width: 72px; border-left: 2px solid #23282f; padding: 4px 10px 6px;
  display: flex; flex-direction: column; gap: 4px;
}
.ls-bar b { font-family: 'Fraunces', Georgia, serif; font-weight: 640; font-size: 22px; color: #23282f; }
.ls-bar i { display: block; height: 4px; border-radius: 2px; background: #c9c3b4; }
.ls-bar.now { background: rgba(200, 120, 0, 0.16); border-radius: 4px; }
.ls-bar.now b { text-decoration: underline; }
.ls-bar.hit i { background: #8a5a00; }
.ls-bar.part i { background: transparent; border: 1px dashed #8a5a00; height: 4px; }

/* global song search (2026-08-28): one box, every shelf */
.lib-search-global {
  margin-left: auto; background: var(--panel-2); border: 1px solid var(--line);
  border-radius: 999px; color: var(--ink); padding: 7px 16px; font-size: 14px;
  width: 230px; max-width: 45vw;
}
.lib-search-global:focus { outline: none; border-color: var(--accent); }

}   /* end @layer app */



/* Unlayered, and therefore stronger than every rule above regardless of
   specificity. Inside a canon subtree the app's stylesheet stands down and the
   design's own inline styles are the only author styles that apply.

   `revert`, NOT `revert-layer`. Unlayered rules ARE the last layer, so
   revert-layer rolls back INTO the app layer and changes nothing - it read as a
   fix and did nothing at all, which is the worst kind. `revert` drops to the
   user-agent origin, and the cascade compares inline styles BEFORE layers, so
   the design's own inline styles still win and only the properties it never set
   fall back to the browser default. That is precisely the app's `margin-top:
   8px` on a canvas the design gave no margin. */
/* Keyboard focus. `all: revert` also reverted the app's focus treatment, and the
   artboards never drew one, so inside the canon a keyboard user had only the
   browser default ring over a black ground. --accent is a custom property, and
   custom properties are not touched by `all`, so the design's own accent still
   resolves in here. */
.canon-root :focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: inherit;
}

/* ☠️ THE SCORE SUBTREE IS EXEMPT, and it has to be an exemption rather than a
   patch. `all: revert` beats SVG PRESENTATION ATTRIBUTES, which are the lowest
   priority author declarations there are, and score.mjs draws with them. That
   cost three separate rounds of this bug: first stroke and fill (the staves and
   stems painted with no colour), then `color` behind currentColor (the heads
   painted white on a cream page), and then `rx` and `ry`, which are CSS
   properties in SVG2, so every note head collapsed to a 0x0 box while still
   reporting the correct fill. Converting attributes one at a time was losing to
   a class of bug; the subtree the app DRAWS into is simply not canon markup and
   must not be reset. */
/* #cp-again joined the exemption 2026-08-31, the FOURTH time this bug was paid
   for. The immersed "Play again" pill is app-drawn, and its refresh-arrow icon
   is an inline SVG stroked with presentation attributes. The pill's own inline
   cssText survived (inline styles outrank any stylesheet), so it measured a
   correct 114x44 with a correct 16x16 icon inside it and passed every check,
   while the icon painted with no stroke: black on a black pill. The tell is
   always the same, the box is right and the ink is missing. App-draw anything
   new in here and exempt it in the same breath. */
/* #lesson-stave joined 2026-09-06, the FIFTH time. Mark and his housemate sat
   at the lesson drill reading an EMPTY stave ("it felt like notes were meant to
   show up here and weren't"): the lesson's prompt note is the same ScoreView
   ellipse, its rx/ry reverted to 0, a 0x0 head with the right fill, and the
   staff lines still painted because lines have no rx. Same tell as ever: the
   box is right and the ink is missing. */
/* .lib-collections joined 2026-09-13, and it joined in the SAME EDIT that drew
   it, which is the whole point of the rule above. The Explore collection chips
   are app-drawn buttons inside the canon column: every property they need is
   written inline (the box and the ink together, so they cannot come apart), and
   the exemption is what lets the hover and focus rules below reach them at all,
   since no inline style can express a pseudo-class. */
.canon-root,
.canon-root *:not([data-reflow], #score-wrap, #score-wrap *, #cp-again, #cp-again *, #lesson-stave, #lesson-stave *, .practice-prescription, .practice-prescription *, .practice-adjust, .practice-adjust *, .session-guide, .session-guide *, .lib-collections, .lib-collections *) {
  all: revert;
  /* The one thing that must come BACK. The canon was authored in a page with
     `* { box-sizing: border-box }` and every width in it assumes that; reverting
     to the browser's content-box turned 13 passing screens into 13 failures in
     one edit. Measured from the design itself and asserted on every rebuild by
     tools/build-canon-templates.mjs, so it cannot drift silently. */
  box-sizing: border-box;
}

/* INTERIM, 2026-08-29. Every artboard in the canon is a fixed 756px frame, and
   Mark's window is 1418 x 738, so the app sat hard against the left edge with
   half the screen black. This does NOT redesign anything: it only centres the
   frame the design already specifies, so it reads as a deliberate column rather
   than as something that failed to load.

   The real fix is a desktop composition, which Claude Design is drawing. DELETE
   this block the moment that artboard lands: a centred 756px column is still
   half a laptop screen of nothing. */
.canon-root { display: flex; justify-content: center; }

/* THE SCORE PAGE LIVES OUT HERE ON PURPOSE. It is an APP SURFACE the canon
   HOSTS, exactly like the falls canvas; the artboard only ever drew a 56px
   picture of one. Left inside @layer app it was unreachable: the canon's
   unlayered `all: revert` below beats every layered rule REGARDLESS of
   specificity, so the printed page, the horizontal scroll and the ink
   variables all evaporated inside a canon subtree, the notation painted with
   an undefined colour on black, and Fur Elise rendered as an empty box. Adding
   specificity did nothing, because layers are compared before specificity.
   It sits at the END of the file, AFTER the canon reset: both are unlayered
   and equally specific, so the only thing that separates them is order. */
.score-wrap {
  flex: 1; overflow-x: auto; overflow-y: hidden; background: #f5f1e6;
  border-radius: 12px; padding: 14px 0;
  /* THE PAGE'S OWN INK. Note heads, accidentals and flags paint with
     `currentColor`, and until a run starts nothing sets a colour on them, so
     they inherited the app's near-white body ink and were invisible on the
     cream page: a score with staves, stems and barlines and no notes. The
     per-note hand colours in ScoreView.update still override this while
     playing. */
  color: #23282f;
  /* score mode is printed-page look: dark ink on cream, ratio 13.8:1 */
  --score-ink: #23282f;
  /* #9a948a measured 2.67:1 on this cream and stave lines are MEANINGFUL
     graphics (they carry pitch), so they owe the 3:1 floor. #837c69 is the
     same hue at 3.68:1: legible, still clearly subordinate to the notes at
     13.14:1. Caught by tools/score-render-check.mjs, not by eye. */
  --score-line: #837c69;
  --score-passive: #b3ada1;
  --score-played: #8d8779;
  --score-finger: #6b6558;
  --score-cur-bar: rgba(155, 97, 8, 0.13);
  --score-next-bar: rgba(35, 40, 47, 0.05);
  /* Score mode is a printed page, cream not black, so the tokens invert here
     and scoping does the work. --right was #b8730a, which measured 3.39:1 on
     this cream and FAILED AA: a pre-existing bug found during the port and
     fixed, not introduced by it. #9b6108 is the same hue at 4.53:1. */
  --right: #9b6108;
  --left: #0a6fa8;
  --accent: #2e6b47;   /* 5.62:1 on the cream page */
}
.score-wrap.dimmed { opacity: 0.5; }
/* THE LESSON STAVE IS NOT THE PRINTED PAGE. The canon draws #lesson-stave as a
   black box (inline background:#000, which no class rule can beat), and since
   2026-09-12 ScoreView adds .score-wrap to whatever it draws in, which handed
   the lesson the cream page's DARK ink: dark clefs and note heads on black,
   which Mark could not read (2026-09-15). The lesson keeps the app's own dark
   look it had up to keys-v131: near-white ink on black. The staff lines are
   #6b7280 rather than the root's #4a5160 because they carry pitch and owe the
   3:1 floor on black (#4a5160 measures 1.9:1, #6b7280 measures 4.4:1). */
#lesson-stave.score-wrap {
  background: #000; color: #e8e4da;
  --score-ink: #e8e4da; --score-line: #6b7280;
  --score-passive: #7d8694; --score-played: #a8b0ba; --score-finger: #a8b0ba;
  --score-cur-bar: rgba(240, 168, 50, 0.10); --score-next-bar: rgba(232, 228, 218, 0.05);
  --right: #f0a832; --left: #5ec8f2; --accent: #82bf9c;
}

/* ── PRESS FEEL ───────────────────────────────────────────────────────────────
   Mark, 2026-08-31: "can we make the feeling of pressing the buttons better?"
   Then, one build later: "why does the whole screen shake when we press a
   button now and theres lag haha i didnt want that, i just wanted the button to
   feel nice to press."

   ☠️ BOTH FAULTS WERE SCOPE, AND THEY ARE THE SAME MISTAKE TWICE.
   1. THE SHAKE: I had `.canon-root .dv-card:active` in the list. `.dv-card` is
      not a card, it is the WHOLE SCREEN container - 1418x738 - so pressing
      anything inside it scaled the entire app. A selector named like a small
      component was the biggest element on the page.
   2. THE LAG: a blanket `transition` on every button/card/tool, plus
      `filter: brightness()`, which forces a repaint of the whole painted
      subtree. On a 300px card that is cheap; applied broadly it is not.

   So this now touches ONLY things a finger actually lands on, moves them with
   `transform` alone (compositor-only, no repaint), and names no container.
   No hue carries the press: Mark is colour-blind and that is a law.

   ☠️ !important is required, not lazy. The canon reset is
   `.canon-root *:not(#score-wrap, ...)` and :not() takes the specificity of its
   heaviest argument - IDs - so it scores (1,1,0) and beats any class selector.
   Proven with CDP.forcePseudoState: the rule matched, was in the CSSOM, had no
   inline shadow, and still computed to `none`. */
.canon-root button:active,
.canon-root [role="button"]:active,
button:active:not(:disabled),
[role="button"]:active,
.tool:active:not(:disabled), .level-btn:active, .ghost:active, .seg-btn:active {
  transform: scale(0.97) !important;
  transition: transform 50ms ease-out !important;
}
/* ☠️ THE LINGER WAS NEVER JANK. Mark: "can we get rid of the lag when we press a
   button?" Instrumented (tools/latency-probe.mjs): click -> painted frame is
   15ms, the handler is 27ms, and there are ZERO long tasks. Nothing is blocked.
   What he was feeling is that the canon gives every control an INLINE
   `transition: border-color .12s, background .12s`, so the colour keeps moving
   for an eighth of a second after the finger has gone. The control answers
   instantly and then goes on settling, which reads as mush rather than as speed.
   Cut to 60ms: still a fade rather than a jump, but done before the eye asks.
   Inline styles beat stylesheets, so !important is the only way to reach it. */
.canon-root button, .canon-root [role="button"],
.tool, .level-btn, .ghost, .seg-btn {
  transition-duration: 60ms !important;
}
/* A song card is a real target but a big one: 3% of 300px is 9px of travel and
   reads as the layout lurching, so it gets a tenth of the movement. */
.song-card:active, .lesson-card:active:not(:disabled), .next-action:active {
  transform: scale(0.994) !important;
  transition: transform 50ms ease-out !important;
}
/* ☠️ NO BASE TRANSITION, AND THE MEASUREMENT IS WHY. Mark: "can we get rid of
   the lag when we press a button?" Instrumenting it (tools/latency-probe.mjs)
   found no jank at all - the click handler runs in 24ms and there are zero long
   tasks - but 142 elements on one screen carried a transition, and every one is
   a thing the compositor must consider on each frame.
   Worse, the rule was doing NOTHING for its main target: the canon's buttons
   carry an INLINE `transition: border-color .12s, background .12s`, and an
   inline style beats a stylesheet, so `transform` was never in their transition
   list. It cost frames everywhere and bought nothing where it was aimed.
   The press still eases in over 50ms via :active. The RELEASE is now instant,
   which is not a compromise: a control that snaps back reads as more responsive
   than one that eases back, because the finger has already left it. */
@media (prefers-reduced-motion: reduce) {
  .canon-root button:active, .canon-root [role="button"]:active,
  button:active:not(:disabled), [role="button"]:active,
  .song-card:active, .lesson-card:active:not(:disabled), .next-action:active {
    transform: none !important;
  }
}

/* Recovery sits outside the canon board and its reset. */
#progress-safety { padding: 8px 16px; max-width: 72rem; margin: auto; }
#progress-safety summary { cursor: pointer; padding: 8px 0; }
#progress-safety button, #progress-safety input { min-height: 44px; margin: 4px; }
#save-status:not([hidden]) { border: 2px solid currentColor; padding: 12px; font-weight: 700; }

/* The prescription is app-ordered, with the collection below it. */
#screen-library .practice-library { height: auto !important; min-height: 100vh; }
#screen-library .practice-reflow { height: auto !important; overflow: visible !important; }
#screen-library .practice-library [data-lib-grid] { height: auto !important; overflow: visible !important; }
.practice-library .practice-flow { display: flex !important; flex-direction: column !important; height: auto !important; }
.practice-library .practice-prescription { flex: 0 0 auto !important; width: 100% !important; height: auto !important; min-height: 166px; margin-bottom: 20px; }
.practice-library .practice-prescription [hidden] { display: none !important; }
.practice-library #practice-primary { width: auto !important; padding: 10px 16px !important; min-height: 44px !important; white-space: normal !important; }
.practice-library .practice-secondary { background: transparent !important; box-shadow: none !important; border-color: transparent !important; }

/* The Explore collection chips. Everything visible is inline on the elements
   (canon-library.mjs renderCollections, harvested from the design's own tab
   strip); these three rules are only the states no inline style can reach.
   The row WRAPS and never scrolls: up to three lines at 375px, one at 1418. */
.lib-collections { flex-wrap: wrap !important; overflow: visible !important; }
/* Hover leaves a SELECTED chip alone. The first cut did not, and the probe
   caught it at once: a real click leaves the pointer resting on the chip, so
   the hover border overwrote the active underline and the measured colour came
   back #3d4f45 instead of the accent. State outranks hover. */
.lib-collections > button[aria-pressed="false"]:hover { border-color: var(--chip-hover-border, #3d4f45) !important; }
/* The canon's own focus ring, repeated here because the reset exemption above
   hands this subtree back to the app stylesheet and `.canon-root :focus-visible`
   is not specific enough to beat a chip's inline border. */
.lib-collections > button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.practice-adjust { width: 100%; flex-basis: 100%; color: inherit; }
.practice-adjust summary { cursor: pointer; min-height: 44px; padding: 12px 4px; font: inherit; }
.practice-adjust-modes { display: flex; flex-wrap: wrap; gap: 8px; }
/* Chrome keeps layout boxes for a closed details' content (content-visibility), so the
   hidden mode buttons still reported rects and the geometry gate read them as overlapping
   Hear it. Closed means no box at all. (Fable review of the Astra build, 2026-09-09) */
.practice-adjust:not([open]) > .practice-adjust-modes { display: none; }
.practice-adjust-modes > * { min-height: 44px; max-width: 100%; }
.session-guide { box-sizing: border-box; flex: 0 0 auto; width: 100%; padding: 10px 12px; border: 1px solid currentColor; border-radius: 12px; color: inherit; font: inherit; }
/* While immersed, the Play again pill lives in the top-right of the readout strip (canon-play.mjs, the
   only band with nothing in it). Run A put the session guide in that strip, so the pill printed over the
   guide's first lines (restart-probe, 2026-09-10). The guide cedes that corner while the pill is shown. */
.canon-root [data-immersed="1"] .session-guide { display: none !important; }
.session-guide #guide-toggle { min-height: 44px; cursor: pointer; }
.session-guide .guide-heading { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; }
.session-guide #practice-from-start { min-height: 44px; cursor: pointer; margin-left: auto; }
.session-guide #practice-from-start[hidden] { display: none; }
.session-guide .guide-heading p { margin: 0; }
.session-guide.is-collapsed .session-goal { display: none; }
.session-guide #guide-body[hidden] { display: none; }
.session-guide.is-collapsed { padding-top: 0; padding-bottom: 0; border-color: transparent; }
.session-guide p { margin: 0 0 8px; line-height: 1.4; }
.session-guide .session-goal { font-weight: 700; }
.session-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.session-actions button { min-height: 44px; max-width: 100%; white-space: normal; text-align: left; }
.session-actions #j-go { font-weight: 700; border: 2px solid currentColor; }
.session-actions #j-exit { margin-left: auto; }
.correction-card { margin-top: 12px; padding-top: 12px; border-top: 1px solid currentColor; }
.correction-card .session-actions { margin-bottom: 8px; }
.session-guide { border-color: #253129; }
.practice-tools { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); column-gap: 16px; }
.practice-insight { grid-column: 1/-1; margin: 8px 0 0; padding-top: 10px; border-top: 1px solid #253129; }
.practice-insight strong { display: inline; font-size: 12px; margin-right: 8px; }
.practice-insight p { display: inline; font-size: 12px; }
.practice-insight #practice-conditions { display: block; margin: 5px 0 0; color: #b5c5b9; }
.practice-details { margin-top: 4px; font-size: 12px; min-width: 0; }
.practice-details[open] { grid-column: 1/-1; }
.practice-details summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; gap: 8px; text-decoration: underline; text-underline-offset: 4px; }
.practice-details summary::before { content: '+'; font-size: 18px; }
.practice-details[open] summary::before { content: '−'; }
.practice-details dl { display: grid; grid-template-columns: minmax(70px, .4fr) minmax(0, 1fr); gap: 8px 12px; margin: 8px 0; }
.practice-details dt { font-weight: 700; }
.practice-details dd { margin: 0; overflow-wrap: anywhere; }
.passage-fields { display: flex; flex-wrap: wrap; align-items: end; gap: 8px; }
.passage-fields label { flex: 1 1 90px; display: grid; gap: 6px; }
.passage-fields input { box-sizing: border-box; min-width: 0; width: 100%; min-height: 44px; border: 1px solid var(--line, #253129); border-radius: 6px; padding: 8px; color: inherit; background: var(--bg, #0a0d0b); font: inherit; }
.passage-fields button { min-height: 44px; }
.session-guide :is(button,input,summary):focus-visible { outline: 2px solid #82bf9c; outline-offset: 3px; }
.practice-history { margin: 8px 0; padding-left: 18px; }
.practice-history li { margin-bottom: 8px; line-height: 1.5; }
@media(max-width:600px) { .practice-tools { grid-template-columns: 1fr; gap: 0; } }
.score-notice { position: sticky; left: 0; max-width: min(65ch, 90vw); padding: 12px; font: 13px/1.5 Helvetica,Arial,sans-serif; color: #23282f; }
.engraved-score { color: #23282f; }
.engraved-score svg { display: block; max-width: none; }
.score-wrap > .engraved-score { flex: 0 0 auto; min-width: 0; }
#screen-play #score-wrap { background: #f5f1e6 !important; }
.engraved-score [data-state="current"] { filter: drop-shadow(0 0 1px #23282f); }
.engraved-score [data-state="current"] path { fill: #2e6b47; stroke: #2e6b47; }
.engraved-score [data-state="played"] { opacity: .6; }
@media (prefers-reduced-motion: reduce) {
  .session-guide *, #cp-again { transition: none !important; animation: none !important; }
}
@media (max-width: 755px) {
  .canon-root[data-canon-screen="play"] { width: 100% !important; max-width: 100%; margin: 0 !important; }
  .canon-root[data-canon-screen="play"] [data-reflow="board"],
  .canon-root[data-canon-screen="play"] [data-reflow="frame"] {
    width: 100% !important; height: auto !important; min-height: 100dvh; zoom: 1 !important; margin: 0 !important;
  }
  .canon-root[data-canon-screen="play"] [data-reflow="row"] { flex-wrap: wrap !important; min-width: 0; height: auto !important; }
  .canon-root[data-canon-screen="play"] [data-reflow="column"] { width: 100% !important; max-width: 100%; min-width: 0; height: auto !important; }
  .canon-root[data-canon-screen="play"] [data-reflow] { box-sizing: border-box; }
  .canon-root[data-canon-screen="play"] #score-wrap { max-width: 100%; min-width: 0; overflow-x: auto; }
  .canon-root[data-canon-screen="play"] #falls { width: 100% !important; min-height: 260px; }
  .canon-root[data-canon-screen="play"] .session-guide { width: 100%; min-width: 0; }
  .canon-root[data-canon-screen="play"] :has(> #cp-title-n) { min-width: 150px !important; flex: 1 1 150px !important; }
  .canon-root[data-canon-screen="play"] #cp-title-n { white-space: normal; overflow-wrap: normal; }
  .canon-root[data-canon-screen="play"] :is(button, summary, input, select) { min-height: 44px !important; max-width: 100%; }
}
.first-phrase-keys { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 6px; }
.first-phrase-keys p { flex-basis: 100%; }
.first-phrase-keys button { min-width: 44px; min-height: 44px; }
.firstrun-card { max-height: calc(100dvh - 40px); overflow-y: auto; }
.firstrun-card button { min-height: 44px; }

/* Responsive regions have their own low-specificity reset. This preserves
   canon isolation at the drawn widths while letting layout rules win. */
:where(.canon-root [data-reflow]):not(.practice-prescription) { all: revert; box-sizing: border-box; }

/* The two reference widths remain pixel-faithful. No font or colour changes.
   A desktop between or beyond them redistributes space at natural type size. */
@media (1024px <= width < 1418px), (width > 1418px) {
  .canon-root[data-canon-screen] { width: 100%; min-width: 0; }
  .canon-root [data-reflow="board"],
  .canon-root [data-reflow="frame"] {
    width: 100% !important; max-width: 100% !important;
    height: auto !important; min-height: 100dvh; overflow: visible !important;
  }
  .canon-root [data-reflow="row"] {
    flex-wrap: wrap !important; min-width: 0 !important;
    height: auto !important; max-height: none !important;
  }
  .canon-root [data-reflow="column"] {
    min-width: 0 !important; max-width: 100% !important;
  }
  .canon-root [data-reflow] > * { min-width: 0; }
  .canon-root [data-responsive-board] :is(button, [role="button"], summary) {
    min-width: 44px !important; min-height: 44px !important;
    flex-shrink: 0 !important; max-width: 100%; white-space: normal !important;
  }
  .canon-root[data-canon-screen="library"] [data-reflow="frame"] > [data-reflow="row"] {
    min-height: 50px; flex: 0 0 auto !important;
  }
  .canon-root[data-canon-screen="library"] [data-lib-grid] {
    width: 100% !important; height: auto !important; overflow: visible !important;
    display: flex !important; flex-wrap: wrap !important; align-items: flex-start !important;
  }
  .canon-root[data-canon-screen="library"] [data-lib-grid] > * {
    height: auto !important; min-height: 166px; flex-shrink: 0 !important;
  }
  /* Dashboard cards retain their drawn preferred widths, sharing spare space
     and moving to another line when the preferred widths no longer fit. */
  .canon-root[data-canon-screen="library"] [data-reflow="row"]:not([data-lib-grid]) > [data-reflow="column"][style*="width:"] {
    flex-grow: 1 !important; max-width: 100% !important;
  }
  .canon-root[data-canon-screen="play"] [data-reflow="board"] { min-height: 0; }
  .canon-root [data-reflow="play-frame"] {
    width: 100% !important; height: 100dvh !important; min-height: 600px;
    display: flex !important; flex-direction: column !important;
  }
  .canon-root [data-reflow="play-header"] { flex-wrap: wrap !important; min-height: 66px; }
  .canon-root [data-reflow="play-main"] {
    display: grid !important; grid-template-columns: minmax(0, 1fr) clamp(280px, 23.3vw, 330px);
    flex: 1 !important; min-height: 0 !important; height: auto !important;
  }
  .canon-root [data-reflow="play-stage"] { width: auto !important; min-width: 0; min-height: 0; }
  .canon-root [data-reflow="play-controls"] {
    width: auto !important; min-width: 0; min-height: 0; overflow-y: auto !important;
  }
  .canon-root [data-reflow="play-controls"] > * { flex-shrink: 0 !important; }
  .canon-root [data-reflow="play-deck"] {
    min-width: 0; min-height: 0; height: auto !important; overflow-y: auto !important;
  }
  .canon-root[data-canon-screen="play"] #falls {
    flex: 1 0 240px !important; min-height: 240px !important; max-width: 100%;
  }
  .canon-root[data-canon-screen="play"] #score-wrap {
    flex: 1 0 238px !important; min-height: 238px !important; min-width: 0;
    max-width: 100%; overflow-x: auto;
  }
  .canon-root[data-canon-screen="play"] #score-wrap > svg { max-width: none; flex: none; }
  .canon-root[data-canon-screen="play"] .session-guide { min-width: 0; height: auto; }
  .canon-root [data-responsive-board="play"][data-immersed="1"] [data-reflow="play-main"] {
    grid-template-columns: minmax(0, 1fr);
  }
  .canon-root [data-responsive-board="play"][data-immersed="1"] [data-reflow="play-deck"] { padding-right: 48px !important; }
  .canon-root [data-reflow="play-rail"] { width: 44px !important; }
  .canon-root[data-canon-screen="play"] #cp-again { right: 60px !important; }
  .canon-root:is([data-canon-screen="path"], [data-canon-screen="lesson"], [data-canon-screen="lessons"]) [data-reflow="frame"] {
    /* the drawn height, not the viewport: stretching a content board to 100dvh opened a 25%
       void beside the lesson stave on a 950px-tall window (void-check, 2026-09-10) */
    min-height: 738px;
  }
  /* Content boards (path, lesson, lessons) keep the drawn proportions: wider than the drawn
     width they stretched the stave panel into a void (void-check at 1600, 2026-09-10). They
     reflow up to 1418 and centre beyond it; the library and play keep using the whole width. */
  .canon-root:is([data-canon-screen="path"], [data-canon-screen="lesson"], [data-canon-screen="lessons"]) [data-reflow="board"] {
    max-width: 1418px !important; margin-left: auto !important; margin-right: auto !important;
  }
  .canon-root:is([data-canon-screen="path"], [data-canon-screen="lesson"], [data-canon-screen="lessons"]) [data-reflow="column"] {
    height: auto !important; max-height: none !important; overflow: visible !important;
  }
  .canon-root[data-canon-screen="path"] #path-skills {
    display: grid !important; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    height: auto !important;
  }
  .canon-root[data-canon-screen="path"] #path-reason { max-height: none !important; }
  .canon-root[data-canon-screen="path"] #path-reason > *,
  .canon-root[data-canon-screen="lesson"] #lesson-msg > * { white-space: normal !important; }
  .canon-root[data-canon-screen="path"] [data-reflow="row"] > [data-reflow="column"][style*="width:430px"] {
    flex: 1 1 320px !important; width: auto !important;
  }
  .canon-root[data-canon-screen="path"] [data-reflow="row"]:has(> [style*="width:430px"]) > :first-child {
    flex: 2 1 560px !important;
  }
  .canon-root[data-canon-screen="lesson"] [data-reflow="row"] > [style*="width:400px"] {
    flex: 1 1 320px !important; width: auto !important;
  }
  .canon-root[data-canon-screen="lesson"] [data-reflow="row"]:has(> [style*="width:400px"]) > :last-child {
    flex: 2 1 500px !important;
  }
  .canon-root[data-canon-screen="lesson"] #lesson-stave { min-height: 210px !important; }
  .canon-root[data-canon-screen="lesson"] div:has(> #lesson-keys) {
    min-height: clamp(240px, 40dvh, 480px) !important; min-width: 0;
  }
  .canon-root[data-canon-screen="lesson"] #lesson-msg { flex-wrap: wrap !important; }
  .canon-root[data-canon-screen="lesson"] #lesson-nomidi { flex-basis: 100% !important; min-height: 44px; }
}

/* Phones: the library board is drawn 756px wide with a 186px rail beside the
   collection, which pushed the page to 520px+ on a 390px screen and cut the
   rail and the welcome card off. Below 755px the rail stacks above the
   collection as a wrapped strip, and nothing is wider than the screen. */
@media (max-width: 755px) {
  #screen-library .practice-reflow { width: 100% !important; max-width: 100vw; min-width: 0 !important; }
  #screen-library .practice-reflow:has(> [style*="width:186px"]) { flex-direction: column !important; min-height: 0 !important; }
  #screen-library .practice-reflow > [style*="width:186px"] {
    width: 100% !important; border-right: 0 !important; border-bottom: 1px solid #253129 !important;
    flex-direction: row !important; flex-wrap: wrap !important; height: auto !important;
  }
  #screen-library .practice-reflow > [style*="width:186px"] > * { min-width: 0; }
  #screen-library .practice-reflow [style*="width:412px"] { width: 100% !important; }
  #screen-library .practice-reflow [style*="flex:1;min-width:0"] { width: 100% !important; }
  #screen-library .practice-reflow [style*="gap:12px;padding:14px"],
  #screen-library .practice-reflow [style*="gap:12px;padding:0 14px 14px"] { flex-wrap: wrap !important; }
  #screen-library .practice-reflow [style*="gap:12px;padding:14px"] > *,
  #screen-library .practice-reflow [style*="gap:12px;padding:0 14px 14px"] > * { flex: 1 1 100% !important; min-width: 0 !important; width: auto !important; }
  /* the four shelf tabs scroll sideways inside their own row, never the page */
  #screen-library .practice-reflow :has(> [style*="flex: 0 0 auto; padding: 0px 13px; height: 48px"]) {
    overflow-x: auto !important; max-width: 100% !important; scrollbar-width: none;
  }
  #screen-library .practice-reflow [style*="gap:8px;padding:0 14px 7px 12px"] { display: none !important; }
  /* song rows (Learning, search results): four fixed columns left the title
     0px wide, so it could not be read or tapped. Title gets the first line,
     plays and diff go, state and tiers drop to a second line under it. */
  #screen-library .practice-reflow :has(> [style*="width:140px;flex:none"]) { flex-wrap: wrap !important; row-gap: 6px !important; }
  #screen-library .practice-reflow :has(> [style*="width:140px;flex:none"]) > [style*="flex:1;min-width:0"] { flex: 1 1 calc(100% - 64px) !important; }
  #screen-library .practice-reflow :has(> [style*="width:140px;flex:none"]) > [style*="width:40px;flex:none"],
  #screen-library .practice-reflow :has(> [style*="width:140px;flex:none"]) > [style*="width:52px;flex:none"] { display: none !important; }
  #screen-library .practice-reflow :has(> [style*="width:140px;flex:none"]) > [style*="width:92px;flex:none"] { margin-left: 56px; }
  #screen-library .practice-reflow [style*="width:140px;flex:none"] { width: auto !important; flex: 0 1 auto !important; flex-wrap: wrap; }
  .firstrun-card { max-width: calc(100vw - 32px); margin: 16px; padding: 22px 20px; box-sizing: border-box; }
  .firstrun-card h2 { font-size: 28px; }
}

/* Flat menus (Mark, 2026-10-23: "no random glows in the background of the main
   menus"). The library design put a blurred tinted copy behind every cover;
   the covers keep their 1px frame and sit on plain black. */
#screen-library [style*="blur("], .practice-reflow [style*="blur("], [data-canon-screen^="library"] [style*="blur("] { display: none !important; }
