/*
 * Styles for the student and teacher apps.
 *
 * Accessibility commitments (WCAG 2.1 AA), made concrete:
 *   - Every text/background pair below meets 4.5:1; large text meets 3:1.
 *   - Focus is ALWAYS visible. No `outline: none` anywhere in this file.
 *   - Colour never carries meaning alone: pass/fail states have an icon and a
 *     word as well as a colour.
 *   - `prefers-reduced-motion` disables every transition and animation.
 *   - Hit targets are at least 44x44 CSS px.
 *   - Body text is 17px with a 1.65 line height, and layout is fluid down to
 *     320px so lesson prose is readable on a phone.
 */

/* ---------------------------------------------------------------- */
/* Tokens                                                            */
/* ---------------------------------------------------------------- */

:root {
  /* A light, cheerful palette: warm cream background, sun-orange accent.
     Every text/background pair below is checked at >= 4.5:1 (large text
     >= 3:1) with the WCAG relative-luminance formula -- see .wizard history
     for the exact ratios computed while choosing these. */
  --bg: #fff8ee;
  --bg-subtle: #fff1dc;
  --surface: #ffffff;
  --fg: #2b2140;
  --muted: #5b4a70;
  --border: #ead9bf;

  --accent: #c7440c;
  --accent-fg: #ffffff;
  --accent-subtle: #ffe8d6;

  --pass: #0b6b3a;
  --pass-bg: #e3f6e9;
  --fail: #9c2320;
  --fail-bg: #fdeceb;
  --warn: #7a4b06;
  --warn-bg: #fff3d6;

  --focus: #b34700;

  --editor-bg: #fffdf7;
  --editor-fg: #2b2140;
  --editor-gutter: #fff3e0;
  /* Semi-transparent on purpose: CodeMirror paints the selection layer at
     z-index -2, BEHIND the line, so an opaque active line hides the selection
     on the one line you are always selecting on. */
  --editor-active: rgba(199, 68, 12, 0.08);
  /* CodeMirror's own caret is black and its selection is a pale lavender,
     both hard-coded for a light editor. Ours follow the page theme instead. */
  --editor-caret: #2b2140;
  --editor-selection: #ffd9b3;
  --editor-match: rgba(255, 196, 61, 0.45);

  /* Syntax colours. Every one of these is >= 4.5:1 against --editor-bg. */
  --tok-keyword: #8118a8;
  --tok-name: #2b2140;
  --tok-function: #b34700;
  --tok-constant: #7a4b06;
  --tok-type: #0b6b6e;
  --tok-operator: #4a4358;
  --tok-string: #a11111;
  --tok-comment: #6b6478;
  --tok-invalid: #9c2320;

  --radius: 14px;
  --shadow: 0 1px 2px rgba(43, 33, 64, 0.06), 0 4px 12px rgba(43, 33, 64, 0.06);
  --measure: 68ch;
}

:root[data-theme='dark'] {
  --bg: #10141a;
  --bg-subtle: #171d26;
  --surface: #1a212b;
  --fg: #e9edf3;
  --muted: #a2aebd;
  --border: #2f3947;

  /* Same warm family as the light theme's accent, retuned for a dark ground. */
  --accent: #ffb37a;
  --accent-fg: #241200;
  --accent-subtle: #33231a;

  --pass: #6cd39a;
  --pass-bg: #12281d;
  --fail: #ff9a92;
  --fail-bg: #2c1614;
  --warn: #f0c274;
  --warn-bg: #2b2113;

  --focus: #ffb060;

  --editor-bg: #141a22;
  --editor-fg: #e9edf3;
  --editor-gutter: #171e27;
  --editor-active: rgba(255, 179, 122, 0.1);
  --editor-caret: #e9edf3;
  --editor-selection: #2b4a72;
  --editor-match: rgba(255, 196, 61, 0.26);

  --tok-keyword: #cf9bf0;
  --tok-name: #e9edf3;
  --tok-function: #ffb37a;
  --tok-constant: #f0c274;
  --tok-type: #6cd39a;
  --tok-operator: #c3cdda;
  --tok-string: #ff9a92;
  --tok-comment: #a2aebd;
  --tok-invalid: #ff9a92;

  --shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 4px 14px rgba(0, 0, 0, 0.4);
}

* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 17px/1.65 system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* ---------------------------------------------------------------- */
/* Focus and skip link                                               */
/* ---------------------------------------------------------------- */

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent);
  color: var(--accent-fg);
  padding: 0.75rem 1.25rem;
  z-index: 100;
  border-radius: 0 0 var(--radius) 0;
}
.skip-link:focus {
  left: 0;
}

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

.mt-0 {
  margin-top: 0;
}

/* ---------------------------------------------------------------- */
/* Layout                                                            */
/* ---------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: 1080px;
  margin: 0 auto;
  padding: 1.5rem 1.25rem 4rem;
}

.container-narrow {
  width: 100%;
  max-width: 34rem;
  margin: 0 auto;
  padding: 3rem 1.25rem 4rem;
}

main {
  flex: 1;
}

.site-header {
  background: var(--bg-subtle);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 20;
}

.site-header-inner {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0.6rem 1.25rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.brand-mark {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: inherit;
  text-decoration: none;
  /* Keeps the logo+wordmark from being squeezed by neighboring flex items in
     .site-header-inner at narrow widths. */
  min-width: max-content;
}

.brand-logo {
  display: block;
  border-radius: 6px;
  flex-shrink: 0;
}

.brand-logo-full {
  display: block;
  height: 32px;
  width: auto;
  border-radius: 6px;
}

.wordmark {
  font-weight: 700;
  letter-spacing: -0.01em;
}

.header-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.course-label {
  font-size: 0.85rem;
  color: var(--muted);
  white-space: nowrap;
}
.course-label[hidden] {
  display: none;
}

.course-switcher {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}
/* An explicit `display` above would otherwise outrank the UA stylesheet's
   `[hidden] { display: none }` -- found while auditing the same footgun in
   .certificate-link and .btn-google during this change. */
.course-switcher[hidden] {
  display: none;
}
.course-switcher .btn[aria-pressed="true"] {
  background: var(--accent, var(--fg));
  color: var(--bg);
}

.identity {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  color: var(--muted);
  flex-wrap: wrap;
}
/* Same footgun as .course-switcher/.certificate-link/.btn-google below: an
   explicit `display` here would otherwise outrank `[hidden] { display: none }`,
   leaving a signed-out visitor looking at an empty identity bar with a
   "Sign out" button in it. */
.identity[hidden] {
  display: none;
}
.identity-name {
  color: var(--fg);
  font-weight: 600;
}

.identity-avatar {
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  border: 2px solid var(--border);
  object-fit: cover;
}

.btn-google {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
}
.btn-google[hidden] {
  display: none;
}
.google-g {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  background: var(--surface);
  color: var(--accent);
  font-weight: 700;
  font-size: 0.9rem;
}

.join-class {
  margin: 1.25rem 0;
}
.join-class summary {
  cursor: pointer;
  color: var(--accent);
  font-weight: 600;
}
.join-class form {
  margin-top: 0.75rem;
  display: flex;
  align-items: flex-end;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.certificate-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.75rem 0 1.25rem;
  text-decoration: none;
}
/* An explicit `display` above would otherwise outrank the UA stylesheet's
   `[hidden] { display: none }`, leaving the link visible while "hidden". */
.certificate-link[hidden] {
  display: none;
}

#header-login-link[hidden] {
  display: none;
}

.python-status {
  margin: 0;
  padding: 0.5rem 1.25rem;
  background: var(--accent-subtle);
  color: var(--fg);
  font-size: 0.9rem;
  text-align: center;
}
.python-status.is-warning {
  background: var(--warn-bg);
  color: var(--warn);
}

.site-footer {
  border-top: 1px solid var(--border);
  padding: 1.5rem 1.25rem;
  color: var(--muted);
  font-size: 0.85rem;
  text-align: center;
}
/* Guards a footer with nothing in it (a template that dropped its include) --
   the site's own footer now always carries int_legal/_identity_block.html. */
.site-footer:empty {
  display: none;
}

