/* blendtutor design tokens + semantic layout shell
 *
 * This file defines the --bt- design-token system and semantic region rules
 * shared by both webR and Pyodide target shells. It is embedded at compile
 * time via include_str! in crates/core/src/site/mod.rs and referenced by
 * both index.html shells via <link rel="stylesheet" href="styles.css">.
 *
 * What it does:
 *  - Declares all --bt- custom properties in :root (typography, color, spacing,
 *    radii) — the single source of truth for cross-target visual vocabulary.
 *  - Overrides all --bt-color-* tokens inside @media (prefers-color-scheme: dark)
 *    for WCAG AA dark-mode contrast (4.5:1 text, 3:1 UI / large text).
 *  - Styles the page shell: <header.site-header>, <main.workspace>,
 *    <footer.site-footer>, <body>, <h1> — the foundation AC-2 and AC-3 build on.
 *
 * What it does NOT do:
 *  - No component-level styles for the workspace internals (textarea, controls,
 *    output, feedback panel) — AC-2 and AC-3 own those regions.
 *  - No eval-results styling.
 *
 * Token contract for AC-2 (workspace styling):
 *   --bt-font-family-code, --bt-color-surface-code, --bt-color-status-*,
 *   --bt-radius-*, --bt-space-*
 *
 * Token contract for AC-3 (BYOK feedback panel styling):
 *   --bt-color-text-*, --bt-radius-*, --bt-font-family-ui, --bt-space-*
 */

/* ── Design tokens ─────────────────────────────────────────────── */

:root {
  /* Typography */
  --bt-font-family-ui: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --bt-font-family-code: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  --bt-font-size-base: 1rem;
  --bt-line-height: 1.5;

  /* Colors — light theme */
  --bt-color-surface: #ffffff;
  --bt-color-surface-code: #f5f5f5;
  --bt-color-text-primary: #1a1a1a;
  --bt-color-text-secondary: #555555;
  --bt-color-status-pass: #0a7d28;
  --bt-color-status-fail: #c0202a;
  --bt-color-status-running: #b06a00;
  --bt-color-brand: #1a1a1a;
  --bt-color-brand-hover: #000000;
  --bt-color-border: #d4d4d4;
  --bt-color-status-idle: #e8e8e8;

  /* Spacing */
  --bt-space-page-width: 50rem;
  --bt-space-xs: 0.25rem;
  --bt-space-sm: 0.5rem;
  --bt-space-md: 0.75rem;
  --bt-space-lg: 1rem;

  /* Shadows */
  --bt-shadow-sm: 0 1px 3px rgba(0,0,0,0.08);

  /* Radii */
  --bt-radius-sm: 0.25rem;
  --bt-radius-md: 0.5rem;
  --bt-radius-pill: 9999px;

  /* AC-3: BYOK verdict tint backgrounds — distinct from status-pass/fail accents */
  --bt-color-success-bg: #e8f5e9;
  --bt-color-danger-bg: #fff3e0;

  /* Syntax highlighting token colors — CM6 default light-theme palette. Used
   * by the custom HighlightStyle's `.tok-*` classes (lesson-runner-core.js).
   * Distinct from the status/surface vocabulary; a fixed syntax palette. Dark-
   * mode overrides in the @media block below use a VS Code dark-theme palette. */
  --bt-color-syntax-keyword: #055;
  --bt-color-syntax-string: #a11;
  --bt-color-syntax-number: #708;
  --bt-color-syntax-comment: #6a6a6a;
  --bt-color-syntax-variable: #000;
  --bt-color-syntax-function: #30a;
  --bt-color-syntax-operator: #000;

  /* Cursor — dark on light background (same as CM6 default black). The
   * dark-mode override sets this to #ffffff for maximum contrast. */
  --bt-color-cursor: #1a1a1a;
}

/* ── Semantic region rules ─────────────────────────────────────── */

body {
  font-family: var(--bt-font-family-ui);
  font-size: var(--bt-font-size-base);
  line-height: var(--bt-line-height);
  color: var(--bt-color-text-primary);
  background: var(--bt-color-surface);
  max-width: var(--bt-space-page-width);
  margin: 0 auto;
  padding: 0 var(--bt-space-lg);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

header.site-header {
  display: flex;
  align-items: baseline;
  gap: var(--bt-space-md);
  padding: var(--bt-space-lg) 0;
  border-bottom: 1px solid var(--bt-color-border);
  margin-bottom: var(--bt-space-lg);
}

header.site-header h1 {
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--bt-color-brand);
  margin: 0;
}

