/* JEE Study App - client styles.
   Elderly-first per ARCHITECTURE section 7: body 18-20px+, primary actions 24px+,
   48px touch targets, high contrast, one task per screen, generous whitespace.
   Brand per JEE_SHARED_CONTRACT section 2: palette carries the brand on content
   screens; the crest appears only on the key surfaces (splash / home / sign-in). */

:root {
  --jee-primary: #2f7d92;      /* locked brand primary */
  --jee-primary-dk: #22606f;
  --jee-coral: #e2725b;        /* CTAs */
  --jee-coral-dk: #c85b45;
  --jee-blue: #cfe6ee;         /* logo light blue accent */
  --jee-pink: #f3dfe0;         /* soft pink accent */
  --jee-cream: #fbf6ee;

  --ink: #23282b;
  --ink-soft: #5a6469;
  --line: #dfd8ce;
  --ok: #2e7d5b;
  --ok-bg: #e7f4ee;
  --check: #5a9e78;            /* soft green — the "check my speaking" CTA (never coral, never red) */
  --check-dk: #47845f;
  --check-bg: #eef6f1;
  --no: #b3402c;
  --no-bg: #fbeae6;
  --card: #ffffff;

  --body: 20px;                /* elderly-first floor */
  --lead: 1.7;
  --tap: 48px;                 /* minimum touch target */
  --radius: 14px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  background: var(--jee-cream);
  color: var(--ink);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  font-size: var(--body);
  line-height: var(--lead);
  -webkit-text-size-adjust: 100%;
}

#app { max-width: 620px; margin: 0 auto; padding: 0 20px 120px; }

/* ---------- typography ---------- */
h1 { font-size: 30px; line-height: 1.3; margin: 0 0 8px; color: var(--jee-primary-dk); }
h2 { font-size: 24px; line-height: 1.35; margin: 0 0 12px; color: var(--jee-primary-dk); }
h3 { font-size: 20px; margin: 0 0 6px; }
p  { margin: 0 0 14px; }
.ja { color: var(--ink-soft); font-size: 17px; line-height: 1.75; }
.en { font-size: 20px; }
.muted { color: var(--ink-soft); }
.small { font-size: 16px; }

/* focus_construct cue (2026-07-18): a focused typed drill declares its target, so an off_target
   redirect is fair rather than a hidden gotcha. Calm and secondary, never alarming; the JA sits on
   its own line per the bilingual rule. MINIMAL and provisional pending Mitsuyo's sitting. */
.focus-hint {
  font-size: 17px; color: var(--jee-primary-dk);
  background: var(--jee-blue); border-radius: 10px;
  padding: 8px 14px; margin: 0 0 14px;
}
.focus-hint .ja { display: block; font-size: 15px; margin-top: 2px; }

/* ---------- brand surfaces (crest only here) ---------- */
.brandbar {
  display: flex; align-items: center; gap: 12px;
  padding: 22px 0 10px;
}
.brandbar img { width: 56px; height: 56px; }
.wordmark {
  font-family: "Edwardian Script ITC", "Segoe Script", "Brush Script MT", cursive;
  font-size: 30px; color: var(--jee-primary-dk); line-height: 1;
}

/* ---------- cards ---------- */
.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px;
  margin: 0 0 18px;
}
.card.accent { border-left: 6px solid var(--jee-primary); }

