/* palette.css ,  THE ONLY FILE IN THIS PROJECT THAT MAY CONTAIN A COLOUR LITERAL.
 *
 * check.mjs fails the build if a hex, rgb(), hsl(), or named colour appears
 * anywhere else. That single rule is what makes a brand swap a one-file edit
 * instead of a six-page hunt.
 *
 * Nothing here describes a JOB. These are raw values with measured ratios.
 * Roles live in semantic.css, and elements may only ever reference roles.
 *
 * ---------------------------------------------------------------------------
 * WHEN THE PAID BRAND KIT LANDS (September 2026):
 *   1. node build/contrast.mjs --derive '#NEWACCENT'
 *   2. paste the printed ramp over the accent block below
 *   3. node build/contrast.mjs        (must print all-pass)
 *   4. node build/build.mjs
 * Ten minutes, every page, with a printed proof.
 * ---------------------------------------------------------------------------
 */

:root {
  /* -- surfaces ----------------------------------------------------------
   * Carried over from the deployed site so the new pages match what is
   * already public at firstcausestudio.com. */
  --fcs-parchment: #F5EEDD;   /* page ground */
  --fcs-ivory:     #FBF6EC;   /* raised panels and cards */

  /* -- ink ---------------------------------------------------------------
   * 14.12:1 on parchment. Comfortably past the 7:1 house body floor, which
   * is what buys the freedom to set body type over a textured ground. */
  --fcs-ink:       #241F1A;

  /* Muted ink, DARKENED 2026-08-12 from #5B5145 (6.71:1) after verify.mjs
   * measured it from rendered pixels rather than from this file.
   *
   * Two things the static prover could not see, and both are why the runtime
   * gate exists. First, the parchment is a photograph, so the ground under a
   * given paragraph ranges roughly rgb(229,224,193) to rgb(246,241,224) , 
   * the vignette alone costs about 0.8 of contrast, and a token proved
   * against the nominal swatch is proved against a colour that appears
   * nowhere on the page. Second, this token carries running prose (the CTA
   * note, the lede on every legal page, the overlay copy), not just labels,
   * and body copy takes the 7:1 house floor rather than the 4.5:1 one.
   *
   * At #4A4137 it clears 7:1 against the darkest ground the ORIGINAL
   * survey found (7.50). CORRECTED 2026-08-16: that survey was three
   * viewports wide, and the fixed object-fit:cover crop shows different,
   * sometimes darker paper patches at other ratios ,  verify.mjs measured
   * rgb(208,192,161) under hero furniture at 480px, where this token
   * reads 5.58:1. So this token is NOT safe for body-floor prose that
   * sits directly on the photographic ground at arbitrary widths; body
   * prose on the raw ground takes --fcs-ink, and this token keeps to
   * raised panels and non-body text away from the crop's dark patches. */
  --fcs-ink-muted: #4A4137;

  /* -- accent ------------------------------------------------------------
   * Hue-locked ramp derived from the brand orange (H20.0 S88%, lightness
   * stepped). Every step is unmistakably the same orange; a darker step must
   * never read as brown. Regenerate with:
   *     node build/contrast.mjs --derive '#F16722'
   *
   *   step   hex        on parchment   job
   *   500    #F16722       2.71        ORNAMENT ONLY (fails even the 3:1 UI bar)
   *   600    #C0480C       4.35        spare ,  does not clear the text floor
   *   650    #B6440C       4.75        minimum passing text step
   *   700    #993A0A       6.13        links, button labels, button fills
   *   800    #863209       7.34        clears the 7:1 body floor
   *   900    #602406      10.36        deep step
   */
  --fcs-accent-500: #F16722;  /* the brand orange, exactly as Felix specified */
  --fcs-accent-600: #C0480C;
  --fcs-accent-650: #B6440C;
  --fcs-accent-700: #993A0A;
  --fcs-accent-800: #863209;
  --fcs-accent-900: #602406;

  /* -- carried from the deployed palette ---------------------------------
   * Gold and teal shipped on the live page before the orange was chosen.
   * They are kept as raw values so nothing that still references them breaks
   * mid-migration, and so a later ruling can restore either as a secondary
   * without re-deriving anything. Neither is mapped to a text role today. */
  --fcs-gold:      #B0884A;   /* 2.81:1 on parchment ,  decorative if used at all */
  --fcs-gold-ink:  #77571F;   /* 5.73:1 ,  the passing step of the old gold */
  --fcs-teal:      #2C6C64;   /* 5.28:1 on parchment */

  /* -- depth -------------------------------------------------------------
   * The letterpress effect the deployed page uses: an ivory highlight above
   * the glyph and a warm shadow below it. These are literals because they
   * are translucent and cannot be expressed as a role reference, and they
   * live here for the same reason every other literal does: so a brand swap
   * is one file. Never used as text or as a background. */
  --fcs-emboss:       rgba(251, 246, 236, 0.42);  /* ivory, above the glyph */
  --fcs-shadow-soft:  rgba(63, 46, 22, 0.08);
  /* The vignette's top/bottom band only. Separate from shadow-soft, and
     weaker, because this one is painted relative to the VIEWPORT and therefore
     sweeps across text as the reader scrolls, while shadow-soft is used for
     letterpress depth that sits still. At 0.08 over the outer 7% it took an
     accent link to 3.96:1 against a 4.5:1 floor. */
  --fcs-shadow-band:  rgba(63, 46, 22, 0.04);
  --fcs-shadow-firm:  rgba(63, 46, 22, 0.18);
  --fcs-shadow-deep:  rgba(26, 20, 13, 0.62);     /* the modal scrim */
  --fcs-edge:         rgba(36, 31, 26, 0.28);     /* the pressed edge of a key */

  /* -- icons that carry a colour inside them -----------------------------
   * An SVG in a data: URI is a separate document. It cannot read currentColor
   * and it cannot read a custom property, so any colour it paints has to be
   * written into the URI as a literal. That is a real CSS limitation, not a
   * shortcut.
   *
   * Which is exactly why it belongs HERE. This is the one file permitted to
   * hold a literal, so putting the whole URI in it keeps the promise that
   * matters: a brand change is still a single-file edit, and the tick follows
   * the parchment instead of staying the old colour forever.
   *
   * Added 2026-08-13 after check.mjs grew a rule for colours smuggled inside
   * url(). The contact form's consent checkbox had '%23F5EEDD' encoded in its
   * tick, passed every check, and would have survived the September rebrand
   * still painted the old parchment.
   *
   * WHEN THE BRAND KIT LANDS: the %23XXXXXX below is --fcs-parchment,
   * percent-encoded (%23 is '#'). It must be changed with it. */
  --fcs-tick-on-accent:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7' fill='none' stroke='%23F5EEDD' stroke-width='2.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");

  /* -- hairlines ---------------------------------------------------------- */
  --fcs-line:      #E4DAC4;   /* 1.20:1 ,  a hairline, never a border that carries meaning */
  --fcs-line-firm: #94836B;   /* 3.18:1 ,  clears the 3:1 non-text UI bar (WCAG 1.4.11) */
}

/* semantic.css ,  roles, not colours. No hex may appear in this file.
 *
 * Elements reference ONLY these. An element that reaches past a role to a raw
 * palette value is a lint failure, because it would survive a brand swap
 * unchanged and quietly break the new palette's contrast guarantees.
 *
 * Every colour role below has a matching row in the PAIRS table in
 * build/contrast.mjs. Adding a role here without adding its pair there is a
 * lint failure too, so the proof can never fall behind the stylesheet.
 */

