/* ============================================================================
   Root Note - Huisstijl (definitief). Look & Feel her-uitrol v0.76.0.
   Leidend document: Root_Note_Huisstijl_Definitief.md (+ .html).
   Elke kleurwaarde staat LETTERLIJK in elk themablok - nooit --x: var(--x),
   nooit een alias. Drie thema's: licht (standaard bij daglicht) . donker
   (grafiet, de rustigste) . neon (Neon Pulse, ongewijzigd van kleur).
   ========================================================================== */
:root{
  /* ---- Vorm - de vier radii (1.4). Gelijk in alle drie de thema's. ---- */
  --r-sm:9px; --r-md:13px; --r-lg:17px; --r-pill:99px;

  /* ---- Ruimte - acht stappen (1.7). Staat een afstand hier niet in, dan is
     hij fout. Uitzonderingen, en verder niets:
       1. randen/scheidingslijnen - 1px, 1,5px, 3px (lijndikte, geen afstand)
       2. optische centrering IN een bouwsteen (staat vast in 1.12)
       3. negatieve correcties - uitsluitend als calc(var(--sp-N) * -1) ---- */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px;
  --sp-5:24px; --sp-6:32px; --sp-7:48px; --sp-8:72px;

  /* ---- Beweging (1.10). --ease: snel weg, zacht aan. ---- */
  --mo-1:120ms; --mo-2:200ms; --mo-3:320ms; --ease:cubic-bezier(.2,.7,.3,1);

  /* ---- Breedtes en breekpunten (1.11). De --bp-* hier zijn documentatie -
     @media kan geen var() lezen; de drie waarden staan hard in elke @media. ---- */
  --w-focus:640px; --w-read:720px; --w-wide:1080px;
  --bp-sm:560px; --bp-md:820px; --bp-lg:1120px;

  /* ---- Het klavier - de enige vaste kleuren (1.5). Wit is wit en zwart is
     zwart, in alle drie de thema's. ---- */
  --key-white:#FFFFFF; --key-black:#16181C; --key-edge:#B8BEC4; --key-ink:#5C646C;
}

/* ---- Licht - standaard bij daglicht. Kleurloze ondergrond, een blauw accent. */
[data-theme="light"]{
  --canvas:#F4F5F6; --surface:#FFFFFF; --surface2:#E9EBED;
  --border:#D8DCE0; --border-strong:#BFC5CB;
  --text:#14171A; --muted:#5C646C; --faint:#8A9198;
  --accent:#1A64D8; --accent-hover:#1550B4; --accent-ink:#FFFFFF; --accent-soft:#E1EBFC;
  /* BL-1.5b — was #15703F: te donker/gedempt om op de notenbalk goed te
     onderscheiden van --notation (#14171A, bijna zwart) — beide vrij donker,
     dus weinig helderheidscontrast, alleen kleurtoon verschilde. Een
     levendiger groen (Tailwind green-600) blijft ruim genoeg contrast houden
     tegen --paper/--surface (wit) voor tekst/badges, en steekt nu duidelijk
     af tegen de bijna-zwarte notatiekleur. */
  --ok:#16A34A; --ok-soft:#E4F2E9;
  --err:#B02121; --err-soft:#FBE7E7;
  --off:#8A6112; --off-soft:#FAF0DC;
  --play:#6E50CE; --play-soft:#EBE7FA;
  --paper:#FFFFFF; --staff-line:#A8B0B8; --notation:#14171A;
  --wheel-maj:#2D7FF9; --wheel-min:#6B7683;
  --icon-g1:#1A64D8; --icon-g2:#6BA5F5; --icon-disc:#E1EBFC; --icon-glow:rgba(26,100,216,.20);
  --cover:#E4E7EA;
  --sh-1:0 1px 2px rgba(20,23,26,.06);
  --sh-2:0 4px 14px rgba(20,23,26,.10);
  --sh-3:0 18px 44px rgba(20,23,26,.15);
  --scrim:rgba(20,23,26,.55);
}

/* ---- Donker - grafiet. Dezelfde opzet, lichter afgestemd. De rustigste. */
[data-theme="dark"]{
  --canvas:#131619; --surface:#1A1E22; --surface2:#23282D;
  --border:#31373D; --border-strong:#454C53;
  --text:#E9ECEF; --muted:#939BA3; --faint:#6E767E;
  --accent:#62A0FA; --accent-hover:#8AB8FC; --accent-ink:#0B1220; --accent-soft:#1A2534;
  --ok:#4ADE80; --ok-soft:#122C1D;
  --err:#F87171; --err-soft:#331617;
  --off:#F2B544; --off-soft:#33270F;
  --play:#A48EE6; --play-soft:#272040;
  --paper:#171B1F; --staff-line:#4A525A; --notation:#E9ECEF;
  --wheel-maj:#4E93FA; --wheel-min:#8B959F;
  --icon-g1:#8FB9FF; --icon-g2:#2D7FF9; --icon-disc:#1A2534; --icon-glow:rgba(45,127,249,.40);
  --cover:#0B0D10;
  --sh-1:0 1px 2px rgba(0,0,0,.35);
  --sh-2:0 6px 18px rgba(0,0,0,.45);
  --sh-3:0 22px 52px rgba(0,0,0,.60);
  --scrim:rgba(0,0,0,.66);
}

/* ---- Neon - Neon Pulse, ongewijzigd van kleur. Alleen de merkkleur verschilt. */
[data-theme="neon"]{
  --canvas:#0A0D1F; --surface:#141833; --surface2:#1B1F42;
  --border:#233158; --border-strong:#33437A;
  --text:#F5F7FB; --muted:#8B93A9; --faint:#6A7189;
  --accent:#22D3EE; --accent-hover:#67E3F5; --accent-ink:#0A0D1F; --accent-soft:#0F2A3A;
  --ok:#4ADE80; --ok-soft:#12301F;
  --err:#F87171; --err-soft:#331416;
  --off:#FBBF24; --off-soft:#33280C;
  --play:#C084FC; --play-soft:#251440;
  --paper:#10132A; --staff-line:#3A4470; --notation:#F2F4F9;
  --wheel-maj:#3B82F6; --wheel-min:#4F46E5;
  --icon-g1:#22D3EE; --icon-g2:#C026D3; --icon-disc:#101430; --icon-glow:rgba(34,211,238,.45);
  --cover:#05071A;
  --sh-1:0 1px 2px rgba(0,0,0,.40);
  --sh-2:0 6px 18px rgba(0,0,0,.50);
  --sh-3:0 22px 52px rgba(0,0,0,.65);
  --scrim:rgba(0,0,0,.66);
}

/* ---- Vangnet: geen data-theme op <html> -> grafiet (L1-02b). ---- */
:root:not([data-theme]){
  --canvas:#131619; --surface:#1A1E22; --surface2:#23282D;
  --border:#31373D; --border-strong:#454C53;
  --text:#E9ECEF; --muted:#939BA3; --faint:#6E767E;
  --accent:#62A0FA; --accent-hover:#8AB8FC; --accent-ink:#0B1220; --accent-soft:#1A2534;
  --ok:#4ADE80; --ok-soft:#122C1D;
  --err:#F87171; --err-soft:#331617;
  --off:#F2B544; --off-soft:#33270F;
  --play:#A48EE6; --play-soft:#272040;
  --paper:#171B1F; --staff-line:#4A525A; --notation:#E9ECEF;
  --wheel-maj:#4E93FA; --wheel-min:#8B959F;
  --icon-g1:#8FB9FF; --icon-g2:#2D7FF9; --icon-disc:#1A2534; --icon-glow:rgba(45,127,249,.40);
  --cover:#0B0D10;
  --sh-1:0 1px 2px rgba(0,0,0,.35);
  --sh-2:0 6px 18px rgba(0,0,0,.45);
  --sh-3:0 22px 52px rgba(0,0,0,.60);
  --scrim:rgba(0,0,0,.66);
}

*{ box-sizing:border-box; margin:0; padding:0; font-family:'Inter',sans-serif; user-select:none; -webkit-tap-highlight-color:transparent; }

/* Focus voor toetsenbordgebruik (1.12 / L1-17) — een regel, overal gelijk,
   nooit outline:none zonder vervanging. */
:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }

/* L1-28 / S1-01 — geen ambient kleurwolken meer; kleurloze ondergrond. */
body{
  background-color:var(--canvas); color:var(--text); display:flex; flex-direction:row;
  height:100dvh; min-height:100vh; overflow:hidden;
  transition:background-color var(--mo-3),color var(--mo-3);
}

#app-shell{ display:flex; flex-direction:column; width:100%; height:100%; }

/* MIDI-statusbolletje (Fase 1.1): bewust onopvallend, linksonder in beeld
   — grijs/gedimd zolang er niets verbonden is (of de browser geen Web MIDI
   ondersteunt), groen zodra een apparaat actief is. Geen klik-actie (nog
   geen apparaat-kiezer), dus geen cursor:pointer/hover-stijl nodig — de
   title-tooltip blijft wel werken zonder pointer-events uit te zetten.
   Stond tot v0.20.25 naast #samples-hidden-trigger (verwijderd, zie
   Root_Note_Context.md) — positie zelf ongewijzigd. */
#midi-status-indicator{
  position:fixed; left:8px; bottom:11px; z-index:15; width:8px; height:8px;
  border-radius:50%; background:var(--muted); opacity:.35;
  transition:background-color var(--mo-2) var(--ease), opacity var(--mo-2) var(--ease);
}
#midi-status-indicator.is-known{ background:var(--ok); opacity:.9; }
/* Geel/amber tussenstadium (Plan_van_Aanpak_MIDI_Status_en_Bereik_
   Soundcheck, v0.92.0) — verbonden, maar nog geen bereik/geluid ingesteld
   voor dít apparaat. Hergebruikt het bestaande --off-token (amber), zelfde
   semantiek als .cn-amber bij de Kwintencirkel-quiz — geen nieuwe kleur. */
#midi-status-indicator.is-new{ background:var(--off); opacity:.9; }

/* "Nieuwe versie beschikbaar"-melding (Fase PWA-vervolg, sinds v0.20.19) —
   klein, opvallend genoeg om te zien maar niet storend modaal: een balkje
   onderin beeld i.p.v. een blokkerende dialoog, want de gebruiker kan
   prima nog even doorwerken vóór het herladen. */
#update-banner{
  /* z-index 10001: BOVEN alle andere position:fixed-overlays (#tiles-page
     9998, .init/tiles-achtergrond 9999) — anders werd de melding
     overschilderd zodra #tiles-page zichtbaar is (gevonden tijdens testen:
     9500 lag ONDER #tiles-page se 9998, dus de banner was nooit zichtbaar op
     het tegel-overzicht ondanks correcte display:flex). */
  position:fixed; left:50%; bottom:16px; transform:translateX(-50%); z-index:10001;
  display:flex; align-items:center; gap:var(--sp-3); background:var(--surface); color:var(--text);
  border:1px solid var(--border); border-radius:var(--r-md); padding:var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-4);
  box-shadow:0 12px 32px rgba(0,0,0,.4); font-size:.85rem; max-width:calc(100vw - 32px);
}
/* Tekst mag nooit tussenwoord afbreken (gevonden tijdens testen op 390px-
   breed scherm: zonder dit kreeg de korte tekst toch een lelijke 3-regelige
   afbreking naast de knoppen, want een flex-item mag standaard tot 0
   krimpen). shrink:0 op de knoppen zodat ZIJ nooit de tekst verdringen. */
#update-banner span{ white-space:nowrap; }
#update-banner button{ flex-shrink:0; }
#update-banner button{ font-size:.8rem; padding:var(--sp-2) var(--sp-4); white-space:nowrap; }

/* DEV-herkenning (B-10) — de hostname-check in <head> (`is-dev-env` op
   <html>) blijft bestaan voor het rode manifest/favicon/apple-touch-icon
   (zie index.html), maar het topbalk-merkteken dat 'm vroeger ook rood
   tintte is op gebruikersverzoek verwijderd (stond de topbalk-iconen in de
   weg op mobiel, geen meerwaarde binnen een module/oefening). */
#update-dismiss-btn{ background:transparent; border:none; color:var(--muted); cursor:pointer; padding:var(--sp-1); font-size:.9rem; }
#update-dismiss-btn:hover{ color:var(--text); }

#content-area{ flex:1; display:flex; flex-direction:column; overflow:hidden; min-width:0; }
/* Grid i.p.v. flex+space-between (gebruikersfeedback: met de modus-
   schakelaar als los 4e flex-item stond die met een grote, onnette
   tussenruimte los van de terug-knop, EN duwde de titel uit het midden).
   `1fr auto auto 1fr` met #module-title in de middelste `auto`-kolom(men)
   houdt de titel gegarandeerd gecentreerd t.o.v. de volledige breedte,
   ongeacht hoeveel er links (.topbar-left) of rechts (.topbar-right) staat
   — zolang geen van beide kolommen breder wordt dan zijn `1fr`-aandeel. */
#content-topbar{
  background-color:transparent; backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px);
  padding:var(--sp-4) var(--sp-5); display:grid; grid-template-columns:1fr auto 1fr;
  align-items:center; gap:var(--sp-4); border-bottom:1px solid var(--border); position:relative;
  z-index:30; transition:background-color var(--mo-3); flex-shrink:0;
}
/* Light mode: getinte kaart-achtergrond i.p.v. puur transparant (sinds
   v0.18.3-feedback, "header mag beter uitspringen") — nu het canvas
   (--canvas) zuiver wit is, moet de topbar juist NIET ook wit-op-wit zijn;
   dezelfde lichtblauwe tint als --surface/--paper (zie de toelichting
   bij [data-theme="light"] hierboven) geeft 'm hetzelfde "opgetilde
   kaart"-gevoel als de flashcard eronder, i.p.v. gewoon lucht. */
.topbar-left{ display:flex; align-items:center; gap:var(--sp-2); grid-column:1; justify-self:start; min-width:0; }
/* G-01 — scherm-titel: Fraunces 600, 17px (1.8 tekstrol). */
#content-topbar h1{
  grid-column:2; justify-self:center; text-align:center;
  font-family:'Fraunces',serif; font-size:17px; font-weight:600; letter-spacing:-.01em; color:var(--text);
}
.topbar-right{ display:flex; gap:var(--sp-2); align-items:center; grid-column:3; justify-self:end; }

/* G-01 — één topbalk-grammatica. Elke systeemknop 34×34 met een tekening
   van 20px (v1.1-reconciliatie, 2026-09-12: was 32×32/19 — gebruikersverzoek
   om dezelfde hoogte als de modus-schakelaar-pil aan te houden, gemeten op
   .mode-switch-btn = 33px; 34 is de dichtstbijzijnde ronde waarde, ratio
   icoon/knop ongewijzigd ~0,59). */
/* BL-1.2 — standaard grijs (--muted), pas --accent zodra de lade openstaat
   (SettingsUI.toggleDrawer() zet .is-active). */
#settings-btn{
  width:34px; height:34px; padding:0; border-radius:var(--r-sm); flex-shrink:0;
  background:transparent; border:1px solid transparent; color:var(--muted);
  display:inline-flex; align-items:center; justify-content:center;
  transition:background-color var(--mo-1) var(--ease), color var(--mo-1) var(--ease);
}
@media (hover:hover){ #settings-btn:hover{ background:var(--surface2); color:var(--text); } }
#settings-btn.is-active{ color:var(--accent); }
.topbar-icon-btn{
  width:34px; height:34px; padding:0; border-radius:var(--r-sm); flex-shrink:0;
  background:transparent; border:1px solid transparent; color:var(--muted);
  display:inline-flex; align-items:center; justify-content:center;
  transition:background-color var(--mo-1) var(--ease), color var(--mo-1) var(--ease);
}
@media (hover:hover){ .topbar-icon-btn:hover{ background:var(--surface2); color:var(--text); } }
.topbar-icon-btn:active{ transform:scale(.96); }
/* Thema-/geluid-SVG's (THEME_SOUND_ICONS, `.sys-icon`, sinds v0.18.3)
   hebben geen eigen width/height-attribuut — zonder expliciete maat viel de
   browser terug op een intrinsieke standaardgrootte die per context anders
   uitpakte (te groot in de topbar, te klein op de cover-/tegelpagina; een
   eerdere poging met losse per-context pixel-regels loste de topbar wél op
   maar de cover-/tegelpagina-variant bleef om onduidelijke reden op de
   oude, te kleine maat hangen). `1em` i.p.v. een vaste pixelwaarde is
   robuuster: elke knop-context bepaalt zijn eigen icoon-grootte gewoon via
   zijn BESTAANDE `font-size` (topbar 1.05rem, cover-/tegelpagina 1.2rem,
   zie de knop-basisregels), zelfde principe als hoe de oude emoji's altijd
   al schaalden. */
/* Systeemicoontje — 20px in de topbalk (M-07, v1.1: was 19px). De cover-/
   tegelrij gebruikt dezelfde maat (S1-02). */
.sys-icon{ width:20px; height:20px; display:block; flex-shrink:0; }

/* Modus-schakelaar (sinds de tegel-consolidatie naar 1 tegel per app) —
   vervangt de vroegere Modus-tegels op de tegel-pagina: je kiest de modus nu
   direct in de app en kunt tussentijds wisselen zonder terug te gaan. Zit
   sinds de logo-ronde (gebruikersverzoek: "kunnen ze niet gewoon op de
   bestaande [balk] naast het pijltje") INLINE in `#content-topbar` naast
   `#back-to-tiles-btn`, i.p.v. een eigen balk eronder — dus geen eigen
   border-bottom/padding meer nodig, de topbar levert dat al. Een
   MIDI-vereisende modus is grijs/niet-klikbaar zolang MidiEngine.connected
   false is (zie App.renderModeSwitcher), met een tooltip die uitlegt
   waarom — bewust GEEN aparte badge-stijl hier (die kleurtaal leeft al op
   de tegel-pagina), gewoon een gedimde knop is duidelijk genoeg naast de
   actieve/beschikbare modi ernaast. */
#mode-switcher-bar{
  display:none; gap:var(--sp-2); flex-wrap:wrap; flex-shrink:0;
}
/* Tekstkleur op gebruikersfeedback opgehoogd ("kleurcontrast niet goed te
   lezen") — was `var(--muted)` voor ELKE niet-actieve knop, inclusief
   gewoon-beschikbare modi (niet alleen de MIDI-only-gedimde), tegen de
   doorzichtige/geblurde topbar-achtergrond te weinig contrast. Beschikbare
   modi lezen nu net zo goed als de actieve knop; alleen `.disabled` (MIDI
   vereist, geen keyboard) blijft bewust gedimd, maar minder extreem dan
   voorheen (opacity .45→.55) zodat de tekst nog leesbaar blijft i.p.v.
   vrijwel te verdwijnen. */
/* Glasachtige look (v0.20.0, gebruikersverzoek — kleur zelf blijft
   ongewijzigd) — zelfde `--surface`/`backdrop-filter:blur`-recept als
   de instellingen-drawer/zijbalk sinds de Piano Masterclass "Aurora
   Glass"-ronde, hier voor het eerst op de modus-knoppenrij toegepast. */
.mode-switch-btn{
  padding:var(--sp-2) var(--sp-3); border-radius:999px; border:1px solid var(--border);
  background:var(--surface); backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
  color:var(--text); font-size:.78rem; font-weight:600;
  font-family:'Inter',sans-serif; cursor:pointer;
  transition:background-color var(--mo-1) var(--ease), color var(--mo-1) var(--ease), border-color var(--mo-1) var(--ease);
}
.mode-switch-btn:hover:not(.disabled):not(.active){ border-color:var(--accent); }
.mode-switch-btn.active{ background:var(--accent); border-color:var(--accent); color:var(--accent-ink); font-weight:700; }
.mode-switch-btn.disabled{ color:var(--muted); opacity:.55; cursor:not-allowed; }
/* Vergrendelde modus is sinds v0.52.1 klikbaar (toont een melding) — dus
   geen "not-allowed"-cursor meer. */
.mode-switch-btn.disabled{ cursor:pointer; }
/* Mobiele variant (2026-09-13, herzien) — een eigen klein paneel i.p.v. de
   knoppenrij, zie App.renderModeSwitcher(). EERSTE POGING was een systeem-
   `<select>`: simpel, maar een native keuzelijst is browser-chrome — geen
   eigen paneel-header of per-optie-inhoud (het MIDI-slotje+uitleg) mogelijk.
   Vandaar dit eigen paneel: `.mode-switch-wrap` is het positioneringsanker
   (relative), `.mode-switch-trigger` het compacte "M"-knopje (zelfde
   34×34-maat als de systeemknoppen in de topbalk, zie .topbar-icon-btn),
   `.mode-switch-panel` het uitklappende lijstje eronder. */
.mode-switcher-mobile{ width:auto; }
.mode-switch-wrap{ position:relative; }
/* v0.85.3 (gebruikersmelding, mobiel): zag eruit als een aparte knop
   ("out of place") naast de andere systeemicoontjes (?)/(i)/NL — die zijn
   allemaal `.topbar-icon-btn` (transparant, geen rand, pas kleur bij hover/
   actief). De trigger krijgt nu exact diezelfde basisstijl; alleen het
   "actief/opengeklapt"-accent (zoals #settings-btn.is-active) blijft eigen. */
.mode-switch-trigger{
  width:auto; min-width:34px; height:34px; padding:0 var(--sp-2); border-radius:var(--r-sm); flex-shrink:0;
  background:transparent; border:1px solid transparent; color:var(--muted);
  display:inline-flex; align-items:center; justify-content:center; gap:2px;
  font-size:.9rem; font-weight:700; font-family:'Inter',sans-serif; cursor:pointer;
  transition:background-color var(--mo-1) var(--ease), color var(--mo-1) var(--ease);
}
@media (hover:hover){ .mode-switch-trigger:hover{ background:var(--surface2); color:var(--text); } }
.mode-switch-trigger:active{ transform:scale(.96); }
.mode-switch-trigger[aria-expanded="true"]{ color:var(--accent); }
/* Chevron-pijltje (v0.86.1) — maakt de "M" herkenbaar als dropdown-trigger
   i.p.v. een op zichzelf staand lettertje; draait 180° zodra het paneel
   openstaat, zelfde taal als elke andere uitklap-indicator. */
.mode-switch-chevron{ display:inline-flex; margin-top:1px; transition:transform var(--mo-1) var(--ease); }
.mode-switch-chevron .sys-icon{ width:14px; height:14px; }
.mode-switch-trigger[aria-expanded="true"] .mode-switch-chevron{ transform:rotate(180deg); }
.mode-switch-trigger:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
/* Ontdek-puls (Plan_van_Aanpak_Mobiel_Modus_Ontdekking, v0.92.0) — zachte
   accent-gloed op de mobiele trigger zolang deze module nog nooit is
   opengeklapt (pm_mode_discovered_<id>, zie App.renderModeSwitcher() /
   _openModeDropdown()). Blauw (--accent), geen nieuwe kleur — dooft zodra
   de gebruiker 1x tikt. */
@keyframes mode-discover-pulse{
  0%, 100%{ box-shadow:0 0 0 0 transparent; }
  50%{ box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 45%, transparent); }
}
.mode-switch-trigger.is-unexplored{ animation:mode-discover-pulse 2s infinite; }
/* Pc/tablet in-/uitklap-schakelaar (v0.86.1, gebruikersverzoek) — hergebruikt
   .mode-switch-trigger voor de knop-basisstijl, maar toont/verbergt de
   bestaande knoppenrij zelf i.p.v. een los paneel te openen (dat is de
   mobiele variant hierboven). Horizontaal (links/rechts) i.p.v. verticaal
   (boven/beneden) zoals de mobiele chevron: uitgeklapt (standaard, aria-
   expanded="true") wijst naar links — "klap terug"; ingeklapt naar rechts —
   "klap uit". Zelfde bronselector-vorm (class+attr+afstammeling) als de
   mobiele regel hierboven, hier NA die regel geplaatst zodat deze bij
   gelijke specificiteit wint (de mobiele trigger deelt de .mode-switch-
   trigger-klasse, dus zonder dat zou de 180°-regel hierboven ook hier gelden). */
.mode-switch-desktop{ display:flex; align-items:center; gap:var(--sp-2); flex-shrink:0; }
.mode-switch-desktop-row{ display:flex; align-items:center; gap:var(--sp-2); flex-wrap:wrap; }
.mode-switch-desktop.collapsed .mode-switch-desktop-row{ display:none; }
.mode-switch-desktop-toggle[aria-expanded="true"] .mode-switch-chevron{ transform:rotate(90deg); }
.mode-switch-desktop-toggle[aria-expanded="false"] .mode-switch-chevron{ transform:rotate(-90deg); }
.mode-switch-panel{
  position:absolute; top:calc(100% + var(--sp-2)); left:0; z-index:40;
  min-width:200px; max-width:min(300px, 90vw);
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md);
  box-shadow:var(--sh-3); padding:var(--sp-2); display:flex; flex-direction:column; gap:2px;
}
/* v0.85.3 (mobiel bugreport: "kan het paneel niet sluiten") — de ECHTE
   oorzaak: een auteur-regel met `display:flex` wint altijd van de browser-
   eigen `[hidden]{display:none}` (auteur-CSS gaat vóór user-agent-CSS,
   ongeacht specificiteit), dus `panel.hidden = true` in JS deed helemaal
   niets — het paneel stond al vanaf de eerste render onzichtbaar-maar-niet
   permanent open. Zelfde patroon als elders in dit bestand (bijv.
   .rhythm-tap-btn[hidden]) — hier alsnog netjes toevoegen i.p.v. de JS naar
   een class-toggle om te bouwen. */
.mode-switch-panel[hidden]{ display:none; }
.mode-switch-panel-head{
  font-size:.68rem; font-weight:700; text-transform:uppercase; letter-spacing:.6px;
  color:var(--muted); padding:var(--sp-2) var(--sp-3) var(--sp-1);
}
.mode-switch-option{
  width:100%; background:transparent; border:1px solid transparent; border-radius:var(--r-sm);
  color:var(--text); font-size:.85rem; font-weight:600; font-family:'Inter',sans-serif;
  padding:var(--sp-2) var(--sp-3); display:flex; align-items:center; justify-content:space-between;
  text-align:left; cursor:pointer;
}
.mode-switch-option.active{ background:var(--accent); color:var(--accent-ink); }
@media (hover:hover){ .mode-switch-option:hover:not(.active){ background:var(--surface2); } }
.mode-switch-option-locked{ width:100%; padding:0; display:flex; flex-direction:column; align-items:stretch; }
/* v0.86.1: de inline uitlegregel eronder is weg (gebruikersmelding: te veel
   tekst, een tik geeft toch al een toast) — daarom weer symmetrische
   padding zoals .mode-switch-option, i.p.v. de eerdere `2px` onderaan die
   ruimte vrijhield voor die tekst. */
.mode-switch-option-locked .mode-switch-option-btn{
  width:100%; background:transparent; border:none; color:var(--muted);
  font-size:.85rem; font-weight:600; font-family:'Inter',sans-serif;
  padding:var(--sp-2) var(--sp-3); display:flex; align-items:center; justify-content:space-between;
  text-align:left; cursor:pointer;
}
/* BL-1.10 — klavier-icoontje vóór het label bij een MIDI-vergrendelde modus
   (Fase 5.5), i.p.v. het vorige 🔒-teken. */
.mode-lock{ display:inline-flex; align-items:center; margin-right:4px; opacity:.75; }
.mode-lock svg{ width:15px; height:auto; vertical-align:middle; }
/* Scheiding in de schakelaar tussen een tool en de quizzen (v0.56.0,
   Kwintencirkel: "Verkennen │ Relatieve toonsoort · Voortekens · Welke noten"). */
.mode-switch-sep{
  display:inline-block; width:1px; align-self:stretch; margin:2px var(--sp-1);
  background:var(--border);
}

/* Sub-schakelaar bínnen een oefenvorm (v0.56.0) — bijv. Lopende band:
   "Eigen tempo / Tegen de klok". Kleiner en rustiger dan de hoofd-schakelaar,
   staat als eigen regeltje bovenaan het werkgebied. */
#mode-sub-bar{
  display:none; gap:var(--sp-2); flex-wrap:wrap; justify-content:center;
  margin:0 auto var(--sp-1); padding:0 var(--sp-3);
}
.mode-sub-btn{
  padding:var(--sp-1) var(--sp-3); border-radius:999px; border:1px solid var(--border);
  background:transparent; color:var(--muted); font-size:.74rem; font-weight:600;
  font-family:'Inter',sans-serif; cursor:pointer;
  transition:background-color var(--mo-1) var(--ease), color var(--mo-1) var(--ease), border-color var(--mo-1) var(--ease);
}
.mode-sub-btn:hover:not(.active){ color:var(--text); border-color:var(--accent); }
.mode-sub-btn.active{
  background:color-mix(in srgb, var(--accent) 16%, transparent);
  border-color:color-mix(in srgb, var(--accent) 45%, transparent); color:var(--accent);
}

/* MIDI-knop in de module-topbar (v0.52.1) — icoon + statusstipje. Sinds de
   bugfix-ronde ná v0.96.3 hergebruikt door #midi-btn-tiles (tegel-overzicht-
   topbar) — zelfde opzet, zie de HTML-toelichting bij #midi-btn-tiles. */
#midi-btn-header, #midi-btn-tiles{ position:relative; }
#midi-btn-header-dot, #midi-btn-tiles-dot{
  position:absolute; top:6px; right:6px; width:7px; height:7px; border-radius:50%;
  background:var(--muted); opacity:.5; transition:background-color var(--mo-2), opacity var(--mo-2);
}
#midi-btn-header-dot.is-known, #midi-btn-tiles-dot.is-known{ background:var(--ok); opacity:1; }
#midi-btn-header-dot.is-new, #midi-btn-tiles-dot.is-new{ background:var(--off); opacity:1; }

/* Korte melding (v0.52.1, App.toast). Themakleur-randje (v0.86.1,
   gebruikersverzoek: "laat 'm meer opvallen, zowel op pc als mobiel" — nu
   ook de enige plek die de MIDI-vergrendel-uitleg toont, sinds de inline
   hint in het mobiele modus-paneel is weggehaald) i.p.v. het neutrale
   `--border`-randje. BOVENIN beeld i.p.v. onderin (bugfix-ronde ná v0.96.3,
   gebruikersmelding: "lastig te vinden") — top:20px+gecentreerd, zoals
   gevraagd, i.p.v. de oude bottom-positie die op mobiel makkelijk buiten
   beeld/duimzone viel. */
#app-toast{
  position:fixed; left:50%; top:20px; bottom:auto;
  transform:translate(-50%, -12px); z-index:10800;
  max-width:min(420px, calc(100vw - 32px)); text-align:center;
  background:var(--surface); color:var(--text);
  border:1px solid color-mix(in srgb, var(--accent) 55%, transparent); border-radius:var(--r-md);
  /* Symmetrische padding (bugfix-ronde ná v0.96.4, punt 15) — was rechts
     breder dan links (ruimte voor de sluitknop reserveren), waardoor de
     TEKST optisch niet gecentreerd stond binnen de toast — bij een
     anker-gepositioneerde toast (bijv. mode_switcher_tip) op een smal
     scherm zag dat uit als "te ver naar links". De sluitknop is klein
     genoeg (26px) om ook binnen symmetrische padding te passen zonder de
     tekst te overlappen. */
  padding:var(--sp-3) var(--sp-6); font-size:.86rem;
  box-shadow:0 12px 40px rgba(0,0,0,.45), 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent);
  opacity:0; pointer-events:none; transition:opacity var(--mo-2) var(--ease), transform var(--mo-2) var(--ease);
}
/* v0.86.2: `pointer-events:auto` alleen zolang zichtbaar — de toast is
   normaal puur informatief (geen klikdoel), maar het optionele actie-
   knopje hieronder (bijv. "Ongedaan maken") en de sluitknop hieronder
   moeten wél klikbaar zijn. */
#app-toast.show{ opacity:1; transform:translate(-50%, 0); pointer-events:auto; }
/* Sluitknop (×), sinds de bugfix-ronde ná v0.96.3 — elke toast heeft er nu
   één, gebruikersmelding: banners "missen een sluitknop". Extra rechter-
   padding op #app-toast hierboven (--sp-6 i.p.v. --sp-4) reserveert de
   ruimte zodat de knop nooit over de boodschap heen valt. */
.app-toast-close{
  position:absolute; top:2px; right:2px; width:26px; height:26px;
  display:flex; align-items:center; justify-content:center;
  background:transparent; border:none; color:var(--muted); font-size:1.1rem;
  line-height:1; cursor:pointer; border-radius:50%;
}
@media (hover:hover){ .app-toast-close:hover{ background:var(--surface2); color:var(--text); } }
/* Optioneel actieknopje IN de toast (v0.86.2, gebruikersverzoek — "Ongedaan
   maken" ná het resetten van een oefening se instellingen). Kale tekstknop
   in de themakleur, geen eigen vak/rand — de toast zelf is al een duidelijk
   afgebakend kader. */
.app-toast-action{
  display:block; width:auto; margin:var(--sp-2) auto 0; padding:0;
  background:transparent; border:none; color:var(--accent);
  font-size:.86rem; font-weight:700; text-decoration:underline;
  cursor:pointer;
}
@media (hover:hover){ .app-toast-action:hover{ filter:brightness(1.15); } }
/* Gedimde achtergrond achter de toast (v0.86.1, gebruikersverzoek: "laat
   'm meer opvallen") — simpele volledige achtergrond (geen spotlight-
   uitsparing nodig, de toast markeert geen bestaand pagina-element).
   `pointer-events:none`, net als de toast zelf — puur visueel, blokkeert
   nooit een volgende klik. */
#app-toast-backdrop{
  position:fixed; inset:0; z-index:10799; background:rgba(0,0,0,.65);
  opacity:0; pointer-events:none; transition:opacity var(--mo-2) var(--ease);
}
#app-toast-backdrop.show{ opacity:1; }

/* S8-03 — op de telefoon dunt de topbalk UIT, hij verschuift niet. De vaste
   onderbalk uit v0.20.25 vervalt (B-12).

   Taal + "meer info" verhuisden ooit naar de instellingenlade om het
   topbalk-icoontjes-budget (max. 4) niet te overschrijden — op
   gebruikersverzoek (Fase 5-nazorg) is dat teruggedraaid: taal hoort
   ALTIJD als topbalk-icoontje te tonen, nooit in het instellingenmenu (en
   "meer info" hoort alleen nog op de tegel-pagina, achter de (i)-knop, zie
   daar). Om toch binnen 4 icoontjes te blijven verdwijnt in plaats daarvan
   "volledig scherm" van de telefoon-topbalk (blijft op desktop/tablet) —
   mobiele browsers ondersteunen de Fullscreen-API toch beperkt/inconsistent,
   dus geen functieverlies dat opweegt tegen een altijd-zichtbare taalkeuze.
   Het topbalk-merkteken (B-09) is inmiddels helemaal verwijderd (zie
   index.html), dus dat telt niet meer mee in het budget.

   De schermtitel past niet naast de iconen op een telefoon (2 links + 4
   rechts laten geen ruimte voor een gecentreerde titel). Daarom zakt de
   titel naar een eigen regel ONDER de iconenrij — de iconen zelf blijven staan
   waar ze staan. Rij 1: links de terug-/overzicht-knoppen, rechts het
   systeemcluster (`margin-left:auto`). Rij 2: de gecentreerde titel (de naam
   van het scherm, bijv. "Noten Lezen"). Rij 3 (indien aanwezig): de
   modus-schakelaar — die hoort ONDER de naam, want het is een keuze bínnen
   dat scherm (flashcards / lopende band / tegen de klok). */
