/* =====================================================================
   BUILD METHODOLOGY

   The build methodology and collaboration philosophy now live in
   claude.md — they govern all work in the repo, not just CSS. The
   bullets below are the CSS-specific application of those principles.

   CSS ARCHITECTURE PRINCIPLES

   - Trace the constraint to its source instead of adding compensating
     rules. When a layout breaks, remove the rule causing the problem —
     don't add a new rule to override it. Each individually correct
     rule must be evaluated as part of the set; locally correct rules
     can produce globally incorrect layouts.
   - Children own spacing, parents own padding. Generic classes drive
     layout, specifics only override presentation.
   - The stylesheet is a live design system, not a collection of ad-hoc
     fixes. Every rule participates in the whole.
   - Cache strategy follows the same principle: don't add explicit rules
     for systems that already work correctly. The default behavior was
     working; the added rule caused the problem it was meant to prevent.
   - Use predefined token values (--s1..--s10, etc.) when a near match
     exists. Ad-hoc px values fragment the spacing system.
   ===================================================================== */

/* =====================================================================
   Choose13 — Stylesheet
   Single source of truth for all page styles.
   Sections:
     1. Design tokens + base reset
     2. Page container, topnav, header-brand, back-link
     3. Section anatomy, body sections, drop cap
     4. Hero, lexicon, editorial, callout, rail, foot-nav  (character-profile.html)
     5. Voting slip primitive  (shared)
     6. Postal strip, brand-foot
     7. my-13-traits.html voting page  (header, ring, picked, trait grid, compact slip)
   ===================================================================== */

/* =====================================================================
   Choose13 — Character Profile Template
   Faithful to v1 spatial frame · Literata everywhere
   12-col grid · 7-col body / 4-col sidebar (sticky callout)
   ===================================================================== */

:root {
  /* Core canvas + surfaces */
  --canvas: #FDFAF6;
  --surface: #FEFDFC;

  /* Brand lockup: standard distance between the 12-star ring and the
     wordmark, used by the header AND footer (single source of truth). */
  --brand-ring-gap: 10px;

  /* Paper / artifact surfaces */
  --paper: #F4EFE6;
  --paper-soft: #F8F4ED;
  --paper-warm: #F1E8DC;

  /* Primary ink */
  --ink: #172033;
  --ink-soft: rgba(23, 32, 51, 0.72);
  --ink-mid: rgba(23, 32, 51, 0.85);   /* between --ink (1.0) and --ink-soft (0.72) */

  /* Warm cream — for brand surfaces on dark stages */
  --cream: #ECE0C8;

  /* Civic navy / structural blue */
  --indigo: #123B66;
  --indigo-soft: rgba(18, 59, 102, 0.72);

  /* Voting / action identity */
  --coral: #D24A3D;
  --coral-deep: #A93A34;
  --coral-soft: #E37B6E;
  --coral-light: #DE6B5A;   /* one gentle step lighter than --coral (mirrors --coral-deep the other way); hero CTA hover */
  --coral-wash: #F7D8D0;
  --cta-star-color: var(--red);   /* brand star on the filled-coral CTAs: RED on light surfaces; .stage-dark flips it to cream for the dark hero. */
  --cta-fill: #E37B6E;              /* the home/hero CTA coral — single source, reused by the floating CTA so they match exactly */
  --cta-fill-hover: #EF9484;        /* one gentle step lighter — CTA hover */
  --cta-fill-soft: #F4A998;         /* one more gentle step up — floating-CTA default only (hero CTA unchanged) */

  /* TRUE red — brand voice (e.g. "I say…", topnav numerals) */
  --red: #BF2D20;

  /* Cool secondary — periwinkle blue */
  --blue: #7DA1BE;

  /* Secondary warm accent */
  --blush: #F3B4A7;

  /* Neutral text */
  --slate: #6B6B72;
  --slate-soft: #9C9CA2;

  /* Rules / lines */
  --rule: rgba(23, 32, 51, 0.16);
  --rule-2: rgba(23, 32, 51, 0.28);
  --rule-3: rgba(23, 32, 51, 0.45);
  --line-soft: #E8DDD0;

  /* Charcoal field — named semantic darks, the single source of truth for
     the dark theme. Promoted from the literals .stage-dark used to inline;
     .stage-dark now references these (same values, just named). The live
     participation map composes its field from them. */
  --charcoal:         #121110;  /* base field — darkest near-black */
  --charcoal-soft:    #16140F;  /* lifted surface */
  --charcoal-deep:    #1A1814;  /* warmer surface */
  --charcoal-deepest: #1C1A16;  /* warmest lift (upper-center of the field) */

  /* Gold FOIL ramp — metallic linework, not a flat gold. Light rakes the
     strokes: white-hot amber highlight on upper edges → mid amber → deep
     bronze in lower/interior segments. The map outline and the pin share
     this ramp so the pin belongs to the map's material. Gold-on-charcoal
     only — never partisan red/blue. */
  --gold-bright: #FAEBB8;  /* highlight — near white-hot amber */
  --gold:        #CB9A38;  /* mid amber base */
  --gold-deep:   #6E5022;  /* deep bronze */

  /* Perforated postal divider — single source for the punched-paper dot
     pattern. Each dot has a dark core (the hole) + soft halo. Used by
     .trait-row, .id-field, and anywhere a perforated rule is wanted.
     Apply with: background: var(--perforated-dots); background-size:
     8px 4px; background-repeat: repeat-x; background-position: bottom; */
  --perforated-dots: radial-gradient(
    circle,
    rgba(23, 32, 51, 0.6) 0px,
    rgba(23, 32, 51, 0.55) 0.5px,
    rgba(23, 32, 51, 0.25) 0.9px,
    transparent 1.2px
  );

  /* Common Ground choropleth — 5-stop sequential scale.
     Hot coral = strong agreement → cool slate = wide variety.
     Consumed by .cl-scale .sw-N on my-13-traits.html; sampled from the
     baked-in legend on assets/choropleth-community.png. */
  --ch-1: #E89488;
  --ch-2: #F2B7AE;
  --ch-3: #F8D9D3;
  --ch-4: #C8D5E1;
  --ch-5: #8FA6BE;

  /* Type roles */
  --font-display: 'Literata', 'Iowan Old Style', Georgia, serif;
  --font-body:    'Literata', 'Iowan Old Style', Georgia, serif;
  --font-ui:      'Onest', 'Inter', system-ui, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, Menlo, monospace;
  --font-accent:  'Italianno', cursive;

  /* Type scale — major third (1.25×), body 19 */
  --t-hero:  68px;
  /* Section-title fluid size, named so display-script siblings can derive
     their size as a RATIO of it (hierarchy is a relationship; independent
     clamps can cross at narrow widths and invert it). */
  --t-section-title: clamp(34px, 2.5vw + 24px, 47px);
  --t-h1:    47px;
  --t-h2:    30px;
  --t-h3:    24px;
  --t-rail:  17px; /* rail-copy size: callout body, moves, voice quote */
  --t-body:  19px;
  --t-small: 15px;
  --t-micro: 12px;

  /* Spacing scale */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px;
  --s6:32px; --s7:48px; --s8:64px; --s9:96px; --s10:128px;

  /* Motion */
  --t-fast: 150ms;
  --t-base: 220ms;

  /* Stacking scale */
  --z-bg:        -1;
  --z-content:    1;
  --z-overlay:   10;
  --z-sticky:    50;
  --z-floating: 100;

  /* Grid */
  --page-max:   1280px;
  /* Fluid page gutter: 80px at the full --page-max, scaling down to a 20px
     floor on phones (6.25vw × 1280px = 80px — the desktop value is unchanged). */
  --page-pad:   clamp(var(--s4), 6.25vw, 80px);
  --col-gap:    32px;     /* one column gap (12-col) */
  --section-pad: var(--s8);
}

/* Community resonance ramp — three recalculated bands, page-scoped to the
   community mirror (#my-communitys-13). Dark enough for the legend and cell
   seams to read against the paper canvas without sampling the old 5-stop ramp. */
#my-communitys-13 {
  --ch-1: #805b73;   /* resonant */
  --ch-2: #a7839a;   /* converging */
  --ch-3: #c7b1bf;   /* wide-ranging */
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
::selection { background: var(--blush); color: var(--ink); }
img { display: block; max-width: 100%; }

/* ---------- Heading defaults ----------
   Element selectors carry size only (fixed, off the token scale). The
   .heading class opts an h-element into the header-brand treatment AND swaps
   the size to a fluid clamp(). Scale modifiers (.heading-page,
   .heading-section) override the size when more or less prominence is
   needed than the h-level alone provides. */
h1 { font-size: var(--t-h1); }
h2 { font-size: var(--t-h2); }
h3 { font-size: var(--t-h3); }
h4 { font-size: var(--t-rail); }
h5 { font-size: var(--t-small); }
h1, h2, h3, h4, h5 { margin: 0; }

/* Brand heading treatment — font + color + spacing + balance.
   Size lives on h1.heading, h2.heading, … (clamped, below). */
.heading {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--indigo);
  line-height: 1.1;
  letter-spacing: -0.018em;
  margin: 0 0 var(--s5);
  text-wrap: balance;
}

/* Fluid heading sizes when .heading is on an h-element. clamp(min, fluid, max)
   scales smoothly across viewports without media queries. */
h1.heading { font-size: clamp(34px, 2.5vw + 24px, 47px); }
h2.heading { font-size: clamp(24px, 1.5vw + 18px, 30px); }
h3.heading { font-size: clamp(20px, 1vw + 16px, 24px); }
h4.heading,
h5.heading { font-size: clamp(15px, 0.4vw + 13px, 17px); }

/* Scale modifiers — override the h-element size.
   .heading-page    : hero / largest page title (68px max)
   .heading-section : in-body section heading (47px max, same as h1.heading
                      default — lets an <h2> render at h1 scale when needed) */
.heading.heading-page    { font-size: clamp(48px, 4vw + 30px, 68px); line-height: 1.15; letter-spacing: -0.025em; }
.heading.heading-section { font-size: var(--t-section-title); line-height: 1.2; }  /* looser than the base 1.1 — section titles wrap to 2 lines, this keeps them from cramping */

/* Style modifiers (color/weight/style — not size). */
.heading-ink    { color: var(--ink); }
.heading-italic { font-style: italic; font-weight: 400; }
.heading-mid    { font-weight: 600; line-height: 1.2; letter-spacing: -0.005em; margin-bottom: 4px; }

/* Secondary line under a heading (e.g. "known as 'Molly Pitcher'"). */
.subheading {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: var(--t-h3);
  color: var(--ink-soft);
  line-height: 1.2;
  margin: var(--s4) 0 var(--s6);
}
.subheading q { quotes: "“" "”"; }

/* ---------- Page ---------- */
.page {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 var(--page-pad);
  position: relative;
}

/* Placeholder body for the stub pages (about / faq) until Claude Design ships
   their real layouts — just enough breathing room that a not-yet-designed page
   doesn't read as broken at launch. Safe to delete once those are designed. */
.page-stub { padding: var(--s7) 0 var(--s10); }
.page-stub h1 { margin: 0 0 var(--s4); }
.page-stub section { margin-top: var(--s7); }
.page-stub section h2 { margin: 0 0 var(--s3); }

/* 12-col grid utility */
.grid-12 {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--col-gap);
}

/* ---------- Top header ---------- */
.header {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--s7);
  /* The topnav bar is full-width on every page with the page gutter
     (--page-pad), so the brand + My-13 pill sit in the SAME horizontal spot
     page to page (no left/right jump when navigating). 20px block — sits
     between --s4 (16) and --s5 (24); no near token. Home's dark-stage header
     intentionally runs a touch taller (24px — see .stage-home-hero .header) to
     breathe on the stage; that 4px is by design, not drift. */
  padding: 20px var(--page-pad);
  border-bottom: 1px dotted var(--rule-2, var(--rule));
}
/* On every page except home, the header sits inside the centered .page wrapper,
   which would cap it at --page-max. Break it out to span the full viewport —
   same calc(50% - 50vw) trick as .stage-home-hero-bleed — so the bar + border
   run edge-to-edge and the brand/pill sit at the SAME --page-pad gutter as
   home's full-width topnav. (Home's header is in the full-bleed
   .stage-home-hero, so it is full-width without this.) No width literal. */
.page > .header {
  margin-inline: calc(50% - 50vw);
}

/* ---- Chrome height reservation (anti-CLS) ----------------------------------
   script/shared/site-chrome.js injects the header/footer AFTER parse, so the
   placeholders are empty for a beat. Reserve their rendered heights on the
   still-EMPTY elements so the page doesn't shift when they fill. :empty applies
   ONLY before injection — once the chrome is filled it stops matching, so it
   never constrains the live chrome (stays responsive). Values = rendered
   border-box heights; keep in sync if the chrome's height changes. */
.header[data-chrome]:empty                  { min-height: 82px; }   /* inner pages (20px block) */
.stage-home-hero .header[data-chrome]:empty { min-height: 90px; }   /* home (24px block, taller) */
.footer[data-chrome]:empty                  { min-height: 104px; }  /* base footer */
.choice-body .footer[data-chrome]:empty       { min-height: 82px; }   /* my-13 + community (shorter) */

/* ---------- Brand lockup (ring mark + wordmark) ----------
   Reusable wherever the Choose13 brand appears. The header uses it as
   `.header-brand brand`; other surfaces can use just `.brand`. */
.brand,
.header-brand { display: flex; align-items: center; gap: var(--brand-ring-gap); text-decoration: none; }
/* The topnav + footer brands link to home; footer mark lays out the ring + word-
   mark without the .brand gap (the footer ring carries its own margin-end). */
.footer-brand-link { display: inline-flex; align-items: center; text-decoration: none; }
.brand-mark {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 22px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1;
  color: var(--indigo);
}
.brand-mark .num { color: var(--coral); }
.brand-tag {
  font-family: var(--font-body);
  font-style: italic;
  font-size: var(--t-small);
  line-height: 1.3;
  color: var(--ink);
  border-left: 1px solid var(--rule-2);
  padding-left: 14px;
  max-width: 18ch;
}
/* Inner navigation (the <nav class="header-nav">) inside the page header */
.header-nav {
  display: flex; align-items: center; gap: 36px;
  justify-self: start;
}
.header-nav a {
  font-family: var(--font-body);
  font-size: clamp(var(--t-small), 0.6vw + 7.5px, var(--t-body));  /* chrome scale — nav links grow --t-small→--t-body (15→19px) on large screens instead of pinning at the 1280-era 15; settled token ends, fluid middle. STOPGAP in the convention's own idiom; superseded post-launch by the global fluid-root scale (see concept/build/kiv.md). */
  color: var(--ink);
  text-decoration: none;
  padding: 6px 0;
  position: relative;
}
a { color: var(--coral); }
.header-nav a.active { color: var(--coral); }
.header-nav a.active::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px;
  height: 1.5px; background: var(--coral);
}
.header-cta { display: flex; align-items: center; gap: 14px; }

/* ---------- Header responsive: nav links drop to a second row ----------
   Below 880px the inline links no longer fit beside the brand + pill.
   Brand stays top-left, the CTA cluster top-right, and the nav becomes a
   wrapping second row — every link stays visible (nothing retreats into
   the drawer, which is identity-only). */
@media (max-width: 991px) {
  .header {
    grid-template-columns: auto 1fr;
    column-gap: var(--s5);
    row-gap: var(--s3);
  }
  .header-brand { grid-column: 1; grid-row: 1; }
  .header-cta   { grid-column: 2; grid-row: 1; justify-self: end; }
  .header-nav   { grid-column: 1 / -1; grid-row: 2; flex-wrap: wrap; gap: var(--s3) var(--s5); }
  .brand-tag    { display: none; }
  .c13-megamenu-panel { max-width: calc(100vw - var(--s5) * 2); }
}
@media (max-width: 767px) {
  .brand-mark { font-size: 20px; }
  .header-cta { gap: 10px; }
  /* Phone header: the brand reduces to its RING — the wordmark re-seats
     into the identity drawer's head (the hamburger is its door), freeing
     the row for pill + hamburger — reposition, then sacrifice. */
  .header .header-brand .brand-mark { display: none; }
  .id-drawer-title .id-drawer-title-text { display: none; }
  .id-drawer .id-drawer-title .id-drawer-brand { display: inline-flex; align-items: center; gap: 10px; text-transform: none; letter-spacing: normal; }
  .id-drawer .id-drawer-title .id-drawer-brand .brand-mark { display: block; }
}

/* ---------- Character Profiles mega menu (script/shared/profiles-menu.js) ----
   The topnav "Character Profiles" link becomes a dropdown of every profile,
   data-driven from the Sheet profile tab. The panel is appended to <body> and
   positioned `fixed` by the script, so it escapes the home hero's
   overflow:hidden. Fail-open: no JS / no data → the link just navigates. */
.header-nav a.has-megamenu { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; white-space: nowrap; }
/* Real caret element (appended by profiles-menu.js), NOT ::after — the active
   nav link already uses ::after for its underline, so a pseudo here would
   collide on the Character Profiles page. */
.c13-megamenu-caret {
  flex: none; width: 8px; height: 8px;
  border-right: 1.75px solid currentColor; border-bottom: 1.75px solid currentColor;
  /* The link centres this box vertically (align-items:center); the -1px optically
     centres the rotated corner against the cap height. */
  transform: translateY(-1px) rotate(45deg);
  transition: transform 300ms cubic-bezier(0.34, 1.5, 0.5, 1);
  opacity: 0.7;
}
.header-nav a.has-megamenu[aria-expanded="true"] .c13-megamenu-caret {
  transform: translateY(1px) rotate(-135deg);
}

.c13-megamenu-panel {
  position: fixed; z-index: 200;
  background: var(--canvas);
  border-radius: 10px;
  box-shadow: 0 18px 50px -16px rgba(23, 32, 51, 0.28);
  padding: var(--s5) var(--s6);
  max-width: min(94vw, 1200px);
  max-height: min(84vh, 720px); overflow-y: auto;
  /* Graceful open/close — fade + slide, eased with a cubic-bezier. Closed by
     default and driven by .is-open (not the hidden attribute) so it can animate.
     visibility flips to hidden only AFTER the fade-out, so it's non-interactive
     when closed without killing the transition. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-10px);
  transform-origin: top center;
  transition: opacity 200ms cubic-bezier(0.16, 1, 0.3, 1),
              transform 280ms cubic-bezier(0.16, 1, 0.3, 1),
              visibility 0s linear 280ms;
  pointer-events: none;
}
.c13-megamenu-panel.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity 240ms cubic-bezier(0.16, 1, 0.3, 1),
              transform 340ms cubic-bezier(0.16, 1, 0.3, 1),
              visibility 0s;
  pointer-events: auto;
}
.c13-megamenu-grid {
  display: grid;
  column-gap: var(--s6);
  row-gap: 0;
  max-width: 100%;
  /* width + grid-template-columns are set inline by renderItems, scaled to the
     profile count (1 column for a few, up to 4 on a laptop for 20+). */
}
/* Each item: the profile NAME is primary (the prominent line — this is a
   profiles menu), the trait(s) a smaller label beneath. A dotted rule separates
   the rows within each column. */
.c13-megamenu-item {
  display: flex; flex-direction: column; gap: 7px;
  padding: var(--s3) 0;
  border-bottom: 1px dotted var(--rule-2, var(--rule));
  text-decoration: none; color: var(--ink);
}
.c13-megamenu-name {
  font-family: var(--font-body);
  font-size: var(--t-rail);
  font-weight: 600;
  line-height: 1.2;
  color: var(--ink);
  /* Site link convention: dotted underline following the text colour. Hidden
     by default on the megamenu name — revealed on hover/focus only. */
  text-decoration: none;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: currentColor;
  transition: color var(--t-fast) ease;
}
.c13-megamenu-traits {
  font-family: var(--font-ui);
  font-size: var(--t-micro);
  color: var(--slate);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.c13-megamenu-item:hover .c13-megamenu-name,
.c13-megamenu-item:focus-visible .c13-megamenu-name { color: var(--coral); text-decoration: underline dotted; }
.c13-megamenu-empty { margin: 0; padding: var(--s3); font-family: var(--font-body); font-size: var(--t-small); color: var(--ink); opacity: 0.7; }
.c13-btn.c13-btn-secondary.c13-btn-pill {
  display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid var(--ink);
  border-radius: 999px;
  /* Sized up to the base-button scale (was the compact 6px·16px / --t-small)
     so the primary nav CTA reads as primary — defined tokens, no new size. */
  padding: var(--s2) var(--s5) calc(var(--s2) + 3px);   /* +3px bottom — Literata sits high in its line box, so symmetric padding looks top-heavy */
  font-family: var(--font-display);   /* Literata — matches the topnav text links (was --font-ui/Onest) */
  font-size: 16px;
  color: var(--ink);
  text-decoration: none;
  transition: background-color var(--t-fast) ease, color .15s ease, border-color .15s ease;
}
.c13-btn.c13-btn-secondary.c13-btn-pill.active {
  background: var(--indigo);
  border-color: var(--indigo);
  color: var(--canvas);
}
.c13-btn.c13-btn-secondary.c13-btn-pill.active .seal { color: var(--coral); }
.c13-btn.c13-btn-secondary.c13-btn-pill .seal {
  display: inline-grid; place-items: center;
  font-family: var(--font-display);   /* SHARP star (matches the print materials) */
  font-size: 16px;
  line-height: 1;
  color: var(--coral);
}
.menu { width: 28px; display: grid; gap: 5px; padding-left: 4px; }
.menu i { height: 1.5px; background: var(--ink); display: block; }

/* Side labels */
.side-label {
  position: absolute;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--slate);
  white-space: nowrap;
  writing-mode: vertical-rl;
}
.side-label.right { top: 320px; right: 24px; }
.side-label.left  { top: 600px; left: 24px; transform: rotate(180deg); }
.side-label .dot {
  display: inline-block; width: 6px; height: 6px; background: var(--coral);
  border-radius: 50%; margin: 0 8px;
}

/* Back link */
.back-link {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-body);
  font-size: var(--t-small);
  color: var(--indigo);
  text-decoration: none;
  padding: 26px 0 8px;
}
/* Orientation mirror: sketch-on-the-left pushes the back link to follow the text
   block to the RIGHT, clearing the now-left sketch that would otherwise cover it.
   Body-scoped (.profile-page.art-left, set by character-profile.js) because the
   link is a sibling BEFORE the hero, unreachable from .stage-hero. */
.profile-page.art-left .back-link { display: flex; width: fit-content; margin-left: auto; }

/* ---------- Section anatomy ----------
   One base rule for any content section. Each section:
   - h2 → first content: s5 (24px) via h2 margin-bottom
   - between paragraphs: 1em (~19px) via p margin-bottom
   - last child has no bottom margin
   - between sibling sections: symmetric s5 padding above and below the
     1px rule. Total gap: 24 + 1 + 24 = 49px. */
.section {
  padding-bottom: var(--s5);
}
.section:last-of-type {
  padding-bottom: 0;
}
/* .section h2 sizing/styling lives on .heading; element gets class="heading" + .heading-section */
.section p {
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.7;
  color: var(--ink);
  margin: 0 0 1em;
  /* NO global measure cap. The CONTAINER is the vessel that constrains width.
     A ch line-length cap belongs ONLY as a section/container-level override
     (e.g. .cm-descriptor, #faq .faq-a p) — never global: a blanket cap here
     leaks onto every sanitized descriptor <p> and wraps it short of its box. */
}
.section > *:last-child { margin-bottom: 0; }
.section + .section {
  padding-top: var(--s5);
  border-top: 1px solid var(--rule);
}

/* Drop cap — first letter of opening paragraph */
.dropcap {
  margin-top: var(--s3); /* breathing room so the cap doesn't crash the h2 */
}
.dropcap::first-letter {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 96px;
  line-height: 0.72;
  float: left;
  padding: 4px 16px 0 0;
  color: var(--ink);
}

.stage-hero {
  position: relative;
  /* Contain the portrait's stacking: .stage-hero-art is z-index:1 but a bare
     position:relative makes NO stacking context, so the art escapes to the root
     layer and covers the lexicon below. isolate keeps its overflow BEHIND the
     following sections — the lexicon overlaps the sketch's excess, not vice versa. */
  isolation: isolate;
  display: block;
  padding: var(--s4) 0 var(--s8);
  min-height: 540px;
}
.stage-hero-text {
  position: relative;
  width: 40%;   /* narrowed from 48% so name/traits/meta wrap clear of the sketch (both orientations) */
  z-index: 2;
}
.stage-hero-art {
  position: absolute;
  top: -20px;
  right: -40px;
  width: 78%;
  z-index: 1;
}
/* No verified portrait (profile-sketch blank) -> the art is absent, so the hero
   stops reserving the portrait's height AND its tall-portrait bottom padding
   (var(--s8) -> 0; the metadata's own bottom margin carries the gap to the
   lexicon), and the column collapses. Set by character-profile.js. */
.stage-hero.no-sketch { min-height: 0; padding-bottom: 0; }
.stage-hero.no-sketch .stage-hero-art { display: none; }
/* Portrait orientation — script/character-profile.js sets .art-left /
   .art-right on .stage-hero from the profile-sketch-orientation
   column. Default (art-right) matches the base layout; art-left mirrors
   it (text to the right, portrait to the left). */
.stage-hero.art-left .stage-hero-text { margin-left: auto; text-align: right; }
.stage-hero.art-left .stage-hero-art { left: -40px; right: auto; }
/* Mirror the in-column elements so the text block hugs the RIGHT edge, clear of
   the now-left sketch (the true reflection of the default left-text layout): the
   star-rule divider pushes right, the meta stack right-aligns, and each meta item
   reverses so its icon sits on the right of the value. */
.stage-hero.art-left .star-rule { margin-left: auto; }
.stage-hero.art-left .bio-meta { align-items: flex-end; }
.stage-hero.art-left .bio-meta .item { flex-direction: row-reverse; }

/* ---------- Stamp primitives — stamped uppercase headings (the "civic label")
   Two sizes:
     .stamp     — 13px / 0.22em / weight 500. Used for eyebrows + small
                  section markers.
     .stamp-lg  — 15px / 0.10em / weight 700. Used for rail headings and
                  field labels (the zip/trait stamps).
   Both default to coral on transparent. Inline tokens (.star, .sep, .num)
   stay shared so any stamp can carry the same ornament vocabulary. */
.stamp,
.stamp-lg {
  font-family: var(--font-display);
  color: var(--coral);
  text-transform: uppercase;
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  line-height: 1.2;
  white-space: nowrap;
}
.stamp {
  font-weight: 500;
  font-size: 13px;
  letter-spacing: 0.22em;
}
.stamp-lg {
  font-weight: 700;
  font-size: var(--t-small);
  letter-spacing: 0.10em;
}
.stamp .star,
.stamp-lg .star { font-size: 11px; line-height: 1; color: var(--coral); }
.stamp .sep,
.stamp-lg .sep { color: var(--rule-2); }
.stamp .num,
.stamp-lg .num { color: var(--slate); letter-spacing: 0.2em; }

.eyebrow {
  display: inline-flex; align-items: center; gap: 12px;
  margin: 0 0 var(--s5);
  white-space: nowrap;
}

/* Hero h1 sizing now lives on .heading.heading-page (applied as a class). */

/* Subtitle / subheading lives on .subheading primitive (above) */

.star-rule {
  display: flex; align-items: center; gap: 14px;
  margin: 0 0 var(--s4);
  max-width: 220px;
}
.star-rule .l { flex: 1; height: 1px; background: var(--rule-2); }
.star-rule .star { color: var(--coral); font-size: 12px; line-height: 1; }

/* ---------- Script line ----------
   Italianno cursive primitive for ceremonial / decorative type.
   Variants:
   - .display-script-center : centered single-line variant (above the ring)
   The pattern handles any number of trait words — one, two, three. Use
   <br/> for line breaks and the .amp child for an ampersand separator.
   Modifiers stay on the .display-script element. */
.display-script,
p.display-script {
  display: block;
  margin: var(--s2) 0 var(--s4);
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 60px;
  line-height: 1.05;
  color: var(--coral);
  max-width: none;
}
.display-script-center {
  text-align: center;
  margin: 0 auto var(--s4);
  white-space: nowrap;
  font-size: clamp(34px, 4vw + 12px, 56px);
}
.display-script .amp {
  display: inline;
  font-family: var(--font-accent);
  color: var(--ink);
  opacity: 0.5;
  font-weight: 400;
  margin: 0 6px;
}

/* Bio meta line */
.bio-meta {
  /* Stacked vertical list (was a horizontal wrap row): each meta item on its own
     line, so a long bio/role wraps within the narrowed column instead of running
     one nowrap line across the sketch. align-items sets the side; art-left flips
     it to flex-end. */
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--s3);
  font-family: var(--font-body);
  font-size: var(--t-small);
  color: var(--ink);
  margin: 0 0 var(--s6);
}
.bio-meta .item {
  /* Icon + value; the value WRAPS now (nowrap removed) so it stays in the column.
     min-width:0 lets it shrink to wrap. flex-start keeps the icon on the FIRST
     line of a value that wraps to two lines (not centered against the whole
     block) -- the icon itself is sized to 1lh below so it centers WITHIN that
     first line rather than floating above its text. art-left reverses the row so
     the icon sits on the right of the value. */
  display: inline-flex; align-items: flex-start; gap: 8px;
  min-width: 0;
}
.bio-meta .meta-ic {
  /* Height matched to 1lh so, with the item's flex-start, the 18px glyph (centered
     by the SVG's default preserveAspectRatio) sits at the FIRST line's vertical
     centre rather than the line-box top -- it would otherwise float ~4.5px above
     the text. 18px is the fallback where 1lh is unsupported. */
  width: 18px; height: 18px; height: 1lh; display: block; flex: 0 0 18px; color: var(--coral);
}

/* Standing rule: a blank Sheet cell is INTENTIONALLY blank, so hide the whole
   metadata item -- icon and all -- not just the empty text the carrier already
   hides (otherwise the coral icon orphans). The second rule collapses the strip
   entirely when every cell is blank, leaving no stray gap. :empty matches both
   the untouched baseline span and any cell the carrier left blank. */
.bio-meta .item:has(> [data-cp]:empty) { display: none; }
.bio-meta:not(:has(.item > [data-cp]:not(:empty))) { display: none; }

/* ---------- Definition card (full width, torn paper edges) ---------- */
.stage-lexicon {
  padding: var(--s3) 0 var(--s4);
}
.lexicon {
  position: relative;
  padding: var(--s5) var(--s7);
  background: transparent;
  max-width: none;
}
/* ---------- Torn-paper backdrop primitive ----------
   Position: absolute on a relatively-positioned parent. JS module computes
   a polygon clip-path from the element's bounding box on load + resize,
   so the cream paper appears torn at every edge. Used by .lexicon and the
   choropleth wrapper today. */
.bg-torn-paper {
  position: absolute;
  inset: -6px;
  background: var(--paper-soft);
  z-index: 0;
  pointer-events: none;
  /* Drop shadow follows the torn clip-path silhouette, so the shadow's
     edge always matches the paper edge — no mismatched torn outline. */
  filter: drop-shadow(0 3px 6px rgba(23, 32, 51, 0.07))
          drop-shadow(0 1px 2px rgba(23, 32, 51, 0.05));
}
.lexicon > *:not(.bg-torn-paper) { position: relative; z-index: 1; }
.lexicon-entries {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s7);
}
.lexicon .lexicon-h {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--t-micro);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--slate);
  margin: 0 0 var(--s3);
  padding-bottom: var(--s2);
  border-bottom: 1px solid var(--line-soft);
  display: flex; justify-content: space-between;
}
.lexicon-entry { padding: var(--s3) 0; }
/* (Removed the dotted border-top between entries — in the 2-column grid
   it drew a stray line above the right-hand entry. The grid gap + column
   layout separate the two entries on their own.) */
/* Lexicon entry vocabulary word — styled via .heading.heading-ink on the element
   with a 21px size override here. The `.margin-none` utility is added in HTML
   to remove the default .heading bottom margin so .meta sits tight under it. */
.lexicon-entry .word {
  font-size: 21px;
}
.lexicon-entry .word .syl { color: var(--coral); padding: 0 1px; }
.lexicon-entry .row-meta {
  display: flex; align-items: baseline; gap: 12px;
  margin-top: 2px;
}
.lexicon-entry .pos {
  font-family: var(--font-body);
  font-style: italic;
  font-size: 14px;
  color: var(--slate);
}
.lexicon-entry .pron {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--slate);
}
.lexicon-entry .def {
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink);
  margin: 8px 0 0;
}
.lexicon-foot {
  margin-top: var(--s4);
  padding-top: var(--s3);
  border-top: 1px solid var(--line-soft);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--slate);
}

.stage-hero-art .sketch-wrap {
  position: relative;
  width: 100%;
}
.stage-hero-art .sketch {
  width: 100%;
  height: auto;
  display: block;
  /* Per-profile framing nudge. character-profile.js reads profile-sketch-offset-x
     / -y (px) from the Sheet into these custom props so the content team can sit
     each portrait right in its frame; default 0 = no shift. Negative = left/up,
     positive = right/down. (Draft Signal's portrait Image-Offset model, adapted
     from its SVG <image> transform to our HTML <img> + CSS transform.) */
  transform: translate(var(--sketch-offset-x, 0), var(--sketch-offset-y, 0));
}
.postmark {
  position: absolute;
  top: 16px; right: 4%;
  width: 150px;
  height: auto;
  transform: rotate(-8deg);
}
.postmark-wave {
  position: absolute;
  top: 56px; right: -88px;
  width: 240px;
  height: auto;
  transform: rotate(-8deg);
  opacity: .9;
}

/* ---------- Editorial Body (Story + Turn + sticky sidebar) ---------- */
.stage-editorial {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--col-gap);
  padding: var(--s7) 0 var(--s8);
  border-top: 1px solid var(--rule);
  position: relative;
  align-items: start;
}
.stage-editorial .stage-editorial-body { grid-column: 1 / span 7; }
.stage-editorial .stage-editorial-side {
  grid-column: 8 / span 5;
  position: relative;
  align-self: stretch; /* fill the grid row so the divider can span full editorial height */
}
/* Full-height divider rule on the editorial sidebar's left edge. Lives on
   the grid cell (not on .callout) so it spans the row's full height even
   when .callout is shorter or scrolled away by sticky. */
.stage-editorial .stage-editorial-side::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 1px;
  background: var(--rule);
  pointer-events: none;
}
/* .section spacing inherited from MAIN BODY SECTIONS rule above */

/* Fit-line role: single-line display text whose length is data-driven
   (the hero trait word, the postcard title carrying a first name). The
   element's CSS font-size is the ceiling; script/shared/fit-line.js
   shrinks the line to its container width when the text runs wider.
   Scale-down only — never up. */
.fit-line { max-width: 100%; white-space: nowrap; }
/* The dispatch-nav trait is the one fit-line allowed to WRAP at spaces: a two-trait
   label ("Compassion & Service to Others") wraps at full size, while fit-line.js
   still shrinks an unbreakable single word ("Purposefulness") so it never clips. */
.footer-nav .title.fit-line { white-space: normal; }

/* Reusable lead copy block for short editorial prompts. */
.lead {
  margin-top: var(--s6);
  padding: var(--s5) 0;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}