/* ---------- buttons ---------- */
button {
  font: inherit;
  min-height: var(--tap);
  border-radius: 12px;
  border: 2px solid transparent;
  cursor: pointer;
}
.btn-primary {
  display: block; width: 100%;
  background: var(--jee-coral); color: #fff;
  font-size: 24px; font-weight: 700;
  padding: 16px 20px; min-height: 60px;
  border: none;
}
.btn-primary:hover { background: var(--jee-coral-dk); }
.btn-primary:disabled { background: #cfcac3; cursor: not-allowed; }

.btn-secondary {
  background: #fff; color: var(--jee-primary-dk);
  border: 2px solid var(--jee-primary);
  font-size: 18px; padding: 10px 18px;
}
.btn-secondary:hover { background: var(--jee-blue); }

/* choice buttons (MC / sentence selection) */
.choice {
  display: block; width: 100%; text-align: left;
  background: #fff; border: 2px solid var(--line);
  padding: 16px 18px; margin: 0 0 12px;
  font-size: 20px; min-height: var(--tap);
}
.choice:hover { border-color: var(--jee-primary); background: var(--jee-blue); }
.choice.picked { border-color: var(--jee-primary); background: var(--jee-blue); }
.choice.right { border-color: var(--ok); background: var(--ok-bg); }
.choice.wrong { border-color: var(--no); background: var(--no-bg); }
.choice:disabled { cursor: default; }

/* tiles (ordering) */
.tiles { display: flex; flex-wrap: wrap; gap: 10px; margin: 0 0 16px; }
.tile {
  background: #fff; border: 2px solid var(--line);
  padding: 12px 16px; font-size: 19px; min-height: var(--tap);
}
.tile:hover { border-color: var(--jee-primary); background: var(--jee-blue); }
.tile.used { opacity: .35; pointer-events: none; }
.answer-strip {
  min-height: 62px; background: #fff;
  border: 2px dashed var(--line); border-radius: 12px;
  padding: 12px; margin: 0 0 12px;
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
}
.answer-strip .tile { border-style: solid; border-color: var(--jee-primary); }

/* matching */
.match-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.match-col { display: flex; flex-direction: column; gap: 10px; }
.match-item {
  background: #fff; border: 2px solid var(--line);
  padding: 14px; font-size: 18px; text-align: left; min-height: var(--tap);
}
.match-item:hover { border-color: var(--jee-primary); }
.match-item.picked { border-color: var(--jee-primary); background: var(--jee-blue); }
.match-item.done { border-color: var(--ok); background: var(--ok-bg); opacity: .75; pointer-events: none; }
.match-item.wrong { border-color: var(--no); background: var(--no-bg); }

/* text input */
input[type="text"] {
  width: 100%; font: inherit; font-size: 20px;
  padding: 14px 16px; min-height: var(--tap);
  border: 2px solid var(--line); border-radius: 12px;
  background: #fff;
}
input[type="text"]:focus { outline: none; border-color: var(--jee-primary); }

/* ---------- audio ---------- */
.audio-btn {
  flex: 0 0 auto;
  width: var(--tap); height: var(--tap);
  border-radius: 50%;
  background: var(--jee-primary); color: #fff;
  border: none; font-size: 20px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
}
.audio-btn:hover { background: var(--jee-primary-dk); }
.audio-btn.playing { background: var(--jee-coral); }

/* ---------- vocab / dialogue ---------- */
.vocab-item { display: flex; gap: 14px; padding: 16px 0; border-bottom: 1px solid var(--line); }
.vocab-item:last-child { border-bottom: none; }
.vocab-body { flex: 1; }
.lemma { font-size: 22px; font-weight: 700; color: var(--jee-primary-dk); }
.example { font-style: italic; color: var(--ink-soft); font-size: 18px; }

/* Play the whole dialogue (2026-07-16). A primary-weight control: hearing the conversation
   run naturally is the point of the screen, so it sits above the card, not beside a line. */
.btn-playall {
  display: block; width: 100%;
  background: #fff; color: var(--jee-primary-dk);
  border: 2px solid var(--jee-primary); border-radius: var(--radius);
  font-size: 19px; font-weight: 700; line-height: 1.35;
  padding: 12px 18px; min-height: 60px; margin: 0 0 16px;
}
.btn-playall:hover { background: var(--jee-blue); }
.btn-playall.playing { background: var(--jee-coral); border-color: var(--jee-coral); color: #fff; }
.btn-playall .ja { font-size: 15px; font-weight: 400; }
.btn-playall.playing .ja { color: #fff; }

.line { display: flex; gap: 14px; padding: 14px 0; border-radius: 10px; transition: background .15s ease; }
/* The line currently being spoken, so an elderly reader can follow without hunting. */
.line.speaking { background: var(--jee-blue); }
.speaker {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 17px;
}
.speaker.A { background: var(--jee-blue); color: var(--jee-primary-dk); }
.speaker.B { background: var(--jee-pink); color: #8a4a49; }

/* ---------- feedback ---------- */
.feedback { border-radius: 12px; padding: 16px 18px; margin: 4px 0 16px; }
.feedback.right { background: var(--ok-bg); border: 2px solid var(--ok); }
.feedback.wrong { background: var(--no-bg); border: 2px solid var(--no); }
.feedback.info  { background: var(--jee-cream); border: 2px solid var(--jee-primary); }
.feedback .head { font-weight: 700; font-size: 20px; margin-bottom: 6px; }

/* ---------- top bar: Back + progress ---------- */
.topbar { display: flex; align-items: center; gap: 14px; margin: 14px 0 20px; }
.btn-back {
  flex: 0 0 auto;
  background: #fff; color: var(--jee-primary-dk);
  border: 2px solid var(--line);
  font-size: 17px; font-weight: 600;
  padding: 10px 16px; min-height: var(--tap);
}
.btn-back:hover { border-color: var(--jee-primary); background: var(--jee-blue); }

/* ---------- progress (gentle, no guilt) ---------- */
.progress { flex: 1; display: flex; align-items: center; gap: 12px; margin: 0; }
.progress .bar { flex: 1; height: 10px; background: #e8e0d5; border-radius: 6px; overflow: hidden; }
.progress .fill { height: 100%; background: var(--jee-primary); border-radius: 6px; transition: width .3s ease; }
.progress .txt { font-size: 16px; color: var(--ink-soft); white-space: nowrap; }

/* ---------- sticky action ---------- */
.actions {
  position: fixed; left: 0; right: 0; bottom: 0;
  background: linear-gradient(to top, var(--jee-cream) 70%, rgba(251,246,238,0));
  padding: 16px 20px 22px;
}
.actions-inner { max-width: 620px; margin: 0 auto; }

/* ---------- PIN sign-in (3.3) ----------
   A key surface, so the crest belongs here (see the brand note at the top). Keys are
   72px, well over the 48px floor: this is the screen an elderly student meets first. */
.signin { text-align: center; }
.signin .brandbar { justify-content: center; }
.signin input[type="text"] { text-align: center; max-width: 340px; margin: 0 auto; }

.pin-dots { display: flex; justify-content: center; gap: 14px; margin: 24px 0 26px; }
.pin-dot {
  width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid var(--jee-primary); background: #fff;
  transition: background .12s ease;
}
.pin-dot.filled { background: var(--jee-primary); }
.pin-dots.wrong .pin-dot { border-color: var(--no); }
.pin-dots.wrong { animation: pin-shake .35s; }
@keyframes pin-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-7px); }
  75% { transform: translateX(7px); }
}

.pin-pad {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;
  max-width: 340px; margin: 0 auto;
}
.pin-key {
  background: #fff; border: 2px solid var(--line); border-radius: var(--radius);
  font-size: 30px; font-weight: 700; color: var(--jee-primary-dk);
  min-height: 72px;
}
.pin-key:hover { border-color: var(--jee-primary); background: var(--jee-blue); }
.pin-key:active { background: var(--jee-blue); }
.pin-key.ghost { background: transparent; border-color: transparent; cursor: default; }
.pin-key.action { font-size: 26px; color: var(--ink-soft); }
.pin-msg { min-height: 56px; margin: 20px 0 8px; }

.badge {
  display: inline-block; background: var(--jee-blue); color: var(--jee-primary-dk);
  border-radius: 999px; padding: 5px 14px; font-size: 16px; font-weight: 700;
}
.pattern {
  background: var(--jee-cream); border: 2px solid var(--jee-primary);
  border-radius: 12px; padding: 14px 16px; margin: 0 0 14px;
  font-size: 21px; font-weight: 700; color: var(--jee-primary-dk);
}
/* pattern_ja (2026-07-19): a short Japanese gloss of the grammar FORM, beneath the English
   formula inside the pattern box, so an A1 beginner can parse the structure. Softer + lighter
   than the bold English so the hierarchy reads formula-first, meaning-second. */
.pattern-ja {
  display: block; margin-top: 10px;
  font-size: 17px; font-weight: 400; color: var(--ink-soft); line-height: 1.65;
}

/* ---------- THE PATH (S4.4 skin v2, 2026-07-31) ----------
   The Busuu reference silhouette (docs/reference/busuu-examples) in the JEE
   brand: NAKED rows — a big ringed circle + one bold title. No boxes, no
   locked-row lectures. Done = solid teal ring + ✓ badge; current = coral ring
   on a soft highlight pill with the only action words on screen; locked =
   quieter everything. Short dashes connect the circles; the header owns the
   progress bar with its % chip. Elderly-first: ≥48px taps, ≥16px text. */

.lvl-head { margin: 2px 0 18px; }
.lvl-head h1 { margin-bottom: 4px; }
.lvl-range { font-size: 18px; font-weight: 700; color: var(--ink-soft); margin-left: 8px; }
.lvl-bar {
  position: relative; height: 16px; margin-top: 12px;
  background: #eee7db; border-radius: 999px;
}
.lvl-fill {
  height: 100%; min-width: 16px; background: var(--jee-primary);
  border-radius: 999px; transition: width .4s ease;
}
.lvl-pct {
  position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  background: var(--jee-primary); color: #fff;
  font-size: 14px; font-weight: 700; line-height: 1;
  padding: 6px 10px; border-radius: 999px;
}

.bpath { display: flex; flex-direction: column; align-items: stretch; padding: 6px 0 24px; }

.bconn {
  width: 6px; height: 26px; border-radius: 3px;
  background: #e6dfd2; margin: 4px 0 4px 41px;
}
.bconn.on { background: var(--jee-primary); }

.brow {
  display: flex; align-items: center; gap: 18px;
  padding: 10px 12px; border-radius: 20px;
}
.brow[data-step] { cursor: pointer; }
.brow[data-step]:focus-visible { outline: 3px solid var(--jee-primary); outline-offset: 2px; }

.bnode {
  position: relative; flex: 0 0 auto;
  width: 88px; height: 88px; border-radius: 50%;
  background: #fff; border: 5px solid #e6dfd2;
  display: flex; align-items: center; justify-content: center;
}
.bnum { font-size: 30px; font-weight: 800; color: var(--ink-soft); }
.bbadge {
  position: absolute; bottom: -4px; right: -2px;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--jee-primary); color: #fff;
  border: 3px solid #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; font-weight: 700;
}
.btext { flex: 1; min-width: 0; }
.btitle { font-size: 21px; font-weight: 800; color: var(--ink); line-height: 1.35; }
.bmeta { font-size: 16px; color: var(--ink-soft); margin-top: 3px; }
.bstart { color: var(--jee-coral-dk); font-weight: 800; }
.breview { color: var(--jee-primary-dk); font-weight: 600; }

.brow.done .bnode { border-color: var(--jee-primary); }
.brow.done .bnum { color: var(--jee-primary-dk); }

.brow.now { background: var(--jee-blue); }
.brow.now .bnode {
  border-color: var(--jee-coral);
  animation: bnow 2.6s ease-in-out infinite;
}
.brow.now .bnum { color: var(--jee-coral-dk); }
.brow.now .btitle { color: var(--jee-primary-dk); }
@keyframes bnow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(226, 114, 91, .25); }
  50%      { box-shadow: 0 0 0 10px rgba(226, 114, 91, .12); }
}

