/* jp-ar.css — shared components for the Japanese + Arabic course.
 *
 * Layered on top of style.css: script-specific font stacks, the interactive
 * hiragana chart, and the bilingual phrase cards. Light-only, like style.css.
 *
 * Load AFTER style.css so these rules win where they overlap.
 */

:root {
  /* Script-specific stacks. Body text stays on --serif; only Japanese and Arabic
     runs opt in, because a Latin serif has no glyphs for either script and the
     browser's silent fallback picks an inconsistent face otherwise. */
  --jp: "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic Medium", "Yu Gothic",
        "Noto Sans JP", "Noto Sans CJK JP", Meiryo, "MS Gothic", sans-serif;
  --ar: "SF Arabic", "Geeza Pro", "Noto Naskh Arabic", "Amiri", "Traditional Arabic",
        "Arabic Typesetting", "Segoe UI", Tahoma, serif;

  --jp-ink: #1d3557;
  --ar-ink: #1f6b4a;

  /* style.css has no red — nothing in a lesson was ever wrong before the drill.
     Matched to the amber/blue/green triples already in the palette. */
  --wrong-ink: #a4322b;
  --wrong-bg: #fcefed;
  --wrong-edge: #e6b3ac;
}

.jp { font-family: var(--jp); font-weight: 500; }
.ar { font-family: var(--ar); direction: rtl; unicode-bidi: isolate; line-height: 1.9; }

/* Arabic sitting INSIDE an English sentence. `unicode-bidi: isolate` is the
   load-bearing part: without it the bidi algorithm resolves neighbouring runs
   together, so "فَهِمْتُ versus فَهِمْتَ" can render with the two words swapped —
   silently teaching the opposite of what the sentence says. Isolation also keeps
   adjacent Latin punctuation on the side the English reader expects. */
.ar-i {
  font-family: var(--ar);
  font-size: 1.08em;
  direction: rtl;
  unicode-bidi: isolate;
}

/* The size bump is for Arabic set inside Latin prose, where the script looks
   small next to the surrounding text. Inside a block that already sizes Arabic,
   inherit instead — otherwise the two multiply. */
.chart-ar .ar-i,
.side-text .ar-i,
.ar .ar-i { font-size: inherit; }
.romaji { font-family: var(--mono); font-size: .82em; color: var(--muted); }

/* ---------- play buttons ---------- */

.kana-play,
.say {
  flex: 0 0 auto;
  min-width: 0;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--accent-ink);
  border-radius: 999px;
  cursor: pointer;
  font: 500 13px/1 var(--mono);
  padding: 7px 11px;
  transition: background .12s ease, border-color .12s ease, transform .12s ease;
}
.kana-play:hover,
.say:hover { border-color: var(--accent); background: var(--blue-bg); }
.kana-play:active,
.say:active { transform: scale(.94); }
.kana-play.speaking,
.say.speaking { background: var(--blue-bg); border-color: var(--accent); }
.kana-play.no-voice,
.say.no-voice { opacity: .4; }

.say-ar,
.kana-play-ar { color: var(--ar-ink); }
.say-ar:hover,
.kana-play-ar:hover { border-color: var(--ar-ink); background: var(--green-bg); }

.voice-warning {
  font-size: .85rem;
  color: #8a6414;
  background: var(--amber-bg);
  border: 1px solid var(--amber-edge);
  border-radius: 8px;
  padding: var(--s-2) var(--s-3);
  margin: 0 0 var(--s-4);
}

/* A control shown as a specimen inside prose — a how-to-use table naming the
   buttons and keys, rather than a control you can press. Lived in reading.css
   until 2026-08-13, when the flash-card deck became the second page type to
   need one; it was never a reading-chapter idea. */
.rd-key {
  display: inline-block;
  border: 1px solid var(--border);
  background: var(--card);
  border-radius: 999px;
  padding: .12rem .45rem;
  font: 600 10px/1.4 var(--mono);
  color: var(--accent-ink);
  white-space: nowrap;
}

/* ---------- hiragana chart ---------- */

/* Prefix match, so a lesson carrying more than one chart (day 9 has the gojūon
   and the marked rows as separate sections) styles both. */
[id^="kana-grid"] { margin: var(--s-4) 0 var(--s-5); }

.kana-row { margin-bottom: var(--s-3); }

.kana-row-label {
  font: 500 12px/1.5 var(--mono);
  color: var(--faint);
  margin: 0 0 var(--s-1);
}

.kana-line {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 7px;
}
.kana-line > * { min-width: 0; }