:root {
  /* -- surfaces ----------------------------------------------------------- */
  --color-surface-page:   var(--fcs-parchment);
  --color-surface-raised: var(--fcs-ivory);

  /* -- text ---------------------------------------------------------------
   * body carries the 7:1 house floor; everything else carries 4.5:1, which is
   * stricter than WCAG's 3:1 large-text allowance. The audience is 55-80. */
  --color-text-body:  var(--fcs-ink);
  --color-text-muted: var(--fcs-ink-muted);

  /* Links and button labels sit at 700 (6.13:1), not at the 4.75:1 minimum.
   * The extra headroom is deliberate: contrast is verified on RENDERED PIXELS
   * and there is a parchment grain behind this text, so a token-value ratio
   * sitting exactly on the floor will measure under it on screen. */
  --color-text-accent: var(--fcs-accent-700);

  /* The same accent, one step darker, for accent text that is SMALL, italic,
     or sitting somewhere the parchment photograph runs dark. 700 proves at
     6.13:1 against the nominal swatch but measured 4.67:1 on the footer
     tagline at 1920, a margin of +0.17 over the floor. A pass that thin is
     luck, not design, and that line appears on every page of the site. */
  --color-text-accent-strong: var(--fcs-accent-800);
  /* the deepest accent ink: for small warm furniture (eyebrows, chapter
     numerals) that must clear the 7:1 body floor with real margin on the
     darkest parchment patches */
  --color-text-accent-deep: var(--fcs-accent-900);

  /* -- accent as a fill ---------------------------------------------------
   * Parchment on 700 is the same 6.13:1 pair inverted. Note the brand orange
   * itself CANNOT be a button fill: parchment on #F16722 is 2.71:1 and white
   * on it is 3.13:1, both of which fail the label. */
  --color-accent-fill:    var(--fcs-accent-700);
  --color-on-accent-fill: var(--fcs-parchment);
  --color-accent-fill-hover: var(--fcs-accent-800);

  /* The checkmark drawn ON an accent fill. It is a whole SVG rather than a
   * colour because a data: URI cannot read a token from inside itself; see the
   * note in palette.css. Elements reference this role, never the URI. */
  --icon-check-on-accent: var(--fcs-tick-on-accent);

  /* -- ornament -----------------------------------------------------------
   * THE BRAND ORANGE. 2.71:1 on parchment, which fails the 4.5:1 text floor,
   * fails the 3:1 large-text bar, and fails the 3:1 non-text UI bar as well.
   *
   * So it is not merely "not for body text". It cannot be a focus ring, a
   * form border, a control edge, or the only thing marking a state. It is
   * ornament: rules, fleurons, flourishes, washes behind nothing readable.
   *
   * check.mjs permits this token ONLY in border-color, outline-color, fill,
   * stroke, box-shadow and gradient stops. Never in color or background-color.
   * That is enforcement, not documentation. */
  --color-ornament: var(--fcs-accent-500);

  /* -- structure ----------------------------------------------------------
   * The focus ring is INK, not the accent, because the accent cannot legally
   * carry it. This is the single most likely place for a builder to reach for
   * the brand colour and produce an inaccessible page that looks on-brand. */
  --color-focus: var(--fcs-ink);
  --color-rule:  var(--fcs-line-firm);
  --color-rule-hairline: var(--fcs-line);

  /* -- depth --------------------------------------------------------------
   * Letterpress, not drop shadows. The page is meant to read as a printed
   * book, so depth is a highlight above the glyph and a warm shadow below. */
  --color-emboss:      var(--fcs-emboss);
  --color-shadow-soft: var(--fcs-shadow-soft);
  --color-shadow-band: var(--fcs-shadow-band);
  --color-shadow-firm: var(--fcs-shadow-firm);
  --color-scrim:       var(--fcs-shadow-deep);
  --color-edge:        var(--fcs-edge);

  /* -- type families ------------------------------------------------------ */
  --font-serif: "EB Garamond", "Iowan Old Style", Palatino, Georgia, "Times New Roman", serif;
  --font-sans:  -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;

  /* -- spacing ------------------------------------------------------------
   * An 8px base rhythm. Elements may not invent spacing values; that is what
   * stops three builders producing three vertical rhythms in one merged page. */
  --space-1: 0.5rem;   /* 8  */
  --space-2: 1rem;     /* 16 */
  --space-3: 1.5rem;   /* 24 */
  --space-4: 2rem;     /* 32 */
  --space-5: 3rem;     /* 48 */
  --space-6: 4rem;     /* 64 */
  --space-7: 6rem;     /* 96 */
  --space-8: 8rem;     /* 128 */

  /* -- type ---------------------------------------------------------------
   * Every clamp carries a rem term so browser text zoom scales it. The live
   * site currently violates this on four of five pages; fixing it here fixes
   * it everywhere at once.
   *
   * The floor of every scale step is >= 1rem (16px). There is no step below
   * the senior floor, so a builder cannot reach for one. Genuinely decorative
   * furniture uses --type-furniture AND must carry data-decorative. */
  --type-body:   clamp(1.125rem, 1.05rem + 0.25vw, 1.25rem);   /* 18 -> 20 */
  --type-small:  clamp(1rem, 0.97rem + 0.15vw, 1.0625rem);     /* 16 -> 17 */
  --type-label:  clamp(1.125rem, 1.05rem + 0.25vw, 1.25rem);   /* 18 -> 20: real small caps set at text size; labels only */
  --type-lead:   clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);       /* 20 -> 24 */
  --type-h3:     clamp(1.375rem, 1.2rem + 0.7vw, 1.75rem);
  --type-h2:     clamp(1.75rem, 1.4rem + 1.6vw, 2.75rem);
  --type-h1:     clamp(2.25rem, 1.5rem + 3.2vw, 4rem);
  --type-phone:  clamp(1.125rem, 1.05rem + 0.3vw, 1.375rem);   /* tel: >= 18px, always */
  --type-furniture: 0.8rem;  /* 12.8px ,  data-decorative ONLY, never actionable */

  /* The booking overlay is a distinct surface (a two-leaf book spread) and
     carries display sizes the page scale does not. */
  --type-phone-display: 1.55rem;                            /* the overlay's larger click-to-call; 24.8px, never under the 18px tel: floor */
  --type-leaf-head:     clamp(1.7rem, 1.2rem + 1.2vw, 2.2rem);   /* heading on an overlay leaf */
  --type-leaf-display:  clamp(2.4rem, 1.7rem + 2.2vw, 3.4rem);   /* the post-booking "And so it is." display line */

  --leading-body:    1.55;
  --leading-heading: 1.05;
  --measure-body:  38rem;   /* ~60-70 characters at body size */
  --measure-lead:  32rem;

  /* -- motion -------------------------------------------------------------
   * Elements may not write literal durations or easings. base.css zeroes all
   * of these under prefers-reduced-motion, which is how one media query
   * disarms every animation in the project at once. */
  --motion-fast: 140ms;
  --motion-base: 240ms;
  --motion-slow: 420ms;
  /* The book overlay's page-turn: a real leaf takes over a second ,  slow
     lift, swing through, gentle landing. 420ms read as a snap (Felix,
     2026-08-15). Zeroed under reduced motion like the others. */
  --motion-turn: 1200ms;
  --ease-out:    cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0.05, 0.36, 1);
  --ease-turn:   cubic-bezier(0.45, 0.05, 0.30, 1);

  /* -- shape --------------------------------------------------------------- */
  --radius-sm: 2px;
  --radius-md: 4px;
  --radius-pill: 999px;

  /* -- touch --------------------------------------------------------------
   * 48px, the FCS house rule. WCAG 2.2 AA only asks 24x24. */
  --touch-min: 48px;

  /* -- z bands ------------------------------------------------------------
   * Declared so three independently built elements cannot fight. An element
   * is assigned a band in ELEMENT-PLAN.md and check.mjs holds it there. */
  --z-ground:     -2;
  --z-atmosphere:  1;
  --z-content:    10;
  --z-overlay:    60;
}

/* fonts.css ,  @font-face only. Nothing else belongs here.
 *
 * Elements are forbidden from declaring @font-face, so this is the one place
 * a face is defined and the one place a file path is written. Both faces are
 * preloaded in the page skeletons.
 */

@font-face {
  font-family: "EB Garamond";
  src: url(/assets/fonts/ebgaramond-var.woff2) format("woff2");
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "EB Garamond";
  src: url(/assets/fonts/ebgaramond-italic-var.woff2) format("woff2");
  font-weight: 400 800;
  font-style: italic;
  font-display: swap;
}

/* reset.css ,  the floor every page stands on. Loaded first, before tokens.
 *
 * Deliberately tiny. This is not Normalize; it is the four or five things the
 * FCS senior standard actually requires, plus box-sizing.
 */

*, *::before, *::after { box-sizing: border-box; }

html {
  /* Stop iOS inflating text in landscape, which silently breaks a measured
     type scale on exactly the devices older readers hold sideways. */
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--color-surface-page);
  color: var(--color-text-body);
  font-family: var(--font-serif);
  font-size: var(--type-body);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, svg, video { max-width: 100%; height: auto; display: block; }

/* Focus is INK and it is never removed. The brand orange measures 2.71:1 and
   cannot legally carry a focus indicator, which is the single most likely
   place for a builder to reach for the brand colour and ship an inaccessible
   page that looks correct. */
:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
}

/* Screen-reader-only text. Kept in the reset because more than one element
   needs it and duplicating it per element would be three definitions. */
.sr-text {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* base.css ,  the page frame and the shared atmosphere.
 *
 * What lives here: the paper (ground, vignette, grain), the page grid, the
 * settle animation, and the reduced-motion switch. Anything an element could
 * reasonably own does NOT live here, because a base edit is a decision that
 * affects every element rather than a fix to one.
 *
 * The single most important block in this file is the reduced-motion one at
 * the bottom: it zeroes the motion tokens, which disarms every animation in
 * the project at once rather than relying on fourteen elements each
 * remembering to do it.
 */

/* ---------------------------------------------------------------- the paper */

.ground { position: fixed; inset: 0; z-index: var(--z-ground); }
.ground img { width: 100%; height: 100%; object-fit: cover; }

.vignette {
  position: fixed; inset: 0; z-index: var(--z-atmosphere);
  pointer-events: none;
  /* THE BAND IS NARROWER AND SHORTER THAN IT WAS, and this is a legibility
   * change rather than a taste one.
   *
   * Both layers here are `position: fixed`, so they are painted relative to
   * the VIEWPORT, not the document. The old linear gradient darkened the top
   * and bottom 7% of the viewport, which meant the dark band sat at the bottom
   * of every screenful and swept across every paragraph as the reader
   * scrolled. Measured on the built page at 1920, a link inside that band read
   * 3.96:1 against a 4.5:1 floor. Body ink survived it comfortably at about
   * 11.8:1; accent text did not.
   *
   * Cutting the band to the outer 3% and halving its opacity keeps the printed
   * page-edge feel, which comes mostly from the radial layer anyway, and stops
   * the atmosphere from deciding whether text passes. Found by the stage-7
   * critic and confirmed by direct measurement, 2026-08-12. */
  background:
    radial-gradient(120% 95% at 50% 42%, transparent 58%, var(--color-shadow-firm) 100%),
    linear-gradient(var(--color-shadow-band), transparent 3%, transparent 97%, var(--color-shadow-band));
}

.grain {
  position: fixed; top: -50%; left: -50%; width: 200%; height: 200%;
  z-index: calc(var(--z-atmosphere) + 1);
  pointer-events: none; opacity: 0.05; mix-blend-mode: multiply;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E") repeat;
  background-size: 240px;
  animation: drift 80s linear infinite alternate;
}
@keyframes drift {
  from { transform: translate(0, 0); }
  to   { transform: translate(2.2%, 1.4%); }
}

/* ----------------------------------------------------------- the page frame */

.page {
  position: relative;
  z-index: var(--z-content);
  min-height: 100svh;
  max-width: 1660px;
  margin: 0 auto;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: clamp(1.375rem, 3.5vh, 2.75rem) clamp(1.375rem, 5.5vw, 5.5rem) clamp(1.625rem, 4vh, 3.25rem);
}

/* The measure container. The skeleton owns it, not any element, which is what
   lets a hero from one builder sit above a call-to-action from another and
   still share one column. */
.passage {
  position: relative;
  max-width: var(--measure-lead);
  margin: clamp(1.8rem, 5.5vh, 4.5rem) auto 2.2rem;
}

/* ------------------------------------------------------------ ink settling */
/* Content is VISIBLE without JavaScript. These animate from opacity 0 only
   because the keyframe runs on load with `both`; a page whose sections start
   at opacity 0 waiting for a script is a defect under the non-negotiables. */

.settle { animation: settle var(--motion-settle, 1.05s) var(--ease-settle, cubic-bezier(.22,1,.36,1)) both; }
@keyframes settle {
  from { opacity: 0; transform: translateY(9px); }
  to   { opacity: 1; transform: translateY(0); }
}
.d1 { animation-delay: .08s; }
.d2 { animation-delay: .20s; }
.d3 { animation-delay: .36s; }
.d4 { animation-delay: .50s; }
.d5 { animation-delay: .66s; }
.d6 { animation-delay: .85s; }
.d7 { animation-delay: 1.05s; }

/* ------------------------------------------------------------ reduced motion
 * One block, whole project. Zeroing the tokens means an element that used
 * --motion-base for a transition is disarmed here without knowing it exists. */

@media (prefers-reduced-motion: reduce) {
  :root {
    --motion-fast: 0ms;
    --motion-base: 0ms;
    --motion-slow: 0ms;
    --motion-turn: 0ms;
    --motion-settle: 0ms;
  }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
  .settle { animation: none; opacity: 1; }
  .grain  { animation: none; }
}

/* --------------------------------------------------- short desktop viewports
 * The landing composition is meant to hold in one screen. These compress the
 * frame, never the type floor: body stays on the token scale, whose minimum
 * is 18px, so nothing here can push text under the senior floor. */

@media (min-width: 900px) and (max-height: 1120px) {
  .page { padding-top: clamp(1.125rem, 2.6vh, 2rem); padding-bottom: clamp(1.125rem, 2.6vh, 2rem); }
  .passage { margin-top: clamp(1.5rem, 7vh, 5rem); margin-bottom: 1.3rem; }
}

@media (min-width: 900px) and (max-height: 850px) {
  .page { padding-top: 1rem; padding-bottom: 1.125rem; }
  .passage { margin-top: clamp(1rem, 4vh, 2.5rem); margin-bottom: 1rem; }
}

/* ------------------------------------------------------------ small screens */

@media (max-width: 640px) {
  /* Bottom clearance so nothing rests under Safari's floating toolbar. */
  .page { padding: 1.125rem 1.375rem calc(1.875rem + env(safe-area-inset-bottom, 0px) + 2.5rem); }
  .passage { margin: 2rem auto 2.4rem; }
}

/* -------------------------------------------------- the multi-section frame
 *
 * `.page` above is the one-screen composition the holding page was. The real
 * site scrolls, so it needs a frame that stacks sections instead of fitting
 * them, and the SKELETON owns the space between them. That is the rule that
 * lets a hero from one builder sit above a section from another and still
 * share one vertical rhythm: an element that set its own outer margin would
 * be composing the page, and three of them would compose three pages.
 */

.page--site {
  position: relative;
  z-index: var(--z-content);
  max-width: 76rem;
  margin: 0 auto;
  padding: 0 clamp(1.25rem, 5vw, 4rem)
           calc(var(--space-6) + env(safe-area-inset-bottom, 0px));
}

/* The one place vertical rhythm between sections is decided. */
.page--site > main > * + * { margin-top: clamp(3.5rem, 9vh, 7rem); }
.page--site > main { padding: clamp(2rem, 6vh, 4.5rem) 0; }

/* Every section reads inside one measure unless it deliberately opts out. */
.page--site :where(p, li) { max-width: var(--measure-body); }

/* ---------------------------------------------------------------- skip link
 * Required by the non-negotiables and easy to forget, so it lives in base
 * rather than in a header element that a merge could replace. */

.skip-link {
  position: absolute;
  left: var(--space-2);
  top: var(--space-2);
  z-index: calc(var(--z-overlay) + 1);
  transform: translateY(-200%);
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-min);
  padding: var(--space-1) var(--space-3);
  background: var(--color-surface-raised);
  color: var(--color-text-body);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
  font-size: var(--type-small);
  text-decoration: none;
}
.skip-link:focus-visible { transform: translateY(0); }

/* The skip link's landing: #main takes programmatic focus (the skeletons
   carry tabindex="-1") and lands clear of the sticky masthead. Without
   the scroll margin the jump parks the content under the header; without
   the tabindex focus never moves and the next Tab restarts at the top. */
main[id="main"] { scroll-margin-top: 6.5rem; outline: none; }

/* ------------------------------------------------------------- focus, once
 * Declared here so no element has to remember it, and so no element can
 * reach for the brand orange to draw it. #F16722 measures 2.71:1 on parchment
 * and fails even the 3:1 non-text bar, which means it is not legally capable
 * of being a focus ring. The ring is ink. */

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* ------------------------------------------------------------- scroll lock */
/* The one shared JS hook. base.js adds this when an overlay opens; overlay
   elements must not implement their own, or two of them would fight. */
body.is-locked { overflow: hidden; }
/* The masthead's overflow-x guard made html the page's scroller, which
   quietly disabled the body-level lock: with an overlay open the page
   still scrolled by wheel, PageDown, and mobile scroll chaining. Lock the
   real scroller too. */
html:has(body.is-locked) { overflow: hidden; }