@media (max-width:560px){
  /* v0.83.3 (gebruikersverzoek: "topbar-lijn scrollt mee op mobiel") —
     `position:relative` liet de balk (incl. zijn border-bottom, en op deze
     breedte ook de modus-schakelaar-rij erin) gewoon meescrollen zodra de
     inhoud eronder langer is dan het scherm. `sticky` houdt 'm vast aan de
     bovenkant van zijn scroll-omgeving, ongeacht welk element daadwerkelijk
     scrollt — bestaande `z-index:30` (basisregel hierboven) blijft gelden,
     dus de inhoud schuift er correct onderdoor. */
  #content-topbar{ padding:var(--sp-3) var(--sp-4); display:flex; flex-wrap:wrap; align-items:center; row-gap:var(--sp-1); backdrop-filter:none; -webkit-backdrop-filter:none; position:sticky; top:0; min-height:34px; background-color:var(--canvas); }
  .topbar-left{ display:contents; }
  /* Systeemcluster naar de rechterrand; de terug-/overzicht-knoppen blijven links. */
  .topbar-right{ margin-left:auto; gap:var(--sp-2); }
  #content-topbar h1{
    order:3; flex-basis:100%; margin:0;
    text-align:center; font-size:15px; line-height:1.3;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  /* v0.86.1 (gebruikersverzoek, ná het weghalen van #nav-back-btn): de
     modus-schakelaar hoort nu op regel 1 náást het huisje — net als op
     pc/tablet — i.p.v. op een eigen tweede regel met de titel. Was ooit
     bewust de andere kant op besloten (2026-09-13: "modus-select + titel op
     ÉÉN regel", met een `.has-mode-select`-klasse + `::after`-spacer-truc om
     dat te forceren) — die klasse/truc zijn nu weer weg. Zonder eigen
     `order`/`flex-basis` valt #mode-switcher-bar terug op de standaard
     DOM-volgorde (default order:0, meteen ná het huisje binnen
     `.topbar-left{ display:contents }` hierboven), dus samen met het huisje
     vanzelf op regel 1; h1 behoudt gewoon zijn basisregel hierboven
     (order:3, flex-basis:100%) en krijgt dus altijd zijn eigen gecentreerde
     regel, met of zonder modus-schakelaar. */
  /* "Volledig scherm" verdwijnt op de telefoon — zie de toelichting
     hierboven. Taal blijft nu altijd staan. */
  #fullscreen-btn-header{ display:none; }
}
/* v0.94.0 (Plan_van_Aanpak_v0.94.0_Banner_en_Mobiel_Fix) — zelfde
   opschoning als hierboven, maar dan voor #fullscreen-btn-tiles: dat
   fullscreen-icoontje stond nog gewoon in de iconenrij van het TEGEL-
   overzicht (#tiles-page .theme-toggle-container), een andere DOM-plek dan
   #fullscreen-btn-header (module-topbar) — die laatste was al langer
   verborgen op mobiel, deze was over het hoofd gezien. Bewust een losse
   mediaquery i.p.v. toevoegen aan het #content-topbar-blok hierboven: andere
   DOM-context (#tiles-page, niet #content-topbar), en #fullscreen-btn-start
   (coverpagina, deelt dezelfde .theme-toggle-container-klasse) blijft
   bewust ONGEMOEID — geen onderdeel van deze klacht.
   TERUGGEDRAAID in de bugfix-ronde ná v0.96.3: destijds kwam er bewust GEEN
   MIDI-icoon in de vrijgekomen plek (de volledig-tekst #tiles-midi-status-pil
   eronder was juist gebouwd omdat een kaal stipje onvindbaar bleek op touch).
   Op expliciet gebruikersverzoek + mockup komt er ALSNOG een icoon
   (#midi-btn-tiles) in deze plek, maar ALLEEN op mobiel — de volledig-tekst
   pil blijft op desktop gewoon bestaan (nu op dezelfde hoogte als deze
   iconenrij, zie #tiles-midi-status hierboven). Dus geen algehele vervanging
   (dat was een eerdere, te ver doorgeschoten tussenstap in deze bugfix-
   ronde), maar een responsive keuze per breakpoint: pil op desktop, icoon
   op mobiel.
   BUGFIX (gebruikersmelding ná live-mobiel-test): #midi-btn-tiles kreeg zijn
   "sta standaard uit"-basisregel eerder NA deze media query te staan (verderop
   in dit bestand, bij #tiles-midi-dot) — bij gelijke specificiteit (2 ID's,
   beide kanten) wint bij een cascade-conflict de regel die LATER in
   bronvolgorde staat, dus die onvoorwaardelijke "uit" overschreef de mobiele
   "aan" hieronder altijd, ongeacht schermbreedte. Nu vóór de media query. */
#tiles-page #midi-btn-tiles{ display:none; }
@media (max-width:560px){
  /* `#tiles-page #fullscreen-btn-tiles` (2 ID's), niet zomaar
     `#fullscreen-btn-tiles` alleen: de basisregel hierboven
     (`#tiles-page .start-theme-btn{display:flex}`) is zelf al 1 ID + 1
     class — bij gelijke bron-volgorde wint die van een enkele ID-selector
     op specificiteit (zelfde valkuil als de ID-vs-class-les in
     Root_Note_Context.md, hier de omgekeerde variant: ID+class > ID). */
  #tiles-page #fullscreen-btn-tiles{ display:none; }
  /* Wisseling pil ↔ icoon op de mobiele breakpoint (zelfde 2-ID-specificiteit-
     reden als hierboven, voor beide kanten van de wissel). */
  #tiles-page #tiles-midi-status{ display:none; }
  #tiles-page #midi-btn-tiles{ display:flex; }
}

/* Knop (1.12) — 14px/600, padding 9 18, --r-pill, rand 1px transparant.
   Rustende knop krijgt GEEN schaduw. Hover: iets lichter; ingedrukt: scale(.97). */
button{
  background:var(--surface); color:var(--text); border:1px solid var(--border);
  padding:var(--sp-2) var(--sp-4); border-radius:var(--r-pill); cursor:pointer; font-weight:600;
  font-size:14px; display:flex; align-items:center; justify-content:center; gap:var(--sp-2);
  transition:transform var(--mo-1) var(--ease), background-color var(--mo-1) var(--ease),
             border-color var(--mo-1) var(--ease), color var(--mo-1) var(--ease);
}
@media (hover:hover){ button:hover{ background:var(--surface2); } }
button:active{ transform:scale(.97); }
button.primary{ background:var(--accent); color:var(--accent-ink); border-color:transparent; }
@media (hover:hover){ button.primary:hover{ filter:brightness(1.06); } }
button.primary:active{ filter:brightness(.97); }
button:disabled{ opacity:.42; cursor:not-allowed; transform:none; }

select, input[type="number"]{
  background:var(--canvas); color:var(--text); border:1px solid var(--border);
  padding:var(--sp-3); border-radius:var(--r-sm); outline:none; font-size:.9rem; font-weight:500;
  transition:background-color var(--mo-1) var(--ease), border-color var(--mo-1) var(--ease);
}
select:focus{ border-color:var(--accent); }

/* S1-01 — cover-ondergrond, geen versiering. */
#init-overlay{
  position:fixed; inset:0; background:var(--cover); display:flex; flex-direction:column;
  justify-content:center; align-items:center; z-index:9999; text-align:center; padding:var(--sp-5);
  overflow-y:auto; transition:background-color var(--mo-3);
}
/* S1-02 — bedieningsrij rechtsboven, --sp-4 van de rand, knoppen 34×34
   (v1.1: was 32×32, zie G-01). */
.theme-toggle-container{ position:absolute; top:var(--sp-4); right:var(--sp-4); z-index:20; display:flex; gap:var(--sp-2); align-items:center; }
#lang-btn-start, #lang-btn-tiles{ font-family:'Inter',sans-serif; font-weight:700; font-size:12px; }
#init-overlay .start-theme-btn, #tiles-page .start-theme-btn{
  background:transparent; border:1px solid transparent; width:34px; height:34px; border-radius:var(--r-sm);
  display:flex; align-items:center; justify-content:center; padding:0;
  color:var(--muted); cursor:pointer;
  transition:background-color var(--mo-1) var(--ease), color var(--mo-1) var(--ease);
}
@media (hover:hover){ #init-overlay .start-theme-btn:hover, #tiles-page .start-theme-btn:hover{ background:var(--surface2); color:var(--text); } }
#init-overlay .start-theme-btn:active, #tiles-page .start-theme-btn:active{ transform:scale(.96); }
/* "Uitleg"-knop (v0.49.0) — zelfde knop, maar met tekstlabel ernaast zodat
   de rondleiding/uitleg beter opvalt tussen de icoon-knoppen. */
#tiles-page .start-theme-btn--labeled{
  width:auto; border-radius:999px; padding:0 var(--sp-4) 0 var(--sp-3); gap:var(--sp-2); font-size:.82rem; font-weight:700;
}
.start-theme-btn--labeled .stb-ic{ display:flex; width:18px; height:18px; }
.start-theme-btn--labeled .stb-ic svg{ width:100%; height:100%; }
.start-theme-btn--labeled .stb-label{ white-space:nowrap; }

/* Tegel-overzicht (sinds v0.17.5) — tussenscherm tussen coverpagina en een
   module, zelfde fixed-fullscreen-recept als #init-overlay maar een eigen,
   lagere z-index (ze zijn mutueel exclusief via display:none/flex, maar
   nooit gelijk aan elkaar laten zijn is veiliger). Top-uitgelijnd i.p.v.
   verticaal gecentreerd (zoals #init-overlay) — een lijst van 9 groepen/17
   tegels past niet altijd op één scherm, dus overflow-y:auto i.p.v. één
   gecentreerde kaart. */
#tiles-page{
  position:fixed; inset:0; background:var(--canvas); z-index:9998;
  display:flex; flex-direction:column; align-items:center;
  padding:var(--sp-8) var(--sp-5) var(--sp-7); overflow-y:auto; transition:background-color var(--mo-3);
}
/* S2-09 — hairline onder de bedieningsrij, zoals elke submodule.
   v0.86.1 (gebruikersmelding: "de lijn blijft hangen/drift mee bij het
   scrollen") — was `position:fixed`, dus vast t.o.v. de VIEWPORT, terwijl
   `.theme-toggle-container` (de iconenrij erboven) `position:absolute` is
   en dus WEL met de tegelinhoud meescrolt. Dat verschil liet de lijn
   permanent zichtbaar blijven staan (PC) resp. los van de iconenrij lijken
   te "reizen" (mobiel) zodra je scrolt. Nu ook `position:absolute` —
   zelfde `#tiles-page`-containing-block als de iconenrij, dus beide
   scrollen voortaan samen weg. */
#tiles-page::before{
  content:''; position:absolute; top:64px; left:0; right:0; height:1px;
  background:var(--border); z-index:11; pointer-events:none;
}
/* Ambient gloed-blobs (sinds de dashboard-herstijling, gebruikersverzoek:
   "de referentiestijl is de gecentreerde glow-esthetiek van het
   startscherm") — hergebruikt #init-overlay .welcome-bg-decor/.blob/
   @keyframes blob-float (selectors verbreed naar #tiles-page, zie verderop
   in dit bestand) i.p.v. verdubbeld. */
/* Tegel-grid: geconsolideerd naar 1 tegel per app (8 tegels totaal, was 17
   tegels/9 gegroepeerde rijen) — past daardoor op vrijwel elk scherm zonder
   scrollen, dus geen aparte .tile-group/.tile-group-header-indeling meer
   nodig (elke tegel draagt zijn eigen naam al). Vaste kolomaantal per
   breakpoint i.p.v. auto-fill — voorspelbaar. **3 kolommen op groot scherm
   (was 4, gebruikersverzoek: "misschien 3x3" — 9 tegels vormen zo een
   nette 3x3-rooster i.p.v. 4+4+1) geeft bredere tegels, dus meer ruimte
   voor de omschrijving vóór de 3-regel-afkap (zie .tile-desc verderop).**
   De oude 700-1000px-tussenstap (ook 3 kolommen) is nu overbodig, want dat
   is al de standaardwaarde. */
/* Zichtbare MIDI-statustekst op het tegel-overzicht (sinds v0.20.19), DESKTOP-
   ONLY sinds de bugfix-ronde ná v0.96.3 (zie de @media hieronder + de
   HTML-toelichting bij #tiles-midi-status). `position:absolute` i.p.v. de
   oude normale-document-flow-regel eronder: op gebruikersverzoek + mockup nu
   op DEZELFDE hoogte als .theme-toggle-container (de iconenrij), gecentreerd
   op de pagina i.p.v. rechts uitgelijnd — vandaar left:50%+translateX i.p.v.
   die rij zijn eigen right-uitlijning. `#tiles-page` (position:fixed) is de
   containing block, dus dit blijft binnen de al gereserveerde top-padding
   staan, geen effect op de tegel-inhoud eronder. */
#tiles-midi-status{
  position:absolute; top:var(--sp-4); left:50%; transform:translateX(-50%); z-index:15;
  display:flex; align-items:center; gap:var(--sp-2);
  padding:var(--sp-2) var(--sp-4); background:var(--surface);
  border:1px solid var(--border); border-radius:999px;
  font-size:.78rem; color:var(--muted); font-family:'JetBrains Mono',monospace;
  cursor:pointer;
}
#tiles-midi-status:hover{ border-color:var(--accent); color:var(--text); }
#tiles-midi-caret{ font-size:.8rem; opacity:.6; margin-left:1px; }
#tiles-midi-status:hover #tiles-midi-caret{ opacity:1; }
#tiles-midi-dot{
  width:8px; height:8px; border-radius:50%; background:var(--muted); opacity:.5;
  transition:background-color var(--mo-2) var(--ease), opacity var(--mo-2) var(--ease); flex-shrink:0;
}
#tiles-midi-dot.is-known{ background:var(--ok); opacity:1; }
#tiles-midi-dot.is-new{ background:var(--off); opacity:1; }

/* MIDI-paneel (v0.51.0) — zelfde overlay-/kaart-opzet als #credits-modal. */
#midi-panel-overlay{
  position:fixed; inset:0; z-index:10500; display:none;
  align-items:center; justify-content:center; padding:var(--sp-5);
  background:rgba(0,0,0,.6); backdrop-filter:blur(2px);
}
#midi-panel-overlay.visible{ display:flex; }
#midi-panel{
  background:var(--surface); color:var(--text); border:1px solid var(--border);
  border-radius:var(--r-md); padding:var(--sp-5) var(--sp-5); max-width:460px; width:100%;
  max-height:85vh; overflow-y:auto; box-shadow:0 24px 64px rgba(0,0,0,.5); position:relative;
}
#midi-panel h2{ font-size:1.1rem; margin:0 0 var(--sp-4); padding-right:var(--sp-5); }
#midi-panel-close{
  position:absolute; top:16px; right:16px; background:transparent; border:0;
  color:var(--muted); font-size:1.1rem; cursor:pointer; line-height:1; padding:var(--sp-1);
}
#midi-panel-close:hover{ color:var(--text); }
.midi-panel-sec{ margin:0 0 var(--sp-4); }
.midi-panel-sec:last-child{ margin-bottom:0; }
.midi-panel-sec h3{ font-size:.9rem; margin:0 0 var(--sp-2); }
.midi-panel-conn{ font-size:.86rem; color:var(--muted); margin:0; }
.midi-panel-conn.is-on{ color:var(--ok); }
.midi-panel-note{ font-size:.84rem; color:var(--muted); line-height:1.55; margin:0; }
.midi-panel-recalib{
  margin-top:var(--sp-3); font:inherit; font-size:.8rem; font-weight:600; padding:var(--sp-2) var(--sp-3);
  border-radius:var(--r-sm); cursor:pointer;
  background:var(--surface2); color:var(--text); border:1px solid var(--border);
}
.midi-panel-recalib:hover{ border-color:var(--accent); }
.midi-panel-recalib.active{ color:var(--accent-ink); background:var(--accent); border-color:transparent; }
/* "Virtual Piano Sound" (2026-09-12) — knop naast "Opnieuw kalibreren",
   klapt bij een klik de aan/uit-knoppen + volumeslider eronder open. */
.midi-panel-btn-row{ display:flex; flex-wrap:wrap; gap:var(--sp-2); margin-top:var(--sp-3); }
.midi-panel-btn-row .midi-panel-recalib{ margin-top:0; }
.midi-panel-vps-body{ margin-top:var(--sp-3); display:flex; flex-direction:column; gap:var(--sp-2); }
/* "Sessie"-groep (v0.83.0, instellingenlade-herziening) — Auto/Meerkeuze/
   Sessielengte en per module Richting/Vingerzetting e.d. worden knoppen die
   van stand wisselen bij een klik, i.p.v. elk hun eigen rij met N losse
   opties. Zelfde look-and-feel als `.midi-panel-recalib` hierboven (bewust
   hergebruikt, niet een nieuwe stijl ernaast). Vast 3-koloms grid: een
   zichtbaar `.combo-body`-paneel (bijv. Bedenktijd) spant altijd de volle
   breedte, dus alles ERNA wordt door CSS-grid vanzelf naar een verse regel
   geduwd — `SettingsBuilder._updateComboSpans()` zet daarnaast per geval de
   laatste, alleenstaande knop van zo'n verse regel ook op volle breedte. */
.combo-row{ display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:var(--sp-2); width:100%; }
.combo-btn{
  font:inherit; font-size:.8rem; font-weight:600; padding:var(--sp-2) var(--sp-3);
  border-radius:var(--r-sm); cursor:pointer; background:var(--surface2); color:var(--text);
  border:1px solid var(--border); display:flex; align-items:center; justify-content:center; gap:6px;
  min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
/* v0.83.1: de labeltekst zit in een <span> (voor _buildCycleBtn's render()) —
   een flex-kind krijgt van zichzelf min-width:auto (negeert de ellipsis van
   z'n ouder hierboven), dus zonder deze regel liep lange tekst (bijv.
   Ritme's "Metronome accent"/"Alleen metronoom" op mobiel) buiten de knop
   i.p.v. netjes af te breken met "…". */
.combo-btn span{ min-width:0; overflow:hidden; text-overflow:ellipsis; }
.combo-btn:hover{ border-color:var(--accent); }
.combo-btn.active{ color:var(--accent-ink); background:var(--accent); border-color:transparent; }
.combo-btn .aa-icon{ width:15px; height:15px; flex-shrink:0; }
.combo-body{
  grid-column:1 / -1; border:1px solid var(--accent); border-radius:var(--r-md);
  padding:var(--sp-3) var(--sp-4); background:var(--accent-soft);
  display:flex; flex-direction:column; gap:var(--sp-2);
}
.combo-body[hidden]{ display:none; }
.combo-body .slider-row{ display:flex; align-items:center; gap:var(--sp-3); }
.combo-body .slider-row .lbl{ display:flex; align-items:center; gap:6px; font-size:.8rem; font-weight:600; color:var(--text); white-space:nowrap; }
.combo-body .slider-row input[type=range]{ flex:1; }
.midi-panel-vps-vol{ display:flex; align-items:center; gap:var(--sp-2); flex-wrap:wrap; }
.midi-panel-vps-vol .auto-delay-slider{ flex:1 1 120px; max-width:160px; }
/* BL-2.2 — "Aangepast", de 5e knop in de keyboardgrootte-rij (v0.76.8: was
   een los invoervak + "Instellen"-knop naast de rij). `.opt-btn` geeft 'm
   dezelfde vorm/kleur als de vaste knoppen (25/49/61/88) in beide standen —
   dit blok overschrijft alleen wat een `<input>` anders nodig heeft dan een
   `<button>`: vaste breedte (i.p.v. flex-grow), tekstcursor, geen
   spinner-pijltjes, en dezelfde accent-focusrand als elders in de app. */
.opt-btn.midi-panel-custom-input{
  width:88px; text-align:center; cursor:text;
  -moz-appearance:textfield;
}
.opt-btn.midi-panel-custom-input::-webkit-outer-spin-button,
.opt-btn.midi-panel-custom-input::-webkit-inner-spin-button{ -webkit-appearance:none; margin:0; }
.opt-btn.midi-panel-custom-input:focus{ outline:none; border-color:var(--accent); }
.midi-panel-kbds{ list-style:none; margin:0; padding:0; }
.midi-panel-kbd{
  display:flex; align-items:center; gap:var(--sp-2); padding:var(--sp-2) 0;
  border-bottom:1px solid var(--border); font-size:.84rem;
}
.midi-panel-kbd:last-child{ border-bottom:0; }
.midi-panel-kbd-name{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.midi-panel-kbd.is-active .midi-panel-kbd-name{ color:var(--ok); }
.midi-panel-kbd-range{ color:var(--muted); font-family:'JetBrains Mono',monospace; font-size:.78rem; }
.midi-panel-forget{
  background:transparent; border:0; color:var(--muted); cursor:pointer;
  font-size:.95rem; line-height:1; padding:var(--sp-1) var(--sp-2); flex-shrink:0;
}
.midi-panel-forget:hover{ color:var(--err); }
/* Hero Banner (v0.90.0, Plan_van_Aanpak_Layout_Onboarding-v3) — verving het
   wegklikbare "nieuw hier?"-strookje (v0.49.0-v0.89.x). Regel 1 (welkom +
   streak + Muziektheorie-CTA) is permanent; Regel 2 (zelftest-uitnodiging)
   alleen tot pm_level_assessed gezet is — zie App._maybeShowHelpHint(). */
#help-hint{
  /* Bugfix (gebruikersmelding 2026-09-20): stond op een hardcoded 1180px,
     100px breder dan #tiles-grid's var(--w-wide) (1080px) — beide zijn
     directe kinderen van #tiles-page (align-items:center), dus elk apart
     gecentreerd; het breedteverschil duwde de linkerrand van deze balk
     zichtbaar verder naar links dan de tegels/sectiekoppen eronder. Nu
     dezelfde var(--w-wide) als #tiles-grid, zodat beide randen gelijk lopen. */
  position:relative; z-index:10; width:100%; max-width:var(--w-wide); margin:0 0 var(--sp-4);
  display:flex; flex-direction:column; gap:var(--sp-2);
}
#help-hint[hidden]{ display:none; }
#help-hint .hero-row1{
  display:flex; align-items:center; gap:var(--sp-3); flex-wrap:wrap;
  padding:var(--sp-2) var(--sp-1); font-size:.86rem; color:var(--text);
}
#help-hint .hero-welcome{ font-weight:600; }
#help-hint .hero-streak{ color:var(--muted); }
#help-hint .hero-cta-theory{
  margin-left:auto; font:inherit; font-size:.82rem; font-weight:700;
  padding:var(--sp-1) var(--sp-3); border-radius:999px;
  background:var(--surface2); color:var(--accent); border:1px solid var(--accent); cursor:pointer;
}
#help-hint .hero-cta-theory:hover{ background:color-mix(in srgb, var(--accent) 14%, transparent); }
/* Mobiel (gebruikersverzoek 2026-09-20): margin-left:auto duwt de CTA op
   desktop naar de rechterkant van dezelfde regel als Welkom/streak — prima
   daar, maar op mobiel past de knop meestal niet meer op die regel
   (flex-wrap:wrap) en oogt dan als een los, rechts zwevend knopje op zijn
   eigen regel. Links uitlijnen op mobiel, gewoon onder Welkom/streak. */
@media (max-width:560px){
  #help-hint .hero-cta-theory{ margin-left:0; }
}
#help-hint .hero-row2{
  display:flex; align-items:center; gap:var(--sp-3); flex-wrap:wrap;
  padding:var(--sp-3) var(--sp-4); background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-md); font-size:.86rem; color:var(--text);
}
#help-hint .hero-assess-text{ flex:1 1 200px; }
#help-hint .help-hint-cta{
  font:inherit; font-size:.82rem; font-weight:700; padding:var(--sp-1) var(--sp-3); border-radius:999px;
  background:transparent; color:var(--accent); border:1px solid var(--accent); cursor:pointer;
}
#help-hint .help-hint-cta:hover{ background:color-mix(in srgb, var(--accent) 14%, transparent); }

/* Eenmalige oefen-hint boven het speelveld (v0.90.0, Plan_van_Aanpak_
   InModule_Onboarding, Pijler 2.3) — zelfde rustige opzet als #help-hint's
   Regel 2. */
#exercise-hint{
  max-width:1180px; margin:0 0 var(--sp-3); padding:var(--sp-2) var(--sp-4);
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md);
  font-size:.84rem; color:var(--muted);
  /* Bugfix-ronde ná v0.96.4 (kruisje-patroon app-breed) — kreeg er een
     .help-hint-x-sluitknop bij, dus display:flex zoals #theory-hint/
     .tool-hint hieronder (tekst+knop naast elkaar) i.p.v. kaal blokelement. */
  display:flex; align-items:center; gap:var(--sp-3);
}
#exercise-hint[hidden]{ display:none; }

/* Wegklikbare hintstroken (v0.90.0) — theorieles (#theory-hint) en de
   Virtuele Piano/Metronoom-hint (.tool-hint), beide "eenmalig" via hun eigen
   localStorage-vlag (zie theory-lesson-ui.js resp. App._maybeShowToolHint). */
#theory-hint, .tool-hint{
  display:flex; align-items:center; gap:var(--sp-3);
  margin:0 0 var(--sp-4); padding:var(--sp-2) var(--sp-4);
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md);
  font-size:.84rem; color:var(--text);
}
.tool-hint:empty{ display:none; }
#theory-hint .help-hint-text, .tool-hint .help-hint-text, #exercise-hint .exercise-hint-text{ flex:1 1 200px; }
#theory-hint .help-hint-x, .tool-hint .help-hint-x, #exercise-hint .help-hint-x, #circle-hint .help-hint-x{
  background:transparent; border:0; color:var(--muted); font-size:1rem; cursor:pointer;
  line-height:1; padding:var(--sp-1); flex-shrink:0;
}
#theory-hint .help-hint-x:hover, .tool-hint .help-hint-x:hover, #exercise-hint .help-hint-x:hover, #circle-hint .help-hint-x:hover{ color:var(--text); }

/* Zichtbare feedback-ingang onderaan het tegel-overzicht (v0.49.0) */
#tiles-feedback-link{
  margin:var(--sp-5) 0 var(--sp-1); padding:var(--sp-2) var(--sp-4); font:inherit; font-size:.82rem; font-weight:600;
  background:transparent; border:1px solid var(--border); border-radius:999px;
  color:var(--muted); cursor:pointer;
}
#tiles-feedback-link:hover{ color:var(--text); border-color:var(--accent); }
/* #tiles-grid — HERZIEN v0.90.0 ("layout E"): een verticale stapel van drie
   gelijkwaardige, gelabelde zone-blokken (zie TilesUI._buildZones in
   js/tiles-ui.js), alle drie in dezelfde geharmoniseerde kaartgrootte (was
   nog een aparte, grotere .tile-top-maat vóór v0.90.0):
   - kopje "Kernoefeningen" + .tiles-grid-practice  3-koloms kernraster (3×2)
   - kopje "Kennis & Inzicht" + .tiles-row-depth    Muziektheorie · Kwintencirkel
   - kopje "Hulpmiddelen & Voortgang" + .tiles-row-extra
                         Mijn Voortgang · Virtuele Piano · Metronoom
                         (Vooruit Lezen is sinds v0.86.0 een niet-gerenderde
                         inert-tegel, zie TilesUI._buildZones). */
#tiles-grid{
  position:relative; z-index:10; width:100%; max-width:var(--w-wide);
  display:flex; flex-direction:column; gap:var(--sp-4); padding-bottom:var(--sp-5);
}
/* S2-08 — sectiekop: Fraunces 20px/600, marge --sp-6 boven / --sp-4 onder. */
.tiles-section{
  font-family:'Fraunces', serif; font-weight:600; font-size:20px;
  color:var(--text); letter-spacing:-.01em;
  margin:var(--sp-6) 0 var(--sp-4);
}
.tiles-section:first-child{ margin-top:0; }
/* S2-07 — sectielijn onder de kop. */
.tiles-section-ln{
  height:1.5px; width:100%; border:0; margin:calc(var(--sp-4) * -1) 0 var(--sp-4);
  background:linear-gradient(to right, var(--accent), transparent 78%);
}
/* S2-11 — oefentegels 3 kolommen, gat --sp-3; top-3 3 kolommen, gat --sp-4. */
.tiles-grid-practice{ display:grid; grid-template-columns:1fr; gap:var(--sp-3); }
.tiles-row{ display:grid; gap:var(--sp-4); grid-template-columns:1fr; }
@media (min-width:820px){
  .tiles-grid-practice{ grid-template-columns:repeat(2, minmax(0,1fr)); }
  .tiles-row.tiles-cols-2, .tiles-row.tiles-cols-3{ grid-template-columns:repeat(2, minmax(0,1fr)); }
}
@media (min-width:1120px){
  .tiles-grid-practice{ grid-template-columns:repeat(3, minmax(0,1fr)); }
  .tiles-row.tiles-cols-3{ grid-template-columns:repeat(3, minmax(0,1fr)); }
}

/* T-02 — tegel/modulekaart/theorierij. Rust: alleen rand, geen schaduw, geen
   gloed. Hover (achter @media hover:hover, T-06): −3px + rand --accent + --sh-2.
   Ingedrukt: −1px scale(.98) + --sh-1. */
.tile-btn{
  position:relative; display:flex; flex-direction:row; align-items:center;
  gap:var(--sp-3);
  background:var(--surface);
  border:1px solid var(--border); border-radius:var(--r-md);
  padding:var(--sp-3) var(--sp-4); text-align:left; cursor:pointer;
  transition:transform var(--mo-1) var(--ease), border-color var(--mo-1) var(--ease), box-shadow var(--mo-1) var(--ease);
}
.tile-text{ display:flex; flex-direction:column; gap:2px; min-width:0; flex:1; }
@media (hover:hover){
  .tile-btn:hover{ transform:translateY(-3px); border-color:var(--accent); box-shadow:var(--sh-2); }
}
.tile-btn:active{ transform:translateY(-1px) scale(.98); box-shadow:var(--sh-1); }

/* S2-02 — oefentegel: drager 44×44 --r-sm / tekening 34, titel 13,5px/600,
   omschrijving 11,5px --muted 2 regels. */
.tile-practice{ min-height:0; }
.tile-practice .tile-icon-wrap{ width:44px; height:44px; }
.tile-practice .tile-label{ font-size:13.5px; }
.tile-practice .tile-desc{ font-size:11.5px; -webkit-line-clamp:2; }

/* 'depth' — Muziektheorie + Kwintencirkel, brede rij. Sinds v0.90.0 dezelfde
   geharmoniseerde maat als .tile-practice/.tile-extra (was tot dan een
   grotere, staande kaart met accentrand: .tile-top — zie
   Plan_van_Aanpak_Layout_Onboarding-v3). */
.tile-depth{ min-height:0; padding:var(--sp-3) var(--sp-4); }
.tile-depth .tile-icon-wrap{ width:44px; height:44px; }
.tile-depth .tile-label{ font-size:13.5px; }
.tile-depth .tile-desc{ font-size:11.5px; -webkit-line-clamp:2; }

/* 'extra' — Mijn Voortgang, Virtuele Piano, Metronoom + de inerte Vooruit
   Lezen-tegel, brede rij. */
.tile-extra{ min-height:0; padding:var(--sp-3) var(--sp-4); }
.tile-extra .tile-icon-wrap{ width:44px; height:44px; }
.tile-extra .tile-label{ font-size:13.5px; }
.tile-extra .tile-desc{ font-size:11.5px; -webkit-line-clamp:2; }

/* Inert-tegel (Vooruit Lezen) staat sinds v0.60.3 in de "Extra"-rij naast
   Piano — dezelfde .tile-extra-maat, alleen gedimd (.tile-disabled). */
/* Icoon-cirkel — HERZIEN (Neon-herstijling, v0.18.0): niet langer een
   zelf-getekend wit SVG-icoon op een aparte accent-kleurverloop-cirkel —
   de negen PianoICO_Library-PNG's dragen hun neon-cirkel-badge AL
   ingebakken (cyaan/magenta-lijnwerk op een eigen donkere ronde
   achtergrond, zie TILE_ICONS in tiles-ui.js), dus geen tweede cirkel er
   omheen meer nodig (dat gaf eerder een dubbele-cirkel-effect tijdens het
   testen). `.tile-icon-wrap` is nu puur een maat-container; de gloed komt
   van een `drop-shadow`-filter op de `<img>` zelf i.p.v. een
   `box-shadow` op een gekleurd vlak — een `drop-shadow` volgt de
   ronde/transparante vorm van de PNG, een `box-shadow` zou een vierkante
   gloed achter de cirkel tonen. */
/* Pictogramdrager (3.3) — de drager staat in CSS, niet in de SVG. */
.tile-icon-wrap{ display:grid; place-items:center; flex-shrink:0; }
.rn-ico{
  display:grid; place-items:center; flex:0 0 auto;
  background:var(--icon-disc); border-radius:var(--r-sm);
  filter:drop-shadow(0 1px 5px var(--icon-glow));
}
.rn-ico svg{ display:block; }
.tile-icon-wrap svg{ pointer-events:none; }
.tile-label{ font-weight:600; color:var(--text); font-family:'Inter',sans-serif; line-height:1.35; }
.tile-desc{
  color:var(--muted); line-height:1.42;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}
/* Badge gecentreerd ONDERAAN (sinds v0.18.3, was de rechterbovenhoek sinds
   de dashboard-herstijling in v0.17.6) — enige stuk dat overleefde uit een
   verder teruggedraaide tegel-herontwerpronde (zie .tile-btn hierboven).
   `position:absolute` + `left:50%`/`transform` i.p.v. de eerdere
   `margin-top:auto`-flexbox-aanpak uit die ronde, want `.tile-btn` is weer
   een horizontale rij (icoon+tekst naast elkaar), niet meer een kolom
   waarin de badge vanzelf onderaan terechtkomt. De kleurgecodeerde vulling
   (groen/amber) uit v0.17.6 is op gebruikersverzoek destijds al
   TERUGGEDRAAID naar de rustigere, uniforme outline-stijl uit v0.17.5 —
   alleen de TEKST verschilt nog tussen "MIDI Enabled"/"MIDI Only", geen
   apart gevuld/solid-kleurtje meer. */
.tile-badge{
  position:absolute; bottom:var(--sp-2); left:50%; transform:translateX(-50%);
  display:inline-block; padding:2px var(--sp-2); border-radius:var(--r-pill); font-size:10.5px; font-weight:600;
  letter-spacing:.12em; text-transform:uppercase; font-family:'JetBrains Mono',monospace;
  color:var(--accent); border:1px solid var(--accent); background:transparent;
  white-space:nowrap;
}
.tile-badge-construction{ color:var(--muted); border-color:var(--muted); background:transparent; }
/* v0.83.5 (gebruikersverzoek) — op de brede `.tile-extra`-rij (Vooruit
   Lezen) viel de onderaan-gecentreerde badge over de omschrijvingstekst
   heen; een rechtsboven-hoek past hier beter, want de kaart is hier
   horizontaal (icoon+tekst naast elkaar), niet verticaal. */
.tile-extra .tile-badge-construction{
  position:absolute; top:var(--sp-3); right:var(--sp-4); bottom:auto; left:auto; transform:none;
}
/* .tile-streak (reeks-pil, Mijn Voortgang) en .tile-theory-cta ("Hervat
   les"-pil, Muziektheorie) zijn vervallen sinds v0.92.0 (Plan_van_Aanpak_
   Onboarding_en_Kernoefeningen §1.A/§1.B) — allebei stonden ze dubbel met
   de hero banner (zie App._maybeShowHelpHint, app-core.js), die nu de
   enige plek is voor streak + theorie-vervolgknop. */