/* Lead line. Body font + italic by default; max-width keeps it tight
   in editorial rails and lets pages reuse the treatment without title styling.
   The lead holds a single <p> — styled structurally, no child class.
   (Kicker treatment, if a lead ever needs one, is the .stamp/.eyebrow primitive.) */
.lead > p {
  font-family: var(--font-body);
  font-style: italic;
  font-weight: 400;
  font-size: var(--t-h3);
  line-height: 1.35;
  margin: 0;
  max-width: 40ch;
}

/* ---------- THE CALLOUT (sticky sidebar, no separate bg) ---------- */
.callout {
  position: sticky;
  top: 32px;
  background: transparent;
  /* Divider rule lives on .stage-editorial-side (parent cell) so it can
     span the full editorial-section height even when callout is shorter
     or scrolled away by sticky. */
  padding: 0 0 0 var(--s7);
  display: grid; gap: var(--s5);
}
/* ---------- RAIL HEADINGS — see .stamp-lg primitive above ----------
   .callout-tag / .moves-h / .choice-h / .progress-h previously defined the
   same styles individually; they now compose .stamp-lg in the markup. */
/* Star mark removed by request — headings stand on type alone */
/* Pull quote inside callout — Literata italic, sized to match body content */
.script-quote {
  position: relative;
  padding-left: 32px;
  padding-top: var(--s3); /* room above for the mark */
}
.script-quote .mk {
  position: absolute; left: -2px; top: 14px;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: 64px;
  line-height: 0.6;
  color: var(--coral);
  opacity: 0.38;
}
/* Centered ceremonial variant: quotation mark above the text, both centered.
   Used in .stage-ring for the “My chosen traits…” moment. */
.script-quote.script-quote-center {
  padding-left: 0;
  padding-top: var(--s6);
  text-align: center;
  max-width: 38ch;
}
.script-quote.script-quote-center .mk {
  left: 50%;
  top: 0;
  transform: translateX(-50%);
  line-height: 1;
}
.script-quote.script-quote-center p {
  margin: 0 auto;
}

.script-quote p {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: var(--t-rail);
  line-height: 1.5;
  color: var(--ink);
  margin: 0;
}
.script-quote .sig {
  margin-top: var(--s3);
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: 14px;
  line-height: 1.35;
  color: var(--slate);
}
/* Leading em-dash before the citation (the cell holds no dash). Unicode
   escape avoids the charset mojibake a literal — would cause. */
.script-quote .sig::before { content: "\2014\00a0"; }
.script-quote .meta {
  margin-top: 4px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 10.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--slate);
}

/* ---------- RAIL SECTION SPACING ----------
   One base rule for every rail section. Each section is a sub-grid with
   gap: s4 between heading and content. Sections after the first carry a
   divider rule + matching padding-top. Heading margins are 0.
   Bottom padding is never used — the next section owns the divider above it.
   Total between-section gap = s5 (callout) + s4 (padding-top) + 1px = 41px. */
.section-rail {
  display: grid;
  gap: var(--s4);
}
.section-rail + .section-rail {
  padding-top: var(--s5);
  border-top: 1px solid var(--rule);
}

/* moves block: heading + items */
.move {
  display: grid; grid-template-columns: 24px 1fr;
  gap: 14px;
  align-items: start;
}
.move .n {
  font-family: var(--font-display);
  font-weight: 700;
  font-style: italic;
  font-size: 22px;
  color: var(--indigo);
  background: transparent;
  border: 0;
  width: 22px; height: auto;
  text-align: left;
  margin-top: 0;
  line-height: 1;
}
/* Move head — styling lives on .heading.heading-mid; no per-context overrides needed. */

.move .body {
  font-family: var(--font-body);
  font-weight: 400;
  font-style: normal;
  font-size: var(--t-rail);
  line-height: 1.5;
  color: var(--ink);
  margin: 0;
}

/* Vote panel — spacing inherited from .section-rail */
/* choice panel — sub copy (gets extra space below before the slips) */
.choice-panel .choice-sub {
  font-family: var(--font-body);
  font-weight: 400;
  font-style: normal;
  font-size: var(--t-rail);
  line-height: 1.5;
  color: var(--ink);
  margin: 0 0 var(--s2);
  max-width: 36ch;
}
/* ===========================================================
   VOTE SLIP — civic mail-in dispatch slip CTA
   coral default (mail icon) <-> paper selected (rotated star)
   =========================================================== */
.choice-ctas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: 14px;
}
.c13-slip {
  position: relative;
  display: grid;
  /* Both icon states share the "icon" area; both label states share the
     "label" area. The cell sizes to the LARGER of its contents, so the
     slip's height is stable when toggling between mail/star and add/done. */
  grid-template-columns: 1fr;
  grid-template-areas: "icon" "label";
  justify-items: center;
  align-content: center;
  gap: 12px;
  /* generous internal breathing room around the inner frame */
  padding: 42px 22px 36px 30px; /* extra left for perforated edge */
  min-width: 0; /* allow flex/grid item to shrink without forcing squish */
  /* Default = paper slip + mail icon (invite to send).
     Selected = coral slip + filled star (stamped, in your 13). */
  background: var(--paper-soft);
  color: var(--coral-deep);
  border: 0;
  border-radius: 4px 10px 10px 4px;
  font-family: var(--font-display);
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--t-base) ease,
    color .22s ease,
    transform .22s ease;
  overflow: hidden;
  isolation: isolate;
  width: 100%;
}
/* very subtle paper grain on default (dark on paper) */
.c13-slip::before {
  content: "";
  position: absolute; inset: 0;
  background-image:
    repeating-linear-gradient(
      0deg,
      rgba(23,32,51,0.022) 0 1px,
      transparent 1px 3px
    );
  pointer-events: none;
  z-index: 0;
}
/* perforated tear edge — canvas-colored notches eat into the left edge */
.c13-slip::after {
  content: "";
  position: absolute;
  left: -3px; top: 0; bottom: 0; width: 7px;
  background-image: radial-gradient(
    circle 3.2px at center,
    var(--canvas) 96%,
    transparent 100%
  );
  background-size: 7px 11px;
  background-repeat: repeat-y;
  background-position: center 6px;
  z-index: 1;
  pointer-events: none;
}
.c13-slip > * { position: relative; z-index: 2; }

/* Inner rule — default (paper bg): coral-deep tinted hairline */
.vs-frame {
  position: absolute;
  inset: 16px 14px 16px 22px;
  border: 1px solid rgba(169, 58, 52, 0.32);
  border-radius: 6px;
  pointer-events: none;
  z-index: 1;
}

/* Tiny monospace stamp tag, top-right — default coral-deep on paper */
.vs-stamp {
  position: absolute;
  top: 24px; right: 22px;
  font-family: var(--font-mono);
  font-size: 7.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--coral-deep);
  opacity: 0.62;
  z-index: 2;
  white-space: nowrap;
  pointer-events: none;
}

/* Icon — fixed slot, currentColor SVG, both states stacked in same area */
.vs-ic {
  grid-area: icon;
  width: 38px; height: 38px;
  display: grid; place-items: center;
  margin-top: 2px;
  transition: transform .25s ease, opacity .18s ease;
}
.vs-ic svg { width: 100%; height: 100%; display: block; }

/* Label — both states stacked in same area so height is stable */
.vs-label {
  grid-area: label;
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 15.5px;
  line-height: 1.18;
  letter-spacing: -0.003em;
  max-width: 14ch;
  text-wrap: balance;
  transition: opacity .18s ease;
}
.vs-sub {
  display: block;
  margin-top: 4px;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: 12.5px;
  line-height: 1.2;
  letter-spacing: 0;
  opacity: 0.88;
}

/* DEFAULT vs SELECTED — both states stay laid out (visibility:hidden retains
   the cell's size). Only the visible one is shown. Height stays fixed. */
.c13-slip .vs-ic--star,
.c13-slip .vs-label--done {
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
}
.c13-slip[aria-pressed="true"] .vs-ic--mail,
.c13-slip[aria-pressed="true"] .vs-label--add {
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
}
.c13-slip[aria-pressed="true"] .vs-ic--star,
.c13-slip[aria-pressed="true"] .vs-label--done {
  visibility: visible;
  opacity: 1;
}

/* Selected state — coral slip, canvas ink, stamped/sent feel */
.c13-slip[aria-pressed="true"] {
  background: var(--coral);
  color: var(--canvas);
}
.c13-slip[aria-pressed="true"] .vs-frame {
  border: 1px solid rgba(253, 250, 246, 0.36);
}
.c13-slip[aria-pressed="true"] .vs-stamp {
  color: var(--canvas);
  opacity: 0.7;
}
/* Subtle stamped irregularity on the selected coral slip — soft light wash */
.c13-slip[aria-pressed="true"]::before {
  background-image:
    repeating-linear-gradient(
      0deg,
      rgba(255,255,255,0.02) 0 1px,
      transparent 1px 3px
    ),
    radial-gradient(
      ellipse 60% 38% at 82% 88%,
      rgba(255, 255, 255, 0.10),
      transparent 60%
    );
}

/* Hover — default (paper) deepens slightly + mail icon nudges like "sending" */
.c13-slip:not([aria-pressed="true"]):hover {
  background: var(--paper-warm);
}
.c13-slip:not([aria-pressed="true"]):hover .vs-ic--mail {
  transform: translate(2px, -1.5px) rotate(-4deg);
}
/* Selected hover — deepen coral, star wiggles */
.c13-slip[aria-pressed="true"]:hover {
  background: var(--coral-deep);
}
.c13-slip[aria-pressed="true"]:hover .vs-ic--star {
  transform: rotate(6deg) scale(1.04);
}

.c13-slip:active { transform: translateY(0.5px); }

.c13-slip:disabled,
.c13-slip[aria-disabled="true"] {
  cursor: not-allowed;
}
.c13-slip:disabled:hover,
.c13-slip[aria-disabled="true"]:hover {
  transform: none;
}
.c13-slip[aria-disabled="true"]:not([aria-pressed="true"]):hover {
  background: var(--paper-soft);
}
.c13-slip[aria-disabled="true"][aria-pressed="true"]:hover {
  background: var(--coral);
}
.c13-slip[aria-disabled="true"]:hover .vs-ic {
  transform: none;
}

.c13-slip:focus-visible {
  outline: 2px solid var(--coral);
  outline-offset: 3px;
}

/* .choice-ctas: container-aware fallback for very narrow rails.
   Items are placed in a single row so they share a height (grid stretches
   the row to the tallest item). align-items: stretch ensures both slips
   end up the same height even when one trait label is longer. */
.choice-ctas { container-type: inline-size; container-name: choice-ctas; align-items: stretch; }
@container choice-ctas (max-width: 320px) {
  .choice-ctas { grid-template-columns: 1fr; }
}

/* Mobile / narrow sidebar — keep legibility */
@media (max-width: 720px) {
  .vs-label { font-size: 14.5px; }
  .vs-sub { font-size: 12px; }
  .vs-ic { width: 34px; height: 34px; }
}

.progress-row {
  display: grid; grid-template-columns: 1fr;
  justify-items: center;
  gap: var(--s3);
}
.progress-stars {
  position: relative;
  width: 240px; max-width: 100%;
}
.progress-stars img { width: 100%; height: auto; display: block; }
.progress-copy { text-align: center; }
.progress-copy p { max-width: 28ch; margin-left: auto; margin-right: auto; }
.progress-copy .body {
  font-family: var(--font-body); font-size: var(--t-rail);
  margin: 0 0 4px;
  color: var(--ink);
  line-height: 1.5;
}
.progress-copy a {
  font-family: var(--font-body); font-size: var(--t-rail);
  color: var(--coral); text-decoration: none;
}
/* "Your 13" progress ring — match the centre text to the my-13 postcard ring:
   indigo mono "OF 13" + coral mono "CHOSEN" (not the base slate / display-italic). */
.progress-stars svg.ring .ring-count { font-size: 88px; }
.progress-stars svg.ring .ring-of {
  font-family: var(--font-mono); font-weight: 600; font-size: var(--t-body);
  letter-spacing: 0.32em; fill: var(--indigo);
}
.progress-stars svg.ring .ring-sub {
  font-family: var(--font-mono); font-weight: 600; font-size: var(--t-rail);
  letter-spacing: 0.32em; fill: var(--coral); font-style: normal;
}

/* .progress-block — spacing inherited from .section-rail */

/* ---------- Foot header ---------- */
.footer-nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
}
.footer-nav a {
  text-decoration: none; color: inherit;
  display: grid; grid-template-columns: auto 1fr;
  gap: 18px; align-items: start;
  padding: 22px 28px;
  border-right: 1px solid var(--rule);
}
.footer-nav a:last-child { border-right: 0; }
.footer-nav a.mid .ic { order: 2; justify-self: end; }
.footer-nav a.mid { grid-template-columns: 1fr auto; text-align: left; }
.footer-nav a.next { text-align: right; grid-template-columns: 1fr auto; }
.footer-nav a.next .ic { order: 2; justify-self: end; }
.footer-nav .ic {
  width: 40px; height: 40px;
  border: 1px solid var(--ink);
  border-radius: 50%;
  display: grid; place-items: center;
  color: var(--ink);
}
.footer-nav .ic svg { width: 22px; height: 22px; }
.footer-nav .label {
  font-family: var(--font-mono);
  font-size: var(--t-micro); /* 12px */
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--coral);
  margin: 0 0 6px;
}
/* Footer-nav title — styled via .heading.heading-ink on the element; size override here. */
.footer-nav .title {
  font-size: 22px;
}
.footer-nav .meta {
  font-family: var(--font-body);
  font-size: var(--t-small); /* 15px */
  color: var(--slate);
}

/* Postal strip — airmail bunting on a clean 56x42 tile (one red+blue stride).
   Layered distress: paper grain, horizontal scratches, missing-ink speckle. */
.bg-postal-strip {
  height: 9px;
  margin: var(--s6) 0 0;
  background: var(--canvas)
    url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='68'%20height='9'%20viewBox='0%200%2068%209'%3E%3Cpolygon%20points='4,0%2026,0%2022,9%200,9'%20fill='%23BF2D20'/%3E%3Cpolygon%20points='38,0%2060,0%2056,9%2034,9'%20fill='%23123B66'/%3E%3C/svg%3E")
    repeat-x left center;
  background-size: 68px 9px;
  opacity: 0.82;
  filter: none;
}
/* character-profile's body sits close to the footer; give the strip a touch more
   breathing room above it there than the default --s6. */
.profile-page .bg-postal-strip { margin-top: var(--s7); }

/* The reflection quote runs the full prose measure (maintainer-directed;
   the 40ch lead cap serves the narrow rails it was written for) and wraps
   as prose — the .heading class on it brings text-wrap: balance, which
   splits a short question into two even, oddly-broken lines at any width. */
.profile-page .lead > p { max-width: none; text-wrap: pretty; }

/* A trait name is an unbreakable unit. The hero trait line's names ride
   in bare spans (built by character-profile.js): the pair reads as one
   line where the measure allows and wraps BETWEEN names at the "&" where
   it doesn't — never mid-name, never changing size. */
.profile-page .display-script span { white-space: nowrap; }

/* ---------- Character profile touch tiers (991 / 767 ladder) ----------
   The profile is an editorial dispatch: its document order (masthead text ->
   portrait -> lexicon -> story -> rail -> prev/next) IS the narrow layout;
   the desktop's overlapping portrait and side rail are the spatial
   elaboration. Every constraint below dies or re-derives with the
   relationship that created it. */
@media (max-width: 991px) {
  /* Vertical edge labels annotate the print margin; touch tiers have no
     margin to annotate (the gutter IS the page pad). Ornament yields. */
  .side-label { display: none; }

  /* Hero: 48%-text / 78%-portrait was an overlap relationship; stacked,
     both width constraints die. Text takes the full measure, the portrait
     seats below it at a postcard width. */
  .profile-page .stage-hero { min-height: 0; padding-bottom: var(--s6); }
  .profile-page .stage-hero-text { width: 100%; }
  .profile-page .stage-hero-art {
    position: static;
    width: min(100%, 560px);
    margin: var(--s6) auto 0;
  }
  /* The per-profile sketch offset (profile-sketch-offset-x/-y → translate) is a
     framing nudge for the DESKTOP overlap only; once the portrait is stacked and
     centred, that translate just shifts it off-centre. Drop it on this band. */
  .profile-page .stage-hero-art .sketch { transform: none; }
  /* art-left mirrored the overlap; stacked there is nothing to mirror — reset the
     desktop mirror flips so the text reads left-aligned like every other profile. */
  .profile-page .stage-hero.art-left .stage-hero-text { margin-left: 0; text-align: left; }
  .profile-page .stage-hero.art-left .star-rule { margin-left: 0; }
  .profile-page .stage-hero.art-left .bio-meta { align-items: flex-start; }
  .profile-page .stage-hero.art-left .bio-meta .item { flex-direction: row; }
  .profile-page.art-left .back-link { display: inline-flex; width: auto; margin-left: 0; }

  /* Editorial: prose and rail stack in document order. The vertical
     divider dies with the side-by-side relationship and re-derives as a
     horizontal rule above the rail (the section-break grammar). */
  .profile-page .stage-editorial { grid-template-columns: minmax(0, 1fr); }
  .profile-page .stage-editorial .stage-editorial-body,
  .profile-page .stage-editorial .stage-editorial-side { grid-column: auto; }
  .profile-page .stage-editorial-side::before {
    top: 0; bottom: auto; left: 0; right: 0;
    width: auto; height: 1px;
  }
  /* Sticky was side-rail behavior; the rail's left inset served the
     divider it sat beside. Both die. */
  .profile-page .callout {
    position: static;
    padding: var(--s6) 0 0;
  }
  /* The 36ch sub-copy cap served the narrow desktop rail; full-width it
     manufactures a ragged early wrap. */
  .profile-page .choice-panel .choice-sub { max-width: none; }
}
/* Phones return to the single document column. (A 768–991 2-up rail
   elaboration was tried and ruled out — the rail reads as one column at
   every touch tier; only the slips pair up, via their own container query.) */
@media (max-width: 767px) {
  /* Lexicon: one definition per row; the paper inset steps down-ladder.
     Stacked, the 2-col grid's field gap overstates the distance between
     two entries of one lexicon — a list rhythm, not a section break. */
  .profile-page .lexicon { padding: var(--s5) var(--s5); }
  .profile-page .lexicon-entries { grid-template-columns: 1fr; gap: var(--s2); }

  /* The portrait takes the full column on phones. */
  .profile-page .stage-hero-art { width: 100%; }

  /* Dispatch prev/next: ONE row, two half-columns (column rule stays).
     Line 1 is the declared 28px wayfinding row: circled chevron + bare
     word; title (single-line by fit-line) then meta below. The cells
     share the outer grid row, so the SHORTER cell's auto rows would
     stretch to fill it and shove its title/meta downward (align-content
     defaults to stretch) — align-content: start keeps both cells' rows
     in lockstep and pools the slack at the bottom. Next mirrors: the
     whole cell right-bound, icon at the right edge (page-turn grammar). */
  .profile-page .footer-nav a,
  .profile-page .footer-nav a.next {
    grid-template-columns: auto 1fr;
    grid-template-rows: 28px auto auto;
    align-content: start;
    gap: 6px 10px;
    align-items: center;
    padding: var(--s4);
  }
  .profile-page .footer-nav a > span:not(.ic) { display: contents; }
  .profile-page .footer-nav .label-mark,
  .profile-page .footer-nav .label-kind { display: none; }
  .profile-page .footer-nav .ic { width: 28px; height: 28px; grid-row: 1; grid-column: 1; }
  .profile-page .footer-nav .ic svg { width: 16px; height: 16px; }
  .profile-page .footer-nav .label { margin: 0; grid-row: 1; grid-column: 2; }
  .profile-page .footer-nav a.next { grid-template-columns: 1fr auto; }
  .profile-page .footer-nav a.next .ic { grid-column: 2; justify-self: end; }
  .profile-page .footer-nav a.next .label { grid-column: 1; }
  .profile-page .footer-nav .title { grid-row: 2; grid-column: 1 / -1; font-size: var(--t-h3); margin: 0; }
  .profile-page .footer-nav .meta { grid-row: 3; grid-column: 1 / -1; margin: 0; }

  /* Progress ring centers in its full-width rail. */
  .profile-page .progress-stars { margin-inline: auto; }
}

/* Brand foot */
.footer {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--s7);
  padding: 22px var(--page-pad) 32px;
}
/* Match the topnav exactly: break out of the centered .page cap to span the
   full viewport, with content held at the SAME --page-pad gutter as .header.
   (Mirror of `.page > .header`.) Keeps brand + links vertically aligned with
   the header brand + pill on viewports wider than --page-max. */
.page > .footer {
  margin-inline: calc(50% - 50vw);
}
.footer .seal { display: flex; align-items: center; gap: 0; }
.footer .seal .brand-mini-ring { margin-inline-end: var(--brand-ring-gap); }
.footer .seal .brand-mark {
  /* Footer instance of the canonical .brand-mark wordmark — only narrows
     font-size; family/weight/letter-spacing/color (incl. .num coral) all
     inherit from the base .brand-mark rule. */
  font-size: 20px;
}
.footer .seal .lockup {
  /* Dotted, not solid — a solid rule isn't a design primitive here; reserve it. */
  border-left: 1px dotted var(--rule-2);
  margin-left: 20px;
  padding-left: 20px;
  /* One gap drives even spacing across all three lines (tagline top/bot +
     copyright), instead of a per-line margin that left the copyright too far down. */
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* ---------- Postcard frame (reusable) ----------
   Mounts media (image / video) inside the blank postcard artifact
   (scalloped deckle + red dashed border + built-in shadow). Keeps the
   postcard's 3:2 aspect; a 16:9 child sits centered in the dashed interior
   like a photo mounted on a card. Reusable anywhere a postcard mount fits. */
.postcard-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 1380 / 908;
  background: url("../assets/bg-postcard-blank.png") center / 100% 100% no-repeat;
  display: grid;
  place-items: center;
}
.postcard-frame > iframe,
.postcard-frame > .postcard-media {
  width: 87%;
  aspect-ratio: 16 / 9;
  border: 0;
}
.footer .seal .lockup .top {
  font-family: var(--font-display);
  font-weight: 600;
  font-style: italic;
  font-size: 16px;
  color: var(--coral);
}
.footer .seal .lockup .bot {
  font-family: var(--font-body);
  font-style: italic;
  font-size: 14px;
  color: var(--ink);
}
/* Fine-print copyright under the tagline — upright + muted so it reads as a
   notice, not part of the italic tagline. It lives in the brand lockup (not the
   desktop-only links), so it shows on every viewport. */
.footer .seal .lockup .copyright {
  font-family: var(--font-body);
  font-size: 11px;
  color: var(--slate);
}
.footer header,
.footer .footer-links { display: flex; gap: 26px; justify-self: end; }
.footer header a,
.footer .footer-links a {
  font-family: var(--font-body);
  font-size: var(--t-small);
  color: var(--ink);
  text-decoration: none;
}
.footer .footer-links a:hover { color: var(--coral); }

/* ---------- Footer responsive: stack brand over links ---------- */
@media (max-width: 991px) {
  .footer { grid-template-columns: 1fr; gap: var(--s5); }
  .footer header { justify-self: start; flex-wrap: wrap; gap: var(--s4) var(--s5); }
  /* Tablet + phone: brand elements only — the footer drops its links (the topnav
     already names the places); the brand lockup stays. */
  .footer .footer-links { display: none; }
}




/* =====================================================================
   my-13-traits.html — Voting page specific styles
   ===================================================================== */

/* ---------- The ring (SVG) — 13 stars on a circle + labels at outer radius ---------- */
.stage-ring-area {
  display: grid;
  gap: var(--s6);
  justify-items: center;
}
svg.ring {
  display: block;
  width: 600px;
  max-width: 100%;
  height: auto;
  overflow: visible;
}
svg.ring .ring-slot {
  font-family: var(--font-display);
  font-size: 38px;
  fill: rgba(210, 74, 61, 0.32);
  transition: fill .25s ease;
  dominant-baseline: middle;
  text-anchor: middle;
}
svg.ring .ring-slot.filled { fill: var(--coral); }

svg.ring .ring-center text { dominant-baseline: middle; }
svg.ring .ring-count {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 92px;
  fill: var(--indigo);
  letter-spacing: -0.025em;
}
svg.ring .ring-of {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 16px;
  letter-spacing: 0.22em;
  fill: var(--slate);
}
svg.ring .ring-sub {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: 18px;
  fill: var(--coral);
}

/* ---------- Radial trait labels (SVG text) ---------- */
svg.ring .ring-label-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-small);
  fill: var(--ink);
  dominant-baseline: middle;
}
svg.ring .ring-label-x {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--t-rail);
  fill: var(--ink);
  opacity: 0.55;
  cursor: pointer;
  dominant-baseline: middle;
  transition: opacity var(--t-fast) ease, fill .15s ease;
}
svg.ring .ring-label-x:hover { opacity: 1; fill: var(--coral); }

/* ---------- Ring actions ---------- */
.stage-ring-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s5);
}
/* ===== Button system =====
   .c13-btn is the base; pair with ONE color variant. The canonical
   shape is a PILL (border-radius 999px) — used consistently across the
   header CTA, ring actions, hero block pair, and the identity drawer.
   The -pill / -block modifiers exist only to tune size/layout for
   specific placements; they no longer change the shape (all pills now). */
.c13-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-body);
  line-height: 1;
  padding: var(--s3) var(--s6);
  border: 1px solid transparent;
  border-radius: 999px;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;     /* labels stay on one line — pills grow wider, never wrap */
  transition: background-color var(--t-fast) ease, color var(--t-fast) ease,
              border-color var(--t-fast) ease, transform var(--t-fast) ease;
}
/* Default variants for standalone use (no -pill / -block needed). The
   multi-class combos elsewhere keep their higher specificity and win
   where they apply. */
.c13-btn.c13-btn-secondary {
  background: transparent;
  color: var(--ink);
  border-color: var(--rule-3);
}
.c13-btn.c13-btn-secondary:hover { border-color: var(--ink); }
/* Secondary fills indigo on the active (current-page) state or keyboard focus. */
.c13-btn.c13-btn-secondary.active,
.c13-btn.c13-btn-secondary.is-filled,
.c13-btn.c13-btn-secondary:focus-visible {
  background: var(--indigo);
  border-color: var(--indigo);
  color: var(--canvas);
}
.c13-btn.c13-btn-secondary.is-filled:hover { background: color-mix(in srgb, var(--indigo) 88%, #000); border-color: color-mix(in srgb, var(--indigo) 88%, #000); }
/* Tertiary = coral-wash fill. More emphasis than a link; reads against boxed
   surfaces (e.g. the identity drawer) where an outline is too faint. */
.c13-btn.c13-btn-tertiary {
  background: var(--coral-wash);
  color: var(--ink);
  border-color: transparent;
}
.c13-btn.c13-btn-tertiary:hover { background: var(--coral-soft); color: var(--ink); }
.c13-btn.c13-btn-tertiary[disabled] { opacity: 0.45; cursor: not-allowed; }
.c13-btn.c13-btn-ghost {
  background: transparent;
  color: var(--ink-soft);
}
.c13-btn.c13-btn-ghost:hover { color: var(--ink); background: rgba(23, 32, 51, 0.05); }
/* Text button — no fill, border, or underline. The quietest action
   (e.g. modal close); distinct from -link, which underlines. */
.c13-btn.c13-btn-text {
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
  color: var(--slate);
  gap: var(--s2);
}
.c13-btn.c13-btn-text:hover { color: var(--coral); }

.c13-btn.c13-btn-primary {
  background: var(--ink);
  color: var(--canvas);
  border: 0;
  border-radius: 999px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-body);
  cursor: pointer;
  opacity: 0.28;
  transition: opacity .25s ease, background-color .25s ease;
  min-width: 200px;
}
.c13-btn.c13-btn-primary:not([disabled]) {
  opacity: 1;
  background: var(--coral);
}
.c13-btn.c13-btn-primary:not([disabled]):hover {
  background: var(--coral-deep);
}
.c13-btn.c13-btn-primary[disabled] { cursor: not-allowed; }
.c13-btn.c13-btn-link {
  background: transparent;
  border: 0;
  border-radius: 0;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  color: var(--slate);
  cursor: pointer;
  padding: 0 0 10px;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  transition: color var(--t-fast) ease, border-color var(--t-fast) ease;
}
.c13-btn.c13-btn-link .ph { font-size: 16px; }
.c13-btn.c13-btn-link:hover { color: var(--ink); }
/* Color modifiers — default is slate; these tint the link + its underline. */
.c13-btn.c13-btn-link.c13-btn-link-coral { color: var(--coral); }
.c13-btn.c13-btn-link.c13-btn-link-coral:hover { color: var(--coral-deep); }
.c13-btn.c13-btn-link.c13-btn-link-indigo { color: var(--indigo); }
.c13-btn.c13-btn-link.c13-btn-link-indigo:hover { color: var(--coral); }

/* ---------- Picked sidebar removed — selected traits now show as ring labels.
   Styles for .ring-label live below. ---------- */

/* ---------- Responsive ---------- */
@media (max-width: 720px) {
  svg.ring { width: 460px; }
}



/* =====================================================================
   my-13-traits.html — full-width voting layout (restructured)
   Header (full bleed) → 2-col select-stage (zip + trait list) → ring at bottom
   ===================================================================== */

.choice-body {
  background: var(--canvas);
}

/* Full-width main, sections handle their own horizontal padding */
.stage-choice {
  width: 100%;
}

/* Override: choice-header is constrained to header width (--page-max). */
.stage-choice .header-choice {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: var(--s6) var(--page-pad) var(--s5);
}
/* my-13 page only: drop the hero's bottom padding so the quilt-backed
   select-stage starts immediately under the star-rule divider. */
.choice-body .stage-choice .header-choice { padding-bottom: 0; }
/* my-13 choice-header h1 uses the default h1.heading clamp — no size override needed.
   The .choice-body class scopes the bottom-padding reset (quilt extends behind).
   (Removed dead .stage-choice .header-choice h1 { max-width: none } rule — its parent
    .header-choice-text only sets min-width: 0, no max-width to clear.) */
.stage-choice .header-choice .lede {
  max-width: none;
  font-size: var(--t-body);
  line-height: 1.5;
  color: var(--ink);
}
/* Inline ZIP cue inside the lede prose — a coral, body-weight link (NOT the
   standalone .c13-btn-link, whose display font + bottom border would break a
   prose line). Injected by linkifyZip() over the Sheet's "<enter your zip code>"
   placeholder; opens the identity drawer via [data-open-drawer="zip"]. */
.zip-cue {
  appearance: none;
  -webkit-appearance: none;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  font-weight: 600;             /* semibold — the cue stands out in the prose */
  color: var(--coral);
  cursor: pointer;
  text-decoration: underline dotted;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
/* inline-block so the dotted underline skips the icon (only the text is underlined). */
.zip-cue .ph { display: inline-block; font-size: 0.95em; margin-right: 0.2em; vertical-align: -0.08em; }
.zip-cue:hover { color: var(--coral-deep); }
/* Inline action cues woven into the descriptor's SHARE/SEE lines. Until the 13
   are confirmed they read as plain sentence text (inert); once confirmed they
   become coral links (matching the zip cue's treatment) that forward to the real
   Share / See actions. */
/* .cp-richtext a.descriptor-cue (0,2,1) out-specifies the content-anchor primitive
   .cp-richtext a (0,1,1), which would otherwise force its dotted underline onto
   these even before confirmation. */
.cp-richtext a.descriptor-cue {
  color: inherit;
  text-decoration: none;
  cursor: text;
  pointer-events: none;          /* inert sentence text until confirmed */
}
.descriptor-cue .ph { display: none; }   /* icon appears only once the cue is an action (post-confirm) */
#my-13.is-confirmed .cp-richtext a.descriptor-cue {
  color: var(--coral);
  font-weight: 600;
  text-decoration: underline dotted;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  cursor: pointer;
  pointer-events: auto;
}
#my-13.is-confirmed .descriptor-cue .ph { display: inline-block; font-size: 0.95em; margin-right: 0.2em; vertical-align: -0.08em; }
#my-13.is-confirmed .cp-richtext a.descriptor-cue:hover { color: var(--coral-deep); }

/* ---------- Two-column select stage ----------
   Outer .stage-select spans full viewport width so the quilt background
   can run edge to edge. Inner .stage-select-inner holds the grid at
   page-max width, centered. Columns stretch so the divider runs the
   full row height. */
.band-quilt {
  position: relative;
  isolation: isolate;
}
.stage-select {
  width: 100%;
  position: relative;
}
/* (The .band-quilt::before PNG watermark — bg-quilt-band.webp — was removed
   at source: both pages that carry .band-quilt had display:none'd it, so the
   rule and the asset reference were dead. The wrapper class stays as the
   structural mount for the my-13 fixed SVG quilt.) */
.stage-select-inner {
  position: relative;
  max-width: var(--page-max);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 440px 1fr;
  gap: var(--s9);
  padding: var(--s6) var(--page-pad) var(--s7);
  align-items: stretch;
}
/* Vertical divider — spans full row height, centered in the gap.
   Star ornament sits at the midpoint of the divider. */
.stage-select-inner::before {
  content: "";
  position: absolute;
  top: var(--s6);
  bottom: var(--s7);
  left: calc(var(--page-pad) + 440px + var(--s9) / 2);
  width: 1px;
  background: var(--rule);
  pointer-events: none;
}
.stage-select-inner::after {
  content: "★";
  position: absolute;
  top: 50%;
  left: calc(var(--page-pad) + 440px + var(--s9) / 2);
  transform: translate(-50%, -50%);
  font-family: var(--font-display);
  font-size: 14px;
  line-height: 1;
  color: var(--coral);
  padding: 0;
  pointer-events: none;
}

/* ---------- Left rail: zip / address + choropleth placeholder ----------
   .col-zip and .col-traits both use gap: var(--s5) and let the grid gap
   own all vertical rhythm. NO per-element margin-bottom on headings or
   inputs — the gap is the gap. ---------- */
.col-zip {
  display: grid;
  gap: var(--s5);
  align-self: stretch; /* column stretches so torn paper fills full row height */
  align-content: start; /* but content sits at the top of the column */
  position: relative;
  padding: var(--s6) var(--s5) var(--s4);
}
.col-zip > *:not(.bg-torn-paper) {
  position: relative;
  z-index: 1;
}

/* ---------- Form input — outlined box with persistent floating label.
   Pattern: a bordered container with an always-visible micro-uppercase
   label stacked above the input. The container is the focusable target. */
.c13-input {
  position: relative;
  display: block;
  border: 1px solid var(--rule-3);
  border-radius: 4px;
  padding: 10px 14px;
  background: transparent;
  transition: border-color var(--t-fast) ease;
}
.c13-input:focus-within { border-color: var(--ink); }
.c13-input-label {
  display: block;
  font-family: var(--font-display);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--indigo);
  line-height: 1.2;
  margin-bottom: 4px;
}
.c13-input input,
.c13-input select {
  font-family: var(--font-body);
  font-size: var(--t-body);
  font-weight: 400;
  line-height: 1.4;
  padding: 0;
  background: transparent;
  border: 0;
  color: var(--ink);
  width: 100%;
  outline: none;
  letter-spacing: 0.01em;
}
.c13-input select {
  /* Strip the native chrome so the field matches the input variant. */
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  padding-right: 24px; /* room for the custom caret below */
}
.c13-input input::placeholder { color: var(--slate-soft); font-weight: 300; }
.c13-input input::-webkit-search-cancel-button { -webkit-appearance: none; }