header.site-header #boot-status {
  font-size: 0.875rem;
  color: var(--bt-color-text-secondary);
  margin: 0;
}

main.workspace {
  flex: 1;
  padding-bottom: var(--bt-space-lg);
}

footer.site-footer {
  padding: var(--bt-space-lg) 0;
  border-top: 1px solid var(--bt-color-border);
  font-size: 0.75rem;
  color: var(--bt-color-text-secondary);
  text-align: center;
}

/* === workspace === */
/* Lesson workspace region (<main class="workspace">). Component-level rules
 * for picker, editor, controls, status badge, and output console. Scoped to
 * workspace-specific selectors — no bare element selectors that bleed into
 * header/footer.
 *
 * What it does NOT do:
 *  - No #feedback panel styling (AC-3 owns that region).
 *  - No header/footer overrides.
 *  - No JS changes — pure CSS only.
 *  - Dark mode is handled by the dark-mode @media block :root overrides
 *    at the bottom of this file — workspace rules inherit via var(--bt-*) tokens.
 */

.lesson-picker {
  display: flex;
  align-items: center;
  gap: var(--bt-space-sm);
}

.lesson-picker label {
  color: var(--bt-color-text-secondary);
}

.lesson-picker select {
  border: 1px solid var(--bt-color-border);
  border-radius: var(--bt-radius-md);
  padding: var(--bt-space-xs) var(--bt-space-sm);
  background: var(--bt-color-surface);
  color: var(--bt-color-text-primary);
  font-family: var(--bt-font-family-ui);
}

#lesson-title {
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--bt-color-text-primary);
  margin-bottom: var(--bt-space-sm);
}

#lesson-prompt {
  line-height: var(--bt-line-height);
  color: var(--bt-color-text-secondary);
  margin-bottom: var(--bt-space-md);
}

/* Hints — expandable <details> panel rendered by lesson-runner-core.js when a
 * lesson carries hints. Created dynamically (no static element in the HTML
 * shell); removed when switching to a lesson without hints. Dark mode is
 * handled by the existing :root token overrides in the @media block. */
#lesson-hints {
  margin-bottom: var(--bt-space-md);
  padding: var(--bt-space-sm) var(--bt-space-md);
  border: 1px solid var(--bt-color-border);
  border-radius: var(--bt-radius-md);
  background: var(--bt-color-surface-code);
}

#lesson-hints summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--bt-color-text-secondary);
}

#lesson-hints p {
  margin: var(--bt-space-sm) 0 0;
  color: var(--bt-color-text-secondary);
  line-height: var(--bt-line-height);
}

#lesson-hints ul {
  margin: var(--bt-space-sm) 0 0;
  padding-left: var(--bt-space-lg);
  color: var(--bt-color-text-secondary);
  line-height: var(--bt-line-height);
}

/* Gotchas — expandable <details> panel rendered by lesson-runner-core.js when a
 * lesson carries gotchas. Created dynamically (no static element in the HTML
 * shell); removed when switching to a lesson without gotchas. Dark mode is
 * handled by the existing :root token overrides in the @media block. */
#lesson-gotchas {
  margin-bottom: var(--bt-space-md);
  padding: var(--bt-space-sm) var(--bt-space-md);
  border: 1px solid var(--bt-color-border);
  border-radius: var(--bt-radius-md);
  background: var(--bt-color-surface-code);
}

#lesson-gotchas summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--bt-color-text-secondary);
}

#lesson-gotchas p {
  margin: var(--bt-space-sm) 0 0;
  color: var(--bt-color-text-secondary);
  line-height: var(--bt-line-height);
}

#lesson-gotchas ul {
  margin: var(--bt-space-sm) 0 0;
  padding-left: var(--bt-space-lg);
  color: var(--bt-color-text-secondary);
  line-height: var(--bt-line-height);
}

#submission {
  font-family: var(--bt-font-family-code);
  background: var(--bt-color-surface-code);
  border: 1px solid var(--bt-color-border);
  border-radius: var(--bt-radius-md);
  padding: var(--bt-space-sm);
  box-shadow: var(--bt-shadow-sm);
  min-height: 6rem;
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
  color: var(--bt-color-text-primary);
  font-size: var(--bt-font-size-base);
  line-height: var(--bt-line-height);
}

#submission:focus {
  outline: none;
  border-color: var(--bt-color-brand);
}