/* Vooruit Lezen-tegel (sinds v0.17.5 terug als tegel, was tot en met
   v0.17.4 volledig uit de navigatie verborgen): blijft een gewone, klikbare
   <button> — de klik doet alleen niets (zie TilesUI/App), de grijze/
   gedimde stijl communiceert dat. */
.tile-btn.tile-disabled{ filter:grayscale(1); opacity:.55; cursor:default; }
.tile-btn.tile-disabled:hover{ transform:none; border-color:var(--border); box-shadow:none; }

/* S1-01 — geen gloed-blobs, geen radiale verlopen op cover en tegel-overzicht. */
#init-overlay .welcome-bg-decor, #tiles-page .welcome-bg-decor,
#init-overlay .blob, #tiles-page .blob{ display:none; }

#init-overlay .welcome-content{ position:relative; z-index:10; display:flex; flex-direction:column; align-items:center; gap:var(--sp-7); max-width:600px; width:100%; }

/* S1-03 / T-03 — de merkkaart IS de startknop. Vlak --surface (het helderste
   vlak op het scherm), --r-lg, padding --sp-7 --sp-8, gat --sp-4, --sh-3. */
#init-overlay .brand-launch-btn{
  display:flex; flex-direction:column; align-items:center; gap:var(--sp-4);
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg);
  padding:var(--sp-7) var(--sp-8); cursor:pointer; position:relative;
  box-shadow:var(--sh-3);
  transition:transform var(--mo-1) var(--ease), border-color var(--mo-1) var(--ease), box-shadow var(--mo-1) var(--ease);
}
@media (hover:hover){
  #init-overlay .brand-launch-btn:hover{ transform:translateY(-3px); border-color:var(--accent); }
}
#init-overlay .brand-launch-btn:active{ transform:translateY(-1px) scale(.985); box-shadow:var(--sh-2); }

/* Cover-merkteken (B-08 / S1-04) — merk_klavier op 120px, GEEN drager,
   alleen een zachte gloed via drop-shadow. */
.brand-mark-lg{
  display:flex; align-items:center; justify-content:center;
  filter:drop-shadow(0 3px 16px var(--icon-glow));
}
.brand-mark-lg svg{ width:120px; height:120px; display:block; }

/* S1-05 / Root_Note_Merkteken.html §2 — cover-titel: Fraunces 600, 56px,
   regelafstand 1,02, letterafstand −.025em, font-variation-settings:'opsz'
   144 (op displaymaat duidelijk sierlijker; zonder deze regel zet de browser
   opsz op de tekstgrootte). Effen --text, GEEN verlooptekst.
   VASTE waarde i.p.v. de vroegere `clamp(38px, 6vw, 56px)` (bugfix-ronde ná
   v0.96.3, Stap 1, gebruikersmelding: logo/kaart-verhouding klopte niet op
   elk scherm) — de kaart eronder (.brand-launch-btn) heeft geen eigen
   `width`, dus hangt zijn breedte puur af van de titel-tekstbreedte; een
   doorlopende `vw`-schaal liet die breedte (en dus de kaartverhouding)
   met de vensterbreedte meeschuiven, terwijl de hoogte (vaste 120px-logo)
   grotendeels gelijk bleef — een brede/platte kaart op desktop tegenover
   een smallere/hogere op mobiel. Nu twee vaste waarden op dezelfde
   @media(max-width:560px)-knip als de rest van deze pagina, i.p.v. een
   doorlopende schaal die bij ELKE tussenliggende vensterbreedte weer een
   andere verhouding gaf. */
#init-overlay .title-group{
  display:flex; flex-direction:column; align-items:center; gap:var(--sp-2);
}
#init-overlay .main-title{
  font-family:'Fraunces',serif; font-size:56px; font-weight:600;
  color:var(--text); line-height:1.02; letter-spacing:-.025em; margin:0;
  font-variation-settings:'opsz' 144;
}
/* S1-06 / Merkteken.html §2 — ondertitel: JetBrains Mono 600, 11px, .19em,
   hoofdletters, --muted. Bewust strak-technisch tegen de sierlijke titel in;
   dat contrast draagt het ontwerp. */
#init-overlay .sub-title-premium{
  font-family:'JetBrains Mono',monospace; font-size:11px; color:var(--muted);
  letter-spacing:.19em; text-transform:uppercase; font-weight:600; margin:0;
}

#init-overlay .start-meta{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-2); }
/* S1-07 — voettekst onderaan, 11,5px, --faint. */
#init-overlay .version-tag{ font-size:11.5px; color:var(--faint); font-family:'JetBrains Mono',monospace; }
.creator-credit{ color:var(--faint); font-size:11.5px; font-weight:500; letter-spacing:.3px; }

/* "Meer info"-modal (sinds v0.20.23) — bevat o.a. de CC BY 3.0-
   naamsvermelding voor de standaard-pianosamples (zie audio-engine.js
   DEFAULT_SAMPLE_NOTES). Bewust NIET op de homepage/#init-overlay (was
   eerder daar geplaatst, op gebruikersverzoek verplaatst naar een apart,
   minder prominent info-knopje op het tegel-overzicht — zie
   #info-btn-tiles). z-index hoger dan alle bestaande overlays (tiles-page
   9998, welcome-bg-decor 9999, update-banner 10001, dev-watermark 10002)
   zodat een bewust geopende modal altijd bovenop ligt. */
#credits-modal-overlay{
  position:fixed; inset:0; z-index:10500; display:none;
  align-items:center; justify-content:center; padding:var(--sp-5);
  background:rgba(0,0,0,.6); backdrop-filter:blur(2px);
}
#credits-modal-overlay.visible{ display:flex; }
#credits-modal{
  background:var(--surface); color:var(--text); border:1px solid var(--border);
  border-radius:var(--r-md); padding:var(--sp-5) var(--sp-5); max-width:600px; width:100%;
  max-height:85vh; overflow-y:auto;
  box-shadow:0 24px 64px rgba(0,0,0,.5); position:relative;
}
#credits-modal h2{ font-size:1.1rem; margin:0 0 var(--sp-4); }
#credits-modal h3{ font-size:.95rem; margin:0 0 var(--sp-2); }
#credits-modal p{ font-size:.9rem; color:var(--muted); line-height:1.6; margin:0 0 var(--sp-3); }
#credits-modal a{ color:inherit; text-decoration:underline; }
/* Gegevens & reset (v0.28.0) */
.credits-data-section{
  margin-top:var(--sp-4); padding-top:var(--sp-4); border-top:1px solid var(--border);
}
.credits-data-section p{ font-size:.82rem; }
.credits-data-buttons{ display:flex; flex-direction:column; gap:var(--sp-2); margin-top:var(--sp-3); }
.credits-data-buttons button{
  font:inherit; font-size:.85rem; font-weight:600; padding:var(--sp-2) var(--sp-4);
  border-radius:var(--r-sm); cursor:pointer;
  background:var(--surface2); color:var(--text); border:1px solid var(--border);
  transition:border-color var(--mo-1), background var(--mo-1);
}
.credits-data-buttons button:hover{ border-color:var(--accent); background:var(--surface2); }
.credits-data-buttons .credits-data-danger{ color:var(--err); border-color:var(--err-soft); }
.credits-data-buttons .credits-data-danger:hover{ border-color:var(--err); background:var(--err-soft); }
/* Cloud Sync-blok (v0.30.0) — sinds v0.30.1 sync + back-up onder één kop */
.credits-data-manual{ font-size:.8rem; color:var(--muted); margin:var(--sp-4) 0 var(--sp-2); }
.sync-block{ margin:var(--sp-2) 0; }
.sync-intro{ font-size:.82rem; color:var(--muted); margin:0 0 var(--sp-3); }
.sync-status{ font-size:.84rem; color:var(--text); margin:0 0 var(--sp-2); }
.sync-warn{ font-size:.82rem; color:var(--off); margin:0 0 var(--sp-1); }
.sync-substatus{ font-size:.76rem; color:var(--muted); margin:0 0 var(--sp-2); }
.sync-error{ font-size:.8rem; color:var(--err); margin:0 0 var(--sp-1); }
.sync-btn{
  font:inherit; font-size:.85rem; font-weight:600; padding:var(--sp-2) var(--sp-4);
  border-radius:var(--r-sm); cursor:pointer;
  background:var(--surface2); color:var(--text); border:1px solid var(--border);
  transition:border-color var(--mo-1), background var(--mo-1);
}
.sync-btn:hover{ border-color:var(--accent); background:var(--surface2); }
.sync-btn-primary{ width:100%; color:var(--accent); border-color:var(--accent); }
.sync-btn-row{ display:flex; gap:var(--sp-2); }
.sync-btn-row .sync-btn{ flex:1; }
.sync-btn-off{ color:var(--muted); }
#credits-modal-close{
  position:absolute; top:12px; right:12px; background:transparent; border:none;
  color:var(--muted); font-size:1.2rem; cursor:pointer; line-height:1; padding:var(--sp-1);
}
#credits-modal-close:hover{ color:var(--text); }

/* Help-modal voortgangsdashboard (Fase 5.3-vervolg, sinds v0.23.0) — zelfde
   overlay-/kaart-opzet als #credits-modal hierboven, iets breder omdat de
   uitleg langer is. */
#progress-help-overlay{
  position:fixed; inset:0; z-index:10500; display:none;
  align-items:center; justify-content:center; padding:var(--sp-5);
  background:rgba(0,0,0,.6); backdrop-filter:blur(2px);
}
#progress-help-overlay.visible{ display:flex; }
#progress-help-modal{
  background:var(--surface); color:var(--text); border:1px solid var(--border);
  border-radius:var(--r-md); padding:var(--sp-5) var(--sp-5); max-width:860px; width:100%;
  max-height:calc(100vh - 48px); overflow-y:auto;
  box-shadow:0 24px 64px rgba(0,0,0,.5); position:relative;
}
/* v0.65.7: secties in twee kolommen op een breed scherm (geen scrollen). */
@media (min-width:820px){
  #progress-help-body{
    display:grid; grid-template-columns:1fr 1fr; gap:0 var(--sp-6); align-items:start;
  }
  #progress-help-body > h2,
  #progress-help-body > .progress-help-foot{ grid-column:1 / -1; }
  .proghelp-sec h3{ margin-top:var(--sp-4); }
}
#progress-help-close{
  position:absolute; top:12px; right:12px; background:transparent; border:none;
  color:var(--muted); font-size:1.2rem; cursor:pointer; line-height:1; padding:var(--sp-1);
}
#progress-help-close:hover{ color:var(--text); }
#progress-help-body h2{ font-family:'Fraunces',serif; font-weight:600; font-size:1.15rem; margin:0 0 var(--sp-4); padding-right:var(--sp-5); }
#progress-help-body h3{ font-size:.86rem; font-weight:700; color:var(--text); margin:var(--sp-4) 0 var(--sp-1); }
#progress-help-body p{ font-size:.86rem; color:var(--muted); line-height:1.55; margin:0; }
#progress-help-body p.progress-help-foot{ margin-top:var(--sp-4); font-size:.76rem; }
#progress-help-body em{ color:var(--accent); font-style:normal; font-weight:600; }

/* Resetten & gegevens wissen (v0.59.0) — zelfde overlay-/kaart-opzet als
   #progress-help-overlay. */
#reset-modal-overlay{
  position:fixed; inset:0; z-index:10600; display:none;
  align-items:center; justify-content:center; padding:var(--sp-5);
  background:rgba(0,0,0,.6); backdrop-filter:blur(2px);
}
#reset-modal-overlay.visible{ display:flex; }
#reset-modal{
  background:var(--surface); color:var(--text); border:1px solid var(--border);
  border-radius:var(--r-md); padding:var(--sp-5) var(--sp-5); max-width:460px; width:100%;
  max-height:calc(100vh - 48px); overflow-y:auto;
  box-shadow:0 24px 64px rgba(0,0,0,.5); position:relative;
}
#reset-modal-close{
  position:absolute; top:12px; right:12px; background:transparent; border:none;
  color:var(--muted); font-size:1.2rem; cursor:pointer; line-height:1; padding:var(--sp-1);
}
#reset-modal-close:hover{ color:var(--text); }
#reset-modal-body h2{ font-family:'Fraunces',serif; font-weight:600; font-size:1.15rem; margin:0 0 var(--sp-3); padding-right:var(--sp-5); }
#reset-modal-body > p.reset-intro{ font-size:.86rem; color:var(--muted); line-height:1.55; margin:0 0 var(--sp-4); }
.reset-more-head{ font-size:.8rem; font-weight:700; color:var(--text); margin:0 0 var(--sp-2); text-transform:uppercase; letter-spacing:.03em; }
.reset-opt{
  display:flex; gap:var(--sp-3); align-items:flex-start; padding:var(--sp-3) var(--sp-3); margin-bottom:var(--sp-2);
  border:1px solid var(--border); border-radius:var(--r-sm); cursor:pointer;
}
.reset-opt:hover{ border-color:var(--muted); }
.reset-opt input{ margin:2px 0 0; flex:0 0 auto; width:16px; height:16px; accent-color:var(--err); cursor:pointer; }
.reset-opt-text{ display:flex; flex-direction:column; gap:2px; }
.reset-opt-label{ font-size:.86rem; font-weight:600; color:var(--text); }
.reset-opt-hint{ font-size:.78rem; color:var(--muted); line-height:1.4; }
.reset-summary{
  margin:var(--sp-4) 0 0; padding:var(--sp-3) var(--sp-4); border-radius:var(--r-sm);
  background:var(--err-soft); border:1px solid var(--err-soft);
}
.reset-summary-head{ font-size:.82rem; font-weight:700; color:var(--err); margin:0 0 var(--sp-2); }
.reset-summary ul{ margin:0; padding-left:var(--sp-4); }
.reset-summary li{ font-size:.84rem; color:var(--text); line-height:1.5; }
.reset-summary .reset-irreversible{ margin:var(--sp-2) 0 0; font-size:.8rem; color:var(--muted); }
.reset-type-row{ margin:var(--sp-4) 0 0; }
.reset-type-row label{ display:block; font-size:.82rem; color:var(--text); margin-bottom:var(--sp-2); }
.reset-type-row input{
  width:100%; box-sizing:border-box; padding:var(--sp-2) var(--sp-3); font-size:.9rem;
  background:var(--canvas); color:var(--text);
  border:1px solid var(--border); border-radius:var(--r-sm);
}
.reset-type-row input:focus{ outline:none; border-color:var(--err); }
.reset-modal-btn-row{ display:flex; gap:var(--sp-3); justify-content:flex-end; margin-top:var(--sp-5); }
.reset-modal-btn-row button{
  padding:var(--sp-2) var(--sp-4); font-size:.86rem; border-radius:var(--r-sm); cursor:pointer;
  border:1px solid var(--border); background:transparent; color:var(--text);
}
.reset-modal-btn-row button.reset-go{
  color:#fff; background:var(--err); border-color:var(--err); font-weight:600;
}
.reset-modal-btn-row button.reset-go:disabled{ opacity:.4; cursor:not-allowed; }
.reset-modal-btn-row button.reset-cancel:hover{ border-color:var(--muted); }
.reset-status{ margin:var(--sp-4) 0 0; font-size:.85rem; line-height:1.5; }
.reset-status.ok{ color:var(--accent); }
.reset-status.err{ color:var(--err); }
.reset-status.busy{ color:var(--muted); }

/* Per-app uitleg-paneel (v0.52.0) — zelfde overlay-/kaart-opzet als
   #progress-help-overlay. */
#modhelp-overlay{
  position:fixed; inset:0; z-index:10500; display:none;
  align-items:flex-start; justify-content:center; padding:var(--sp-5);
  background:rgba(0,0,0,.6); backdrop-filter:blur(2px);
}
#modhelp-overlay.visible{ display:flex; }
#modhelp-modal{
  background:var(--surface); color:var(--text); border:1px solid var(--border);
  border-radius:var(--r-md); padding:0 0 var(--sp-5); max-width:960px; width:100%;
  max-height:calc(100vh - 48px); overflow-y:auto;
  box-shadow:0 24px 64px rgba(0,0,0,.5); position:relative; margin:auto;
}
/* v0.65.7: op een breed scherm de "Modi" en "Belangrijkste instellingen"
   naast elkaar; intro, Niveaus en Tip over de volle breedte. Zo hoeft er
   niet meer gescrold te worden. */
@media (min-width:820px){
  .modhelp-content{
    display:grid; grid-template-columns:1fr 1fr; gap:0 var(--sp-6); align-items:start;
  }
  .modhelp-content > .modhelp-intro,
  .modhelp-content > h3.modhelp-sec,
  .modhelp-content > .modhelp-p,
  .modhelp-content > .modhelp-tip,
  .modhelp-content > .modhelp-theory-link,
  .modhelp-content > .app-credit-foot{ grid-column:1 / -1; }
  .modhelp-block .modhelp-sec{ margin-top:var(--sp-4); }
}
.modhelp-close{
  position:absolute; top:14px; right:14px; background:transparent; border:none;
  color:var(--text); font-size:1.2rem; cursor:pointer; line-height:1; padding:var(--sp-1); z-index:1;
}
.modhelp-close:hover{ opacity:.7; }
/* Kop met de tegel-icoon in een accent-glow-vlak — zelfde "neon"-gevoel als
   het tegel-overzicht (v0.52.1, gebruikersverzoek: uitleg wat aantrekkelijker). */
.modhelp-head{
  display:flex; align-items:center; gap:var(--sp-4);
  padding:var(--sp-5) var(--sp-5) var(--sp-5);
  background:
    radial-gradient(120% 140% at 12% 0%, color-mix(in srgb, var(--accent) 22%, transparent), transparent 60%),
    radial-gradient(120% 140% at 100% 0%, color-mix(in srgb, var(--icon-g2) 18%, transparent), transparent 55%);
  border-bottom:1px solid var(--border);
}
.modhelp-icon{
  flex:0 0 44px; width:44px; height:44px;
  border:1px solid var(--border);
}
.modhelp-icon svg{ pointer-events:none; }
#modhelp-body h2{ font-family:'Fraunces',serif; font-weight:600; font-size:1.3rem; margin:0; }
.modhelp-content{ padding:var(--sp-4) var(--sp-5) 0; }
.modhelp-intro{ font-size:.9rem; color:var(--text); line-height:1.6; margin:0 0 var(--sp-2); }
.modhelp-sec{
  font-family:'Fraunces',serif; font-weight:600; font-size:1rem; color:var(--accent);
  margin:var(--sp-5) 0 var(--sp-2); padding-bottom:var(--sp-2); border-bottom:1px solid color-mix(in srgb, var(--accent) 35%, transparent);
}
.modhelp-list{ margin:0; }
.modhelp-list > div{ padding:var(--sp-2) 0; border-bottom:1px solid var(--border); }
.modhelp-list > div:last-child{ border-bottom:0; }
.modhelp-list dt{ font-weight:600; font-size:.86rem; color:var(--text); }
.modhelp-list dd{ margin:2px 0 0; font-size:.84rem; color:var(--muted); line-height:1.5; }
.modhelp-p{ font-size:.85rem; color:var(--muted); line-height:1.55; margin:0; }
.modhelp-tip{
  margin:var(--sp-5) 0 0; padding:var(--sp-3) var(--sp-3); border-radius:var(--r-sm);
  background:color-mix(in srgb, var(--accent) 10%, transparent);
  font-size:.85rem; color:var(--text); line-height:1.5;
}
.modhelp-tip strong{ color:var(--accent); }
/* #043 — link terug naar de bijbehorende theorie-leskaart; hergebruikt
   .tl-practice-link's tekstlink-met-pijl-stijl, alleen het blok-gedrag +
   de marge zijn hier eigen (die zit in modhelp-content, niet tl-lesson). */
.modhelp-theory-link{ display:block; margin:var(--sp-4) 0 0; }

/* Self-assessment (v0.88.0) — zelfde overlay-opzet als #modhelp-overlay
   hierboven, maar gecentreerd en smaller: een 3-staps-vragenkaart heeft geen
   lange scrollende inhoud nodig. */
#assess-overlay{
  position:fixed; inset:0; z-index:10500; display:none;
  align-items:center; justify-content:center; padding:var(--sp-5);
  background:rgba(0,0,0,.6); backdrop-filter:blur(2px);
}
#assess-overlay.visible{ display:flex; }
#assess-modal{
  background:var(--surface); color:var(--text); border:1px solid var(--border);
  border-radius:var(--r-md); padding:var(--sp-5); max-width:420px; width:100%;
  max-height:calc(100vh - 48px); overflow-y:auto;
  box-shadow:0 24px 64px rgba(0,0,0,.5); position:relative; margin:auto;
}
.assess-close{
  position:absolute; top:var(--sp-3); right:var(--sp-3);
  background:none; border:none; color:var(--muted); cursor:pointer; font-size:1rem; padding:var(--sp-1);
}
.assess-close:hover{ color:var(--text); }
.assess-step-counter{ font-size:.75rem; color:var(--muted); font-family:'JetBrains Mono',monospace; margin:0 0 var(--sp-2); }
.assess-q{ font-family:'Fraunces',serif; font-weight:600; font-size:1.1rem; margin:0 0 var(--sp-4); padding-right:var(--sp-5); }
.assess-opts{ display:flex; flex-direction:column; gap:var(--sp-2); }
.assess-opt-btn{
  font:inherit; font-size:.9rem; padding:var(--sp-3) var(--sp-4); text-align:left; cursor:pointer;
  border-radius:var(--r-sm); background:var(--surface2); color:var(--text); border:1px solid var(--border);
  transition:border-color var(--mo-2);
}
.assess-opt-btn:hover{ border-color:var(--accent); }
.assess-result-level{
  display:flex; align-items:center; gap:var(--sp-2);
  font-size:1rem; font-weight:600; margin:0 0 var(--sp-3);
}
.assess-result-body{ font-size:.88rem; color:var(--muted); line-height:1.55; margin:0 0 var(--sp-5); }
.assess-done-btn{ width:100%; }
/* Troubleshooting-tips bij aanhoudende stilte (v0.93.0, Plan_van_Aanpak_
   MIDI_Soundcheck_Feedback) — zelfde tekstmaat/kleur als .assess-result-body,
   los gehouden omdat het een lijst i.p.v. een alinea is. */
.assess-troubleshoot-list{
  margin:0 0 var(--sp-4); padding:0; list-style:none;
  display:flex; flex-direction:column; gap:var(--sp-2);
}
.assess-troubleshoot-list li{
  font-size:.85rem; color:var(--muted); line-height:1.5;
  padding:var(--sp-2) var(--sp-3); border-radius:var(--r-sm); background:var(--surface2);
}

/* "Ontdek Root Note"-overlay (Fase 7, v0.38.0) — zelfde overlay-/kaart-opzet
   als #credits-modal / #progress-help-overlay, breder omdat het een pagina is. */
#about-overlay{
  position:fixed; inset:0; z-index:10500; display:none;
  align-items:flex-start; justify-content:center; padding:var(--sp-5);
  background:rgba(0,0,0,.6); backdrop-filter:blur(2px);
}
#about-overlay.visible{ display:flex; }
#about-modal{
  background:var(--surface); color:var(--text); border:1px solid var(--border);
  border-radius:var(--r-md); padding:var(--sp-5) var(--sp-6) var(--sp-6); max-width:1000px; width:100%;
  max-height:calc(100vh - 48px); overflow-y:auto;
  box-shadow:0 24px 64px rgba(0,0,0,.5); position:relative;
  margin:auto;
}
/* v0.65.7: breder + de onderdelen-lijst in twee kolommen op een breed
   scherm, zodat de pagina korter wordt. */
@media (min-width:820px){
  .about-mods{ display:grid; grid-template-columns:1fr 1fr; gap:0 var(--sp-6); align-items:start; }
  .about-mods > .about-mod-lead{ grid-column:1 / -1; }
}
/* "Toon alle eerdere updates" — als een linkje, native <details>. */
.about-news-more{ margin-top:var(--sp-2); }
.about-news-more > summary{
  cursor:pointer; list-style:none; display:inline-block;
  font-size:.82rem; font-weight:600; color:var(--accent);
  padding:var(--sp-1) 0;
}
.about-news-more > summary::-webkit-details-marker{ display:none; }
.about-news-more > summary::before{ content:'▸ '; }
.about-news-more[open] > summary::before{ content:'▾ '; }
.about-news-more[open] > summary{ margin-bottom:var(--sp-3); }
.about-close{
  position:absolute; top:12px; right:12px; background:transparent; border:none;
  color:var(--muted); font-size:1.2rem; cursor:pointer; line-height:1; padding:var(--sp-1);
}
.about-close:hover{ color:var(--text); }
#about-body h2{
  font-family:'Fraunces',serif; font-weight:600; font-size:1.4rem;
  margin:0 0 var(--sp-2); padding-right:var(--sp-5);
}
.about-intro{ font-size:.92rem; color:var(--text); line-height:1.65; margin:0 0 var(--sp-4); }
.about-intro b{ color:var(--text); }
/* v0.64.6: inleidende alinea onder een sectiekop + een afsluitende noot-regel. */
.about-sec-lead{ font-size:.86rem; color:var(--muted); line-height:1.6; margin:0 0 var(--sp-4); }
.about-sec-lead b{ color:var(--text); }
.about-sec-note{
  font-size:.82rem; color:var(--muted); line-height:1.55; margin:var(--sp-4) 0 var(--sp-1);
  padding:var(--sp-3) var(--sp-3); border-left:2px solid var(--accent);
  background:color-mix(in srgb, var(--accent) 6%, transparent); border-radius:0 var(--r-sm) var(--r-sm) 0;
}
/* Samenhang-tekst boven de Muziektheorie-kaart. */
.about-mod-lead{
  font-size:.86rem; color:var(--muted); line-height:1.6; margin:0 0 var(--sp-3);
  padding:var(--sp-3) var(--sp-3); border-left:2px solid var(--accent);
  background:color-mix(in srgb, var(--accent) 6%, transparent); border-radius:0 var(--r-sm) var(--r-sm) 0;
}
.about-sec{
  font-family:'Fraunces',serif; font-weight:600; font-size:1.05rem;
  color:var(--text); margin:var(--sp-5) 0 var(--sp-3); padding-bottom:var(--sp-2);
  border-bottom:1px solid var(--border);
}
/* Zo werkt Root Note (v0.49.0) */
.about-how{ margin:0 0 var(--sp-2); }
.about-how-step{ display:flex; gap:var(--sp-3); padding:var(--sp-3) 0; border-bottom:1px solid var(--border); }
.about-how-step:last-child{ border-bottom:0; }
.about-how-ic{
  flex:0 0 34px; width:34px; height:34px; display:flex; align-items:center; justify-content:center;
  border-radius:10px; background:color-mix(in srgb, var(--accent) 12%, transparent); color:var(--accent);
}
.about-how-ic svg{ width:20px; height:20px; }
.about-how-step strong{ display:block; font-size:.9rem; color:var(--text); margin-bottom:2px; }
.about-how-step p{ font-size:.83rem; color:var(--muted); line-height:1.55; margin:0; }

/* Feedbackformulier in de "Meer info"-modal (v0.49.0) */
#feedback-block .feedback-label{
  display:block; font-size:.78rem; color:var(--muted); margin:var(--sp-3) 0 var(--sp-1);
}
#feedback-form textarea, #feedback-form input[type="email"]{
  width:100%; box-sizing:border-box; font:inherit; font-size:.86rem; padding:var(--sp-2) var(--sp-3);
  background:var(--surface); color:var(--text);
  border:1px solid var(--border); border-radius:var(--r-sm); resize:vertical;
}
#feedback-form textarea:focus, #feedback-form input[type="email"]:focus{
  outline:none; border-color:var(--accent);
}
.feedback-check{ display:flex; align-items:center; gap:var(--sp-2); font-size:.83rem; color:var(--text); margin:var(--sp-3) 0 0; cursor:pointer; }
.feedback-actions{ margin:var(--sp-3) 0 0; }
/* Feedback-bijlagen (v0.58.3) */
#feedback-form input[type="file"]{ font:inherit; font-size:.8rem; color:var(--muted); max-width:100%; }
.feedback-files-hint{ font-size:.74rem; color:var(--muted); margin:var(--sp-1) 0 0; }
.feedback-file-list{ list-style:none; margin:var(--sp-2) 0 0; padding:0; display:flex; flex-direction:column; gap:var(--sp-1); }
.feedback-file{
  display:flex; align-items:center; gap:var(--sp-2); font-size:.78rem;
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-sm); padding:var(--sp-1) var(--sp-2) var(--sp-1) var(--sp-3);
}
.feedback-file-name{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--text); }
.feedback-file-size{ flex:none; color:var(--muted); font-variant-numeric:tabular-nums; }
.feedback-file-x{
  flex:none; width:22px; height:22px; border:0; border-radius:6px; cursor:pointer;
  background:transparent; color:var(--muted); font-size:1.1rem; line-height:1;
}
.feedback-file-x:hover{ background:var(--border); color:var(--text); }
#feedback-submit{
  font:inherit; font-size:.85rem; font-weight:700; padding:var(--sp-2) var(--sp-4); cursor:pointer;
  border-radius:var(--r-sm); background:var(--accent); color:var(--accent-ink); border:1px solid transparent;
}
#feedback-submit:disabled{ opacity:.55; cursor:default; }
/* #-scope nodig: #credits-modal p (1,0,1) verslaat anders .feedback-status
   (0,1,0). */
#feedback-status{ font-size:.82rem; margin:var(--sp-3) 0 0; }
#feedback-status[hidden]{ display:none; }
/* Bevestiging prominent (v0.50.0): vet, wit, groter + een groen vinkje.
   v0.51.0 (gebruikersverzoek): geen groene balk meer, alleen de tekst +
   het vinkje. */
#feedback-status.is-ok{ color:#fff; font-weight:700; font-size:1rem; }
#feedback-status.is-ok::before{ content:"✓ "; color:var(--ok); }
#feedback-status.is-err{ color:var(--err); font-weight:600; }
#feedback-status.is-busy{ color:var(--muted); }
/* Wat is er nieuw */
.about-rel{ margin:0 0 var(--sp-4); }
.about-rel-head{ display:flex; align-items:baseline; gap:var(--sp-3); margin-bottom:3px; }
.about-rel-v{
  font-family:'JetBrains Mono',monospace; font-weight:700; font-size:.8rem;
  color:var(--accent);
}
.about-rel-d{ font-size:.72rem; color:var(--muted); }
.about-rel ul{ margin:0; padding-left:var(--sp-4); }
.about-rel li{ font-size:.85rem; color:var(--muted); line-height:1.5; margin:2px 0; }
/* Niveau-legenda */
.about-legend{ list-style:none; margin:0 0 var(--sp-5); padding:0; }
/* v0.64.8: niveau-items zijn twee regels (<b>naam</b><br>uitleg).
   v0.65.6: de tekst in één blok (.about-legend-txt) zodat de naam én de
   uitleg links uitlijnen; de dot hangt er als marker links van. */
.about-legend li{
  font-size:.82rem; color:var(--muted); line-height:1.55;
  display:flex; align-items:flex-start; gap:var(--sp-2); margin:var(--sp-3) 0;
}
.about-legend-txt{ display:block; }
.about-legend li b{ color:var(--text); }
.about-dot{ width:8px; height:8px; border-radius:50%; flex:none; display:inline-block; position:relative; top:1px; }
.about-legend .about-dot{ top:5px; }
/* Modules */
.about-mod{ padding:var(--sp-4) 0 var(--sp-4); border-bottom:1px solid var(--border); }
.about-mod:last-child{ border-bottom:0; }
.about-mod-name{ font-family:'Fraunces',serif; font-weight:600; font-size:1.05rem; margin-bottom:2px; }
.about-mod-sum{ font-size:.86rem; color:var(--text); margin:0 0 var(--sp-2); }
.about-mod-does{ font-size:.83rem; color:var(--muted); line-height:1.55; margin:0 0 var(--sp-2); }
.about-mod-helps{ font-size:.83rem; color:var(--muted); line-height:1.55; margin:0 0 var(--sp-3); }
.about-mod-helps span{ color:var(--accent); font-weight:600; }
.about-lvls{ display:flex; flex-wrap:wrap; gap:var(--sp-2); }
.about-lvl{
  font-size:.72rem; color:var(--muted); display:inline-flex; align-items:center; gap:var(--sp-2);
  border:1px solid var(--border); border-radius:999px; padding:3px var(--sp-3);
}
/* Door de hele app heen */
.about-feats{ margin:0; }
.about-feat{
  display:grid; grid-template-columns:150px 1fr; gap:var(--sp-1) var(--sp-4);
  padding:var(--sp-3) 0; border-bottom:1px solid var(--border);
}
.about-feat:last-child{ border-bottom:0; }
.about-feat dt{ font-weight:600; font-size:.85rem; color:var(--text); }
.about-feat dd{ margin:0; font-size:.83rem; color:var(--muted); line-height:1.5; }
.about-foot{ font-size:.74rem; color:var(--muted); margin:var(--sp-5) 0 0; }
/* Kleine gecentreerde credit-regel onderaan de opklap-pagina's (v0.52.0,
   gebruikersverzoek) — "Meer info", "Ontdek Root Note", de per-app-uitleg.
   Bewust NIET op het tegel-overzicht of in de oefeningen zelf. */
.app-credit-foot{
  margin:var(--sp-5) 0 0; padding-top:var(--sp-4); border-top:1px solid var(--border);
  text-align:center; font-size:.72rem; color:var(--muted); letter-spacing:.3px;
}
@media (max-width:560px){
  #about-modal{ padding:var(--sp-5) var(--sp-5) var(--sp-5); }
  .about-feat{ grid-template-columns:1fr; gap:1px; padding:var(--sp-2) 0; }
  .modhelp-head{ padding:var(--sp-5) var(--sp-4) var(--sp-4); }
  .modhelp-content{ padding:var(--sp-4) var(--sp-4) 0; }
}

@media (max-width:560px){
  #init-overlay .brand-launch-btn{ padding:var(--sp-6) var(--sp-5); gap:var(--sp-4); }
  #init-overlay .welcome-content{ gap:var(--sp-5); }
  /* Mobiele tegenhanger van de vaste 56px hierboven (Stap 1) — was het
     `6vw`-minimum van de oude clamp (38px bij een smalle telefoon), nu als
     vaste waarde op dezelfde breakpoint als de padding-verkleining hierboven,
     zodat kaartbreedte/-hoogte-verhouding hier consistent blijft t.o.v. de
     desktop-maat (beide vast, geen doorlopende vw-schaal meer ertussenin). */
  #init-overlay .main-title{ font-size:38px; }
}

#module-view{ width:100%; flex:1; display:flex; flex-direction:column; overflow:hidden; }

/* Instellingen wonen in het opvraagbare paneel (drawer, #settings-drawer)
   i.p.v. een altijd-zichtbare balk boven de kaart — knoppen i.p.v. een
   dropdown-menu, zodat je in één tik kunt wisselen (zelfde patroon als de
   kwintencirkel), maar nu opt-in via de tandwiel-knop. */