/* int_legal/_identity_block.html -- this site loads no Bootstrap, so the
   shared footer partial's utility classes need plain-CSS equivalents or the
   policy links degrade to a stacked bulleted list (the documented
   int_intelligena symptom). */
.int-legal-identity {
  margin-top: 0.5rem;
}
.int-legal-identity.small,
.int-legal-identity p {
  font-size: 0.8rem;
  color: var(--muted);
  margin: 0.2rem 0;
}
.int-legal-identity a {
  color: inherit;
}
.int-legal-identity .list-inline {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 0.9rem;
  list-style: none;
  margin: 0.2rem 0 0;
  padding: 0;
}
.int-legal-identity .list-inline-item {
  display: inline;
}

/* Cleared once boot() knows which screen to reveal -- otherwise a signed-in
   visitor to '/' sees the full-bleed landing photo flash before the course
   screen replaces it. */
body.is-booting main {
  visibility: hidden;
}

/* ---------------------------------------------------------------- */
/* Landing                                                           */
/*                                                                    */
/* Deliberately NOT built from --bg/--fg: the brief asks for a fixed  */
/* white bar, panel and footer regardless of the light/dark theme */
/* toggle, so these tokens do not vary under :root[data-theme='dark'] */
/* and every rule below reads from them, never from the page tokens.  */
/* ---------------------------------------------------------------- */

/* Declared on :root (not scoped to `.landing`) because `.site-header--landing`
   needs them and the header is a SIBLING of `#screen-landing`, not a
   descendant -- a custom property scoped to `.landing` never reaches it
   (custom properties cascade down the tree from where they're declared, not
   sideways). Still theme-invariant: absent from the `:root[data-theme='dark']`
   block below, on purpose. */
:root {
  --landing-topbar: #ffffff;
  --landing-panel: #ffffff;
  --landing-fg: #111827;
  --landing-fg-muted: #4b5563;
  --card-blue-bg: #dbeafe;
  --card-blue-fg: #1e3a5f;
  --card-green-bg: #d7f0e0;
  --card-green-fg: #1e4a34;
}

.landing {
  /* Fixed accent for buttons/focus rings nested INSIDE the landing screen
     (a real descendant relationship, unlike the header above), so they don't
     flip with the theme toggle either. */
  --accent: #c7440c;
  --accent-fg: #ffffff;
  --focus: #b34700;
}

.site-header--landing {
  background: var(--landing-topbar);
  border-bottom-color: #e5e7eb;
}
body.on-landing .site-footer {
  background: #ffffff;
  color: var(--landing-fg-muted);
  border-top-color: #e5e7eb;
}
.site-header--landing .wordmark,
.site-header--landing .course-label,
.site-header--landing #header-login-link,
.site-header--landing #theme-toggle {
  color: #111827;
}

.landing-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  /* `minmax(100vh, auto)`, not a fixed height: if the right column's content
     ever exceeds one viewport, the row -- and the photo with it -- grows to
     match, rather than the photo letterboxing while the panel overflows.
     Because .site-header stays in normal flow (sticky, not fixed), total
     page height becomes header-height + 100vh: the page runs slightly below
     the fold, which is what was asked for. */
  grid-template-rows: minmax(100vh, auto);
}

.landing-photo {
  overflow: hidden;
}
.landing-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.landing-panel {
  background: var(--landing-panel);
  color: var(--landing-fg);
  padding: clamp(2rem, 4vw, 4rem) clamp(1.5rem, 4vw, 3rem);
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}
.landing-panel .lede,
.landing-panel .fine-print {
  color: var(--landing-fg-muted);
}

/* .google-g's own background reads --surface, which this scope deliberately
   does not override (nothing else in the landing screen uses it) -- fixed
   directly here instead, for the same reason --accent/--accent-fg/--focus
   are fixed above: this button must not flip with the theme toggle. */
.landing .google-g {
  background: #ffffff;
}

.landing-tagline {
  font-size: clamp(1.4rem, 1.1rem + 1.2vw, 2rem);
  font-weight: 700;
  font-style: italic;
  color: var(--landing-fg);
  margin: 0 0 1.5rem;
}

