/* ============================================================
   THE ANNOTATED NOTEBOOK — flashcards study surface (Phase 3
   Wave 1, Task 3). Page-scoped: it legitimately styles the
   shared flashcards.js DOM classes (#fc-card, .flashcard-face,
   .is-flipped, .fc-progress-fill, .esa-dots …) — restyle, never
   rename. The 3-D flip transform contract is reproduced HERE
   because nb pages load ONLY the nb layers (no noteviewer.css,
   which owns the legacy flip). No styles.css either, so there is
   no `theme-transitions-enabled *` rule to fight — the transform
   transitions win on their own.

   Discipline (test-enforced by pages/tests_notebook.py):
   · zero raw colors — every color enters as var(--nb-*)/color-mix
   (NOT on the nb-prefix ratchet: a page layer may style frozen
    foreign classes.)

   The card is a raised sheet of paper. The QUESTION side is the
   student's blue pen edge; the ANSWER side is the teal answer
   edge. Motion is the notebook's quiet spring; the flip is the
   one place a 3-D turn is sanctioned (it IS the interaction).

   Contents
     1 · Stage + column
     2 · Preview label (partial paywall)
     3 · Session bar  (mastery + counter chip)
     4 · Ink-fill progress  (.fc-progress-track/-fill)
     5 · The flip card  (scene / card / faces / is-flipped)
     6 · Card contents  (label / text / divider / hint / flip cue)
     7 · Controls + helper row
     8 · Loading dots  (.esa-dots — is-loading state)
     9 · Empty state
    10 · Paywall placement
    11 · Mobile
   ============================================================ */

/* ---------- 1 · Stage + column -------------------------------- */
/* The flashcards column shares the notes proof layout (.nb-page-layout
   rail + column) but never wants the notes reading measure — the stage
   centers its own card.
   width:100% is load-bearing: the column inherits auto inline margins
   from .nb-notes-column, and auto margins switch a grid item from
   stretch to fit-content sizing — without an explicit width the card's
   width tracked the breadcrumb's one-line length and jittered per topic
   (720/679/645px at the same viewport). Pinned to the track, the card
   is one size everywhere.
   margin-inline:auto centers the stage in the track at EVERY width (the
   notes column's clamp() left bias is for prose, not a card stage; kept
   on top of a full-width column it overflows the track by the bias on
   ~900–1100px viewports). Extends the item-5 ≥1440 centering decision
   (2026-07-03) to all sizes. */
.nb-fc-column {
  width: 100%;
  max-width: 720px;
  margin-inline: auto;
}
.nb-notes-header .nb-fc-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--nb-s3);
  margin-top: var(--nb-s5);
}
.nb-fc-back {
  padding-left: var(--nb-s2);
  padding-right: var(--nb-s2);
}
.nb-fc-whole {
  margin-left: auto; /* flush right, mirror of the legacy --chapter float */
}

.nb-fc-body {
  margin-top: var(--nb-s7);
}
.nb-fc-stage {
  display: flex;
  flex-direction: column;
  gap: var(--nb-s5);
}

/* ---------- 2 · Preview label (partial paywall) --------------- */
.nb-fc-preview-label {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--nb-s3);
  margin: 0 0 var(--nb-s5);
  font: var(--nb-type-label);
  letter-spacing: 0.02em;
  color: var(--nb-ink-2);
}

/* ---------- 3 · Session bar (mastery + counter) --------------- */
.nb-fc-sessionbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--nb-s4);
}
.nb-fc-mastery {
  display: inline-flex;
  align-items: center;
  gap: var(--nb-s2);
  font: var(--nb-type-label);
  color: var(--nb-ink-2);
  transition: color var(--nb-dur-1) var(--nb-ease);
}
.nb-fc-mastery-icon {
  color: var(--nb-blue);
}
.nb-fc-mastery-pct {
  font-variant-numeric: tabular-nums;
  color: var(--nb-ink);
}
.nb-fc-mastery-label {
  color: var(--nb-ink-2);
}
/* At 100% flashcards.js adds .is-complete — the whole indicator re-inks
   to the plain success voice (a UI confirmation, not a judgment mark). */
