/* Any author rule that sets a display beats the browser's own [hidden] rule,
   however low its specificity - so an element with a `hidden` attribute stays on
   screen the moment it also matches something like `.icon-btn { display:grid }`.
   That has now cost a dead mic button on browsers without speech recognition and
   a maths keypad showing in every subject. One rule, once, instead of a patch per
   element. Toggle visibility with el.hidden and this holds. */
[hidden] { display:none !important; }

:root {
    /* Warmer than a stock chat app - this is for kids, not a support desk. */
    --bg:#f7f5ff; --surface:#ffffff; --surface-2:#f0eefc;
    --primary:#5b4bdb; --primary-2:#8b5cf6; --accent:#f59e0b;
    --text:#1f2033; --muted:#6b7089; --border:#e6e3f5;
    --user-text:#ffffff;
    --shadow:0 1px 2px rgba(40,30,90,.06), 0 8px 24px rgba(40,30,90,.07);
    --subject:#5b4bdb;
  }
  @media (prefers-color-scheme: dark) {
    :root {
      --bg:#15141f; --surface:#211f2e; --surface-2:#2b283b;
      --primary:#8b83f5; --primary-2:#b18bfa; --accent:#fbbf24;
      --text:#eeecf7; --muted:#a0a0bb; --border:#332f45;
      --shadow:0 1px 2px rgba(0,0,0,.35), 0 8px 24px rgba(0,0,0,.3);
      --subject:#8b83f5;
    }
  }
  /* Themes the student picks for themselves. Identity matters at this age -
     "I made it mine" is most of why a kid shows an app to a friend. */
  [data-theme="grape"]   { --primary:#5b4bdb; --primary-2:#8b5cf6; }
  [data-theme="ocean"]   { --primary:#0284c7; --primary-2:#06b6d4; }
  [data-theme="sunset"]  { --primary:#e11d48; --primary-2:#f97316; }
  [data-theme="forest"]  { --primary:#059669; --primary-2:#65a30d; }
  [data-theme="bubble"]  { --primary:#db2777; --primary-2:#a855f7; }
  [data-theme="mint"]    { --primary:#0d9488; --primary-2:#22c55e; }

  /* Each subject gets its own colour so the app feels less uniform. */
  [data-subject="math"]    { --subject:#2563eb; }
  [data-subject="science"] { --subject:#0d9488; }
  [data-subject="reading"] { --subject:#ea580c; }
  [data-subject="history"] { --subject:#b45309; }
  [data-subject="bible"]   { --subject:#7c3aed; }
  @media (prefers-color-scheme: dark) {
    [data-subject="math"]    { --subject:#60a5fa; }
    [data-subject="science"] { --subject:#2dd4bf; }
    [data-subject="reading"] { --subject:#fb923c; }
    [data-subject="history"] { --subject:#fbbf24; }
    [data-subject="bible"]   { --subject:#a78bfa; }
  }
  /* ---------- grade-band skins ----------
     One look can't serve a kindergartener and a junior. Each of the four
     tutoring bands gets its own visual language - geometry, type, density and
     chrome all shift. The colour theme the student picked rides on top. */
  :root {
    --r-bubble:14px; --r-ctl:12px; --r-chip:10px;
    --fs-body:15.5px; --fs-chip:13px; --fs-title:16.5px;
    --hdr-weight:640; --track:0px; --avatar:28px; --avatar-r:9px;
    --gap:14px; --pad:12px 15px;
    --grad:linear-gradient(135deg, var(--primary), var(--primary-2));
    --hdr-bg:var(--grad); --hdr-blur:none; --hdr-border:transparent;
    --lift:.985; --chip-w:640;
    --font:-apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto,
           system-ui, sans-serif;
  }

  /* K-2: big, warm and unmistakably friendly. */
  [data-band="k2"] {
    --r-bubble:22px; --r-ctl:18px; --r-chip:999px;
    --fs-body:17.5px; --fs-chip:14.5px; --fs-title:18px;
    --hdr-weight:800; --avatar:36px; --avatar-r:50%;
    --gap:16px; --pad:14px 17px; --lift:.93; --chip-w:800;
    --font:ui-rounded, "SF Pro Rounded", "Varela Round", "Nunito",
           -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  }
  /* 3-5: still rounded and colourful, a notch calmer. */
  [data-band="g35"] {
    --r-bubble:18px; --r-ctl:15px; --r-chip:999px;
    --fs-body:16.5px; --fs-chip:14px; --fs-title:17px;
    --hdr-weight:750; --avatar:32px; --avatar-r:50%;
    --gap:15px; --pad:12px 16px; --lift:.94; --chip-w:750;
    --font:ui-rounded, "SF Pro Rounded", "Varela Round", "Nunito",
           -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  }
  /* 6-8: a real app. Tighter geometry, translucent chrome, no baby talk. */
  [data-band="g68"] {
    --r-bubble:13px; --r-ctl:11px; --r-chip:9px;
    --fs-body:15.5px; --fs-chip:13px; --fs-title:16px;
    --hdr-weight:640; --avatar:27px; --avatar-r:9px;
    --gap:13px; --pad:11px 14px; --lift:.985; --chip-w:640;
    --hdr-bg:var(--primary); --hdr-blur:saturate(160%) blur(14px);
  }
  /* 9-12: studio tool. Near-monochrome, one accent, tight tracking. */
  [data-band="g912"] {
    --r-bubble:10px; --r-ctl:9px; --r-chip:7px;
    --fs-body:15px; --fs-chip:12.5px; --fs-title:15px;
    --hdr-weight:600; --track:-.15px; --avatar:22px; --avatar-r:6px;
    --gap:11px; --pad:10px 13px; --lift:.99; --chip-w:600;
    --hdr-blur:saturate(180%) blur(18px);
    /* Neutral surfaces so the accent does the talking. */
    --bg:#fafafa; --surface:#ffffff; --surface-2:#f2f2f4; --border:#e4e4e8;
    --text:#16161a; --muted:#71717a;
    --hdr-bg:rgba(255,255,255,.72); --hdr-border:#e4e4e8;
    --shadow:0 1px 2px rgba(0,0,0,.04);
  }
  @media (prefers-color-scheme: dark) {
    [data-band="g912"] {
      --bg:#0c0c0f; --surface:#151519; --surface-2:#1e1e24; --border:#26262e;
      --text:#f4f4f6; --muted:#8f8f9c;
      --hdr-bg:rgba(18,18,22,.72); --hdr-border:#26262e;
      --shadow:0 1px 2px rgba(0,0,0,.5);
    }
  }
  /* The oldest band gets a light header, so its controls need dark ink. */
  [data-band="g912"] header { color:var(--text); }
  [data-band="g912"] header button {
    background:var(--surface-2); color:var(--text); border:1px solid var(--border);
  }
  [data-band="g912"] header .logo { font-size:16px; opacity:.85; }
  [data-band="g68"]  header .logo { font-size:18px; opacity:.92; }

  * { box-sizing:border-box; -webkit-tap-highlight-color:transparent; }
  html, body { height:100%; }
  body {
    margin:0; background:var(--bg); color:var(--text);
    /* ui-rounded picks up SF Pro Rounded on iOS - friendlier for kids, and it
       costs nothing because it's already on the device. */
    font-family:var(--font);
    display:flex; flex-direction:column;
    /* Fallbacks first: dvh is iOS 16.4+, so older iPhones need a real height or
       the flex column collapses. Later rules win where supported. */
    height:100vh;
    height:-webkit-fill-available;
    height:100dvh;
    overflow:hidden;
  }

  /* ---- header ---- */
  header {
    background:var(--hdr-bg);
    -webkit-backdrop-filter:var(--hdr-blur); backdrop-filter:var(--hdr-blur);
    border-bottom:1px solid var(--hdr-border);
    color:#fff; padding:calc(env(safe-area-inset-top) + 12px) 16px 12px;
    display:flex; align-items:center; gap:10px; flex:none;
    position:relative; z-index:5;
  }
  header .logo { font-size:22px; line-height:1;
                 background:none; border:none; padding:0; cursor:pointer; }
  header .logo svg { width:21px; height:21px; display:block; }
  header h1 { font-size:var(--fs-title); font-weight:var(--hdr-weight); margin:0;
               flex:1; letter-spacing:var(--track); }
  header button {
    background:rgba(255,255,255,.18); color:#fff; border:none;
    padding:8px 12px; border-radius:999px; font-size:13px; font-weight:600; cursor:pointer;
  }
  header button:active { background:rgba(255,255,255,.3); }

  /* ---- subject chips ---- */
  #subjects {
    display:flex; gap:8px; padding:10px 12px; overflow-x:auto; flex:none;
    background:var(--surface); border-bottom:1px solid var(--border);
    scrollbar-width:none;
  }
  #subjects::-webkit-scrollbar { display:none; }
  .chip {
    flex:none; border:2px solid var(--border); background:var(--surface-2); color:var(--text);
    padding:8px 14px; border-radius:var(--r-chip); font-size:var(--fs-chip);
    font-weight:var(--chip-w); letter-spacing:var(--track);
    cursor:pointer; white-space:nowrap;
    transition:transform .12s ease, background .15s ease, border-color .15s ease;
  }
  .chip:active { transform:scale(var(--lift)); }
  .chip.on {
    background:var(--subject); border-color:var(--subject); color:#fff;
    box-shadow:0 3px 12px color-mix(in srgb, var(--subject) 45%, transparent);
  }
  /* Project isn't a subject - give it its own accent so the distinction reads. */
  #projectChip.on {
    background:var(--accent); border-color:var(--accent); color:#3b2600;
    box-shadow:0 3px 12px color-mix(in srgb, var(--accent) 45%, transparent);
  }

  /* ---- chat ---- */
  #chat { flex:1; overflow-y:auto; padding:16px 14px 8px; display:flex; flex-direction:column; gap:var(--gap);
          -webkit-overflow-scrolling:touch; }
  .row {
    display:flex; gap:9px; align-items:flex-end; max-width:100%;
    animation:rise .28s cubic-bezier(.2,.8,.3,1) both;
  }
  /* Tutor replies run long, so pin the avatar to the top of its bubble - at the
     bottom it drifts away from the start of the message. */
  .row.bot { align-items:flex-start; }
  @keyframes rise { from { opacity:0; transform:translateY(10px); } to { opacity:1; transform:none; } }
  @media (prefers-reduced-motion: reduce) {
    .row { animation:none; }
    .dots i { animation:none; }
  }
  .row.me { flex-direction:row-reverse; }
  .avatar {
    flex:none; width:var(--avatar); height:var(--avatar); border-radius:var(--avatar-r);
    display:grid; place-items:center; background:var(--grad);
    font-size:calc(var(--avatar) * .52); box-shadow:0 2px 8px rgba(91,75,219,.28);
  }
  /* Older bands: a quiet monogram tile, not a mascot. */
  [data-band="g68"] .avatar, [data-band="g912"] .avatar {
    background:var(--surface-2); color:var(--muted); box-shadow:none;
    border:1px solid var(--border); font-size:calc(var(--avatar) * .45);
  }
  .row.me .avatar { display:none; }
  .bubble {
    max-width:min(80%, 620px); padding:var(--pad); border-radius:var(--r-bubble);
    font-size:var(--fs-body); line-height:1.55; box-shadow:var(--shadow); overflow-wrap:anywhere;
  }
  .bot .bubble { background:var(--surface); border:1px solid var(--border); border-bottom-left-radius:4px; }
  .me .bubble {
    background:var(--grad);
    color:var(--user-text); border-bottom-right-radius:4px;
  }
  .bubble p { margin:0 0 8px; } .bubble p:last-child { margin-bottom:0; }
  .bubble ul, .bubble ol { margin:6px 0; padding-left:20px; }
  .bubble li { margin:3px 0; }
  .bubble h4 { margin:6px 0 4px; font-size:15.5px; }
  .bubble code {
    background:var(--surface-2); padding:1px 5px; border-radius:5px;
    font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:14px;
  }
  .me .bubble code { background:rgba(255,255,255,.22); }
  .bubble img { max-width:200px; border-radius:12px; display:block; margin-bottom:7px; }

  /* typing dots */
  .dots { display:flex; gap:5px; padding:4px 2px; }
  .dots i { width:8px; height:8px; border-radius:50%; background:var(--muted); animation:bounce 1.3s infinite; }
  .dots i:nth-child(2){ animation-delay:.18s } .dots i:nth-child(3){ animation-delay:.36s }
  @keyframes bounce { 0%,60%,100%{ transform:translateY(0); opacity:.5 } 30%{ transform:translateY(-6px); opacity:1 } }

  /* ---- starters ---- */
  #starters { display:flex; flex-wrap:wrap; gap:8px; padding:2px 40px 4px; }
  #starters button {
    background:var(--surface); border:1px dashed var(--border); color:var(--text);
    border-radius:var(--r-ctl); padding:10px 13px; font-size:13.5px; cursor:pointer; text-align:left;
  }
  #starters button:active { background:var(--surface-2); }

  /* ---- composer ---- */
  #preview { display:none; align-items:center; gap:9px; padding:8px 14px 0; }
  #preview.on { display:flex; }
  #preview img { width:44px; height:44px; object-fit:cover; border-radius:9px; border:1px solid var(--border); }
  #preview span { font-size:13px; color:var(--muted); flex:1; }
  #preview button { background:none; border:none; color:var(--muted); font-size:20px; cursor:pointer; padding:4px 8px; }

  /* Scoped to the composer by id. A bare `form` selector here would also flatten
     the gate / parent / setup sheets, which are forms too. */
  #form {
    display:flex; gap:8px; align-items:flex-end; flex:none;
    padding:10px 12px calc(env(safe-area-inset-bottom) + 10px);
    background:var(--surface); border-top:1px solid var(--border);
    -webkit-backdrop-filter:var(--hdr-blur); backdrop-filter:var(--hdr-blur);
  }
  /* The overlay sheets stack their contents normally. */
  #gate .card, #parentSheet .card, #meSheet .card { display:block; }
  .icon-btn {
    flex:none; width:46px; height:46px; border-radius:50%; border:2px solid var(--border);
    background:var(--surface-2); font-size:21px; cursor:pointer; display:grid; place-items:center;
    color:var(--text); transition:transform .12s ease;
  }
  .icon-btn:active { transform:scale(.92); }
  .icon-btn svg { width:21px; height:21px; display:block; }
  #send svg { width:20px; height:20px; }
  /* Speaking beats thumb-typing a long question on a phone. */
  #mic.rec {
    background:#ef4444; border-color:#ef4444; color:#fff;
    animation:pulse 1.2s ease-in-out infinite;
  }
  @keyframes pulse { 50% { box-shadow:0 0 0 9px rgba(239,68,68,.22); } }
  @media (prefers-reduced-motion: reduce) { #mic.rec { animation:none; } }

  /* The camera is the main way in - make it look like it. */
  label.icon-btn {
    border-color:color-mix(in srgb, var(--primary) 35%, transparent);
    background:color-mix(in srgb, var(--primary) 12%, var(--surface-2));
  }
  #text {
    flex:1; resize:none; border:1px solid var(--border); background:var(--bg); color:var(--text);
    border-radius:var(--r-ctl); padding:11px 15px; font-size:16px; /* 16px stops iOS zoom-on-focus */
    line-height:1.4; max-height:120px; font-family:inherit;
  }
  #text:focus { outline:2px solid var(--primary); outline-offset:-1px; }
  #send {
    flex:none; width:46px; height:46px; border-radius:50%; border:none; cursor:pointer;
    background:linear-gradient(135deg, var(--primary), var(--primary-2)); color:#fff; font-size:19px;
    box-shadow:0 3px 12px rgba(91,75,219,.35); transition:transform .12s ease;
  }
  #send:active { transform:scale(.92); }
  #send:disabled { opacity:.4; box-shadow:none; }

  /* friendly "thinking" line next to the dots */
  .thinking { display:flex; align-items:center; gap:9px; }
  .thinking span { font-size:14px; color:var(--muted); }

  /* ---- passcode gate ---- */
  #gate { position:fixed; inset:0; background:rgba(16,18,30,.72); backdrop-filter:blur(4px);
          display:grid; place-items:center; z-index:50; padding:20px; }
  #gate.hidden { display:none; }
  #gate .card { background:var(--surface); padding:26px 22px; border-radius:18px; width:100%; max-width:330px;
                box-shadow:0 20px 50px rgba(0,0,0,.3); text-align:center; }
  #gate .logo { font-size:38px; }
  #gate h2 { margin:8px 0 4px; font-size:19px; }
  #gate p { margin:0 0 16px; font-size:13.5px; color:var(--muted); }
  #gate input {
    width:100%; padding:13px; border:1px solid var(--border); border-radius:12px;
    font-size:16px; margin-bottom:8px; text-align:center; background:var(--bg); color:var(--text);
  }
  #gate button { width:100%; padding:13px; border:none; border-radius:12px; color:#fff; font-size:15px;
                 font-weight:600; cursor:pointer; background:linear-gradient(135deg, var(--primary), var(--primary-2)); }
  #gateErr { color:#ef4444; font-size:13px; min-height:19px; }
  /* Discrete maker's mark. */
  .madeBy { margin-top:16px; font-size:11px; letter-spacing:.3px; color:var(--muted);
            opacity:.75; text-align:center; }
  #chatFooter { flex:none; text-align:center; font-size:10.5px; letter-spacing:.3px;
                color:var(--muted); opacity:.55; padding:0 0 4px; background:var(--surface); }

  /* ---- parent (answer key) mode ---- */
  #parentBar {
    display:none; align-items:center; gap:10px; flex:none;
    background:#fef3c7; color:#7c2d12; padding:9px 14px;
    font-size:13.5px; font-weight:700; border-bottom:1px solid #fcd34d;
  }
  #parentBar.on { display:flex; }
  #parentBar span { flex:1; }
  #parentBar button {
    background:#7c2d12; color:#fff; border:none; border-radius:999px;
    padding:6px 12px; font-size:12.5px; font-weight:700; cursor:pointer;
  }
  @media (prefers-color-scheme: dark) {
    #parentBar { background:#4a2f0a; color:#fde68a; border-bottom-color:#78500f; }
    #parentBar button { background:#fde68a; color:#4a2f0a; }
  }
  #parentSheet { position:fixed; inset:0; background:rgba(16,18,30,.72); backdrop-filter:blur(4px);
                 display:none; place-items:center; z-index:60; padding:20px; }
  #parentSheet.on { display:grid; }
  #parentSheet .card { background:var(--surface); padding:24px 22px; border-radius:18px;
                       width:100%; max-width:340px; text-align:center; box-shadow:0 20px 50px rgba(0,0,0,.3); }
  #parentSheet h2 { margin:6px 0 4px; font-size:18px; }
  #parentSheet p { margin:0 0 14px; font-size:13px; color:var(--muted); line-height:1.45; }
  #parentSheet input { width:100%; padding:13px; border:1px solid var(--border); border-radius:12px;
                       font-size:16px; margin-bottom:8px; text-align:center;
                       background:var(--bg); color:var(--text); }
  #parentSheet .row2 { display:flex; gap:8px; }
  #parentSheet button { flex:1; padding:13px; border:none; border-radius:12px; font-size:15px;
                        font-weight:700; cursor:pointer; }
  #parentGo { background:linear-gradient(135deg, var(--primary), var(--primary-2)); color:#fff; }
  #parentCancel { background:var(--surface-2); color:var(--text); }
  #parentErr { color:#ef4444; font-size:13px; min-height:19px; }

  /* ---- quick replies: one tap beats typing on a phone ---- */
  #quick { display:flex; flex-wrap:wrap; gap:7px; padding:0 14px 4px 51px; }
  #quick button {
    background:var(--surface); border:1.5px solid color-mix(in srgb, var(--primary) 30%, transparent);
    color:var(--primary); border-radius:var(--r-chip); padding:8px 13px;
    font-size:var(--fs-chip); font-weight:var(--chip-w); cursor:pointer; font-family:inherit;
    animation:rise .3s cubic-bezier(.2,.8,.3,1) both;
  }
  #quick button:active { transform:scale(.94); background:var(--surface-2); }
  @media (prefers-reduced-motion: reduce) { #quick button { animation:none; } }

  /* ---- read aloud ---- */
  .speak {
    background:none; border:none; cursor:pointer; padding:4px 4px 0; margin-top:6px;
    opacity:.45; line-height:1; color:var(--muted);
  }
  .speak svg { width:17px; height:17px; display:block; }
  .speak:active, .speak.on { opacity:1; }

  /* streaming caret */
  .caret { display:inline-block; width:2px; height:1em; background:var(--primary);
           vertical-align:-2px; animation:blink 1s step-end infinite; }
  @keyframes blink { 50% { opacity:0; } }

  /* ---- streak / stats ---- */
  #stats { display:flex; gap:8px; justify-content:center; flex-wrap:wrap; padding:4px 14px 8px; }
  #stats div {
    background:var(--surface); border:1px solid var(--border); border-radius:999px;
    padding:6px 13px; font-size:13px; font-weight:700; color:var(--muted);
  }
  #stats b { color:var(--text); }

  /* ---- "make it yours" sheet ---- */
  #meSheet { position:fixed; inset:0; background:rgba(16,18,30,.72); backdrop-filter:blur(4px);
             display:none; place-items:center; z-index:70; padding:20px; }
  #meSheet.on { display:grid; }
  #meSheet .card { background:var(--surface); padding:24px 22px; border-radius:20px;
                   width:100%; max-width:340px; text-align:center;
                   box-shadow:0 20px 50px rgba(0,0,0,.3);
                   /* This card has grown - name, grade, reading voice, colours,
                      and the study note. On a smaller phone it ran off the
                      bottom, taking the Save button with it, with no way to
                      reach it. It scrolls now. */
                   max-height:calc(100dvh - 32px);
                   overflow-y:auto; -webkit-overflow-scrolling:touch;
                   overscroll-behavior:contain; }
  #meSheet h2 { margin:8px 0 4px; font-size:19px; }
  #meSheet p { margin:0 0 14px; font-size:13px; color:var(--muted); }
  #meSheet input { width:100%; padding:13px; border:1px solid var(--border); border-radius:12px;
                   font-size:16px; margin-bottom:12px; text-align:center;
                   background:var(--bg); color:var(--text); font-family:inherit; }
  #meSheet .meLabel { display:block; font-size:12.5px; font-weight:700; color:var(--muted);
                      margin:0 0 6px; }
  #meSheet select {
    width:100%; padding:12px; border:1px solid var(--border); border-radius:12px;
    font-size:16px; margin-bottom:14px; text-align:center; text-align-last:center;
    background:var(--bg); color:var(--text); font-family:inherit; appearance:none;
  }
  .swatches { display:flex; gap:9px; justify-content:center; margin-bottom:16px; flex-wrap:wrap; }
  /* Sized so all six fit one row inside the card on a 375px-wide iPhone. */
  .swatch { width:38px; height:38px; border-radius:50%; border:3px solid transparent;
            cursor:pointer; padding:0; flex:none; }
  .swatch.on { border-color:var(--text); }
  #meSheet button[type="submit"] {
    width:100%; padding:13px; border:none; border-radius:12px; color:#fff;
    font-size:15px; font-weight:700; cursor:pointer; font-family:inherit;
    background:linear-gradient(135deg, var(--primary), var(--primary-2));
  }
  /* What the tutor remembers, shown plainly so a parent can read it and clear it. */
  #memoryBox { margin:2px 0 16px; text-align:left; }
  #memoryText { font-size:12.5px; line-height:1.5; color:var(--muted); white-space:pre-wrap;
                background:var(--bg); border:1px solid var(--border); border-radius:12px;
                padding:10px 12px; max-height:120px; overflow-y:auto; }
  #memoryForget { margin-top:8px; background:none; border:none; padding:4px;
                  font:inherit; font-size:12.5px; color:var(--muted);
                  text-decoration:underline; cursor:pointer; }

  /* Moved out of style="" attributes so the page can run under a strict
     Content-Security-Policy (no inline styles). */
  .swatch[data-t="grape"] { background:linear-gradient(135deg,#5b4bdb,#8b5cf6); }
  .swatch[data-t="ocean"] { background:linear-gradient(135deg,#0284c7,#06b6d4); }
  .swatch[data-t="sunset"] { background:linear-gradient(135deg,#e11d48,#f97316); }
  .swatch[data-t="forest"] { background:linear-gradient(135deg,#059669,#65a30d); }
  .swatch[data-t="bubble"] { background:linear-gradient(135deg,#db2777,#a855f7); }
  .swatch[data-t="mint"] { background:linear-gradient(135deg,#0d9488,#22c55e); }
  .sheetIcon { font-size:34px; }
  #parentSheet .sheetIcon { font-size:32px; }

/* "Try again" under a failed answer, so a question never has to be retyped. */
.bubble .retry {
  display:block; margin-top:10px; padding:8px 14px;
  border:1px solid var(--border); border-radius:var(--r-ctl);
  background:var(--surface-2); color:var(--text);
  font:inherit; font-size:14px; font-weight:600; cursor:pointer;
}
.bubble .retry:active { transform:scale(.96); }
/* The send button while a reply is streaming. */
#send.stopping { background:var(--surface-2); color:var(--text); }
#send.stopping svg { width:17px; height:17px; }

/* Multiple-choice answers: tapping instead of thumb-typing. Full-width rows so
   they're easy to hit, and they read as answers rather than as suggestions. */
#quick.choices { flex-direction:column; align-items:stretch; }
#quick.choices button {
  display:flex; align-items:center; gap:10px; width:100%;
  text-align:left; padding:13px 14px; font-size:15px; font-weight:600;
  border:1px solid var(--border); border-radius:var(--r-ctl);
  background:var(--surface); color:var(--text);
}
#quick.choices button:active {
  background:var(--surface-2); border-color:var(--subject); transform:scale(.99);
}
/* Yes / No / Not sure. Three short words, so they go side by side rather than
   as three full-width rows - a stack of them reads like a menu of options when
   it is really one question with an obvious shape. Yes and No take the width
   they need; "Not sure" is deliberately quieter, so the two real answers lead. */
#quick.choices.yesno { flex-direction:row; flex-wrap:wrap; align-items:center; }
#quick.choices.yesno button {
  width:auto; flex:1 1 0; min-width:96px;
  justify-content:center; text-align:center;
}
#quick.choices.yesno button:last-child {
  flex:0 0 auto; color:var(--muted); font-weight:600;
}

.choiceLetter {
  flex:none; display:grid; place-items:center;
  width:26px; height:26px; border-radius:50%;
  background:var(--subject); color:#fff; font-size:13px; font-weight:800;
}
[data-band="k2"] #quick.choices button,
[data-band="g35"] #quick.choices button { font-size:16.5px; padding:15px 16px; }

/* ============================================================
   Document layout
   ------------------------------------------------------------
   The "kids' app" feeling came mostly from chrome, not from
   friendliness: every reply sat in a shadowed card, inside a
   coloured frame, next to an avatar. Chat products that read as
   grown-up tools do the opposite - the assistant's words are just
   text on the page, the only colour is the person's own message,
   and the space between turns does the separating.

   So the assistant's bubble goes away for every band, and the
   reading measure opens up. What stays band-specific is the
   personality: type size, roundness, warmth, emoji. A
   kindergartener still gets big rounded friendly type - it just
   isn't wrapped in a card any more.
   ============================================================ */

/* The reply is the page, not an object on it. */
.bot .bubble {
  background:none; border:none; box-shadow:none;
  border-bottom-left-radius:0; padding:0;
  max-width:100%; line-height:1.68;
}
.row.bot { gap:0; }
/* No avatar beside the text - it pushes the reply into a column and
   is the single strongest "chat toy" signal. */
.row.bot .avatar { display:none; }

/* The student's own message keeps their colour: one deliberate spot
   of it, which reads as identity rather than decoration. */
.me .bubble {
  background:var(--primary); box-shadow:none;
  border-radius:var(--r-bubble); border-bottom-right-radius:6px;
  max-width:min(85%, 560px); line-height:1.55;
}

/* Turns are separated by space now, so there needs to be more of it. */
#chat { padding:18px 16px 10px; gap:calc(var(--gap) + 8px); }
.bubble p { margin:0 0 12px; }
.bubble ul, .bubble ol { margin:10px 0; padding-left:22px; }
.bubble li { margin:5px 0; }
.bubble h4 { margin:14px 0 6px; }
/* Follow-ups and choices line up with the text, not with a gutter. */
#quick { padding:2px 16px 6px; }

/* A single rounded composer with the controls inside it. */
/* The maths symbol row. Scrolls sideways rather than wrapping: a second row
   would push the composer up and shove the conversation off a small screen. */
#keypad {
  display:flex; gap:6px; overflow-x:auto; -webkit-overflow-scrolling:touch;
  padding:0 12px 6px; margin:0; scrollbar-width:none;
}
#keypad::-webkit-scrollbar { display:none; }
#keypad button {
  flex:0 0 auto; min-width:42px; height:38px; padding:0 10px;
  font-size:18px; line-height:1; font-weight:600;
  background:var(--surface); color:var(--text);
  border:1px solid var(--border); border-radius:10px;
}
#keypad button:active { background:var(--surface-2); }

#form {
  align-items:flex-end; gap:2px;
  margin:6px 12px calc(env(safe-area-inset-bottom) + 10px);
  padding:5px 5px 5px 6px;
  background:var(--surface); border:1px solid var(--border);
  border-top:1px solid var(--border); border-radius:26px;
  box-shadow:0 1px 3px rgba(0,0,0,.05);
}
#form:focus-within { border-color:color-mix(in srgb, var(--primary) 45%, var(--border)); }
#text {
  border:none; background:transparent; padding:10px 8px; line-height:1.45;
}
#text:focus { outline:none; }
.icon-btn, label.icon-btn {
  width:40px; height:40px; border:none; background:transparent; color:var(--muted);
}
.icon-btn:active, label.icon-btn:active { background:var(--surface-2); }
#send {
  width:40px; height:40px; background:var(--primary); color:#fff; box-shadow:none;
}
#send:disabled { opacity:.35; }

/* Quieter chrome for the bands old enough to notice it. The younger
   two keep their colourful header - a 6-year-old is not asking for a
   grown-up tool. */
[data-band="g68"] {
  --hdr-bg:var(--surface); --hdr-border:var(--border);
}
[data-band="g68"] header { color:var(--text); }
[data-band="g68"] header button {
  background:var(--surface-2); color:var(--text); border:1px solid var(--border);
}
[data-band="g68"] header .logo { color:var(--muted); }
[data-band="g68"] #subjects, [data-band="g912"] #subjects {
  background:var(--bg); border-bottom:none; padding-bottom:6px;
}
[data-band="g68"] .chip, [data-band="g912"] .chip {
  background:var(--surface); border:1px solid var(--border); color:var(--muted);
}
[data-band="g68"] .chip.on, [data-band="g912"] .chip.on {
  background:var(--subject); border-color:var(--subject); color:#fff;
}

/* Working, laid out as steps. Consecutive steps are one block with a line
   each, so a four-step derivation reads as one piece rather than a stack of
   cards. Tabular figures keep the digits aligned down the steps, and the tint
   comes from the student's own colour so it belongs to the app rather than
   looking like a code block. */
.bubble .math {
  margin:12px 0; padding:11px 14px;
  border-radius:var(--r-ctl);
  background:color-mix(in srgb, var(--subject) 7%, var(--surface-2));
  border-left:3px solid color-mix(in srgb, var(--subject) 45%, transparent);
  font-size:calc(var(--fs-body) + 1px);
  font-variant-numeric:tabular-nums; letter-spacing:.2px;
  overflow-x:auto;
}
/* A step must not reflow - "3/12 + 2/12" broken across two lines stops being
   one step - but it must never be silently CLIPPED either, which is what
   nowrap alone did on a phone. Scroll the block instead. */
.bubble .math { overflow-x:auto; -webkit-overflow-scrolling:touch; }
.bubble .math span { display:block; white-space:nowrap; }
.bubble .math span + span { margin-top:5px; }
.me .bubble .math {
  background:rgba(255,255,255,.16); border-left-color:rgba(255,255,255,.5);
}

/* ---- the "you worked it out" moment ----
   Understated on purpose. For a 12-year-old a confetti cannon reads as a
   babyish app - the exact thing they reject - so the older bands get a brief
   lift and a warm edge, and only the younger two get the party. */
@keyframes gotitLift {
  0%   { transform: none; }
  35%  { transform: translateY(-4px); }
  100% { transform: none; }
}
.row.gotit .bubble { animation: gotitLift .5s cubic-bezier(.2,.8,.3,1); }
.row.gotit .bubble::after {
  content: ""; position: absolute; inset: -6px -10px; border-radius: 14px;
  border: 2px solid color-mix(in srgb, var(--subject) 55%, transparent);
  animation: gotitGlow 1.3s ease-out forwards; pointer-events: none;
}
.row.gotit .bubble { position: relative; }
@keyframes gotitGlow {
  0%   { opacity: 0; transform: scale(.98); }
  25%  { opacity: 1; }
  100% { opacity: 0; transform: scale(1.02); }
}

/* The younger bands get something to actually cheer at. */
.burst { position: absolute; left: 50%; top: 0; width: 0; height: 0; pointer-events: none; }
.burst i {
  position: absolute; width: 9px; height: 9px; border-radius: 2px;
  background: var(--subject); opacity: 0;
  animation: pop 1.1s cubic-bezier(.2,.7,.3,1) var(--d, 0ms) forwards;
}
.burst i:nth-child(3n)   { background: var(--accent); }
.burst i:nth-child(3n+1) { background: var(--primary-2); border-radius: 50%; }
@keyframes pop {
  0%   { opacity: 1; transform: translate(0, 0) scale(.6) rotate(0deg); }
  100% { opacity: 0; transform: translate(var(--x, 0), 120px) scale(1) rotate(220deg); }
}
@media (prefers-reduced-motion: reduce) {
  .row.gotit .bubble, .row.gotit .bubble::after, .burst i { animation: none; }
  .row.gotit .bubble::after { display: none; }
}

/* ---------------- speech class ----------------
   Writing a speech is a sit-down job, not something done between chat messages,
   so the workspace takes the whole screen. The two numbers that matter - how
   long it runs, and how long it took - are the biggest things on it. */
#speechSheet, #practiceSheet {
  position:fixed; inset:0; background:rgba(16,18,30,.72); backdrop-filter:blur(4px);
  display:none; place-items:center; z-index:70; padding:16px;
}
#speechSheet.on, #practiceSheet.on { display:grid; }
#speechSheet .card, #practiceSheet .card {
  background:var(--surface); padding:20px 18px calc(20px + env(safe-area-inset-bottom));
  border-radius:20px; width:100%; max-width:420px; position:relative;
  max-height:92vh; overflow-y:auto; -webkit-overflow-scrolling:touch;
}
#speechSheet h2 { margin:6px 0 14px; font-size:19px; text-align:center; }
#speechSheet .sheetIcon { text-align:center; }
.sheetClose {
  position:absolute; top:10px; right:12px; width:32px; height:32px;
  border:0; background:transparent; color:var(--muted); font-size:24px;
  line-height:1; cursor:pointer; border-radius:8px;
}
.sheetClose:hover { background:var(--surface-2); }