.course-cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.landing-kicker {
  margin: 0 0 0.35rem;
  font-weight: 800;
  font-size: 0.95rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

.course-card {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 1.25rem 1.5rem;
  border: 1px solid #e5e7eb;
  border-left: 6px solid var(--card-accent);
  border-radius: var(--radius);
  background: #ffffff;
  box-shadow: 0 1px 3px rgba(17, 24, 39, 0.08);
  color: var(--landing-fg);
  text-decoration: none;
  min-height: 44px;
  transition: transform 120ms ease, box-shadow 120ms ease;
}
/* Same footgun as .course-switcher/.identity/.certificate-link/.btn-google
   above: an explicit `display` here would otherwise outrank the UA
   stylesheet's `[hidden] { display: none }`. */
.course-card[hidden] {
  display: none;
}
.course-card--blue {
  --card-accent: #2563eb;
  --card-tint: var(--card-blue-bg);
  --card-ink: var(--card-blue-fg);
}
.course-card--green {
  --card-accent: #16a34a;
  --card-tint: var(--card-green-bg);
  --card-ink: var(--card-green-fg);
}
.course-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(17, 24, 39, 0.12);
}
.course-card:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}
.course-card-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.course-card-icon {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 999px;
  background: var(--card-tint);
  color: var(--card-ink);
  font-weight: 700;
  font-size: 0.85rem;
}
.course-card-title {
  font-weight: 700;
  font-size: 1.2rem;
}
.course-card-subtitle {
  font-size: 0.95rem;
  line-height: 1.45;
  color: var(--landing-fg-muted);
}
.course-card-skills {
  list-style: none;
  margin: 0.2rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.3rem;
  font-size: 0.92rem;
}
.course-card-skills li {
  position: relative;
  padding-left: 1.5rem;
}
.course-card-skills li::before {
  content: "\2713";
  position: absolute;
  left: 0;
  font-weight: 700;
  color: var(--card-accent);
}

@media (max-width: 48rem) {
  .landing-split {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
  }
  .landing-photo {
    height: 45vh;
  }
}

/* ---------------------------------------------------------------- */
/* Typography                                                        */
/* ---------------------------------------------------------------- */

h1 {
  font-size: clamp(1.6rem, 1.2rem + 1.8vw, 2.3rem);
  line-height: 1.2;
  letter-spacing: -0.02em;
  margin: 0.2em 0 0.5em;
}
h2 {
  font-size: clamp(1.25rem, 1.1rem + 0.8vw, 1.6rem);
  line-height: 1.25;
  margin: 2.25rem 0 0.75rem;
}
h3 {
  font-size: 1.15rem;
  margin: 1.75rem 0 0.5rem;
}
h1:focus,
h2:focus {
  outline: none; /* programmatic focus for screen readers; not keyboard-reachable */
}

.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--muted);
  margin: 0;
}

.lede {
  font-size: 1.1rem;
  color: var(--muted);
}

.muted {
  color: var(--muted);
}

.fine-print {
  margin-top: 2rem;
  font-size: 0.85rem;
  color: var(--muted);
}

