/* ============================================================
   Ellie — English Speaking Buddy
   Colours come from the workspace design system (css skill),
   screen-surface mode. Do not hand-pick new hexes here.
   brand-900 #0F2B58 · brand-800 #1B3B70 · brand-700 #315592
   brand-400 #84A9E5 · brand-100 #E3EEFF · brand-50 #F2F7FF
   gold-400  #C9A227 · gold-300 #DEBF6C · gold-100 #F9ECCB
   grey-100  #EBEDEF · grey-400 #A4A8AE · grey-800 #3E4147
   green-400 #6EBD7D · red-500 #E8504E · amber-300 #ECB963
   ============================================================ */

:root {
  --brand-900:#0F2B58; --brand-800:#1B3B70; --brand-700:#315592;
  --brand-600:#486FB1; --brand-400:#84A9E5; --brand-200:#C6DCFF;
  --brand-100:#E3EEFF; --brand-50:#F2F7FF;
  --gold-400:#C9A227; --gold-300:#DEBF6C; --gold-100:#F9ECCB;
  --grey-100:#EBEDEF; --grey-400:#A4A8AE; --grey-800:#3E4147;
  --green-400:#6EBD7D; --red-500:#E8504E; --amber-300:#ECB963;

  --ink:#F2F7FF;
  --ink-dim:#A6C4F5;
  --sheet-bg:#FFFFFF;
  --radius:8px;

  --font-ui:"Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", Arial, sans-serif;

  --room: url("data:image/jpeg;base64,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MEFDBdHQMF0dAwQAwQBXR0uhA+n1PR0FdHU9HQV0dT0dBXR1PR0FdHU9HQV0dT0dA+gujoAEAAHSAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAACoFAAAIAAAAAAMjUAAAABAdMgBjpAAAAAAAABQAAAAEAAAB9IAYIAYIAYIAYIAYIAOjoADo6AB9HSAH0dIAfR0gB9HSAH0dIAOjoAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAFQYQIGAIGAIGAIwFAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//2Q==");

  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);
}

* { box-sizing:border-box; -webkit-tap-highlight-color:transparent; }

html, body {
  margin:0; padding:0; height:100%;
  overflow:hidden;
  font-family:var(--font-ui);
  color:var(--ink);
  background:#140D09;
  overscroll-behavior:none;
}

#app {
  position:fixed; inset:0;
  display:grid;
  grid-template-rows:auto auto 1fr;   /* topbar · modebar · stage — the rest are implicit auto */
  /* Scrim first, photo second, brand gradient last as the fallback ground.
     The scrim is not decoration: it is what keeps white captions legible
     over the photo's bright window and monitors. */
  background:
    linear-gradient(180deg,
      rgba(18,12,9,.30) 0%,
      rgba(18,12,9,.06) 30%,
      rgba(18,12,9,.30) 60%,
      rgba(18,12,9,.88) 84%,
      rgba(18,12,9,.99) 100%),
    var(--room) center/cover no-repeat,
    radial-gradient(120% 70% at 50% 28%, #3A2A1E 0%, #241811 44%, #140D09 80%);
  padding-top:var(--safe-t);
  padding-bottom:var(--safe-b);
}

/* ---------------- top bar ---------------- */
#topbar {
  display:flex; align-items:center; gap:8px;
  padding:10px 14px 4px;
}
.spacer { flex:1; }

.chip {
  display:inline-flex; align-items:center; gap:6px;
  background:rgba(255,255,255,.10);
  border:1px solid rgba(198,220,255,.22);
  color:var(--brand-100);
  font-family:inherit; font-size:14px; font-weight:600;
  padding:7px 12px; border-radius:999px; cursor:pointer;
}
.chip:active { background:rgba(255,255,255,.18); }
.chev { width:15px; height:15px; fill:none; stroke:currentColor; stroke-width:2.4;
        stroke-linecap:round; stroke-linejoin:round; }

.icon-btn {
  width:40px; height:40px; display:grid; place-items:center;
  background:transparent; border:0; cursor:pointer; color:var(--brand-200);
}
.icon-btn svg { width:21px; height:21px; fill:none; stroke:currentColor;
                stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round; }

/* ---------------- stage / Ellie ---------------- */
#stage { position:relative; display:grid; place-items:center; min-height:0; }
/* the lesson sheet covers the lower half of the stage, so she moves up
   to keep her eyes and mouth above it */
body.lesson #charwrap { transform-origin:50% 20%; }
body.lesson #stage    { align-items:start; padding-top:1.5vh; }

#aura {
  position:absolute; pointer-events:none; width:min(78vw, 340px); aspect-ratio:1;
  border-radius:50%;
  background:radial-gradient(circle, rgba(222,191,108,.28) 0%, rgba(201,162,39,.10) 45%, transparent 70%);
  filter:blur(6px);
  transition:transform .5s ease, opacity .5s ease;
  opacity:.85;
}
body.state-listening #aura { transform:scale(1.16); opacity:1;
  background:radial-gradient(circle, rgba(110,189,125,.30) 0%, rgba(110,189,125,.10) 48%, transparent 72%); }
body.state-speaking  #aura { transform:scale(1.08); }
body.state-thinking  #aura { opacity:.5; }

#ellie {
  height:100%; width:auto;
  max-width:min(96vw, 430px);
  display:block;
  cursor:grab;
  touch-action:none;              /* the character owns the drag gesture */
  filter:drop-shadow(0 18px 26px rgba(0,0,0,.38));
  outline:none;
}
#ellie:active { cursor:grabbing; }
#ellie:focus-visible { outline:2px solid var(--gold-300); outline-offset:4px; border-radius:12px; }