/* === CodeMirror 6 editor === */
/* The CM6 editor mounts inside #submission (a <div>, not a textarea). The
 * .cm-editor is the root CM6 view; .cm-content is the editable surface; .cm-
 * scroller is the scroll container. Styled to match the old textarea: code
 * font, surface-code background, border, min-height, and horizontal scroll for
 * long lines. Token colors use a custom HighlightStyle (lesson-runner-core.js)
 * that emits deterministic `.tok-*` classes — NOT CM6's default opaque unicode
 * classes (e.g. `ͼa`) — so the AC-2 deterministic check can grep for them.
 * Colors are the CM6 default light-theme palette; dark-mode overrides live in
 * the @media block at the end of this file (AC-3 will refine the theme).
 */
.cm-editor {
  min-height: 6rem;
  border: 1px solid var(--bt-color-border);
  border-radius: var(--bt-radius-md);
  background: var(--bt-color-surface-code);
}

.cm-content {
  font-family: var(--bt-font-family-code);
  padding: var(--bt-space-sm);
}

.cm-scroller {
  overflow: auto;
}

/* Line number gutter — AC-3 UX polish. The gutter renders line numbers in a
 * monospace font matching the code surface (prevents gutter/code misalignment —
 * sneaky-pass #6: .cm-content monospace but .cm-gutters inherits system-ui).
 * Background uses surface-code so the gutter is visually distinct from the
 * editable content area. */
.cm-gutters {
  background: var(--bt-color-surface-code);
  border-right: 1px solid var(--bt-color-border);
  font-family: var(--bt-font-family-code, monospace);
}

.cm-gutterElement {
  font-family: var(--bt-font-family-code, monospace);
}

/* Active line highlight — the line holding the cursor gets a subtle background
 * tint so the learner can locate the insertion point. The tint must be DISTINCT
 * from .cm-content's background (sneaky-pass #4: transparent or matching bg =
 * zero visual difference). */
.cm-activeLine {
  background: rgba(0, 0, 0, 0.04);
}

/* Bracket match highlight — when the cursor sits adjacent to a bracket, the
 * matching bracket is highlighted. bracketMatching() adds the
 * .cm-matchingBracket class to the DOM; this rule makes it VISIBLE (sneaky-pass
 * #2: class added but no CSS = no visual). The background + outline are
 * non-transparent so the match is unambiguous. */
.cm-matchingBracket {
  background: rgba(0, 0, 0, 0.12);
  outline: 1px solid rgba(0, 0, 0, 0.2);
}

/* Focus outline removal — CM6 manages its own focus ring inside .cm-editor;
 * suppress the browser default outline on the contenteditable to avoid a
 * double-ring. */
.cm-focused {
  outline: none;
}

/* Syntax token colors — deterministic `.tok-*` classes emitted by the custom
 * HighlightStyle in lesson-runner-core.js. CM6's defaultHighlightStyle uses
 * opaque generated classes (ͼa, ͼb, …) that cannot be grepped; these stable
 * names make token spans testable (AC-2 deterministic_check). Palette matches
 * the CM6 default light theme. */
.tok-keyword { color: var(--bt-color-syntax-keyword); }
.tok-string { color: var(--bt-color-syntax-string); }
.tok-number { color: var(--bt-color-syntax-number); }
.tok-comment { color: var(--bt-color-syntax-comment); font-style: italic; }
.tok-variableName { color: var(--bt-color-syntax-variable); }
.tok-function { color: var(--bt-color-syntax-function); }
.tok-operator { color: var(--bt-color-syntax-operator); }

.controls {
  display: flex;
  align-items: center;
  gap: var(--bt-space-md);
  margin-top: var(--bt-space-sm);
  margin-bottom: var(--bt-space-sm);
}

#run {
  background: var(--bt-color-brand);
  color: var(--bt-color-surface);
  border: none;
  border-radius: var(--bt-radius-sm);
  padding: var(--bt-space-xs) var(--bt-space-sm);
  font-family: var(--bt-font-family-ui);
  font-size: var(--bt-font-size-base);
  cursor: pointer;
  font-weight: 600;
}

#run:hover {
  background: var(--bt-color-brand-hover);
}

#submit {
  background: transparent;
  border: 1px solid var(--bt-color-border);
  color: var(--bt-color-text-primary);
  border-radius: var(--bt-radius-sm);
  padding: var(--bt-space-xs) var(--bt-space-sm);
  font-family: var(--bt-font-family-ui);
  font-size: var(--bt-font-size-base);
  cursor: pointer;
  font-weight: 600;
}

#submit:hover {
  background: color-mix(in srgb, var(--bt-color-border) 20%, transparent);
}