.prose {
  max-width: var(--measure);
}
.prose p,
.prose li {
  font-size: 1.02rem;
}
.prose code {
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.1em 0.35em;
  font-size: 0.9em;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.prose table {
  border-collapse: collapse;
  width: 100%;
  margin: 1rem 0;
  display: block;
  overflow-x: auto;
}
.prose th,
.prose td {
  border: 1px solid var(--border);
  padding: 0.5rem 0.7rem;
  text-align: left;
}
.prose blockquote {
  border-left: 4px solid var(--accent);
  margin: 1rem 0;
  padding: 0.25rem 0 0.25rem 1rem;
  color: var(--muted);
}
.prose .admonition {
  border: 1px solid var(--border);
  border-left: 4px solid var(--warn);
  background: var(--warn-bg);
  border-radius: var(--radius);
  padding: 0.75rem 1rem;
  margin: 1.25rem 0;
}
.prose .admonition-title {
  font-weight: 700;
  margin-top: 0;
}

/* ---------------------------------------------------------------- */
/* Lesson infographics: inline <svg> inside <figure class="infographic"> */
/* Colours come from the theme tokens, so light and dark both work and  */
/* the CSP needs no inline <style>. Never rely on colour alone: every   */
/* state also carries a label or a shape (see docs/09).                 */
/* ---------------------------------------------------------------- */

.prose figure.infographic {
  margin: 1.5rem 0;
  padding: 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.prose figure.infographic svg {
  display: block;
  width: 100%;
  height: auto;
  max-width: 100%;
}
.prose figure.infographic figcaption {
  margin-top: 0.5rem;
  font-size: 0.9rem;
  color: var(--muted);
}
.ig-text { fill: var(--fg); font: 14px/1.2 system-ui, sans-serif; }
.ig-mono { fill: var(--fg); font: 14px/1.2 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.ig-muted { fill: var(--muted); font: 13px/1.2 system-ui, sans-serif; }
.ig-title { fill: var(--fg); font: 700 15px/1.2 system-ui, sans-serif; }
.ig-box { fill: var(--bg-subtle); stroke: var(--border); stroke-width: 2; }
.ig-accent { fill: var(--accent-subtle); stroke: var(--accent); stroke-width: 2; }
.ig-pass { fill: var(--pass-bg); stroke: var(--pass); stroke-width: 2; }
.ig-fail { fill: var(--fail-bg); stroke: var(--fail); stroke-width: 2; }
.ig-warn { fill: var(--warn-bg); stroke: var(--warn); stroke-width: 2; }
.ig-line { stroke: var(--fg); stroke-width: 2; fill: none; }
.ig-line-fail { stroke: var(--fail); stroke-width: 2; stroke-dasharray: 6 4; fill: none; }
.ig-arrowhead { fill: var(--fg); }

/* ---------------------------------------------------------------- */
/* Buttons and forms                                                 */
/* ---------------------------------------------------------------- */

.btn {
  font: inherit;
  font-weight: 600;
  min-height: 44px;
  padding: 0.55rem 1.1rem;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--fg);
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.btn:hover:not(:disabled) {
  background: var(--bg-subtle);
}
.btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}
.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
}
.btn-primary:hover:not(:disabled) {
  filter: brightness(1.08);
  background: var(--accent);
}
.btn-quiet {
  background: transparent;
  border-color: transparent;
  color: var(--muted);
}
.btn-quiet:hover:not(:disabled) {
  color: var(--fg);
  background: var(--bg-subtle);
}
.btn-small {
  min-height: 36px;
  padding: 0.3rem 0.7rem;
  font-size: 0.875rem;
}
.btn-danger {
  border-color: var(--fail);
  color: var(--fail);
}

.field {
  margin-bottom: 1.25rem;
}
.field label {
  display: block;
  font-weight: 600;
  margin-bottom: 0.3rem;
}
.field input,
.field select,
.field textarea {
  font: inherit;
  width: 100%;
  min-height: 44px;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--fg);
}
.field textarea {
  min-height: 8rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.field-help {
  margin: 0.35rem 0 0;
  font-size: 0.85rem;
  color: var(--muted);
}

.form-error {
  background: var(--fail-bg);
  color: var(--fail);
  border: 1px solid currentColor;
  border-radius: var(--radius);
  padding: 0.7rem 0.9rem;
  margin: 0 0 1rem;
}

/* ---------------------------------------------------------------- */
/* Course map                                                        */
/* ---------------------------------------------------------------- */

.progress-block {
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem 1.15rem;
  margin-bottom: 2rem;
}
.progress-track {
  height: 12px;
  background: var(--border);
  border-radius: 999px;
  overflow: hidden;
}
.progress-bar {
  height: 100%;
  width: 0;
  background: var(--accent);
  border-radius: 999px;
  transition: width 300ms ease;
}
.progress-text {
  margin: 0.55rem 0 0;
  font-size: 0.95rem;
}
.streak {
  margin: 0.35rem 0 0;
  color: var(--pass);
  font-weight: 600;
  font-size: 0.9rem;
}

.lesson-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
  gap: 0.85rem;
}
.block-heading {
  grid-column: 1 / -1;
  margin: 1.75rem 0 0.25rem;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.lesson-card {
  display: flex;
}
.lesson-card-inner {
  display: grid;
  gap: 0.2rem;
  width: 100%;
  text-align: left;
  font: inherit;
  padding: 1rem 1.1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--fg);
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: transform 120ms ease, border-color 120ms ease;
}
button.lesson-card-inner:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
}
.lesson-card.is-locked .lesson-card-inner {
  opacity: 0.6;
  cursor: default;
  box-shadow: none;
  background: var(--bg-subtle);
}
.lesson-card.is-complete .lesson-card-inner {
  border-left: 4px solid var(--pass);
}
.lesson-number {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.lesson-title {
  font-weight: 650;
  font-size: 1.05rem;
}
.lesson-summary {
  color: var(--muted);
  font-size: 0.9rem;
}
.lesson-status {
  margin-top: 0.35rem;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--accent);
}
.lesson-card.is-complete .lesson-status {
  color: var(--pass);
}
.lesson-card.is-locked .lesson-status {
  color: var(--muted);
}

