/* LearningAIWithSilky — per spec: dark terminal-meets-editorial
   flat, sharp corners, thin borders, one accent */

:root {
  --bg: #0a0a0a;
  --border: #262626;
  --text: #e6e4df;
  --text-dim: #8a8880;
  --accent: #4ade80;          /* terminal green — swap to #f5a623 for amber */
  --amber: #f5a623;           /* warn callouts + amber labels only */
  --mono: ui-monospace, "Cascadia Code", "Consolas", "Menlo", monospace;
  --serif: Georgia, "Times New Roman", serif;
  --sans: system-ui, -apple-system, "Segoe UI", sans-serif;
  --measure: 44rem;           /* ~ 65-70ch reading width */
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.7;
  margin: 0;
}

.wrap {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 1.5rem;
}

/* --- labels: the terminal flavor --- */
.label,
.card-label,
.log-date {
  font-family: var(--mono);
  font-size: 0.8rem;
  letter-spacing: 0.04em;
}

.label {
  color: var(--text-dim);
  margin: 0 0 0.75rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

/* the rule that runs from the label to the column edge */
.label::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--border);
}

/* --- headings: the editorial half --- */
h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 400;
  line-height: 1.15;
}

h1 {
  /* floor dropped to 2.25rem: at 2.5rem the unbroken brand word measures
     ~346px wide and can overflow phones narrower than ~365px */
  font-size: clamp(2.25rem, 7vw, 4rem);
  margin: 0 0 1rem;
  letter-spacing: -0.02em;
}

h2 {
  font-size: clamp(1.75rem, 4vw, 2.25rem);
  margin: 0 0 1.5rem;
}

h3 { font-size: 1.2rem; margin: 0 0 0.5rem; }

p { margin: 0 0 1.25rem; }

/* magazine lede: a prose section's lead paragraph reads bigger, in serif —
   the editorial promise from the spec, no new colors involved */
.lede {
  font-family: var(--serif);
  font-size: 1.3rem;
  line-height: 1.55;
}

a { color: var(--accent); }
a:hover { text-decoration-thickness: 2px; }

/* keyboard focus: accent ring with offset, so it clears the green CTA fill.
   :focus-visible = keyboard only, mouse clicks stay clean */
a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* --- sections --- */
.section {
  border-top: 1px solid var(--border);
  padding: 4.5rem 0;
}

/* --- hero --- */
.hero { position: relative; padding: 6rem 0 4.5rem; }

/* the mark as a watermark: line art reads as a whisper at 6% (a filled
   shape would get away with less). right: -6% bleeds it past the column
   but always stays inside the viewport — no overflow-x clipping needed */
.hero-mark {
  position: absolute;
  z-index: -1;
  top: 50%;
  right: -6%;
  width: min(65vw, 32rem);
  transform: translateY(-50%);
  opacity: .06;
  pointer-events: none;
}

.pitch {
  font-size: 1.2rem;
  color: var(--text-dim);
  max-width: 32rem;
  margin-bottom: 2.25rem;
}

.cta {
  display: inline-block;
  font-family: var(--mono);
  font-size: 0.9rem;
  color: var(--bg);
  background: var(--accent);
  padding: 0.85rem 1.6rem;
  text-decoration: none;
  border: 1px solid var(--accent);
}

.cta:hover {
  background: var(--bg);
  color: var(--accent);
}

/* --- principles grid --- */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1px;
  background: var(--border);       /* hairlines show through the gaps */
  border: 1px solid var(--border);
}

.card {
  background: var(--bg);
  padding: 1.5rem;
}

/* odd count (2-up): the orphaned last card takes the full row instead of
   leaving an empty cell — the grid shows its own grey background there.
   even count → :nth-child(odd):last-child matches nothing, layout untouched */
.card:nth-child(odd):last-child { grid-column: 1 / -1; }

.card-label {
  color: var(--accent);
  margin: 0 0 0.75rem;
}

/* --- field log --- */
.log {
  list-style: none;
  margin: 0;
  padding: 0;
}

.log-entry {
  display: grid;
  grid-template-columns: 7.5rem 1fr;
  gap: 1.5rem;
  padding: 1.5rem 0;
  border-top: 1px solid var(--border);
}