/* While an overlay is open the page furniture behind it is hidden. This is
   body-level state, so it belongs here rather than in an element: an element
   that reached out to style the header would break the moment a merge
   paired it with a different masthead. The selector once named
   .el-masthead__running, the pre-kit header, so the real header stayed
   visible through the scrim and collided with the close control. */
body.is-locked .el-site-header { visibility: hidden; }

/* ---------------------------------------------------- the content-page frame
 * The colophon and the three legal pages are a single column of prose, not
 * the one-screen composition the landing page is. They share every token and
 * every floor with it; only the frame differs.
 *
 * This is where the rem-term bug lived. All four pages set body type as
 * clamp(17px, .3vw + 16px, 18.5px): no rem term, so browser text zoom did not
 * scale it, and it landed at 17-18.5px against an 18-20px floor. They now
 * inherit --type-body from the token scale like everything else, which fixes
 * it in one place rather than four.
 */

.page--content {
  position: relative;
  z-index: var(--z-content);
  max-width: 44em;
  margin: 0 auto;
  display: block;
  min-height: 0;
  padding: clamp(1.5rem, 4vh, 3.25rem) clamp(1.375rem, 5vw, 3.5rem)
           calc(clamp(2.5rem, 7vh, 5.25rem) + env(safe-area-inset-bottom, 0px) + 2rem);
}

/* The legal pages now sit inside the site frame (masthead + colophon,
   Felix's ruling 2026-08-15), so the prose column drops its own side
   padding ,  the frame already provides it ,  or narrow phones pay it
   twice. */
.page--site .page--content { padding-left: 0; padding-right: 0; }

/* The policy text arrives by remote script; reserving a tall sheet keeps
   its arrival from hurling the colophon down the page (CLS). Every
   policy is far taller than a viewport, so the reservation never leaves
   dead space. */
.page--content .policy_embed_div { min-height: 100svh; }

.page--content .running-head {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  font-variant-caps: all-small-caps;
  letter-spacing: 0.11em;
  font-size: var(--type-label);
  font-weight: 500;
  color: var(--color-text-muted);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--color-rule-hairline);
  margin-bottom: clamp(2rem, 5vh, 3.4rem);
}
.page--content .running-head a {
  color: inherit;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-min);
}
.page--content .running-head a:hover { color: var(--color-text-accent); }

.page--content h1 {
  font-size: var(--type-h2);
  line-height: 1.15;
  font-weight: 500;
  color: var(--color-text-body);
  margin: 0 0 0.4em;
  text-shadow: 0 1px 0 var(--color-emboss);
}
/* Accent step DEEPENED 2026-09-21 from --color-text-accent (700) to the 800
   step, when these headings became real small caps. The rule asked for smcp
   for a long time while the served font had no such feature, so it had been
   rendering as full capitals. Real small caps are shorter and finer, so they
   lay down less ink on the photographic ground, and verify.mjs measures
   rendered pixels rather than the token: the guide's "The letters" fell from
   5.54:1 to 4.71:1 at 375px on the same colour. Same hue, one step deeper,
   margin restored. */
.page--content h2 {
  font-variant-caps: all-small-caps;
  font-weight: 600;
  letter-spacing: 0.07em;
  font-size: var(--type-label);
  color: var(--color-text-accent-strong);
  margin: 2.1em 0 0.5em;
}
.page--content p { margin: 0 0 1em; max-width: var(--measure-body); }
.page--content .lede {
  font-style: italic;
  color: var(--color-text-muted);
  font-size: var(--type-lead);
  margin: 0 0 2.2em;
}
.page--content a { color: var(--color-text-accent); }
/* Prose links get a 48px tap target without disturbing the line rhythm. */
.page--content main p a {
  display: inline-block;
  padding: 0.85em 0;
  margin: -0.85em 0;
}

.page--content .ornament {
  display: flex;
  align-items: center;
  gap: 1.2em;
  margin: 2.4em 0 2.2em;
}
.page--content .ornament::before,
.page--content .ornament::after {
  content: "";
  height: 1px;
  flex: 0 0 3.4em;
  /* The one place the brand orange earns its keep: a rule is decoration, and
     decoration is the only thing 2.71:1 may paint. */
  background: var(--color-ornament);
}

@media (prefers-reduced-motion: no-preference) {
  .page--content { animation: settle var(--motion-settle, 0.9s) var(--ease-out) both; }
}

/* ------------------------------------------------------- the leaf, and why
 *
 * `.leaf` already existed in the markup of the three legal pages and was
 * styled NOWHERE ,  a hook someone left for a paper treatment that was never
 * written. It is the right place for a fix that verify.mjs made necessary.
 *
 * The problem it solves is measured, not aesthetic. The ground is a
 * photograph under a vignette, so the pixels behind the reading column range
 * from about rgb(246,241,224) down to rgb(208,192,161) ,  a spread of 0.32 in
 * relative luminance. On the darkest patch, a link at --color-text-accent
 * measured 3.96:1 against a 4.5:1 floor, on a page that is live right now.
 * Nothing was wrong with the colour; the ground moved underneath it.
 *
 * Laying a near-opaque leaf of paper under the prose fixes every text colour
 * at once instead of one token at a time, and it holds when the brand kit
 * lands in September and the accent changes. Measured over the darkest ground
 * the leaf composites to rgb(245,238,226), which puts links at 6.15:1, muted
 * prose at 8.67:1 and body ink at 14.16:1.
 *
 * It also suits the metaphor the rest of the site already uses ,  leaf, recto,
 * verso, colophon. Long legal prose belongs on a sheet, not floating on grain.
 */

.page--content .leaf {
  position: relative;
  background: var(--color-surface-raised);
  /* Not flat: a sheet of paper is lighter where it lifts. Both stops are
     token-derived, so a palette swap carries them. */
  background-image: linear-gradient(180deg,
    var(--color-emboss) 0%, transparent 42%);
  border-radius: var(--radius-md);
  box-shadow:
    0 1px 0 var(--color-emboss) inset,
    0 var(--space-1) var(--space-4) var(--color-shadow-soft);
  padding: clamp(1.5rem, 4vw, 3rem) clamp(1.25rem, 4vw, 2.75rem);
  margin: 0 0 var(--space-4);
}

/* ------------------------------------------- third-party policy content
 *
 * Termageddon injects the policy markup for the three legal pages, and it
 * injects a stylesheet with it. Measured 2026-08-12: every table-of-contents
 * link was 25px tall against the 48px floor, across all three live pages, for
 * an audience of 55-80 year olds tapping them on a phone. 117 failures.
 *
 * THE !important IS LOAD-BEARING AND IS NOT LAZINESS. Their reset is keyed to
 * an ID:
 *     #<policy-key> a, #<policy-key> abbr, … { padding: revert; margin: revert }
 * One ID outranks any number of classes ,  that is how the cascade works, not a
 * thing more selectors can fix ,  and `revert` rolls the box back to the
 * browser default, which is zero. The only ways to win are to match their id
 * (a per-page Termageddon key that changes whenever a policy is regenerated,
 * so it would rot silently) or to raise priority. Priority is the honest one.
 *
 * Chrome was asked which rules actually won here rather than being assumed.
 * Scope is deliberately narrow: injected policy content only, nothing else on
 * the site is permitted this. */

.page--content .tg-toc-link {
  display: block;
  min-height: var(--touch-min);
  box-sizing: border-box;
  padding: 0.62em 0 !important;
}

/* Padding plus an equal negative margin is what buys a 48px hit box WITHOUT
   pushing the lines of a paragraph apart. min-height alone would work and
   would need no !important, but it would expand every line box containing a
   link, which on a page of dense legal prose reads as broken spacing. */
.page--content .policy_embed_div p a,
.page--content .policy_embed_div li:not(.tg-toc-item) a {
  display: inline-block;
  padding: 0.72em 0 !important;
  margin: -0.72em 0 !important;
}

/* ------------------------------------------------------- the desktop scale
 * Felix's ruling (2026-08-15): on wide screens the site should read the way
 * it does at 125% browser zoom ,  larger type, fuller measure, less bare
 * parchment. Raising the ROOT font size scales every rem-based token
 * (type, spacing, measures) together, exactly as zoom does, while px-based
 * floors (touch targets, hairlines) hold. 1440 is the cut because the
 * one-row masthead needs ~1095 effective px: 1440 / 1.25 = 1152, safe.
 * Media queries are in CSS px and unaffected, so breakpoints stay put. */

