/* Cijferkonijn - vormgeving volgens docs/designspec.md.
   Neo-brutalistisch: 2px zwarte randen, harde schaduwen zonder blur,
   warme papierachtergrond, groen als enige accentkleur.
   De designspec-fonts reizen mee met de app: ze staan als woff2 in web/fonts/
   en worden hieronder met @font-face geladen. De Google Fonts-link uit de
   designspec is terecht geschrapt -- de CSP staat alleen 'self' toe en een
   kinderapp hoort geen verzoek naar een CDN te doen -- maar de conclusie was
   zelf hosten, niet weglaten. De fallback-stacks blijven staan, zodat een
   ontbrekend bestand een systeemletter oplevert en geen leeg scherm. */

/* Alleen de gewichten die deze stijl echt gebruikt: Figtree 400 (body), 600,
   700 en 800; Source Serif 4 uitsluitend 700. font-display: swap toont de
   fallback meteen -- de bladspiegel verspringt dan bij het inladen, en dat is
   de ruil: zichtbare tekst wint van een strak uitgelijnde lege pagina. */
@font-face {
  font-family: Figtree;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/Figtree-Regular.woff2") format("woff2");
}

@font-face {
  font-family: Figtree;
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/Figtree-SemiBold.woff2") format("woff2");
}

@font-face {
  font-family: Figtree;
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/Figtree-Bold.woff2") format("woff2");
}

@font-face {
  font-family: Figtree;
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("fonts/Figtree-ExtraBold.woff2") format("woff2");
}

@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/SourceSerif4-Bold.woff2") format("woff2");
}

:root {
  --inkt: #14171A;
  --papier: #FBFAF7;
  --canvas: #EFEDE6;
  --paneel: #F4F2EB;
  --paneel-hover: #F1EFE8;
  --groen: #0E9F6E;
  --groen-donker: #0B7A55;
  --groen-label: #0B6A4A;
  --groen-tekst: #08251B;
  --mint: #E7F2EC;
  --mint-dof: #DDE9E3;
  --zalm: #FBF1EC;
  --rood: #A5432A;
  --tekst-sterk: #3D444B;
  --tekst-zwak: #5A6169;
  --lijn-zacht: #E2DFD4;
  --streep-grijs: #C7C2B4;

  /* Eén hoogte voor alles wat in een formulierrij naast elkaar staat. Zonder
     die afspraak was een invoerveld 56px en een knop 48px; de rij lijnt
     onderaan uit, dus de bovenkanten liepen 8px uiteen en dat leest als
     scheef. De designspec noemt 48px als raakhoogte-ondergrens voor een
     secundaire knop, niet als vaste maat, dus 56px blijft binnen die regel. */
  --veldhoogte: 56px;

  /* De hoekstraal van knoppen, kaarten, toetsen en het antwoordveld. De
     designspec zegt 0, en dat blijft zo op het docent- en loginscherm; het
     leerlingscherm zet hem hieronder op 18px (#61: rond was unaniem). */
  --radius: 0;

  /* De vulling van een voortgangsbalk. Het donkere accent en niet --groen:
     zie .balk-vulling. Hij volgt --groen-donker, dus elk thema krijgt hem
     mee zonder een eigen regel. */
  --balkvulling: var(--groen-donker);

  --ui: Figtree, system-ui, -apple-system, "Segoe UI", sans-serif;
  --serif: "Source Serif 4", Georgia, "Times New Roman", serif;
}

/* --- Leerlingscherm: ronde hoeken en kleurthema's (#61) ---

   Alleen leerling.html draagt data-scherm="leerling"; het docentscherm blijft
   recht en groen. Een thema hangt als data-thema aan <body> en overschrijft
   precies deze tien tokens, en geen andere:

     --canvas, --papier, --paneel, --paneel-hover   de vlakken
     --groen, --groen-donker, --groen-label,        het accent: knop, balk,
     --groen-tekst                                  gekozen optie, labels
     --mint, --mint-dof                             de zachte accentvulling

   --inkt, --rood, --zalm, --tekst-sterk, --tekst-zwak, --lijn-zacht en
   --streep-grijs blijven staan: randen, foutkleur en lopende tekst zijn in
   elk thema hetzelfde, anders leest een fout er in het ene thema als een
   waarschuwing en in het andere als versiering.

   "nu" is geen blok: dat is :root zoals hij is.

   Contrast, gemeten met web/tests/thema.test.js (WCAG 2.x):
   - --groen-tekst op --groen (de primaire knop, altijd 21px vet of groter,
     dus grote tekst): zon 8.26, zee 3.08, snoep 4.73. Zee haalt daarmee
     alleen de grens voor grote tekst (3:1); het accent #009cde en witte tekst
     erop zijn de opdracht uit het issue, en de test bewaakt dat er nergens
     kleine tekst in die combinatie bijkomt.
   - --papier op --groen-donker (hover van de primaire knop): zon 5.01,
     zee 5.19, snoep 6.91.
   - --groen-label op --papier (15px labels): zon 6.06, zee 6.74, snoep 6.75.
   Geen paars als achtergrond, ook niet bij snoep: het lila zit daar alleen
   in de labeltekst. */

body[data-scherm="leerling"] {
  --radius: 18px;
}

body[data-thema="zon"] {
  --canvas: #FFF1CC;
  --papier: #FFFBF0;
  --paneel: #FFF4D6;
  --paneel-hover: #FFEDB8;
  --groen: #FFB400;
  --groen-donker: #C2410C;
  --groen-label: #9A4A00;
  --groen-tekst: #3B2300;
  --mint: #FFECB3;
  --mint-dof: #FFE08A;
}

body[data-thema="zee"] {
  --canvas: #DDF1FA;
  --papier: #F7FCFF;
  --paneel: #E8F5FC;
  --paneel-hover: #D9EEF9;
  --groen: #009CDE;
  --groen-donker: #0071A6;
  --groen-label: #005F8C;
  --groen-tekst: #FFFFFF;
  --mint: #D6EEF9;
  --mint-dof: #BFE3F4;
}

body[data-thema="snoep"] {
  --canvas: #FDE7F0;
  --papier: #FFF7FA;
  --paneel: #FCE9F1;
  --paneel-hover: #F9DCE8;
  --groen: #D9266B;
  --groen-donker: #A8154F;
  --groen-label: #6D28D9;
  --groen-tekst: #FFFFFF;
  --mint: #FBE0EB;
  --mint-dof: #F6C9DB;
}

* {
  box-sizing: border-box;
}

/* Verborgen is verborgen, ook voor elementen met een eigen display-waarde. */
[hidden] {
  display: none !important;
}

html,
body {
  margin: 0;
}

body {
  background: var(--canvas);
  font-family: var(--ui);
  color: var(--inkt);
  min-height: 100dvh;
  display: flex;
  justify-content: center;
  padding: 24px;
}

a {
  color: var(--groen-donker);
  text-decoration: underline;
  text-underline-offset: 2px;
}

a:hover {
  color: var(--inkt);
}

/* De designspec noemt het ontbreken van focus-states als gat (5.6).
   Gevuld met de outline die het ontwerp al kent -- maar in inkt en niet in het
   accent, en dat is geen stijlkeuze: op het zon-canvas haalde een ring in
   --groen 1.59:1 en op zee 2.65:1, dus de focus was daar niet te zien terwijl
   WCAG 2.4.11 om 3:1 vraagt. Inkt haalt tegen elk vlak van elk thema minstens
   14.5:1 (gemeten in web/tests/thema.test.js), en de ring hoort bij de
   bediening en niet bij de kleur die het kind koos. */
:focus-visible {
  outline: 4px solid var(--inkt);
  outline-offset: 3px;
}

/* --- App-frame (2.1) --- */