.log-entry:last-child { border-bottom: 1px solid var(--border); }

.log-date { color: var(--accent); }

.log-body p { color: var(--text-dim); margin: 0; }

/* --- about + footer --- */
.footer {
  border-top: 1px solid var(--border);
  padding: 2rem 0 3rem;
  font-family: var(--mono);
  font-size: 0.8rem;
  color: var(--text-dim);
}

.footer p { margin: 0; }
.footer p + p { margin-top: .5rem; }   /* credit line sits under name · year */

/* --- narrow screens --- */
@media (max-width: 560px) {
  .log-entry { grid-template-columns: 1fr; gap: 0.5rem; }
  .hero { padding-top: 4rem; }
  .section { padding: 3rem 0; }
}

/* --- motion: web_motion playbook — transform/opacity only --- */

/* hero: the one load moment — pure CSS, staggered via data-delay.
   (h1 sits this one out — its letters bounce in on their own, below.) */
.rv-hero { opacity: 0; animation: fadeUp .5s ease-out forwards; }
.rv-hero[data-delay="2"] { animation-delay: .6s; }
.rv-hero[data-delay="3"] { animation-delay: .72s; }

@keyframes fadeUp {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* main header: letters bounce in — drop from above, two decaying rebounds.
   ease-in-out, not the house default ease-out: every bounce segment is an
   arc, and arcs read best slow-fast-slow. inline-block because transforms
   don't apply to plain inline text. Spans + delays come from script.js —
   no JS, no spans, title just sits there visible. */
.ch { display: inline-block; opacity: 0; animation: letterBounce .6s ease-in-out both; }
@keyframes letterBounce {
  0%   { opacity: 0; transform: translateY(-0.55em); }
  38%  { opacity: 1; transform: translateY(0.1em); }
  58%  { transform: translateY(-0.07em); }
  78%  { transform: translateY(0.03em); }
  100% { opacity: 1; transform: translateY(0); }
}

/* the sticker wrapper: carries the tilt (the pop animation owns .badge's
   transform, so the rotation must live one level up) and parks in the
   right-hand margin on wide screens — stickers live on edges, not columns */
.sticker {
  transform: rotate(-5deg);
  margin: 0 0 1.75rem;
}

@media (min-width: 1000px) {
  .sticker {
    position: absolute;
    top: 0.5rem;
    right: -7rem;
    margin: 0;
  }
}

/* hero masthead: the mark as a sticker — pops in as the opening beat,
   ring text rotates flat (24s/turn), the rooster tumbles on a vertical
   3D axis (perspective on .badge gives the flip its depth). transform only. */
.badge {
  position: relative;
  display: grid;
  place-items: center;
  perspective: 600px;
  width: 140px;
  height: 140px;
  margin: 0;
  opacity: 0;
  transform: scale(.6);
  animation: badgePop .45s cubic-bezier(.34, 1.56, .64, 1) forwards;
}
.badge-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  animation: spin 24s linear infinite;
}
.badge-ring-text {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .14em;
  fill: var(--text-dim);
}
.badge-mark {
  width: 64px;
  height: 64px;
  /* tumbles on a 3D vertical axis (coin-flip; back face reads mirrored);
     grid centers it — no centering transform here, the animation owns
     transform and would fling it out of the badge otherwise */
  animation: flipY 24s linear infinite;
}
@keyframes badgePop {
  from { opacity: 0; transform: scale(.6); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes spin { to { transform: rotate(360deg); } }      /* ring only */
@keyframes flipY { to { transform: rotateY(360deg); } }    /* rooster only */

/* sections: reveal on scroll — JS adds .seen once, then unobserves.
   gated on html.js: without the class (script.js missing) nothing hides,
   so the page renders fully visible — no blank-page failure mode */
.js .rv { opacity: 0; transform: translateY(22px); transition: opacity .55s ease-out, transform .55s ease-out; }
.js .rv.seen { opacity: 1; transform: translateY(0); }

/* principle cards: stagger in when the grid enters view — same js gate */
.js .stag .card { opacity: 0; }
.stag.go .card { animation: fadeUp .45s ease-out forwards; }
.stag.go .card:nth-child(2) { animation-delay: .09s; }
.stag.go .card:nth-child(3) { animation-delay: .18s; }
.stag.go .card:nth-child(4) { animation-delay: .27s; }
.stag.go .card:nth-child(5) { animation-delay: .36s; }
/* a filled animation outranks :hover — clear it once entrance finishes */
.stag.done .card { animation: none; opacity: 1; }

/* hover lift — desktop only, nothing essential hidden behind it */
.card { transition: transform .25s ease, box-shadow .25s ease; }
.card:hover { transform: translateY(-6px); box-shadow: 0 14px 26px rgba(0,0,0,.45); }

/* inline code — terminal flavor for keys, vars, endpoints in coursework */
code { font-family: var(--mono); color: var(--accent); font-size: .92em; }

/* --- coursework chrome (course.html): TOC current state, flow rows, bar --- */

/* the lesson you're reading — accent bar down its side, no layout shift */
.lesson-nav li.is-current { box-shadow: inset 2px 0 0 var(--accent); }
.lesson-nav li.is-current a { color: var(--accent); font-weight: 600; }
.lesson-nav li.is-done a::after { content: " ✓"; color: var(--accent); }

/* lesson 08: one request's journey as hairline rows with mono step
   numbers — field-log grammar. Without styles.css the <ol> falls back
   to the browser's native 1. 2. 3., same order either way. */
.flow {
  list-style: none;
  counter-reset: step;
  margin: 1rem 0 0;
  padding: 0;
  border-top: 1px solid var(--border);
}
.flow li {
  counter-increment: step;
  position: relative;
  padding: 1rem 0 1rem 3.5rem;
  border-bottom: 1px solid var(--border);
}
.flow li::before {
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 1rem;
  width: 2.25rem;
  padding: .15rem 0;
  text-align: center;
  font-family: var(--mono);
  font-size: .78rem;
  color: var(--accent);
  background: var(--bg);
  border: 1px solid var(--border);
}

/* prev/next lesson bar: no .js → display stays none (dead controls never
   shown); .is-on added while the Foundations section is in view */
.lesson-bar {
  position: fixed;
  left: 50%;
  bottom: 16px;
  transform: translateX(-50%);
  z-index: 40;
  display: none;
  gap: 1rem;
  align-items: center;
  padding: .55rem .9rem;
  background: var(--bg);
  border: 1px solid var(--border);
  font-family: var(--mono);
  font-size: .8rem;
  opacity: 0;
  visibility: hidden;
  transition: opacity .2s ease-out, visibility .2s;
}
.js .lesson-bar { display: flex; }
.lesson-bar.is-on { opacity: 1; visibility: visible; }
.lesson-bar a { text-decoration: none; }
.lesson-bar a:hover { text-decoration: underline; }
.bar-pos { color: var(--text-dim); }

@media (max-width: 560px) {
  .lesson-bar { font-size: .72rem; gap: .6rem; padding: .5rem .7rem; bottom: 12px; }
  .flow li { padding-left: 3rem; }
}

/* --- progress spine (both pages) --- ships hidden in the HTML: without JS
   there are no counts to show, and a wrong count is worse than none.
   script.js fills the numbers from localStorage and drops the hidden attr. */
.progress-count {
  margin: 0 0 .75rem;
  font-family: var(--mono);
  font-size: .85rem;
  color: var(--text-dim);
}
.progress-count strong { color: var(--text); font-weight: 600; }

.progress-track {
  height: 10px;
  border: 1px solid var(--border);
  background: var(--bg);
  overflow: hidden;
}
/* fill spans the whole track and scales on X — motion playbook rule 1
   (transform only) holds even for a progress bar */
.progress-fill {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .45s ease-out;
}

.progress-continue { margin: .9rem 0 0; font-family: var(--mono); font-size: .85rem; }
.progress-course {
  margin: .9rem 0 0;
  font-family: var(--mono);
  font-size: .85rem;
  color: var(--accent);
}

/* --- lesson completion (course.html) --- the button ships hidden until
   script.js wires it up. The pressed rule comes last on purpose: same
   specificity as :hover, later wins, so a completed button stays filled. */
.lesson-done {
  font-family: var(--mono);
  font-size: .8rem;
  color: var(--accent);
  background: var(--bg);
  border: 1px solid var(--accent);
  border-radius: 0;
  padding: .5rem 1rem;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
}
.lesson-done:hover { background: var(--accent); color: var(--bg); }
.lesson-done:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.lesson-done[aria-pressed="true"] { background: var(--accent); color: var(--bg); }

/* completion announces itself twice: on the card label, and (via the
   is-done class script.js toggles) on the TOC row */
.card:has(.lesson-done[aria-pressed="true"]) .card-label::after { content: " · complete"; }

/* --- checkpoint quiz (course.html #checkpoint) ---
   Same grammar as everything else: hairline boxes, mono accents, sharp
   corners, one green. The radios stay native (keyboard + screen readers
   get them for free); the <label> is the click target. Verdict styling is
   driven by the .is-* classes script.js adds — without JS nothing looks
   "unanswered-but-broken", the questions just read as a list. */
.quiz-form { margin-top: .5rem; }

.q {
  display: flow-root;             /* contains the legend float below */
  border: 1px solid var(--border);
  margin: 0 0 1rem;
  padding: 1rem 1.1rem 1.1rem;
  min-width: 0;                   /* fieldsets won't shrink below content otherwise */
}

/* float kills the browser's "legend sits in the border" cutout; the next
   element clears it so the options don't ride alongside */
.q legend {
  float: left;
  width: 100%;
  padding: 0;
  margin: 0 0 .75rem;
  font-family: var(--sans);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.5;
}
.q legend + .opt { clear: both; }

.q-num {
  display: inline-block;
  font-family: var(--mono);
  font-size: .76rem;
  font-weight: 400;
  color: var(--accent);
  border: 1px solid var(--border);
  padding: .05rem .45rem;
  margin-right: .55rem;
  vertical-align: .12em;
}

.opt {
  display: flex;
  align-items: flex-start;
  gap: .7rem;
  padding: .55rem .75rem;
  border: 1px solid var(--border);
  margin-top: .5rem;
  cursor: pointer;
  transition: border-color .15s ease, opacity .15s ease;
}
.opt:hover { border-color: var(--text-dim); }
.opt input {
  accent-color: var(--accent);    /* green radio, no custom widget needed */
  margin: .38rem 0 0;
  flex: none;
}
.opt input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* :has() marks the pick live, before JS even runs; older browsers just
   keep showing the native checked radio — no loss of function */
.opt:has(input:checked) { border-color: var(--accent); }

/* locked states — JS adds these after a pick, and disables the inputs */
.q.is-done .opt { cursor: default; }
.q.is-done .opt:hover { border-color: var(--border); }
.opt.is-answer { border-color: var(--accent); }
.opt.is-answer::after {
  content: "✓";
  margin-left: auto;
  font-family: var(--mono);
  color: var(--accent);
}
.opt.is-wrong { opacity: .6; }
.opt.is-wrong::after {
  content: "✗";
  margin-left: auto;
  font-family: var(--mono);
}

/* verdict + one-line why. Empty until JS answers it; aria-live in the HTML
   so screen readers get the result announced */
.q-fb {
  margin: .8rem 0 0;
  font-family: var(--mono);
  font-size: .84rem;
  color: var(--text-dim);
  min-height: 1.3em;
}
.q-fb.is-ok { color: var(--accent); }
.fb-why { font-family: var(--sans); font-size: .92rem; }

.quiz-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  border-top: 1px solid var(--border);
  margin-top: 1.25rem;
  padding-top: 1rem;
}
.quiz-score { margin: 0; font-family: var(--mono); font-size: .84rem; color: var(--text-dim); }
.quiz-reset {
  font-family: var(--mono);
  font-size: .84rem;
  color: var(--accent);
  background: var(--bg);
  border: 1px solid var(--accent);
  border-radius: 0;
  padding: .5rem 1rem;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
}
.quiz-reset:hover { background: var(--accent); color: var(--bg); }
.quiz-reset:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* pass/fail badge under the checkpoint heading — script.js's gate code
   fills it in from the stored best score. The [hidden] guard is required:
   an author display would otherwise beat the hidden attribute. */
.quiz-gate {
  display: inline-block;
  margin: 0 0 1rem;
  font-family: var(--mono);
  font-size: .78rem;
  color: var(--text-dim);
  border: 1px solid var(--border);
  padding: .15rem .6rem;
}
.quiz-gate[hidden] { display: none; }
.quiz-gate.is-pass { color: var(--accent); border-color: var(--accent); }

/* shown only when the head-gate watchdog dropped .js (script.js missing) */
.quiz-fallback { display: none; }
html:not(.js) .quiz-fallback {
  display: block;
  color: var(--text-dim);
  font-family: var(--mono);
  font-size: .85rem;
}

/* --- per-lesson check-in (course.html) --- one .q per lesson, wired the
     same way as the checkpoint questions. The [hidden] guard is required:
     an author display would otherwise beat the hidden attribute. */
.checkin { margin-top: 1.75rem; }
.checkin[hidden] { display: none; }
.checkin .q-num { color: var(--text-dim); }  /* badge marks the lesson's own number — dim so it doesn't read as a new section */
.checkin-title { display: block; margin: .35rem 0 .55rem; font-family: var(--mono); font-size: .78rem; font-weight: 400; letter-spacing: .04em; color: var(--accent); }
.checkin-reset {
  font-family: var(--mono);
  font-size: .8rem;
  color: var(--accent);
  background: var(--bg);
  border: 1px solid var(--accent);
  border-radius: 0;
  padding: .35rem .8rem;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
}
.checkin-reset:hover { background: var(--accent); color: var(--bg); }
.checkin-reset:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.checkin-reset[hidden] { display: none; }
.checkin-foot { margin: .75rem 0 0; }   /* keeps the <p> rhythm of the card */
.checkin-foot[hidden] { display: none; }

/* --- Your Turn box (course.html) --- the writing half of each lesson.
     Ships with the textarea hidden: without JS it can't save, so the box
     reads as a prompt to think about instead of a text field that eats
     words. script.js unhides the textarea once it's ready to persist. */
.your-turn {
  border: 1px solid var(--border);
  border-left: 2px solid var(--accent);
  padding: 1rem 1.1rem;
  margin: 1.25rem 0;
}
.your-turn-label { margin: 0 0 .5rem; font-family: var(--mono); font-size: .78rem; letter-spacing: .04em; color: var(--accent); }
.your-turn-task { margin: 0 0 .75rem; font-size: .95rem; color: var(--text-dim); }
.your-turn textarea {
  display: block;
  width: 100%;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: .6rem .7rem;
  font: inherit;
  font-size: .92rem;
  line-height: 1.6;
  resize: vertical;
  min-height: 5.5rem;
}
.your-turn textarea[hidden] { display: none; }
.your-turn textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.your-turn-note { margin: .5rem 0 0; font-family: var(--mono); font-size: .76rem; color: var(--text-dim); }
.your-turn-note[hidden] { display: none; }

/* --- callout boxes (Ticket C) — rehoused sentences, same words.
   Thin box + a colored left edge + one mono label. Without JS nothing
   changes: the boxes are plain HTML/CSS. */
.callout {
  border: 1px solid var(--border);
  padding: .85rem 1.1rem 1rem;
  margin: 1.5rem 0;
}
.callout-label {
  margin: 0 0 .45rem;
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.callout p { margin: 0; }
.callout p + p { margin-top: .75rem; }
.callout--key { border-left: 3px solid var(--accent); }
.callout--key .callout-label { color: var(--accent); }
.callout--example { border-left: 3px solid var(--text-dim); }
.callout--warn { border-left: 3px solid var(--amber); }
.callout--warn .callout-label { color: var(--amber); }

/* --- lesson diagrams (Ticket C) — one inline SVG per lesson, drawn in
   the site palette. .diagram figure + figcaption carries the meaning in
   text under the picture (a visual is an added door, not a replacement). */
.diagram {
  margin: 1.5rem 0;
  border: 1px solid var(--border);
  padding: .9rem;
  background: var(--bg);
}
.diagram svg { display: block; width: 100%; height: auto; }
.diagram figcaption {
  margin: .7rem 0 0;
  padding-top: .6rem;
  border-top: 1px solid var(--border);
  font-family: var(--mono);
  font-size: .78rem;
  color: var(--text-dim);
}
.dg-box { fill: none; stroke: var(--border); stroke-width: 1; }
.dg-box--hi { stroke: var(--accent); }
.dg-label { fill: var(--text); font-family: var(--sans); font-size: 14px; }
.dg-label--sm { fill: var(--text-dim); font-family: var(--mono); font-size: 12px; }
.dg-accent { fill: var(--accent); font-family: var(--mono); font-size: 12px; }
.dg-line { fill: none; stroke: var(--border); stroke-width: 1; }
.dg-line--hi { stroke: var(--accent); }
.dg-fill { fill: var(--accent); }

/* --- token demo (Ticket C, lesson 07) --- */
.token-demo {
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  padding: 1rem 1.1rem;
  margin: 1.5rem 0;
}
.token-demo-label {
  margin: 0 0 .5rem;
  font-family: var(--mono);
  font-size: .78rem;
  letter-spacing: .04em;
  color: var(--accent);
}
.token-demo input {
  display: block;
  width: 100%;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: .6rem .7rem;
  font: inherit;
  font-size: .95rem;
}
.token-demo input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.token-chips {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin: .8rem 0 0;
  padding: 0;
  list-style: none;
}
.token-chips li {
  font-family: var(--mono);
  font-size: .85rem;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  padding: .15rem .5rem;
}
.token-chips li span {
  display: block;
  font-size: .66rem;
  color: var(--text-dim);
  text-align: center;
}
.token-count {
  margin: .75rem 0 0;
  font-family: var(--mono);
  font-size: .78rem;
  color: var(--text-dim);
}
/* with JS on: the live count hides, the live list appears */
.token-demo .token-live { display: none; }
.token-demo.js .token-live { display: flex; }
.token-demo.js .token-count { display: none; }
.token-demo.js .token-static { display: none; }
/* with JS off: no inert input — the static example is the whole box */
.token-demo .token-demo-label,
.token-demo input { display: none; }
.token-demo.js .token-demo-label { display: block; }
.token-demo.js input { display: block; }

/* --- course map (Ticket C) — replaces the progress bar on both pages.
   Ships hidden; the no-JS list (html:not(.js)) is the fallback, JS on
   draws the nodes from the same localStorage set Ticket A wrote. */
.map {
  margin: 0 0 1.5rem;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  padding: 1rem 0;
}
.map-path {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .55rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.map-item { display: flex; align-items: center; gap: .55rem; }
.map-item::after {
  content: "";
  width: .85rem;
  border-top: 1px solid var(--border);
}
.map-item:last-child::after { display: none; }
.map-node {
  display: inline-block;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text-dim);
  padding: .35rem .7rem;
  font-family: var(--mono);
  font-size: .78rem;
  text-decoration: none;
  white-space: nowrap;
}
.map-node:hover { text-decoration: none; border-color: var(--text-dim); }
.map-node:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.map-node.is-done { background: var(--accent); color: var(--bg); border-color: var(--accent); }
.map-node.is-gate { border-style: dashed; border-color: var(--text-dim); }
.map-node.is-gate.is-pass { background: var(--accent); color: var(--bg); border-color: var(--accent); border-style: solid; }
/* no-JS: the node list stands in as the labeled list */
html:not(.js) .map-path { flex-direction: column; align-items: stretch; gap: .35rem; }
html:not(.js) .map-item { display: block; }
html:not(.js) .map-item::after { display: none; }
html:not(.js) .map-node { display: block; text-align: left; }
@media (max-width: 560px) {
  .map-node { font-size: .72rem; padding: .3rem .55rem; }
  .map-item::after { width: .5rem; }
}

/* house guard: reduced motion — also zeroes delays and smooth scroll.
   iteration-count: 1 — without it, an infinite loop at .01ms strobes. */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; animation-delay: 0s !important;
      animation-iteration-count: 1 !important;
      transition-duration: .01ms !important; transition-delay: 0s !important; }
  html { scroll-behavior: auto; }
}
