/* PAL 9000 — friendly-HAL cockpit console.
   Near-black cabin, warm amber eye, HAL-red reserved for wrong answers. */

/* Self-hosted fonts (latin subsets) — no third-party requests. */
@font-face {
  font-family: 'Michroma';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/michroma-400.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-sans-var.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-sans-italic-var.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-mono-400.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-mono-600.woff2') format('woff2');
}

:root {
  --bg: #0b0c10;
  --panel: #12141a;
  --panel-raised: #171a22;
  --line: #333947;
  --text: #e8e6e1;
  --dim: #98948a;
  --amber: #ffb000;
  --amber-soft: #ffdd88;
  --red: #f2555a;
  --green: #3dd68c;
  --accent: #ffb000;
  --line-strong: #636c85;
  --glow: #1a1408;
  --tint-correct: rgba(61, 214, 140, 0.08);
  --tint-wrong: rgba(242, 85, 90, 0.08);
  --btn-text: #131007;
  --dim-2: #8a867e;
  color-scheme: dark;
  --font-body: 'IBM Plex Sans', sans-serif;
  --font-mono: 'IBM Plex Mono', monospace;
  --font-display: 'Michroma', sans-serif;
}

/* Daylight console — same cockpit, sun through the canopy. All text tokens
   hold WCAG AA (see tests/unit/contrast.test.js); amber stays graphical-only
   because #ffb000 text can't pass on light backgrounds (--accent darkens it). */
:root[data-theme="light"] {
  --bg: #f4f1ea;
  --panel: #fbf9f4;
  --panel-raised: #eeeae0;
  --line: #cdc7b8;
  --line-strong: #837c69;
  --text: #26231c;
  --dim: #5b564a;
  --dim-2: #6b6659;
  --accent: #7d5300;
  --red: #b42328;
  --green: #157a46;
  --glow: #eadfc6;
  --tint-correct: rgba(21, 122, 70, 0.10);
  --tint-wrong: rgba(180, 35, 40, 0.08);
  color-scheme: light;
}

* { box-sizing: border-box; }

/* iOS inflates text in landscape without this; 100% keeps the author size. */
html { -webkit-text-size-adjust: 100%; }

/* Android pull-to-refresh reloads the page — mid-quiz that's disruptive even
   with session resume. contain keeps normal scrolling, drops the gesture. */
html, body { overscroll-behavior-y: contain; }

body {
  margin: 0;
  background:
    radial-gradient(1200px 500px at 50% -200px, var(--glow) 0%, transparent 60%),
    var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.6;
  min-height: 100svh; /* svh, not vh: vh is the LARGE viewport on iOS, so the
                         footer would sit under the Safari toolbar */
  display: flex;
  flex-direction: column;
  /* Notch / rounded-corner clearance in landscape and standalone mode. The
     background paints full-bleed underneath; only the content columns inset.
     env() is 0 everywhere else, so desktop is untouched. */
  padding-left: max(0px, env(safe-area-inset-left));
  padding-right: max(0px, env(safe-area-inset-right));
}

/* Touch ergonomics: no double-tap zoom while tapping answers fast, and no iOS
   gray flash competing with the amber/green/red answer states. Focus rings
   (:focus-visible, below) are untouched. */
button,
a,
summary,
[role="button"],
input,
select,
textarea,
label {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

.mono { font-family: var(--font-mono); }
.wrap { width: min(680px, 100% - 2.5rem); margin-inline: auto; flex: 1; }

/* ---------- header ---------- */

.site-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: min(680px, 100% - 2.5rem);
  margin: 1.25rem auto 2.5rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--line);
}

.wordmark {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  text-decoration: none;
  color: var(--text);
  font-family: var(--font-display);
  font-size: 1.05rem;
  letter-spacing: 0.14em;
}

.wordmark-num { color: var(--accent); margin-left: 0.35em; }

.pal-eye {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 42%, var(--amber-soft) 0 18%, var(--amber) 40%, #7a4d00 78%, #241800 100%);
  box-shadow: 0 0 14px rgba(255, 176, 0, 0.55), inset 0 0 4px rgba(0, 0, 0, 0.6);
  animation: eye-breathe 5s ease-in-out infinite;
}

