/* style.css -- no framework, no web fonts, no CDN.
 *
 * Everything the page needs is in this file, which is what lets the CSP stay at
 * `default-src 'none'` with `script-src 'self'`.
 *
 * Mobile is the primary target, not an afterthought: the controls sit at the
 * bottom where a thumb reaches them, tap targets are at least 44 px, and
 * `env(safe-area-inset-*)` keeps them clear of the iPhone home indicator and
 * the notch in landscape.
 */

:root {
  --bg: #f6f7f9;
  --surface: #ffffff;
  --surface-2: #eef0f4;
  --ink: #16181d;
  --ink-soft: #5c6270;
  --line: #d9dde4;
  --accent: #2f6df6;
  --accent-ink: #ffffff;
  --danger: #c0392b;
  --ok: #1e9e6a;
  --warn: #b7791f;
  --radius: 14px;
  --shadow: 0 1px 2px rgba(16, 20, 30, .06), 0 8px 24px rgba(16, 20, 30, .08);
  --tap: 44px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #14161a;
    --surface: #1d2026;
    --surface-2: #262a32;
    --ink: #eceff4;
    --ink-soft: #a2aab8;
    --line: #333844;
    --accent: #6f9bff;
    --accent-ink: #101319;
    --danger: #ff7a6b;
    --ok: #4bd39b;
    --warn: #e0b055;
    --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px rgba(0, 0, 0, .35);
  }
}

* { box-sizing: border-box; }

/* `hidden` has to actually hide, and by default it does not.
 
   The browser's own rule is `[hidden] { display: none }`, which lives in the
   USER-AGENT stylesheet. Any `display` an author writes beats it, whatever the
   specificity -- so `.sheet { display: flex }` made the settings panel
   permanent: `hidden = true` flipped the attribute and changed nothing on
   screen, and "collapse" looked like a dead button. It was also open on first
   load for the same reason.

   This is asserted in tests/run.js, because no DOM test can see it: the
   stand-in DOM reports `hidden` correctly while the pixels do not move. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", "PingFang SC", "Microsoft YaHei", sans-serif;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: none;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* 100dvh where supported: on iOS 100vh is taller than the visible area, which
   pushes the controls under the browser chrome. */
.app {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           calc(env(safe-area-inset-bottom)) env(safe-area-inset-left);
}

/* ------------------------------------------------------------------ bar */

.bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 14px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.bar__title { display: flex; align-items: center; gap: 8px; min-width: 0; }
.bar__title h1 { font-size: 15px; font-weight: 650; margin: 0; letter-spacing: .01em; }
.bar__actions { display: flex; align-items: center; gap: 8px; }

.dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--ink-soft); flex: none;
}
.app[data-state="listening"] .dot { background: var(--ok); animation: pulse 1.4s infinite; }
.app[data-state="thinking"]  .dot { background: var(--warn); animation: pulse 1.4s infinite; }
.app[data-state="speaking"]  .dot { background: var(--accent); animation: pulse 1.4s infinite; }
.app[data-state="error"]     .dot { background: var(--danger); }

@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .3; } }

@media (prefers-reduced-motion: reduce) {
  .dot { animation: none !important; }
}

.pill {
  font-size: 12px;
  color: var(--ink-soft);
  background: var(--surface-2);
  border-radius: 999px;
  padding: 4px 10px;
  white-space: nowrap;
}

/* ---------------------------------------------------------------- stage */

