/* ============================================================
   Native Past — design system
   "The Living Index" · archival paper, lamplight, letterpress
   No frameworks. No dependencies. Hand-set.
   ============================================================ */

/* ---------- fonts ---------- */
@font-face {
  font-family: 'Fraunces';
  src: url('../fonts/fraunces-latin.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Fraunces';
  src: url('../fonts/fraunces-italic-latin.woff2') format('woff2');
  font-weight: 300 700;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('../fonts/inter-latin.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

/* ---------- tokens ---------- */
:root {
  --paper: #FBF7EF;
  --paper-deep: #F3ECDD;
  --ink: #2A2118;
  --ink-soft: #51453A;
  --ink-faint: #74675B;   /* 5.1:1 on --paper, 4.7:1 on --paper-deep (was #8A7B6C, 3.8:1: WCAG 1.4.3, audit 2026-09-27) */
  --saddle: #8B4513;
  --saddle-deep: #6E3208;
  --ember: #C8702A;
  --gold: #B98A2F;
  --night: #181210;
  --night-2: #221A14;
  --on-night: #EFE5D5;
  --on-night-soft: #B7A890;
  --hairline: rgba(42, 33, 24, 0.14);
  --hairline-strong: rgba(42, 33, 24, 0.28);

  --cherokee: #B5482E;
  --choctaw: #2E5A88;
  --chickasaw: #2E7D4F;
  --creek: #C8702A;
  --muscogee: #C8702A;
  --seminole: #6B4A8A;
  --delaware: #7A6230;

  --font-display: 'Fraunces', 'Iowan Old Style', Georgia, serif;
  --font-ui: 'Inter', -apple-system, 'Segoe UI', sans-serif;

  /* fluid type scale */
  --t-hero: clamp(2.6rem, 7.2vw, 5.6rem);
  --t-1: clamp(2rem, 4.6vw, 3.4rem);
  --t-2: clamp(1.5rem, 2.8vw, 2.1rem);
  --t-3: clamp(1.17rem, 1.8vw, 1.35rem);
  --t-body: clamp(1rem, 1.1vw, 1.0925rem);
  --t-small: 0.875rem;
  --t-micro: 0.76rem;

  --space: clamp(1rem, 2.5vw, 2rem);
  --radius: 14px;
  --radius-sm: 9px;

  --shadow-1: 0 1px 2px rgba(42, 33, 24, .07), 0 4px 16px rgba(42, 33, 24, .06);
  --shadow-2: 0 2px 6px rgba(42, 33, 24, .09), 0 18px 48px rgba(42, 33, 24, .12);
  --ease-out: cubic-bezier(.22, 1, .36, 1);
  --ease-spring: cubic-bezier(.34, 1.45, .5, 1);
  --dur: .65s;

  /* cross-promotion bar height — body padding and .site-head's sticky top both
     read this, so the bar costs ZERO layout shift. Change here only.
     76/68px matches the studio bar on oliviarenee.media. */
  --promo-h: 76px;
}

/* ---------- reset-ish ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
/* The fixed promo bar plus the sticky header (65px) cover the top of the screen. scroll-padding keeps
   anchor jumps AND keyboard focus below them (WCAG 2.4.11: Shift+Tab used to park links under the bar
   on phones). Targets need no scroll-margin of their own; one would add to this. */
html { scroll-padding-top: calc(var(--promo-h) + 65px + 12px); }
body {
  margin: 0;
  padding-top: var(--promo-h);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: var(--t-body);
  line-height: 1.62;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}
img, svg, canvas { display: block; max-width: 100%; }
a { color: var(--saddle); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--saddle-deep); }
::selection { background: rgba(139, 69, 19, .22); }
.btn::selection { background: rgba(255, 248, 238, .92); color: var(--saddle-deep); }

h1, h2, h3, .display {
  font-family: var(--font-display);
  font-weight: 560;
  line-height: 1.06;
  letter-spacing: -0.012em;
  margin: 0 0 .5em;
  font-optical-sizing: auto;
}
h1 { font-size: var(--t-1); }
h2 { font-size: var(--t-2); }
h3 { font-size: var(--t-3); font-weight: 600; }
p { margin: 0 0 1em; max-width: 68ch; }
.lede { font-size: calc(var(--t-body) * 1.18); color: var(--ink-soft); line-height: 1.55; }
.muted { color: var(--ink-faint); }
.small { font-size: var(--t-small); }
.micro { font-size: var(--t-micro); letter-spacing: .02em; }
.tnum { font-variant-numeric: tabular-nums; }

/* letterpress display text on paper */
.letterpress {
  text-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 -1px 0 rgba(42, 33, 24, .12);
}

/* ---------- paper grain (whole site) ---------- */
/* Pinned top-left at a fixed size (100vh is the LARGE viewport on phones). It used to be `inset: -50%`,
   which moved it whenever the viewport's height changed, e.g. when Chrome's address bar hid or came back.
   A moving full-screen layer counts as a layout shift over the whole screen: the field showed CLS 0.465
   on /search/, and a Moto g power reproduced the shift on every address-bar change (2026-09-26). */
body::after {
  content: '';
  position: fixed;
  top: 0; left: 0;
  width: 100vw; height: 100vh;
  pointer-events: none;
  z-index: 2147483646;
  opacity: .05;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- layout ---------- */
.wrap { width: min(1120px, calc(100% - 2 * var(--space))); margin-inline: auto; }
.wrap-narrow { width: min(760px, calc(100% - 2 * var(--space))); margin-inline: auto; }
section { padding-block: clamp(3.5rem, 9vw, 7.5rem); }
.rule { border: 0; border-top: 1px solid var(--hairline); margin: 0; }

/* ---------- header ---------- */
.site-head {
  position: sticky; top: var(--promo-h); z-index: 50;
  backdrop-filter: blur(14px) saturate(1.1);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  background: color-mix(in srgb, var(--paper) 82%, transparent);
  border-bottom: 1px solid var(--hairline);
  transition: box-shadow .35s var(--ease-out);
}
.site-head.is-scrolled { box-shadow: var(--shadow-1); }
.site-head .bar {
  display: flex; align-items: center; gap: 1.4rem;
  min-height: 64px;
}
.brand {
  display: flex; align-items: center; gap: .6rem;
  font-family: var(--font-display); font-weight: 620; font-size: 1.18rem;
  color: var(--ink); text-decoration: none; letter-spacing: -0.01em;
}
.brand svg { width: 27px; height: 27px; }
.nav { display: flex; gap: 1.15rem; margin-left: auto; align-items: center; }
.nav a {
  color: var(--ink-soft); text-decoration: none; font-size: var(--t-small);
  font-weight: 530; position: relative; padding-block: .4rem;
  white-space: nowrap;
}
.nav a::after {
  content: ''; position: absolute; left: 0; right: 100%; bottom: 0;
  border-bottom: 2px solid var(--saddle);
  transition: right .32s var(--ease-out);
}
.nav a:hover::after, .nav a[aria-current="page"]::after { right: 0; }
.nav a[aria-current="page"] { color: var(--ink); }

/* ---------- buttons ---------- */
.btn {
  --btn-bg: var(--saddle);
  display: inline-flex; align-items: center; gap: .55rem;
  background: var(--btn-bg); color: #FFF8EE;
  font: 600 var(--t-small)/1 var(--font-ui);
  letter-spacing: .01em;
  padding: .95rem 1.45rem; border-radius: 999px;
  border: 0; cursor: pointer; text-decoration: none;
  position: relative; overflow: hidden; isolation: isolate;
  box-shadow: 0 1px 0 rgba(255,255,255,.25) inset, 0 8px 22px rgba(110, 50, 8, .28);
  transition: transform .35s var(--ease-spring), box-shadow .35s var(--ease-out), background .25s;
  will-change: transform;
}
.btn::before { /* sheen sweep */
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(105deg, transparent 38%, rgba(255, 244, 222, .35) 50%, transparent 62%);
  transform: translateX(-130%);
  transition: transform .7s var(--ease-out);
}
.btn:hover { box-shadow: 0 1px 0 rgba(255,255,255,.25) inset, 0 14px 34px rgba(110, 50, 8, .36); }
.btn:hover::before { transform: translateX(130%); }
.btn:active { transform: scale(.97); }
.btn-ghost {
  --btn-bg: transparent;
  background: transparent; color: var(--ink);
  box-shadow: inset 0 0 0 1.5px var(--hairline-strong);
}
.btn-ghost:hover { box-shadow: inset 0 0 0 1.5px var(--saddle); color: var(--saddle-deep); }
:where(a, button, input, select, [tabindex]):focus-visible {
  outline: 2px solid var(--saddle); outline-offset: 2.5px; border-radius: 4px;
}
/* Skip link (WCAG 2.4.1): first Tab stop on every page, over the promo bar (55) and consent banner (65). */
.skip-link {
  position: fixed; top: 8px; left: 8px; z-index: 200;
  padding: .7rem 1.1rem; border-radius: var(--radius-sm);
  background: var(--ink); color: var(--paper); font-weight: 600; text-decoration: none;
  transform: translateY(calc(-100% - 16px));
}
.skip-link:focus { transform: none; color: var(--paper); outline: 2px solid #E8C98A; outline-offset: 2px; }
/* the skip link's target takes focus only so the next Tab starts inside it; no ring round the whole page */
main[tabindex="-1"]:focus { outline: none; }

/* ---------- tribe chips ---------- */
.chip {
  --chip: var(--ink-faint);
  display: inline-flex; align-items: center; gap: .45rem;
  font: 560 var(--t-micro)/1 var(--font-ui); letter-spacing: .035em; text-transform: uppercase;
  color: var(--chip);
  border: 1.5px solid color-mix(in srgb, var(--chip) 42%, transparent);
  background: color-mix(in srgb, var(--chip) 7%, transparent);
  padding: .5rem .8rem; border-radius: 999px;
  cursor: pointer; user-select: none;
  transition: background .25s, border-color .25s, color .25s, transform .3s var(--ease-spring);
}
.chip::before { content: ''; width: .55em; height: .55em; border-radius: 50%; background: var(--chip); }
.chip:hover { transform: translateY(-1px); }
.chip[aria-pressed="true"] {
  background: var(--chip); color: var(--paper);
  border-color: var(--chip);
}
.chip[aria-pressed="true"]::before { background: var(--paper); }
.chip[data-tribe="cherokee"]  { --chip: var(--cherokee); }
.chip[data-tribe="choctaw"]   { --chip: var(--choctaw); }
.chip[data-tribe="chickasaw"] { --chip: var(--chickasaw); }
.chip[data-tribe="creek"]     { --chip: var(--creek); }
.chip[data-tribe="seminole"]  { --chip: var(--seminole); }
.chip[data-tribe="delaware"]  { --chip: var(--delaware); }

.badge {
  display: inline-block; font: 600 var(--t-micro)/1 var(--font-ui);
  letter-spacing: .04em; text-transform: uppercase;
  padding: .32rem .55rem; border-radius: 6px;
  background: color-mix(in srgb, var(--tone, var(--ink-faint)) 12%, transparent);
  color: var(--tone, var(--ink-soft));
}
.badge[data-tribe="cherokee"]  { --tone: var(--cherokee); }
.badge[data-tribe="choctaw"]   { --tone: var(--choctaw); }
.badge[data-tribe="chickasaw"] { --tone: var(--chickasaw); }
.badge[data-tribe="creek"]     { --tone: var(--creek); }
.badge[data-tribe="seminole"]  { --tone: var(--seminole); }
.badge[data-tribe="delaware"]  { --tone: var(--delaware); }

/* ---------- reveal-on-scroll motion ---------- */
[data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  filter: blur(5px);
  transition:
    opacity var(--dur) var(--ease-out),
    transform var(--dur) var(--ease-out),
    filter var(--dur) var(--ease-out);
  transition-delay: calc(var(--i, 0) * 90ms);
}
/* the hint only until the block is shown: kept for good, it held the search form and the other blocks on layers of
   their own for the whole visit (2026-10-04, with the record-view INP work) */
[data-reveal]:not(.is-in) { will-change: opacity, transform, filter; }
[data-reveal].is-in { opacity: 1; transform: none; filter: none; }
/* a focused block shows at once, stagger or not (main.js also marks it is-in so it stays shown) */
[data-reveal]:focus-within { opacity: 1; transform: none; filter: none; transition-delay: 0s; transition-duration: .2s; }

/* scroll-driven drift for big numerals (progressive) */
@supports (animation-timeline: view()) {
  .drift { animation: drift linear both; animation-timeline: view(); animation-range: entry 0% exit 100%; }
  @keyframes drift { from { transform: translateY(7vh); } to { transform: translateY(-7vh); } }
}

/* ---------- hero ---------- */
.hero {
  position: relative;
  min-height: min(78svh, 760px);
  display: grid; place-items: center;
  overflow: clip;
  background:
    radial-gradient(1100px 520px at 70% -10%, rgba(200, 144, 42, .16), transparent 60%),
    radial-gradient(900px 600px at 12% 110%, rgba(139, 69, 19, .11), transparent 65%),
    linear-gradient(var(--paper), var(--paper-deep) 130%);
  padding-block: 0;
  border-bottom: 1px solid var(--hairline);
}
.hero-mark {
  position: absolute; z-index: 1;
  width: min(58vw, 640px); height: auto;
  right: -9%; top: 50%; transform: translateY(-52%) rotate(8deg);
  opacity: .055;
  pointer-events: none;
}
.hero-stats {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 0; margin: 3rem 0 0; padding: 0;
}
.hero-stats div {
  padding: .2rem 1.6rem;
  border-left: 1px solid var(--hairline-strong);
}
.hero-stats div:first-child { border-left: 0; }
.hero-stats dt {
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 2.4vw, 1.9rem);
  font-weight: 560; color: var(--saddle-deep);
  letter-spacing: -0.01em;
}
.hero-stats dd {
  margin: .1rem 0 0;
  font-size: var(--t-micro); font-weight: 600;
  letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-faint);
}
@media (max-width: 720px) {
  .hero { min-height: auto; }
  .hero-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem 0; }
  .hero-stats div:nth-child(odd) { border-left: 0; }
  .hero-mark { width: 90vw; right: -34%; opacity: .04; }
}
/* Phone-width header: everything on one line, no internal wrapping */
@media (max-width: 480px) {
  .site-head .bar { gap: .7rem; }
  .brand { font-size: 1.02rem; gap: .45rem; }
  .brand svg { width: 23px; height: 23px; }
  .nav { gap: .7rem; }
  .nav a { font-size: .8rem; }
  .nav .btn { padding: .45rem .75rem !important; font-size: .76rem; }
}
.hero-inner {
  position: relative; z-index: 3; text-align: center;
  padding: clamp(1.4rem, 3.5vh, 2.4rem) 0 clamp(1.8rem, 4.5vh, 2.8rem);
  pointer-events: none;
}
.hero-inner > * { pointer-events: auto; }
.hero-kicker {
  font: 600 var(--t-micro)/1 var(--font-ui);
  letter-spacing: .22em; text-transform: uppercase; color: var(--saddle);
  /* it's a <p>: the global 68ch cap would otherwise pin its box left */
  margin-inline: auto;
}
.hero h1 {
  font-size: var(--t-hero);
  font-weight: 480;
  margin: .35em 0 .22em;
}
.hero h1 em { font-style: italic; font-weight: 540; color: var(--saddle-deep); }
.hero .lede { margin-inline: auto; max-width: 44ch; }
.hero-cta { display: flex; gap: .9rem; justify-content: center; margin-top: 2.1rem; flex-wrap: wrap; }


/* ---------- dark narrative chapters ---------- */
.night {
  background:
    radial-gradient(900px 480px at 80% 0%, rgba(200, 112, 42, .12), transparent 60%),
    linear-gradient(var(--night), var(--night-2));
  color: var(--on-night);
}
.night h2, .night h3 { color: #F6EBD7; }
.night .muted { color: #A8967F; }
.night .rule { border-color: rgba(239, 229, 213, .14); }
.chapter { display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); gap: clamp(1.5rem, 5vw, 4.5rem); align-items: center; }
.chapter + .chapter { margin-top: clamp(3.5rem, 9vw, 7rem); }
.chapter:nth-child(even) .chapter-num { order: 2; }
.chapter-num {
  font-family: var(--font-display);
  font-size: clamp(3.6rem, 9.5vw, 7.6rem);
  font-weight: 320; line-height: .95;
  letter-spacing: -0.03em;
  color: transparent;
  background: linear-gradient(160deg, #F1DDBA, #C8902A 55%, #8B5A13);
  -webkit-background-clip: text; background-clip: text;
  font-variant-numeric: tabular-nums;
}
.chapter-num .unit { display: block; font-family: var(--font-ui); font-size: var(--t-micro); font-weight: 600; letter-spacing: .2em; text-transform: uppercase; color: #A8967F; margin-top: .9rem; -webkit-text-fill-color: #A8967F; }

/* ---------- ledger-paper record cards ---------- */
.record {
  background:
    repeating-linear-gradient(transparent, transparent 27px, rgba(42, 33, 24, .055) 28px),
    linear-gradient(#FFFDF8, var(--paper-deep));
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  padding: 1.1rem 1.25rem;
  transition: transform .45s var(--ease-spring), box-shadow .45s var(--ease-out), border-color .3s;
}
.record:hover { transform: translateY(-3px); box-shadow: var(--shadow-2); border-color: var(--hairline-strong); }

/* ---------- search page ---------- */
.search-hero { padding-block: clamp(2.5rem, 6vw, 4rem) 1.2rem; }
.searchbox {
  display: flex; align-items: center; gap: .8rem;
  background: #FFFDF8;
  border: 1.5px solid var(--hairline-strong);
  border-radius: 999px;
  padding: .45rem .6rem .45rem 1.4rem;
  box-shadow: var(--shadow-1);
  transition: border-color .3s, box-shadow .3s;
}
.searchbox:focus-within { border-color: var(--saddle); box-shadow: 0 0 0 4px rgba(139, 69, 19, .12), var(--shadow-2); }
/* the input itself draws no ring (outline: 0 below), so the pill carries the site's focus outline (WCAG 2.4.7) */
.searchbox:has(input:focus-visible) { outline: 2px solid var(--saddle); outline-offset: 3px; }
.searchbox input {
  flex: 1; border: 0; outline: 0; background: transparent;
  font: 480 clamp(1.05rem, 1.7vw, 1.25rem)/1.3 var(--font-display);
  color: var(--ink); min-width: 0;
}
.searchbox input::placeholder { color: var(--ink-faint); font-style: italic; }
.filters { display: flex; flex-wrap: wrap; gap: .55rem; align-items: center; margin-top: 1.1rem; }
.filters select {
  font: 530 var(--t-small)/1 var(--font-ui); color: var(--ink-soft);
  background: transparent; border: 1.5px solid var(--hairline-strong);
  border-radius: 999px; padding: .55rem .8rem;
}
[hidden] { display: none !important; } /* keep the hidden attribute authoritative over display rules */

/* the About-this-record-set band (night treatment, readable body type) */
.about-band #context-card p {
  font-size: 1.04rem; line-height: 1.7; color: #C9B89F; margin: 0 0 .9em;
}
.about-band #context-card p:last-child { margin-bottom: 0; }
.about-band #context-card strong { color: #F6EBD7; }
.about-band #context-card a { color: #E8C98A; }
.about-band #context-card em { color: #D9C7A8; }
.filters .numwrap {
  display: inline-flex; align-items: center; gap: .15rem; cursor: text;
  background: #FFFDF8; border: 1.5px solid var(--saddle);
  border-radius: 999px; padding: .12rem .3rem .12rem .9rem;
  transition: box-shadow .25s, border-color .25s;
}
.filters .numwrap:focus-within { border-color: var(--ink); box-shadow: 0 0 0 3px rgba(139,69,19,.14); }
.filters .numwrap:has(.numbox:focus-visible) { outline: 2px solid var(--saddle); outline-offset: 3px; }
.filters .numlabel {
  font: 700 .72rem/1 var(--font-ui); letter-spacing: .09em;
  text-transform: uppercase; color: var(--saddle); white-space: nowrap;
}
.filters .numbox {
  font: 530 var(--t-small)/1 var(--font-ui); color: var(--ink);
  background: transparent; border: none;
  padding: .5rem .4rem; width: 4.6rem; font-variant-numeric: tabular-nums;
}
.filters .numbox:focus { outline: none; }
.filters .numbox::placeholder { color: var(--ink-faint); opacity: .55; }
.filters-sep {
  width: 1px; align-self: stretch; background: var(--hairline);
  margin-inline: .35rem;
}
.result-meta { color: var(--ink-faint); font-size: var(--t-small); margin-block: 1.2rem .4rem; min-height: 1.4em; }

.results { display: grid; gap: .65rem; padding: 0; margin: 0; list-style: none; }
.result {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) auto;
  gap: .25rem 1rem;
  align-items: center;
  cursor: pointer;
}
.result .r-name { font-family: var(--font-display); font-size: 1.18rem; font-weight: 560; }
/* The row is a list item; the name inside it is the button (WCAG 1.3.1: <li role="button"> lost the list). */
.result .r-open {
  font: inherit; color: inherit; background: none; border: 0; padding: 0; margin: 0;
  text-align: inherit; cursor: pointer;
}
.result .r-open:focus-visible { outline: none; }
.result:has(.r-open:focus-visible) { outline: 2px solid var(--saddle); outline-offset: 2.5px; }
.result .r-sub { display: flex; flex-wrap: wrap; gap: .45rem .9rem; align-items: center; color: var(--ink-soft); font-size: var(--t-small); }
.result .r-go { color: var(--ink-faint); transition: transform .35s var(--ease-spring), color .25s; font-size: 1.25rem; }
.result:hover .r-go { transform: translateX(4px); color: var(--saddle); }
/* `backwards`, not `both`: a filling animation (with a filter in it) stayed applied to every row for the rest of the
   visit, and a long session holds hundreds of rows. That made each frame dearer, so opening and closing a record was
   slow on desktops without GPU help: the field's desktop INP was 304 ms (2026-10-04 report). search.js also drops the
   class when the animation ends. */
.result.entering { animation: result-in .6s var(--ease-out) backwards; animation-delay: calc(var(--i) * 55ms); }
@keyframes result-in {
  from { opacity: 0; transform: translateY(14px); filter: blur(3px); }
  to { opacity: 1; transform: none; filter: none; }
}
.struck-note { color: var(--ink-faint); font-style: italic; }

/* A page opened on a search link holds the results area open until search.js puts its placeholders in
   (search/index.html sets the class in <head>; search.js removes it) — see "placeholders" in search.js. */
.np-searching #results { min-height: 100vh; }

/* skeleton shimmer */
.skeleton { position: relative; overflow: hidden; background: var(--paper-deep); border-radius: var(--radius); height: 74px; }
.skeleton::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 30%, rgba(255, 253, 248, .9) 50%, transparent 70%);
  animation: shimmer 1.3s infinite;
}
@keyframes shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }

/* ---------- record detail: centered modal (2026-09-26; was a right-hand drawer) ----------
   Built like the cross-promotion modal, which was measured on iPhone Safari: the overlay is the fixed
   `inset: 0` box and the modal is sized to it (`max-height: 100%`), never to vh, because on iOS 100vh
   is taller than the visible area. The close button sits outside the scrolling body so it can't
   scroll away. The modal hangs from the TOP of the overlay rather than being centred vertically: the
   record loads a moment after the click, and a vertically centred box would move its top edge up as
   it grows, which counts as a layout shift. Growing downward moves nothing. z-index 95: over the
   consent banner (65) and the promo bar (55), under the promo modal (100). */
/* No scrollbar-gutter: stable here. It would stop the page behind shifting ~8px when a classic scrollbar comes back,
   but it leaves an undimmed strip down the right edge while the modal is open (tried 2026-09-26). */
html.rec-locked { overflow: hidden; }
.rec-overlay {
  position: fixed; inset: 0; z-index: 95;
  display: flex; align-items: flex-start; justify-content: center;
  padding: clamp(12px, 5vh, 56px) 16px 16px;
  /* No backdrop-filter: a full-screen blur, redone whenever anything in the open record changed, was most of the
     cost of opening a record, opening its card text and closing it on desktops without GPU help (INP, 2026-10-04).
     The tint is a touch darker instead (.52 with a 3px blur before). */
  background: rgba(24, 18, 16, .56);
  opacity: 0; visibility: hidden;
  /* hidden only once the fade-out ends, but visible at once on open: focus() on a still-hidden box is ignored */
  transition: opacity .3s var(--ease-out), visibility 0s linear .3s;
}
.rec-overlay.open { opacity: 1; visibility: visible; transition: opacity .3s var(--ease-out), visibility 0s; }
@supports (height: 100svh) {
  .rec-overlay { max-height: 100svh; }
}
.rec-modal {
  position: relative; width: 100%; max-width: 1120px;   /* the page's own .wrap width */
  max-height: 100%; min-height: min(420px, 100%);
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--paper); border: 1px solid var(--hairline); border-radius: var(--radius);
  box-shadow: 0 24px 80px rgba(24, 18, 16, .38);
  transform: translateY(14px) scale(.98);
  transition: transform .35s var(--ease-out);
}
.rec-overlay.open .rec-modal { transform: none; }
.rec-modal:focus { outline: none; }
.rec-body {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  padding: 1.7rem 2rem 2.2rem;
}
.rec-body h2:focus { outline: none; }   /* focused on each record so a screen reader announces it */
/* The bar never scrolls: Back / Forward through the records opened here, the trail of them, and ✕.
   Fixed height, so a trail that changes can't move the record under it. */
