/* MoonJug Water Math Calculator — stylesheet
 *
 * Every value below is transcribed from MOONJUG_UI_SPEC.md (spec v1.0,
 * design system MoonJug v2.1). No styling decision is made in this file.
 * Section numbers in comments point at the spec section the values came from.
 * To change a value here, change the spec first.
 */

/* ---- fonts — spec §2.1, self-hosted, no fonts.googleapis.com link -------- */
@font-face {
  font-family: 'Bebas Neue';
  src: url('/fonts/bebas-neue-400.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Poppins';
  src: url('/fonts/poppins-300.woff2') format('woff2');
  font-weight: 300; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Poppins';
  src: url('/fonts/poppins-400.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Poppins';
  src: url('/fonts/poppins-500.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Poppins';
  src: url('/fonts/poppins-600.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Great Vibes';
  src: url('/fonts/great-vibes-400.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('/fonts/ibm-plex-mono-400.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}

/* ---- tokens — spec §1.1 color, §1.2 type, §1.3 spacing ------------------ *
 * One bare :root. Dark-only by construction: the spec has no [data-theme]
 * and no prefers-color-scheme block anywhere. Do not add one here.
 * There is no radius token (§1.4), no elevation token and no box-shadow
 * (§1.5), and no motion token (§1.6) — those are literals at the
 * declaration, per the spec.
 */
:root {
  /* The UA paints parts of <input type="date"> and <input type="time"> itself
     — the calendar and clock indicators, the empty mm/dd/yyyy and --:-- --
     placeholders, and the picker panel. Those parts do not read var(--bone);
     they follow the UA's colour scheme, which defaults to light, so on the
     Void ground they rendered black on black and were invisible.
     `color-scheme: dark` is the standard property that tells the UA which
     palette to paint them from. It introduces NO new colour value and no
     prefixed pseudo-element (so §9.4's prefix inventory is untouched) — it
     only makes §6.4's ruled `color: var(--bone)` reach the parts of the
     control the stylesheet cannot address. */
  color-scheme: dark;

  --void:      #0A0A0A;
  --bone:      #F4F1EA;
  --moonstone: #9C9A94;
  --hairline:  #2A2A28;
  --foil:      #C9A24B;
  --footer-grey: #4a4a48;   /* §11.2 — page-class only, never outside §11 */

  --display: 'Bebas Neue', Impact, sans-serif;
  --ui:      'Poppins', system-ui, sans-serif;
  --script:  'Great Vibes', cursive;
  --mono:    'IBM Plex Mono', ui-monospace, monospace;

  /* Section separation, §11.5 row 9: pinned at 40px, no width breakpoint.
   * Ruled Sep 2026. The earlier 20px/40px was tuned against a 32px numeral and
   * a 32px headline; at the §11.8 numeral (80px) and the §11.4 headline (54px)
   * the sep stopped separating and the mode toggle read wedged between two
   * heavy blocks. .sep is the token's only consumer, so this is the whole
   * major-section rhythm. */
  --gap: 40px;
}

/* No width breakpoint on --gap: §11.5 row 9 pins it for this page class.
 * The base's §3.2 768px step (40px → 72px) does not apply here. */

/* ---- base — spec §10 starter -------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

/* spec §9.7 — load-bearing, not a style choice. Any class that sets display
   (the flex ones below) beats the UA's single-element-name [hidden] rule. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--void);
  color: var(--bone);
  font-family: var(--ui);
  font-weight: 400;
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;   /* spec §9.8 — backs the zero-horizontal-scroll gate */
}

p { margin: 0; }

/* ---- layout ------------------------------------------------------------- *
 * The spec's index .wrap is 1080px (§3.1), sized for the wide product grid.
 * This is a phone-first single-column tool, so the column is locked at 430px
 * with 28px side padding — identical to ~/moonjug-poured, which took the same
 * decision against the same spec (invite.html is the spec's own precedent for
 * running this kit as one narrow column). Background layers stay full-bleed
 * behind it.
 */
.wrap { max-width: 430px; margin: 0 auto; padding: 0 28px; }

main { padding: 32px 0 48px; }   /* spacing ladder, spec §3.6 */

/* ---- night sky — spec §4.5, §4.6, §5.1 verbatim ------------------------- *
 * Lives outside the flow behind the column and is never re-created.
 */
#sky {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
  animation: drift 240s linear infinite alternate;
  will-change: transform;
}
#sky-canvas { position: absolute; inset: 0; width: 100%; height: 100%; }

#caustics-canvas {
  position: absolute;
  inset: -8%;
  width: 116%;
  height: 116%;
  filter: blur(14px);
  opacity: 0.5;
  mix-blend-mode: screen;
  will-change: opacity;
}

@keyframes drift {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-16px, -10px, 0); }
}