/* Custom caret for select inputs — absolutely positioned in the row so
   it visually replaces the native arrow. */
.c13-input-caret {
  width: 16px;
  height: 16px;
  color: var(--slate);
  flex-shrink: 0;
  pointer-events: none;
}

/* Optional inner row — used for inputs that need an inline element (e.g. a
   search-icon) on the same line as the input. */
.c13-input-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.c13-input-row input,
.c13-input-row select { flex: 1; min-width: 0; }
.c13-input-icon {
  width: 18px;
  height: 18px;
  color: var(--slate);
  flex-shrink: 0;
}
/* Clear / escape (×) for the trait search — only present once the field has a
   value (CSS :placeholder-shown gate; the field is its own sibling). */
.search-clear {
  display: none;
  flex-shrink: 0;
  width: 24px; height: 24px;
  padding: 0; border: 0; background: none; cursor: pointer;
  color: var(--slate-soft);
  align-items: center; justify-content: center;
}
.search-clear svg { width: 15px; height: 15px; }
.search-clear:hover { color: var(--slate); }
.c13-input-row input:not(:placeholder-shown) ~ .search-clear { display: inline-flex; }

.choropleth-frame {
  position: relative;
  margin-top: var(--s4);
  padding: 0;
  background: transparent;
  border-radius: 0;
}
/* .bg-torn-paper primitive defined alongside .lexicon — see top of file */
.choropleth-map { position: relative; }
.choropleth {
  width: 100%;
  height: auto;
  display: block;
  object-fit: contain;
  /* Reserve the square the live SVG (600×600 viewBox) will occupy, so the
     empty host holds its space before the bloom — no collapse, no shift. */
  aspect-ratio: 1 / 1;
}
/* "Your Community" callout — sits inside the highlighted polygon, above the
   star ring (both baked into the choropleth image). */
.choropleth-callout {
  position: absolute;
  top: 50%;
  left: 51%;
  transform: translate(-50%, -50%);
  text-align: center;
  pointer-events: none;
}
.choropleth-callout .cc-zip {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 22px;
  letter-spacing: -0.01em;
  color: var(--indigo);
  line-height: 1;
}
.choropleth-callout .cc-tag {
  margin: 6px 0 0;
  font-family: var(--font-body);
  font-style: italic;
  font-size: 13px;
  color: var(--ink);
  line-height: 1;
}
.choropleth-legend {
  margin-top: var(--s4);
  padding: var(--s3) var(--s4);
  background: var(--canvas);
  border: 1px solid rgba(23, 32, 51, 0.18);
}
.choropleth-legend .cl-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink);
}
.choropleth-legend .cl-sub {
  margin: 2px 0 var(--s3);
  font-family: var(--font-body);
  font-size: 11px;
  font-style: italic;
  color: var(--slate);
  line-height: 1.3;
}
.choropleth-legend .cl-scale {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 5px;
}
.choropleth-legend .cl-scale li {
  display: grid;
  grid-template-columns: 18px 1fr;
  align-items: center;
  gap: 10px;
  font-family: var(--font-body);
  font-size: 12px;
  color: var(--ink);
}
.choropleth-legend .sw {
  display: block;
  width: 18px;
  height: 14px;
  border: 1px solid rgba(23, 32, 51, 0.18);
}
/* Sequential 5-stop scale modifiers — sampled from the baked-in legend on
   assets/choropleth-community.png. Tokens (--ch-1..--ch-5) live at :root
   so the palette swaps in one place if we ever rework the map gradient. */
.choropleth-legend .sw-1 { background: var(--ch-1); }
.choropleth-legend .sw-2 { background: var(--ch-2); }
.choropleth-legend .sw-3 { background: var(--ch-3); }
.choropleth-legend .sw-4 { background: var(--ch-4); }
.choropleth-legend .sw-5 { background: var(--ch-5); }
.choropleth-caption {
  margin: var(--s3) 0 0;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--slate);
  text-align: center;
}

/* ---------- Right column: simplified trait list ---------- */
.col-traits {
  display: grid;
  gap: var(--s5);
  padding: var(--s6) var(--s5) var(--s4) 0;
}
.header-trait-list {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s5);
}
.status-trait-list {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--slate);
  margin: 0;
}
.status-trait-list.is-max {
  color: var(--ink);
  font-weight: 600;
}

/* Floating confirm button — bottom-right of viewport, appears at 13/13 */
.c13-btn.c13-btn-primary.is-floating {
  position: fixed;
  bottom: 32px;
  right: 32px;
  background: var(--coral);
  color: var(--canvas);
  border: 0;
  border-radius: 999px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-body);
  padding: 12px 26px;
  min-width: 200px;
  cursor: pointer;
  z-index: var(--z-floating);
  box-shadow:
    0 4px 16px rgba(23, 32, 51, 0.18),
    0 1px 3px rgba(23, 32, 51, 0.12);
  transform: translateY(20px);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-base) ease,
    transform .25s cubic-bezier(.2, .8, .2, 1),
    background-color .15s ease;
}
.c13-btn.c13-btn-primary.is-floating.is-active {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.c13-btn.c13-btn-primary.is-floating:hover { background: var(--coral-deep); }

/* Search input under "The 35 traits" — same civic underline as zip input */
/* (Old per-ID rules for #zip-input and #trait-search removed — styling lives
   on .c13-input above; IDs are JS hooks only.) */


/* ---------- Trait list — CSS columns so rows flow per-column at natural height ---------- */
.trait-list {
  column-count: 2;
  column-gap: var(--s7);
  /* Avoid orphan first-row distribution issues. */
}
.trait-row {
  break-inside: avoid;
  padding: 14px 0 19px;
  /* Perforated postal-style divider — see --perforated-dots token. */
  background-image: var(--perforated-dots);
  background-size: 6px 4px;
  background-repeat: repeat-x;
  background-position: bottom;
}
.c13-trait-item {
  appearance: none;
  display: grid;
  grid-template-columns: 22px 1fr;
  align-items: center;
  gap: 12px;
  padding: 0;
  margin: 0;
  background: transparent;
  border: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--t-body);
  line-height: 1.3;
  color: var(--ink);
  cursor: pointer;
  text-align: left;
  transition: color var(--t-fast) ease;
}
.c13-trait-item:hover { color: var(--coral); }
.c13-trait-item-mark {
  font-family: serif;
  font-size: 20px;
  line-height: 1;
  color: var(--slate-soft);
  text-align: center;
  transition: color var(--t-fast) ease;
}
.c13-trait-item[aria-pressed="true"] {
  color: var(--coral);
  font-weight: 600;
}
.c13-trait-item[aria-pressed="true"] .c13-trait-item-mark {
  color: var(--coral);
}
.c13-trait-item:disabled,
.c13-trait-item[disabled] {
  color: var(--slate-soft);
  cursor: not-allowed;
  opacity: 0.55;
}
/* Indented meta block sitting beneath the .c13-trait-item button. Holds the
   optional descriptor + character-profile link. Its left margin matches the
   button's mark column (22px) + gap (12px) so meta lines up with the name. */
.c13-trait-item-meta {
  margin: var(--s1) 0 0 34px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.c13-trait-item-desc {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--t-small);
  line-height: 1.45;
  color: var(--ink-soft);
}
.c13-trait-item-link {
  display: inline-block;
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--t-small);
  line-height: 1.6;
  font-style: italic;
  color: var(--slate);
  text-decoration: underline dotted;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  transition: color var(--t-fast) ease;
  width: max-content;
}
.c13-trait-item-desc + .c13-trait-item-link {
  margin-top: var(--s1);
}
.c13-trait-item-link:hover { color: var(--coral); }

/* ---------- Ring stage at the bottom (visualization of selections) ----------
   Inner postcard is a fixed-canvas layout (.ring-postcard) scaled to fit
   its wrapper by JS — the .stage-ring itself just provides vertical
   breathing room above and below. No PNG quilt background, no top hairline:
   the postcard frame carries all the chrome. */
.stage-ring {
  position: relative;
  isolation: isolate;
  margin: 0 auto;
  padding: var(--s8) 0 var(--s7);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: var(--s4);
}
.stage-ring .stage-ring-area {
  margin: 0 auto;
}

/* ---------- Responsive ---------- */
@media (max-width: 920px) {
  .stage-select-inner {
    grid-template-columns: 1fr;
    gap: var(--s6);
    padding: var(--s5) var(--s6) var(--s6);
  }
  .stage-select-inner::before,
  .stage-select-inner::after { display: none; }
  .stage-choice .header-choice { padding: var(--s5) var(--s6) var(--s4); }
  .stage-ring { padding: var(--s6) var(--s6) var(--s7); }
}
/* my-13's title sits at the SAME 48px (--s7) top rhythm as About/FAQ, via the
   .page-stub mechanism: a --s7 top on the section + the title row's negative
   margin (.header-choice-titlerow, below) swallowing the 140px ring's phantom air,
   so the title lands at that rhythm and the ring clears the topnav by ~16px.
   Constant across breakpoints like .page-stub — NOT a per-tier padding patch
   (this replaces an earlier tablet --s8 and a desktop --s7 media query that were
   both compensating on padding). The base .stage-choice .header-choice is --s6,
   shared with the community page, so this scopes the --s7 to my-13. Mobile hides
   the ring (see the 767 block) but the title keeps the same rhythm. */
#my-13 .stage-choice .header-choice { padding-top: var(--s7); }
/* (640px .trait-list rule removed — it set grid-template-columns on a
   column-count element: dead. Single-column flip now lives in the my-13
   767px block, on the property the list actually uses.) */


/* =====================================================================
   my-13-traits.html — Priority 1 enhancements
   Brand mini star ring, header postmark, star-rule divider,
   search icon, "Your 13" ring eyebrow, footer route cancellation.
   ===================================================================== */

/* Small star-ring brand mark beside the wordmark */
.brand-mini-ring {
  display: inline-block;
  width: 36px;
  height: 36px;
  color: var(--coral);
  flex-shrink: 0;
}
.brand-mini-ring svg { width: 100%; height: 100%; display: block; }

/* ---------- Vote header: 2-col grid with postmark on the right ---------- */
/* my-13 title row — the About/FAQ .page-title-row convention: the postal matrix
   sits in the SAME row as the (deliberately small) title, which frees the
   descriptor to run full width below instead of being boxed in a side column.
   Desktop only — the matrix is display:none on touch tiers, leaving just the title. */
.header-choice-titlerow {
  display: flex;
  align-items: center;
  gap: var(--s6);                 /* ring sits right next to the title (About/FAQ convention) with a little breathing room */
  /* The 140px ring is taller than the title's line box; align-center splits the
     overflow (~31px) into phantom air above the title — swallow it to keep the
     title on the page's top rhythm. --s6 (32) is the nearest token; the 1px over
     the exact 31 is invisible. (About/FAQ's .page-title-row carries a -31px literal.) */
  margin-top: calc(-1 * var(--s6));
  margin-bottom: var(--s4);
}
.header-choice-titlerow .heading { margin: 0; }
/* my-13 page title uses the base .heading-page clamp at every width, matching
   About/FAQ (Jinn's call June 12). The earlier ≤991 override that shrank it to
   34–47px when the postal matrix hid is gone — the title reads at the full
   page-title size on tablet/mobile too. */

/* Postmark watermark block (right side of header) */
.header-choice-postmark {
  display: flex;
  align-items: center;
  gap: var(--s4);
  padding-top: var(--s2);
}
.postmark-svg {
  width: 280px;
  height: auto;
  display: block;
  flex-shrink: 0;
}
.postmark-tag {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--t-small);
  line-height: 1.45;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink);
  font-weight: 500;
}
.postmark-tag-accent {
  display: inline-block;
  margin-top: 4px;
  padding-bottom: 4px;
  border-bottom: 1.5px solid var(--coral);
}

/* Star-rule divider below the header */
.star-rule-divider {
  display: flex;
  align-items: center;
  gap: var(--s4);
  margin-top: var(--s6);
}
.star-rule-divider .line {
  flex: 1;
  height: 1px;
  background: var(--rule);
}
.star-rule-divider .star {
  color: var(--coral);
  font-size: 12px;
  line-height: 1;
}

/* (Old .c13-input.c13-input-search override removed — search variant lives in the primitive above.) */

/* ---------- "Your 13" eyebrow above the ring — cinematic letter-spacing ---------- */
.stage-ring-eyebrow {
  letter-spacing: 0.18em;
}
.stage-ring-eyebrow .star {
  font-size: 11px;
}

/* ---------- Footer ROUTE 13 cancellation block ---------- */
/* my-13 page only: zero out the footer's top spacing so the postal strip
   (full-bleed, sits on top of the quilt) leads straight into the footer
   without an extra gap. Keep until quilt backdrop changes. */
.choice-body .footer { margin-top: 0; padding-top: var(--s5); }

/* ---------- Header responsive: stack postmark beneath title at narrow widths ---------- */
@media (max-width: 920px) {
  .header-choice-grid { grid-template-columns: 1fr; }
  .header-choice-postmark { padding-top: 0; }
  .postmark-svg { width: 220px; }
}

/* =====================================================================
   UTILITIES — keep these last so they override primitives on tie
   ===================================================================== */
.margin-none  { margin: 0; }
.padding-none { padding: 0; }



/* =====================================================================
   my-13 postcard + ring-stage layout (LIVE -- do NOT remove).
   The shareable .ring-postcard the render service screenshots, plus the ring
   stage and the hero postmark. This block once carried a "my-13-alt.html"
   header (that page was retired), but the styles became the LIVE my-13 design:
   my-13-traits.html uses .ring-postcard / .ring-rail-left / .ring-center-col /
   .ring-postcard-wrap / .header-choice-postmark. Per-page spacing is overridden in
   the MY-13 PAGE section (#my-13), not here. The .postcard-overlay / .overlay-* /
   .delivered-callout / .hero-star-ring postal overlays are unused in the markup
   but KEPT as intentional design items (per the lead).
   ===================================================================== */

/* ===== HERO POSTMARK =====
     Simple star-ring asset (no inner ring, no "13"), recolored to coral
     and vertically centered with the hero text. */
  .header-choice-grid { align-items: center; }
  .header-choice-postmark {
    padding-top: 0;
    align-items: center;
  }
  .header-choice-postmark .postmark-tag {
    margin: 0;
    align-self: center;
    line-height: 1.7;
  }

  .header-choice-postmark .hero-star-ring {
    width: 140px;
    height: 140px;
    display: block;
    color: var(--coral);
    opacity: 0.95;
    align-self: center;
    margin: auto 0;
  }

  /* ====== RING STAGE REDESIGN — fixed-canvas postcard, scales to fit ======
     The internal three-column layout is sized to a fixed 1400px canvas so
     the ring stays dominant at every viewport. A tiny JS observer scales
     the canvas to fit its outer wrapper; nothing reflows when the window
     resizes — the postcard just gets smaller as a whole.
     (.band-quilt::before + .stage-ring base rules now carry the redesign's
      final values; their override blocks here were removed when the
      !important clusters were resolved.) */

  .ring-postcard-wrap {
    width: 100%;
    max-width: var(--page-max);
    margin: 0 auto;
    padding: 0;
    /* Height set by scale-to-fit JS so page flow stays correct. */
    overflow: hidden;
  }
  /* ===== POSTCARD LAYOUT — the shareable my-13 card (render-service screenshots
     .ring-postcard; share buttons are hidden in that PNG). A 2-column grid:
       .ring-rail-left  — left: the "13" lockup + .share-block (share buttons,
                          pinned to the rail bottom via margin-top:auto; on-page only).
       ::before         — the dotted vertical divider (inset --s6 top + bottom).
       .ring-center-col — right ("body"): .display-script-center title + .ring star ring.
     Per-page spacing (padding, the body's top inset, the divider style, the
     share-block lift) is overridden in my-13-traits.html's inline <style> under
     #my-13 — NOT here. ===== */
  .ring-postcard {
    position: relative;
    width: var(--page-max);  /* expanded — full page-max width */
    margin: 0 auto;
    padding: 64px 40px;
    display: grid;
    grid-template-columns: 240px 1fr;
    column-gap: 48px;        /* 24px on each side of the vertical divider */
    align-items: stretch;
    transform-origin: top left;
    background: transparent;
    /* Border drawn by inline SVG (.postcard-border) below. */
    border: 0;
    border-radius: 0;
  }
  /* SVG postcard frame — fills the postcard, paints the clipped-corner
     border via a non-scaling-stroke path. Sits behind all content. */
  .ring-postcard > .postcard-border {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: 0;
    overflow: visible;
  }
  /* Lift normal content above the frame */
  .ring-postcard > .ring-rail-left,
  .ring-postcard > .ring-center-col {
    position: relative;
    z-index: 1;
  }
  /* (no corner-cap pseudo-elements needed; SVG frame handles corners) */
  /* Floating corner overlays — cancellation seal (top-right) and delivered
     callout (bottom-right). Positioned absolutely so they don't steal
     space from the ring's center column. */
  .postcard-overlay {
    position: absolute;
    z-index: 2;
    pointer-events: none;
  }
  .overlay-top-right {
    top: var(--s6);
    right: var(--s6);
    width: 260px;
    transform: rotate(-4deg);
    transform-origin: top right;
  }
  .overlay-top-right img {
    width: 100%;
    height: auto;
    display: block;
    opacity: 0.92;
  }
  .overlay-bottom-right {
    bottom: var(--s7);
    right: var(--s7);
    width: 220px;
  }
  /* Delivered callout — postal-style L-bracket frame:
     a coral dot pinned to the top-left corner, and an L-shaped bracket
     line extending from the top-right and bottom-right corners, ending
     in a second coral dot. The text sits inside the inner rectangle. */
  .overlay-bottom-right .delivered-callout {
    position: relative;
    padding: 22px 28px;
    background: transparent;
    /* Inner rectangle = three sides of a thin indigo border; the right
       side stays open so the L-bracket reads as the "missing" corner. */
    border: 1px solid var(--indigo);
    border-right: 0;
  }
  /* L-bracket extending past the top-right and bottom-right corners */
  .overlay-bottom-right .delivered-callout::before {
    /* Top-left red dot anchor */
    content: "";
    position: absolute;
    top: -4px; left: -4px;
    width: 9px; height: 9px;
    border-radius: 50%;
    background: var(--coral);
  }
  .overlay-bottom-right .delivered-callout::after {
    /* Bottom-right L bracket: 1px lines on the right and bottom of an
       extended area, with the coral dot anchor at the outer corner. */
    content: "";
    position: absolute;
    top: -1px;
    right: -22px;
    bottom: -22px;
    width: 22px;
    border: 1px solid var(--indigo);
    border-left: 0;
    border-top: 0;
    /* Dot anchor at the L's outer corner */
    background:
      radial-gradient(circle 5px at 100% 100%, var(--coral) 96%, transparent 100%);
  }
  .overlay-bottom-right .delivered-callout .l {
    display: block;
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: 11px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--indigo);
    line-height: 1.85;
    text-align: center;
  }
  /* Single hairline divider between left rail and center column */
  .ring-postcard::before {
    content: "";
    position: absolute;
    top: var(--s6);
    bottom: var(--s6);
    width: 1px;
    background: var(--rule);
    pointer-events: none;
    left: calc(40px + 240px + 24px);
  }

  /* ---- Left rail ---- */
  .ring-rail-left {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    gap: var(--s5);
    /* Lift the brand off the rail top so its caps ink-align with the personalized
       line's top strokes (the export hides .share-block, which had left the brand
       crowded at the top). 21px = .ring-center-col's title padding (29px) minus an
       8px script-vs-caps ink delta. Safe on the live page too — .share-block's
       margin-top:auto keeps it pinned to the bottom and the rail's slack absorbs
       this padding. */
    padding-top: 21px;
  }
  /* Top: large 13 + pipe + lockup (no box — just type) */
  .record-lockup {
    display: grid;
    grid-template-columns: auto 1px 1fr;
    gap: var(--s4);
    align-items: center;
  }
  .record-lockup .num13 {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 76px;
    line-height: 0.85;
    color: var(--indigo);
    letter-spacing: -0.04em;
    text-align: center;
    padding: 0;
    background: transparent;
    border-radius: 0;
    min-width: 0;
  }
  .record-lockup .pipe {
    height: 64px;
    background: var(--rule-2);
    align-self: center;
  }
  .record-lockup .lockup-text {
    display: grid;
    gap: 6px;
  }
  .record-lockup .lockup-text .l1 {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 22px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--indigo);
    line-height: 1.1;
  }
  .record-lockup .lockup-text .l2 {
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: 11px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--slate);
    line-height: 1.6;
  }
  /* Record meta block */
  .record-meta {
    display: grid;
    gap: var(--s4);
    margin-top: var(--s4);
  }
  .record-meta .row {
    display: grid;
    gap: 6px;
  }
  .record-meta .row.split {
    grid-template-columns: 1fr 1px 1fr;
    column-gap: var(--s3);
    align-items: start;
  }
  .record-meta .row.split > div {
    display: grid;
    gap: 6px;
  }
  .record-meta .row.split .div {
    width: 1px;
    height: 100%;
    background: var(--rule);
    min-height: 28px;
  }
  .record-meta .label {
    /* Mirror .c13-input-label exactly — same size, weight, letter-spacing
     * and color. Only font-family differs (mono vs display). */
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: var(--t-micro);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--coral);
    line-height: 1.2;
  }
  .record-meta .val {
    font-family: var(--font-display);
    font-weight: 500;       /* slightly lighter than before */
    font-size: 16px;
    color: var(--indigo);
    letter-spacing: 0.02em;
    line-height: 1.55;
    text-transform: uppercase;
  }
  /* Dashed/dotted hairline rule between meta rows */
  .record-meta .row + .row {
    padding-top: var(--s3);
    border-top: 1px dotted var(--rule-2);
  }
  /* Cancellation waves + dot matrix — side by side, larger sizes so they
     read together without dead space between them. */
  .rail-cancel {
    margin-top: var(--s4);
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--s3);
    align-items: center;
  }
  .rail-cancel .waves {
    width: 100%;
    max-width: 130px;
    height: 44px;
    opacity: 0.75;
  }
  .rail-cancel .dots {
    display: grid;
    grid-template-columns: repeat(5, 11px);
    grid-auto-rows: 11px;
    gap: 6px;
  }
  .rail-cancel .dots .d {
    width: 11px; height: 11px; border-radius: 50%;
    border: 1px solid var(--indigo);
  }
  .rail-cancel .dots .d.fill-i { background: var(--indigo); border-color: var(--indigo); }
  .rail-cancel .dots .d.fill-c { background: var(--coral); border-color: var(--coral); }
  .rail-cancel .dots .d.open { background: transparent; }

  /* ---- Center column ---- */
  .ring-center-col {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-rows: auto auto;
    grid-template-columns: minmax(0, 1fr);   /* cap the column so the script line wraps within it on a long first name instead of growing past it into the seal */
    gap: var(--s4);
    padding: 0;
    min-width: 0;
    align-items: start;
    justify-items: center;
  }
  /* USA-map watermark: fills the whole center column behind the script
     line + ring + actions. Recolored to a faint indigo so it reads as a
     watermark, not a competing element. */
  .ring-center-col {
    position: relative;
  }
  .ring-center-col::before {
    content: "";
    position: absolute;
    inset: 0;
    background: url('../assets/us-map.svg') no-repeat center;
    background-size: 92% auto;
    background-position: center 72%;
    opacity: 0.05;
    pointer-events: none;
    z-index: 0;
  }
  .ring-center-col > * { position: relative; z-index: 1; }

  /* Title sits centered in the column; padding-right reserves space so the
     absolutely-positioned seal doesn't overlap the wrap. The title also
     carries .fit-line (shared role, script/shared/fit-line.js): its length
     is data-driven — "My" becomes "<FirstName>'s" — so a long first name
     shrinks the line to the room the seal leaves rather than overflowing
     the card. */
  .ring-center-col .display-script-center {
    justify-self: stretch;   /* fill the capped column so a long line wraps within it, not to its own content width */
    min-width: 0;            /* let it shrink below its min-content so the column cap bites */
    white-space: normal;     /* override .fit-line's nowrap — a long first name WRAPS within the boundary instead of running the first line long (fit-line stays as a backstop for extreme cases) */
    text-wrap: balance;      /* even line lengths, not a long first line + short tail */
    padding-right: 220px;    /* boundary: reserves .center-head-seal (200px) + clearance for its -4deg rotation, so the wrap stays off the marks */
    margin: 0;
    line-height: 0.9;
  }
  /* Cancellation seal — absolutely positioned in the top-right of the
     center column, riding above the title line. */
  .center-head-seal {
    position: absolute;
    top: 4px;       /* lowered slightly (Jinn, June 12) so the postmark rides a touch lower over the title */
    right: -10px;   /* nudged right (Jinn, June 12) so the postmark sits closer to the card's right corner */
    width: 220px;   /* 280 → 240 → 200 → 220 (Jinn's call) */
    height: auto;
    display: block;
    transform: rotate(-4deg);
    transform-origin: top right;
    opacity: 0.92;
    z-index: 2;
    pointer-events: none;
  }

  .ring-map-wrap {
    position: relative;
    width: 100%;
    max-width: 500px;
    aspect-ratio: 1.15 / 1;
    display: grid;
    place-items: center;
    margin: 0 auto;
  }
  .ring-map-wrap svg.ring {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: none;
    overflow: visible;
  }

  /* Star → center connectors. Thin dashed coral spokes that radiate from
     each star toward the center "13". Top star reads as a straight
     vertical line down; the rest distribute around the dial. */
  .stage-ring svg.ring .ring-star-connector {
    stroke: var(--coral);
    stroke-width: 1;
    stroke-dasharray: 1.5 4;
    stroke-linecap: round;
    opacity: 0.55;
  }

  /* (Unused — kept for backward compatibility; the seal now sits in
     .center-head instead of as an overlay.) */
  /* Tighter ring text inside the center motif */
  .stage-ring svg.ring .ring-count { font-size: 88px; }
  .stage-ring svg.ring .ring-of {
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: var(--t-body);
    letter-spacing: 0.32em;
    fill: var(--indigo);
  }
  .stage-ring svg.ring .ring-stars {
    font-family: var(--font-display);
    font-size: 11px;
    fill: var(--coral);
    letter-spacing: 0.4em;
  }
  .stage-ring svg.ring .ring-sub {
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: var(--t-rail);
    letter-spacing: 0.32em;
    fill: var(--coral);
    font-style: normal;
  }

  /* Stars on the ring — render coral when filled (already styled by base
     stylesheet; nothing to override). */
  /* Label name color/size override — ink (charcoal) instead of indigo. */
  .stage-ring svg.ring .ring-label-name {
    fill: var(--ink);
    font-weight: 600;
    font-size: var(--t-h3);
  }
  .stage-ring svg.ring .ring-label-x-bg {
    fill: transparent;
    stroke: var(--slate);
    stroke-width: 1;
    opacity: 0.55;
    cursor: pointer;
    transition: stroke var(--t-fast), opacity var(--t-fast);
  }
  .stage-ring svg.ring .ring-label-x-bg:hover { stroke: var(--coral); opacity: 1; }
  .stage-ring svg.ring .ring-label-x {
    font-family: var(--font-ui);
    font-weight: 500;
    font-size: 14px;
    fill: var(--slate);
    opacity: 0.85;
    cursor: pointer;
  }
  .stage-ring svg.ring .ring-label-x:hover { fill: var(--coral); opacity: 1; }

  /* Center column actions — Confirm + Reset stays here. */
  .ring-center-actions {
    display: grid;
    grid-auto-flow: column;
    gap: var(--s5);
    align-items: center;
    justify-items: center;
  }
  .actions-primary {
    display: flex;
    align-items: center;
    gap: var(--s4);
  }
  .actions-divider {
    color: var(--rule-2);
    font-size: 18px;
    line-height: 1;
    user-select: none;
  }
  .stage-ring #reset {
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: 13px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--ink);
    text-decoration: none;
    padding: 8px 4px;
    margin-bottom: 0;
  }
  .stage-ring #reset:hover { color: var(--coral); }
  .stage-ring .c13-btn-link { margin-bottom: 0; }
  .ring-center-actions {
    display: grid;
    grid-auto-flow: column;
    gap: var(--s5);
    align-items: center;
    justify-items: center;
  }
  .stage-ring .c13-btn.c13-btn-link { margin-bottom: 0; }

  /* (right-rail + delivered-callout overlay rules removed; left rail
     owns rail content and the delivered callout uses arc-dotted) */

  /* Share row */
  .share-block { display: grid; gap: var(--s3); }
  .share-block .share-h {
    /* Same micro-uppercase label treatment as .record-meta .label and
       .c13-input-label — font-mono / 12px / 0.08em / coral. The original
       v1 values (10px, 0.22em, weight 500) sat too tight against the share
       icons; bumped to the canonical label-stamp values during the ring
       redesign. If a second consumer surfaces, promote this to a shared
       .label-stamp primitive. */
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: var(--t-micro);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--coral);
    line-height: 1.2;
  }
  .share-row {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: var(--s2);
  }
  .share-btn {
    appearance: none;
    position: relative;
    background: transparent;
    border: 1px solid var(--rule-2);
    border-radius: 2px;
    aspect-ratio: 1;
    display: grid;
    place-items: center;
    color: var(--indigo);
    cursor: pointer;
    transition: background-color var(--t-fast), color var(--t-fast), border-color var(--t-fast);
    text-decoration: none;
  }
  .share-btn:hover {
    background: color-mix(in srgb, var(--slate) 14%, transparent);
  }
  .share-btn svg { width: 18px; height: 18px; display: block; }
  /* Icon-only buttons: the label rides up as a hover/focus tooltip. Hidden by
     default (so the rendered PNG stays icons-only) and shown on hover/focus.
     Sits above the row — well inside the card, so the wrap's overflow:hidden
     never clips it. */
  .share-btn .l {
    position: absolute;
    left: 50%;
    bottom: calc(100% + 8px);
    transform: translateX(-50%);
    white-space: nowrap;
    padding: 6px 10px;
    /* Match the lexicon tooltip (.trait-lex-pop): ink-navy, rounded, soft shadow. */
    background: rgba(23, 32, 51, 0.95);
    color: #fff;
    box-shadow: 0 10px 26px rgba(23, 32, 51, 0.28);
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: 11px;
    letter-spacing: 0.04em;
    line-height: 1;
    border-radius: 6px;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--t-fast);
    z-index: 20;
  }
  .share-btn .l::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent;
    border-top-color: rgba(23, 32, 51, 0.95);
  }
  .share-btn:hover .l,
  .share-btn:focus-visible .l { opacity: 1; }

  /* Delivered-to callout at the foot of the left rail. The arc-dotted PNG
     above acts as a divider/ornament; text sits below with the same
     mono caps treatment as the meta labels. */
  .rail-delivered {
    margin-top: var(--s5);
    display: grid;
    justify-items: center;
    gap: 4px;
    text-align: center;
  }
  .rail-delivered .rail-delivered-arc {
    width: 100%;
    max-width: 220px;
    height: auto;
    display: block;
    margin-bottom: var(--s2);
  }
  .rail-delivered .arc-line   { stroke: var(--indigo); }
  .rail-delivered .arc-dot-i  { fill: var(--indigo); }
  .rail-delivered .arc-dot-c  { fill: var(--coral); }
  .rail-delivered .arc-star   { fill: var(--coral); }
  .rail-delivered .rail-delivered-l {
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: 11px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--indigo);
    line-height: 1.75;
  }

  /* Subtle status flag when the ring is complete — visible only when the
     body carries .is-confirmed (toggled by Confirm button). */
  .confirm-flag {
    display: none;
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: 10px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--coral);
    text-align: center;
    padding: 6px 12px;
    border: 1.5px dashed var(--coral);
    border-radius: 2px;
    transform: rotate(-3deg);
    align-self: center;
    justify-self: center;
  }
  body.is-confirmed .confirm-flag { display: inline-block; }
  body.is-confirmed #confirm { display: none; }

  /* ----- Scale-to-fit handled in JS — no responsive stack needed ----- */

  /* v2: white torn paper covers the entire select-stage band, contained
     to page-max width (inside .stage-select-inner). */
  .stage-select { overflow: hidden; }
  .stage-select-inner { isolation: isolate; }
  .stage-select-inner > .bg-torn-paper {
    position: absolute;
    top: var(--s4); /* breathing room below the section's top rule */
    left: var(--s4);
    right: var(--s4);
    bottom: var(--s2); /* sit inside the stage so the torn bottom edge is visible */
    /* Match the choice-slip paper grain \u2014 ultra-subtle horizontal striations\n       that preserve the bright white of the paper. */
    background-color: #FEFDFC;
    background-image: repeating-linear-gradient(
      0deg,
      rgba(23, 32, 51, 0.0075) 0 1px,
      transparent 1px 3px
    );
    /* Stronger drop-shadow stack so the torn edge reads against the cream page. */
    filter: drop-shadow(0 6px 14px rgba(23, 32, 51, 0.14))
            drop-shadow(0 2px 4px rgba(23, 32, 51, 0.10))
            drop-shadow(0 0 1px rgba(23, 32, 51, 0.18));
  }
  /* Spacing on .col-zip / .col-traits is now box-to-box (grid gap only).
     Both base rules use gap: var(--s5) and have no per-element
     margin-bottom on headings/inputs — see the source rules above. */

  /* (.stage-ring::before display:none override removed — the base
      .stage-ring no longer renders a top hairline, so nothing to hide.) */
  /* Star + divider above the paper */
  .stage-select-inner::before,
  .stage-select-inner::after { z-index: 2; }
  /* Drop the per-column paper from v1 */
  .col-zip .bg-torn-paper { display: none; }
  .col-zip > *,
  .col-traits > * { position: relative; z-index: 1; }

  /* ===== SVG quilt-stitch animation scaffold (bottom quilt only) =====
     When the SVG quilt mount is present, hide the PNG fallback. The script
     below generates a placeholder grid of patches into .quilt-stitch-mount;
     swap that mount’s contents for the real vectorized quilt when ready. */
  /* (.stage-ring::after no longer exists — the v1 PNG quilt background
      was removed at source. The quilt-stitch-mount lives inside
      .stage-ring under the postcard with no PNG to suppress.) */
  .quilt-stitch-mount {
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    opacity: 0.85;
    display: flex;
    align-items: flex-end;
    justify-content: center;
  }
  .quilt-stitch-svg {
    width: 100%;
    height: auto;
    max-height: 100%;
    display: block;
  }
  .quilt-stitch-mount .patch {
    transform-origin: center;
    transform-box: fill-box;
    opacity: 0;
    transform: scale(0.35) rotate(-6deg);
    transition:
      opacity var(--patch-duration, 520ms) ease-out,
      transform var(--patch-duration, 520ms) cubic-bezier(.34, 1.56, .64, 1);
    transition-delay: calc(var(--i, 0) * var(--patch-step, 55ms));
  }
  .quilt-stitch-mount.stitched .patch {
    opacity: 1;
    transform: scale(1) rotate(0);
  }
  /* Stitch seam lines — hidden until the patches finish, then draw on. */
  .quilt-stitch-mount .seam {
    fill: none;
    stroke: rgba(40, 32, 24, 0.35);
    stroke-width: 1;
    stroke-dasharray: 4 5;
    stroke-dashoffset: 1200;
    transition: stroke-dashoffset 900ms ease-out;
    transition-delay: calc(var(--seam-delay, 1100ms));
  }
  .quilt-stitch-mount.stitched .seam { stroke-dashoffset: 0; }

