/* Base layout shared by both skins. Skins override the CSS variables. */
:root {
  --bg: #f7f8fa; --card: #ffffff; --text: #1d232b; --muted: #6b7480;
  --accent: #2563eb; --ok: #16a34a; --warn: #d97706; --fail: #dc2626;
  --radius: 12px; --font: system-ui, -apple-system, "Segoe UI", sans-serif;
  --sentence-size: 1.6rem;
}
* { box-sizing: border-box; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; }   /* iOS must not resize text on rotate */
body { margin: 0; font-family: var(--font); background: var(--bg); color: var(--text); }
/* iOS Safari zooms the whole page when a focused input is under 16px. Setting
   the floor here keeps typing from hijacking the layout. */
input, select, textarea { font-size: max(16px, 1rem); }
header { display: flex; align-items: center; justify-content: space-between;
  padding: 0.8rem 1.2rem; background: var(--card); box-shadow: 0 1px 4px rgba(0,0,0,.06); }
header h1 { font-size: 1.15rem; margin: 0; }
nav { display: flex; gap: .5rem; }
main { max-width: 760px; margin: 1.2rem auto; padding: 0 1rem; }
.card { background: var(--card); border-radius: var(--radius); padding: 1.2rem;
  margin: 1rem 0; box-shadow: 0 1px 6px rgba(0,0,0,.07); }
.center { text-align: center; }
.row { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; margin: .6rem 0; }
.row.center { justify-content: center; }
.space-between { justify-content: space-between; }
button { font: inherit; border: 1px solid #d6dae1; background: var(--card); color: var(--text);
  border-radius: 10px; padding: .5rem .9rem; cursor: pointer; }