@keyframes eye-breathe {
  0%, 100% { box-shadow: 0 0 10px rgba(255, 176, 0, 0.4), inset 0 0 4px rgba(0, 0, 0, 0.6); }
  50% { box-shadow: 0 0 20px rgba(255, 176, 0, 0.7), inset 0 0 4px rgba(0, 0, 0, 0.6); }
}

.head-status {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.22em;
  color: var(--dim);
}

/* Connectivity state, set by sw-register.js. Offline is a state, not chrome —
   it takes the accent so it reads as a readout rather than a caption. */
.head-status.offline { color: var(--accent); }

/* Phone headers have no room for the online readout, but it is a live region
   (role="status"): display:none would drop it out of the accessibility tree
   and the offline announcement would never fire. Clip it instead — invisible,
   still announced. Offline keeps its normal box (see below). */
@media (max-width: 480px) {
  .head-status:not(.offline) {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
}

/* Offline is exactly when the phone-sized reader needs the readout on screen.
   The longer string would squeeze the header at these widths, so it drops to
   its own line under the wordmark and toggle. Wrapping is opt-in on
   .site-head.offline (also set by sw-register.js) so the normal header keeps
   its single-line no-wrap layout. */
@media (max-width: 560px) {
  .site-head.offline { flex-wrap: wrap; }
  .site-head.offline .head-status {
    order: 1;
    flex-basis: 100%;
    margin-top: 0.6rem;
  }
}

.theme-toggle {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.14em;
  color: var(--dim);
  background: none;
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  padding: 0.45rem 0.7rem;
  min-height: 44px; /* Apple HIG / WCAG 2.5.5 (AAA); 2.5.8 (AA) only asks 24px */
  cursor: pointer;
}
.theme-toggle:hover, .theme-toggle:focus-visible {
  color: var(--accent);
  border-color: var(--accent);
}

/* ---------- hero / headings ---------- */

.kicker {
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  color: var(--accent);
  margin: 0 0 0.6rem;
}

h1 {
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 4.5vw, 2rem);
  letter-spacing: 0.04em;
  line-height: 1.25;
  margin: 0 0 0.75rem;
}

.lede { color: var(--dim); max-width: 56ch; margin: 0; }
.hero { margin-bottom: 2.75rem; }
.hero-quiz { margin-bottom: 1.75rem; }

.crumb { font-size: 0.75rem; letter-spacing: 0.12em; margin: 0 0 1.75rem; }
.crumb a { color: var(--dim); text-decoration: none; }
.crumb a:hover, .crumb a:focus-visible { color: var(--accent); }

.panel-label {
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  color: var(--dim);
  border-bottom: 1px solid var(--line);
  padding-bottom: 0.5rem;
  margin: 0 0 0.9rem;
  font-weight: 400;
}

/* ---------- mission list ---------- */

.mission-list { list-style: none; margin: 0 0 2.5rem; padding: 0; display: grid; gap: 0.6rem; }

.mission {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 1rem;
  padding: 0.9rem 1.1rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  text-decoration: none;
  color: var(--text);
  transition: border-color 140ms ease, transform 140ms ease;
}

.mission:hover, .mission:focus-visible {
  border-color: var(--accent);
  transform: translateX(3px);
}

.mission-num { color: var(--accent); font-size: 0.8rem; letter-spacing: 0.1em; }
.mission-title { font-weight: 600; }
.mission-meta { display: flex; gap: 0.9rem; font-size: 0.72rem; letter-spacing: 0.08em; color: var(--dim); }
.mission-meta .ok { color: var(--green); }
.mission-meta .alert { color: var(--accent); }
#review-count.alert { color: var(--accent); }

.review-panel { margin-bottom: 3rem; }
.hint { color: var(--dim); font-size: 0.85rem; margin-top: 0.9rem; }

/* ---------- quiz ---------- */

.quiz-panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 1.5rem 1.4rem 1.75rem;
  margin-bottom: 3rem;
}

.readout {
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  color: var(--accent);
  margin: 0 0 1.1rem;
}

.stem {
  font-family: var(--font-body);
  font-size: 1.1rem;
  font-weight: 600;
  line-height: 1.55;
  margin: 0 0 1.5rem;
  white-space: pre-line;
}

.options { display: grid; gap: 0.6rem; }

.option {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.9rem;
  align-items: baseline;
  width: 100%;
  text-align: left;
  padding: 0.85rem 1rem;
  background: var(--panel-raised);
  color: var(--text);
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  font: inherit;
  line-height: 1.5;
  cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
}