.nb-fc-mastery.is-complete,
.nb-fc-mastery.is-complete .nb-fc-mastery-icon,
.nb-fc-mastery.is-complete .nb-fc-mastery-pct,
.nb-fc-mastery.is-complete .nb-fc-mastery-label {
  color: var(--nb-success);
}

/* The counter reuses the neutral nb-chip; tabular figures so the width
   never jitters as the number climbs. */
.nb-fc-counter {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--nb-ink);
}
.nb-fc-counter-sep {
  color: var(--nb-ink-3);
  margin: 0 var(--nb-s1);
}

/* ---------- 4 · Ink-fill progress ----------------------------- */
/* The signature line: a 3px track filling with the student's ink as the
   deck advances. flashcards.js (FROZEN) writes `elFill.style.width = pct%`
   straight onto the fill — NOT a transform, and it never sets --nb-progress
   — so the transition MUST be on `width` (a transform/scaleX approach the
   linter would prefer is impossible without editing the frozen JS). The bar
   is a 3px absolutely-positioned cosmetic line inside a fixed-height track,
   so the width transition causes no meaningful layout thrash. */
.nb-fc-progress {
  position: relative;
  height: 3px;
  background: var(--nb-border);
  border-radius: var(--nb-r-pill);
  overflow: hidden;
}
.nb-fc-progress-fill {
  width: 0;
  height: 100%;
  background: var(--nb-blue);
  border-radius: var(--nb-r-pill);
  transition: width var(--nb-dur-3) var(--nb-ease);
}

/* ---------- 5 · The flip card --------------------------------- */
.nb-fc-cardsystem {
  display: flex;
  flex-direction: column;
  gap: var(--nb-s5);
}
/* Scene = perspective container. The card turns inside it. */
.nb-fc-scene {
  position: relative;
  width: 100%;
  height: 420px;
  perspective: 1600px;
}
/* Card shell = the 3-D flip target. */
.nb-fc-card {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transform-origin: center center;
  cursor: pointer;
  outline: none;
  transition: transform var(--nb-dur-3) var(--nb-ease);
  /* flashcards.js scrollIntoView target (#fc-card) — clear the shared
     .topbar for any block:'start'/'nearest' scroll. The init call uses
     block:'center' (which ignores scroll-margin), so a nonce'd correction
     script in nb_flashcard_index.html finishes the job. */
  scroll-margin-top: calc(var(--nb-chrome-h) + var(--nb-s5));
}
.nb-fc-card.is-flipped {
  transform: rotateY(180deg);
}
.nb-fc-card:focus-visible {
  outline: 2px solid var(--nb-blue);
  outline-offset: 6px;
  border-radius: var(--nb-r-lg);
}

/* Faces stacked, back pre-rotated; only the forward face shows. */
.nb-fc-face {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--nb-s4);
  padding: var(--nb-s9) var(--nb-s8);
  background-color: var(--nb-paper-raised);
  background-image:
    radial-gradient(
      circle at 18% 24%,
      color-mix(in srgb, var(--nb-ink) 5%, transparent) 0 1px,
      transparent 1.25px
    ),
    radial-gradient(
      circle at 76% 64%,
      color-mix(in srgb, var(--nb-ink) 5%, transparent) 0 0.9px,
      transparent 1.2px
    ),
    radial-gradient(
      circle at 44% 84%,
      color-mix(in srgb, var(--nb-ink) 5%, transparent) 0 0.8px,
      transparent 1.1px
    );
  background-size: 25px 27px, 33px 31px, 21px 23px;
  border: 1px solid var(--nb-border);
  border-radius: var(--nb-r-lg);
  box-shadow: var(--nb-shadow-2);
  text-align: center;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.nb-fc-face::before {
  content: "";
  position: absolute;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  top: var(--nb-s4);
  right: var(--nb-s5);
  width: var(--nb-s7);
  height: var(--nb-s7);
  background: url("../img/logo.png") center / contain no-repeat;
  filter: none;
  opacity: 0.72;
  pointer-events: none;
}