.back-link {
  margin-bottom: 0.5rem;
}

.objectives {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.6rem 0.9rem;
  margin-bottom: 1.5rem;
  background: var(--bg-subtle);
}
.objectives summary {
  cursor: pointer;
  font-weight: 600;
}
.objective-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.8em;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.05em 0.3em;
}

/* ---------------------------------------------------------------- */
/* Runnable examples                                                 */
/* ---------------------------------------------------------------- */

.example {
  margin: 1.5rem 0;
}
.example-editor {
  max-height: 26rem;
  overflow: auto;
}
.example-bar {
  margin-top: 0.5rem;
}
.example-note {
  color: var(--muted);
  font-size: 0.85rem;
}
.example-output {
  margin: 0.5rem 0 0;
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius);
  padding: 0.7rem 0.9rem;
  white-space: pre-wrap;
  word-break: break-word;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9rem;
  overflow-x: auto;
}
.example-output.has-error {
  border-left-color: var(--fail);
  background: var(--fail-bg);
  color: var(--fail);
}

/* ---------------------------------------------------------------- */
/* Concept checks                                                    */
/* ---------------------------------------------------------------- */

.concept-check {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem 1.15rem;
  margin: 0 0 1rem;
  max-width: var(--measure);
}
.concept-check legend {
  font-weight: 650;
  padding: 0 0.35rem;
}
.radio-row {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.35rem 0;
  min-height: 44px;
}
.radio-row input {
  margin-top: 0.45rem;
  width: 20px;
  height: 20px;
  flex: none;
}
.radio-row label {
  cursor: pointer;
  padding-top: 0.2rem;
}
.concept-feedback {
  margin: 0.6rem 0 0;
  font-size: 0.92rem;
  padding: 0.5rem 0.7rem;
  border-radius: var(--radius);
}
.concept-feedback:empty {
  display: none;
}
.concept-feedback.is-correct {
  background: var(--pass-bg);
  color: var(--pass);
}
.concept-feedback.is-wrong {
  background: var(--warn-bg);
  color: var(--warn);
}

/* ---------------------------------------------------------------- */
/* Exercises                                                         */
/* ---------------------------------------------------------------- */