.kana-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-width: 0;
  padding: 10px 2px 7px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
  color: var(--ink);
  cursor: pointer;
  transition: border-color .12s ease, background .12s ease, transform .12s ease;
}
.kana-cell:hover { border-color: var(--accent); background: var(--blue-bg); }
.kana-cell:active { transform: scale(.96); }
.kana-cell.on {
  border-color: var(--accent);
  background: var(--blue-bg);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.kana-cell-char {
  font-family: var(--jp);
  font-size: clamp(1.5rem, 6.4vw, 2rem);
  line-height: 1.1;
  color: var(--jp-ink);
}
.kana-cell-romaji {
  font: 500 11px/1.2 var(--mono);
  color: var(--muted);
}

/* A marked kana's box holds both characters: the base above, quiet, and the
   marked form beneath at reading size — the eye should land on the new one and
   find the old one as provenance rather than as competition. The romaji then
   carries the sound change, which is the only thing that actually changed. */
.kana-cell-from {
  font-family: var(--jp);
  font-size: clamp(.8rem, 3.4vw, 1rem);
  line-height: 1;
  color: var(--faint);
}
.kana-cell-marked .kana-cell-romaji {
  font-size: 10px;
  white-space: nowrap;
}

/* A katakana cell stacks the same way, and the hiragana above it is quieter
   still: on this chart the hiragana is the thing already known and the katakana
   is the thing being learned, so the new shape has to win the eye. The dotted
   rule between them says "same sound, other spelling" without spending a word. */
.kana-cell-pair .kana-cell-from {
  padding-bottom: 3px;
  border-bottom: 1px dotted var(--border);
  opacity: .75;
}

.kana-headline-from { font: 500 .8rem/1.4 var(--mono); color: var(--faint); }

/* The man'yōgana line on a katakana card. Sits between the writing note and the
   words, and stays out of the way — it is provenance, not instruction. */
.kana-origin {
  font: 500 12px/1.5 var(--mono);
  color: var(--faint);
  margin: calc(-1 * var(--s-2)) 0 var(--s-3);
}
.kana-origin[hidden] { display: none; }
.kana-origin-kanji {
  font-family: var(--jp);
  font-size: 1.15em;
  color: var(--jp-ink);
}

/* A bare ゛ or ゜ sits high in its em box and occupies almost no ink, so at body
   size it reads as a smudge or as nothing at all. Where the mark itself is the
   subject — a column whose whole job is to show it — it needs its own size. */
.mark-glyph {
  display: inline-block;
  font-family: var(--jp);
  font-size: 2.6rem;
  line-height: 1;
  color: var(--jp-ink);
}

/* ---------- kana detail card ---------- */

.kana-detail {
  display: grid;
  grid-template-columns: minmax(0, 226px) minmax(0, 1fr);
  gap: var(--s-4);
  align-items: start;
  /* The card is re-parented into whichever row was tapped, so it needs breathing
     room on both sides rather than just above. */
  margin: var(--s-2) 0 var(--s-3);
  padding: var(--s-3);
  border: 1px solid var(--accent);
  border-radius: 12px;
  background: var(--output-bg);
  box-shadow: 0 1px 3px rgba(15, 98, 183, .07);
}
.kana-detail > * { min-width: 0; }

.kana-stage { min-width: 0; }

.kana-svg {
  display: block;
  width: 100%;
  max-width: 200px;
  height: auto;
  margin: 0 auto;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 10px;
}

.kana-guide { stroke: #e8e4d6; stroke-width: 1; stroke-dasharray: 4 4; }
.kana-ghost path { fill: none; stroke: #e2ded0; stroke-width: 5.5; stroke-linecap: round; stroke-linejoin: round; }
.kana-ink path { fill: none; stroke: var(--jp-ink); stroke-width: 5.5; stroke-linecap: round; stroke-linejoin: round; }

.kana-mark { opacity: 0; transition: opacity .18s ease; }
.kana-mark.on { opacity: 1; }
.kana-mark circle { fill: var(--accent); }
.kana-mark text {
  fill: #fff;
  font: 700 7.5px/1 var(--mono);
  text-anchor: middle;
  dominant-baseline: central;
}

.kana-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  margin-top: var(--s-2);
}

.kana-btn {
  min-width: 0;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--accent-ink);
  border-radius: 999px;
  cursor: pointer;
  font: 500 11px/1 var(--mono);
  padding: 8px 9px;
  white-space: nowrap;
}
.kana-btn:hover { border-color: var(--accent); background: var(--blue-bg); }

.kana-headline { display: flex; align-items: baseline; gap: var(--s-2); margin: 0 0 var(--s-1); flex-wrap: wrap; }
.kana-headline-char { font-family: var(--jp); font-size: 2.4rem; line-height: 1; color: var(--jp-ink); }
.kana-headline-romaji { font: 600 1.1rem/1 var(--mono); color: var(--accent-ink); }

.kana-strokes { font: 500 12px/1.5 var(--mono); color: var(--faint); margin: 0 0 var(--s-2); }
.kana-mnemonic { font-size: .95rem; color: var(--muted); margin: 0 0 var(--s-3); font-style: italic; }

.kana-words-title {
  font: 600 11px/1.4 var(--mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0 0 var(--s-2);
}

.kana-words { list-style: none; padding: 0; margin: 0; }

.kana-word {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 6px 0;
  border-top: 1px solid var(--border);
  margin: 0;
}
.kana-word:first-child { border-top: 0; }

.kana-word-body { display: flex; align-items: baseline; gap: var(--s-2); flex-wrap: wrap; min-width: 0; }
.kana-word-jp { font-family: var(--jp); font-size: 1.25rem; color: var(--jp-ink); }
.kana-word-romaji { font: 500 12px/1 var(--mono); color: var(--muted); }
.kana-word-en { font-size: .92rem; color: var(--ink); }

/* Days whose notes carry no sentences hang the bilingual parallel on the
   example words instead, so a word card can carry an Arabic gloss. .ar-i inside
   already sets the script and isolates it; this only pairs it with its speaker
   button and shrinks that button so it sits inside a word row rather than
   competing with the Japanese one at the head of the line. */
.kana-word-ar {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 1.05rem;
  color: var(--ar-ink);
  unicode-bidi: isolate;
}
.kana-word-ar .kana-play { padding: 4px 8px; font-size: 11px; }
.kana-word-translit { font: 500 12px/1 var(--mono); color: var(--muted); }

/* ---------- bilingual phrase cards ---------- */

.phrases { list-style: none; padding: 0; margin: var(--s-4) 0 0; counter-reset: phrase; }

/* Three columns: Japanese, English, Arabic — one row, not two.
   The English used to sit on its own full-width row above a rule, which cost a
   line of height per card AND left a wide hole between the left-aligned Japanese
   and the right-aligned Arabic. Putting the meaning in that hole fixes both at
   once: the card gets shorter and the empty middle gets a job.
   DOM order stays English-first (it is the thing being taught); the visual order
   is set by explicit grid placement, so screen readers still read it first. */
.phrase {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--card);
  padding: var(--s-2) var(--s-3);
  margin: 0 0 var(--s-2);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, auto) minmax(0, 1fr);
  align-items: center;
  column-gap: var(--s-3);
  row-gap: var(--s-2);
}
.phrase > * { min-width: 0; }

.side-jp { grid-column: 1; grid-row: 1; }
.phrase-en { grid-column: 2; grid-row: 1; }
.side-ar { grid-column: 3; grid-row: 1; }

.phrase-en {
  font-size: 1.02rem;
  line-height: 1.4;
  margin: 0;
  text-align: center;
  text-wrap: balance;
  max-width: 15rem;
}
.phrase-en .no {
  font: 600 12px/1 var(--mono);
  color: var(--faint);
  margin-right: .5em;
}

.side { min-width: 0; }
.side-head {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0 0 var(--s-1);
  flex-wrap: wrap;
}
.side-tag {
  font: 600 10px/1 var(--mono);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--faint);
}
.side-jp .side-tag { color: var(--jp-ink); }
.side-ar .side-tag { color: var(--ar-ink); }

.side-text { margin: 0 0 4px; overflow-wrap: break-word; }
.side-jp .side-text { font-family: var(--jp); font-size: 1.35rem; line-height: 1.6; color: var(--jp-ink); }
.side-ar .side-text { font-family: var(--ar); font-size: 1.45rem; line-height: 1.95; color: var(--ar-ink); direction: rtl; unicode-bidi: isolate; }

.side-translit { font: 500 12px/1.5 var(--mono); color: var(--muted); margin: 0; overflow-wrap: break-word; }

/* The Arabic column is set flush right as a block — label, button, script and
   transliteration all on the same edge. Left-aligning the transliteration under
   right-aligned Arabic leaves it stranded halfway across the card, reading as a
   layout bug rather than as the pair it is. */
.side-ar { text-align: right; }
.side-ar .side-head { justify-content: flex-end; }

/* Kana the learner has already been taught, lit up inside real sentences. */
b.known {
  font-weight: inherit;
  color: var(--accent-ink);
  background: var(--blue-bg);
  border-radius: 3px;
  box-shadow: 0 1px 0 var(--blue-edge);
}

.phrase-note {
  grid-column: 1 / -1;
  grid-row: 2;
  font-size: .86rem;
  color: var(--muted);
  margin: 0;
  padding-top: var(--s-2);
  border-top: 1px solid var(--border);
}

/* ---------- reference tables ---------- */

.chart-jp { font-family: var(--jp); font-size: 1.3rem; color: var(--jp-ink); }

/* In a table cell a short Japanese word must not break across lines — on a
   phone す·し would otherwise stack as two rows inside its own column. The
   table already scrolls inside its own box, so keeping the word whole costs
   nothing. Prose keeps normal wrapping. */
td.chart-jp, th.chart-jp { white-space: nowrap; }
.chart-ar { font-family: var(--ar); font-size: 1.25rem; color: var(--ar-ink); direction: rtl; unicode-bidi: isolate; }

/* ---------- §3 story cards (lesson 3, generated by gen_kana.py) ----------
   The glyph is the true KanjiVG shape; behind it, at watermark opacity, sits
   a flat silhouette of the mnemonic (or the roman letters, for the stories
   that are about letterforms). One warm colour for both kinds, so the 46
   read as one family. */