#quick-controls{
  width:100%; display:flex; flex-direction:column; align-items:stretch; gap:var(--sp-5);
  /* v0.83.3 (gebruikersverzoek, vooral mobiel): `.settings-reset-row`
     hieronder duwt zichzelf met `margin-top:auto` naar de onderkant van de
     lade — zodra de instellingen zelf de lade al vullen (weinig scrollruimte
     over, typisch op een telefoon) rekent de browser die auto-marge dan op
     0 uit, en plakt de scheidingslijn direct tegen de laatste knoppenrij
     (bijv. Akkoorden se Exact/Beide). Een vaste minimum-marge hier blijft
     ALTIJD gelden, los van hoeveel ruimte er nog over is. */
  margin-bottom:var(--sp-5);
}
#quick-controls:empty{ display:none; }
/* Fase 4 (BL-4.2) — de lade valt uiteen in twee blokken: "Wat leer ik?"
   (didactische filters) en "Hoe oefen ik?" (sessie-/speelregels), zie
   SettingsBuilder._splitSettingsIntoSections(). v0.83.0: de tekstkoppen
   ("Wat leer ik?"/"Hoe oefen ik?") zijn weg — dat las dubbelop naast de
   kleine Niveau/Type/Toonsoort-labels en stond nooit zo in de mockup. Een
   kale lijn knipt de twee blokken nu uit elkaar, zonder tekst. */
.settings-section-divider{ height:1px; background:var(--border); flex-shrink:0; }
.setting-group{ display:flex; flex-direction:column; gap:var(--sp-2); align-items:flex-start; width:100%; }
.setting-group label{
  display:inline-flex; align-items:center; gap:var(--sp-2); font-size:.68rem; color:var(--muted);
  text-transform:uppercase; letter-spacing:.6px; font-weight:700;
}
.aa-icon{ width:19px; height:19px; flex-shrink:0; }
/* Type/Toonsoort naast elkaar i.p.v. onder elkaar (v0.20.0, Toonladders-
   verzoek: "de vele opties zorgen voor een wat vollere weergave") — Type
   verticaal (één knop per regel, i.p.v. de gewone wrappende rij) links,
   Toonsoort (blijft wél wrappen, 12 knoppen) rechts, met een subtiel
   verticaal lijntje ertussen. Valt terug naar gestapeld op een smalle
   drawer/telefoon (zie de @media hieronder). Generiek genoeg om ook elders
   te hergebruiken, niet Toonladders-specifiek in de CSS zelf. */
.settings-split{ display:grid; grid-template-columns:minmax(90px,auto) 1px minmax(140px,1fr); gap:0 var(--sp-4); align-items:start; }
/* Ritme: Notenwaarden/Rusten (2026-09-13, gebruikersverzoek: "maak er twee
   kolommen van, noten links en rusten rechts") — ANDERS dan Toonladders se
   Type/Toonsoort hierboven zijn dit twee gelijkwaardige, ongeveer even lange
   lijsten, dus gelijke kolombreedtes (`1fr 1px 1fr`) i.p.v. het
   auto/1fr-verschil. Blijft BEWUST twee kolommen op mobiel — de generieke
   `@media(max-width:560px){ .settings-split{ grid-template-columns:1fr } }`
   verderop (voor Type/Toonsoort, waar smal scherm wél naar 1 kolom
   terugvalt) zou dit anders ook naar 1 kolom terugklappen, precies het
   omgekeerde van het verzoek — dus hier een eigen override met hogere
   specificiteit die na die media query in het bestand staat. */
.rhythm-nv-rv-split{ grid-template-columns:1fr 1px 1fr; }
@media (max-width:560px){
  .rhythm-nv-rv-split{ grid-template-columns:1fr 1px 1fr !important; row-gap:0 !important; }
  .rhythm-nv-rv-split .settings-split-divider{ display:block !important; }
  .rhythm-nv-rv-split .opt-row-vertical .opt-btn{ white-space:normal; font-size:.82rem; padding:var(--sp-2) var(--sp-2); }
}
.settings-split-col{ display:flex; flex-direction:column; gap:var(--sp-2); align-items:flex-start; min-width:0; }
.settings-split-divider{ align-self:stretch; background:var(--border); width:1px; }
.opt-row-vertical{ flex-direction:column; align-items:stretch; }
/* v0.83.0-bugfix: `text-align:left` deed hier NOOIT iets — de globale
   `button{display:flex; justify-content:center}` (styles.css regel ~379)
   wint van text-align op een flex-container, precies zoals
   `#opt-notes-level .opt-btn` hieronder al met een eigen `justify-content`-
   override moest oplossen. Onopgemerkt zolang de Type-knoppen de korte
   labels toonden (nauwelijks zichtbaar verschil); met de volledige namen
   terug (zie hierboven) viel de misplaatste centrering meteen op. */
.opt-row-vertical .opt-btn{ justify-content:flex-start; text-align:left; white-space:nowrap; }
/* Toonsoorten-keuze (v0.65.4): laat de 12 knoppen netjes teruglopen.
   Sinds de instellingenfilter-ronde (Fase 5, gebruikersfeedback: "veel
   loze ruimte naast staat") een vast 3-koloms-grid i.p.v. flex-wrap — bij
   12 ongelijk brede knoppen (C/G/D/A/E/B/F#/Db/Ab/Eb/Bb/F) liet flex-wrap
   een oneven laatste rij achter (bijv. één knop alleen met veel ruimte
   ernaast); een grid verdeelt ze voorspelbaar 4 rijen × 3 (of, vanaf 400px,
   3 rijen × 4). `.opt-row.opt-keys-row` (dubbele klasse) wint van de
   losse `.opt-row{display:flex}`-regel verderop, ongeacht bronvolgorde. */
/* Zelfde `align-self:stretch`-reden als .chord-type-tier hierboven — de
   Toonsoort-kolom in .settings-split is ook `align-items:flex-start`, dus
   zonder deze regel zou de grid hier ook z'n eigen max-content-breedte
   pakken i.p.v. de toegewezen kolombreedte. */
.settings-split-col .opt-keys-row{ align-self:stretch; }
/* Bewust ALTIJD 3 kolommen (geen bredere-scherm-variant met 4) — de
   Toonsoort-kolom in .settings-split deelt zijn breedte met de Type-kolom
   (die zelf ook kan groeien, bijv. Akkoorden se 2-koloms type-groepen),
   dus "hoe breed is de Toonsoort-kolom echt" hangt af van de ANDERE kolom
   se inhoud, niet alleen van het schermformaat — een vaste 4de kolom bleek
   daardoor op praktische breedtes knoppen afknippen. 3 kolommen geeft 12
   toonsoorten in 4 volle rijen, geen oneven laatste rij meer. */
.opt-row.opt-keys-row{ display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:var(--sp-2); }
.opt-keys-row .opt-btn{ text-align:center; }
.opt-keys-row .opt-all-btn{ grid-column:1 / -1; }
/* Toonladders (v0.83.0, instellingenlade-herziening): Type terug naar de
   VOLLEDIGE namen ("Mineur Natuurlijk" i.p.v. "Mineur Nat.") — gemeten in
   de browser dat Type als gewone eenkoloms-lijst met volledige namen op
   exact dezelfde hoogte uitkomt als Toonsoort hieronder in 2 kolommen
   (317,5px, beide kanten, NL én EN — geen enkele naam breekt naar een 2e
   regel), dus geen afkorting nodig. Vervangt de vorige `.lbl-short`-
   geforceerde afkorting. Eigen kolomverdeling (1fr/1fr i.p.v. de gedeelde
   auto/1fr van `.settings-split`) zodat Type niet breder claimt dan
   Toonsoort ernaast toelaat. */
/* Alleen BOVEN de mobiele stapel-breakpoint (zie
   `@media(max-width:560px){ .settings-split{ grid-template-columns:1fr } }`
   verderop) — een kale ID-selector zou anders zijn hogere specificiteit
   laten winnen van die media-query-regel en Type/Toonsoort op mobiel
   permanent naast elkaar houden i.p.v. te stapelen (bug gevonden en
   gefixt tijdens het testen op 390px). */
@media (min-width:561px){ #scales-settings-split{ grid-template-columns:1fr 1px 1fr; } }
/* Toonsoort ging van 3 naar 2 kolommen (6 rijen i.p.v. 4) — dat is precies
   wat de 317,5px-vergelijking hierboven mogelijk maakt; scoped op scales
   alleen, Akkoorden se eigen `opt-keys-row` (chords-roots) blijft 3. Blijft
   2 kolommen op elke breedte (ook mobiel) — dat is onafhankelijk van de
   Type/Toonsoort-naast-elkaar-vraag hierboven. */
#opt-scale-roots.opt-keys-row{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
/* Akkoorden Type-kolom: zelfde reden/patroon (CircleWheel.chordAbbr als
   shortLabel, zie app-core.js) — "Diminished" e.d. past anders niet op 1
   regel in deze nu smalle kolom. */
/* BL-4.4-chords — de 18 akkoordtypes in drie herkenbare groepen (Basis/
   Septiemen/Uitgebreid, zie App._renderChordTypeGroups()) i.p.v. één platte
   lijst. Elke groep krijgt zijn eigen 2-koloms-grid (6 types → 3 rijen×2) —
   zelfde reden als de vorige platte 2-koloms-grid hieronder verving: 1 lange
   kolom per groep zou de lade onnodig lang maken. */
.chord-type-tier + .chord-type-tier{ margin-top:var(--sp-3); }
.chord-type-tier-label{
  font-family:'JetBrains Mono',monospace; font-size:9.5px; font-weight:600;
  letter-spacing:.1em; text-transform:uppercase; color:var(--faint);
  margin-bottom:var(--sp-2);
}
/* De root cause zat niet (alleen) in de 1fr-koloms: `.settings-split-col`
   is `align-items:flex-start`, dus zijn flex-kinderen (de drie
   `.chord-type-tier`-blokken) krijgen NOOIT de 143px-breedte van hun
   ouder opgelegd — ze nemen gewoon hun eigen voorkeursbreedte (max-content
   van hun `1fr`-grid, ±190px) en steken zichtbaar over de rand heen de
   Toonsoort-kolom in (geen clipping, want overflow staat niet op hidden).
   `align-self:stretch` dwingt ELK tier-blok wél op de volle 143px, wat een
   ECHTE (niet-intrinsieke) breedte aan de binnenste grid doorgeeft — pas
   dan werkt `minmax(0, 1fr)` (i.p.v. kaal `1fr`) zoals bedoeld en krimpen
   de knoppen daadwerkelijk mee. `white-space:normal` blijft het laatste
   vangnet voor een label dat ook dan nog niet past (bijv. "Diminished"). */
.settings-split-col .chord-type-tier{ align-self:stretch; }
.chord-type-tier .opt-row-vertical{ display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:var(--sp-2); }
.chord-type-tier .opt-btn{ white-space:normal; text-align:center; }
/* Toonsoort (12 knoppen) blijft de gewone wrappende .opt-row (zie hieronder)
   — een geforceerde bredere grid (bijv. 4 kolommen) bleek de beschikbare
   drawerbreedte te overschrijden (horizontale scrollbar, knoppen afgesneden,
   bevestigd met een screenshot) zodra de Type-kolom ernaast ook al ruimte
   claimt. De natuurlijke wrap (3 kolommen × 4 rijen bij de standaard
   drawerbreedte) is het compactst wat hier zonder overflow past. */
#opt-chord-types .lbl-full{ display:none; }
#opt-chord-types .lbl-short{ display:inline; }
@media (max-width:560px){
  /* v0.83.3 (gebruikersverzoek: "Toonsoort zit te dicht boven Type") —
     `.settings-split`'s `gap:0 var(--sp-4)` (basisregel) zet de rij-tussen-
     ruimte bewust op 0 voor de BREDE, naast-elkaar-weergave (geen ruimte
     nodig tussen kolommen die toch al door de verticale scheidingslijn
     gescheiden zijn). Zodra dit hier terugvalt naar 1 kolom (Type/Toonsoort
     ONDER elkaar) erft die 0 gewoon mee als rij-afstand — vandaar dat
     Toonsoort's label vlak onder Type's laatste knop kleefde. */
  .settings-split{ grid-template-columns:1fr; row-gap:var(--sp-5); }
  .settings-split-divider{ display:none; }
}
.aa-delay-val{ text-transform:none; letter-spacing:0; color:var(--text); }
/* Knop-labels met een korte mobiele variant (bijv. "Niv 1 (C3-C5)" i.p.v.
   "Makkelijk (C3-C5)") — standaard (breed scherm) toont de volledige tekst. */
.lbl-short{ display:none; }
.opt-row{ display:flex; flex-wrap:wrap; gap:var(--sp-2); justify-content:flex-start; }
.opt-btn{
  background:var(--canvas); color:var(--text); border:1px solid var(--border);
  border-radius:var(--r-sm); padding:var(--sp-2) var(--sp-4); font-size:.85rem; font-weight:700; cursor:pointer;
  transition:all var(--mo-1) var(--ease); font-family:'JetBrains Mono',monospace;
}
.opt-btn:hover{ background:var(--border); }
/* Effen cyaan i.p.v. de gradient (v0.20.0) — zelfde reden als button.primary
   hierboven. */
.opt-btn.active{ color:var(--accent-ink); background:var(--accent); border-color:transparent; box-shadow:0 4px 12px color-mix(in srgb, var(--accent) 35%, transparent); }
/* "Alle 12"-snelknop vóór een multi-select-rij (v0.27.0) — als een .opt-btn,
   maar met een streepjeslijn zodat 'ie leest als "alles" i.p.v. een losse waarde. */
.opt-all-btn{
  background:transparent; color:var(--muted); border:1px dashed var(--border);
  border-radius:var(--r-sm); padding:var(--sp-2) var(--sp-4); font-size:.85rem; font-weight:700; cursor:pointer;
  transition:all var(--mo-1) var(--ease); font-family:'JetBrains Mono',monospace; margin-right:var(--sp-1);
}
.opt-all-btn:hover{ color:var(--text); border-color:var(--accent); }
.opt-all-btn.active{ color:var(--accent-ink); background:var(--accent); border-color:transparent; border-style:solid; }
/* Handen-icoontjes (Toonladders, L3-04 / 3.4) — inline SVG uitgesneden uit
   hands.svg, currentColor, geen drager: dit is bediening, geen merkbeeld. */
.hand-icon{ display:inline-flex; align-items:center; justify-content:center; flex-shrink:0; color:var(--text); }
.hand-icon svg{ display:block; }

.auto-delay-slider{
  -webkit-appearance:none; appearance:none; width:150px; height:6px; border-radius:3px;
  background:var(--border); outline:none; cursor:pointer;
}
.auto-delay-slider::-webkit-slider-thumb{
  -webkit-appearance:none; appearance:none; width:20px; height:20px; border-radius:50%;
  background:linear-gradient(135deg, var(--accent), var(--icon-g2)); cursor:pointer; box-shadow:0 2px 6px rgba(0,0,0,.3);
}
.auto-delay-slider::-moz-range-thumb{
  width:20px; height:20px; border-radius:50%; border:none;
  background:linear-gradient(135deg, var(--accent), var(--icon-g2)); cursor:pointer; box-shadow:0 2px 6px rgba(0,0,0,.3);
}
/* Challenge-BPM-slider + handmatig tekstveld (v0.20.0) — de slider zelf
   hergebruikt .auto-delay-slider; alleen de rij-indeling en het tekstveld/
   "BPM"-label zijn nieuw. `list=` op de slider (zie
   buildChallengeSpeedControl()) geeft native tick-streepjes op elke 15
   BPM-stap zonder extra CSS. */
.bpm-control-row{ display:flex; align-items:center; gap:var(--sp-3); flex-wrap:wrap; }
.bpm-control-row .auto-delay-slider{ flex:1 1 140px; max-width:200px; }
.bpm-manual-input{
  /* 56px i.p.v. 72px oogde te krap (gebruikersfeedback, screenshot) — een
     `type="number"`-veld reserveert intern ruimte voor de browser-eigen
     spinner-pijltjes, dus het echte tekstgedeelte was smaller dan de
     opgegeven breedte deed vermoeden. */
  width:72px; background:var(--canvas); color:var(--text); border:1px solid var(--border);
  border-radius:var(--r-sm); padding:var(--sp-1) var(--sp-2); font-size:.85rem; font-weight:700;
  font-family:'JetBrains Mono',monospace; text-align:center;
}
.bpm-manual-input:focus{ outline:none; border-color:var(--accent); }
.bpm-unit-label{ font-size:.72rem; font-weight:700; color:var(--muted); letter-spacing:.4px; }

#workspace{
  flex:1; display:flex; flex-direction:column; align-items:center;
  /* BUGFIX (2026-09-13) — `justify-content:safe center` bleek niet overal
     betrouwbaar (zie de uitgebreide toelichting bij `.fc-stage` hieronder,
     zelfde onderliggende probleem één laag hoger). Vervangen door
     `flex-start` + `.flashcard{margin-block:auto}` — bij normale
     (kleinere) kaarten identiek zichtbaar gecentreerd, bij een kaart die
     niet past nu bovenkant-uitgelijnd i.p.v. symmetrisch geclipt. */
  justify-content:flex-start;
  padding:var(--sp-5); background:var(--canvas); overflow-y:auto; overflow-x:hidden; width:100%;
}

/* Instellingen wonen nu altijd in het opvraagbare paneel (drawer, zie
   #settings-drawer) i.p.v. een header-rij op breed scherm vs. een
   inklapbaar paneel op smal scherm — daarom gelden de "smal-scherm"-
   opmaakregels voor instellingen nu ONVOORWAARDELIJK (de drawer zelf is
   altijd zo'n 380px breed, ongeacht viewportbreedte). */

/* Niveau-knoppen (Noten Lezen) onder elkaar i.p.v. 3-op-een-rij — de
   drawer heeft nu ruim genoeg verticale ruimte, dus de volledige labels
   ("Makkelijk (C3-C5)") passen weer gewoon op één regel per knop (zie
   basisregel .lbl-short{display:none} hierboven — .lbl-full blijft dus
   gewoon zichtbaar, geen override meer nodig). */
#opt-notes-level{ display:grid; grid-template-columns:1fr; gap:var(--sp-2); }
#opt-notes-level .opt-btn{ justify-content:flex-start; text-align:left; }

/* ---- Instellingen-paneel (drawer), rechts, op elke schermbreedte ---- */
/* BL-4.1 — laat de topbalk ook vrij van het donkere overlay (zelfde
   `--topbar-height` als #settings-drawer hierboven). */
#settings-drawer-backdrop{
  position:fixed; top:var(--topbar-height, 64px); right:0; bottom:0; left:0;
  background:rgba(0,0,0,.35); z-index:8999; opacity:0; pointer-events:none; transition:opacity var(--mo-2) var(--ease);
}
#settings-drawer-backdrop.open{ opacity:1; pointer-events:auto; }
/* BL-4.1 — start ónder de topbalk i.p.v. 'm te overlappen (hoofdnavigatie
   blijft zo altijd zichtbaar/bereikbaar). `--topbar-height` wordt door
   SettingsUI.toggleDrawer() gemeten (de topbalk wisselt van hoogte per
   breakpoint); de vaste `64px`-fallback dekt alleen het randgeval dat de
   lade ooit zonder die meting zou openen. */
#settings-drawer{
  position:fixed; top:var(--topbar-height, 64px); right:0;
  height:calc(100vh - var(--topbar-height, 64px)); height:calc(100dvh - var(--topbar-height, 64px));
  width:min(380px, 92vw); z-index:9000;
  background:var(--surface); border-left:1px solid var(--border); box-shadow:var(--sh-3);
  transform:translateX(100%); transition:transform var(--mo-2) var(--ease);
  display:flex; flex-direction:column; padding:var(--sp-5);
}
/* Gebruikersverzoek (Fase 5-nazorg, twee rondes): op pc/tablet minder
   verticaal scrollen door de lade breder te maken — mobiel blijft
   ongewijzigd (`92vw` daar was al bedoeld als "bijna het hele scherm",
   geen probleem). Tweede ronde ging tot 640px, wat achteraf te breed bleek
   (instellingenlade-herziening, v0.83.0) — de nieuwe combo-knoppen en de
   2-koloms Type/Toonsoort-indeling bij Toonladders maken die extra breedte
   overbodig; 460px is de door de gebruiker gekozen, definitieve maat. */
@media (min-width:820px){ #settings-drawer{ width:min(460px, 46vw); } }
#settings-drawer.open{ transform:translateX(0); }
.settings-drawer-head{ display:flex; justify-content:space-between; align-items:center; margin-bottom:var(--sp-5); flex-shrink:0; }
.settings-drawer-head span{ font-family:'Fraunces',serif; font-weight:600; font-size:20px; }
.settings-drawer-head-actions{ display:flex; align-items:center; gap:var(--sp-2); }
#settings-drawer-close{ width:32px; height:32px; padding:0; border-radius:50%; }
/* v0.86.2 (gebruikersverzoek) — kleine reset-knop naast de sluitknop,
   vervangt de oude volle-breedte "Deze oefening terugzetten"-rij onderaan
   de lade (+ de blokkerende confirm()-popup die erbij hoorde). Zelfde
   32px/rond model als #settings-drawer-close hierboven, alleen met een
   gedimde rustkleur (zoals .topbar-icon-btn) zodat 'm niet even zwaar oogt
   als de sluitknop. */
#settings-reset-icon-btn{
  width:32px; height:32px; padding:0; border-radius:50%; flex-shrink:0;
  background:transparent; border:1px solid transparent; color:var(--muted);
  display:inline-flex; align-items:center; justify-content:center;
  transition:background-color var(--mo-1) var(--ease), color var(--mo-1) var(--ease);
}
#settings-reset-icon-btn .sys-icon{ width:16px; height:16px; }
@media (hover:hover){ #settings-reset-icon-btn:hover{ background:var(--surface2); color:var(--text); } }
#settings-reset-icon-btn:active{ transform:scale(.94); }
/* `scrollbar-gutter:stable` + een eigen padding-right (met een gelijke
   negatieve margin, zodat de rest van de lade-inhoud niet opeens smaller
   wordt) — zonder dit lag de browserscrollbar bovenop de laatste paar
   pixels van de instellingenknoppen (gebruikersfeedback: "de schuifbalk
   valt eroverheen"). */
.settings-drawer-body{
  overflow-y:auto; flex:1; display:flex; flex-direction:column;
  scrollbar-gutter:stable;
  padding-right:var(--sp-3); margin-right:calc(-1 * var(--sp-3));
}

/* S3-02 / G-02 — oefenscherm op --w-focus (640). Eigen-weergave-modi
   (Kwintencirkel, Lopende band, Virtuele Piano — herkenbaar aan een zichtbare
   .circle-main of #scroll-view) verbreden naar --w-wide. De 1400px vervalt. */
.flashcard{
  background:var(--paper); border-radius:var(--r-lg); width:100%; max-width:var(--w-focus); min-height:340px;
  box-shadow:var(--sh-3); display:flex; flex-direction:column; align-items:center; gap:var(--sp-3);
  padding:var(--sp-5); position:relative; color:var(--notation); border:1px solid var(--border);
  transition:background-color var(--mo-3), border-color var(--mo-3), color var(--mo-3), min-height var(--mo-3) var(--ease);
  /* BUGFIX vervolg op de `overflow-y`-fix verderop in dit blok: zonder
     `overflow-x:hidden` bleek de kaart nog steeds SAMENGEPERST te worden
     door de standaard flex-krimp (`flex-shrink:1`) van `#workspace` zodra de
     inhoud niet meer in het zichtbare venster paste — het RONDE randje/
     schaduw stopte dan bij de samengeperste hoogte terwijl wiel/klavier/
     knoppen er zichtbaar voorbij liepen (met `overflow:visible` clipt dat
     niet meer, maar de kaart-rand hoorde daar niet te eindigen). `flex-
     shrink:0` laat de kaart zijn volledige, natuurlijke inhoudshoogte
     behouden; `#workspace` scrollt vervolgens de HELE (nu correct hoge)
     kaart, rand inclusief. */
  flex-shrink:0;
  /* BUGFIX (2026-09-13, gebruikersmelding: Kwintencirkel op mobiel — meer
     dan de helft van het wiel viel boven de kaart, ONBEREIKBAAR met welke
     scrollpositie dan ook). Werkt samen met `#workspace`'s
     `justify-content:flex-start` (zie de uitgebreide toelichting bij
     `.fc-stage` verderop) — dit is de kant-en-klare CSS-truc voor
     "centreer als het past, lijn boven uit als het niet past": bij normale
     (kleinere) kaarten consumeert deze auto-marge alle overtollige ruimte
     en centreert dus nog steeds precies als voorheen; bij een kaart die
     niet past resolveert de auto-marge naar 0 (kan nooit negatief worden)
     en blijft de kaart bovenkant-uitgelijnd i.p.v. symmetrisch te clippen.
     LET OP: dit werkt UITSLUITEND zolang de ouder GEEN concurrerende
     `justify-content:center` heeft — met `center` ernaast blijft de
     browser bij overflow toch symmetrisch centreren (geverifieerd,
     `margin:auto` alléén loste het niet op) — vandaar dat `#workspace`
     hierboven naar `flex-start` is omgezet i.p.v. dit als losstaande fix
     te laten staan. */
  margin-block:auto;
  /* BUGFIX vervolg (2026-09-13, gebruikersmelding: "de onderkant van de
     kaart is soms niet bereikbaar, gaat soms vanzelf goed bij een andere
     module heen-en-terug") — de vroegere `overflow-x:hidden` hier liet de
     browser `overflow-y` impliciet op `auto` berekenen, ONGEACHT of je
     `overflow-y` zelf ook expliciet op `visible` zet (geverifieerd: had
     geen effect — dit is een CSS-spec-regel op de COMPUTED waarde, niet
     alleen de default: zodra één as niet-`visible` is, wordt de andere as
     hoe dan ook `auto`, `overflow-y:visible` er letterlijk bij zetten
     verandert daar niets aan). Dat maakte `.flashcard` zélf een TWEEDE,
     geneste scrolbare laag bovenop `#workspace` (die ook al
     `overflow-y:auto` heeft) — bevestigd via `#workspace.scrollHeight ===
     #workspace.clientHeight` terwijl `.flashcard` intern wél moest
     scrollen. Geneste scroll-containers zijn op mobiel notoir onbetrouwbaar
     (scroll-chaining-quirks, vooral ná een dynamische inhoudswijziging) —
     dat verklaart het wisselende "soms vanzelf goed"-gedrag. Echte fix:
     `overflow-x:hidden` hier gewoon WEGGEHAALD (niet vervangen) — horizontaal
     clippen gebeurt toch al een laag hoger, `#workspace` heeft zijn eigen
     `overflow-x:hidden`. Zonder een eigen niet-`visible` as blijft
     `.flashcard` op de spec-default (`visible`/`visible`) staan, dus geen
     eigen scrol-laag meer; `#workspace` wordt zo de ENIGE scrol-omgeving —
     één natuurlijke scroll i.p.v. een geneste, en de
     `margin-block:auto`/`flex-start`-truc hierboven blijft intact omdat die
     op de OUDER (`#workspace`) plaatsvindt, niet op deze as. */
}
/* v0.83.4 (gebruikersverzoek: "breedte mag nagenoeg schermvullend, hoogte
   van Notenspelen [Noten Lezen-Lopende band] is perfect, trek Toonladders
   daarmee gelijk") — een eigen, ruimere maat i.p.v. de gedeelde --w-wide
   (die ook de Muziektheorie-overzichtstegels en het voortgangsdashboard
   gebruiken, dus niet zomaar op te rekken). `min(…, 94vw)` krimpt netjes
   terug op een kleiner scherm; de vaste `min-height` dwingt bij ELKE
   fc-wide-oefenvorm dezelfde kaarthoogte af, ook waar (zoals Toonladders'
   vaste ScoreRenderer-canvas) de eigen inhoud vanzelf korter zou uitvallen. */
.flashcard.fc-wide{ max-width:min(1600px, 94vw); min-height:740px; }
/* v0.86.0 (gebruikersmelding: Toonladders-Flashcards se notenbalk "voelt
   te compact op de pc") — eerste poging deelde `.fc-wide` met Toonladders-
   Spelen (op gebruikersverzoek), maar bleek te groot ("wel heel groot, te
   groot") — terug naar een eigen, lichtere maat: alleen breder
   (#score-paper svg{width:100%} schaalt de 1-octaaf-reeks vanzelf groter
   mee), GEEN vaste 740px-hoogte. 1000px getest: duidelijk leesbaarder
   zonder overdreven groot te worden. */
.flashcard.fc-scales-wide{ max-width:min(1000px, 92vw); }

/* S3-01/G-03 — vier vaste banden: A status 40px · B speelveld flex:1 min
   260 · C antwoord 108px (132 mobiel, S3-07) · D acties 56px (.flashcard-
   actions, zie verderop). A/C reserveren hun hoogte ook leeg — alleen B
   groeit/krimpt mee, zodat het speelveld nooit verspringt. */
.fc-band{ width:100%; }
.fc-status{ min-height:40px; display:flex; align-items:center; }
.fc-stage{
  position:relative;
  flex:1 1 auto; min-height:260px; display:flex; flex-direction:column;
  /* BUGFIX (2026-09-13, gebruikersmelding: Kwintencirkel op mobiel — meer
     dan de helft van het wiel viel boven de kaart, ONBEREIKBAAR met welke
     scrollpositie dan ook — al eerder gehad, zie de technische les
     hieronder). Root-oorzaak: `justify-content:center` op een
     `overflow`-drager centreert een kind dat groter is dan de container
     SYMMETRISCH over de rand heen — de bovenkant is dan met geen enkele
     scrollpositie te bereiken. `#workspace` heeft hiertegen al
     `justify-content:safe center` (zie de les in Root_Note_Context.md),
     maar "safe"-centrering wordt niet overal betrouwbaar ondersteund (met
     name oudere mobiele Safari), én dekt sowieso alleen zijn EIGEN kind
     (.flashcard), niet dit geneste niveau eronder — `#svg-container` bij
     Kwintencirkel/Lopende Band/Virtuele Piano (~988px) werd hier evengoed
     over de rand heen gecentreerd zodra dat hoger werd dan de ~452px die
     `.fc-stage` op een telefoon overhoudt. VASTE, browser-onafhankelijke
     fix: `justify-content:flex-start` + `margin-block:auto` op het kind
     (hieronder) — bij NORMALE (kleinere) inhoud consumeert de auto-marge
     alle overtollige ruimte en centreert dus nog steeds precies zoals
     voorheen (justify-content krijgt dan simpelweg niets meer te verdelen);
     pas bij inhoud die NIET past, valt dit terug op bovenkant-uitgelijnd
     i.p.v. symmetrisch te clippen. Geen "safe"-keyword-steun nodig. */
  align-items:center; justify-content:flex-start;
}
.fc-stage > *{ margin-block:auto; }
/* v0.86.0 (gebruikersmelding: de Kwintencirkel-vraag stond "te ver
   bovenaan") — alleen voor de Kwintencirkel-tekstvragen (geen notenbalk):
   laat de gedeelde 260px-ondergrens hierboven los zodat band B vanzelf
   compact blijft i.p.v. gecentreerd in een veel te grote lege zone. Andere
   modules (die de 260px wél nodig hebben voor hun notenbalk/wiel/klavier)
   krijgen deze klasse nooit, zie App.renderData().
   VERVOLG (gebruikersmelding: de kaart verspringt alsnog zodra een vraag
   naar een tweede regel doorloopt, bijv. "F mineur heeft 4 mollen (♭).
   Hoeveel heeft F majeur?") — een kale `min-height:0` liet band B immers nog
   steeds MEEGROEIEN met de tekst (1 vs. 2 regels), dus exact hetzelfde
   euvel als de oorspronkelijke kaart-sprong, nu een tandje kleiner. Vaste
   `min-height` i.p.v. 0, gemeten op de TWEE-regelige variant (109px in de
   browser, hier 112px met een kleine marge) — ALLE Kwintencirkel-
   tekstvragen (ook de notenquiz, "welke noten…") delen dezelfde
   `id==='circle'`-tak in App.renderData() en dus deze klasse, dus dit dekt
   ze allemaal in één keer. Een eventuele kortere, één-regelige vraag
   centreert er gewoon binnen (bestaande `.fc-stage > *{margin-block:auto}`
   hierboven) — geen wijziging nodig aan hoe qParMinorAcc/qParMajorAcc de
   twee-regelige zin nu met een expliciete `<br>` afbreekt op de zin-grens
   (lang.js), i.p.v. een kaal woord-wrap ergens midden in de zin. */
.fc-stage.fc-stage-compact{ min-height:112px; flex:0 0 auto; padding-block:var(--sp-2); }
.fc-answer{
  min-height:158px; display:flex; flex-direction:column;
  align-items:center; justify-content:center;
}
/* v0.86.0 (gebruikersmelding: "het veld verspringt geregeld... met name
   als je een noot moet aanklikken") — band C was op 108px (132px mobiel)
   afgestemd op de KORTE inhoud (Meerkeuze-rij, zelfrapportage-vinkjes),
   terwijl de Kwintencirkel-notenquiz (`#cn-row`+"Controleren"+resultaatregel,
   zie `_renderCircleNotesQuiz()`) daar met ~178px ruim overheen groeide.
   EERSTE poging verhoogde band C naar 185px/210px (ruimte voor de langste
   inhoud) — GEBRUIKERSFEEDBACK: dat gaf juist een lelijke lege kloof op de
   kortere Meerkeuze-vragen ("super veel vrije ruimte"). Losse, betere fix:
   de "Controleren"-knop bleek zelf overbodig (zie het vervolgpunt hieronder)
   — zonder die knop mat de notenquiz nog maar ~111px.
   VERVOLG (nieuwe gebruikersmelding, Vorige/Volgende sprong nog steeds mee
   zodra "Goed!/Fout! Antwoord: …" verscheen): #cn-result reserveert sindsdien
   ALTIJD zijn regelhoogte (zie .cn-result hieronder) — dat legde er zelf
   weer ~34px bovenop, dus de notenquiz meet nu ~156px. 158px (was 116px) is
   de nieuw geverifieerde marge die alle Kwintencirkel-vraagvormen (gewone
   Meerkeuze ÉN de notenquiz) weer zonder merkbaar gat/sprong gelijk houdt.
   Derde punt uit dezelfde eerdere melding: de losse "Controleren"-knop in
   de notenquiz liet SRS-registratie helemaal achterwege zodra je "Volgende"
   gebruikte zonder 'm eerst in te drukken (een hele sessie zo doorlopen gaf
   0 goed/0 fout) — knop weg, "Volgende" controleert nu zelf via
   `App._cnCheck()` (zie `_revealsBeforeAdvance()`/`nextQuestion()` in
   app-core.js), zelfde tweetrapspatroon als Meerkeuze/open-vraag. */
@media (max-width:560px){
  /* S3-07 — band C op mobiel hoger, inhoud bovenaan i.p.v. gecentreerd, met
     eigen onderpadding. 182px (was 132px) — zelfde marge-redenering als
     hierboven. */
  .fc-answer{ min-height:182px; justify-content:flex-start; padding-bottom:var(--sp-5); }
}

/* Flashcard-sessie (v0.43.0) — voortgangsbalk, nu gewoon in de normale
   documentstroom van band A i.p.v. absoluut over de kaart-padding heen. */
#session-bar{ display:flex; align-items:center; gap:var(--sp-3); width:100%; }
#session-bar[hidden]{ display:none; }
.session-bar-track{
  flex:1; height:6px; border-radius:var(--r-pill); overflow:hidden;
  background:var(--surface2);
}
.session-bar-fill{
  display:block; height:100%; border-radius:var(--r-pill); background:var(--accent);
  transition:width var(--mo-3) var(--ease);
}
/* S3-05 — teller: mono 11,5px, tabulair. */
.session-bar-count{
  font-family:'JetBrains Mono',monospace; font-size:11.5px; font-weight:600; color:var(--muted);
  font-variant-numeric:tabular-nums; white-space:nowrap; flex:0 0 auto;
}
#session-end, #scroll-end{ width:100%; display:flex; justify-content:center; }
#session-end[hidden], #scroll-end[hidden]{ display:none; }
#scroll-end{ padding:var(--sp-5) 0; }
/* §4 resultatenscherm (S4) — anatomie: bovenschrift -> % -> woord ->
   verdeelbalk -> legenda -> pillen -> twee knoppen. Gat --sp-4. */
.session-end-card{
  text-align:center; width:100%; max-width:var(--w-focus); padding:var(--sp-7) var(--sp-4);
  display:flex; flex-direction:column; align-items:center; gap:var(--sp-4);
}
.session-end-eyebrow{
  font-family:'JetBrains Mono',monospace; font-size:10.5px; font-weight:600;
  letter-spacing:.12em; text-transform:uppercase; color:var(--faint);
}
/* S4-02 — percentage: Fraunces 64px (52 mobiel), tabulair. */
.session-end-score{
  font-family:'Fraunces',serif; font-weight:600; font-size:64px; line-height:.98; letter-spacing:-.03em;
  color:var(--text); font-variant-numeric:tabular-nums;
}
.session-end-pct{ font-size:26px; color:var(--muted); margin-left:2px; }
/* S4-03 — woord: 16px/600. */
.session-end-sub{ font-size:16px; font-weight:600; color:var(--text); margin:0; }
/* S4-04 — verdeelbalk: volle breedte, 10px, --r-pill, spoor --surface2. */
.session-end-split{
  width:100%; height:10px; border-radius:var(--r-pill); overflow:hidden;
  background:var(--surface2); display:flex;
}
.session-end-split .seg-ok{ background:var(--ok); }
.session-end-split .seg-err{ background:var(--err); }
/* S4-05 — legenda: vierkantje 18×18 --r-sm, 12,5px/600 tabulair. */
.session-end-legend{ display:flex; gap:var(--sp-4); font-size:12.5px; font-weight:600; font-variant-numeric:tabular-nums; }
.session-end-legend span{ display:inline-flex; align-items:center; gap:var(--sp-2); }
.session-end-legend .leg-box{ width:18px; height:18px; border-radius:var(--r-sm); display:inline-flex; align-items:center; justify-content:center; font-size:11px; }
.session-end-legend .leg-ok{ background:var(--ok-soft); color:var(--ok); }
.session-end-legend .leg-err{ background:var(--err-soft); color:var(--err); }
/* S4-06 — zwakke onderdelen: losse pillen in --off-soft/--off. */
.session-end-weak{
  display:flex; flex-wrap:wrap; gap:var(--sp-2); justify-content:center;
  font-size:12.5px; color:var(--muted); margin:0; line-height:1.5;
}
.session-end-weak .weak-pill{
  font-size:12.5px; font-weight:600; padding:var(--sp-1) var(--sp-3); border-radius:var(--r-pill);
  background:var(--off-soft); color:var(--off);
}
.session-end-perfect{ font-size:13.5px; color:var(--ok); font-weight:600; margin:0; }
/* S4-07 — twee knoppen, even breed. */
.session-end-actions{ display:flex; gap:var(--sp-2); width:100%; margin-top:var(--sp-2); }
.session-end-actions button{ flex:1 1 0; }

/* Toonladders "Oefenen"-modus (sinds v0.20.5) — zelfde vormgevingspatroon
   als #scroll-counter (dikgedrukt, accent-cyaan, gecentreerd): de "X/N
   foutloos"-teller. .drill-flash wisselt tijdelijk naar groen/rood voor
   directe terugkoppeling (voltooid/te langzaam/foute noot), zelfde
   kleurenpaar als #scroll-status/#midi-answer-status hierboven. */
#scale-drill-status{
  font-size:1.05rem; font-weight:800; color:var(--accent); font-family:'JetBrains Mono',monospace;
  text-align:center; margin-bottom:var(--sp-3); transition:color var(--mo-1) var(--ease);
}
#scale-drill-status.drill-flash-correct{ color:var(--ok); }
#scale-drill-status.drill-flash-wrong{ color:var(--err); }
/* Tempo-logboek (sinds v0.20.8) — bewust kleiner/gedimd t.o.v.
   #scale-drill-status hierboven: dat blijft het primaire, opvallende
   signaal (teller + groen/rood-flash), dit is secundaire, blijvend
   zichtbare context eronder. */