.frame {
  /* Het ontwerp is getekend op 1280x800, maar dat is een tekencanvas en geen
     apparaat. Een Chromebook is 1366x768 (na browserchrome ~660px hoog) of
     1920x1080, en die laatste draait meestal op 125% schaling en meldt zich
     dus als ~1536x864. Vaste maten liepen aan beide kanten mis: op de kleine
     viel "Nakijken" onder de vouw, op de grote bleef een derde van het scherm
     leeg terwijl het kind in een kadertje tuurde.
     Dus meegroeien tot het past, met een bovengrens daarboven. Die grens is
     er omdat een opgave één ding is om naar te kijken: op 1920x1023 stond de
     som verloren in een kolom van 1160px en dreef "Nakijken" 190px los van
     het keypad. Groeien lost scrollen op; doorgroeien maakt het scherm leeg.
     1440x900 is waar de verhoudingen van het ontwerp nog kloppen. */
  width: min(1440px, 100%);
  height: min(900px, 100%);
  flex: none;
  background: var(--papier);
  border: 2px solid var(--inkt);
  box-shadow: 10px 10px 0 var(--inkt);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* Het leraarscherm mag breder dan het leerlingscherm. De docent werkt met
   tabellen van tweehonderdzevenentachtig doelen; daar is breedte lucht tussen
   de kolommen. De bovengrens van 1760px is er wel: een tabelregel die over
   twee meter scherm loopt, lees je niet meer terug naar de goede rij. */
.frame--breed {
  width: min(1760px, 100%);
  /* En de volle hoogte: de 900px van .frame is er voor een opgave, niet voor
     een tabel. Op 1447px hoog scheelt dat acht tabelregels in beeld. */
  height: 100%;
}

body {
  align-items: stretch;
  height: 100dvh;
}

/* Past het kader niet meer met marge eromheen, dan gaat de marge eraf en de
   slagschaduw uit: die kost alleen maar ruimte die er niet is. */
@media (max-width: 1328px), (max-height: 848px) {
  body {
    padding: 0;
  }

  .frame {
    box-shadow: none;
  }
}

/* --- Header (2.2) --- */

.header {
  height: 72px;
  flex: 0 0 72px;
  border-bottom: 2px solid var(--inkt);
  display: flex;
  align-items: center;
  padding: 0 32px;
  gap: 20px;
}

.header--tussen {
  justify-content: space-between;
}

.header--sessie {
  gap: 24px;
}

.header--leraar {
  background: var(--inkt);
  color: var(--papier);
  justify-content: space-between;
}

/* De mascotte naast het wordmerk. Puur versiering: alt="" en aria-hidden,
   want de naam staat er in tekst naast en een schermlezer hoort hem niet twee
   keer te krijgen.
   Hij mag boven de headerrand uitsteken -- de kop komt dan boven de lijn uit
   en dat is precies wat een mascotte hoort te doen. De header knipt niet af. */
.header-links {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.merk-mascotte {
  height: 62px;
  width: auto;
  flex: none;
  margin-bottom: -10px;
}

.wordmark {
  margin: 0;
  font-size: 17px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.header-rechts {
  display: flex;
  align-items: center;
  gap: 16px;
  font-size: 17px;
  color: var(--tekst-sterk);
}

.header--leraar .header-rechts {
  color: var(--streep-grijs);
}

.avatar {
  width: 40px;
  height: 40px;
  border: 2px solid var(--inkt);
  border-radius: 999px;
  background: var(--mint-dof);
  display: grid;
  place-items: center;
  font-weight: 700;
}

.schermtitel {
  margin: 0;
  font-size: 19px;
  font-weight: 700;
}

.teller {
  font-size: 17px;
  font-weight: 700;
  white-space: nowrap;
}

/* --- Knoppen (2.3 t/m 2.5) --- */

.knop-primair {
  border: 2px solid var(--inkt);
  background: var(--groen);
  color: var(--groen-tekst);
  font-family: var(--ui);
  font-size: 22px;
  font-weight: 800;
  padding: 22px 40px;
  min-height: 68px;
  border-radius: var(--radius);
  box-shadow: 6px 6px 0 var(--inkt);
  cursor: pointer;
  transition: none;
}

.knop-primair:hover {
  background: var(--groen-donker);
  color: var(--papier);
}

.knop-primair:active {
  box-shadow: 2px 2px 0 var(--inkt);
  transform: translate(4px, 4px);
}

.knop-primair--klein {
  font-size: 21px;
  padding: 20px 38px;
  min-height: 64px;
}

/* Geen opacity op een uitgeschakelde knop: dat maakt juist het label dat
   uitlegt wat er gebeurt de slechtst leesbare tekst op het scherm. */
.knop-primair[disabled] {
  background: var(--mint-dof);
  color: var(--tekst-sterk);
  box-shadow: 6px 6px 0 var(--streep-grijs);
  cursor: not-allowed;
}

.knop-primair[disabled]:hover {
  background: var(--mint-dof);
  color: var(--tekst-sterk);
}

.knop-secundair[disabled] {
  background: var(--canvas);
  color: var(--tekst-sterk);
  border-color: var(--tekst-zwak);
  cursor: not-allowed;
}

.knop-secundair[disabled]:hover {
  background: var(--canvas);
}

.knop-secundair {
  border: 2px solid var(--inkt);
  background: var(--papier);
  color: var(--inkt);
  font-family: var(--ui);
  font-size: 17px;
  font-weight: 700;
  padding: 12px 18px;
  min-height: 48px;
  border-radius: var(--radius);
  cursor: pointer;
}

.knop-secundair:hover {
  background: var(--paneel-hover);
}

.knop-secundair--groot {
  font-size: 21px;
  padding: 20px 32px;
  min-height: 64px;
}

.knop-tekst {
  border: none;
  background: none;
  padding: 10px 4px;
  font-family: var(--ui);
  font-size: 18px;
  font-weight: 600;
  color: var(--tekst-sterk);
  text-decoration: underline;
  text-underline-offset: 4px;
  min-height: 44px;
  cursor: pointer;
}

.knop-tekst:hover {
  color: var(--groen-donker);
}

/* --- Progressbar (2.6) --- */

.balk {
  height: 16px;
  border: 2px solid var(--inkt);
  background: var(--canvas);
}

.balk--breed {
  flex: 1;
}

.balk--kaart {
  width: 100%;
  height: 14px;
}

.balk--rij {
  height: 22px;
}

/* De vulling staat op --balkvulling en niet op --groen. Een balk is een
   grafisch element: hij moet 3:1 halen tegen zijn eigen track (--canvas), en
   het accent haalde dat nergens -- zon 1.59:1, zee 2.65:1, en de groene stijl
   van nu zelf 2.89:1. --balkvulling is per thema het donkere accent en haalt
   4.56:1 (nu), 4.61 (zon), 4.61 (zee) en 6.19 (snoep). */
.balk-vulling {
  height: 100%;
  background: var(--balkvulling);
}

/* De klok bij een som, rechts in de sessieheader naast de teller. Een korte
   balk die leegloopt en een stand in tabelcijfers, zodat de tekst niet
   verspringt als de 1 een 0 wordt. Bij "tonen" staat de balk verborgen en
   blijft alleen de stand over. */
.klok {
  display: flex;
  align-items: center;
  gap: 10px;
}

.klok[hidden] {
  display: none;
}

.balk--klok {
  width: 120px;
}

.klok-tekst {
  font-size: 17px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  min-width: 3.2em;
  text-align: right;
  white-space: nowrap;
}

/* Nog niet begonnen is geen nul procent goed: een gestreepte, neutrale balk
   zegt "hier moet je nog beginnen" in plaats van "zes keer fout". */
.balk--leeg {
  background: repeating-linear-gradient(
    135deg,
    var(--canvas),
    var(--canvas) 6px,
    var(--lijn-zacht) 6px,
    var(--lijn-zacht) 12px
  );
}

/* --- Kaart (2.7) --- */

.kaart {
  border: 2px solid var(--inkt);
  background: var(--papier);
  padding: 24px;
  border-radius: var(--radius);
}

.kaart--accent {
  background: var(--mint);
}

.kaart--passief {
  border: 2px dashed var(--streep-grijs);
}

.kaart--ruim {
  padding: 32px;
}

.raster-drie {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 20px;
}

/* Vier kaarten op één regel, en niet drie plus een tweede regel. Dat is een
   hoogtebesluit: op 1366x660 houdt .body-ruim 584px over en staat de
   dashboardinhoud op 548px; een tweede kaartregel kost een kaarthoogte plus
   20px gap (samen ongeveer 125px) en duwt de rij dan 89px onder de vouw. Vier
   kolommen kosten nul pixels hoogte -- de kaarten worden smaller, van 353px
   naar 260px bij een kader van 1100px. De rekensom staat in
   web/tests/rekenmuur.test.js; de klasse komt er in JS op zodra de vierde
   kaart (de rekenmuur) verschijnt. */
.raster-drie--vier {
  grid-template-columns: repeat(4, 1fr);
}

/* --- Micro-label (2.12) --- */

.micro {
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--tekst-zwak);
}

.micro--goed {
  color: var(--groen-label);
}

h1.micro,
h1.micro--fout {
  margin: 0;
}

.micro--groot {
  font-size: 17px;
  letter-spacing: 0.16em;
  color: var(--groen-label);
}

.micro--stil {
  color: var(--tekst-sterk);
}

.micro--fout {
  font-size: 17px;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--rood);
}

/* --- Chip (2.14), hier als tabknop op het docentscherm --- */

.chip {
  border: 2px solid var(--inkt);
  background: var(--papier);
  color: var(--inkt);
  padding: 10px 16px;
  font-family: var(--ui);
  font-size: 15px;
  font-weight: 700;
  min-height: 44px;
  cursor: pointer;
}

.chip[aria-selected="true"] {
  background: var(--inkt);
  color: var(--papier);
}

/* --- Schermen --- */

.scherm {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.scherm[hidden] {
  display: none;
}

.body-ruim {
  flex: 1;
  padding: 40px 48px;
  display: flex;
  flex-direction: column;
  gap: 32px;
  overflow: auto;
}

.body-midden {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: safe center;
  gap: 28px;
  padding: 48px 64px;
  overflow: auto;
}

/* --- Login --- */

.login-frame {
  width: 560px;
  height: auto;
}

.login-body {
  padding: 48px;
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.login-titel {
  font-family: var(--serif);
  font-size: 44px;
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin: 0;
}

/* De regel onder het formulier: wachtwoord vergeten, terug naar inloggen. */
.login-extra {
  margin: 0;
  font-size: 17px;
  color: var(--tekst-sterk);
}

.veld {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.veld label {
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--tekst-zwak);
}

.invoer {
  border: 2px solid var(--inkt);
  background: var(--papier);
  color: var(--inkt);
  font-family: var(--ui);
  font-size: 19px;
  padding: 14px 16px;
  min-height: var(--veldhoogte);
}

select.invoer {
  min-height: var(--veldhoogte);
  font-size: 17px;
}

.melding {
  border: 2px solid var(--inkt);
  border-radius: var(--radius);
  background: var(--zalm);
  color: var(--rood);
  padding: 14px 16px;
  font-size: 17px;
  font-weight: 700;
}

.melding[hidden] {
  display: none;
}

.melding--goed {
  background: var(--mint);
  color: var(--groen-label);
}

.melding--rustig {
  background: var(--paneel);
  color: var(--tekst-sterk);
  font-weight: 600;
}

/* --- Dashboard (3.1) --- */

/* De mascotte naast de begroeting. Twee dingen houden hem stil:
   - `min-height` op de rij is de hoogte van de mascotte zelf, dus een langere
     of kortere begroetingsregel verandert de rijhoogte niet en verschuift
     niets eronder;
   - hij hangt rechts (`margin-left: auto`) en onderaan uit, zodat zijn plek
     los staat van hoe breed of hoog de tekst links wordt.
   De hoogte groeit mee met het kader, maar in de hoogte en niet in de
   breedte: het kader wint tussen 1366x768 en 1440x900 vooral verticaal, en
   dat is precies de ruimte die hij mag opeten. De ondergrens houdt hem
   herkenbaar, de bovengrens houdt de drie kaarten op 1366x768 boven de vouw. */
/* De splash ligt over het scherm heen en kost geen bladspiegel. Dat is de hele
   reden dat hij een overlay is en geen figuur in de begroetingsrij: op een
   Chromebook houdt 1366x768 na browserchrome ongeveer 660px over, en daar duwde
   een mascotte in de kolom de kaartenrij onder de vouw.
   pointer-events uit: hij ligt anderhalve seconde over knoppen die al werken. */
.splash {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--papier);
  pointer-events: none;
  z-index: 20;
  animation: splash-weg 1400ms ease-in forwards;
}

.splash-mascotte {
  width: min(320px, 46vw);
  max-height: 60vh;
  animation: splash-op 500ms ease-out both;
}

@keyframes splash-weg {
  0%,
  62% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

@keyframes splash-op {
  from {
    transform: scale(0.86);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

/* Wie beweging liever niet ziet, krijgt hem stil: de splash staat er even en
   gaat dan weg, zonder schalen of vervagen. Het opruimen gebeurt in JS, dus
   zonder animatie verdwijnt hij nog steeds. */
@media (prefers-reduced-motion: reduce) {
  .splash,
  .splash-mascotte {
    animation: none;
  }
}

.begroeting {
  font-size: 40px;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 0;
}

.begroeting-sub {
  margin: 6px 0 0;
  font-size: 20px;
  color: var(--tekst-zwak);
}

/* De begroetingsrij: de tekst links, de kleurkiezer rechts ernaast.
   Náást en niet eronder, en dat is een hoogtebesluit: op een Chromebook van
   1366x768 houdt .body-ruim na browserchrome ongeveer 584px over, en de
   inhoud stond met de kiezer eronder op 608px -- bij een tweeregelige
   hero-titel zakte de kaartenrij 28px onder de vouw. De kiezer is 44px hoog
   plus 16px marge; de begroeting met haar subregel is hoger dan dat, dus
   naast de tekst kost hij nul pixels bladspiegel. Dezelfde reden als bij de
   splash-overlay: op dit scherm is hoogte de schaarse maat.
   flex-end en niet center: de bolletjes lijnen uit met de subregel, zodat de
   rij onderaan één lijn heeft. */
.begroetingskop {
  display: flex;
  align-items: flex-end;
  gap: 24px;
  flex-wrap: wrap;
}

/* Levels (#60): het level in een badge, een balk en de regel eronder, plus de
   schakelaar ernaast. In de begroetingsrij en niet eronder, om dezelfde reden
   als de kleurkiezer: de rij is met de begroeting (40px) en haar subregel
   hoger dan dit blok, dus het kost nul pixels bladspiegel. De rekensom staat
   in web/tests/schermhoogte.test.js.
   Het blok krijgt margin-left: auto zodat de begroeting links blijft staan;
   de kiezer erna doet hetzelfde en komt dus rechts van de levels. */
.levelblok {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-left: auto;
}

.levelblok[hidden] {
  display: none;
}

.levelrij {
  display: flex;
  align-items: center;
  gap: 12px;
}

.levelrij[hidden] {
  display: none;
}

/* De badge draagt het level als getal. Een cirkel in het accent, even groot
   als de avatar in de kop: het is hetzelfde soort ding -- een teken dat bij dit
   kind hoort -- en twee bijna-gelijke maten naast elkaar lezen als een fout. */
.levelbadge {
  width: 40px;
  height: 40px;
  flex: none;
  border: 2px solid var(--inkt);
  border-radius: 999px;
  background: var(--mint-dof);
  display: grid;
  place-items: center;
  font-size: 19px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.levelkolom {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.balk--level {
  width: 148px;
  height: 12px;
}

.levelregel {
  font-size: 15px;
  color: var(--tekst-zwak);
  white-space: nowrap;
}

/* De schakelaar is een tekstknop en geen tweede grote knop, net als "Er klopt
   iets niet": het is een keuze van het kind over zijn eigen scherm, niet de
   handeling van deze pagina. Hij blijft staan als de levelrij weg is, want
   anders is er geen weg terug zonder een nieuw scherm. */
.levelknop {
  flex: none;
}

/* De punten van één antwoord op het goed-scherm. Eén regel met dezelfde balk
   als op de startpagina, zodat het kind hetzelfde ding ziet groeien. */
.puntenwinst {
  display: flex;
  align-items: center;
  gap: 16px;
}

.puntenwinst[hidden] {
  display: none;
}

.puntenwinst-getal {
  font-size: 24px;
  font-weight: 800;
  color: var(--groen-label);
  font-variant-numeric: tabular-nums;
}

/* Vier bolletjes, elk in het accent van zijn thema. Echte knoppen in een
   radiogroep -- van vier kleuren staat er precies één aan, en dat is een
   radiogroep en geen rij schakelaars, net als .mk-opties. Een gekleurde
   cirkel zegt een schermlezer niets, dus elke bol draagt een aria-label.
   44px is de raakmaat, en de bolkleur staat hier vast en niet als token: de
   bol toont het thema dat je kríjgt, niet het thema dat je hebt. */
.themakiezer {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-left: auto;
}

.themabol {
  width: 44px;
  height: 44px;
  padding: 0;
  border: 2px solid var(--inkt);
  border-radius: 999px;
  background: var(--bol);
  cursor: pointer;
}

.themabol[data-thema="nu"] {
  --bol: #0E9F6E;
}

.themabol[data-thema="zon"] {
  --bol: #FFB400;
}

.themabol[data-thema="zee"] {
  --bol: #009CDE;
}

.themabol[data-thema="snoep"] {
  --bol: #D9266B;
}

/* De gekozen bol is groter en draagt een stip in zijn midden. Een ring eromheen
   kon niet: dat is precies de vorm van de focusring, en focus op de gekozen bol
   tekende dan twee ringen over elkaar heen -- je zag niet meer welke bol
   gekozen was, alleen waar de focus stond. Een binnenstip en een maatverschil
   staan naast een outline in plaats van eronder.
   De stip is inkt op een spleet in papier, zodat hij ook op het donkere accent
   van snoep leesbaar blijft. */
.themabol[aria-checked="true"] {
  transform: scale(1.14);
  box-shadow: inset 0 0 0 3px var(--papier), inset 0 0 0 9px var(--inkt);
}

/* En de focusring krijgt meer lucht dan de standaard 3px: op de gekozen bol
   staat hij anders tegen de rand van de vergrote cirkel aan. */
.themabol:focus-visible {
  outline-offset: 8px;
}

.hero {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
}

.hero-kolom {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.hero-titel {
  font-family: var(--serif);
  font-size: 44px;
  font-weight: 700;
  line-height: 1.05;
}

.hero-meta {
  font-size: 19px;
  color: var(--tekst-sterk);
}

.kaartknop {
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 132px;
  cursor: pointer;
  font-family: var(--ui);
  color: var(--inkt);
}

.kaartknop:hover {
  background: var(--paneel-hover);
}

.kaart-titel {
  font-size: 21px;
  font-weight: 700;
}

.kaart-sub {
  font-size: 17px;
  color: var(--tekst-zwak);
}

.kaart--passief .kaart-titel {
  color: var(--tekst-sterk);
}

/* --- Onderwerp kiezen (3.2) --- */

.intro {
  font-size: 19px;
  color: var(--tekst-zwak);
}

.doelkaart {
  padding: 26px;
  min-height: 176px;
  gap: 14px;
}

.doelkaart:hover {
  background: var(--mint);
}

.doelkaart-naam {
  font-family: var(--serif);
  font-size: 27px;
  font-weight: 700;
  line-height: 1.15;
}

.doelkaart-meta {
  font-size: 17px;
  color: var(--tekst-zwak);
}

.doelkaart .balk {
  margin-top: auto;
}

.doelkaart-pct {
  font-size: 15px;
  font-weight: 700;
  color: var(--groen-label);
}

.doelkaart-pct--stil {
  color: var(--tekst-zwak);
}

/* --- Zelf een trede kiezen (#57) --- */

/* Het vak om een kaart met tredeknoppen: de kaart vult de hoogte, de knoppen
   staan eronder. Zonder dit zou een kaart met knoppen korter zijn dan de
   kaarten ernaast, want het rastervak is dan over twee dingen verdeeld. */
.doelvak {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.doelvak .doelkaart {
  flex: 1;
}

.tredenrij {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

/* Kleiner en rustiger dan de kaart zelf: dit is de uitweg en niet het
   hoofdpad. Wel de volle tikhoogte van 48px, want het is een knop voor een
   kind van negen. */
.knop-trede {
  flex: 1 1 0;
  min-width: 140px;
  min-height: 48px;
  border: 2px solid var(--lijn-zacht);
  background: var(--papier);
  color: var(--tekst-sterk);
  font-family: var(--ui);
  font-size: 15px;
  font-weight: 700;
  padding: 10px 12px;
  border-radius: var(--radius);
  cursor: pointer;
}

.knop-trede:hover {
  background: var(--mint);
  border-color: var(--groen-label);
  color: var(--inkt);
}

.knop-trede:disabled {
  cursor: default;
  opacity: 0.6;
}

/* --- Opgave (3.3 t/m 3.7) --- */

.opgave-body {
  flex: 1;
  display: grid;
  grid-template-columns: 1fr 440px;
  min-height: 0;
}

/* `safe center` en niet `center`: bij een lange vraag met een tekening eronder
   is de kolom hoger dan het scherm, en dan duwt gewoon centreren de bovenkant
   buiten beeld. Een scrollcontainer kan niet naar negatief scrollen, dus die
   overloop is onbereikbaar -- ook met scrollen. `safe` valt bij overloop terug
   op flex-start en houdt de bovenkant binnen bereik. */
.opgave-kolom {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: safe center;
  gap: 40px;
  padding: 48px;
  overflow: auto;
}

.som-vraag {
  font-family: var(--serif);
  font-size: 112px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
  text-align: center;
}

.som-vraag--lang {
  font-size: 52px;
  line-height: 1.15;
  letter-spacing: 0;
  max-width: 720px;
}

.tekening {
  display: flex;
  align-items: center;
  justify-content: center;
  max-width: 100%;
}

.tekening svg {
  max-width: 100%;
  height: auto;
}

/* Een invulbare tekening krimpt niet onder haar ware grootte; past ze niet in
   de kolom, dan scrolt haar houder.

   Lestaal rekent de maat van zijn klikvakken uit de breedte waarop het component
   ontworpen is (voor de tijdbalk 720px) en houdt ze daarbinnen op minstens 24px,
   zoals WCAG 2.5.8 vraagt. `max-width: 100%` haalde die vloer onderuit zodra de
   kolom smaller werd: bij een viewport van 1093 CSS-px -- een Chromebook van
   1366 op 125% zoom -- schaalde de tijdbalk naar 0,81 en werden de vakken
   22,6x27,6 met jaartallen op 8,1px. Gemeten in de browser, net als de rest.
   Vanaf ongeveer 1129 CSS-px speelt dit niet: op 1366 en op 1280 staat de balk
   op ware grootte en scrolt er niets.

   Op `:has` en niet op `.tekening` zelf, want alleen deze houder kan overlopen:
   elke andere tekening houdt `max-width: 100%` en past per definitie. Zo staat
   het besluit op één plek en blijven het foutscherm, het meerkeuzescherm en de
   docentkaarten gewone, centrerende houders. De sleutelplaat is daar het bewijs
   van: die houder is 480px breed terwijl een bouwplaat 176px meet, dus
   `flex-start` zou haar naar links schuiven (gemeten: marge 0 links, 333
   rechts, tegen 152 om 152 nu).

   Dat elke `.tekening` al een scrollcontainer wás, komt van lestaal zelf:
   `oefen.css` zet er `overflow-x: auto` op. Die regel zit in de cascadelaag en
   verliest van deze, maar hij verklaart waarom een houder zonder eigen regel
   toch `overflow: auto` rapporteert.

   Twee dingen die nodig zijn en waarom:

   `overflow: auto hidden` en niet alleen de x-as: één as op auto zetten maakt de
   andere volgens de CSS-regels ook auto, en dan reserveert de browser een
   verticale scrollbalk van 15px die de tekening scheef in de kolom zet (gemeten:
   houder 297 om een plaat van 282). De hoogte volgt de inhoud, dus er valt
   verticaal niets te verbergen.

   `flex-start` plus `margin-inline: auto` en niet `justify-content: center`: een
   gecentreerde flexregel die overloopt begint links van haar scrollbare gebied,
   en dan is de eerste eeuw met geen enkele scrollbeweging te bereiken (gemeten:
   de balk opende op `scrollLeft` 204 met "500 v.Chr." buiten beeld). Automarges
   centreren zolang er ruimte is en vallen bij overloop terug op nul.

   Niet krimpen is een aparte regel en staat hieronder: dat geldt voor élke
   tekening in de opgavekolom en niet alleen voor deze. */
.tekening:has(svg[data-antwoord]) {
  justify-content: flex-start;
  overflow: auto hidden;
}

/* Geen enkele tekening in de opgavekolom krimpt mee met die kolom.

   De opgavekolom is een flexkolom met een vaste hoogte, en `overflow` op iets
   anders dan `visible` zet de automatische minimumhoogte van een flexitem uit.
   Elke `.tekening` heeft zo'n overflow: de regel hierboven zet hem op de
   invulbare SVG's, en lestaal zet `overflow-x: auto` op alle andere
   (`oefen.css`, in de cascadelaag, en deze stylesheet verklaart geen overflow op
   `.tekening` zelf, dus die gelaagde regel wint per property). De kolom kan de
   houder daardoor tot 0 persen zodra de vraag lang is.

   Gemeten in de browser op de grafiek-opgave van G7.VB.TGR.11, waar de vraag
   zeven regels beslaat: houder 0 hoog, plaat 148px boven haar eigen houder
   getekend terwijl haar SVG gewoon 296px meet. Het raakt de HTML-werkvlakken
   net zo goed als de SVG's -- zeven van de twaalf zijn een `<div>` of een
   `<table>` -- dus de regel hangt aan de kolom en niet aan de vorm van de
   tekening. De kolom scrolt al verticaal, dus niet krimpen is het goede
   antwoord.

   Alleen in de opgavekolom: het foutscherm en de docentkaarten hebben geen
   kolom die knijpt, en daar hoort de sleutelplaat juist te mogen meeschalen. */
.opgave-kolom > .tekening {
  flex: none;
}

.tekening svg[data-antwoord] {
  max-width: none;
  flex: none;
  margin-inline: auto;
}

/* --- Breukvakjes (#51, designspec 3.6) ---

   Een breuk typt een kind boven elkaar: teller boven de streep, noemer
   eronder. Bij twee breuken twee paren met "en" ertussen, zoals de vraag het
   zegt. Het antwoordveld staat dan op hidden en draagt alleen nog de waarde.

   Smaller dan de 168px uit de designspec: die maat gaat over één breuk, en
   twee paren met "en" ertussen zijn dan breder dan de opgavekolom op een
   Chromebook. 120px houdt twee paren binnen 480px. */
.breukvakjes {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 24px;
  flex-wrap: wrap;
}

.breukpaar {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.breukstreep {
  width: 120px;
  height: 5px;
  background: var(--inkt);
}

.breukvak {
  width: 120px;
  height: 104px;
  border: 2px solid var(--inkt);
  border-radius: var(--radius);
  background: var(--papier);
  box-shadow: 6px 6px 0 var(--inkt);
  padding: 0 8px;
  font-family: var(--serif);
  font-size: 64px;
  font-weight: 700;
  color: var(--inkt);
  text-align: center;
}

/* Het actieve vakje krijgt de accentschaduw: waar je typt hoort te zien zijn,
   en de focusring alleen is op een vak van 120px makkelijk te missen. */
.breukvak:focus {
  box-shadow: 6px 6px 0 var(--groen);
}

.breukvakjes-en {
  font-family: var(--serif);
  font-size: 40px;
  font-weight: 700;
  color: var(--inkt);
}

/* Een gestapelde breuk in de vraagtekst zelf. Hij staat midden in een regel
   tekst, dus inline-flex en niet flex, en de regelhoogte van de vraag blijft
   die van de vraag: een breuk van twee regels hoog in een vraag van 112px zou
   de vraag anderhalf keer zo hoog maken. De streep is een rand en geen eigen
   element -- de breuk komt uit tekst en niet uit een invoervak. */
.breuk {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  vertical-align: middle;
  line-height: 1;
  font-size: 0.62em;
}

.breuk-teller {
  padding: 0 0.15em;
  border-bottom: 0.09em solid currentColor;
}

.breuk-noemer {
  padding: 0 0.15em;
}

.antwoordveld {
  width: 360px;
  max-width: 100%;
  min-width: 0;
  height: 116px;
  border: 2px solid var(--inkt);
  border-radius: var(--radius);
  background: var(--papier);
  box-shadow: 6px 6px 0 var(--inkt);
  padding: 0 32px;
  font-family: var(--serif);
  font-size: 72px;
  font-weight: 700;
  color: var(--inkt);
  text-align: center;
}

.zijpaneel {
  border-left: 2px solid var(--inkt);
  background: var(--paneel);
  padding: 32px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  overflow: auto;
}

/* Vijf rijen in plaats van vier (spatie en komma erbij), dus 76px per toets en
   een iets kleinere gap: met de 84px uit de designspec kreeg het zijpaneel een
   scrollbar en verdween "Nakijken" onder de vouw. */
.keypad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}

.toets {
  border: 2px solid var(--inkt);
  background: var(--papier);
  color: var(--inkt);
  font-family: var(--serif);
  font-size: 34px;
  font-weight: 700;
  height: 76px;
  border-radius: var(--radius);
  box-shadow: 4px 4px 0 var(--inkt);
  cursor: pointer;
}

.toets--breed {
  grid-column: span 2;
}

/* De spatietoets draagt een woord, geen cijfer: de serif op 34px past niet. */
.toets--woord {
  font-family: var(--ui);
  font-size: 20px;
  font-weight: 700;
}

.toets:hover:not(:disabled) {
  background: var(--mint);
}

.toets:active:not(:disabled) {
  box-shadow: 0 0 0 var(--inkt);
  transform: translate(4px, 4px);
}

/* Een toets die niets doet, ziet er ook zo uit: de komma staat uit zolang er
   breukvakjes staan, want in een breuk hoort geen komma (#51). Uitzetten en
   niet weghalen -- een gat in het raster zou alle andere toetsen verschuiven,
   en een kind dat de komma zoekt vindt hem dan niet meer terug. De
   hover- en actief-stijl gaan hierboven mee uit: een toets die oplicht en
   indrukt maar niets doet, is erger dan een doffe toets. */
.toets:disabled {
  box-shadow: none;
  background: var(--paneel-hover);
  color: var(--tekst-zwak);
  cursor: default;
}

.paneel-onder {
  margin-top: auto;
  height: 84px;
  padding: 0;
}

.hulpregel {
  font-size: 15px;
  color: var(--tekst-zwak);
}

/* De tweede kans (#52): de regel onder de opgave na de eerste fout, met de tip
   van de docent eronder. Geen groot foutblok: de opgave blijft de hoofdzaak en
   dit is een aanwijzing ernaast. Daarom de zalmkleur van .melding, maar kleiner
   en met de tip in de rustige tekstkleur.

   `[hidden]` apart, want een eigen display-regel verslaat de hidden-stijl van
   de browser -- dezelfde reden als bij .melding. */
.tweedekans {
  display: flex;
  flex-direction: column;
  gap: 6px;
  border: 2px solid var(--inkt);
  border-radius: var(--radius);
  background: var(--zalm);
  padding: 12px 16px;
}

.tweedekans[hidden] {
  display: none;
}

.tweedekans-regel {
  font-size: 17px;
  font-weight: 700;
  color: var(--rood);
}

.tweedekans-tip {
  font-size: 16px;
  color: var(--tekst-sterk);
}

/* De bevestiging na het melden. Rustig van toon: een kind dat een fout
   aanwijst hoort geen alarm te krijgen, alleen een bedankje. */
.meldregel {
  font-size: 16px;
  color: var(--tekst-sterk);
  background: var(--mint);
  border-radius: var(--radius);
  padding: 10px 12px;
}

/* Meerkeuze (3.4) */

.meerkeuze-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: safe center;
  gap: 44px;
  padding: 48px 64px;
  overflow: auto;
}

.mk-vraag {
  font-family: var(--serif);
  font-size: 64px;
  font-weight: 700;
  line-height: 1.1;
  text-align: center;
  max-width: 940px;
}

.mk-vraag--lang {
  font-size: 44px;
}

/* Flex en geen grid met vier vaste kolommen: bij drie opties hield de vierde
   track zijn plek en stonden de knoppen uit het midden. */
.mk-opties {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 20px;
  max-width: 100%;
}

.mk-opties .mk-optie {
  flex: 0 1 260px;
  min-width: 200px;
}

.mk-opties--twee .mk-optie {
  flex: 0 1 320px;
  min-width: 260px;
}

/* Een tekstuele optie ("35 groepjes van 12, 5 over") heeft meer ruimte nodig
   dan een kaal getal. Twee kolommen en een kleinere letter, want de designspec
   tekende deze knoppen met een enkel getal erin. */
.mk-opties--tekst .mk-optie {
  flex: 0 1 380px;
  min-width: 280px;
}

.mk-optie {
  border: 2px solid var(--inkt);
  background: var(--papier);
  color: var(--inkt);
  font-family: var(--serif);
  font-size: 46px;
  font-weight: 700;
  /* min-height en geen height: een optie die niet in 132px past, hoort door te
     lopen en niet afgeknipt te worden. Afgeknipte tekst maakt een opgave
     onbeantwoordbaar, en dat is precies het soort fout dat een leerling niet
     kan melden omdat hij niet weet dat er iets mist. */
  min-height: 132px;
  padding: 16px 20px;
  line-height: 1.15;
  border-radius: var(--radius);
  box-shadow: 6px 6px 0 var(--inkt);
  cursor: pointer;
}

.mk-opties--tekst .mk-optie {
  font-size: 26px;
}

.mk-optie[aria-checked="true"] {
  background: var(--groen);
  color: var(--groen-tekst);
}

/* De optie die al fout geprobeerd is (#52): blijft staan, maar dooft en ligt
   plat op het papier -- geen slagschaduw, dus hij leest niet meer als een knop
   die nog ingedrukt kan worden. */
.mk-optie--weg {
  opacity: 0.4;
  box-shadow: none;
  cursor: default;
}

.mk-onder {
  display: flex;
  align-items: center;
  gap: 24px;
}

.mk-hint {
  font-size: 17px;
  color: var(--tekst-zwak);
}

/* --- Feedback (3.8, 3.9) --- */

.feedback-goed {
  background: var(--mint);
}

.feedback-fout {
  background: var(--zalm);
  gap: 26px;
}

/* De uitslag staat in een eigen blok met role="status": dat blok wordt
   voorgelezen, de knop eronder hoort er niet bij. */
.fb-inhoud {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  max-width: 100%;
}

.fb-uitspraak {
  font-family: var(--serif);
  font-size: 104px;
  font-weight: 700;
  line-height: 1;
  text-align: center;
  max-width: 100%;
  overflow-wrap: anywhere;
}

.fb-uitspraak--lang {
  font-size: 56px;
}

.fb-toelichting {
  font-size: 21px;
  line-height: 1.5;
  color: var(--tekst-sterk);
  text-align: center;
  max-width: 680px;
}

/* De tip van de docent op het foutscherm (#56). Een kolom en geen rij: de
   uitleg klapt onder de knop open, zodat de knop op zijn plek blijft staan en
   het kind niet hoeft te zoeken waar de tekst gebleven is. */
.uitlegblok {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  max-width: 680px;
}

.uitlegtekst {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  border: 2px solid var(--inkt);
  background: var(--papier);
  padding: 16px 20px;
}

/* --- Sessie afgerond (3.12) --- */

.afrond-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: safe center;
  gap: 32px;
  padding: 64px;
  overflow: auto;
}

.afrond-score {
  font-family: var(--serif);
  font-size: 76px;
  font-weight: 700;
  line-height: 1.05;
  text-align: center;
  max-width: 900px;
}

.samenvatting {
  width: 100%;
  max-width: 720px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 32px;
}

.samenvatting-regel {
  display: flex;
  justify-content: space-between;
  /* Een gap en geen kale space-between: een lange doeltekst duwt de waarde
     anders tegen het label aan, en dan staat er "OnderwerpIk kan uitleggen". */
  gap: 24px;
  font-size: 20px;
}

.samenvatting-regel span:first-child {
  color: var(--tekst-sterk);
  flex: none;
}

.samenvatting-regel span:last-child {
  font-weight: 700;
  text-align: right;
}

.knoppenrij {
  display: flex;
  gap: 16px;
  align-items: center;
}

/* --- Hoe ging het? (#64) --- */

.gevoelvraag {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}

/* De kop wisselt van tekst (vraag, bevestiging, foutzin) en niet van hoogte:
   een vaste min-height houdt de knoppenrij eronder op zijn plek. */
.gevoelvraag-kop {
  margin: 0;
  min-height: 32px;
  font-size: 21px;
  line-height: 32px;
  font-weight: 700;
  text-align: center;
}

.gezichtenrij {
  display: flex;
  gap: 20px;
}

/* Rond en niet vierkant zoals de andere knoppen: dit zijn geen knoppen die
   iets doen maar gezichtjes die je aanwijst. Groot genoeg voor een vinger op
   een tablet en voor een kind dat niet precies mikt. */
.gezichtknop {
  width: 88px;
  height: 88px;
  padding: 10px;
  border: 2px solid var(--inkt);
  border-radius: 50%;
  background: var(--papier);
  cursor: pointer;
  transition: transform 120ms ease, opacity 120ms ease;
}

.gezichtknop svg {
  display: block;
  width: 100%;
  height: 100%;
}

.gezichtknop:hover:not(:disabled) {
  transform: translateY(-2px);
  background: var(--paneel-hover);
}

.gezichtknop[aria-pressed="true"] {
  background: var(--mint);
  box-shadow: 4px 4px 0 var(--inkt);
}

/* Na de keuze blijven de andere twee klikbaar (de laatste keuze wint) maar
   gedimd, zodat het kind ziet wat het koos. Tijdens het opsturen zijn ze even
   uitgeschakeld tegen dubbelklikken; dat ziet er hetzelfde uit. */
.gezichtenrij:has([aria-pressed="true"]) .gezichtknop:not([aria-pressed="true"]),
.gezichtknop:disabled {
  opacity: 0.35;
}

.gezichtknop:disabled {
  cursor: default;
}

/* De kleur zit op de mond en de ogen (currentColor), dus één regel per gevoel
   bedient het afrondscherm en het docentscherm allebei. */
.gezicht--goed {
  color: var(--groen-donker);
}

.gezicht--gewoon {
  color: var(--tekst-sterk);
}

.gezicht--moeilijk {
  color: var(--rood);
}

/* Het kleine gezichtje bij het percentage in het leerlingdetail van de docent. */
.gezicht {
  display: inline-block;
  width: 28px;
  height: 28px;
  vertical-align: middle;
}

.gezicht svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* Negatieve verticale marges: het gezichtje is hoger dan de regel, en zonder
   die marges tilt zijn margebox de regel op, zodat een rij mét gezichtje 5px
   hoger werd dan een rij zonder. Zo blijft elke rij even hoog. */
.gezicht--cel {
  width: 28px;
  height: 28px;
  margin: -8px 0 -8px 10px;
}

/* --- Voortgang (3.11) --- */

.statkaart {
  padding: 26px;
}

.statgetal {
  font-family: var(--serif);
  font-size: 56px;
  font-weight: 700;
  line-height: 1;
}

.statbij {
  font-size: 18px;
  color: var(--tekst-sterk);
  margin-top: 8px;
}

.voortgangslijst {
  display: flex;
  flex-direction: column;
  gap: 18px;
  margin-top: 18px;
}

.voortgangsrij {
  display: grid;
  grid-template-columns: 260px 1fr 150px;
  gap: 20px;
  align-items: center;
}

.voortgangsrij-naam {
  font-size: 20px;
  font-weight: 600;
}

.voortgangsrij-pct {
  font-size: 18px;
  font-weight: 700;
  text-align: right;
}

/* --- Rekenmuur (#59) ---

   Eén bord per groep: de klasmuur bovenaan, daaronder een balk per leerling.
   Hetzelfde bord op het leerling- en het docentscherm (App.muurbord), zodat
   een kind en zijn juf naar hetzelfde plaatje kijken. */
.muurbord {
  border: 2px solid var(--inkt);
  background: var(--papier);
  border-radius: var(--radius);
  padding: 24px;
  margin-bottom: 24px;
}

.muurkop {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}

.muurkop-naam {
  font-size: 22px;
  font-weight: 800;
}

.muurkop-tekst {
  font-family: var(--serif);
  font-weight: 700;
  font-size: 20px;
  color: var(--tekst-sterk);
}

/* De muur zelf: één blokje per opgave van vandaag, gevuld als hij goed was.
   Een wikkelende rij en geen vast raster: het aantal hangt van de dag af, en
   een raster met een vaste kolombreedte laat bij twaalf opgaven een lege muur
   zien die er niet is. 18px is klein genoeg voor honderdtwintig blokjes op een
   Chromebook (120 x 22px inclusief gap is 2640px, dus ruim zes regels van 20
   blokjes) en groot genoeg om los te zien. */
.muur {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.muursteen {
  width: 18px;
  height: 18px;
  border: 2px solid var(--inkt);
  background: var(--canvas);
}

.muursteen--goed {
  background: var(--balkvulling);
}

.muur-schaal {
  margin: 10px 0 0;
  font-size: 15px;
  color: var(--tekst-zwak);
}

.muurbalken {
  margin-top: 20px;
  display: grid;
  gap: 10px;
}

/* Naam, balk, getal. Zonder namen valt de eerste kolom weg -- de balken staan
   dan zonder kolom voor een naam die er niet is, in plaats van met een lege
   kolom die de vraag oproept wie daar hoorde te staan. */
.muurbalk {
  display: grid;
  grid-template-columns: 160px 1fr 70px;
  gap: 16px;
  align-items: center;
}

.muurbalken--anoniem .muurbalk {
  grid-template-columns: 1fr 70px;
}

.muurbalk-naam {
  font-size: 19px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.muurbalk-getal {
  font-family: var(--serif);
  font-weight: 700;
  font-size: 18px;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.muurbalk-getal--stil {
  color: var(--tekst-zwak);
}

/* --- Leraar-overzicht (3.13) --- */

.leraar-body {
  flex: 1;
  padding: 36px 44px;
  display: flex;
  flex-direction: column;
  gap: 24px;
  overflow: auto;
}

.titelrij {
  display: flex;
  align-items: baseline;
  gap: 20px;
}

.titelrij h2 {
  font-size: 30px;
  font-weight: 800;
  margin: 0;
}

.titelrij-meta {
  font-size: 19px;
  color: var(--tekst-zwak);
}

.tabel {
  border: 2px solid var(--inkt);
  /* Wordt het te smal voor de kolommen, dan schuift de tabel in zichzelf en
     niet de hele pagina. De ondergrens per kolom zorgt dat de omschrijving
     nooit tot nul knijpt -- dat is de tekst waarop de docent kiest. */
  overflow-x: auto;
}

.tabel-kop,
.tabel-rij {
  min-width: 700px;
}

.tabel-kop,
.tabel-rij {
  display: grid;
  gap: 16px;
  align-items: center;
}

.tabel-kop {
  padding: 16px 24px;
  background: var(--paneel-hover);
  border-bottom: 2px solid var(--inkt);
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--tekst-sterk);
}

.tabel-rij {
  padding: 18px 24px;
  border-bottom: 1px solid var(--lijn-zacht);
  font-size: 19px;
  width: 100%;
  text-align: left;
  background: var(--papier);
  color: var(--inkt);
  font-family: var(--ui);
  border-left: 0;
  border-right: 0;
  border-top: 0;
}

button.tabel-rij {
  cursor: pointer;
}

button.tabel-rij:hover {
  background: var(--paneel-hover);
}

.tabel-rij--leeg {
  display: block;
}

/* Vaste maten voor wat een vaste maat heeft, de rest naar de tekst die je
   werkelijk leest. Met alles in fr kreeg een doelcode van twaalf tekens 352px
   en een getal van drie cijfers 205px, terwijl de omschrijving op twee regels
   brak. minmax(0, 1fr) en niet 1fr: anders weigert de kolom te krimpen onder
   de breedste ononderbroken tekst en loopt de rij op een smal scherm buiten
   het kader. */
.kolommen-doelen {
  /* De actiekolom draagt sinds de jaarplanning ook een datumveld; zonder die
     extra ruimte breekt de knop eronder af op een laptopscherm. */
  grid-template-columns: 160px minmax(200px, 1fr) 90px minmax(320px, 520px);
}

.kolommen-voortgang {
  grid-template-columns: 160px minmax(200px, 1fr) 120px 120px;
}

/* Een naam en een gebruikersnaam worden niet leesbaarder van 700px. Die twee
   krijgen een bovengrens; de ruimte die overblijft gaat naar de laatste kolom,
   zodat de actie rechts uitlijnt in plaats van dat de tabel uitgerekt oogt. */
.kolommen-leerlingen {
  grid-template-columns: minmax(160px, 420px) minmax(140px, 300px) 200px minmax(120px, 1fr);
}

/* De groepentabel: naam, aantal, de klok en de rekenmuur als keuzelijst, het
   vinkje "zelf kiezen", en rechts de knop naar de leerlingen. Beide
   keuzekolommen zijn vast: de langste keuzes zijn "alleen tijd tonen" en
   "balken met namen" en die passen hier op één regel. De vinkkolom is smal,
   want er staat een vierkantje van 24px in.
   Drie instellingen naast elkaar en niet onder elkaar in één cel: de som van
   de minimumbreedtes is 160 + 100 + 220 + 220 + 110 + 160 = 970px plus vijf
   gaps van 16px, samen 1050px. Het docentpaneel is op een 1366-scherm ruim
   1250px breed, dus het past zonder dat de tabel in zichzelf hoeft te
   schuiven -- en instellingen onder elkaar in één cel maakt elke rij 30px
   hoger, wat bij twintig groepen een halve schermhoogte kost. */
.kolommen-groepen {
  grid-template-columns: minmax(160px, 420px) minmax(100px, 200px) 220px 220px 110px minmax(160px, 1fr);
  /* Boven de 700px van .tabel-rij: met zes kolommen is dit de echte
     ondergrens, en daaronder schuift de tabel (overflow-x op .tabel). */
  min-width: 1050px;
}

/* Het vinkje van een groepsinstelling die een ja of een nee is (#57): een echt
   vinkje, maar groot genoeg om met een vinger te raken. */
.vinkje-groep {
  width: 24px;
  height: 24px;
  accent-color: var(--groen-donker);
  cursor: pointer;
}

.cel-actie--rechts {
  justify-content: flex-end;
}

/* De keuzelijst in een tabelrij: lager en kleiner dan een formulierveld,
   zoals het datumveld in de doelentabel. */
.invoer-klok {
  width: 100%;
  min-height: 0;
  padding: 6px 8px;
  font-size: 15px;
}

/* De leerlingenlijst draagt er een klaskolom bij. Die is smal en vast: er
   staat "7B" in en nooit iets langers. */
.kolommen-leerlingen-klas {
  grid-template-columns: minmax(160px, 360px) 80px minmax(140px, 260px) 200px minmax(120px, 1fr);
}

.cel-sterk {
  font-weight: 600;
}

.cel-zwak {
  color: var(--tekst-zwak);
}

.cel-serif {
  font-family: var(--serif);
  font-weight: 700;
}

.cel-reden {
  color: var(--tekst-sterk);
}

/* Geen opacity: dat maakte juist de reden waarom een doel niet klaarstaat de
   slechtst leesbare tekst van de tabel (2.85:1). Een eigen achtergrond met
   volle tekstkleur zegt hetzelfde en is leesbaar. */
.rij-uit {
  background: var(--canvas);
}

.rij-uit .cel-sterk,
.rij-uit .cel-serif {
  color: var(--tekst-sterk);
  font-weight: 600;
}

.rij-uit .cel-reden {
  color: var(--tekst-sterk);
}

/* Een klaargezet doel is aan de rij te zien, niet alleen aan het knoplabel. */
.rij-klaar {
  background: var(--mint);
  box-shadow: inset 6px 0 0 var(--groen);
}

.cel-actie {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* Het datumveld staat in een tabelrij en niet in een formulier: smal genoeg om
   naast de knoppen te passen, en met de tekstgrootte van de rij eromheen. */
.invoer-datum {
  width: 9.5rem;
  padding: 4px 8px;
  font-size: 0.85rem;
}

/* De tip en de link naar een filmpje staan op een eigen regel onder de
   knoppen: 280 tekens naast een datumveld en twee knoppen past op geen
   laptopscherm. De cel is al flex-wrap, dus een volle breedte legt hem
   onderaan. */
.tipregel {
  flex-basis: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.invoer-tip {
  flex: 1 1 16rem;
  min-width: 0;
  padding: 6px 8px;
  font-size: 0.85rem;
  resize: vertical;
}

.invoer-tiplink {
  flex: 1 1 12rem;
  min-width: 0;
  padding: 4px 8px;
  font-size: 0.85rem;
}

/* De tekenteller is context en geen boodschap: klein, dof, en hij trekt geen
   aandacht weg van het veld waar hij bij hoort. */
.tipteller {
  font-size: 0.75rem;
  color: var(--tekst-zwak);
  white-space: nowrap;
}

.doelmerk {
  border: 2px solid var(--groen-donker);
  background: var(--papier);
  color: var(--groen-label);
  padding: 4px 10px;
  font-size: 14px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
}

.voetregel {
  font-size: 18px;
  color: var(--tekst-zwak);
}

.filterrij {
  display: flex;
  gap: 16px;
  align-items: flex-end;
  flex-wrap: wrap;
}

.filterrij .veld {
  gap: 6px;
}

/* Een knop die naast invoervelden staat, deelt hun hoogte: zo lopen de
   bovenkanten én de onderkanten van de hele rij gelijk. */
.filterrij > .knop-secundair,
.formulier-rij > .knop-secundair {
  min-height: var(--veldhoogte);
}

.tabbalk {
  display: flex;
  gap: 10px;
}

.formulier-rij {
  display: flex;
  gap: 16px;
  align-items: flex-end;
  flex-wrap: wrap;
}

.kolom-smal {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Eén gemelde som op de meldingentab. Een kaart en geen tabelrij: er staat een
   tekening in, en een tekening past niet in een cel. */
.meldkaart {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-start;
}

.meldkop {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* Per leerling zijn telling en een wegstreepknop, bóven de kaarten: wie 42
   meldingen van één kind ziet, hoort dat te zien voordat hij gaat scrollen. */
.melders {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.melderregel {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* Hoe vaak dezelfde som gemeld is: dat getal zegt hoe hard het signaal is. */
.meldtelling {
  border: 2px solid var(--inkt);
  padding: 4px 10px;
  font-size: 14px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
}

.meldvraag {
  font-family: var(--serif);
  font-size: 26px;
  font-weight: 700;
}

.meldsleutel {
  font-family: var(--serif);
  font-size: 20px;
  font-weight: 700;
  background: var(--mint);
  padding: 6px 10px;
}

/* "Zo mag het getypt worden": per gedaante van de sleutel de invoer die het
   nakijken goedkeurt, als code -- het gaat om de tekens zelf, dus een vaste
   breedte en geen serif. Het staat in een tabelrij (over de hele breedte,
   onder de vier cellen) én op een meldkaart, met dezelfde opmaak. */
.schrijfwijzen {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.schrijfwijzen-vak {
  grid-column: 1 / -1;
}

.schrijfwijzen-regel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.schrijfwijze {
  font-family: monospace;
  font-size: 16px;
  color: var(--tekst-sterk);
  background: var(--papier);
  border: 1px solid var(--inkt);
  padding: 2px 8px;
  white-space: pre;
}

.schrijfwijzen-of {
  font-size: 15px;
  color: var(--tekst-zwak);
}

/* Seed en contractversie: bedoeld om te kopiëren, dus selecteerbaar en in een
   vaste breedte, niet in de lopende tekst verstopt. */
.meldbron {
  font-family: monospace;
  font-size: 15px;
  color: var(--tekst-sterk);
  user-select: all;
  word-break: break-all;
}

/* De twee knoppen onder een melding. Naast elkaar zolang het past, want ze zijn
   even zwaar: de docent kiest tussen twee dingen en wordt niet naar één ervan
   geduwd. */
.meldknoppen {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

/* De uitzetknop wordt naar de overkant geduwd. Hij ziet er hetzelfde uit als
   zijn buur -- een eigen kleur zou een nieuwe knopvariant zijn en dat is een
   groter gebaar dan nodig -- maar hij hoort geen knoppenpaar te vormen met een
   handeling die maar één regel raakt. Wat hij doet staat op zijn label. */
.knop-ver {
  margin-left: auto;
}

.tekening--melding {
  justify-content: flex-start;
}

/* De tekening op het foutscherm: het antwoord op de plek waar het hoorde. Ze
   staat tussen de sleutel en de toelichting en mag het scherm niet vullen --
   het kind moet de hele boodschap in één blik zien, zonder te scrollen. */
.tekening--sleutel {
  width: 100%;
  max-width: 480px;
  margin: 6px auto 12px;
}

.wachtwoordkaart {
  background: var(--mint);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.wachtwoord {
  font-family: var(--serif);
  font-size: 44px;
  font-weight: 700;
  line-height: 1.05;
}

.waarschuwing {
  font-size: 17px;
  color: var(--rood);
  font-weight: 700;
}

.leeg {
  font-size: 19px;
  color: var(--tekst-zwak);
}

#peilingen {
  margin-top: 40px;
}

.peilingkop {
  margin: 0 0 6px;
  font-size: 24px;
}

/* De kaart van het herhalingsbakje (#54). Zelf geen knop -- hij draagt er
   drie -- dus geen cursor en geen hover op de kaart: alleen de knoppen
   reageren. Dezelfde maten als een doelkaart, zodat het raster niet hapert. */
.herhaalkaart {
  display: flex;
  flex-direction: column;
  gap: 14px;
  text-align: left;
}

.bakknoppen {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* Klein, want er staan er drie op één kaart, en met de rand en de harde
   schaduw van de andere knoppen: het is dezelfde taal. */
.bakknop {
  border: 2px solid var(--inkt);
  background: var(--papier);
  color: var(--inkt);
  font-family: var(--ui);
  font-size: 17px;
  font-weight: 700;
  padding: 10px 14px;
  min-height: 44px;
  border-radius: var(--radius);
  box-shadow: 3px 3px 0 var(--inkt);
  cursor: pointer;
}

.bakknop:hover {
  background: var(--mint);
}

.bakknop:active {
  box-shadow: 1px 1px 0 var(--inkt);
  transform: translate(2px, 2px);
}

/* De laatste keuze van het kind staat aan in de accentkleur. Niet alleen de
   kleur: een kind dat kleur niet ziet hoort ook uit aria-current te weten
   welke het is (zie herhaalkaart in leerling.js). */
.bakknop--aan {
  background: var(--groen);
  color: var(--groen-tekst);
}

.bakknop--aan:hover {
  background: var(--groen-donker);
  color: var(--papier);
}

.bakknop[disabled] {
  background: var(--mint-dof);
  color: var(--tekst-sterk);
  box-shadow: 3px 3px 0 var(--streep-grijs);
  cursor: not-allowed;
}

.doelkaart--peiling {
  background: var(--vlak-zacht, #f4f8fb);
}

.visueel-verborgen {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Korte schermen (Chromebook na browserchrome) --- */

@media (max-height: 780px) {
  .toets {
    height: 54px;
    font-size: 24px;
  }

  .hulpregel {
    margin: 4px 0 0;
    font-size: 14px;
  }

  .keypad {
    gap: 8px;
  }

  .paneel-onder {
    height: 68px;
  }

  .antwoordveld {
    height: 92px;
    font-size: 56px;
  }

  /* Dezelfde krimp als het antwoordveld: de vakjes staan op zijn plek. */
  .breukvak {
    height: 80px;
    font-size: 48px;
  }

  .breukvakjes {
    gap: 16px;
  }

  .som-vraag {
    font-size: 84px;
  }

  /* De --lang-varianten staan hier opnieuw, en dat is geen dubbeling maar de
     cascade. Ze hebben dezelfde specificiteit als .som-vraag en .fb-uitspraak,
     dus zonder deze regels wint de latere: een lánge vraag kreeg op een
     Chromebook juist 84px in plaats van 52px -- precies omgekeerd aan de
     bedoeling. Korter scherm betekent kleiner, ook hier. */
  .som-vraag--lang {
    font-size: 44px;
  }

  .opgave-kolom {
    gap: 28px;
    padding: 32px;
  }

  /* Het afrondscherm draagt sinds #64 de gezichtjes; met de volle 64px
     padding en 32px gap liep de body op 660px hoog 74px over en stond de
     knoppenrij buiten beeld. */
  .afrond-body {
    padding: 32px 64px;
    gap: 24px;
  }

  .gezichtknop {
    width: 72px;
    height: 72px;
  }

  .zijpaneel {
    padding: 24px;
  }

  .fb-uitspraak {
    font-size: 76px;
  }

  .fb-uitspraak--lang {
    font-size: 40px;
  }

  /* Minder bladspiegel eromheen, zodat het hele foutscherm -- kop, sleutel,
     tekening, knop -- op 660px in één blik past. Met 48px eromheen stak het
     erdoorheen en moest een kind naar de knop scrollen. */
  .body-midden {
    padding: 32px 48px;
    gap: 20px;
  }

  /* De puntenregel op het goed-scherm krimpt mee met de rest van dat scherm:
     de kop, de uitspraak en de knop staan er al krap op 660px. */
  .puntenwinst-getal {
    font-size: 20px;
  }

  /* En de sleutelplaat krijgt een dak. De bouwplaat is met 228px de hoogste van
     de drie en duwde als enige de knop eronder buiten beeld. */
  .tekening--sleutel svg {
    max-height: 190px;
    width: auto;
  }
}

/* --- Doelentabel: de balk boven de tabel en de knop eronder (issue #10) --- */

/* De weergavekiezer staat tussen de uitleg en de tabel in, niet in de
   filterrij: hij past zich meteen toe en de filters pas na een knop. Rechts
   uitgelijnd zodat hij ook visueel bij de tabel hoort en niet bij het
   formulier erboven. */
.tabelbalk {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
}

/* Een label naast zijn veld in plaats van erboven: in een balk van één regel
   leest "Toon: alleen wat klaarstaat" als een zin, en een kolom van twee
   regels zou de balk twee keer zo hoog maken als hij hoeft te zijn. */
.veld--liggend {
  flex-direction: row;
  align-items: center;
  gap: 10px;
}

/* De knop is een bediening onder de tabel, geen extra tabelrij: hij volgt de
   breedte van het kader en schuift dus niet mee als de tabel op een smal
   scherm in zichzelf scrollt. Dat is de bedoeling -- een knop die half buiten
   beeld begint is erger dan een knop die stil blijft staan. */
.tabelvoet-knop {
  width: 100%;
}

/* --- Berichtje van de juf of meester (issue #55) --- */

/* Het tekstvak bij het leerlingdetail. Een kolom en geen kaart: het hoort bij
   het detail dat eromheen staat, en een tweede kader zou er een los paneel van
   maken. */
.berichtvak {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Drie regels hoog en alleen verticaal te rekken: breder dan de kolom zou de
   tabel ernaast laten schuiven. */
.invoer--bericht {
  width: 100%;
  resize: vertical;
  line-height: 1.4;
}

/* De vier vaste zinnen. Ze wrappen, want op een smal scherm zijn vier knoppen
   naast elkaar vier onleesbare knoppen. */
.zinnenrij {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

/* De kaart op de startpagina van het kind zodra er een bericht staat. De
   afzenderregel is een micro-label en de tekst mag afbreken zoals de docent
   hem typte: witruimte blijft staan, lange woorden breken af in plaats van de
   kaart uit het raster te duwen. */
.berichttekst {
  font-size: 19px;
  white-space: pre-wrap;
  overflow-wrap: break-word;
}

/* --- Confetti bij een goed antwoord (#62) ---
   Unaniem gevraagd in de speelhoek van 14 september, dus geen instelling.

   Eén laag over het goed-scherm, zestig snippers, elk met zijn eigen
   startpositie, duur en vertraging uit leerling.js. De animatie is CSS en
   geen JavaScript-lus: een lus van zestig elementen op een Chromebook kost
   frames die het scherm nodig heeft voor de knop.

   pointer-events staat uit, want de knop Volgende ligt eronder en hoort
   direct klikbaar te blijven. De kleur is het accent van het thema
   (var(--groen), dat per data-thema verschilt) met twee tinten erbij, zodat
   de snippers niet als één vlak lezen. */
.confetti {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.confetti-snipper {
  position: absolute;
  top: -24px;
  width: 9px;
  height: 14px;
  background: var(--groen);
  opacity: 0;
  animation-name: confetti-val;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}

.confetti-snipper--twee {
  background: var(--groen-donker);
}

.confetti-snipper--drie {
  background: var(--inkt);
}

@keyframes confetti-val {
  0% {
    transform: translateY(0) rotate(0deg);
    opacity: 1;
  }
  100% {
    transform: translateY(104vh) rotate(540deg);
    opacity: 1;
  }
}

/* Wie beweging liever niet ziet, krijgt geen confetti. De laag blijft leeg:
   leerling.js kijkt dezelfde voorkeur na en zet er dan niets in, en deze
   regel is de tweede poort voor wie de voorkeur midden in een sessie omzet. */
@media (prefers-reduced-motion: reduce) {
  .confetti-snipper {
    animation: none;
    display: none;
  }
}
