/* ─────────────────────────────────────────────────────────────────────────────
   cadence.css — mobile-first band system for `type: cadence` pages.

   Spec: ../../../../MOBILE_CADENCE_SPEC.md
   Imagery framing contract: ../../../../MOBILE_CADENCE_IMAGERY.md §2

   ⚠️ MOBILE-FIRST. The base rules are written for a phone; wider screens are
   media-query blocks layered on top, and the large-screen design was decided on
   the homepage, which went live on it 2026-10-12 (MANTIS-847 (convert the
   homepage to cadence) https://bugs.jaji.us/view.php?id=847). Most of it is
   opt-in — the HOMEPAGE BEATS classes, `pillars: bleed`, `channel: true`,
   `.cad-show--desktop` — so pages built before them render unchanged. The
   component gallery constrains itself to a phone-width column so it can be
   reviewed on a laptop.

   ⚠️ FULL-BLEED PHOTOS DEPEND ON THE IMAGERY CONTRACT. Type sits in the top
   sixth and the floating card covers the bottom two-fifths. Art generated or
   shot without those quiet zones does not fit and cannot be made to fit by
   changing CSS. See the imagery file before commissioning anything.

   CHOOSE deliberately has NO markup of its own: it reuses lp-self-select.html
   so that lp-self-select-js.html binds unchanged and the whole measurement
   instrument transfers by construction. Only the styling is overridden, below.
   ───────────────────────────────────────────────────────────────────────────── */

.cad { --cad-gap: 1.15rem; }

/* ── shared type scale ──────────────────────────────────────────────────── */
.cad-eyebrow {
  font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--color-brand); margin: 0;
}
.cad h1, .cad h2 { font-family: var(--font-heading); font-weight: 700; margin: 0; text-wrap: balance; }
.cad h1 { font-size: 2.1875rem; line-height: 1.14; letter-spacing: -0.005em; }
.cad h2 { font-size: 1.8125rem; line-height: 1.18; }
.cad-swap { color: var(--color-brand); font-style: normal; }
.cad-lead { font-size: 1.0625rem; line-height: 1.55; color: var(--color-muted); margin: 0; }
.cad-body { font-size: 0.96875rem; line-height: 1.65; color: var(--color-muted); margin: 0; }

