/* Fonts (Inter + JetBrains Mono) load via a <link> in each page's <head> — see
   index.html / module_template.html — so there is no @import here: that avoids a
   second, render-blocking request for the same families. */

/* ============================================================================
   Stereochemistry in Drug Discovery — theme, retargeted to the NUS Python
   bridging-course design language.

   Palette: NUS navy #003D7C, accent orange #FF6B35, ink #2c3e50.

   CONTRACT NOTE — the JS in assets/js/*.js queries these class names exactly,
   and the RDKit answer keys are baked against them at build time. Every widget
   selector below is restyled but never renamed. In particular:
     .mol3d-view  keeps an explicit non-zero height (3Dmol measures once)
     .jsme-host   keeps a non-zero min-height (the Kekule composer needs real height)
   ========================================================================== */

:root {
  /* --- retargeted legacy tokens (names kept; values now Python's) --- */
  --nus-orange: #FF6B35;          /* was #EF7C00 — the old NUS orange is gone */
  --nus-orange-bright: #ff8555;   /* light end of the orange gradient */
  --nus-blue: #003D7C;
  --nus-blue-700: #0052a3;        /* light end of the navy gradient */
  --ink: #2c3e50;
  --muted: #5a6c7d;
  --line: rgba(0,61,124,0.10);
  --bg: #ffffff;
  --card: #ffffff;
  --good: #2ea36b;
  --good-bg: rgba(46,163,107,0.10);
  --bad: #c94f4f;
  --bad-bg: rgba(201,79,79,0.10);
  --radius: 12px;
  --shadow: 0 8px 32px rgba(0,61,124,0.06);
  --maxw: 1600px;                 /* repurposed: was the 860px column, now the grid cap */

  /* --- Rule 3 phantom-atom purple (retargeted) --- */
  --ph: #8458b3;
  --ph-bg: #f3ecfa;

  /* --- new tokens --- */
  --navy-shadow: rgba(0,61,124,0.10);
  --line-soft: rgba(0,61,124,0.08);
  --line-strong: rgba(0,61,124,0.18);
  --faint: #94a3b8;
  --inset: #f8fafc;
  --tabbar: #f1f5f9;
  --info: #5b8def;
  --info-2: #7da3f5;
  --amber: #f59e0b;
  --purple: #8458b3;
  --purple-2: #a474d4;
  --pink: #d6336c;
  --pink-2: #e8659a;
  --code-bg: #0f172a;
  --code-ink: #e2e8f0;
  --radius-sm: 6px;
  --radius-btn: 10px;
  --radius-card: 16px;
  --radius-lg: 20px;
  --radius-pill: 999px;
  --shadow-hover: 0 16px 48px rgba(0,61,124,0.14);
  --shadow-cta: 0 4px 14px rgba(255,107,53,0.25);
  --shadow-nav: 0 8px 32px rgba(0,61,124,0.10);
  --shadow-content: 0 10px 40px rgba(0,61,124,0.10);
  --mono: 'JetBrains Mono', Menlo, Consolas, 'Courier New', monospace;
}

/* ---------- base ---------- */
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  background-color: var(--bg);
  color: var(--ink);
  line-height: 1.7;
  font-size: 16px;
  min-height: 100vh;
  position: relative;
}
body::before {
  content: '';
  position: fixed; inset: 0; z-index: -1;
  background:
    radial-gradient(circle at 20% 50%, rgba(0,61,124,0.04) 0%, transparent 50%),
    radial-gradient(circle at 80% 80%, rgba(255,107,53,0.04) 0%, transparent 50%),
    radial-gradient(circle at 40% 20%, rgba(0,61,124,0.03) 0%, transparent 50%);
  animation: bgFloat 20s ease-in-out infinite;
}
@keyframes bgFloat {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33%      { transform: translate(-20px, -20px) scale(1.05); }
  66%      { transform: translate(20px, -10px) scale(0.95); }
}

code, pre, .mono { font-family: var(--mono); }
code {
  font-family: var(--mono);
  font-size: 0.9em;
  background: var(--tabbar);
  color: var(--code-bg);
  padding: 1px 6px;
  border-radius: 4px;
  border: 1px solid #e2e8f0;
}

/* ---------- a11y ---------- */
.skip-link {
  position: absolute; top: -100%; left: 16px;
  background: var(--nus-blue); color: #fff;
  padding: 12px 24px; border-radius: 0 0 8px 8px;
  z-index: 10000; font-weight: 600; font-size: 14px;
  text-decoration: none; transition: top 0.2s;
}
.skip-link:focus { top: 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;
}

a:focus-visible,
button:focus-visible,
.opt:focus-visible,
.subnav-item:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--nus-orange);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ---------- top banner ---------- */
.top-banner {
  background: rgba(255,255,255,0.97);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  padding: 20px 60px;
  border-bottom: 1px solid rgba(0,61,124,0.1);
  position: sticky; top: 0; z-index: 1001;
  box-shadow: 0 2px 20px rgba(0,61,124,0.06);
}
.top-banner-content {
  display: flex; align-items: center; gap: 20px;
  max-width: var(--maxw); margin: 0 auto;
}
/* .biochem-logo is the class the template emits; .banner-logo kept as an alias. */
.banner-logo,
.biochem-logo { height: 50px; width: auto; max-width: 100%; display: block; transition: transform 0.3s ease; }
.banner-logo:hover,
.biochem-logo:hover { transform: scale(1.05); }

/* "← Course" control in the banner, mirroring the Python course's Dashboard link. */
.back-link {
  margin-left: 16px;
  font-size: 12px; font-weight: 600; letter-spacing: 0.3px;
  color: var(--nus-blue); text-decoration: none;
  padding: 7px 13px;
  border: 1px solid #d6e4f0; border-radius: var(--radius-sm);
  background: #f1f6fb;
  display: inline-flex; align-items: center; gap: 6px;
  transition: all 0.2s ease;
  font-family: inherit;
}
.back-link:hover { background: var(--nus-blue); border-color: var(--nus-blue); color: #fff; }
.back-link:focus-visible { outline: 2px solid var(--nus-orange); outline-offset: 2px; }
.banner-reset-btn {
  margin-left: auto;
  font-size: 12px; font-weight: 600; letter-spacing: 0.3px;
  color: var(--muted);
  background: #ffffff;
  border: 1px solid #e2e8f0;
  border-radius: var(--radius-sm);
  padding: 7px 13px;
  cursor: pointer; font-family: inherit;
  display: inline-flex; align-items: center; gap: 6px;
  transition: all 0.2s ease;
}
.banner-reset-btn:hover {
  color: var(--nus-orange);
  border-color: var(--nus-orange);
  background: #fff7f3;
}

/* ---------- module hero ---------- */
.module-hero {
  max-width: var(--maxw); margin: 0 auto;
  padding: 50px 60px 30px;
}
.module-hero h1 {
  font-size: 42px; font-weight: 800; color: var(--nus-blue);
  line-height: 1.1; margin-bottom: 12px;
}
.module-hero .subtitle {
  font-size: 19px; color: var(--muted); font-weight: 400; max-width: 760px;
}
.module-hero .eyebrow {
  font-size: 12px; font-weight: 700; letter-spacing: 2px;
  text-transform: uppercase; color: var(--nus-orange);
  margin-bottom: 8px;
}

/* ---------- responsive chrome: hamburger drawer ---------- */
.mobile-topbar {
  display: none;
  position: sticky; top: 0; z-index: 1050;
  align-items: center; gap: 12px;
  padding: 10px 16px;
  background: rgba(255,255,255,0.92);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
.hamburger-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; flex-shrink: 0;
  background: #fff; border: 1.5px solid var(--line-strong);
  border-radius: var(--radius-btn); color: var(--nus-blue);
  font-size: 20px; line-height: 1;
  cursor: pointer; transition: all 0.2s;
}
.hamburger-btn:hover { border-color: var(--nus-orange); color: var(--nus-orange); }
.mobile-topbar-title {
  font-size: 14px; font-weight: 700; color: var(--nus-blue);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mobile-close-btn {
  display: none;
  position: absolute; top: 12px; right: 16px;
  background: none;
  border: 2px solid rgba(0,61,124,0.15);
  border-radius: 50%;
  width: 40px; height: 40px;
  font-size: 20px; color: var(--nus-blue);
  cursor: pointer;
  align-items: center; justify-content: center;
  z-index: 1002; transition: all 0.2s;
}
.mobile-close-btn:hover {
  background: var(--tabbar);
  border-color: var(--nus-orange);
  color: var(--nus-orange);
}
.overlay-backdrop {
  position: fixed; inset: 0;
  background: rgba(0,61,124,0.45);
  z-index: 1090; border: 0; cursor: pointer;
  opacity: 0; transition: opacity 0.28s;
}
.overlay-backdrop.show { opacity: 1; }
.overlay-backdrop[hidden] { display: none; }

/* ---------- layout: 2-column (no scratchpad — stereochem has no Pyodide) ---------- */
.module-grid {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 20px 48px 80px;
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr);
  gap: 24px;
  align-items: start;
}

.subnav {
  position: sticky; top: 90px;
  background: #fff;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-nav);
  padding: 22px 16px;
  max-height: calc(100vh - 110px);
  overflow-y: auto;
}
.subnav-title {
  font-size: 11px; font-weight: 700; letter-spacing: 1.2px;
  text-transform: uppercase; color: var(--nus-orange);
  padding: 0 8px 12px; border-bottom: 1px solid var(--line-soft);
  margin-bottom: 8px;
}
.subnav-item {
  display: block; width: 100%; text-align: left;
  background: none; border: 0; cursor: pointer;
  font-family: inherit; text-decoration: none;
  color: var(--ink); font-size: 14px; font-weight: 500;
  padding: 10px 12px; margin: 2px 0;
  border-radius: 8px;
  border-left: 3px solid transparent;
  transition: all 0.2s ease;
  line-height: 1.35;
}
.subnav-item:hover {
  background: rgba(0,61,124,0.08);
  color: var(--nus-blue);
  transform: translateX(3px);
  box-shadow: 0 2px 8px rgba(0,61,124,0.08);
}
.subnav-item.active {
  background: rgba(0,61,124,0.08);
  color: var(--nus-blue);
  border-left-color: var(--nus-orange);
  font-weight: 600;
}
.subnav-item-sub { font-size: 13px; padding-left: 26px; color: var(--muted); }
.subnav-num {
  display: inline-block; min-width: 22px;
  color: var(--nus-orange); font-weight: 600; font-size: 12px;
}
.subnav-item.done::after { content: ' ✓'; color: var(--good); font-weight: 700; margin-left: 4px; }

.time-remaining-bar {
  text-align: center;
  font-size: 12px; color: var(--faint);
  font-weight: 500; letter-spacing: 0.02em;
  padding: 8px 0 4px;
}

.module-content {
  background: #fff;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-content);
  padding: 40px 52px;
  min-width: 0;
}

/* ---------- pages ---------- */
.page { display: none; animation: pageFadeIn 0.35s ease-out; }
.page.active { display: block; }
@keyframes pageFadeIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

.progressbar,
.page-progress-bar {
  width: 100%; height: 4px;
  background: var(--line-soft);
  border-radius: 2px;
  overflow: hidden;
  margin-bottom: 14px;
}
.progressbar__fill,
.page-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--nus-blue) 0%, var(--nus-orange) 100%);
  transition: width 0.4s ease;
}

.page-meta {
  font-size: 12px; font-weight: 600;
  letter-spacing: 1.2px; text-transform: uppercase;
  color: var(--nus-orange);
  margin-bottom: 10px;
}

/* ---------- typography ---------- */
.section-title {
  font-size: 30px; font-weight: 700; color: var(--nus-blue);
  margin: 4px 0 24px;
  padding-bottom: 14px;
  border-bottom: 2px solid rgba(0,61,124,0.12);
  line-height: 1.2;
}
.subsection-title {
  font-size: 26px; font-weight: 700; color: var(--nus-blue);
  margin: 4px 0 24px;
  padding-bottom: 12px;
  border-bottom: 2px solid rgba(0,61,124,0.12);
  line-height: 1.25;
}

/* `.module` is retained ONLY as a transitional alias so a module_template.html
   that has not yet been migrated to .module-grid/.module-content still renders
   readable prose. New markup should use .module-content. */
.module-content h1, .module h1 {
  font-size: 42px; font-weight: 800; line-height: 1.1;
  margin: 0.2rem 0 12px; color: var(--nus-blue);
}
.module-content h2, .module h2 {
  font-size: 30px; font-weight: 700; color: var(--nus-blue);
  margin: 40px 0 24px; padding-bottom: 14px;
  border-bottom: 2px solid rgba(0,61,124,0.12); line-height: 1.2;
}
.module-content h3, .module h3 {
  font-size: 26px; font-weight: 700; color: var(--nus-blue);
  margin: 28px 0 12px; line-height: 1.25;
}
.module-content h4, .module h4 {
  margin: 0 0 8px; font-size: 17px; font-weight: 700; color: var(--ink);
}
.module-content p, .module p, .page-body p { margin: 14px 0; font-size: 16px; }
.module-content ul, .module-content ol,
.module ul, .module ol,
.module-list { margin: 14px 0 14px 24px; }
.module-content li, .module li, .module-list li { margin: 8px 0; font-size: 16px; }

.lesson-intro { font-size: 19px; color: var(--muted); font-weight: 400; line-height: 1.6; }
.muted { color: var(--muted); }