#lesson-status {
  display: inline-block;
  padding: var(--bt-space-xs) var(--bt-space-sm);
  border-radius: var(--bt-radius-pill);
  font-weight: 600;
  text-transform: uppercase;
  font-size: 0.75rem;
  box-shadow: var(--bt-shadow-sm);
  line-height: 1.75;
}

#lesson-status[data-status="idle"] {
  background: var(--bt-color-status-idle);
  color: var(--bt-color-text-secondary);
}

#lesson-status[data-status="running"] {
  background: var(--bt-color-status-running);
  color: var(--bt-color-surface);
}

#lesson-status[data-status="pass"] {
  background: var(--bt-color-status-pass);
  color: var(--bt-color-surface);
}

#lesson-status[data-status="fail"] {
  background: var(--bt-color-status-fail);
  color: var(--bt-color-surface);
}

#output {
  background: var(--bt-color-surface-code);
  border: 1px solid var(--bt-color-border);
  border-radius: var(--bt-radius-md);
  padding: var(--bt-space-sm);
  box-shadow: var(--bt-shadow-sm);
  white-space: pre-wrap;
  min-height: 4rem;
  font-family: var(--bt-font-family-code);
  font-size: var(--bt-font-size-base);
  line-height: var(--bt-line-height);
  color: var(--bt-color-text-primary);
}

/* === exercise UX polish (AC-8) === */
/* Per-exercise UX elements: hints <details> toggle, solution/check/run buttons,
 * data-status badge, and disabled-button cursor. These are the class-based
 * equivalents of the singleton #lesson-* selectors above, used by
 * exercise-runtime.js's per-exercise wireExercise().
 *
 * What it does:
 *  - .bt-hints: expandable <details> panel for hints (clause 1).
 *  - .bt-run-btn / .bt-check-btn / .bt-solution-btn: control buttons.
 *  - button[disabled]: cursor not-allowed (clause 5).
 *  - .bt-status[data-status]: closed-set status badge (clause 6).
 *
 * What it does NOT do:
 *  - No JS changes — pure CSS only.
 *  - No hex color literals — all colors via var(--bt-*) tokens.
 *  - Dark mode is handled by the dark-mode @media block :root overrides.
 */

.bt-hints {
  margin-bottom: var(--bt-space-md);
  padding: var(--bt-space-sm) var(--bt-space-md);
  border: 1px solid var(--bt-color-border);
  border-radius: var(--bt-radius-md);
  background: var(--bt-color-surface-code);
}

.bt-hints summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--bt-color-text-secondary);
}

.bt-hints p {
  margin: var(--bt-space-sm) 0 0;
  color: var(--bt-color-text-secondary);
  line-height: var(--bt-line-height);
}

.bt-hints ul {
  margin: var(--bt-space-sm) 0 0;
  padding-left: var(--bt-space-lg);
  color: var(--bt-color-text-secondary);
  line-height: var(--bt-line-height);
}

.bt-controls {
  display: flex;
  align-items: center;
  gap: var(--bt-space-md);
  margin-top: var(--bt-space-sm);
  margin-bottom: var(--bt-space-sm);
}

.bt-run-btn {
  background: var(--bt-color-brand);
  color: var(--bt-color-surface);
  border: none;
  border-radius: var(--bt-radius-sm);
  padding: var(--bt-space-xs) var(--bt-space-sm);
  font-family: var(--bt-font-family-ui);
  font-size: var(--bt-font-size-base);
  cursor: pointer;
  font-weight: 600;
}

.bt-run-btn:hover {
  background: var(--bt-color-brand-hover);
}

.bt-check-btn {
  background: transparent;
  border: 1px solid var(--bt-color-border);
  color: var(--bt-color-text-primary);
  border-radius: var(--bt-radius-sm);
  padding: var(--bt-space-xs) var(--bt-space-sm);
  font-family: var(--bt-font-family-ui);
  font-size: var(--bt-font-size-base);
  cursor: pointer;
  font-weight: 600;
}

.bt-check-btn:hover {
  background: color-mix(in srgb, var(--bt-color-border) 20%, transparent);
}

.bt-solution-btn {
  background: transparent;
  border: 1px solid var(--bt-color-border);
  color: var(--bt-color-text-secondary);
  border-radius: var(--bt-radius-sm);
  padding: var(--bt-space-xs) var(--bt-space-sm);
  font-family: var(--bt-font-family-ui);
  font-size: var(--bt-font-size-base);
  cursor: pointer;
  font-weight: 600;
}