.rec-bar {
  flex: 0 0 auto; display: flex; align-items: center; gap: .45rem;
  height: 58px; padding: 0 12px 0 14px;
  border-bottom: 1px solid var(--hairline);
  background: color-mix(in srgb, var(--paper-deep) 55%, var(--paper));
}
.rec-nav {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: .3rem;
  height: 36px; padding: 0 .75rem; border-radius: 99px;
  font: 600 var(--t-small)/1 var(--font-ui); color: var(--ink);
  background: #FFFDF8; border: 1px solid var(--hairline-strong); cursor: pointer;
  transition: border-color .2s, color .2s;
}
.rec-nav span[aria-hidden] { font-size: 1.25rem; line-height: 0; margin-top: -2px; }
.rec-nav:hover:not(:disabled) { border-color: var(--saddle); color: var(--saddle-deep); }
.rec-nav:disabled { opacity: .38; cursor: default; }
.rec-trail {
  flex: 1 1 auto; min-width: 0; overflow: hidden;   /* never scrolls: what doesn't fit folds into "…" */
  white-space: nowrap; font-size: var(--t-small);
}
.rec-trail ol { display: flex; align-items: center; margin: 0; padding: 0 .3rem; list-style: none; }
.rec-trail li { flex: 0 0 auto; }
.rec-trail li[hidden] { display: none; }
/* the current crumb may shrink (ellipsis) only once everything else is folded; not while measuring */
.rec-trail li:has(> [aria-current]) { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.rec-trail.is-measuring li { flex: 0 0 auto; }
.rec-trail li:not([hidden]) ~ li:not([hidden])::before { content: '›'; margin: 0 .45rem; color: var(--ink-faint); }
/* more specific than `.rec-trail button` below, which would otherwise turn the chip into a plain link */
.rec-trail .rec-trail-more button {
  text-decoration: none; font-weight: 600; color: var(--ink);
  border: 1px solid var(--hairline-strong); border-radius: 99px; padding: .25rem .6rem; background: #FFFDF8;
}
.rec-trail .rec-trail-more button:hover, .rec-trail .rec-trail-more button[aria-expanded="true"] { border-color: var(--saddle); color: var(--saddle-deep); }
/* every record opened in the window, from the "…" chip */
.rec-list {
  position: absolute; top: 64px; left: 12px; z-index: 3;
  width: min(460px, calc(100% - 24px)); max-height: min(60%, 460px); overflow-y: auto;
  padding: .8rem .5rem .6rem; border-radius: var(--radius-sm);
  background: #FFFDF8; border: 1px solid var(--hairline-strong); box-shadow: var(--shadow-2);
  font-size: var(--t-small);
}
.rec-list[hidden] { display: none; }
.rec-list-title { margin: 0 .6rem .4rem; font: 600 var(--t-micro)/1.3 var(--font-ui); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-faint); }
.rec-list ol { margin: 0; padding: 0; list-style: none; counter-reset: rec; }
.rec-list li { counter-increment: rec; }
.rec-list li > * { display: block; width: 100%; text-align: left; padding: .5rem .6rem; border-radius: 6px; }
.rec-list li > *::before { content: counter(rec) ". "; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.rec-list button { font: inherit; color: var(--saddle-deep); background: none; border: 0; cursor: pointer; }
.rec-list button:hover { background: var(--paper-deep); }
.rec-list [aria-current] { font-weight: 700; color: var(--ink); background: color-mix(in srgb, var(--saddle) 7%, transparent); }
.rec-list em { font-style: normal; font-weight: 500; color: var(--ink-faint); }
.rec-trail button {
  font: inherit; color: var(--saddle); background: none; border: 0; padding: .2rem .15rem; cursor: pointer;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px;
}
.rec-trail [aria-current] { font-weight: 700; color: var(--ink); }
.rec-trail-sub { font-weight: 500; color: var(--ink-faint); font-size: .9em; }
.rec-close {
  flex: 0 0 auto;
  background: var(--paper-deep); border: 1px solid var(--hairline);
  width: 38px; height: 38px; border-radius: 50%;
  font-size: 1.05rem; cursor: pointer; color: var(--ink-soft);
  transition: transform .3s var(--ease-spring), color .2s;
}
.rec-close:hover { transform: rotate(90deg); color: var(--ink); }
/* a parent named on someone else's card: says so first, with their own enrollment */
.rec-callout {
  margin: 0 0 1.2rem; padding: 1rem 1.15rem 1.1rem;
  border: 1px solid color-mix(in srgb, var(--saddle) 35%, var(--hairline));
  border-left: 4px solid var(--saddle); border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--saddle) 6%, #FFFDF8);
}
.rec-callout-title { margin: 0 0 .4em; font: 700 var(--t-small)/1.35 var(--font-ui); color: var(--saddle-deep); }
.rec-callout .micro[style*="uppercase"]:first-of-type { margin-top: .9rem; }
/* the wider modal has room for the household and other record links side by side */
.rec-modal .rel-list { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
@media (max-width: 600px) {
  .rec-overlay { padding: 10px; }
  .rec-body { padding: 1.3rem .9rem 1.8rem; }
  .rec-bar { height: 54px; padding: 0 8px 0 10px; gap: .35rem; }
  .rec-nav { padding: 0 .7rem; }
  .rec-nav-label { display: none; }   /* ‹ › alone on a phone; the aria-labels still say Back / Forward */
  /* the six-column table needs ~303px: it fits from 360px-wide phones up; below that the card scrolls sideways
     rather than clip the Roll column (the drawer clipped it) */
  .rec-body .record { padding: .95rem .6rem; overflow-x: auto; }
  .rec-body .persons-table { font-size: .8rem; }
  .rec-body .persons-table th, .rec-body .persons-table td { padding-inline: .25rem; }
}
.persons-table { width: 100%; border-collapse: collapse; font-size: var(--t-small); }
.persons-table th { text-align: left; font: 600 var(--t-micro)/1.3 var(--font-ui); letter-spacing: .05em; text-transform: uppercase; color: var(--ink-faint); padding: .5rem .55rem .35rem; border-bottom: 1.5px solid var(--hairline-strong); }
.persons-table td { padding: .5rem .55rem; border-bottom: 1px solid var(--hairline); vertical-align: top; }
.v-badge {
  display: inline-block; font-size: .62em; font-weight: 700;
  color: var(--chickasaw); background: color-mix(in srgb, var(--chickasaw) 14%, transparent);
  border-radius: 99px; padding: .18em .5em; vertical-align: .25em; cursor: help;
}
.rel-list { display: grid; gap: .4rem; }
.rel-item {
  display: flex; flex-direction: column; align-items: flex-start; gap: .1rem;
  width: 100%; text-align: left; cursor: pointer;
  background: #FFFDF8; border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  padding: .6rem .8rem; font: inherit; color: inherit;
  transition: border-color .25s, transform .3s var(--ease-spring), box-shadow .3s;
}
.rel-item:hover { border-color: var(--saddle); transform: translateX(3px); box-shadow: var(--shadow-1); }
.rel-item .rel-name { font-family: var(--font-display); font-weight: 560; }
.rel-item .rel-sub { font-size: var(--t-micro); color: var(--ink-faint); }
.transcript {
  font-family: var(--font-display); font-style: italic; font-size: .95rem;
  color: var(--ink-soft); white-space: pre-wrap;
  max-height: 200px; overflow-y: auto;
  background: #FFFDF8; border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  padding: .9rem 1rem;
}

/* ---------- guides / prose ---------- */
.prose h2 { margin-top: 2.2em; }
.prose h3 { margin-top: 1.6em; }
.prose ul, .prose ol { padding-left: 1.3rem; }
.prose li { margin-bottom: .45em; }
.prose blockquote {
  margin: 1.4em 0; padding: .9em 1.2em;
  border-left: 3px solid var(--gold);
  background: var(--paper-deep); border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-family: var(--font-display); font-style: italic; color: var(--ink-soft);
}
.guide-card { display: block; text-decoration: none; color: inherit; padding: 1.5rem 1.6rem; }
.guide-card h2, .guide-card h3 { transition: color .25s; }
.guide-card h2 { font-size: var(--t-3); font-weight: 600; }   /* h2 for heading order; looks like the old h3 */
.guide-card:hover h2, .guide-card:hover h3 { color: var(--saddle-deep); }
.guide-card .more { color: var(--saddle); font-weight: 600; font-size: var(--t-small); }

/* ---------- footer ---------- */
.site-foot {
  background: var(--night); color: #A8967F;
  padding-block: 3.2rem 2.4rem; font-size: var(--t-small);
}
.site-foot a { color: #D8C5A5; }
.site-foot .cols { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 2rem; margin-bottom: 2.2rem; }
.site-foot .notice { font-size: var(--t-micro); line-height: 1.7; color: #93836E; max-width: 64ch; }   /* 5.0:1 on --night (was #8B7A64, 4.47:1) */

/* ---------- helpers ---------- */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space); }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space); }
.stack > * + * { margin-top: .9rem; }
.center { text-align: center; }
.center p { margin-inline: auto; }
.kicker {
  font: 600 var(--t-micro)/1 var(--font-ui);
  letter-spacing: .22em; text-transform: uppercase; color: var(--saddle);
  display: block; margin-bottom: 1rem;
}