@media (min-width: 1440px) {
  html { font-size: 125%; }
}

/* The masthead's full-bleed rule extends past the content column by
 * design; clip (not hidden: no scroll container, no scrollbar) keeps that
 * and any future stray overflow from ever producing sideways scroll. */
html, body { overflow-x: clip; }


/* , , , , ,  print , , , , , 
 * The buyers print pages for board meetings. Ink on white, no fixed
 * furniture, no interactive shell. (Admitted to this build's product
 * paths by SPEC amendment, round 4, 2026-08-16.) */
@media print {
  .ground, .vignette, .grain { display: none; }
  /* no body background: the UA's white paper is the print ground */
  /* !important because the element sheets are emitted after base and
     would win at equal specificity (same mechanism the reduced-motion
     block already relies on) */
  .el-site-header, .el-site-footer { position: static !important; background: none !important; box-shadow: none !important; }
  [data-el="book-overlay"] { display: none; }
  .settle { animation: none; opacity: 1; }
  video { display: none; }
}

/* giveaway-opening ,  the giveaway page's frontispiece and prize plate.
 * Ported 2026-08-21 from the critic-passed EA-repo draft
 * (projects/antn-conference/entry-form/index.html) into the element
 * contract: tokens only, .el- prefix, no literals, no JS. The standfirst
 * carries the ruled header sentence verbatim; the deck statements and the
 * benefit-first prize rows are Felix-approved copy; the dates are the
 * ruled window (opens Sep 21 12:00 PM CT, ruled 2026-08-21). */

.el-giveaway-opening {
  padding: var(--space-6) var(--space-3) 0;
  text-align: center;
}

.el-giveaway-opening__frontis {
  max-width: 46.5rem;
  margin: 0 auto var(--space-5);
}

.el-giveaway-opening__mark {
  width: var(--space-7);
  height: auto;
  margin: 0 auto var(--space-2);
  opacity: 0.92;
}

.el-giveaway-opening__wordmark {
  width: min(19rem, 72vw);
  height: auto;
  margin: 0 auto;
}

.el-giveaway-opening__tagline {
  margin: var(--space-2) auto 0;
  color: var(--color-text-body);
  font-size: var(--type-label);
  letter-spacing: 0.09em;
  font-variant-caps: all-small-caps;
}

.el-giveaway-opening__device {
  margin: 0 auto var(--space-1);
  max-width: 46.5rem;
  color: var(--color-text-accent-deep);
  font-size: var(--type-label);
  font-weight: 550;
  letter-spacing: 0.13em;
  font-variant-caps: all-small-caps;
}

.el-giveaway-opening__title {
  margin: 0 auto;
  max-width: 16ch;
  color: var(--color-text-body);
  font-size: var(--type-h1);
  font-weight: 560;
  letter-spacing: 0.01em;
  line-height: var(--leading-heading);
  text-wrap: balance;
  text-shadow: 0 1px 0 var(--color-emboss), 0 2px 2px var(--color-shadow-soft);
}

.el-giveaway-opening__standfirst {
  margin: var(--space-3) auto 0;
  max-width: var(--measure-lead);
  color: var(--color-text-body);
  font-size: var(--type-lead);
  font-style: italic;
  line-height: 1.45;
}

.el-giveaway-opening__deck {
  margin: var(--space-5) auto 0;
  max-width: 40rem;
}

.el-giveaway-opening__line {
  margin: 0;
  color: var(--color-text-body);
  font-size: var(--type-lead);
  font-weight: 500;
  line-height: 1.42;
}

.el-giveaway-opening__line + .el-giveaway-opening__line {
  margin-top: var(--space-3);
}

.el-giveaway-opening__line strong {
  font-weight: 640;
}

.el-giveaway-opening__em {
  color: var(--color-text-accent-strong);
}

.el-giveaway-opening__sub {
  margin: var(--space-3) auto 0;
  max-width: var(--measure-body);
  color: var(--color-text-body);
  font-size: var(--type-body);
  font-style: italic;
  line-height: var(--leading-body);
}

/* the prize plate: the same ivory paper-on-paper sheet the site uses */
.el-giveaway-opening__prize {
  margin: var(--space-5) auto 0;
  max-width: 42rem;
  padding: var(--space-4) var(--space-3);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-raised);
  box-shadow: 0 var(--space-1) var(--space-4) var(--color-shadow-soft),
              0 12px 32px var(--color-shadow-band);
  text-align: left;
}

@media (min-width: 768px) {
  .el-giveaway-opening__prize {
    padding: var(--space-5);
  }
}

.el-giveaway-opening__prize-head {
  margin: 0 0 var(--space-3);
  color: var(--color-text-accent-strong);
  font-size: var(--type-label);
  font-weight: 550;
  letter-spacing: 0.12em;
  text-align: center;
  font-variant-caps: all-small-caps;
}

.el-giveaway-opening__row {
  display: flex;
  gap: var(--space-3);
  align-items: baseline;
  padding: var(--space-2) 0;
  border-top: 1px solid var(--color-rule-hairline);
}

.el-giveaway-opening__row--first {
  border-top: 0;
}

.el-giveaway-opening__row--total {
  margin-top: var(--space-1);
  border-top: 2px solid var(--color-rule);
  padding-top: var(--space-2);
}

.el-giveaway-opening__row-body {
  flex: 1;
}

.el-giveaway-opening__what {
  margin: 0;
  color: var(--color-text-body);
  font-size: var(--type-h3);
  font-weight: 640;
  line-height: 1.3;
}

.el-giveaway-opening__what--total {
  font-size: var(--type-body);
  font-variant-caps: all-small-caps;
  letter-spacing: 0.06em;
}

.el-giveaway-opening__how {
  margin: var(--space-1) 0 0;
  color: var(--color-text-muted);
  font-size: var(--type-body);
  line-height: var(--leading-body);
}

.el-giveaway-opening__val {
  flex: none;
  margin: 0;
  color: var(--color-text-body);
  font-size: var(--type-h3);
  font-weight: 560;
  white-space: nowrap;
}

.el-giveaway-opening__val--total {
  color: var(--color-text-accent-strong);
  font-weight: 700;
}

/* the calendar band */
.el-giveaway-opening__dates {
  display: grid;
  gap: var(--space-3);
  margin: var(--space-5) auto 0;
  max-width: 42rem;
  padding: var(--space-3) 0;
  border-top: 1px solid var(--color-rule);
  border-bottom: 1px solid var(--color-rule);
  text-align: left;
}

@media (min-width: 640px) {
  .el-giveaway-opening__dates {
    grid-template-columns: 1fr 1fr 1fr;
    gap: var(--space-2);
    text-align: center;
  }
}

.el-giveaway-opening__date-label {
  margin: 0;
  color: var(--color-text-accent-deep);
  font-size: var(--type-label);
  font-variant-caps: all-small-caps;
  letter-spacing: 0.1em;
}

.el-giveaway-opening__date-val {
  margin: var(--space-1) 0 0;
  color: var(--color-text-body);
  font-size: var(--type-body);
  font-weight: 560;
  line-height: 1.35;
}

.el-giveaway-opening__date-note {
  margin: var(--space-1) 0 0;
  color: var(--color-text-body);
  font-size: var(--type-small);
  line-height: 1.4;
}

/* The entry-window band: sits directly under the standfirst so nobody reads
 * the whole page excited and only learns at the bottom form that entry has
 * not opened (Felix's ruling 2026-08-23). Its own JS fills and unhides it
 * outside the entry window; inside the window it never appears. */
.el-giveaway-opening__window-band {
  max-width: 34rem;
  margin: var(--space-3) auto 0;
  padding: var(--space-2) var(--space-3);
  border: 2px solid var(--color-text-accent-deep);
  border-radius: var(--radius-sm);
  background: var(--color-surface-raised);
  color: var(--color-text-body);
  font-size: var(--type-body);
  font-weight: 600;
  line-height: 1.5;
  text-align: center;
}

.el-giveaway-opening__window-band[hidden] {
  display: none;
}

/* giveaway-entry ,  the sweepstakes reply card. Ported 2026-08-21 from the
 * critic-passed EA-repo draft into the element contract, dressed in the
 * contact form's proven field grammar: labels above fields at body size,
 * required in words, 48px targets, error text in plain words beside its
 * field, the same honeypot cage and Turnstile slot. The consent sentences
 * are RULED text (entry-form-spec.md in the EA repo) and must never be
 * edited here without a new disclosure version in the backend. */