/* The second of the system's two keyframes — spec §5.1, verbatim. Transform
   only: compositor work, no layout, no paint. Used by the jug stepper. */
@keyframes pop {
  0%   { transform: scale(1); }
  50%  { transform: scale(1.18); }
  100% { transform: scale(1); }
}

/* ---- section rule — spec §3.3, §7.2 ------------------------------------- */
.sep {
  width: 40px; height: 1px;
  margin: var(--gap) auto;
  background: var(--hairline);
  border: 0;
}

/* LOCAL, PENDING A §11 AMENDMENT — proposed, not yet ruled.
 * The first rule on the page is not separating two things the reader has
 * finished with; it stands between the subhead and the first thing they are
 * asked to do, so at the full gap it reads as a wait rather than a break.
 * Half the ruled token — 20px, on the §3.6 ladder — gives a 41px break instead
 * of 81px. No new value: calc(var(--gap) / 2) of the §11.5 row 9 token. */
main > .sep:first-of-type { margin-block: calc(var(--gap) / 2); }

/* ---- micro-label — spec §7.3. A role, not an element. ------------------- */
.micro {
  font-family: var(--ui);
  font-size: 11px;
  font-weight: 500;
  line-height: 1.5;
  text-transform: uppercase;
  letter-spacing: 0.3em;
  color: var(--moonstone);
  margin: 0;
}

/* ---- wordmark — spec §7.5 ----------------------------------------------- */
.wordmark {
  font-family: var(--display);
  letter-spacing: 0.04em;
  font-size: clamp(56px, 12vw, 96px);
  line-height: 1;
  margin: 16px 0 0;
  font-weight: 400;
}
.wordmark .period { color: var(--foil); }

/* ---- headline / lede -------------------------------------------------- *
 * LOCAL DIVERGENCE from §11.4, pending a spec ruling. §11.4 gives h1 the
 * clamp(40px, 12.5vw, 54px) headline row — ruled for /poured, where the
 * headline IS the content. Here the headline is a question answered by four
 * inputs, and the §11.8 numeral (80px) is the content; at 54px the question
 * competed with the answer and ran to three lines.
 *
 * This takes §11.4's CAPTURE HEADING row instead — Bebas 30px / 1.06 / 0.04em
 * / Bone — unchanged, every term. In /poured that row is the heading standing
 * above the form that asks for input, which is exactly this element's role.
 * No new value is introduced: it is a different existing row of the same
 * page-class table.
 *
 * The lede is the 16px .hero-line, capped at 40ch (§3.1).
 */
.headline {
  font-family: var(--display);
  font-size: 30px;          /* §11.4 capture heading */
  line-height: 1.06;
  letter-spacing: 0.04em;
  font-weight: 400;
  color: var(--bone);
  margin: 8px 0 0;   /* tight: eyebrow + headline are one unit */
}
.hero-line { font-size: 16px; max-width: 40ch; margin-top: 12px; }

/* ---- segmented control — spec §7.10 ------------------------------------ *
 * Selection is aria-pressed, not a class — the a11y state IS the style hook,
 * so they can never diverge (§9.8).
 */