/* ---------------- poke speech bubble ---------------- */
#bubble {
  position:absolute; top:6px; left:50%;
  transform:translate(-50%, -6px) scale(.9);
  max-width:min(78vw, 320px);
  padding:9px 15px; border-radius:16px;
  background:#FFFFFF; color:var(--brand-800);
  font-size:15px; font-weight:600; line-height:1.35;
  box-shadow:0 6px 18px rgba(15,43,88,.35);
  opacity:0; pointer-events:none; z-index:5;
  transition:opacity .18s ease, transform .22s cubic-bezier(.2,1.5,.4,1);
}
#bubble[hidden] { display:none; }
#bubble.show { opacity:1; transform:translate(-50%, 0) scale(1); }
#bubble::after {
  content:""; position:absolute; bottom:-7px; left:50%;
  width:14px; height:14px; margin-left:-7px;
  background:#FFFFFF; transform:rotate(45deg);
  border-radius:0 0 3px 0;
}

/* ---------------- captions ---------------- */
#captions {
  padding:2px 22px 6px;
  background:linear-gradient(180deg, rgba(18,12,9,0) 0%, rgba(18,12,9,.70) 42%, rgba(18,12,9,.90) 100%);
  min-height:84px;
  display:flex; flex-direction:column; justify-content:flex-end;
  gap:4px; text-align:center;
}
/* `hidden` is only display:none at the weakest specificity, and the rule
   above sets display:flex — so the caption block kept its 84 px even when
   hidden, stealing that height from Ellie in both drill and lesson mode. */
#captions[hidden] { display:none; }

.cap { margin:0; line-height:1.42; }
.cap:empty { display:none; }

.cap-ellie {
  font-size:clamp(16px, 4.4vw, 19px); font-weight:600; color:#FFFFFF;
  text-shadow:0 1px 8px rgba(0,0,0,.35);
}
.cap-ellie .vi { display:block; font-size:13px; font-weight:400;
                 color:var(--brand-200); opacity:.8; margin-top:2px; }
.cap-you {
  font-size:14px; color:var(--brand-200); opacity:.9; font-style:italic;
}
.cap-you.interim { opacity:.55; }
.cap-tip {
  font-size:13px; color:var(--gold-300);
  background:rgba(201,162,39,.12);
  border:1px solid rgba(222,191,108,.28);
  border-radius:var(--radius); padding:6px 10px; margin-top:4px;
}

body.no-captions #cap-ellie, body.no-captions #cap-you { display:none; }

/* ---------------- controls ---------------- */
#controls {
  display:flex; align-items:center; justify-content:center; gap:26px;
  padding:6px 20px 2px;
}

.side-btn {
  width:62px; background:transparent; border:0; cursor:pointer;
  color:var(--brand-200); font-family:inherit; font-size:11px;
  display:flex; flex-direction:column; align-items:center; gap:4px;
  opacity:.85;
}
.side-btn svg { width:22px; height:22px; fill:none; stroke:currentColor;
                stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
.side-btn:active { opacity:1; }
.side-btn[disabled] { opacity:.3; }

/* Which language the microphone is listening for. The recogniser handles
   one at a time and cannot detect, so this has to be his choice, one tap,
   where his thumb already is. */
.lang-btn b {
  display:grid; place-items:center;
  width:22px; height:22px; border-radius:6px;
  font-size:11px; font-weight:800; letter-spacing:.02em;
  background:rgba(201,162,39,.22); color:var(--gold-300);
  border:1px solid rgba(222,191,108,.4);
}
.lang-btn.en b { background:rgba(132,169,229,.22); color:var(--brand-200);
                 border-color:rgba(198,220,255,.4); }
#controls { gap:18px; }

.mic {
  position:relative; width:84px; height:84px; border-radius:50%;
  border:0; cursor:pointer;
  background:linear-gradient(160deg, var(--gold-300), var(--gold-400));
  color:#3D2800;
  display:grid; place-items:center;
  box-shadow:0 8px 22px rgba(201,162,39,.38), 0 2px 0 rgba(255,255,255,.35) inset;
  transition:transform .12s ease, background .25s ease;
  flex:none;
}
.mic:active { transform:scale(.94); }
.mic svg { width:34px; height:34px; fill:none; stroke:currentColor;
           stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
.mic .stop-ico { display:none; fill:currentColor; stroke:none; }

body.state-listening .mic {
  background:linear-gradient(160deg, #97D4A1, var(--green-400));
  color:#00501E;
  box-shadow:0 8px 22px rgba(110,189,125,.42), 0 2px 0 rgba(255,255,255,.35) inset;
}
body.state-listening .mic .mic-ico { display:none; }
body.state-listening .mic .stop-ico { display:block; }

body.state-speaking .mic, body.state-thinking .mic { opacity:.45; pointer-events:none; }

.mic-ring {
  position:absolute; inset:0; border-radius:50%;
  border:2px solid var(--green-400); opacity:0;
}
body.state-listening .mic-ring.r1 { animation:pulse 1.9s ease-out infinite; }
body.state-listening .mic-ring.r2 { animation:pulse 1.9s ease-out .95s infinite; }
@keyframes pulse {
  0%   { transform:scale(1);    opacity:.7; }
  100% { transform:scale(1.85); opacity:0; }
}

#hint {
  margin:0; padding:2px 20px 12px; text-align:center;
  font-size:12px; color:var(--brand-400); min-height:18px;
}

/* ---------------- type bar ---------------- */
#typebar {
  position:fixed; left:0; right:0; bottom:0; z-index:40;
  display:flex; gap:8px; padding:10px 12px calc(10px + var(--safe-b));
  background:#140D09; border-top:1px solid rgba(255,225,190,.14);
}
#typebar[hidden] { display:none; }
#type-input {
  flex:1; font-family:inherit; font-size:16px;
  padding:12px 14px; border-radius:var(--radius);
  border:1px solid rgba(198,220,255,.28);
  background:rgba(255,255,255,.06); color:#fff;
}
#type-input::placeholder { color:var(--brand-400); }
#type-send {
  width:48px; border:0; border-radius:var(--radius); cursor:pointer;
  background:var(--gold-400); color:#3D2800; display:grid; place-items:center;
}
#type-send svg { width:22px; height:22px; fill:currentColor; }