#speechTitle, #speechDraft, #speechTarget {
  width:100%; padding:12px; border:1px solid var(--border); border-radius:12px;
  background:var(--surface); color:var(--text); font-size:16px;  /* 16px: iOS won't zoom */
  font-family:inherit; margin-bottom:12px;
}
#speechDraft { resize:vertical; min-height:180px; line-height:1.5; }

/* The meter. This is the feature: a page of writing can't tell you how long it
   takes to say, and that is exactly what the assignment is graded on. */
#speechMeter { background:var(--surface-2); border-radius:14px; padding:12px 14px; margin-bottom:14px; }
.meterRow { display:flex; align-items:baseline; justify-content:space-between; }
#speechTime { font-size:28px; font-weight:800; letter-spacing:-.5px; }
#speechWords { font-size:13px; color:var(--muted); }
.meterBar { height:8px; border-radius:99px; background:var(--border); overflow:hidden; margin:10px 0 8px; }
.meterBar i { display:block; height:100%; width:0; border-radius:99px;
              background:var(--primary); transition:width .25s ease, background .25s ease; }
.meterBar i.good { background:#16a34a; }
.meterBar i.over { background:#dc2626; }
#speechAdvice { font-size:13px; color:var(--muted); line-height:1.45; }

.speechButtons { display:flex; gap:10px; }
.speechButtons button {
  flex:1; padding:13px; border-radius:12px; border:1px solid var(--border);
  background:var(--surface); color:var(--text); font-size:15px; font-weight:600;
  font-family:inherit; cursor:pointer;
}
.speechButtons button.primary { background:var(--primary); border-color:var(--primary); color:#fff; }

#speechRuns { margin-top:14px; }
.runsTitle { font-size:12px; font-weight:700; color:var(--muted);
             text-transform:uppercase; letter-spacing:.4px; margin-bottom:6px; }
.run { display:flex; justify-content:space-between; padding:7px 0;
       border-top:1px solid var(--border); font-size:14px; }
.run em { font-style:normal; color:var(--muted); font-size:13px; }
.run em.ok { color:#16a34a; font-weight:600; }

/* Practice: read from this screen while it times you, so the clock has to be
   legible at arm's length and nothing else competes with it. */
#practiceTitle { font-size:14px; color:var(--muted); text-align:center; margin-bottom:4px; }
#practiceClock { font-size:56px; font-weight:800; text-align:center;
                 letter-spacing:-2px; font-variant-numeric:tabular-nums; line-height:1.1; }
#practiceTarget { text-align:center; font-size:13px; color:var(--muted); margin-top:4px; }
.practiceBar { height:10px; border-radius:99px; background:var(--border);
               overflow:hidden; margin:14px 0; }
.practiceBar i { display:block; height:100%; width:0; border-radius:99px;
                 background:var(--primary); transition:width .2s linear; }
.practiceBar i.near { background:var(--accent); }
.practiceBar i.over { background:#dc2626; }
#practiceScript { max-height:34vh; overflow-y:auto; white-space:pre-wrap;
                  font-size:17px; line-height:1.6; padding:12px;
                  background:var(--surface-2); border-radius:12px; margin-bottom:14px; }
#practiceScript:empty { display:none; }

@media (prefers-reduced-motion: reduce) {
  .meterBar i, .practiceBar i { transition:none; }
}

/* The reading-voice picker. #meSheet styles its select already; this is the
   note underneath explaining that a robotic list is an iOS setting, not a bug. */
#meVoiceHint { font-size:11.5px; color:var(--muted); line-height:1.45;
               margin:-6px 0 14px; text-align:left; }
#meVoiceHint:empty { display:none; }

/* ---------------- working shown on the board ----------------
   Long division only teaches anything if the columns line up: the 245 has to
   sit under the 281 it came from. That needs a monospace font, equal-width
   digits, and the spaces kept exactly as written. */
.board {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;   /* every digit the same width */
  font-size: 15px; line-height: 1.55; margin: 10px 0;
  padding: 14px 16px; border-radius: 12px;
  background: var(--surface-2); color: var(--text);
  border-left: 3px solid var(--primary);
  white-space: pre;                     /* never reflow a lined-up sum */
  overflow-x: auto;                     /* a wide one scrolls rather than squashing */
  -webkit-overflow-scrolling: touch;
  tab-size: 2;
}
/* The younger bands get a bigger board - they're reading digits, not prose. */
:root[data-band="k2"] .board, :root[data-band="g35"] .board { font-size: 17px; }

/* ---------------- conversation mode ----------------
   A kid talking to their phone needs to know, without reading, whether it is
   listening to them or about to talk. Hence a bar that is always visible while
   the mode is on, with a state you can tell apart at a glance. */
#talkBar { display:none; }
#talkBar.on {
  display:flex; align-items:center; gap:10px;
  margin:0 12px 8px; padding:10px 14px; border-radius:14px;
  background:var(--surface); border:1px solid var(--border);
  font-size:14px; color:var(--text);
}
#talkLabel { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis;
             white-space:nowrap; color:var(--muted); }