.option:hover:not(:disabled), .option:focus-visible:not(:disabled) { border-color: var(--accent); }
.option:disabled { cursor: default; }

.option-key {
  color: var(--accent);
  font-size: 0.8rem;
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 0.05rem 0.45rem;
}

.option.is-correct { border-color: var(--green); background: var(--tint-correct); }
.option.is-correct .option-key { color: var(--green); border-color: var(--green); }
.option.is-wrong { border-color: var(--red); background: var(--tint-wrong); }
.option.is-wrong .option-key { color: var(--red); border-color: var(--red); }
.option.is-dim { opacity: 0.45; }

/* ---------- feedback ---------- */

.feedback { margin-top: 1.4rem; }
.feedback:empty { display: none; }

.fb-verdict { font-size: 0.78rem; letter-spacing: 0.18em; margin: 0 0 0.7rem; }
.fb-verdict.ok { color: var(--green); }
.fb-verdict.no { color: var(--red); }

.fb-correct { margin: 0 0 0.9rem; }
.fb-distractor { color: var(--dim); margin: 0 0 0.9rem; }

.fb-tag {
  display: inline-block;
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  color: var(--accent);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 0.1rem 0.45rem;
  margin-right: 0.5rem;
  vertical-align: 0.1em;
}

.self-explain {
  border: 1px dashed var(--accent);
  border-radius: 6px;
  padding: 0.9rem 1rem;
  margin: 1.1rem 0 1.3rem;
  background: rgba(255, 176, 0, 0.05);
}
.self-explain p { margin: 0.5rem 0 0; }

.btn-next {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  color: var(--btn-text);
  background: var(--amber);
  border: none;
  border-radius: 6px;
  padding: 0.85rem 1.4rem;
  cursor: pointer;
  text-decoration: none;
  transition: filter 120ms ease;
}
.btn-next:hover, .btn-next:focus-visible { filter: brightness(1.12); }

/* ---------- completion ---------- */

.done-panel { text-align: center; padding-block: 2.5rem; }
.done-score {
  font-family: var(--font-display);
  font-size: 2.4rem;
  color: var(--accent);
  margin: 0.5rem 0 1rem;
}
.done-note { color: var(--dim); max-width: 44ch; margin: 0 auto 1.5rem; }
.done-stamp {
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.8rem 1rem;
  display: inline-block;
  margin: 0 0 1.5rem;
  line-height: 1.9;
}

/* ---------- footer ---------- */

.site-foot {
  width: min(680px, 100% - 2.5rem);
  /* Clears the home indicator when installed to the home screen; env() is 0
     on desktop, where max() keeps the original 1.5rem. */
  margin: 3rem auto max(1.5rem, calc(env(safe-area-inset-bottom) + 0.75rem));
  padding-top: 1rem;
  border-top: 1px solid var(--line);
  font-size: 0.8rem;
  color: var(--dim);
}
.site-foot p { margin: 0.3rem 0; }
.site-foot a { color: var(--dim); }
.site-foot a:hover, .site-foot a:focus-visible { color: var(--accent); }
.foot-dim { color: var(--dim-2); font-size: 0.75rem; }

/* ---------- disclosure, stamps, helpers ---------- */

.others {
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.6rem 1rem;
  margin: 0 0 0.9rem;
}
.others summary {
  cursor: pointer;
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  color: var(--dim);
}
.others summary:hover, .others summary:focus-visible { color: var(--accent); }
.others p { color: var(--dim); margin: 0.7rem 0 0; }

.btn-next:disabled {
  opacity: 0.55;
  cursor: wait;
  filter: none;
}

.stamp-banner {
  border: 1px solid var(--line);
  border-left: 3px solid var(--green);
  border-radius: 6px;
  padding: 0.9rem 1.1rem;
  margin-bottom: 1.25rem;
  background: var(--panel);
}
.stamp-line { margin: 0; font-size: 0.8rem; letter-spacing: 0.06em; }
.stamp-note { display: inline-block; color: var(--dim); font-size: 0.85rem; margin-top: 0.4rem; }
.stamp-banner .stamp-note { margin: 0.4rem 0 0; }

/* Install prompt on the home page — shown by home.js once there's progress
   worth protecting, dismissed for good with GOT IT. */