#scale-drill-bpm-log{
  font-size:.85rem; font-weight:600; color:var(--muted); font-family:'JetBrains Mono',monospace;
  text-align:center; margin-top:calc(var(--sp-2) * -1); margin-bottom:var(--sp-3);
}
/* Gespeeld tempo, gewone MIDI-modus (sinds v0.20.9) — zelfde opvallende
   stijl als #scale-drill-status (geen streak/doel hier, dus geen
   flash-varianten nodig, puur een simpele tempo-uitlezing). */
#scale-midi-tempo{
  font-size:1.05rem; font-weight:800; color:var(--accent); font-family:'JetBrains Mono',monospace;
  text-align:center; margin-bottom:var(--sp-3);
}
#score-paper{ width:100%; min-width:0; display:flex; justify-content:center; }
#score-paper svg, #answer-score svg{ width:100%; height:auto; display:block; }
/* Toonladders "Handen: Beide" dubbele weergave (Fase 2.7, aanvullend punt 1,
   v0.20.0) — twee gestapelde, onafhankelijke enkele-sleutel-notenbalken. */
#scale-dual-wrap{ display:none; flex-direction:column; align-items:center; width:100%; gap:var(--sp-2); }
/* 100% → 76% (sinds v0.20.5, gebruikersmelding: "noten vallen bij twee
   handen meestal buiten het scherm") — beide notenbalken schalen mee via
   width:100%/height:auto (behouden aspect-ratio), dus een smallere
   container hier verkleint OOK de hoogte evenredig, precies wat nodig is om
   de twee gestapelde notenbalken (+ vingerzetting-cijfers/pillen/knoppen
   eronder) weer binnen een normale vensterhoogte te laten passen zonder te
   hoeven scrollen. Werkt SAMEN met (i.p.v. in plaats van) de octaafplaatsing-
   fix in _bestScaleOctave() hierboven — die vermindert al hoeveel
   hulplijntjes/8va er sowieso nodig zijn, dit is de resterende, structurele
   marge voor toonsoorten waar zelfs de beste plaatsing nog relatief veel
   ruimte kost. */
#scale-dual-treble, #scale-dual-bass{ width:76%; min-width:0; display:flex; justify-content:center; }
#scale-dual-treble svg, #scale-dual-bass svg{ width:100%; height:auto; display:block; }
#circle-chord-preview svg{ width:100%; height:auto; display:block; }
#answer-score{ margin-top:var(--sp-2); width:100%; min-width:0; max-width:460px; display:flex; justify-content:center; }
#svg-container{ width:100%; display:none; flex-direction:column; align-items:center; padding:var(--sp-3) 0; gap:var(--sp-3); position:relative; }

/* Lopende-band-modus (Fase 1.2, Noten Lezen) — child van #svg-container,
   net als .circle-main; welke van de twee zichtbaar is bepaalt
   App.renderData(). left:140px van de hit-lijn-marker MOET gelijk blijven
   aan ScrollEngine.HIT_LINE_X in scroll-engine.js (CSS kan geen JS-
   constante lezen, dus twee losse plekken die bij wijziging allebei
   bijgewerkt moeten worden). Zelfde voor height:380px, MOET gelijk blijven
   aan ScrollEngine.CANVAS_H × ScrollEngine.RENDER_SCALE (270×1.4=378,
   naar boven afgerond) — anders wordt de notenbalk weer afgesneden (zie
   de toelichting bij CANVAS_H/RENDER_SCALE in scroll-engine.js).
   max-width verwijderd (was 560px) — op verzoek "maximaliseren op de
   flashcard" i.p.v. een smal apart venstertje: vult nu gewoon de volledige
   breedte die .flashcard toelaat (zelf al begrensd op max-width:1400px). */
#scroll-view{ display:none; flex-direction:column; align-items:center; gap:var(--sp-4); width:100%; }
/* Sessie-teller (sinds v0.11.0): de hele lopende-band-sessie is nu één
   doorlopende reeks (100 noten) i.p.v. steeds terugspringende reeksjes van
   8 — deze teller toont de voortgang daarin. */
#scroll-counter{
  font-size:1.1rem; font-weight:800; color:var(--accent); font-family:'JetBrains Mono',monospace;
  /* Vooruit Lezen (sinds v0.17.3) zet hier een rijtje losse segmenten
     (tijd/melodie/akkoorden/score, zie .sr-stat hieronder) i.p.v. één platte
     tekstregel — flex+wrap laat dat netjes afbreken op smalle schermen.
     Noten Lezen/Akkoorden se Lopende Band/Challenge zetten hier nog gewoon
     platte tekst (geen kind-elementen), flex heeft daar geen zichtbaar
     effect op. */
  display:flex; flex-wrap:wrap; justify-content:center; align-items:baseline; gap:var(--sp-2) var(--sp-4);
}
.sr-stat{ font-size:.95rem; font-weight:700; color:var(--muted); }
.sr-stat-time, .sr-stat-score{ color:var(--accent); font-weight:800; }
.sr-good{ color:var(--ok); }
.sr-bad{ color:var(--err); }
#scroll-strip-host{
  /* height wordt sinds v0.16.3 per render() door ScrollEngine zelf gezet
     (`element.style.height`, zie _effectiveScale()) — de vaste 380px hier
     is puur een fallback vóór de allereerste render (voorkomt een flits
     van 0-hoogte). ScrollEngine schaalt de notatie op basis van
     window.innerHeight (nooit boven RENDER_SCALE=2.2, nooit onder
     MIN_RENDER_SCALE=1.1) — op een kort scherm (bijv. een compact
     secundair beeldscherm) zou een vaste 2.2×-hoogte de hele flashcard-
     kaart hoger maken dan de viewport, met een onhandige scrollbalk tot
     gevolg (bevestigd met foto's, gefixt in v0.16.3). */
  position:relative; width:100%; height:380px; overflow:hidden;
  border-radius:var(--r-md); background:var(--paper); border:1px solid var(--border);
}
/* left:140px = de --scroll-cursor-x-fallback, moet gelijk blijven aan
   ScrollEngine.HIT_LINE_X. Vooruit Lezen (Fase 3.1) zet --scroll-cursor-x
   inline op #scroll-strip-host naar een verschoven waarde (zie
   ScrollEngine.startChallenge()'s opts.cursorMeasures) zodat de cursor
   verder in de strip staat i.p.v. vlak na de gutter — alle andere
   aanroepers laten deze var weg en vallen terug op 140px. */
#scroll-strip-host::after{
  content:''; position:absolute; left:var(--scroll-cursor-x, 140px); top:0; bottom:0; width:2px;
  background:var(--accent); opacity:.55; pointer-events:none;
}
/* Vaste sleutel-"gutter" (sinds v0.11.0, op verzoek: vioolsleutel/
   bassleutel blijven een herkenningspunt i.p.v. mee te scrollen) — width
   MOET gelijk blijven aan ScrollEngine.GUTTER_W. Ondoorzichtige achtergrond
   (zelfde als het paneel) verbergt wat er in de scrollende laag erachter
   voorbijkomt; z-index boven de scrollende strip, maar ruim vóór
   HIT_LINE_X (140px) zodat de noot bij de hit-lijn nooit overlapt wordt. */
.scroll-gutter{
  position:absolute; left:0; top:0; bottom:0; width:124px; overflow:hidden;
  background:var(--paper); z-index:2; pointer-events:none;
}
#scroll-status{
  font-size:.95rem; font-weight:700; text-align:center; color:var(--muted); transition:color var(--mo-1) var(--ease);
}
#scroll-status.correct{ color:var(--ok); }
#scroll-status.wrong{ color:var(--err); }

/* Meerkeuze-antwoordmodus (sinds v0.20.15) — vervangt "Toon Antwoord" in
   #flashcard-actions wanneer de instelling actief staat, zie
   App._renderAnswerMode() in app-core.js. Zelfde visuele taal als .opt-btn
   (instellingen-knoppen), maar los gehouden i.p.v. hergebruikt — .opt-btn
   se JS-wiring (renderSingleSelect) gaat uit van radiogedrag + instelling-
   opslag, dit hier is een eenmalige quizvraag met een eigen goed/fout-
   status per klik. Groen/rood (var(--ok)/var(--err)) zijn dezelfde kleuren als
   #scroll-status/#midi-answer-status hierboven — één consistente
   goed/fout-taal door de hele app. */
/* S3-04 — Meerkeuze: 4 kolommen op desktop, 2×2 op de telefoon, gat --sp-2. */
#mc-options{
  display:grid; grid-template-columns:repeat(4, 1fr); gap:var(--sp-2);
  width:100%; max-width:var(--w-focus); margin:var(--sp-3) auto 0;
}
@media (max-width:560px){ #mc-options{ grid-template-columns:1fr 1fr; } }
.mc-btn{
  /* v0.86.0 (gebruikersmelding: "noten staan naast i.p.v. onder de naam")
     — de algemene `button{display:flex}` (hierboven) laat de `<br>` +
     `.mc-notes`-span (Intervallen-tweeregel-opmaak) als losse flex-items
     NAAST elkaar belanden i.p.v. de bedoelde regel-afbreking te volgen —
     `display:block` herstelt normale tekstdoorloop, zodat `<br>` weer
     gewoon een regel afbreekt. `.mc-btn` heeft nooit een icoon nodig
     (alleen tekst), dus dit kost geen ander gedrag. */
  display:block;
  background:var(--surface); color:var(--text); border:1.5px solid var(--border);
  border-radius:var(--r-md); padding:var(--sp-3) var(--sp-2); font-weight:600; cursor:pointer;
  font-family:'Fraunces',serif; text-align:center;
  transition:transform var(--mo-1) var(--ease), background-color var(--mo-1) var(--ease), border-color var(--mo-1) var(--ease);
  /* v0.86.0 (gebruikersmelding, Toonladders-Meerkeuze: "opties staan soms
     op 3 regels, beperk dit in alle gevallen tot max 2, tekst wat
     kleiner") — was 17px; het langste realistische geval ("C Pentatonisch
     Mineur") paste daarbij niet in 2 regels binnen de 4-koloms-breedte.
     Geldt voor alle MC-opties (gedeelde klasse), niet alleen Toonladders. */
  font-size:14.5px;
}
@media (hover:hover){ .mc-btn:hover:not(:disabled){ background:var(--surface2); } }
.mc-btn:active:not(:disabled){ transform:scale(.96); }
.mc-btn.mc-correct{ background:var(--ok-soft); border-color:var(--ok); color:var(--ok); }
.mc-btn.mc-wrong{ background:var(--err-soft); border-color:var(--err); color:var(--err); }
/* v0.86.0 — het juiste antwoord bij een GEMISTE (onbeantwoorde) vraag via
   "Volgende" (_mcRevealUnanswered()): rood, zelfde familie als `.mc-wrong`.
   Sinds de bugfix-ronde ná v0.96.3 (Stap ZK3) ook voor _mcAutoTimeout()'s
   bedenktijd-verval (was tot dan toe het neutralere `.mc-timeout` — die
   klasse/regel is nu vervallen, zie de toelichting bij _mcAutoTimeout() in
   app-core.js) — "geen antwoord" hoort er overal hetzelfde (rood) uit te
   zien, ongeacht OF dat kwam door een bedenktijd-verval of een handmatige
   "Volgende"-klik. */
.mc-btn.mc-missed{ background:var(--err-soft); border-color:var(--err); color:var(--err); }
.mc-btn:disabled{ cursor:not-allowed; }
.mc-btn:disabled:not(.mc-correct):not(.mc-wrong):not(.mc-missed){ opacity:.4; }
/* v0.86.0 (Intervallen, gebruikersverzoek: "haakjes weg, noten op een eigen
   regel") — secundaire regel onder een intervalnaam: in .mc-btn (Meerkeuze)
   ÉN #answer-display (open-vraag-onthulling), altijd gedempt/kleiner dan de
   naam erboven — zelfde kleurtaal als .chord-name-alt (circle-wheel.js). */
.mc-notes{
  /* .85em i.p.v. .7em (gebruikersverzoek: "letters onder de omschrijving
     iets groter, zonder dat de knoppen groter worden") — de knop groeit
     hooguit een paar px mee (auto-hoogte op de inhoud), geen aparte
     min-height ergens die hierdoor zou gaan overschrijden. */
  display:block; margin-top:var(--sp-1); font-family:'JetBrains Mono',monospace;
  font-weight:500; font-size:.85em; color:var(--muted); letter-spacing:.01em;
}

/* Cyaan bevestiging van de op MIDI gespeelde noten in Meerkeuze-modus (v0.46.0) */
.mc-midi-notes{
  margin:var(--sp-3) auto 0; text-align:center; font-family:'JetBrains Mono',monospace;
  font-weight:700; font-size:1rem; letter-spacing:.03em;
  color:var(--accent); transition:color var(--mo-1), transform var(--mo-1);
}
.mc-midi-notes.is-correct{ color:var(--play); animation:mc-midi-pop .3s ease; }
.mc-midi-notes.is-wrong{ color:var(--err); }
@keyframes mc-midi-pop{ 0%{ transform:scale(.9); } 60%{ transform:scale(1.08); } 100%{ transform:scale(1); } }

/* Kwintencirkel "Welke noten"-quiz (v0.44.0) */
.cn-quiz{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-3); width:100%; }
.cn-hint{ font-size:.8rem; color:var(--muted); text-align:center; margin:0; max-width:34ch; line-height:1.45; }
.cn-row{ display:flex; gap:var(--sp-2); flex-wrap:wrap; justify-content:center; }
.cn-row.cn-flash{ animation:cn-flash .3s ease; }
@keyframes cn-flash{ 0%,100%{ transform:none; } 50%{ transform:translateX(-3px); } }
.cn-btn{
  min-width:46px; padding:var(--sp-3) var(--sp-2); border-radius:10px; cursor:pointer;
  background:var(--canvas); color:var(--text); border:1px solid var(--border);
  font-family:'JetBrains Mono',monospace; font-weight:700; font-size:1rem;
  display:flex; flex-direction:column; align-items:center; gap:1px; transition:all var(--mo-1) var(--ease);
}
.cn-btn:hover{ border-color:var(--accent); }
.cn-btn .cn-acc{ font-size:.85rem; min-height:1em; color:var(--accent); }
.cn-btn.cn-sel{ background:color-mix(in srgb, var(--accent) 16%, transparent); border-color:var(--accent); }
.cn-btn.cn-ok{ background:var(--ok-soft); border-color:var(--ok); color:var(--ok); }
.cn-btn.cn-ok .cn-acc{ color:var(--ok); }
.cn-btn.cn-no{ background:var(--err-soft); border-color:var(--err); color:var(--err); }
.cn-btn.cn-no .cn-acc{ color:var(--err); }
/* v0.86.0 — live invoerfeedback (klik-cyclus én MIDI), vóór "Controleren":
   amber voor een letter die op dit moment klopt maar eerder fout heeft
   gestaan (`App._cnMarkTouched()`), zelfde kleurfamilie als `.cn-result.
   is-no`/`--off` elders in de app. */
.cn-btn.cn-amber{ background:var(--off-soft); border-color:var(--off); color:var(--off); }
.cn-btn.cn-amber .cn-acc{ color:var(--off); }
/* v0.86.0 (gebruikersmelding: "de knoppen verspringen zodra de regel tekst
   bij controle eronder komt te staan") — `#cn-result` stond t/m "Controleren"
   op `hidden` (dus `display:none`, NEEMT GEEN RUIMTE in). Zodra "Volgende"
   'm onthulde nam de tekst er ineens ruimte bij, en omdat `.fc-answer`
   z'n hele inhoud (hint+rij+resultaat) als één blok verticaal centreert
   (`justify-content:center`), schoof de knoppenrij daardoor zelf ook mee
   naar boven — precies dezelfde "band C wisselt van hoogte"-valkuil als de
   eerdere kaart-sprong, nu op kleinere schaal binnen band C zelf. Fix:
   `#cn-result` reserveert nu ALTIJD z'n regelhoogte (`min-height`) en wordt
   met `visibility` i.p.v. `display`/`hidden` getoond — de ruimte staat er
   dus al vóór "Volgende", niets in band C verandert nog van hoogte. */
.cn-result{ font-size:.9rem; margin:0; text-align:center; line-height:1.5; min-height:1.5em; visibility:hidden; }
.cn-result.is-ok{ color:var(--ok); visibility:visible; }
.cn-result.is-no{ color:var(--off); visibility:visible; }

/* Zelfrapportage-knopjes voor spaced-repetition (Fase 3, sinds v0.20.17) —
   klein en terughoudend (dit is een optioneel achtergrond-signaal, geen
   hoofdinteractie zoals de meerkeuze-knoppen hierboven), vlak onder het
   onthulde antwoord. Zelfde groen/rood-taal als .mc-btn/#scroll-status. */
#answer-selfreport{ display:flex; justify-content:center; gap:var(--sp-3); margin-top:var(--sp-2); }
.selfreport-btn{
  background:var(--canvas); color:var(--muted); border:1px solid var(--border);
  border-radius:50%; width:34px; height:34px; font-size:1rem; font-weight:700; cursor:pointer;
  transition:all var(--mo-1) var(--ease); line-height:1;
}
.selfreport-btn:hover:not(:disabled){ background:var(--border); color:var(--text); }
.selfreport-btn:disabled{ cursor:not-allowed; opacity:.5; }
.selfreport-wrong.active{ background:var(--err); border-color:transparent; color:#fff; opacity:1; }
.selfreport-correct.active{ background:var(--ok); border-color:transparent; color:#fff; opacity:1; }

/* CSS GRID met benoemde gebieden i.p.v. flexbox+order+wrap-trucs — dat
   bleek herhaaldelijk onvoorspelbaar op écht mobiel/tablet/desktop zonder
   dat live te kunnen testen. Grid-template-areas beschrijft de layout
   letterlijk als een ASCII-tekening per breakpoint — geen giswerk.
   Mobiel (standaard): één kolom — wiel, dan notenbalk+toetsenbord, dan
   de knoppenrijen. Vanaf 900px: vier kolommen naast elkaar.
   min-width:0 blijft nodig zodat een brede notenbalk-SVG nooit een kolom
   kan dwingen breder te worden dan zijn grid-track. */
.circle-main{
  width:100%; min-width:0; display:grid; gap:var(--sp-4); position:relative;
  grid-template-columns: 1fr;
  /* Mobiele volgorde: wiel, dan notenbalk+keyboard, dan de
     akkoordsoort-knoppen (extra opties), dan de toets-CTA helemaal onderaan
     (bugfix-ronde ná v0.96.4, punt 18, gebruikersverzoek — op mobiel ligt
     "rechtsboven op de kaart" te dicht op de topbalk/andere iconen; op
     desktop, @media(min-width:900px) hieronder, blijft het wél een los-
     zwevende hoek rechtsboven). */
  grid-template-areas: "wheel" "staff" "chordjump" "cta";
}
/* Toets-CTA — sinds de bugfix-ronde ná v0.96.4, punt 18 een responsive
   wissel: op mobiel (hier, de default) een GEWOON grid-onderdeel onderaan de
   kaart (grid-area:cta hierboven), op desktop (@media hieronder) los-
   zwevend rechtsboven (position:absolute, buiten de grid-flow). */
#circle-quiz-cta{ grid-area:cta; justify-self:center; }
#circle-quiz-cta:empty{ display:none; }
#circle-quiz-cta .help-hint-cta{
  font-size:.82rem; font-weight:700; padding:var(--sp-1) var(--sp-3); border-radius:999px;
  background:transparent; color:var(--accent); border:1px solid var(--accent); cursor:pointer;
}
#circle-quiz-cta .help-hint-cta:hover{ background:color-mix(in srgb, var(--accent) 14%, transparent); }
.circle-left-half{ display:contents; }
.circle-center{
  grid-area:wheel; min-width:0; width:100%; max-width:480px; justify-self:center;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--sp-2);
}
/* Hint boven het wiel (v0.90.0, Plan_van_Aanpak_InModule_Onboarding, Pijler
   2.2). Zie CircleWheel._renderHint(). Sinds de bugfix-ronde ná v0.96.4:
   rij-indeling (tekstblok + kruisje naast elkaar, zelfde .help-hint-x-
   patroon als #theory-hint/.tool-hint/#exercise-hint) i.p.v. een kale
   kolom — de tekstregels zelf (.circle-hint-body) blijven wél gestapeld en
   gecentreerd. */
#circle-hint{
  display:flex; align-items:center; gap:var(--sp-2);
  max-width:400px; font-size:.82rem; color:var(--muted);
}
.circle-hint-body{
  display:flex; flex-direction:column; align-items:center; gap:var(--sp-1);
  flex:1 1 auto; text-align:center;
}
#circle-hint:empty{ display:none; }
#circle-hint .help-hint-cta{
  font:inherit; font-size:.82rem; font-weight:700; padding:var(--sp-1) var(--sp-3); border-radius:999px;
  background:transparent; color:var(--accent); border:1px solid var(--accent); cursor:pointer;
}
#circle-hint .help-hint-cta:hover{ background:color-mix(in srgb, var(--accent) 14%, transparent); }
/* Geen eigen max-width meer (2026-08-27) — width:100% laat dit gewoon de
   breedte van .circle-center (de echte begrenzing, incl. de bredere
   @media(min-width:900px)-waarde) volgen i.p.v. een eigen, lager plafond
   dat die extra breedte alsnog blokkeerde. */
#circle-wheel-wrap{ width:100%; min-width:0; display:flex; justify-content:center; aspect-ratio:1/1; }
#circle-wheel-wrap svg{ width:100%; min-width:0; max-width:100%; height:auto; display:block; aspect-ratio:1/1; }
.circle-right-half{ grid-area:staff; width:100%; max-width:400px; min-width:0; display:flex; flex-direction:column; align-items:center; gap:var(--sp-4); justify-self:center; }
/* Twee rijen (2026-08-27, gebruikersverzoek: meest gebruikte akkoordsoorten
   boven, exotische eronder — zie CircleWheel.renderChordJump()) — de
   flex-row/wrap/gap-opzet die hier vroeger rechtstreeks op #circle-chord-
   jump stond, staat nu op elke .chord-jump-row afzonderlijk; #circle-chord-
   jump zelf is alleen nog de verticale stapel-container. */
#circle-chord-jump{ grid-area:chordjump; display:flex; flex-direction:column; gap:var(--sp-2); max-width:320px; justify-self:center; }
.chord-jump-row{ display:flex; flex-direction:row; flex-wrap:wrap; justify-content:center; gap:var(--sp-2); }
/* Akkoordnaam-label (gebruikersverzoek, v0.20.0 — ná live MIDI-test bleek
   het herkende akkoord nergens als TEKST genoemd te worden, alleen via de
   notenbalk/toetsenbord-weergave) — CircleWheel.showChord() zet hier bij
   ELKE weergave (klik én MIDI) de root+soort in, bijv. "C Majeur". */
/* Losse noot-namen boven de akkoordnaam — zelfde functie als Virtuele
   Piano se .pnd-notes, monospace. Was tot 2026-08-27 bewust kleiner/
   gedempt (--muted, .95rem) zodat de akkoordnaam eronder de
   hoofdregel bleef; op gebruikersverzoek OMGEDRAAID — deze noot-letters
   zijn nu juist de prominentste regel (wit/--text, groter dan
   #circle-chord-name's 1.2rem eronder). */
#circle-chord-notes{
  font-family:'JetBrains Mono',monospace; font-weight:700; font-size:1.4rem; color:var(--text);
  text-align:center; letter-spacing:.02em; min-height:1.3em;
}
#circle-chord-name{
  font-family:'Fraunces',serif; font-weight:600; font-size:1.2rem; color:var(--text); text-align:center;
  /* Vaste hoogte i.p.v. min-height (2026-08-27, gebruikersmelding, zelfde
     fix als .piano-note-display hierboven) — bij meerdere leeswijzen
     (bijv. een symmetrisch Aug-akkoord: 1 primaire naam + 2 alternatieven =
     3 regels) groeide dit element, wat de notenbalk/mini-klavier eronder
     én — via de gedeelde grid-rij op breed scherm — de kwintencirkel zelf
     liet verspringen. 3.4em = de gemeten worst-case (3 regels), bewust
     géén min-height meer zodat het nooit verder groeit. */
  height:3.4em;
  display:flex; flex-direction:column; justify-content:center; gap:2px; align-items:center;
}
/* BL-1.8 — MIDI-afkomst: was --accent (cyaan/merkkleur), maar een gespeelde
   noot/akkoord is per de huisstijl `--play` (violet), geen merkkleur (zie
   L1-21 in de werklijst — die conversie gold tot nu toe alleen voor
   .mc-midi-notes.is-correct, niet voor deze twee MIDI-afkomst-indicatoren). */
#circle-chord-name.midi{ color:var(--play); }
/* Meerdere mogelijke akkoordnamen (2026-08-26, gebruikersverzoek): de
   primaire (meest voor de hand liggende) naam blijft gewoon de bestaande
   kleur volgen (cyaan bij MIDI-afkomst, zie .midi hierboven); elke
   alternatieve leeswijze eronder in --muted en iets kleiner, zodat
   de primaire naam duidelijk het "hoofdantwoord" blijft. Was --icon-g2
   (paars/magenta) t/m 2026-08-27 — gebruikerswens om paars minder prominent
   te maken op precies deze tekst, zie de toelichting bij :root in dit
   bestand. Ook hergebruikt voor de expliciete "Onbekend akkoord"-status
   (showUnknownChord()).*/
.chord-name-primary{ color:inherit; }
.chord-name-alt{ color:var(--muted); font-size:.8em; font-weight:500; }
.chord-name-unknown{ color:var(--muted); font-size:.9em; font-style:italic; }
/* 380px i.p.v. 330px (2026-08-27) — meegeschaald met de bredere
   .circle-right-half hierboven (400px basis/460px breed scherm, zie
   @media(min-width:900px)), zelfde 82,5%-verhouding aangehouden zodat de
   bewuste zijruimte rond notenbalk/klavier evenredig meegroeit i.p.v. óf
   leeg te blijven óf ineens randvullend te worden. */
#circle-chord-preview{ min-width:0; min-height:60px; max-width:380px; overflow:hidden; display:flex; align-items:center; justify-content:center; width:100%; }
/* Breedte gelijk getrokken met #circle-chord-preview hierboven (2026-08-27,
   gebruikersverzoek) — zelfde max-width, dus beide schalen samen mee op elk
   schermformaat. Geen overflow-x:auto meer nodig: MiniKeyboard (piano-ui.js)
   geeft elke toets voortaan een PROCENTUELE breedte i.p.v. een vaste
   pixelbreedte, dus de rij vult altijd exact deze container-breedte, hoeveel
   toetsen er ook nodig zijn (het dynamische bereik, min. 1 octaaf+terts, max.
   2 octaven — zie MiniKeyboard.MIN_SPAN/MAX_SPAN). */
#circle-keyboard-wrap{ display:flex; justify-content:center; justify-content:safe center; min-width:0; min-height:40px; align-items:center; max-width:380px; width:100%; }

@media (min-width:820px){
  /* Twee kolommen (wiel, staff) i.p.v. voorheen vier (2026-08-27,
     gebruikersverzoek: de losse "Toonsoort"-sprongenlijst-kolom is
     vervallen, zie de toelichting bij CircleWheel.render() in
     circle-wheel.js) — Toontypes ("chordjump") staat nu in een eigen rij
     ONDER wiel+staff i.p.v. een vijfde kolom, en spant beide kolommen
     (zelfde area-naam in beide cellen van rij 2). De vrijgekomen breedte
     gaat naar grotere minmax-caps op beide overgebleven kolommen. */
  .circle-main{
    grid-template-columns: minmax(360px, 620px) minmax(360px, 520px);
    grid-template-areas: "wheel staff" "chordjump chordjump";
    align-items:center; gap:var(--sp-6); justify-content:center;
  }
  .circle-center{ width:100%; max-width:620px; }
  #circle-chord-jump{ max-width:none; justify-self:center; margin-top:var(--sp-1); }
  .circle-right-half{ width:auto; max-width:460px; padding-top:0; justify-self:stretch; }
  /* Toets-CTA: vanaf hier los-zwevend rechtsboven i.p.v. het mobiele
     grid-onderdeel onderaan (zie de basisregel hierboven) — geen "cta" meer
     in grid-template-areas nodig, position:absolute valt sowieso buiten de
     grid-flow. */
  #circle-quiz-cta{ position:absolute; top:var(--sp-3); right:var(--sp-3); z-index:5; justify-self:auto; }
}

html.fullscreen-active #workspace{ padding:var(--sp-5); }
/* Bugfix-ronde ná v0.96.3 (gebruikersmelding): deze regel gold voorheen voor
   ELKE .flashcard, dus ook Noten Lezen/Toonladders/Intervallen/Akkoorden in
   hun gewone (niet-verbrede) weergave — die werden daardoor in fullscreen
   onbedoeld tot 98vw uitgerekt i.p.v. hun normale --w-focus (640px) te
   behouden. Nu net als de niet-fullscreen breedtes hierboven (.fc-wide/
   .fc-scales-wide) SCOPED tot alleen de "eigen weergave"-modi die al bewust
   breder zijn (Kwintencirkel Verkennen, Noten/Akkoorden-band/Challenge,
   Toonladders-Spelen, Progressies-Reeks — zie de .fc-wide-toggle in
   app-core.js) — de normale flashcard-modi (en .fc-scales-wide, dat zijn
   eigen 1000px-cap had zonder deze regel al zichtbaar) blijven ongemoeid. */
html.fullscreen-active .flashcard.fc-wide{ max-width:min(1800px, 98vw); }
html.fullscreen-active .circle-jump-btn{ font-size:1rem; height:40px; padding:0 var(--sp-3); }
/* Breedte NIET meer hier (2026-08-27) — MiniKeyboard.render() (piano-ui.js)
   zet width/margin-left/margin-right inline per toets (procentueel, zie de
   toelichting bij #circle-keyboard-wrap hierboven), dat wint sowieso altijd
   van een class-gebaseerde regel. Alleen de hoogte blijft hier. */
html.fullscreen-active .mini-key.white{ height:112px; }
html.fullscreen-active .mini-key.black{ height:68px; }
html.fullscreen-active .mini-key .mk-dot{ width:15px; height:15px; bottom:22px; }
html.fullscreen-active .mini-key.black .mk-dot{ bottom:9px; }

/* "Blauw op grafiet" (F4) — het wiel roteert niet meer; C majeur staat vast
   op 12 uur. Van toonsoort wisselen is een segment aanklikken (geen sleep-
   rotatie meer), dus geen grab-cursor. */
#circle-svg{ display:block; width:100%; height:auto; }
.seg{ cursor:pointer; }
/* Bugfix v0.85.2, HERZIEN v0.86.0: `outline` op een <g> volgt de
   rechthoekige bounding box van BEIDE ringdelen samen (majeur+mineur-
   taartpunt) — dat gaf een lelijk vierkant dwars over het wiel i.p.v. de
   taartpunt zelf te markeren (gebruikersmelding: "als ik klik zie ik een
   vierkant", nogmaals gemeld ná v0.85.2). `drop-shadow` volgt wél de
   daadwerkelijk getekende (niet-transparante) vorm, dus dat licht precies
   de aangeklikte taartpunt op.
   v0.85.2 richtte dit alleen op `:focus-visible`, in de veronderstelling dat
   Chromium dat ook bij een muisklik op een niet-natief interactief element
   zet — LIVE GEVERIFIEERD dat dat niet zo is: een muisklik op `.seg` matcht
   wél `:focus` maar NIET `:focus-visible` (`el.matches(':focus-visible')` →
   false, `el.matches(':focus')` → true, browser-default `outline:auto`
   bleef dus gewoon staan). Fix: de regel geldt nu voor het bredere `:focus`
   i.p.v. `:focus-visible` — dekt zowel muisklik als toetsenbord/tab, en
   dient meteen als de gevraagde "klik-animatie" (zoals de tegels op het
   overzicht die ook op klik geven). */