/* ---------- responsive ---------- */
@media (max-width: 880px) {
  .chapter { grid-template-columns: 1fr; }
  .chapter:nth-child(even) .chapter-num { order: 0; }
  .grid-3 { grid-template-columns: 1fr; }
  .grid-2 { grid-template-columns: 1fr; }
  .site-foot .cols { grid-template-columns: 1fr; }
  .nav { gap: .85rem; }
  .nav .nav-sec { display: none; }
}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
  [data-reveal] { opacity: 1; transform: none; filter: none; }
}
  
/* ---------- view transitions (progressive) ---------- */
/* NO cross-document `@view-transition { navigation: auto }` — removed 2026-09-20.
   It made every in-site click animate TWICE: the outgoing page's snapshot stayed
   painted, slid away, and only then did the new page run its own [data-reveal]
   entrance, so hero text appeared, vanished and animated in again. Measured on
   nativepast.com/search/: ink in the hero band went 20.6% -> 4.6% -> 9.6% with the
   rule, and a single 0 -> 9.6% ramp without it. The reveal animation already gives
   the site its entrance; the page-level one only fought it.
   The rules below are kept for the SAME-document transition that search.js drives
   through document.startViewTransition() when switching record sets. */
::view-transition-old(root) { animation: vt-out .28s var(--ease-out) both; }
::view-transition-new(root) { animation: vt-in .42s var(--ease-out) both; }
@keyframes vt-out { to { opacity: 0; transform: translateY(-8px); } }
@keyframes vt-in { from { opacity: 0; transform: translateY(10px); } }