:root { --story-warm: #e07b4f; }

.mn-stories {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
  margin: var(--s-4) 0;
}
.mn-rowhead {
  grid-column: 1 / -1;
  font: 600 11px/1.4 var(--mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
  border-bottom: 1px solid var(--border);
  padding: var(--s-3) 2px 5px;
  break-after: avoid;
}
.mn-rowhead .chart-jp { font-size: 1.05rem; vertical-align: -2px; }
.mn-card {
  margin: 0;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
  padding: 10px 8px 9px;
  text-align: center;
  break-inside: avoid;
}
.mn-pic { position: relative; width: 96px; height: 96px; margin: 0 auto; }
.mn-pic > svg:last-child { position: relative; width: 100%; height: 100%; }
.mn-pic > svg:last-child path {
  fill: none;
  stroke: var(--ink);
  stroke-width: 5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.mn-pic-bg {
  position: absolute;
  inset: 10%;
  width: 80%;
  height: 80%;
  fill: var(--story-warm);
  opacity: .2;
}
span.mn-pic-letters {
  display: flex;
  align-items: center;
  justify-content: center;
  font: italic 700 3rem/1 var(--serif);
  color: var(--story-warm);
  opacity: .25;
}
span.mn-pic-letters-1 { font-size: 4.6rem; }
.mn-sound { font: 700 .95rem/1.3 var(--mono); color: var(--accent-ink); }
.mn-strokes { font: 500 11px/1.3 var(--mono); color: var(--faint); margin-left: 6px; }
.mn-story {
  display: block;
  font-size: .82rem;
  line-height: 1.45;
  color: var(--muted);
  margin-top: 4px;
}

/* The drill's miss-reveal borrows the card watermark around its font glyph. */
.mn-pic-drill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 84px;
  height: 84px;
}
.mn-pic-drill .kana-headline-char { position: relative; }
.mn-pic-drill .mn-pic-letters { font-size: 2.4rem; }

/* ---------- printable stroke chart (kana-chart.js) ---------- */

.chart-row { margin: 0 0 var(--s-4); }

.chart-row-label {
  font: 600 11px/1.4 var(--mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0 0 var(--s-2);
  padding-bottom: 4px;
  border-bottom: 1px solid var(--border);
}

.chart-line {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--s-2);
}
.chart-line > * { min-width: 0; }

.chart-cell { margin: 0; min-width: 0; text-align: center; }

.chart-svg {
  display: block;
  width: 100%;
  height: auto;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
}

.chart-cap {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin-top: 5px;
}
.chart-cap-romaji { font: 700 15px/1.2 var(--mono); color: var(--accent-ink); }
.chart-cap-from {
  font-family: var(--jp);
  font-size: .8rem;
  line-height: 1.2;
  color: var(--muted);
}
.chart-cap-strokes { font: 500 10px/1.2 var(--mono); color: var(--faint); }

/* The man'yōgana ancestor on the katakana sheet. A sibling pair gets one kanji
   and the accent colour, so the printed page can be scanned for them; an
   unrelated pair spells both out and stays grey. */
.chart-cap-origin {
  font-family: var(--jp);
  font-size: .68rem;
  line-height: 1.25;
  color: var(--faint);
  overflow-wrap: break-word;
}
.chart-cap-origin.is-sib { color: var(--accent-ink); }

.chart-word {
  margin: 4px 0 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.chart-word-jp { font-family: var(--jp); font-size: .95rem; color: var(--jp-ink); overflow-wrap: break-word; }
.chart-word-en { font-size: .68rem; line-height: 1.3; color: var(--muted); overflow-wrap: break-word; }
/* ヲ, ヂ, ヅ: the cell keeps its height so the grid stays even, and says why it
   is empty rather than looking like a rendering failure. */
.chart-word-none { font-style: italic; opacity: .75; }

@media (max-width: 620px) {
  .chart-line { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-2); }
}

@media print {
  .chart-row { break-inside: avoid; }
  .chart-line { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

/* ---------- two-kana word cards (vocab-list.js) ---------- */

.vw-group { margin: 0 0 var(--s-5); }

.vw-grouphead {
  font-family: var(--serif);
  font-size: 1.05rem;
  font-weight: 700;
  margin: 0 0 var(--s-2);
  padding-bottom: 5px;
  border-bottom: 1px solid var(--border);
  overflow-wrap: break-word;
}
.vw-groupname { font-family: var(--jp); color: var(--jp-ink); }
.vw-grouproma { font: 500 12px var(--mono); color: var(--faint); }
.vw-groupen { color: var(--muted); font-weight: 400; }

/* auto-fill rather than a fixed count: the same grid gives four columns on a
   laptop and two on a phone with no breakpoint of its own. */
.vw-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
  gap: var(--s-2);
}
.vw-grid > * { min-width: 0; }

.vw {
  min-width: 0;
  padding: var(--s-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
}

.vw-jp { display: flex; align-items: center; gap: 6px; min-width: 0; }
.vw-kana {
  font-family: var(--jp);
  font-size: 1.7rem;
  line-height: 1.25;
  color: var(--jp-ink);
  overflow-wrap: break-word;
}
.vw-jp .kana-play,
.vw-ar .kana-play { padding: 3px 7px; font-size: 11px; flex: 0 0 auto; }

/* Opt-in on the mount point: <div id="vocab-list" class="vw-long">. Chapter 7
   is the first list whose words run to five, six and seven characters, and at
   the default four-column width a five-character word splits across two lines
   inside its own card — which looks like carelessness on the one element whose
   whole job is showing the word. Wider tracks and a smaller kana fix it.
   Lessons 4, 5 and 6 do not set the class: three columns would be wasteful for
   words that are two characters long. */
.vw-long .vw-grid { grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr)); }
.vw-long .vw-kana { font-size: 1.45rem; }

.vw-romaji { display: block; font: 500 11px/1.4 var(--mono); color: var(--muted); }
.vw-en {
  margin: 3px 0 var(--s-1);
  font-size: .92rem;
  line-height: 1.35;
  overflow-wrap: break-word;
}

/* The row itself stays LTR so the card has one left edge: word, then speaker,
   exactly like the Japanese row above it. The Arabic run inside is reversed by
   `.ar-i`, which already carries direction and isolation. Turning the whole row
   RTL instead puts the script flush right and strands its transliteration
   left-aligned underneath, which is the zigzag this avoids. */
.vw-ar {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  padding-top: var(--s-1);
  border-top: 1px solid var(--border);
}
.vw-ar .ar-i { font-family: var(--ar); font-size: 1.15rem; color: var(--ar-ink); line-height: 1.9; }
.vw-translit { display: block; font: 500 11px/1.4 var(--mono); color: var(--muted); }

.vw-note {
  margin: var(--s-1) 0 0;
  font-size: .76rem;
  line-height: 1.4;
  font-style: italic;
  color: var(--muted);
}

/* An English gloss on its own line under a Japanese table cell. Pairs with
   `.romaji`, which carries the reading — never the meaning. */
.chart-en {
  display: block;
  font-family: var(--serif);
  font-size: .84rem;
  line-height: 1.4;
  color: var(--muted);
  overflow-wrap: break-word;
}

/* A sentence pattern shown on its own, as a specimen rather than as prose. */
.jp-frame {
  font-family: var(--jp);
  font-size: 1.5rem;
  line-height: 1.6;
  color: var(--jp-ink);
  text-align: center;
  margin: var(--s-3) 0;
  padding: var(--s-2);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  overflow-wrap: break-word;
}

/* ---------- こそあど grid (kosoado-grid.js) ---------- */

.ks-mounted { margin: var(--s-4) 0; }

.ks-head { margin: 0 0 var(--s-2); }
.ks-headlabel {
  display: block;
  font: 500 11px/1.5 var(--mono);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 4px;
}
.ks-headline { align-items: end; }
.ks-col {
  min-width: 0;
  padding: 0 0 5px;
  border-bottom: 2px solid var(--border);
  overflow-wrap: break-word;
}
.ks-col.is-q { border-bottom-color: var(--accent); }
.ks-colchar { font-family: var(--jp); font-size: 1.25rem; color: var(--jp-ink); }
.ks-col.is-q .ks-colchar { color: var(--accent-ink); }
.ks-colroma { font: 500 11px var(--mono); color: var(--faint); }
.ks-colen { font-size: .8rem; color: var(--muted); }

.ks-set { margin: 0 0 var(--s-3); }

.ks-setlabel {
  font-family: var(--serif);
  font-size: .98rem;
  font-weight: 700;
  margin: 0 0 6px;
  overflow-wrap: break-word;
}
.ks-setend { font-family: var(--jp); color: var(--jp-ink); }
.ks-seten { color: var(--muted); font-weight: 400; font-size: .88rem; }

.ks-line {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s-2);
}
.ks-line > * { min-width: 0; }

.ks-cell {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  text-align: left;
  padding: 8px 9px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
  font: inherit;
  cursor: pointer;
  transition: border-color .12s ease, background .12s ease, transform .08s ease;
}
.ks-cell:hover { border-color: var(--accent); background: var(--blue-bg); }
.ks-cell:active { transform: scale(.97); }
.ks-cell.speaking { border-color: var(--accent); background: var(--blue-bg); }
.ks-cell.no-voice { cursor: default; }

.ks-cell.is-q {
  border-color: var(--accent);
  background: var(--blue-bg);
  box-shadow: inset 3px 0 0 var(--accent);
}
.ks-cell.is-dim { opacity: .5; }

.ks-jp {
  font-family: var(--jp);
  font-size: 1.35rem;
  line-height: 1.3;
  color: var(--jp-ink);
  overflow-wrap: break-word;
}
.ks-cell.is-q .ks-jp { color: var(--accent-ink); }
.ks-pfx { display: none; font: 500 10px/1.3 var(--mono); color: var(--faint); }
.ks-roma { font: 500 11px/1.3 var(--mono); color: var(--muted); }
.ks-en { font-size: .8rem; line-height: 1.35; color: var(--ink); overflow-wrap: break-word; }
.ks-odd {
  font: 500 10px/1.3 var(--mono);
  color: var(--wrong-ink);
  overflow-wrap: break-word;
}

@media (max-width: 620px) {
  .ks-line { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ks-head { display: none; }
  .ks-pfx { display: block; }
  .ks-jp { font-size: 1.2rem; }
}

@media print {
  .ks-set { break-inside: avoid; }
  .ks-cell { transition: none; }
}

/* ---------- yōon grid (yoon-grid.js) ---------- */

.yo-mounted { margin: var(--s-4) 0; }

.yo-head { margin: 0 0 var(--s-2); }
.yo-headlabel {
  display: block;
  font: 500 11px/1.5 var(--mono);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 4px;
}
.yo-headline { align-items: end; }
.yo-col {
  min-width: 0;
  padding: 0 0 5px;
  border-bottom: 2px solid var(--accent);
  overflow-wrap: break-word;
}
.yo-colchar { font-family: var(--jp); font-size: 1.25rem; color: var(--accent-ink); }
.yo-colroma { font: 500 11px var(--mono); color: var(--faint); }
.yo-colen { font-size: .8rem; color: var(--muted); }

.yo-row { margin: 0 0 var(--s-3); }

.yo-rowlabel {
  font-family: var(--serif);
  font-size: .98rem;
  font-weight: 700;
  margin: 0 0 6px;
  overflow-wrap: break-word;
}
.yo-rowbase { font-family: var(--jp); font-size: 1.2rem; color: var(--jp-ink); }
.yo-rowroma { font: 500 12px var(--mono); color: var(--accent-ink); }
.yo-rowmk { color: var(--muted); font-weight: 400; font-size: .82rem; }

.yo-line {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-2);
}
.yo-line > * { min-width: 0; }

.yo-cell {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  text-align: left;
  padding: 8px 9px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
  font: inherit;
  cursor: pointer;
  transition: border-color .12s ease, background .12s ease, transform .08s ease;
}
.yo-cell:hover { border-color: var(--accent); background: var(--blue-bg); }
.yo-cell:active { transform: scale(.97); }
.yo-cell.speaking { border-color: var(--accent); background: var(--blue-bg); }
.yo-cell.no-voice { cursor: default; }

/* A yōon with no word the course can yet spell. Dimmed rather than hidden: six
   holes in a chart of thirty-three are a fact about the language, and three of
   them are the ぴ row waiting on the small っ. */
.yo-cell.is-gap { background: transparent; border-style: dashed; }

.yo-jp {
  font-family: var(--jp);
  font-size: 1.5rem;
  line-height: 1.25;
  color: var(--jp-ink);
  overflow-wrap: break-word;
}
.yo-cell.is-gap .yo-jp { color: var(--muted); }
.yo-vow { display: none; font: 500 10px/1.3 var(--mono); color: var(--faint); }
.yo-roma { font: 700 12px/1.3 var(--mono); color: var(--accent-ink); }
.yo-cell.is-gap .yo-roma { color: var(--faint); }

.yo-word {
  display: block;
  margin-top: 3px;
  padding-top: 4px;
  border-top: 1px solid var(--border);
  min-width: 0;
}
.yo-wordjp {
  display: block;
  font-family: var(--jp);
  font-size: .95rem;
  line-height: 1.4;
  color: var(--jp-ink);
  overflow-wrap: break-word;
}
.yo-worden {
  display: block;
  font-size: .68rem;
  line-height: 1.35;
  color: var(--muted);
  overflow-wrap: break-word;
}
.yo-word.is-gap .yo-wordjp { color: var(--faint); text-decoration: line-through; }
.yo-word.is-gap .yo-worden { color: var(--faint); }

@media (max-width: 620px) {
  .yo-head { display: none; }
  .yo-vow { display: block; }
  .yo-cell { padding: 7px 6px; }
  .yo-jp { font-size: 1.3rem; }
  .yo-wordjp { font-size: .85rem; }
}

@media print {
  .yo-row { break-inside: avoid; }
  .yo-cell { transition: none; }
}

/* ---------- recognition drill ---------- */

.kana-drill-mounted,
.vocab-drill-mounted {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--card);
  padding: var(--s-3);
  margin: var(--s-4) 0;
}