button:hover { border-color: var(--accent); }
button.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
button.ghost { border: none; background: transparent; font-size: 1.2rem; }
input, select { font: inherit; padding: .5rem .7rem; border: 1px solid #d6dae1; border-radius: 10px; }
.error { color: var(--fail); }
.meta { color: var(--muted); font-size: .85rem; }
.chip { background: #fef3c7; border-radius: 999px; padding: .25rem .7rem; font-size: .85rem; }
.badge { background: var(--fail); color: #fff; border-radius: 999px; padding: 0 .45rem;
  font-size: .75rem; margin-left: .3rem; }
.deploy-badge { border-radius: 999px; padding: .25rem .7rem; font-size: .78rem;
  font-weight: 600; white-space: nowrap; }
.deploy-badge.local { background: #dcfce7; color: #14532d; }
.deploy-badge.cloud { background: #e0f2fe; color: #075985; }
@media (prefers-color-scheme: dark) {
  .deploy-badge.local { background: #14330f; color: #a7e8a0; }
  .deploy-badge.cloud { background: #0c3349; color: #7dd3fc; }
}

.learner-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: .8rem; }
.learner-tile { display: flex; flex-direction: column; align-items: center; gap: .4rem;
  padding: 1rem; border-radius: var(--radius); font-weight: 600; }
.learner-tile .avatar { font-size: 2.2rem; }

.sentence { font-size: var(--sentence-size); line-height: 1.5; text-align: center; font-weight: 600; }
.transcript { text-align: center; color: var(--muted); min-height: 1.4em; }
.status { text-align: center; min-height: 1.4em; }
.mic .lbl-sm { display: none; }
.mic { font-size: 1.15rem; padding: 1rem 1.6rem; border-radius: 999px; user-select: none;
  -webkit-user-select: none; touch-action: none; }
.mic.recording { background: var(--fail); color: #fff; border-color: var(--fail); animation: pulse 1.2s infinite; }
@keyframes pulse { 50% { transform: scale(1.06); } }

.scored-words { display: flex; flex-wrap: wrap; gap: .45rem; justify-content: center; margin: .6rem 0; }
.word { font-size: 1.25rem; font-weight: 600; border-radius: 8px; padding: .3rem .55rem; border: 2px solid transparent; }
.word.ok { background: #dcfce7; color: #14532d; }
.word.warn { background: #fef3c7; color: #713f12; }
.word.fail { background: #fee2e2; color: #7f1d1d; border-color: var(--fail); }
.warn-msg { text-align: center; font-size: 1.1rem; }

.popover { position: fixed; bottom: 1rem; left: 50%; transform: translateX(-50%);
  width: min(460px, 92vw); background: var(--card); border-radius: var(--radius);
  padding: 1.1rem; box-shadow: 0 8px 30px rgba(0,0,0,.25); z-index: 10; }
.phoneme-row { display: flex; gap: .35rem; flex-wrap: wrap; margin: .4rem 0; }
.ph { font-family: ui-monospace, monospace; background: #eef2f7; border-radius: 6px;
  padding: .15rem .5rem; font-size: .95rem; }
.ph.fail { background: #fee2e2; color: var(--fail); font-weight: 700; }
.ph.warn { background: #fef3c7; color: var(--warn); font-weight: 600; }
.ph sub { font-size: .62em; opacity: .65; margin-left: .12em; }
.tip { background: #eff6ff; border-radius: 8px; padding: .7rem; }

.prosody { display: flex; flex-wrap: wrap; gap: .4rem; justify-content: center; margin: .5rem 0; }

.focus-bar { display: flex; align-items: center; justify-content: space-between;
  gap: .8rem; padding: .8rem 1rem; }
.focus-bar p { margin: .2rem 0 0; }

/* dvh, not vh: on phones the URL bar collapses on scroll and vh keeps sizing
   against the TALL viewport, so the log runs under the browser chrome. */
.chat-log { display: flex; flex-direction: column; gap: .5rem; margin: 1rem 0;
  max-height: 46vh; max-height: 46dvh; overflow-y: auto; padding: .3rem;
  -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
.bubble { max-width: 78%; padding: .6rem .9rem; border-radius: 16px; line-height: 1.4; }
.bubble.partner { background: var(--card); align-self: flex-start;
  border-bottom-left-radius: 4px; box-shadow: 0 1px 4px rgba(0,0,0,.08); }
.bubble.learner { background: var(--accent); color: #fff; align-self: flex-end;
  border-bottom-right-radius: 4px; }
.bubble.pending { opacity: .55; font-style: italic; }

/* Passive pronunciation badge inside a learner bubble. Both themes keep the
   accent background (dark mode doesn't redefine --accent), so one set of
   light-on-accent colours is correct everywhere. */
.pron-dot { background: none; border: 0; padding: 0 0 0 .45rem; margin: 0;
  font-size: .8rem; line-height: 1; cursor: pointer; vertical-align: baseline;
  text-shadow: 0 0 3px rgba(0,0,0,.45); }
.pron-dot.ok { color: #7ee787; } .pron-dot.warn { color: #ffd479; }
.pron-dot.fail { color: #ff9c8f; }
.pron-dot:focus-visible { outline: 2px solid #fff; outline-offset: 2px; border-radius: 50%; }
.pron-detail { font-size: .78rem; opacity: .85; margin-top: .3rem;
  padding-top: .3rem; border-top: 1px solid rgba(255,255,255,.25); }
.stars { text-align: center; font-size: 2.6rem; }
.stars .dim { filter: grayscale(1); opacity: .35; }

.grade { min-width: 90px; }
.grade.ok { border-color: var(--ok); } .grade.warn { border-color: var(--warn); }
.grade.fail { border-color: var(--fail); }

.bar-row { display: flex; align-items: center; gap: .6rem; margin: .35rem 0; }
.bar { flex: 1; height: 10px; background: #eef2f7; border-radius: 999px; overflow: hidden; }
.bar .fill { height: 100%; background: var(--warn); border-radius: 999px; }
.history-row { display: flex; gap: .8rem; align-items: baseline; padding: .35rem 0;
  border-bottom: 1px solid #eef2f7; }
.history-row span:nth-child(2) { flex: 1; }

/* Role-play progress. Speaking practice works in short bursts — the research
   is consistent that 10-15 focused minutes beats 40 fatigued ones — so the
   learner must be able to SEE the end coming, or a five-line scene feels
   open-ended and they bail mid-way. */
/* wrap: role-play shows ~5 dots and never wraps, calibration shows 30 and
   would otherwise squeeze itself off a phone screen */
.steps { display: flex; align-items: center; gap: .3rem; margin: .1rem 0 .4rem;
  flex-wrap: wrap; }
.step { width: 9px; height: 9px; border-radius: 999px; background: #d6dae1; flex: 0 0 auto; }
.step.done { background: var(--ok); }
.step.now { background: var(--accent); transform: scale(1.35); }
.step-label { color: var(--muted); font-size: .78rem; margin-left: .4rem; }
/* Always on screen, never shouting: a visible way out is what makes a learner
   willing to attempt a line they are unsure of. */
button.skip { color: var(--muted); font-size: .82rem; }

/* Role-play end-of-run summary: one row per spoken line, expanding on tap
   into word chips + coach tip. Feedback lives here, after the dialogue —
   never interrupting it (tester-shaped flow). */
.line-row { border-bottom: 1px solid #eef2f7; }
.line-head { display: flex; align-items: center; gap: .6rem; width: 100%;
  border: none; background: none; text-align: left; padding: .55rem .2rem; }
.line-head .line-text { flex: 1; }
.line-head .word { flex: 0 0 auto; min-width: 2.4em; text-align: center; font-size: 1rem; }
.line-detail { padding: .2rem .2rem .8rem; }

/* a button that is visibly working in the background */
.busy { animation: busy-pulse 1.1s ease-in-out infinite; cursor: progress; }
@keyframes busy-pulse { 50% { opacity: .55; } }

@media (prefers-color-scheme: dark) {
  :root { --bg: #12161c; --card: #1c2230; --text: #e8ecf2; --muted: #98a2b3; }
  input, select, button { border-color: #333c4d; }
  .ph { background: #26304a; }
  .word.ok { background: #14330f; color: #a7e8a0; }
  .word.warn { background: #3d2e08; color: #fbd688; }
  .word.fail { background: #451414; color: #fda4a4; }
  .tip { background: #182338; }
  .bar { background: #26304a; }
  .chip { background: #3d2e08; }
  .step { background: #39414f; }
  .line-row { border-color: #26304a; }
}

/* ===================== PHONES =====================
   Most learners are on a phone, held one-handed. Three things follow from
   that: the thumb reaches the BOTTOM of the screen, not the top; every target
   must be at least ~44px or it gets mis-tapped; and vertical space is scarce,
   so chrome shrinks and the practice content comes first. */
@media (max-width: 640px) {
  :root { --sentence-size: 1.35rem; }

  /* --- header: compact, ONE line ---
     Every row here is a row the learner doesn't get for practising, so the
     title stops wrapping, the deploy badge drops the model name it was
     spelling out in full, and "Switch learner" falls back to its icon. */
  header { padding: .45rem .6rem; gap: .45rem; position: sticky; top: 0; z-index: 20; }
  header h1 { font-size: .95rem; white-space: nowrap; }
  #deploy-badge { font-size: .66rem; padding: .2rem .45rem; max-width: 5.4rem;
    overflow: hidden; text-overflow: ellipsis; }
  #btn-switch { padding: .4rem .55rem; min-width: 44px; }
  #btn-switch .lbl { display: none; }
  #btn-switch .ico { font-size: 1.15rem; }

  main { margin: .7rem auto; padding: 0 .7rem; }
  .card { padding: .9rem; margin: .7rem 0; }

  /* --- nav becomes a bottom tab bar: where the thumb already is --- */
  nav {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
    display: flex; gap: 0; background: var(--card);
    border-top: 1px solid rgba(128,128,128,.22);
    /* clear the iPhone home indicator */
    padding-bottom: env(safe-area-inset-bottom, 0);
    box-shadow: 0 -2px 12px rgba(0,0,0,.08);
  }
  nav button {
    flex: 1 1 0; min-width: 0;            /* equal tabs, labels may ellipsize */
    display: flex; flex-direction: column; align-items: center; gap: .12rem;
    border: 0; background: none; border-radius: 0;
    padding: .45rem .1rem .5rem; font-size: .66rem; color: var(--muted);
    min-height: 52px; position: relative;
  }
  nav button:hover { border-color: transparent; }
  nav button .ico { font-size: 1.25rem; line-height: 1; }
  nav button .lbl { max-width: 100%; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; }
  nav button.active { color: var(--accent); font-weight: 700; }
  nav button.active .ico { transform: scale(1.08); }
  nav .badge { position: absolute; top: .25rem; right: 50%; margin-right: -1.4rem; }
  /* keep the tab bar from covering the end of the page */
  body.has-tabbar main { padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }

  /* --- tap targets: 44px floor (Apple HIG / Material) --- */
  button { min-height: 44px; padding: .6rem .9rem; }
  button.ghost { min-width: 44px; }
  .mic { width: 100%; max-width: 320px; min-height: 60px; font-size: 1.1rem; }
  /* The side buttons flank the mic and must stay compact so the mic — the one
     control that matters — keeps the width. Labels collapse to their icons. */
  #btn-prev, #btn-next { flex: 0 0 auto; min-width: 48px; font-size: 1.35rem; }
  #btn-script-listen, #btn-script-slow,
  #btn-hear, #btn-hear-slow { flex: 0 0 auto; min-width: 48px; font-size: 1.3rem; }
  #btn-script-listen .lbl, #btn-script-slow .lbl,
  #btn-hear .lbl, #btn-hear-slow .lbl { display: none; }
  /* Read's row carries five controls on a phone (listen/prev/mic/next/slow);
     the mic keeps a short label so the row stays one line and the mic stays
     the widest, most obvious target. */
  #btn-mic .lbl { display: none; }
  #btn-mic .lbl-sm { display: inline; }
  #btn-mic, #btn-script-mic { flex: 1 1 auto; }
  .sentence-card .row.center { flex-wrap: nowrap; gap: .4rem; }

  /* --- action rows: a readable grid instead of ragged wrapping --- */
  #result-card .row.center, #conv-report .row, #script-report .row {
    display: grid; grid-template-columns: 1fr 1fr; gap: .5rem;
  }
  #result-card .row.center button { width: 100%; font-size: .88rem; padding: .6rem .4rem; }

  .learner-grid { grid-template-columns: repeat(auto-fill, minmax(108px, 1fr)); gap: .6rem; }
  .learner-tile { padding: .8rem .5rem; font-size: .9rem; }
  .learner-tile .avatar { font-size: 1.9rem; }

  .bubble { max-width: 88%; }
  .chat-log { max-height: 38dvh; }
  .word { font-size: 1.1rem; }
  .stars { font-size: 2.1rem; }

  /* --- popover becomes a bottom sheet, above the tab bar --- */
  .popover {
    left: 0; right: 0; bottom: 0; transform: none; width: 100%;
    border-radius: var(--radius) var(--radius) 0 0;
    padding-bottom: calc(1.1rem + env(safe-area-inset-bottom, 0px));
    max-height: 82dvh; overflow-y: auto;
  }
  .popover .row { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; }
  .popover .row button { width: 100%; }

  /* focus bar stacks: the button is the point, give it full width */
  .focus-bar { flex-direction: column; align-items: stretch; text-align: center; }
  .focus-bar button { width: 100%; }

  .grade { min-width: 0; flex: 1 1 0; }
  .history-row { flex-wrap: wrap; gap: .35rem .8rem; }
}

/* Very small phones (iPhone SE and similar) */
@media (max-width: 360px) {
  :root { --sentence-size: 1.2rem; }
  nav button { font-size: .6rem; }
  nav button .ico { font-size: 1.15rem; }
}

/* Coarse pointers of any size: hover styling misfires on touch, and the
   press-and-hold mic must never trigger text selection or the iOS callout. */
@media (pointer: coarse) {
  button:hover { border-color: #d6dae1; }
  button.primary:hover { border-color: var(--accent); }
  .mic { -webkit-touch-callout: none; }
  .word, .bubble { -webkit-tap-highlight-color: transparent; }
}