.record-meta .val .dot-link {
  text-decoration: underline dotted;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: currentColor;
}

/* Ring-stage left rail: brand wordmark variant of .record-lockup */
.record-lockup-wordmark {
  display: flex;
  align-items: center;
  gap: 10px;
  grid-template-columns: none;
}
.record-lockup-wordmark .brand-mini-ring {
  display: inline-block;
  width: 48px;
  height: 48px;
  color: var(--coral);
  flex-shrink: 0;
}
.record-lockup-wordmark .brand-mini-ring svg { width: 100%; height: 100%; display: block; }
.record-lockup-wordmark .brand-mark {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 32px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1;
  color: var(--indigo);
  flex: 1;
}
.record-lockup-wordmark .brand-mark .num { color: var(--coral); }

/* QR code block at the bottom of the left rail */
.rail-qr {
  margin-top: var(--s2);
  display: grid;
  gap: var(--s3);
  justify-items: start;
}
.rail-qr-svg {
  width: 112px;
  height: 112px;
  display: block;
  shape-rendering: crispEdges;
}
.rail-qr-l {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--slate);
  line-height: 1.4;
}

/* Push share-block to the very bottom of the left rail. */
.ring-rail-left .share-block { margin-top: auto; }

/* Hero route-dot matrix — replaces the star ring in the hero. Same
   visual vocabulary as the postal cancellation dots in the left rail. */
.hero-route-dots {
  display: grid;
  grid-template-columns: repeat(5, 16px);
  grid-auto-rows: 16px;
  gap: 10px;
  align-self: center;
  flex-shrink: 0;
}
.hero-route-dots .d {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 1.5px solid var(--indigo);
}
.hero-route-dots .d.fill-i { background: var(--indigo); border-color: var(--indigo); }
.hero-route-dots .d.fill-c { background: var(--coral); border-color: var(--coral); }
.hero-route-dots .d.open   { background: transparent; }

/* Hero: bump gap between route-dots and the tag text. */
.header-choice-postmark { gap: var(--s6); }

/* Actions: space between the pipe divider and the confirm button. */
.actions-primary { gap: var(--s5); }

/* (.share-block .share-h override removed — the base rule above now
   carries the canonical label-stamp values, no !important fight needed.) */


/* =====================================================================
   civic-traits.html — The 35 Traits page
   - Navy hero band (image baked at right)
   - Cream canvas filter bar
   - 4-up card grid w/ CSS 3D flip
   - Footer CTA strip
   ===================================================================== */

:root {
  /* Navy sampled from bg-header.webp's dominant blue. Use as solid
     background on the hero — image seam to navy is invisible. */
  --traits-navy: #012148;
  --traits-navy-deep: #001838;
}

.traits-body { background: var(--canvas); }

/* ---------- Hero band ---------- */
.traits-hero {
  position: relative;
  background: var(--traits-navy);
  color: #F5EFE4;
  overflow: hidden;
  /* Image is 3200x1200 = 2.67:1. Cap height so the artwork reads but the
     band still leaves room for content. */
  min-height: 380px;
}
/* Quilt artwork + grounding shadow live on ::before so they can be
   "wiped" in on load (a left→right mask reveal — the fabric filling in).
   Base layer stays plain navy, so if the animation is skipped the band
   is still on-brand. */
.traits-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background:
    linear-gradient(180deg, transparent 78%, rgba(0,0,0,0.22)),
    url('../assets/traits/bg-header.webp') no-repeat right center / auto 100%;
  animation: traits-quilt-wipe 1500ms cubic-bezier(0.22, 0.61, 0.36, 1) 250ms both;
}
/* Warm "needle" light that rides the leading edge of the wipe — reads as
   a stitch line trailing the fabric behind it. */
.traits-hero::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 140px;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(90deg,
    transparent,
    rgba(255, 232, 196, 0.0) 28%,
    rgba(255, 236, 200, 0.55) 50%,
    rgba(255, 232, 196, 0.0) 72%,
    transparent);
  mix-blend-mode: screen;
  opacity: 0;
  animation: traits-needle 1500ms cubic-bezier(0.22, 0.61, 0.36, 1) 250ms both;
}
@keyframes traits-quilt-wipe {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}
@keyframes traits-needle {
  0%   { left: -140px; opacity: 0; }
  14%  { opacity: 0.9; }
  86%  { opacity: 0.9; }
  100% { left: 100%; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .traits-hero::before { animation: none; clip-path: none; }
  .traits-hero::after  { display: none; }
}
.traits-hero-inner {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 56px var(--page-pad) 64px;
  position: relative;
  z-index: 2;
  max-width: var(--page-max);
}
/* The eyebrow above the hero h1 uses the .stamp.eyebrow primitive
   (same pattern as character-profile.html). On the dark navy band we
   re-tone the .sep and .num so they read on the navy backdrop — the
   primitive's default greys are for light surfaces. */
.traits-hero .stamp.eyebrow {
  font-size: var(--t-small);
}
.traits-hero .stamp.eyebrow .num {
  color: rgba(245, 239, 228, 0.78);
}
.traits-hero .stamp.eyebrow .sep {
  color: rgba(245, 239, 228, 0.36);
}
.traits-hero-h {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(56px, 4.5vw + 24px, 88px);
  line-height: 1.02;
  letter-spacing: -0.025em;
  margin: 0 0 var(--s5);
  color: #FAF5EC;
  max-width: 14ch;
  text-wrap: balance;
}
.traits-hero-lede {
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.55;
  color: rgba(245, 239, 228, 0.82);
  margin: 0 0 var(--s6);
  max-width: 64ch;
}
.traits-hero-meta {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  gap: var(--s5);
}
.traits-hero-meta li {
  display: flex;
  align-items: center;
  gap: 12px;
}
.traits-hero-meta li.sep {
  width: 1px;
  height: 36px;
  background: rgba(245, 239, 228, 0.22);
}
.traits-hero-meta .m-ic {
  display: inline-grid;
  place-items: center;
  width: 28px; height: 28px;
  color: rgba(245, 239, 228, 0.92);
  flex-shrink: 0;
}
.traits-hero-meta .m-ic svg { width: 100%; height: 100%; display: block; }
.traits-hero-meta .m-l {
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(245, 239, 228, 0.78);
  line-height: 1.35;
}
.traits-hero-meta .m-l strong {
  font-weight: 600;
  color: #FAF5EC;
}

/* ---------- Filter bar ---------- */
/* The body — filters + card grid — breaks out of the 1280 page-max
   to a wider 1400 frame so 4 cards have room for full button labels.
   The header and hero stay at page-max above. */
.traits-filters-wrap {
  max-width: 1400px;
  margin: 0 auto;
  padding: var(--s7) 40px var(--s5);
}
.traits-filters {
  display: grid;
  grid-template-columns: 1fr 280px;
  gap: var(--s4);
  align-items: stretch;
}

/* ---------- Card grid ---------- */
.traits-grid-wrap {
  max-width: 1400px;
  margin: 0 auto;
  padding: var(--s4) 40px var(--s8);
}
.traits-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  /* Wider gap so each card breathes; cards get a bit narrower. */
  gap: 40px;
}

/* ---------- Single card ---------- */
.trait-card {
  /* Card sized to the source illustration aspect (1122x1402 ≈ 0.80)
     plus footer height for buttons + flip link. We let the inner
     .tc-flip set the height — the card just provides the perspective. */
  position: relative;
  perspective: 1800px;
  /* Tight aspect: card image is 0.80, plus footer ~140px → card aspect
     close to 0.62 at 270px wide → 435px tall. We let .tc-flip control
     height via padding-bottom for stable cross-face geometry. */
}
.tc-flip {
  position: relative;
  width: 100%;
  transform-style: preserve-3d;
  transition: transform 0.7s cubic-bezier(.4, .15, .25, 1);
  /* Shorter card — was 270/460. */
  aspect-ratio: 270 / 410;
}
.trait-card.is-flipped .tc-flip { transform: rotateY(180deg); }

.tc-face {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: #FDFAF6;
  border-radius: 6px;
  padding: var(--s5) var(--s2) var(--s3);
  /* Front and back layered via 3D — backface hidden so only the showing
     face is visible. */
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  /* Material-style elevation. Indigo-tinted shadow to fit the cream/navy
     palette rather than neutral grey. Two layers: a tight contact shadow
     and a softer ambient one. */
  box-shadow:
    0 2px 4px rgba(23, 32, 51, 0.12),
    0 4px 12px rgba(23, 32, 51, 0.10);
  transition: box-shadow var(--t-base) ease;
}
.trait-card:hover .tc-face {
  /* Elevation lifts on hover. */
  box-shadow:
    0 4px 8px rgba(23, 32, 51, 0.14),
    0 12px 28px rgba(23, 32, 51, 0.14);
}
.tc-back { transform: rotateY(180deg); }

/* Card edge — Material-style elevation only. No border or brackets;
   the box-shadow on .tc-face creates the card boundary. .tc-frame is
   kept as an empty element for backwards compat but renders nothing. */
.tc-frame {
  display: none;
}

/* ---------- Card-front art ---------- */
.tc-art {
  position: relative;
  margin: 0;
  flex: 1 1 auto;
  display: flex;
  align-items: stretch;
  justify-content: center;
  min-height: 0;
  /* Background matches the card surface so the WEBP's cream edge blends
     into the FDFAF6 card. */
  background: #FDFAF6;
  border-radius: 2px;
  overflow: hidden;
}
.tc-art img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Center the crop so neither the top stamps nor the bottom title/star
     get clipped — both are inside the rebased ~6% cream margin, so the
     crop only eats blank canvas. */
  object-position: center;
  /* No multiply blend — the rebased image bg is already exact #FDFAF6, and
     multiplying it against the page color was darkening the whole card to
     ~#FCF5EE. */
}

/* ---------- Card footer (buttons + flip link) ---------- */
.tc-foot {
  flex: 0 0 auto;
  display: grid;
  gap: 0;
  padding: 12px 6px 14px;
  position: relative;
  z-index: 1;
}
.tc-actions {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
}
/* Vertical hairline between the two buttons. */
.tc-actions::after {
  content: "";
  position: absolute;
  top: 10px;
  bottom: 10px;
  left: 50%;
  width: 1px;
  background: rgba(18, 59, 102, 0.22);
  transform: translateX(-0.5px);
  pointer-events: none;
}
.tc-btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 12px 10px;
  background: transparent;
  border: 0;
  border-radius: 0;
  color: var(--indigo);
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.04em;
  line-height: 1;
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--t-fast), color var(--t-fast);
  white-space: nowrap;
}
.tc-btn svg { width: 14px; height: 14px; flex-shrink: 0; }

/* Default state — both buttons read as flat card-color labels. */
.tc-btn-ghost,
.tc-btn-coral {
  background: transparent;
  color: var(--indigo);
}
.tc-btn-ghost:hover {
  color: var(--coral);
}
.tc-btn-coral:hover {
  color: var(--coral);
}
/* Active / added state — only the "Add to My 13" button fills coral. */
.tc-btn-coral.is-added {
  background: var(--coral);
  color: var(--canvas);
}
.tc-btn-coral.is-added svg { color: var(--canvas); }
.tc-btn-coral.is-added:hover {
  background: var(--coral-deep);
  color: var(--canvas);
}

/* ---------- Flip link ---------- */
.tc-flip-link {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  padding: var(--s4) var(--s1) var(--s1);
}
.tc-flip-link .bar {
  height: 1px;
  background: rgba(18, 59, 102, 0.42);
}
.tc-flip-link .l {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 10.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--indigo);
  transition: color var(--t-fast);
}
.tc-flip-link:hover .l { color: var(--coral); }
.tc-flip-link:hover .bar {
  background: rgba(210, 74, 61, 0.6);
}

/* ---------- Card back (Webster lexicon style) ---------- */
.tc-back-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  padding: 22px 18px 14px;
  min-height: 0;
}
.tc-lex-h {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-bottom: var(--s2);
  margin-bottom: var(--s4);
  border-bottom: 1px solid var(--line-soft);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 9.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--slate);
}
.tc-lex-entry {
  flex: 1 1 auto;
}
.tc-lex-word {
  margin: 0 0 var(--s2);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 26px;
  line-height: 1.1;
  letter-spacing: -0.012em;
  color: var(--ink);
}
.tc-lex-word .syl { color: var(--coral); padding: 0 1px; font-weight: 500; }
.tc-lex-meta {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0 0 var(--s3);
}
.tc-lex-meta .pos {
  font-family: var(--font-body);
  font-style: italic;
  font-size: 13px;
  color: var(--slate);
}
.tc-lex-meta .pron {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--slate);
}
.tc-lex-def {
  margin: 0;
  font-family: var(--font-body);
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--ink);
  text-wrap: pretty;
}
.tc-back-stamp {
  margin: var(--s5) 0 0;
  padding-top: var(--s3);
  border-top: 1px solid var(--line-soft);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 9.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--slate);
  text-align: center;
}

/* ---------- Responsive ---------- */
@media (max-width: 1080px) {
  .traits-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 760px) {
  .traits-grid { grid-template-columns: repeat(2, 1fr); }
  .traits-filters { grid-template-columns: 1fr; }
}


/* =====================================================================
   home.html — Landing page (Stage 1: still hero, 16:9 cap)

   Reusable primitives composed by this page:
     .stage-dark        — composable dark theme via token override.
     .stage-spotlight   — warm radial-gradient key light overlay.
     .stage-noise       — paper-grain texture overlay.
     .quilt-fabric      — full-bleed monochrome quilt stitching.
                          Visible texture is the seam stitches; patches
                          themselves are absorbed into the canvas.
     .declaration       — "I say… X." block. Cue + word + quote.
     .script-opener     — cursive opening question (Italianno).

   New .c13-btn variants:
     .c13-btn-block     — block-shape CTA (hero actions, both colors)
   ===================================================================== */


/* ===== Stage: dark theme (composable) =====
   Apply to a section or to <body> to invert the surface tokens locally.
   Existing components that read these tokens (header, .heading, buttons,
   rules) follow automatically — no per-component dark overrides needed. */
.stage-dark {
  --canvas:      var(--charcoal);               /* warm-neutral near-black */
  --surface:     var(--charcoal-soft);
  --paper:       var(--charcoal-soft);
  --paper-soft:  var(--charcoal-deep);
  --paper-warm:  var(--charcoal-deepest);
  --ink:         #F4ECDD;                       /* warm cream */
  --ink-soft:    rgba(244, 236, 221, 0.78);
  --ink-mid:     rgba(244, 236, 221, 0.88);     /* dark-stage mirror of --ink-mid */
  --cream:       #ECE0C8;                       /* deeper warm cream — for brand surfaces */
  --indigo:      #F4ECDD;                       /* heading color flips to cream */
  --indigo-soft: rgba(244, 236, 221, 0.78);
  --coral:       #E37B6E;                       /* slightly warmer on dark */
  --coral-deep:  #D24A3D;
  --coral-light: #EF9484;                       /* one step lighter than the dark-stage --coral — hero CTA hover */
  --cta-star-color: var(--cream);               /* CTA star stays cream on the dark hero (light surfaces use red) */
  /* --red, --blue, --blush, --cream inherited from base :root */
  --slate:       rgba(244, 236, 221, 0.55);
  --slate-soft:  rgba(244, 236, 221, 0.32);
  --rule:        rgba(244, 236, 221, 0.10);
  --rule-2:      rgba(244, 236, 221, 0.22);
  --rule-3:      rgba(244, 236, 221, 0.34);
  --line-soft:   rgba(244, 236, 221, 0.10);

  background: var(--canvas);
  color: var(--ink);
}


/* ===== Stage: spotlight overlay =====
   Theatrical cone — SVG so we can clip to a polygon with soft edges
   (CSS radial gradients alone can't make a true cone shape). Includes
   the corner vignette in the same overlay. */
.stage-spotlight {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  display: block;
}


/* ===== Stage: noise (paper grain) =====
   Subtle texture so the dark canvas doesn't read as flat. Uses the
   existing texture-paper.svg, screen-blended at low opacity. */
.stage-noise {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: url("../assets/texture-paper.svg");
  background-size: 400px 400px;
  opacity: 0.05;
  mix-blend-mode: screen;
}


/* ===== Quilt fabric =====
   Full-bleed monochrome quilt. Slices are filled with shades just barely
   off the canvas; stitching (dashed strokes) runs along every seam — the
   stitches are the visible texture.

   ON THE HOME PAGE the quilt is inlined as an SVG (not <img>) with each
   stitch as its own <path> — see script/home/hero-cycle.js, which animates
   stitches individually during the per-cycle ripple. Other pages may
   still load this via <img> for performance; the base rule below
   handles both cases. */
.quilt-fabric {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;        /* applies when loaded as <img> */
  pointer-events: none;
  opacity: 1;
}


/* ===== Declaration component =====
   The "I say… X." pattern. Three voices: cue (italic stage direction),
   word (display bell), quote (small inscription). The declaration is
   the RESPONSE to the script-opener question — sized so it answers
   without drowning out the question. */
.declaration {
  text-align: left;
  position: relative;
}
.declaration-cue {
  font-family: var(--font-accent);   /* Italianno — matches the question's script voice */
  font-style: normal;
  font-weight: 400;
  font-size: clamp(60px, 5.4vw + 14px, 92px);
  line-height: 1.0;
  color: var(--red);
  letter-spacing: 0;
  margin: 0 0 -0.05em;       /* tight — 'I say...' optically attached to 'vision.' below */
  display: inline-block;
}
.declaration-cue .ellipsis {
  color: var(--red);
  margin-left: 0.02em;
}
/* The word — Literata at display optical size, sized to balance the
   script-opener question rather than dominate it. Toned down from
   the original clamp(72/7.5vw+4/120) so long trait words (e.g.
   "responsibility") stay within the column without overflowing
   into the seal. */
.declaration-word {
  font-family: var(--font-display);
  font-weight: 700;
  font-style: normal;
  font-variation-settings: "opsz" 72;
  font-size: clamp(60px, 5.6vw + 4px, 88px);
  line-height: 0.92;
  letter-spacing: -0.038em;
  color: var(--ink);
  margin: 0;
  text-shadow: 0 0 80px rgba(244, 236, 221, 0.10);
  white-space: nowrap;
}
.declaration-word .period {
  color: var(--coral);
  margin-left: -0.03em;
}
/* Quote — sits in the foot row, paired with CTAs. Italic Literata,
   airy line-height, attribution in tracked caps below. Max-width
   58ch — short trait words don't leave a dead zone to the right;
   longer traits stay readable. */
.declaration-quote {
  margin: var(--s6) 0 0;
  max-width: 58ch;
  padding: 0;
  border: 0;
}
.declaration-quote p {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(18px, 0.3vw + 15px, 22px);
  line-height: 1.55;
  color: var(--ink-soft);
  margin: 0;
  letter-spacing: 0.02em;
  /* text-wrap default (not balance) — balance was evening the lines
     and visibly narrowing the text. The quote now fills its column
     up to .declaration-quote's max-width. */
}
.declaration-quote cite {
  display: block;
  margin-top: var(--s5);
  font-family: var(--font-display);
  font-style: normal;
  font-weight: 500;
  font-size: 24px;                  /* up from 17px -- larger now that the cite stands alone (quote commented out) */
  line-height: 1.35;
  letter-spacing: 0;
  text-transform: none;
  color: var(--slate);
}
.declaration-quote cite::before {
  content: "\2014\00a0";   /* em-dash + nbsp via unicode escape (avoids charset mojibake) */
  display: inline;
  background: transparent;
  width: auto;
  height: auto;
  margin: 0;
  transform: none;
  opacity: 1;
}


/* ===== Script opener =====
   The page's premise — a cursive question. Sized to LEAD the visual
   hierarchy: the declaration answers this voice, not the other way
   around. */
.script-opener {
  font-family: var(--font-accent);
  font-size: clamp(38px, 3.44vw + 7.2px, 75.9px);  /* 1.5 major-third steps below the map title (its curve ÷ 1.3975, 38px mobile floor) — the shorter Sheet question carries a touch more presence while staying subordinate */
  line-height: 1.05;
  color: var(--ink-soft);
  letter-spacing: 0;
  /* Right-aligned so the three lines hug the declaration column on
     their right — the question reads as voiced TOWARD the response,
     not stranded against the page edge. */
  text-align: right;
  text-wrap: balance;
  /* Narrow measure so the question wraps to a few tidy lines, but never
     wider than its grid column (min(…, 100%) caps it to the column so it
     can't overflow into the response column). */
  /* Fixed ch measure (not capped to the column). Right-aligned with
     margin-left:auto, the block hugs the right of its column and any
     extra width spills LEFT toward the page margin — never into the
     response column — so the question gets a comfortable ~3-line wrap
     without widening the grid column. */
  max-width: 20ch;
  margin-left: auto;
}
.script-opener p { margin: 0; }
.script-opener .accent { color: var(--red); font-style: normal; }   /* <you> — same --red as the "I say…" cue (.declaration-cue) */
.script-opener .opener-rule {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: var(--s4);
  max-width: 200px;
}
.script-opener .opener-rule .l {
  flex: 1; height: 1px; background: var(--rule-2);
}
.script-opener .opener-rule .star {
  font-size: 11px; color: var(--coral); line-height: 1;
}


/* ===== Button variants added for home =====
   Two new combos, in the existing .c13-btn pattern. */

/* Coral pill — primary action in a pill shape. Header "Start Your 13". */
.c13-btn.c13-btn-primary.c13-btn-pill {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--coral);
  color: var(--ink);
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 8px 18px;
  font-family: var(--font-ui);
  font-size: var(--t-small);
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  min-width: 0;
  transition: background-color var(--t-fast) ease, transform var(--t-fast) ease;
}
.c13-btn.c13-btn-primary.c13-btn-pill:hover { background: var(--coral-deep); }
.c13-btn.c13-btn-primary.c13-btn-pill .seal { color: var(--ink); font-size: 14px; }

/* Block CTAs — used as a pair in the hero. Same dimensions, different
   surfaces. Inherit primary/secondary color from the existing variants. */
.c13-btn.c13-btn-block {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s5);
  padding: 14px 26px;
  border-radius: 999px;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  text-decoration: none;
  transition: background-color var(--t-fast) ease,
              color var(--t-fast) ease,
              border-color var(--t-fast) ease,
              transform var(--t-fast) ease;
  /* No min-width — lets the parent column control the dimension. */
}
.c13-btn.c13-btn-block.c13-btn-primary { background: var(--coral); color: var(--ink); border: 1px solid transparent; }
.c13-btn.c13-btn-block.c13-btn-primary:not([disabled]):hover { background: var(--coral-deep); transform: translateY(-1px); }

/* ===== Site-wide floating CTA  (script/shared/floating-cta.js) =====
   Persistent "Choose My 13 Traits" pill, bottom-right, injected on every page
   EXCEPT home (the hero cluster owns it) and my-13-traits (choosing IS the
   page). Filled-coral pill with the brand star; a soft shadow lifts it off
   the light inner-page surfaces. */
.floating-cta {
  position: fixed;
  right: var(--s7);
  bottom: var(--s7);
  z-index: var(--z-sticky);
}
.floating-cta .c13-btn.c13-btn-block {
  padding: 15px 26px;
  font-size: 18px;
  justify-content: center;
  box-shadow: 0 10px 28px rgba(23, 32, 51, 0.22);
}
/* Match the home/hero CTA EXACTLY (not the deep base coral): same --cta-fill
   coral + dark label + cream star, so it's the same button on every surface.
   FLIPPED on these light pages: the lighter --cta-fill-hover is the DEFAULT (to
   offset the simultaneous-contrast darkening on cream), and the base --cta-fill
   becomes the hover. */
.floating-cta .c13-btn.c13-btn-block.c13-btn-primary {
  background: var(--cta-fill-soft);
  color: var(--charcoal);
}
.floating-cta .c13-btn.c13-btn-block.c13-btn-primary:not([disabled]):hover {
  background: var(--cta-fill-hover);
  transform: translateY(-1px);
}
.floating-cta .cta-text { display: inline-flex; align-items: center; gap: 10px; }
.floating-cta .seal {
  display: inline-grid; place-items: center;
  font-family: var(--font-display);   /* sharp star */
  font-size: 18px;
  line-height: 1;
  color: var(--cta-star-color);
}
.c13-btn.c13-btn-block.c13-btn-secondary {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--rule-3);
}
.c13-btn.c13-btn-block.c13-btn-secondary:hover {
  border-color: var(--ink);
  background: rgba(244, 236, 221, 0.04);
}
.c13-btn.c13-btn-block .arrow { font-family: var(--font-ui); font-weight: 400; font-size: 1.25em; }  /* arrow a touch larger than the label, em-based so it scales with the button text */


/* ===== Hero declaration carousel =====
   Dots beneath the descriptor quote. Active dot fills with red. */
.hero-carousel {
  list-style: none;
  margin: var(--s6) 0 0;
  padding: 0;
  display: flex;
  gap: 14px;
  align-items: center;
}
.hero-carousel-dot {
  width: var(--t-small);
  height: var(--t-small);
  border-radius: 50%;
  border: 1px solid var(--rule-3);
  background: transparent;
  cursor: pointer;
  transition: background-color var(--t-fast) ease, border-color var(--t-fast) ease, transform var(--t-fast) ease;
  position: relative;
}
.hero-carousel-dot:hover { border-color: var(--ink-soft); }
.hero-carousel-dot.is-active {
  background: var(--blush);
  border-color: var(--blush);
  transform: scale(1.15);
}
.hero-carousel-dot .sr-only {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}


/* ===== Mirror seal =====
   Circular brand seal — 13-star ring with "13" centered. Same vocabulary
   as the topnav brand-mini-ring, scaled up for the hero. Stars are
   sourced from assets/ring-star.svg via <use>, so the symbol's
   fill="currentColor" inherits from `color:` set here. The central "13"
   stays host-rendered (separate <text>) so its color is independent. */
.mirror-seal {
  display: inline-block;
  width: clamp(96px, 7vw + 30px, 140px);
  aspect-ratio: 1;
  color: var(--cream); /* paints the symbol's stars via currentColor */
}
.mirror-seal svg { width: 100%; height: 100%; display: block; }
.mirror-seal .seal-num {
  fill: var(--blush);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 30px;
  letter-spacing: -0.01em;
  text-anchor: middle;
  dominant-baseline: central;
}


/* ===== Section divider — line / star / line =====
   Reusable horizontal divider used between major page sections. Renders
   as SVG so it scales smoothly; color inherits from .section-divider via
   currentColor (set on the img's parent). */
.section-divider {
  width: 100%;
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 var(--page-pad);
  color: var(--indigo);
}
.section-divider img {
  display: block;
  width: 100%;
  height: 32px;
}

/* ===== Stage: intro (Section 2) =====
   Editorial 3-zone layout: copy left, video center with decorative
   postal-seal stamps flanking, on the cream canvas. Section padding
   uses generous top/bottom space; video stays uncarded (no border-
   radius, no shadow). */
section.stage-intro.stage-intro {
  background: var(--canvas);
  padding-top: var(--s9);
  padding-bottom: var(--s8);
}

.stage-intro-frame {
  max-width: var(--page-max);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr 1.55fr;
  gap: var(--s9);
  align-items: start;
}
/* The copy column carries the watermark-ring stacking context (isolation): scoped
   here, not on .stage-intro-headline, so the ring's z-index:-1 sits behind the WHOLE
   column — headline AND descriptor — instead of being trapped above the descriptor. */
.stage-intro-copy { text-align: left; position: relative; isolation: isolate; }

.stage-intro-copy .heading-section { color: var(--indigo); }
.stage-intro-copy .heading-section .period { color: var(--red); }
.stage-intro-copy .stage-intro-subhead {
  font-family: var(--font-accent);
  font-size: clamp(var(--t-h3), 2.4vw + 14px, 56px);  /* floor on the major-third ladder */
  line-height: 1.0;
  color: var(--coral);
  margin: 0 0 var(--s5);
}
.stage-intro-copy em { font-style: italic; color: var(--coral); }
.stage-intro-copy .stage-intro-closer {
  font-family: var(--font-display);
  font-size: var(--t-rail);
  color: var(--ink);
  line-height: 1.5;
}

/* Headline group — title + script subhead, with a star-ring watermark
   sitting behind them (z-index: -1) and centered around the heading. */
.stage-intro-headline {
  position: relative;   /* isolation moved up to .stage-intro-copy (see note there) */
}
.stage-intro-headline-ring {
  position: absolute;
  top: 50%;
  right: -32px;
  transform: translateY(-50%);
  width: 240px;
  height: 240px;
  color: var(--coral-wash);
  opacity: 1;
  z-index: -1;
  pointer-events: none;
}
.stage-intro-headline-ring svg { width: 100%; height: 100%; display: block; }
/* Page title with the brand seal beside it (About, FAQ). Replaces the old
   .ring-watermark / .title-wm-wrap treatment, which never landed reliably.
   Seal reuses the community .cm-desc-seal treatment: brand ring + "13" numeral,
   numeral proportioned to match the home seal (30px on the 120 viewBox). */
.page-title-row {
  display: flex;
  align-items: center;
  gap: var(--s5);
  margin: 0 0 var(--s4);
}
.page-title-row .heading-page { margin: 0; }
/* Seal CENTER-aligNED with the title (maintainer-ruled). The seal is
   taller than the title's line box, so the row inflates and splits the
   overflow into phantom air above the title; the negative top margin
   swallows that phantom so the title keeps the page's 48px top rhythm,
   while the row's real height still reserves the seal's lower half.
   Desktop: (140 seal − ~78 title line)/2 ≈ 31. */
.page-title-row { align-items: center; margin-top: -31px; }
@media (max-width: 767px) {
  .page-title-row { margin-top: -20px; }   /* About: (96 − ~55)/2 */
  #faq .page-title-row { margin-top: 0; }  /* seal hidden — no phantom */
}
.page-seal {
  flex: none;
  /* 140px = the home hero seal cap (.mirror-seal) and .hero-star-ring size —
     the established "ring beside a large title" dimension. Not a one-off. */
  width: 140px;
  height: 140px;
  color: var(--coral); /* paints the ring stars via currentColor */
}
.page-seal svg { width: 100%; height: 100%; display: block; }
.page-seal-num {
  fill: var(--indigo);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 30px;
  letter-spacing: -0.01em;
  text-anchor: middle;
  dominant-baseline: central;
}
@media (max-width: 560px) {
  .page-seal { width: 96px; height: 96px; } /* = mirror-seal floor / --s9 */
}
/* FAQ drops the seal on phones (maintainer-ruled: it crowds the long title
   there; About's shorter title carries it nicely, so About keeps it — the
   shrink rule above is its phone size). Home's question-seal has its own
   phone rule. my-13 also drops its ring on mobile (Jinn's call June 12) — and
   with the ring gone the title row needs no phantom-air swallow, so it resets
   to flush there. (Tablet keeps the ring.) */
@media (max-width: 767px) {
  #faq .page-seal { display: none; }
  #my-13 .header-choice-titlerow .page-seal { display: none; }
  #my-13 .header-choice-titlerow { margin-top: 0; }
}

/* ---------- About — team grid (Sheet tab: about-team) ----------
   Two columns of collaborators; each card: ring-framed portrait left,
   name + descriptor right. The frame is the brand 13-star ring in BLUSH
   (the secondary warm accent — not the coral the seals wear), portrait
   clipped to the ring's hollow (stars sit at r≈42% of the 1000 viewBox;
   the 14% inset keeps the photo just inside their inner tips). Built by
   about.html's inline script from the about-team rows; no rows = no
   section. */
.team-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s6) var(--s7);
  margin-top: var(--s8);
}
.team-member {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s5);
  align-items: start;   /* ring tops align with the name line (maintainer-directed) */
}
.team-portrait {
  position: relative;
  width: 160px; height: 160px;   /* bigger than the seals — the ring is a frame here, not a stamp */
  color: var(--blush);            /* paints the ring stars via currentColor */
}
.team-portrait svg { width: 100%; height: 100%; display: block; opacity: 0.45; }  /* watermark-faint frame */
.team-portrait img {
  position: absolute;
  /* Stars sit at r≈42% of the viewBox, inner tips ≈38% — the 19% inset
     (62% circle) keeps clear air between the photo edge and the points.
     Vertical: +1.5% optical nudge DOWN — the ring has a star at 12 o'clock
     and a gap at 6, so the hollow's perceptual middle sits below its
     geometric one; a box-centered photo reads a tad high (eye-tuned). */
  inset: 19%;
  top: 20.5%;
  width: 62%; height: 62%;
  border-radius: 50%;
  object-fit: cover;
}
/* Name + descriptor sizes = the character-profile RAIL pattern (.move: a
   .heading-mid head over a t-rail body) — an existing register, not a new
   one. Name wears the heading's own indigo (ink-soft was tried and ruled
   out); descriptor ink. heading-mid brings weight 600 / lh 1.25 / 4px under. */
.team-name {
  font-size: clamp(15px, 0.4vw + 13px, 17px);  /* = h4/h5.heading scale (the rail move-head size) */
  color: var(--indigo);
}
.team-descriptor {
  font-family: var(--font-body);
  font-size: var(--t-small);  /* one step under the 17px name (t-rail read as body at this width — eye-ruled) */
  line-height: 1.5;
  color: var(--ink);
  margin: 0;
  max-width: 44ch;
}
/* Blank-line-split paragraphs (cp-richtext discipline): one paragraph
   break of rhythm, however many empty lines the cell carried. */
.team-descriptor p { margin: 0 0 var(--s2); }
.team-descriptor p:last-child { margin-bottom: 0; }
/* Every cp-richtext / prose-descriptor container (the carrier fills it with
   proseHTML's <p> paragraphs) gets the same paragraph rhythm: a blank line in
   the Sheet cell becomes a paragraph BREAK with real spacing — never a <br><br>
   gap. A single-paragraph descriptor is one <p> (first == last), so it carries
   NO margin and reads exactly like the old inline text. The per-descriptor class
   still owns the typography on the container; this only spaces the <p>s inside. */
.cp-richtext > p { margin: 0 0 var(--s3); }
.cp-richtext > p:last-child { margin-bottom: 0; }
/* Lists authored in the Sheet prose (the content team writes <ul>/<li>): a
   standard indented rhythm that matches the paragraph spacing above. */
.cp-richtext ul,
.cp-richtext ol { margin: 0 0 var(--s3); padding-left: var(--s5); }
.cp-richtext li { margin: 0 0 var(--s2); }
.cp-richtext li:last-child { margin-bottom: 0; }
.cp-richtext > ul:last-child,
.cp-richtext > ol:last-child { margin-bottom: 0; }

/* ---------- Content-anchor primitive ----------
   Links that arrive IN CONTENT — Sheet cells via sanitizeSheetHTML's <a>,
   richtext bodies, FAQ answers — wear the dotted-underline register
   (solid lines are not a primitive; metrics match .dot-link and the
   my-13 trait links). Ink at rest, coral on hover. */