.seg:focus{ outline:none; animation:seg-focus-pulse .5s ease-out forwards; }
@keyframes seg-focus-pulse{
  0%   { filter:drop-shadow(0 0 0 transparent); }
  35%  { filter:drop-shadow(0 0 10px var(--accent)) drop-shadow(0 0 10px var(--accent)); }
  100% { filter:drop-shadow(0 0 4px var(--accent)); }
}
.seg-hit{ fill:transparent; }

.circle-jump-btn{
  width:56px; height:32px; padding:0 var(--sp-2); border-radius:var(--r-sm); font-size:.76rem; font-weight:700;
  color:var(--notation); background:var(--surface2); border:1px solid var(--border); flex-shrink:0; font-family:'JetBrains Mono',monospace;
  transition:all var(--mo-1) var(--ease);
}
.circle-jump-btn:hover{ background:var(--surface2); }
/* Effen cyaan i.p.v. de gradient (gebruikersverzoek, v0.20.0, vervolg —
   zelfde reden als button.primary/.opt-btn.active hierboven: consistent
   met de rest van de app). Tekstkleur via --accent-ink i.p.v. altijd wit —
   in dark mode is --accent een felle, lichte cyaan, dus wit-op-wit-achtig
   contrast; --accent-ink is daar donkerblauw. In light mode blijft dit
   gewoon wit (--accent-ink is daar #fff, --accent zelf al dieper cyaan). */
.circle-jump-btn.active{ color:var(--accent-ink); background:var(--accent); border-color:transparent; box-shadow:0 4px 12px color-mix(in srgb, var(--accent) 35%, transparent); }
.circle-jump-btn.chord{ width:60px; }

/* width/margin-left/margin-right:NIET meer hier (2026-08-27) — gezet via
   inline style per toets in MiniKeyboard.render() (piano-ui.js), procentueel
   t.o.v. #circle-keyboard-wrap i.p.v. een vaste pixelbreedte (zie daar). */
.mini-key-row{ display:flex; align-items:flex-start; width:100%; }
.mini-key{ position:relative; flex-shrink:0; user-select:none; }
.mini-key.white{ height:100%; background:var(--key-white); border:1px solid var(--key-edge); border-radius:0 0 4px 4px; z-index:1; box-sizing:border-box; }
.mini-key.black{ height:62%; background:var(--key-black); z-index:2; border-radius:0 0 3px 3px; box-sizing:border-box; }
.mini-key .mk-dot{ position:absolute; left:50%; transform:translateX(-50%); width:11px; height:11px; border-radius:50%; bottom:18px; box-shadow:0 1px 3px rgba(0,0,0,.35); }
.mini-key.black .mk-dot{ bottom:8px; }
.mini-key .mk-dot.root{ background:var(--accent); }
.mini-key .mk-dot.tone{ background:var(--ok); }
/* MIDI-afkomst-kleurcode (Fase 2.7, aanvullend punt 3, v0.20.0) — grondtoon
   én overige noten dezelfde kleur, zolang de weergave het gevolg is van
   MIDI-input i.p.v. een klik op het scherm (Kwintencirkel). De klik/MIDI-
   afkomst blijft te zien doordat een MIDI-akkoord ALLE stipjes (ook de
   niet-grondtoon-noten) uniform kleurt, terwijl een klik grondtoon=accent/
   overige=groen gemengd toont.
   BL-1.8 — terug naar `--play` (violet): een tussentijdse ronde had dit op
   `--accent` gezet ("past beter naast .mk-dot.root"), maar een gespeelde
   noot is per de huisstijl geen merkkleur — zie ook #circle-chord-name.midi
   hierboven, dezelfde correctie. */
.mini-key .mk-dot.midi{ background:var(--play); }

@media (max-width:560px) {
    /* S7-10 — geen vaste toetshoogte meer; de .mini-key-row-verhouding
       bepaalt de hoogte, de toetsen volgen op 100% / 62%. */
    .mini-key .mk-dot { width: 8px; height: 8px; bottom: 12px; }
    .mini-key.black .mk-dot { bottom: 5px; }
}

.text-quiz-display{ font-size:1.5rem; font-weight:bold; text-align:center; margin:var(--sp-4) 0; display:none; }
/* v0.86.0 (gebruikersverzoek: kernwoorden van de Kwintencirkel-vraag
   uitlichten, bijv. "voortekens" en "D mineur") — `.text-quiz-display`
   staat al op `font-weight:bold`, dus een `<strong>` alléén zou niets
   zichtbaars doen (Fraunces is hier alleen geladen t/m gewicht 700, er is
   geen zwaarder gewicht om naar te "bolderen"). Kleur is hier het
   onderscheid i.p.v. gewicht. */
.text-quiz-display .q-em{ color:var(--accent); }
/* Vraagtekst + "Weet je het al?"-knop (v0.87.1) — zie de toelichting bij
   #fc-question/#fc-reveal-btn in index.html. */
#fc-question{
  font-family:'Fraunces',serif; font-weight:600; font-size:1rem; color:var(--text);
  text-align:center; margin:0 0 var(--sp-2);
}
/* Plan_van_Aanpak_v1.0_Bugfix_MIDI_en_OpenVraag §1 (Item B, gebruikers-
   verzoek): de losse "Weet je het al?"-knop maakte het scherm onnodig druk
   — CSS-verborgen i.p.v. uit de DOM/JS gehaald (zie index.html/app-core.js
   voor de toelichting). Vervangen door #fc-reveal-hint hieronder. */
.fc-reveal-btn{ display:none !important; }
#fc-reveal-hint{
  font-size:.78rem; color:var(--muted); text-align:center; font-style:italic;
  margin:0 0 var(--sp-2); line-height:1.4;
}
#answer-display{
  margin-top:var(--sp-3); margin-bottom:var(--sp-3); font-size:1.4rem; font-weight:800; font-family:'JetBrains Mono',monospace;
  color:var(--accent-hover); min-height:34px; opacity:0; transition:opacity var(--mo-3); text-align:center;
  /* Kaart-flip-reveal (Fase 4, sinds v0.20.18) heeft loodrecht perspectief
     nodig om de rotateX()-animatie hieronder er daadwerkelijk 3D uit te
     laten zien i.p.v. een platte verticale squash. */
  perspective:400px;
}
#answer-display.visible{ opacity:1; }
/* Kaart-flip-reveal (Fase 4, sinds v0.20.18, mobiel/no-MIDI-leerverrijking
   vervolg) — een korte 3D-flip (alsof de kaart "omklapt" naar het
   antwoord) i.p.v. de kale opacity-fade hierboven, plus een cyaan gloed-
   puls die dezelfde curve/kleurtaal volgt als de bestaande .glitter-shine-
   sweep/key-glow-*-effecten elders in de app (zie daar). ALLEEN de nieuwe
   animatie zit achter de reduced-motion-guard — de gewone opacity-
   transition hierboven blijft als vanzelfsprekende fallback bestaan voor
   wie animaties liever uitgezet heeft (dit is de EERSTE plek in de app die
   `prefers-reduced-motion` respecteert; toekomstige animaties kunnen
   ditzelfde patroon volgen, zie Root_Note_Context.md). */
@media (prefers-reduced-motion: no-preference){
  #answer-display.visible{ animation:answer-flip-in .5s cubic-bezier(.34,1.56,.64,1), answer-flip-glow .8s ease-out; }
}
/* v0.58.0 (a11y): wie "verminderde beweging" in het OS heeft aangezet, krijgt
   overal (bijna) geen animaties/transities meer. De lopende notenbalk +
   ritme-timing lopen via requestAnimationFrame / de audioklok, niet via
   CSS-transitions, dus die blijven werken. De kwintencirkel-draai (CSS
   transition op transform) wordt een directe sprong — voor een
   reduced-motion-gebruiker de bedoeling. */
/* L1-13 / B-25 — de beweging verdwijnt, de terugkoppeling niet.
   transform/box-shadow/border-color/background gaan naar 0ms; ALLEEN opacity
   houdt --mo-2 (een scherm dat wisselt mag vervagen, niet schuiven).
   Indrukken wordt een vlakverandering. Het skeleton (2.3) staat stil maar
   blijft zichtbaar (animation-iteration-count:1). */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    scroll-behavior:auto !important;
    transition-property:opacity !important;
    transition-duration:var(--mo-2) !important;
  }
  button:active, .primary:active, .opt-btn:active, .opt-all-btn:active,
  .mc-btn:active, .cn-btn:active, .tl-choice:active,
  .tile-btn:active, .tl-mod-row:active, .tl-cap-card:active,
  .rhythm-tap-btn:active, #init-overlay .brand-launch-btn:active{
    transform:none !important; background:var(--surface2) !important;
  }
}
@keyframes answer-flip-in{
  0%{ transform:rotateX(-90deg); }
  100%{ transform:rotateX(0deg); }
}
/* L1-28 — was hardcoded neon-cyaan; nu volgt de flits het thema-accent. */
@keyframes answer-flip-glow{
  0%{ text-shadow:0 0 0 color-mix(in srgb, var(--accent) 0%, transparent); }
  35%{ text-shadow:0 0 14px color-mix(in srgb, var(--accent) 85%, transparent); }
  100%{ text-shadow:0 0 0 color-mix(in srgb, var(--accent) 0%, transparent); }
}

/* MIDI-akkoordcontrole (Fase 2.2): neutraal = "aan het luisteren" (gedimd,
   volgt tekstkleur), correct = groen, fout = rood — bewust GEEN eigen
   kleurvariabelen, dit zijn de enige twee plekken in de app die
   goed/fout-feedback tonen dus vaste kleuren volstaan. */
#midi-answer-status{
  margin-top:calc(var(--sp-2) * -1); margin-bottom:var(--sp-3); font-size:.95rem; font-weight:700; text-align:center;
  color:var(--muted); transition:color var(--mo-1) var(--ease);
}
#midi-answer-status.correct{ color:var(--ok); }
#midi-answer-status.wrong{ color:var(--err); }
/* Plan_van_Aanpak_v1.0 Deel 1, §2.7 — Kwintencirkel-keyboard-vraagtypen
   ("Speel de relatieve mineur"/"Speel het dominant-akkoord"), zelfde opzet
   als .cn-quiz/.cn-hint hierboven maar met een eigen statusregel i.p.v.
   een knoppenrij (zie App._renderCirclePlayQuiz()). */
.cp-quiz{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-2); width:100%; }
.cp-hint{ font-size:.85rem; color:var(--muted); text-align:center; margin:0; max-width:34ch; line-height:1.45; }
.cp-status{ font-size:.95rem; font-weight:700; text-align:center; color:var(--muted); margin:0; min-height:1.3em; }
.cp-status.correct{ color:var(--ok); }
.cp-status.wrong{ color:var(--err); }

/* MIDI-toonladder-speel-na (Fase 2.3): één "pil" per noot van de reeks —
   grijs = nog niet bereikt, accentkleur+rand = huidig verwachte noot, groen
   = correct gespeeld (voltooid), rood = korte foutmelding op de HUIDIGE pil
   (schuift pas door bij een juiste noot, zie App._evaluateMidiScaleStep). */
#midi-scale-progress{
  margin-top:calc(var(--sp-2) * -1); margin-bottom:var(--sp-3); display:flex; flex-wrap:wrap; justify-content:center; gap:var(--sp-1);
}
/* v0.83.5 (gebruikersverzoek: "die vierkante blokjes onder de notenbalk
   mogen weg, de noten kleuren al mee") — de onderliggende voortgangs-/
   fumble-logica in midi-wiring.js (`_buildMidiScaleProgress` e.a., ruim 10
   aanroepplekken) blijft ONGEWIJZIGD, want die stuurt ook de score/drill-
   afhandeling; alleen de VISUELE rij verdwijnt. `!important` is nodig omdat
   die JS-functies zelf `progress.style.display` (inline) zetten — een
   gewone externe regel zou daar altijd van verliezen. JS-checks als
   `progress.style.display !== 'none'` lezen de INLINE waarde (ongemoeid
   door deze CSS), dus alle bestaande status-logica blijft feilloos werken. */
#midi-scale-progress{ display:none !important; }
/* BUGFIX (2026-08-26, gebruikersfeedback: "Intervallen-meerkeuze-badges
   vallen over de knoptekst heen"): de -6px hierboven is afgestemd op de
   GEWONE context van dit element (vlak onder #score-paper/#answer-score in
   de normale notenbalk-/zelf-raden-weergave, waar een kleine optrek prima
   oogt). Zodra Meerkeuze-antwoordmodus actief is, staat #mc-options
   (de 4 antwoordknoppen) ervoor in plaats daarvan — dezelfde negatieve
   marge trekt de "1"/"2"-notenvoortgangspillen dan over de onderrand van de
   laatste knop heen. Positieve marge i.p.v. negatief, ALLEEN wanneer
   #mc-options zichtbaar is (inline style="display:flex", zie
   App._renderAnswerMode()) — twee ID's + attribuutselector wint sowieso van
   de basisregel hierboven, dus geen !important nodig. */
#mc-options[style*="grid"] ~ #midi-scale-progress{ margin-top:var(--sp-3); }
.midi-scale-note{
  min-width:28px; height:24px; padding:0 var(--sp-2); border-radius:6px; display:flex; align-items:center; justify-content:center;
  font-size:.72rem; font-weight:700; font-family:'JetBrains Mono',monospace;
  background:var(--surface2); color:var(--muted); border:1px solid var(--border);
  transition:background-color var(--mo-1) var(--ease), color var(--mo-1) var(--ease), border-color var(--mo-1) var(--ease);
}
.midi-scale-note.current{ border-color:var(--accent); color:var(--notation); }
.midi-scale-note.done{ background:var(--ok); color:#fff; border-color:transparent; }
.midi-scale-note.wrong{ background:var(--err); color:#fff; border-color:transparent; }

/* S3-03 — band D: één rij van drie, vaste 56px hoogte.
   v0.86.0 (gebruikersmelding: "Speel Af staat niet mooi gecentreerd") — was
   een flex-rij met auto-margins (Volgende: margin-left:auto, Speel Af:
   margin:0 auto); met twee AUTO-marges tussen Speel Af en Volgende
   tegenover maar één ervoor, verdeelt de vrije ruimte zich 2:1 en schuift
   Speel Af zichtbaar naar Vorige toe i.p.v. écht midden op de kaart. Een
   expliciete 3-koloms grid (buiten-kolommen 1fr, middelste kolom naar
   inhoud) centreert de middelste knop ONGEACHT hoe breed Vorige/Volgende
   zijn — ook als de middelste kolom leeg is (Meerkeuze-modus verbergt
   Speel Af/Toon Antwoord) blijft Vorige links en Volgende rechts staan. */
.flashcard-actions{
  width:100%; max-width:var(--w-focus); min-height:56px;
  display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:var(--sp-3);
}
.fc-nav-btn{ font-size:13.5px; }
#btn-prev{ grid-column:1; justify-self:start; }
#btn-play{ grid-column:2; justify-self:center; }
#btn-next{ grid-column:3; justify-self:end; }
/* Fase 5-nazorg — "Afspelen" werd een bredere tekst-pil, gecentreerd tussen
   Vorige/Volgende (i.p.v. twee kleine ronde icoonknoppen naast elkaar, zie
   index.html voor de reden dat het "Toon antwoord"-oogje verviel). */
.fc-play-btn-ico{ display:inline-flex; width:16px; height:16px; flex-shrink:0; }
.fc-play-btn-ico svg{ width:100%; height:100%; display:block; }
.swipe-hint{ text-align:center; font-size:11.5px; color:var(--faint); margin-top:var(--sp-2); }
@media (max-width:560px){
  .fc-nav-btn{ font-size:13px; padding:var(--sp-2) var(--sp-3); }
}

#piano-module{ display:none; flex-direction:column; width:100%; height:100%; background:var(--canvas); overflow:hidden; transition:background-color var(--mo-3); }
.piano-ui-controls{ display:flex; justify-content:space-between; width:100%; max-width:600px; margin:0 auto; padding:var(--sp-5); gap:var(--sp-3); }
.piano-btn{ flex:1; }
/* Toets-highlight + akkoordherkenning (Fase 2.7, punten 9+10) — toont de
   naam/namen van de momenteel ingedrukte noten (met-de-hand of MIDI, zelfde
   gedeelde event-stream), plus een herkend akkoord als 2+ noten samen een
   bekend type vormen. &nbsp; als lege-staat placeholder houdt de regel-
   hoogte vast zodat de rest van het scherm niet springt zodra er iets komt
   te staan. */
.piano-note-display{
  text-align:center; padding:0 var(--sp-5) var(--sp-2); font-size:1.05rem; font-weight:700;
  color:var(--text); letter-spacing:.02em; transition:color var(--mo-3);
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px;
  /* Vaste hoogte i.p.v. min-height (2026-08-27, gebruikersmelding): zodra er
     een akkoordnaam bij komt (notenregel + naam = 2 regels) sprong de hele
     pagina (incl. het klavier) omlaag, want min-height reserveerde maar ÉÉN
     regel. 5.25em is de WORST-CASE hoogte (4 regels: notenregel +
     akkoordnaam + 2 alternatieve leeswijzen) — brute-force gecheckt over elk
     akkoordtype/grondtoon in MusicTheory.chords, alleen symmetrische
     akkoorden (Aug/Aug7, elke grondtoon) bereiken dit maximum (3
     alternatieven). De 2-regelige normale staat (verreweg de meeste
     akkoorden) heeft dus wat lucht eronder i.p.v. de zeldzame Aug-staat af
     te knippen — bewuste afweging, nooit meer springen weegt zwaarder. */
  height:5.25em;
}
.piano-note-display .pnd-notes{ color:var(--text); }
/* Meerdere mogelijke akkoordnamen (2026-08-26, gebruikersverzoek): cyaan =
   meest voor de hand liggend, --muted = overige leeswijzen — zelfde
   kleurpaar/redenering als CircleWheel's .chord-name-primary/.chord-name-alt
   (circle-wheel.js/styles.css). Was --icon-g2 (paars/magenta) t/m
   2026-08-27, zie de toelichting bij :root in dit bestand. */
.piano-note-display .pnd-chord-primary{ color:var(--accent); font-weight:600; }
.piano-note-display .pnd-chord-alt{ color:var(--muted); font-weight:500; font-size:.85em; }
.piano-note-display .pnd-chord-unknown{ color:var(--muted); font-weight:600; font-style:italic; }
.piano-wrapper{
  width:100%; padding:var(--sp-5) 0; overflow-x:auto; -webkit-overflow-scrolling:touch; background:var(--canvas);
  border-top:1px solid var(--border); scroll-behavior:smooth; flex:1; display:flex; align-items:center;
}
.piano-keyboard{ display:flex; position:relative; height:250px; min-width:max-content; padding:0 var(--sp-7); }
.key{ cursor:pointer; flex-shrink:0; border-radius:0 0 6px 6px; user-select:none; }
.key.white{ width:50px; height:100%; background:var(--key-white); border:1px solid var(--key-edge); position:relative; z-index:1; box-shadow:inset 0 -4px 6px rgba(0,0,0,.1); }
.key.white:active, .key.white.active{ background:var(--accent); border-bottom:6px solid var(--accent); animation:key-glow-white .35s ease-out; }
.key.black{ width:30px; height:60%; background:var(--key-black); margin-left:calc(var(--sp-4) * -1); margin-right:calc(var(--sp-4) * -1); z-index:2; border-radius:0 0 4px 4px; box-shadow:inset 0 -4px 4px rgba(255,255,255,.2); }
.key.black:active, .key.black.active{ background:var(--accent); border-bottom:4px solid var(--accent); animation:key-glow-black .35s ease-out; }
/* L1-28 — was hardcoded neon-cyaan (rgba(34,211,238,…)), dus deze gloed bleef
   ook in licht/donker cyaan i.p.v. mee te kleuren met het thema-accent. */
@keyframes key-glow-white{
  0%{ box-shadow:inset 0 -4px 6px rgba(0,0,0,.1), 0 0 16px 4px color-mix(in srgb, var(--accent) 65%, transparent); }
  100%{ box-shadow:inset 0 -4px 6px rgba(0,0,0,.1), 0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent); }
}
@keyframes key-glow-black{
  0%{ box-shadow:inset 0 -4px 4px rgba(255,255,255,.2), 0 0 16px 4px color-mix(in srgb, var(--accent) 65%, transparent); }
  100%{ box-shadow:inset 0 -4px 4px rgba(255,255,255,.2), 0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent); }
}
.key span{ position:absolute; bottom:15px; width:100%; text-align:center; font-size:14px; font-weight:700; color:var(--key-ink); pointer-events:none; }

/* Metronoom (Extra's, sinds v0.87.0) — zelfde "los top-level scherm,
   display:none tot getoond via App.loadModule()"-opzet als #piano-module/
   #theory-view hierboven. MetronomeUI (js/metronome-ui.js) bouwt
   #metronome-content. Kleuren bewust --accent (rust) / --ok (speelt af) —
   geen quiz-context op dit scherm, dus geen botsing met --ok se "goed
   antwoord"-betekenis elders; --play is bewust NIET gebruikt, die kleur
   betekent overal elders specifiek "van MIDI-input afkomstig". */
#metronome-view{
  display:none; flex-direction:column; width:100%; height:100%; overflow-y:auto;
  background:var(--canvas); transition:background-color var(--mo-3);
}
#metronome-content{ width:100%; max-width:var(--w-focus); margin:0 auto; padding:var(--sp-5) var(--sp-5) var(--sp-8); }
.metronome-card{
  width:100%; background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg);
  padding:var(--sp-6) var(--sp-5); display:flex; flex-direction:column; align-items:center; gap:var(--sp-5);
  box-shadow:var(--sh-1);
}
.metronome-bpm-display{ display:flex; align-items:baseline; gap:var(--sp-2); }
/* v0.87.1: #metronome-bpm-num is nu een <input> (was een <span>) — het losse
   getalveld naast de schuifbalk (.bpm-manual-input elders) is vervallen, dit
   IS voortaan het invoerveld. Was border:none/transparant, puur een
   hover-tint als enige aanwijzing dat dit aanklikbaar is — bugfix-ronde ná
   v0.96.3 Deel 2, Stap 19c (gebruikersmelding: "niet direct zichtbaar dat
   de BPM-waarde klikbaar is", want zonder hover-actie of op touch is er
   geen enkele aanwijzing) — nu ALTIJD een subtiele rand+achtergrond
   ("chip"-achtig), met hover/focus als duidelijk sterkere staat erbovenop. */
.metronome-bpm-num{
  font-family:'JetBrains Mono',monospace; font-weight:600; font-size:4rem; line-height:1;
  color:var(--text); font-variant-numeric:tabular-nums;
  border:1px solid var(--border); background:var(--surface); text-align:right; width:3.2ch;
  padding:0 var(--sp-1); cursor:pointer;
  border-radius:var(--r-sm); transition:background-color var(--mo-1), border-color var(--mo-1);
}
@media (hover:hover){
  .metronome-bpm-num:hover{ background:color-mix(in srgb, var(--text) 8%, transparent); border-color:var(--accent); cursor:text; }
}
.metronome-bpm-num:focus{ outline:2px solid var(--accent); outline-offset:2px; background:color-mix(in srgb, var(--text) 8%, transparent); border-color:var(--accent); cursor:text; }
.metronome-bpm-unit{ font-family:'JetBrains Mono',monospace; font-size:.85rem; font-weight:600; color:var(--muted); text-transform:uppercase; letter-spacing:.06em; }
.metronome-tempo-word{ font-family:'Fraunces',serif; font-style:italic; font-size:1rem; color:var(--muted); }
.metronome-bpm-row{ display:flex; align-items:center; gap:var(--sp-3); width:100%; flex-wrap:wrap; justify-content:center; }
/* Bugfix-ronde ná v0.96.3 Deel 2, Stap 19a — de twee stapknoppen aan elke
   kant zijn nu een eigen flex-groep (zie de HTML-toelichting in
   metronome-ui.js), zodat een afbreking op een smal scherm altijd de HELE
   groep meeneemt i.p.v. een los knopje. flex-shrink:0 houdt de groep op zijn
   eigen breedte, zodat de slider ertussenin altijd symmetrisch overblijft. */
.metronome-step-group{ display:flex; gap:var(--sp-3); flex-shrink:0; }
.metronome-step-btn{ min-width:44px; font-family:'JetBrains Mono',monospace; }
/* Bugfix (gebruikersmelding 2026-09-20): .metronome-bpm-control (de
   buitenste wrapper, max 280px) groeit breder dan de SLIDER erin
   (.bpm-control-row .auto-delay-slider, elders in dit bestand, max 200px)
   — .bpm-control-row zelf heeft geen justify-content, dus die default
   (flex-start) pakte de ~80px restruimte altijd aan de RECHTERkant van de
   slider binnen zijn eigen wrapper. Optisch schoof de slider daardoor naar
   links t.o.v. de -5/-1- en +1/+5-knopgroepen, ook al stond de wrapper zelf
   wél gecentreerd in .metronome-bpm-row. justify-content:center hier zorgt
   dat de (smallere) slider binnen zijn eigen wrapper ook echt centreert. */
.metronome-bpm-control{ flex:1 1 200px; max-width:280px; justify-content:center; }
.metronome-tap-btn{
  border:none; border-radius:var(--r-pill); background:var(--accent); color:var(--accent-ink);
  font-family:'Inter',sans-serif; font-weight:700; font-size:1rem; letter-spacing:.08em;
  padding:var(--sp-4) var(--sp-7); cursor:pointer; box-shadow:var(--sh-2);
  transition:transform var(--mo-1);
}
.metronome-tap-btn:active{ transform:scale(.96); }
.metronome-beats-row{ display:flex; gap:var(--sp-3); flex-wrap:wrap; justify-content:center; }
.metronome-beat-dot{
  width:22px; height:22px; border-radius:50%; border:2px solid var(--border-strong);
  background:transparent; cursor:pointer; padding:0;
  transition:background-color var(--mo-1), border-color var(--mo-1), transform var(--mo-1), box-shadow var(--mo-1);
}
.metronome-beat-dot.accent{ border-color:var(--accent); background:color-mix(in srgb, var(--accent) 25%, transparent); }
.metronome-beat-dot.live{
  transform:scale(1.35); background:var(--accent); border-color:var(--accent);
  box-shadow:0 0 0 5px color-mix(in srgb, var(--accent) 30%, transparent);
}
.metronome-play-btn{
  width:76px; height:76px; border-radius:50%; border:none; background:var(--accent); color:var(--accent-ink);
  display:flex; align-items:center; justify-content:center; cursor:pointer; box-shadow:var(--sh-2);
  transition:background-color var(--mo-2), transform var(--mo-1);
}
.metronome-play-btn svg{ width:32px; height:32px; }
.metronome-play-btn:active{ transform:scale(.96); }
.metronome-play-btn.playing{ background:var(--ok); }
.metronome-settings{ display:flex; flex-direction:column; gap:var(--sp-4); width:100%; border-top:1px solid var(--border); padding-top:var(--sp-5); }
/* v0.87.1 (gebruikersverzoek): Maatsoort en Nootsoort naast elkaar i.p.v.
   onder elkaar — Volume blijft een eigen volle-breedte rij eronder. */
.metronome-settings-row{ display:flex; gap:var(--sp-5); width:100%; }
.metronome-settings-row > .metronome-setting-group{ flex:1; min-width:0; }
.metronome-setting-group{ display:flex; flex-direction:column; gap:var(--sp-2); }
.metronome-setting-label{ font-size:.78rem; font-weight:700; color:var(--muted); text-transform:uppercase; letter-spacing:.05em; }
@media (max-width: 560px){
  .metronome-bpm-num{ font-size:3rem; }
  .metronome-bpm-control{ order:5; flex-basis:100%; max-width:none; }
  .metronome-settings-row{ flex-direction:column; gap:var(--sp-4); }
}

/* Muziektheorie-naslagwerk (Fase 3.2, sinds v0.15.0) — doorbladerbare
   cheat-sheet, geen flashcard/quizstructuur. Zelfde "los top-level scherm,
   display:none tot getoond via App.loadModule()"-opzet als #piano-module
   hierboven. TheoryUI.render() (theory-ui.js) bouwt #theory-content. */
#theory-view{
  display:none; flex-direction:column; width:100%; height:100%; overflow-y:auto;
  background:var(--canvas); transition:background-color var(--mo-3);
}
#theory-content{ width:100%; max-width:1100px; margin:0 auto; padding:var(--sp-5) var(--sp-5) var(--sp-8); }
/* Modulefilter (v0.78.0, BL-5.5) — chips boven het naslagwerk. */
.theory-modfilter{ display:flex; flex-wrap:wrap; gap:var(--sp-2); margin-bottom:var(--sp-5); }
.theory-modchip{
  border:1px solid var(--border); background:var(--surface); color:var(--muted);
  border-radius:var(--r-pill); padding:var(--sp-1) var(--sp-3); font-size:.78rem; font-weight:600;
  font-family:'JetBrains Mono',monospace; cursor:pointer; transition:background-color var(--mo-2), color var(--mo-2), border-color var(--mo-2);
}
.theory-modchip.is-active{ background:var(--accent); border-color:var(--accent); color:var(--accent-ink); }
.theory-card-kbd{ width:100%; margin:0; padding:var(--sp-2); }
.theory-category{ margin-bottom:var(--sp-6); }
.theory-category:last-child{ margin-bottom:0; }
.theory-category h2{
  font-family:'Fraunces',serif; font-weight:600; font-size:1.3rem; margin:0 0 var(--sp-4);
  color:var(--text); padding-bottom:var(--sp-2); border-bottom:1px solid var(--border);
}
.theory-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(220px, 1fr)); gap:var(--sp-4); }
.theory-card{
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md);
  padding:var(--sp-4); display:flex; flex-direction:column; align-items:center; text-align:center; gap:var(--sp-2);
}
.theory-card-visual{ width:100%; min-height:70px; display:flex; align-items:center; justify-content:center; }
.theory-card-visual svg{ width:100%; height:auto; max-width:200px; display:block; }
.theory-card h3{ font-size:.95rem; font-weight:700; color:var(--text); margin:var(--sp-1) 0 0; }
.theory-card p{ font-size:.8rem; color:var(--muted); margin:0; line-height:1.4; }

/* ============================================================
   Muziektheorie-leerpad (Fase 7.5, v0.32.0) — TheoryLessonUI
============================================================ */
/* S7-06 / G-02 — lespagina op --w-read (720px). */
.tl-wrap{ width:100%; max-width:var(--w-read); margin:0 auto; padding:var(--sp-6) var(--sp-5) var(--sp-8); }
.tl-intro{ font-size:13.5px; color:var(--muted); line-height:1.55; margin:0 0 var(--sp-5); }
.tl-back{
  font:inherit; font-size:.82rem; font-weight:600; color:var(--muted);
  background:transparent; border:0; cursor:pointer; padding:var(--sp-1) 0; margin-bottom:var(--sp-4);
}
.tl-back:hover{ color:var(--accent); }

/* -- module-overzicht — 3×3-raster (v0.64.0) --
   Herzien op gebruikersverzoek: dezelfde "tegel"-taal als het tegel-overzicht
   (accent-gloed, hover-lift, drop-shadow-neon op het icoon), i.p.v. de vlakke
   stapel losse kaartjes met alleen een cijferbolletje. Icoon = PianoICO-badge
   per module (assets/icons/theory-m<n>.png, `icon` op TheoryModules). Alleen
   deze weergave is breder (1080px); de lees-/toetsweergave blijft 760px. */
.tl-wrap.tl-wrap-overview{ max-width:1080px; }

.tl-ov-progress{ display:flex; align-items:center; gap:var(--sp-3); margin:0 0 var(--sp-5); }
.tl-ov-bar{
  flex:1; max-width:280px; height:6px; border-radius:999px; overflow:hidden;
  background:color-mix(in srgb, var(--muted) 20%, transparent);
}
.tl-ov-bar span{ display:block; height:100%; border-radius:999px; background:var(--accent); transition:width var(--mo-3) var(--ease); }
.tl-ov-count{ font-size:.78rem; font-weight:600; color:var(--muted); font-variant-numeric:tabular-nums; }

/* S6-01 — modulerij: raster 34px 44px 1fr, gat --sp-3. T-02-aanraakstaten. */
/* v0.83.5 (gebruikersverzoek: "maak deze modules 2x2, volg de nummering
   links 1, rechts 2, dan naar beneden") — was een enkele kolom (M1 t/m M9
   allemaal onder elkaar); nu 2 kolommen op een breed scherm zodat de
   nummering 1-2/3-4/... leest. Smaller dan 561px (zie media query
   hieronder) terug naar 1 kolom — de titels ("Toonsoorten en de
   kwintencirkel") zouden in een smalle helft-kolom lelijk afbreken. */
.tl-modules{ display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:var(--sp-2); }
@media (max-width:560px){ .tl-modules{ grid-template-columns:1fr; } }
.tl-mod-row{
  display:grid; grid-template-columns:34px 44px 1fr; align-items:center; gap:var(--sp-3);
  text-align:left; font:inherit; cursor:pointer; color:var(--text);
  padding:var(--sp-3) var(--sp-4);
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md);
  transition:transform var(--mo-1) var(--ease), border-color var(--mo-1) var(--ease), box-shadow var(--mo-1) var(--ease);
}
@media (hover:hover){
  .tl-mod-row:hover:not(:disabled){ transform:translateY(-3px); border-color:var(--accent); box-shadow:var(--sh-2); }
}
.tl-mod-row:active:not(:disabled){ transform:translateY(-1px) scale(.98); box-shadow:var(--sh-1); }
.tl-mod-row.is-soon{ opacity:.5; cursor:default; }
.tl-mod-row.is-soon:hover{ transform:none; border-color:var(--border); box-shadow:none; }
.tl-mod-n{
  font-family:'JetBrains Mono',monospace; font-size:15px; font-weight:600;
  color:var(--faint); text-align:center; font-variant-numeric:tabular-nums;
}
.tl-mod-row.is-done .tl-mod-n{ color:var(--ok); }
.tl-mod-icon{ width:44px; height:44px; }
.tl-mod-icon svg{ pointer-events:none; }
.tl-mod-body{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.tl-mod-title-row{ display:flex; align-items:baseline; gap:var(--sp-2); flex-wrap:wrap; }
.tl-mod-title{ font-family:'Inter',sans-serif; font-weight:600; font-size:14.5px; line-height:1.3; }
/* #015/#044 — driekleurig curriculum-niveau (basis/verdieping/gevorderd),
   hergebruikt bestaande themakleuren i.p.v. nieuwe tokens: groen=--ok,
   blauw=--accent, paars=--play (elders het MIDI-gespeeld-accent). */
.tl-mod-level-badge{ font-size:.62rem; font-weight:700; padding:1px var(--sp-2); border-radius:5px; letter-spacing:.02em; text-transform:uppercase; white-space:nowrap; }
.tl-mod-level-badge.is-basis{ color:var(--ok); background:var(--ok-soft); }
.tl-mod-level-badge.is-verdieping{ color:var(--accent); background:var(--accent-soft); }
.tl-mod-level-badge.is-gevorderd{ color:var(--play); background:var(--play-soft); }
.tl-mod-blurb{
  font-size:11.5px; color:var(--muted); line-height:1.4;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}
/* S6-02 — voortgangsstreepje: 3px, --accent, --ok zodra de module af is. */
.tl-mod-streak{ display:block; height:3px; margin-top:var(--sp-1); border-radius:var(--r-pill); background:var(--surface2); overflow:hidden; max-width:180px; }
.tl-mod-streak span{ display:block; height:100%; background:var(--accent); }
.tl-mod-row.is-done .tl-mod-streak span{ background:var(--ok); }
.tl-mod-count, .tl-mod-flag{ font-size:10.5px; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); font-family:'JetBrains Mono',monospace; margin-top:3px; }
.tl-legacy-note{ font-size:.82rem; color:var(--muted); margin:0 0 var(--sp-4); }
.tl-moduletest-btn{ margin-top:var(--sp-4); width:100%; }
.tl-mod-continue{ display:block; width:100%; margin-bottom:var(--sp-4); }
.tl-mod-score{ margin-top:var(--sp-2); text-align:center; font-size:.85rem; font-weight:600; color:var(--muted); }
.tl-mod-score.is-pass{ color:var(--ok); }