/* ── bands ──────────────────────────────────────────────────────────────── */
.cad-band { padding: 3.75rem 1.375rem; display: flex; flex-direction: column; gap: var(--cad-gap); }
.cad-band--cream  { background: var(--color-bg-soft); }
.cad-band--white  { background: var(--color-bg); }
.cad-band--purple { background: var(--color-brand); color: #fff; }
.cad-band--purple h1,
.cad-band--purple h2       { color: #fff; }
.cad-band--purple .cad-swap,
.cad-band--purple .cad-eyebrow { color: #d9c6ee; }
.cad-band--purple .cad-lead,
.cad-band--purple .cad-body    { color: #e6d9f3; }

/* ── OPENER · base box ───────────────────────────────────────────────────────
   Layout only. The hero's actual treatment — photograph filling the section
   behind a scrim — is in the HERO block further down and applies at EVERY width.

   ⚠️ THIS COMMENT USED TO SAY THE OPPOSITE, and that is worth knowing rather
   than quietly deleting. It claimed the treatment was desktop-only and that
   phone and tablet kept a stacked hero, which was true for exactly one commit.
   It went stale when the phone gained an art-directed portrait crop and the
   treatment moved to every width. A stale comment about the cascade is worse
   than none: a reader reasons from it instead of from the rules, which is how
   the mistake it warned about gets reintroduced.
   ───────────────────────────────────────────────────────────────────────────── */
.cad-opener { padding: 0; background: var(--color-bg-soft);
  display: flex; flex-direction: column; gap: 1rem; }
.cad-opener__head { padding: 1.625rem 1.375rem 0; display: flex; flex-direction: column; gap: 1rem; }
/* ⚠️ MATCHES .btn / .btn--cta IN main.css — 8px radius, 600 weight, no shadow.
   An earlier draft used a 999px pill with a drop shadow, which is not a FamYarn
   button: `border-radius: 999px` appears in main.css only on the nav toggle bars.
   Sized up from .btn's 0.62rem/0.95rem because this is a full-width primary
   action on a phone, not a nav button — the SHAPE is the brand, not the scale. */
.cad-cta {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.625rem;
  background: var(--color-brand); color: #fff; font-size: 1rem; font-weight: 600;
  padding: 0.95rem 1.25rem; border-radius: 8px; text-decoration: none;
  border: 1px solid var(--color-brand);
}
.cad-cta:hover, .cad-cta:focus-visible { background: #1f3a26; border-color: #1f3a26; }
.cad-cta--ghost { background: #fff; color: var(--color-brand); border-color: #fff; }
.cad-cta--ghost:hover, .cad-cta--ghost:focus-visible {
  background: var(--color-brand-soft); border-color: var(--color-brand-soft); color: var(--color-brand-dark);
}
.cad-trust { font-size: 0.78125rem; color: var(--color-muted); margin: 0; text-align: center; }
.cad-band--purple .cad-trust { color: #e0d0f0; }
/* ⚠️ height:auto IS LOAD-BEARING. The <img> carries width/height attributes (good —
   they reserve layout space and stop the reflow), but without height:auto the 1250
   attribute wins over width:100% and the photograph renders badly stretched. This
   was shipped broken once, 2026-09-06. Any <img> in this file needs the same. */
.cad img { height: auto; }
.cad-opener__img { display: block; width: 100%; }

/* ── PILLAR ─────────────────────────────────────────────────────────────── */
/* ⚠️ max-height IS IN PIXELS ON PURPOSE, AND THE NUMBER IS LOAD-BEARING.
   9/16 is the right shape on a phone and absurd above it: at 820px (iPad Air)
   the section was 1,458px tall — taller than the 1,180px screen — so the
   headline and its card could never be in frame together, and the beat read as
   an endless photograph.

   780px is chosen to be INERT ON EVERY PHONE. The tallest phone case is a 430px
   viewport (iPhone Pro Max), which gives 430 × 16/9 = 764px — under the cap, so
   nothing below ~438px changes at all. Above that the cap engages and the photo
   crops via object-fit rather than the section growing.

   Not a vh/svh unit: 80svh sounds tidier but bites phones. A 393×852 iPhone is
   699px of natural height against 682px of 80svh, so it would have cropped the
   one size this shape was designed for. */
.cad-pillar {
  /* ⚠️ `width: 100%` IS NOT REDUNDANT. With `aspect-ratio` and an auto width,
     a max-height constraint is transferred back to the width — measured: the
     section came out 439px wide (780 × 9/16) inside a 574px viewport, quietly
     ending the full-bleed photograph. Making the width definite stops the
     transfer, so max-height clamps only the height and the photo crops through
     object-fit instead. */
  position: relative; width: 100%; aspect-ratio: 9 / 16; max-height: 780px;
  /* ⚠️ NO `isolation: isolate` HERE. It trapped the card's z-index inside the
     section, so a following positioned section (another PILLAR) painted over the
     card's 2.125rem overhang and hid its button. Without it the card's z-index 3
     competes at page level and wins; photo 0, scrim 1 and head 2 still order
     correctly inside each pillar. Found 2026-10-06 on the homepage prototype;
     MANTIS-846 (homepage cadence redesign) https://bugs.jaji.us/view.php?id=846 */
  display: flex; flex-direction: column;
}
/* The photograph is an <img> so it can carry srcset. It fills the section and is
   the bottom layer: photo 0, scrim 1, type 2, card 3.
   ⚠️ The height needs TWO classes to win. `.cad img { height: auto }` (0,1,1)
   out-ranks a lone `.cad-pillar__photo` (0,1,0), so the photo would collapse to
   its intrinsic ratio and stop covering the section. */
.cad-pillar__photo { position: absolute; inset: 0; z-index: 0; }
.cad-pillar .cad-pillar__photo {
  width: 100%; height: 100%; object-fit: cover; object-position: center;
}
.cad-pillar picture { display: contents; }
.cad-tile picture { display: contents; }
/* ⚠️ THE SCRIM IS A FLOOR FOR LEGIBILITY, NOT A WASH.
   Two mistakes on 2026-09-07, in opposite directions, both recorded because the
   pair is the lesson.

   First it was too SHORT: both gradients died at 46–50% of the section height,
   so a third line of lead landed on bare photograph and dissolved into it.
   Then the fix went too FAR — 0.96 at the top holding 0.72 to 55% — and the
   photograph stopped being readable. A PILLAR whose photo you cannot make out is
   a cream band with an expensive background attached.

   What was missed the first time: the two levers are COUPLED. The lead over a
   light photograph moved from --color-muted to --color-text in the same change,
   and near-black type needs far LESS scrim than muted type does. Fix contrast
   first, then take the scrim down to the least that still works — not the other
   way round. Copy length is the third lever: at the 2–3 line budget the type
   ends around 30% of the frame, so nothing below ~55% needs covering at all.

   MEASURED, not guessed. With near-black type over the brightest plausible area
   of the held-photograph shot, contrast stays above 13:1 across the whole
   gradient — far past the 4.5:1 floor. So the scrim's remaining job is not
   luminance at all: it is separating type from BUSY DETAIL, which needs much
   less opacity than separating it from brightness did. If a future photograph is
   noisier behind the headline, raise the top stop only, and leave the tail. */
.cad-pillar::before { content: ""; position: absolute; inset: 0; z-index: 1; }
.cad-pillar--light::before {
  background: linear-gradient(180deg,
    rgba(251, 248, 243, 0.72) 0%, rgba(251, 248, 243, 0.46) 24%,
    rgba(251, 248, 243, 0.18) 40%, rgba(251, 248, 243, 0) 52%);
}
.cad-pillar--dark::before {
  background: linear-gradient(180deg,
    rgba(20, 12, 16, 0.74) 0%, rgba(20, 12, 16, 0.50) 25%,
    rgba(20, 12, 16, 0.22) 42%, rgba(20, 12, 16, 0) 54%);
}
.cad-pillar__head {
  position: relative; z-index: 2; padding: 2.125rem 1.375rem 0;
  display: flex; flex-direction: column; gap: 0.75rem;
}
/* A pillar after a pillar starts under the previous card's 2.125rem overhang, which
   used to be painted over and is now visible: give its eyebrow room to clear the
   card and its shadow. Matches the homepage prototype (58px there). */
.cad-pillar + .cad-pillar .cad-pillar__head { padding-top: 3.25rem; }
/* Over a photograph, --color-muted (#5b4a42) is tuned for a flat cream band, not
   for a scrimmed image whose luminance varies under it. The light PILLAR takes
   the full text colour instead. */
.cad-pillar--light .cad-pillar__head .cad-lead { color: var(--color-text); }
.cad-pillar--dark .cad-pillar__head h2 { color: #fff; }
.cad-pillar--dark .cad-pillar__head .cad-swap,
.cad-pillar--dark .cad-pillar__head .cad-eyebrow { color: #cbb3e4; }
.cad-pillar--dark .cad-pillar__head .cad-lead { color: #e9ded9; }

/* ── floating card ──────────────────────────────────────────────────────── */
.cad-card {
  position: relative; z-index: 3; margin: auto 1rem -2.125rem; background: #fff;
  border-radius: 18px; padding: 1.125rem; box-shadow: 0 18px 44px rgba(33,23,18,0.30);
  display: flex; flex-direction: column; gap: 0.8125rem;
}
.cad-card__kicker {
  font-size: 0.65625rem; font-weight: 700; letter-spacing: 0.15em;
  text-transform: uppercase; color: var(--color-brand); margin: 0;
}
.cad-card__title { font-family: var(--font-heading); font-size: 1.15625rem; line-height: 1.25; margin: 0; }
.cad-card__sub   { font-size: 0.875rem; color: var(--color-muted); margin: 0; }
.cad-card__quote { font-size: 0.875rem; line-height: 1.5; color: var(--color-muted); font-style: italic; margin: 0; }
.cad-rows { display: flex; flex-direction: column; border-top: 1px solid var(--color-border); }
.cad-row  { display: flex; align-items: center; gap: 0.6875rem; padding: 0.6875rem 0;
  border-bottom: 1px solid var(--color-border); font-size: 0.90625rem; }
.cad-row:last-child { border-bottom: 0; }
.cad-row__thumb { width: 38px; height: 38px; border-radius: 9px; object-fit: cover; flex: none; }
.cad-row__txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.cad-row__txt b { font-weight: 600; }
.cad-row__txt span { font-size: 0.78125rem; color: var(--color-muted); }
.cad-row__chev { color: #b9aca4; flex: none; font-size: 1.125rem; line-height: 1; }
.cad-people { display: flex; gap: 0.5625rem; }
.cad-person { display: flex; flex-direction: column; align-items: center; gap: 5px; flex: 1; min-width: 0; }
.cad-person__av { width: 44px; height: 44px; border-radius: 50%; background: var(--color-brand-soft);
  display: grid; place-items: center; font-size: 0.875rem; font-weight: 700; color: var(--color-brand-dark); }
/* ⚠️ AN OUTLINE, NOT A BOX-SHADOW RING. A 2.5px box-shadow spread drew the ring
   up to 31% thicker on one side in Firefox at 1x (the avatar lands on a fraction
   of a pixel: 18px root, rem gaps); an integer outline stays within 4% in Chrome
   and Firefox at 1x, 1.25x, 2x and 3x (measured 2026-10-12). */
.cad-person--on .cad-person__av { outline: 2px solid var(--color-brand); outline-offset: 0; }
.cad-person b { font-size: 0.75rem; font-weight: 600; }
.cad-person span { font-size: 0.65625rem; color: var(--color-muted); }
.cad-card__btn { display: flex; align-items: center; justify-content: center; gap: 0.5rem;
  background: var(--color-brand); color: #fff; font-size: 0.9375rem; font-weight: 700;
  padding: 0.8125rem; border-radius: 8px; text-decoration: none;
  border: 1px solid var(--color-brand); }
.cad-card__btn:hover, .cad-card__btn:focus-visible { background: #1f3a26; border-color: #1f3a26; }
/* The audio block centres as a GROUP — play button, strip, duration and the
   quote under them. The card's title and kicker stay left-aligned: centring
   those too would turn the card into a poster, and the rows in the other cards
   are read as a list, which wants a left edge. */
.cad-audio { display: flex; flex-direction: column; align-items: center;
  gap: 0.8125rem; text-align: center; }
.cad-wave { display: flex; align-items: center; justify-content: center; gap: 0.6875rem; }
.cad-wave__play { width: 38px; height: 38px; border-radius: 50%; background: var(--color-brand);
  flex: none; display: grid; place-items: center; }
.cad-wave__play::after { content: ""; border-left: 11px solid #fff;
  border-top: 7px solid transparent; border-bottom: 7px solid transparent; margin-left: 3px; }
/* A real one (wave.audio; cadence/video-js.html, CARD AUDIO): a button, which
   turns into pause while the clip plays; the hairline fills with progress. */
button.cad-wave__play { border: 0; padding: 0; cursor: pointer; }
button.cad-wave__play:hover { background: var(--color-brand-dark); }
button.cad-wave__play:focus-visible { outline: 2px solid var(--color-brand); outline-offset: 3px; }
button.cad-wave__play:disabled { cursor: default; opacity: 0.45; background: var(--color-brand); }
.cad-wave.is-playing .cad-wave__play::after { width: 12px; height: 14px; margin-left: 0; box-sizing: border-box;
  border: 0; border-left: 4px solid #fff; border-right: 4px solid #fff; }
/* While a card's clip plays its strip moves like the app's does while recording:
   the app's own envelope (genes app/globals.css `audio-signal-voice`, 4 s,
   linear, every bar on one clock), each bar offset by its --d (cadence/card.html
   has the provenance). Reduced motion stops it with every other animation. */
@keyframes cad-audio-voice {
  0% { transform: scaleY(0.30); } 3% { transform: scaleY(0.92); } 7% { transform: scaleY(0.61); }
  10% { transform: scaleY(0.84); } 15% { transform: scaleY(0.44); } 18% { transform: scaleY(1); }
  24% { transform: scaleY(0.58); } 28% { transform: scaleY(0.71); } 31% { transform: scaleY(0.36); }
  38% { transform: scaleY(0.88); } 43% { transform: scaleY(0.52); } 47% { transform: scaleY(0.24); }
  54% { transform: scaleY(0.20); } 58% { transform: scaleY(0.19); } 62% { transform: scaleY(0.86); }
  66% { transform: scaleY(0.55); } 69% { transform: scaleY(0.94); } 75% { transform: scaleY(0.42); }
  79% { transform: scaleY(0.66); } 84% { transform: scaleY(0.31); } 88% { transform: scaleY(0.78); }
  93% { transform: scaleY(0.45); } 97% { transform: scaleY(0.33); } 100% { transform: scaleY(0.30); }
}
.cad-wave.is-playing .cad-wave__fill { animation: cad-audio-voice 4s linear infinite; animation-delay: var(--d, 0ms); }
.cad-wave[style*="--cad-p"] .cad-wave__line { height: 2px; background: linear-gradient(90deg,
  var(--color-brand) var(--cad-p), color-mix(in srgb, var(--color-brand) 25%, transparent) var(--cad-p)); }
/* ⚠️ GEOMETRY MIRRORS genes/frontend/components/stories/AudioSignalIndicator.tsx.
   3px bars, 3px gaps, a 40px track, fully rounded ends, a permanent resting dot
   per bar and a 25% hairline behind them. 25 bars at 3+3 comes to 147px, which
   is why the strip is `flex: none` — letting it stretch would change the bar
   pitch and stop it looking like the component. Change these with that file. */
.cad-wave__bars { position: relative; display: flex; align-items: center;
  justify-content: center; gap: 3px; height: 40px; flex: none; }
.cad-wave__line { position: absolute; left: 0; right: 0; top: 50%; height: 1px;
  transform: translateY(-50%);
  background: color-mix(in srgb, var(--color-brand) 25%, transparent); }
.cad-wave__bar { position: relative; display: flex; align-items: center;
  justify-content: center; width: 3px; height: 100%; flex: none; }
.cad-wave__dot { position: absolute; height: 3px; width: 100%; border-radius: 999px;
  background: var(--color-brand); opacity: 0.4; }
.cad-wave__fill { position: absolute; width: 100%; border-radius: 999px;
  background: var(--color-brand); }
.cad-wave__t { font-size: 0.78125rem; color: var(--color-muted); flex: none; }

/* ── STATEMENT ──────────────────────────────────────────────────────────── */
.cad-statement { padding: 3.25rem 1.375rem; }
.cad-statement h2 { font-size: 1.6875rem; line-height: 1.28; }

/* ── RUN-ON (replaced the removed micro-list; see spec §2) ───────────────── */
.cad-runon { font-family: var(--font-heading); font-size: 1.5rem; line-height: 1.42;
  color: var(--color-text); margin: 0.125rem 0 0; text-wrap: pretty; }

/* ── REASSURE pledges ───────────────────────────────────────────────────── */
.cad-pledges { display: flex; flex-direction: column; margin: 0.375rem 0 0;
  border-top: 1px solid var(--color-border); }
.cad-pledges p { margin: 0; padding: 1.0625rem 0.125rem; font-size: 1.09375rem;
  font-weight: 600; line-height: 1.4; color: var(--color-text);
  border-bottom: 1px solid var(--color-border); }

/* ── REVEAL ─────────────────────────────────────────────────────────────── */
.cad-app { background: var(--color-bg-soft); border: 1px solid var(--color-border);
  border-radius: 20px; padding: 0.875rem; display: flex; flex-direction: column; gap: 0.6875rem; }
.cad-app__bar { display: flex; align-items: center; justify-content: space-between; padding: 2px 4px 6px; }
.cad-app__logo { font-family: var(--font-heading); font-weight: 700; font-size: 1.0625rem; }
.cad-app__plus { width: 30px; height: 30px; border-radius: 50%; background: var(--color-brand);
  color: #fff; display: grid; place-items: center; font-size: 1.1875rem; line-height: 1; padding-bottom: 2px; }
.cad-tile { background: #fff; border-radius: 13px; padding: 0.6875rem; display: flex;
  gap: 0.6875rem; align-items: center; box-shadow: 0 2px 8px rgba(33,23,18,0.06); }
.cad-tile--stack { flex-direction: column; align-items: stretch; gap: 0.5rem; padding: 0.5625rem; }
.cad-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0.625rem; }
.cad-tile__img { width: 100%; aspect-ratio: 4 / 3; border-radius: 9px; object-fit: cover;
  background: var(--color-brand-soft); }
.cad-tile__lab { font-size: 0.84375rem; font-weight: 600; }
.cad-tile__lab span { display: block; font-size: 0.71875rem; font-weight: 400; color: var(--color-muted); }
.cad-privacy-pill { background: var(--color-brand-soft); color: var(--color-brand-dark);
  border-radius: 11px; padding: 0.6875rem; font-size: 0.78125rem; text-align: center; font-weight: 600; }
.cad-anno { font-family: 'Caveat', 'Segoe Script', cursive; font-size: 1.25rem;
  color: var(--color-brand); line-height: 1.1; }
.cad-anno--l { transform: rotate(-6deg); align-self: flex-start; margin: 0 0 -6px 4px; }
.cad-anno--r { transform: rotate(4deg); align-self: flex-end; margin: -6px 6px 0 0; text-align: right; }

/* ── CLOSE ──────────────────────────────────────────────────────────────── */
.cad-close { text-align: center; gap: 1.25rem; padding: 3.625rem 1.375rem 2.875rem; }
.cad-close h2 { font-size: 1.8125rem; }
.cad-close .cad-cta { align-self: stretch; }
.cad-underlink { font-size: 0.875rem; color: #e6d9f3; text-decoration: underline; text-align: center; }

/* ── CHOOSE ─────────────────────────────────────────────────────────────────
   Markup and JS hooks are lp-self-select's; only the styling is ours, so the
   measurement instrument binds unchanged (spec §8).

   ⚠️ THIS IS "VARIANT B" FROM THE 2026-09-06 TEST, CONSOLIDATED. Two treatments
   were built and compared on a phone: A previewed the payload with a thumbnail
   and a teaser in the closed row; B reframed the block as a spoken question on a
   tinted ground with large first-person rows. B won and A is deleted — the two
   were competing hypotheses about WHY the block was not enticing, and B's answer
   ("it read as a form, not an invitation") is the one that held up. If this is
   ever revisited, A's hypothesis was that people could not tell what was behind
   the tap; it is in git at 5b53261..HEAD, not lost.

   ⚠️ NEVER ADD `open` TO A CARD — see the header of cadence/choose.html. It
   silently stops the branch being measured.

   The tinted ground is what separates this beat from the cream bands either side;
   it is doing the work a photograph does in a PILLAR. The chevron points RIGHT
   when closed and DOWN when open: right reads as "there is something through
   here", which is the affordance being bought, and down then aims at what opened.
   Both need the .cad-choose class in front of the [open] selector to out-rank
   landing.css's own rotate(-135deg) rule.
   ───────────────────────────────────────────────────────────────────────────── */
.cad-choose { background: var(--color-brand-soft); border: 0; padding: 3.75rem 1.375rem; }
.cad-choose .container { padding: 0; max-width: none; }
.cad-choose .lp-selfselect__lead { font-family: var(--font-heading); font-size: 1.9375rem;
  line-height: 1.16; color: var(--color-brand-dark); margin: 0 0 0.5rem; }
.cad-choose .lp-selfselect__hint { font-size: 1rem; color: var(--color-muted); margin: 0 0 1.375rem; }
.cad-choose .lp-selfselect__grid { display: flex; flex-direction: column; gap: 0.5rem; }
.cad-choose .lp-ss-card { background: #fff; border: 1px solid transparent; border-radius: 12px;
  box-shadow: 0 1px 2px rgba(33, 23, 18, 0.06); }
/* Affordance must be visible at rest — there is no hover on a phone, and 64px
   keeps the whole row a comfortable target rather than just the label. */
.cad-choose .lp-ss-card__summary { padding: 1.125rem; min-height: 64px; gap: 0.75rem;
  font-size: 1.09375rem; font-weight: 600; line-height: 1.35; color: var(--color-text); }
.cad-choose .lp-ss-card[open] { border-color: var(--color-brand);
  box-shadow: 0 4px 14px rgba(116, 75, 154, 0.14); }
.cad-choose .lp-ss-card__chev { border-color: var(--color-brand);
  border-width: 0 2.5px 2.5px 0; padding: 4px; transform: rotate(-45deg); }
.cad-choose .lp-ss-card[open] .lp-ss-card__chev { transform: rotate(45deg); }
.cad-choose .lp-ss-card__body { padding: 0 1.125rem 1.125rem; }
.cad-choose .lp-ss-card__body p { font-size: 1rem; line-height: 1.6; }
.cad-choose .lp-ss-card__cta { display: inline-flex; align-items: center; min-height: 44px;
  font-weight: 700; color: var(--color-brand); }
.cad-choose .lp-ss-choice { min-height: 44px; }

/* ── MEASURE ────────────────────────────────────────────────────────────────
   ⚠️ NO BREAKPOINT, DELIBERATELY. The first attempt put all of this behind
   `@media (min-width: 600px)` and it did nothing on a real browser window —
   measured at 574px, which is well past phone width, every paragraph and the
   CTA were still running the full width of the viewport. A max-width does not
   need a breakpoint: on a 390px phone the band padding already holds text at
   ~346px, so these rules are inert there and engage on their own the moment
   there is room. Picking a breakpoint just creates a band of widths where the
   page is unconstrained, and 480–600px is a very ordinary window size.

   ⚠️ THE ROOT FONT-SIZE IS 18px, NOT 16px. Every rem here is 18 real pixels, and
   getting that wrong is what made two earlier passes too wide: 34rem was not the
   544px it was chosen as, it was 612px, and 30rem was 540px rather than 480px.
   Measured in the browser, not calculated. If you change a measure, check the
   computed value rather than multiplying by 16.

   27rem = 486px, about 57 characters at the 1.0625rem lead size — the middle of
   the 45–75 range rather than the top of it.

   ⚠️ STILL UNSOLVED, AND IT IS THE NEXT DECISION: .cad-pillar is
   aspect-ratio 9/16 with no cap, so a pillar is 1,365px tall at 768px and
   1,820px at 1024px. Measured at 574px it is already 994px. Capping the type
   does not touch it.
   ───────────────────────────────────────────────────────────────────────────── */
.cad { --cad-measure: 27rem; }  /* 486px — see the note above */

/* These two carry their own side padding (1.375rem each), so the cap is the
   measure plus that padding — otherwise the text lands narrower than intended. */
.cad-opener__head,
.cad-pillar__head { max-width: calc(var(--cad-measure) + 2.75rem); margin-inline: auto; }

/* Bands cannot be capped themselves — the background IS the band, and
   constraining it would end the full-bleed colour. Their children are capped. */
.cad-band > * { max-width: var(--cad-measure); margin-inline: auto; width: 100%; }

/* Only the horizontal margins: `margin-top: auto` is what pushes the card to the
   bottom of the photo, and the negative bottom margin is the overlap. */
/* ⚠️ `width` IS REQUIRED ALONGSIDE THE AUTO MARGINS. .cad-pillar is a column
   flex container, and auto inline margins on a flex item cancel the default
   stretch — so the card shrank to fit its text and never reached its cap:
   measured 335px at a 1600px viewport, identical to its width on a phone. The
   explicit width restores the stretch, the cap still binds, and the 2rem keeps
   the phone's side gutters. */
.cad-card { width: calc(100% - 2rem); max-width: 26rem;
  margin-left: auto; margin-right: auto; }

.cad-choose .lp-selfselect__lead,
.cad-choose .lp-selfselect__hint,
.cad-choose .lp-selfselect__grid { max-width: var(--cad-measure); margin-inline: auto; }

/* ⚠️ BUTTONS ARE THE ONE THING THAT DOES NEED A BREAKPOINT. Full-width is right
   on a phone — it is the easiest possible tap target — and wrong above it, where
   it reads as a banner rather than something to press. `width: auto` sizes the
   button to its label; align-self stops the column's default stretch from
   overriding that, and .cad-close needs its own line because the base rule sets
   align-self: stretch there. Must follow `.cad-band > *`, which sets width: 100%
   and ties with this on specificity, so source order decides. */
@media (min-width: 600px) {
  .cad:not(.cadg) .cad-opener__head { padding: 3rem 2.25rem 1.5rem; }
}

@media (min-width: 480px) {
  .cad-cta { width: auto; max-width: none; align-self: center; margin-inline: auto; }
  .cad-close .cad-cta { align-self: center; }
}

/* ── HERO · the photograph becomes the ground ───────────────────────────────
   At EVERY width — these rules are NOT in a media query. They were briefly
   wrapped in `@media (min-width: 0px)`, which is always true and therefore only
   misleading; it was an artifact of editing a 600px block rather than
   restructuring it. The stacked version — type on cream, photo beneath — is much
   worse once the section is wide enough that a band of cream above a band of
   photograph reads as two unrelated blocks. This is the concept art's hero:
   headline over the keepsake tableau.

   ⚠️ PHONE ONLY WORKS BECAUSE OF THE PORTRAIT CROP. letters.jpg is a LANDSCAPE
   flat-lay, and filling a phone section with it crops to roughly 0.47:1 — a
   sliver. cadence/img.html art-directs a 3:4 crop of the SAME photograph below
   600px, which keeps message-match (the page must look like the ad that was
   clicked) while giving the phone a usable shape. Remove the crop and this
   treatment stops being right on a phone.

   ⚠️ THE SCRIM IS DARK AND THE TYPE IS LIGHT BECAUSE THE ART IS DARK. A light
   scrim heavy enough to carry dark type over this photograph would have to be
   near-opaque, which is the wash-out the pillars already went through. If a
   LIGHT hero image is ever swapped in, this inverts — not a free swap.

   ⚠️ THE HOLD RUNS TO 72%, WHICH IS FURTHER THAN IT LOOKS LIKE IT SHOULD, AND
   THE PHONE IS WHY. There the type block reaches ~70% of the section, so a scrim
   that has already decayed by then leaves the trust line over bare paper. At the
   depth the earlier curve reached by that point, EVEN PURE WHITE measured 3.8:1
   — the colour was never the fix, the hold was.

   ⚠️ THE FIRST GRADIENT LOOKED RIGHT AND MEASURED TERRIBLY. It faded smoothly
   from the top, which flattered the image. Sampled against the BRIGHTEST pixel
   under each line — this photograph is full of pale paper — the lead came out at
   1.9:1 and the trust line at 1.1:1. A gradient tuned to flatter the image is not
   a scrim. It now holds near-opaque through the whole type block and collapses
   over ~14% of the height, so the clear photograph at the bottom is bought from
   the part with no words over it.
   ───────────────────────────────────────────────────────────────────────────── */
.cad:not(.cadg) .cad-opener { position: relative; isolation: isolate;
  min-height: clamp(32rem, 82vh, 44rem); }
.cad:not(.cadg) .cad-opener picture { display: contents; }
/* Two classes so it out-ranks `.cad img { height: auto }` (0,1,1), which would
   otherwise collapse it to its intrinsic ratio instead of filling the section. */
.cad:not(.cadg) .cad-opener .cad-opener__img { position: absolute; inset: 0;
  z-index: 0; width: 100%; height: 100%; object-fit: cover;
  object-position: center 40%; }
.cad:not(.cadg) .cad-opener::before { content: ""; position: absolute; inset: 0;
  z-index: 1; background: linear-gradient(180deg,
    rgba(20, 12, 16, 0.93) 0%, rgba(20, 12, 16, 0.91) 58%,
    rgba(20, 12, 16, 0.86) 72%, rgba(20, 12, 16, 0.30) 84%,
    rgba(20, 12, 16, 0) 92%); }
.cad:not(.cadg) .cad-opener__head { position: relative; z-index: 2;
  padding: 2.25rem 1.375rem 1.25rem; }
/* Lighter than the dark PILLAR's equivalents, deliberately: there the type is
   over a lamplit interior, here over pale paper, and the same colours measured
   2-3 points lower. Do not harmonise without re-measuring. */
.cad:not(.cadg) .cad-opener h1 { color: #fff; }
.cad:not(.cadg) .cad-opener .cad-swap { color: #e4d5f5; }
.cad:not(.cadg) .cad-opener .cad-lead { color: #f1eae7; }
.cad:not(.cadg) .cad-opener .cad-trust { color: #ece4e0; }

/* ── DESKTOP ────────────────────────────────────────────────────────────────
   ⚠️ THE PROBLEM AT DESKTOP IS THE CROP, NOT THE WHITESPACE. The art is portrait
   (900x1599, 0.56:1). A full-bleed band at 1920 is 2.44:1, so `cover` was
   showing a 23% horizontal slice of every photograph — measured — and the
   imagery contract's "subject in the upper half, calm bottom for the card"
   described a composition nobody could see any more.

   So the photograph gets a COLUMN instead of a band. A portrait source in a
   portrait column is shown nearly whole, the width is used by the layout rather
   than by stretching one element, and the type moves onto solid ground — which
   is why the scrim is switched off here: at this size nothing sits over the
   photo, so there is nothing to protect.

   Two columns, two rows, no markup change: head top-left, card bottom-left,
   photo spanning the right. The phone and tablet layouts are untouched below
   900px, where full-bleed is right and the crop is close to the source.
   ───────────────────────────────────────────────────────────────────────────── */
@media (min-width: 900px) {

  /* ⚠️ EVERY SELECTOR BELOW IS SCOPED `.cad:not(.cadg)`, AND IT HAS TO BE.
     The component gallery clamps itself to a 430px column so it can be reviewed
     on a laptop — but a media query fires on the VIEWPORT, not on that column.
     Unscoped, opening /lab/cadence/ on a desktop would lay the two-column
     desktop pillar out inside a 430px box: two ~200px columns, which is neither
     layout. Real pages wrap in `.cad`; the gallery wraps in `.cadg .cad`. */

  /* ── PILLAR · photo beside the type ────────────────────────────────────── */
  /* ⚠️ THE PHOTO COLUMN IS FIXED-WIDTH, AND THAT IS WHAT CONTROLS THE HEIGHT.
     A portrait source shown whole makes the section as tall as the column is
     wide divided by 0.563 — a half-and-half split at 1920 gave a 953px column
     and a 1,692px section, taller than the full-bleed version it replaced. At
     26rem the photo is still shown whole and the section lands near 830px,
     which is about one laptop screen. Widening this column makes the page
     taller, not bigger; that is the trade a portrait photograph imposes. */
  .cad:not(.cadg) .cad-pillar {
    aspect-ratio: auto; max-height: none; min-height: 34rem;
    display: grid; align-items: center;
    /* ⚠️ THE LEADING 1fr IS A SPACER, NOT A COLUMN. Without it the type stayed
       pinned 3rem from the left edge while the photo stayed flush right, so past
       ~1200px the two drifted apart and left a growing void between them — at
       1920 it was ~850px of empty ground. The spacer absorbs the excess instead,
       so the headline travels toward the photograph as the screen widens and the
       diagonal keeps its relationship to the type. Below ~1200 the middle column
       shrinks to nothing and the layout is unchanged. */
    grid-template-columns: minmax(0, 1fr) minmax(0, 40rem) 26rem;
    grid-template-rows: auto auto;
    background: var(--color-bg-soft);
  }
  /* ⚠️ A DARK PILLAR IS NEAR-BLACK, NOT BRAND PURPLE. Giving it the brand colour
     put two purple blocks in a row on the landing page — a purple STATEMENT
     followed by a dark PILLAR — which reads as a mistake, and it broke the rule
     written in cadence/pillar.html: a pillar's head must not repeat the band
     immediately above it. Purple is punctuation in this system (§4); spending it
     on a whole beat's ground dilutes it wherever it lands next.
     The near-black is warm and slightly plum so it continues the photograph
     rather than fighting it — the dark pillar's art is a lamplit interior, and
     brand purple sits near the complement of those tones, which is the same
     reason a gradient dissolve failed here. */
  .cad:not(.cadg) .cad-pillar--dark { background: #1b1117; }
  /* No type over the photograph at this size, so no scrim to protect it.
     Scoped like the rest of this block: unscoped, it stripped the scrim from the
     gallery's 430px phone column whenever the gallery was opened on a desktop. */
  .cad:not(.cadg) .cad-pillar::before { display: none; }

  /* ⚠️ margin-inline: auto has to be undone here. The measure rules centre the
     head in whatever box it is in, which on a phone is the viewport and at this
     size is the grid column — so the head sat centred at 536px while the card
     sat left at 468px, and the two never lined up. Both are left-aligned to the
     same 3rem now. */
  /* ⚠️ THE RIGHT GUTTER IS SIZED TO THE SEAM, AND IT IS NOT DECORATION. The wedge
     leans LEFT as it descends: it covers none of column 1 at the top and a full
     --seam of it at the bottom. So anything low in the column has to stand
     further back than anything high in it. Measured before this: the card
     overlapped the diagonal by 15px at 900 and 28px at 1024 — invisible at 1280
     and above, which is exactly the width most people would have checked.
     The card is at the bottom and clears a whole seam; the head sits mid-height
     and clears half. Both are inert at wide widths, where the measure cap binds
     long before the gutter does. */
  .cad:not(.cadg) .cad-pillar__head { grid-column: 2; grid-row: 1; align-self: end;
    margin-inline: 0; max-width: calc(var(--cad-measure) + 6rem);
    padding: 3.5rem calc(3rem + var(--seam) * 0.5) 1rem 3rem; }
  .cad:not(.cadg) .cad-card { grid-column: 2; grid-row: 2; align-self: start;
    margin: 0 calc(3rem + var(--seam)) 3.5rem 3rem;
    width: auto; max-width: var(--cad-measure); }
  /* Static, not absolute: it is a grid item now, filling the right-hand column
     across both rows. object-fit still does the cropping, but a portrait source
     in a portrait column barely needs any. */
  /* ⚠️ THE SEAM IS CUT ON A DIAGONAL, AND THAT IS THE WHOLE POINT.
     A vertical butt joint between the photograph and the flat ground read as
     "two rectangles bolted together" — the photography is soft, warm and grainy
     and the join was a crisp 90° corner. A diagonal cannot be a column boundary,
     so it stops reading as a layout accident and starts reading as composition.

     This is the concept art's device, finally applied. MOBILE_CADENCE_SPEC.md §9
     records that the comps' diagonal splits were dropped for BUILD COST, never
     for design reasons; they had never been tried at a column seam.

     Chosen over the alternatives after rendering all four on both photographs:
       · a gradient dissolve gives the best light frame on the page and FAILS on
         dark — lamplit orange-brown into brand purple goes to a muddy plum haze,
         because the purple sits near the complement of the photography's tones.
         ⚠️ That is why no soft treatment works here while the dark ground is
         brand purple. Do not retry a fade without changing that ground first.
       · overhanging the card across the seam lands it on the subject in both
         photographs; the desktop card is proportionally taller than the phone's,
         so the contractually quiet bottom 40% is not enough room.
       · framing the photo as a print removes the seam but is the conventional
         picture-in-a-box answer, and the light photo is already a hand holding a
         print — it would gain a second frame.

     A crisp edge does not care what two colours meet on it, which is why this one
     works in both tones where softness could not.

     HOW IT WORKS: the photo is widened by --seam and pulled left by the same
     amount, so it overlaps column 1; the clip-path then cuts that overlap back on
     an angle. The clipped triangle is transparent, so the section's own ground
     shows through and there is no second colour to keep in sync. The head
     (z-index 2) and card (z-index 3) are positioned and the photo is static, so
     they already paint over the wedge.

     ⚠️ max-height CAPS THE IMAGE'S ROW CONTRIBUTION, and without it the section
     grows: a 34rem-wide portrait source is 1,087px tall.
     ⚠️ object-position is 30%, not centre. The crop this buys is ~24% of the
     photo's height; biasing it to the quiet bottom keeps faces intact — centred,
     it clipped the top of the laughing woman's hair.
     Dials: --seam (angle and crop), max-height (section height), object-position. */
  .cad:not(.cadg) .cad-pillar { --seam: clamp(5rem, 10vw, 8rem); }
  .cad:not(.cadg) .cad-pillar__photo { position: static; grid-column: 3; grid-row: 1 / -1;
    width: calc(100% + var(--seam)); margin-left: calc(-1 * var(--seam)); }
  .cad:not(.cadg) .cad-pillar .cad-pillar__photo {
    height: 100%; max-height: 46rem;
    object-fit: cover; object-position: 50% 30%;
    clip-path: polygon(var(--seam) 0, 100% 0, 100% 100%, 0 100%);
  }

  /* ── OPENER · text beside the hero ─────────────────────────────────────── */
  /* The hero image was unconstrained: 1905x1429 at a 1920 viewport, taller than
     the screen and pushing every other beat below the fold. */
  /* The hero needs almost nothing here now: the photograph is the beat's ground
     at every width, so desktop only widens the type's gutter. It is deliberately
     NOT split into columns — that read as clumsy, and two seams inside the first
     two screens is one too many when the pillars already carry the diagonal. */
  /* The hero treatment itself starts at 600px — see the block above. Desktop
     only widens its gutter. */
  .cad:not(.cadg) .cad-opener__head { padding: 4rem 3rem 1.5rem; }

  /* ── CHOOSE · two columns ──────────────────────────────────────────────── */
  /* The branches are independent of one another, so a single column at this
     width is just a long scroll. The tracking is unaffected: the JS binds to
     the cards, not to their arrangement. */
  .cad:not(.cadg) .cad-choose .lp-selfselect__lead,
  .cad:not(.cadg) .cad-choose .lp-selfselect__hint { max-width: 46rem; }
  .cad:not(.cadg) .cad-choose .lp-selfselect__grid { max-width: 46rem;
    display: grid; grid-template-columns: 1fr 1fr; align-items: start; }
}

/* ═════════════════════════════════════════════════════════════════════════════
   HOMEPAGE BEATS (2026-10-10) — video OPENER, SHOW, PRIVACY, swipe PILLAR, a
   full-width waveform and a cream CLOSE, built from the homepage prototype for
   what was then a hidden preview page and is now the homepage (MANTIS-847 (convert the homepage to cadence)
   https://bugs.jaji.us/view.php?id=847). Every rule below targets a class no
   existing page uses, so pages built before this section render unchanged.
   Values are the prototype's, converted at an 18px root (see MEASURE above).
   ═════════════════════════════════════════════════════════════════════════════ */

/* ── shared: the pause button on a looping video (WCAG 2.2.2) ─────────────── */
.cad-vbtn { position: absolute; right: 0.75rem; bottom: 0.75rem; z-index: 3;
  width: 44px; height: 44px; border-radius: 50%; border: 0; cursor: pointer;
  background: rgba(33, 23, 18, 0.55); display: grid; place-items: center; }
/* ⚠️ display:grid above beats the UA's [hidden] rule, so it has to be restated;
   the button is hidden until the script runs (no dead control without JS). */
.cad-vbtn[hidden] { display: none; }
.cad-vbtn::before { content: ""; width: 12px; height: 14px;
  border-left: 4px solid #fff; border-right: 4px solid #fff; box-sizing: border-box; }
.cad-vbtn.is-paused::before { width: 0; height: 0; border: 0; margin-left: 4px;
  border-left: 13px solid #fff; border-top: 8px solid transparent; border-bottom: 8px solid transparent; }
.cad-vbtn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.cad-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ── OPENER · video ───────────────────────────────────────────────────────────
   Placed where each cut keeps its picture clear (the cue sheet's
   layout.clear_region; cadence/opener-video.html). Phone: the type on cream, then
   the 2:3 phone cut full-bleed, the later words over its top third. 600px and up
   the video is the ground and the type sits over a dark scrim: at the top when
   upright (the tablet framing, the phone cut for now), on the left in landscape
   (the desktop cut).

   ⚠️ UPRIGHT AND LANDSCAPE ARE framing() IN cadence/video-js.html, not widths:
   `(min-width: 600px) and (min-aspect-ratio: 1/1)` is when the desktop cut plays,
   so its words go on the left exactly then. Change one, change both.

   WORDS ON THE CLOCK. Script marks the head .is-off and a line or the CTA copy
   .is-on, each a 0.3 s fade inside its window (the script turns each off 0.3 s
   before the window ends). The scrims move more slowly, on their own classes:
   the section's big one (behind the head) goes with .is-head-off, and each
   beat's own (one later line, plus the CTA copy when it shows with that line;
   sized to them) with .is-scrim on the beat. The script turns a
   scrim on half a second before its words and off as their window ends, and each
   eases over 0.8 s, so the dark arrives before the words and leaves after them
   rather than snapping with them (owner, 2026-10-12: the "Save the stories."
   scrim felt jerky, and too tall for one line). Without script none of these
   classes exist, so the head and its scrim simply stay. The section's .is-cued (a sheet is driving
   it) has no style: it is there to check in devtools and in tests. */
.cad-vopener { background: var(--color-bg-soft); display: flex; flex-direction: column; gap: 1rem; }
.cad-vopener__head { padding: 1.625rem 1.375rem 0; display: flex; flex-direction: column; gap: 1rem;
  width: 100%; max-width: calc(var(--cad-measure) + 2.75rem); margin-inline: auto; box-sizing: border-box; }
/* The section is the positioning box so the pause button (a sibling of the head,
   z 3) sits above both the scrim and the head at every width. Inside the media
   box it was trapped under them from 600px, where the media becomes a z 0 layer. */
.cad-vopener { position: relative; }
.cad-vopener__media { position: relative; background: #1b1117; overflow: hidden; }
/* The cut starts and ends on the homepage's night, so night behind it hides the
   loop's seam and anything the box shows past the picture. Never taller than
   the screen less 120px (AGENTS.md → Video); the cover crop takes the excess
   evenly from top and bottom, and the cut keeps its top third clear for that. */
.cad-vopener__video { display: block; width: 100%; aspect-ratio: 2 / 3; max-height: calc(100svh - 120px);
  object-fit: cover; background: #1b1117; }
.cad-vopener__cues { position: absolute; inset: 0 0 auto; z-index: 2;
  padding: 1.25rem 1.375rem 0; box-sizing: border-box; pointer-events: none; display: grid; }
/* Every beat in one grid cell, so a line never moves for another. */
/* align-self: start, or every beat stretches to the tallest and so does its scrim. */
.cad-vopener__beat { grid-area: 1 / 1; align-self: start; position: relative; z-index: 0;
  display: grid; align-content: start; justify-items: start; row-gap: 1rem; }
/* The beat's own scrim: a full-width band (the media box clips it) from the top
   of the picture to a feathered tail below what the beat holds, so one line gets
   one band, not a third of the picture. Many stops, not two, so the falloff has
   no visible edge. Behind the words: z -1 inside the beat's stacking context. */
.cad-vopener__beat::before { content: ""; position: absolute; z-index: -1; inset: -1.25rem -100vw -3rem;
  pointer-events: none; opacity: 0; transition: opacity 0.8s ease-in-out;
  background: linear-gradient(180deg, rgba(20, 12, 16, 0.74) 0%, rgba(20, 12, 16, 0.66) 35%,
    rgba(20, 12, 16, 0.44) 62%, rgba(20, 12, 16, 0.2) 82%, rgba(20, 12, 16, 0.06) 94%, rgba(20, 12, 16, 0) 100%); }
.cad-vopener__beat.is-scrim::before { opacity: 1; }
/* Every line in one grid cell, so a line never moves for another; the CTA copy
   below them. Upright, never italic (owner, 2026-10-12). */
.cad-vopener__line { margin: 0; font-family: var(--font-heading); font-weight: 700;
  font-size: 2.1875rem; line-height: 1.14; letter-spacing: -0.005em; color: #fff; text-wrap: balance;
  opacity: 0; transition: opacity 0.3s ease-in-out; }
.cad-vopener .cad-vopener__cta { margin: 0; width: auto;
  opacity: 0; transition: opacity 0.3s ease-in-out; }
.cad-vopener__beat.is-on > .cad-vopener__line, .cad-vopener .cad-vopener__beat.is-on > .cad-vopener__cta { opacity: 1; }
.cad-vopener .cad-vopener__beat.is-on > .cad-vopener__cta { pointer-events: auto; }
@media (min-width: 600px) {
  /* Upright tablets keep the heading and CTA over the video,
     with the existing fade timing, but omit the lead and trust line. */
  .cad-vopener .cad-lead, .cad-vopener .cad-trust { display: none; }
  .cad:not(.cadg) .cad-vopener { position: relative; isolation: isolate; gap: 0;
    min-height: clamp(32rem, calc(100svh - 4.5rem), 56rem); justify-content: flex-start; background: #1b1117; }
  /* z auto, not 0: a z 0 media box would trap the cue layer under the scrim. */
  .cad:not(.cadg) .cad-vopener__media { position: absolute; inset: 0; z-index: auto; }
  .cad:not(.cadg) .cad-vopener__video { height: 100%; max-height: none; aspect-ratio: auto; }
  .cad:not(.cadg) .cad-vopener::before { content: ""; position: absolute; inset: 0; z-index: 1;
    pointer-events: none; transition: opacity 0.8s ease-in-out; background: linear-gradient(180deg,
      rgba(20, 12, 16, 0.86) 0%, rgba(20, 12, 16, 0.6) 30%, rgba(20, 12, 16, 0) 52%); }
  .cad:not(.cadg) .cad-vopener.is-head-off::before { opacity: 0; }
  /* ⚠️ THIS VIDEO FILLS THE SCREEN ON PURPOSE: it is the beat's ground, chosen
     on MANTIS-859 (homepage cadence on desktop). AGENTS.md's "never taller than
     calc(100svh - 120px)" is for a video shown inside a beat (SHOW), so the
     headline or the next beat stays in view; it does not apply here. */
  .cad:not(.cadg) .cad-vopener__head,
  .cad:not(.cadg) .cad-vopener__cues { position: relative; z-index: 2; margin: 0; max-width: 40rem;
    padding: 3rem 2.25rem 0; }
  .cad:not(.cadg) .cad-vopener__head { transition: opacity 0.3s ease-in-out; }
  /* Faded, never removed: the h1 stays in the page, and anything in the head
     that takes focus brings it back. */
  .cad:not(.cadg) .cad-vopener__head.is-off:not(:focus-within) { opacity: 0; pointer-events: none; }
  /* …and the line it shares the place with steps aside meanwhile. */
  .cad:not(.cadg) .cad-vopener:has(.cad-vopener__head:focus-within) .cad-vopener__cues { opacity: 0; }
  /* Upright: the layer stands where the head does, at the top; each beat's band
     reaches up to the top of the screen. */
  .cad:not(.cadg) .cad-vopener__cues { position: absolute; inset: 0 auto auto 0; width: 100%; }
  .cad:not(.cadg) .cad-vopener__beat { row-gap: 1.4rem; }
  .cad:not(.cadg) .cad-vopener__beat::before { top: -3rem; bottom: -3.5rem; }
  .cad:not(.cadg) .cad-vopener h1 { color: #fff; }
  .cad:not(.cadg) .cad-vopener .cad-swap { color: #e4d5f5; }
  .cad:not(.cadg) .cad-vopener .cad-lead { color: #f1eae7; }
  .cad:not(.cadg) .cad-vopener .cad-trust { color: #ece4e0; text-align: left; }
  .cad:not(.cadg) .cad-vopener .cad-cta { align-self: flex-start; margin-inline: 0; }
  .cad:not(.cadg) .cad-vopener .cad-vbtn { right: 1.5rem; bottom: 1.5rem; }
}
@media (min-width: 600px) and (min-aspect-ratio: 1/1) {
  .cad-vopener .cad-lead, .cad-vopener .cad-trust { display: block; }
  .cad:not(.cadg) .cad-vopener { justify-content: center; }
  .cad:not(.cadg) .cad-vopener::before { background:
    linear-gradient(90deg, rgba(20, 12, 16, 0.82) 0%, rgba(20, 12, 16, 0.55) 34%, rgba(20, 12, 16, 0) 58%),
    linear-gradient(0deg, rgba(20, 12, 16, 0.5) 0%, rgba(20, 12, 16, 0) 40%); }
  .cad:not(.cadg) .cad-vopener__head,
  .cad:not(.cadg) .cad-vopener__cues { padding: 0 3rem 0 clamp(3rem, 8vw, 7.5rem); gap: 1.4rem; }
  /* Landscape: the layer sits at the middle of the left, where the head is
     centred. Each beat's band runs from the screen's left edge (it starts a
     screen-width to the left and the media box clips it) to about 36rem past the
     words' edge, fading as it goes, and is feathered top and bottom, so only the
     beat's own height is darkened. */
  .cad:not(.cadg) .cad-vopener__cues { top: 50%; transform: translateY(-50%); padding-block: 0; }
  .cad:not(.cadg) .cad-vopener__beat { align-self: center; }
  .cad:not(.cadg) .cad-vopener__beat::before { inset: -5rem auto -5rem -100vw; width: calc(100vw + 40rem);
    background: linear-gradient(90deg, rgba(20, 12, 16, 0.8) 0, rgba(20, 12, 16, 0.78) 100vw,
      rgba(20, 12, 16, 0.6) calc(100vw + 14rem), rgba(20, 12, 16, 0.3) calc(100vw + 26rem),
      rgba(20, 12, 16, 0.08) calc(100vw + 35rem), rgba(20, 12, 16, 0) 100%);
    -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 34%, #000 66%, transparent 100%);
    mask-image: linear-gradient(180deg, transparent 0%, #000 34%, #000 66%, transparent 100%); }
}
@media (min-width: 900px) {
  /* ⚠️ A CEILING, NOT A SCALE: the display size stops at 3.1rem (56px). The
     inspiration sites that read as shouty set paragraphs at display sizes
     (wiki: Homepage cadence: large-screen inspiration study). */
  .cad:not(.cadg) .cad-vopener h1,
  .cad:not(.cadg) .cad-vopener__line { font-size: clamp(2.1875rem, 3.4vw, 3.1rem); }
}

/* ── SHOW · one video, never taller than the screen minus 120px ───────────── */
.cad-show > .cad-show__media { max-width: none; width: auto; margin: 0.25rem -1.375rem 0;
  display: flex; justify-content: center; }
.cad-show__frame { position: relative; width: 100%; max-width: calc((100svh - 120px) * 2 / 3); }
.cad-show__video { display: block; width: 100%; aspect-ratio: 2 / 3; height: auto;
  object-fit: cover; background: #f3f1f6; }
/* The desktop cut is 16:9. ⚠️ THIS MEDIA CONDITION IS framing() IN
   cadence/video-js.html: the script serves the desktop cut exactly when it holds,
   so a change to one is a change to both. 68rem (1224px) keeps the tree's names
   readable without running edge to edge on a wide screen. */
@media (min-width: 600px) and (min-aspect-ratio: 1/1) {
  .cad-show--desktop .cad-show__frame { max-width: min(68rem, calc((100svh - 120px) * 16 / 9)); }
  .cad-show--desktop .cad-show__video { aspect-ratio: 16 / 9; }
}

/* ── PRIVACY ──────────────────────────────────────────────────────────────── */
.cad-privacy { background: #1b1117; color: #f6efe9; padding: 5.75rem 1.375rem 5.25rem;
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: 1.45rem; }
.cad-privacy .cad-eyebrow { color: #cbb3e4; }
.cad-dissolve { display: grid; align-items: center; min-height: 3.6em; max-width: var(--cad-measure);
  font-family: var(--font-heading); font-weight: 700; font-size: 1.83rem; line-height: 1.2; text-wrap: balance; }
.cad-dissolve__line { grid-area: 1 / 1; opacity: 0; filter: blur(7px);
  transition: opacity 1.1s ease, filter 1.1s ease; }
.cad-dissolve__line.is-on { opacity: 1; filter: none; }
.cad-dissolve em { font-style: normal; color: #cbb3e4; }
.cad-dissolve__line--final { font-size: 2.45rem; }
.cad-cta--outline { background: transparent; color: #fff; border: 2px solid rgba(255, 255, 255, 0.7); }
.cad-cta--outline:hover, .cad-cta--outline:focus-visible { background: rgba(255, 255, 255, 0.1); border-color: #fff; }
.cad-privacy__sub { margin: -0.55rem 0 0; font-size: 0.78rem; color: #bfaeb4; }
@media (min-width: 900px) {
  .cad:not(.cadg) .cad-privacy { min-height: min(100svh, 56rem); justify-content: center; }
  .cad:not(.cadg) .cad-dissolve { font-size: 2.45rem; max-width: 50rem; }
  .cad:not(.cadg) .cad-dissolve__line--final { font-size: 3.55rem; }
}

/* ── CLOSE on cream ───────────────────────────────────────────────────────── */
.cad-close--cream .cad-underlink { color: var(--color-brand); }

/* ── waveform, full width (card wave.fill) ────────────────────────────────── */
.cad-wave--fill { align-self: stretch; justify-content: flex-start; }
/* ⚠️ width:0 with flex:1, not just min-width:0: min-width does not lower an item's
   min-CONTENT contribution, so 72 bars (429px) set the card's minimum width and
   pushed swipe slides off a phone screen. width:0 makes the strip contribute
   nothing and take only the space left over. */
.cad-wave--fill .cad-wave__bars { flex: 1; width: 0; min-width: 0; overflow: hidden; justify-content: flex-start;
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 1.25rem), transparent);
  mask-image: linear-gradient(90deg, #000 calc(100% - 1.25rem), transparent); }

/* ── PILLAR · swipe ───────────────────────────────────────────────────────────
   See cadence/pillar-swipe.html. Phone first; the desktop grid follows. */
.cad-pillar--swipe::before { display: none; }
.cad-pillar--swipe .cad-pillar__head { pointer-events: none; }
/* ⚠️ NO z-index ON THE TRACK. A z-index would make it a stacking context and trap
   the card's z-index 3 inside it, so the next PILLAR's scrim and head (later in
   the DOM) would paint over the card's overhang and swallow taps on its button:
   the trap noted at .cad-pillar above, by another route. Unindexed, the track
   paints in DOM order under the head (z 2), and the card still wins page-wide. */
.cad-swipe__track { position: absolute; left: 0; right: 0; top: 0; bottom: -3.25rem;
  display: flex; overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain; scrollbar-width: none; }
.cad-swipe__track::-webkit-scrollbar { display: none; }
.cad-swipe__track:focus-visible { outline: 2px solid #cbb3e4; outline-offset: -4px; }
.cad-swipe__slide { position: relative; flex: 0 0 calc(100% - 2rem); min-width: 0; scroll-snap-align: start;
  scroll-snap-stop: always; display: flex; flex-direction: column; justify-content: flex-end;
  padding-bottom: 1.6rem; }
.cad-swipe__slide:last-child { flex-basis: 100%; }
.cad-swipe__photo { position: absolute; left: 0; right: 0; top: 0; bottom: 3.25rem; }
.cad-swipe__photo picture { display: contents; }
.cad-swipe__photo .cad-swipe__img { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: var(--cad-pos, center); }
.cad-swipe__photo::after { content: ""; position: absolute; inset: 0; }
.cad-pillar--dark .cad-swipe__photo::after { background: linear-gradient(180deg,
  rgba(20, 12, 16, 0.80) 0%, rgba(20, 12, 16, 0.52) 28%, rgba(20, 12, 16, 0) 50%); }
.cad-pillar--light .cad-swipe__photo::after { background: linear-gradient(180deg,
  rgba(251, 248, 243, 0.72) 0%, rgba(251, 248, 243, 0.46) 24%, rgba(251, 248, 243, 0) 46%); }
/* Peek: every card but the last has no right margin, so the next card shows at
   the edge; the last slide is full width and keeps both margins. */
.cad-pillar--swipe .cad-swipe__slide .cad-card { margin: 0 0 0 1rem; width: auto; max-width: 26rem; }
.cad-pillar--swipe .cad-swipe__slide:last-child .cad-card { margin: 0 1rem; }
/* The dots sit over whatever beat comes next, so they carry their own ground. */
.cad-swipe__dots { position: absolute; left: 50%; transform: translateX(-50%); bottom: -3.1rem;
  height: 1.35rem; z-index: 3; display: flex; align-items: center; padding: 0 0.2rem;
  border-radius: 0.7rem; background: rgba(255, 255, 255, 0.94); box-shadow: 0 1px 4px rgba(33, 23, 18, 0.18); }
.cad-swipe__dot { width: 1.55rem; height: 1.35rem; border: 0; background: none; padding: 0;
  cursor: pointer; display: grid; place-items: center; }
/* #86769a: about 4:1 against the dots' white backing, over the 3:1 a control needs
   (WCAG 1.4.11). The prototype's #a99bb8 measured 2.6:1. */
.cad-swipe__dot::before { content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: #86769a; transition: background 0.2s, width 0.2s; }
.cad-swipe__dot[aria-current="true"]::before { background: var(--color-brand); width: 22px; border-radius: 4px; }
.cad-swipe__dot:focus-visible { outline: 2px solid var(--color-brand); outline-offset: 1px; border-radius: 4px; }
.cad-pillar--swipe + .cad-pillar .cad-pillar__head { padding-top: 5.1rem; }
@media (min-width: 900px) {
  .cad:not(.cadg) .cad-pillar--swipe .cad-pillar__head { pointer-events: auto; }
  .cad:not(.cadg) .cad-pillar--swipe .cad-swipe__track { position: relative; inset: auto;
    grid-column: 3; grid-row: 1 / -1; height: 46rem; }
  .cad:not(.cadg) .cad-pillar--swipe .cad-swipe__slide { flex-basis: calc(100% - 2.5rem); padding-bottom: 1.5rem; }
  .cad:not(.cadg) .cad-pillar--swipe .cad-swipe__slide:last-child { flex-basis: 100%; }
  .cad:not(.cadg) .cad-pillar--swipe .cad-swipe__photo { bottom: 0; }
  .cad:not(.cadg) .cad-pillar--swipe .cad-swipe__photo::after { display: none; }
  /* align-self undoes the still pillar's `.cad-card { align-self: start }`, which
     would shrink a slide's card to its content. */
  .cad:not(.cadg) .cad-pillar--swipe .cad-swipe__slide .cad-card { margin: 0 0 0 1rem; max-width: none; align-self: stretch; }
  .cad:not(.cadg) .cad-pillar--swipe .cad-swipe__slide:last-child .cad-card { margin: 0 1rem; }
  .cad:not(.cadg) .cad-pillar--swipe .cad-swipe__dots { position: static; transform: none;
    grid-column: 2; grid-row: 2; align-self: start; justify-self: start; margin: 0 0 3.5rem 3rem; }
  .cad:not(.cadg) .cad-pillar--swipe + .cad-pillar .cad-pillar__head { padding-top: 3.5rem; }
}

/* ── PILLAR · full bleed on large screens (`pillars: bleed`) ──────────────────
   Owner, 2026-10-12, on MANTIS-859 (homepage cadence on desktop)
   https://bugs.jaji.us/view.php?id=859: every PILLAR is a full-bleed photograph
   at every width, and every widget (the card, the dots) is centred, not aligned
   left. The words sit over a darkened left side. Opt-in per page via front matter
   (partials/cadence/page-main.html adds .cad--bleed) so the live landing pages keep the
   photo-column layout above until they move.

   ⚠️ EVERY SELECTOR STARTS `.cad.cad--bleed:not(.cadg)`. That out-ranks the
   `.cad:not(.cadg)` desktop rules by one class with the same tail, so this block
   wins without !important, and the gallery's 430px column is left alone.
   ⚠️ THE PHOTOGRAPHS ARE PORTRAIT. On a desktop cover-cropping keeps about the
   middle third of each; landscape art per pillar is the real fix.

   SWIPE: from 600px the slides are full width and the card is centred, so the
   next card is a screen away and cannot peek. Previous and next arrows replace
   the peek as the "there is more" signal, and a mouse needs them anyway. Smoked
   glass, not brand purple: a control on a photograph is subdued. */
@media (min-width: 600px) {
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe .cad-swipe__slide,
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe .cad-swipe__slide:last-child { flex-basis: 100%; }
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe .cad-swipe__slide .cad-card,
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe .cad-swipe__slide:last-child .cad-card {
    margin: 0 auto; width: calc(100% - 2rem); max-width: 26rem; }
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe.is-ready .cad-swipe__nav { display: grid; }
}
.cad-swipe__nav { display: none; position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 3rem; height: 3rem; place-items: center; padding: 0; border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 50%; cursor: pointer; color: #fff; background: rgba(20, 12, 16, 0.45);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); transition: opacity 0.2s, background 0.2s; }
.cad-swipe__nav--prev { left: 1.25rem; }
.cad-swipe__nav--next { right: 1.25rem; }
.cad-swipe__nav:hover { background: rgba(20, 12, 16, 0.65); }
.cad-swipe__nav:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.cad-pillar--light .cad-swipe__nav:focus-visible { outline-color: var(--color-brand); }
.cad-swipe__nav:disabled { opacity: 0; pointer-events: none; }

@media (min-width: 900px) {
  /* The section: one screen of photograph, not a grid.
     ⚠️ THE 42rem FLOOR KEEPS A SWIPE CARD OFF THE HEAD. The swipe track is
     absolute, so nothing in flow holds its card below the words; at a 36rem floor
     (a window 720px tall or less) the heirloom card met the lead's last line
     (review of static-sites@23d45e2). The still pillar's card is in flow and
     safe either way.
     The head's 7rem left gutter clears the previous arrow (2rem + 3rem) at 900px,
     where a percentage gutter put the arrow on the text. */
  .cad.cad--bleed:not(.cadg) .cad-pillar {
    display: flex; flex-direction: column; align-items: stretch; grid-template-columns: none;
    aspect-ratio: auto; max-height: none; min-height: clamp(42rem, calc(100svh - 4rem), 56rem); }
  .cad.cad--bleed:not(.cadg) .cad-pillar__photo { position: absolute; inset: 0; margin: 0; width: 100%; }
  .cad.cad--bleed:not(.cadg) .cad-pillar .cad-pillar__photo {
    height: 100%; max-height: none; clip-path: none; object-position: 50% 30%; }
  /* The scrim comes back, from the left, where the words are. */
  .cad.cad--bleed:not(.cadg) .cad-pillar::before { display: block; }
  .cad.cad--bleed:not(.cadg) .cad-pillar--dark::before,
  .cad.cad--bleed:not(.cadg) .cad-pillar--dark .cad-swipe__photo::after {
    background: linear-gradient(90deg, rgba(20, 12, 16, 0.84) 0%, rgba(20, 12, 16, 0.58) 34%, rgba(20, 12, 16, 0) 60%); }
  .cad.cad--bleed:not(.cadg) .cad-pillar--light::before,
  .cad.cad--bleed:not(.cadg) .cad-pillar--light .cad-swipe__photo::after {
    background: linear-gradient(90deg, rgba(251, 248, 243, 0.88) 0%, rgba(251, 248, 243, 0.62) 34%, rgba(251, 248, 243, 0) 60%); }
  /* align-self undoes the photo-column layout's `align-self: end`, which in a
     column flexbox means the RIGHT edge. */
  .cad.cad--bleed:not(.cadg) .cad-pillar__head {
    align-self: flex-start; margin-inline: 0; max-width: calc(var(--cad-measure) + 8rem);
    padding: 6rem 3rem 2rem 7rem; }
  .cad.cad--bleed:not(.cadg) .cad-pillar + .cad-pillar .cad-pillar__head { padding-top: 6rem; }
  /* Centred at the foot, inside the photograph: no overhang into the next beat. */
  .cad.cad--bleed:not(.cadg) .cad-pillar > .cad-card {
    margin: auto auto 4.5rem; width: calc(100% - 2rem); max-width: 26rem; align-self: auto; }

  /* Swipe: the track is the whole section and the head floats over it. */
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe::before { display: none; }
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe .cad-pillar__head { pointer-events: none; }
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe .cad-swipe__track {
    position: absolute; inset: 0; height: auto; grid-column: auto; grid-row: auto; }
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe .cad-swipe__slide { padding-bottom: 4.5rem; }
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe .cad-swipe__photo { bottom: 0; }
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe .cad-swipe__img { object-position: var(--cad-pos, 50% 30%); }
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe .cad-swipe__photo::after { display: block; }
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe .cad-swipe__slide .cad-card,
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe .cad-swipe__slide:last-child .cad-card {
    margin: 0 auto; align-self: auto; }
  .cad.cad--bleed:not(.cadg) .cad-pillar--swipe .cad-swipe__dots {
    position: absolute; left: 50%; transform: translateX(-50%); bottom: 1.6rem; margin: 0; }
  .cad.cad--bleed:not(.cadg) .cad-swipe__nav--prev { left: 2rem; }
  .cad.cad--bleed:not(.cadg) .cad-swipe__nav--next { right: 2rem; }
}

/* ── LARGE SCREENS · one text channel (`channel: true`) ──────────────────────
   Owner, 2026-10-12: on large screens every beat's text keeps to one centred
   channel and starts at its left edge, so the text's left edge never moves as
   the page scrolls. Before this it started at 25px in a statement band, 126px in
   a pillar, 135px in the opener and 717px in a run-on (measured at 1920).
   Photographs and video stay full width behind the text; the channel governs the
   words, not the pictures. Opt-in per page (partials/cadence/page-main.html adds
   .cad--channel) so the live landing pages are unchanged.

   ONE FORMULA FOR THE LEFT EDGE, --cad-edge: the gutter, or the space either side
   of the channel, whichever is larger. ⚠️ IT IS A PERCENTAGE OF THE ELEMENT'S
   CONTAINING BLOCK, which is why it works unchanged in a band (the page) and in a
   pillar head (the pillar): both are the page's width. Keep every section that
   holds text full width for that reason; cap the picture inside it instead, as
   `capped` does below.
   ⚠️ THE 7rem GUTTER CLEARS THE SWIPE ARROWS (2rem from the edge, 3rem wide).
   A narrower gutter puts the previous arrow on the words at 900px.

   Every selector is `.cad.cad--channel:not(.cadg)`, the same weight as the
   full-bleed block above; this block comes after it, so it wins on order. */
.cad.cad--channel { --cad-channel: 56rem; --cad-gutter: 7rem;
  --cad-edge: max(var(--cad-gutter), calc((100% - var(--cad-channel)) / 2));
  --cad-photo-max: 70rem; }

@media (min-width: 900px) {
  /* Bands (STATEMENT, RUN-ON, SHOW, CLOSE): left-aligned on the edge. The base
     `.cad-band > *` centres each child with auto margins; `.cad h2 { margin: 0 }`
     out-ranks it, which is how headings ended up hard left while paragraphs sat
     centred. Here everything is on the edge, so neither centres. */
  .cad.cad--channel:not(.cadg) .cad-band { padding-inline: var(--cad-edge) var(--cad-gutter);
    align-items: flex-start; text-align: left; }
  .cad.cad--channel:not(.cadg) .cad-band > * { margin-inline: 0; }
  .cad.cad--channel:not(.cadg) .cad-band > h2,
  .cad.cad--channel:not(.cadg) .cad-band > .cad-runon { max-width: 40rem; }
  .cad.cad--channel:not(.cadg) .cad-band .cad-cta { align-self: flex-start; margin-inline: 0; }
  .cad.cad--channel:not(.cadg) .cad-underlink { text-align: left; }
  /* SHOW: the video starts on the edge too, and stops at the channel. */
  .cad.cad--channel:not(.cadg) .cad-show > .cad-show__media { width: 100%; max-width: var(--cad-channel);
    justify-content: flex-start; }

  /* OPENER: the head spans the screen and its padding puts the words on the edge;
     the lines that follow it on the video's clock stand on the same edge. */
  .cad.cad--channel:not(.cadg) .cad-vopener__head,
  .cad.cad--channel:not(.cadg) .cad-vopener__cues { width: 100%; max-width: none;
    padding-inline: var(--cad-edge) var(--cad-gutter); }
  .cad.cad--channel:not(.cadg) .cad-vopener__head > *,
  .cad.cad--channel:not(.cadg) .cad-vopener__cues > * { max-width: 34rem; }

  /* PILLAR heads, still and swipe. */
  .cad.cad--channel:not(.cadg) .cad-pillar__head { align-self: stretch; max-width: none;
    padding-left: var(--cad-edge); padding-right: var(--cad-gutter); }
  .cad.cad--channel:not(.cadg) .cad-pillar__head > * { max-width: 28rem; }
  /* `capped` swipe pillars: each photograph stops at --cad-photo-max (1260px),
     centred in its slide; the section and its words stay full width. */
  .cad.cad--channel:not(.cadg) .cad-pillar--capped .cad-swipe__photo .cad-swipe__img {
    left: calc(50% - min(50%, var(--cad-photo-max) / 2)); right: auto;
    width: min(100%, var(--cad-photo-max)); }

  /* PRIVACY: the dissolving lines on the edge as well. */
  .cad.cad--channel:not(.cadg) .cad-privacy { padding-inline: var(--cad-edge) var(--cad-gutter);
    align-items: flex-start; text-align: left; }
  .cad.cad--channel:not(.cadg) .cad-privacy .cad-cta { align-self: flex-start; margin-inline: 0; }
}
/* Past the cap, a capped photograph's sides fade into the band's own ground
   instead of ending in a hard edge (owner, 2026-10-12; chosen over a blurred
   copy of the photo, which left a seam, and a fade into that copy, which costs
   a full-screen blur on every slide). ⚠️ 1260px IS --cad-photo-max IN PIXELS: a
   media query's rem is the browser's 16px, not this page's 18px root. */
@media (min-width: 1260px) {
  .cad.cad--channel:not(.cadg) .cad-pillar--capped .cad-swipe__photo { background: #1b1117; }
  .cad.cad--channel:not(.cadg) .cad-pillar--capped.cad-pillar--light .cad-swipe__photo {
    background: var(--color-bg-soft); }
  .cad.cad--channel:not(.cadg) .cad-pillar--capped .cad-swipe__photo .cad-swipe__img {
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
    mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent); }
}

/* ═════════════════════════════════════════════════════════════════════════════
   ABOUT PAGE (2026-10-18) — the collage OPENER, opt-in PILLAR options (a phone
   cut, a white scrim, the lead below the photograph on phones), still pillars on
   tablets, and links inside a lead or body. Built for /about/, MANTIS-1312
   (About Us page in the cadence look) https://bugs.jaji.us/view.php?id=1312.
   Every rule but one targets a class or a combination no page used before, so
   the homepage renders as it did. THE EXCEPTION is STILL PILLARS ON TABLETS
   below: it reaches every `pillars: bleed` page, the homepage included, and its
   effect there is recorded beside it.
   ═════════════════════════════════════════════════════════════════════════════ */

/* ── a link inside a lead or body ─────────────────────────────────────────────
   The shortcodes pass a lead or body that holds a markdown link through as HTML
   (shortcodes/pillar.html, reassure.html); before that, a link there could not
   render at all, so no page had one. Brand colour and an underline on light
   grounds; on dark and purple grounds the link takes the text's own colour. */
.cad .cad-lead a, .cad .cad-body a { color: var(--color-brand); text-decoration: underline;
  text-underline-offset: 0.15em; }
.cad .cad-pillar--dark .cad-lead a,
.cad .cad-band--purple .cad-lead a,
.cad .cad-band--purple .cad-body a { color: inherit; }

/* ── OPENER · collage ─────────────────────────────────────────────────────────
   cadence/opener-collage.html. Three snapshots as white-bordered prints on the
   dark pillars' plum (#1b1117), so the words' contrast comes from a plain
   ground, not a scrim. Same light type colours as the photo opener.

   GEOMETRY. The back prints are absolute in the top corners; the front print is
   IN FLOW and pushed down by a percentage margin, so it alone sets the cluster's
   height and the cluster scales as one piece. ⚠️ The margin is a percentage of
   the cluster's WIDTH (a margin's percentage always is), which is what keeps the
   overlap the same at every size. The prints' 12px border and 18px foot are
   fixed, as on a real print.

   ⚠️ overflow: hidden on the section is for the rotations: a rotated print's
   corners stand a few pixels outside its box, and at the screen's edge that
   would be a horizontal scroll on a phone. */
.cad .cad-collage { position: relative; overflow: hidden; background: #1b1117; color: #f6efe9;
  display: flex; flex-direction: column; gap: 2.25rem; padding: 2.25rem 1.375rem 3.5rem; }
.cad .cad-collage__head { display: flex; flex-direction: column; gap: 1rem;
  width: 100%; max-width: var(--cad-measure); margin-inline: auto; }
.cad .cad-collage h1 { color: #fff; }
.cad .cad-collage .cad-swap { color: #e4d5f5; }
.cad .cad-collage .cad-lead { color: #f1eae7; }
.cad .cad-collage .cad-eyebrow { color: #cbb3e4; }
/* Below 900px the prints come first on screen; in the DOM they follow the words,
   so the h1 still leads the page for a screen reader. */
.cad .cad-collage__prints { order: -1; position: relative; width: 100%; max-width: 26rem;
  margin-inline: auto; }
.cad .cad-print { background: #fff; padding: 12px 12px 18px;
  box-shadow: 0 14px 32px rgba(0, 0, 0, 0.55), 0 2px 6px rgba(0, 0, 0, 0.35); }
.cad .cad-print picture { display: block; }
.cad .cad-print .cad-print__img { display: block; width: 100%; height: auto; }
.cad .cad-print--back-left  { position: absolute; z-index: 1; top: 0.75rem; left: 0; width: 50%;
  transform: rotate(-5deg); }
.cad .cad-print--back-right { position: absolute; z-index: 2; top: 0; right: 0; width: 54%;
  transform: rotate(4deg); }
.cad .cad-print--front { position: relative; z-index: 3; width: 74%; margin: 27% 0 0 13%;
  transform: rotate(-1.5deg); }
@media (min-width: 600px) {
  .cad:not(.cadg) .cad-collage { padding: 3rem 2.25rem 4rem; gap: 2.75rem; }
  .cad:not(.cadg) .cad-collage__prints { max-width: 32rem; }
}
/* 900px and up: words on the left, prints filling the right half, about one
   screen tall. The prints' flex basis is a floor (42% of the row), so as the
   screen narrows the WORDS give way, never the pictures: at 900 the text block is
   about 20rem, from about 1250 it reaches its 30rem cap. Nothing overlaps the
   words because the two are separate flex items with a 3rem gap, wider than a
   rotated print's corner. */
@media (min-width: 900px) {
  .cad:not(.cadg) .cad-collage { flex-direction: row; align-items: center; gap: 3rem;
    min-height: 46rem; padding: 4rem 3rem; }
  .cad:not(.cadg) .cad-collage__head { order: 0; flex: 0 1 30rem; max-width: 30rem; margin: 0; }
  .cad:not(.cadg) .cad-collage h1 { font-size: clamp(2.1875rem, 3.5vw, 2.8rem); }
  .cad:not(.cadg) .cad-collage__prints { order: 0; flex: 1 0 42%; max-width: 40rem; margin: 0; }
  /* On the channel: the words start on the page's one left edge. */
  .cad.cad--channel:not(.cadg) .cad-collage { padding-left: var(--cad-edge); }
}

/* ── PILLAR · options (cadence/pillar.html) ───────────────────────────────── */
/* The eyebrow and heading, wrapped only on a `lead_below` pillar. */
.cad .cad-pillar__title { display: flex; flex-direction: column; gap: 0.75rem; }

/* scrim "white": the light scrim's stops, in white. The shared cream default is
   untouched (root CLAUDE.md rule 34: new grounds are white). */
.cad:not(.cadg) .cad-pillar--scrim-white::before {
  background: linear-gradient(180deg,
    rgba(255, 255, 255, 0.72) 0%, rgba(255, 255, 255, 0.46) 24%,
    rgba(255, 255, 255, 0.18) 40%, rgba(255, 255, 255, 0) 52%);
}
@media (min-width: 900px) {
  .cad.cad--bleed:not(.cadg) .cad-pillar--scrim-white::before {
    background: linear-gradient(90deg, rgba(255, 255, 255, 0.88) 0%,
      rgba(255, 255, 255, 0.62) 34%, rgba(255, 255, 255, 0) 60%); }
  /* A `lead_below` pillar's lead is three or four sentences, 28rem wide on the
     channel. The shared side scrim is gone by 60% of the width, which at 1024
     leaves the lead's right half on bare photograph (measured 2026-10-18: the
     scrapbook's snapshots behind "using it to listen"). So the scrim is measured
     from the words instead: held to the lead's right edge (--cad-edge + 28rem),
     gone 12rem later. At 1440 that ends about where the shared curve does. */
  .cad.cad--bleed:not(.cadg) .cad-pillar--lead-below { --cad-scrim-end: calc(var(--cad-edge, 3rem) + 28rem); }
  .cad.cad--bleed:not(.cadg) .cad-pillar--lead-below.cad-pillar--dark::before {
    background: linear-gradient(90deg, rgba(20, 12, 16, 0.86) 0%, rgba(20, 12, 16, 0.7) calc(var(--cad-scrim-end) - 4rem),
      rgba(20, 12, 16, 0.4) var(--cad-scrim-end), rgba(20, 12, 16, 0) calc(var(--cad-scrim-end) + 12rem)); }
  .cad.cad--bleed:not(.cadg) .cad-pillar--lead-below.cad-pillar--light::before {
    background: linear-gradient(90deg, rgba(251, 248, 243, 0.9) 0%, rgba(251, 248, 243, 0.72) calc(var(--cad-scrim-end) - 4rem),
      rgba(251, 248, 243, 0.4) var(--cad-scrim-end), rgba(251, 248, 243, 0) calc(var(--cad-scrim-end) + 12rem)); }
  .cad.cad--bleed:not(.cadg) .cad-pillar--lead-below.cad-pillar--scrim-white::before {
    background: linear-gradient(90deg, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0.72) calc(var(--cad-scrim-end) - 4rem),
      rgba(255, 255, 255, 0.4) var(--cad-scrim-end), rgba(255, 255, 255, 0) calc(var(--cad-scrim-end) + 12rem)); }
}

/* lead_below "phone": under 600px the pillar becomes a two-row grid. Row 1 is
   the 9:16 photograph with the scrim and the eyebrow and heading over its calm
   top; row 2 is the lead on a band of the pillar's own tone. The head is
   `display: contents` so the title and the lead can sit in different rows
   without the lead being written twice. ⚠️ The scrim is absolutely positioned
   but placed in row 1, so its box is that grid area, not the whole section:
   without the placement it would also darken the lead's band. */
@media (max-width: 599px) {
  .cad:not(.cadg) .cad-pillar--lead-below { display: grid; grid-template-columns: minmax(0, 1fr);
    aspect-ratio: auto; max-height: none; }
  .cad:not(.cadg) .cad-pillar--lead-below .cad-pillar__photo { position: relative; inset: auto;
    grid-area: 1 / 1; width: 100%; height: auto; aspect-ratio: 9 / 16; max-height: 780px;
    object-fit: cover; }
  .cad:not(.cadg) .cad-pillar--lead-below::before { grid-area: 1 / 1; }
  .cad:not(.cadg) .cad-pillar--lead-below .cad-pillar__head { display: contents; }
  .cad:not(.cadg) .cad-pillar--lead-below .cad-pillar__title { grid-area: 1 / 1; align-self: start;
    position: relative; z-index: 2; width: 100%; max-width: calc(var(--cad-measure) + 2.75rem);
    margin-inline: auto; padding: 2.125rem 1.375rem 0; }
  /* The side padding keeps the band full width and the words on the measure. */
  .cad:not(.cadg) .cad-pillar--lead-below .cad-pillar__head > .cad-lead { grid-area: 2 / 1;
    position: relative; z-index: 2; margin: 0;
    padding: 1.5rem max(1.375rem, calc((100% - var(--cad-measure)) / 2)) 3rem; }
  .cad:not(.cadg) .cad-pillar--lead-below.cad-pillar--dark .cad-pillar__head > .cad-lead { background: #1b1117; }
  .cad:not(.cadg) .cad-pillar--lead-below.cad-pillar--light .cad-pillar__head > .cad-lead { background: #fff; }
}

/* ── STILL PILLARS ON TABLETS (`pillars: bleed`, 600–899px) ───────────────────
   The photograph fills the pillar (cover, centred, as at every other width) and
   the words stay at the top over the top-down scrim, in a section about two
   thirds of the screen tall. Before this a still pillar here kept the phone's
   9:16 shape, capped at 780px.
   ⚠️ THIS REACHES THE HOMEPAGE, which is also `pillars: bleed`: its two still
   pillars (the photograph and the house) are clamp(36rem, 70svh, 44rem) tall at
   these widths instead of 780px, so on a 768x1024 tablet 717px. Their words,
   scrim, card and centred crop are unchanged. Swipe pillars are excluded: they
   keep their own track geometry. */
@media (min-width: 600px) and (max-width: 899px) {
  .cad.cad--bleed:not(.cadg) .cad-pillar:not(.cad-pillar--swipe) {
    aspect-ratio: auto; max-height: none; min-height: clamp(36rem, 70svh, 44rem); }
  /* A `lead_below` pillar carries a lead of three or four sentences, which on a
     tablet stays over the photograph and ends near 45% of the section, where
     the shared scrim is almost gone. Its scrim holds further. Only these pillars:
     the homepage's one-line leads keep the shared curve. */
  .cad.cad--bleed:not(.cadg) .cad-pillar--lead-below.cad-pillar--dark::before {
    background: linear-gradient(180deg, rgba(20, 12, 16, 0.84) 0%, rgba(20, 12, 16, 0.74) 30%,
      rgba(20, 12, 16, 0.5) 46%, rgba(20, 12, 16, 0) 64%); }
  .cad.cad--bleed:not(.cadg) .cad-pillar--lead-below.cad-pillar--light::before {
    background: linear-gradient(180deg, rgba(251, 248, 243, 0.86) 0%, rgba(251, 248, 243, 0.76) 30%,
      rgba(251, 248, 243, 0.5) 46%, rgba(251, 248, 243, 0) 64%); }
  .cad.cad--bleed:not(.cadg) .cad-pillar--lead-below.cad-pillar--scrim-white::before {
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.86) 0%, rgba(255, 255, 255, 0.76) 30%,
      rgba(255, 255, 255, 0.5) 46%, rgba(255, 255, 255, 0) 64%); }
}

@media (prefers-reduced-motion: reduce) {
  .cad *, .cad *::before { transition: none !important; animation: none !important; }
  /* PRIVACY without motion: all three lines at once, stacked. */
  .cad-dissolve { gap: 0.4rem; }
  .cad-dissolve__line { grid-area: auto; opacity: 1; filter: none; }
}
