/* ============================================================
   /pricing/ — the notebook's own price list.
   One column, read top to bottom: the offer, three plan sheets
   with one deliberate action beneath them, the proof panel, then
   the questions as native disclosures. Layers over
   notebook-components.css (nb-btn, nb-tick, nb-link) and the nb
   token layer.

   SPACING CONTRACT — three tiers, nothing improvised:
     INTRA   var(--nb-s2)   8px   inside one component
     INTER   var(--nb-s6)  24px   between siblings in a section
     SECTION --nb-pricing-section-space  clamp(64px, 9vh, 112px)
   Card interiors carry their own stated padding tokens below.

   Test-enforced discipline (pages/tests_notebook.py):
   · every class starts nb-, every custom property --nb-pricing-
   · zero raw colors; token font sizes only; no theme forks
   Fail-safe motion: content ships visible; html.nb-anim (set by a
   head gate only when motion is allowed) opts into reveals, and
   reduced motion zeroes the --nb-dur-* tokens.
   ============================================================ */
.nb-pricing {
  --nb-pricing-gutter: var(--nb-s6);
  --nb-pricing-section-space: clamp(64px, 9vh, 112px);
  /* Two widths on this page and no third: the shell below, and
     this reading measure for prose-width blocks. */
  --nb-pricing-measure: 720px;
  --nb-pricing-card-pad: var(--nb-s6);
  --nb-pricing-panel-pad: var(--nb-s7);
  --nb-pricing-row-pad: var(--nb-s5);

  box-sizing: border-box;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  margin-inline: auto;
  padding-inline: var(--nb-pricing-gutter);
  padding-block: clamp(48px, 7vh, 84px) clamp(56px, 8vh, 96px);
  contain: inline-size;
  overflow-wrap: anywhere;
  color: var(--nb-ink);
  font-family: var(--nb-sans);
  font-size: var(--nb-text-base);
}

.nb-pricing *,
.nb-pricing *::before,
.nb-pricing *::after {
  box-sizing: inherit;
  min-width: 0;
}

/* The shell width. Hero, plan row, value panel and exit ramp all
   sit on it; only the FAQ steps in, to a reading measure. */
.nb-pricing__inner {
  width: 100%;
  max-width: 1060px;
  margin-inline: auto;
}

/* Visually hidden text: the sheet landmark and the radiogroup's
   own legend, which the hero already says out loud on screen. */
.nb-pricing-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;
}

/* ── Hero ─────────────────────────────────────────────────── */
.nb-pricing-hero {
  text-align: center;
}
.nb-pricing-title {
  margin: 0;
  font: var(--nb-type-display);
  letter-spacing: -0.025em;
  text-wrap: balance;
  color: var(--nb-ink);
}
.nb-pricing-title-line {
  display: block;
}
.nb-pricing-lede {
  margin: var(--nb-s6) auto 0; /* INTER */
  max-width: 58ch;
  font-size: var(--nb-text-lg);
  font-weight: 400;
  line-height: 1.55;
  color: var(--nb-ink-2);
  text-wrap: pretty;
}

/* ── Notices (checkout messages, above the plans) ──────────── */
.nb-pricing-notices {
  display: grid;
  gap: var(--nb-s6); /* INTER */
  max-width: var(--nb-pricing-measure);
  margin: 0 auto var(--nb-s6); /* INTER */
}
.nb-pricing-notice {
  padding: var(--nb-s3) var(--nb-s4);
  background: var(--nb-paper-raised);
  border: 1px solid var(--nb-border-strong);
  border-radius: var(--nb-r-md);
  box-shadow: var(--nb-shadow-1);
  font-size: var(--nb-text-base);
  line-height: 1.5;
  color: var(--nb-ink);
}
.nb-pricing-notice--error {
  border-color: color-mix(in srgb, var(--nb-error) 45%, transparent);
  color: var(--nb-error);
}

/* ── The plan block ───────────────────────────────────────────
   Cards, then the one action, then the fine print — one visual
   group, held together by the INTER gap. */
.nb-pricing-plans-section {
  margin-top: var(--nb-pricing-section-space); /* SECTION */
}
.nb-pricing-fieldset {
  margin: 0;
  padding: 0;
  border: 0;
}
.nb-pricing-plans {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--nb-s6); /* INTER */
}

/* Each plan is a sheet of paper the student can pick up — the
   nb-card grammar (DESIGN.md §5), with the radio doing the real
   work underneath. All three share one top edge and one bottom
   edge; the chosen one differs in surface, border and shadow. */