.drill-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s-2);
  flex-wrap: wrap;
  margin: 0 0 var(--s-1);
}
.drill-count,
.drill-tally { font: 500 12px/1.4 var(--mono); color: var(--faint); margin: 0; }
.drill-tally { color: var(--muted); }

.drill-bar {
  height: 4px;
  border-radius: 2px;
  background: var(--border);
  overflow: hidden;
  margin: 0 0 var(--s-3);
}
.drill-bar-fill {
  display: block;
  height: 100%;
  width: 0;
  background: var(--accent);
  transition: width .25s ease;
}

.drill-stage { display: none; }
.drill-stage.shown { display: block; }

.drill-hint { font: 500 12px/1.4 var(--mono); color: var(--faint); margin: 0; text-align: center; }

.drill-prompt {
  font-family: var(--jp);
  font-size: 5.5rem;
  line-height: 1.15;
  color: var(--jp-ink);
  text-align: center;
  margin: var(--s-1) 0 var(--s-3);
}

.drill-choices {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s-2);
}
.drill-choices > * { min-width: 0; }

.drill-choice {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 6px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg);
  cursor: pointer;
  transition: border-color .12s ease, background .12s ease, transform .08s ease;
}
.drill-choice:hover:not(:disabled) { border-color: var(--accent); background: var(--blue-bg); }
.drill-choice:active:not(:disabled) { transform: scale(.97); }
.drill-choice:disabled { cursor: default; }

.drill-choice-key { font: 500 10px/1 var(--mono); color: var(--faint); }
.drill-choice-romaji { font: 600 1.15rem/1 var(--mono); color: var(--accent-ink); }

.drill-choice.right {
  border-color: var(--green-edge);
  background: var(--green-bg);
}
.drill-choice.right .drill-choice-romaji { color: var(--green); }
.drill-choice.wrong {
  border-color: var(--wrong-edge);
  background: var(--wrong-bg);
}
.drill-choice.wrong .drill-choice-romaji { color: var(--wrong-ink); }

.drill-verdict {
  font: 500 .92rem/1.5 var(--serif);
  margin: var(--s-3) 0 0;
  min-height: 1.5em;
  text-align: center;
}
.drill-verdict.is-right { color: var(--green); }
.drill-verdict.is-wrong { color: var(--wrong-ink); }

.drill-reveal {
  display: none;
  margin-top: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1px solid var(--border);
}
.drill-reveal.shown { display: block; }

/* The character being drilled, marked inside each example word — the reason the
   words are shown at all. */
/* Same mark lesson 2 uses for "this character is yours" — a weight change alone
   is invisible on a Japanese face with no bold cut, which is the usual case. */