html.theme-light .nb-fc-face::before {
  filter: brightness(0);
  opacity: 0.62;
}

.nb-fc-face::after {
  content: "";
  position: absolute;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  inset: calc(var(--nb-s8) + var(--nb-s3))
    var(--nb-s5)
    calc(var(--nb-s8) + var(--nb-s1));
  border-block: 1px solid var(--nb-border);
  opacity: 0.72;
  pointer-events: none;
}
/* QUESTION = the student's blue pen edge. */
.nb-fc-face--front {
  border-top: 2px solid var(--nb-blue);
}
/* ANSWER = the teal answer edge (the contract's --fc-teal role, drawn
   from the definition-family token so it flips with the theme). */
.nb-fc-face--back {
  transform: rotateY(180deg);
  border-top: 2px solid var(--nb-adm-def);
}

/* ---------- 6 · Card contents --------------------------------- */
/* Corner label pill — QUESTION in blue, ANSWER in teal, seated at the
   card's top-left like a filed tab. */
.nb-fc-label {
  position: absolute;
  top: var(--nb-s5);
  left: var(--nb-s5);
  display: inline-flex;
  align-items: center;
  gap: var(--nb-s2);
  font: var(--nb-type-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.nb-fc-label::before {
  content: "";
  width: var(--nb-s2);
  height: var(--nb-s2);
  border-radius: var(--nb-r-pill);
  background: currentColor;
  visibility: hidden;
}
.nb-fc-label--q {
  color: var(--nb-blue);
}
.nb-fc-label--a {
  color: var(--nb-adm-def);
}

/* Card body text — the hero line. Serif is the examiner's alone, so the
   card stays in the sans reading voice; a touch larger, tightly measured. */
.nb-fc-text {
  margin: 0;
  max-width: 46ch;
  font: var(--nb-type-title);
  letter-spacing: -0.01em;
  color: var(--nb-ink);
  overflow-wrap: break-word;
}
/* KaTeX math inside the card inherits the card ink. */
.nb-fc-text .katex {
  color: var(--nb-ink);
}

/* Lists need their own marker gutter because the shared reset removes list
   padding. Without it an outside marker clips against the phone card border. */
.fc-card-text > :is(ul, ol) {
  box-sizing: border-box;
  width: 100%;
  margin: 0;
  padding-inline-start: 1.5em;
  text-align: left;
  list-style-position: outside;
}

.nb-fc-divider {
  width: var(--nb-s8);
  height: 1px;
  background: var(--nb-border);
}
.nb-fc-hint,
.nb-fc-empty .nb-empty-note {
  font: var(--nb-type-ui);
  color: var(--nb-ink-2);
}
/* Hint collapses to nothing when flashcards.js leaves it empty. */
.nb-fc-hint {
  min-height: 0;
}
.nb-fc-hint:empty,
.nb-fc-hint span:empty {
  display: none;
}

/* Chapter-level topic tag (hidden by JS on topic pages; a quiet chip
   when shown). */
.nb-fc-topic-tag {
  display: inline-flex;
  align-items: center;
  padding: var(--nb-s1) var(--nb-s3);
  background: var(--nb-paper-sunken);
  border: 1px solid var(--nb-border);
  border-radius: var(--nb-r-pill);
  font: var(--nb-type-label);
  color: var(--nb-ink-2);
}
.nb-fc-topic-tag[hidden] {
  display: none;
}

/* The flip affordance — a quiet cue pinned to the card foot, keyed to
   the face's own pen. */
.nb-fc-flip-cue {
  position: absolute;
  bottom: var(--nb-s5);
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: var(--nb-s2);
  font: var(--nb-type-label);
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.nb-fc-face--front .nb-fc-flip-cue {
  color: var(--nb-blue);
}
.nb-fc-face--back .nb-fc-flip-cue {
  color: var(--nb-adm-def);
}

/* Loading state: the loader lives in #fc-front-text; hide the resting
   card furniture so only the dots read while a card streams in. */
.nb-fc-card.is-loading {
  cursor: progress;
}
.nb-fc-card.is-loading .nb-fc-divider,
.nb-fc-card.is-loading .nb-fc-flip-cue {
  visibility: hidden;
}

/* ---------- 7 · Controls + helper row ------------------------- */
.nb-fc-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--nb-s3);
}
/* Prev/Shuffle are the secondary pen; Next fills as the primary action.
   Both already inherit .nb-btn; the icon just needs to seat cleanly. */
.nb-fc-btn .fc-btn-icon {
  flex-shrink: 0;
}

.nb-fc-helper {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--nb-s2);
  margin: 0;
  font: var(--nb-type-label);
  color: var(--nb-ink-2); /* small help text needs the 4.5:1 tier */
}
.nb-fc-helper .fc-helper-icon {
  color: var(--nb-ink-2);
}