.seg { display: flex; flex-wrap: wrap; gap: 8px; }
.seg-btn {
  min-height: 44px;
  min-width: 44px;
  padding: 0 14px;
  border: 1px solid var(--hairline);
  border-radius: 2px;
  background: transparent;
  color: var(--moonstone);
  font-family: var(--ui);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: color 150ms ease, border-color 150ms ease;
}
.seg-btn[aria-pressed="true"] { border-color: var(--bone); color: var(--bone); }

/* ---- benefits bullet — spec §7.9, verbatim ------------------------------ *
 * An 8px HOLLOW ring — a new moon. Not a filled disc and not a list-style-type,
 * which is what the browser supplies if this is left unported. margin-top 7px
 * optically centres it on the first line of 14px/1.55 text.
 */
.benefits { list-style: none; margin: 12px 0 0; padding: 0; }
.benefits li {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 14px;
  color: var(--moonstone);
  line-height: 1.55;
  margin-bottom: 6px;
}
.moon-dot {
  flex: none;
  width: 8px; height: 8px;
  margin-top: 7px;
  border: 1px solid var(--moonstone);
  border-radius: 50%;
}

/* ---- slider — spec §7.28 ----------------------------------------------- *
 * Every adjuster on this page. §6.4's "there is no range slider" is amended
 * and §9.4 now permits ::-moz-range-track and ::-moz-range-thumb for this
 * component only — the two are required for a cross-browser range and nothing
 * else in the repo may use a -moz- prefix.
 *
 * Built from ruled primitives and nothing else: the track is the §4.7 hairline,
 * the thumb is Bone at the §1.4 2px radius, the hit area is 44px per §9.6, and
 * focus is the global §6.1 ring. No gradient, no shadow, no glow (§4.1, §4.2).
 * appearance is unprefixed-above-prefixed, per §9.4's existing pairing rule.
 */
.slider {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  height: 44px;              /* §9.6 tap target — the track is 1px, the reach is 44 */
  background: transparent;
  cursor: pointer;
  display: block;
}
.slider::-webkit-slider-runnable-track { height: 1px; background: var(--hairline); }
.slider::-moz-range-track            { height: 1px; background: var(--hairline); }
.slider::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 20px; height: 20px;
  margin-top: -10px;         /* centres a 20px thumb on a 1px track */
  border: 0;
  border-radius: 2px;
  background: var(--bone);
}
.slider::-moz-range-thumb {
  width: 20px; height: 20px;
  border: 0;
  border-radius: 2px;
  background: var(--bone);
}
/* The label and the live value sit on one baseline above the track. */
.slider-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.slider-value {
  font-family: var(--display);
  font-size: 24px;
  letter-spacing: 0.04em;
  color: var(--bone);
  margin: 0;
}

/* ---- stepper — spec §7.11, verbatim ------------------------------------ *
 * The jug count the visitor is booking. Not a slider: §6.4 records that there
 * is no range input in the system and why, and this is a whole count with a
 * floor and a ceiling, which is what the stepper already is. Radius stays 2px
 * as .seg-btn's does — §11.5 row 3 moves .btn and .input to 0, not these.
 * .qty.active is set permanently in the markup: the count floors at 1, so the
 * zero state that dims the control is unreachable on this page.
 * No disabled rule for .step — §6.2 rules the bound as JS-only, so a step at
 * the floor or the ceiling renders unchanged and is simply inert.
 */
.qty { display: flex; align-items: center; gap: 16px; }
.step {
  width: 44px; height: 44px;
  border: 1px solid var(--hairline);
  border-radius: 2px;
  background: transparent;
  color: var(--moonstone);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  transition: color 150ms ease;
}
.qty.active .step { color: var(--bone); }
.qty-count {
  font-family: var(--display);
  letter-spacing: 0.04em;
  font-size: 24px;
  min-width: 32px;
  text-align: center;
  color: var(--moonstone);
  transition: color 150ms ease;
}
.qty.active .qty-count { color: var(--bone); }
.qty-count.pop { animation: pop 150ms ease; }   /* §5.2 — quantity change only */