#talkBar.listening { border-color:var(--primary); }
#talkBar.speaking  { border-color:var(--accent); }
#talkStop {
  border:0; background:var(--surface-2); color:var(--text);
  font:inherit; font-weight:600; font-size:13px;
  padding:7px 14px; border-radius:99px; cursor:pointer; flex:none;
}

/* Three dots: bouncing while listening, steady while thinking or talking, so
   the state reads from across a room. */
.talkDot { display:flex; gap:4px; flex:none; }
.talkDot i { width:7px; height:7px; border-radius:50%; background:var(--muted); }
#talkBar.listening .talkDot i { background:var(--primary); animation:talkPulse 1.1s infinite; }
#talkBar.listening .talkDot i:nth-child(2) { animation-delay:.15s; }
#talkBar.listening .talkDot i:nth-child(3) { animation-delay:.3s; }
#talkBar.speaking  .talkDot i { background:var(--accent); }
@keyframes talkPulse { 0%,100%{ transform:translateY(0); opacity:.5; }
                       50%   { transform:translateY(-4px); opacity:1; } }
@media (prefers-reduced-motion: reduce) {
  #talkBar.listening .talkDot i { animation:none; opacity:1; }
}

/* ---------------- the tutor catching its own slip ----------------
   Not styled as an error. To a child this is someone noticing their own
   mistake and saying so, which is a good thing to watch an adult do - so it
   reads as a note, not an alarm. Under the answer, never inside it. */
.correction {
  margin-top: 10px; padding: 10px 12px;
  border-radius: 10px; border-left: 3px solid var(--accent);
  background: var(--surface-2); color: var(--text);
  font-size: 14px; line-height: 1.5;
}