.stage {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.transcript { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }

.turn {
  max-width: min(680px, 92%);
  padding: 10px 13px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.turn--tutor { align-self: flex-start; }
.turn--learner { align-self: flex-end; background: var(--accent); color: var(--accent-ink); border-color: transparent; }
.turn--system {
  align-self: center;
  background: transparent;
  border: 0;
  box-shadow: none;
  color: var(--ink-soft);
  font-size: 13px;
  text-align: center;
  max-width: 100%;
}

.turn__who {
  display: block;
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  opacity: .65;
  margin-bottom: 3px;
}

/* The sentence being asked back, inside the tutor's line. */
.turn__practice {
  display: block;
  margin-top: 8px;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--surface-2);
  border-left: 3px solid var(--accent);
  font-style: italic;
}
.turn--learner .turn__practice { background: rgba(255,255,255,.18); border-left-color: #fff; }

.partial {
  margin: 0 0 auto;
  min-height: 1.2em;
  color: var(--ink-soft);
  font-style: italic;
  padding: 0 4px;
}

.notes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }

.note-card {
  font-size: 13px;
  background: var(--surface-2);
  border-radius: 10px;
  padding: 8px 10px;
  border-left: 3px solid var(--warn);
}
.note-card b { font-weight: 600; }
.note-card s { opacity: .6; }

/* --------------------------------------------------------------- banner */

.banner {
  margin: 0;
  padding: 10px 14px;
  background: var(--surface-2);
  border-top: 1px solid var(--line);
  color: var(--ink);
  font-size: 13px;
  white-space: pre-wrap;
}
.banner[data-kind="error"] { border-left: 4px solid var(--danger); }

/* ------------------------------------------------------------- controls */

.controls {
  background: var(--surface);
  border-top: 1px solid var(--line);
  padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.controls__row { display: flex; align-items: center; gap: 10px; }

.mic {
  flex: 1;
  min-height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border: 0;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  touch-action: manipulation;
  transition: transform .08s ease, filter .15s ease;
}
.mic:active { transform: scale(.985); }
.mic:disabled { filter: grayscale(1) opacity(.5); cursor: default; }
.mic__glyph { font-size: 13px; line-height: 1; }

.app[data-state="listening"] .mic { background: var(--ok); }
.app[data-state="speaking"] .mic,
.app[data-state="thinking"] .mic { background: var(--surface-2); color: var(--ink); }

.btn {
  min-height: var(--tap);
  padding: 0 16px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-size: 15px;
  font-weight: 550;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-appearance: none;
  appearance: none;
}
.btn:active { transform: scale(.98); }
.btn--ghost { background: transparent; }
.btn--danger { color: var(--danger); border-color: var(--danger); }

.composer { display: flex; gap: 8px; }

.composer input {
  flex: 1;
  min-width: 0;
  min-height: var(--tap);
  padding: 0 12px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--ink);
  font-size: 16px; /* 16px stops iOS zooming the page on focus */
}
.composer input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.hint { margin: 0; font-size: 12px; color: var(--ink-soft); min-height: 1.2em; }

/* Input level, so it is obvious the microphone is live. */
.meter { height: 3px; background: var(--surface-2); overflow: hidden; }
.meter span { display: block; height: 100%; width: 0; background: var(--ok); transition: width .06s linear; }

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

.sheet-backdrop {
  position: fixed; inset: 0; background: rgba(10, 12, 16, .45);
  z-index: 40;
}

.sheet {
  position: fixed;
  z-index: 50;
  inset: 0 0 0 auto;
  width: min(560px, 100%);
  background: var(--surface);
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow);
}

@media (max-width: 640px) {
  .sheet { inset: auto 0 0 0; height: min(92dvh, 92vh); border-radius: 16px 16px 0 0; }
}

.sheet__head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 16px; border-bottom: 1px solid var(--line);
}
.sheet__head h2 { font-size: 16px; margin: 0; }

.sheet__body {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 12px 16px calc(28px + env(safe-area-inset-bottom));
}

.group { border-bottom: 1px solid var(--line); padding: 10px 0; }
.group:last-child { border-bottom: 0; }
.group > summary {
  cursor: pointer;
  font-weight: 600;
  padding: 6px 0;
  list-style: none;
}
.group > summary::-webkit-details-marker { display: none; }
.group > summary::before { content: "\25B8"; display: inline-block; width: 1.1em; color: var(--ink-soft); }
.group[open] > summary::before { content: "\25BE"; }

.group h3 { font-size: 14px; margin: 14px 0 6px; }
.req { font-weight: 400; font-size: 12px; color: var(--ink-soft); }

.field { display: block; margin: 10px 0; }
.field > span { display: block; font-size: 13px; color: var(--ink-soft); margin-bottom: 4px; }
.field em { font-style: normal; opacity: .75; }
.field output { display: inline-block; font-size: 13px; color: var(--ink-soft); margin-left: 8px; }