/* ---- mode panels — spec §3.5 screen mechanism -------------------------- */
.panel { display: none; }
/* 32px, not a section rule: the toggle selects this panel, so the two read as
 * one unit. §3.6 ladder. */
.panel.is-active { display: block; margin-top: 32px; }

/* ---- fields — spec §7.7, §6.4 ------------------------------------------ */
.fields { display: flex; flex-direction: column; gap: 20px; }
.field { display: block; }
.field > label, .field > .micro { display: block; margin-bottom: 8px; }

/* §11.5 rows 12-14: a bottom hairline, no box, no radius; focus takes the rule
 * to foil; invalid takes it to bone at 2px. No left inset — on a rule-only
 * field the value sits flush under its label. */
.input {
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--hairline);
  border-radius: 0;
  color: var(--bone);
  font-family: var(--ui);
  font-weight: 300;    /* §11.4 — Poppins Light, a real face (§11.3) */
  font-size: 16px;
  padding: 12px 0;
  min-height: 48px;
}
.input::placeholder { color: var(--moonstone); opacity: 1; }
.input:focus { border-bottom-color: var(--foil); }
.input[aria-invalid="true"] { border-bottom-color: var(--bone); border-bottom-width: 2px; }

.hint { font-size: 12px; color: var(--moonstone); margin-top: 6px; letter-spacing: 0; text-transform: none; }

/* The spec's §7 component inventory has no <select>. It is styled as the
   ruled .input box with the native chrome removed — appearance:none paired
   unprefixed-above-prefixed per §9.4 — and the caret is the spec's own
   rotated-border primitive (§4.7, §6.5: "a rotated L, not a glyph"),
   reused rather than a new glyph. No other property is introduced. */
.select-wrap { position: relative; display: block; }
.select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 40px;
}
.select-wrap::after {
  content: '';
  position: absolute;
  right: 0;   /* the box is gone (§11.5 row 12) — the caret sits at the rule's end */
  top: 50%;
  width: 6px; height: 6px;
  margin-top: -5px;
  border: solid var(--moonstone);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
  pointer-events: none;
}

/* ---- panel instruction line — spec §2.4, the 14px --ui tier -------------
 * The subhead's treatment one step down the register: same family, same bone,
 * 16px -> 14px. Measure capped at 60ch, the spec's .expectation cap (§3.1).
 */
.panel-note { font-size: 14px; max-width: 60ch; margin-top: 6px; }

/* ---- field label — §11.4 ------------------------------------------------ *
 * Mono 10px / 0.13em / moonstone. Replaces .micro on input labels only; the
 * section eyebrows (MODE, MY EVENT, MY HOME) stay .micro, which §11 leaves
 * alone.
 */
.field-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--moonstone);
}

/* ---- result ------------------------------------------------------------- *
 * §11.8, RULED — Doll Avant, Sep 2026. The §11.4 headline clamp x1.5 at every
 * term (40->60, 12.5vw->18.75vw, 54->80). line-height 0.9 because a digit
 * string has no ascender or descender; letter-spacing 0.015em is §11.5 row 6,
 * the page class's display value. Larger than the wordmark's 56px floor at
 * 430px by design — the two are never in one glance.
 */
.result-value {
  font-family: var(--display);
  font-size: clamp(60px, 18.75vw, 80px);
  line-height: 0.9;
  letter-spacing: 0.015em;
  font-weight: 400;
  color: var(--bone);
  margin: 0;
}
.result-label { margin-top: 8px; }

/* The label UNDER the numeral in home mode. Deliberately not .micro: Doll's
 * copy (# of Jugs to Start) is mixed case and ships exactly as written, and
 * .micro would uppercase it and space it out to 0.3em. Same colour and weight,
 * no transform, no tracking. */
.result-sublabel {
  font-family: var(--ui);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.5;
  color: var(--moonstone);
  margin: 8px 0 0;
}

