/* ===========================================================================
 * enhancements.css — additive polish + subtle, clarity-focused motion
 *
 * Loaded AFTER style.css via a <link> in <head>. It NEVER edits app.js or
 * style.css; everything here is layered on top using the existing design
 * tokens (--paper / --ink / --accent / --sage / --g-* / --radius / --shadow-*)
 * so it tracks all three reading themes (paper / obsidian / linen).
 *
 * Safety contract
 * ---------------
 *  - The scroll-reveal HIDDEN state is gated on the `.enh-js` class, which is
 *    added to <html> only by enhancements.js. If the JS never runs (or throws),
 *    `.enh-js` is absent and NOTHING is ever hidden — content is fully visible
 *    without JS. The reveal classes (.enh-reveal / .enh-shown) are applied
 *    exclusively by the JS, never by markup.
 *  - All motion lives inside `@media (prefers-reduced-motion: no-preference)`,
 *    and a global kill-switch neutralises any residual motion for users who
 *    opt out. Durations stay in the 180–400ms band; translations stay <=12px.
 * ========================================================================= */


/* ---------------------------------------------------------------------------
 * 0. Global reduced-motion kill-switch (safety net for ALL motion, old + new)
 * ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}


/* ===========================================================================
 * 1. Non-motion polish (applies in every motion preference)
 * ========================================================================= */

/* 1a. Tell the browser each theme's nature so native scrollbars / form
 *     controls / mobile chrome match the surface (no white scrollbar on the
 *     dark Obsidian theme). */
:root                      { color-scheme: light; }
[data-theme="obsidian"]    { color-scheme: dark; }
[data-theme="linen"]       { color-scheme: light; }

/* 1b. One clear, theme-aware focus ring for keyboard users everywhere.
 *     :focus-visible keeps it off mouse clicks. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

/* 1c. Reusable screen-reader-only utility. */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0);
  white-space: nowrap; border: 0;
}

/* 1d. Long URLs / inline code wrap inside the reading column instead of
 *     forcing a sideways scroll on narrow phones. Block <pre> is left alone
 *     (it keeps its own horizontal scroll). */
.markdown { overflow-wrap: break-word; }
.markdown :not(pre) > code { overflow-wrap: anywhere; word-break: break-word; }

/* 1e. Quiet, theme-safe frame for figures. The inline `max-width:70%` on each
 *     plot still wins (inline styles beat selectors), so this only adds the
 *     frame + a max-width:100% safety net for any future un-styled image. */
.markdown img {
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
  border: 1px solid var(--rule);
  background: var(--card);
}
@media (max-width: 520px) {
  /* On phones, let capped figures fill the column (beats the inline 70%). */
  .markdown img { max-width: 100% !important; }
}

/* 1f. Re-theme the ai-stats callouts with design tokens so they read in all
 *     three themes (the page-local <style> hardcodes light hex backgrounds,
 *     which glare on Obsidian). `.markdown .x` (0,2,0) outranks the page's
 *     `.x` (0,1,0), so this wins regardless of source order — colour-only,
 *     same emoji labels, mapped to existing meaning:
 *       prompt-box -> --accent   checker -> --sage   warning-box -> --g-foundations */