/* -- Afsluitende kaarten: Eindtoets + Naslag (v0.61; iconen v0.64.0) -- */
.tl-capstones{ display:grid; gap:var(--sp-3); margin-top:var(--sp-5); padding-top:var(--sp-5); border-top:1px solid var(--border); }
.tl-cap-card{
  display:flex; flex-direction:row; align-items:center; gap:var(--sp-4);
  text-align:left; font:inherit; cursor:pointer;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md);
  padding:var(--sp-4) var(--sp-4); color:var(--text);
  transition:transform var(--mo-2) var(--ease), border-color var(--mo-2) var(--ease), box-shadow var(--mo-2) var(--ease);
}
.tl-cap-card:hover{ transform:translateY(-3px); border-color:var(--accent); box-shadow:0 12px 28px color-mix(in srgb, var(--accent) 24%, transparent); }
.tl-cap-card.is-test{
  border-color:color-mix(in srgb, var(--accent) 45%, var(--border));
  background:radial-gradient(circle at 90% 8%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 55%), color-mix(in srgb, var(--accent) 6%, var(--surface));
}
.tl-cap-icon{ flex:none; width:44px; height:44px; }
.tl-cap-icon svg{ pointer-events:none; }
.tl-cap-body{ display:flex; flex-direction:column; gap:3px; min-width:0; }
.tl-cap-title{ font-family:'Fraunces',serif; font-weight:600; font-size:1.05rem; }
.tl-cap-blurb{ font-size:.82rem; color:var(--muted); line-height:1.45; }

/* -- Naslag: samenvatting per les -- */
.tl-ref-head{
  font-family:'Fraunces',serif; font-weight:600; font-size:1.1rem; color:var(--text);
  margin:var(--sp-5) 0 var(--sp-3); padding-bottom:var(--sp-2); border-bottom:1px solid var(--border);
}
.tl-ref-sec{ margin-bottom:var(--sp-5); }
.tl-ref-sec h3{
  font-size:.78rem; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  color:var(--muted); margin:0 0 var(--sp-3);
}
.tl-ref-grid{ display:grid; gap:var(--sp-3); }
.tl-ref-card{
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md);
  padding:var(--sp-4) var(--sp-4); display:flex; flex-direction:column; gap:var(--sp-2);
}
.tl-ref-open{
  font:inherit; font-weight:600; font-size:.98rem; color:var(--text);
  background:transparent; border:0; padding:0; cursor:pointer; text-align:left;
  display:flex; align-items:baseline; gap:var(--sp-2); flex-wrap:wrap;
}
.tl-ref-open:hover{ color:var(--accent); }
.tl-ref-goto{ font-size:.72rem; font-weight:600; color:var(--accent); opacity:.85; white-space:nowrap; }
.tl-ref-rule{ font-size:.84rem; color:var(--muted); line-height:1.5; margin:0; }
.tl-ref-vis{ display:flex; justify-content:flex-start; overflow-x:auto; min-height:64px; }
.tl-ref-vis svg{ max-width:280px; height:auto; }
.tl-ref-kbd{ padding:var(--sp-3) var(--sp-2) var(--sp-2); min-height:96px; }
/* S7-10 — compacte naslag-figuur: kleinere schaal per toets i.p.v. een eigen
   vaste hoogte, de verhouding (1 : 3,06) blijft hetzelfde. */
.tl-ref-kbd .tl-kbd-row{ max-width: calc(var(--kbd-keys, 14) * 22px); }
.theory-card-visual{ min-height:70px; }
@media (min-width:820px){
  .tl-capstones{ grid-template-columns:1fr 1fr; }
  .tl-cap-title{ font-size:1.12rem; }
  .tl-ref-head{ font-size:1.2rem; }
  .tl-ref-grid{ grid-template-columns:1fr 1fr; }
  .tl-ref-open{ font-size:1.02rem; }
  .tl-ref-rule{ font-size:.86rem; }
  .tl-ref-kbd .tl-kbd-row{ max-width: calc(var(--kbd-keys, 14) * 26px); }
}

/* Naslag-tab per les: samenvatting + alle visuele weergaves */
.tl-naslag-figs{ display:flex; flex-wrap:wrap; gap:var(--sp-4); justify-content:center; margin-top:var(--sp-2); }
.tl-naslag-fig{ margin:0; max-width:320px; }
.tl-naslag-fig figcaption{ font-size:.76rem; color:var(--muted); line-height:1.4; margin-top:var(--sp-2); text-align:center; }
.tl-naslag-card #tl-naslag-kbd{ margin:var(--sp-3) 0 var(--sp-1); }

/* -- lessenlijst -- */
.tl-mod-h{ font-family:'Fraunces',serif; font-weight:600; font-size:1.35rem; color:var(--text); margin:0 0 var(--sp-1); }
.tl-mod-sub{ font-size:.86rem; color:var(--muted); margin:0 0 var(--sp-4); }
.tl-lessons{ display:grid; gap:var(--sp-2); }
.tl-les-row{
  display:grid; grid-template-columns:auto 1fr auto auto; align-items:center; gap:var(--sp-3);
  text-align:left; font:inherit; cursor:pointer;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-sm);
  padding:var(--sp-3) var(--sp-4); color:var(--text);
}
.tl-les-row:hover{ border-color:var(--accent); }
.tl-les-n{ font-size:.78rem; font-weight:700; color:var(--muted); font-variant-numeric:tabular-nums; }
.tl-les-title{ font-weight:600; font-size:.95rem; }
.tl-les-chev{ color:var(--muted); }
.tl-les-badge{ font-size:.68rem; font-weight:700; padding:2px var(--sp-2); border-radius:5px; }
.tl-les-badge.is-mastered{ color:var(--ok); background:var(--ok-soft); }
.tl-les-badge.is-due{ color:var(--off); background:var(--off-soft); }
.tl-les-badge.is-learning{ color:var(--accent); background:color-mix(in srgb, var(--accent) 14%, transparent); }
.tl-les-badge.is-new{ color:var(--muted); background:var(--surface2); }

/* -- les: kop + tabs -- */
.tl-les-eyebrow{ font-family:'JetBrains Mono',monospace; font-size:10.5px; font-weight:600; letter-spacing:.12em; text-transform:uppercase; color:var(--muted); margin-bottom:var(--sp-1); }
/* S7-08 — lestitel: Fraunces 600, 30px (24 op de telefoon). */
.tl-les-h{ font-family:'Fraunces',serif; font-weight:600; font-size:30px; line-height:1.12; letter-spacing:-.02em; color:var(--text); margin:0 0 var(--sp-4); }
/* Les-navigatiedropdown (v0.92.0, Plan_van_Aanpak_Onboarding_en_
   Kernoefeningen §2.A) — hergebruikt de generieke select-stijl hierboven,
   puur volle breedte + marge tot de tabs. Sinds de bugfix-ronde ná v0.96.3
   (Stap 9) in een rij samen met het moduletoets-icoon (.tl-module-test-btn)
   — de select zelf verliest daarom zijn eigen marge (die komt nu op de rij
   eromheen te staan) en wordt flex:1 i.p.v. width:100%. */
.tl-lesson-nav-row{ display:flex; align-items:center; gap:var(--sp-2); margin:0 0 var(--sp-4); }
.tl-lesson-nav{ display:block; flex:1; min-width:0; margin:0; }
.tl-module-test-btn{
  width:34px; height:34px; padding:0; border-radius:var(--r-sm); flex-shrink:0;
  background:transparent; border:1px solid var(--border); color:var(--muted);
  display:inline-flex; align-items:center; justify-content:center;
  transition:background-color var(--mo-1) var(--ease), color var(--mo-1) var(--ease), border-color var(--mo-1) var(--ease);
}
@media (hover:hover){ .tl-module-test-btn:hover{ background:var(--surface2); color:var(--accent); border-color:var(--accent); } }
.tl-module-test-btn:active{ transform:scale(.96); }
.tl-module-test-btn svg{ width:20px; height:20px; display:block; }
/* S7-01 — segmentschakelaar sticky onder de topbalk, met --canvas erachter
   en een hairline eronder. */
.tl-tabs{
  display:flex; gap:2px; border-bottom:1px solid var(--border); margin-bottom:var(--sp-5);
  position:sticky; top:0; z-index:5; background:var(--canvas);
}
.tl-tab{
  flex:1; font:inherit; font-size:13px; font-weight:600; color:var(--muted);
  background:transparent; border:0; border-bottom:2px solid transparent; padding:var(--sp-3) var(--sp-2);
  cursor:pointer; min-height:44px;
}
.tl-tab.is-active{ color:var(--accent); border-bottom-color:var(--accent); }
@media (hover:hover){ .tl-tab:hover:not(.is-active){ color:var(--text); } }

/* -- Leer -- */
.tl-teach-body{ margin-bottom:var(--sp-5); }
.tl-teach-body :is(p, h4):first-child{ margin-top:0; }
/* S7-06 — lestekst: 15px, regelafstand 1,68.
   Bugfix (gebruikersmelding 2026-09-20): de ch-gebaseerde max-width hieronder
   (62/64/68/72ch, ook in de breakpoints verderop) hield lestekst een stuk
   smaller dan de rest van de kolom — .tl-teach-h (koppen) en .tl-examples
   (voorbeeldkaarten) hadden nooit zo'n cap en liepen al gewoon door tot de
   volle .tl-wrap-breedte, dus de tekst oogde onnodig scheef/smaller
   uitgelijnd t.o.v. die andere elementen. Cap overal verwijderd — tekst volgt
   nu gewoon dezelfde breedte als de kolom, zoals de rest van de pagina. */
.tl-teach-p{ font-size:15px; color:var(--text); line-height:1.68; margin:0 0 var(--sp-3); }
.tl-teach-p b{ font-weight:600; }
.tl-teach-p i{ font-style:italic; }
.tl-teach-h{
  font-family:'Fraunces',serif; font-weight:600; font-size:1.02rem; color:var(--text);
  margin:var(--sp-5) 0 var(--sp-2);
}
.tl-teach-note{
  font-size:.9rem; color:var(--muted); line-height:1.6;
  margin:var(--sp-4) 0; padding:var(--sp-3) var(--sp-4); border-radius:var(--r-sm);
  background:color-mix(in srgb, var(--accent) 8%, transparent);
  border-left:3px solid var(--accent);
}
.tl-teach-note b{ color:var(--text); font-weight:600; }
/* #013 (Fase 4) — inklapbaar zijspoor, dicht bij .tl-teach-note maar met een
   klikbare summary-rij (44px-target) i.p.v. altijd-open. */
.tl-teach-aside{
  margin:var(--sp-4) 0; border-radius:var(--r-sm);
  background:var(--surface); border:1px solid var(--border);
}
.tl-teach-aside > summary{
  cursor:pointer; list-style:none; font-size:.9rem; font-weight:600; color:var(--text);
  padding:var(--sp-3) var(--sp-4); min-height:44px; display:flex; align-items:center;
}
.tl-teach-aside > summary::-webkit-details-marker{ display:none; }
.tl-teach-aside > summary::before{ content:'▸'; display:inline-block; margin-right:var(--sp-2); color:var(--muted); transition:transform .15s; }
.tl-teach-aside[open] > summary::before{ transform:rotate(90deg); }
.tl-teach-aside-body{
  font-size:.9rem; color:var(--muted); line-height:1.6;
  padding:0 var(--sp-4) var(--sp-3);
}
.tl-teach-aside-body b{ color:var(--text); font-weight:600; }
.tl-examples{ display:flex; flex-wrap:wrap; gap:var(--sp-4); margin-bottom:var(--sp-5); }
.tl-example{
  margin:0; flex:1 1 220px; background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-sm); padding:var(--sp-3);
}
.tl-example-staff{ min-height:74px; display:flex; align-items:center; justify-content:center; }
.tl-example-staff svg{ width:100%; height:auto; max-width:200px; }
.tl-example figcaption{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3); margin-top:var(--sp-2); font-size:.8rem; color:var(--muted); }
.tl-hear{
  font:inherit; font-size:.74rem; font-weight:600; color:var(--accent); white-space:nowrap;
  background:transparent; border:1px solid var(--border); border-radius:999px; padding:3px var(--sp-3); cursor:pointer;
}
.tl-hear:hover{ border-color:var(--accent); }

/* -- Klavier-schema in de Leer-tab (v0.61) -- niet speelbaar, wijst het
   lespunt aan (ankernoten, ligging van C/F, zwarte toetsen). --------------- */
.tl-kbd-fig{ margin:0 0 var(--sp-5); }
.tl-kbd-fig figcaption{ font-size:.8rem; color:var(--muted); margin-top:var(--sp-2); line-height:1.45; }
.tl-kbd{
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-sm); padding:var(--sp-4) var(--sp-3) var(--sp-3);
}
/* S7-10 — klavierverhouding ligt vast: een witte toets is nooit breder dan
   34px en de hoogte volgt de breedte (1 : 3,06). --kbd-keys wordt inline
   gezet door de code die het klavier bouwt (nu: MiniKeyboard.render). */
.mini-key-row{
  aspect-ratio: var(--kbd-keys, 14) / 3.06;
  max-width: calc(var(--kbd-keys, 14) * 34px);
  height:auto; margin-inline:auto;
}
.tl-kbd-row{
  display:flex; align-items:flex-start; margin-inline:auto;
  aspect-ratio: var(--kbd-keys, 14) / 3.06;
  max-width: calc(var(--kbd-keys, 14) * 34px);
  width:100%; height:auto;
}
.tl-kbd-key{ position:relative; box-sizing:border-box; user-select:none; }
.tl-kbd-key.white{
  height:100%; background:var(--key-white); border:1px solid var(--key-edge);
  border-radius:0 0 4px 4px; z-index:1;
}
.tl-kbd-key.black{
  height:62%; background:var(--key-black); border:1px solid var(--key-edge);
  border-radius:0 0 3px 3px; z-index:2;
}
.tl-kbd-key.white.is-mark.is-anchor{ background:var(--accent-soft); }
.tl-kbd-key.white.is-mark.is-focus{ background:var(--accent); }
.tl-kbd-key.white.is-mark.is-ghost{ background:var(--surface2); }
.tl-kbd-key.black.is-mark.is-anchor{ background:var(--accent); }
.tl-kbd-key.black.is-mark.is-focus{ background:var(--accent); }
.tl-kbd-key.black.is-mark.is-ghost{ background:var(--surface2); }
.tl-kbd-lab{
  position:absolute; left:50%; transform:translateX(-50%);
  bottom:5px; font-size:.62rem; font-weight:700; letter-spacing:.01em;
  color:var(--key-ink); white-space:nowrap; pointer-events:none;
}
.tl-kbd-key.black .tl-kbd-lab{
  bottom:auto; top:-16px; color:var(--muted);
}
.tl-kbd-key.white.is-focus .tl-kbd-lab{ color:var(--accent-ink); }
@media (min-width:820px){
  .tl-kbd{ padding:var(--sp-4) var(--sp-4) var(--sp-3); }
  .tl-kbd-lab{ font-size:.7rem; bottom:7px; }
  .tl-kbd-key.black .tl-kbd-lab{ top:-18px; }
  .tl-kbd-fig figcaption{ font-size:.86rem; }
}

/* -- Klikbaar klavier als antwoordvorm in de Toets (v0.61) -- */
.tl-clickkb{ margin-bottom:var(--sp-4); }
.tl-clickkb-hint{ font-size:.84rem; color:var(--muted); text-align:center; margin:0 0 var(--sp-3); line-height:1.4; }
.tl-clickkb-row{
  margin-bottom:var(--sp-3); padding:var(--sp-3) var(--sp-3) 0;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-sm);
}
.tl-clickkb .tl-kbd-key:not(.is-given){ cursor:pointer; }
.tl-clickkb .tl-kbd-key.white:not(.is-given):hover{ background:var(--accent-soft); }
.tl-clickkb .tl-kbd-key.black:not(.is-given):hover{ background:var(--accent-soft); }
.tl-clickkb .tl-kbd-key.white.is-given{ background:var(--accent-soft); }
.tl-clickkb .tl-kbd-key.black.is-given{ background:var(--accent); }
.tl-clickkb .tl-kbd-key.white.is-picked{ background:var(--accent); }
.tl-clickkb .tl-kbd-key.black.is-picked{ background:var(--accent); }
.tl-clickkb .tl-kbd-key.is-hit{ background:var(--ok) !important; }
.tl-clickkb .tl-kbd-key.is-miss{ background:var(--err) !important; }
.tl-kb-check{ display:block; margin:0 auto; min-height:44px; padding:var(--sp-3) var(--sp-5); }
.tl-kb-check:disabled{ opacity:.45; cursor:default; }
.tl-kb-swap{
  display:block; margin:var(--sp-3) auto 0; font:inherit; font-size:.8rem; font-weight:600;
  color:var(--muted); background:transparent; border:0; cursor:pointer;
  min-height:44px; padding:var(--sp-2) var(--sp-4);
}
.tl-kb-swap:hover{ color:var(--accent); }
@media (min-width:820px){ .tl-clickkb-row{ height:140px; } .tl-clickkb-hint{ font-size:.9rem; } }

/* S7-04 — rustige rand, GEEN accentrand: "Probeer het" is een tip, geen
   call-to-action (die taal is voor .tl-cta/.tl-totest-btn gereserveerd). */
.tl-tryit{
  font-size:.88rem; color:var(--muted); line-height:1.55; margin-bottom:var(--sp-5);
  padding:var(--sp-3) var(--sp-4); border-radius:var(--r-sm);
  background:var(--surface2);
  border:1px solid var(--border);
}
.tl-tryit b{ color:var(--text); }
.tl-cta{
  font:inherit; font-size:.9rem; font-weight:700; color:var(--accent-ink); background:var(--accent);
  border:0; border-radius:999px; padding:var(--sp-3) var(--sp-5); cursor:pointer;
}
.tl-cta:hover{ background:var(--accent-hover, var(--accent)); }
.tl-btn{
  font:inherit; font-size:.88rem; font-weight:600; color:var(--muted);
  background:transparent; border:1px solid var(--border); border-radius:999px; padding:var(--sp-3) var(--sp-5); cursor:pointer;
}
.tl-btn:hover{ color:var(--text); border-color:var(--accent); }

/* Onder de les — S7-02 / S7-03 / S7-07. */
/* S7-02 — "Naar de toets van deze les": volle primaire knop, boven de
   lesnavigatie. Geen los pijltje-omhoog. */
.tl-totest-btn{
  display:block; width:100%; margin-top:var(--sp-6); padding:var(--sp-3) var(--sp-4);
  font-size:14px; font-weight:600; min-height:44px;
}
/* Taak 4.2 (Fase 4) — outline-variant voor "Oefen dit direct op het klavier
   in …": zelfde blok-formaat/gewicht als .tl-totest-btn, maar met minder
   visuele nadruk dan de gevulde primaire toets-knop erboven. min-height 44px
   is de touch-target-eis uit Taak 4.3. */
.tl-totest-btn.is-outline{
  background:transparent; color:var(--accent); border:1px solid var(--accent);
  margin-top:var(--sp-3); min-height:44px; display:flex; align-items:center; justify-content:center; gap:var(--sp-1);
}
@media (hover:hover){ .tl-totest-btn.is-outline:hover{ background:color-mix(in srgb, var(--accent) 10%, transparent); } }
/* S7-03 (voorheen) — ".tl-practice-link" blijft bestaan als losse tekstlink-
   stijl voor ANDERE plekken (bv. het "?"-modulehelp-paneel, module-help.js) —
   de lesvoet hierboven gebruikt sinds Fase 4 Taak 4.2 de CTA-knop hierboven. */
.tl-practice-link{
  display:inline-flex; align-items:center; gap:var(--sp-1);
  margin-top:var(--sp-3); font-size:13px; font-weight:600; color:var(--accent);
  background:transparent; border:0; padding:0; cursor:pointer;
}
@media (hover:hover){ .tl-practice-link:hover{ text-decoration:underline; } }
/* Plan_van_Aanpak_v1.0 Deel 1, §1 — Zone 4 "Snelkoppelingen" onderin de
   instellingenlade: theorielink (hergebruikt .tl-practice-link) + de
   globale niveau-reset, los van de Wat/Hoe-leer-ik-blokken erboven. */
.settings-shortcuts{
  display:flex; flex-direction:column; align-items:flex-start; gap:var(--sp-2);
  margin-top:var(--sp-3); padding-top:var(--sp-3); border-top:1px solid var(--border); width:100%;
}
.settings-global-reset-link{
  display:inline-flex; align-items:center; gap:var(--sp-1);
  font-size:13px; font-weight:600; color:var(--muted);
  background:transparent; border:0; padding:0; cursor:pointer;
}
@media (hover:hover){ .settings-global-reset-link:hover{ color:var(--accent); text-decoration:underline; } }
.level-block-reset{ margin-top:var(--sp-2); }
/* S7-07 — lesnavigatie: vorige/volgende met de lesnaam erin, --sp-7 boven,
   hairline erboven. */
.tl-les-foot{
  display:grid; grid-template-columns:1fr 1fr; gap:var(--sp-3);
  margin-top:var(--sp-7); padding-top:var(--sp-4); border-top:1px solid var(--border);
}
.tl-lnav-btn{
  display:flex; align-items:center; gap:var(--sp-2);
  font:inherit; text-align:left; cursor:pointer;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md);
  padding:var(--sp-3) var(--sp-4); color:var(--text);
  transition:border-color var(--mo-1) var(--ease);
}
@media (hover:hover){ .tl-lnav-btn:hover{ border-color:var(--accent); } }
.tl-lnav-next{ justify-content:flex-end; text-align:right; }
.tl-lnav-dir{ color:var(--muted); font-size:1.1em; flex-shrink:0; }
.tl-lnav-txt{ display:flex; flex-direction:column; min-width:0; }
.tl-lnav-lbl{ font-size:10.5px; font-weight:600; letter-spacing:.12em; text-transform:uppercase; color:var(--muted); font-family:'JetBrains Mono',monospace; }
.tl-lnav-name{ font-size:13.5px; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
@media (max-width:560px){
  .tl-les-foot{ grid-template-columns:1fr; }
}

/* -- Naslag -- */
.tl-naslag-card{
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md);
  padding:var(--sp-4); text-align:center;
}
.tl-naslag-title{ font-family:'Fraunces',serif; font-weight:600; font-size:1.05rem; color:var(--text); margin-bottom:var(--sp-2); }
.tl-naslag-rule{ font-size:.9rem; color:var(--muted); line-height:1.55; margin:0 0 var(--sp-3); }
.tl-naslag-staff{ display:flex; justify-content:center; }
.tl-naslag-staff svg{ max-width:200px; height:auto; }

/* -- Toets (quiz) -- */
.tl-quiz-progress{ font-size:.76rem; color:var(--muted); text-align:center; margin-bottom:var(--sp-3); }
.tl-quiz-prompt{ font-family:'Fraunces',serif; font-size:1.1rem; font-weight:600; color:var(--text); text-align:center; margin-bottom:var(--sp-4); line-height:1.4; }
.tl-quiz-staff{ display:flex; justify-content:center; margin-bottom:var(--sp-4); }
.tl-quiz-staff svg{ max-width:230px; height:auto; }
.tl-hear-btn{ display:block; margin:0 auto var(--sp-4); }
.tl-choices{ display:grid; grid-template-columns:1fr 1fr; gap:var(--sp-2); }
@media (max-width:560px){ .tl-choices{ grid-template-columns:1fr; } }
/* Taak 4.3 (Fase 4) — 44px-touch-target-vloer voor .tl-kbd-key: de hoogte
   volgt normaal alleen de breedte/aspect-ratio (dus platter bij méér
   toetsen in beeld), zonder vloer kon dat op een smal telefoonscherm onder
   44px duiken. Vloer alleen op mobiel (desktop had al ruim voldoende
   hoogte); breedte/aspect-ratio blijven ongewijzigd. */
@media (max-width:560px){ .tl-kbd-row{ min-height:64px; } }
.tl-choice{
  font:inherit; font-size:.9rem; font-weight:600; color:var(--text);
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-sm);
  padding:var(--sp-3) var(--sp-3); cursor:pointer;
  /* Taak 4.3 (Fase 4) — 44px-touch-target-vloer, was net onder 44px op
     mobiel (12px padding + ~1 tekstregel). */
  min-height:44px; display:flex; align-items:center; justify-content:center; text-align:center;
}
.tl-choice:hover:not(:disabled){ border-color:var(--accent); }
.tl-choice:disabled{ cursor:default; }
.tl-choice.is-correct{ border-color:var(--ok); background:var(--ok-soft); color:var(--text); }
.tl-choice.is-wrong{ border-color:var(--err); background:var(--err-soft); }
.tl-midi-wait{
  text-align:center; font-size:.86rem; font-weight:600; color:var(--accent);
  padding:var(--sp-4); border:1px dashed var(--border); border-radius:var(--r-sm);
}
.tl-midi-wait.is-ok{ color:var(--ok); border-color:var(--ok); }
.tl-midi-wait.is-no{ color:var(--err); border-color:var(--err); }
.tl-quiz-feedback{ margin-top:var(--sp-4); font-size:.86rem; line-height:1.5; padding:var(--sp-3) var(--sp-3); border-radius:var(--r-sm); }
.tl-quiz-feedback[hidden]{ display:none; }
.tl-quiz-feedback.is-ok{ background:var(--ok-soft); color:var(--text); }
.tl-quiz-feedback.is-no{ background:var(--err-soft); color:var(--text); }
.tl-quiz-feedback b{ display:block; margin-bottom:2px; }
/* v0.66.7: vaste ruimte voor het antwoord-vak zodat de knoppen eronder
   niet verspringen tussen "vraag open" en "beantwoord". */
.tl-quiz-after{ margin-top:var(--sp-4); }
.tl-quiz-after .tl-quiz-feedback{ margin-top:0; min-height:4.2em; }
.tl-quiz-after .tl-quiz-feedback:not(.is-ok):not(.is-no){ padding:0; }
.tl-quiz-nav{ display:flex; justify-content:space-between; align-items:center; gap:var(--sp-3); margin-top:var(--sp-4); min-height:44px; }
.tl-quiz-nav #tl-quiz-next{ margin-top:0; }
#tl-quiz-next[hidden]{ display:none; }
#tl-quiz-next{ margin-top:var(--sp-4); }
.tl-quiz-done{ text-align:center; padding:var(--sp-5) 0; }
.tl-quiz-score{ font-family:'Fraunces',serif; font-size:2rem; font-weight:700; color:var(--accent); }
.tl-quiz-pct{ font-size:1.15rem; font-weight:600; color:var(--muted); margin-left:var(--sp-2); }
.tl-quiz-pct.is-pass{ color:var(--ok); }
.tl-quiz-passmark{ font-size:.76rem !important; color:var(--muted); margin:2px 0 var(--sp-4) !important; opacity:.85; }
.tl-quiz-done p{ font-size:.9rem; color:var(--muted); margin:var(--sp-2) 0 var(--sp-4); }
.tl-quiz-actions{ display:flex; gap:var(--sp-3); justify-content:center; flex-wrap:wrap; }
.tl-quiz-err{ text-align:center; color:var(--err); font-size:.86rem; }

/* -- Desktop: ruimer en groter (v0.61, gebruikersverzoek: "op pc te klein/
   minimalistisch"). Mobiel blijft ongemoeid — deze regels gelden pas vanaf
   een echte bureaubladbreedte. --------------------------------------------- */
@media (min-width:820px){
  .tl-wrap{ max-width:var(--w-read); padding:var(--sp-7) var(--sp-5) var(--sp-8); }
  .tl-wrap.tl-wrap-overview{ max-width:var(--w-wide); }
  .tl-intro{ font-size:15px; margin-bottom:var(--sp-5); }

  .tl-mod-h{ font-size:1.6rem; }
  .tl-mod-sub{ font-size:.94rem; margin-bottom:var(--sp-5); }
  .tl-les-row{ padding:var(--sp-4) var(--sp-4); }
  .tl-les-title{ font-size:1rem; }

  .tl-les-h{ margin-bottom:var(--sp-4); }
  .tl-tab{ font-size:.94rem; padding:var(--sp-3) var(--sp-2); }
  .tl-teach-p{ font-size:1rem; line-height:1.7; margin-bottom:var(--sp-4); }
  .tl-teach-h{ font-size:1.15rem; margin:var(--sp-5) 0 var(--sp-3); }
  .tl-teach-note{ font-size:.96rem; padding:var(--sp-4) var(--sp-4); }
  .tl-teach-aside > summary{ font-size:.96rem; }
  .tl-teach-aside-body{ font-size:.96rem; }
  .tl-tryit{ font-size:.94rem; padding:var(--sp-4) var(--sp-4); }

  .tl-examples{ gap:var(--sp-4); }
  .tl-example{ flex-basis:260px; padding:var(--sp-4); }
  .tl-example-staff{ min-height:96px; }
  .tl-example-staff svg{ max-width:300px; }
  .tl-example figcaption{ font-size:.84rem; }
  .tl-hear{ font-size:.78rem; }

  .tl-naslag-card{ padding:var(--sp-5); }
  .tl-naslag-title{ font-size:1.15rem; }
  .tl-naslag-rule{ font-size:.98rem; }
  .tl-naslag-staff svg{ max-width:300px; }

  .tl-quiz-prompt{ font-size:1.22rem; }
  .tl-quiz-staff svg{ max-width:300px; }
  .tl-choice{ font-size:.96rem; padding:var(--sp-4) var(--sp-3); }
}

@media (min-width:1120px){
  .tl-wrap{ max-width:960px; }
}

@media (max-width:560px){
  #workspace{ padding:var(--sp-3); }
  .flashcard{ min-height:200px; padding:var(--sp-4); transition:background-color var(--mo-3), border-color var(--mo-3), color var(--mo-3), min-height var(--mo-3) var(--ease); }
  /* v0.83.4-fix: `.flashcard.fc-wide`'s 740px-vaste hoogte (desktop, zie
     hierboven) won ook hier van deze regel (twee klassen > één), en gaf op
     de telefoon een enorme, grotendeels lege kaart met de knoppenrij eronder
     buiten beeld — de brede kaarten mogen hier gewoon net als alle andere op
     hun inhoud krimpen. */
  .flashcard.fc-wide{ min-height:200px; }
  /* v0.86.1 (gebruikersmelding: "onder de knoppen sluit de kaart niet mooi
     af") — Kwintencirkel-Verkennen op mobiel eindigt met de akkoordsoort-
     knoppenrijen; de gewone .flashcard-padding (var(--sp-4), alle kanten)
     voelde daaronder te krap. Extra ademruimte ALLEEN onderaan (niet
     boven, om het wiel niet verder van de titel af te duwen) en ALLEEN
     voor Verkennen (niet de andere .fc-wide-oefenvormen elders). */
  .flashcard.fc-circle-visual{ padding-bottom:var(--sp-7); }
  /* Kaart moet op mobiel in één beeld passen (v0.52.1, gebruikersverzoek):
     de notenbalk-SVG (width:100% + height:auto) werd op een smal scherm veel
     te hoog — begrens 'm op de hoogte en laat 'm dan zelf smaller worden. */
  #score-paper svg, #answer-score svg{ max-height:30vh; width:auto; max-width:100%; margin:0 auto; }
  .flashcard-actions{ gap:var(--sp-2); }
  .piano-keyboard{ height:200px; }
  .key.white{ width:44px; }
  .key.black{ width:28px; margin-left:calc(var(--sp-4) * -1); margin-right:calc(var(--sp-4) * -1); }
  #theory-content{ padding:var(--sp-4) var(--sp-4) var(--sp-8); }
  .theory-grid{ grid-template-columns:repeat(auto-fill, minmax(160px, 1fr)); gap:var(--sp-3); }
  /* S8-04 — koppen krimpen: lestitel 30→24, resultaatpercentage 64→52. Stond
     eerder abusievelijk ANDERSOM (24px pas vanaf 820px, dus juist kleiner op
     desktop) — nu wél op de telefoon. */
  .tl-les-h{ font-size:24px; }
  .session-end-score{ font-size:52px; }
}

/* De vaste mobiele onderbalk is vervallen (S8-03), dus geen extra ruimte
   onderin meer nodig — alleen de veilige zone respecteren op scroll-schermen. */
@media (max-width:560px){
  #workspace{ padding-bottom:calc(var(--sp-6) + env(safe-area-inset-bottom)); }
  #theory-content{ padding-bottom:calc(var(--sp-7) + env(safe-area-inset-bottom)); }
  #progress-content{ padding-bottom:calc(var(--sp-7) + env(safe-area-inset-bottom)); }
}

/* Voortgangsdashboard (Fase 5.3, sinds v0.22.0) — los top-level scherm,
   zelfde display:none/flex-opzet als #theory-view/#piano-module. Bouwt
   volledig op uit ProgressUI.render() (js/progress-ui.js) op basis van de
   bestaande spaced-repetition-data. Puur weergave, geen interactie. */
#progress-view{
  display:none; flex-direction:column; width:100%; height:100%; overflow-y:auto;
  background:var(--canvas); transition:background-color var(--mo-3);
}
#progress-content{ width:100%; max-width:var(--w-wide); margin:0 auto; padding:var(--sp-7) var(--sp-5) var(--sp-8); }
.progress-wrap{ display:flex; flex-direction:column; gap:var(--sp-5); }
/* Z-03 — onderbroken (cloud-sync-fout): strook in --err-soft, tekst --err,
   een herstelactie erin, NOOIT blokkerend — geen overlay/modal, gewoon een
   regel bovenaan. Zelfde strook staat in de instellingenlade (#sync-block,
   .sync-error hierboven); dit is de dashboard-kopie, zie
   ProgressUI._syncErrorBanner(). */
.z03-banner{
  display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3);
  flex-wrap:wrap; padding:var(--sp-3) var(--sp-4); border-radius:var(--r-md);
  background:var(--err-soft); color:var(--err); font-size:13px; font-weight:600;
}
.z03-banner button{
  flex-shrink:0; padding:var(--sp-1) var(--sp-3); font-size:12.5px;
  background:transparent; border:1px solid var(--err); color:var(--err);
}
@media (hover:hover){ .z03-banner button:hover{ background:color-mix(in srgb, var(--err) 12%, transparent); } }
/* Z-02 — laden: drie balken in de vorm van wat komt, geen draaiend rondje.
   Puls 1,4s tussen dekking 1 en .45; stil bij reduced-motion (zie de
   @media(prefers-reduced-motion)-regel elders, die zet alle animatie-
   duur op --mo-2 en enkel opacity blijft bewegen — deze animatie ZELF is
   al alleen opacity, dus die valt vanzelf binnen die regel). */