.brow.locked { opacity: .55; }
.brow.locked .bnode { border-style: dashed; border-width: 4px; }

/* skin v3 (2026-07-31) — the audition-winning anime-film illustrations.
   The emblem fills the circle (the step number sits beneath as the
   no-art / failed-load fallback); the ✓ badge stays on top. */
.bemblem {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border-radius: 50%; object-fit: cover;
}
.brow.locked .bemblem { filter: grayscale(.85); opacity: .5; }
.hero-art {
  /* No fixed ratio: the heroes are drawn square and composed as a whole —
     cropping cut gestures mid-air (Aragorn, 2026-08-01). Full frame, always. */
  display: block; width: 100%;
  border-radius: 12px; margin-bottom: 14px;
}

/* ---------- speech speed (2026-08-01) — big thumb for elderly hands ---------- */
.speed-row {
  display: flex; align-items: center; gap: 10px;
  margin: 6px 0 14px; font-size: 15px; color: var(--ink-soft);
}
.speed-row label { font-weight: 700; white-space: nowrap; }
.speed-row input[type="range"] { flex: 1; min-width: 90px; accent-color: var(--jee-primary); height: 28px; }
.speed-row #spd-val { white-space: nowrap; min-width: 118px; text-align: right; }

/* ---------- the pass fanfare v2 (2026-08-01 — v1 was ruled lame) ---------- */
.fanfare { position: fixed; inset: 0; pointer-events: none; overflow: hidden; z-index: 50; transition: opacity 1.2s; }
.fanfare.out { opacity: 0; }
.fw { position: absolute; }
.fw i {
  position: absolute; width: 7px; height: 7px; border-radius: 50%;
  animation: fwfly 1.25s cubic-bezier(.1, .8, .4, 1) forwards;
}
@keyframes fwfly {
  0%   { transform: translate(0, 0) scale(1.4); opacity: 1; }
  70%  { opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)) scale(.4); opacity: 0; }
}
.cf {
  position: absolute; top: -22px; width: 10px; height: 15px; border-radius: 2px;
  animation-name: cfall; animation-timing-function: linear; animation-fill-mode: forwards;
}
@keyframes cfall {
  0%   { transform: translateY(0) rotate(0deg); opacity: 1; }
  100% { transform: translateY(114vh) rotate(560deg); opacity: .85; }
}
.balloon {
  position: absolute; bottom: -90px;
  border-radius: 50% 50% 50% 50% / 44% 44% 56% 56%;
  animation: bfloat 4.4s ease-in forwards;
}
.balloon::before {
  content: ""; position: absolute; left: 24%; top: 14%;
  width: 26%; height: 20%; border-radius: 50%;
  background: rgba(255, 255, 255, .4);
}
.balloon::after {
  content: ""; position: absolute; left: 50%; top: 100%;
  width: 2px; height: 46px; background: rgba(0, 0, 0, .16);
}
@keyframes bfloat {
  0%   { transform: translateY(0) translateX(0) rotate(-4deg); opacity: 1; }
  50%  { transform: translateY(-58vh) translateX(16px) rotate(4deg); opacity: 1; }
  100% { transform: translateY(-118vh) translateX(-10px) rotate(-3deg); opacity: .9; }
}
.trophy {
  position: absolute; left: 50%; top: 33%;
  transform: translate(-50%, -50%);
  text-align: center;
  animation: tpop 1s cubic-bezier(.2, 1.6, .4, 1) both; animation-delay: .4s;
}
.trophy .rays {
  position: absolute; left: 50%; top: 44%; z-index: -1;
  width: 240px; height: 240px; margin: -120px 0 0 -120px; border-radius: 50%;
  background: repeating-conic-gradient(rgba(217, 165, 63, .28) 0 9deg, transparent 9deg 24deg);
  -webkit-mask-image: radial-gradient(circle, #000 30%, transparent 70%);
  mask-image: radial-gradient(circle, #000 30%, transparent 70%);
  animation: rayspin 9s linear infinite;
}
@keyframes rayspin { to { transform: rotate(360deg); } }
.trophy .cup2 { width: 150px; height: 162px; filter: drop-shadow(0 10px 24px rgba(184, 134, 46, .45)); }
.trophy .ribbon {
  display: inline-block; margin-top: 6px; padding: 5px 18px;
  background: var(--jee-coral); color: #fff; font-weight: 800; font-size: 16px;
  border-radius: 999px; letter-spacing: .04em;
  box-shadow: 0 3px 10px rgba(226, 114, 91, .4);
}
@keyframes tpop {
  0%   { transform: translate(-50%, -50%) scale(.2); opacity: 0; }
  70%  { transform: translate(-50%, -50%) scale(1.1); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .balloon, .cf, .fw, .trophy .rays { display: none; }
  .trophy { animation: none; }
}

/* fanfare v3 — the pet celebration (teacher-droppable cast in assets/celebrate/) */
.pet-pop {
  position: absolute; left: 50%; top: 40%;
  transform: translate(-50%, -50%);
  text-align: center;
  animation: tpop .9s cubic-bezier(.2, 1.6, .4, 1) both; animation-delay: .25s;
}
.pet-img {
  width: 270px; max-width: 72vw;
  border-radius: 22px; border: 6px solid #fff;
  box-shadow: 0 12px 34px rgba(47, 125, 146, .35);
}
.bubble {
  position: relative; display: inline-block;
  background: #fff; color: var(--ink);
  font-size: 24px; font-weight: 800; line-height: 1.4;
  padding: 12px 22px; border-radius: 18px;
  border: 3px solid var(--jee-primary);
  margin-bottom: 16px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .12);
}
.bubble::after {
  content: ""; position: absolute; left: 50%; top: 100%; margin-left: -10px;
  border: 10px solid transparent; border-top-color: var(--jee-primary);
}
.pet-name { margin-top: 10px; font-size: 18px; font-weight: 700; color: var(--jee-primary-dk); }
@media (prefers-reduced-motion: reduce) { .pet-pop { animation: none; } }

/* fanfare v3 mode "full" — the cast-sheet panels (bubbles baked into the art)
   take the whole screen; entrance/exit drawn at random per pass. */
.pet-stage {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(251, 246, 238, .93);
}
.pet-card {
  max-width: 94vw; max-height: 86vh;
  border-radius: 18px; border: 6px solid #fff;
  box-shadow: 0 16px 44px rgba(47, 125, 146, .35);
}
.anim-fade { animation: stageFadeIn .8s ease both; }
.fanfare.out .anim-fade { animation: stageFadeOut 1s ease both; }
@keyframes stageFadeIn { from { opacity: 0; transform: scale(.93); } to { opacity: 1; transform: scale(1); } }
@keyframes stageFadeOut { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(.96); } }
.anim-rise { animation: stageRise .85s cubic-bezier(.2, 1.15, .4, 1) both; }
.fanfare.out .anim-rise { animation: stageSink .85s ease-in both; }
@keyframes stageRise { from { transform: translateY(110vh); } to { transform: translateY(0); } }
@keyframes stageSink { from { transform: translateY(0); } to { transform: translateY(112vh); } }
.anim-spin { animation: stageSpinIn .9s cubic-bezier(.2, 1.05, .4, 1) both; }
.fanfare.out .anim-spin { animation: stageSpinOut .9s ease-in both; }
@keyframes stageSpinIn { from { transform: rotate(-540deg) scale(.05); opacity: 0; } to { transform: rotate(0deg) scale(1); opacity: 1; } }
@keyframes stageSpinOut { from { transform: rotate(0deg) scale(1); opacity: 1; } to { transform: rotate(540deg) scale(.05); opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .pet-card { animation: none !important; }
}

/* ---------- the habits card (2026-08-01) — a rhythm, never a debt ---------- */
.habits { margin-top: 20px; }
.habits-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.habits-head .ja { font-size: 14px; color: var(--ink-soft); font-weight: 400; }
.habits-head .best { color: var(--jee-primary-dk); font-weight: 700; font-size: 15px; white-space: nowrap; }
.hgrid { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 10px; }
.hd { width: 16px; height: 16px; border-radius: 5px; background: #eee7d9; }
.hd.on { background: var(--jee-primary); }
.hd.today { outline: 2px solid var(--jee-coral); outline-offset: 1px; }

.sync-ok { color: var(--ok); font-weight: 700; }

/* ---------- speaking practice (2026-07-31) ---------- */
.speak-line {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 0; border-bottom: 1px solid var(--line);
}
.speak-line:last-child { border-bottom: none; }
.speak-controls { display: flex; gap: 10px; align-items: center; flex: 0 0 auto; }
.rec-btn {
  width: var(--tap); height: var(--tap); border-radius: 50%;
  background: #fff; border: 3px solid var(--no); color: var(--no);
  font-size: 22px; line-height: 1;
}
.rec-btn.recording {
  background: var(--no); color: #fff;
  animation: rec-pulse 1.2s ease-in-out infinite;
}
@keyframes rec-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(179, 64, 44, .3); }
  50%      { box-shadow: 0 0 0 8px rgba(179, 64, 44, .15); }
}
.you-btn { position: relative; }
.you-btn .you-tag {
  position: absolute; bottom: -4px; right: -4px;
  font-size: 10px; font-weight: 700; color: var(--jee-primary-dk);
  background: var(--jee-blue); border-radius: 6px; padding: 0 4px;
}
.you-btn:disabled { opacity: .35; }

/* Speaking Layer 2 (2026-08-05). The assessed attempt is a BLANK CANVAS: the English and
   the Japanese both go, so the student produces the line rather than reading it, and
   rather than translating it in their head. The opt-in reads as a quiet offer, never a
   demand — being assessed is something they choose. */
/* The check button takes the CTA's exact FORM (full width, 24px, 60px tall) in a soft
   green — Aragorn 2026-08-05. It must never be coral or red: coral is the lesson CTA and
   red is "recording now", and an elderly student must never confuse "start being checked"
   with "start recording". The first version of this was a quiet underlined text link at
   the bottom edge of the screen and he simply never saw it. */
.btn-check {
  display: block; width: 100%;
  background: var(--check); color: #fff;
  font-size: 24px; font-weight: 700;
  padding: 16px 20px; min-height: 60px;
  border: none;
}
.btn-check:hover { background: var(--check-dk); }
/* Recording: the app's own red, the same colour the practice record button uses, so
   "this is recording right now" reads identically wherever you meet it. */
.btn-check.recording { background: var(--no); }
.btn-check.recording:hover { background: var(--no); }
.btn-check:disabled { background: #cfcac3; cursor: not-allowed; }
/* The build stamp: enough for Aragorn to read at a glance on a phone, small and quiet
   enough that a student never wonders what it means. */
.build-stamp { text-align: right; color: #a9a29a; font-size: 12px; margin: 14px 0 0;
               letter-spacing: .04em; }

.speak-checkcard { border: 2px solid var(--check); background: var(--check-bg); }
.speak-checkcard .head { font-weight: 700; font-size: 20px; margin-bottom: 6px; }
@media (prefers-reduced-motion: reduce) { .rec-btn.recording { animation: none; } }

@media (prefers-reduced-motion: reduce) {
  .brow.now .bnode { animation: none; }
  .lvl-fill { transition: none; }
}

/* ---------- the reading layer (2026-08-05) ----------
   The shelf is the ruled Ghibli-B skin, same as the lesson art. The readable book sits
   FACE-OUT (its real cover) because rotated spine text is a genuine legibility problem
   at a 20px floor; spines are for the LOCKED books, where they are decoration and nobody
   needs to read them. Teal is the reading CTA — coral is the lesson, green the speaking
   check — so the palette says what each action is. */
.btn-read {
  display: block; width: 100%;
  background: var(--jee-primary); color: #fff;
  font-size: 24px; font-weight: 700;
  padding: 16px 20px; min-height: 60px;
  border: none;
}
.btn-read:hover { background: var(--jee-primary-dk); }
.btn-read:disabled { background: #cfcac3; cursor: not-allowed; }

.shelf { margin: 6px 0 4px; }
/* The board is the Ghibli-B illustration itself (same locked charter as the lesson art).
   If it ever fails to load the cream fallback still reads as a shelf, so the screen is
   never broken by a missing image — the same law as the lesson hero art. */
/* One book, centred, sitting on the shelf rather than pasted across its upright. With
   the placeholder spines gone the board is a backdrop, so the composition is simply
   "a book displayed on a shelf" — which is honest while there is one book, and still
   right when there are four. */
.shelf-board {
  position: relative; display: flex; align-items: flex-end; justify-content: center;
  gap: 14px; flex-wrap: wrap;
  min-height: 250px; padding: 34px 18px 30px; border-radius: var(--radius);
  background: var(--jee-cream) url('../assets/books/shelf.jpg') center 46% / cover no-repeat;
  border: 1px solid var(--line);
}

.book-face {
  padding: 0; border: 0; background: none; cursor: pointer; position: relative;
  flex: 0 0 auto; width: 148px; min-height: 0;
  transition: transform .22s ease, filter .22s ease;
}
.book-face img { width: 100%; border-radius: 4px; display: block;
  box-shadow: 0 6px 14px rgba(0,0,0,.28); }
.book-face:hover { transform: translateY(-4px); }
.book-face.popping { transform: translateY(-10px) scale(1.04); filter: brightness(1.03); }
/* the bookmark ribbon: the emotional payoff — it shows how far in they are */
.book-ribbon { position: absolute; right: 12px; top: 0; width: 10px; height: 34px;
  background: var(--jee-coral); border-radius: 0 0 3px 3px;
  box-shadow: 0 2px 3px rgba(0,0,0,.25); }

/* Title, then Author, then the name on its own line — Raymond wrote all twenty by hand
   and his name is not a footnote. .book-author is the hook for the link to his website
   when it lands: styling it here means that change is one line of markup, not a relayout. */
.shelf-title { margin: 10px 2px 0; }
.book-name { display: block; font-size: 22px; line-height: 1.3; color: var(--ink); }
.book-authorlabel { display: block; margin-top: 10px; font-size: 15px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--ink-soft); }
/* His name is set LARGER than the book's own metadata and close to the title's weight —
   Aragorn, 2026-08-05: "bigger font for his name". */
.book-author { display: block; font-size: 24px; font-weight: 700; line-height: 1.3;
  color: var(--jee-primary-dk); margin-top: 2px; }
a.book-author { text-decoration: underline; }          /* ready for the website link */
.book-meta { display: block; margin-top: 8px; }

/* ── the reader ── */
.reader-top { display: flex; align-items: center; justify-content: space-between; padding-top: 6px; }
.reader-size button { background: #fff; border: 1px solid var(--line); border-radius: 8px;
  min-height: 40px; min-width: 46px; margin-left: 6px; font-size: 17px; font-weight: 700;
  color: var(--jee-primary-dk); }
/* the timer is KEPT QUIET: a hairline that fills, never a ticking number. Numerals appear
   only in the finish card, where they help rather than nag. */
.read-track { height: 3px; background: var(--line); border-radius: 2px; margin: 10px 0 4px; }
.read-fill { height: 3px; width: 0; background: var(--jee-primary); border-radius: 2px;
  transition: width .4s linear; }
/* ── narration (2026-08-06) ──────────────────────────────────────────────────
   The highlight IS the feature, not decoration on the audio: it is what lets a
   student SHADOW the reading. One file per paragraph is what makes it exact, so
   the styling can afford to be plain and certain rather than clever. */
.read-listen-row {
  display: flex; align-items: center; gap: 12px;
  flex-wrap: wrap; margin: 4px 0 10px;
}
.btn-listen {
  background: var(--jee-primary); color: #fff;
  font-size: 20px; font-weight: 700;
  padding: 12px 22px; min-height: 52px;      /* thumb-sized: the audience is elderly */
  border: none; border-radius: 8px; white-space: nowrap;
}
.btn-listen:hover { background: var(--jee-primary-dk); }
.btn-listen.playing { background: #b4462f; }  /* stop reads as stop, never as another play */
/* ⚠ .ja is ink-soft by default, which on a coloured button is dark-on-dark — the
   Japanese label was very nearly invisible on the red Stop state. The Japanese is
   not decoration here: for several of these students it is the label they read. */
.btn-listen .ja { color: #fff; font-size: 17px; }
.read-listen-row .speed-row { flex: 1; min-width: 210px; margin: 0; }

/* A warm band behind the line being spoken. Deliberately a background rather than
   a colour change: at 21px, recolouring the text hurts legibility for exactly the
   readers who need the narration most. */
.reader-prose .speaking {
  background: #fdf0c9;
  box-shadow: 0 0 0 6px #fdf0c9;             /* pads the band without moving the text */
  border-radius: 3px;
}
/* Only hint at tappability when there is actually something to hear. */
.reader-prose.has-audio p, .reader-prose.has-audio h2 { cursor: pointer; }

.reader-prose { line-height: 1.85; padding: 6px 0 10px; }
.reader-prose p { margin: 0 0 1.05em; }
.reader-prose h2 { font-size: 24px; margin: 4px 0 .8em; }
.reader-img { width: 100%; border-radius: 10px; display: block; margin: 4px 0 14px; }
/* a SLIM nav bar: the 60px lesson CTA would cost ~50px of story on a small phone */
.reader-nav { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.rnav { flex: 0 0 84px; min-height: 48px; font-size: 22px; background: #fff;
  border: 1px solid var(--line); border-radius: 10px; color: var(--jee-primary-dk); }
.rnav:disabled { opacity: .3; }
.rpage { font-size: 16px; color: var(--ink-soft); }

@media (prefers-reduced-motion: reduce) {
  .book-face, .book-face.popping { transition: none; transform: none; }
  .read-fill { transition: none; }
}

/* The speaking practice room banner (Mitsuyo's ruling, 2026-08-05). The sentences are a
   ROOM you practise in, and the check sits at the bottom for when you are ready — the
   earlier order read as a test with some practice attached, which is backwards. Calm and
   welcoming, never a heading that looks like an instruction. */
.room-banner {
  display: block; background: var(--jee-blue); border-radius: var(--radius);
  padding: 12px 18px; margin: 0 0 12px; border: 1px solid #bcdae4;
}
.room-title { display: block; font-size: 21px; font-weight: 700; color: var(--jee-primary-dk); }
.room-banner .ja { display: block; font-size: 16px; }
/* The notes are Japanese-ONLY now (Aragorn 2026-08-05: an explanation does not need
   saying twice). So .ja must not shrink them — when Japanese is the only text there is,
   it IS the body copy and sits at the small-text floor, not below it. */
.room-note { display: block; font-size: 16px; color: var(--ink-soft); margin-top: 6px;
             line-height: 1.7; }
.room-note.ja { font-size: 16px; }
/* The signpost to the check. Mitsuyo put the check at the BOTTOM, which only works if the
   room says it is down there — otherwise it is the invisible-button problem relocated.
   The arrow is drawn in CSS so it never depends on an emoji font. */
.room-down { font-weight: 600; color: var(--jee-primary-dk); }
.room-down::before { content: '\2193'; margin-right: 6px; font-weight: 700; }

/* The reading gate on the path. A KEY, NOT A PADLOCK — ruled 2026-08-03: missing a day
   never takes anything away, the gate simply waits. So a waiting row is quieter than the
   current step but still TAPPABLE (it goes to the shelf), and there is no red anywhere. */
.read-card { border-left: 6px solid var(--jee-primary); }
.read-card.done { border-left-color: var(--ok); background: var(--ok-bg); }
.read-card p { margin: 0 0 6px; }
.read-card .btn-secondary { margin-top: 8px; }
/* ⚠ A WAITING ROW MUST NOT WEAR THE DONE RING (fixed 2026-08-06, found by Aragorn on
   his phone: "somehow all the lesson icons are now showing as completed even though I
   hadn't finished them all").

   The first version gave `waiting` the SAME `--jee-primary` ring as `done`, differing
   only by 15% opacity and a pale fill that the emblem then covers. The solid teal ring
   IS the completion signal in this app — so with the gate closed, an entire path of
   untouched lessons read as finished. Nobody had seen it before because it needs
   several waiting rows at once, which only happens on a day with no reading yet.

   THE RULE: the solid teal ring belongs to `done` and nothing else. A waiting row keeps
   the NEUTRAL ring of an untouched node, and says what it is waiting for with a teal
   left edge tying it to the reading CTA — a key, not a padlock. Never red, never
   "locked", and never the tick. */
.brow.waiting { opacity: .95; border-left: 6px solid var(--jee-primary); border-radius: 8px 20px 20px 8px; }
.brow.waiting .bnode { border-color: #e6dfd2; background: var(--jee-blue); }
.bwait { color: var(--jee-primary-dk); font-weight: 600; }
/* End of the book. The book's OWN questions, warm feedback, NO score and NO total —
   "enough to be sure they read it, NOT tested" (ruled 2026-08-03). The answer is always
   revealed, so a wrong tap still teaches rather than just marking. */
.bookq { padding: 6px 0 2px; border-top: 1px solid var(--line); margin-top: 14px; }
.bookq:first-of-type { border-top: none; margin-top: 4px; }
.bookq .choice { font-size: 18px; padding: 12px 16px; margin-bottom: 8px; }
.bookq-fb:empty { display: none; }
.rnav-end { flex: 0 0 auto; padding: 0 16px; font-size: 17px; font-weight: 700; }