.exercise {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem 1.35rem 1.5rem;
  margin-bottom: 1.75rem;
  background: var(--surface);
  box-shadow: var(--shadow);
}
.exercise h3 {
  margin-top: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.exercise-prompt {
  white-space: pre-wrap;
  max-width: var(--measure);
  margin-bottom: 1rem;
}
.hidden-note {
  background: var(--accent-subtle);
  border-radius: var(--radius);
  padding: 0.6rem 0.85rem;
  font-size: 0.9rem;
  max-width: var(--measure);
}

.badge {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
  white-space: nowrap;
}
.badge-passed {
  background: var(--pass-bg);
  color: var(--pass);
  border-color: currentColor;
}
.badge-hidden {
  background: var(--bg-subtle);
}
.badge-guided {
  background: var(--accent-subtle);
  color: var(--accent);
}
.badge-synthesis {
  background: var(--warn-bg);
  color: var(--warn);
}

.editor-host {
  height: 22rem;
  margin-bottom: 0.4rem;
}
.editor-host .cm-editor {
  height: 100%;
}

/* CodeMirror decides "light" or "dark" from the theme it was built with, not
   from the page, so a page-level theme swap leaves it drawing a black caret on
   a dark editor (invisible) and a pale lavender selection over pale text
   (unreadable). These rules take both colours from our own variables, which do
   follow the page theme. The selection selector deliberately matches the shape
   and specificity of CodeMirror's own focused-selection rule -- anything less
   loses to it. */
.cm-editor .cm-cursor,
.cm-editor .cm-dropCursor {
  border-left-color: var(--editor-caret);
  border-left-width: 2px;
}
.cm-editor .cm-selectionLayer .cm-selectionBackground,
.cm-editor.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground {
  background: var(--editor-selection);
}
/* highlightSelectionMatches (part of basicSetup) washes every other copy of the
   selected word in a fixed #99ff7780 green, which over a dark editor reads as a
   pale block sitting on top of the text. */
.cm-editor .cm-selectionMatch {
  background-color: var(--editor-match);
}
/* Leave ::selection alone: CodeMirror sets it transparent on purpose, because
   drawSelection paints the layer above instead. Colouring both muddies them. */
.editor-hint {
  font-size: 0.8rem;
  color: var(--muted);
  margin: 0 0 0.75rem;
}

.controls {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  align-items: center;
}
.controls-note {
  flex-basis: 100%;
  margin: 0.5rem 0 0;
  font-size: 0.82rem;
  color: var(--muted);
  max-width: var(--measure);
}

.console {
  margin: 1rem 0 0;
  background: var(--editor-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.8rem 1rem;
  white-space: pre-wrap;
  word-break: break-word;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9rem;
  max-height: 20rem;
  overflow: auto;
}
.console.has-error {
  border-color: var(--fail);
  background: var(--fail-bg);
  color: var(--fail);
}

/* ---------------------------------------------------------------- */
/* Results                                                           */
/* ---------------------------------------------------------------- */

.results {
  margin-top: 1rem;
}
.result-banner {
  border-radius: var(--radius);
  padding: 0.8rem 1rem;
  margin-bottom: 0.85rem;
  border: 1px solid var(--border);
  border-left-width: 4px;
}
.result-banner p {
  margin: 0.35rem 0 0;
  font-size: 0.92rem;
}
.result-banner.is-pass {
  background: var(--pass-bg);
  border-left-color: var(--pass);
  color: var(--pass);
}
.result-banner.is-partial {
  background: var(--warn-bg);
  border-left-color: var(--warn);
  color: var(--warn);
}
.result-banner.is-error {
  background: var(--fail-bg);
  border-left-color: var(--fail);
  color: var(--fail);
}

.result-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0.4rem;
}
.result {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-subtle);
}
.result-icon {
  font-weight: 700;
  flex: none;
  width: 1.2em;
  text-align: center;
}
.result-passed .result-icon {
  color: var(--pass);
}
.result-failed .result-icon {
  color: var(--fail);
}
.result-skipped .result-icon,
.result-errored .result-icon {
  color: var(--muted);
}
.result-main {
  min-width: 0;
  flex: 1;
}
.result-name {
  font-weight: 600;
}
.result-message {
  margin: 0.3rem 0 0;
  font-size: 0.92rem;
  color: var(--muted);
}
.result-error {
  background: var(--fail-bg);
  color: var(--fail);
  border-radius: var(--radius);
  padding: 0.7rem 0.9rem;
}
.result-detail {
  margin-top: 0.5rem;
  font-size: 0.88rem;
}
.result-detail summary {
  cursor: pointer;
  color: var(--accent);
  min-height: 32px;
}
.result-detail dl {
  margin: 0.4rem 0 0;
}
.result-detail dt {
  font-weight: 600;
  font-size: 0.8rem;
  color: var(--muted);
  margin-top: 0.4rem;
}
.result-detail dd {
  margin: 0.15rem 0 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  white-space: pre-wrap;
  word-break: break-word;
  background: var(--editor-bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.35rem 0.5rem;
  overflow-x: auto;
}

.history {
  margin-top: 1rem;
  font-size: 0.9rem;
}
.history summary {
  cursor: pointer;
  color: var(--accent);
  font-weight: 600;
  min-height: 32px;
}
.attempt-list {
  margin: 0.5rem 0 0;
  padding-left: 1.4rem;
  color: var(--muted);
}

.teacher-feedback {
  margin-top: 1rem;
  border: 1px solid var(--accent);
  border-left-width: 4px;
  border-radius: var(--radius);
  background: var(--accent-subtle);
  padding: 0.75rem 0.95rem;
}
.teacher-feedback p {
  margin: 0.3rem 0 0;
}

/* ---------------------------------------------------------------- */
/* Teacher dashboard                                                 */
/* ---------------------------------------------------------------- */

.toolbar {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 1.25rem;
}
.toolbar .field {
  margin-bottom: 0;
}

.card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 1.15rem 1.3rem;
  margin-bottom: 1.25rem;
  box-shadow: var(--shadow);
}