.bt-solution-btn:hover {
  background: color-mix(in srgb, var(--bt-color-border) 20%, transparent);
}

/* Disabled buttons — cursor not-allowed (clause 5). Applies to any button
 * inside .bt-exercise that carries the [disabled] attribute. */
button[disabled] {
  cursor: not-allowed;
  opacity: 0.6;
}

.bt-status {
  display: inline-block;
  padding: var(--bt-space-xs) var(--bt-space-sm);
  border-radius: var(--bt-radius-pill);
  font-weight: 600;
  text-transform: uppercase;
  font-size: 0.75rem;
  box-shadow: var(--bt-shadow-sm);
  line-height: 1.75;
}

.bt-status[data-status="idle"] {
  background: var(--bt-color-status-idle);
  color: var(--bt-color-text-secondary);
}

.bt-status[data-status="running"] {
  background: var(--bt-color-status-running);
  color: var(--bt-color-surface);
}

.bt-status[data-status="pass"] {
  background: var(--bt-color-status-pass);
  color: var(--bt-color-surface);
}

.bt-status[data-status="fail"] {
  background: var(--bt-color-status-fail);
  color: var(--bt-color-surface);
}

.bt-output {
  background: var(--bt-color-surface-code);
  border: 1px solid var(--bt-color-border);
  border-radius: var(--bt-radius-md);
  padding: var(--bt-space-sm);
  box-shadow: var(--bt-shadow-sm);
  white-space: pre-wrap;
  min-height: 4rem;
  font-family: var(--bt-font-family-code);
  font-size: var(--bt-font-size-base);
  line-height: var(--bt-line-height);
  color: var(--bt-color-text-primary);
}

/* === feedback / BYOK === */
/* BYOK feedback panel — styled via data-byok / data-correct attribute selectors.
 * All rules scoped to #feedback-descendant selectors or specific
 * [data-byok] / #byok-disclosure selectors — never bare element selectors.
 *
 * What it does:
 *  - Cards each #feedback child with surface + border + shadow + radius + padding.
 *  - Verdict states (correct/incorrect) visually distinct via success-bg/danger-bg.
 *  - Disclosure (#byok-disclosure) styled as muted privacy note.
 *  - Form elements consistent with AC-2 workspace styling.
 *  - Transient states (pending, loading, error) styled with appropriate emphasis.
 *
 * What it does NOT do:
 *  - No JS changes — pure CSS only. feedback.js byte-unchanged.
 *  - No className/style./classList manipulation (those are feedback.js's job).
 *  - No hex color literals in BYOK rules — all colors via var(--bt-*) tokens.
 *  - Dark mode is handled by the dark-mode @media block :root overrides
 *    at the bottom of this file — BYOK rules inherit via var(--bt-*) tokens.
 */

/* Card container — each phase uses surface + border + shadow for elevation */
#feedback [data-byok="key-prompt"],
#feedback [data-byok="model-picker"],
#feedback [data-byok="verdict"],
#feedback [data-byok="pending"],
#feedback [data-byok="error"],
#feedback [data-byok="models-loading"] {
  background: var(--bt-color-surface);
  border: 1px solid var(--bt-color-border);
  border-radius: var(--bt-radius-md);
  box-shadow: var(--bt-shadow-sm);
  padding: var(--bt-space-sm);
  font-family: var(--bt-font-family-ui);
}

/* Form elements — consistent with AC-2 workspace input/select/button styling */
#feedback [data-byok="provider"],
#feedback [data-byok="model"],
#feedback input[type="password"] {
  border: 1px solid var(--bt-color-border);
  border-radius: var(--bt-radius-md);
  padding: var(--bt-space-xs) var(--bt-space-sm);
  background: var(--bt-color-surface);
  color: var(--bt-color-text-primary);
  font-family: var(--bt-font-family-ui);
}

#feedback input[type="password"] {
  width: 100%;
  box-sizing: border-box;
}

#feedback button[type="submit"] {
  background: var(--bt-color-brand);
  color: var(--bt-color-surface);
  border: none;
  border-radius: var(--bt-radius-sm);
  padding: var(--bt-space-xs) var(--bt-space-sm);
  font-family: var(--bt-font-family-ui);
  cursor: pointer;
  font-weight: 600;
}

#feedback button[type="submit"]:hover {
  background: var(--bt-color-brand-hover);
}

/* Verdict: correct — green-tinted surface, green left accent */
#feedback [data-byok="verdict"][data-correct="true"] {
  background: var(--bt-color-success-bg);
  color: var(--bt-color-text-primary);
  border-left: 4px solid var(--bt-color-status-pass);
}