.markdown .prompt-box,
.markdown .checker,
.markdown .warning-box {
  margin: 1.4em 0;
  padding: 14px 20px;
  border-radius: var(--radius);
  border-left: 4px solid;
  line-height: 1.6;
  box-shadow: var(--shadow-sm);
}
.markdown .prompt-box::before,
.markdown .checker::before,
.markdown .warning-box::before {
  display: block;
  margin-bottom: 0.45em;
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.markdown .prompt-box {
  background: color-mix(in oklab, var(--accent-tint) 65%, var(--card));
  border-left-color: var(--accent);
}
.markdown .prompt-box::before { content: "🤖 Ask Claude Code"; color: var(--accent); }

.markdown .checker {
  background: color-mix(in oklab, var(--sage-tint) 55%, var(--card));
  border-left-color: var(--sage);
}
.markdown .checker::before { content: "🔬 Scientist check"; color: var(--sage); }

.markdown .warning-box {
  background: color-mix(in oklab, var(--g-foundations) 14%, var(--card));
  border-left-color: var(--g-foundations);
}
.markdown .warning-box::before {
  content: "⚠️ Not magic";
  color: color-mix(in oklab, var(--g-foundations) 78%, var(--ink));
}

/* 1g. Keep the theme switcher reachable on mobile (style.css hides
 *     .header-meta below 900px, which would strip the only theme control on
 *     phones/tablets), and cap the brand title so the sticky header stays
 *     near its assumed ~71px height when the long title wraps. */
@media (max-width: 900px) {
  .header-meta { display: flex; align-items: center; }
  .brand-title { font-size: 14px; line-height: 1.15; }
}


/* ===========================================================================
 * 2. Motion — gated behind prefers-reduced-motion: no-preference
 * ========================================================================= */

/* 2a. Scroll-reveal pre-state. Applied ONLY when JS is live (`.enh-js`) and
 *     ONLY to elements the JS has tagged (`.enh-reveal`). No JS => no hidden
 *     content. The transition is declared on the shown state so revealing
 *     animates, while the resting hidden state is instant. */
@media (prefers-reduced-motion: no-preference) {
  .enh-js .enh-reveal {
    opacity: 0;
    transform: translateY(12px);
  }
  .enh-js .enh-reveal.enh-shown {
    opacity: 1;
    transform: none;
    transition: opacity .32s ease, transform .32s ease;
  }
  /* Sequential stagger for the closing "The new AI workflow" steps:
     each step carries its own --enh-delay set by the JS. */
  .enh-js .enh-step.enh-shown {
    transition-delay: var(--enh-delay, 0ms);
  }
}

/* 2b. Route entrance: app.js replaces #view's child on every navigation, so a
 *     one-shot keyframe on the direct child re-fires per route — a "the page
 *     changed" settle in an SPA where the address bar barely moves. `both`
 *     fill means it always resolves to fully visible. */
@media (prefers-reduced-motion: no-preference) {
  @keyframes enh-view-enter {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
  }
  #view > * { animation: enh-view-enter .28s ease both; }
}

/* 2c. Smooth <details> expand + marker rotation (progressive enhancement;
 *     browsers without ::details-content / interpolate-size simply snap as
 *     they do today). The +/- glyph becomes a single rotating mark so the
 *     open/closed state reads mid-transition. */
:root { interpolate-size: allow-keywords; }
@media (prefers-reduced-motion: no-preference) {
  .markdown details::details-content {
    block-size: 0;
    overflow: hidden;
    transition: block-size .25s ease, content-visibility .25s allow-discrete;
  }
  .markdown details[open]::details-content { block-size: auto; }

  /* rotate a single glyph instead of swapping +/- (style.css already declares
     `transition: transform .2s` on this marker). */
  .markdown details[open] summary::before {
    content: "+";
    transform: rotate(135deg);
  }
}

/* 2d. Nav-rail hover: smooth affordance + a 2px inward nudge so live block
 *     links feel distinct from the dimmed, non-interactive locked rows
 *     (locked rows use .locked-link and get no transform). */
.nav-item a {
  transition: background .15s ease, transform .15s ease, color .15s ease;
}
@media (prefers-reduced-motion: no-preference) {
  .nav-item a:hover { transform: translateX(2px); }
}

/* 2e. Copy button: press-in on click + a small pop on the confirmed state,
 *     giving felt feedback for an action whose result (clipboard) is invisible.
 *     app.js already toggles `.copied` for 1.5s. */
.copy-btn {
  transition: opacity .15s ease, background .15s ease,
              border-color .15s ease, transform .12s ease;
}
.copy-btn:active { transform: scale(.94); }
@media (prefers-reduced-motion: no-preference) {
  @keyframes enh-copied-pop {
    0%   { transform: scale(.9); }
    60%  { transform: scale(1.06); }
    100% { transform: scale(1); }
  }
  .copy-btn.copied { animation: enh-copied-pop .25s ease; }
}

/* 2f. Theme popover: scale/fade out of its top-right anchor (the Theme button)
 *     so the menu visibly "belongs to" that control. app.js keeps toggling the
 *     `hidden` attribute exactly as now; @starting-style + allow-discrete make
 *     it animate where supported and snap where not. */
@media (prefers-reduced-motion: no-preference) {
  .theme-pop {
    transition: opacity .15s ease, transform .15s ease,
                overlay .15s allow-discrete, display .15s allow-discrete;
    transform-origin: top right;
  }
  .theme-pop:not([hidden]) { opacity: 1; transform: scale(1); }
  @starting-style {
    .theme-pop:not([hidden]) { opacity: 0; transform: scale(.96); }
  }
  .theme-pop[hidden] { opacity: 0; transform: scale(.96); }
}

/* "What you've learned" recap — a calm green summary box (shared by Intro + First Analysis) */
.markdown .recap { background: color-mix(in oklab, var(--sage-tint) 60%, var(--card)); border: 1px solid color-mix(in oklab, var(--sage) 30%, var(--rule)); border-left: 4px solid var(--sage); border-radius: var(--radius); padding: 16px 20px; margin: 1.7em 0; line-height: 1.6; }
.markdown .recap::before { content: "🎓 What you've learned"; display: block; font-weight: 700; color: var(--sage); margin-bottom: .5em; font-size: 13px; letter-spacing: .04em; text-transform: uppercase; font-family: var(--font-sans); }
.markdown .recap ul { margin: .35em 0 0; }
.markdown .recap li { margin: .15em 0; }


/* ===========================================================================
 * 3. Self-check multiple-choice ("Quick check")
 * ---------------------------------------------------------------------------
 * Pure CSS, no JS: selecting a radio reveals ONLY that option's feedback and
 * marks it right (green ✓) or wrong (red ✗). Other options are left untouched,
 * so picking a wrong answer does not give away the correct one — the student
 * explores by trying the options. Authored in the Markdown as a blank-line-free
 * <form class="quiz"> block so marked passes it through as raw HTML; KaTeX still
 * renders $…$ inside afterwards.
 * ========================================================================= */
.markdown .quiz {
  margin: 1.7em 0;
  padding: 16px 20px 18px;
  background: color-mix(in oklab, var(--accent-tint) 42%, var(--card));
  border: 1px solid color-mix(in oklab, var(--accent) 22%, var(--rule));
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.markdown .quiz::before {
  content: "🧠 Question";
  display: block;
  font-family: var(--font-sans);
  font-size: 12px; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase;
  color: var(--accent);
  margin-bottom: .7em;
}
.markdown .quiz-q { margin: 0 0 .9em; font-weight: 600; line-height: 1.5; }
.markdown .quiz-opt {
  display: block; position: relative;
  margin: .5em 0; padding: 11px 15px 11px 44px;
  background: var(--card);
  border: 1px solid var(--rule);
  border-left: 3px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer; line-height: 1.5;
  transition: background .12s ease, border-color .12s ease;
}
.markdown .quiz-opt:hover { background: color-mix(in oklab, var(--accent-tint) 38%, var(--card)); }
.markdown .quiz-opt > input { position: absolute; opacity: 0; width: 0; height: 0; }
.markdown .quiz-mark {
  position: absolute; left: 15px; top: 12px;
  width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid color-mix(in oklab, var(--accent) 45%, var(--rule));
  background: var(--paper);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700; line-height: 1; color: var(--paper);
  transition: border-color .12s ease, background .12s ease;
}
.markdown .quiz-fb {
  display: none;
  margin-top: .6em; padding-top: .55em;
  border-top: 1px dashed var(--rule);
  font-size: 14.5px; line-height: 1.55; color: var(--ink-2);
}
.markdown .quiz-opt > input:checked ~ .quiz-fb { display: block; }

/* selected option — correct */
.markdown .quiz-correct > input:checked ~ .quiz-mark { border-color: var(--sage); background: var(--sage); }
.markdown .quiz-correct > input:checked ~ .quiz-mark::after { content: "✓"; }
.markdown .quiz-correct > input:checked ~ .quiz-fb { color: color-mix(in oklab, var(--sage) 78%, var(--ink)); }
.markdown .quiz-correct:has(> input:checked) {
  border-left-color: var(--sage);
  background: color-mix(in oklab, var(--sage-tint) 40%, var(--card));
}

/* selected option — wrong */
.markdown .quiz-opt:not(.quiz-correct) > input:checked ~ .quiz-mark { border-color: var(--g-foundations); background: var(--g-foundations); }
.markdown .quiz-opt:not(.quiz-correct) > input:checked ~ .quiz-mark::after { content: "✗"; }
.markdown .quiz-opt:not(.quiz-correct) > input:checked ~ .quiz-fb { color: color-mix(in oklab, var(--g-foundations) 70%, var(--ink)); }
.markdown .quiz-opt:not(.quiz-correct):has(> input:checked) {
  border-left-color: var(--g-foundations);
  background: color-mix(in oklab, var(--g-foundations) 10%, var(--card));
}


/* ===========================================================================
 * 4. Per-exercise objective line ("🎯 Goal — …")
 * ========================================================================= */
.markdown .goal {
  margin: .2em 0 1.2em;
  padding: 9px 14px;
  background: color-mix(in oklab, var(--accent-tint) 38%, var(--card));
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  font-size: 14.5px; line-height: 1.5; color: var(--ink-2);
}
.markdown .goal::before { content: "🎯 Goal — "; font-weight: 700; color: var(--accent); }
.markdown .goal strong, .markdown .goal em { color: var(--ink); }


/* ===========================================================================
 * 5. Per-exercise "Objectives" list (🎯), placed after the hypothesis / before
 *    the prompt. Authored as a blank-line-free <div class="aim"><ul>…</ul></div>.
 * ========================================================================= */
.markdown .aim {
  margin: 1.4em 0 1.6em;
  padding: 16px 20px 18px;
  background: color-mix(in oklab, var(--accent-tint) 38%, var(--card));
  border-left: 4px solid var(--accent);
  border-radius: var(--radius);
  line-height: 1.55;
}
.markdown .aim::before {
  content: "🎯 Objectives";
  display: block;
  font-family: var(--font-sans);
  font-weight: 700; color: var(--accent);
  font-size: 13px; letter-spacing: .05em; text-transform: uppercase;
  margin-bottom: .65em;
}
.markdown .aim ul { margin: 0; padding-left: 1.5em; }
.markdown .aim li { margin: .45em 0; font-size: 16px; }
/* GFM checkboxes (enabled + tagged .task-item by app.js) — make them easy to tap */
.markdown .aim li.task-item input[type="checkbox"] { width: 17px; height: 17px; }


/* ===========================================================================
 * 6. Home — "Meet Your Instructors"
 * ========================================================================= */
.instructors { margin: 3.5rem 0 0.5rem; text-align: center; }
.instructors h2 {
  font-family: var(--font-serif);
  font-weight: 600; font-size: 22px; letter-spacing: -0.01em;
  color: var(--ink); margin: 0;
}
.instructor-list {
  list-style: none; margin: 1.9rem auto 0; padding: 0;
  display: flex; gap: 3rem; justify-content: center; flex-wrap: wrap;
}
.instructor-list li { margin: 0; }
.instructor-list a {
  display: inline-flex; flex-direction: column; align-items: center; gap: 0.85rem;
  text-decoration: none; border-bottom: 0; color: var(--ink);
}
.instructor-list img {
  width: 132px; height: 132px; border-radius: 50%;
  object-fit: cover; border: 3px solid var(--rule); background: var(--card);
  box-shadow: var(--shadow-sm);
  transition: border-color .15s ease, transform .15s ease;
}
.instructor-list a:hover img { border-color: var(--accent); transform: translateY(-3px); }
.instructor-name {
  font-family: var(--font-sans); font-weight: 600; font-size: 15.5px;
  color: var(--ink); transition: color .15s ease;
}
.instructor-list a:hover .instructor-name { color: var(--accent); }
@media (max-width: 520px) {
  .instructor-list { gap: 1.8rem; }
  .instructor-list img { width: 104px; height: 104px; }
}

/* --- funding acknowledgement (home footer) --- */
/* Two logo files swap by theme so the mark stays legible and is never
   recoloured (per SNSF brand guidelines): colour/positive on the light
   themes, white/negative on the dark Obsidian theme. */
.funding { margin: 3.2rem 0 1rem; text-align: center; }
.funding-label {
  font-family: var(--font-sans); font-size: 11px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
  margin: 0 0 1rem;
}
.funding-logo { display: inline-block; border-bottom: 0; transition: transform .15s ease; }
.funding-logo:hover { transform: translateY(-2px); }
.funding-logo img { display: block; height: 42px; width: auto; }
/* colour logo on light themes, white logo on dark — selectors kept specific
   enough to beat `.funding-logo img` above (0,1,1). */
.funding-logo .funding-logo-neg { display: none; }
[data-theme="obsidian"] .funding-logo .funding-logo-pos { display: none; }
[data-theme="obsidian"] .funding-logo .funding-logo-neg { display: block; }
.funding-grants {
  font-family: var(--font-sans); font-size: 12px; color: var(--ink-3);
  margin: .95rem 0 0;
}
@media (max-width: 520px) { .funding-logo img { height: 34px; } }