.cp-richtext a,
[data-cp-html] a,
.team-descriptor a,
.faq-a a {
  color: inherit;
  text-decoration: underline dotted;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.cp-richtext a:hover,
[data-cp-html] a:hover,
.team-descriptor a:hover,
.faq-a a:hover { color: var(--coral); }
@media (max-width: 767px) {
  .team-grid { grid-template-columns: 1fr; gap: var(--s5); }
  .team-portrait { width: 120px; height: 120px; }
}
.stage-intro-headline > .heading,
.stage-intro-headline > .display-script { position: relative; }

.video-card {
  position: relative;
  width: 100%;
  aspect-ratio: 1380 / 967;        /* cropped postcard ratio (transparent edges trimmed) */
  filter: drop-shadow(0 24px 36px rgba(23, 32, 51, 0.20));
  isolation: isolate;
}
.video-card-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  mix-blend-mode: multiply;
  pointer-events: none;
}
.video-card-inner {
  position: absolute;
  inset: 27% 16% 14%;     /* generous top + side padding inside postcard */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  text-align: left;
}
.video-card-title {
  font-family: var(--font-display);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: clamp(22px, 1.4vw + 12px, 34px);
  line-height: 1.05;
  color: var(--indigo);
  margin: 0 0 var(--s4);
  max-width: 80%;
}
.video-card-title .period { color: var(--red); }

.video-card-body {
  font-family: var(--font-body);
  font-size: var(--t-rail);
  line-height: 1.5;
  color: var(--ink);
  margin: 0;
  /* No measure cap: this is a DESCRIPTOR, not a caption — it fills its container
     (the video column) like every other descriptor. The old 38ch cap was forcing
     the one-line copy to wrap. */
}
.video-card-script {
  font-family: var(--font-accent);
  font-size: clamp(var(--t-body), 1.4vw + 14px, 36px);
  line-height: 1.0;
  color: var(--coral);
  margin: 0;
}

/* Play button — circular, red, prominent. Click activates the video. */
.video-play-btn {
  margin: 0 auto;
  width: 72px;
  height: 72px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  border-radius: 50%;
  transition: transform var(--t-fast) ease;
  filter: drop-shadow(0 6px 12px rgba(210, 74, 61, 0.30));
  align-self: center;
}
.video-play-btn svg { width: 100%; height: 100%; display: block; }
.video-play-btn:hover { transform: scale(1.06); }

/* ===== Video modal — opens at 75vw when the play button is pressed. */
.video-modal[hidden] { display: none; }
.video-modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
}
.video-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 17, 23, 0.88);
  cursor: pointer;
}
.video-modal-content {
  position: relative;
  width: 75vw;
  max-width: 1400px;
  aspect-ratio: 16 / 9;
  background: #000;
  box-shadow: 0 30px 80px -20px rgba(0, 0, 0, 0.65);
}
.video-modal-frame {
  width: 100%;
  height: 100%;
}
.video-modal-frame iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}
.video-modal-close {
  position: absolute;
  top: -44px;
  right: 0;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--cream);
  font-size: 32px;
  line-height: 1;
  cursor: pointer;
}
.video-modal-close:hover { color: var(--coral); }
.video-poster-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.video-poster-play {
  position: absolute;
  top: 50%; left: 50%;
  width: 80px; height: 80px;
  transform: translate(-50%, -50%);
  transition: transform var(--t-fast) ease;
}
.video-poster-play svg { width: 100%; height: 100%; display: block; }
.video-poster:hover .video-poster-play { transform: translate(-50%, -50%) scale(1.08); }
.video-card iframe {
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  display: block;
}

/* Video caption — inside the card, below the video. */
.video-caption {
  margin-top: var(--s4);
  text-align: center;
}
.video-caption-eyebrow {
  font-family: var(--font-display);
  font-weight: 600;
  font-style: italic;
  font-size: var(--t-rail);
  color: var(--coral);
  margin: 0 0 var(--s1);
}
.video-caption-body {
  font-family: var(--font-body);
  font-size: var(--t-small);
  color: var(--ink-soft);
  margin: 0;
}


/* ===== Stage: mosaic (Section 3) =====
   Full-bleed monochrome portrait mosaic. The SVG keeps its native
   aspect-ratio (3260:1120 ≈ 2.91:1) so photos stay at full scale; the
   copy block overlays the SVG at the position where the original glyph
   paths sat (x=21.5%, y=69.6% of the viewBox = the lower-left negative
   space the artwork reserved for type). */
section.stage-mosaic.stage-mosaic {
  padding-top: var(--s8);
  padding-bottom: var(--s8);     /* breathing room before the postal strip */
  position: relative;
  isolation: isolate;
  container-type: inline-size;
}

/* Route connector at the top of the mosaic — dashed wavy line that
   threads across the section, picking up the postal/airmail vocabulary. */
.stage-mosaic .route-connector-mosaic {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  width: 100%;
  height: 56px;
  color: var(--indigo);
  opacity: 0.45;
  pointer-events: none;
}
.route-connector svg,
svg.route-connector { width: 100%; height: 100%; display: block; color: inherit; }

.stage-mosaic-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 3260 / 1120;
  container-type: inline-size;
}
.stage-mosaic-svg {
  /* Loaded via <object> — width/height percentages resolve against
     the .stage-mosaic-frame container, and the SVG's intrinsic
     viewBox keeps coordinates rendering 1:1 to the original. */
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
}

/* Copy block — flows below the frame in normal layout, then uses negative
   margin-top to slide UP into the SVG's lower-left negative space.
   Math: original glyphs sat at top=69.6% of frame, so distance from frame
   bottom = 30.4% × frame_height = 30.4% × (width × 1120/3260)
         ≈ 10.4% of width
   → margin-top: -10.4cqw pulls the copy block into the SVG's empty zone.
   left: 21.5% places it at viewBox x=700 (where original glyphs started). */
.stage-mosaic-copy {
  margin-top: -10.4cqw;
  margin-left: 21.5%;
  width: 36%;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 1.2cqw;
}
.stage-mosaic-copy .eyebrow { margin: 0; }

/* Heading scales with section width via cqw so it lines up with the
   SVG's intrinsic geometry at any viewport. 3.2cqw at the section's
   ~1672px width is ~54px. */
.stage-mosaic-copy .mosaic-tagline {
  font-family: var(--font-accent);
  font-weight: 400;
  font-size: 5cqw;
  line-height: 1.0;
  letter-spacing: 0;
  color: var(--indigo);
  margin: 0;
}
.stage-mosaic-copy .mosaic-tagline .period { color: var(--red); }

.stage-mosaic-copy .mosaic-body {
  margin: 0;
  max-width: none;
}

.stage-mosaic-copy .mosaic-ctas {
  display: inline-flex;
  align-items: baseline;
  gap: 24px;
  margin-top: 0.5cqw;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
}
.stage-mosaic-copy .mosaic-cta-link {
  color: var(--coral);
  text-decoration: none;
  border-bottom: 1px solid var(--coral);
  padding-bottom: 3px;
  transition: color var(--t-fast) ease, border-color var(--t-fast) ease;
}
.stage-mosaic-copy .mosaic-cta-link:hover { color: var(--coral-deep); border-color: var(--coral-deep); }
.stage-mosaic-copy .mosaic-cta-link .arrow { font-family: var(--font-ui); font-weight: 400; margin-left: 4px; }
.stage-mosaic-copy .mosaic-cta-sep { color: var(--rule-3); font-weight: 400; }

/* Closing question — bookends the hero's opening question. Script
   (Italianno) in coral, sized between body and tagline, sits as a
   bridge between the descriptor and the CTA pair. */
.stage-mosaic-copy .mosaic-closer {
  font-family: var(--font-accent);
  font-size: clamp(32px, 2vw + 14px, 48px);
  line-height: 1;
  color: var(--coral);
  margin: 0;
  margin-top: 0.5cqw;
}

/* ===== Hero side (Col 3) =====
   Mirror seal stacked above CTAs, left-aligned within the column. */
.home-hero-side {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s6);                /* ring → actions group spacing */
}
.home-hero-side .home-hero-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  align-self: stretch;
  gap: var(--s5);                /* between-button spacing */
}


/* ===== Stage: home hero =====
   The hero composes a 16:9 stage on a typical desktop viewport (matches
   the rest of the theatrical sections), but treats that ratio as a
   MINIMUM, not a strict box. If content needs more vertical room
   — longer pull-quote, larger heading, narrow column wrapping — the
   section grows past 16:9 instead of clipping. Background layers
   (.stage-noise, .quilt-fabric, .stage-spotlight) are all absolute
   inset:0 so they stretch with the hero; overflow:hidden stays to clip
   the spotlight SVG's slice. */
.stage-home-hero {
  position: relative;
  width: 100%;
  /* 16:9 baseline, capped to viewport so the stage never demands more
     than one screen worth of height when content is short. Beyond
     this, the flex column below lets the section grow naturally. */
  min-height: min(100vh, calc(100vw * 9 / 16));
  overflow: hidden;
  isolation: isolate;
  /* Flex column: topnav sits at top in flow; .stage-home-hero-content
     stretches (flex: 1) to fill the remaining min-height when content
     is short, and grows past it when content is tall. */
  display: flex;
  flex-direction: column;
}

/* Full-bleed past the .page container so the watermark spans the whole
   viewport. Used when the hero sits inside a .page wrapper. */
.stage-home-hero-bleed {
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  width: 100vw;
}

/* Layer ordering (back → front) */
.stage-home-hero .stage-noise         { z-index: 0; }
.stage-home-hero .quilt-fabric        { z-index: 1; }
.stage-home-hero .stage-spotlight     { z-index: 2; }
.stage-home-hero .stage-home-hero-content { z-index: 3; }


/* ===== Hero topnav (integrated, no separator) =====
   The page's <header class="header"> is moved inside .stage-home-hero.
   We strip its border + adjust padding so it reads as part of the stage. */
.stage-home-hero .header {
  position: relative;
  z-index: 4;
  /* Same --page-pad gutter as every other page, so the brand + My-13 pill sit
     in the same horizontal spot (no left/right jump when navigating). Two
     intentional, stage-only differences: border stripped + transparent (the
     bar reads as part of the dark stage), and 24px block padding vs the
     standard 20px so it breathes a touch more on the stage. (hero-map-handoff
     .css clears the old max-width cap via width:auto/max-width:none/margin:0.) */
  padding: 24px var(--page-pad);
  border-bottom: 0;
  background: transparent;
}


/* ===== Hero content frame =====
   3 columns × 3 rows. Question gets its own vertical row at the top;
   response + CTAs share the middle row; quote + Mirror seal share the
   bottom row.
     Row 1: Question         | —                | —
     Row 2: —                | I say… + vision. | CTAs
     Row 3: —                | quote + cite     | Mirror seal
   auto-1fr-auto rows let the response band claim the remaining vertical
   space and stay vertically centered between the question and quote.

   The content layer was previously position:absolute inset:0 inside a
   strict 16:9 box; that clipped overflow invisibly. It now flows in
   the hero's flex column — flex: 1 claims the leftover height when
   content fits the stage, and the frame grows the hero when it doesn't. */
.stage-home-hero-content {
  position: relative;
  z-index: 3;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  pointer-events: none;
}
.stage-home-hero-frame {
  position: relative;
  width: 100%;
  flex: 1 1 auto;
  /* Top padding is the breathing room BELOW the topnav (topnav now sits
     in flow above this frame; it owns its own ~80px header height). */
  padding: var(--s7) var(--page-pad) var(--s7);
  display: grid;
  grid-template-columns: minmax(0, 0.7fr) minmax(0, 1.5fr) minmax(0, 0.5fr);
  grid-template-rows: auto 1fr auto;
  column-gap: var(--s7);
  row-gap: 0;
}
.stage-home-hero-frame > * { pointer-events: auto; }

/* Grid placements */
.stage-home-hero-frame .script-opener     { grid-column: 1; grid-row: 1; align-self: start; }
.stage-home-hero-frame .declaration       { grid-column: 2; grid-row: 2; align-self: start; margin-top: -20px; }
.stage-home-hero-frame .home-hero-side    { grid-column: 3; grid-row: 2 / 4; align-self: end; justify-self: end; }


/* ===== Topnav brand on dark stage =====
   "Choose" wordmark in warm cream; the star ring + "13" both render
   in TRUE red, matching the "I say…" voice. */
.stage-dark .brand-mark        { color: var(--cream); }
.stage-dark .brand-mark .num   { color: var(--red); }
.stage-dark .brand-mini-ring   { color: var(--red); }

/* Accessibility — coral primary CTA needs DARK text on its blush
   surface; in stage-dark, --ink is cream, which fails contrast. Force
   the canvas color (dark midnight) on the primary block button. */
.stage-dark .c13-btn.c13-btn-block.c13-btn-primary { color: var(--canvas); }



/* =====================================================================
   Hero cycle engine — animation states
   Driven by script/home/hero-cycle.js. Progressive enhancement: without
   JS (or with prefers-reduced-motion), all engine-managed elements
   render in their default static state — first declaration only,
   spotlight + quilt fully visible, no movement.

   The engine adds  body.cycle-engine-active  when it boots; that's
   when these animation states take effect. The engine adds
   .cycle-reduce  in addition when prefers-reduced-motion: reduce is
   set, which strips ALL transitions/animations and just instant-swaps
   text on each cycle.
   ===================================================================== */

/* While the engine is active but hasn't yet completed first paint,
   the dynamic layers start hidden. Topnav + side actions are also
   hidden so the stage opens EMPTY — the question types onto a clear
   black stage, and the surrounding chrome populates AROUND it once
   the first words appear. */
body.cycle-engine-active .quilt-fabric,
body.cycle-engine-active .stage-spotlight,
body.cycle-engine-active .stage-home-hero > .header,
body.cycle-engine-active .stage-home-hero .mirror-seal,
body.cycle-engine-active .stage-home-hero .home-hero-actions,
body.cycle-engine-active .script-opener > p,
body.cycle-engine-active .declaration-cue,
body.cycle-engine-active .declaration-word,
body.cycle-engine-active .declaration-quote,
body.cycle-engine-active .hero-carousel {
  opacity: 0;
}

/* Reveal classes the engine toggles. Transitions are tuned to match
   the first-paint timeline in script/home/hero-cycle.js. The transition
   sits on the BASE rule so removing the class also animates (fade-OFF
   needs the same timing as fade-ON when the engine cycles the
   spotlight off/on — "move first, then shine."). */
body.cycle-engine-active .quilt-fabric {
  transition: opacity 800ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
body.cycle-engine-active .quilt-fabric.is-revealed { opacity: 1; }

body.cycle-engine-active .stage-spotlight {
  transition: opacity 700ms ease-out;
}
body.cycle-engine-active .stage-spotlight.is-revealed { opacity: 1; }

body.cycle-engine-active .stage-home-hero .mirror-seal {
  transition: opacity 500ms ease-out;
}
body.cycle-engine-active .stage-home-hero .mirror-seal.is-revealed { opacity: 1; }

/* Topnav + side-stack CTAs share the "stage populate" beat — they
   fade in together after the question typewriter has revealed its
   first line. Engine adds .is-revealed at the appropriate time. */
body.cycle-engine-active .stage-home-hero > .header,
body.cycle-engine-active .stage-home-hero .home-hero-actions {
  transition: opacity 600ms ease-out;
}
body.cycle-engine-active .stage-home-hero > .header.is-revealed,
body.cycle-engine-active .stage-home-hero .home-hero-actions.is-revealed { opacity: 1; }

body.cycle-engine-active .script-opener > p,
body.cycle-engine-active .declaration-cue,
body.cycle-engine-active .hero-carousel {
  transition: opacity 350ms ease-out;
}
body.cycle-engine-active .script-opener > p.is-revealed,
body.cycle-engine-active .declaration-cue.is-revealed,
body.cycle-engine-active .hero-carousel.is-revealed {
  opacity: 1;
}

/* ---------- Trait word (typed in per-char by the engine) ----------
   The trait used to scale + translate in ("float"); now it's revealed
   via per-character typewriter in script/home/hero-cycle.js, so the
   element itself just snaps to opacity 1 when is-revealed lands and
   the chars inside reveal one at a time. Exit is a graceful opacity
   fade only — no transform. */
body.cycle-engine-active .declaration-word {
  /* No transform, no entrance opacity transition. Typewriter handles
     the visible reveal. */
}
body.cycle-engine-active .declaration-word.is-revealed { opacity: 1; }
body.cycle-engine-active .declaration-word.is-exiting {
  opacity: 0;
  transition: opacity 240ms ease-in;
}

/* ---------- Quote (fades in gracefully after the trait lands) ---------- */
body.cycle-engine-active .declaration-quote {
  transition: opacity 700ms ease-out;
}
body.cycle-engine-active .declaration-quote.is-revealed { opacity: 1; }
body.cycle-engine-active .declaration-quote.is-exiting {
  opacity: 0;
  transition: opacity 240ms ease-in;
}

/* ---------- Mirror seal idle pulse ----------
   Almost-not-there breath so the page never feels frozen between
   cycles. ±0.5% scale, ±2% opacity, 4s cycle. */
@keyframes seal-idle-breath {
  0%, 100% { transform: scale(1.000); opacity: 1.00; }
  50%      { transform: scale(1.005); opacity: 0.98; }
}
body.cycle-engine-active .stage-home-hero .mirror-seal.is-revealed {
  animation: seal-idle-breath 4s ease-in-out infinite;
}

/* ---------- Spotlight beam variants ----------
   Three separately-shaped polygons live inside <g class="spot-beam">,
   each with its own source position on the TOP edge of the viewBox
   and its own beam axis aimed at the trait. The engine picks one by
   adding .beam-a / .beam-b / .beam-c to the parent .stage-spotlight;
   only the matching .beam-poly-* is rendered.

     .beam-a  =  default — source above-right, ~19° tilt to trait
                 (used on first paint and the commonest cycle pick)
     .beam-b  =  source far upper-right, ~37° tilt across the stage
                 (most diagonal)
     .beam-c  =  source nearly overhead, ~8° tilt
                 (most vertical, source closest to centered above trait)

   No transform/rotation is applied to the polygons — each one is
   pre-shaped to land on the trait. The spotlight as a whole still
   fades off → repositions (silent class swap) → fades back on under
   cover, so the "move first, then shine" sequencing works the same
   way it did with rotated cones. */
.stage-spotlight .beam-poly-a,
.stage-spotlight .beam-poly-b,
.stage-spotlight .beam-poly-c { display: none; }
.stage-spotlight.beam-a .beam-poly-a { display: block; }
.stage-spotlight.beam-b .beam-poly-b { display: block; }
.stage-spotlight.beam-c .beam-poly-c { display: block; }

.stage-spotlight .spot-beam {
  /* No transform here — variants are pre-shaped polygons, not rotations. */
}

/* ---------- Carousel dots ---------- */
.hero-carousel-dot {
  transition: background-color 250ms ease, transform 250ms ease;
}
.hero-carousel-dot:hover { transform: scale(1.15); }

/* ---------- Quilt stitch ripple ----------
   Each stitch path has a default state inherited from the SVG group
   (stroke-width 1.3, stroke #201E1C). During a ripple peak, JS adds
   .ripple-peak to a stitch; the transition runs from default → peak
   on add and peak → default on remove. The CSS-variable indirection
   lets us tweak peak values in one place.

   PEAK VALUES TUNED FOR SUBTLETY — we want the wave to read as a
   tactile fabric flinch, not a graphic flash. Stroke shift is tiny
   (#201E1C → #2D2A26, ~1 luminance step) and width nudge is half a
   pixel. The peak holds 420ms so the wave reads as a slow sweep
   rather than a sparkle. */
.quilt-stitches > path {
  --stitch-stroke-color: #201E1C;
  --stitch-stroke-width: 1.3;
  --stitch-stroke-opacity: 1;
  stroke: var(--stitch-stroke-color);
  stroke-width: var(--stitch-stroke-width);
  stroke-opacity: var(--stitch-stroke-opacity);
  transition: stroke 420ms ease-out, stroke-width 420ms ease-out, stroke-opacity 420ms ease-out;
}
.quilt-stitches > path.ripple-peak {
  --stitch-stroke-color: #2D2A26;
  --stitch-stroke-width: 1.7;
  --stitch-stroke-opacity: 1;
  transition: stroke 200ms ease-out, stroke-width 200ms ease-out;
}

/* ---------- Reduced motion ----------
   When the user has prefers-reduced-motion: reduce, the engine adds
   .cycle-reduce. We strip transitions/animations and instant-swap.

   NOTE on !important: the methodology says no !important, but this
   IS the legitimate exception — accessibility overrides that must
   beat every per-element transition declared above. The blanket *
   selector also has very low specificity on its own, so without
   !important these wouldn't reliably win. Scope is tight (only
   inside the cycle-reduce body) so the override is contained. */
body.cycle-engine-active.cycle-reduce *,
body.cycle-engine-active.cycle-reduce *::before,
body.cycle-engine-active.cycle-reduce *::after {
  transition: none !important;
  animation: none !important;
}
body.cycle-engine-active.cycle-reduce .declaration-word {
  transform: none;
}


/* ===== Ellipsis dot pulse =====
   Used by the first-paint sequence in script/home/hero-cycle.js.
   After "I say…" finishes typing, the engine pauses briefly and then
   adds .dot-pulse to the LAST dot of the ellipsis to play this
   animation three times — a rhetorical "three-beat pause" before
   the trait declaration lands. Each pulse: scale + opacity dip + back.
   Total time = 3 × 320ms = 960ms. */
@keyframes dot-pulse-anim {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.32; }
}
.declaration-cue .ellipsis .dot {
  display: inline-block;
  transform-origin: 50% 70%;
}
.declaration-cue .ellipsis .dot.dot-pulse {
  animation: dot-pulse-anim 720ms ease-in-out 1;
}

/* When reduced-motion is active, no pulse — the engine resolves the
   pulse promise instantly via its own check. Belt-and-suspenders rule
   below covers any case where someone toggles classes directly. */
body.cycle-engine-active.cycle-reduce .declaration-cue .ellipsis .dot.dot-pulse {
  animation: none;
}


/* ===== Question-mark pulse =====
   After the question typewriter finishes, the engine pulses the
   ".qmark" three times — a dramatic beat before "I say…" begins.
   Same pattern as .dot-pulse on the ellipsis. */
.script-opener .qmark {
  /* inline (not inline-block) so the "?" can't wrap onto its own line — an
     inline-block creates a soft-wrap opportunity before it. The pulse is
     opacity-only, so inline is fine. */
  display: inline;
}
.script-opener .qmark.qmark-pulse {
  animation: qmark-pulse-anim 720ms ease-in-out 1;
}
@keyframes qmark-pulse-anim {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.32; }
}
body.cycle-engine-active.cycle-reduce .script-opener .qmark.qmark-pulse {
  animation: none;
}


/* =====================================================================
   Stage Intro (Section 2) — scroll-triggered entrance + ring rotation
   ---------------------------------------------------------------------
   The intro section animates as it scrolls into view, driven by
   script/home/intro-section.js (IntersectionObserver). The engine adds
   .intro-in-view to the .stage-intro section after which these
   transitions kick in.

   Sequence (matches the engine's timeline):
     +0ms     heading floats down from above        (translateY -24 → 0)
     +400ms   subtitle fades in
     +600ms   descriptor paragraphs float up         (translateY +20 → 0)
                with a 100ms stagger between them
     +1000ms  ring starts its single slow rotation   (360°, 13s, once)
   ===================================================================== */

/* ---------- Watermark ring ----------
   Color + opacity are set on the base rule (see .stage-intro-headline-ring
   earlier in this file). Here we just add the rotation animation. */
/* One single rotation, locked at the final state via `forwards`.
   Driven by .ring-turn class added once by the IntersectionObserver
   in script/home/intro-section.js. */
@keyframes intro-ring-turn {
  from { transform: translateY(-50%) rotate(0deg);  }
  to   { transform: translateY(-50%) rotate(45deg); }
}
.stage-intro-headline-ring.ring-turn {
  animation: intro-ring-turn 13s cubic-bezier(0.4, 0, 0.2, 1) forwards 1;
}

/* ---------- Heading + subtitle + descriptor + postcard (entrance) ---------- */
/* All start hidden + offset; engine adds .intro-in-view to .stage-intro
   to trigger the staggered entrance. The whole postcard rises with
   the descriptor as a single beat. */
.stage-intro .heading-section,
.stage-intro .display-script,
.stage-intro-copy > p,
.stage-intro .video-card {
  opacity: 0;
  will-change: transform, opacity;
}
.stage-intro .heading-section {
  transform: translateY(-24px);
  transition: opacity 600ms ease-out, transform 600ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.stage-intro .display-script {
  transition: opacity 500ms ease-out 400ms;       /* +400ms delay */
}
.stage-intro-copy > p,
.stage-intro .video-card {
  transform: translateY(20px);
  transition: opacity 700ms ease-out, transform 700ms cubic-bezier(0.22, 0.61, 0.36, 1);
  transition-delay: 600ms;
}
.stage-intro-copy > p + p {
  transition-delay: 700ms;
}
/* Postcard rises with the first descriptor paragraph — one cohesive
   right-side beat instead of a separate stamp animation. */
.stage-intro .video-card {
  transition-delay: 600ms;
}

/* In-view state */
.stage-intro.intro-in-view .heading-section,
.stage-intro.intro-in-view .display-script,
.stage-intro.intro-in-view .stage-intro-copy > p,
.stage-intro.intro-in-view .video-card {
  opacity: 1;
  transform: translateY(0);
}

/* ---------- Wax seal play button ----------
   The seal is part of the postcard — it inherits the postcard's
   entrance animation (no separate stamp). Sized larger than the
   previous play button to give it presence. Shadow is a tight,
   dark contact shadow (not a material-design float) so the seal
   reads as resting ON the postcard surface. */
.video-play-btn.wax-seal {
  background: url('../assets/wax-seal.webp') center/contain no-repeat;
  border: 0;
  width: 140px;
  height: 140px;
  padding: 0;
  cursor: pointer;
  margin: 0 auto;
  align-self: center;
  position: relative;
  transition: transform 250ms cubic-bezier(0.34, 1.2, 0.64, 1);
  /* Tight, dark contact shadow + a slightly broader inner darkness.
     Total throw < 4px so it reads as pressed-onto-paper, not floating. */
  filter: drop-shadow(0 1px 1px rgba(20, 4, 4, 0.65))
          drop-shadow(0 3px 3px rgba(40, 8, 8, 0.35));
}
.video-play-btn.wax-seal::after {
  /* Play triangle as a clip-path on a filled box, so we can use inset
     box-shadow for a true INNER shadow (CSS triangles made from
     borders cannot take inset shadows). The clip-path clips the
     inset shadow to the triangle silhouette, so the dark inner edge
     reads as the glyph pressed INTO the wax. */
  content: "";
  position: absolute;
  top: 50%;
  left: 53%;
  transform: translate(-50%, -50%);
  width: 28px;
  height: 26px;
  background: #EDDFCB;
  /* Rounded triangle via clip-path: path() with cubic-bezier corners.
     Each of the three corners is softened (~3px radius) so the play
     glyph reads as a pressed-in shape, not a sharp arrowhead. Base
     widened (height 26) so the triangle reads as plump and rounded
     rather than steeply pointed. */
  clip-path: path("M 0,3 C 0,0 0,0 3,0 L 25,11 C 28,12 28,14 25,15 L 3,26 C 0,26 0,26 0,23 Z");
  box-shadow:
    inset  2px  2px 3px rgba(20, 2, 2, 0.45),
    inset -1px -1px 2px rgba(255, 240, 220, 0.30);
}
/* Hover: subtle lift, like the seal is being pressed. */
.video-play-btn.wax-seal:hover {
  transform: scale(1.04) rotate(1deg);
}
/* Reduced motion: hover effect off. */
body.cycle-engine-active.cycle-reduce .video-play-btn.wax-seal:hover {
  transform: none;
}


/* =====================================================================
   Stage Mosaic (Section 3) — stitch-in cascade
   ---------------------------------------------------------------------
   The mosaic is now inlined into home.html so each fabric square /
   image tile is a reachable <g class="mosaic-tile" style="--tile-i:N">.
   The cascade plays once when the section enters the viewport.

   Sequence:
     +0ms     section enters viewport
     +0ms     tagline ("Built by all of us...") floats up from below
     +700ms   first tile fades + scales in
     +700ms + 60ms*N   each subsequent tile (18 tiles → ~1.7s cascade tail)
   ===================================================================== */

/* ---------- Tagline entrance ---------- */
.stage-mosaic .mosaic-tagline,
.stage-mosaic .mosaic-body,
.stage-mosaic .mosaic-closer,
.stage-mosaic .mosaic-ctas {
  opacity: 0;
  transform: translateY(20px);
  will-change: opacity, transform;
  transition: opacity 900ms ease-out, transform 900ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.stage-mosaic.mosaic-in-view .mosaic-tagline { transition-delay: 0ms;    }
.stage-mosaic.mosaic-in-view .mosaic-body    { transition-delay: 350ms;  }
.stage-mosaic.mosaic-in-view .mosaic-closer  { transition-delay: 700ms;  }
.stage-mosaic.mosaic-in-view .mosaic-ctas    { transition-delay: 1000ms; }
.stage-mosaic.mosaic-in-view .mosaic-tagline,
.stage-mosaic.mosaic-in-view .mosaic-body,
.stage-mosaic.mosaic-in-view .mosaic-closer,
.stage-mosaic.mosaic-in-view .mosaic-ctas {
  opacity: 1;
  transform: translateY(0);
}

/* ---------- Tile cascade ---------- */
/* Each <g class="mosaic-tile"> starts hidden + slightly scaled down
   (with transform-box: fill-box so the scale pivots from each tile's
   own center, not the SVG root). When .mosaic-stitching lands on the
   section, the tiles fade + scale in, staggered by --tile-i. */
.stage-mosaic-svg .mosaic-tile {
  opacity: 0;
  transform: scale(0.96);
  transform-box: fill-box;
  transform-origin: center;
  transition:
    opacity   1100ms cubic-bezier(0.22, 0.61, 0.36, 1),
    transform 1100ms cubic-bezier(0.22, 0.61, 0.36, 1);
  transition-delay: calc(900ms + var(--tile-i, 0) * 110ms);
  will-change: opacity, transform;
}
.stage-mosaic.mosaic-stitching .stage-mosaic-svg .mosaic-tile {
  opacity: 1;
  transform: scale(1);
}

/* Reduced motion: snap everything to its final state, no cascade. */
body.cycle-engine-active.cycle-reduce .stage-mosaic .mosaic-tagline,
body.cycle-engine-active.cycle-reduce .stage-mosaic .mosaic-body,
body.cycle-engine-active.cycle-reduce .stage-mosaic .mosaic-closer,
body.cycle-engine-active.cycle-reduce .stage-mosaic .mosaic-ctas,
body.cycle-engine-active.cycle-reduce .stage-mosaic-svg .mosaic-tile {
  opacity: 1;
  transform: none;
  transition: none;
}


/* =====================================================================
   Topnav identity drawer (script/shared/identity-drawer.js)
   Hamburger lives in the header's third column (.header-cta), beside
   the "My 13" button. Drawer slides in from the right with a scrim.
   ===================================================================== */

/* Make the third header column a flex row so the hamburger sits next
   to the My 13 button with a gap. */
.header-cta {
  display: flex;
  align-items: center;
  gap: var(--s4);
  justify-self: end;
}

/* ---------- Hamburger ---------- */
.nav-hamburger {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;                 /* cream on the dark hero, ink elsewhere */
  cursor: pointer;
  opacity: 0.85;
  transition: opacity 180ms ease;
}
.nav-hamburger:hover { opacity: 1; }
.nav-hamburger-bars {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 20px;
}
.nav-hamburger-bars span {
  display: block;
  height: 1.5px;
  width: 100%;
  background: currentColor;
  border-radius: 1px;
}
/* (The hamburger count badge was removed — a coral alert pip read as a
   notification/warning and created anxiety. The count lives calmly
   inside the drawer instead.) */

/* ---------- Scrim ---------- */
.id-drawer-scrim {
  position: fixed;
  inset: 0;
  background: rgba(15, 12, 10, 0.42);
  opacity: 0;
  transition: opacity 320ms ease;
  z-index: 1200;
}
.id-drawer-scrim.is-open { opacity: 1; }

/* ---------- Drawer panel ---------- */
.id-drawer {
  position: fixed;
  top: 0;
  right: 0;
  height: 100vh;          /* fallback for browsers without dvh */
  height: 100dvh;         /* fit the DYNAMIC mobile viewport, not the toolbar-inclusive 100vh */
  width: min(400px, 90vw);
  background: var(--paper-soft);
  border-left: 1px solid var(--rule-2);
  box-shadow: -18px 0 50px rgba(15, 12, 10, 0.22);
  transform: translateX(100%);
  transition: transform 360ms cubic-bezier(0.22, 0.61, 0.36, 1);
  z-index: 1201;
  display: flex;
  flex-direction: column;
  overflow: hidden;       /* the head stays put; the BODY is the scroll container */
}
.id-drawer.is-open { transform: translateX(0); }

.id-drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: none;             /* fixed band; never shrinks as the body scrolls */
  padding: var(--s6) var(--s6) var(--s4);
  border-bottom: 1px solid var(--rule);
}
/* Phone: no topnav to align to inside the drawer — drop the topnav-height
   band to a snug, vertically-EVEN head so the re-seated brand and the close
   glyph share one clean centerline. (After the base so source order wins —
   a media query adds no specificity.) */
@media (max-width: 767px) {
  .id-drawer-head { padding: var(--s4) var(--s6); }
  /* Center the re-seated brand within its h2 so it shares the close glyph's
     centerline — the h2's line box otherwise leaves descent space that floats
     the inline brand above center. */
  .id-drawer-title { display: flex; align-items: center; }
}
.id-drawer-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 20px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink);
  margin: 0;
}
/* Drawer brand wordmark — hidden on desktop (title reads "Your details");
   on phones it replaces the title text (the header brand re-seats here,
   keeping the phone topbar to nav + actions). */
.id-drawer-title .id-drawer-brand { display: none; }
.id-drawer-close {
  border: 0;
  background: transparent;
  color: var(--ink-soft);
  font-size: 28px;
  line-height: 1;
  cursor: pointer;
  /* Square the hit area and FLEX-center the glyph: the "×" rides high in its
     own line box, so a plain inline button reads above the brand's midline.
     Centering it in a fixed box seats it on the head's centerline. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
}
.id-drawer-close:hover { color: var(--ink); }

.id-drawer-body {
  display: flex;
  flex-direction: column;
  gap: var(--s5);
  padding: var(--s6);
  flex: 1 1 auto;         /* fill the space under the fixed head ... */
  min-height: 0;          /* ... and allow it to shrink so overflow scrolls */
  overflow-y: auto;
}
/* Drawer edit-mode inputs: the canonical .c13-input box, but matched to the read
   field's vertical rhythm. The perforated read row (.id-field.perforated-foot)
   leaves --s4 of breathing room below the value; the canonical input's 10px
   padding-block is tighter, so toggling view->edit visibly narrowed the field.
   Match the --s4 here so the inner y-padding stays put across the toggle. The
   perforated line itself stays reserved for the READ-ONLY state (.id-field). */
.id-drawer-body .c13-input { width: 100%; padding-block: var(--s4); }
/* Confirm: a filled coral-wash pill so it reads as the clear primary
   action — distinct from the outlined input fields. Sized to its
   content (not full width) and left-aligned. */