.join-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: 0.15em;
  background: var(--accent-subtle);
  color: var(--accent);
  padding: 0.3rem 0.7rem;
  border-radius: var(--radius);
  display: inline-block;
}

.table-scroll {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
table.grid {
  border-collapse: collapse;
  width: 100%;
  font-size: 0.85rem;
}
table.grid th,
table.grid td {
  border-bottom: 1px solid var(--border);
  padding: 0.4rem 0.5rem;
  text-align: left;
  white-space: nowrap;
}
table.grid thead th {
  position: sticky;
  top: 0;
  background: var(--bg-subtle);
  z-index: 1;
}
table.grid tbody tr:hover {
  background: var(--bg-subtle);
}
.cell-pass {
  background: var(--pass-bg);
  color: var(--pass);
  font-weight: 700;
  text-align: center;
}
.cell-fail {
  background: var(--fail-bg);
  color: var(--fail);
  text-align: center;
}
.cell-none {
  color: var(--muted);
  text-align: center;
}

.heat {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));
  gap: 0.3rem;
}
.heat-cell {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.35rem;
  font-size: 0.7rem;
  text-align: center;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* ---------------------------------------------------------------- */
/* Motion and print                                                  */
/* ---------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

@media (max-width: 40rem) {
  .container,
  .container-narrow {
    padding-left: 1rem;
    padding-right: 1rem;
  }
  .editor-host {
    height: 18rem;
  }
  .controls .btn {
    flex: 1 1 auto;
  }
}

/* Forced-colors (Windows High Contrast): let the OS palette win, but keep
   borders so structure survives. */
@media (forced-colors: active) {
  .btn,
  .card,
  .exercise,
  .result,
  .lesson-card-inner,
  .course-card {
    border: 1px solid CanvasText;
  }
  .progress-bar {
    background: Highlight;
  }
}

/* ---- Legal pages (int_legal documents inside legal_shell.html) ---- */
.legal-main {
  background: var(--bg);
  color: var(--fg);
  padding: 2rem 1.25rem 3rem;
}
.legal-main .int-legal {
  max-width: 46rem;
  margin: 0 auto;
  padding: 0;
  line-height: 1.65;
}
.legal-main .int-legal h1 {
  font-size: clamp(1.6rem, 1.3rem + 1.2vw, 2.2rem);
  line-height: 1.2;
  margin: 0 0 0.75rem;
}
.legal-main .int-legal h2,
.legal-main .int-legal h3 {
  line-height: 1.3;
  margin: 2rem 0 0.5rem;
}
.legal-main .int-legal p,
.legal-main .int-legal li {
  max-width: 68ch;
}
.legal-main .int-legal a {
  color: var(--accent);
}
.legal-main .int-legal table {
  width: 100%;
  border-collapse: collapse;
  margin: 1rem 0;
  font-size: 0.92rem;
}
.legal-main .int-legal th,
.legal-main .int-legal td {
  border: 1px solid var(--border);
  padding: 0.5rem 0.65rem;
  text-align: left;
  vertical-align: top;
}
.legal-main .int-legal th {
  background: var(--bg-subtle);
}