.drill-hit {
  font-weight: inherit;
  color: var(--accent-ink);
  background: var(--blue-bg);
  border-radius: 3px;
  box-shadow: 0 1px 0 var(--blue-edge);
}

.drill-next { display: none; margin-top: var(--s-3); }
.drill-next.shown { display: inline-flex; }

.drill-done { display: none; text-align: center; }
.drill-done.shown { display: block; }

.drill-score { font: 600 1.3rem/1.3 var(--serif); color: var(--ink); margin: var(--s-2) 0; }
.drill-clean { color: var(--green); margin: 0 0 var(--s-3); }
.drill-missed-label { font: 500 12px/1.4 var(--mono); color: var(--faint); margin: 0 0 var(--s-2); }

.drill-missed {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  justify-content: center;
  margin: 0 0 var(--s-3);
}
.drill-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 5px 10px;
  border: 1px solid var(--wrong-edge);
  border-radius: 999px;
  background: var(--wrong-bg);
}
.drill-chip-char { font-family: var(--jp); font-size: 1.2rem; color: var(--jp-ink); }
.drill-chip-romaji { font: 500 11px/1 var(--mono); color: var(--wrong-ink); }

.drill-restart { margin-top: var(--s-2); }

/* ---------- meaning drill extras (vocab-drill.js) ---------- */

.vd-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  margin: 0 0 var(--s-3);
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--border);
}
.vd-controls > * { min-width: 0; }

.vd-seg { display: flex; flex-wrap: wrap; gap: 4px; }
.vd-segbtn {
  padding: 5px 10px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
  font: 500 12px/1.5 var(--mono);
  color: var(--muted);
  cursor: pointer;
  transition: border-color .12s ease, background .12s ease, color .12s ease;
}
.vd-segbtn:hover { border-color: var(--accent); color: var(--accent-ink); }
.vd-segbtn.on {
  border-color: var(--accent);
  background: var(--blue-bg);
  color: var(--accent-ink);
}

.vd-cat { display: flex; align-items: center; gap: 6px; min-width: 0; }
.vd-catlabel { font: 500 11px/1.5 var(--mono); color: var(--faint); flex: 0 0 auto; }
.vd-select {
  max-width: 100%;
  padding: 4px 8px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  font: 500 12px var(--mono);
  color: var(--ink);
}

/* Two columns, not four: these answers are words and phrases, not two-letter
   romaji, and four across forces every one of them to wrap. */
.vd-choices { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.vd-choice { justify-content: center; min-height: 4.2rem; padding: 10px; }
.vd-choice-text {
  font-family: var(--serif);
  font-size: 1rem;
  line-height: 1.35;
  color: var(--ink);
  text-align: center;
  overflow-wrap: break-word;
}
.vd-choice-text.is-jp { font-family: var(--jp); font-size: 1.5rem; color: var(--jp-ink); }
.vd-choice-text.is-ar {
  font-family: var(--ar);
  font-size: 1.3rem;
  line-height: 1.95;
  color: var(--ar-ink);
  direction: rtl;
  unicode-bidi: isolate;
}
.drill-choice.right .vd-choice-text { color: var(--green); }
.drill-choice.wrong .vd-choice-text { color: var(--wrong-ink); }

/* The English prompt is a sentence-ish thing, not a glyph — 5.5rem would put
   "my older brother" on three lines. */
.drill-prompt.is-en {
  font-family: var(--serif);
  font-size: 2rem;
  line-height: 1.3;
  color: var(--ink);
  overflow-wrap: break-word;
}

.vd-reveal-en { margin: 0 0 var(--s-1); font-size: 1.05rem; }
.vd-reveal-ar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin: 0 0 var(--s-2);
}
.vd-reveal-ar .ar-i { font-family: var(--ar); font-size: 1.35rem; line-height: 1.95; color: var(--ar-ink); }
.vd-reveal-cat { font: 500 11px/1.5 var(--mono); color: var(--faint); margin: 0 0 var(--s-1); }

/* ---------- words-language switch (lang-switch.js) ----------
 *
 * Two buttons and a caveat. The caveat is not decoration: the switch changes the
 * word cards, the walk and the drill, and it deliberately does NOT change the
 * numbered sections, which teach how Japanese builds a word. A control that
 * looked like it translated the page would be lying, so the note sits directly
 * under it at the same visual weight as a meta line.
 */

.ls-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.ls-label { font: 500 11px/1 var(--mono); color: var(--faint); text-transform: uppercase; letter-spacing: .04em; }
.ls-btn {
  font-size: 1rem;
  line-height: 1.4;
  color: var(--muted);
  background: none;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 5px 14px;
  cursor: pointer;
}
.ls-btn[lang="ja"] { font-family: var(--jp); }
.ls-btn[lang="ar"] { font-family: var(--ar); font-size: 1.15rem; }
.ls-btn:hover { border-color: var(--blue-edge); color: var(--accent-ink); }
.ls-btn.on {
  color: var(--accent-ink);
  background: var(--blue-bg);
  border-color: var(--blue-edge);
  font-weight: 600;
}
.ls-note {
  margin: var(--s-2) 0 0;
  font-size: .84rem;
  line-height: 1.6;
  color: var(--muted);
  max-width: 34rem;
}

/* Arabic mode on a word card. The five slots are positions rather than
   languages, so each one has to be told which script it is holding this time. */
.vw.is-ar .vw-kana {
  font-family: var(--ar);
  font-size: 1.5rem;
  line-height: 1.9;
  color: var(--ar-ink);
  direction: rtl;
  unicode-bidi: isolate;
}
.vw.is-ar .vw-ar .ar-i {
  font-family: var(--jp);
  font-size: 1.15rem;
  color: var(--jp-ink);
  direction: ltr;
}

/* ---------- one-day walk (one-day.js) ----------
 *
 * Prose with the Japanese load-bearing inside it, so the Japanese has to sit ON
 * the text baseline rather than in a box of its own. Every word is a button;
 * none of them may look like one, or fourteen scenes become a wall of chrome.
 * The affordance is the colour and the dotted underline, which is enough to say
 * "tappable" without breaking the line.
 */