.id-drawer-body .id-confirm { align-self: flex-end; }
/* Secondary (indigo) fill: the button carries .c13-btn-secondary.is-filled in
   the markup, so the canonical filled-secondary styling drives its colors. */

/* Invalid ZIP feedback rides next to the label — a compact coral cue ("enter
   valid zip") that appears inline when the ZIP is bad. It sits on the label's
   own line, so showing it never shifts the fields below. */
.id-zip-flag {
  font-family: var(--font-mono);
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: none;
  color: var(--coral-deep);
}
/* Gate prompt — why the drawer opened from a held pick. Plain ink, body voice. */
.id-gate-note {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--t-small);
  font-weight: 500;
  line-height: 1.4;
  color: var(--ink);
}
/* "ZIP or address" — the ZIP field doubles as an address search; suggestions drop
   into a floating list in the drawer's own colour: no box, no border — elevation
   lifts it off the panel, dotted rules separate the options. */
.id-zip-wrap { position: relative; }
.id-addr-list {
  position: absolute;
  top: 100%; left: 0; right: 0;
  z-index: 20;
  margin-top: 6px;
  max-height: 244px;
  overflow-y: auto;
  background: var(--paper-soft);
  border-radius: 6px;
  box-shadow: 0 12px 30px rgba(23, 32, 51, 0.20), 0 2px 6px rgba(23, 32, 51, 0.10);
}
.id-addr-opt {
  display: block; width: 100%;
  text-align: left;
  background: none; border: 0; cursor: pointer;
  padding: var(--s3) var(--s4);
  border-bottom: 1px dotted color-mix(in srgb, var(--ink) 30%, transparent);
}
.id-addr-opt:last-child { border-bottom: 0; }
.id-addr-opt.is-active,
.id-addr-opt:hover { background: color-mix(in srgb, var(--coral) 10%, transparent); }
.id-addr-opt-main {
  display: block;
  font-family: var(--font-body);
  font-size: var(--t-small);
  color: var(--ink);
}
.id-addr-opt-sub {
  display: block;
  font-family: var(--font-body);
  font-size: var(--t-micro);
  color: var(--ink-soft);
  margin-top: 1px;
}
.id-drawer-body input.is-invalid {
  border-color: var(--coral);
  box-shadow: 0 0 0 2px rgba(210, 74, 61, 0.18);
}

/* ---------- Confirmed (read-mode) field ----------
   Boxless: the SAME .c13-input-label as the editable input, the value as
   plain text, and an inline Edit link. Shared by the topnav drawer's
   view mode AND the my-13 identity block, so a field looks identical
   whether it's editable (input) or confirmed (read mode) — only the box
   and the control differ. */
.id-field {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
/* Perforated divider beneath a field — the ONE definition, applied to
   both the read state (.id-field) and the input state (.c13-input in
   the drawer) via this class in the markup. Pulls the dot pattern from
   the --perforated-dots token. */
.perforated-foot {
  padding-bottom: var(--s4);
  background-image: var(--perforated-dots);
  background-size: 6px 4px;
  background-repeat: repeat-x;
  background-position: bottom;
}
/* Label is .c13-input-label verbatim; when it hosts an Edit link, lay it
   out as a row with the link pushed to the right. */
.id-field .c13-input-label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s4);
}
.id-edit {
  border: 0;
  background: transparent;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
  cursor: pointer;
  padding: 0;
}
.id-edit span {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.id-edit:hover { color: var(--coral); }
.id-edit-icon {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}
.id-field-value {
  font-family: var(--font-body);
  font-size: var(--t-body);
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0.01em;
  color: var(--ink);
  margin: 0;
}
.id-field-empty {
  font-style: italic;
  color: var(--ink-soft);
}

/* ---------- Count ----------
   One calm centered line. A star-rule divider (★—line—★, as on the home
   section dividers) sits above it instead of a plain border. */
.id-count {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: 0;
  font-family: var(--font-mono);
  font-size: var(--t-small);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.id-count-rule { margin: 0; }
/* Count slip = shared c13-slip on a paper-warm surface so the grain + perforation
   read by default (not only on hover); notches stay canvas (from .c13-slip::after). */
.id-count.c13-slip {
  margin: var(--s3) 0;
  /* Symmetric inset: unlike the LEFT-aligned trait slips (whose extra-left
     padding clears the perforated tear edge), the count reads CENTERED, so
     equal insets keep the line visually balanced — no extra left. */
  padding: var(--s5);
  background: var(--paper);
  cursor: default;
}
.id-count.c13-slip:hover { background: var(--paper); }
/* Notches reveal the drawer behind the slip, so they must be the drawer color
   (--paper-soft), not --canvas. Slip is paper-warm (darker) → torn edge reads. */
.id-count.c13-slip::after { background-image: radial-gradient(circle 3.2px at center, var(--paper-soft) 96%, transparent 100%); }
/* The shared .vs-frame is inset extra-left (22 vs 14) to clear the trait slips'
   perforated tear edge — but the COUNT slip CENTERS its text, so that
   right-shifted frame crowds the line against the left rule. A symmetric inset
   re-centers the inner border on the (now symmetric) padding, so the text gets
   even breathing room on both sides. */
.id-count.c13-slip .vs-frame { inset: 14px; }
.id-count-star { font-family: var(--font-display); color: var(--coral); font-size: 17px; line-height: 1; margin-right: var(--s2); transform: translateY(-0.06em); }
.id-count-check { width: 20px; height: 20px; color: var(--coral); margin-left: var(--s2); }
.id-field .c13-input-label { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); }
.id-count-num,
.id-count-of {
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
}
/* Phone: the count must read as ONE sentence. As flex items, the "of 13
   traits chosen" span wrapped INTERNALLY beside the numeral ("13 | of 13
   traits / chosen"). At narrow widths the slip becomes centered inline
   prose — any wrap is then a natural text break — and the slip's side
   padding steps down to win back line length. */
@media (max-width: 767px) {
  .id-count { display: block; text-align: center; }
  .id-count.c13-slip { padding-inline: var(--s4); }
  .id-count-check { vertical-align: -0.28em; }
}


/* ---------- Drawer FAQ links ---------- */
.id-faq {
  padding-top: 0;
}
.id-faq-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.id-faq-list a {
  font-family: var(--font-body);
  font-size: var(--t-small);
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  padding-bottom: 1px;
  transition: color 160ms ease, border-color 160ms ease;
}
.id-faq-list a:hover {
  color: var(--coral);
  border-bottom-color: var(--coral);
}


/* ---------- my-13 identity (confirmed display above the choropleth) ----------
   Uses the shared boxless .id-field read-mode pattern — including its
   perforated divider, defined once on .id-field. This block only sets
   the column layout. */
.col-zip-identity {
  display: grid;
  gap: var(--s4);
}


/* =====================================================================
   Civic-traits hero — simple staggered fade-in on load
   The hero is above the fold, so a one-shot load animation (no scroll
   trigger) is the reliable choice: eyebrow → heading → lede fade up in
   sequence. Respects prefers-reduced-motion.
   ===================================================================== */
@keyframes traits-hero-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
/* Only the title + descriptor animate (the hero band, eyebrow, and quilt
   stay put). Both run on the SAME timing — no stagger — so there's no
   jitter. */
.traits-hero-h,
.traits-hero-lede {
  opacity: 0;
  animation: traits-hero-fade 800ms ease-out 200ms both;
}
@media (prefers-reduced-motion: reduce) {
  .traits-hero-h,
  .traits-hero-lede { animation: none; opacity: 1; transform: none; }
}


/* =====================================================================
   Character-profile hero — quick staggered fade-in on load
   Above the fold, so load-triggered (no scroll observer). Text block
   rises in sequence; the portrait art fades in alongside.
   ===================================================================== */
@keyframes cp-hero-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes cp-hero-fadein {
  from { opacity: 0; }
  to   { opacity: 1; }
}
/* Only the title group (name, "known as", trait line) rises — the
   eyebrow, star-rule, bio-meta, and the hero space itself stay put. All
   on the SAME timing (no stagger) so there's no jitter. Portrait fades. */
.stage-hero-text .heading-page,
.stage-hero-text .subheading,
.stage-hero-text .display-script {
  opacity: 0;
  animation: cp-hero-fade 800ms ease-out 120ms both;
}
.stage-hero-art {
  opacity: 0;
  animation: cp-hero-fadein 1000ms ease-out 220ms both;
}
@media (prefers-reduced-motion: reduce) {
  .stage-hero-text .heading-page,
  .stage-hero-text .subheading,
  .stage-hero-text .display-script,
  .stage-hero-art { animation: none; opacity: 1; transform: none; }
}


/* =====================================================================
   LIVE PARTICIPATION MAP  —  .stage-map
   ---------------------------------------------------------------------
   A flat US foil-outline map on a charcoal field. One ZIP "pops" at a
   time: a pseudo-3D pin drops and lands, holds for a beat, then settles
   to a small resting gold light that lingers and fades. Cadence + data
   seam live in script/map/map.js.

   Staged here for now; built DARK and cleanly bounded (every selector is
   .stage-map / .c13map-*) so it can move into the hero later untouched.

   Tokens only — charcoal field, the gold FOIL ramp, --cream text. Every
   translucent value is color-mixed FROM those tokens, so there are no
   ad-hoc color literals. NO red/blue: this must never read as partisan.

   Stack (back→front): field gradient · paper grain (.stage-noise) · foil
   SVG outline · resting lights · active pin+tag · visually-hidden live
   region (assistive text — never a total count).
   ===================================================================== */

.stage-map {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  padding-block: var(--s9) var(--s8);
  color: var(--cream);

  /* Custom motion durations. Base unit is --t-base (220ms); the drop arc
     and settle need their own longer values to feel physical, so they're
     named here and mirrored by the timing constants in script/map/map.js. */
  --c13map-drop:      450ms;   /* crisp drop + bounce (mirror DROP_MS in map.js) */
  --c13map-settle:    380ms;   /* ease back down to the surface */
  --c13map-fade:     2500ms;   /* resting light slowly recedes off (mirror LIGHT_FADE_MS in map.js) */
  --c13map-tag-delay: 300ms;   /* tag arrives just after the landing */
  --c13map-tag-float: 400ms;   /* tag's own calm float-in (no bounce) */

  /* Outline ramp. The SVG stops in home.html reference these via var().

     GOLD ramp — COMMENTED OUT while we test a coral-wash outline ("not sure
     the gold is working"). To restore the gold map: uncomment these two, delete
     the coral block below, and repoint the two foil-mid SVG stops in home.html
     back to var(--gold).
  --c13map-foil-hi: color-mix(in srgb, var(--gold-bright) 42%, var(--gold));
  --c13map-foil-lo: color-mix(in srgb, var(--gold-deep)   45%, var(--gold));
  */
  /* National outline: ORIGINAL pale coral-wash ramp (palest top-left → a touch
     deeper lower-right). Used by #c13mapFoilNat. */
  --c13map-foil-hi:  var(--coral-wash);
  --c13map-foil-mid: color-mix(in srgb, var(--coral-soft) 30%, var(--coral-wash));
  --c13map-foil-lo:  color-mix(in srgb, var(--coral-soft) 60%, var(--coral-wash));
  /* Interior state lines: deepened ramp with the brand --coral (#D24A3D)
     blended in, so they read against the dark landmass fill. Used by
     #c13mapFoilInt. */
  --c13map-foil-int-hi:  color-mix(in srgb, var(--coral) 30%, var(--coral-wash));
  --c13map-foil-int-mid: color-mix(in srgb, var(--coral) 55%, var(--coral-wash));
  --c13map-foil-int-lo:  color-mix(in srgb, var(--coral) 80%, var(--coral-wash));

  /* The dropping pin is RED — a postal "you are here", a touch deeper and
     more saturated than the coral field. Warm-red specular highlight →
     true-red body → charcoal-shaded base give a glossy 3-D bead. The light
     it settles into is coral. */
  --c13map-pin-hi:   var(--coral-soft);
  --c13map-pin:      var(--red);
  --c13map-pin-deep: color-mix(in srgb, var(--red) 58%, var(--charcoal-deepest));

  /* Field: NOT flat black — a warm lift in the upper-center falling off
     to the darkest charcoal at the corners, the same composed warmth as
     the hero. */
  background:
    radial-gradient(125% 100% at 50% 4%,
      var(--charcoal-deepest) 0%,
      var(--charcoal-deep)   24%,
      var(--charcoal-soft)   50%,
      var(--charcoal)       100%);
}
/* Shared paper-grain overlay sits above the field, below the content. */
.stage-map > .stage-noise { z-index: 0; }

.c13map-inner {
  position: relative;
  z-index: 1;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: clamp(var(--s4), 4vw, var(--page-pad));
}

/* ---- Standing copy (sheet-driven via data-cp) ---------------------- */
.c13map-head { text-align: center; margin-bottom: var(--s7); }
/* Display-script section title — coral (--coral; #E37B6E on the dark stage), the
   brand accent. When the title stood alone it was warm-cream; now the .subheading
   subtitle beneath carries the cream/light, so the title takes the warm accent and
   the pairing reads coral title over cream subtitle. (Distinct from the reserved
   pin --red — coral is the brand accent, not partisan red.) */
.c13map-title {
  font-family: var(--font-accent);   /* Italianno — display-script, same voice as "I say…" */
  font-weight: 400;
  font-style: normal;
  font-size: clamp(48px, 4.8vw + 10px, 106px);  /* scales up but reined so the 16" laptop head stays ~93 (not 100); ≈102 @1920, cap 106 */
  line-height: 0.75;
  color: var(--coral);               /* brand accent — #E37B6E on the dark stage; the subtitle carries the cream */
  letter-spacing: 0;
  margin: 0;
}

/* Map subtitle — mirrors character-profile's .subheading (Literata, --t-h3,
   --ink-soft → light on this dark stage), plus the map-context bits: centered under
   the title, a line-length cap, and the hero engine's reveal (.is-revealed) right
   after the title types in. Scoped under .c13map-head so its size out-specifies the
   base `.section p` rule (--t-body) this <p> would otherwise inherit. */
.c13map-head .c13map-subtitle {
  font-family: var(--font-display);  /* Literata serif — same face as the body text */
  font-style: normal;                /* upright, not italic — the lead's call for the map subtitle */
  font-weight: 400;
  font-size: clamp(24px, 1.8vw, 33.5px);  /* scales up with the title on large screens (≈33.5 @1920); floors at --t-h3's 24px */
  color: var(--ink-soft);            /* on dark: warm cream @ .78 */
  line-height: 1.2;
  max-width: 52ch;
  margin: var(--s5) auto var(--s3);
  text-align: center;
  opacity: 0;
  transition: opacity 1.2s ease;     /* slow fade-in; the engine reveals it (.is-revealed) after the title types */
}
.c13map-head .c13map-subtitle.is-revealed { opacity: 1; }

/* ---- Map stage + foil outline -------------------------------------- */
.c13map-stage {
  position: relative;
  width: 100%;
  max-width: 1040px;
  margin-inline: auto;
}
.c13map-svg { display: block; width: 100%; height: auto; overflow: visible; }

.c13map-interior {                 /* shared state borders — deepened coral ramp (#c13mapFoilInt) */
  fill: none;
  stroke: url(#c13mapFoilInt);
  stroke-width: 1;                 /* interior state lines */
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  opacity: 0.75;
}
.c13map-national {                 /* national outline — slightly heavier than states */
  fill: none;
  stroke: url(#c13mapFoilNat);
  stroke-width: 1.5;               /* national outline — matches interior weight */
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  opacity: 0.85;
  /* Halo REMOVED (testing a flatter outline). To restore the coral glow:
     filter: drop-shadow(0 0 3px color-mix(in srgb, var(--coral-soft) 75%, transparent)); */
}

/* ---- Overlay: pins + lights, projected by JS into % coords --------- */
.c13map-overlay { position: absolute; inset: 0; pointer-events: none; }

/* Resting WHITE light — the dot a pin LEAVES BEHIND (was gold → coral → red →
   warm candlelight → bright white; now a BRIGHT, JUST-WARM white). A bright white
   core (a little --cream warmth) → a faint warm-white halo (white with a touch of
   --gold — enough to read warm, not yellow) → transparent, so it reads as a LIT
   POINT, not a coloured target. Same recipe AND position as .c13map-pin__glow, and
   it is BORN LIT (opacity 0.85, no fade-in): the pin's base glow is already this
   colour at full strength, so when the pin lifts away the resting light is simply
   revealed as the dot left in its place — never a fresh dot fading up. The
   transition only runs on the way OUT (is-out). */
.c13map-light {
  position: absolute;
  width: 22px; height: 22px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle,
     #fbf8f4 0%,
     color-mix(in srgb, color-mix(in srgb, white 85%, var(--gold)) 42%, transparent) 46%,
     transparent 74%);
  opacity: 0.85;
  transition: opacity var(--c13map-fade) cubic-bezier(0.4, 0, 0.2, 1);
}
.c13map-light.is-lit { opacity: 0.85; }
.c13map-light.is-out { opacity: 0; }

/* ---- The pop: pseudo-3D pin ---------------------------------------- */
/* The map is a flat ground plane; the pin is the only thing with height.
   .c13map-pin is a zero-size anchor whose bottom-center sits exactly on
   the ZIP coordinate. The shadow is ground-anchored; __body (stem +
   head) is what drops, leans and settles. The tag is a separate sibling
   that floats in calmly on its own track — it must NOT bounce. */
.c13map-pin { position: absolute; transform: translate(-50%, -100%); }

.c13map-pin__shadow {              /* soft cast shadow on the map */
  position: absolute;
  left: 50%; bottom: -3px;
  width: 30px; height: 9px;
  transform: translate(-50%, 0) scale(1);
  border-radius: 50%;
  background: radial-gradient(circle,
     color-mix(in srgb, var(--charcoal) 80%, transparent) 0%,
     transparent 70%);
  opacity: 0;
}
.c13map-pin__glow {                /* WHITE light pooled at the base, centered on
                                      the tip — IDENTICAL recipe to .c13map-light
                                      so it's continuous with the dot left behind.
                                      The pin head stays RED; the light it kindles
                                      is a bright, just-warm white. */
  position: absolute;
  left: 50%; bottom: -16px;
  width: 32px; height: 32px;
  transform: translate(-50%, 0) scale(1);
  border-radius: 50%;
  background: radial-gradient(circle,
     #fbf8f4 0%,
     color-mix(in srgb, color-mix(in srgb, white 85%, var(--gold)) 42%, transparent) 46%,
     transparent 74%);
  opacity: 0;
  pointer-events: none;
}
.c13map-pin__body {                /* the standing object; base == landed */
  position: absolute;
  left: 50%; bottom: 0;
  width: 40px; height: 34px;
  transform: translate(-50%, 0) rotate(-2.5deg);
  transform-origin: 50% 100%;
}
.c13map-pin__stem { display: none; }   /* location-pin variant: the teardrop head is self-pointed — no separate stem */
.c13map-pin__head {                     /* LOCATION PIN — assets/pin-location.svg used as a MASK, so the
                                           pin keeps its established RED 3-D sheen (the SVG ships flat coral).
                                           The SVG's even-odd inner circle is a real transparent cutout, so the
                                           map shows THROUGH the hole. Pseudo-3D = the gradient bead + the
                                           drop-shadow here + __shadow (ground cast) + __glow (base light). */
  position: absolute;
  left: 50%; bottom: 0;
  width: 24px; height: 28px;            /* SVG viewBox 433×512 ≈ 0.846 aspect */
  margin-left: -12px;                   /* center the box on left:50% */
  /* red ramp: upper specular → true red → charcoal-shaded base = a glossy bead */
  background:
    radial-gradient(circle at 38% 26%,
       var(--c13map-pin-hi) 0%,
       color-mix(in srgb, var(--c13map-pin-hi) 35%, transparent) 24%,
       transparent 50%),
    linear-gradient(160deg,
       var(--c13map-pin-hi) 0%, var(--c13map-pin) 42%, var(--c13map-pin-deep) 100%);
  -webkit-mask: url('../assets/pin-location.svg') no-repeat center bottom / contain;
          mask: url('../assets/pin-location.svg') no-repeat center bottom / contain;
  /* lift it off the map — soft shadow following the pin silhouette */
  filter:
     drop-shadow(0 1px 1px color-mix(in srgb, var(--charcoal) 55%, transparent))
     drop-shadow(0 3px 4px color-mix(in srgb, var(--charcoal) 36%, transparent));
}
.c13map-pin__tag {                 /* postal slip floating beside the pin */
  position: absolute;
  left: calc(50% + 20px);   /* clear of the location pin without drifting */
  bottom: 16px;
  padding: var(--s3) var(--s4);   /* reduced x-padding on the slip */
  /* Light paper slip: flat warm cream with a single, very subtle dark
     hairline grain — mirrors .c13-slip on character-profile.html (which
     uses one faint repeating hairline on flat paper, not a heavy texture). */
  background-color: var(--cream);
  background-image:
    repeating-linear-gradient(0deg,
       color-mix(in srgb, var(--charcoal-deepest) 3%, transparent) 0 1px,
       transparent 1px 3px);
  border: 1px solid color-mix(in srgb, var(--gold-deep) 42%, transparent);
  border-radius: 3px;
  box-shadow: 0 5px 16px color-mix(in srgb, var(--charcoal) 72%, transparent);
  white-space: nowrap;
  text-align: center;               /* center the trait / place / zip stack */
  opacity: 0;
}
.c13map-tag-trait {
  display: block;
  font-family: var(--font-display);
  font-size: var(--t-body);          /* 19px — matches body text */
  font-weight: 700;                  /* bold (Literata 700 is loaded) */
  line-height: 1.15;
  color: var(--red);                 /* red, matching the drop-pin */
}
/* The gold hairline rule sits above whichever element follows the trait:
   the place name when present, otherwise the zip. */
.c13map-tag-place,
.c13map-tag-zip {
  display: block;
  margin-top: 10px;                  /* a bit more space above the hairline rule... */
  padding-top: 10px;                 /* ...and below it */
  border-top: 1px solid color-mix(in srgb, var(--gold-deep) 38%, transparent);
  letter-spacing: 0.04em;            /* shared, so neighborhood + zip track identically */
}
/* Place name — human-readable "City, ST", below the rule, above the zip. */
.c13map-tag-place {
  font-family: var(--font-ui);       /* Onest */
  font-size: 15px;
  font-weight: 500;                  /* lighter than the zip's 600 */
  line-height: 1.2;
  /* Dark ink. NOTE: both --ink (#172033) and --slate are remapped to cream inside
     the dark .stage-map, so --charcoal-deepest (#1C1A16, not stage-remapped) is used
     directly to render dark ink on the cream slip. */
  color: var(--charcoal-deepest);
}
.c13map-tag-zip {
  font-family: var(--font-ui);       /* Onest */
  font-size: 13px;                   /* up from --t-micro */
  font-weight: 600;                  /* heavier for legibility at micro size */
  color: var(--charcoal-deepest);    /* dark ink, matches the place (see its --ink/--slate remap note) */
}
/* When a place precedes the zip, the place owns the rule — the zip tucks
   directly beneath it with no second line. */
.c13map-tag-place + .c13map-tag-zip {
  margin-top: 3px;
  padding-top: 0;
  border-top: none;
}

/* Drop + spring landing, shadow, slight forward lean. The
   drop keyframe ENDS at the same transform as __body's base rule, so
   when JS swaps is-dropping → is-settling there is no jump. */
.c13map-pin.is-dropping .c13map-pin__body {
  /* linear base — each keyframe segment carries its OWN easing below, which
     is what makes the bounce read crisp (gravity-fall vs. spring-up differ). */
  animation: c13map-drop var(--c13map-drop) linear both;
}
.c13map-pin.is-dropping .c13map-pin__shadow {
  animation: c13map-shadow var(--c13map-drop) ease-out both;
}
.c13map-pin.is-dropping .c13map-pin__glow {
  /* dark until the pin makes contact (~46%), then the base light blooms */
  animation: c13map-baseglow var(--c13map-drop) ease-out both;
}
.c13map-pin.is-dropping .c13map-pin__tag {
  animation: c13map-tag-in var(--c13map-tag-float) ease-out var(--c13map-tag-delay) both;
}

@keyframes c13map-drop {
  /* fall: accelerate like gravity so the landing hits hard. opacity snaps in
     early so a SOLID object is seen dropping (not a fade). */
  0%   { opacity: 0; transform: translate(-50%, 0) translateY(-80px) scale(0.96) rotate(-2.5deg);
         animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.35); }
  16%  { opacity: 1; }
  /* contact: square hit on the baseline with a touch of squash, then spring up */
  46%  { transform: translate(-50%, 0) translateY(0)     scale(1.07) rotate(-2.5deg);
         animation-timing-function: cubic-bezier(0.1, 0.8, 0.35, 1); }
  /* the ONE rebound: spring up off the surface, slight back-lean */
  68%  { transform: translate(-50%, 0) translateY(-11px) scale(0.98) rotate(-1.8deg);
         animation-timing-function: cubic-bezier(0.45, 0, 0.5, 1); }
  /* settle: ease back down to rest — a single bounce, no second tap */
  100% { transform: translate(-50%, 0) translateY(0)     scale(1)    rotate(-2.5deg); }
}
@keyframes c13map-shadow {
  0%   { opacity: 0;    transform: translate(-50%, 0) scale(2.1); }
  60%  { opacity: 0.45; }
  100% { opacity: 0.42; transform: translate(-50%, 0) scale(1); }
}
@keyframes c13map-baseglow {
  /* stays dark through the fall; blooms only once the pin lands (~44%) */
  0%, 44% { opacity: 0;    transform: translate(-50%, 0) scale(0.5); }
  100%    { opacity: 0.85; transform: translate(-50%, 0) scale(1); }
}
@keyframes c13map-tag-in {     /* calm float up from below — no overshoot */
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Settle: tag fades, body eases back into the surface, glow/shadow off. */
.c13map-pin.is-settling .c13map-pin__body {
  transition: transform var(--c13map-settle) ease-in, opacity var(--c13map-settle) ease-in;
  transform: translate(-50%, 0) translateY(2px) scale(0.7) rotate(0deg);
  opacity: 0;
}
.c13map-pin.is-settling .c13map-pin__tag {
  transition: opacity var(--c13map-tag-float) ease-in, transform var(--c13map-tag-float) ease-in;
  opacity: 0; transform: translateY(6px);
}
.c13map-pin.is-settling .c13map-pin__shadow {
  transition: opacity var(--c13map-settle) ease-in; opacity: 0;
}
.c13map-pin.is-settling .c13map-pin__glow {
  /* fade the base glow out as the lingering resting light fades in */
  transition: opacity var(--c13map-settle) ease-in; opacity: 0;
}

/* ---- Reduced motion -----------------------------------------------
   Mirrors hero-cycle.js: the engine adds .is-reduced when
   prefers-reduced-motion is set. No drop, no bounce, no continuous
   popping — script/map/map.js switches to a calm path that just updates a
   single featured marker + the live text. The @media block is a
   belt-and-suspenders backstop if the class is ever absent. */
.stage-map.is-reduced .c13map-pin__body { animation: none; transform: translate(-50%, 0); opacity: 1; }
.stage-map.is-reduced .c13map-pin__shadow { animation: none; opacity: 0; }
.stage-map.is-reduced .c13map-pin__glow  { animation: none; opacity: 0.85; }
.stage-map.is-reduced .c13map-pin__tag  { animation: none; opacity: 1; transform: none; }
.stage-map.is-reduced .c13map-light,
.stage-map.is-reduced .c13map-pin__body,
.stage-map.is-reduced .c13map-pin__glow,
.stage-map.is-reduced .c13map-pin__tag  { transition: none; }

@media (prefers-reduced-motion: reduce) {
  .c13map-pin__body, .c13map-pin__shadow,
  .c13map-pin__glow, .c13map-pin__tag, .c13map-light {
    animation: none !important;
    transition: none !important;
  }
}

/* Visually-hidden live region — assistive text for the current pop. */
.c13map-live {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap;
}

@media (max-width: 720px) {
  .stage-map { padding-block: var(--s8) var(--s7); }
  .c13map-head { margin-bottom: var(--s6); }
}

/* =====================================================================
   MY-13 PAGE  (#my-13 = <body class="choice-body" id="my-13">)
   ---------------------------------------------------------------------
   The confirmed-13 + postcard redesign, graduated from the page's inline <style>
   into the shared sheet (no-inline-CSS rule). EVERY rule is scoped to #my-13,
   so it stays page-local exactly as it was inline. The @keyframes are global by
   nature (unique names: cm-rise, tp-hop, tp-expand, tp-pop, tp-count-pop,
   c13-trait-fade, cm-card-in). NOTE: .stage-select-inner + .trait-list also
   appear on my-communitys — candidates to merge into shared rules once that
   page is consolidated too.
   ===================================================================== */

/* Background quilt across the top two sections; replaces the flipped PNG watermark. */
#my-13 .star-rule-divider:not(.id-count-rule) { display: none; }   /* hide the hero star line, but NOT the shared drawer's count rule */
#my-13 .stage-choice .header-choice { padding-bottom: 0; }
#my-13 .stage-select-inner {
  grid-template-columns: 1fr;                      /* single column — Choose moves left; right section TBD */
  padding: var(--s7) 0;                            /* larger vertical inset; paper carries x */
}
/* The s7 (48px) vertical inset suits the wide desktop sheet but is far too much
   stacked on a phone — especially the bottom. Tighten both, the bottom most. */
@media (max-width: 767px) {
  #my-13 .stage-select-inner { padding-top: var(--s5); padding-bottom: var(--s3); }
}
/* Paper elevation. The torn-paper's clip-path is applied AFTER the filter in the
   render pipeline, so a drop-shadow on the paper gets clipped away by the torn
   silhouette. Put the shadow on this UNCLIPPED wrapper instead. */
#my-13 .stage-select-inner > .paper-elev {
  position: absolute;
  left: 0; right: 0; top: var(--s5); bottom: var(--s4);
  z-index: 0;
  pointer-events: none;
  filter:
    drop-shadow(0 1px 2px rgba(23, 32, 51, 0.18))
    drop-shadow(0 2px 4px rgba(23, 32, 51, 0.12));
}
#my-13 .stage-select-inner > .paper-elev > .bg-torn-paper {
  position: absolute; inset: 0; left: 0; right: 0; top: 0; bottom: 0;
  width: auto; margin: 0; opacity: 1; filter: none;
  background: #FDFBF8;
}
/* overflow visible restores position:sticky (floating star) and lets the paper
   drop-shadow show; no clip-path so the shadow isn't cut off. */
#my-13 .stage-select { overflow: visible; }
#my-13 .col-traits { padding: var(--s5) var(--s8) var(--s6); }   /* content sits inside the paper; extra top + bottom inset */

/* Profile link: allow it to WRAP (override the shared inline-block / max-content
   single-line rule) and sit a person icon beside it. */
#my-13 .c13-trait-item-link {
  display: flex;
  align-items: flex-start;
  gap: 5px;
  width: auto;
}
#my-13 .c13-trait-item-link-icon {
  font-size: 15px;
  line-height: 1.5;
  flex: 0 0 auto;
  text-decoration: none;
  position: relative;
  top: 1px;
}
/* keep the dotted underline on the text, not the icon */
#my-13 .c13-trait-item-link { text-decoration: none; }
#my-13 .c13-trait-item-link > span {
  text-decoration: underline dotted;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

/* Trait body: two trait columns + a third column holding the star progress meter. */
#my-13 .trait-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 400px;
  gap: var(--s7);
  align-items: start;
}
#my-13 .trait-body > .trait-list { min-width: 0; }
#my-13 .trait-progress {
  position: sticky;
  top: var(--s7);
  align-self: start;
}
#my-13 .tp-ring { width: 100%; height: auto; overflow: visible; display: block; }
/* Confirm + Start Over stacked under the star meter. */
#my-13 .star-actions {
  display: flex; flex-direction: column; align-items: center; gap: var(--s3);
  margin-top: var(--s5);
}
/* Continue only appears once all 13 are chosen (disabled until then). */
#my-13 #confirm[disabled] { display: none; }
#my-13.is-confirmed #confirm { display: none; }
#my-13.is-confirmed #reset { display: none; }   /* Start Over hidden after confirm */
#my-13 .confirmed-actions { display: none; flex-direction: column; align-items: stretch; gap: var(--s5); }
#my-13.is-confirmed .confirmed-actions { display: flex; }
/* Gate the postcard's social share buttons until the 13 are confirmed — the
   postcard itself stays a live preview; only sharing waits for the committed set. */
#my-13:not(.is-confirmed) .share-block { display: none; }
/* Share-block readiness: buttons inert until the postcard link is stored. */
#my-13 .share-btn.is-inert { opacity: .45; cursor: not-allowed; }
#my-13 .share-btn.is-inert:hover { background: transparent; color: var(--indigo); border-color: var(--rule-2); }
#my-13 .share-btn.is-fallback-hidden { display: none; }
#my-13 .share-hint { margin: var(--s3) 0 0; font-size: .82rem; color: var(--slate-soft); text-align: center; }
#my-13 .share-hint:empty { display: none; }
#my-13 .share-retry { background: none; border: 0; padding: 0; color: var(--coral); font: inherit; text-decoration: underline; cursor: pointer; }
#my-13 .confirmed-actions .c13-btn { justify-content: space-between; }
#my-13 [data-community-mirror-link].is-disabled {
  opacity: .56;
  cursor: not-allowed;
}

/* ---------- my-13 responsive (structural pass, ladder 767/991) ----------
   Document order IS the narrow layout: header (title, descriptor, actions)
   → trait list → star meter + Confirm → postcard. The desktop's side-by-side
   list/meter relationship dies on stack; the meter re-seats below the list
   at a contained scale. The postmark aside is ornament — it yields entirely
   on phones (existing 920px rule already stacks it on tablets). The top-hung
   rotating ring (status at the top edge) is NEXT round's prototype; this
   pass keeps the page correct until that mechanic lands. */