.el-giveaway-entry {
  padding: var(--space-6) var(--space-3);
}

.el-giveaway-entry__head {
  margin-bottom: var(--space-4);
  text-align: center;
}

.el-giveaway-entry__device {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  max-width: 100%;
  min-width: 0;
  margin: 0 0 var(--space-2);
  white-space: normal;
  color: var(--color-text-accent-deep);
  font-size: var(--type-label);
  font-weight: 550;
  letter-spacing: 0.11em;
  font-variant-caps: all-small-caps;
}

.el-giveaway-entry__device::before,
.el-giveaway-entry__device::after {
  content: "";
  flex: 0 1 var(--space-6);
  width: var(--space-6);
  min-width: 0;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: var(--color-ornament);
}

.el-giveaway-entry__title {
  margin: 0 auto;
  max-width: 22ch;
  color: var(--color-text-body);
  font-size: var(--type-h2);
  font-weight: 520;
  letter-spacing: -0.008em;
  line-height: 1.1;
  text-wrap: balance;
  text-shadow: 0 1px 0 var(--color-emboss), 0 2px 2px var(--color-shadow-soft);
}

.el-giveaway-entry__sheet {
  max-width: 42rem;
  margin: 0 auto;
  padding: var(--space-5) var(--space-3);
  border: 1px solid var(--color-rule-hairline);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-raised);
  box-shadow: 0 var(--space-1) var(--space-4) var(--color-shadow-soft),
              0 12px 32px var(--color-shadow-band);
}

@media (min-width: 768px) {
  .el-giveaway-entry__sheet {
    padding: var(--space-5);
  }
}

.el-giveaway-entry__noscript {
  margin: 0 0 var(--space-3);
  color: var(--color-text-body);
  font-size: var(--type-body);
  line-height: var(--leading-body);
}

.el-giveaway-entry__form {
  margin: 0;
}

.el-giveaway-entry__group {
  margin: 0 0 var(--space-5);
  padding: 0;
  border: 0;
}

.el-giveaway-entry__group:last-of-type {
  margin-bottom: 0;
}

.el-giveaway-entry__legend {
  width: 100%;
  margin: 0 0 var(--space-3);
  padding: 0 0 var(--space-1);
  border-bottom: 1px solid var(--color-rule);
  color: var(--color-text-body);
  font-size: var(--type-h3);
  font-weight: 640;
  letter-spacing: 0.01em;
}

.el-giveaway-entry__legend-num {
  color: var(--color-text-accent-strong);
  font-variant-caps: all-small-caps;
  margin-right: var(--space-1);
}

.el-giveaway-entry__group-label {
  margin: 0 0 var(--space-1);
  color: var(--color-text-body);
  font-size: var(--type-body);
  font-weight: 600;
  line-height: 1.3;
}

.el-giveaway-entry__hint {
  margin: 0 0 var(--space-2);
  color: var(--color-text-muted);
  font-size: var(--type-small);
  font-style: italic;
  line-height: 1.5;
}

.el-giveaway-entry__field {
  margin-top: var(--space-3);
}

.el-giveaway-entry__field:first-of-type {
  margin-top: 0;
}

.el-giveaway-entry__label {
  display: block;
  margin-bottom: var(--space-1);
  color: var(--color-text-body);
  font-size: var(--type-body);
  font-weight: 600;
  line-height: 1.3;
}

.el-giveaway-entry__required,
.el-giveaway-entry__optional {
  color: var(--color-text-muted);
  font-size: var(--type-small);
  font-weight: 400;
}

.el-giveaway-entry__input,
.el-giveaway-entry__select,
.el-giveaway-entry__textarea {
  display: block;
  width: 100%;
  min-height: var(--touch-min);
  margin: 0;
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface-page);
  color: var(--color-text-body);
  font-family: var(--font-serif);
  font-size: var(--type-body);
  line-height: 1.4;
}

.el-giveaway-entry__textarea {
  line-height: 1.55;
  resize: vertical;
}

.el-giveaway-entry__input[aria-invalid="true"],
.el-giveaway-entry__select[aria-invalid="true"] {
  border-color: var(--color-text-accent-strong);
  box-shadow: inset 0 0 0 1px var(--color-text-accent-strong);
}

.el-giveaway-entry__error {
  margin: var(--space-1) 0 0;
  color: var(--color-text-body);
  font-size: var(--type-body);
  font-weight: 650;
  line-height: 1.4;
}

.el-giveaway-entry__error[hidden] {
  display: none;
}

/* the polite closes: a marked passage, same voice as the form's status */
.el-giveaway-entry__close {
  margin: var(--space-2) 0 0;
  padding: var(--space-2);
  border-left-style: solid;
  border-left-width: 3px;
  border-left-color: var(--color-ornament);
  background: var(--color-surface-page);
  color: var(--color-text-body);
  font-size: var(--type-body);
  font-weight: 600;
  line-height: 1.5;
}

.el-giveaway-entry__close[hidden] {
  display: none;
}

/* a closed form. 'elig' (None of these) folds every later section; 'state'
   (Rhode Island) keeps the contact section, where its message lives beside
   the state question, and folds the rest. Both are reversible: change the
   answer back and the form returns. */
.el-giveaway-entry__form[data-closed="elig"] [data-closeable],
.el-giveaway-entry__form[data-closed="state"] [data-closeable="about"],
.el-giveaway-entry__form[data-closed="state"] [data-closeable="agree"] {
  display: none;
}

/* choice rows: whole row clickable, 48px honest targets */
.el-giveaway-entry__choices {
  border-top: 1px solid var(--color-rule-hairline);
}

.el-giveaway-entry__choice {
  display: flex;
  align-items: flex-start;
  gap: var(--space-1);
  min-height: var(--touch-min);
  padding: var(--space-1) 0;
  border-bottom: 1px solid var(--color-rule-hairline);
  cursor: pointer;
}

.el-giveaway-entry__radio {
  -webkit-appearance: none;
  appearance: none;
  flex: none;
  width: var(--touch-min);
  height: var(--touch-min);
  font-size: var(--type-body);
  margin: calc(0.7em - 24px) 0 0 -13px;
  padding: 0;
  border: 13px solid transparent;
  border-radius: 50%;
  background: var(--color-surface-page) padding-box;
  box-shadow: inset 0 0 0 1px var(--color-rule);
  cursor: pointer;
}

.el-giveaway-entry__radio:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}

.el-giveaway-entry__radio:checked {
  background: var(--color-accent-fill) padding-box;
  box-shadow: inset 0 0 0 1px var(--color-text-accent),
              inset 0 0 0 6px var(--color-surface-page);
}

.el-giveaway-entry__choice-text {
  flex: 1;
  color: var(--color-text-body);
  font-size: var(--type-body);
  line-height: 1.4;
  padding-top: var(--space-1);
}

/* the agreements: same checkbox grammar as the contact form's opt-in */
.el-giveaway-entry__agree {
  display: flex;
  align-items: flex-start;
  gap: var(--space-1);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-rule-hairline);
}

.el-giveaway-entry__agree--rules {
  border-bottom: 0;
  border-top: 1px solid var(--color-rule-hairline);
}

.el-giveaway-entry__checkbox {
  -webkit-appearance: none;
  appearance: none;
  flex: none;
  width: var(--touch-min);
  height: var(--touch-min);
  font-size: var(--type-body);
  margin: calc(0.7em - 24px) 0 0 -13px;
  padding: 0;
  border: 13px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--color-surface-page) padding-box;
  box-shadow: inset 0 0 0 1px var(--color-rule);
  cursor: pointer;
}

.el-giveaway-entry__checkbox:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}

.el-giveaway-entry__checkbox:checked {
  background: var(--icon-check-on-accent) center / 14px no-repeat padding-box,
              var(--color-accent-fill) padding-box;
  box-shadow: inset 0 0 0 1px var(--color-text-accent);
}

.el-giveaway-entry__agree-label {
  color: var(--color-text-body);
  font-size: var(--type-body);
  line-height: 1.45;
  cursor: pointer;
}

.el-giveaway-entry__agree-label strong {
  font-weight: 640;
}

.el-giveaway-entry__agree-label a {
  color: var(--color-text-accent);
  /* the house prose-link pattern (base.css): a 48px tap target from
     invisible padding, without disturbing the sentence's line rhythm */
  display: inline-block;
  /* the small horizontal pad widens a short word like "Terms" past 48px */
  padding: 0.85em 0.2em;
  margin: -0.85em -0.2em;
}