/* inline emphasis (authored in Word via font colour) */
.hl-blue   { color: var(--nus-blue); font-weight: 600; }
.hl-orange { color: var(--nus-orange); font-weight: 600; }
.hl-red    { color: #D32F2F; font-weight: 600; }

/* ---------- buttons ---------- */
.btn {
  font-family: inherit; font-size: 14px; font-weight: 600;
  cursor: pointer;
  border: 1.5px solid var(--line-strong);
  color: var(--nus-blue);
  background: #fff;
  padding: 10px 22px;
  border-radius: 8px;
  transition: transform 0.15s, box-shadow 0.15s, background 0.2s, border-color 0.2s;
}
.btn:hover:not(:disabled) {
  background: rgba(0,61,124,0.06);
  border-color: rgba(0,61,124,0.40);
  transform: translateY(-1px);
}
.btn.primary {
  background: linear-gradient(135deg, var(--nus-orange) 0%, var(--nus-orange-bright) 100%);
  border-color: transparent; color: #fff;
  box-shadow: var(--shadow-cta);
}
.btn.primary:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 8px 22px rgba(255,107,53,0.35);
}
.btn.ghost { border-color: var(--line); color: var(--muted); background: #fff; }
.btn.ghost:hover:not(:disabled) { color: var(--nus-blue); border-color: var(--nus-blue); background: #fff; }
.btn.small { padding: 6px 13px; font-size: 12px; border-radius: var(--radius-sm); }
.btn:disabled { opacity: 0.5; cursor: default; transform: none; box-shadow: none; }

/* ---------- cards ----------
   Python look: white card, 16px radius, hairline navy border, navy-tinted
   shadow. The old 5px left stripe is replaced by a top-edge gradient bar plus
   a coloured .card__tag pill. Each variant only sets --accent/--accent-2, so
   the shared rules below read var(--accent) instead of repeating the colour. */
.card {
  --accent: var(--nus-orange);
  --accent-2: var(--nus-orange-bright);
  position: relative;
  background: var(--card);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-card);
  padding: 24px 28px;
  margin: 28px 0;
  box-shadow: var(--shadow);
  transition: box-shadow 0.25s ease, transform 0.25s ease;
}
/* the accent bar. Kept on a pseudo-element (not overflow:hidden on .card) so
   3Dmol canvases, JSME's toolbars and the Rule-3 "+N" float are never clipped. */
.card::before {
  content: '';
  position: absolute; top: 0; left: 0; right: 0;
  height: 4px;
  border-radius: var(--radius-card) var(--radius-card) 0 0;
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
}
.card:hover { box-shadow: var(--shadow-hover); }
.card__tag {
  display: inline-block;
  padding: 4px 14px;
  border-radius: 20px;
  font-size: 11px; font-weight: 700; letter-spacing: 1px;
  text-transform: uppercase;
  margin-bottom: 14px;
  color: #fff;
  background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
}
.prompt, .card .prompt {
  font-size: 17px; font-weight: 600; color: var(--nus-blue);
  margin-bottom: 16px; line-height: 1.5;
}

/* per-variant accents, mapped onto the Python palette */
.card--reflect       { --accent: var(--purple);    --accent-2: var(--purple-2); }
.card--misconception { --accent: var(--nus-blue);   --accent-2: var(--nus-blue-700); }
.card--predict       { --accent: var(--nus-orange); --accent-2: var(--nus-orange-bright); }
.card--worked        { --accent: var(--info);       --accent-2: var(--info-2); }
.card--video         { --accent: var(--nus-blue);   --accent-2: var(--nus-blue-700); }
.card--mol3d,
.card--rs,
.card--rsfree,
.card--enantiomer,
.card--linked        { --accent: var(--nus-blue);   --accent-2: var(--nus-blue-700); }
.card--mol2d         { --accent: var(--faint);      --accent-2: #b8c2d0; }
.card--draw,
.card--draw3d        { --accent: var(--pink);       --accent-2: var(--pink-2); }
.card--ciprank,
.card--ciptrainer,
.card--cipduel,
.card--ciplabel,
.card--ciprule1,
.card--ciprule2,
.card--ciprule3      { --accent: var(--nus-orange); --accent-2: var(--nus-orange-bright); }
.card--chiralsort    { --accent: var(--info);       --accent-2: var(--info-2); }
.card--stereospot    { --accent: var(--info);       --accent-2: var(--info-2); }
.card--hunt          { --accent: var(--purple);     --accent-2: var(--purple-2); }
.card--dock          { --accent: var(--good);       --accent-2: #4cc285; }

/* ---------- inputs ---------- */
textarea, input[type=text] {
  width: 100%; font-family: inherit; font-size: 15px;
  padding: 12px 14px;
  border: 1.5px solid rgba(0,61,124,0.2);
  border-radius: 8px;
  resize: vertical; margin: 0.4rem 0;
  background: #fff;
  color: var(--ink);
}
textarea:focus, input:focus {
  outline: none; border-color: var(--nus-orange);
  box-shadow: 0 0 0 3px rgba(255,107,53,0.15);
}

/* ---------- options / radios ---------- */
.opts { display: flex; flex-direction: column; gap: 8px; margin: 14px 0; }
.opt {
  display: flex; gap: 10px; align-items: flex-start;
  text-align: left; width: 100%;
  background: #fff;
  border: 1.5px solid var(--line-strong);
  border-radius: 8px;
  padding: 12px 16px;
  font-family: inherit; font-size: 15px; color: var(--ink);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s, transform 0.10s;
}
.opt:hover { border-color: var(--nus-blue); background: rgba(0,61,124,0.04); }
.opt input { margin-top: 0.25rem; }
.opt.correct   { border-color: var(--good); background: rgba(46,163,107,0.10); }
.opt.incorrect { border-color: var(--bad);  background: rgba(201,79,79,0.10); }

.feedback {
  margin-top: 16px; padding: 14px 16px;
  border-left: 4px solid var(--nus-blue);
  background: rgba(0,61,124,0.04);
  border-radius: var(--radius-sm);
  font-size: 14px; line-height: 1.6;
}
.feedback.correct   { border-left-color: var(--good); background: rgba(46,163,107,0.06); color: var(--good); }
.feedback.incorrect { border-left-color: var(--bad);  background: rgba(201,79,79,0.06);  color: var(--bad); }

.reveal {
  margin-top: 16px; padding: 14px 18px;
  background: rgba(0,61,124,0.05);
  border-left: 3px solid var(--nus-blue);
  border-radius: var(--radius-sm);
  font-size: 15px; line-height: 1.65;
}

/* ---------- worked example ---------- */
.worked-stage { margin: 14px 0; }
.stage-label {
  font-size: 12px; font-weight: 700; letter-spacing: 0.6px;
  text-transform: uppercase; color: var(--info); margin: 8px 0;
}
.scaffold {
  font-family: var(--mono);
  font-size: 13px; line-height: 1.55;
  background: var(--code-bg); color: var(--code-ink);
  padding: 14px 16px; border-radius: 8px;
  overflow-x: auto; white-space: pre-wrap;
  border: 1px solid #1e293b;
}
.code-block { margin: 18px 0; }
.code-ref {
  font-family: var(--mono);
  font-size: 13px; line-height: 1.55;
  background: var(--code-bg); color: var(--code-ink);
  padding: 14px 16px; border-radius: 8px;
  overflow-x: auto; white-space: pre;
  border: 1px solid #1e293b;
}
.code-ref code { font-family: inherit; font-size: inherit; color: inherit; background: none; padding: 0; border: none; border-radius: 0; }

/* ---------- molecules (3Dmol) ----------
   3Dmol measures its container ONCE at creation and never re-measures, so every
   host below keeps a real, explicit pixel height. */
.mol3d-view {
  width: 100%; height: 340px; position: relative;
  border-radius: var(--radius-btn);
  background: radial-gradient(circle at 50% 40%, #ffffff, var(--inset));
  border: 1px solid var(--line-soft);
}
.mol3d-controls { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }

/* ---------- enantiomer pair ---------- */
.enant-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin: 0.3rem 0 0.2rem; }
.enant-cell { margin: 0; text-align: center; }
.enant-cell h4 { margin: 0.1rem 0 0.5rem; }
.enant-cell .mol3d-view { height: 300px; }
.enant-mirror { transform: scaleX(-1); }   /* S pane rendered as a true mirror of R */
.enant-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-top: 0.9rem; }
.enant-actions .btn.primary { margin-left: auto; }
.enant-merged {
  margin-top: 1.1rem; opacity: 0; transform: translateY(10px);
  transition: opacity 0.55s ease, transform 0.55s ease;
}
.enant-merged.show { opacity: 1; transform: none; }
.enant-merged .mol3d-view { height: 360px; }
.enant-legend { display: flex; gap: 0.6rem; justify-content: center; flex-wrap: wrap; margin: 0.1rem 0 0.7rem; }
.enant-legend span {
  display: inline-flex; align-items: center; gap: 0.45rem;
  font-size: 12px; color: var(--muted);
  background: var(--inset); border: 1px solid var(--line-soft);
  padding: 0.25rem 0.7rem; border-radius: var(--radius-pill);
}
.enant-legend i { width: 0.72rem; height: 0.72rem; border-radius: 50%; display: inline-block; }
.enant-verdict {
  margin-top: 0.8rem; padding: 14px 18px;
  background: rgba(0,61,124,0.05);
  border-radius: var(--radius-sm); border-left: 3px solid var(--nus-blue);
  font-size: 15px; line-height: 1.65;
  opacity: 0; transform: translateY(6px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
.enant-verdict.show { opacity: 1; transform: none; }
@media (max-width: 620px) { .enant-pair { grid-template-columns: 1fr; } }
@media (prefers-reduced-motion: reduce) {
  .enant-merged, .enant-verdict { transition: none; }
}

/* ---------- linked 2D/3D pair ----------
   a 3D model beside the 2D drawing of that exact viewpoint — turning the model
   on the left redraws the formula on the right */
.linked-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin: 0.3rem 0 0.2rem; }
.linked-cell { margin: 0; text-align: center; }
.linked-cell h5 {
  margin: 0.1rem 0 0.5rem; font-size: 11px; font-weight: 700; color: var(--nus-blue);
  text-transform: uppercase; letter-spacing: 1px;
}
.linked-cell h5 span { font-weight: 400; color: var(--muted); text-transform: none; letter-spacing: 0; }
.linked-cell .mol3d-view { height: 300px; }
.linked-2d {
  height: 300px; border-radius: var(--radius-btn);
  border: 1px solid var(--line-soft); background: #fff;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.linked-2d svg { width: 100%; height: 100%; }
.linked-legend { display: flex; gap: 0.5rem; justify-content: center; flex-wrap: wrap; margin: 0.9rem 0 0; }
.linked-legend span {
  display: inline-flex; align-items: center; gap: 0.45rem;
  font-size: 12px; color: var(--muted);
  background: var(--inset); border: 1px solid var(--line-soft);
  padding: 0.25rem 0.7rem; border-radius: var(--radius-pill);
}
.linked-status {
  margin-top: 0.7rem; padding: 12px 16px;
  background: var(--inset); border-radius: var(--radius-sm);
  border-left: 3px solid var(--line); font-size: 14px; line-height: 1.6;
  transition: background 0.3s ease;
}
.linked-status.good { background: var(--good-bg); border-left-color: var(--good); }
.linked-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-top: 0.9rem; }
.linked-actions .linked-snap { margin-left: auto; }
@media (max-width: 620px) {
  .linked-pair { grid-template-columns: 1fr; }
  .linked-actions .linked-snap { margin-left: 0; }
}

/* ---------- draw -> 3D -> wedge/dash ---------- */
.d3-result {
  margin-top: 1.1rem; opacity: 0; transform: translateY(10px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}
.d3-result.show { opacity: 1; transform: none; }
.d3-msg { font-size: 14px; }
.d3-msg.bad { color: var(--bad); }
.d3-formula { font-weight: 700; color: var(--nus-blue); font-family: var(--mono); }
@media (prefers-reduced-motion: reduce) { .d3-result, .linked-status { transition: none; } }

/* ---------- 2D drawings & figures ---------- */
.mol2d {
  display: flex; justify-content: center;
  background: #fff; border-radius: var(--radius-btn); padding: 0.4rem;
}
.mol2d svg { max-width: 100%; height: auto; }
figure.card { text-align: center; }
figcaption { margin-top: 10px; font-size: 14px; color: var(--muted); font-style: italic; }
.module-figure { margin: 28px 0; text-align: center; }
.module-figure img {
  max-width: 100%; height: auto;
  border-radius: var(--radius-btn);
  box-shadow: 0 8px 24px rgba(0,61,124,0.12);
}
.module-figure figcaption { margin-top: 10px; font-size: 14px; color: var(--muted); font-style: italic; }

/* ---------- drawing sketchpad (Kekule.js, loaded lazily via jsme.js) ----------
   Empty, the host centres a "loading..." line inside a dashed outline. Once
   Kekule has built its composer inside, .ready turns the host into a plain block
   (Kekule lays out its own toolbars and canvas and must not be a flex item) and
   the dashes give way to a solid card frame. Kekule breaks at zero size, so the
   min-height stays. */
.jsme-host {
  min-height: 400px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-card);
  margin: 0.5rem 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--muted);
  background: var(--inset);
}
.jsme-host.ready {
  display: block; overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-card);
  background: #fff;
  box-shadow: var(--shadow);
}

/* --- Kekule composer, retinted to the course palette ------------------------
   Stock Kekule paints flat medium-grey toolbars AND a grey drawing canvas
   (rgb(170,170,170)); on the white cards that reads as dated and makes the drawn
   molecule hard to see. Every rule below is scoped to .jsme-host so it only
   touches the course sketchpads, and it restyles CONTAINERS and button STATES
   only: each tool glyph is a PNG on a child <span class="K-Glyph-Content">, so
   recolouring a button never erases its icon. Kekule injects its own stylesheet
   at runtime (after this file loads), so the !important flags are what win the
   cascade. The class names are Kekule's stable theme hooks. */

/* drawing canvas: paper-white, not grey */
.jsme-host .K-Chem-Editor,
.jsme-host .K-Chem-Editor2D,
.jsme-host .K-Chem-Composer-Editor-Stage { background: #fff !important; }
.jsme-host .K-Chem-Composer-Editor-Stage { min-height: 300px; }

/* toolbars: a soft rail instead of solid grey, split off by hairlines */
.jsme-host .K-Chem-Composer-Top-Region,
.jsme-host .K-Chem-Composer-Left-Region,
.jsme-host .K-Chem-Composer-Bottom-Region,
.jsme-host .K-Chem-Composer-Toolbar,
.jsme-host .K-Chem-InnerToolbar { background: var(--inset) !important; }
.jsme-host .K-Chem-Composer-Top-Region  { border-bottom: 1px solid var(--line-soft) !important; }
.jsme-host .K-Chem-Composer-Left-Region { border-right:  1px solid var(--line-soft) !important; }

/* tool buttons: flat and quiet at rest, brand-tinted on hover and when active */
.jsme-host .K-Button {
  background: transparent !important;
  border: 1px solid transparent !important;
  border-radius: var(--radius-sm) !important;
  color: var(--ink) !important;
  margin: 2px !important;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.jsme-host .K-Button.K-State-Hover {
  background: rgba(0,61,124,0.06) !important;
  border-color: var(--line-strong) !important;
}
/* the currently-picked drawing tool. Kekule marks it with K-Chem-Toggle-Select-State
   and pins that button's own background transparent (it beats a background override
   even at high specificity), so the reliable cue is an inset orange ring, which
   Kekule never sets. The background tint is a harmless bonus for tool types that do
   accept it. */
.jsme-host .K-Button.K-Chem-Toggle-Select-State,
.jsme-host .K-Button.K-State-Selected,
.jsme-host .K-Button.K-State-Checked {
  background: rgba(255,107,53,0.15) !important;
  border-color: var(--nus-orange) !important;
  box-shadow: inset 0 0 0 2px var(--nus-orange) !important;   /* orange ring marks the live tool */
  color: var(--nus-orange) !important;
}
.jsme-host .K-Button.K-State-Disabled { opacity: 0.4 !important; }
.draw-actions { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.hint {
  margin-top: 0.5rem; padding: 12px 16px;
  background: #fff7f3; border-radius: var(--radius-sm);
  border-left: 3px solid var(--nus-orange); font-size: 14px;
}

/* ============================================================================
   CIP_TRAINER (.card--ciptrainer)
   ========================================================================== */
.cipt-stage { margin-top: 1rem; padding-top: 0.2rem; }
.cipt-stage + .cipt-stage { border-top: 1px dashed var(--line); }
.cipt-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-top: 0.6rem; }
.cipt-chip {
  display: inline-block; width: 12px; height: 12px; border-radius: 3px;
  margin-right: 0.5rem; vertical-align: -1px;
}

/* the drawing, with one outline per group */
.cipt-mol { margin: 0.6rem auto; max-width: 100%; }
.cipt-mol .cipt-svg svg { display: block; border-radius: var(--radius-btn); background: #fff; }
/* Every host drawMolecule() draws into needs to be a containing block, or the
   overlay below resolves against the viewport and scatters the blobs page-wide. */
.cipt-mol, .cipd-mol, .cipl-mol { position: relative; }
.cipt-overlay { position: absolute; inset: 0; }
.cipt-blob { opacity: 0.13; transition: opacity 0.18s; cursor: pointer; }
.cipt-blob.hot { opacity: 0.34; }

/* first atom + atomic number */
.cipt-rows { width: 100%; border-collapse: collapse; margin: 0.6rem 0; }
.cipt-rows th {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.6px; color: var(--muted);
  text-align: left; font-weight: 700; padding: 0.35rem 0.4rem;
  border-bottom: 1px solid var(--line);
}
.cipt-rows td { padding: 0.4rem; border-bottom: 1px solid var(--line); vertical-align: middle; }
.cipt-rows tr.hot td { background: rgba(0,61,124,0.05); }
.cipt-rows input {
  width: 5.4rem; margin: 0; padding: 0.35rem 0.5rem; text-align: center;
  font-family: var(--mono); font-size: 13px;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--inset);
}
.cipt-rows input.ok { border-color: var(--good); background: var(--good-bg); }
.cipt-rows input.no { border-color: var(--bad);  background: var(--bad-bg); }
.cipt-mark { font-size: 13px; color: var(--good); font-weight: 700; }
.cipt-hint {
  margin-top: 0.5rem; padding: 12px 16px;
  background: #fff7f3; border-radius: var(--radius-sm);
  border-left: 3px solid var(--nus-orange); font-size: 14px;
}

/* one bond out */
.cipt-sph { display: flex; gap: 0.8rem; flex-wrap: wrap; margin: 0.7rem 0; }
.cipt-col {
  flex: 1 1 190px; border: 1px solid var(--line-soft); border-radius: var(--radius);
  padding: 0.7rem 0.8rem; background: var(--inset);
}
.cipt-col h5 { margin: 0 0 0.4rem; font-size: 14px; font-weight: 700; color: var(--nus-blue); }
.cipt-col .muted { font-size: 12px; }
.cipt-set { display: flex; gap: 0.35rem; margin-top: 0.4rem; }
.cipt-atom {
  flex: 1; text-align: center;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  padding: 0.35rem 0.2rem; background: #fff;
  font-family: var(--mono); font-weight: 700; transition: 0.25s;
}
.cipt-atom small { display: block; font-family: inherit; font-weight: 400; color: var(--muted); font-size: 10px; }
.cipt-atom.phantom { color: var(--faint); border-style: dashed; }
.cipt-atom.tie  { background: var(--tabbar); }
.cipt-atom.win  { background: var(--good-bg); border-color: var(--good); color: var(--good); }
.cipt-atom.lose { background: var(--bad-bg);  border-color: var(--bad);  color: var(--bad); }
.cipt-atom.grew { animation: cipt-pop 0.45s ease; }
@keyframes cipt-pop {
  0% { transform: scale(0.6); opacity: 0.2; } 60% { transform: scale(1.15); } 100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) { .cipt-atom.grew { animation: none; } }

.cipt-verdict { margin-top: 0.6rem; padding: 14px 16px; border-radius: var(--radius-sm); font-size: 14px; }
.cipt-verdict.good { background: var(--good-bg); border-left: 3px solid var(--good); }
.cipt-verdict.bad  { background: var(--bad-bg);  border-left: 3px solid var(--bad); }
.cipt-verdict.tie  { background: #fff7f3;        border-left: 3px solid var(--nus-orange); }

.cipt-meta { margin-left: auto; color: var(--muted); font-size: 13px; }
.cipt-3d {
  width: 100%; height: 300px; position: relative;
  border-radius: var(--radius-btn); background: var(--inset);
}
.cipt-legend { display: flex; gap: 0.9rem; flex-wrap: wrap; font-size: 13px; margin: 0.5rem 0; color: var(--muted); }
.cipt-legend i { display: inline-block; width: 11px; height: 11px; border-radius: 3px; margin-right: 0.35rem; }

/* ============================================================================
   CIP_DUEL (.card--cipduel) — ranking as head-to-head comparison
   Reuses .cipt-mol / .cipt-blob for the outlined drawing; .dim is the duel's
   addition, so the two groups actually duelling stand out from the two that are not.
   ========================================================================== */
.cipt-blob.dim { opacity: 0.05; }

.cipd-top { display: flex; gap: 1.2rem; flex-wrap: wrap; align-items: flex-start; }
.cipd-ladder { flex: 1 1 230px; min-width: 210px; }
.cipd-ladder h5 {
  margin: 0.1rem 0 0.5rem; font-size: 11px; letter-spacing: 1px;
  text-transform: uppercase; color: var(--muted);
}
.cipd-rung {
  display: flex; align-items: center; gap: 0.55rem;
  border: 1px dashed var(--line-strong); border-radius: var(--radius-btn);
  padding: 0.4rem 0.6rem; margin-bottom: 0.35rem; min-height: 2.4rem;
  background: var(--inset); font-size: 14px;
}
.cipd-rung.filled { border-style: solid; background: #fff; }
.cipd-rung.just { animation: cipd-pop 0.45s ease; }
@keyframes cipd-pop { 0% { transform: scale(0.9); background: #fff7f3; } 100% { transform: scale(1); } }
.cipd-pos {
  width: 1.4rem; height: 1.4rem; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 11px; font-weight: 700;
  background: var(--nus-blue); color: #fff; flex: 0 0 auto;
}
.cipd-pos.empty { background: var(--line); color: var(--muted); }
.cipd-sw { width: 0.85rem; height: 0.85rem; border-radius: 3px; flex: 0 0 auto; }
.cipd-lb { font-weight: 500; }
.cipd-why { margin-left: auto; font-size: 11px; color: var(--muted); font-family: var(--mono); }

.cipd-arena { margin-top: 1rem; border-top: 1px solid var(--line); padding-top: 1rem; }
.cipd-head { display: flex; align-items: baseline; gap: 0.6rem; margin-bottom: 0.7rem; }
.cipd-n { font-size: 11px; letter-spacing: 1px; text-transform: uppercase; color: var(--muted); font-weight: 700; }
.cipd-q { font-size: 14px; color: var(--muted); }
.cipd-fighters { display: grid; grid-template-columns: 1fr auto 1fr; gap: 0.7rem; align-items: stretch; }
.cipd-fighter {
  border: 2px solid var(--line-strong); border-radius: var(--radius);
  padding: 0.7rem; text-align: center; background: #fff;
  transition: border-color 0.2s, background 0.2s;
}
.cipd-fighter.win { border-color: var(--good); background: var(--good-bg); }
.cipd-fighter.lose { opacity: 0.5; }
.cipd-lb2 {
  font-weight: 700; font-size: 16px;
  display: flex; align-items: center; justify-content: center; gap: 0.4rem;
}
.cipd-vs { align-self: center; font-weight: 700; color: var(--muted); font-size: 12px; }
.cipd-z { margin-top: 0.4rem; font-size: 12px; color: var(--muted); font-family: var(--mono); }
.cipd-z b { color: var(--ink); font-size: 14px; }

.cipd-sph { margin-top: 0.55rem; display: flex; gap: 0.25rem; justify-content: center; align-items: center; }
.cipd-sphlab { font-size: 10px; color: var(--muted); margin-right: 0.15rem; }
.cipd-set { display: flex; gap: 0.25rem; }
.cipd-none { font-size: 11px; }
.cipd-slot {
  width: 2rem; height: 2rem;
  border: 1.5px solid var(--line-strong); border-radius: 7px;
  display: grid; place-items: center;
  font-family: var(--mono); font-size: 13px; font-weight: 700;
  background: #fff; transition: all 0.25s;
}
.cipd-slot.empty { color: var(--faint); border-style: dashed; }
.cipd-slot.ph {
  border-color: var(--nus-orange); color: var(--nus-orange); background: #fff7f3;
  border-style: dashed; animation: cipt-pop 0.5s ease;
}
.cipd-slot.scan { border-color: var(--nus-blue); box-shadow: 0 0 0 3px rgba(0,61,124,0.13); }
.cipd-slot.same { opacity: 0.35; }
.cipd-slot.decides {
  border-color: var(--good); background: var(--good-bg); color: var(--good);
  box-shadow: 0 0 0 3px rgba(46,163,107,0.15);
}
.cipd-slot.beaten { border-color: var(--bad); background: var(--bad-bg); color: var(--bad); }
@media (prefers-reduced-motion: reduce) { .cipd-slot.ph, .cipd-rung.just { animation: none; } }

.cipd-choices { display: flex; gap: 0.5rem; justify-content: center; margin-top: 0.9rem; flex-wrap: wrap; }
.cipd-btn.tie { background: var(--nus-blue); border-color: var(--nus-blue); color: #fff; }
.cipd-btn.rule3 { background: #fff7f3; border-color: var(--nus-orange); color: var(--nus-orange); font-weight: 600; }
.cipd-fb { margin-top: 0.8rem; padding: 14px 16px; border-radius: var(--radius-sm); font-size: 14px; }
.cipd-fb.ok   { background: var(--good-bg); border-left: 4px solid var(--good); }
.cipd-fb.no   { background: var(--bad-bg);  border-left: 4px solid var(--bad); }
.cipd-fb.info { background: rgba(0,61,124,0.04); border-left: 4px solid var(--nus-blue); }

.cipd-done { margin: 1rem 0 0.3rem; font-size: 16px; }
.cipd-cmp { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin: 0.6rem 0 1rem; }
.cipd-col h5 { margin: 0.2rem 0 0.45rem; font-size: 11px; letter-spacing: 0.6px; text-transform: uppercase; }
.cipd-col.cip h5 { color: var(--good); }
.cipd-col.mass h5 { color: var(--bad); }
.cipd-col.cip .cipd-pos { background: var(--good); }
.cipd-col.mass .cipd-pos { background: var(--bad); }
.cipd-mini {
  display: flex; align-items: center; gap: 0.45rem; padding: 0.3rem 0.5rem;
  border: 1px solid var(--line-soft); border-radius: var(--radius-sm);
  margin-bottom: 0.3rem; font-size: 13px; background: #fff;
}
.cipd-x { margin-left: auto; font-size: 11px; color: var(--muted); font-family: var(--mono); }
@media (max-width: 640px) {
  .cipd-cmp { grid-template-columns: 1fr; }
  .cipd-fighters { grid-template-columns: 1fr; }
  .cipd-vs { padding: 0.2rem 0; }
}

/* ============================================================================
   CIP_LABEL (.card--ciplabel) — mass on show, atomic number withheld
   ========================================================================== */
.cipl-top { display: flex; gap: 1.2rem; flex-wrap: wrap; align-items: flex-start; }
.cipl-side { flex: 1 1 280px; min-width: 260px; }
.cipl-tray {
  display: flex; gap: 0.45rem; padding: 0.5rem 0.6rem;
  border: 2px dashed var(--line-strong); border-radius: var(--radius);
  min-height: 3rem; align-items: center; background: var(--inset);
}
.cipl-tray.over { border-color: var(--nus-orange); background: #fff7f3; }
.cipl-tag {
  width: 2.1rem; height: 2.1rem; border-radius: var(--radius-sm);
  display: grid; place-items: center;
  font-weight: 700; font-size: 14px;
  background: var(--nus-blue); color: #fff; cursor: grab;
  user-select: none; flex: 0 0 auto;
  transition: transform 0.12s, box-shadow 0.12s;
}
.cipl-tag:hover { transform: translateY(-1px); }
.cipl-tag.dragging { opacity: 0.4; }
.cipl-tag.picked { box-shadow: 0 0 0 3px var(--nus-orange); transform: translateY(-2px); }

.cipl-rows { width: 100%; border-collapse: collapse; margin: 0.7rem 0 0.2rem; }
.cipl-rows th {
  text-align: left; font-size: 11px; letter-spacing: 0.6px; text-transform: uppercase;
  color: var(--muted); border-bottom: 1px solid var(--line); padding: 0.3rem 0.4rem; font-weight: 700;
}
.cipl-rows td { padding: 0.4rem; border-bottom: 1px solid var(--line); vertical-align: middle; }
.cipl-rows tr.hot td { background: rgba(0,61,124,0.05); }
/* the decoy: present and legible, but never the loudest thing on the row */
.cipl-mass { color: var(--muted); font-size: 13px; white-space: nowrap; font-family: var(--mono); }
.cipl-slot {
  display: grid; place-items: center; width: 2.4rem; height: 2.4rem;
  border: 2px dashed var(--line-strong); border-radius: 9px; background: #fff;
}
.cipl-slot.over { border-color: var(--nus-orange); background: #fff7f3; }
.cipl-slot.ok { border-style: solid; border-color: var(--good); }
.cipl-slot.no { border-style: solid; border-color: var(--bad); }
.cipl-mark { font-weight: 700; font-size: 15px; }
.cipl-mark.ok { color: var(--good); }
.cipl-mark.no { color: var(--bad); }

.cipl-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-top: 0.7rem; }
.cipl-hint {
  margin-top: 0.5rem; padding: 12px 16px;
  background: #fff7f3; border-radius: var(--radius-sm);
  font-family: var(--mono); font-size: 13px;
}
.cipl-fb { margin-top: 0.8rem; padding: 14px 16px; border-radius: var(--radius-sm); font-size: 14px; }
.cipl-fb.ok { background: var(--good-bg); border-left: 4px solid var(--good); }
.cipl-fb.no { background: var(--bad-bg);  border-left: 4px solid var(--bad); }
@media (max-width: 640px) { .cipl-side { min-width: 0; } }

/* ============================================================================
   CIP_RULE1 (.card--ciprule1) — Rule 1 on a 3D model, then R or S
   ========================================================================== */
.cipr-ptable { margin: 0.8rem 0; padding: 0.7rem 0.8rem; border: 1px solid var(--line-soft); border-radius: var(--radius); }
.cipr-ptable h5 {
  margin: 0 0 0.5rem; font-size: 11px; letter-spacing: 0.6px;
  text-transform: uppercase; color: var(--muted);
}
.cipr-els { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.cipr-el {
  border: 1px solid var(--line-soft); border-radius: var(--radius-btn);
  padding: 0.35rem 0.6rem; text-align: center; background: var(--inset); min-width: 4.2rem;
}
.cipr-el b { display: block; font-size: 16px; font-family: var(--mono); }
.cipr-el .w { display: block; font-family: var(--mono); font-size: 14px; font-weight: 700; color: var(--nus-orange); }
.cipr-el .z { display: block; font-size: 10px; color: var(--muted); }

/* shared step-rail across Rules 1/2/3 */
.cipr-steps, .cip2-steps, .cip3-steps {
  display: flex; gap: 0.4rem; align-items: center; margin: 0.5rem 0 1rem;
  font-size: 13px; flex-wrap: wrap;
}
.cipr-step, .cip2-step, .cip3-step { display: flex; align-items: center; gap: 0.4rem; color: var(--muted); }
.cipr-n, .cip2-n, .cip3-n {
  width: 1.5rem; height: 1.5rem; border-radius: 50%;
  display: grid; place-items: center;
  font-weight: 700; font-size: 11px;
  background: var(--tabbar); color: var(--muted);
}
.cipr-step.on, .cip2-step.on, .cip3-step.on { color: var(--ink); font-weight: 600; }
.cipr-step.on .cipr-n, .cip2-step.on .cip2-n, .cip3-step.on .cip3-n { background: var(--nus-orange); color: #fff; }
.cipr-step.done .cipr-n, .cip2-step.done .cip2-n, .cip3-step.done .cip3-n { background: var(--good); color: #fff; }
.cipr-arrow, .cip2-arrow, .cip3-arrow { color: var(--faint); }

.cipr-top, .cip2-top, .cip3-top { display: flex; gap: 1.2rem; flex-wrap: wrap; align-items: flex-start; }
/* The model column must not shrink. A flex child defaults to `flex:0 1 auto`, so the side
   panel's growth squeezed this mid-layout and 3Dmol measured the container at 69px — the
   canvas then keeps that size forever, since it never re-measures on its own. */
.cipr-molwrap, .cip2-molwrap, .cip3-molwrap { flex: 0 0 auto; }
.cipr-mol, .cip2-mol, .cip3-mol {
  width: 420px; height: 360px; position: relative;
  border-radius: var(--radius); background: var(--inset); overflow: hidden;
}
.cipr-mol canvas, .cip2-mol canvas, .cip3-mol canvas { border-radius: var(--radius); }
/* the R/S trace sits over the WebGL canvas and never eats clicks */
.cipr-ov, .cip2-ov, .cip3-ov {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none; z-index: 5;
}
.cipr-side, .cip2-side, .cip3-side { flex: 1 1 340px; min-width: 320px; }
.cipr-legend, .cip2-legend, .cip3-legend {
  display: flex; gap: 0.9rem; flex-wrap: wrap; font-size: 13px; margin: 0.5rem 0; color: var(--muted);
}
.cipr-legend i, .cip2-legend i, .cip3-legend i {
  display: inline-block; width: 11px; height: 11px; border-radius: 3px; margin-right: 0.35rem;
}

.cipr-rows { width: 100%; border-collapse: collapse; }
.cipr-rows th {
  text-align: left; font-size: 11px; letter-spacing: 0.6px; text-transform: uppercase;
  color: var(--muted); border-bottom: 1px solid var(--line); padding: 0.3rem 0.4rem; font-weight: 700;
}
.cipr-rows td { padding: 0.5rem 0.4rem; border-bottom: 1px solid var(--line); vertical-align: middle; }
.cipr-rows tr.hot td { background: rgba(0,61,124,0.05); }
.cipr-win {
  width: 6rem; padding: 0.4rem 0.5rem;
  border: 2px solid var(--line-strong); border-radius: var(--radius-sm);
  font-family: var(--mono); font-size: 13px; font-weight: 700; text-align: center; margin: 0;
}
.cipr-win:focus { outline: none; border-color: var(--nus-orange); box-shadow: 0 0 0 3px rgba(255,107,53,0.15); }
.cipr-win.ok { border-color: var(--good); background: var(--good-bg); color: var(--good); }
.cipr-win.no { border-color: var(--bad);  background: var(--bad-bg);  color: var(--bad); }
.cipr-mark { font-weight: 700; }
.cipr-mark.ok { color: var(--good); }
.cipr-mark.no { color: var(--bad); }
.cipr-wcol { font-family: var(--mono); font-weight: 700; color: var(--nus-blue); white-space: nowrap; }

/* shared phantom drop-slot + tray across Rules 1/2/3 */
.cipr-pslot, .cip2-pslot, .cip3-pslot {
  display: grid; place-items: center; min-width: 4.1rem; height: 2.4rem;
  border: 2px dashed var(--line-strong); border-radius: 9px; background: #fff;
  font-weight: 700; font-size: 13px;
}
.cipr-pslot.over, .cip2-pslot.over, .cip3-pslot.over { border-color: var(--nus-orange); background: #fff7f3; }
.cipr-pslot.ok, .cip2-pslot.ok, .cip3-pslot.ok { border-style: solid; border-color: var(--good); background: var(--good-bg); }
.cipr-pslot.no, .cip2-pslot.no, .cip3-pslot.no { border-style: solid; border-color: var(--bad); background: var(--bad-bg); }
.cipr-tray, .cip2-tray, .cip3-tray {
  display: flex; gap: 0.45rem; padding: 0.5rem 0.6rem;
  border: 2px dashed var(--line-strong); border-radius: var(--radius);
  min-height: 3.2rem; align-items: center; background: var(--inset);
  flex-wrap: wrap; margin-top: 0.8rem;
}
.cipr-tray.over, .cip2-tray.over, .cip3-tray.over { border-color: var(--nus-orange); background: #fff7f3; }
.cipr-ptile, .cip2-ptile, .cip3-ptile {
  min-width: 3.6rem; height: 2.2rem; padding: 0 0.6rem; border-radius: var(--radius-sm);
  display: grid; place-items: center; font-weight: 700; font-size: 13px;
  background: var(--nus-blue); color: #fff; cursor: grab; user-select: none;
  transition: transform 0.12s, box-shadow 0.12s;
}
.cipr-ptile:hover, .cip2-ptile:hover, .cip3-ptile:hover { transform: translateY(-1px); }
.cipr-ptile.dragging, .cip2-ptile.dragging, .cip3-ptile.dragging { opacity: 0.4; }
.cipr-ptile.picked, .cip2-ptile.picked, .cip3-ptile.picked { box-shadow: 0 0 0 3px var(--nus-orange); transform: translateY(-2px); }

.cipr-actions, .cip2-actions, .cip3-actions {
  display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; margin-top: 0.9rem;
}
.cipr-fb, .cip2-fb, .cip3-fb {
  margin-top: 0.85rem; padding: 14px 16px; border-radius: var(--radius-sm); font-size: 14px;
}
.cipr-fb.ok, .cip2-fb.ok, .cip3-fb.ok { background: var(--good-bg); border-left: 4px solid var(--good); }
.cipr-fb.no, .cip2-fb.no, .cip3-fb.no { background: var(--bad-bg);  border-left: 4px solid var(--bad); }
.cipr-stage, .cip2-stage, .cip3-stage { display: none; }
.cipr-stage.on, .cip2-stage.on, .cip3-stage.on { display: block; }

/* shared R/S step list */
.cipr-rssteps, .cip2-rssteps, .cip3-rssteps { margin: 0.2rem 0 0; padding: 0; list-style: none; }
.cipr-rssteps li, .cip2-rssteps li, .cip3-rssteps li {
  padding: 0.45rem 0 0.45rem 1.7rem; position: relative; color: var(--muted);
  font-size: 14px; transition: opacity 0.3s;
}
.cipr-rssteps li { opacity: 0.35; }
.cip2-rssteps li, .cip3-rssteps li { opacity: 0.55; }
.cipr-rssteps li.on, .cip2-rssteps li.on, .cip3-rssteps li.on { opacity: 1; color: var(--ink); }
.cipr-rssteps li::before, .cip2-rssteps li::before, .cip3-rssteps li::before {
  content: "\25CB"; position: absolute; left: 0; color: var(--faint);
}
.cipr-rssteps li.on::before, .cip2-rssteps li.on::before, .cip3-rssteps li.on::before {
  content: "\25CF"; color: var(--nus-orange);
}

.cipr-verdict {
  margin-top: 0.8rem; padding: 1rem; border-radius: var(--radius);
  text-align: center; background: var(--inset);
  opacity: 0; transform: translateY(6px);
  transition: opacity 0.4s, transform 0.4s;
}
.cipr-verdict.show { opacity: 1; transform: none; }
.cipr-sense, .cipr-why { font-size: 14px; color: var(--muted); }
.cipr-letter { font-size: 3rem; font-weight: 700; line-height: 1.1; font-family: var(--mono); }
.cipr-verdict.R { background: rgba(0,61,124,0.05); --glow: 0,61,124; }
.cipr-verdict.R .cipr-letter { color: var(--nus-blue); }
.cipr-verdict.S { background: rgba(255,107,53,0.07); --glow: 255,107,53; }
.cipr-verdict.S .cipr-letter { color: var(--nus-orange); }

/* The answer breathes rather than sitting inert — slow enough to read as alive, not busy. */
@keyframes cipr-breathe {
  0%, 100% { transform: scale(1); text-shadow: 0 0 8px rgba(var(--glow), 0.28); }
  50% { transform: scale(1.05); text-shadow: 0 0 26px rgba(var(--glow), 0.7); }
}
.cipr-verdict.show .cipr-letter { animation: cipr-breathe 2.8s ease-in-out infinite; }
@keyframes cipr-draw { to { stroke-dashoffset: 0; } }
@keyframes cipr-pop { from { opacity: 0; transform: scale(0.2); } to { opacity: 1; transform: scale(1); } }
/* The arrowhead ORBITS rather than parking at the end. Two reasons: a parked head sat
   underneath the "3" badge and was invisible, and a head that keeps going round states the
   direction continuously instead of once. Because the path is a circle, spinning the head
   about the circle's centre both moves it along the path and keeps it tangent — no
   motion-path needed, and it loops seamlessly with no jump back to the start. */
@keyframes cipr-orbit-cw  { from { transform: rotate(0); } to { transform: rotate(360deg); } }
@keyframes cipr-orbit-ccw { from { transform: rotate(0); } to { transform: rotate(-360deg); } }
.cipr-arc { animation: cipr-draw 1.05s cubic-bezier(.4,0,.2,1) forwards; }
.cipr-badge {
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: cipr-pop 0.38s cubic-bezier(.34,1.56,.64,1) backwards;
}
.cipr-runner { transform-box: view-box; }   /* so transform-origin is in SVG user units */
.cipr-runner.cw  { animation: cipr-orbit-cw 3.4s linear 1.05s infinite; }
.cipr-runner.ccw { animation: cipr-orbit-ccw 3.4s linear 1.05s infinite; }
@media (prefers-reduced-motion: reduce) {
  .cipr-arc, .cipr-badge, .cipr-runner.cw, .cipr-runner.ccw,
  .cipr-verdict.show .cipr-letter { animation: none; }
  .cipr-arc { stroke-dashoffset: 0 !important; }
}
@media (max-width: 820px) { .cipr-mol { width: 100%; } .cipr-side { min-width: 0; } }

/* ============================================================================
   CIP_RULE2 (.card--ciprule2) — step out and compare. Shares the rails, model
   column, trays and stages with .cipr-* above; what follows is only what Rule 2
   adds: the tie picker, the click-to-build slots, and the position-by-position scan.
   ========================================================================== */
.cip2-fb.info { background: rgba(0,61,124,0.04); border-left: 4px solid var(--nus-blue); }
/* the sum trap is not an error — it is a different rule, and it gets its own colour */
.cip2-fb.trap { background: rgba(245,158,11,0.10); border-left: 4px solid var(--amber); }

/* stage 1 — mark the groups Rule 1 cannot separate */
.cip2-picks, .cip3-picks {
  list-style: none; margin: 0.2rem 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 0.45rem;
}
.cip2-pick, .cip3-pick {
  display: flex; align-items: center; gap: 0.5rem;
  border: 2px solid var(--line-strong); border-radius: var(--radius-btn);
  padding: 0.5rem 0.65rem; cursor: pointer; background: #fff;
  font: inherit; text-align: left; width: 100%; color: var(--ink);
  transition: border-color 0.15s, background 0.15s;
}
.cip2-pick:hover, .cip3-pick:hover { border-color: var(--nus-orange); }
.cip2-pick.sel, .cip3-pick.sel { border-color: var(--nus-orange); background: #fff7f3; }
.cip2-pick.ok, .cip3-pick.ok { border-color: var(--good); background: var(--good-bg); }
.cip2-pick.no, .cip3-pick.no { border-color: var(--bad);  background: var(--bad-bg); }
.cip2-pick .zz, .cip3-pick .zz { margin-left: auto; font-family: var(--mono); font-size: 13px; color: var(--muted); }
.cip2-pick .tick, .cip3-pick .tick { width: 1.2rem; text-align: center; font-weight: 700; }
.cip2-pick.sel .tick::before, .cip3-pick.sel .tick::before { content: "\2713"; color: var(--nus-orange); }
.cip2-pick.ok .tick::before, .cip3-pick.ok .tick::before { content: "\2713"; color: var(--good); }
.cip2-pick.no .tick::before, .cip3-pick.no .tick::before { content: "\2717"; color: var(--bad); }
.cip3-pick .lb { font-family: var(--mono); font-weight: 700; }

/* stage 2 — build each set by clicking atoms on the model */
.cip2-focus { border: 1px solid var(--line-soft); border-radius: var(--radius-btn); padding: 0.6rem 0.7rem; margin-bottom: 0.6rem; }
.cip2-focus h5, .cip3-focus h5 { margin: 0 0 0.4rem; font-size: 14px; font-weight: 700; color: var(--nus-blue); }
.cip2-slots, .cip3-slots { display: flex; gap: 0.4rem; align-items: center; }
.cip2-slot, .cip3-slot {
  width: 2.6rem; height: 2.6rem;
  border: 2px dashed var(--line-strong); border-radius: 9px;
  display: grid; place-items: center;
  font-family: var(--mono); font-weight: 700; font-size: 15px;
  color: var(--muted); background: #fff;
}
.cip2-slot.filled, .cip3-slot.filled { border-style: solid; border-color: var(--good); background: var(--good-bg); color: var(--good); }
.cip2-slot.pop { animation: cip2-pop 0.34s cubic-bezier(.34,1.56,.64,1); }
@keyframes cip2-pop { from { transform: scale(0.3); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.cip2-done, .cip3-done {
  border: 1px solid var(--line-soft); border-radius: var(--radius-btn);
  padding: 0.45rem 0.6rem; margin-bottom: 0.4rem;
  display: flex; align-items: center; gap: 0.5rem; font-size: 13px; background: var(--inset);
}
.cip2-done .st, .cip3-done .st { margin-left: auto; font-family: var(--mono); color: var(--nus-blue); font-weight: 700; }
.cip3-done .lb { font-family: var(--mono); font-weight: 700; }
.cip2-hint, .cip3-hint { font-size: 13px; color: var(--muted); margin-top: 0.5rem; }

/* stage 3 — rank the tied groups, and the position-by-position scan */
.cip2-rows, .cip3-rows { width: 100%; border-collapse: collapse; }
.cip2-rows th, .cip3-rows th {
  text-align: left; font-size: 11px; letter-spacing: 0.6px; text-transform: uppercase;
  color: var(--muted); font-weight: 700; padding: 0.3rem 0.4rem; border-bottom: 1px solid var(--line);
}
.cip2-rows td, .cip3-rows td { padding: 0.5rem 0.4rem; border-bottom: 1px solid var(--line); vertical-align: middle; }
.cip2-rows tr.hot td, .cip3-rows tr.hot td { background: rgba(0,61,124,0.05); }
/* during a walk only the two groups being compared stay lit: CIP compares a PAIR, and a
   third set at full strength beside them invites reading all three at once */
.cip2-rrows.walking tr, .cip3-rrows.walking tr { opacity: 0.35; transition: opacity 0.25s; }
.cip2-rrows.walking tr.cmp, .cip3-rrows.walking tr.cmp { opacity: 1; }
.cip2-rrows tr.cmp td, .cip3-rrows tr.cmp td { background: rgba(0,61,124,0.05); }
.cip2-setcell { display: flex; gap: 0.25rem; }
.cip3-setcell { display: flex; gap: 0.25rem; align-items: center; }
.cip2-a, .cip3-a {
  min-width: 1.9rem; height: 1.9rem;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  display: grid; place-items: center;
  font-family: var(--mono); font-weight: 700; font-size: 13px;
  background: #fff; transition: all 0.18s;
}
.cip3-a { position: relative; }
.cip2-a.scan { border-color: var(--nus-orange); box-shadow: 0 0 0 3px rgba(255,107,53,0.18); transform: translateY(-2px); }
.cip3-a.scan { box-shadow: 0 0 0 3px rgba(255,107,53,0.18); transform: translateY(-2px); }
.cip2-a.same, .cip3-a.same { opacity: 0.28; }
.cip2-a.decides, .cip3-a.decides { border-color: var(--good); background: var(--good-bg); color: var(--good); transform: scale(1.12); }
.cip2-a.beaten, .cip3-a.beaten { border-color: var(--bad); background: var(--bad-bg); color: var(--bad); }
.cip2-mark, .cip3-mark { font-weight: 700; }
.cip2-mark.ok, .cip3-mark.ok { color: var(--good); }
.cip2-mark.no, .cip3-mark.no { color: var(--bad); }

/* the payoff: which rule placed each group */
.cip2-final, .cip3-final { margin-top: 0.8rem; border: 1px solid var(--line-soft); border-radius: var(--radius-btn); overflow: hidden; }
.cip2-frow, .cip3-frow {
  display: flex; align-items: center; gap: 0.5rem; padding: 0.45rem 0.6rem;
  border-bottom: 1px solid var(--line); font-size: 13px;
}
.cip2-frow:last-child, .cip3-frow:last-child { border-bottom: 0; }
.cip2-frow .pos, .cip3-frow .pos { width: 2.2rem; font-weight: 700; color: var(--nus-orange); font-family: var(--mono); }
.cip3-frow .lb { font-family: var(--mono); font-weight: 700; }
.cip2-frow .by, .cip3-frow .by {
  margin-left: auto; font-size: 11px; color: var(--muted);
  border: 1px solid var(--line-strong); border-radius: var(--radius-pill); padding: 0.05rem 0.5rem;
}
.cip2-frow .by.r2 { border-color: var(--nus-orange); color: var(--nus-orange); }
.cip3-frow .by.r3 { border-color: var(--ph); color: var(--ph); }

/* stage 4 — the R/S trace */
.cip2-verdict, .cip3-verdict {
  margin-top: 0.8rem; padding: 1rem; border-radius: var(--radius);
  text-align: center; opacity: 0; transform: translateY(6px); transition: all 0.4s;
}
.cip2-verdict.show, .cip3-verdict.show { opacity: 1; transform: none; }
.cip2-sense, .cip2-why, .cip3-sense, .cip3-why { font-size: 14px; color: var(--muted); }
.cip2-letter, .cip3-letter { font-size: 3rem; font-weight: 700; line-height: 1.1; font-family: var(--mono); }
.cip2-verdict.R, .cip3-verdict.R { background: rgba(0,61,124,0.05); }
.cip2-verdict.R .cip2-letter, .cip3-verdict.R .cip3-letter { color: var(--nus-blue); }
.cip2-verdict.S, .cip3-verdict.S { background: rgba(255,107,53,0.07); }
.cip2-verdict.S .cip2-letter, .cip3-verdict.S .cip3-letter { color: var(--nus-orange); }
@keyframes cip2-draw { to { stroke-dashoffset: 0; } }
@keyframes cip2-badge { from { opacity: 0; transform: scale(0.2); } to { opacity: 1; transform: scale(1); } }
@keyframes cip2-orbit-cw  { from { transform: rotate(0); } to { transform: rotate(360deg); } }
@keyframes cip2-orbit-ccw { from { transform: rotate(0); } to { transform: rotate(-360deg); } }
.cip2-arc { animation: cip2-draw 1.05s cubic-bezier(.4,0,.2,1) forwards; }
.cip2-badge {
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: cip2-badge 0.38s cubic-bezier(.34,1.56,.64,1) backwards;
}
.cip2-runner { transform-box: view-box; }   /* so transform-origin is in SVG user units */
.cip2-runner.cw  { animation: cip2-orbit-cw 3.4s linear 1.05s infinite; }
.cip2-runner.ccw { animation: cip2-orbit-ccw 3.4s linear 1.05s infinite; }
@media (prefers-reduced-motion: reduce) {
  .cip2-arc, .cip2-badge, .cip2-runner.cw, .cip2-runner.ccw { animation: none; }
  .cip2-arc { stroke-dashoffset: 0 !important; }
}
@media (max-width: 820px) { .cip2-mol { width: 100%; } .cip2-side { min-width: 0; } }

/* ============================================================================
   CIP_RULE3 (.card--ciprule3) — count the bonds, not the atoms. Shares the rails,
   model column, trays, picks and stages above; what is new is the empty slot
   (.cip3-slot.gap), the phantom Rule 3 invents (.cip3-slot.ph / .cip3-a.phantom),
   and the "+N" that floats up as each bond is counted.
   ========================================================================== */
.cip3-fb.info { background: rgba(0,61,124,0.04); border-left: 4px solid var(--nus-blue); }
.cip3-fb.trap { background: rgba(245,158,11,0.10); border-left: 4px solid var(--amber); }
.cip3-fb.ph   { background: var(--ph-bg); border-left: 4px solid var(--ph); }

/* stage 2 — build, and run out of atoms */
/* position:relative so the floating "+N" anchors HERE, beside the slots it is filling —
   without it the absolutely-positioned float hunts up the tree for a positioned ancestor */
.cip3-focus {
  border: 1px solid var(--line-soft); border-radius: var(--radius-btn);
  padding: 0.6rem 0.7rem; margin-bottom: 0.6rem;
  position: relative; overflow: visible;
}
/* the empty slot is the whole point of the card, so it gets to be loud */
.cip3-slot.gap { border-color: var(--nus-orange); color: var(--nus-orange); animation: cip3-throb 1.6s ease-in-out infinite; }
.cip3-slot.ph { border-style: solid; border-color: var(--ph); background: var(--ph-bg); color: var(--ph); }
.cip3-slot.pop { animation: cip3-pop 0.34s cubic-bezier(.34,1.56,.64,1); }
@keyframes cip3-pop { from { transform: scale(0.3); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes cip3-throb {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,107,53,0.5); }
  50%      { box-shadow: 0 0 0 6px rgba(255,107,53,0); }
}
/* the "+1 / +2 / +3" that floats up as each bond is counted */
.cip3-plus {
  position: absolute; right: 1.4rem; top: 0.3rem;
  font-family: var(--mono); font-weight: 700; font-size: 1.25rem;
  color: var(--ph); pointer-events: none; white-space: nowrap; text-align: right;
  animation: cip3-float 1.3s ease-out forwards;
}
.cip3-plus-lb {
  display: block; font-family: 'Inter', sans-serif; font-size: 10px;
  font-weight: 600; letter-spacing: 0.03em; opacity: 0.85;
}
@keyframes cip3-float {
  0%   { opacity: 0; transform: translateY(6px) scale(0.6); }
  20%  { opacity: 1; transform: translateY(-4px) scale(1.2); }
  45%  { opacity: 1; transform: translateY(-12px) scale(1); }
  100% { opacity: 0; transform: translateY(-38px) scale(1); }
}

/* stage 3 — compare, duplicate, compare again */
.cip3-a.empty { border-style: dashed; color: var(--nus-orange); border-color: var(--nus-orange); }
.cip3-a.phantom { border-style: dashed; border-color: var(--ph); background: var(--ph-bg); color: var(--ph); }
.cip3-a.landed { animation: cip3-pop 0.4s cubic-bezier(.34,1.56,.64,1); }
.cip3-verdictbar {
  margin-top: 0.7rem; padding: 12px 14px; border-radius: var(--radius-sm);
  font-size: 13px; background: var(--inset);
  border: 1px solid var(--line-soft); font-family: var(--mono);
}
.cip3-verdictbar .old { color: var(--bad); text-decoration: line-through; opacity: 0.7; }
.cip3-verdictbar .new { color: var(--good); font-weight: 700; }

@keyframes cip3-draw { to { stroke-dashoffset: 0; } }
@keyframes cip3-badge { from { opacity: 0; transform: scale(0.2); } to { opacity: 1; transform: scale(1); } }
@keyframes cip3-orbit-cw  { from { transform: rotate(0); } to { transform: rotate(360deg); } }
@keyframes cip3-orbit-ccw { from { transform: rotate(0); } to { transform: rotate(-360deg); } }
.cip3-arc { animation: cip3-draw 1.05s cubic-bezier(.4,0,.2,1) forwards; }
.cip3-badge {
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: cip3-badge 0.38s cubic-bezier(.34,1.56,.64,1) backwards;
}
.cip3-runner { transform-box: view-box; }
.cip3-runner.cw  { animation: cip3-orbit-cw 3.4s linear 1.05s infinite; }
.cip3-runner.ccw { animation: cip3-orbit-ccw 3.4s linear 1.05s infinite; }
@media (prefers-reduced-motion: reduce) {
  .cip3-arc, .cip3-badge, .cip3-runner.cw, .cip3-runner.ccw, .cip3-slot.gap, .cip3-plus { animation: none; }
  .cip3-arc { stroke-dashoffset: 0 !important; }
}
@media (max-width: 820px) { .cip3-mol { width: 100%; } .cip3-side { min-width: 0; } }

/* ---------- drag ranking ---------- */
.drag-list, .sort-bank {
  list-style: none; margin: 14px 0; padding: 0;
  display: flex; flex-direction: column; gap: 8px;
}
.drag-item {
  padding: 12px 16px; background: #fff;
  border: 1.5px solid var(--line-strong); border-radius: 8px;
  cursor: grab; display: flex; align-items: center; gap: 0.6rem;
  box-shadow: 0 2px 8px rgba(0,61,124,0.06);
  font-size: 15px;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.drag-item::before { content: "⠿"; color: var(--faint); }
.drag-item:hover { border-color: var(--nus-blue); box-shadow: 0 4px 14px rgba(0,61,124,0.10); }
.drag-item.dragging { opacity: 0.4; }
.drag-list.counted { counter-reset: rank; }
.drag-list.counted .drag-item { counter-increment: rank; }

/* ---------- chiral sort ---------- */
.sort-bank { flex-flow: row wrap; }
.sort-item {
  width: 130px; text-align: center; background: #fff;
  border: 1.5px solid var(--line-strong); border-radius: 8px;
  padding: 0.4rem; cursor: grab; font-size: 13px;
  transition: border-color 0.15s;
}
.sort-item:hover { border-color: var(--nus-blue); }
.sort-item.dragging { opacity: 0.4; }
.sort-mol svg { max-width: 100%; height: auto; }
.sort-zones { display: grid; grid-template-columns: 1fr 1fr; gap: 0.7rem; margin: 14px 0; }
.sort-zone {
  min-height: 120px; border: 2px dashed var(--line-strong);
  border-radius: var(--radius); padding: 0.5rem; background: var(--inset);
}
.sort-zone h5 {
  margin: 0.1rem 0 0.5rem; text-align: center;
  font-size: 11px; font-weight: 700; letter-spacing: 1px;
  text-transform: uppercase; color: var(--nus-blue);
}
.sort-zone.over { border-color: var(--nus-orange); background: #fff7f3; }
.sort-zone .sort-item { display: inline-block; margin: 0.2rem; width: 110px; }

/* ---------- stereospot ---------- */
.spot-opts { display: flex; flex-wrap: wrap; gap: 8px; margin: 14px 0; }
.spot-opt {
  border: 1.5px solid var(--line-strong); border-radius: var(--radius-pill);
  padding: 6px 14px; cursor: pointer; background: #fff;
  font-family: inherit; font-size: 14px; color: var(--ink);
  transition: border-color 0.15s, background 0.15s;
}
.spot-opt:hover { border-color: var(--nus-blue); background: rgba(0,61,124,0.04); }

/* ---------- R/S trainer ---------- */
.rs-choice { display: flex; gap: 0.6rem; margin: 14px 0; }
.rs-pick { font-size: 19px; font-weight: 700; min-width: 70px; font-family: var(--mono); }

/* ---------- RS_FREEDRAW: draw your own, then assign it ---------- */
.rsfree-pick { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; margin: 0.7rem 0 0.3rem; }
.rsfree-label { font-weight: 600; color: var(--muted); margin-right: 0.1rem; }
.rsfree-choice { font-weight: 700; border: 2px solid var(--line-strong); background: #fff; }
.rsfree-choice.sel[data-v="R"] { border-color: var(--nus-blue); background: rgba(0,61,124,0.06); color: var(--nus-blue); }
.rsfree-choice.sel[data-v="S"] { border-color: var(--nus-orange); background: #fff7f3; color: #b4550a; }
.rsfree-choice.sel[data-v="none"] { border-color: var(--muted); background: var(--inset); color: var(--ink); }
.rsfree-check { margin-left: auto; }

/* ---------- molecule-stemmed test questions (RS_MCQ_2D / RS_MCQ_3D) ----------
   These sit inside an ordinary .ppq fieldset between the legend and the options, so
   they inherit all the pre/post styling and grading; only the molecule itself is new. */
.rsq-media { margin: 12px 0 14px; }
.rsq-2d {
  display: grid; place-items: center;
  background: #fff; border: 1px solid var(--line-soft); border-radius: var(--radius);
  padding: 6px;
}
.rsq-2d svg { width: 100%; max-width: 320px; height: auto; }
.rsq-3d .mol3d-view { height: 300px; }
.rsq-3d .mol3d-controls { margin-top: 8px; }

/* the on-demand 3D companion: the drawing stood up as a model you can turn, so the
   "point the lowest priority away" step is something you do rather than imagine */
.rsfree-build { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; margin: 0.7rem 0 0; }
.rsfree-msg { font-size: 13.5px; color: var(--muted); }
.rsfree-3d { margin-top: 0.8rem; }
.rsfree-3d .mol3d-view { height: 300px; }

/* ---------- gates: pre/post/results ---------- */
.gate {
  background: #fff;
  border: 2px solid var(--line-strong);
  border-radius: var(--radius-card);
  padding: 24px 28px; margin: 28px 0;
  box-shadow: 0 4px 14px rgba(0,61,124,0.06);
}
.gate h2 { margin-top: 0.2rem; border: 0; padding-bottom: 0; }
.ppq, .conf {
  border: 1px solid var(--line-soft); border-radius: var(--radius);
  padding: 14px 18px; margin: 14px 0;
}
.ppq legend, .conf legend { font-weight: 600; padding: 0 0.3rem; color: var(--nus-blue); }
.scale { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.scale label { display: flex; align-items: center; gap: 0.2rem; }
.scale span { color: var(--muted); font-size: 12px; }
.stars { font-size: 1.6rem; }
.star {
  border: 0; background: none; cursor: pointer; color: #cdd4df;
  transition: color 0.15s, transform 0.15s;
}
.star:hover { color: #ffb84d; transform: scale(1.10); }
.star.on { color: var(--nus-orange); }
#gain-report { margin: 0.5rem 0 1rem; }
.gain-badge {
  display: inline-block; padding: 12px 18px; border-radius: var(--radius);
  font-weight: 700; background: var(--good-bg); color: var(--good);
}

/* ---------- gates: modernised pre/post questions + confidence meter ----------
   Scoped to .gate so the inline lesson MCQs (.card--misconception .opt) keep
   their existing look. Selection state is driven by a .chosen class toggled in
   assessment.js (this build's Chromium restyles :has(:checked) unreliably), and
   the confidence 1-5 radios become a fill-to-value meter with a live caption.
   No module HTML changes: the A-D letter badges and question numbers are CSS
   counters, and the caption element is injected by assessment.js. */
.gate { counter-reset: qnum; }

/* question card */
.gate .ppq {
  counter-increment: qnum;
  position: relative;
  border: 1px solid var(--line-soft);
  border-radius: 16px;
  padding: 22px 24px 20px 62px;
  margin: 16px 0;
  box-shadow: 0 1px 2px rgba(0,61,124,.04), 0 10px 26px rgba(0,61,124,.05);
  transition: box-shadow .3s cubic-bezier(.22,.61,.36,1),
              transform .3s cubic-bezier(.22,.61,.36,1), border-color .3s;
}
.gate .ppq:hover { transform: translateY(-2px);
  box-shadow: 0 2px 4px rgba(0,61,124,.05), 0 16px 40px rgba(0,61,124,.10); }
.gate .ppq.answered { border-color: rgba(0,61,124,.22); }
.gate .ppq::before {
  content: counter(qnum);
  position: absolute; left: 18px; top: 22px;
  width: 30px; height: 30px; border-radius: 10px;
  display: grid; place-items: center;
  font-size: 14px; font-weight: 800; color: var(--nus-blue);
  background: rgba(0,61,124,.07); border: 1px solid var(--line);
  transition: background .3s, color .3s, transform .35s cubic-bezier(.34,1.56,.64,1);
}
.gate .ppq.answered::before { background: var(--nus-blue); color: #fff; transform: scale(1.06); }
.gate .ppq legend { font-weight: 700; font-size: 16px; color: var(--ink); line-height: 1.5; padding: 0; }

/* options: card + A-D letter badge that doubles as the select indicator */
.gate .opts { counter-reset: opt; gap: 10px; margin: 16px 0 0; }
.gate .opt {
  counter-increment: opt; position: relative; overflow: hidden;
  display: grid; grid-template-columns: 34px 1fr; align-items: center; gap: 14px;
  padding: 13px 16px 13px 14px;
  border: 1.5px solid var(--line-strong); border-radius: 12px;
  transition: border-color .2s, background .25s, box-shadow .25s,
              transform .16s cubic-bezier(.22,.61,.36,1);
}
.gate .opt::before {
  content: counter(opt, upper-alpha);
  grid-column: 1; width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center; font-weight: 700; font-size: 14px;
  color: var(--nus-blue); background: var(--tabbar); border: 1.5px solid var(--line-strong);
  transition: background .25s, color .25s, border-color .25s, transform .35s cubic-bezier(.34,1.56,.64,1);
}
.gate .opt::after {                 /* left accent bar, grows in on select */
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
  background: var(--nus-blue); transform: scaleY(0);
  transition: transform .3s cubic-bezier(.34,1.56,.64,1);
}
.gate .opt input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.gate .opt span { grid-column: 2; }
.gate .opt:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(0,61,124,.09); }
.gate .opt:hover::before { border-color: var(--nus-blue); }
.gate .opt:active { transform: translateY(0) scale(.995); }
.gate .opt:focus-within { outline: 2px solid var(--nus-orange); outline-offset: 2px; }
/* selected (assessment.js toggles .chosen) */
.gate .opt.chosen { border-color: var(--nus-blue); background: rgba(0,61,124,.06);
  box-shadow: 0 8px 22px rgba(0,61,124,.12); }
.gate .opt.chosen::before { background: var(--nus-blue); color: #fff; border-color: var(--nus-blue);
  animation: gateBadgePop .4s cubic-bezier(.34,1.56,.64,1); }
.gate .opt.chosen::after { transform: scaleY(1); }
/* graded — assessment.js adds .correct/.incorrect; kept AFTER .chosen so it wins the tie */
.gate .opt.correct { border-color: var(--good); background: var(--good-bg); }
.gate .opt.correct::before { content: "\2713"; background: var(--good); color: #fff; border-color: var(--good);
  animation: gateBadgePop .45s cubic-bezier(.34,1.56,.64,1); }
.gate .opt.correct::after { background: var(--good); transform: scaleY(1); }
.gate .opt.incorrect { border-color: var(--bad); background: var(--bad-bg); animation: gateShake .4s; }
.gate .opt.incorrect::before { content: "\2715"; background: var(--bad); color: #fff; border-color: var(--bad); }
.gate .opt.incorrect::after { background: var(--bad); transform: scaleY(1); }
@keyframes gateBadgePop { 0%{transform:scale(1)} 45%{transform:scale(1.18)} 100%{transform:scale(1)} }
@keyframes gateShake { 10%,90%{transform:translateX(-2px)} 20%,80%{transform:translateX(3px)}
  30%,50%,70%{transform:translateX(-5px)} 40%,60%{transform:translateX(5px)} }

/* confidence ("I can explain…"): 1-5 radios become a fill-to-value meter */
.gate .conf { border-radius: 16px; padding: 20px 22px;
  background: linear-gradient(180deg,#fff,rgba(248,250,252,.6)); }
.gate .conf legend { font-weight: 700; font-size: 15.5px; color: var(--ink); }
.gate .conf .scale {
  display: grid; grid-template-columns: auto repeat(5,1fr) auto; align-items: center; gap: 10px; margin-top: 8px;
}
.gate .conf .scale > span { font-size: 12px; font-weight: 600; color: var(--faint); text-align: center; }
.gate .conf .scale > span:first-child { text-align: right; }
.gate .conf .scale > span:last-child { text-align: left; }
.gate .conf .scale label {
  position: relative; display: grid; place-items: center; height: 48px; border-radius: 12px;
  font-weight: 700; font-size: 15px; color: var(--muted);
  background: var(--tabbar); border: 1.5px solid var(--line-strong); cursor: pointer;
  transition: background .25s, color .25s, border-color .25s,
              transform .2s cubic-bezier(.34,1.56,.64,1), box-shadow .25s;
}
.gate .conf .scale label input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.gate .conf .scale label:hover { border-color: var(--nus-blue); color: var(--nus-blue); transform: translateY(-2px); }
.gate .conf .scale label:focus-within { outline: 2px solid var(--nus-orange); outline-offset: 2px; }
.gate .conf .scale label.lit {          /* every pip up to the chosen value */
  background: rgba(0,61,124,.10); border-color: rgba(0,61,124,.30); color: var(--nus-blue); }
.gate .conf .scale label.sel {          /* the chosen value */
  background: linear-gradient(135deg, var(--nus-blue), var(--nus-blue-700)); border-color: var(--nus-blue);
  color: #fff; transform: translateY(-3px); box-shadow: 0 8px 20px rgba(0,61,124,.28);
  animation: gateBadgePop .4s cubic-bezier(.34,1.56,.64,1); }
.gate .conf-caption {                    /* injected by assessment.js */
  margin-top: 12px; font-size: 13px; font-weight: 600; color: var(--nus-blue);
  min-height: 20px; opacity: 0; transform: translateY(4px);
  transition: opacity .3s, transform .3s cubic-bezier(.22,.61,.36,1);
}
.gate .conf-caption.show { opacity: 1; transform: none; }

/* feedback slides in instead of popping */
.gate .feedback { border-radius: 12px; animation: gateSlideDown .4s cubic-bezier(.22,.61,.36,1); }
@keyframes gateSlideDown { from{opacity:0; transform:translateY(-6px)} to{opacity:1; transform:none} }

@media (prefers-reduced-motion: reduce) {
  .gate .ppq, .gate .ppq::before, .gate .opt, .gate .opt::before, .gate .opt::after,
  .gate .conf .scale label, .gate .conf-caption, .gate .feedback {
    transition: none !important; animation: none !important;
  }
  .gate .ppq:hover, .gate .opt:hover, .gate .conf .scale label:hover { transform: none; }
}
@media (max-width: 560px) {
  .gate .conf .scale { grid-template-columns: repeat(5,1fr); gap: 8px; }
  .gate .conf .scale > span { grid-column: span 5; text-align: center !important; }
  .gate .conf .scale > span:first-child { order: -1; }
}

/* ---------- results / "Your progress": learning-gain card + rating -----------
   renderGain()/gradeAndFinish() in assessment.js emit .gain-card markup; the
   before/after bars fill via a pure-CSS scaleX so no JS animation timing is
   needed. The rating stars get a hover preview + a JS-injected caption. */
#gain-report { margin: 4px 0 22px; }
.gate .gain-card {
  display: flex; align-items: center; gap: 22px 26px; flex-wrap: wrap;
  padding: 22px 24px; border-radius: 18px;
  background: linear-gradient(135deg, rgba(0,61,124,.05), rgba(255,107,53,.05));
  border: 1px solid var(--line); box-shadow: 0 10px 30px rgba(0,61,124,.08);
  animation: gateSlideDown .5s cubic-bezier(.22,.61,.36,1);
}
.gate .gain-card.solo { justify-content: center; text-align: center; }
.gate .gain-card.full {
  background: linear-gradient(135deg, rgba(46,163,107,.12), rgba(46,163,107,.03));
  border-color: rgba(46,163,107,.28);
}
.gate .gain-figure { text-align: center; min-width: 116px; flex: none; }
.gate .gain-pct {
  font-size: 46px; font-weight: 800; line-height: 1; letter-spacing: -1.5px;
  background: linear-gradient(135deg, var(--nus-blue), var(--nus-orange));
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  animation: gateBadgePop .6s cubic-bezier(.34,1.56,.64,1);
}
.gate .gain-card.full .gain-pct { background: linear-gradient(135deg, var(--good), #3cbd82);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; color: transparent; }
.gate .gain-label { margin-top: 8px; font-size: 11.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .8px; color: var(--muted); }
.gate .gain-meter { flex: 1; min-width: 230px; display: flex; flex-direction: column; gap: 11px; }
.gate .gain-row { display: grid; grid-template-columns: 52px 1fr 46px; align-items: center; gap: 12px; font-size: 13px; }
.gate .gain-row > span { color: var(--muted); font-weight: 600; }
.gate .gain-row > b { text-align: right; font-weight: 700; color: var(--nus-blue); font-variant-numeric: tabular-nums; }
.gate .gain-bar { height: 10px; border-radius: 999px; background: rgba(0,61,124,.10); overflow: hidden; }
.gate .gain-bar i {
  display: block; height: 100%; border-radius: inherit; transform-origin: left;
  background: linear-gradient(90deg, var(--nus-blue), var(--nus-blue-700));
  animation: gainFill .9s cubic-bezier(.22,.61,.36,1) both;
}
.gate .gain-row.after .gain-bar i { background: linear-gradient(90deg, var(--nus-orange), var(--nus-orange-bright)); animation-delay: .12s; }
.gate .gain-note { margin-top: 3px; font-size: 12.5px; color: var(--faint); }
#gain-report .muted { padding: 16px 18px; border-radius: 12px; background: var(--inset);
  border: 1px dashed var(--line-strong); }
@keyframes gainFill { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* rating stars — sized off the gain figure (46px) and the confidence pips (48px)
   so the row carries the same weight as the rest of the results card. The
   `font: inherit` on .star is load-bearing: buttons do not inherit font from
   their parent, so without it the glyphs fall back to the UA default (~13px
   Arial) and the size set on .stars is silently ignored. */
.gate .stars { display: inline-flex; gap: 10px; font-size: 2.75rem; margin: 8px 0 2px; }
.gate .star { font: inherit; padding: 2px 4px; line-height: 1; color: #cdd4df;
  transition: color .18s, transform .2s cubic-bezier(.34,1.56,.64,1); }
.gate .star:hover { transform: scale(1.18) rotate(-4deg); }
.gate .star:active { transform: scale(.92); }
.gate .star.hover { color: var(--nus-orange-bright); }   /* preview up to the hovered star */
.gate .star.on { color: var(--nus-orange); }
.gate .star.pop { animation: gateBadgePop .45s cubic-bezier(.34,1.56,.64,1); }
.rating-caption { margin-top: 10px; font-size: 15px; font-weight: 700; color: var(--nus-orange);
  min-height: 20px; opacity: 0; transform: translateY(4px); transition: opacity .3s, transform .3s; }
.rating-caption.show { opacity: 1; transform: none; }

/* "nothing to submit" reassurance under the wrap-up text boxes */
.gate .autosave-note {
  margin: 8px 0 0; font-size: 12.5px; color: var(--faint); display: flex; gap: 6px;
}
.gate .autosave-note::before { content: "\2713"; color: var(--good); font-weight: 700; }

/* text box ("one thing you learnt") */
.gate .conf textarea { border: 1.5px solid var(--line-strong); border-radius: 12px; background: #fff;
  transition: border-color .2s, box-shadow .2s; }
.gate .conf textarea:focus { border-color: var(--nus-orange); box-shadow: 0 0 0 3px rgba(255,107,53,.15); outline: none; }

@media (prefers-reduced-motion: reduce) {
  .gate .gain-card, .gate .gain-pct, .gate .gain-bar i, .gate .star, .gate .star.pop, .rating-caption {
    transition: none !important; animation: none !important;
  }
  .gate .gain-bar i { transform: none; }
  .gate .star:hover { transform: none; }
}
@media (max-width: 560px) {
  .gate .gain-card { justify-content: center; }
  .gate .gain-figure { min-width: 0; }
  /* keep the five stars on one line inside the narrow .conf box */
  .gate .stars { font-size: 2.25rem; gap: 6px; }
}

/* ---------- resume banner (injected by resume.js) ---------- */
.resume-note {
  display: flex; align-items: center; justify-content: space-between; gap: 0.8rem;
  flex-wrap: wrap; background: #fff;
  border: 1px solid rgba(0,61,124,0.14);
  border-left: 4px solid var(--nus-orange);
  border-radius: var(--radius);
  box-shadow: 0 6px 20px rgba(255,107,53,0.08);
  padding: 14px 18px; margin: 0 0 1.4rem; font-size: 14px;
}
.resume-note .btn { flex: none; background: #fff; }

.lesson-end { text-align: center; margin: 2rem 0 0; padding-top: 1.4rem; border-top: 2px solid var(--line); }
.module__foot { display: flex; justify-content: space-between; margin-top: 2.5rem; }

/* ---------- video ---------- */
.video-wrap {
  position: relative; padding-bottom: 56.25%; height: 0;
  border-radius: var(--radius); overflow: hidden;
  background: #000;
}
.video-wrap iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* ---------- pagination ---------- */
.page-nav {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; margin-top: 48px; padding-top: 28px;
  border-top: 1px solid var(--line);
}
.page-nav-btn {
  background: linear-gradient(135deg, var(--nus-blue) 0%, var(--nus-blue-700) 100%);
  color: #fff; border: 0;
  padding: 14px 28px; border-radius: var(--radius-btn);
  font-family: inherit; font-weight: 600; font-size: 15px; cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
  transition: transform 0.15s, box-shadow 0.15s, opacity 0.15s;
  box-shadow: 0 4px 14px rgba(0,61,124,0.20);
}
.page-nav-btn:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 8px 22px rgba(0,61,124,0.28); }
.page-nav-btn:disabled { opacity: 0.35; cursor: not-allowed; background: var(--faint); box-shadow: none; }
.page-nav-btn.prev {
  background: #fff; color: var(--nus-blue);
  border: 1.5px solid var(--line-strong); box-shadow: none;
}
.page-nav-btn.prev:hover:not(:disabled) { background: rgba(0,61,124,0.06); border-color: rgba(0,61,124,0.40); box-shadow: 0 4px 14px rgba(0,61,124,0.10); }
.page-nav-btn.next {
  background: linear-gradient(135deg, var(--nus-orange) 0%, var(--nus-orange-bright) 100%);
  box-shadow: var(--shadow-cta);
}
.page-nav-btn.next:hover:not(:disabled) { box-shadow: 0 8px 22px rgba(255,107,53,0.35); }
.page-nav-indicator { font-size: 14px; font-weight: 600; color: var(--muted); }
.page-nav-indicator strong { color: var(--nus-blue); }
.page-nav-helper {
  text-align: center; font-size: 13px; color: var(--faint);
  margin-top: 10px; min-height: 20px; font-weight: 500;
  transition: opacity 0.2s;
}

/* ---------- site footer ---------- */
.site-footer,
footer.site-foot {
  max-width: var(--maxw); margin: 0 auto;
  padding: 24px clamp(20px, 5vw, 48px) 44px;
  font-size: 12px; color: var(--faint);
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 12px;
  border-top: 1px solid rgba(0,61,124,0.06);
}
footer.site-foot .foot-contact { color: var(--muted); }
footer.site-foot .foot-contact strong { color: var(--nus-blue); font-weight: 600; }
footer.site-foot a.foot-mail {
  color: var(--nus-blue); font-weight: 600; text-decoration: none;
  border-bottom: 1px solid rgba(0,61,124,0.25);
  transition: color 0.2s ease, border-color 0.2s ease;
}
footer.site-foot a.foot-mail:hover { color: var(--nus-orange); border-bottom-color: var(--nus-orange); }
footer.site-foot a.foot-mail:focus-visible { outline: 2px solid var(--nus-orange); outline-offset: 2px; }

/* ============================================================================
   HUB (index.html)
   ========================================================================== */
.hub-hero {
  max-width: var(--maxw); margin: 0 auto;
  padding: 50px 60px 30px; text-align: center;
}
.hub-hero h1 { font-size: 42px; font-weight: 800; color: var(--nus-blue); line-height: 1.1; margin: 0.3rem 0; }
.hub-hero p { color: var(--muted); font-size: 19px; max-width: 640px; margin: 0.4rem auto; }
.hub { max-width: 960px; margin: 0 auto 3rem; padding: 0 24px; }
.ladder { display: grid; gap: 1rem; }
.rung {
  --accent: var(--nus-orange);
  position: relative;
  display: flex; gap: 1rem; align-items: flex-start;
  background: #fff; border: 1px solid var(--line-soft);
  border-radius: var(--radius-card);
  padding: 24px 28px;
  box-shadow: var(--shadow);
  text-decoration: none; color: var(--ink);
  transition: transform 0.2s, box-shadow 0.25s;
}
.rung::before {
  content: '';
  position: absolute; top: 0; left: 0; right: 0; height: 4px;
  border-radius: var(--radius-card) var(--radius-card) 0 0;
  background: linear-gradient(90deg, var(--accent) 0%, var(--nus-orange-bright) 100%);
}
.rung:hover { transform: translateY(-2px); box-shadow: var(--shadow-hover); }
.rung__num {
  background: linear-gradient(135deg, var(--nus-blue) 0%, var(--nus-blue-700) 100%);
  color: #fff; width: 42px; height: 42px; flex: none;
  border-radius: 50%; display: grid; place-items: center; font-weight: 700;
}
.rung.done .rung__num { background: linear-gradient(135deg, var(--good) 0%, #4cc285 100%); }
.rung.done { --accent: var(--good); }
.rung.inprogress .rung__num { background: linear-gradient(135deg, var(--nus-orange) 0%, var(--nus-orange-bright) 100%); }
.rung.inprogress .rung__status { color: var(--nus-orange); font-weight: 600; }
.rung__body h3 { margin: 0.1rem 0 0.3rem; color: var(--nus-blue); font-size: 19px; font-weight: 700; }
.rung__body p { margin: 0; color: var(--muted); font-size: 15px; }
.rung__status { margin-left: auto; font-size: 12px; color: var(--muted); align-self: center; }
.hub-reset { display: block; margin: 1.6rem auto 0; }

/* ---------- locked modules (the course runs in order) ----------
   The hub emits every rung as a link; its script strips the href and adds .locked
   to the ones still out of reach. This has to read as "not yet", not "broken", so
   a locked card stays legible and only loses its colour and its lift. */
.hub-note {
  max-width: 760px; margin: 0 auto 1.4rem; padding: 12px 16px; text-align: center;
  border-radius: var(--radius); background: var(--inset);
  border: 1px dashed var(--line-strong);
  color: var(--muted); font-size: 14px; line-height: 1.55;
}
.hub-locked-msg {                     /* shown after a bounce from a locked module */
  max-width: 760px; margin: 0 auto 1rem; padding: 12px 16px; text-align: center;
  border-radius: var(--radius); background: var(--bad-bg); color: var(--bad);
  border: 1px solid var(--bad); font-weight: 600; font-size: 14px;
}
.rung.locked {
  --accent: var(--line-strong);
  cursor: not-allowed; background: var(--inset);
  border-style: dashed; box-shadow: none;
}
.rung.locked:hover { transform: none; box-shadow: none; }
.rung.locked .rung__num { background: linear-gradient(135deg, #b6bfcc 0%, #98a3b3 100%); }
.rung.locked .rung__body h3 { color: var(--muted); }
.rung.locked .rung__body p { color: var(--faint); }
.rung.locked .rung__status { color: var(--muted); font-weight: 700; }
/* the actionable line, so it has to out-rank .rung.locked .rung__body p above */
.rung.locked .rung__body .rung__why {   /* "finish module N to unlock this one" */
  margin: 0.45rem 0 0; font-size: 13px; font-weight: 600; color: var(--nus-orange);
}

/* the same lock, on the cross-module links inside a module */
.navlink.locked, .module-step.locked {
  cursor: not-allowed; color: var(--faint); text-decoration: none; font-style: italic;
}
.navlink.locked::before, .module-step.locked::before { content: "\1F512\00A0"; font-style: normal; }

/* ---------- results: what is left before the module counts as done ----------
   assessment.js injects #completion-status above the Back to course map button
   and rewrites it as each requirement is met. */
#completion-status {
  margin: 18px 0 20px; padding: 18px 20px; border-radius: 16px;
  border: 1px solid var(--line-strong); background: var(--inset);
}
#completion-status h3 {
  margin: 0 0 10px; padding: 0; border: 0; font-size: 16px; color: var(--nus-blue);
}
#completion-status ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
#completion-status li {
  position: relative; padding-left: 30px; font-size: 14.5px; line-height: 1.5; color: var(--ink);
}
#completion-status li::before {
  position: absolute; left: 0; top: 1px; width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center; font-size: 12px; font-weight: 700; box-sizing: border-box;
}
#completion-status li.met { color: var(--muted); }
#completion-status li.met::before { content: "\2713"; background: var(--good); color: #fff; }
#completion-status li.unmet::before { content: ""; border: 2px solid var(--line-strong); }
#completion-status .req-detail { color: var(--faint); font-size: 13px; }
#completion-status.complete { background: var(--good-bg); border-color: var(--good); }
#completion-status.complete h3 { color: var(--good); }
#completion-status.complete p { margin: 0; font-size: 14.5px; color: var(--ink); }

/* ============================================================================
   DOCK_CHIRALITY mini-game (.card--dock)
   ========================================================================== */
.dock-game { display: grid; gap: 0.9rem; margin-top: 0.6rem; }
@media (min-width: 760px) { .dock-game { grid-template-columns: 1fr 290px; align-items: start; } }
.dock-wrap {
  position: relative; border-radius: var(--radius-btn); overflow: hidden;
  border: 1px solid var(--line-soft); background: #fff;
}
.dock-view { width: 100%; height: 420px; position: relative; }
.dock-flash { position: absolute; inset: 0; pointer-events: none; opacity: 0; transition: opacity 0.18s; }
.dock-flash.good { background: radial-gradient(circle, rgba(46,163,107,0.30), rgba(46,163,107,0) 70%); opacity: 1; }
.dock-flash.bad  { background: radial-gradient(circle, rgba(201,79,79,0.30), rgba(201,79,79,0) 70%); opacity: 1; }
.dock-badge {
  position: absolute; top: 14px; left: 50%;
  transform: translateX(-50%) scale(0.6); opacity: 0;
  padding: 0.45rem 1rem; border-radius: var(--radius-pill);
  font-weight: 700; font-size: 16px; color: #fff;
  box-shadow: 0 6px 20px rgba(0,0,0,0.2); transition: 0.25s; white-space: nowrap;
}
.dock-badge.show { opacity: 1; transform: translateX(-50%) scale(1); }
.dock-badge.good { background: linear-gradient(135deg, var(--good) 0%, #4cc285 100%); }
.dock-badge.bad  { background: linear-gradient(135deg, var(--bad) 0%, #e07070 100%); }
.dock-shake { animation: dock-shake 0.5s; }
@keyframes dock-shake {
  0%,100% { transform: translate(0,0); } 20% { transform: translate(-6px,3px); }
  40% { transform: translate(5px,-4px); } 60% { transform: translate(-4px,-3px); } 80% { transform: translate(4px,3px); }
}
.dock-panel { display: flex; flex-direction: column; gap: 0.6rem; }
.dock-hands { display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem; }
.dock-hand {
  cursor: pointer; border: 2px solid var(--line-strong); background: #fff;
  border-radius: var(--radius-btn); padding: 0.5rem 0.35rem;
  font-family: inherit; font-weight: 700; font-size: 14px; color: var(--ink);
  transition: 0.12s;
}
.dock-hand small { display: block; font-weight: 400; font-size: 10px; color: var(--muted); }
.dock-hand:hover { border-color: var(--nus-orange); }
.dock-hand.sel[data-hand="S"] { border-color: var(--nus-orange); background: #fff7f3; color: #b4550a; }
.dock-hand.sel[data-hand="R"] { border-color: var(--purple); background: var(--ph-bg); color: #6d3f96; }
.dock-surf.on { background: var(--nus-blue); color: #fff; border-color: var(--nus-blue); }
.dock-msg {
  background: rgba(0,61,124,0.04); border-left: 3px solid var(--nus-blue);
  border-radius: var(--radius-sm); padding: 12px 14px;
  font-size: 13px; min-height: 3.2rem;
}
.dock-msg.good { background: var(--good-bg); border-color: var(--good); }
.dock-msg.bad  { background: var(--bad-bg);  border-color: var(--bad); }
.dock-row { display: flex; gap: 0.4rem; }
.dock-row .btn { flex: 1; }
.dock-legend { display: flex; gap: 0.7rem; flex-wrap: wrap; font-size: 11px; color: var(--muted); justify-content: center; }
.dock-legend span { display: flex; align-items: center; gap: 0.3rem; }
.dock-dot { width: 11px; height: 11px; border-radius: 50%; display: inline-block; }
@media (prefers-reduced-motion: reduce) { .dock-shake { animation: none; } }

/* ============================================================================
   Stereocentre Hunter (STEREO_HUNT_2D / _3D / _DRAW)
   ========================================================================== */
.hunt-hud { display: flex; align-items: center; gap: 0.4rem; margin: 0.6rem 0 0.8rem; }
.hunt-stat {
  flex: 0 0 auto; min-width: 74px; background: #fff;
  border: 1px solid var(--line-soft); border-radius: var(--radius-btn);
  padding: 0.35rem 0.5rem; text-align: center;
}
.hunt-stat b { display: block; font-size: 1.25rem; line-height: 1; color: var(--purple); font-variant-numeric: tabular-nums; }
.hunt-stat span { font-size: 10px; text-transform: uppercase; letter-spacing: 0.6px; color: var(--muted); }
.hunt-pips { display: flex; gap: 0.3rem; margin-left: auto; }
.hunt-pip {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--tabbar); border: 1px solid var(--line-strong); transition: 0.2s;
}
.hunt-pip.now { background: var(--nus-orange); border-color: var(--nus-orange); transform: scale(1.25); }
.hunt-pip.done { background: var(--purple); border-color: var(--purple); }

.hunt-mol-name h4 { margin: 0 0 0.4rem; color: var(--nus-blue); }
.hunt-stage { background: #fff; border: 1px solid var(--line-soft); border-radius: var(--radius); overflow: hidden; }
.hunt-stage--3d .hunt-view { width: 100%; height: 340px; position: relative; }

/* The picker: an SVG with a hotspot laid over every atom. Hotspots are placed in
   per-cent, so the drawing can be responsive and the targets still land true. */
.hunt-pickwrap { position: relative; width: 100%; max-width: 460px; margin: 0 auto; }
.hunt-pickwrap svg { display: block; width: 100%; height: 100%; }
.hunt-hot {
  position: absolute; width: 30px; height: 30px; transform: translate(-50%, -50%);
  border-radius: 50%; border: 2px dashed transparent; background: transparent;
  cursor: pointer; padding: 0; transition: 0.12s;
}
.hunt-hot:hover { border-color: var(--purple); background: rgba(132,88,179,0.10); }
.hunt-hot:focus-visible { outline: 3px solid var(--nus-orange); outline-offset: 2px; }
.hunt-hot.right { border: 2px solid var(--good); background: rgba(46,163,107,0.22); }
.hunt-hot.wrong { border: 2px solid var(--bad); background: rgba(201,79,79,0.18); animation: hunt-shake 0.4s; }
.hunt-hot.reveal { border: 2px solid var(--nus-orange); background: rgba(255,107,53,0.18); animation: hunt-pulse 1.4s ease-out 2; }
@keyframes hunt-shake {
  0%,100% { transform: translate(-50%,-50%); }
  25% { transform: translate(calc(-50% - 4px),-50%); }
  75% { transform: translate(calc(-50% + 4px),-50%); }
}
@keyframes hunt-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(255,107,53,0.55); }
  100% { box-shadow: 0 0 0 16px rgba(255,107,53,0); }
}
@media (prefers-reduced-motion: reduce) { .hunt-hot.wrong, .hunt-hot.reveal { animation: none; } }

.hunt-msg {
  margin-top: 0.7rem; padding: 12px 16px; border-radius: var(--radius-sm);
  font-size: 14px; background: rgba(0,61,124,0.04);
  border-left: 3px solid var(--nus-blue); min-height: 2.6rem;
}
.hunt-msg.correct   { background: var(--good-bg); border-color: var(--good); color: var(--good); }
.hunt-msg.incorrect { background: var(--bad-bg);  border-color: var(--bad);  color: var(--bad); }
.hunt-bonus {
  display: inline-block;
  background: linear-gradient(135deg, var(--nus-orange) 0%, var(--nus-orange-bright) 100%);
  color: #fff; border-radius: var(--radius-pill);
  padding: 0.05rem 0.5rem; font-size: 11px; font-weight: 700;
}

.hunt-actions { display: flex; gap: 0.4rem; flex-wrap: wrap; margin-top: 0.6rem; }
.hunt-hint { font-size: 13px; margin-top: 0.5rem; }
/* keep a real height so the composer isn't clipped before it builds */
.hunt-draw-pad .jsme-host { min-height: 400px; }
.hunt-draw-msg { display: block; margin-top: 0.35rem; font-size: 13px; }
.hunt-draw-msg.bad { color: var(--bad); }
.hunt-result { margin-top: 0.8rem; }

.hunt-done {
  display: flex; align-items: center; gap: 0.7rem; margin-top: 0.8rem;
  padding: 14px 18px; border-radius: var(--radius);
  background: linear-gradient(90deg, var(--ph-bg), #fff7f3);
  border: 1px solid rgba(132,88,179,0.25);
}
.hunt-trophy { font-size: 1.7rem; color: var(--nus-orange); line-height: 1; }

@media (max-width: 620px) {
  .hunt-stat { min-width: 62px; }
  .hunt-stat b { font-size: 1.05rem; }
  .hunt-stage--3d .hunt-view { height: 260px; }
}

/* ============================================================================
   STEREO_HUNT — "Spot the stereocentre", 2D + 3D side by side (stereospot.js)
   Ported from the verified _preview_stereocentre.html. Reuses .hunt-pickwrap /
   .hunt-hot (+ .right/.wrong/.reveal) above for the 2D hotspots.
   ========================================================================== */
.sc { padding: 22px 22px 20px; }
.sc-top { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; margin-bottom: 12px; }
.sc-tag { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--nus-orange); }
.sc-hud { display: flex; gap: 18px; }
.sc-hud div { text-align: center; line-height: 1.1; }
.sc-hud b { display: block; font-size: 20px; font-weight: 800; color: var(--nus-blue);
  font-variant-numeric: tabular-nums; }
.sc-hud span { font-size: 10px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }

.sc-pips { display: flex; gap: 6px; margin: 0 0 14px; }
.sc-pip { width: 26px; height: 6px; border-radius: 99px; background: #e2e8f0; transition: background .2s; }
.sc-pip.now { background: var(--nus-orange); }
.sc-pip.done { background: var(--good); }

.sc-lead { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; justify-content: space-between;
  margin-bottom: 14px; padding: 14px 16px; border-radius: 12px;
  background: linear-gradient(135deg, rgba(0,61,124,.05), rgba(255,107,53,.06));
  border: 1px solid var(--line-soft); }
.sc-lead-text { flex: 1 1 340px; }
.sc-lead-text h3 { margin: 0 0 3px; font-size: 15px; color: var(--nus-blue); }
.sc-lead-text p { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--ink); }
.sc-none { flex: 0 0 auto; font-weight: 700; font-size: 14.5px; border: 2px solid var(--nus-blue);
  color: var(--nus-blue); background: #fff; padding: 12px 20px; border-radius: 11px; cursor: pointer;
  white-space: nowrap; transition: .15s; box-shadow: 0 1px 2px rgba(0,0,0,.06); }
.sc-none:hover:not(:disabled) { background: var(--nus-blue); color: #fff; transform: translateY(-1px);
  box-shadow: 0 6px 16px rgba(0,61,124,.22); }
.sc-none:disabled { opacity: .45; cursor: default; }
.sc-none .x { font-size: 17px; margin-right: 5px; vertical-align: -1px; }

.sc-molhead { display: flex; align-items: baseline; gap: 10px; margin-bottom: 8px; }
.sc-name { margin: 0; font-size: 19px; font-weight: 700; color: var(--nus-blue); }
.sc-formula { font-family: var(--mono); font-size: 13px; color: var(--muted); }
.sc-formula sub { font-size: .8em; }

.sc-views { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: start; }
@media (max-width: 620px) { .sc-views { grid-template-columns: 1fr; } }
.sc-pane { margin: 0; }
.sc-pane figcaption { display: flex; align-items: baseline; gap: 6px; margin-bottom: 6px;
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
  color: var(--nus-blue); }
.sc-pane figcaption em { font-style: normal; font-weight: 500; text-transform: none;
  letter-spacing: 0; color: var(--muted); }
.sc-view { height: 300px; touch-action: none; cursor: grab; position: relative; }
.sc-view:active { cursor: grabbing; }
.sc-pick { height: 300px; display: flex; align-items: center; justify-content: center; padding: 6px;
  border-radius: var(--radius-btn); border: 1px solid var(--line-soft);
  background: radial-gradient(circle at 50% 40%, #ffffff, var(--inset)); }
.sc-pick .hunt-pickwrap { max-width: 300px; }

.sc-controls { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }

.sc-msg { min-height: 44px; margin: 14px 0 6px; padding: 10px 14px; border-radius: 10px;
  font-size: 14.5px; line-height: 1.5; background: #f4f7fb; border: 1px solid var(--line-soft); }
.sc-msg.correct { background: var(--good-bg); border-color: rgba(46,163,107,.4); color: #1c6b45; }
.sc-msg.incorrect { background: var(--bad-bg); border-color: rgba(201,79,79,.4); color: #8f2f2f; }
.sc-bonus { display: inline-block; margin-left: 6px; font-size: 12px; font-weight: 700;
  color: #1c6b45; background: rgba(46,163,107,.18); padding: 1px 8px; border-radius: 99px; }

.sc-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 8px; }

.sc-done { margin-top: 16px; padding: 18px; border-radius: 14px; text-align: center;
  background: linear-gradient(135deg, rgba(0,61,124,.05), rgba(255,107,53,.08));
  border: 1px solid var(--line-soft); }
.sc-done h3 { margin: 0 0 4px; color: var(--nus-blue); }

/* ============================================================================
   MIRROR — "make the mirror image, then try to superimpose it" (mirror.js)
   Ported from _preview_mirror.html; the dropdown (.mirror-pick/select) is omitted
   because each card carries a single molecule via data-mol.
   ========================================================================== */
.mirror-stage { position: relative; width: 100%; height: 460px; border: 1px solid var(--line-strong);
  border-radius: var(--radius-card); background: #fff; overflow: hidden; touch-action: none; }
.mirror-toolbar { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin: 0.9rem 0 0.2rem; }
.mirror-toolbar .spacer { flex: 1 1 auto; }
.mirror-caption { min-height: 0; opacity: 0; transform: translateY(4px);
  transition: opacity .35s ease, transform .35s ease; margin: 0.7rem 0 0; font-size: 14px;
  color: var(--muted); line-height: 1.55; border-left: 3px solid var(--info); padding-left: 0.7rem; }
.mirror-caption.show { opacity: 1; transform: none; }
.mirror-legend { display: flex; gap: 0.7rem; justify-content: center; flex-wrap: wrap;
  margin: 0.9rem 0 0.2rem; opacity: 0; transition: opacity .35s ease; }
.mirror-legend.show { opacity: 1; }
.mirror-legend span { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 12.5px; color: var(--muted); }
.mirror-legend i { width: 0.72rem; height: 0.72rem; border-radius: 50%; display: inline-block; }
.mirror-verdict { opacity: 0; transform: translateY(6px); transition: opacity .4s ease, transform .4s ease;
  margin: 0.9rem 0 0; padding: 0.9rem 1rem; background: var(--inset); border: 1px solid var(--line);
  border-radius: var(--radius-card); font-size: 14.5px; line-height: 1.6; }
.mirror-verdict.show { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .mirror-caption, .mirror-legend, .mirror-verdict { transition: none; } }

/* ============================================================================
   Responsive breakpoints
   ========================================================================== */
@media (max-width: 1180px) {
  .module-grid { grid-template-columns: 210px minmax(0, 1fr); gap: 24px; padding: 20px 28px 60px; }
  .module-content { padding: 32px 36px; }
  .module-hero, .hub-hero { padding: 40px 36px 24px; }
  .top-banner { padding: 20px 36px; }
}
@media (max-width: 1024px) {
  .module-grid { grid-template-columns: minmax(0, 1fr); gap: 24px; padding: 20px 24px 60px; }
  /* the section nav becomes a left slide-in drawer behind the hamburger */
  .subnav {
    position: fixed; top: 0; left: 0;
    width: min(82vw, 320px); height: 100dvh;
    max-height: none; border-radius: 0;
    padding-top: 56px;
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform 0.3s cubic-bezier(.4,0,.2,1), visibility 0.3s;
    z-index: 1200; overflow-y: auto;
  }
  .subnav.open { transform: translateX(0); visibility: visible; box-shadow: 0 10px 40px rgba(0,0,0,0.28); }
  .mobile-topbar { display: flex !important; }
  .mobile-close-btn { display: flex; }
  .module-content { padding: 32px 28px; }
  .module-hero, .hub-hero { padding: 32px 24px 16px; }
  .module-hero h1, .hub-hero h1 { font-size: 32px; }
  .top-banner { padding: 16px 24px; }
  .top-banner-content { flex-wrap: wrap; gap: 12px; }
  .section-title { font-size: 26px; }
  .subsection-title { font-size: 22px; }
  .module-content h2, .module h2 { font-size: 26px; }
  .module-content h3, .module h3 { font-size: 22px; }
}
@media (max-width: 720px) {
  .cipr-top, .cip2-top, .cip3-top, .cipd-top, .cipl-top { gap: 0.8rem; }
  .cipr-molwrap, .cip2-molwrap, .cip3-molwrap { width: 100%; }
  .cipr-mol, .cip2-mol, .cip3-mol { width: 100%; height: 320px; }
  .sort-zones { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .module-hero h1, .hub-hero h1 { font-size: 26px; }
  .module-hero .subtitle, .hub-hero p { font-size: 16px; }
  .module-content { padding: 24px 20px; }
  .section-title { font-size: 22px; }
  .subsection-title { font-size: 19px; }
  .module-content h1, .module h1 { font-size: 26px; }
  .module-content h2, .module h2 { font-size: 22px; }
  .module-content h3, .module h3 { font-size: 19px; }
  .card { padding: 20px 18px; }
  .gate { padding: 20px 18px; }
  .page-nav { flex-wrap: wrap; }
  .page-nav-btn { padding: 12px 20px; font-size: 14px; }
}

/* ============================================================================
   Global reduced-motion backstop for the new chrome
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  body::before { animation: none; }
  .page { animation: none; }
  .subnav-item:hover { transform: none; }
  .card:hover, .rung:hover { transform: none; }
  .btn:hover:not(:disabled),
  .btn.primary:hover:not(:disabled),
  .page-nav-btn:hover:not(:disabled) { transform: none; }
  .star:hover { transform: none; }
}

/* ======================================================================
   Re-skin chrome added during integration (module switcher, hero eyebrow,
   module footer, gate-as-page reconciliation, resume-note placement).
   ====================================================================== */

/* Gates (pretest/posttest/results) are now .page sections living inside the
   .module-content card, so cancel the standalone card look .gate gave them. */
.page.gate {
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
  margin: 0;
}

/* Hero eyebrow ("Module N of M"). */
.module-hero-eyebrow {
  display: block;
  font-size: 12px; font-weight: 700; letter-spacing: 1.5px;
  text-transform: uppercase; color: var(--nus-orange);
  margin-bottom: 6px;
}

/* Module switcher dropdown in the top banner. */
.module-switch { position: relative; margin-left: auto; }
.module-switch-btn {
  font: inherit; font-size: 12px; font-weight: 600; letter-spacing: 0.3px;
  color: var(--nus-blue); background: #f1f6fb;
  border: 1px solid #d6e4f0; border-radius: var(--radius-sm, 6px);
  padding: 7px 13px; cursor: pointer; transition: all 0.2s ease;
}
.module-switch-btn:hover { background: var(--nus-blue); border-color: var(--nus-blue); color: #fff; }
.module-switch-menu {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 1200;
  min-width: 280px; max-height: 70vh; overflow-y: auto;
  background: #fff; border: 1px solid rgba(0,61,124,0.14);
  border-radius: 12px; box-shadow: 0 16px 48px rgba(0,61,124,0.18);
  padding: 8px;
}
.module-switch-menu .navlink {
  display: block; padding: 9px 12px; border-radius: 8px;
  color: var(--ink); text-decoration: none; font-size: 14px; line-height: 1.35;
}
.module-switch-menu .navlink:hover { background: rgba(0,61,124,0.06); color: var(--nus-blue); }
.module-switch-menu .navlink.current { background: rgba(255,107,53,0.12); color: var(--nus-blue); font-weight: 600; }
.module-switch-menu .navlink.done::before { content: "\2713 "; color: var(--good); font-weight: 700; }

/* Prev/Next-module footer (below the in-module page nav). */
.module-foot {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  margin-top: 20px; padding-top: 20px;
  border-top: 1px solid var(--line);
}
.module-step {
  font-size: 14px; font-weight: 600; color: var(--nus-blue);
  text-decoration: none; padding: 8px 14px;
  border: 1px solid #d6e4f0; border-radius: var(--radius-sm, 6px);
  background: #f1f6fb; transition: all 0.2s ease;
}
.module-step:hover { background: var(--nus-blue); border-color: var(--nus-blue); color: #fff; }
.module-step.next { margin-left: auto; }

/* Resume banner should span the content column, not sit inside a page. */
.module-content > .resume-note { margin: 0 0 20px; }

/* Hub (index.html) chrome bits. */
.banner-tag {
  font-size: 13px; font-weight: 600; letter-spacing: 0.2px;
  color: var(--nus-blue);
}
.hub-hero-eyebrow {
  display: block;
  font-size: 12px; font-weight: 700; letter-spacing: 1.5px;
  text-transform: uppercase; color: var(--nus-orange);
  margin-bottom: 8px;
}