/* ---------- App store badges (official Apple/Google art; not yet linked) ----------
   Both assets are exact-cropped to the visible pill (the Google PNG was
   extracted from Google's padded art), so equal CSS height = equal badges. */
.store-badges {
  display: flex; flex-wrap: wrap; align-items: center; gap: 16px;
  margin-top: 1.1rem;
}
.store-badge { display: inline-block; line-height: 0; }
.store-badge img {
  height: 54px; width: auto; display: block; border: 0;
}
.store-badges + .micro { margin-top: .55rem; }
/* Hero placement: centered like .hero-cta (flex rows ignore text-align) */
.hero .store-badges { justify-content: center; margin-top: 1.4rem; }
.hero .store-badges + .micro { text-align: center; margin-inline: auto; }

/* ---------- mobile hero: badges above the fold on first visit ----------
   (Placed at end of file: the earlier 720px block precedes the hero base
   rules and loses the cascade at equal specificity.) */
@media (max-width: 720px) {
  .hero-inner { padding-top: 1.1rem; }
  .hero h1 { font-size: clamp(2.05rem, 8.6vw, 2.5rem); }
  .hero .lede { font-size: .95rem; line-height: 1.55; margin-top: .9rem; }
  .hero-cta { margin-top: 1.2rem; }
  .hero .store-badges { margin-top: 1rem; }
  .store-badge img { height: 46px; }
  .hero .store-badges + .micro { margin-top: .45rem; }
  .hero-stats { margin-top: 2rem; }
}