/* ---------------- sheets ---------------- */
#scrim {
  position:fixed; inset:0; z-index:50;
  background:rgba(15,43,88,.62); backdrop-filter:blur(2px);
}
#scrim[hidden] { display:none; }

.sheet {
  position:fixed; left:0; right:0; bottom:0; z-index:60;
  max-height:86vh; overflow-y:auto;
  background:var(--sheet-bg); color:var(--grey-800);
  border-radius:18px 18px 0 0;
  padding:8px 20px calc(26px + var(--safe-b));
  box-shadow:0 -6px 24px rgba(15,43,88,.35);
  animation:slideUp .22s ease-out;
}
.sheet[hidden] { display:none; }
@keyframes slideUp { from { transform:translateY(100%); } to { transform:translateY(0); } }

.sheet-grip {
  width:40px; height:4px; border-radius:2px; background:var(--grey-100);
  margin:6px auto 12px;
}
.sheet h2 { font-size:17px; margin:0 0 14px; color:var(--brand-800); }
.sheet h3 { font-size:15px; margin:16px 0 6px; color:var(--brand-800);
            display:flex; align-items:center; gap:8px; }
.sheet hr { border:0; border-top:1px solid var(--grey-100); margin:18px 0 6px; }

.badge-opt {
  font-size:11px; font-weight:600; padding:2px 8px; border-radius:999px;
  background:var(--grey-100); color:var(--grey-800);
}

.note { font-size:12.5px; line-height:1.5; color:var(--grey-800); opacity:.8; margin:0 0 10px; }
.note.small { font-size:11px; margin-top:14px; }

.row {
  display:flex; align-items:center; justify-content:space-between; gap:14px;
  padding:11px 0; font-size:14px; border-bottom:1px solid var(--grey-100);
}
.row:last-of-type { border-bottom:0; }
.row small { color:var(--grey-400); font-size:11.5px; font-weight:400; }
.row.btn-row { justify-content:flex-start; border-bottom:0; }
.switch-row span { flex:1; }

.row select, .row input[type=password], .row input[type=text] {
  font-family:inherit; font-size:14px; padding:9px 11px;
  border:1px solid var(--grey-100); border-radius:var(--radius);
  background:var(--brand-50); color:var(--grey-800);
  max-width:56%;
}
.row input[type=range] { width:46%; accent-color:var(--brand-600); }

.switch {
  appearance:none; -webkit-appearance:none;
  width:46px; height:27px; border-radius:999px; background:var(--grey-100);
  position:relative; cursor:pointer; flex:none; transition:background .18s;
}
.switch::after {
  content:""; position:absolute; top:3px; left:3px; width:21px; height:21px;
  border-radius:50%; background:#fff; box-shadow:0 1px 3px rgba(0,0,0,.28);
  transition:transform .18s;
}
.switch:checked { background:var(--brand-600); }
.switch:checked::after { transform:translateX(19px); }

.ghost-btn {
  font-family:inherit; font-size:13.5px; font-weight:600;
  padding:9px 16px; border-radius:var(--radius); cursor:pointer;
  background:var(--brand-50); color:var(--brand-800);
  border:1px solid var(--brand-100);
}
.ghost-btn.danger { color:#7F0010; background:#FFF4F3; border-color:#FFE6E4; }
.key-status { font-size:12.5px; margin-left:10px; }
.key-status.ok  { color:#00692A; }
.key-status.bad { color:#A4071A; }

/* ---------------- topic list ---------------- */
.topic-list { display:grid; gap:9px; }
.topic {
  display:flex; align-items:center; gap:12px; text-align:left;
  padding:13px 14px; border-radius:var(--radius); cursor:pointer;
  background:var(--brand-50); border:1px solid var(--brand-100);
  font-family:inherit; color:var(--grey-800);
}
.topic.active { background:var(--brand-100); border-color:var(--brand-400); }
.topic .emo { font-size:22px; flex:none; }
.topic b { display:block; font-size:14.5px; color:var(--brand-800); }
.topic small { display:block; font-size:11.5px; color:var(--grey-400); margin-top:2px; }

/* ---------------- reduced motion ---------------- */
@media (prefers-reduced-motion:reduce) {
  #aura, .mic-ring, .sheet { animation:none !important; transition:none !important; }
}

/* short screens */
@media (max-height:680px) {
  #ellie { max-width:min(74vw, 320px); }
  #captions { min-height:66px; }
  .mic { width:74px; height:74px; }
}

/* ---------------- keyboard focus ---------------- */
:focus-visible {
  outline:2px solid var(--gold-300);
  outline-offset:3px;
  border-radius:4px;
}
.sheet :focus-visible { outline-color:var(--brand-600); }

/* ============================================================
   Photo character
   ============================================================ */
#stage { overflow:hidden; touch-action:none; }

#ambient {
  position:absolute; inset:-4%;
  background:var(--room) center/cover no-repeat;
  filter:blur(18px) brightness(.55) saturate(.9);
  transform:scale(1.06);
  will-change:transform;
  pointer-events:none;
}
#stage::after {                       /* vignette keeps the eye on her face */
  content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(72% 55% at 50% 38%, transparent 40%, rgba(12,8,5,.62) 100%);
}

#charwrap {
  position:relative;
  /* aspect-ratio keeps the box exactly the shape of the portrait, so the
     percentage-positioned touch zones stay glued to her face at any size.
     height + max-width together mean she can never overflow the stage —
     on a wide desktop the height caps her, on a narrow phone the width does. */
  /* size is set in JS (fitCharacter) — a percentage height inside a grid
     item resolves against an indefinite track and silently overflows */
  display:block;
  will-change:transform;
  transform-origin:50% 32%;
  cursor:grab;
}
#charwrap:active { cursor:grabbing; }

#char {
  width:100%; height:100%;
  /* The feather is baked into the PNG/WebP alpha, not done here: a CSS
     radial mask never reached zero inside the box, so the portrait still
     read as a pasted rectangle, and mask-composite support is uneven. */
  display:block;
  object-fit:contain; object-position:center top;
  -webkit-user-drag:none; user-select:none;
  filter:drop-shadow(0 22px 40px rgba(0,0,0,.55));
}