.z02-skeleton{ display:flex; flex-direction:column; gap:var(--sp-2); }
.z02-skeleton-bar{
  height:11px; border-radius:var(--r-pill); background:var(--surface2);
  animation:z02-pulse 1.4s ease-in-out infinite;
}
.z02-skeleton-bar:nth-child(2){ animation-delay:.15s; width:82%; }
.z02-skeleton-bar:nth-child(3){ animation-delay:.3s; width:60%; }
@keyframes z02-pulse{ 0%, 100%{ opacity:1; } 50%{ opacity:.45; } }
/* S5-05 — inleiding: één regel met de back-up-link erin. */
.progress-intro{
  font-size:13.5px; color:var(--muted); line-height:1.5; margin:0; max-width:60ch;
}
.progress-intro-link{
  background:none; border:0; padding:0; margin:0; cursor:pointer;
  font:inherit; color:var(--accent); font-weight:600; white-space:nowrap;
}
@media (hover:hover){ .progress-intro-link:hover{ text-decoration:underline; } }

/* S5-01 — samenvattingsband: 4 cellen, één omlijsting, scheidingslijnen,
   de beheersingsbalk als onderrand over de volle breedte. */
.pd-stats{
  display:grid; grid-template-columns:repeat(4, 1fr);
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg);
  overflow:hidden;
}
.pd-stat{
  padding:var(--sp-4) var(--sp-5); display:flex; flex-direction:column; gap:2px;
  border-left:1px solid var(--border);
}
.pd-stat:first-child{ border-left:0; }
.pd-stat-lbl{ font-family:'JetBrains Mono',monospace; font-size:10px; font-weight:600; letter-spacing:.1em; text-transform:uppercase; color:var(--faint); }
.pd-stat-num{ font-family:'Fraunces',serif; font-weight:600; font-size:28px; line-height:1; color:var(--text); font-variant-numeric:tabular-nums; }
.pd-stat-num i{ font-style:normal; font-size:.6em; color:var(--muted); }
.pd-stat-off .pd-stat-num{ color:var(--off); }
.pd-stats-bar{ grid-column:1/-1; height:6px; background:var(--surface2); }
.pd-stats-bar span{ display:block; height:100%; background:var(--accent); transition:width var(--mo-3) var(--ease); }
@media (max-width:560px){
  .pd-stats{ grid-template-columns:1fr 1fr; }
  .pd-stat:nth-child(3){ border-left:0; }
  .pd-stat:nth-child(odd){ border-left:0; }
  .pd-stat:nth-child(3), .pd-stat:nth-child(4){ border-top:1px solid var(--border); }
}
/* Z-01 — leeg is geen fout: gestippelde rand, één regel, één knop. */
.progress-empty{
  background:transparent; border:1.5px dashed var(--border-strong); border-radius:var(--r-md);
  padding:var(--sp-6) var(--sp-5); color:var(--muted); font-size:14px; line-height:1.5;
  text-align:center; display:flex; flex-direction:column; align-items:center; gap:var(--sp-4);
}
.progress-foot{
  font-size:.74rem; color:var(--muted); line-height:1.45; margin:var(--sp-1) 0 0;
  max-width:60ch;
}

/* (De cloud-sync-balk uit v0.38.1 is in v0.39.0 verwijderd — zie
   progress-ui.js. Sync-bediening staat in de "Meer info"-modal.) */

/* Niveau-regels per module in Mijn Voortgang (v0.39.0) */
.progress-lvl-rows{ display:flex; flex-direction:column; gap:var(--sp-2); margin:var(--sp-1) 0 2px; }
.progress-lvl-row{ display:flex; align-items:center; gap:var(--sp-3); font-size:.8rem; }
.progress-lvl-name{ display:flex; align-items:center; gap:var(--sp-2); flex:0 0 8.5em; color:var(--text); }
.progress-lvl-track{
  flex:1; height:7px; border-radius:999px; overflow:hidden;
  background:color-mix(in srgb, var(--muted) 22%, transparent);
}
.progress-lvl-fill{ display:block; height:100%; border-radius:999px; }
.progress-lvl-num{ flex:0 0 auto; color:var(--muted); font-variant-numeric:tabular-nums; }
.progress-lvl-row.is-done .progress-lvl-num{ color:var(--accent); font-weight:600; }

/* "Gespeeld"-teken in het verdiep-raster (v0.40.0; v0.65.10: klein
   piano-klavier-icoontje i.p.v. het ⌨-teken). */
.pd-play-mark{
  display:inline-block; width:1.25em; height:.82em; margin-left:var(--sp-1);
  opacity:.8; vertical-align:-.1em;
}
.pd-play-mark svg{ display:block; width:100%; height:100%; }
/* Zelfde klavier-icoontje (ProgressUI._PLAY_ICO) vóór de MIDI-statustekst op
   het tegel-overzicht + in het MIDI-paneel (Fase 5-nazorg, verving een los
   🎹-emoji — zie MidiEngine.updateStatusIndicator()/App._renderMidiPanel()). */
.tiles-midi-ico{
  display:inline-block; width:20px; height:12.7px; margin-right:var(--sp-2);
  vertical-align:-2px; color:currentColor;
}
.tiles-midi-ico svg{ display:block; width:100%; height:100%; }
.pd-cat.pd-is-played{ font-weight:600; }
.pd-leg.pd-leg-played{ color:var(--muted); }
.pd-leg.pd-leg-played::before{ display:none; }

/* Niveau-stipje (v0.39.0) — bij opties in de instellingen, niveau-knoppen
   en voortgangsregels. */
.lvl-dot{
  display:inline-block; width:8px; height:8px; border-radius:50%;
  flex:0 0 auto; vertical-align:middle;
}
.opt-btn .lvl-dot{ margin-right:var(--sp-1); }
.setting-group-level .opt-row{ margin-bottom:2px; }
/* Niveau-banner vlak onder de titel, boven het speelveld (v0.88.0) — verving
   de verplichte rondleiding + de losse "kies je niveau"-kaart. Herzien
   ná gebruikersfeedback op de eerste versie (een kleine chip náást de
   titel): "nauwelijks zichtbaar, moet prominenter". Nu een volle-breedte
   balk, zelfde gewicht/opzet als de overige eenmalige tegel-overzicht-
   banners (#help-hint e.d.) — elke oefening met een eigen
   niveau-preset toont hier stil het effectieve niveau (eigen instelling →
   anders globaal → anders 'Beginner' als weergave-standaard), klik opent
   de instellingenlade. */
.lvl-banner{
  display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3);
  width:100%; max-width:var(--w-focus); box-sizing:border-box;
  margin:0 0 var(--sp-4); padding:var(--sp-3) var(--sp-4);
  border:1px solid var(--border); border-radius:var(--r-md);
  background:var(--surface); color:var(--text);
  font-size:.9rem; font-weight:600; cursor:pointer;
  transition:border-color var(--mo-2);
}
.lvl-banner:hover{ border-color:var(--accent); }
.lvl-banner[hidden]{ display:none; }
.lvl-banner-label{ display:inline-flex; align-items:center; gap:var(--sp-2); }
.lvl-banner .lvl-dot{ width:10px; height:10px; }
.lvl-banner .sys-icon{ color:var(--muted); flex-shrink:0; }
.lvl-btn-free{ font-style:italic; }
/* Gebruikersverzoek (Fase 5-nazorg, tweede ronde; v0.83.4 herzien): op de
   bredere lade (zie #settings-drawer hierboven, vanaf 820px) stond dit
   eerst als 4 gelijke kolommen op één regel — bleek in de praktijk (echte
   browser-lettertypes, niet de headless-teststraat) net te krap: langere
   namen ("Gevorderd"/"Gemiddeld") liepen tegen hun 93px-kolom aan en vielen
   terug op de ellipsis-fix hieronder i.p.v. leesbaar te blijven.
   Teruggezet naar 2 kolommen × 2 rijen — Beginner/Gemiddeld boven,
   Gevorderd/Vrij eronder — elke knop krijgt zo ruim het dubbele van de
   breedte. Smaller dan 820px (mobiel/smalle tablet) blijft het bestaande
   wrap-gedrag. */
@media (min-width:820px){
  /* Grid i.p.v. flex:1 — bleek betrouwbaarder om exact op de beschikbare
     breedte te blijven (flex:1 met flex-basis:0% bleef hier de rij ~75px
     breder maken dan zijn eigen ouder, ook met min-width:0 op de knoppen;
     `minmax(0,1fr)`-kolommen sommeren altijd exact tot 100%, zelfde
     patroon als .opt-keys-row/.chord-type-tier hierboven). */
  .setting-group-level .opt-row{
    display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:var(--sp-2); flex-wrap:nowrap;
  }
  /* v0.83.1: gemeten dat "Intermediate"/"Gemiddeld" (single-word, kan niet
     afbreken) buiten zijn 93px-kolom bleedde in plaats van te wrappen —
     white-space:normal deed hier niks nuttigs, want een los woord heeft geen
     spatie om op af te breken. min-width:0 is nodig op een grid-item (default
     min-width:auto negeert overflow/ellipsis anders net als bij een flex-item). */
  .setting-group-level .opt-row .opt-btn{
    min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; text-align:center;
  }
}

/* MIDI-kalibratie-overlay (bugfix-ronde ná v0.96.5) — verving de inline
   .mrange-prompt-kaart die op het tegeloverzicht niet opviel en onzichtbaar
   was zodra #tiles-page op display:none stond (binnen een module). Zelfde
   overlay-/modal-opzet als #assess-overlay/#assess-modal hierboven — de
   inhoud zelf hergebruikt ook gewoon de .assess-*-klassen, geen eigen set. */
#midi-calib-overlay{
  position:fixed; inset:0; z-index:10500; display:none;
  align-items:center; justify-content:center; padding:var(--sp-5);
  background:rgba(0,0,0,.6); backdrop-filter:blur(2px);
}
#midi-calib-overlay.visible{ display:flex; }
#midi-calib-modal{
  background:var(--surface); color:var(--text); border:1px solid var(--border);
  border-radius:var(--r-md); padding:var(--sp-5); max-width:420px; width:100%;
  max-height:calc(100vh - 48px); overflow-y:auto;
  box-shadow:0 24px 64px rgba(0,0,0,.5); position:relative; margin:auto;
}

/* Niveau-schakelaar in de "Meer info"-modal (v0.39.0) */
.credits-level-section{ margin-top:var(--sp-4); }
.credits-level-section h3{ font-size:.9rem; margin:0 0 var(--sp-1); }
.level-block{ margin-top:var(--sp-2); }
.level-block .lvl-btn{ display:inline-flex; align-items:center; gap:var(--sp-2); }

/* Gedeelde balk (totaal + per module) */
.progress-bar{
  width:100%; height:8px; border-radius:999px; overflow:hidden;
  background:color-mix(in srgb, var(--muted) 22%, transparent);
}
.progress-bar-fill{
  display:block; height:100%; border-radius:999px;
  background:var(--accent);
  transition:width var(--mo-3) var(--ease);
}
.progress-pct-sign{ font-size:.6em; font-weight:600; margin-left:1px; color:var(--muted); }

/* Per-module raster */
.progress-modules{
  display:grid; grid-template-columns:repeat(auto-fill, minmax(240px, 1fr)); gap:var(--sp-3);
}
.progress-mod{
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md);
  padding:var(--sp-4); display:flex; flex-direction:column; gap:var(--sp-2);
  transition:border-color var(--mo-1) var(--ease);
}
.progress-mod-empty{ opacity:.6; }
.progress-mod-head{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-2); }
.progress-mod-head h3{ font-family:'Inter',sans-serif; font-size:14.5px; font-weight:600; color:var(--text); margin:0; }
.progress-mod-none{ font-size:.8rem; color:var(--muted); margin:0; }
.progress-mod-mastery{ display:flex; align-items:baseline; justify-content:space-between; gap:var(--sp-2); }
.progress-mod-label{ font-size:.72rem; text-transform:uppercase; letter-spacing:.04em; color:var(--muted); }
.progress-mod-pct{ font-size:1.15rem; font-weight:800; color:var(--text); font-family:'Inter',sans-serif; }
.progress-mod-pctnum{ font-size:.82rem; font-weight:700; color:var(--muted); }
/* Context bij de score (v0.29.0) */
.progress-mod-status{ font-size:.78rem; color:var(--text); margin:0; line-height:1.4; }
/* Twee compacte statuschips op de kaart (Fase 8, v0.82.0) — verving de
   vierledige uitsplitsing + Herkennen/Spelen-regel + trendpijl. */
.progress-mod-chips{ display:flex; flex-wrap:wrap; gap:var(--sp-2); }
.mc-chip{
  display:inline-flex; align-items:center; gap:var(--sp-1); font-size:.72rem; color:var(--text);
  background:var(--surface2); border:1px solid var(--border); border-radius:999px; padding:3px var(--sp-2);
}
.mc-dot{ width:7px; height:7px; border-radius:50%; flex-shrink:0; }
.mc-mastered .mc-dot{ background:var(--ok); }
.mc-busy .mc-dot{ background:var(--off); }
.progress-streak{
  font-family:'JetBrains Mono',monospace; font-size:.74rem; font-weight:800; color:var(--accent);
  border:1px solid var(--accent); border-radius:999px; padding:1px var(--sp-2);
}

/* Klikbare modulekaart → verdiep-paneel (v0.24.0) */
.progress-mod[data-open]{ cursor:pointer; }
.progress-mod[data-open]:hover{ border-color:var(--accent); }
.progress-mod[data-open]:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.progress-mod-chevron{ margin-left:auto; color:var(--muted); font-size:1.1rem; line-height:1; }
.progress-mod-head{ position:relative; }
/* Uitnodiging, geen waarschuwing (Fase 8, v0.82.0) — vervangt de vroegere
   "N te herhalen"-chip + naamlijst op de kaart zelf; staat nu alleen nog
   in het verdiep-paneel, in gewone/rustige tekst i.p.v. een gekleurde pil. */
.progress-refresh-hint{ font-size:.78rem; color:var(--muted); margin:0; line-height:1.4; }
/* Ritme-verdiep-paneel (v0.60.0): "gemiddeld op tijd X% · N rondes" bovenaan. */
.progress-detail-rhythm{
  font-size:.82rem; color:var(--muted); margin:2px 0 var(--sp-3); line-height:1.5;
}
.progress-detail-rhythm strong{ color:var(--text); }
/* .progress-practice-mini + .progress-mod-rhythm zijn in v0.60.0 vervallen
   (losse Ritme-kaart weg — Ritme loopt nu via de gewone _moduleCard). */
.progress-practice{
  font:inherit; font-weight:700; cursor:pointer; border-radius:999px;
  font-size:.85rem; padding:var(--sp-2) var(--sp-5); margin-top:var(--sp-3); align-self:flex-start;
  background:var(--accent); color:var(--accent-ink); border:none;
}
/* Plan_van_Aanpak_v1.0 Deel 2 §1 / Deel 3 §2 (Trigger 2) — actieknop op de
   modulekaart zodra Beginner 100% beheerst is; volle breedte i.p.v. de
   compacte .progress-practice-pil, zodat 'ie duidelijk als de vervolgstap
   opvalt naast de twee statuschips. */
.progress-levelup-btn{
  font:inherit; font-weight:700; cursor:pointer; border-radius:var(--r-md);
  font-size:.82rem; padding:var(--sp-2) var(--sp-4); margin-top:var(--sp-1); width:100%;
  background:var(--accent); color:var(--accent-ink); border:none;
}
@media (hover:hover){ .progress-levelup-btn:hover{ filter:brightness(1.08); } }

/* Verdiep-per-module-paneel */
/* S5-03 — verdiep-paneel: volle breedte onder de rij, 1,5px --accent-rand,
   padding --sp-5. */
.progress-detail{
  grid-column:1/-1;
  background:var(--surface); border:1.5px solid var(--accent); border-radius:var(--r-lg);
  padding:var(--sp-5); display:flex; flex-direction:column; gap:var(--sp-3);
}
.progress-detail-head{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3); }
.progress-detail-head h3{ font-family:'Fraunces',serif; font-weight:600; font-size:1.05rem; margin:0; color:var(--text); }
.progress-detail-close{
  background:transparent; border:none; color:var(--muted); font-size:1.3rem; line-height:1; cursor:pointer; padding:2px var(--sp-2);
}
.progress-detail-close:hover{ color:var(--text); }
.progress-detail-legend{ display:flex; flex-wrap:wrap; gap:var(--sp-1) var(--sp-3); font-size:.72rem; }
.pd-leg{ display:inline-flex; align-items:center; gap:var(--sp-1); color:var(--muted); }
.pd-leg::before{ content:''; width:9px; height:9px; border-radius:2px; background:currentColor; }
.pd-leg.pd-mastered{ color:var(--ok); }
.pd-leg.pd-attention{ color:var(--err); }
.pd-leg.pd-learning{ color:var(--off); }
.pd-leg.pd-untried{ color:var(--muted); opacity:.6; }
.progress-detail-grid{ display:flex; flex-wrap:wrap; gap:var(--sp-2); }
.pd-cat{
  font-size:.76rem; font-weight:600; padding:var(--sp-1) var(--sp-3); border-radius:8px;
  border:1px solid var(--border); background:color-mix(in srgb, var(--muted) 8%, transparent);
  color:var(--text);
}
.pd-cat.pd-mastered{ border-color:var(--ok); color:var(--ok); background:var(--ok-soft); }
.pd-cat.pd-attention{ border-color:var(--err); color:var(--err); background:var(--err-soft); }
.pd-cat.pd-learning{ border-color:var(--off); color:var(--off); background:var(--off-soft); }
.pd-cat.pd-untried{ opacity:.5; }
/* Recent % / voortgang per onderdeel (v0.41.0) */
.pd-cat-pct{ margin-left:var(--sp-1); font-weight:700; opacity:.9; font-variant-numeric:tabular-nums; }
.pd-cat-pct.pd-cat-prog{ font-weight:600; opacity:.7; }
.pd-cat-refresh{
  margin-left:var(--sp-1); font-size:.85em; font-weight:600; font-style:italic;
  opacity:.85;
}
.pd-cat.pd-is-decayed{ border-style:dashed; }
.progress-detail-summary{ display:flex; flex-direction:column; gap:var(--sp-1); }
.progress-detail-sumline{ font-size:.85rem; color:var(--muted); display:flex; align-items:center; gap:var(--sp-2); flex-wrap:wrap; }
.progress-detail-sumline strong{ color:var(--text); }
.progress-detail-sumline .pd-att-note{ color:var(--err); }
.progress-detail-sumline .pd-mod-check{ font-weight:600; color:var(--muted); }
.progress-detail-sumline .pd-mod-check.is-pass{ color:var(--ok); }
/* Kern/Uitgebreid-koppen in het verdiep-paneel (v0.26.0, Toonladders/Akkoorden). */
.progress-detail-subhead{ font-size:.74rem; text-transform:uppercase; letter-spacing:.04em; color:var(--muted); margin:var(--sp-4) 0 var(--sp-2); }
.progress-detail-subhead:first-of-type{ margin-top:var(--sp-1); }
/* Plan_van_Aanpak_v1.0 Deel 2, §3.1/§3.2 — per-type 12-toonsoorten-grid
   (Toonladders: 7 types; Akkoorden: idem, binnen elk van de drie
   CHORD_TYPE_TIERS-groepen), zie ProgressUI._typeGrids()/_chordTierGrids(). */
.progress-detail-typegroup{ margin-bottom:var(--sp-3); }
.progress-detail-typehead{ display:flex; align-items:baseline; gap:var(--sp-2); }
.pd-type-count{ font-weight:700; color:var(--text); text-transform:none; letter-spacing:normal; font-size:.9rem; }
/* Plan_van_Aanpak_v1.0 Deel 2, §3.3 — per-maatsoort-regel (chip + "% op
   tijd"-statistiek), vervangt de generieke _grid() voor Ritme. */
.pd-rhythm-meterstat{ font-size:.8rem; color:var(--muted); }
.pd-rhythm-meterstat strong{ color:var(--text); }
/* "+ N / M uitgebreide vormen"-regeltje onder de voortgangsbalk op een modulekaart. */
.progress-mod-ext{ font-size:.72rem; color:var(--muted); margin-top:var(--sp-1); }
.pd-dot{ width:9px; height:9px; border-radius:2px; flex-shrink:0; }
.pd-dot.pd-mastered{ background:var(--ok); }
.pd-dot.pd-attention{ background:var(--err); }
.pd-dot.pd-learning{ background:var(--off); }
.pd-dot.pd-untried{ background:var(--muted); opacity:.5; }

@media (max-width:560px){
  #progress-content{ padding:var(--sp-4) var(--sp-4) var(--sp-8); }
  .progress-modules{ grid-template-columns:1fr; }
}

/* Ritme & Maatsoort-module (Fase 5.7, sinds v0.23.0) — los top-level scherm,
   zelfde display:none/flex-opzet als #theory-view/#progress-view. RhythmUI
   (js/rhythm-ui.js) bouwt #rhythm-content op. */
#rhythm-view{
  display:none; flex-direction:column; width:100%; height:100%; overflow-y:auto;
  background:var(--canvas); transition:background-color var(--mo-3);
}
#rhythm-content{ width:100%; max-width:620px; margin:0 auto; padding:var(--sp-5) var(--sp-5) var(--sp-8); }
.rhythm-wrap{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-4); }
.rhythm-intro{
  font-size:.82rem; color:var(--muted); line-height:1.5; margin:0; max-width:52ch; text-align:center;
}
.rhythm-intro-short{ font-size:.8rem; max-width:44ch; }
/* Kalibratie-prompt bij binnenkomst (v0.28.0) — één keer per sessie, zie
   RhythmUI.CALIB_SESSION_KEY. Zachte accent-kaart bovenaan het scherm. */
.rhythm-calib-prompt{
  width:100%; max-width:460px; margin-bottom:var(--sp-1); padding:var(--sp-4) var(--sp-4);
  background:
    radial-gradient(circle at 90% 8%, color-mix(in srgb, var(--accent) 14%, transparent), transparent 60%),
    var(--surface);
  border:1px solid color-mix(in srgb, var(--accent) 42%, transparent); border-radius:var(--r-md);
  display:flex; flex-direction:column; align-items:center; gap:var(--sp-3); text-align:center;
}
.rhythm-calib-prompt p{ margin:0; font-size:.82rem; color:var(--muted); line-height:1.5; }
.rhythm-calib-prompt-actions{ display:flex; flex-wrap:wrap; gap:var(--sp-2) var(--sp-3); align-items:center; justify-content:center; }
.rhythm-calib-prompt .rhythm-action{ width:auto; padding:var(--sp-2) var(--sp-5); }
.rhythm-opts{ display:flex; flex-wrap:wrap; gap:var(--sp-2) var(--sp-4); align-items:center; justify-content:center; }
.rhythm-mini{
  font:inherit; font-size:.78rem; font-weight:600; padding:var(--sp-1) var(--sp-3); border-radius:999px;
  background:transparent; color:var(--muted); border:1px solid var(--border); cursor:pointer;
}
.rhythm-mini:hover:not(:disabled){ color:var(--text); border-color:var(--accent); }
.rhythm-mini:disabled{ opacity:.45; cursor:default; }
/* Kalibratieknop (v0.60.1) — duidelijker dan de oude mini-knop: een echte
   knop met een korte uitlegregel eronder. */
.rhythm-calib-box{
  display:flex; flex-direction:column; align-items:center; gap:var(--sp-1);
  max-width:340px; text-align:center;
}
.rhythm-calib-action{ width:auto; padding:var(--sp-2) var(--sp-4); font-size:.82rem; }
.rhythm-calib-action:disabled{ opacity:.5; cursor:default; }
.rhythm-calib-hint{ font-size:.72rem; color:var(--muted); line-height:1.4; }
/* "Beluister ritme" — prominenter dan de mini-knoppen (v0.53.0, gebruiker
   miste hem); staat nu direct onder de notenbalk. */
.rhythm-listen{
  font:inherit; font-size:.84rem; font-weight:700; padding:var(--sp-2) var(--sp-5); border-radius:999px;
  background:color-mix(in srgb, var(--accent) 12%, transparent);
  color:var(--accent); border:1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  cursor:pointer;
}
.rhythm-listen{ min-height:38px; box-sizing:border-box; }
.rhythm-listen:hover:not(:disabled){ background:color-mix(in srgb, var(--accent) 20%, transparent); }
.rhythm-listen:disabled{ opacity:.45; cursor:default; }
/* Lopende band heeft geen "Beluister"-knop, maar houdt de ruimte vrij zodat
   het scherm niet verspringt bij het wisselen van oefenvorm (v0.60.2). */
.rhythm-listen-slot{ min-height:38px; }
@media (max-width:560px){ .rhythm-listen, .rhythm-listen-slot{ min-height:34px; } }
/* Actie-rij: "Opnieuw" (v0.53.0) naast de primaire Start/Volgende-knop. */
.rhythm-actions{ display:flex; gap:var(--sp-3); align-items:center; justify-content:center; flex-wrap:wrap; }
.rhythm-action.ghost{ background:transparent; border:1px solid var(--border); color:var(--muted); }
.rhythm-action.ghost:hover{ color:var(--text); border-color:var(--accent); }
.rhythm-action[hidden]{ display:none; }
/* Plan_van_Aanpak_v1.0 Deel 1, §3 — BPM-bediening rechtstreeks op de
   oefenkaart (verving de -/+ -stepper die hier tot v0.95.0 in de
   instellingen-drawer stond, zie RhythmUI._tempoWidgetHtml()). */
.rhythm-tempo-card{
  display:flex; align-items:center; justify-content:center; flex-wrap:wrap;
  gap:var(--sp-2); margin:0 0 var(--sp-2);
}
.rhythm-tempo-btn{
  font:inherit; font-size:.82rem; font-weight:700; min-width:38px; padding:var(--sp-1) var(--sp-3);
  border-radius:999px; background:transparent; border:1px solid var(--border); color:var(--muted); cursor:pointer;
}
.rhythm-tempo-btn:hover{ color:var(--text); border-color:var(--accent); }
.rhythm-tempo-tap{ color:var(--accent); border-color:color-mix(in srgb, var(--accent) 45%, transparent); }
.rhythm-tempo-val{ font-size:.85rem; color:var(--muted); min-width:70px; text-align:center; }
.rhythm-tempo-val strong{ color:var(--text); }
/* Kleine toelichting onder een instelling in de drawer (sinds v0.25.0, Ritme-Geluid). */
.setting-hint-text{ font-size:.74rem; color:var(--muted); margin:var(--sp-2) 0 0; line-height:1.4; }
.rhythm-score{
  width:100%; max-width:540px; min-height:96px;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md);
  padding:var(--sp-3) var(--sp-4); display:flex; align-items:center; justify-content:center;
}
.rhythm-score svg{ width:100%; height:auto; max-width:520px; display:block; }
/* Desktop: de ritme-notatie een stuk groter (gebruikersverzoek v0.28.1) —
   de VexFlow-SVG heeft een viewBox, dus een bredere container schaalt het
   hele notenbeeld (ook de noten zelf) mee omhoog. Mobiel ongewijzigd. */
@media (min-width:820px){
  #rhythm-content{ max-width:880px; }
  .rhythm-score{ max-width:840px; min-height:150px; padding:var(--sp-4) var(--sp-5); }
  .rhythm-score svg{ max-width:800px; }
}
.rhythm-beat-dots{ display:flex; gap:var(--sp-4); }
.rhythm-beat-dots span{
  width:12px; height:12px; border-radius:50%;
  background:color-mix(in srgb, var(--muted) 30%, transparent);
  transition:background-color var(--mo-1) var(--ease), transform var(--mo-1) var(--ease);
}
.rhythm-beat-dots span.on{ background:var(--accent); transform:scale(1.35); }
.rhythm-status{ font-size:.9rem; color:var(--muted); min-height:1.4em; text-align:center; }
.rhythm-status.is-countin{ color:var(--icon-g2); }
.rhythm-status.is-playing{ color:var(--accent); font-weight:600; }
.rhythm-tap-btn{
  width:100%; max-width:340px; padding:var(--sp-5) 0; border-radius:var(--r-md);
  border:2px solid var(--accent); background:var(--surface);
  backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
  color:var(--accent); font-family:'Inter',sans-serif; font-weight:800; font-size:1.15rem;
  letter-spacing:.12em; cursor:pointer; user-select:none; touch-action:manipulation;
  transition:background-color var(--mo-1) var(--ease), transform var(--mo-1) var(--ease);
}
.rhythm-tap-btn:active, .rhythm-tap-btn.flash{
  background:var(--accent); color:var(--accent-ink); transform:scale(.985);
}
.rhythm-action{
  padding:var(--sp-3) var(--sp-6); border-radius:999px; font-weight:700; font-size:.9rem; cursor:pointer;
}
.rhythm-action:disabled{ opacity:.5; cursor:default; }
.rhythm-result{
  width:100%; max-width:520px; text-align:center;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md); padding:var(--sp-4) var(--sp-4);
}
/* Meetikken-sessie (v0.60.2) — "N / 25"-balk boven de notenbalk + eindkaart. */
.rhythm-session-bar{
  width:100%; max-width:520px; display:flex; align-items:center; gap:var(--sp-3); margin-top:calc(var(--sp-1) * -1);
}
.rhythm-session-bar[hidden]{ display:none; }
.rhythm-session-track{
  flex:1; height:6px; border-radius:999px; overflow:hidden;
  background:color-mix(in srgb, var(--text) 14%, transparent);
}
.rhythm-session-fill{
  display:block; height:100%; border-radius:999px; background:var(--accent); transition:width var(--mo-3) var(--ease);
}
.rhythm-session-count{
  font-size:.78rem; font-weight:700; color:var(--muted);
  font-variant-numeric:tabular-nums; white-space:nowrap;
}
.rhythm-session-end[hidden]{ display:none; }
/* Tijdens het sessie-eindscherm verbergen we de tik-/beluister-knop en de
   actie-rij — die zetten zelf een display, dus [hidden] moet forceren. */
.rhythm-tap-btn[hidden], .rhythm-actions[hidden], .rhythm-listen[hidden]{ display:none !important; }
.rhythm-session-end-card{
  width:100%; max-width:420px; text-align:center;
  background:var(--surface); border:1px solid var(--accent); border-radius:var(--r-md); padding:var(--sp-4) var(--sp-4);
  display:flex; flex-direction:column; align-items:center; gap:var(--sp-2);
}
.rhythm-session-end-head{ font-family:'Fraunces',serif; font-weight:600; font-size:1.05rem; margin:0; color:var(--text); }
.rhythm-session-end-sub{ font-size:.85rem; color:var(--muted); margin:0; }
.rhythm-session-end-card .rhythm-actions{ margin-top:var(--sp-1); }
.rhythm-res-head{ font-size:.95rem; font-weight:700; color:var(--text); margin-bottom:var(--sp-2); }
.rhythm-res-score{ color:var(--accent); }
.rhythm-res-chips{ display:flex; flex-wrap:wrap; gap:var(--sp-2); justify-content:center; }
.rhythm-chip{ font-size:.74rem; font-weight:600; border-radius:999px; padding:3px var(--sp-3); }
/* Kleuren gelijk aan RhythmUI.VERDICT_COLORS + de legenda onder de balk (v0.31.0). */
.rhythm-chip.v-perfect{ color:var(--ok); background:var(--ok-soft); }
.rhythm-chip.v-good{ color:var(--ok); background:var(--ok-soft); }
.rhythm-chip.v-early{ color:var(--off); background:var(--off-soft); }
.rhythm-chip.v-late{ color:var(--off); background:var(--off-soft); }
.rhythm-chip.v-miss{ color:var(--err); background:var(--err-soft); }
.rhythm-chip.v-extra{ color:var(--err); background:var(--err-soft); }

/* Kleurenlegenda onder de ritme-notenbalk (v0.31.0, Ritme v2 punt 2) — toont
   alleen de uitkomsten die in de afgelopen ronde voorkwamen. */
/* min-height reserveert de regel zodra een ronde loopt, ook als er nog geen
   uitkomst is — anders sprong de tik-knop omlaag zodra de eerste noot een
   kleur (en dus de legenda) kreeg (v0.57.2, gebruikersfeedback). */

/* Lopende band (v0.54.0, Ritme deel 2) — twee gestapelde maten: bovenaan de
   huidige, eronder (gedimd) de vooruitkijk. */
.rhythm-band{
  width:100%; max-width:560px; display:flex; flex-direction:column; gap:var(--sp-2);
  background:var(--surface); border:2px solid var(--border); border-radius:var(--r-md);
  padding:var(--sp-3) var(--sp-4); transition:border-color var(--mo-1) var(--ease), box-shadow var(--mo-1) var(--ease);
}
@media (min-width:820px){ .rhythm-band{ max-width:720px; padding:var(--sp-4) var(--sp-5); } }
.rhythm-band-row{ display:flex; align-items:center; }
.rhythm-band-staff{ flex:1; min-width:0; display:flex; align-items:center; }
.rhythm-band-staff svg{ width:100%; height:auto; display:block; }
.rhythm-band-now{ position:relative; }
.rhythm-band-next{ opacity:.52; }
.rhythm-band-row + .rhythm-band-row{ border-top:1px dashed var(--border); padding-top:var(--sp-2); }
/* Rand-flits per afgeronde maat. */
.rhythm-band.flash-perfect{ border-color:var(--ok); box-shadow:0 0 0 3px var(--ok-soft); }
.rhythm-band.flash-good{ border-color:var(--ok); box-shadow:0 0 0 3px var(--ok-soft); }
.rhythm-band.flash-near{ border-color:var(--off); box-shadow:0 0 0 3px var(--off-soft); }
.rhythm-band.flash-miss{ border-color:var(--err); box-shadow:0 0 0 3px var(--err-soft); }
.rhythm-band-tally{ font-size:.85rem; font-weight:700; color:var(--muted); min-height:1.2em; }
.rhythm-band-tally[hidden]{ display:none; }
.rhythm-band-tally.is-summary{ color:var(--text); font-size:.92rem; }

@media (max-width:560px){
  /* v0.54.1 (gebruikersfeedback: te veel tekst/hoogte op mobiel, valt buiten
     beeld — de "?"-knop heeft de uitleg). Compacter: minder tussenruimte,
     kortere intro, kleinere tik-knop. */
  #rhythm-content{ padding:var(--sp-4) var(--sp-4) calc(var(--sp-8) + env(safe-area-inset-bottom)); }
  .rhythm-wrap{ gap:var(--sp-3); }
  .rhythm-intro{ font-size:.78rem; margin:0; }
  .rhythm-intro-short{ max-width:34ch; }
  .rhythm-tap-btn{ padding:var(--sp-4) 0; font-size:1.05rem; }
  .rhythm-score{ min-height:auto; padding:var(--sp-2) var(--sp-3); }
  .rhythm-result{ padding:var(--sp-3) var(--sp-3); }
  .rhythm-res-head{ margin-bottom:var(--sp-1); }
  .rhythm-band{ padding:var(--sp-2) var(--sp-3); }
  /* na de eerste ronde is de intro overbodig — de "?"-knop heeft de uitleg */
  .rhythm-wrap.has-played .rhythm-intro{ display:none; }
}