/* The framing line above the numeral. Mono 12px moonstone is the spec's
 * .handling / .fee-note / .pricing-note tier (§2.4). Case is whatever is typed
 * in the markup — there is no text-transform here, which is .micro's signature,
 * not mono's, and home mode's "We recommend" depends on that staying true.
 * 6px below: label and numeral are one unit. */
.result-eyebrow {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--moonstone);
  margin-bottom: 6px;
}

/* ---- readout — spec §7.14 the order row -------------------------------- */
.lines { margin-top: 16px; }
.line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 0;
  border-bottom: 1px solid var(--hairline);
  font-family: var(--mono);
  font-size: 14px;
}
.line-price { white-space: nowrap; min-width: 56px; text-align: right; }

/* ---- notes — spec §7.15 .pricing-note, §2.4 .expectation --------------- */
.pricing-note { font-family: var(--mono); font-size: 12px; color: var(--moonstone); margin-top: 8px; }
.expectation { font-size: 14px; color: var(--moonstone); max-width: 60ch; margin-top: 20px; }

/* ---- empty resting state — spec §7.23 ---------------------------------- */
.empty { color: var(--moonstone); font-size: 15px; }

/* ---- buttons — spec §7.6, §6.2 ----------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0 20px;
  border-radius: 0;                /* §11.5 row 3 */
  font-family: var(--display);     /* §11.5 row 15 — Bebas, not Poppins */
  font-size: 19px;
  font-weight: 400;                /* Bebas Neue ships 400 only (§2.2) */
  letter-spacing: 0.09em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: opacity 180ms ease;
}
.btn:hover { opacity: 0.82; }
.btn-primary { background: var(--bone); color: var(--void); border: 1px solid var(--bone); }
.btn-secondary { background: transparent; color: var(--bone); border: 1px solid var(--hairline); }
.btn-block { width: 100%; }

/* spec §3.4 — .actions is a column at gap 12px, stretched */
.actions { display: flex; flex-direction: column; gap: 12px; align-items: stretch; margin-top: 24px; }

/* ---- the product card — spec §7.8, transcribed ------------------------- */
.card {
  border: 1px solid var(--hairline);
  border-radius: 2px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  background: rgba(10, 10, 10, 0.72);
}

/* TREATMENT 16C, ruled by Doll Avant Sep 2026. The three asks were one filled
 * button and two transparent ones, so on the Void ground Gift-a-Jug and
 * Sponsorship read as absences rather than choices, and each .hint floated
 * under a button it was not visibly attached to.
 *
 * Each ask is now the ruled §7.8 .card — 1px hairline, 2px radius, 20px
 * padding over rgba(10,10,10,0.72), transcribed unchanged, so the starfield
 * reads faintly through all three. The card is the enclosure that binds a
 * description to its button and gives the two secondaries an edge.
 *
 * Rent-a-Jug's card takes a BONE border. That is the system's existing
 * emphasis signal, not a new one — .input:focus, .seg-btn[aria-pressed=true]
 * and .check input:checked all mark the live thing by moving a hairline
 * border to bone (§1.1). Primacy is now carried by that border instead of by
 * the other two choices reading as empty space.
 *
 * .action is no longer a bare spacing wrapper; it is a .card in the markup and
 * these rules only add the ones .card does not carry. */
.actions { gap: 24px; }
.action > .hint { margin-top: 8px; }
.action-lead { border-color: var(--bone); }
.gift-terms { margin-top: 6px; }

/* ---- script line — spec §7.4 ------------------------------------------- */
.affirmation { font-family: var(--script); font-size: 44px; line-height: 1.4; color: var(--foil); }  /* §11.4 row 16 */
.closing { text-align: center; }

/* ---- page footer — spec §7.26 ------------------------------------------ *
 * Required on every MoonJug page. Mono 10px / 2 / 0.12em centred is §11.4's
 * Footer row; Footer grey is §11.2. 40px above, nothing below — the page's own
 * bottom padding is the space beneath. The divider is a middot with one space
 * either side, in the text, never a pipe. Each part is nowrap so the only
 * break opportunities are the divider's spaces.
 */