/* ============================================================
   Face rig
   ------------------------------------------------------------
   Every measurement below is a percentage of the 880 x 984 photo,
   so the rig scales with #charwrap and never drifts off her face.

     jaw     x 280-640   y 566-828   (lip seam down through the chin)
     lid-L   x 318-434   y 326-352   (skin between brow and lash)
     lid-R   x 496-608   y 324-350
     cavity  x 384-536   y 566-618   (drawn behind the jaw)

   The jaw layer holds the same pixels that sit under it, so at rest
   it is invisible. Translate it down and the mouth opens, revealing
   the cavity behind. The lids are thin strips of eyelid skin that
   stretch downward to close the eye — real skin, real colour, so a
   blink reads as a blink and not as a grey box.
   ============================================================ */
.patch {
  position:absolute; overflow:hidden; pointer-events:none;
  will-change:transform; backface-visibility:hidden;
}
.patch img {
  position:absolute; display:block; max-width:none;
  -webkit-user-drag:none; user-select:none;
}

#jaw {
  /* x 358-562, y 564-700 — the mouth and the chin under it, nothing more.
     A wider patch showed a straight seam across both cheeks the moment it
     moved: the mask has to fall to zero INSIDE the box, and a big box
     cannot do that without also killing the motion at the lips. */
  /* Measured, not guessed: sampling the photo row by row puts the dark line
     between her lips at y 564-570, darkest at 567. The old patch started at
     564, so it carried that line down with it and the open mouth showed a
     stripe through the middle — the thing that looked wrong. It now starts
     at 571, below the line entirely, and the cavity behind covers where the
     line used to be. Speaking makes the line disappear, which is what a real
     mouth does. */
  left:40.682%; top:58.028%; width:23.182%; height:13.110%;
  transform-origin:50% 0%;
  /* The opaque core is deliberately tiny — about the middle third of the
     lip. Wider than that and the whole lip line drops as one rigid bar,
     which reads as a split lip rather than a mouth. Real lips stay joined
     at the corners and part in the middle, so the mask has to fall away
     steeply on both sides. */
  /* The core used to sit at 4% from the top — right on the box's own edge —
     so that edge stayed opaque and appeared as a straight cut across the
     lip the moment the patch moved. Pulled down and softened: the lip is
     still the strongest part, but nothing is opaque where the box ends. */
  -webkit-mask-image:radial-gradient(ellipse 42% 86% at 50% 16%, #000 0%, rgba(0,0,0,0) 100%);
          mask-image:radial-gradient(ellipse 42% 86% at 50% 16%, #000 0%, rgba(0,0,0,0) 100%);
}
#jaw img { width:431.373%; left:-175.490%; height:762.791%; top:-442.636%; }

#mouthcav {
  position:absolute; pointer-events:none;
  /* Only as tall as the widest opening. It used to be 49 px tall, and since
     the jaw mask is opaque over just a small core, the rest of the cavity
     showed straight through it — a dark smear over her lower lip. */
  /* The opening can never read as wider than the dark area behind it, and
     at 1.829% that area was 9 px tall on a phone while the lip itself
     slides about the same — so the lip ran out of shadow the moment it
     moved and an open mouth looked like a closed one. The mouth is about
     74 px wide at that size; a real one opens roughly a third of its
     width, so the cavity is now tall enough to allow that. */
  left:43.636%; top:57.215%; width:17.273%; height:3.050%;
  transform-origin:50% 0%;        /* it opens downward, from the lip seam */
  /* A mouth does not open onto teeth. It opens onto the shadow under the
     upper lip first; the teeth only appear once it is properly open, and
     they are never white. Getting this order wrong made her grimace. */
  /* No teeth. At the size this face is actually drawn — her mouth is about
     60 px wide on a phone — a tooth highlight reads as a grey stripe and
     turns a smile into a grimace. A warm dark opening reads as speech and
     survives every screen size. */
  background:linear-gradient(180deg,
    rgba(64,30,26,.92) 0%,
    rgba(43,19,17,1)   38%,
    rgba(52,24,21,.78) 78%,
    rgba(90,44,40,0)   100%);   /* fades into the lower lip, no hard bottom */
  /* lens-shaped, tapering to nothing at the mouth corners */
  /* Centred, and reaching nothing before every edge. It used to be anchored
     at 10% from the top with a 108% radius, which left the top edge fully
     opaque — a dead straight dark line ruled across her lower lip. */
  -webkit-mask-image:radial-gradient(ellipse 46% 46% at 50% 50%, #000 12%, rgba(0,0,0,0) 100%);
          mask-image:radial-gradient(ellipse 46% 46% at 50% 50%, #000 12%, rgba(0,0,0,0) 100%);
  opacity:0;
}

/* ---- eyebrows ----
   The single most expressive thing on a face, and the rig did not have
   them. Measured off the photo the same way as the mouth: scanning rows
   of the image puts the brow band at y 312-330, so each patch covers
   y 302-342 with the brow in the middle and skin all round it, and the
   mask fades to nothing before the edge so nothing can show a seam.

   A raised brow is the setup; the inner end dropping is the turn; the
   inner end lifting is the sulk. Those three shapes carry the whole
   performance — far more than the mouth does. */
.brow {
  transform-origin:50% 100%;
  -webkit-mask-image:radial-gradient(ellipse 48% 46% at 50% 55%, #000 42%, rgba(0,0,0,0) 94%);
          mask-image:radial-gradient(ellipse 48% 46% at 50% 55%, #000 42%, rgba(0,0,0,0) 94%);
}
#brow-l { left:34.773%; top:30.691%; width:16.591%; height:4.065%; }
#brow-l img { width:602.740%; left:-209.589%; height:2460.000%; top:-755.000%; }
#brow-r { left:55.000%; top:30.488%; width:16.136%; height:4.065%; }
#brow-r img { width:619.718%; left:-340.845%; height:2460.000%; top:-750.000%; }

/* The eyelids had no mask at all, so each one was a rectangle of skin with
   four hard edges sitting on her face — and when it stretched to close the
   eye, those edges swept across the eye socket. That is the "khung chân
   mày" Dai kept seeing. Same treatment as the brows: fade to nothing well
   before the box ends, on every side. */
.lid {
  transform-origin:50% 0%;
  -webkit-mask-image:radial-gradient(ellipse 52% 50% at 50% 46%, #000 30%, rgba(0,0,0,0) 97%);
          mask-image:radial-gradient(ellipse 52% 50% at 50% 46%, #000 30%, rgba(0,0,0,0) 97%);
}
#lid-l { left:36.136%; top:33.943%; width:13.182%; height:2.236%; }
#lid-l img { width:758.621%; left:-274.138%; height:4472.727%; top:-1518.182%; }
#lid-r { left:56.364%; top:33.740%; width:12.727%; height:2.236%; }
#lid-r img { width:785.714%; left:-442.857%; height:4472.727%; top:-1509.091%; }

/* the lash line only exists while the eye is shut */
.lid::after {
  content:""; position:absolute; left:4%; right:4%; bottom:0; height:16%;
  background:linear-gradient(180deg, rgba(60,34,26,0) 0%, rgba(48,26,20,.55) 100%);
  opacity:var(--lash, 0);
  -webkit-mask-image:radial-gradient(ellipse 50% 90% at 50% 50%, #000 20%, rgba(0,0,0,0) 100%);
          mask-image:radial-gradient(ellipse 50% 90% at 50% 50%, #000 20%, rgba(0,0,0,0) 100%);
}

@media (prefers-reduced-motion: reduce) {
  #jaw, .lid { transition:none; }
}

/* warm rim that lifts while she speaks — the visible sign she is talking */
#rim {
  position:absolute; inset:-6%;
  pointer-events:none; opacity:0;
  background:
    radial-gradient(58% 42% at 50% 30%, rgba(255,196,120,.30) 0%, rgba(255,170,90,.10) 45%, transparent 72%);
  mix-blend-mode:screen;
}
body.state-listening #rim {
  background:
    radial-gradient(58% 42% at 50% 30%, rgba(140,220,170,.30) 0%, rgba(110,189,125,.10) 45%, transparent 72%);
}

.hz { position:absolute; pointer-events:auto; }

@media (prefers-reduced-motion:reduce) {
  #charwrap, #ambient { transition:none !important; }
}

/* ============================================================
   Mode switch · drill panel · notebook
   ============================================================ */
#modebar {
  display:flex; gap:6px; justify-content:center; align-items:center;
  padding:2px 14px 8px;
  flex:0 0 auto;
}
.mode {
  flex:0 0 auto; font-family:inherit; font-size:13.5px; font-weight:600;
  padding:7px 18px; border-radius:999px; cursor:pointer;
  background:rgba(255,255,255,.07); color:var(--brand-200);
  border:1px solid rgba(255,225,190,.16);
}
.mode.is-on {
  background:var(--gold-400); color:#3D2800; border-color:var(--gold-400);
}

/* ============================================================
   Daily lesson panel
   ------------------------------------------------------------
   Sits where the captions normally are, over the bottom of the
   portrait, so Ellie stays on screen while he works. Everything is
   sized to be readable at arm's length on a phone with one hand.
   ============================================================ */
#today, #gotcha, #review {
  /* An overlay, not a row. Given its own grid track it squeezed Ellie down
     to a thumbnail, and she is the reason he opens the app. Pinned to the
     bottom of the stage she keeps her full size and the lesson sits over
     her shoulder, where a caption would have been anyway. */
  position:absolute; left:0; right:0; bottom:0; z-index:4;
  padding:8px 18px 10px; display:flex; flex-direction:column; gap:6px;
  max-height:56%; overflow:auto; touch-action:auto;
  background:linear-gradient(180deg,
    rgba(18,12,9,0) 0%, rgba(18,12,9,.66) 22%, rgba(18,12,9,.93) 52%, rgba(18,12,9,.98) 100%);
}
#today[hidden], #gotcha[hidden], #review[hidden] { display:none; }

.t-head {
  display:flex; align-items:baseline; gap:10px;
  font-size:12px; color:var(--brand-200);
}
.t-day  { font-weight:600; color:var(--gold-300); white-space:nowrap; }
.t-day small { opacity:.55; font-weight:400; }
.t-theme {
  flex:1 1 auto; min-width:0; opacity:.85;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.t-streak { white-space:nowrap; opacity:.9; }

.t-steps { display:flex; gap:5px; }
.t-dot {
  flex:1 1 0; text-align:center; font-size:10.5px; letter-spacing:.01em;
  padding:3px 2px 4px; border-radius:6px;
  color:var(--brand-200); background:rgba(255,255,255,.05);
  border:1px solid rgba(255,225,190,.12);
  opacity:.55; transition:opacity .2s ease, background .2s ease;
}
.t-dot.past { opacity:.8; background:rgba(201,162,39,.14); }
.t-dot.on {
  opacity:1; background:var(--gold-400); color:#3D2800;
  border-color:var(--gold-400); font-weight:600;
}

.t-body { min-height:74px; }

/* --- step 1: one word at a time --- */
.t-word { display:flex; align-items:baseline; flex-wrap:wrap; gap:4px 10px; }
.t-word b   { font-size:clamp(22px,6.4vw,28px); color:#fff; line-height:1.1;
              text-shadow:0 1px 12px rgba(0,0,0,.55); }
.t-word .ipa{ font-size:13px; color:var(--gold-300); }
.t-word .vi { flex:1 0 100%; font-size:13.5px; color:var(--brand-200); }

.t-strip { display:flex; flex-wrap:wrap; gap:4px 6px; margin-top:6px; }
.t-strip span {
  font-size:11px; padding:2px 7px; border-radius:999px;
  color:var(--brand-200); background:rgba(255,255,255,.06);
  border:1px solid rgba(255,225,190,.12); opacity:.5;
}
.t-strip .past { opacity:.85; background:rgba(201,162,39,.16); }
.t-strip .on   { opacity:1; background:var(--gold-400); color:#3D2800;
                 border-color:var(--gold-400); font-weight:600; }

/* --- step 2: the story --- */
.t-story {
  margin:0; font-size:clamp(14.5px,3.9vw,17px); line-height:1.55; color:#fff;
  text-shadow:0 1px 10px rgba(0,0,0,.5);
}
/* one short instruction above every step — he asked what he was meant to do,
   which means the screen was not saying it */
.t-lead {
  margin:0 0 5px; font-size:11.5px; letter-spacing:.02em;
  color:var(--gold-300); text-transform:uppercase;
}
.t-story span { opacity:.42; transition:opacity .2s ease; }
.t-story span.past { opacity:.62; }
.t-story span.on {
  opacity:1; background:rgba(201,162,39,.20);
  box-shadow:0 0 0 3px rgba(201,162,39,.20); border-radius:3px;
}
.t-story:not(:has(span.on)) span { opacity:1; }

.t-storyvi { margin:6px 0 0; font-size:12.5px; line-height:1.5; color:var(--brand-200); opacity:.85; }
.t-storyvi[hidden] { display:none; }
.t-vi-toggle {
  margin-top:5px; font-family:inherit; font-size:11.5px; cursor:pointer;
  background:none; border:0; padding:0; color:var(--gold-300); text-decoration:underline;
}

/* --- step 3: the memory hook — the one thing on screen --- */
.t-hook {
  border-left:3px solid var(--gold-400); padding:2px 0 2px 12px;
}
.t-hook-w {
  display:inline-block; font-size:11px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--gold-300); margin-bottom:3px;
}
/* the line from today's story that the hook is built on */
.t-scene {
  margin:0 0 5px; font-size:12.5px; line-height:1.45; font-style:italic;
  color:var(--brand-200); opacity:.9;
}
.t-empty .vn { display:block; margin-top:6px; opacity:.85; }

.t-hook-line {
  margin:0; font-size:clamp(15px,4.2vw,18px); line-height:1.45; font-weight:600; color:#fff;
}
.t-hook-why { margin:5px 0 0; font-size:12px; line-height:1.5; color:var(--brand-200); opacity:.82; }
.t-hook-do {
  margin:7px 0 0; font-size:11.5px; line-height:1.45; color:var(--gold-300);
  border-top:1px solid rgba(201,162,39,.22); padding-top:6px;
}

/* --- step 4 --- */
.t-ask {
  margin:0; font-size:clamp(15px,4.2vw,18px); line-height:1.45; color:#fff; font-weight:600;
}
.t-done { margin:8px 0 0; font-size:13px; color:var(--gold-300); }
.t-empty { margin:0; font-size:13px; line-height:1.6; color:var(--brand-200); }

.t-said { margin:6px 0 0; font-size:12.5px; color:var(--brand-200); min-height:17px; }
.t-said .ok  { color:#8FD79B; font-weight:600; }
.t-said .mid { color:var(--gold-300); font-weight:600; }
.t-said .low { color:#E88C7D; font-weight:600; }

.t-actions { display:flex; gap:7px; }
.t-actions .ghost-sm { flex:1 1 0; }
.ghost-sm.primary {
  background:var(--gold-400); color:#3D2800; border-color:var(--gold-400); font-weight:600;
}
.t-hint { margin:0; text-align:center; font-size:11.5px; color:var(--brand-200); opacity:.8; min-height:15px; }

/* ============================================================
   Review tab
   ------------------------------------------------------------
   Two screens in the lesson panel's frame, so nothing here has
   to re-describe the head, the buttons or the hint line:

     .r-recap   Ellie's end-of-session summary — her spoken line,
                the key words, and what he said crooked
     .r-ask     one phrase at a time, Vietnamese prompt first

   A key word he gave back is gold; one he fumbled is warm red,
   because that is the one he came here for.
   ============================================================ */
.pip {
  display:inline-block; min-width:16px; margin-left:5px; padding:0 4px;
  font-size:10.5px; font-weight:700; line-height:16px; text-align:center;
  border-radius:999px; background:#B7472F; color:#fff; vertical-align:1px;
}
.mode.is-on .pip { background:#3D2800; color:var(--gold-300); }
.pip[hidden] { display:none; }
/* a conversation waiting to be summed up, rather than a count */
.pip.new { background:var(--gold-400); color:#3D2800; animation:pipPulse 1.9s ease-in-out infinite; }
.mode.is-on .pip.new { background:#3D2800; color:var(--gold-300); animation:none; }
@keyframes pipPulse { 0%,100% { opacity:1; } 50% { opacity:.45; } }
@media (prefers-reduced-motion:reduce) { .pip.new { animation:none; } }

/* the aligner's colours, on the phrase itself */
.r-target .w-ok  { color:#9BE8AE; }
.r-target .w-bad { color:#FF9E96; text-decoration:underline;
                   text-decoration-style:wavy; text-underline-offset:3px; }

.r-recap { display:flex; flex-direction:column; gap:7px; }
.r-line {
  margin:0; font-size:14.5px; line-height:1.55; color:#fff;
}
.r-line .en-run { color:var(--gold-300); font-weight:600; }
.r-meta { margin:0; font-size:11.5px; color:var(--brand-200); opacity:.75; }
.r-h {
  margin:3px 0 0; font-size:11px; font-weight:600; letter-spacing:.06em;
  text-transform:uppercase; color:var(--gold-300); opacity:.9;
}

.r-keys { display:flex; flex-direction:column; gap:5px; }
.r-key {
  padding:6px 9px; border-radius:9px; border:1px solid rgba(255,225,190,.14);
  background:rgba(255,255,255,.05);
  border-left:3px solid var(--gold-400);
}
.r-key.weak { border-left-color:#B7472F; background:rgba(183,71,47,.10); }
.r-key b { display:block; font-size:15px; color:#fff; }
.r-key .vi { display:block; font-size:12.5px; color:var(--brand-200); }
.r-key small { display:block; font-size:11.5px; color:var(--brand-200); opacity:.7; }

.r-fixes { display:flex; flex-direction:column; gap:5px; }
.r-fix {
  padding:6px 9px; border-radius:9px;
  background:rgba(183,71,47,.10); border:1px solid rgba(183,71,47,.28);
}
.r-fix s { display:block; font-size:12.5px; color:#E88C7D; opacity:.85; }
.r-fix b { display:block; font-size:14.5px; color:#9BE8AE; }
.r-fix small { display:block; font-size:11.5px; color:var(--brand-200); opacity:.75; }
.r-note { margin:2px 0 0; font-size:11.5px; line-height:1.5; color:var(--brand-200); opacity:.7; }

.r-ask {
  margin:0; font-size:clamp(17px,4.8vw,21px); line-height:1.35; color:#fff;
}
.r-sub  { margin:4px 0 0; font-size:12.5px; color:var(--brand-200); }
.r-why  { margin:4px 0 0; font-size:12px; line-height:1.5; color:var(--brand-200); opacity:.8; }
.r-count { margin:5px 0 0; font-size:11px; color:var(--brand-200); opacity:.6; }

/* The recap is the longest thing this panel ever shows, so it gets more
   room than a one-phrase drill does, and the buttons stay put while the
   list scrolls.

   Sticky was tried first and was wrong twice over: a translucent bar let
   the list show through the buttons, and two siblings both pinned to
   bottom:0 sat on top of each other, so the hint line printed across a
   heading. The panel is already a flex column — so the BODY is the only
   thing that scrolls, and the head, the buttons and the hint are simply
   where flex puts them. No stacking, nothing to see through. */
#review { max-height:66%; overflow:hidden; }
#review .t-body {
  flex:1 1 auto; min-height:0; overflow:auto;
  -webkit-overflow-scrolling:touch;
}
#review .t-actions { flex:0 0 auto; padding-top:2px; }
#review .t-hint    { flex:0 0 auto; }

/* ---- the notebook sheet: key words, session by session ---- */
.bk { padding:7px 0; border-bottom:1px solid rgba(255,225,190,.09); }
.bk:last-child { border-bottom:0; }
.bk .when { font-size:11px; color:var(--gold-300); opacity:.85; }
.bk .ks { display:flex; flex-wrap:wrap; gap:4px 5px; margin-top:4px; }
.bk .ks em { font-size:12px; color:var(--brand-200); opacity:.6; }
.bk .k {
  padding:3px 8px; border-radius:999px; font-size:12.5px;
  background:rgba(201,162,39,.16); color:var(--gold-300);
  border:1px solid rgba(201,162,39,.28);
}
.bk .k.weak {
  background:rgba(183,71,47,.16); color:#F0A79A; border-color:rgba(183,71,47,.34);
}
.bk .k i { font-style:normal; opacity:.65; margin-left:5px; }


/* ============================================================
   Gotcha
   ------------------------------------------------------------
   Reuses the lesson panel's frame, head and buttons. Only the
   four lines that are unique to the game live here:

     g-vi-ask   the Vietnamese prompt he has to render in English
     g-base     the English sentence a shift item starts from
     g-change   what to change, in Vietnamese
     g-react    her reaction — the one line he reads first
     g-right    the model answer, the thing he copies back

   The reaction is deliberately the largest coloured block on the
   screen: it is the feedback, and feedback he does not read is
   feedback that did not happen.
   ============================================================ */
.g-vi-ask {
  margin:0; font-size:clamp(19px,5.4vw,24px); line-height:1.3; font-weight:600;
  color:#fff; text-shadow:0 1px 12px rgba(0,0,0,.55);
}
.g-base {
  margin:0; font-size:clamp(15px,4.1vw,18px); line-height:1.45; color:#fff;
  text-shadow:0 1px 10px rgba(0,0,0,.5);
}
.g-change {
  margin:6px 0 0; font-size:13px; line-height:1.45; color:var(--gold-300);
  border-left:3px solid var(--gold-400); padding-left:10px;
}
.g-react {
  margin:0; font-size:clamp(15px,4.2vw,18px); line-height:1.45; font-weight:600;
  color:#FFD9A8;
}
.g-react.ok { color:#9BDCA6; }
/* The three beats of a correction. They are staggered on purpose: the
   setup reads as an ordinary compliment, the turn is the loud one, and
   the sulk underneath is quieter — the shape of someone changing their
   mind mid-sentence. */
.g-react.g-b0 { color:#D8E4F5; font-weight:500; opacity:.9; margin-bottom:1px; }
.g-react.g-b1 { color:#FFD9A8; font-weight:700; margin-bottom:1px; }
.g-react.g-b2 { color:#FFC98A; font-weight:500; font-size:clamp(14px,3.9vw,16.5px); }

/* The trapped word. Everything else on this screen is explanation; this
   is the thing he has to walk away remembering, so it is bigger than the
   sentence around it and it arrives late, with a bump. */
.g-word {
  display:inline-block;
  font-size:1.5em; font-weight:800; letter-spacing:.01em;
  color:#FFF3DC;
  padding:0 .18em; border-radius:5px;
  background:rgba(201,162,39,.28);
  box-shadow:0 0 0 1px rgba(222,191,108,.45) inset;
  animation:wordpop .42s cubic-bezier(.2,1.7,.4,1) .18s both;
}
@keyframes wordpop {
  0%   { transform:scale(.6) rotate(-4deg); opacity:0; }
  60%  { transform:scale(1.14) rotate(1.5deg); opacity:1; }
  100% { transform:scale(1) rotate(0); opacity:1; }
}
@media (prefers-reduced-motion:reduce) { .g-word { animation:none; } }
.g-heard { margin:6px 0 0; font-size:12px; color:var(--brand-200); opacity:.85; }
.g-pct { color:var(--gold-300); font-weight:600; }
.g-right {
  margin:2px 0 0; font-size:clamp(17px,4.8vw,21px); line-height:1.35; font-weight:600;
  color:#fff; text-shadow:0 1px 12px rgba(0,0,0,.55);
}

#drill {
  padding:4px 20px 6px; text-align:center;
  display:flex; flex-direction:column; gap:7px;
  background:linear-gradient(180deg, rgba(18,12,9,0) 0%, rgba(18,12,9,.72) 40%, rgba(18,12,9,.92) 100%);
}
#drill[hidden] { display:none; }

.d-focus { margin:0; font-size:11.5px; color:var(--gold-300); letter-spacing:.02em; }
.d-target {
  margin:0; font-size:clamp(17px,4.6vw,21px); font-weight:600; line-height:1.4;
  color:#fff; text-shadow:0 1px 10px rgba(0,0,0,.5);
}
.d-target .w-ok  { color:#9BE8AE; }
.d-target .w-bad { color:#FF9E96; text-decoration:underline; text-decoration-style:wavy;
                   text-underline-offset:4px; }
.d-said { margin:0; font-size:13.5px; font-style:italic; color:var(--brand-200); opacity:.85; }
.d-said:empty { display:none; }

.d-result { display:flex; align-items:baseline; justify-content:center; gap:10px; }
.d-result[hidden] { display:none; }
.d-pct {
  font-size:26px; font-weight:700; font-variant-numeric:tabular-nums;
  color:#9BE8AE;
}
.d-pct.mid { color:var(--gold-300); }
.d-pct.low { color:#FF9E96; }
.d-note { font-size:12.5px; color:var(--brand-200); opacity:.85; }

.d-actions { display:flex; gap:10px; justify-content:center; }
.ghost-sm {
  font-family:inherit; font-size:12.5px; font-weight:600;
  padding:7px 14px; border-radius:999px; cursor:pointer;
  background:rgba(255,255,255,.08); color:var(--brand-100);
  border:1px solid rgba(255,225,190,.20);
}

/* ---- notebook ---- */
.book-stats {
  /* six tiles now that Gotcha coverage is one of them — three columns
     makes two even rows instead of 4 + 2 */
  display:grid; grid-template-columns:repeat(3,1fr); gap:8px; margin-bottom:6px;
}
.bs {
  background:var(--brand-50); border:1px solid var(--brand-100);
  border-radius:var(--radius); padding:10px 8px; text-align:center;
}
.bs b { display:block; font-size:20px; color:var(--brand-800);
        font-variant-numeric:tabular-nums; line-height:1.2; }
.bs span { font-size:10.5px; color:var(--grey-400); }

.book-list { display:grid; gap:7px; margin-bottom:4px; }
.bi {
  display:flex; align-items:flex-start; gap:10px;
  background:var(--brand-50); border:1px solid var(--brand-100);
  border-radius:var(--radius); padding:10px 12px; font-size:13.5px;
}
.bi .n {
  flex:none; min-width:26px; height:22px; border-radius:999px;
  background:#FFE6E4; color:#7F0010; font-size:11.5px; font-weight:700;
  display:grid; place-items:center; font-variant-numeric:tabular-nums;
}
.bi .n.ok { background:#DCF5DF; color:#00501E; }
.bi b { color:var(--brand-800); }
.bi small { display:block; color:var(--grey-400); font-size:11.5px; margin-top:2px; }
.book-empty { font-size:13px; color:var(--grey-400); padding:6px 2px; }

/* the typing bar is fixed to the bottom — keep it from covering the controls */
body.typing #controls { margin-bottom:64px; }
body.typing #hint     { margin-bottom:64px; }


/* English phrase inside one of her Vietnamese lines: the bit he repeats.
   Same gold as the lesson's word chip, sized to sit inside a sentence. */
.en-run {
  font-weight:700; color:#FFF3DC;
  padding:0 .16em; border-radius:4px;
  background:rgba(201,162,39,.24);
  box-shadow:0 0 0 1px rgba(222,191,108,.38) inset;
}

/* The deforming portrait. It sits exactly where the flat <img> sits and
   replaces it when WebGL is available; the <img> stays in the document
   because it is the texture, just hidden once it has been uploaded. */
#facegl {
  position:absolute; inset:0; width:100%; height:100%;
  display:block; pointer-events:none;
  filter:drop-shadow(0 22px 40px rgba(0,0,0,.55));
}
#facegl[hidden] { display:none; }
body.mesh #char { visibility:hidden; }
/* With real photographs of her face, every one of the old cut-out layers
   is not just unnecessary but wrong: they were measured against the
   previous portrait and would sit in the wrong place on this one. */
body.mesh #jaw, body.mesh #brow-l, body.mesh #brow-r,
body.mesh #lid-l, body.mesh #lid-r, body.mesh #mouthcav,
body.mesh #mouthin { display:none; }

/* The drawn mouth interior. Sits under the portrait canvas and is only
   ever seen through the opening the shader cuts, so it needs no mask of
   its own — the photograph is its mask. */
#mouthin {
  position:absolute; left:0; top:0; width:0; height:0;
  display:block; pointer-events:none; opacity:0;
  /* What is behind her lips when they part.
     Three attempts went into drawing teeth and a tongue here — shapes
     first, then pure gradients — and all three were measured and all
     three looked worse than nothing: at the size her mouth is actually
     drawn, about 74 px across, a bright band reads as a sticker and a
     dark mass reads as a hole punched in her face.
     So this is what a parted mouth really looks like from a metre away:
     warm shadow, darkest just under the upper lip, opening up toward the
     throat. Teeth are not invented here. They need a photograph of her
     mouth open, and there isn't one. */
  background:
    linear-gradient(180deg,
      rgba(64,30,30,.96)  0%,
      rgba(44,19,20,.94) 38%,
      rgba(56,26,26,.80) 76%,
      rgba(80,40,38,.26) 100%);
  border-radius:48% 48% 46% 46% / 62% 62% 38% 38%;
  filter:blur(.5px);
}