.od-bar {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  flex-wrap: wrap;
  margin: 0 0 var(--s-4);
  padding-bottom: var(--s-2);
  border-bottom: 1px solid var(--border);
}
.od-toggle {
  font: 500 13px/1 var(--mono);
  color: var(--accent-ink);
  background: var(--blue-bg);
  border: 1px solid var(--blue-edge);
  border-radius: 6px;
  padding: 7px 12px;
  cursor: pointer;
}
.od-toggle:hover { background: #e3edfa; }
.od-barnote { font-size: .84rem; color: var(--muted); }

.od-scene { margin: 0 0 var(--s-5); }

.od-scenehead {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  margin: 0 0 var(--s-1);
}
.od-scenen {
  font: 600 12px/1 var(--mono);
  color: var(--faint);
  /* Fixed width so fourteen numbers form a column down the page rather than
     shuffling the titles left and right as the digit count changes. */
  min-width: 1.6rem;
}
.od-scenetitle { font-size: 1.12rem; }
/* Pushed to the far edge and kept quiet: it is a control you reach for once per
   scene, not a thing to read past fourteen times on the way down the page. */
.od-scenetoggle {
  margin-left: auto;
  font: 500 11px/1 var(--mono);
  color: var(--muted);
  background: none;
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 5px 9px;
  cursor: pointer;
}
.od-scenetoggle:hover { color: var(--accent-ink); border-color: var(--blue-edge); background: var(--blue-bg); }
.od-testing .od-scenetoggle { color: var(--accent-ink); border-color: var(--blue-edge); background: var(--blue-bg); }
.od-lede {
  margin: 0 0 var(--s-3);
  color: var(--muted);
  font-size: .9rem;
  max-width: 34rem;
}

.od-p {
  max-width: 34rem;
  /* Roomier than body prose: every line carries Japanese at a larger size, and
     at the default leading the kana crowd the line above. */
  line-height: 1.95;
}

/* The button wraps; only the kana inside it may not. This used to be
   `white-space: nowrap` on the button, and chapter 12 found the bug —
   シャープペンシル shāpupenshiru (mechanical pencil) is one 380px unit, so a
   single unbreakable button pushed a 390px phone sideways. Long katakana
   loanwords are ordinary from chapter 12 on, so it is fixed in the component.

   The nowrap cannot go on all three children instead: one-day.js puts each
   part's leading space INSIDE its span (` (${gloss})`), so nowrapping the
   children removes the very break opportunities between them. The romaji is a
   single token and will not break anyway; the gloss is English and may. */
.od-w {
  font: inherit;
  background: none;
  border: 0;
  padding: 0 1px;
  margin: 0;
  cursor: pointer;
  color: var(--jp-ink);
  border-bottom: 1px dotted var(--jp-ink);
  white-space: normal;
  max-width: 100%;
}
.od-w:hover { border-bottom-style: solid; }
.od-wk { font-family: var(--jp); font-size: 1.16em; white-space: nowrap; }
/* The same slot holding Arabic. `unicode-bidi: isolate` is what keeps an Arabic
   run from dragging the surrounding English punctuation to the wrong side of
   it — the whole walk is Arabic words inside English sentences, which is the
   case that rule exists for. */
.od-w[data-lang="ar"] { color: var(--ar-ink); border-bottom-color: var(--ar-ink); }
.od-w[data-lang="ar"] .od-wk {
  font-family: var(--ar);
  font-size: 1.24em;
  direction: rtl;
  unicode-bidi: isolate;
}
.od-wr { font: 400 .74em/1 var(--mono); color: var(--muted); }
/* The meaning, every time the word appears. Set quieter than the body text so a
   paragraph still reads as prose rather than as an interlinear gloss. */
.od-wen { font-size: .82em; color: var(--muted); font-style: italic; }
.od-w.speaking { background: var(--blue-bg); }
.od-w.no-voice { cursor: default; border-bottom-style: none; }

/* ---------- digit grouping ---------- */

/* Two readings of the same number with the separators in different places —
   lesson 13's argument that Japanese groups in ten-thousands. HTML rather than
   SVG for the reason recorded on `.zones` below: the content is entirely
   characters, and SVG would scale them with the box. */
.grp { margin: 0; display: grid; gap: var(--s-3); }
.grp-row { margin: 0; }
.grp-lab { font: 500 11px/1.6 var(--mono); color: var(--faint); margin: 0 0 2px; }
.grp-num {
  margin: 0;
  font: 600 clamp(1.15rem, 5.2vw, 1.8rem)/1.3 var(--mono);
  color: var(--ink);
  overflow-wrap: break-word;
}
/* The separators are the whole point, so they are the only thing coloured. */
.grp-sep { color: var(--accent); }
.grp-note { font-size: .84rem; color: var(--muted); margin: 4px 0 0; }

/* ---------- zone strip ---------- */

/* Three labelled territories side by side — lesson 12's こ・そ・あ figure.
   Deliberately HTML and not SVG, for the same reason kosoado-grid.js is not a
   table: an SVG scales its text with its own box, so at a phone's 358px the
   660-unit viewBox came out at 0.54 and the captions rendered at 7px. Nothing
   was clipped and no checker could see it. In HTML the type stays at its CSS
   size and the boxes wrap to a column instead. */
/* A grid of exactly three rather than a wrapping flex row: the figure's whole
   argument is that the three territories run left to right away from you, and a
   flex row wrapped to 2 + 1 on a phone, which says the opposite. `minmax(0,1fr)`
   lets a column get narrower instead of pushing the page sideways. */
.zones { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-2); margin: 0; }
.zone {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 10px 13px;
  text-align: center;
}
.zone > * { display: block; }
.zone-k { font-family: var(--jp); font-size: 2.1rem; line-height: 1.15; color: var(--jp-ink); }
.zone-cap { font-size: .8rem; color: var(--muted); margin-top: 4px; }
.zone-w { font-family: var(--jp); font-size: 1.05rem; color: var(--ink); margin-top: 9px; }
.zone-w + .zone-w { margin-top: 2px; }
.zone-ar {
  font-family: var(--ar); font-size: 1.2rem; line-height: 1.9;
  color: var(--ar-ink); direction: rtl; unicode-bidi: isolate; margin-top: 7px;
}

/* The strip is the retrieval half of the page: read the scene, name its words,
   then check. Set off with a rule rather than a box so it reads as a footnote
   to the scene and not as a second component. */
.od-strip {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin: var(--s-2) 0 0;
  padding-top: var(--s-2);
  border-top: 1px solid var(--border);
}
.od-striplabel {
  font: 500 11px/1.6 var(--mono);
  color: var(--faint);
  min-width: 4.6rem;
}
.od-strip .od-w { border-bottom: 0; }
.od-strip .od-w:hover { border-bottom: 1px solid var(--jp-ink); }

/* Recall mode: the Japanese comes out of the sentences, the English stays to
   carry the context, and each gap is tappable to check.
   `visibility: hidden` rather than `display: none` on purpose — it keeps the
   word's exact width, so the gap shows how long the word is without showing
   which word it is. Hiding it outright would reflow every paragraph the moment
   you toggled, which makes the page unreadable as a test. */
.od-testing .od-w {
  border-bottom: 1px solid var(--jp-ink);
  background: var(--card);
  border-radius: 3px;
}
.od-testing .od-wk { visibility: hidden; }
.od-testing .od-wr { display: none; }
/* The gloss goes with the word. Showing "(road)" beside the gap would simply
   answer the question. */
.od-testing .od-wen { display: none; }
.od-testing .od-w.is-revealed {
  background: none;
  border-bottom-style: dotted;
}
.od-testing .od-w.is-revealed .od-wk { visibility: visible; }
.od-testing .od-w.is-revealed .od-wen { display: inline; }
/* The strips are the same answers in a shorter form, so they go too. */
.od-testing .od-strip { display: none; }

/* ---------- the seven days (week-grid.js) ---------- */

.wk-mounted { margin: var(--s-4) 0; }

.wk-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

/* Three zones — what you write · where it came from · Arabic — plus a full-width
   note row underneath. `auto` on the middle track lets the planet column size to
   its content so the Arabic is not pushed off the right edge on a laptop. */
.wk-day {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1.15fr) minmax(0, .95fr);
  gap: var(--s-2) var(--s-3);
  align-items: start;
  padding: var(--s-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
}
.wk-day > * { min-width: 0; }

.wk-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

.wk-kanji {
  font-family: var(--jp);
  font-size: 1.7rem;
  line-height: 1.25;
  color: var(--jp-ink);
  overflow-wrap: break-word;
}
/* The tinted character is the entire difference between one weekday and the
   next. Colour is not the only cue — it is also the character the middle column
   is about — so a reader who cannot see the tint loses nothing. */
.wk-el { color: var(--accent-ink); }

.wk-read { display: flex; align-items: center; gap: 8px; min-width: 0; }
.wk-kana {
  font-family: var(--jp);
  font-size: 1.05rem;
  color: var(--jp-ink);
  overflow-wrap: break-word;
}
.wk-read .kana-play { padding: 4px 8px; font-size: 11px; }

.wk-roma { font: 500 11.5px/1.4 var(--mono); color: var(--muted); }
.wk-en { font-size: .92rem; font-weight: 600; color: var(--ink); }

.wk-label {
  display: block;
  font: 500 10px/1.5 var(--mono);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 3px;
}

.wk-from { min-width: 0; }
.wk-sky { overflow-wrap: break-word; }
.wk-planet { font-family: var(--jp); font-size: 1.05rem; color: var(--jp-ink); }
.wk-planetr { font: 500 11.5px var(--mono); color: var(--muted); }
.wk-planeten { font-size: .88rem; color: var(--ink); }