@media (max-width: 991px) {
  #my-13 .trait-body { grid-template-columns: minmax(0, 1fr); gap: var(--s6); }
  /* The s8 paper inset served the wide desktop sheet — rebalanced down-ladder
     on touch tiers (s6 here, s5 on phones). */
  #my-13 .col-traits { padding-inline: var(--s6); }
  /* The postal route-dot matrix is ornament — once the meter no longer sits
     beside the list there is no side-by-side hero either; it yields on ALL
     touch tiers (maintainer-directed 2026-06-10). */
  #my-13 .header-choice-postmark { display: none; }
  /* Sticky was a side-rail behavior — meaningless (and jumpy) stacked. */
  #my-13 .trait-progress { position: static; justify-self: center; width: auto; }
  /* The side meter's roles re-seat into the bands: ring -> top band,
     Confirm + onward -> bottom band. Only the preservation status stays
     in flow (aria-live). */
  #my-13 .trait-progress .tp-ring,
  #my-13 .trait-progress #confirm,
  #my-13 .trait-progress .confirmed-actions { display: none; }
  #my-13 .star-actions { margin-top: 0; }
  /* The lexicon popover's rightward seat assumes an open field beside the
     word — gone on touch tiers (it also overflowed the document even
     closed: hidden-but-laid-out). Re-seat it below the word, anchored to
     the row, capped to the viewport. Arrow flips to point up. */
  #my-13 .trait-row .trait-lex { position: static; }
  #my-13 .trait-row .trait-lex-pop {
    top: calc(100% + 6px); left: 0;
    max-width: min(240px, calc(100vw - var(--page-pad) * 2));
  }
  #my-13 .trait-row .trait-lex-pop,
  #my-13 .trait-row .trait-lex.is-open .trait-lex-pop { transform: none; }
  #my-13 .trait-row .trait-lex-pop::after {
    top: auto; bottom: 100%; left: 14px; right: auto;
    transform: none;
    border-color: transparent;
    border-bottom-color: rgba(23, 32, 51, 0.95);
  }
}
/* ---------- my-13 touch mechanic (<=991): pinned ring + bottombar ----
   The star meter never sits beside the list on touch tiers, so BOTH tablet
   and phone get the ring mechanic. Status owns the top edge; thumb, scroll,
   keyboard own the bottom.

   Two-state ring band: in flow below the hero it shows the ENTIRE ring
   first (with the desktop meter's count pattern in the hollow); on scroll,
   sticky with a negative top lets it ride up until only the lower arc
   peeks, then docks (count reverts to the small one-line label). Geometry
   (prototype R=118 / 30px stars, tightened per maintainer review v3):
     band height 334  · svg top -165 (ring center y=155, ring spans 22..288)
     dock peek 146    · sticky top -(334-146) = -188 → 100px of arc visible
     scrim: solid canvas to 40px above the band edge — 46px of veil below
     the ring bottom; a -40px bottom margin tucks the list up under the
     in-flow veil so the full-ring state holds no dead field below.
   Band tools (prototype pattern): Full ring left, Start over right, quiet
   corner affordances ON the band — not in the bottombar.

   Bottombar: ONE canvas + elevation bar, persistent + scroll-activated
   (body.is-bands-on, set on the beat the ring docks). Resting occupant:
   the search tool (the .search-row is re-seated here from .col-traits by
   the band script on touch tiers). At 13/13 it becomes two columns —
   Continue → right; search stays inline on tablet, collapses to an icon
   on phones (the icon summons the field as a band stacked on TOP of the
   bottombar). All new elements are display:none above 991. */
.choice-ring-band,
.choice-bottom-band { display: none; }
@media (max-width: 767px) {
  /* One reading column — but column-count:1 still establishes a MULTICOL
     container, which (as a grid item) balances against the grid-forced row
     height and reserves a tall empty tail below the last trait. `auto` drops
     the multicol context entirely → normal block flow, list ends at its content. */
  .trait-list { column-count: auto; }
  /* Phone paper inset: one ladder step above the page gutter keeps text
     clear of the torn edge without the desktop sheet's s8 field. */
  #my-13 .col-traits { padding-inline: var(--s5); }
  /* Postcard stage (torn-paper ring section): tighter vertical field on
     phones; the card itself carries the presence. */
  #my-13 .stage-ring { padding: var(--s4) var(--s4) var(--s5); }
}
@media (max-width: 991px) {
  /* ----- Ring band: full ring in flow, lower arc docked. ----- */
  #my-13 .choice-ring-band {
    display: block;
    position: sticky;
    top: -188px;                         /* rides up 188px, then docks with a 146px peek */
    z-index: var(--z-sticky);
    height: 334px;                       /* in flow: the ENTIRE ring, seen first */
    margin-bottom: -40px;                /* list tucks under the veil — no dead field */
    overflow: hidden;
    margin-inline: calc(50% - 50vw);     /* full-bleed: the band owns the edge it docks to */
    background: linear-gradient(to bottom, var(--canvas) calc(100% - 40px), rgba(253, 250, 246, 0));
    pointer-events: none;
  }
  #my-13 .choice-ring-band .ring-band-svg {
    position: absolute; top: -165px; left: 50%;
    transform: translateX(-50%);
    overflow: visible;
    transition: top 900ms cubic-bezier(0.5, 0, 0.2, 1), transform 900ms cubic-bezier(0.5, 0, 0.2, 1);
  }
  /* The wheel turns one notch per SELECTION (nadir slot = next empty seat,
     pointing at the list); stars counter-rotate to stay upright. .is-turning
     is set by the band script ONLY for single-step count changes — load/
     hydrate lands silently on the accumulated rotation (animation belongs
     to the user's act, not to restored state; maintainer ruling). */
  #my-13 .choice-ring-band.is-turning .ring-band-wheel,
  #my-13 .choice-ring-band.is-turning .ring-band-seat text {
    transition: transform 700ms cubic-bezier(0.6, 0.05, 0.25, 1);
  }
  /* Seat = the settled primitive: an outlined star that FILLS when chosen. */
  #my-13 .ring-band-seat text {
    font: 700 30px var(--font-display);
    fill: none; stroke: var(--rule-2); stroke-width: 1;
  }
  #my-13 .ring-band-seat.is-next text { stroke: var(--coral); }
  #my-13 .ring-band-seat.on text { fill: var(--coral); stroke: none; }

  /* ----- Count, two states. FULL (in flow): the desktop meter's pattern,
     proportioned to this hollow (tp-ring: 58px numeral in a 200 viewBox →
     64px in this 176px hollow; mono OF-13 line, indigo), centered on the
     ring center (y=155). DOCKED: reverts to the small one-line label
     riding the lower hollow ("chosen" drops). ----- */
  #my-13 .ring-band-count {
    position: absolute; left: 50%; top: 155px;
    transform: translate(-50%, -50%);
    display: flex; flex-direction: column; align-items: center; gap: 10px;
    text-transform: uppercase; color: var(--indigo); text-align: center;
  }
  #my-13 .ring-band-count .n { font: 700 64px/1 var(--font-display); letter-spacing: -0.02em; }
  #my-13 .ring-band-count .rbc-rest {
    font: 600 13px var(--font-mono);
    letter-spacing: 0.42em; margin-right: -0.42em;   /* optical: shed the trailing tracking */
  }
  /* "OF 13" / "CHOSEN" stack as two lines in the full face. */
  #my-13 .ring-band-count .rbc-chosen { display: block; margin-top: 4px; }
  #my-13 .choice-ring-band.is-docked .ring-band-count {
    top: auto; bottom: 100px; transform: translateX(-50%);
    flex-direction: row; align-items: baseline; gap: 0.45em;
    color: var(--ink);
  }
  #my-13 .choice-ring-band.is-docked .ring-band-count .n {
    font: 600 14px var(--font-display); letter-spacing: 0.14em; color: var(--coral);
  }
  #my-13 .choice-ring-band.is-docked .ring-band-count .rbc-rest {
    font: 600 14px var(--font-display); letter-spacing: 0.14em; margin-right: 0;
  }
  #my-13 .choice-ring-band.is-docked .rbc-chosen { display: none; }

  /* ----- Band tools: Full ring left, Start over right. Enter WITH the
     dock (hidden while the full ring shows in flow); narrow two-line
     labels so they never overlap the arc at 390. ----- */
  #my-13 .ring-band-tool {
    position: absolute; bottom: 88px;
    width: 56px;
    border: 0; background: none; cursor: pointer;
    padding: var(--s2);
    font: 500 13px/1.3 var(--font-display); color: rgba(23, 32, 51, 0.55);
    text-decoration: underline dotted;
    opacity: 0; pointer-events: none;
    transition: opacity 300ms ease;
  }
  #my-13 .ring-band-fullview { left: calc(var(--page-pad) - var(--s2)); text-align: left; }
  #my-13 .ring-band-startover { right: calc(var(--page-pad) - var(--s2)); text-align: right; }
  #my-13 .choice-ring-band.is-docked .ring-band-tool { opacity: 1; pointer-events: auto; }
  /* Post-confirm the choice is sealed — Start over yields (revision flows
     through Change My 13 Traits, as on desktop). */
  #my-13.is-confirmed .ring-band-startover { visibility: hidden; }
  #my-13 .choice-ring-band.is-fullview .ring-band-tool,
  #my-13 .choice-ring-band.is-reveal .ring-band-tool { display: none; }

  /* ----- "Full ring" view (band tool, prototype pattern): the whole ring
     over a translucent canvas veil; tap anywhere / Esc closes. The count
     keeps the FULL-state pattern, centered in the hollow (svg top 24 →
     ring center y=344). Placed AFTER the docked rules — source order. ----- */
  #my-13 .choice-ring-band.is-fullview {
    position: fixed; inset: 0; height: auto; margin: 0;
    background: rgba(253, 250, 246, 0.94);
    z-index: var(--z-floating);
    pointer-events: auto;
  }
  #my-13 .choice-ring-band.is-fullview .ring-band-svg { top: 24px; }
  /* Explicit × close (tap-anywhere and Esc also close) — only in fullview. */
  #my-13 .ring-band-close {
    display: none;
    position: absolute; top: var(--s3); right: var(--s3);
    width: 44px; height: 44px;
    align-items: center; justify-content: center;
    border: 0; background: none; cursor: pointer; color: var(--ink);
    pointer-events: auto;
  }
  #my-13 .ring-band-close svg { width: 20px; height: 20px; }
  #my-13 .choice-ring-band.is-fullview .ring-band-close { display: flex; }
  #my-13 .choice-ring-band.is-fullview .ring-band-count {
    top: 344px; bottom: auto; transform: translate(-50%, -50%);
    flex-direction: column; align-items: center; gap: 2px; color: var(--indigo);
  }
  #my-13 .choice-ring-band.is-fullview .ring-band-count .n {
    font: 700 64px/1 var(--font-display); letter-spacing: -0.02em; color: var(--indigo);
  }
  #my-13 .choice-ring-band.is-fullview .ring-band-count .rbc-rest {
    font: 600 12px var(--font-mono); letter-spacing: 0.42em; margin-right: -0.42em;
  }
  #my-13 .choice-ring-band.is-fullview .rbc-chosen { display: block; }

  /* Celebration - the ring's first full reveal (confirmed rising edge only;
     the script gates it to touch tiers + motion-ok and lifts the class).
     The ONLY elaborate motion; everything else floats gently. */
  #my-13 .choice-ring-band.is-reveal {
    position: fixed; inset: 0; height: auto; margin: 0;
    background: rgba(253, 250, 246, 0.96);
    z-index: var(--z-floating);
  }
  #my-13 .choice-ring-band.is-reveal .ring-band-svg { top: 50%; transform: translate(-50%, -50%); }
  #my-13 .choice-ring-band.is-reveal .ring-band-count { opacity: 0; }
  #my-13 .ring-band-reveal-line {
    position: absolute; left: 0; right: 0; top: calc(50% + 200px);
    margin: 0; text-align: center;
    font: 600 22px var(--font-display); color: var(--ink);
    opacity: 0; transition: opacity 600ms ease 1100ms;
  }
  #my-13 .choice-ring-band.is-reveal .ring-band-reveal-line { opacity: 1; }

  /* ----- Bottombar: canvas + elevation, persistent + scroll-activated. ----- */
  #my-13 .choice-bottom-band {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--s4);
    position: fixed; left: 0; right: 0; bottom: 0;
    z-index: var(--z-sticky);
    min-height: 56px;
    padding: var(--s2) var(--page-pad) calc(var(--s2) + env(safe-area-inset-bottom, 0px));
    background: var(--canvas);
    box-shadow: 0 -18px 50px -16px rgba(23, 32, 51, 0.28);
    transform: translateY(130%);
    transition: transform 360ms ease;
    pointer-events: none;
  }
  /* transform: none (NOT translateY(0)) — a transformed bar would become
     the containing block for the fixed search pop-band inside it. */
  #my-13.is-bands-on .choice-bottom-band { transform: none; pointer-events: auto; }
  /* CTA state (Continue / Community) reads a touch more elevated than the resting
     search bar — a slight extra lift when the bar is prompting an action. */
  #my-13.is-thirteen .choice-bottom-band,
  #my-13.is-confirmed .choice-bottom-band {
    box-shadow: 0 -18px 50px -16px rgba(23, 32, 51, 0.28),
                0 -3px 12px -2px rgba(23, 32, 51, 0.15);
  }

  /* Search seated in the bar: shed the desktop row's framing. */
  #my-13 .choice-band-search-slot { flex: 1; min-width: 0; display: flex; }
  #my-13 .choice-band-search-slot .search-row {
    flex: 1; display: flex; margin: 0; padding: 0;
    background: none; box-shadow: none;
  }
  #my-13 .choice-band-search-slot .c13-input { flex: 1; }
  /* In the bar the input sheds its box — a line only (dotted rule); the
     bar itself is the surface. */
  #my-13 .choice-band-search-slot .c13-input,
  #my-13 .choice-band-search-slot .c13-input input {
    background: none; border: 0; box-shadow: none;
  }
  #my-13 .choice-band-search-slot .c13-input { padding: 4px 0; }
  /* Lift the placeholder off the dotted line so it isn't jammed against it; the
     icon + input stay centered (align-items:center) in the space above. */
  #my-13 .choice-band-search-slot .c13-input-row { border-bottom: 1px dotted var(--rule-2); padding-bottom: 5px; }
  /* The slim band has no room for a caption; the placeholder carries it. */
  #my-13 .search-row .c13-input-label { display: none; }
  /* Start Over re-seats onto the ring band (prototype pattern). */
  #my-13 .search-row #reset { display: none; }
  /* The re-seated search-row is persistent bar chrome, NOT entrance content: the
     reveal IntersectionObserver never fires for it inside the fixed, transform-
     hidden bar, so its c13-reveal fade strands it at opacity:0 — an EMPTY bar.
     Pin it visible (.c13-reveal in the selector out-specifies the reveal's
     #my-13.reveal-ready .c13-reveal opacity:0). */
  #my-13 .choice-band-search-slot .search-row.c13-reveal { opacity: 1; transform: none; }
  /* Mobile-only declutter: while a touch search is active, hide the postcard +
     postal strip + footer so the trait results own the screen. visibility (NOT
     display) keeps their boxes, so the page height — and the scroll/dock math —
     don't jump. (is-searching is only set on touch tiers; this block is ≤991 too.) */
  #my-13.is-searching .stage-ring,
  #my-13.is-searching .bg-postal-strip,
  #my-13.is-searching .footer { visibility: hidden; }

  /* Icon-only search toggle becomes a full cell: icon + "Search" — the
     home-bottombar register (icon and text, no button chrome). */
  #my-13 .choice-band-search-toggle {
    display: none;
    flex: 1 1 50%; min-width: 0;
    min-height: 44px;
    align-items: center; justify-content: center; gap: var(--s2);
    border: 0; background: none; cursor: pointer;
    font: 600 17px var(--font-display); color: var(--ink);
  }
  #my-13 .choice-band-search-toggle svg { width: 20px; height: 20px; }

  /* State CTA cell: plain icon + text in the bar's own register — the
     desktop/home pattern. NO button chrome, no separate color; the two
     columns divide on a dotted rule. */
  #my-13 .choice-band-continue,
  #my-13 .choice-band-community {
    display: none;
    flex: 1 1 50%; min-width: 0;
    min-height: 44px;
    align-items: center; justify-content: center; gap: var(--s2);
    border: 0; background: none; cursor: pointer;
    border-left: 1px dotted var(--rule-2);
    font: 600 17px var(--font-display); color: var(--ink);
    text-align: center; text-decoration: none;
  }
  #my-13.is-thirteen:not(.is-confirmed) .choice-band-continue { display: flex; }
  #my-13.is-confirmed .choice-band-community { display: flex; }
  #my-13 .choice-band-community[aria-disabled="true"] { opacity: 0.55; pointer-events: none; }
  /* At 13/13 the search side is the matching half-column. */
  #my-13.is-thirteen .choice-band-search-slot { flex: 1 1 50%; }

  /* The page's last content must clear the bar. */
  #my-13 { padding-bottom: calc(72px + env(safe-area-inset-bottom, 0px)); }
}
/* Tablet at 13/13: the field stays inline — search 60% / Continue 40%. */
@media (min-width: 768px) and (max-width: 991px) {
  #my-13.is-thirteen .choice-band-search-slot { flex: 0 1 60%; }
  #my-13.is-thirteen .choice-band-continue,
  #my-13.is-confirmed .choice-band-community { flex: 0 1 40%; }
}
/* Phone at 13/13: the field yields to the icon; tapping it summons the field
   as its own band stacked ON TOP of the bottombar (canvas, dotted seam).
   AFTER the 991 block — source order. */
@media (max-width: 767px) {
  #my-13.is-thirteen .choice-band-search-slot { display: none; }
  /* The in-flow band holds no dead field below the stars on phones: the
     veil tail + the trait-body gap collapse to a quiet row gap (~22px). */
  #my-13 .choice-ring-band { margin-bottom: -56px; }
  #my-13.is-thirteen .choice-band-search-toggle { display: inline-flex; }
  #my-13.is-thirteen.is-search-open .choice-band-search-slot {
    display: flex;
    /* The slot is a CHILD of the (positioned) bar: absolute + bottom:100%
       seats it exactly on top of the bar at any bar height. */
    position: absolute; left: 0; right: 0; bottom: 100%;
    padding: var(--s2) var(--page-pad);
    background: var(--canvas);
    border-bottom: 1px dotted var(--rule-2);
    box-shadow: 0 -18px 50px -16px rgba(23, 32, 51, 0.28);
  }
}
/* Initial entrance: a gentle float-in only (the celebration is the one
   elaborate animation). Base state is visible; motion only when allowed. */
@keyframes ring-band-float-in {
  from { opacity: 0; transform: translateY(12px); }
}
@media (max-width: 991px) and (prefers-reduced-motion: no-preference) {
  #my-13 .choice-ring-band { animation: ring-band-float-in 700ms cubic-bezier(0.2, 0.6, 0.2, 1); }
}
@media (max-width: 991px) and (prefers-reduced-motion: reduce) {
  #my-13 .choice-ring-band .ring-band-svg,
  #my-13 .choice-ring-band.is-turning .ring-band-wheel,
  #my-13 .choice-ring-band.is-turning .ring-band-seat text,
  #my-13 .ring-band-tool,
  #my-13 .choice-bottom-band { transition: none; }
}
#my-13 .choice-preservation-status {
  min-height: 2.4em;
  margin: 0;
  max-width: 26ch;
  color: var(--slate-soft);
  font: 500 .78rem/1.45 var(--font-sans);
  text-align: center;
}
#my-13 .choice-preservation-status:empty { display: none; }
#my-13 .choice-status-retry {
  margin: var(--s1) 0 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--coral);
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}
/* Onward actions mirrored at the top (below descriptor) for returning visitors. */
#my-13 .choice-top-actions { display: none; align-items: center; gap: var(--s5); margin-top: var(--s4); }
/* The separate onward-actions row is folded into the descriptor's SHARE/SEE lines
   (the inline .descriptor-cue links), so it no longer surfaces post-confirm. */
/* Post-confirm: hide the Choose bullet points (the 13 are chosen) while keeping
   the Choose / Share / See lines — the Share/See cues now lead (maintainer-ruled). */
#my-13.is-confirmed .header-choice .lede ul { display: none; }
#my-13 .choice-top-sep { color: var(--rule-3); }
/* Sealed dispatch: drop the per-trait × remove controls in the postcard ring once confirmed. */
#my-13.is-confirmed .ring-label-x,
#my-13.is-confirmed .ring-label-x-bg { display: none; }
/* After the celebration settles, nudge "My Community's 13" once to draw the eye. */
@keyframes cm-rise { 0% { transform: translateY(0); } 26% { transform: translateY(-10px); } 48% { transform: translateY(0); } 72% { transform: translateY(-4px); } 100% { transform: translateY(0); } }
#my-13.is-confirmed #share-13 { animation: cm-rise 1200ms ease-in-out 2200ms both; }
@media (prefers-reduced-motion: reduce) { #my-13.is-confirmed #share-13 { animation: none; } }
/* When 13 are chosen, blocked (unselected) traits dim slightly. */
#my-13 .c13-trait-item.is-blocked { color: var(--slate-soft); }
#my-13 .c13-trait-item.is-blocked .c13-trait-item-mark { color: var(--slate-soft); }
#my-13 .c13-trait-item.is-blocked .trait-lex { color: var(--ink); }
#my-13 .trait-row:has(> .c13-trait-item.is-blocked) .c13-trait-item-desc { opacity: 0.6; }
#my-13 .c13-trait-item.is-locked { cursor: not-allowed; }
#my-13 .c13-trait-item.is-locked:not([aria-pressed="true"]) {
  color: var(--slate-soft);
}
/* Search + Start Over share a row. */
#my-13 .search-row { display: flex; align-items: flex-end; gap: var(--s5); }
#my-13 .search-row .c13-input { flex: 1 1 auto; min-width: 0; }
#my-13 .search-row #reset { flex: 0 0 auto; white-space: nowrap; margin-bottom: var(--s2); align-self: center; }
#my-13 .tp-slot {
  font-family: var(--font-display);
  font-size: 22px;
  fill: var(--coral-wash);
  fill-opacity: 1;
  text-anchor: middle;
  dominant-baseline: middle;
  transition: fill 260ms ease, fill-opacity 260ms ease;
}
#my-13 .tp-slot.filled { fill: var(--coral); fill-opacity: 1; }
/* Confirm celebration — one jump + a slow star burst sweep + a gentle count pop. */
#my-13 .tp-slot { transform-box: fill-box; transform-origin: center; }
@keyframes tp-hop {
  0% { transform: translateY(0); }
  16% { transform: translateY(-24px); }
  86% { transform: translateY(-24px); }
  100% { transform: translateY(0); }
}
@keyframes tp-expand {
  0%, 64% { transform: scale(1); }
  78% { transform: scale(1.16); }
  88% { transform: scale(1.16); }
  100% { transform: scale(1); }
}
@keyframes tp-pop {
  0% { transform: scale(0.6); }
  50% { transform: scale(1.7); }
  100% { transform: scale(1); }
}
@keyframes tp-count-pop {
  0% { transform: scale(0.6); opacity: 0.3; }
  60% { transform: scale(1.15); }
  100% { transform: scale(1); opacity: 1; }
}
#my-13.is-confirmed .tp-ring { animation: tp-hop 2100ms cubic-bezier(0.45, 0, 0.3, 1) both; transform-origin: center bottom; }
#my-13.is-confirmed .tp-slots { transform-box: fill-box; transform-origin: center; animation: tp-expand 2100ms ease both; }
#my-13.is-confirmed .tp-slot.filled { animation: tp-pop 640ms cubic-bezier(0.34, 1.5, 0.5, 1) both; animation-delay: calc(360ms + var(--i, 0) * 40ms); }
#my-13.is-confirmed .tp-count { transform-box: fill-box; transform-origin: center; animation: tp-count-pop 560ms ease 380ms both; }
@media (prefers-reduced-motion: reduce) {
  #my-13.is-confirmed .tp-ring, #my-13.is-confirmed .tp-slots, #my-13.is-confirmed .tp-slot.filled,
  #my-13.is-confirmed .tp-count { animation: none; }
}
/* Post-confirm: the meter star center stamps "SENT" in place of the count. */
#my-13 .tp-chosen {
  display: none;
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.32em;
  fill: var(--coral);
  text-anchor: middle;
  dominant-baseline: middle;
}
#my-13.is-confirmed .tp-of { display: none; }   /* "OF 13" → "SENT"; the count stays */
#my-13.is-confirmed .tp-chosen {
  display: block;
  transform-box: fill-box; transform-origin: center;
  animation: tp-count-pop 560ms ease 600ms both;
}
@media (prefers-reduced-motion: reduce) { #my-13.is-confirmed .tp-chosen { animation: none; } }
#my-13 .tp-count {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 58px;
  fill: var(--indigo);
  dominant-baseline: middle;
  letter-spacing: -0.02em;
}
#my-13 .tp-of {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.42em;
  fill: var(--indigo);
  dominant-baseline: middle;
}
/* Trait lexicon tooltip — info icon beside the trait name; hover/focus reveals
   a dark tooltip above the icon, with a leftward arrow. */
#my-13 .trait-row { position: relative; }
#my-13 .trait-row:has(.trait-lex.is-open) { z-index: 50; }   /* lift the open tooltip's row above later rows */
#my-13 .trait-lex {
  position: relative;
  display: inline-flex; align-items: center;
  margin-left: 6px; cursor: pointer; color: var(--ink);
  vertical-align: middle;
  transition: color 160ms ease;
}
#my-13 .trait-lex:hover { color: var(--indigo); }
#my-13 .trait-lex-ic { font-size: 20px; line-height: 1; margin-top: -1px; }
#my-13 .trait-lex-pop {
  position: absolute; top: 50%; left: calc(100% + 10px);
  width: max-content; max-width: 240px; z-index: 40;
  display: grid; gap: 4px;
  padding: 12px 14px;
  background: rgba(23, 32, 51, 0.95);   /* ink, slight opacity */
  border-radius: 6px;
  box-shadow: 0 10px 26px rgba(23, 32, 51, 0.28);
  opacity: 0; visibility: hidden;
  transform: translateY(-50%) translateX(4px);
  transition: opacity 150ms ease, transform 150ms ease;
  pointer-events: none;
  text-align: left;
}
/* leftward arrow */
#my-13 .trait-lex-pop::after {
  content: ""; position: absolute; top: 50%; right: 100%;
  transform: translateY(-50%);
  border: 6px solid transparent; border-right-color: rgba(23, 32, 51, 0.95);
}
#my-13 .trait-lex.is-open .trait-lex-pop { opacity: 1; visibility: visible; transform: translateY(-50%) translateX(0); }
#my-13 .trait-lex-word { font-family: var(--font-display); font-weight: 600; font-size: var(--t-body); color: #fff; }
#my-13 .trait-lex-word .syl { color: var(--blush); }
#my-13 .trait-lex-meta { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.04em; color: rgba(255, 255, 255, 0.6); }
#my-13 .trait-lex-def { font-family: var(--font-body); font-size: var(--t-small); line-height: 1.5; color: rgba(255, 255, 255, 0.85); }
/* Trait descriptor icon — small quote/gloss mark before the keywords. */
#my-13 .c13-trait-item-desc { display: flex; align-items: baseline; gap: 5px; }
#my-13 .c13-trait-item-desc-icon { flex: 0 0 auto; font-size: 15px; color: var(--slate-soft); position: relative; top: 2px; }
#my-13 .stage-select-inner::before,
#my-13 .stage-select-inner::after { display: none; }      /* drop the vertical divider + star */
#my-13 .stage-select { margin-bottom: 0; }                /* paper runs to the section foot */
/* Content sits above the fixed quilt layer. */
#my-13 .page, #my-13 .stage-choice { position: relative; z-index: 1; }
/* Canvas-color blocks that mask the quilt. A 100vw centered pseudo paints canvas
   edge-to-edge; the topnav band carries the bottom rule. */
#my-13 > .page > .header,
#my-13 .footer { position: relative; background: transparent; border-bottom: 0; }
#my-13 > .page > .header::before,
#my-13 .footer::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 50%;
  width: 100vw; transform: translateX(-50%);
  background: var(--canvas);
  z-index: -1;
}
#my-13 > .page > .header::before { border-bottom: 1px solid var(--rule); }
/* CANVAS (cream) on the live page — covers the background quilt so the card
   reads as warm paper. The render service injects a WHITE background for the
   EXPORTED PNG only, so the shared / downloaded / printed card blends into white
   feeds and prints no background-color fill. See render-service/server.js. */
#my-13 .ring-postcard { background: var(--canvas); }
/* This page: the postcard's links inherit text color (currentColor), not global coral. */
#my-13 .ring-postcard a { color: currentColor; }
/* Postcard: trim the tall vertical padding now that the buttons are gone. */
#my-13 .ring-postcard { padding-block: 24px; }
/* Postcard body (right column = script title + star ring): top padding sets the
   personalized line's height. 29px = --s6 (32) lifted 3px (Jinn, June 12) so the
   head block sits a touch higher. Sub-token by design — a 2-4px nudge lands
   between --s5/--s6. The brand in the left rail tracks this 8px lower to stay
   ink-aligned with the line's top (see .ring-rail-left padding-top). */
#my-13 .ring-center-col { padding-top: 29px; }
/* Rail/body divider: dotted to match the perforated vocabulary. */
#my-13 .ring-postcard::before { width: 0; background: none; border-left: 1px dotted var(--rule-2); }
/* Align the share block's bottom with the divider's bottom. The trimmed 24px
   vertical padding sits INSIDE the divider's --s6 inset, so the block otherwise
   hangs --s2 below the dotted line; this lifts it to meet it.
   (On-page only — render-service/server.js hides .share-block in the PNG.) */
#my-13 .ring-rail-left .share-block { margin-bottom: var(--s2); }
/* Postal strip sits over the fixed quilt — canvas base so the airmail dashes read on canvas. */
#my-13 .bg-postal-strip { background-color: var(--canvas); }
/* 100vw full-bleed bands can exceed the content width by the scrollbar — clip the overflow. */
#my-13 { overflow-x: clip; }
/* Quilt promoted to a fixed, whole-page texture layer behind everything. */
#my-13 .band-quilt > svg.cm-quilt,
#my-13 #my13-quilt {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  z-index: 0;
  pointer-events: none;
  opacity: 0.95;
  /* Tactile thread: light highlight on top, soft shadow beneath. */
  filter:
    drop-shadow(0 1px 0.7px rgba(21, 16, 7, 0.175));
}
/* Slices unfilled (canvas shows through); the STITCH carries the tone. */
#my-13 .cm-quilt-stitches { stroke: #F7F2E8; }           /* cream thread */
/* ---- Entrance: float-in for title/descriptor/ring; fade for everything else ----
   .c13-reveal = fade only; add .c13-float to ALSO translate up. Gated by
   body.reveal-ready + prefers-reduced-motion; end state transform:none keeps the
   sticky .trait-progress meter intact. */
@media (prefers-reduced-motion: no-preference) {
  #my-13.reveal-ready .c13-reveal {
    opacity: 0;
    transition: opacity 700ms cubic-bezier(0.22, 0.61, 0.36, 1),
                transform 700ms cubic-bezier(0.22, 0.61, 0.36, 1);
  }
  #my-13.reveal-ready .c13-reveal.c13-float { transform: translateY(28px); }
  #my-13.reveal-ready .stage-ring.c13-reveal.c13-float { transform: translateY(48px); }
  #my-13.reveal-ready .c13-reveal.is-in { opacity: 1; transform: none; }
  /* Sheet-wired blocks (.c13-cp) reveal only after content settles: content.js adds
     <html>.cp-ready-my13 once the loader fills the DOM. Fail-open: opacity resolves
     to a static 1 here, so content shows even if the transition can't run. */
  html.cp-ready-my13 #my-13.reveal-ready .c13-cp { opacity: 1; transform: none; }

  /* Trait rows fade in TOGETHER when the list populates -- no per-row stagger.
     The old stagger (40ms x index, ~1.7s across 42 rows) cascaded the list in
     top-to-bottom, leaving the lower rows empty during the fill; one shared
     fade reads as the list arriving as a whole. */
  @keyframes c13-trait-fade { from { opacity: 0; } to { opacity: 1; } }
  #my-13.reveal-ready .trait-list > .trait-row {
    animation: c13-trait-fade 450ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
  }
}

/* ===== Confirmation modal — "Continue" opens it; the coral "Confirm My 13
   Traits" inside is the real commit (adds #my-13.is-confirmed). ===== */
#my-13 .cm-modal {
  position: fixed; inset: 0; z-index: 1000;
  display: none; place-items: safe center; padding: 24px;
  overflow-y: auto;
}
#my-13.cm-open .cm-modal { display: grid; }
#my-13 .cm-modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(18, 17, 16, 0.55);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
}
#my-13 .cm-modal-card {
  position: relative; z-index: 1;
  width: min(900px, 94vw);
  background: var(--canvas);
  border: 1px solid var(--rule);
  padding: 30px 40px 34px;
  text-align: center;
  box-shadow: 0 24px 64px rgba(18, 17, 16, 0.34);
  animation: cm-card-in 300ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
@keyframes cm-card-in {
  from { transform: translateY(12px) scale(0.985); }
  to   { transform: none; }
}
#my-13 .cm-modal-close {
  position: absolute; top: var(--s4); right: var(--s4); z-index: 2;
  padding: var(--s1) var(--s2);
}
#my-13 .cm-close-label {
  font-family: var(--font-mono); font-weight: 600;
  font-size: var(--t-small); letter-spacing: 0.14em; text-transform: uppercase;
  line-height: 1;
}
#my-13 .cm-close-x { width: 1.1em; height: 1.1em; display: block; }
#my-13 .cm-modal-title {
  font-family: var(--font-accent); font-weight: 400;
  font-size: clamp(42px, 3vw + 16px, 60px);
  line-height: 1; color: var(--coral); margin: 0 0 28px;
}
#my-13 .cm-ring-host.stage-ring {
  display: block; padding: 0; min-height: 0; margin: 0 auto 26px;
}
#my-13 .cm-ring-host svg.ring {
  width: 100%; max-width: 400px; height: auto;
  display: block; margin: 0 auto; overflow: visible;
}
/* List view of the 13 (shown <=991 in place of the ring snapshot — the
   display swap lives in the touch-mechanic block). */
#my-13 .cm-trait-list {
  display: none;
  list-style: none;
  margin: 0 auto 26px; padding: 0;
  max-width: 420px; max-height: 52vh; overflow-y: auto;
  text-align: left;
}
#my-13 .cm-trait-list li {
  display: flex; align-items: baseline; gap: var(--s3);
  padding: 9px 2px 10px;
  font: 600 var(--t-body)/1.3 var(--font-display);
  color: var(--ink);
  border-bottom: 1px dotted var(--rule-2);
}
#my-13 .cm-trait-list li:last-child { border-bottom: 0; }
#my-13 .cm-trait-list .cm-li-star { color: var(--coral); flex: none; }
/* Touch tiers confirm with the LIST, not the ring snapshot (the ring is the
   desktop's spatial story; at phone scale a list is the readable
   confirmation). Sits AFTER the base rules — source order, again. */
@media (max-width: 991px) {
  #my-13 .cm-ring-host.stage-ring { display: none; }
  #my-13 .cm-trait-list { display: block; }
}
#my-13 .cm-modal-confirm { min-width: 220px; }
#my-13 .cm-modal-foot { display: flex; align-items: center; justify-content: center; gap: var(--s5); flex-wrap: wrap; }
#my-13 .cm-foot-sep { color: var(--rule-3); }
/* Bigger on desktop. */
@media (min-width: 1024px) {
  #my-13 .cm-modal-card { width: min(1100px, 92vw); padding: 42px 60px 46px; }
  #my-13 .cm-ring-host svg.ring { max-width: 560px; }
}
@media (prefers-reduced-motion: reduce) {
  #my-13 .cm-modal, #my-13 .cm-modal-card { transition: none; }
}
/* ===== end MY-13 PAGE ===== */

/* =====================================================================
   MY-COMMUNITYS-13 PAGE  (#my-communitys-13 = <body class="choice-body" id="my-communitys-13">)
   ---------------------------------------------------------------------
   The community-mirror redesign (resonance map + community top-13 slips),
   graduated from the page's inline <style id="cm-redesign"> into the shared
   sheet. Every rule scoped to #my-communitys-13 so it stays page-local. The
   @keyframes (rmap-bloom / shimmer / fade / pulse) are global (unique names).
   The resonance-ramp tokens (--ch-1..5) are the separate #my-communitys-13 rule
   already in this sheet (the "Resonance ramp" section above).
   NOTE: .stage-select-inner is overridden differently here (2-col map grid) than
   on my-13 (1-col) — intentional per-page, NOT a drift to merge.
   ===================================================================== */