.page-footer {
  margin-top: 40px;
  font-family: var(--mono);
  font-size: 10px;
  line-height: 2;
  letter-spacing: 0.12em;
  color: var(--footer-grey);
  text-align: center;
  text-wrap: balance;
}
.page-footer span { white-space: nowrap; }

/* ---- focus ring — spec §6.1. One rule, unscoped. ----------------------- */
:focus-visible { outline: 2px solid var(--bone); outline-offset: 2px; }

/* ---- reduced motion — spec §5.5 ---------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  /* The water stills — the scene remains. No shooting stars at all. */
  #sky { animation: none !important; transform: none !important; }
}

/* ---- spacing — all values off the spec §3.6 ladder (8 · 12 · 16 · 20 · 32) *
 * Kept here rather than as inline style attributes: the spec's only inline
 * style writes are three in JS (§9.5), and none of them is a margin on markup.
 */
.hero-eyebrow    { margin-top: 16px; }
#mode-seg        { margin-top: 8px; }    /* tight: label + control are one unit */
.panel .fields   { margin-top: 16px; }   /* modest: past the instruction line */
.result          { margin-top: 40px; }   /* the answer breaks from the questions */
.sponsor-note    { margin-top: 12px; }
.membership-note { margin-top: 12px; }

/* The adjust control. 32px above it: it is a control, not more readout, and
 * reads as its own unit — the same value .panel.is-active takes off the toggle.
 * 8px between its label and the stepper, matching #mode-seg. .hint carries its
 * own 6px (§7.7). */
.adjust           { margin-top: 32px; }
.adjust .slider   { margin-top: 4px; }   /* the 44px reach supplies the rest */
.cost-eyebrow     { margin-top: 32px; }
/* ---- the total — spec §7.15 .subtotal ----------------------------------
   Transcribed geometry. Two departures, both recorded:

   1. §7.15 sets the label in .micro, which is uppercase. Doll's copy ships
      mixed case ("Total One Time Set up Fee"), so .subtotal-label takes the
      .line mono 14px face instead. Same tier, same colour, no transform.
   2. .recurring reuses the identical geometry at the .line mono size for the
      monthly charge. The shared shape says both rows are totals rather than
      line items; the size difference says which is the headline and which
      repeats. Its hairline separates it from the sum above it. */
.subtotal { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; padding-top: 24px; }
.subtotal-label { font-family: var(--mono); font-size: 14px; }
.subtotal-value { font-family: var(--display); letter-spacing: 0.04em; font-size: 32px; }

.recurring {
  padding-top: 18px;
  margin-top: 18px;
  border-top: 1px solid var(--hairline);
}
.recurring .subtotal-label { color: var(--moonstone); }
.recurring-value { font-family: var(--mono); font-size: 14px; white-space: nowrap; }

/* The last .line used to draw the rule above this panel. The total and the
   recurring row are no longer .line, and the recurring row can be switched
   off entirely, so the panel now draws its own and holds in both states. */
.member-panel { margin-top: 32px; padding-top: 32px; border-top: 1px solid var(--hairline); }

/* ---- checkbox — spec §6.5, reproduced unchanged -------------------------
   The spec's two implementations (.check, .rotation-check) are byte-identical
   in the input rule and differ only in wrapper font-size. This is .check, at
   the newsletter's 14px, used for the membership toggle and the Gift-a-Jug
   acknowledgement. No hover, focus-within or disabled state is added — §6.5
   records that none exists, and the global focus ring already covers the
   input. Nothing here is invented. */