.nb-pricing-plan {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--nb-s2); /* INTRA */
  padding: var(--nb-pricing-card-pad);
  background: var(--nb-paper-raised);
  border: 1px solid var(--nb-border);
  border-radius: var(--nb-r-lg);
  box-shadow: var(--nb-shadow-1);
  cursor: pointer;
  scroll-margin-top: calc(var(--nb-chrome-h) + var(--nb-s4));
  transition:
    background-color var(--nb-dur-1) var(--nb-ease),
    border-color var(--nb-dur-1) var(--nb-ease),
    box-shadow var(--nb-dur-1) var(--nb-ease),
    transform var(--nb-dur-1) var(--nb-ease);
}
/* THE TRANSFORM LADDER — all four states declared, in strictly
   increasing specificity so none can stack onto another:
     rest              0,1,0   translateY(0)
     hover             0,2,0   translateY(-3px)
     selected          0,3,0   translateY(-4px)
     selected + hover  0,4,0   translateY(-6px)
   The site's reduced-motion guard is duration-only
   (notebook-tokens.css:271-273), so the resting -4px survives with
   motion off — the card stays raised, it just stops easing.

   -3px, not the house card's -1px: a plan card is a ~218px-tall
   primary choice control, and 1px on that mass is 0.46% — below
   the perceptual threshold. Translate only, never a shadow jump
   (DESIGN.md:315(2)). Hover stays inside (hover: hover) so it can
   never stick after a tap. */
@media (hover: hover) {
  .nb-pricing-plan:hover {
    transform: translateY(-3px);
  }
}
/* Selection. The flat 10% blue mix and --nb-shadow-2 at rest are
   the /pricing/ amendments documented at DESIGN.md:315 (2) and
   (3). The shadow stays at --nb-shadow-2: 315(2) reserves it as
   "the page's single elevated stage" and DESIGN.md:333 reserves
   --nb-shadow-3 for modals and the paywall only, so the lift and
   the doubled ring carry the elevation instead of a deeper shadow.
   z-index lifts the raised card's shadow and ring above its
   neighbours, which otherwise overlap it in DOM order. */
.nb-pricing-plan:has(.nb-pricing-radio:checked) {
  z-index: 1;
  background: color-mix(in srgb, var(--nb-blue) 10%, var(--nb-paper-raised));
  border-color: var(--nb-blue);
  box-shadow: var(--nb-shadow-2);
  transform: translateY(-4px);
}
/* The doubled ring, drawn as a pseudo-element rather than the
   inset box-shadow the brief suggested: DESIGN.md:351 bans
   accent-coloured shadows and inset strips outright ("Every
   box-shadow is one of the three tokens"). An absolutely
   positioned border ring is layout-neutral, adds no shadow, and
   leaves `outline` free for the focus ring. */
.nb-pricing-plan:has(.nb-pricing-radio:checked)::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--nb-blue);
  border-radius: inherit;
  pointer-events: none;
}
@media (hover: hover) {
  .nb-pricing-plan:has(.nb-pricing-radio:checked):hover {
    transform: translateY(-6px);
  }
}
.nb-pricing-plan:has(.nb-pricing-radio:focus-visible) {
  outline: 2px solid var(--nb-blue);
  outline-offset: 2px;
}
/* Without :has() the card cannot wear the ring, so the ring falls
   back onto the dot — which is still adjacent to the input. The
   card stays legible and selectable. */
@supports not selector(:has(*)) {
  .nb-pricing-radio:focus-visible + .nb-pricing-dot {
    outline: 2px solid var(--nb-blue);
    outline-offset: 2px;
  }
}

/* The native radio stays focusable but invisible; the dot is the
   student's pen answering the question. It sits next to the input
   so selection never depends on :has(). */
.nb-pricing-radio {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  opacity: 0;
}
.nb-pricing-dot {
  position: absolute;
  top: var(--nb-pricing-card-pad);
  inset-inline-end: var(--nb-pricing-card-pad);
  width: var(--nb-s5);
  height: var(--nb-s5);
  /* ink-3 clears the 3:1 non-text tier on raised paper in both
     themes; border-strong measured 1.6-1.7:1 and vanished. */
  border: 1.5px solid var(--nb-ink-3);
  border-radius: var(--nb-r-pill);
  background: var(--nb-paper-raised);
  transition: border-color var(--nb-dur-1) var(--nb-ease);
}
.nb-pricing-dot::after {
  content: "";
  position: absolute;
  inset: 4px;
  border-radius: var(--nb-r-pill);
  background: var(--nb-blue);
  transform: scale(0);
  transition: transform var(--nb-dur-2) var(--nb-ease);
}
.nb-pricing-radio:checked + .nb-pricing-dot {
  border-color: var(--nb-blue);
}
.nb-pricing-radio:checked + .nb-pricing-dot::after {
  transform: scale(1);
}