.wk-alone {
  margin-top: 4px;
  font-size: .8rem;
  line-height: 1.45;
  color: var(--muted);
  overflow-wrap: break-word;
}
.wk-elchar, .wk-elkana { font-family: var(--jp); color: var(--jp-ink); }
.wk-elen { color: var(--faint); }

.wk-ar { min-width: 0; }
.wk-arword { display: flex; align-items: center; gap: 8px; min-width: 0; }
.wk-arword .ar-i {
  font-family: var(--ar);
  font-size: 1.25rem;
  line-height: 1.9;
  color: var(--ar-ink);
  overflow-wrap: break-word;
}
.wk-arword .kana-play { padding: 4px 8px; font-size: 11px; }
.wk-art { display: block; font: 500 11px/1.5 var(--mono); color: var(--muted); overflow-wrap: break-word; }

.wk-note {
  grid-column: 1 / -1;
  margin: 0;
  padding-top: 7px;
  border-top: 1px solid var(--border);
  font-size: .82rem;
  line-height: 1.5;
  color: var(--muted);
}

@media (max-width: 760px) {
  /* Two columns before one: the Japanese needs the width, but the planet and the
     Arabic are short enough to sit side by side down to phone size. */
  .wk-day { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .wk-main { grid-column: 1 / -1; }
  .wk-kanji { font-size: 1.5rem; }
}

@media (max-width: 460px) {
  .wk-day { grid-template-columns: minmax(0, 1fr); }
  .wk-main { grid-column: auto; }
}

@media print {
  .wk-day { break-inside: avoid; }
}

/* ---------- narrow screens ---------- */

@media (max-width: 620px) {
  .drill-prompt { font-size: 4.4rem; }
  .drill-choices { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* nav.js parks a 42px hamburger fixed at top:14px right:14px. The tally is the
     only right-aligned line in the course, so it is the only thing that scrolls
     underneath it; reserve the width. */
  .drill-head { padding-right: 34px; }

  .mn-stories { grid-template-columns: repeat(2, 1fr); }

  /* The word cards keep two columns — they are small — but the drill's answers
     are prose and need the extra room, so they shrink rather than wrap to four
     lines each. */
  .vw-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Two columns here too — one column would make chapter 7's forty-five cards
     an unreasonable scroll. The two longest words still wrap on a phone, which
     is what a phone is for. */
  .vw-long .vw-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .vw-long .vw-kana { font-size: 1.2rem; }
  .vd-choice { min-height: 3.6rem; padding: 8px 6px; }
  .vd-choice-text { font-size: .9rem; }
  .vd-choice-text.is-jp { font-size: 1.35rem; }
  .vd-choice-text.is-ar { font-size: 1.15rem; }
  .drill-prompt.is-en { font-size: 1.6rem; }
  .vd-controls { padding-right: 34px; }

  .kana-detail { grid-template-columns: minmax(0, 1fr); }
  .kana-cell { padding: 8px 1px 5px; border-radius: 8px; }
  .kana-line { gap: 5px; }

  /* Two columns, two rows. The English drops into the gap beside the JAPANESE
     label — the widest piece of dead space on a phone — instead of claiming a
     row of its own above a rule. Arabic then spans the full width beneath. */
  .phrase {
    grid-template-columns: minmax(0, 1fr) minmax(0, auto);
    align-items: start;
  }
  .side-jp { grid-column: 1; grid-row: 1; }
  .phrase-en {
    grid-column: 2;
    grid-row: 1;
    text-align: right;
    max-width: 11rem;
  }
  .side-ar {
    grid-column: 1 / -1;
    grid-row: 2;
    padding-top: var(--s-2);
    border-top: 1px solid var(--border);
  }
  .phrase-note { grid-row: 3; }
}

@media (prefers-reduced-motion: reduce) {
  .kana-ink path { transition: none !important; }
  .kana-mark { transition: none !important; }
  .drill-bar-fill { transition: none !important; }
}

@media print {
  .kana-controls, .kana-play, .say, .voice-warning { display: none !important; }
  .kana-detail, .phrase { break-inside: avoid; }
  /* The drill is a keyboard-and-tap exercise; on paper it is a blank box. */
  .kana-drill-mounted,
  .vocab-drill-mounted { display: none !important; }

  /* The word list is the part worth having on paper. Keep four to a row, never
     split a card, and never orphan a group heading from its first row. */
  .vw-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .vw { break-inside: avoid; }
  .vw-grouphead { break-after: avoid; }

  /* The walk prints well and is worth carrying. Recall mode does not survive
     paper — on paper the way to hide a word is a hand over it — so printing
     always gives the full text with its strips, whatever the screen was
     showing when you hit print. */
  .od-bar, .od-scenetoggle { display: none !important; }
  .od-testing .od-strip { display: flex !important; }
  .od-testing .od-wk { visibility: visible !important; }
  .od-testing .od-wr, .od-testing .od-wen { display: inline !important; }
  .od-testing .od-w { background: none !important; }
  .od-scene { break-inside: avoid; }
  .od-scenehead { break-after: avoid; }
  .od-w { border-bottom: 0 !important; }
}

/* ── kana-panel.js — the floating kana chart ───────────────────────────────
 *
 * One tab welded to the left screen edge, vertically centred so it cannot land
 * under the course-nav button in the top-right corner. The panel slides out from
 * behind its own tab, which is why the tab is the OUTER child of the aside — it
 * has to stay on screen when the chart is away. The `kp-right` rules are kept
 * because the side is data, not markup, but nothing sets it: the right edge is
 * nav.js's.
 *
 * z-index sits under nav.js (60–62) on purpose: the drawer is a navigation
 * decision and must cover a reference chart, never the other way round.
 */

.kp {
  --kp-w: 238px;
  position: fixed;
  top: 50%;
  z-index: 48;
  display: flex;
  align-items: center;
  transition: transform .24s ease;
}

/* Off-screen by translation, not by `left: -238px`: a fixed box translated out
   of view adds nothing to the viewport's scrollable overflow, so the panel
   cannot give the page a sideways scrollbar. Same arrangement as the nav drawer. */
.kp-left { left: 0; transform: translate(calc(-1 * var(--kp-w)), -50%); }
.kp-right { right: 0; transform: translate(var(--kp-w), -50%); }
.kp.kp-open { transform: translate(0, -50%); }

.kp-tab {
  flex: none;
  appearance: none;
  writing-mode: vertical-rl;
  text-orientation: mixed;
  padding: 15px 7px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--accent-ink);
  font: 600 11.5px/1 var(--mono);
  letter-spacing: .06em;
  cursor: pointer;
  box-shadow: 0 1px 6px rgba(0, 0, 0, .1);
}
.kp-tab:hover { border-color: var(--accent); background: var(--blue-bg); }
.kp-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.kp-left .kp-tab { border-left: 0; border-radius: 0 9px 9px 0; }
.kp-right .kp-tab { border-right: 0; border-radius: 9px 0 0 9px; }
.kp-tab-native { font-family: var(--jp); font-size: 13px; font-weight: 500; }

.kp-body {
  width: var(--kp-w);
  min-width: 0;
  max-height: 84vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0 10px 12px;
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: 0 2px 14px rgba(0, 0, 0, .1);
}
.kp-left .kp-body { border-left: 0; border-radius: 0 11px 11px 0; }
.kp-right .kp-body { border-right: 0; border-radius: 11px 0 0 11px; }

/* Title on its own line above the toggles, not beside them: three buttons and a
   two-word title do not share 218px, and a head that wraps unpredictably is worse
   than one that is two rows by design. It stays sticky, so the toggles are
   reachable from anywhere in a 1500px chart. */
.kp-head {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 9px 0 7px;
  background: var(--card);
  border-bottom: 1px solid var(--border);
}
.kp-title { margin: 0 0 6px; font-size: .84rem; line-height: 1.15; }

.kp-toggles { display: flex; flex-wrap: wrap; gap: 4px; }
.kp-toggles > * { min-width: 0; }

.kp-toggle {
  appearance: none;
  padding: 3px 5px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--bg);
  color: var(--muted);
  font: 600 10px/1 var(--mono);
  letter-spacing: .03em;
  cursor: pointer;
}
.kp-toggle[aria-pressed="true"] {
  border-color: var(--accent);
  background: var(--blue-bg);
  color: var(--accent-ink);
}
.kp-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.kp-sectionhead { margin: var(--s-3) 0 5px; }
.kp-sectiontitle {
  margin: 0;
  font: 700 10.5px/1.3 var(--mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--accent-ink);
}
.kp-sectionsub { margin: 1px 0 0; font-size: .72rem; line-height: 1.35; color: var(--muted); }