.el-giveaway-entry__agree-label a:hover {
  color: var(--color-text-accent-deep);
}

.el-giveaway-entry__noeffect {
  margin: var(--space-2) 0 0;
  color: var(--color-text-muted);
  font-size: var(--type-small);
  font-style: italic;
  line-height: 1.5;
}

.el-giveaway-entry__disclosure {
  margin: var(--space-2) 0;
  color: var(--color-text-muted);
  font-size: var(--type-small);
  line-height: 1.55;
}

.el-giveaway-entry__nectar {
  position: absolute;
  left: 0;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  visibility: hidden;
}

.el-giveaway-entry__nectar input {
  max-width: 100%;
}

.el-giveaway-entry__turnstile {
  margin-top: var(--space-4);
  min-height: 0;
  display: flex;
  justify-content: center;
}

.el-giveaway-entry__turnstile:empty {
  margin-top: 0;
}

.el-giveaway-entry__submit {
  margin-top: var(--space-4);
  display: flex;
  justify-content: center;
}

.el-giveaway-entry__button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--touch-min);
  padding: var(--space-2) var(--space-5);
  border: 1px solid var(--color-edge);
  border-radius: var(--radius-sm);
  background: var(--color-accent-fill);
  box-shadow: 0 1px 0 var(--color-emboss) inset, 0 2px 6px var(--color-shadow-firm);
  color: var(--color-on-accent-fill);
  font-family: var(--font-serif);
  font-size: var(--type-label);
  font-weight: 620;
  letter-spacing: 0.06em;
  font-variant-caps: all-small-caps;
  hyphens: manual;
  overflow-wrap: break-word;
  cursor: pointer;
  transition: background var(--motion-fast) var(--ease-out),
              box-shadow var(--motion-fast) var(--ease-out),
              transform var(--motion-fast) var(--ease-out);
}

.el-giveaway-entry__button:hover {
  background: var(--color-accent-fill-hover);
}

.el-giveaway-entry__button:active {
  transform: translateY(1px);
  box-shadow: 0 1px 0 var(--color-emboss) inset, 0 1px 2px var(--color-shadow-soft);
}

.el-giveaway-entry__button[disabled] {
  opacity: 0.6;
  cursor: default;
  transform: none;
}

.el-giveaway-entry__note {
  margin: var(--space-2) 0 0;
  color: var(--color-text-muted);
  font-size: var(--type-small);
  font-style: italic;
  text-align: center;
  line-height: 1.5;
}

.el-giveaway-entry__status {
  margin: var(--space-3) 0 0;
  padding: var(--space-2);
  border-left-style: solid;
  border-left-width: 3px;
  border-left-color: var(--color-text-accent-strong);
  background: var(--color-surface-page);
  color: var(--color-text-body);
  font-size: var(--type-body);
  font-weight: 600;
  line-height: 1.5;
}

.el-giveaway-entry__status:empty {
  margin: 0;
  padding: 0;
  border-left-width: 0;
  background: none;
}

/* Booth kiosk furniture: the quiet Start-over control and the are-you-still-
 * there dialog. Both exist only in table mode (JS unhides them). */
.el-giveaway-entry__kiosk-reset {
  margin: 0 0 var(--space-2);
  text-align: right;
}

.el-giveaway-entry__kiosk-reset[hidden] {
  display: none;
}

.el-giveaway-entry__kiosk-reset-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--touch-min);
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--color-rule-hairline);
  border-radius: var(--radius-sm);
  background: var(--color-surface-page);
  color: var(--color-text-accent-deep);
  font-family: var(--font-serif);
  font-size: var(--type-label);
  font-weight: 600;
  letter-spacing: 0.05em;
  font-variant-caps: all-small-caps;
  cursor: pointer;
}

.el-giveaway-entry__kiosk-reset-button:focus-visible {
  outline: 2px solid var(--color-text-body);
  outline-offset: 2px;
}

.el-giveaway-entry__still {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-3);
  background: var(--color-scrim);
}

.el-giveaway-entry__still[hidden] {
  display: none;
}

.el-giveaway-entry__still-card {
  max-width: 26rem;
  padding: var(--space-5) var(--space-4);
  border: 1px solid var(--color-edge);
  border-radius: var(--radius-md);
  background: var(--color-surface-raised);
  box-shadow: 0 12px 32px var(--color-shadow-band);
  text-align: center;
}

.el-giveaway-entry__still-title {
  margin: 0;
  color: var(--color-text-body);
  font-size: var(--type-h3);
  font-style: italic;
  font-weight: 520;
  line-height: 1.2;
}

.el-giveaway-entry__still-copy {
  margin: var(--space-2) auto var(--space-3);
  color: var(--color-text-body);
  font-size: var(--type-body);
  line-height: 1.5;
}

.el-giveaway-entry__window {
  padding: var(--space-4) var(--space-2);
  text-align: center;
}

.el-giveaway-entry__window[hidden] {
  display: none;
}

.el-giveaway-entry__window-title {
  margin: 0;
  color: var(--color-text-body);
  font-size: var(--type-h3);
  font-style: italic;
  font-weight: 520;
  line-height: 1.2;
}

.el-giveaway-entry__window-title:focus {
  outline: none;
}

.el-giveaway-entry__window-copy {
  margin: var(--space-2) auto 0;
  max-width: var(--measure-body);
  color: var(--color-text-body);
  font-size: var(--type-body);
  line-height: 1.62;
}

.el-giveaway-entry__sent {
  text-align: center;
}

.el-giveaway-entry__sent[hidden] {
  display: none;
}

/* The received card: a printed reply card filed inside the sheet ,  a
 * parchment panel with the old double rule (border + inset hairline), an
 * inked RECEIVED stamp set slightly askew, and the drawing date presented
 * as its own small device. */
.el-giveaway-entry__sent-frame {
  padding: var(--space-5) var(--space-3) var(--space-5);
  border: 1px solid var(--color-edge);
  border-radius: var(--radius-sm);
  outline: 1px solid var(--color-rule-hairline);
  outline-offset: -7px;
  background: var(--color-surface-page);
}

.el-giveaway-entry__sent-stamp {
  display: inline-block;
  margin-bottom: var(--space-3);
  padding: 0.3em 0.85em;
  border: 2px solid var(--color-text-accent-deep);
  border-radius: var(--radius-sm);
  transform: rotate(-4deg);
  color: var(--color-text-accent-deep);
  font-size: var(--type-label);
  font-weight: 650;
  letter-spacing: 0.1em;
  font-variant-caps: all-small-caps;
  opacity: 0.85;
}

.el-giveaway-entry__sent-title {
  margin: 0;
  color: var(--color-text-body);
  font-size: var(--type-h2);
  font-style: italic;
  font-weight: 520;
  line-height: 1.15;
  text-shadow: 0 1px 0 var(--color-emboss), 0 2px 2px var(--color-shadow-soft);
}

.el-giveaway-entry__sent-title:focus {
  outline: none;
}

.el-giveaway-entry__sent-drawing {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  margin: var(--space-4) 0 0;
}

.el-giveaway-entry__sent-drawing-label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-text-accent-deep);
  font-size: var(--type-label);
  font-weight: 550;
  letter-spacing: 0.11em;
  font-variant-caps: all-small-caps;
}

.el-giveaway-entry__sent-drawing-label::before,
.el-giveaway-entry__sent-drawing-label::after {
  content: "";
  width: var(--space-5);
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: var(--color-ornament);
}

.el-giveaway-entry__sent-drawing-date {
  color: var(--color-text-body);
  font-size: var(--type-h3);
  font-weight: 600;
  line-height: 1.2;
}

.el-giveaway-entry__sent-copy {
  margin: var(--space-3) auto 0;
  max-width: var(--measure-body);
  color: var(--color-text-body);
  font-size: var(--type-body);
  line-height: 1.62;
}

.el-giveaway-entry__sent-copy[hidden] {
  display: none;
}

.el-giveaway-entry__sent-next {
  margin: var(--space-4) 0 0;
}

.el-giveaway-entry__sent-next[hidden] {
  display: none;
}

/* Additional website details only appear for centers with an existing site. */
.el-giveaway-entry__website {
  margin-top: var(--space-3);
}

.el-giveaway-entry__website[hidden] {
  display: none;
}