.nb-pricing-plan-name {
  padding-inline-end: var(--nb-s7); /* clears the dot in the corner */
  font: var(--nb-type-title);
  letter-spacing: -0.01em;
  color: var(--nb-ink);
}
.nb-pricing-plan-desc {
  font-size: var(--nb-text-sm);
  line-height: 1.4;
  color: var(--nb-ink-2);
}
/* The card's two groups — {name, descriptor} and {price, billing,
   saving} — are one INTER apart: the card's 8px INTRA gap plus
   this 16px makes exactly 24px. No auto margin, so a taller
   neighbour's slack falls after the last line, not into a void
   in the middle of the card. */
.nb-pricing-plan-price {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--nb-s1);
  margin-top: var(--nb-s4);
}
.nb-pricing-amount {
  font-size: var(--nb-text-3xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
  white-space: nowrap; /* a price must never break mid-number */
  color: var(--nb-ink);
}
.nb-pricing-per {
  font-size: var(--nb-text-sm);
  font-weight: 600;
  color: var(--nb-ink-2);
}
.nb-pricing-billing {
  font-size: var(--nb-text-sm);
  line-height: 1.4;
  color: var(--nb-ink-2);
}
/* The most persuasive line on the page: separated from the
   billing line above it by the action ink alone — no weight
   change, no wash, no badge. 5.33:1 light / 6.69:1 dark on a
   resting card, 4.62:1 / 5.67:1 on the selected card's tint. */
.nb-pricing-saving {
  font-size: var(--nb-text-sm);
  font-weight: 600;
  line-height: 1.4;
  color: var(--nb-blue);
}

/* ── The one deliberate action ────────────────────────────────
   One INTER below the cards — against a SECTION gap beneath the
   fine print — so the button groups with the row it commits.
   Width is exactly one grid column, so its edges line up with the
   middle card's rather than floating at an arbitrary measure. */
.nb-pricing-cta {
  display: flex;
  width: 100%;
  max-width: calc((100% - 2 * var(--nb-s6)) / 3);
  min-height: 48px;
  margin: var(--nb-s6) auto 0; /* INTER */
  /* nb-btn ships nowrap for chrome buttons; this label carries the
     chosen plan and must wrap rather than run off a 360px screen. */
  white-space: normal;
  text-align: center;
  font: var(--nb-type-control);
}
/* Working, not inert: the busy state keeps the student-blue voice
   (the sunken disabled grammar means dead, which is the opposite
   of what a payment in flight should say). */
.nb-pricing-cta[aria-busy="true"],
.nb-pricing-cta[aria-busy="true"]:disabled {
  background: var(--nb-blue);
  border-color: transparent;
  color: var(--nb-on-blue);
  cursor: progress;
}
.nb-pricing-terms {
  margin: var(--nb-s2) auto 0; /* INTRA — the terms belong to the button */
  max-width: 56ch;
  text-align: center;
  font-size: var(--nb-text-sm);
  line-height: 1.5;
  color: var(--nb-ink-2);
}

/* Premium state: no chooser, one quiet way forward. */
.nb-pricing-premium {
  max-width: var(--nb-pricing-measure);
  margin-inline: auto;
  padding: var(--nb-pricing-panel-pad);
  background: var(--nb-paper-raised);
  border: 1px solid var(--nb-border);
  border-radius: var(--nb-r-lg);
  box-shadow: var(--nb-shadow-1);
  text-align: center;
}
.nb-pricing-premium-note {
  margin: 0 0 var(--nb-s6); /* INTER */
  font-size: var(--nb-text-base);
  line-height: 1.6;
  color: var(--nb-ink-2);
}
.nb-pricing-premium-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--nb-s6); /* INTER */
}

/* ── Value panel: the promise beside the scale ────────────────
   Shell width, like the plan row. align-items: start keeps each
   column at its own content height — neither is stretched, so
   the panel ends where its taller column ends. */