#feedback [data-byok="verdict"][data-correct="true"] strong {
  color: var(--bt-color-status-pass);
}

/* Verdict: incorrect — amber-tinted surface, fail left accent */
#feedback [data-byok="verdict"][data-correct="false"] {
  background: var(--bt-color-danger-bg);
  color: var(--bt-color-text-primary);
  border-left: 4px solid var(--bt-color-status-fail);
}

#feedback [data-byok="verdict"][data-correct="false"] strong {
  color: var(--bt-color-status-fail);
}

/* Disclosure — privacy note, visually distinct from body text */
#byok-disclosure {
  color: var(--bt-color-text-secondary);
  font-size: 0.875em;
  font-style: italic;
  margin-bottom: var(--bt-space-sm);
}

/* Pending / loading — transient states: secondary text with pulsing animation */
#feedback [data-byok="pending"],
#feedback [data-byok="models-loading"] {
  color: var(--bt-color-text-secondary);
  animation: bt-pulse 1.5s ease-in-out infinite;
}

@keyframes bt-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

/* Error — text-only emphasis: fail color, no background tint (distinct from verdict) */
#feedback [data-byok="error"] {
  color: var(--bt-color-status-fail);
}

/* ── Dark mode ────────────────────────────────────────────────────
 * Overrides all 21 --bt-color-* tokens inside @media (prefers-color-scheme: dark)
 * for WCAG AA contrast (4.5:1 text, 3:1 UI/large text). No non-color tokens.
 * The :root block is extracted by the test via brace-counting on the @media
 * selector, then brace-counting again on :root within the media block body.
 * The media block must appear AFTER light :root's closing `}` (positional
 * invariant enforced by build_dark_mode_token_overrides clause 1).
 *
 * WARNING: This block MUST remain at the END of this file, after all semantic
 * rules. The idle-pill status override inside this block has the SAME
 * specificity (1,1,0) as the default rule; @media does NOT add specificity
 * per the CSS cascading spec. If this block appears before the default rule,
 * the override is dead code — the later default rule wins by source order.
 * Tests check token values from parsed CSS custom properties, not computed
 * CSS styles, so they do NOT catch source-order bugs. Keep this block last.
 */

@media (prefers-color-scheme: dark) {
  :root {
    --bt-color-surface: #1e1e1e;
    --bt-color-surface-code: #2d2d2d;
    --bt-color-text-primary: #e0e0e0;
    --bt-color-text-secondary: #a0a0a0;
    --bt-color-status-pass: #66bb6a;
    --bt-color-status-fail: #ff5252;
    --bt-color-status-running: #ff9800;
    --bt-color-brand: #e0e0e0;
    --bt-color-brand-hover: #ffffff;
    --bt-color-border: #808080;
    --bt-color-status-idle: #888888;
    --bt-color-success-bg: #1b3d1b;
    --bt-color-danger-bg: #3d1b1b;

    /* Syntax highlighting — VS Code dark-theme palette */
    --bt-color-syntax-keyword: #569cd6;
    --bt-color-syntax-string: #ce9178;
    --bt-color-syntax-number: #b5cea8;
    --bt-color-syntax-comment: #6a9955;
    --bt-color-syntax-variable: #d4d4d4;
    --bt-color-syntax-function: #dcdcaa;
    --bt-color-syntax-operator: #d4d4d4;

    /* Cursor — pure white for maximum contrast against the dark surface-code
     * background. The previous value (text-primary gray) was visible but
     * faint at 1.2px width; pure white at 2px is clearly visible. */
    --bt-color-cursor: #ffffff;
  }

  /* Idle pill text: surface provides sufficient contrast on dark status-idle */
  #lesson-status[data-status="idle"] {
    color: var(--bt-color-surface);
  }

  /* CM6 UX-polish dark overrides — AC-3. The light-mode rules use rgba(0,0,0,*)
   * tints which are invisible on a dark surface; these flip to rgba(255,255,255,*)
   * so the gutter border, active line, and bracket match remain visible in
   * dark mode. */
  .cm-gutters {
    background: var(--bt-color-surface-code);
    border-right-color: var(--bt-color-border);
  }

  .cm-activeLine {
    background: rgba(255, 255, 255, 0.04);
  }

  .cm-matchingBracket {
    background: rgba(255, 255, 255, 0.12);
    outline-color: rgba(255, 255, 255, 0.2);
  }

}
