/* ============================================================
   ximera-core.css — kernel-owned CSS + shared design vocabulary

   Two roles:

   1. Kernel-projected classes. The kernel writes `data-state` on
      exactly two selectors and installs one chrome button:
        .problem-environment  → "available? complete? experienced?"
        .feedback             → "visible" | "hidden"
        .ximera-reset-btn     → reset-work control chrome

   2. Shared design tokens + button vocabulary. Every ximera-* pilot
      pulls colors, radii, and focus rings from the :root variables
      below, so a course theme is a single override. The .ximera-btn
      base + variants (--full, --icon) + state palette ("correct",
      "attempted", "incorrect") are shipped here so that submit /
      check buttons look identical across mc, sa, fr, answer, and
      third-party packages — legacy Ximera called these classes
      .btn-ximera-submit / -correct / -incorrect; the state variants
      preserve that visual language.
   ============================================================ */

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

:root {
  /* Palette */
  --ximera-color-primary: #2196f3;
  --ximera-color-primary-hover: #1976d2;
  --ximera-color-primary-fg: #ffffff;

  --ximera-color-correct: #2a7a2a;
  --ximera-color-correct-bg: #e8f8e8;

  --ximera-color-incorrect: #c62828;
  --ximera-color-incorrect-bg: #fdecea;

  --ximera-color-focus: #4a90d9;
  --ximera-color-neutral-bg: #f4f4f4;
  --ximera-color-neutral-hover: #e9e9e9;
  --ximera-color-neutral-border: #ccc;
  --ximera-color-muted-fg: #555;
  --ximera-color-muted-border: #999;

  /* Environment box palettes. The four-palette split (formal / problem
     / commentary / caution) and the class-to-palette mapping below
     mirror original-stylesheets/theorems.scss so a course carried
     forward from the legacy Ximera looks the same. Backgrounds are
     low-saturation near-white tints (hsl(hue, ~40%, ~97%)) so the
     border carries the identity and the box stays legible on white. */
  --ximera-color-env-formal: #2e7d32;         /* green — theorem-family + definitional */
  --ximera-color-env-formal-bg: #f4faf4;
  --ximera-color-env-problem: #1976d2;        /* blue — problem-family */
  --ximera-color-env-problem-bg: #f4f8fd;
  --ximera-color-env-commentary: #a1670c;     /* amber — example / observation / remark */
  --ximera-color-env-commentary-bg: #fdfaf1;
  --ximera-color-env-caution: #c62828;        /* red — warning / paradox */
  --ximera-color-env-caution-bg: #fdf5f4;

  /* Shape */
  --ximera-radius: 4px;
  --ximera-focus-ring: 2px solid var(--ximera-color-focus);
  --ximera-focus-ring-offset: 1px;

  /* Button metrics */
  --ximera-btn-padding-y: 0.35em;
  --ximera-btn-padding-x: 0.9em;

  /* Page metrics — max-width caps the measure (line length) to roughly
     70 characters at the default font size, which is where prose
     readability research settles. Courses can override with e.g.
     `body { --ximera-content-width: 60em; }` for wider layouts. */
  --ximera-content-width: 42em;

  /* Body font — MathJax_NewCM points at the *same* woff2 files that
     MathJax 4's CHTML output uses for text inside math expressions
     (`\text{...}`, operator names, roman glyphs). Putting it first in
     the stack guarantees an exact visual match: the "x" in a sentence
     looks the same as the "x" in an equation. Fallbacks pick up any
     glyphs MathJax_NewCM doesn't cover and are all Computer-Modern-
     family faces so the page still reads Modern-ish if the CDN is
     unreachable. The @font-face declarations below source the actual
     font files. Bumping MathJax from 3 to 4 was the trigger for
     switching families: v4's default font is mathjax-newcm (New
     Computer Modern), not the classic MathJax_Main. */
  --ximera-font-serif:
    "MathJax_NewCM",
    "Latin Modern Roman", "LMRoman10-Regular",
    "Computer Modern Serif", "CMU Serif",
    "STIX Two Text", "STIXGeneral",
    Georgia, "Times New Roman", Times, serif;

  /* Sans-serif stack — used for chrome labels (env titles, callouts)
     where we want a clear visual break from the serif body. */
  --ximera-font-sans:
    system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
}