.nb-pricing-value {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: start;
  gap: var(--nb-s6); /* INTER */
  margin-top: var(--nb-pricing-section-space); /* SECTION */
  padding: var(--nb-pricing-panel-pad);
  background: var(--nb-paper-raised);
  border: 1px solid var(--nb-border);
  border-radius: var(--nb-r-lg);
  box-shadow: var(--nb-shadow-1);
}
/* Both columns carry this heading, so both start on the same
   line and neither column opens with a void. --nb-type-title, the
   same role the plan-card names wear: these are component-level
   headings, and at --nb-type-headline they outsized the stat
   figures they label and tied with the FAQ section title. */
.nb-pricing-colhead {
  margin: 0 0 var(--nb-s6); /* INTER */
  font: var(--nb-type-title);
  letter-spacing: -0.01em;
  color: var(--nb-ink);
}

/* ── Unlocks checklist ────────────────────────────────────── */
/* gap: 0 — the rows are separated by their own padding and a
   rule, so a grid gap on top would double-count. */
.nb-pricing-list {
  display: grid;
  gap: 0;
  align-items: center;
  margin: 0;
  padding: 0;
  list-style: none;
}
.nb-pricing-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--nb-s2); /* INTRA */
  padding-block: var(--nb-s3); /* 12 + 12 = one INTER between rows */
  font-size: var(--nb-text-base);
  line-height: 1.55;
  color: var(--nb-ink);
}
/* The checklist rules itself like a notebook list. */
.nb-pricing-item + .nb-pricing-item {
  border-top: 1px solid var(--nb-border);
}
.nb-pricing-item .nb-tick {
  width: var(--nb-s4);
  height: var(--nb-s4);
  margin-top: 3px; /* optical: seats the 16px tick on the first line */
  color: var(--nb-success);
}
/* Fail-safe tick drawing: ticks ship drawn; only the motion gate
   hides them so the pen can draw each stroke in, staggered. */
.nb-pricing-list .nb-tick-path {
  stroke-dashoffset: 0;
  transition-delay: calc(var(--nb-pricing-i, 0) * var(--nb-dur-1));
}
.nb-anim .nb-pricing-list:not(.nb-is-drawn) .nb-tick-path {
  stroke-dashoffset: 24;
}

/* ── Content scale ────────────────────────────────────────────
   The same CONTENT_STATS .floor figures the homepage stat cards
   render (index.html:355,359,363), in this page's own language
   rather than the homepage's role-washed cards — the
   Retired-Candy Rule keeps homepage role colour on the homepage
   (DESIGN.md:272). No accent, no wash.

   Four ruled rows, in the same language as the checklist opposite
   — same 12px row padding, same hairline, no fill — so the two
   columns end within 22px of each other instead of the 79px void
   a 2x2 grid left beside four tick rows.

   WCAG 1.4.4: the row wraps, and the figure trails on
   margin-left: auto until it does, then drops to its own line
   rather than colliding with a grown label. */
.nb-pricing-stats {
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}
.nb-pricing-stat {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--nb-s2); /* INTRA */
  padding-block: var(--nb-s3); /* 12 + 12 = one INTER between rows */
}
.nb-pricing-stat + .nb-pricing-stat {
  border-top: 1px solid var(--nb-border);
}
.nb-pricing-stat-label {
  font: var(--nb-type-label);
  color: var(--nb-ink-2);
}
.nb-pricing-stat-figure {
  margin-left: auto;
  font-size: var(--nb-text-xl);
  font-weight: 700;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
  white-space: nowrap; /* a figure must never break mid-number */
  color: var(--nb-ink);
}

/* ── Margin note ──────────────────────────────────────────── */
.nb-pricing-note {
  margin: var(--nb-pricing-section-space) auto 0; /* SECTION */
  max-width: 56ch;
  text-align: center;
  font-family: var(--nb-serif);
  font-style: italic;
  font-size: var(--nb-text-md);
  line-height: 1.55;
  color: var(--nb-ink-2);
}
.nb-pricing-note .nb-link {
  white-space: nowrap;
}

/* ── FAQ ──────────────────────────────────────────────────────
   Native <details>/<summary>: keyboard and screen-reader
   behaviour comes free, so the only work here is replacing the
   default marker with a chevron that can actually rotate on open
   (content: is not animatable) and giving the summary a focus
   ring of its own. No JS. This is the page's one narrower
   measure — a reading line length for prose.

   One calm list, not eight floating pills: no fill, no radius, no
   outer border, no gap — rows are separated by the same hairline
   the checklist and the stat rows use, so all three lists on the
   page speak one language. */