.kp-grid { display: grid; gap: 2px; }
.kp-grid > * { min-width: 0; }
.kp-grid-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.kp-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

.kp-col {
  font: 600 8.5px/1.6 var(--mono);
  letter-spacing: .08em;
  text-align: center;
  color: var(--faint);
}

.kp-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 3px 1px 2px;
  border-radius: 4px;
  background: var(--bg);
}
/* Small, but not decorative: the character has to be readable at a glance from
   wherever the page is being read, which is what fixes the floor at ~17px. Both
   scripts get the same size and the same ink — hiragana above katakana, always,
   so position is what tells them apart and the reader is never handed the answer
   by a colour when one of the two is switched off. */
.kp-char {
  font-family: var(--jp);
  font-weight: 500;
  font-size: 1.06rem;
  line-height: 1.18;
  color: var(--jp-ink);
}
.kp-romaji {
  margin-top: 1px;
  font: 500 9.5px/1.1 var(--mono);
  color: var(--muted);
}
.kp-new { opacity: .34; }
.kp-gap { justify-content: center; background: none; color: var(--faint); font-size: .8rem; }

.kp-legend { margin: 5px 0 0; font-size: .68rem; line-height: 1.4; color: var(--faint); }

/* A layer off is a study mode, not a layout change: the cells keep their size, so
   the chart never reflows under the reader's finger. Hiragana off leaves katakana
   to read cold, romaji off leaves the two scripts to match against each other,
   both scripts off leaves the readings to recall the kana from. */
.kp-no-hiragana .kp-h,
.kp-no-katakana .kp-k,
.kp-no-romaji .kp-romaji { visibility: hidden; }

@media (max-width: 760px) {
  .kp { --kp-w: min(300px, 80vw); }
  .kp-body { max-height: 78vh; }
}

@media (prefers-reduced-motion: reduce) {
  .kp { transition: none; }
}

@media print {
  .kp { display: none !important; }
}

/* ---------- counter sheet ---------- */

/* reference/counters.html. Every counter the course has taught, 1–10 plus 何,
   rendered by counter-grid.js from counter-data.js.

   The table is eight columns wide, which is more than a phone can hold. It
   scrolls INSIDE its own box — style.css already gives every table
   `display:block; overflow-x:auto`, so nothing here needs to fight it and the
   page itself never scrolls sideways. On paper `display:table` comes back and
   all eight columns print, which is the point of owning the sheet.

   The changed cells carry their flag character in the MARKUP (see
   counter-grid.js), so the colour below is reinforcement, never the only
   signal — this sheet exists to be printed, often in greyscale. */

/* A sound change written as `X → Y` must never break across lines: a small っ
   that wraps away from its base renders as "は っ", which is a different and
   wrong thing. Used wherever a transformation is quoted in prose. */
.nw { white-space: nowrap; }

.ct-caption {
  font: 600 11px/1.5 var(--mono);
  text-transform: uppercase;
  letter-spacing: .05em;
  margin: var(--s-4) 0 var(--s-2);
  padding-left: 9px;
  border-left: 3px solid var(--green);
}
.ct-caption.is-shifty { border-left-color: var(--wrong-ink); color: var(--wrong-ink); }
.ct-caption.is-steady { color: var(--green); }

.ct-table { font-size: .9em; }
.ct-table th, .ct-table td { padding: 7px 9px; vertical-align: top; }

.ct-numhead, .ct-num {
  font: 600 12px/1.4 var(--mono);
  color: var(--faint);
  text-align: right;
  white-space: nowrap;
  width: 1%;
}
.ct-qrow .ct-num { color: var(--accent-ink); font-size: 1.05rem; }
.ct-qrow td { border-top: 2px solid var(--border); }

.ct-head { min-width: 0; }
.ct-head-jp {
  display: block;
  font-family: var(--jp);
  font-size: 1.15rem;
  color: var(--jp-ink);
  text-transform: none;
  letter-spacing: 0;
}
.ct-head-en {
  display: block;
  font: 500 10px/1.4 var(--mono);
  color: var(--muted);
  text-transform: none;
  letter-spacing: 0;
  margin-top: 2px;
}
/* The classification the sheet turns on, printed on the column it describes. */
.ct-first {
  display: block;
  margin-top: 4px;
  font: 500 9px/1.4 var(--mono);
  text-transform: uppercase;
  letter-spacing: .05em;
}
.ct-first.is-vowel,
.ct-first.is-voiced { color: var(--green); }
.ct-first.is-voiceless { color: var(--wrong-ink); }

.ct-cell { min-width: 0; }
.ct-cell.is-changed { background: var(--wrong-bg); }

.ct-say {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  font: inherit;
  text-align: left;
  min-width: 0;
}
.ct-say:hover .ct-jp { color: var(--accent-ink); }
.ct-say:active { transform: scale(.97); }
.ct-say.no-voice { cursor: default; }

.ct-jp {
  font-family: var(--jp);
  font-size: 1.15rem;
  line-height: 1.5;
  color: var(--jp-ink);
  white-space: nowrap;
}
/* The flag is the kana that did the changing, not an abstract symbol — so the
   pattern is legible at a glance and survives the stylesheet being stripped. */
.ct-flag {
  font-family: var(--jp);
  font-size: .72em;
  color: var(--wrong-ink);
  font-weight: 700;
}
.ct-ro { display: block; font-size: .78em; }
.ct-alt {
  display: block;
  font: 500 10px/1.5 var(--mono);
  color: var(--faint);
  white-space: nowrap;
}
.ct-alt-jp { font-family: var(--jp); font-size: 1.15em; }

/* ---------- counter notes ---------- */

.cn-list { display: grid; gap: var(--s-3); margin: var(--s-4) 0 var(--s-5); }
.cn-list > * { min-width: 0; }

.cn-item {
  border: 1px solid var(--border);
  border-left: 3px solid var(--green);
  border-radius: 8px;
  background: var(--card);
  padding: var(--s-3);
  min-width: 0;
}
.cn-item.is-voiceless { border-left-color: var(--wrong-ink); }

.cn-head {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  flex-wrap: wrap;
  margin: 0 0 4px;
  min-width: 0;
}
.cn-head > * { min-width: 0; }
.cn-jp { font-family: var(--jp); font-size: 1.4rem; color: var(--jp-ink); }
.cn-kanji { font-family: var(--jp); font-size: 1.15rem; color: var(--muted); }
.cn-en { font-size: .95rem; color: var(--ink); }

.cn-meta { font: 500 11px/1.5 var(--mono); color: var(--faint); margin: 0 0 var(--s-2); }
.cn-note { margin: 0; font-size: .95rem; line-height: 1.6; color: var(--muted); }
.cn-note strong { color: var(--ink); }

@media print {
  /* The flag characters carry the meaning on paper, so the plate is dropped —
     it prints as a grey wash that makes the kana harder to read for no gain. */
  .ct-cell.is-changed { background: none; }
  .cn-item { break-inside: avoid; }
  /* A group caption stranded at the foot of a page, with its table overleaf,
     says nothing at all. Found by printing the sheet to PDF and looking. */
  .ct-caption { break-after: avoid; }
}