.fc-load-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--nb-s3);
  max-width: 34rem;
  color: var(--nb-ink);
  font: var(--nb-type-ui);
  text-align: center;
}
.fc-load-error-message {
  margin: 0;
  color: var(--nb-error);
}
.fc-load-retry {
  justify-content: center;
  min-block-size: 44px;
}

/* ---------- 8 · Loading dots (.esa-dots) ---------------------- */
/* flashcards.js injects three dots as the .is-loading placeholder; nb
   does not load lazy-loading.css, so the loader is defined here in ink. */
.esa-dots {
  display: inline-flex;
  gap: var(--nb-s1);
  align-items: center;
  line-height: 0;
  color: var(--nb-ink-3);
}
.esa-dots > span {
  width: var(--nb-s2);
  height: var(--nb-s2);
  border-radius: var(--nb-r-pill);
  background: currentColor;
  opacity: 0.35;
  animation: nb-fc-dots 1.1s infinite ease-in-out both;
}
.esa-dots > span:nth-child(2) { animation-delay: 0.16s; }
.esa-dots > span:nth-child(3) { animation-delay: 0.32s; }
@keyframes nb-fc-dots {
  0%, 80%, 100% { opacity: 0.3; transform: translateY(0) scale(0.8); }
  40%           { opacity: 1;   transform: translateY(-4px) scale(1); }
}

/* ---------- 9 · Empty state ----------------------------------- */
.nb-fc-empty {
  margin-top: var(--nb-s6);
}

/* ---------- 10 · Paywall placement ---------------------------- */
/* nb_paywall_overlay ships a centered sheet; give the partial-paywall
   render (after the free deck) breathing room from the card stage. */
.nb-fc-body .nb-paywall-wrap {
  margin-top: var(--nb-s8);
}
.nb-paywall-wrap {
  display: flex;
  justify-content: center;
}

/* ---------- 11 · Mobile --------------------------------------- */
@media (max-width: 720px) {
  .nb-fc-scene {
    height: 380px;
  }
  .nb-fc-face {
    padding: var(--nb-s8) var(--nb-s5);
  }
  .nb-fc-controls {
    flex-wrap: wrap;
  }
  .nb-fc-actions {
    flex-direction: column;
    align-items: stretch;
  }
  .nb-fc-whole {
    margin-left: 0;
  }
}

/* ---------- Reduced motion — duration-only guard (site rule) --- */
@media (prefers-reduced-motion: reduce) {
  .esa-dots > span { animation: none; opacity: 0.55; }
}