/* Background quilt: none — plain canvas while the treatment is decided. */
/* Thin "quiet" postal strip — flatter, wider, more-spaced bunting than the dense
   full strip (#my-communitys-13 beats .choice-body). */
#my-communitys-13 .bg-postal-strip {
  height: 9px;
  margin: var(--s6) 0 0;
  background: var(--canvas)
    url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='68'%20height='9'%20viewBox='0%200%2068%209'%3E%3Cpolygon%20points='4,0%2026,0%2022,9%200,9'%20fill='%23BF2D20'/%3E%3Cpolygon%20points='38,0%2060,0%2056,9%2034,9'%20fill='%23123B66'/%3E%3C/svg%3E")
    repeat-x left center;
  background-size: 68px 9px;
  opacity: 0.82;
  filter: none;
}
#my-communitys-13 .bg-postal-strip::before,
#my-communitys-13 .bg-postal-strip::after { content: none; }
/* Callout = the neighbourhood NAME floating just above the focal ring, with the
   ZIP sitting INSIDE the ring as its badge. */
#my-communitys-13 .choropleth-callout .cc-place {
  position: absolute; left: 50%; bottom: calc(100% + 40px); transform: translateX(-50%);
  margin: 0; white-space: nowrap; font-family: var(--font-display); font-weight: 700;
  font-size: 30px; letter-spacing: -0.01em; color: var(--ink); line-height: 1;
  text-shadow: 0 0 5px var(--canvas), 0 0 3px var(--canvas), 0 1px 2px rgba(23, 32, 51, 0.22);
}
#my-communitys-13 .choropleth-callout .cc-zip {
  margin: 0; font-family: var(--font-mono); font-weight: 700; font-size: 11px;
  letter-spacing: 0.04em; color: color-mix(in srgb, var(--ink) 82%, transparent); line-height: 1;
}
/* Drop the shared select stage's side padding so the map + slips fill the full
   --page-max (the 580 map col + a Responsibility-wide slips col need the width). */
#my-communitys-13 .stage-select-inner { --cm-map-col: 580px; padding-top: var(--s3); padding-inline: 0; grid-template-columns: minmax(0, var(--cm-map-col)) minmax(0, 1fr); }
/* Re-anchor the inherited divider + star to THIS map column's edge. */
#my-communitys-13 .stage-select-inner::before,
#my-communitys-13 .stage-select-inner::after { left: calc(var(--cm-map-col) + var(--s9) / 2); }
/* Under 1280, stack: community-13 on top, the map capped below; restore
   gutters — on the HERO too, same beat: the star-rule divider must always
   share the select section's content width (at ≥1280 both run page-max
   ungutteRed; below, both carry --page-pad). */
@media (max-width: 1279px) {
  #my-communitys-13 .stage-select-inner { grid-template-columns: minmax(0, 1fr); padding-inline: var(--page-pad); }
  #my-communitys-13 .stage-choice .header-choice { padding-inline: var(--page-pad); }
  #my-communitys-13 .col-community-13 { order: -1; }
  #my-communitys-13 .stage-select-inner::before,
  #my-communitys-13 .stage-select-inner::after { display: none; }
  #my-communitys-13 .col-zip { width: min(720px, 100%); margin-inline: auto; }
}
#my-communitys-13 .col-zip { padding-top: var(--s3); padding-inline: 0; align-content: start; }
#my-communitys-13 .cm-hero { max-width: var(--page-max); margin: 0 auto; padding: var(--s2) 0 var(--s4); text-align: center; }
#my-communitys-13 .cm-title { font-family: var(--font-accent); font-weight: 400; font-size: clamp(50px, 7vw + 18px, 96px); line-height: 0.95; color: #6B4A63; margin: 0; }
#my-communitys-13 .cm-subtitle { font-family: var(--font-mono); font-weight: 500; font-size: 17px; letter-spacing: 0.12em; text-transform: uppercase; color: #8A6A80; margin: var(--s2) 0 var(--s4); }
#my-communitys-13 .cm-back-ic { width: 1em; height: 1em; }
#my-communitys-13 .cm-descriptor { font-family: var(--font-body); font-size: var(--t-body); line-height: 1.55; color: var(--ink); max-width: 58ch; margin: var(--s3) auto 0; }
#my-communitys-13 .cm-mode-copy {
  margin: 0;
  color: var(--slate-soft);
  font: 600 .86rem/1.45 var(--font-sans);
  letter-spacing: .02em;
}
/* Hero runs the FULL --page-max width (no --page-pad gutters). */
#my-communitys-13 .stage-choice .header-choice { padding-inline: 0; }
/* Descriptor (+ back link) on the left, seal-ring on the right. */
#my-communitys-13 .cm-desc-row { display: grid; grid-template-columns: 1fr auto; gap: var(--s7); align-items: center; max-width: 780px; margin: var(--s3) auto 0; text-align: left; }
#my-communitys-13 .cm-desc-text { display: grid; gap: var(--s4); justify-items: start; }
#my-communitys-13 .cm-desc-text .cm-descriptor { margin: 0; max-width: none; }
#my-communitys-13 .cm-desc-text .cm-back { margin: 0; }
#my-communitys-13 .cm-desc-seal { width: 168px; height: 168px; flex: none; color: var(--coral); }
#my-communitys-13 .cm-desc-seal svg { width: 100%; height: 100%; display: block; }
/* Numeral proportion matches the home seal exactly (30px on the 120 viewBox). */
#my-communitys-13 .cm-seal-num { fill: var(--indigo); font-family: var(--font-display); font-weight: 600; font-size: 30px; letter-spacing: -0.01em; text-anchor: middle; dominant-baseline: central; }
#my-communitys-13 .col-community-13 { display: grid; gap: var(--s5); align-content: start; min-width: 0; padding-inline: 0; }
#my-communitys-13 .col-community-13 .header-trait-list { display: block; }
#my-communitys-13 .col-community-13 .status-trait-list { margin-top: var(--s2); }
#my-communitys-13 .lead > p { font-weight: 600; }
#my-communitys-13 .cm13-intro { margin-top: 0; padding-block: 0 var(--s4); border: 0; }
#my-communitys-13 .cm13-intro > p { max-width: none; color: var(--ink); white-space: nowrap; }
#my-communitys-13 .col-community-13 .cm13-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); }
#my-communitys-13 .cm13-slip {
  position: relative; display: flex; align-items: center; min-width: 0; min-height: 72px;
  padding: var(--s4) var(--s5) var(--s4) var(--s6);
  background: var(--paper-soft); isolation: isolate; overflow: hidden;
}
#my-communitys-13 .cm13-slip::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image: repeating-linear-gradient(0deg, rgba(23,32,51,0.022) 0 1px, transparent 1px 3px);
}
#my-communitys-13 .cm13-slip::after {
  content: ""; position: absolute; left: -3px; top: 0; bottom: 0; width: 7px; z-index: 1; pointer-events: none;
  background-image: radial-gradient(circle 3.2px at center, var(--canvas) 96%, transparent 100%);
  background-size: 7px 11px; background-repeat: repeat-y; background-position: center 6px;
}
#my-communitys-13 .cm13-slip .vs-frame {
  position: absolute; inset: 7px 9px; z-index: 1; pointer-events: none;
  border: 1px solid color-mix(in srgb, #9A7A90 38%, transparent); border-radius: 3px;
}
#my-communitys-13 .cm13-star {
  position: relative; z-index: 2; flex: none; margin-right: var(--s3);
  color: var(--coral); font-size: 18px; line-height: 1;
}
#my-communitys-13 .cm13-name {
  position: relative; z-index: 2; min-width: 0;
  font-family: var(--font-display); font-weight: 600; font-size: var(--t-body); color: var(--ink);
}
#my-communitys-13 .cm13-message {
  grid-column: 1 / -1;
  min-height: 96px;
}
#my-communitys-13 .cm13-message .cm13-name {
  font-family: var(--font-sans);
  font-weight: 600;
  color: var(--slate-soft);
}

/* ---- Community resonance map (script/community/resonance-map.js) ---------- */
#my-communitys-13 .choropleth.rmap { display:block; width:100%; height:auto; overflow:visible;
  -webkit-mask: radial-gradient(closest-side circle at 50% 50%, #000 84%, transparent 100%);
          mask: radial-gradient(closest-side circle at 50% 50%, #000 84%, transparent 100%); }
/* Static fail-open: shown until/unless the live SVG builds. */
#my-communitys-13 .choropleth-fallback { display:block; width:100%; height:auto;
  -webkit-mask: radial-gradient(closest-side circle at 50% 50%, #000 84%, transparent 100%);
          mask: radial-gradient(closest-side circle at 50% 50%, #000 84%, transparent 100%); }
#my-communitys-13 .choropleth-frame > .lead { margin: 0 0 var(--s6); padding: 0; border: 0; text-align: center; }
#my-communitys-13 .choropleth-frame > .lead > p { max-width: none; color: var(--ink); }
/* Map visual is blank for now — reserve the space so the panel doesn't collapse. */
#my-communitys-13 #choropleth { min-height: 360px; }
#my-communitys-13 .rmap-cell { fill: var(--ch-3); stroke: var(--paper-soft, #F8F4ED); stroke-width:1.1;
  stroke-linejoin:round; transform-box:fill-box; transform-origin:center; opacity:1; }
#my-communitys-13 .rmap-cell.ch-1 { fill: var(--ch-1); }
#my-communitys-13 .rmap-cell.ch-2 { fill: var(--ch-2); }
#my-communitys-13 .rmap-cell.ch-3 { fill: var(--ch-3); }
#my-communitys-13 .rmap-cell.is-focal { stroke: var(--ch-1); stroke-width:1.7; }
#my-communitys-13 .rmap-ring { fill:none; stroke: color-mix(in srgb, var(--ink) 60%, transparent); stroke-width:1.5; stroke-dasharray:3 4.5;
  opacity:.7; transform-box:fill-box; transform-origin:center; }
#my-communitys-13 .rmap-label { font-family: var(--font-mono, ui-monospace, monospace); font-size:10px; font-weight:600;
  fill: color-mix(in srgb, var(--ink, #172033) 80%, transparent); text-anchor:middle;
  dominant-baseline:middle; letter-spacing:.02em; pointer-events:none; opacity:1; }
#my-communitys-13 .rmap-label.is-focal { fill: var(--ch-1); font-size:11px; font-weight:700; }
#my-communitys-13 .choropleth-callout.is-pinned { left:50%; top:45%; transform: translate(-50%, -50%);
  text-align:center; pointer-events:none; }
/* A breath between the map's circular mask edge and the legend card. */
#my-communitys-13 .choropleth-legend { margin-top: var(--s5); }
#my-communitys-13 .choropleth-legend .sw-1 { background: var(--ch-1); }#my-communitys-13 .choropleth-legend .sw-2 { background: var(--ch-2); }
#my-communitys-13 .choropleth-legend .sw-3 { background: var(--ch-3); }
/* ---- Touch tiers (991 / 767 ladder; the 1279 stack above already owns
   the column order). ---- */
@media (max-width: 991px) {
  /* (hero gutters come from the 1279 rule — same beat as the section) */
  /* Desc row: the 168px seal is the desktop composition's counterweight;
     at touch widths it crowds the text column — one step down. */
  #my-communitys-13 .cm-desc-seal { width: 120px; height: 120px; }
}
@media (max-width: 767px) {
  /* The heading wrote its nowrap for the wide 2-col seat. */
  #my-communitys-13 .cm13-intro > p { white-space: normal; }
  /* Community slips: one reading column. */
  #my-communitys-13 .col-community-13 .cm13-list { grid-template-columns: 1fr; }
  /* Desc row stacks in document order: descriptor + back link full
     measure; the seal yields (ornament first — the FAQ phone ruling;
     About keeps its title seal, but here the hero already carries the
     mauve display title as its mark). */
  #my-communitys-13 .cm-desc-row { grid-template-columns: minmax(0, 1fr); }
  #my-communitys-13 .cm-desc-seal { display: none; }
}
@media (prefers-reduced-motion: no-preference) {
  #my-communitys-13 .rmap-cell  { animation: rmap-bloom 600ms cubic-bezier(.22,.61,.36,1) both var(--bloom-delay,0ms),
                           rmap-shimmer 5.4s ease-in-out infinite calc(var(--bloom-delay,0ms) + 1100ms); }
  #my-communitys-13 .rmap-label { animation: rmap-fade 560ms ease both var(--bloom-delay,0ms); }
  #my-communitys-13 .rmap-ring  { animation: rmap-pulse 2.4s ease-in-out infinite 1000ms; }
}
@media (prefers-reduced-motion: reduce) { #my-communitys-13 .rmap-cell, #my-communitys-13 .rmap-label { opacity:1; } #my-communitys-13 .rmap-ring { opacity:.8; } }
@keyframes rmap-bloom   { from { transform:scale(.74); } to { transform:scale(1); } }
@keyframes rmap-shimmer { 0%,100% { filter:none; } 50% { filter:brightness(1.05); } }
@keyframes rmap-fade    { to { opacity:1; } }
@keyframes rmap-pulse   { 0%,100% { transform:scale(.9); opacity:.5; } 50% { transform:scale(1.14); opacity:.95; } }
/* ===== end MY-COMMUNITYS-13 PAGE ===== */

/* =====================================================================
   HOME PAGE  (#home = <body id="home">)
   ---------------------------------------------------------------------
   Graduated from home.html's inline <style id="home-v2-overrides">, scoped to
   #home. The smooth-scroll rule targets html:has(#home) — scroll-behavior acts
   on the document scroll container (above the body), so it can't sit on #home
   itself, but :has keeps it home-only. No page-local CSS.
   ===================================================================== */
/* Topnav present from first paint: same selector as the cycle-engine gate but
   loaded after choose13.css, so it wins on source order — no !important. */
#home.cycle-engine-active .stage-home-hero > .header { opacity: 1; }
/* "Learn more" is the scroll cue — smooth document scroll + a down-arrow nudge. */
html:has(#home) { scroll-behavior: smooth; }
#home .home-hero-actions .c13-btn .arrow.is-down { transition: transform var(--t-base, 220ms) ease; }
#home .home-hero-actions .c13-btn:hover .arrow.is-down { transform: translateY(3px); }
/* ===== end HOME PAGE ===== */

/* =====================================================================
   FAQ PAGE  (#faq = <body id="faq">)
   ---------------------------------------------------------------------
   Graduated from faq.html's inline <style> (the FAQ accordion), scoped to #faq.
   No page-local CSS.
   ===================================================================== */
#faq .faq-accordion { margin: var(--s7) 0 0; }
#faq .faq-item { border-bottom: 1px dotted var(--rule-2, var(--rule)); }
#faq .faq-item:first-child { border-top: 1px dotted var(--rule-2, var(--rule)); }
#faq .faq-q {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  padding: var(--s4) 0;
  font-family: var(--font-display); font-weight: 600; font-size: var(--t-body);
  line-height: 1.3; color: var(--ink);
}
#faq .faq-q::-webkit-details-marker { display: none; }
#faq .faq-q::after { content: ""; flex: none; width: 8px; height: 8px; border-right: 2px solid var(--coral); border-bottom: 2px solid var(--coral); transform: rotate(45deg); transition: transform var(--t-fast) ease; }
#faq .faq-item[open] .faq-q::after { transform: rotate(-135deg); }
#faq .faq-a { padding: 0 0 var(--s4); }
#faq .faq-a p { margin: 0; max-width: 88ch; font-family: var(--font-body); font-size: var(--t-rail); line-height: 1.6; color: var(--ink-mid); }
/* ===== end FAQ PAGE ===== */

/* ===== HOME HERO + MAP -- folded in from style/hero-map-handoff.css (now retired). All selectors are home-only (.stage-home-hero* / .hm-* / .stage-intro-video). ===== */
/* =====================================================================
   Choose13 — Hero ↔ Map hand-off  (v3, layered over choose13.css)
   ---------------------------------------------------------------------
   The participation map is Code's component (script/map/map.js + the
   .c13map-* / .stage-map rules in choose13.css), UNTOUCHED. The hand-off
   engine relocates the real <section.stage-map> into the hero FRAME as
   a GRID ITEM, so spacing comes from the system, not ad-hoc insets:
     • gutter (question ↔ map)  = the grid column-gap token  (--s6)
     • clearance below the nav  = the frame's padding-block  (--s5)
     • space below the title    = .c13map-head margin-bottom (--s2)
   No !important; no ad-hoc px/percent positioning.
   ===================================================================== */

/* ---- Frame grid: narrow side columns, generous center for the map ----
   column-gap IS the question↔map gutter now (the map is a grid item that
   left-aligns to its column). padding-block is tighter than the default
   --s7 to give the map vertical room while still clearing the nav. */
.stage-home-hero-frame {
  grid-template-columns: minmax(0, 0.55fr) minmax(0, 2fr) minmax(0, 0.4fr);
  column-gap: 0;
  padding-block: var(--s5) var(--s6);
  padding-inline: var(--s8);   /* reduced x-padding — content runs fuller */
}
/* Brand seal back ON TOP OF the CTA stack — it's the first child of the fixed
   .home-hero-actions, centered above the buttons. It is NOT part of the
   persistent CTA: it fades out on scroll (body.is-scrolled) so it does not
   travel down the page with the button. */
.stage-home-hero .home-hero-actions .mirror-seal {
  align-self: center;
  width: clamp(140px, 9vw + 44px, 220px);   /* cap raised with the wide-tier CTA scale (was 184) */
  margin: 0 0 var(--s4);
  transition: opacity 350ms ease;
}
body.is-scrolled .stage-home-hero .home-hero-actions .mirror-seal {
  opacity: 0;
  pointer-events: none;
  animation: none;   /* stop the idle-breath so it can't override the fade */
}

/* Question top-left; "I say…" centered. Both sit ABOVE the map layer. */
/* No inter-column gutter: the map's own left whitespace (the Alaska/NW
   empty corner) reads as the spacing. The editorial content is offset from
   the map with a more substantial padding-left instead. */
.stage-home-hero-frame .script-opener  { grid-row: 1 / 4; align-self: start;  z-index: 2; }
.stage-home-hero-frame .declaration    { grid-row: 1 / 4; align-self: center; margin-top: 0; z-index: 2; padding-left: var(--s8); }
.stage-home-hero-frame .home-hero-side { z-index: 2; margin-bottom: var(--s6); }

/* ---- The map: a grid item spanning the center + right columns -------- */
.stage-home-hero-frame > .stage-map {
  grid-column: 2 / 4;
  grid-row: 1 / 4;
  z-index: var(--z-floating);   /* above the fixed seal/CTA (--z-sticky) so edge pin-tags aren't hidden; map is pointer-events:none so the CTA stays clickable */
  min-height: 0;
  margin: 0;
  padding: 0;
  background: transparent;
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;   /* map left-aligns → gutter == column-gap exactly */
  opacity: 0;
  pointer-events: none;
  transition: opacity 700ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.stage-home-hero.hm-map .stage-home-hero-frame > .stage-map { opacity: 1; }

/* Pins/lights near the map edges must not clip — let the map layer overflow. */
.stage-home-hero-frame > .stage-map,
.stage-home-hero-frame > .stage-map .c13map-stage,
.stage-home-hero-frame > .stage-map .c13map-overlay { overflow: visible; }

/* Hero already paints grain — drop the section's duplicate. */
.stage-home-hero-frame > .stage-map > .stage-noise { display: none; }

/* Cap the map at 600px tall (width = 600 × the map's 975/610 aspect, so it
   stays aspect-true with no letterboxing) while it otherwise stretches to the
   column. Left-aligned (margin:0) so the GUTTER is the only spacing on the
   map's left — no centering slack. */
.stage-home-hero-frame > .stage-map .c13map-inner {
  /* 57vw, floored for phones; the cap only bites ABOVE ~1334px viewport —
     800 was the 1280-era cap and strangled 1680/1920 (maintainer wide-view
     review). Grew to 63vw mid-June, then trimmed to 57vw once the title was
     reined to ~102 — the map is kept proportional to the title, not oversized. */
  width: clamp(320px, 57vw, 1240px);
  margin: 0;
  padding: 0 0 0 var(--s8);   /* left gutter restored June 12 — once the map was trimmed back to proportion, sitting flush against the question read too tight, so the s8 gutter returns to keep the map off the editorial text */
}
.stage-home-hero-frame > .stage-map .c13map-head {
  margin-top: 0;
  margin-bottom: var(--s2);      /* reduced space under the title */
}
/* Title hidden until it typewrites in (engine adds .is-revealed). Coral brand
   accent now that the subtitle beneath carries the cream. */
.stage-home-hero-frame > .stage-map .c13map-title { margin: 0; opacity: 0; color: var(--coral); }
.stage-home-hero-frame > .stage-map .c13map-title.is-revealed { opacity: 1; }

/* The foil map + pins fade in AFTER the title types (engine adds .is-map-in). */
.stage-home-hero-frame > .stage-map .c13map-stage {
  width: 100%;
  opacity: 0;
  transform: translateY(34px);
  transition: opacity 1300ms ease-out, transform 1400ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.stage-home-hero-frame > .stage-map.is-map-in .c13map-stage { opacity: 1; transform: translateY(0); }

/* Dark fill INSIDE the map slices (the SVG national path) so the quilt
   doesn't show through the landmass — but still breathes around the shape.
   (Replaces the earlier full-rectangle background.) */
.stage-home-hero-frame > .stage-map .c13map-national {
  fill: color-mix(in srgb, var(--charcoal) 80%, transparent);
}

/* The 6-dot carousel is unused in v3 — one declaration per load. */
.stage-home-hero .hero-carousel { display: none; }

/* Lift the hero's stacking context above the later sections (video, mosaic)
   so the fixed CTA isn't trapped beneath them. Kept under the video modal
   (z-index 100), which must still cover everything when it opens. */
.stage-home-hero { z-index: var(--z-sticky); }

/* Direct video embed (replaces the postcard + modal), framed like a postcard:
   a cream mat, soft shadow, and a dashed coral airmail keyline. */
/* Map backing now sits in the map component; the postcard frame moved to
   choose13.css as the reusable .postcard-frame component. */
.stage-intro-video .stamp-lg { margin: 0 0 var(--s2); }
.stage-intro-video .video-card-body { margin: 0 0 var(--s5); }

/* The CTA stack floats bottom-right. Both buttons share one width (stretch),
   but only "Choose Your 13" persists — "Learn more" fades the moment the page
   starts scrolling (engine toggles body.is-scrolled). */
.stage-home-hero .home-hero-actions {
  position: fixed;
  right: var(--s7);
  bottom: var(--s7);
  z-index: var(--z-sticky);
  /* Hero CTA pill sizing — tune here. Larger than the base .c13-btn-block.
     FLUID above the 1280 design floor (the floor values ARE the settled
     1280 render): px-token components can't ride a root-size bump, so the
     tokens themselves scale — at 1920 the pill reads ~21px in a ~21rem
     stack instead of freezing at its laptop size. */
  --cta-pill-pad-y: clamp(15px, 0.5vw + 9px, 19px);
  --cta-pill-pad-x: clamp(26px, 1vw + 13px, 34px);
  --cta-pill-size: clamp(18px, 0.6vw + 10px, 22px);
  width: clamp(17rem, 12vw + 7.4rem, 21rem);
  align-items: stretch;
}
/* Apply the pill tokens to both hero CTA buttons (they share dimensions). */
.stage-home-hero .home-hero-actions .c13-btn-block {
  padding: var(--cta-pill-pad-y) var(--cta-pill-pad-x);
  font-size: var(--cta-pill-size);
}
/* Star next to the primary label, mirroring the topnav pill's seal. Arrow
   removed, so the label + star group centers in the pill. */
.stage-home-hero .home-hero-actions .c13-btn-primary {
  justify-content: center;
}
.stage-home-hero .home-hero-actions .c13-btn-primary .cta-text {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.stage-home-hero .home-hero-actions .c13-btn-primary .seal {
  display: inline-grid; place-items: center;   /* same treatment as the topnav pill seal */
  font-family: var(--font-display);            /* SHARP star (matches the print materials) */
  font-size: 18px;                             /* original/topnav seal size */
  line-height: 1;
  color: var(--cta-star-color);
}
/* Hero primary CTA hovers LIGHTER (not the default darker coral-deep). The
   :not([disabled]) bumps specificity above the base block-primary hover so
   this wins. */
/* Hero primary CTA — coral fill + lighter hover, both via the shared --cta-*
   tokens so the floating CTA on other pages matches exactly. */
.stage-home-hero .home-hero-actions .c13-btn-block.c13-btn-primary {
  background: var(--cta-fill);
}
.stage-home-hero .home-hero-actions .c13-btn-block.c13-btn-primary:not([disabled]):hover {
  background: var(--cta-fill-hover);
}
/* Once the fixed CTA scrolls off the dark hero onto the light content sections
   (body.is-scrolled), flip to the light-surface scheme — lighter default,
   base coral on hover — matching the floating CTA on the inner pages. */
body.is-scrolled .stage-home-hero .home-hero-actions .c13-btn-block.c13-btn-primary {
  background: var(--cta-fill-hover);
}
body.is-scrolled .stage-home-hero .home-hero-actions .c13-btn-block.c13-btn-primary:not([disabled]):hover {
  background: var(--cta-fill);
}
.stage-home-hero .home-hero-actions .c13-btn-secondary { transition: opacity 350ms ease; }
body.is-scrolled .stage-home-hero .home-hero-actions .c13-btn-secondary {
  opacity: 0;
  pointer-events: none;
}

/* ---- Replay control (prototype affordance only) — sits under the question */
.hm-replay {
  margin: 0 0 0 12px;
  vertical-align: middle;
  display: none;
  align-items: center;
  gap: var(--s2);
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--cream);
  background: color-mix(in srgb, var(--charcoal) 72%, transparent);
  border: 1px solid color-mix(in srgb, var(--cream) 22%, transparent);
  border-radius: 999px;
  padding: 4px 12px;
  cursor: pointer;
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  opacity: 0;
  transition: opacity 300ms ease, border-color 200ms ease;
}
.hm-replay.is-shown { display: inline-flex; opacity: 0.55; }
.hm-replay.is-shown:hover { opacity: 1; border-color: color-mix(in srgb, var(--cream) 50%, transparent); }
.hm-replay .ph { font-size: 14px; }

@media (prefers-reduced-motion: reduce) {
  .stage-home-hero-frame > .stage-map,
  .stage-home-hero-frame > .stage-map .c13map-stage { transition: none; }
}

/* ---- Topnav: full-width (home page) ---------------------------------
   The topnav is now ONE identical bar across every page (defined in
   choose13.css, gutter = --page-pad). Here we only clear the old centered
   max-width cap so home's header spans the full-bleed stage; the gutter is
   inherited from choose13.css so the brand + My-13 pill sit in the SAME place
   as every other page (no jump when navigating between pages). */
.stage-home-hero .header {
  width: auto;
  max-width: none;
  margin: 0;
}
.stage-home-hero .header-nav { justify-self: start; }

/* ---- Hero responsive: the document order takes over ----
   Tiers follow the Draft Signal ladder (767 / 991), device-tested there.
   <=991: question (brand seal seated beside it -- the .page-seal role from
   about/faq), then declaration, then the map. Constraints born of the
   horizontal dialogue (20ch measure, right-hug) die with it; spacing is
   rebalanced for vertical adjacency. The map keeps its handoff fade and
   overlaps the declaration rows -- same as the desktop end-state, where
   the engine fades the declaration as the map lands -- so the stage never
   grows a blank band while the map is hidden. */
.question-seal { display: none; }
/* Seal enters AFTER the question has finished typing — gated on the durable
   p.is-typed marker the engine sets at typewriter completion (the qmark pulse
   class is transient and would snap the seal back off). Keyframe with 'both'
   fill so a missed beat can't strand it invisible. */
body.cycle-engine-active .question-seal { opacity: 0; }
body.cycle-engine-active .script-opener p.is-typed ~ .question-seal {
  animation: question-seal-in 600ms ease-out 250ms both;
}
@keyframes question-seal-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  body.cycle-engine-active .script-opener p.is-typed ~ .question-seal { animation: none; opacity: 1; }
}
@media (max-width: 991px) {
  .stage-home-hero-frame {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto auto;
    padding-inline: var(--page-pad);
    row-gap: var(--s4);
  }
  .stage-home-hero-frame .script-opener {
    grid-column: 1; grid-row: 1;
    display: flex; align-items: center; gap: var(--s6);
    text-align: left; margin-left: 0; max-width: none;
  }
  .stage-home-hero-frame .script-opener p { flex: 1 1 auto; min-width: 0; }
  .question-seal { display: block; flex: none; }
  /* Stage colors: cream ring stars, blush numeral (matches .mirror-seal). */
  .question-seal svg { color: var(--cream); }
  .question-seal .page-seal-num { fill: var(--coral); }
  .stage-home-hero-frame .declaration    { grid-column: 1; grid-row: 2; align-self: start; padding-left: 0; }
  .stage-home-hero-frame .home-hero-side { grid-column: 1; grid-row: 3; margin-bottom: 0; }
  .stage-home-hero-frame > .stage-map    { grid-column: 1; grid-row: 2 / 4; }
  .stage-home-hero-frame > .stage-map .c13map-inner { width: 100%; padding-left: 0; }
  /* The seal role lives beside the question here -- not on the CTA stack. */
  .stage-home-hero .home-hero-actions .mirror-seal { display: none; }
  /* Corner cluster (tablet): tighter inset, viewport-capped. CTA sits
     ABOVE the map layer on touch tiers (desktop keeps map-over-CTA for
     edge pin-tags) and is never gated behind the engine's reveal beat. */
  .stage-home-hero .home-hero-actions {
    right: var(--s5);
    bottom: var(--s5);
    width: min(17rem, calc(100vw - var(--s5) * 2));
  }
  /* The CTA lives inside .home-hero-side — a grid item with z-index:2, i.e.
     its OWN stacking context — so raising the CTA's own z-index can't lift it
     past the map: the map (--z-floating) is a SIBLING grid item at z 100, and
     the whole .home-hero-side subtree is capped beneath it at z 2. Lift the
     SIDE's context above the map instead; its only touch-tier occupant is the
     fixed CTA bar (the seal + "Learn more" are display:none here). Desktop
     keeps the deliberate map-over-CTA layering for edge pin-tags. */
  .stage-home-hero-frame .home-hero-side { z-index: calc(var(--z-floating) + 1); }
  body.cycle-engine-active .stage-home-hero .home-hero-side .home-hero-actions,
  .stage-home-hero .home-hero-side .home-hero-actions { opacity: 1; transform: none; transition: none; }
}

/* ---- Phone (<=767px): ornament yields; the CTA becomes chrome ----
   No seal at all. The CTA stops floating over content and takes the bottom
   edge as a persistent full-width bar -- priority RISES as space falls.
   "Learn more" is a scroll cue; scrolling needs no cue on touch. */
@media (max-width: 767px) {
  .question-seal { display: none; }
  /* The bar IS the button: coral fill on the band, the <a> full-bleed
     inside it. Elevation = the megamenu's shadow flipped upward; no
     hairline (a solid border is not a primitive here). */
  .stage-home-hero .home-hero-actions {
    left: 0; right: 0; bottom: 0;
    width: auto;
    padding: 0;
    background: var(--cta-fill);
    box-shadow: 0 -18px 50px -16px rgba(23, 32, 51, 0.28);
    gap: 0;
  }
  .stage-home-hero .home-hero-actions .c13-btn.c13-btn-primary {
    width: 100%;
    border-radius: 0;
    box-shadow: none;
    background: none;   /* the bar carries the fill */
    padding: 13px var(--page-pad) calc(13px + env(safe-area-inset-bottom, 0px));
  }
  .stage-home-hero .home-hero-actions .c13-btn-secondary { display: none; }
  /* Upright 24px outweighs the 38px script question on a phone — one
     ladder step down keeps the subtitle subordinate to question + title. */
  .c13map-head .c13map-subtitle { font-size: var(--t-body); }
  /* The hero's last content must clear the fixed bar. */
  .stage-home-hero-frame { padding-bottom: calc(var(--s7) + 56px); }
}

/* Footer postal strip: the QUIET version is now the default .bg-postal-strip in
   choose13.css (shared by home + about + faq + community). my-13 opts into the
   full distressed strip via .bg-postal-strip-full. No home-only override needed. */

/* ===== RESPONSIVE TIERS below the hero (Draft Signal ladder) ===== */
@media (max-width: 991px) {
  /* Main (intro): straight vertical stack -- title, script subhead,
     descriptor, video title, video descriptor, video. Document order
     is the layout. */
  .stage-intro-frame {
    grid-template-columns: minmax(0, 1fr);
    /* Tight stacked row-gap (was --s6): the video-title cell is often empty, so a
       large copy→video gap reads as dead "title space" when stacked — keep it close.
       (Side-by-side column gap stays --s9 on the base rule.) */
    gap: var(--s4);
    padding-inline: var(--page-pad);   /* section owns its gutter (DS pattern) */
  }
  .stage-intro-headline-ring { right: 0; }
  /* Intro script line: bound to its title by one major-third step (1.25x)
     so the pairing keeps the desktop ratio at every width (60/47 desktop;
     a fixed 60px over the 34px floored title read inverted on phones). */
  .stage-intro .display-script { font-size: calc(var(--t-section-title) * 1.25); }
  /* Mosaic: the copy leaves the artwork's negative space and stacks
     below it, full measure. */
  .stage-mosaic-copy {
    margin-top: var(--s6);
    margin-left: 0;
    width: auto;
    max-width: 62ch;
    gap: var(--s3);
    padding-inline: var(--page-pad);
  }
  .stage-mosaic-copy .mosaic-tagline { font-size: 60px; /* = .display-script display size (maintainer: the existing desktop subtitle scale is right here) */ }
}
@media (max-width: 767px) {
  /* Phone carries the HALF of the mosaic that bears the Choose13 mark
     (the left half) -- content adapts past the scarcity point. (Draft
     Signal precedent: cropped artwork at narrow tiers.) */
  .stage-mosaic-frame { aspect-ratio: 1630 / 1120; overflow: hidden; }
  .stage-mosaic-svg { width: 200%; height: 100%; }
  /* Inner-page floating CTA becomes the persistent bottom bar (one
     bottom-band slot site-wide). */
  .floating-cta {
    left: 0; right: 0; bottom: 0;
    background: var(--cta-fill-soft);
    /* CTA bottombar elevation — layered lift (matches the my-13 CTA band) so the
       soft-coral prompt reads raised off the page, not flush to the bottom edge. */
    box-shadow: 0 -18px 50px -16px rgba(23, 32, 51, 0.28),
                0 -3px 12px -2px rgba(23, 32, 51, 0.15);
    padding: 0;
  }
  .floating-cta .c13-btn.c13-btn-block {
    width: 100%;
    border-radius: 0;
    box-shadow: none;
    padding: 13px var(--page-pad) calc(13px + env(safe-area-inset-bottom, 0px));
  }
}
/* __C13_EOF__ — end-of-file sentinel. The sandbox file server intermittently
   truncates large responses, and a cut at a rule boundary can still end on a
   closing brace, so a truncated copy looks complete; the sandbox shim demands
   this marker before trusting a fetched copy of this sheet. Keep as the LAST
   line. Note: no literal brace anywhere in this comment — one would leave the
   file's brace count off by one and send the next reader hunting a diff that
   isn't there. Harmless in production. */