.check {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 14px;
  color: var(--moonstone);
  line-height: 1.55;
  cursor: pointer;
}
.check input {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 18px; height: 18px;
  margin: 2px 0 0;
  /* §6.5 gives this box a --hairline border (#2A2A28). On the Void ground
     (#0A0A0A) that is a 1px edge at roughly 1.2:1 — invisible, and the
     control read as empty space. The border moves to --moonstone, which is
     the ruled border colour of .moon-dot (§1.1) and therefore the system's
     existing answer for "a small bordered mark that must be seen on Void".
     No new colour enters the page. Checked still goes to --bone, so the two
     states remain distinct and the checked state is still the brighter one. */
  border: 1px solid var(--moonstone);
  border-radius: 2px;
  background: transparent;
  cursor: pointer;
  position: relative;
}
.check input:checked { border-color: var(--bone); }
.check input:checked::after {
  content: '';
  position: absolute;
  left: 5px; top: 1px;
  width: 5px; height: 10px;
  border: solid var(--bone);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}

/* The membership toggle sits between the panel heading and whichever block it
   governs. .benefits already carries its own top margin. */
/* THE PATH OPTIONS. Each option is a block — the ruled .seg-btn plus its own
   description directly under it — so the description is visibly attached to
   the choice it describes. Three long labels do not fit on one row at phone
   width, so the set is a column. The buttons stay ruled .seg-btn, selection is
   still aria-pressed, and no new property is introduced. */
.paths { display: flex; flex-direction: column; gap: 12px; align-items: stretch; }
.path-option { display: flex; flex-direction: column; }
.path-option .seg-btn { width: 100%; }
/* 10px, not the .hint's 6px: the description is now separated from the button
   above it AND from the next option below it, so it needs a little more air to
   read as belonging to the button rather than floating between two.

   THE min-height IS WHAT STOPS THE OPTIONS JUMPING. Doll ruled that the three
   buttons must not move as descriptions appear and disappear. Toggling the
   detail on its own would move every option below the selected one, so each
   slot reserves the height of the tallest description up front and keeps it
   whether or not its own description is showing. The reserve is stated in em
   against the .hint's own 12px so it tracks the text: 4em covers three wrapped
   lines at phone width, 2.6em covers two once there is room for longer lines.

   ⚠ The Gift-a-Jug acknowledgement is NOT reserved. It is six or seven lines,
   and holding that much blank space under all three options to spare one
   option one downward shift is a bad trade. Choosing Gift-a-Jug therefore
   moves "Apply for a Sponsorship" down; Rent-A-Jug and Gift-a-Jug themselves
   never move, in any state. */
.path-detail {
  padding: 10px 2px 2px;
  font-size: 12px;
  min-height: 4em;
}
.path-detail .hint { margin-top: 0; }
.path-detail .gift-terms { margin-top: 10px; }
@media (min-width: 560px) { .path-detail { min-height: 2.6em; } }

.membership-check { margin-top: 16px; }

/* The non-member terms replace the .benefits list, so they take that list's
   own colour, size and measure rather than introducing a tier. */
.benefits-nonmember {
  margin-top: 16px;
  font-size: 14px;
  color: var(--moonstone);
  line-height: 1.55;
  max-width: 60ch;
}

/* An <a> cannot take :disabled, so the closed state is bound to aria-disabled.
   It is NOT §6.2's opacity 0.35: the button now carries the reason it is
   closed ("Add the event date"), and 0.35 would render that message at roughly
   2:1 against the ground — a button whose whole job is to be read cannot be
   dimmed to the edge of legibility.
   Instead it takes the ruled UNPRESSED .seg-btn treatment (§6.2) — transparent
   ground, hairline border, moonstone text — which is already this system's
   "present, but not the live thing", and pairs it with the ruled
   `cursor: not-allowed`. Moonstone on Void is about 7:1, so the message reads.
   Enabled, it returns to the filled .btn-primary, which is the whole point:
   the button visibly becomes the action once the form is complete. */
.btn[aria-disabled="true"] {
  background: transparent;
  color: var(--moonstone);
  border-color: var(--hairline);
  cursor: not-allowed;
}
.btn[aria-disabled="true"]:hover { opacity: 1; }