.nb-pricing-faq {
  margin-top: var(--nb-pricing-section-space); /* SECTION */
}
.nb-pricing-faq-title {
  margin: 0 0 var(--nb-s6); /* INTER */
  text-align: center;
  font-family: var(--nb-serif);
  font-weight: 600;
  font-size: var(--nb-text-2xl);
  line-height: 1.2;
  color: var(--nb-ink);
}
.nb-pricing-faq-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  max-width: var(--nb-pricing-measure);
  margin: 0 auto;
}
.nb-pricing-faq-item + .nb-pricing-faq-item {
  border-top: 1px solid var(--nb-border);
}
/* padding-block is the touch target: 16 + 16 around a 23.8px line
   clears the 44px floor at 55.8px. */
.nb-pricing-faq-q {
  position: relative;
  padding-block: var(--nb-s4);
  padding-inline-end: var(--nb-s6);
  cursor: pointer;
  list-style: none;
  font-size: var(--nb-text-md);
  font-weight: 700;
  line-height: 1.4;
  color: var(--nb-ink);
}
.nb-pricing-faq-q::-webkit-details-marker {
  display: none;
}
/* M3 · absolute, not floated, so the mark stays pinned to the
   row's first line however far the question wraps at 200% text.
   Drawn from two borders so it can rotate; same --nb-ink-2 the
   marker already wore. */
.nb-pricing-faq-q::after {
  content: "";
  position: absolute;
  top: var(--nb-s6);
  inset-inline-end: 0;
  width: var(--nb-s2);
  height: var(--nb-s2);
  border-right: 1.5px solid var(--nb-ink-2);
  border-bottom: 1.5px solid var(--nb-ink-2);
  transform: rotate(45deg);
  transition: transform var(--nb-dur-1) var(--nb-ease);
}
.nb-pricing-faq-item[open] .nb-pricing-faq-q::after {
  transform: rotate(-135deg);
}
.nb-pricing-faq-q:focus-visible {
  outline: 2px solid var(--nb-blue);
  outline-offset: -2px;
  border-radius: var(--nb-r-sm);
}
.nb-pricing-faq-a {
  margin: 0;
  padding-bottom: var(--nb-pricing-row-pad);
  max-width: 62ch;
  font-size: var(--nb-text-md);
  line-height: 1.6;
  color: var(--nb-ink-2);
}

/* ── Motion (fail-safe; durations are tokens, zeroed under
      reduced motion) ──────────────────────────────────────── */
.nb-anim .nb-pricing-reveal {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity var(--nb-dur-3) var(--nb-ease),
    transform var(--nb-dur-3) var(--nb-ease);
  transition-delay: calc(var(--nb-pricing-i, 0) * var(--nb-dur-1));
}
.nb-anim .nb-pricing-reveal.nb-is-visible {
  opacity: 1;
  transform: none;
}

/* ── Responsive ───────────────────────────────────────────── */
@media (max-width: 880px) {
  .nb-pricing-plans {
    grid-template-columns: minmax(0, 1fr);
  }
  /* One column: the CTA takes the full content width, since there
     is no longer a middle card for it to align with. */
  .nb-pricing-cta {
    max-width: none;
  }
  .nb-pricing-value {
    grid-template-columns: minmax(0, 1fr);
  }
  /* Stacked, the lift's axis IS the stacking axis, so a resting
     -4px reads as an uneven gap rather than elevation. The tint,
     border, doubled ring and --nb-shadow-2 carry selection here. */
  .nb-pricing-plan:has(.nb-pricing-radio:checked) {
    transform: none;
  }
}
/* Hover stays uniform once stacked: the selected card answers a
   pointer with the same -3px every other card does. */
@media (max-width: 880px) and (hover: hover) {
  .nb-pricing-plan:has(.nb-pricing-radio:checked):hover {
    transform: translateY(-3px);
  }
}
@media (max-width: 560px) {
  .nb-pricing {
    --nb-pricing-gutter: var(--nb-s4);
    --nb-pricing-card-pad: var(--nb-s5);
    --nb-pricing-panel-pad: var(--nb-s5);
    --nb-pricing-row-pad: var(--nb-s4);
  }
  .nb-pricing-amount {
    font-size: var(--nb-text-2xl);
  }
}