/* ─── MathJax_NewCM webfont — same woff2 files MathJax 4 CHTML loads ─────── */

@font-face {
  font-family: 'MathJax_NewCM';
  src: url('https://cdn.jsdelivr.net/npm/@mathjax/mathjax-newcm-font/chtml/woff2/mjx-ncm-n.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'MathJax_NewCM';
  src: url('https://cdn.jsdelivr.net/npm/@mathjax/mathjax-newcm-font/chtml/woff2/mjx-ncm-b.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'MathJax_NewCM';
  src: url('https://cdn.jsdelivr.net/npm/@mathjax/mathjax-newcm-font/chtml/woff2/mjx-ncm-i.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: 'MathJax_NewCM';
  src: url('https://cdn.jsdelivr.net/npm/@mathjax/mathjax-newcm-font/chtml/woff2/mjx-ncm-bi.woff2') format('woff2');
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}

/* ─── Page defaults — readability + typographic match to MathJax ────────── */

body {
  font-family: var(--ximera-font-serif);
  max-width: var(--ximera-content-width);
  margin: 0 auto;
  padding: 1.5em 1.5em 4em;
  font-size: 12pt;
  line-height: 1.55;
  color: #222;
  background: #fff;
}

body p {
  margin: 0.6em 0;
}

body h1, body h2, body h3, body h4 {
  line-height: 1.25;
  margin-top: 1.5em;
  margin-bottom: 0.4em;
}

/* Section headings in sans-serif, for a clear visual break from the
   serif body. tex4ht wraps LaTeX sectioning commands in <hN> elements
   with class names encoding the sectioning level (e.g. \section →
   <h3 class="sectionHead">, \section* → <h3 class="likesectionHead">).
   Mirrors original-stylesheets/base.scss. Sizes are set per-class
   because tex4ht emits every level as <h3>, so relying on the tag's
   default cascade collapses the hierarchy. */
.titleHead,
.partHead, .likepartHead,
.chapterHead, .likechapterHead,
.sectionHead, .likesectionHead,
.subsectionHead, .likesubsectionHead,
.subsubsectionHead, .likesubsubsectionHead,
.paragraphHead, .likeparagraphHead,
.subparagraphHead, .likesubparagraphHead {
  font-family: var(--ximera-font-sans);
  font-weight: 600;
}
.titleHead                                   { font-size: 2.1em; }
.partHead,      .likepartHead                { font-size: 1.9em; }
.chapterHead,   .likechapterHead             { font-size: 1.7em; }
.sectionHead,   .likesectionHead             { font-size: 1.5em; }
.subsectionHead, .likesubsectionHead         { font-size: 1.25em; }
.subsubsectionHead, .likesubsubsectionHead   { font-size: 1.1em; }
.paragraphHead, .likeparagraphHead,
.subparagraphHead, .likesubparagraphHead     { font-size: 1em; }

/* ─── Bookkeeping wrappers emitted by tex4ht ─────────────────────────────── */

/* .preamble carries the hidden \(...\) block of MathJax \newcommand
   declarations tex4npm injects at the top of every page. It's runtime-only —
   MathJax processes the definitions so they become page-global, then mounts
   nothing visible — but the div itself is still in the flow. Force it
   invisible so it can never leak whitespace or a stray text-node between
   the maketitle and the first heading. */
.preamble {
  display: none;
}

/* Empty tex4ht wrapper: \maketitle produces <div class="maketitle"></div>
   with nothing inside (title comes through the <h3 class="likesectionHead">
   that follows). Kill its top margin so the section heading sits flush. */
.maketitle:empty {
  display: none;
}

/* .ximera-label is tex4ht's anchor for \label{...}: <a id="key"></a> —
   always empty, purely a scroll target. Should never be visible. */
a.ximera-label {
  display: inline;
  color: inherit;
  text-decoration: none;
}

/* Cross-references (\ref{key}) render as <a class="reference"> whose text
   content is the raw label key, because tex4ht in one-pass mode can't
   resolve the label number. Style it as a subtle link so it doesn't
   dominate visually, and drop the underline decoration in favour of a
   colored on-hover reveal. */
a.reference {
  color: var(--ximera-color-primary);
  text-decoration: none;
  border-bottom: 1px dotted currentColor;
}
a.reference:hover,
a.reference:focus {
  text-decoration: none;
  border-bottom-style: solid;
}

/* ─── Abstract ───────────────────────────────────────────────────────────── */

/* xourse.cls and ximera.cls wrap the activity's \begin{abstract}…
   \end{abstract} in <div class="abstract">. Style it as an italic
   gray lead paragraph with a bold sans-serif "Abstract." label on
   the first line — mirrors original-stylesheets/abstract.scss. */
.abstract {
  font-style: italic;
  color: #555;
  text-align: justify;
  margin: 2em 0;
}
.abstract p:first-child::before {
  content: "Abstract.";
  font-family: var(--ximera-font-sans);
  font-style: normal;
  font-weight: 700;
  padding-right: 0.5em;
}
.abstract:empty {
  display: none;
}

/* ─── Math ───────────────────────────────────────────────────────────────── */

/* Display math from `\[…\]` or `$$…$$` is wrapped in <div class="mathjax-block">.
   Give it consistent vertical rhythm — MathJax's own container adds 1em of
   inner margin, which combined with body p's 0.6em produces uneven gaps
   depending on whether the preceding element is a paragraph or another
   block. Setting explicit symmetric margins here plus text-align:center
   matches AMS conventions. */
.mathjax-block {
  margin: 0.9em 0;
  text-align: center;
  overflow-x: auto;
  overflow-y: hidden;
}

/* Equation environments (align, gather, etc.) — same rhythm as .mathjax-block
   but tex4ht wraps them one level higher in <div class="mathjax-env mathjax-equation">. */
.mathjax-env {
  margin: 0.9em 0;
  overflow-x: auto;
  overflow-y: hidden;
}

/* Inline math must not disturb line-height — MathJax's CHTML container is
   inline-block, and its default vertical-align can push line-boxes when the
   fraction/matrix is tall. Force baseline alignment. */
.mathjax-inline {
  vertical-align: baseline;
}

/* ─── Lists ──────────────────────────────────────────────────────────────── */

/* tex4ht emits <ol class="enumerate1"> or <ul class="itemize1"> at the outer
   level and <li class="enumerate"> / <li class="itemize"> for items. Give
   them a modest indent and item spacing that lines up with body paragraph
   rhythm. Nested lists inherit smaller padding automatically. */
ol.enumerate1,
ul.itemize1,
ol.enumerate2,
ul.itemize2,
ol.enumerate3,
ul.itemize3 {
  padding-left: 1.8em;
  margin: 0.6em 0;
}

li.enumerate,
li.itemize {
  margin: 0.3em 0;
}

/* Paragraph inside a list item — kill the outer margin so the item's own
   spacing controls the rhythm; the inner <p class="noindent"> tex4ht emits
   would otherwise double the gap. */
li.enumerate > p,
li.itemize > p {
  margin: 0;
}

/* ─── Utility wrappers from tex4ht ───────────────────────────────────────── */

/* `.center` wraps \begin{center}…\end{center} content — text-align on the
   wrapper is enough for text; block children (images, math) are handled by
   their own margins. */
.center {
  text-align: center;
  margin: 0.9em 0;
}

/* .noindent is tex4ht's marker for \noindent paragraphs. LaTeX suppresses
   the first-line indent; on the web we don't indent paragraphs at all, so
   .noindent is a no-op selector — but keep it explicit so future themes
   that DO indent (text-indent on `p`) can zero it out here. */
p.noindent {
  text-indent: 0;
}

/* ─── Images ─────────────────────────────────────────────────────────────── */

/* \begin{image}…\end{image} in ximera.cls emits
   <div class="image-environment"> containing an <img> or (for
   tikz-exported SVGs) an <object type="image/svg+xml">. Both are
   inline-replaced elements, so text-align on the wrapper centres
   them. Mirrors original-stylesheets/images.scss. */
.image-environment {
  text-align: center;
  margin: 1em 0;
}

/* ─── Environment boxes ──────────────────────────────────────────────────── */

/* The 4ht configuration in ximeraLatex wraps every theorem-like environment
   (theorem, definition, remark, warning, proof, …27 total) in
     <div class="theorem-like problem-environment {name}">
       <span class="theorem-like-title"> Theorem </span>
       …body…
     </div>
   Plain problems emit `<div class="problem-environment problem">` (no
   `theorem-like` class). We paint them all with a colored left border,
   a tinted background, and a colored title span, grouped into four
   palettes. Courses override --ximera-color-env-* to retheme. */

.theorem-like,
.problem-environment.problem,
.problem-environment.exercise,
.problem-environment.question,
.problem-environment.exploration {
  border-left: 4px solid var(--ximera-color-neutral-border);
  background: var(--ximera-color-neutral-bg);
  padding: 0.5em 0.8em;
  margin: 1em 0;
  border-radius: 0 var(--ximera-radius) var(--ximera-radius) 0;
}

/* First/last child margin collapse — don't let the first paragraph or
   display-math block push a tall gap between the env-name label and
   the box top, and don't let the last one add trailing space below
   the box body. */
.theorem-like > :first-child,
.problem-environment.problem > :first-child,
.problem-environment.exercise > :first-child,
.problem-environment.question > :first-child,
.problem-environment.exploration > :first-child {
  margin-top: 0;
}
.theorem-like > :last-child,
.problem-environment.problem > :last-child,
.problem-environment.exercise > :last-child,
.problem-environment.question > :last-child,
.problem-environment.exploration > :last-child {
  margin-bottom: 0;
}

/* The optional environment title (\begin{theorem}[Ohm's Law]) is emitted
   as this span. Set it in the same sans label font as the "Theorem." prelude
   so the whole line reads as one label: "Theorem (Ohm's Law)."  Color is
   applied per-family by the palette blocks below (matching the ::before). */
.theorem-like-title {
  font-family: var(--ximera-font-sans);
  font-weight: 700;
  font-size: 0.95em;
  color: var(--ximera-color-muted-fg);
  margin-right: 0.4em;
}

/* Wrap the title in parentheses and carry the sentence-final period, so the
   label becomes "Theorem (Ohm's Law)." — the ::before drops its own period
   when a title is present (see the :has() rule below). Proof is excluded: it
   keeps its plain italic title with no parentheses. */
.theorem-like:not(.proof) > .theorem-like-title::before { content: " ("; }
.theorem-like:not(.proof) > .theorem-like-title::after  { content: ")."; }

/* Env name shown as a bold sans-serif label on the first line
   (Theorem, Definition, Example, …). Colored to match the family
   palette by the group blocks below. Proof intentionally omits a
   label — its "Proof." prelude and ∎ terminal handle the framing.
   Problem-family envs (problem/exercise/question/exploration) share
   the same label styling; their content rules and color live with
   the blue palette block below. */
.theorem-like::before,
.problem-environment.problem::before,
.problem-environment.exercise::before,
.problem-environment.question::before,
.problem-environment.exploration::before {
  content: var(--env-label) ".";
  font-family: var(--ximera-font-sans);
  font-weight: 700;
  font-size: 0.95em;
  margin-right: 0.4em;
}

/* When the environment carries a title span, the period belongs after the
   parenthesized title ("Theorem (Ohm's Law)."), so drop it from the prelude
   here and let .theorem-like-title::after supply it. */
.theorem-like:has(> .theorem-like-title)::before {
  content: var(--env-label);
  margin-right: 0;
}

.theorem-like.theorem      { --env-label: "Theorem"; }
.theorem-like.corollary    { --env-label: "Corollary"; }
.theorem-like.lemma        { --env-label: "Lemma"; }
.theorem-like.proposition  { --env-label: "Proposition"; }
.theorem-like.claim        { --env-label: "Claim"; }
.theorem-like.conjecture   { --env-label: "Conjecture"; }
.theorem-like.definition   { --env-label: "Definition"; }
.theorem-like.axiom        { --env-label: "Axiom"; }
.theorem-like.condition    { --env-label: "Condition"; }
.theorem-like.idea         { --env-label: "Idea"; }
.theorem-like.conclusion   { --env-label: "Conclusion"; }
.theorem-like.summary      { --env-label: "Summary"; }
.theorem-like.explanation  { --env-label: "Explanation"; }

.theorem-like.formula      { --env-label: "Formula"; }
.theorem-like.model        { --env-label: "Model"; }
.theorem-like.procedure    { --env-label: "Procedure"; }
.theorem-like.template     { --env-label: "Template"; }

.theorem-like.example      { --env-label: "Example"; }
.theorem-like.observation  { --env-label: "Observation"; }
.theorem-like.fact         { --env-label: "Fact"; }
.theorem-like.remark       { --env-label: "Remark"; }
.theorem-like.algorithm    { --env-label: "Algorithm"; }
.theorem-like.notation     { --env-label: "Notation"; }
.theorem-like.criterion    { --env-label: "Criterion"; }

.theorem-like.warning      { --env-label: "Warning"; }
.theorem-like.paradox      { --env-label: "Paradox"; }

.problem-environment.problem      { --env-label: "Problem"; }
.problem-environment.exercise     { --env-label: "Exercise"; }
.problem-environment.question     { --env-label: "Question"; }
.problem-environment.exploration  { --env-label: "Exploration"; }

/* Green — theorem-family and constructive/definitional.
   Matches the "grass" palette in original-stylesheets/theorems.scss. */
.theorem-like.theorem,
.theorem-like.corollary,
.theorem-like.lemma,
.theorem-like.proposition,
.theorem-like.claim,
.theorem-like.conjecture,
.theorem-like.definition,
.theorem-like.axiom,
.theorem-like.condition,
.theorem-like.idea,
.theorem-like.conclusion,
.theorem-like.summary,
.theorem-like.explanation {
  border-left-color: var(--ximera-color-env-formal);
  background: var(--ximera-color-env-formal-bg);
}
.theorem-like.theorem > .theorem-like-title,
.theorem-like.corollary > .theorem-like-title,
.theorem-like.lemma > .theorem-like-title,
.theorem-like.proposition > .theorem-like-title,
.theorem-like.claim > .theorem-like-title,
.theorem-like.conjecture > .theorem-like-title,
.theorem-like.definition > .theorem-like-title,
.theorem-like.axiom > .theorem-like-title,
.theorem-like.condition > .theorem-like-title,
.theorem-like.idea > .theorem-like-title,
.theorem-like.conclusion > .theorem-like-title,
.theorem-like.summary > .theorem-like-title,
.theorem-like.explanation > .theorem-like-title,
.theorem-like.theorem::before,
.theorem-like.corollary::before,
.theorem-like.lemma::before,
.theorem-like.proposition::before,
.theorem-like.claim::before,
.theorem-like.conjecture::before,
.theorem-like.definition::before,
.theorem-like.axiom::before,
.theorem-like.condition::before,
.theorem-like.idea::before,
.theorem-like.conclusion::before,
.theorem-like.summary::before,
.theorem-like.explanation::before {
  color: var(--ximera-color-env-formal);
}

/* Blue — problem-family. `.problem-environment.NAME` is emitted for
   the four question-environments defined in problem.dtx (problem,
   exercise, question, exploration); the four theorem-like envs below
   (formula, model, procedure, template) were "sky" in the original
   palette and belong here too. */
.theorem-like.formula,
.theorem-like.model,
.theorem-like.procedure,
.theorem-like.template,
.problem-environment.problem,
.problem-environment.exercise,
.problem-environment.question,
.problem-environment.exploration {
  border-left-color: var(--ximera-color-env-problem);
  background: var(--ximera-color-env-problem-bg);
}
.theorem-like.formula > .theorem-like-title,
.theorem-like.model > .theorem-like-title,
.theorem-like.procedure > .theorem-like-title,
.theorem-like.template > .theorem-like-title,
.theorem-like.formula::before,
.theorem-like.model::before,
.theorem-like.procedure::before,
.theorem-like.template::before,
.problem-environment.problem::before,
.problem-environment.exercise::before,
.problem-environment.question::before,
.problem-environment.exploration::before {
  color: var(--ximera-color-env-problem);
}

/* Amber — commentary / example ("sun" in the original palette). */
.theorem-like.example,
.theorem-like.observation,
.theorem-like.fact,
.theorem-like.remark,
.theorem-like.algorithm,
.theorem-like.notation,
.theorem-like.criterion {
  border-left-color: var(--ximera-color-env-commentary);
  background: var(--ximera-color-env-commentary-bg);
}
.theorem-like.example > .theorem-like-title,
.theorem-like.observation > .theorem-like-title,
.theorem-like.fact > .theorem-like-title,
.theorem-like.remark > .theorem-like-title,
.theorem-like.algorithm > .theorem-like-title,
.theorem-like.notation > .theorem-like-title,
.theorem-like.criterion > .theorem-like-title,
.theorem-like.example::before,
.theorem-like.observation::before,
.theorem-like.fact::before,
.theorem-like.remark::before,
.theorem-like.algorithm::before,
.theorem-like.notation::before,
.theorem-like.criterion::before {
  color: var(--ximera-color-env-commentary);
}

/* Red — caution ("blood" in the original palette). */
.theorem-like.warning,
.theorem-like.paradox {
  border-left-color: var(--ximera-color-env-caution);
  background: var(--ximera-color-env-caution-bg);
}
.theorem-like.warning > .theorem-like-title,
.theorem-like.paradox > .theorem-like-title,
.theorem-like.warning::before,
.theorem-like.paradox::before {
  color: var(--ximera-color-env-caution);
}

/* Proof — no box, italic prelude, terminal ∎. The 4ht wraps it in the
   same theorem-like scaffold, so we selectively strip the chrome. */
.theorem-like.proof {
  border: none;
  background: none;
  padding: 0;
  margin: 1em 0;
}
.theorem-like.proof > .theorem-like-title {
  font-family: var(--ximera-font-serif);
  font-size: 1em;
  font-style: italic;
  font-weight: 400;
  color: var(--ximera-color-muted-fg);
}
.theorem-like.proof::after {
  content: "\220E";                        /* ∎ */
  float: right;
  color: var(--ximera-color-muted-fg);
}

/* ─── Problem environments ───────────────────────────────────────────────── */

/* Blocking sub-problems occupy layout space (so MathJax can measure) but
   are unreachable until their parent's answerables complete. */
.problem-environment[data-blocking] {
  visibility: hidden;
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.problem-environment[data-blocking][data-state~="available"] {
  visibility: visible;
  position: relative;
  opacity: 1;
  pointer-events: auto;
  transition: opacity 0.4s ease;
}

/* Completion repaints the left border green. Width matches the env-box
   rule above so a `.problem-environment.problem` doesn't shift on
   completion; the explicit border shorthand also covers a bare
   `.problem-environment` that didn't receive an env-box border. */
.problem-environment[data-state~="complete"] {
  border-left: 4px solid var(--ximera-color-correct);
}

/* ─── Feedback ───────────────────────────────────────────────────────────── */

.feedback {
  display: none;
}

.feedback[data-state="visible"] {
  display: block;
}

/* ─── Buttons — base + variants + state ──────────────────────────────────── */

/* .ximera-btn is the shape base — layout, radius, focus. It intentionally
   does NOT set a color palette; a kind class (.ximera-check-btn,
   .ximera-submit-btn) or state (.ximera-btn[data-state="correct"]) does. */
.ximera-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35em;
  padding: var(--ximera-btn-padding-y) var(--ximera-btn-padding-x);
  font: inherit;
  line-height: 1.2;
  border: 1px solid transparent;
  border-radius: var(--ximera-radius);
  background: transparent;
  color: inherit;
  cursor: pointer;
  user-select: none;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.ximera-btn:focus {
  outline: var(--ximera-focus-ring);
  outline-offset: var(--ximera-focus-ring-offset);
}

.ximera-btn:disabled {
  cursor: default;
  opacity: 0.75;
}

/* Kind: primary/check/submit. All three are the default action — filled blue. */
.ximera-check-btn,
.ximera-submit-btn {
  background: var(--ximera-color-primary);
  border-color: var(--ximera-color-primary);
  color: var(--ximera-color-primary-fg);
}

.ximera-check-btn:hover:not(:disabled),
.ximera-submit-btn:hover:not(:disabled) {
  background: var(--ximera-color-primary-hover);
  border-color: var(--ximera-color-primary-hover);
}

/* State: correct — check button flips to the success palette. Set by
   pilots via btn.dataset.state = 'correct' when the answerable is right. */
.ximera-btn[data-state="correct"],
.ximera-check-btn[data-state="correct"],
.ximera-submit-btn[data-state="correct"] {
  background: var(--ximera-color-correct-bg);
  border-color: var(--ximera-color-correct);
  color: var(--ximera-color-correct);
}

/* State: incorrect / attempted — flips to the danger palette. */
.ximera-btn[data-state="incorrect"],
.ximera-btn[data-state="attempted"],
.ximera-check-btn[data-state="incorrect"],
.ximera-check-btn[data-state="attempted"],
.ximera-submit-btn[data-state="incorrect"],
.ximera-submit-btn[data-state="attempted"] {
  background: var(--ximera-color-incorrect-bg);
  border-color: var(--ximera-color-incorrect);
  color: var(--ximera-color-incorrect);
}

/* Icon glyphs on every check / submit button, delivered via FontAwesome 6
   free-solid loaded from CDN (see ximera.cfg for the <link> that installs
   the @font-face). All state transitions are pure CSS — pilot code never
   touches icon markup. Default: ? for check, ✈ for submit; correct: ✓;
   attempted / incorrect: ✗. Matches original-server's chrome vocabulary. */
.ximera-check-btn::before,
.ximera-submit-btn::before {
  font-family: "Font Awesome 6 Free";
  font-weight: 900;
  font-style: normal;
  line-height: 1;
}

.ximera-check-btn::before  { content: "\f128"; }             /* fa-question */
.ximera-submit-btn::before { content: "\f1d8"; }             /* fa-paper-plane */

.ximera-check-btn[data-state="correct"]::before,
.ximera-submit-btn[data-state="correct"]::before {
  content: "\f00c";                                          /* fa-check */
}

.ximera-check-btn[data-state="incorrect"]::before,
.ximera-check-btn[data-state="attempted"]::before,
.ximera-submit-btn[data-state="incorrect"]::before,
.ximera-submit-btn[data-state="attempted"]::before {
  content: "\f00d";                                          /* fa-xmark */
}

/* Variant: --full. Full-width button for standalone answerables (mc/sa/fr).
   The container decides — the button matches the answerable's box. */
.ximera-btn--full {
  display: flex;
  width: 100%;
}

/* Variant: --icon. Compact square for inline placements (next to a math
   answer input). The FA ::before glyph inherited from the check/submit
   base rules does the labeling; we hide the text label and shrink the
   box. Used with data-state to show ✓ / ✗ / ? state. */
.ximera-btn--icon {
  padding: 0.15em 0.4em;
  min-width: 1.8em;
  min-height: 1.6em;
  gap: 0;
  font-size: 0.95em;
  color: transparent;
}

.ximera-btn--icon::before {
  color: var(--ximera-color-primary-fg);
  font-size: 1.1em;
  line-height: 1;
}

.ximera-btn--icon[data-state="correct"]::before {
  color: var(--ximera-color-correct);
}

.ximera-btn--icon[data-state="incorrect"]::before,
.ximera-btn--icon[data-state="attempted"]::before {
  color: var(--ximera-color-incorrect);
}

/* The state-driven color rules above (specificity 0,2,0) would otherwise
   override `.ximera-btn--icon { color: transparent }` (0,1,0), making the
   button's text label appear in the state color. Icon buttons never show
   text — only the ::before glyph — so pin transparent at matching
   specificity for every state. */
.ximera-btn--icon[data-state="correct"],
.ximera-btn--icon[data-state="incorrect"],
.ximera-btn--icon[data-state="attempted"] {
  color: transparent;
}

/* ─── Reset control ──────────────────────────────────────────────────────── */

#ximera-page-controls {
  margin: 1em 0;
}

.ximera-reset-btn {
  display: inline-block;
  padding: var(--ximera-btn-padding-y) var(--ximera-btn-padding-x);
  font-size: 0.9em;
  border: 1px solid var(--ximera-color-muted-border);
  border-radius: var(--ximera-radius);
  background: var(--ximera-color-neutral-bg);
  color: #333;
  cursor: pointer;
}

.ximera-reset-btn:hover {
  background: var(--ximera-color-neutral-hover);
  border-color: var(--ximera-color-muted-fg);
}

.ximera-reset-btn:focus {
  outline: var(--ximera-focus-ring);
  outline-offset: var(--ximera-focus-ring-offset);
}