.field input[type="text"],
.field input[type="password"],
.field select {
  width: 100%;
  min-height: var(--tap);
  padding: 0 10px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--ink);
  font-size: 16px;
}
.field input[type="range"] { width: 100%; min-height: var(--tap); }

.check, .choice { display: flex; gap: 10px; align-items: flex-start; margin: 10px 0; font-size: 15px; }
.check input, .choice input { margin-top: 11px; flex: none; width: 18px; height: 18px; }
.check em, .choice em { display: block; font-style: normal; font-size: 13px; color: var(--ink-soft); }

.choices { display: flex; flex-direction: column; gap: 6px; }
.choice {
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  cursor: pointer;
}
.choice:has(input:checked) { border-color: var(--accent); background: var(--surface-2); }

.note { font-size: 13px; color: var(--ink-soft); margin: 6px 0; }
.note.warning { color: var(--warn); }
.note code { background: var(--surface-2); padding: 1px 5px; border-radius: 5px; font-size: 12px; }

.row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }

.facts { list-style: none; margin: 10px 0 0; padding: 0; font-size: 13px; color: var(--ink-soft); }
.facts li { display: flex; justify-content: space-between; gap: 10px; padding: 3px 0; }

/* iPad and larger: the transcript gets a comfortable measure and the controls
   stop stretching across the whole screen. */
@media (min-width: 820px) {
  .stage { padding: 20px max(20px, calc((100% - 780px) / 2)); }
  .controls { padding-left: max(14px, calc((100% - 780px) / 2)); padding-right: max(14px, calc((100% - 780px) / 2)); }
}

/* ------------------------------------------------- settings, as a toggle */

.btn--toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
}
.btn__icon { font-size: 15px; line-height: 1; }

.btn--primary {
  background: var(--accent);
  border-color: transparent;
  color: var(--accent-ink);
  font-weight: 600;
}

/* The header button is the one control that must be reachable from anywhere on
   the page, so it is sized for a thumb and stays put. */
/* The bar must sit ABOVE the backdrop (40) and the panel (50).
 
   This was wrong at first: the bar was at z-index 30, and the desktop panel
   spans the full height on the right -- which is exactly where the toggle
   button is. So "close" did nothing on a desktop, and only appeared to work on
   a phone, where the backdrop happened to catch the click and close it. */
:root { --bar-h: 56px; }

.bar { position: sticky; top: 0; z-index: 60; min-height: var(--bar-h); }
.bar .btn--toggle { min-height: 38px; padding: 0 12px; }

/* The desktop panel starts BELOW the bar, so the two never overlap and the
   panel's own header stays visible. The mobile drawer comes up from the bottom
   and never reaches the bar. */
.sheet { top: var(--bar-h); }

@media (max-width: 640px) {
  .sheet { top: auto; }
}

/* ------------------------------------------------------------ sheet polish */

@media (max-width: 640px) {
  /* A grab handle, because a bottom sheet that fills the screen reads as a new
     page unless something says it can be dismissed. */
  .sheet::before {
    content: "";
    display: block;
    width: 44px;
    height: 4px;
    margin: 8px auto 0;
    border-radius: 2px;
    background: var(--line);
  }
  .sheet__head { border-bottom: 1px solid var(--line); }
}

.sheet__body { padding-bottom: calc(40px + env(safe-area-inset-bottom)); }

.group > summary { font-size: 15px; }
.group[open] > summary { color: var(--accent); }

/* A long panel is much easier to scan when the sections are separated by more
   than a hairline. */
.group { padding: 12px 0; }

/* --------------------------------------------------------------- controls */

@media (max-width: 420px) {
  .composer input { font-size: 16px; }   /* stops iOS zooming on focus */
  .controls__row { gap: 8px; }
}

/* While the tutor is talking, the microphone is not the action -- make that
   visible rather than only changing the label. */
.app[data-state="speaking"] .mic,
.app[data-state="thinking"] .mic { border: 1px solid var(--line); }

/* The notes are feedback, not the conversation: keep them visually quieter than
   the transcript so the eye goes to what was said. */
.note-card { font-size: 12.5px; }