/* giveaway-rules ,  the official rules as a single readable document on the
 * ivory sheet. Every sentence is RULED text from the EA repo's
 * sweepstakes-rules-TEMPLATE.md (critic-passed 2026-08-21); edits here
 * require the same ruling process, and any consent-adjacent change needs a
 * new disclosure version in the backend. */

.el-giveaway-rules {
  padding: var(--space-6) var(--space-3) var(--space-6);
}

.el-giveaway-rules__head {
  margin-bottom: var(--space-4);
  text-align: center;
}

.el-giveaway-rules__mark {
  width: var(--space-5);
  height: auto;
  margin: 0 auto var(--space-2);
  opacity: 0.92;
}

.el-giveaway-rules__wordmark {
  width: min(16rem, 68vw);
  height: auto;
  margin: 0 auto var(--space-4);
}

.el-giveaway-rules__device {
  margin: 0 auto var(--space-1);
  max-width: 42rem;
  color: var(--color-text-accent-deep);
  font-size: var(--type-label);
  font-weight: 550;
  letter-spacing: 0.11em;
  font-variant-caps: all-small-caps;
}

.el-giveaway-rules__title {
  margin: 0 auto;
  color: var(--color-text-body);
  font-size: var(--type-h1);
  font-weight: 560;
  line-height: var(--leading-heading);
  text-shadow: 0 1px 0 var(--color-emboss), 0 2px 2px var(--color-shadow-soft);
}

.el-giveaway-rules__standfirst {
  margin: var(--space-2) auto 0;
  max-width: var(--measure-lead);
  color: var(--color-text-muted);
  font-size: var(--type-body);
  font-style: italic;
  line-height: var(--leading-body);
}

.el-giveaway-rules__doc {
  max-width: 42rem;
  margin: 0 auto;
  padding: var(--space-5) var(--space-3);
  border: 1px solid var(--color-rule-hairline);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-raised);
  box-shadow: 0 var(--space-1) var(--space-4) var(--color-shadow-soft),
              0 12px 32px var(--color-shadow-band);
  text-align: left;
}

@media (min-width: 768px) {
  .el-giveaway-rules__doc {
    padding: var(--space-5);
  }
}

.el-giveaway-rules__nopurchase {
  margin: 0 0 var(--space-3);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--color-rule);
  color: var(--color-text-body);
  font-size: var(--type-lead);
  font-weight: 640;
  line-height: 1.4;
  text-align: center;
}

.el-giveaway-rules__h2 {
  margin: var(--space-4) 0 var(--space-2);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-rule-hairline);
  color: var(--color-text-body);
  font-size: var(--type-h3);
  font-weight: 640;
  line-height: 1.25;
}

.el-giveaway-rules__h2:first-of-type {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.el-giveaway-rules__p {
  margin: 0 0 var(--space-2);
  color: var(--color-text-body);
  font-size: var(--type-body);
  line-height: var(--leading-body);
}

.el-giveaway-rules__p strong {
  font-weight: 640;
}

.el-giveaway-rules__p a {
  color: var(--color-text-accent);
  overflow-wrap: anywhere;
  display: inline-block;
  padding: 0.85em 0;
  margin: -0.85em 0;
}

.el-giveaway-rules__p a:hover {
  color: var(--color-text-accent-deep);
}

.el-giveaway-rules__list {
  margin: 0 0 var(--space-2);
  padding-left: var(--space-3);
  color: var(--color-text-body);
  font-size: var(--type-body);
  line-height: var(--leading-body);
}

.el-giveaway-rules__list li {
  margin-bottom: var(--space-1);
}

.el-giveaway-rules__list strong {
  font-weight: 640;
}

.el-giveaway-rules__list a {
  color: var(--color-text-accent);
  display: inline-block;
  padding: 0.85em 0;
  margin: -0.85em 0;
}

.el-giveaway-rules__back {
  margin: var(--space-5) auto 0;
  text-align: center;
}

.el-giveaway-rules__back-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--touch-min);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--color-edge);
  border-radius: var(--radius-sm);
  background: var(--color-accent-fill);
  box-shadow: 0 1px 0 var(--color-emboss) inset, 0 2px 6px var(--color-shadow-firm);
  color: var(--color-on-accent-fill);
  font-family: var(--font-serif);
  font-size: var(--type-label);
  font-weight: 620;
  letter-spacing: 0.06em;
  font-variant-caps: all-small-caps;
  text-decoration: none;
  hyphens: manual;
}

.el-giveaway-rules__back-link:hover {
  background: var(--color-accent-fill-hover);
}


/* Offline booth layout, layered on the published site styles. */
body{min-width:0}.ground img{width:100%;height:100%;object-fit:cover}.booth-main{width:min(100%,48rem);margin:auto;padding:1rem 1rem 4rem}.booth-main>section+section{margin-top:3rem}.booth-jump{max-width:none;text-align:center}.booth-jump a{display:inline-flex;align-items:center;min-height:48px;padding:.5rem 1.25rem;background:var(--color-accent-fill);color:var(--color-on-accent-fill);text-decoration:none}.booth-test{padding:.75rem;text-align:center;border:2px solid var(--color-text-accent-deep);background:var(--color-surface-raised);font-weight:bold}.el-giveaway-opening__frontis img{max-width:100%}.el-giveaway-entry__form input,.el-giveaway-entry__form textarea,.el-giveaway-entry__form select{font-size:max(16px,1rem)}.el-giveaway-entry__form :where(button,a){min-height:48px}.booth-help{border:0;background:transparent;color:var(--color-text-accent);font:inherit;text-decoration:underline;cursor:pointer}.booth-dialog{position:fixed;inset:env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);width:100%;height:100%;max-width:none;max-height:none;margin:0;padding:0;border:0;background:var(--color-surface-page);color:var(--color-text-body)}.booth-dialog::backdrop{background:var(--color-scrim)}.booth-dialog-head{display:flex;justify-content:space-between;align-items:center;gap:1rem;padding:1rem;background:var(--color-surface-raised);border-bottom:1px solid var(--color-rule)}.booth-dialog button,.booth-operator button{min-height:48px;padding:.5rem 1rem;border:1px solid var(--color-rule);background:var(--color-surface-raised);color:var(--color-text-body);font:inherit}.booth-dialog iframe{display:block;width:100%;height:calc(100% - 80px);border:0}.booth-dialog-small{inset:auto;max-width:32rem;max-height:90vh;height:auto;margin:auto;padding:0 1rem 1rem;border:1px solid var(--color-rule)}.booth-dialog-small .booth-dialog-head{margin:0 -1rem 1rem}.booth-dialog-small input{display:block;width:100%;min-height:48px;margin:.5rem 0 1rem;font-size:1.2rem}.booth-operator{position:fixed;z-index:80;inset:0;overflow:auto;padding:1rem max(1rem,calc((100vw - 48rem)/2));background:var(--color-surface-page)}.booth-operator header{display:flex;align-items:center;justify-content:space-between;gap:1rem}.booth-operator header img{width:14rem}.booth-operator dl{display:grid;grid-template-columns:1fr auto;gap:.5rem 1rem}.booth-operator dt{font-weight:600}.booth-operator dd{margin:0;text-align:right}.booth-actions{display:grid;grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));gap:.75rem}.booth-operator input{min-height:48px;font-size:1rem}.booth-operator [hidden],.booth-dialog [hidden]{display:none!important}@media(max-width:600px){.booth-operator header{flex-wrap:wrap}.booth-dialog-head{font-size:1rem}}

/* Modal content needs explicit viewport placement in iPad Safari. */
.booth-dialog-small{
  top:50%;left:50%;right:auto;bottom:auto;
  transform:translate(-50%,-50%);
  width:min(32rem,calc(100vw - 2rem));
  max-height:calc(100vh - 2rem);
  max-height:calc(100dvh - 2rem);
  margin:0;overflow:auto;
}

.booth-dialog[open]:not(.booth-dialog-small){display:flex;flex-direction:column;top:0;left:0;right:0;bottom:0;width:100vw;height:100vh;height:100dvh;overflow:hidden}
.booth-policy-content{flex:1;min-height:0;overflow:auto;padding:1rem max(1rem,calc((100vw - 48rem)/2));-webkit-overflow-scrolling:touch}
.booth-policy-content [data-policy-page]{max-width:48rem;margin:auto}
.booth-policy-content .el-giveaway-rules{padding:1rem 0 3rem}
.booth-policy-content .policy-snapshot{padding:1rem;background:var(--color-surface-raised);overflow-wrap:anywhere}
.booth-policy-content .policy-snapshot *{max-width:100%}