/* ---------- mobile scroll cue (homepage hero) ---------- */
.hero-scroll-cue { display: none; }
@media (max-width: 720px) {
  .hero-scroll-cue {
    position: fixed; left: 50%; bottom: max(16px, env(safe-area-inset-bottom));
    transform: translateX(-50%);
    display: inline-flex; align-items: center; justify-content: center;
    width: 42px; height: 42px; border-radius: 999px;
    color: var(--saddle); background: rgba(255, 253, 248, .92);
    border: 1.5px solid var(--hairline-strong);
    box-shadow: var(--shadow-1);
    z-index: 40;
    animation: cue-bob 2.4s ease-in-out infinite;
    transition: opacity .45s, visibility .45s;
  }
  .hero-scroll-cue.is-gone { opacity: 0; visibility: hidden; }
}
@keyframes cue-bob {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50% { transform: translateX(-50%) translateY(5px); }
}

/* ---------- mobile search form: stacked, uniform touch targets ---------- */
@media (max-width: 720px) {
  .searchbox { padding: .4rem .45rem .4rem 1rem; }
  .searchbox input { font-size: 1rem; }
  .filters { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
  .filters .filters-sep { display: none; }
  .filters select {
    width: 100%; min-height: 46px; background: #FFFDF8;
    grid-column: 1 / -1;
  }
  .filters .numwrap {
    width: 100%; min-height: 46px;
    padding: .12rem .6rem .12rem .9rem;
  }
  .filters .numwrap.coll-only { grid-column: 1 / -1; }
  .filters .numbox { width: 100%; flex: 1; }
}

/* the scroll cue lands the badges just below the sticky bar: html scroll-padding-top does it */

/* #apps badges: centered like the hero's (incl. their caption + link lines;
   the p rules need margin-inline:auto against the global 68ch cap) */
#apps .store-badges { justify-content: center; }
#apps .store-badges ~ .micro,
#apps .store-badges ~ .small { text-align: center; margin-inline: auto; }

/* ---------- analytics consent banner (assets/js/consent.js; ported from karaokesync.com v2.6.0, 2026-09-12) ----------
   Shown only where opt-in is required (EU/EEA, UK, Switzerland), when the region check fails, or with
   ?consent-preview. Allow and Decline share one style on purpose: equal prominence. The site-wide
   [hidden] rule keeps the hidden attribute authoritative over display:flex.
   z-index 65: above the sticky header (50) and the tutorial's back-to-top button (60), under the
   record detail modal (95). */
.consent-banner {
  position: fixed; right: 16px; bottom: 16px; left: 16px; z-index: 65;
  display: flex; align-items: center; gap: 12px 20px;
  max-width: 760px; margin: 0 auto; padding: 16px 20px;
  border-radius: var(--radius);
  background: linear-gradient(var(--night), var(--night-2));
  color: var(--on-night);
  box-shadow: 0 10px 40px rgba(24, 18, 16, .35);
  font-family: var(--font-ui);
}
.consent-text { flex: 1 1 auto; margin: 0; max-width: none; color: #D9C9B0; font-size: var(--t-small); line-height: 1.5; }
.consent-text a { color: #E8C98A; white-space: nowrap; } /* "Privacy details" never splits across lines */
.consent-text a:hover { color: #F6EBD7; }
.consent-actions { display: flex; flex-shrink: 0; gap: 10px; }
.consent-btn {
  min-width: 100px; padding: .6rem 1.1rem;
  border: 1.5px solid #C8902A; border-radius: 999px;
  background: transparent; color: #F6EBD7;
  font: 600 var(--t-small)/1.2 var(--font-ui); cursor: pointer;
  transition: background-color .2s;
}
.consent-btn:hover { background: rgba(200, 144, 42, .18); }
.consent-btn:focus-visible, .consent-text a:focus-visible { outline: 2px solid #E8C98A; outline-offset: 2px; }
/* Phones: the hero's store badges and the scroll cue sit low on the first screen, so the banner goes
   to the top, just under the 64px sticky header, instead of covering them. */
@media (max-width: 720px) {
  .consent-banner { top: calc(72px + var(--promo-h)); right: 8px; bottom: auto; left: 8px; flex-direction: column; align-items: stretch; gap: 10px; padding: 12px 14px; }
  .consent-text { font-size: .8125rem; }
  .consent-btn { flex: 1; min-width: 0; }
}

/* "Privacy Choices" in the footer: hidden until consent.js reveals it, styled like the footer links.
   In the one-line footers it draws its own separator dot, so nothing dangles while it stays hidden
   (without JavaScript no beacon loads, so there is nothing to choose). */
.footer-link-button {
  margin: 0; padding: 0; border: 0; background: none; cursor: pointer;
  font: inherit; color: #D8C5A5;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px;
}
.footer-link-button:hover { color: #F6EBD7; }
.footer-link-button::before { content: "\00B7"; display: inline-block; margin-inline: .3em; color: #A8967F; }
.footer-link-button--stack { display: block; } /* the column footers: its own line, no dot */
.footer-link-button--stack::before { content: none; }

/* the privacy page's section anchors (the banner links to /privacy/#analytics) clear the sticky header
   through html scroll-padding-top */

/* ============================================================
   Cross-promotion bar + modal  ·  assets/js/app-promo.js
   The studio's other apps, in place of third-party ads (owner's decision,
   2026-09-20). Height lives in --promo-h so nothing shifts on load.
   z-index 55: over the sticky header (50), under the consent banner (65)
   so consent stays actionable, and under the record detail modal (95).
   ============================================================ */
.app-promo {
  position: fixed; top: 0; left: 0; right: 0; height: var(--promo-h); z-index: 55;
  background: linear-gradient(var(--night), var(--night-2));
  border-bottom: 1px solid rgba(232, 201, 138, .16);
}
.app-promo-link {
  /* centred as a group, like the studio bar. The crossfade covers the reflow when
     a longer or shorter app name changes the group's width. */
  display: flex; align-items: center; justify-content: center; gap: 1rem;
  height: 100%; max-width: 1120px; margin: 0 auto;
  padding: 0 clamp(14px, 3vw, 26px);
  color: var(--on-night); text-decoration: none;
}
.app-promo-link:hover .app-promo-name { color: #F6EBD7; }
.app-promo-link:hover .app-promo-arrow { transform: translateX(3px); }
.app-promo-link:focus-visible { outline: 2px solid #E8C98A; outline-offset: -4px; border-radius: 3px; }
/* Pause/Play for the rotation (WCAG 2.2.2): the one pause that works on a touch screen. app-promo.js
   unhides it only when the bar actually rotates; it pauses this page and stores nothing. 32px target. */
.app-promo-pause {
  position: absolute; top: 50%; inset-inline-end: 10px; transform: translateY(-50%);
  width: 32px; height: 32px; display: grid; place-items: center; padding: 0;
  border: 1px solid rgba(232, 201, 138, .38); border-radius: 50%;
  background: rgba(255, 255, 255, .06); color: #E8C98A; cursor: pointer;
  transition: background .2s;
}
.app-promo-pause:hover { background: rgba(255, 255, 255, .13); }
.app-promo-pause:focus-visible { outline: 2px solid #E8C98A; outline-offset: 2px; border-radius: 50%; }
.app-promo-pause svg { width: 13px; height: 13px; fill: currentColor; }
.app-promo-pause .app-promo-play-icon,
.app-promo-pause[aria-pressed="true"] .app-promo-pause-icon { display: none; }
.app-promo-pause[aria-pressed="true"] .app-promo-play-icon { display: block; }

.app-promo-icon {
  width: 48px; height: 48px; flex: 0 0 auto;
  border-radius: 11px; background: rgba(255, 255, 255, .07);
  box-shadow: 0 2px 8px rgba(0, 0, 0, .38);
}
.app-promo-copy {
  /* Fixed flex-basis, not auto: the group's width must not depend on the app
     currently showing, or a longer name (Understood In Spanish) shifts the whole
     centred row and the static sub-line visibly slides. Shrinks on narrow screens;
     either line ellipsises rather than pushing anything. */
  flex: 0 1 500px; min-width: 0;
  display: flex; flex-direction: column; gap: 2px; text-align: center;
}
.app-promo-headline {
  font-size: 1rem; line-height: 1.3; color: #F1E3C9;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.app-promo-name { font-weight: 680; }
.app-promo-tagline { color: #D7C6A9; font-weight: 400; }
.app-promo-sub {
  font-size: .8125rem; line-height: 1.35; color: var(--on-night-soft);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.app-promo-sub-brief { display: none; }
.app-promo-arrow {
  color: #E8C98A; font-size: .95rem;
  display: inline-block; transition: transform .25s var(--ease-out);
}

/* The icon and the app line are what swap; the sub-line is a stable anchor and
   never moves, because .app-promo-copy's width no longer depends on the content.
   Two phases: `is-out` lifts the old line away, then the new one is placed below
   (`is-in`, no transition) and released to rise into place. */
.app-promo-fade { transition: opacity .28s var(--ease-out), transform .28s var(--ease-out); }
.app-promo-link.is-out .app-promo-fade { opacity: 0; transform: translateY(-5px); }
.app-promo-link.is-in .app-promo-fade { opacity: 0; transform: translateY(5px); transition: none; }
.app-promo:not(.is-ready) .app-promo-fade { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .app-promo-fade { transition: none; }
}

@media (max-width: 720px) {
  :root { --promo-h: 68px; }
  /* both sides, so the group stays centred clear of the Pause button */
  .app-promo-link { gap: .8rem; padding-inline: calc(clamp(14px, 3vw, 26px) + 36px); }
  .app-promo-copy { flex-basis: 340px; }
  .app-promo-icon { width: 40px; height: 40px; border-radius: 9px; }
  .app-promo-headline { font-size: .9375rem; }
  .app-promo-sub { font-size: .75rem; }
  .app-promo-sub-full { display: none; }
  .app-promo-sub-brief { display: inline; }
}
@media (max-width: 460px) {
  .app-promo-tagline { display: none; }   /* keep the app NAME on one line */
  .app-promo-headline { font-size: .875rem; }
}

/* ---------- modal ---------- */
html.app-promo-locked { overflow: hidden; }
.app-promo-overlay {
  position: fixed; inset: 0; z-index: 100;           /* over the record detail modal (95) */
  display: flex; align-items: center; justify-content: center; padding: 20px;
  background: rgba(24, 18, 16, .62); backdrop-filter: blur(4px);
  opacity: 0; visibility: hidden;
  transition: opacity .3s var(--ease-out), visibility .3s var(--ease-out);
}
.app-promo-overlay.is-open { opacity: 1; visibility: visible; }
/* Second belt on the same trousers as the modal's `max-height: 100%`: iOS Safari
   can lay a fixed `inset: 0` box out taller than the band that is actually on
   screen when BOTH the top address bar and the bottom toolbar are showing
   (Safari's "Single Tab" layout — the one the 2026-09-20 report came from).
   `svh` is that band with every toolbar expanded, so capping the overlay caps the
   centred modal inside it. Ignored by browsers without `svh`, which fall back to
   the `inset: 0` height. */
@supports (height: 100svh) {
  .app-promo-overlay { max-height: 100svh; }
}
.app-promo-modal {
  /* Sized to the OVERLAY, not to vh. On iOS Safari 100vh is the toolbar-less
     height (measured: 739px against a 699px visible area on an iPhone 16e), so a
     vh cap made the modal taller than the screen; flex-centring then pushed its
     top — and the close button with it — above the top edge, out of reach
     (reported 2026-09-20). 100% is the overlay's own height, which IS the
     visible area, so the modal always fits between the browser's toolbars.
     Column layout: the head is fixed and only the body scrolls, so the close
     button can never scroll away either. */
  position: relative; width: 100%; max-width: 520px; max-height: 100%;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--paper); border-radius: var(--radius);
  box-shadow: 0 24px 70px rgba(24, 18, 16, .42);
  transform: translateY(14px) scale(.97);
  transition: transform .35s var(--ease-out);
}
.app-promo-overlay.is-open .app-promo-modal { transform: none; }
.app-promo-close {
  position: absolute; top: 12px; right: 12px; width: 34px; height: 34px; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(255, 255, 255, .16); transition: background-color .2s;
}
.app-promo-close:hover { background: rgba(255, 255, 255, .3); }
.app-promo-close:focus-visible { outline: 2px solid #E8C98A; outline-offset: 2px; }
.app-promo-close svg { width: 17px; height: 17px; stroke: var(--on-night); stroke-width: 2.5; stroke-linecap: round; }
.app-promo-modal-head {
  flex: 0 0 auto;
  padding: 22px 24px 18px; text-align: center;
  background: linear-gradient(var(--night), var(--night-2));
  border-radius: var(--radius) var(--radius) 0 0;
}
.app-promo-modal-icon {
  /* main.css sets `img { display: block }` globally, so the header's
     text-align: center does not centre this — it needs auto margins. */
  width: 72px; height: 72px; border-radius: 16px; margin: 0 auto .7rem;
  box-shadow: 0 4px 18px rgba(0, 0, 0, .34);
}
.app-promo-modal-kicker {
  margin: 0 0 .2rem; font-size: var(--t-micro); font-weight: 600;
  letter-spacing: .15em; text-transform: uppercase; color: #C8902A;
}
.app-promo-modal-title {
  margin: 0; font-family: var(--font-display); font-weight: 600;
  font-size: 1.5rem; line-height: 1.2; color: var(--on-night);
}
.app-promo-modal-subtitle {
  margin: .4rem 0 0; font-size: var(--t-small); line-height: 1.45;
  color: var(--on-night-soft);
}
.app-promo-modal-body {
  /* the only scrolling part of the modal */
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 22px 26px 24px; text-align: center;
}

/* ---------- feature list ---------- */
.app-promo-features {
  list-style: none; margin: 0 0 1.3rem; padding: 0; text-align: left;
  border-top: 1px solid var(--hairline);
}
.app-promo-features li {
  display: flex; align-items: flex-start; gap: .7rem;
  padding: .7rem 0; border-bottom: 1px solid var(--hairline);
  font-size: var(--t-small); line-height: 1.5; color: var(--ink-soft);
  max-width: none;
}
.app-promo-check {
  flex: 0 0 auto; width: 21px; height: 21px; margin-top: .1rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%; background: linear-gradient(135deg, var(--ember), var(--saddle));
}
.app-promo-check svg { width: 11px; height: 11px; stroke: #fff; stroke-width: 3.2; stroke-linecap: round; stroke-linejoin: round; }
.app-promo-feature-text { min-width: 0; }
.app-promo-modal-copy {
  margin: 0 0 1.3rem; max-width: none;
  font-size: var(--t-small); line-height: 1.65; color: var(--ink-soft);
}
.app-promo-modal-site { margin: 0 0 1.1rem; }
.app-promo-modal-site a {
  font-size: var(--t-small); font-weight: 600; color: var(--saddle); text-decoration: none;
}
.app-promo-modal-site a:hover { color: var(--saddle-deep); text-decoration: underline; }
.app-promo-badges { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.app-promo-badge { display: inline-flex; transition: transform .2s var(--ease-out); }
.app-promo-badge:hover { transform: translateY(-2px); }
.app-promo-badge img { height: 40px; width: auto; display: block; }
.app-promo-modal-foot {
  margin: 1.2rem 0 0; font-size: var(--t-micro); line-height: 1.5; color: var(--ink-faint);
}

@media (max-width: 560px) {
  .app-promo-overlay { padding: 12px; }
  .app-promo-modal-head { padding: 18px 20px 15px; }
  .app-promo-modal-icon { width: 60px; height: 60px; border-radius: 14px; margin-bottom: .55rem; }
  .app-promo-modal-title { font-size: 1.28rem; }
  .app-promo-modal-body { padding: 18px 20px 20px; }
  .app-promo-modal-copy { margin-bottom: 1.05rem; }
  .app-promo-features { margin-bottom: 1.05rem; }
  .app-promo-features li { padding: .55rem 0; }
  .app-promo-modal-foot { margin-top: 1rem; }
}

/* Short viewports (landscape, or Safari with BOTH a top address bar and the
   bottom toolbar): shrink the header rather than let it eat the readable part. */
@media (max-height: 620px) {
  .app-promo-modal-head { padding: 14px 20px 12px; }
  .app-promo-modal-icon { width: 46px; height: 46px; border-radius: 11px; margin-bottom: .4rem; }
  .app-promo-modal-title { font-size: 1.15rem; }
  .app-promo-modal-subtitle { margin-top: .25rem; }
  .app-promo-modal-kicker { display: none; }
}

@media print {
  .app-promo, .app-promo-overlay { display: none !important; }
  body { padding-top: 0; }
  .site-head { top: 0; }
}