.install-hint {
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 6px;
  background: var(--panel);
  padding: 1.1rem 1.2rem 1.2rem;
  margin-bottom: 3rem;
}
.install-hint p { font-size: 0.9rem; margin: 0 0 0.8rem; max-width: 58ch; }
.install-steps { color: var(--dim); }
.install-steps .mono {
  color: var(--accent);
  font-size: 0.66rem;
  letter-spacing: 0.18em;
  margin-right: 0.6em;
}
.install-warn { color: var(--dim); }
.install-warn a { color: var(--accent); }

.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;
}

/* ---------- systems page ---------- */

[hidden] { display: none !important; }

.status-strip {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dim);
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  padding: 0.6rem 1rem;
  margin: 0 0 2.25rem;
}
.status-strip .v { color: var(--accent); }
.status-strip .sep { color: var(--dim-2); }

.sys-block { margin-bottom: 2.25rem; }
.sys-note { color: var(--dim); font-size: 0.88rem; margin: 0 0 0.9rem; max-width: 58ch; }

.term {
  background: var(--panel);
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  overflow: hidden;
}
.term-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.6rem;
  background: var(--panel-raised);
  border-bottom: 1px solid var(--line);
  padding: 0.5rem 0.7rem 0.5rem 1rem;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  color: var(--dim);
}
.term-copy {
  font-size: 0.6rem;
  letter-spacing: 0.14em;
  color: var(--dim);
  background: none;
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  padding: 0.3rem 0.55rem;
  cursor: pointer;
  position: relative;
}
/* The terminal header bar is deliberately slim, so the button stays 38px tall
   and grows an invisible hit area instead: 38 + 2×4 = 46px of tappable height,
   which stays inside the .term-head padding and overlaps nothing clickable. */
.term-copy::after {
  content: '';
  position: absolute;
  inset: -4px -6px;
}
.term-copy:hover, .term-copy:focus-visible { color: var(--accent); border-color: var(--accent); }
.term-body {
  padding: 0.9rem 1.1rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  line-height: 2;
  letter-spacing: 0.04em;
}
.term-body .ok { color: var(--green); }
.term-body .off { color: var(--dim-2); }
.term-body.empty { font-family: var(--font-body); color: var(--dim); font-size: 0.88rem; line-height: 1.6; }

.act { display: flex; gap: 0.7rem; flex-wrap: wrap; align-items: center; }

.btn-ghost {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  color: var(--text);
  background: var(--panel-raised);
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  padding: 0.85rem 1.4rem;
  cursor: pointer;
}
.btn-ghost:hover, .btn-ghost:focus-visible { border-color: var(--accent); color: var(--accent); }

.btn-danger {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  color: var(--red);
  background: none;
  border: 1px solid var(--red);
  border-radius: 6px;
  padding: 0.85rem 1.4rem;
  cursor: pointer;
}
.btn-danger:hover, .btn-danger:focus-visible { background: var(--tint-wrong); }

/* Clipboard import: the fallback transport for installed iOS apps, where blob
   downloads silently fail and storage is walled off from Safari's. */
.paste-form {
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: var(--panel);
  padding: 1rem 1.1rem;
  margin-top: 0.7rem;
}
.paste-label { display: block; color: var(--dim); font-size: 0.85rem; margin-bottom: 0.5rem; }
.paste-text {
  display: block;
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
  font-size: 0.72rem;
  line-height: 1.6;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  padding: 0.6rem 0.7rem;
  margin-bottom: 0.9rem;
}
.paste-text:focus-visible { border-color: var(--accent); }

.confirm {
  border: 1px solid var(--red);
  border-radius: 6px;
  background: var(--tint-wrong);
  padding: 1rem 1.1rem;
  margin-top: 0.7rem;
}
.confirm.warn { border-color: var(--accent); background: rgba(255, 176, 0, 0.05); }
.confirm p { margin: 0 0 0.9rem; font-size: 0.95rem; }
.confirm .strong { font-weight: 600; }

.status-msg { color: var(--dim); font-size: 0.85rem; margin: 0.7rem 0 0; }
.status-msg:empty { display: none; }
.status-msg.err { color: var(--red); }

/* ---------- a11y / motion ---------- */

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .pal-eye { animation: none; }
  .mission, .option, .btn-next { transition: none; }
}
