/* ============================================================================
   SNAP (snap-print), deployed page styles (Link-in-bio category): ONE tilted
   instant-photo PRINT on a warm page. The page is a flat tint (--sn-tint,
   inline from snap.tint) under two soft radial washes (cream top-left, lilac
   bottom-right). The identity lives on the print's caption strip: Fredoka
   display name + the house verified badge, "@handle · bio" one-liner, and a
   rotated "18+ ONLY" note (profile kicker) in accent-deep. Below: ONE accent
   pill CTA (featured, no image) with a 3D pressed shadow and a PRICE CHIP
   (featured.subtitle), simple links as soft paper pills in rows of three
   (one flex-wrap group; every other block type takes a full row), mini
   prints for featured-with-image / gallery / media, 44px circular
   full-colour socials, a tiny footer. Tokens ride .sn-root: --sn-tint,
   --sn-paper, --sn-accent and --sn-tilt come inline from the client's
   normalizeSnap (--sn-tilt MUST carry its unit, e.g. '-1.8deg');
   --sn-accent-deep is derived here, color-mix(accent 60%, ink), for the 3D
   shadow + note text. Fredoka (display) + Inter (body), loaded by the baked
   HTML's fonts link. Faithful port of the sn- block in
   src/pages/NewEditor/NewEditor.css; KEEP IN PARITY with that block and with
   SnapPreview.jsx (the markup contract, .claude/tasks/SNAP.md).
   Markup contract (the client emits exactly these classes):
     page      main.sn-root > .sn-col > .sn-stack > .sn-section.is-<id>
     print     .sn-print .sn-print-photo (+ .sn-print-empty) .sn-caption
               .sn-identity .sn-name (+ badge img) .sn-handle .sn-tagline .sn-note
     links     .sn-links .sn-item (+ .is-pill .is-pill-0 / -1 / -2, .has-gated,
               .pc-anim-*) > .sn-cta (.sn-cta-title .sn-cta-chip) | .sn-pill |
               .sn-feature (.sn-feature-media .sn-feature-empty .sn-feature-caption
               .sn-feature-title .sn-feature-sub) | .sn-gallery (.sn-gallery-title
               .sn-gallery-grid .sn-mini (+ .is-even) .sn-mini-photo .sn-mini-empty
               .sn-mini-caption) | .sn-media (.sn-media-frame .sn-media-placeholder
               .sn-media-copy .sn-media-title .sn-media-caption) | .sn-label |
               .sn-text | .sn-divider (+ .sn-divider-chars)
     socials   .sn-socials .sn-social (+ .is-badge) + .ne-fpill
     footer    .sn-footer .sn-footer-brand;  empty  .sn-empty -title -sub
     18+       .has-adult-warning host + .sn-adult-inline family; .bncy-sgate-*
   Page-context differences from the editor preview (everything else verbatim):
   - the DOCUMENT scrolls at every width. The editor's .sn-scroll was
     EDITOR-STRUCTURAL plumbing and does not exist here: main.sn-root >
     .sn-col > sections is the whole tree. The root is the full-width page
     (min-height 100svh, 100vh fallback) and a flex column, so .sn-col can
     grow to the fold (flex: 1 0 auto replaces the editor's min-height: 100%)
     and its justify-content: center still floats a short page mid-screen.
   - the two washes are viewport-anchored, exactly as the editor paints them
     on its non-scrolling root: they ride a position: fixed ::before INSIDE
     the transform/filter-free root (canvas fixed-layer precedent), under the
     content via z-index -1 in the root's isolated stacking context, over the
     root's own --sn-tint base. background-attachment: fixed is NOT used (iOS
     Safari ignores it). The root keeps NO transform/filter/overflow EVER, so
     that layer and the position: fixed .bncy-sgate overlay (mounted inside
     the root) stay viewport-true.
   - NO card at any width (Spotlight full-bleed model): at >= 760px the
     gradient fills the viewport and the column widens to the prototype's
     desktop values (column 580, print 410, links/empty 410, CTA 400).
   - editor-only affordances are dropped: the .is-selected outline, the drag
     cursors on .sn-item and .sn-social, and the selection cursor: pointer on
     furniture (print, name, handle, note, footer, empty state). Interactive
     blocks (cta, pill, feature, social) keep their pointer because gated 18+
     blocks render as span wrappers (no href, UA gives them no cursor).
   - the .ne-frame.is-mobile descendant rules: the frame's fake 58px notch
     clearance is editor-only (real safe-area terms ride the column padding
     here, the prototype's own rule); the narrow-screen pill size became the
     prototype's @media (max-width: 400px) block.
   - the verified mark is the house badge img (/assets/bouncy-verified-badge
     .svg) inside .sn-name; the client sizes it inline at 0.8em, the rule
     here is the fallback.
   - Palette custom properties arrive inline on .sn-root from the client:
     --sn-tint, --sn-paper, --sn-accent, --sn-tilt; the client MAY also set
     --sn-tint on <html> (duotone --dt-stage precedent) so overscroll shows
     the picked tint, the literal fallback below is the default peach.
   VERSION: 1.0
   ========================================================================== */

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; color-scheme: light; }
/* the floor under the page: the tint (inline on <html> when the client sets
   it, else the default peach), visible on phone overscroll only */
html, body { margin: 0; padding: 0; background: var(--sn-tint, #f7b89f); }
body {
  min-height: 100%;
  min-width: 320px;
  color: #2b2030;
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
img { max-width: 100%; }
/* client utility (scene convention): hard-hide toggled nodes */
.sn-hidden { display: none !important; }
/* keyboard focus ring (deploy-only accessibility, canvas convention): ink,
   so it reads on the peach page, the paper pills and the accent CTA alike */
.sn-root :focus-visible {
  outline: 3px solid var(--sn-ink);
  outline-offset: 3px;
}

/* ---- Root + tokens: the page itself. Flat tint base; the two fixed washes
   ride the ::before below. Flex column so the centered column can grow to
   the fold. NO transform/filter/overflow here EVER (fixed descendants). ---- */
.sn-root {
  --sn-tint: #f7b89f;
  --sn-paper: #fffaf1;
  --sn-accent: #f45e91;
  --sn-tilt: -1.8deg;
  --sn-lilac: #c8b4e8;
  --sn-cream: #fffaf1;
  --sn-ink: #2b2030;
  --sn-muted: #766579;
  --sn-pill-ink: #5b455d;
  --sn-accent-deep: color-mix(in srgb, var(--sn-accent) 60%, #2b2030);
  --sn-soft: color-mix(in srgb, var(--sn-paper) 60%, transparent);
  --sn-soft-strong: color-mix(in srgb, var(--sn-paper) 88%, transparent);
  --sn-hair: rgba(255, 255, 255, 0.34);
  --sn-line: color-mix(in srgb, var(--sn-ink) 14%, transparent);
  --sn-shadow: 0 24px 52px -28px rgba(67, 38, 67, 0.68), 0 4px 0 rgba(255, 255, 255, 0.38);
  --sn-shadow-hover: 0 28px 56px -28px rgba(67, 38, 67, 0.75), 0 4px 0 rgba(255, 255, 255, 0.42);
  --sn-shadow-mini: 0 16px 34px -24px rgba(67, 38, 67, 0.6), 0 3px 0 rgba(255, 255, 255, 0.38);
  --sn-shadow-mini-hover: 0 20px 40px -24px rgba(67, 38, 67, 0.7), 0 3px 0 rgba(255, 255, 255, 0.42);
  --sn-display: 'Fredoka', ui-rounded, 'Arial Rounded MT Bold', 'Trebuchet MS', Arial, sans-serif;
  --sn-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --sn-ease: cubic-bezier(0.2, 0, 0, 1);
  --sn-quick: 120ms;
  /* contact blocks (blocks/contactBlocks.css) inherit the Snap look */
  --bc-ink: var(--sn-ink);
  --bc-muted: var(--sn-muted);
  --bc-bg: var(--sn-soft-strong);
  --bc-bg-strong: #ffffff;
  --bc-border: var(--sn-line);
  --bc-accent: var(--sn-accent);
  --bc-accent-ink: #ffffff;
  --bc-radius: 18px;
  --bc-field-radius: 14px;
  --bc-display: var(--sn-display);
  --bc-body: var(--sn-body);
  --bc-pill-bg: var(--sn-soft);
  --bc-pill-ink: var(--sn-pill-ink);
  --bc-pill-radius: 18px;
  --bc-pill-font: var(--sn-display);
  --bc-pill-shadow: inset 0 0 0 1px var(--sn-hair);
  position: relative;
  /* own stacking context: keeps the z -1 wash layer above the root's own
     tint and below the content (no containing-block side effects, unlike
     transform/filter/contain) */
  isolation: isolate;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  /* the page base: the flat tint (the washes paint over it, see ::before) */
  background: var(--sn-tint);
  font-family: var(--sn-body);
  color: var(--sn-ink);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
/* the two FIXED washes (cream #fffaf1 at 12% 10%, lilac #c8b4e8 at 88% 76%,
   prototype stops): viewport-anchored, so they never move while the
   document scrolls, exactly the editor's non-scrolling-root picture */
.sn-root::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(circle at 12% 10%, rgba(255, 250, 241, 0.72), transparent 27%),
    radial-gradient(circle at 88% 76%, rgba(200, 180, 232, 0.82), transparent 38%);
}
.sn-root ::selection { background: var(--sn-accent); color: #ffffff; }
/* anchor blocks never underline, whatever a host reset does (the deployed
   page must not depend on the base a reset above) */
.sn-cta, .sn-pill, .sn-feature { text-decoration: none; }
/* the prototype relied on a global border-box; the skin declares it so
   padded boxes (column, print, mini prints, CTA) never overflow their 100% */
.sn-root, .sn-root * { box-sizing: border-box; }

/* ---- Centered column: grows to the fold (flex: 1 0 auto against the flex
   column root) + justify center, so a short page floats mid-screen and a
   long one simply grows (prototype .snap). Real safe-area terms ride the
   padding (the prototype's rule; the editor frame faked the notch). ---- */
.sn-col {
  display: flex;
  flex: 1 0 auto;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: min(100%, 520px);
  margin: 0 auto;
  padding: max(18px, env(safe-area-inset-top, 0px)) 18px calc(13px + env(safe-area-inset-bottom, 0px));
  /* light follower pill (shared .ne-fpill themed via --fp-*), centered
     under the socials */
  --fp-margin: 10px auto 0;
  --fp-bg: var(--sn-soft);
  --fp-border: 1px solid var(--sn-hair);
  --fp-border-hover: rgba(255, 255, 255, 0.7);
  --fp-text: var(--sn-ink);
  --fp-muted: var(--sn-muted);
  --fp-radius: 999px;
}
.sn-stack { display: flex; flex-direction: column; align-items: center; width: 100%; }
.sn-section { position: relative; width: 100%; }
/* the print keeps its 17px breathing room when another section sits above it */
.sn-section + .sn-section .sn-print { margin-top: 17px; }

/* ---- The print (profile): paper frame, layered paper shadow, tilt from
   --sn-tilt (inline, WITH its unit). The entrance rides the print itself
   and fills backwards so the hover lift survives it. ---- */
.sn-print {
  position: relative;
  width: min(100%, 354px);
  margin: 0 auto;
  padding: 12px 12px 0;
  background: var(--sn-paper);
  box-shadow: var(--sn-shadow);
  transform: rotate(var(--sn-tilt));
  transform-origin: 50% 74%;
  animation: sn-print-in 460ms var(--sn-ease) backwards;
  transition: transform 280ms var(--sn-ease), box-shadow 280ms var(--sn-ease);
}
/* hover eases the print toward upright (0.4 of the tilt: -1.8 -> -0.72,
   the prototype's -0.7) and lifts it 2px */
.sn-print:hover {
  box-shadow: var(--sn-shadow-hover);
  transform: rotate(calc(var(--sn-tilt) * 0.4)) translateY(-2px);
}
/* the photo well: 20 / 23 (4 / 4.6), the SAME aspect as the crop stage so
   the modal's framing is exactly what prints; it clips the crop's scale */
.sn-print-photo {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 20 / 23;
  overflow: hidden;
  background: color-mix(in srgb, var(--sn-tint) 70%, #6b4a55);
}
.sn-print-photo img,
img.sn-print-photo {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* focal point + crop scale come inline from snap.photo */
}
/* no photo: a soft tinted block so the frame still reads as a print
   (standalone at the print's aspect, or filling the photo well) */
.sn-print-empty {
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 20 / 23;
  background: linear-gradient(160deg,
    color-mix(in srgb, var(--sn-tint) 55%, var(--sn-cream)) 0%,
    color-mix(in srgb, var(--sn-tint) 70%, var(--sn-lilac)) 100%);
  color: var(--sn-muted);
  font-size: 12px;
  font-weight: 700;
  text-align: center;
}
.sn-print-photo > .sn-print-empty { position: absolute; inset: 0; aspect-ratio: auto; }

/* ---- Caption strip: identity left, rotated note right ---- */
.sn-caption {
  display: flex;
  min-height: 66px;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 6px 10px;
}
.sn-identity { min-width: 0; }
.sn-name {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-family: var(--sn-display);
  font-size: 1.45rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--sn-ink);
  overflow-wrap: anywhere;
}
/* the verified mark: the house badge img (bouncy-verified-badge.svg) sized
   to the name (the client's inline 0.8em wins; this is the fallback) */
.sn-name img,
.sn-name .sn-verified-badge {
  width: 0.8em;
  height: 0.8em;
  flex: none;
  display: inline-block;
  vertical-align: middle;
}
/* "@handle · bio", ONE line, ellipsised: the caption-strip design */
.sn-handle {
  margin: 5px 0 0;
  overflow: hidden;
  color: var(--sn-muted);
  font-family: var(--sn-body);
  font-size: 0.72rem;
  font-weight: 500;
  line-height: 1.3;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* the bio inside the handle line; its typography comes inline (explicit so
   the sn- contract enumerates every emitted class) */
.sn-tagline { color: inherit; }
/* the rotated note (profile kicker; the client drops it when empty) */
.sn-note {
  flex: 0 1 auto;
  max-width: 42%;
  color: var(--sn-accent-deep);
  font-family: var(--sn-body);
  font-size: 0.64rem;
  font-weight: 900;
  letter-spacing: 0.06em;
  line-height: 1.2;
  text-align: right;
  text-transform: uppercase;
  overflow-wrap: anywhere;
  transform: rotate(2deg);
}

/* ---- Links: ONE flex-wrap group. Every block takes a full row except
   simple links (.sn-item.is-pill), which take a third so consecutive pills
   form rows of three (3 x (33.333% - 4.67px) + 2 x 7px = 100%); one or two
   leftover pills simply sit left. ---- */
.sn-links {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 7px;
  width: min(100%, 354px);
  margin: 17px auto 0;
  justify-content: center;  /* partial pill rows centre (a lone pill) */
}
.sn-item {
  position: relative;
  flex: 0 0 100%;
  min-width: 0;
}
.sn-item.is-pill { display: flex; flex: 0 0 calc(33.333% - 4.67px); }
/* the prototype's 15px between the CTA and the pill row: a full-row block
   adds 8px on its pill-facing side, the 7px row gap supplies the rest */
.sn-item:not(.is-pill):not(:last-child) { margin-bottom: 8px; }
.sn-item.is-pill + .sn-item:not(.is-pill) { margin-top: 8px; }
/* entrance cascade rides the INNER block (the wrapper stays animation-free
   so pc-anim-* can ride it); 70/95/120ms then 25ms steps, late blocks join
   the last step; backwards fill so hover/active lifts survive it */
.sn-item > * { animation: sn-rise 280ms var(--sn-ease) 70ms backwards; }
.sn-item:nth-child(2) > * { animation-delay: 95ms; }
.sn-item:nth-child(3) > * { animation-delay: 120ms; }
.sn-item:nth-child(4) > * { animation-delay: 145ms; }
.sn-item:nth-child(5) > * { animation-delay: 170ms; }
.sn-item:nth-child(n+6) > * { animation-delay: 195ms; }

/* ---- The CTA (featured, no image): ONE accent pill with a 3D pressed
   shadow and the price chip. Custom colours ride --sn-cta-bg / --sn-cta-ink
   (set inline from link.colors.background / .title) so the pressed shadow
   and the hover shade derive from the picked colour ---- */
.sn-cta {
  --sn-cta-deep: color-mix(in srgb, var(--sn-cta-bg, var(--sn-accent)) 60%, #2b2030);
  display: flex;
  width: min(100%, 348px);
  min-height: 60px;
  margin: 0 auto;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px;
  border-radius: 999px;
  background: var(--sn-cta-bg, var(--sn-accent));
  box-shadow: 0 7px 0 var(--sn-cta-deep), 0 18px 30px -22px rgba(76, 35, 69, 0.9);
  color: var(--sn-cta-ink, #ffffff);
  font-family: var(--sn-display);
  font-size: 0.88rem;
  font-weight: 900;
  line-height: 1.15;
  cursor: pointer;
  transition: background var(--sn-quick) ease, box-shadow var(--sn-quick) ease, transform var(--sn-quick) var(--sn-ease);
}
.sn-cta:hover {
  background: color-mix(in srgb, var(--sn-cta-bg, var(--sn-accent)) 92%, #2b2030);
  transform: translateY(-2px);
}
.sn-cta:active { box-shadow: 0 3px 0 var(--sn-cta-deep); transform: translateY(4px); }
.sn-cta-title { min-width: 0; overflow-wrap: anywhere; }
/* the price chip (featured.subtitle; the client drops it when empty) */
.sn-cta-chip {
  flex: none;
  padding: 7px 10px;
  border-radius: 999px;
  /* paper tag, not white-on-pink: the chip must pass AA at 11px */
  background: rgba(255, 250, 241, 0.9);
  color: var(--sn-accent-deep);
  font-family: var(--sn-body);
  font-size: 0.71rem;
  font-weight: 700;
  white-space: nowrap;
}

/* ---- Simple links: soft paper pills, centered title, organic corner
   variants by pill index (2nd / 3rd of each run; the class comes from the
   client on the pill or on its item) ---- */
.sn-pill {
  display: inline-flex;
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  min-height: 48px;
  align-items: center;
  justify-content: center;
  padding: 8px 6px;
  border-radius: 18px;
  background: var(--sn-soft);
  box-shadow: inset 0 0 0 1px var(--sn-hair);
  color: var(--sn-pill-ink);
  font-family: var(--sn-display);
  font-size: 0.68rem;
  font-weight: 800;
  line-height: 1.15;
  text-align: center;
  overflow-wrap: anywhere;
  cursor: pointer;
  transition: background var(--sn-quick) ease, color var(--sn-quick) ease, transform var(--sn-quick) var(--sn-ease);
}
.sn-pill.is-pill-1, .sn-item.is-pill-1 .sn-pill { border-radius: 50% 18px 50% 18px; }
.sn-pill.is-pill-2, .sn-item.is-pill-2 .sn-pill { border-radius: 18px 50% 18px 50%; }
.sn-pill:hover { background: var(--sn-soft-strong); color: var(--sn-accent-deep); transform: translateY(-2px); }
.sn-pill:active { transform: scale(0.97); }

/* Optional link marks leave the photo and no-icon spacing unchanged. */
.sn-link-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin-inline-end: 8px;
  vertical-align: -3px;
  line-height: 1;
  font-size: 11px;
  letter-spacing: 0;
  text-transform: none;
}
.sn-link-icon > img { display: block; width: 18px; height: 18px; object-fit: contain; }

/* ---- Featured WITH image: a mini print card at +1deg. The image sits at
   EXACTLY 2.35 / 1 (the featured crop stage) under a caption strip. The
   rise keyframe carries the tilt via --sn-rise-rot so the card never
   un-tilts during its entrance. ---- */
.sn-feature {
  --sn-rise-rot: 1deg;
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 10px 10px 0;
  background: var(--sn-paper);
  box-shadow: var(--sn-shadow-mini);
  color: var(--sn-ink);
  transform: rotate(var(--sn-rise-rot));
  transform-origin: 50% 60%;
  cursor: pointer;
  transition: transform 280ms var(--sn-ease), box-shadow 280ms var(--sn-ease);
}
.sn-feature:hover { box-shadow: var(--sn-shadow-mini-hover); transform: rotate(0.4deg) translateY(-2px); }
.sn-feature:active { transform: rotate(1deg) translateY(1px); }
.sn-feature-media {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 2.35 / 1;
  overflow: hidden;
  background: color-mix(in srgb, var(--sn-tint) 55%, var(--sn-cream));
}
.sn-feature-media img { display: block; width: 100%; height: 100%; object-fit: cover; }
.sn-feature-empty {
  background: linear-gradient(160deg,
    color-mix(in srgb, var(--sn-tint) 55%, var(--sn-cream)) 0%,
    color-mix(in srgb, var(--sn-tint) 70%, var(--sn-lilac)) 100%);
}
.sn-feature-media > .sn-feature-empty { position: absolute; inset: 0; }
.sn-feature-caption {
  display: flex;
  min-height: 46px;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 4px 9px;
}
.sn-feature-title {
  min-width: 0;
  font-family: var(--sn-display);
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
  overflow-wrap: anywhere;
}
.sn-feature-sub {
  flex: 0 1 auto;
  max-width: 42%;
  color: var(--sn-muted);
  font-size: 0.7rem;
  font-weight: 700;
  line-height: 1.2;
  text-align: right;
  overflow-wrap: anywhere;
}

/* ---- Gallery: a grid of mini prints (square photo, caption line),
   alternating tilt -1 / +1 deg (.is-even); columns from
   --sn-gallery-columns (inline, clamped 1-3 by the client) ---- */
.sn-gallery { display: flex; flex-direction: column; gap: 10px; width: 100%; }
.sn-gallery-title {
  color: color-mix(in srgb, var(--sn-ink) 76%, transparent);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.18em;
  text-align: center;
  text-transform: uppercase;
}
.sn-gallery-grid {
  display: grid;
  grid-template-columns: repeat(var(--sn-gallery-columns, 2), minmax(0, 1fr));
  gap: 14px 12px;
  padding: 4px 6px 6px;   /* room for the tilted corners */
}
.sn-mini {
  display: flex;
  flex-direction: column;
  padding: 7px 7px 0;
  background: var(--sn-paper);
  box-shadow: var(--sn-shadow-mini);
  transform: rotate(-1deg);
  transition: box-shadow 280ms var(--sn-ease);
}
.sn-mini.is-even { transform: rotate(1deg); }
.sn-mini:hover { box-shadow: var(--sn-shadow-mini-hover); }
.sn-mini-photo {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: color-mix(in srgb, var(--sn-tint) 55%, var(--sn-cream));
}
.sn-mini-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* the empty well is the photo box ITSELF (one element carries both classes),
   so it stays in flow at 1:1; only a nested placeholder is absolute */
.sn-mini-empty {
  background: linear-gradient(160deg,
    color-mix(in srgb, var(--sn-tint) 55%, var(--sn-cream)) 0%,
    color-mix(in srgb, var(--sn-tint) 70%, var(--sn-lilac)) 100%);
}
.sn-mini-photo > .sn-mini-empty { position: absolute; inset: 0; }
/* the caption line IS the print's bottom band: always rendered, even empty */
.sn-mini-caption {
  min-height: 28px;
  padding: 6px 2px 7px;
  font-family: var(--sn-display);
  font-size: 0.66rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--sn-ink);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- Media: the universal embed engine in a paper frame + caption strip
   (no tilt: rotated iframes blur their text). Frame sizing comes inline
   from the client's getMediaFrameStyle / getMediaPlaceholderStyle. ---- */
.sn-media {
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 10px 10px 0;
  background: var(--sn-paper);
  box-shadow: var(--sn-shadow-mini);
}
.sn-media-frame {
  display: block;
  width: 100%;
  border: 0;
  background: #000000;
  /* deployed fallback only (duotone/canvas precedent): the client's inline
     sizing (aspect-ratio + height auto, or a pixel height) always wins */
  height: var(--sn-media-frame-height, 220px);
}
.sn-media-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--sn-tint) 55%, var(--sn-cream));
  color: var(--sn-muted);
  font-size: 13px;
  font-weight: 700;
}
.sn-media-copy { display: flex; flex-direction: column; gap: 2px; min-height: 40px; padding: 8px 4px 9px; }
.sn-media-title { font-family: var(--sn-display); font-size: 0.95rem; font-weight: 700; line-height: 1.15; overflow-wrap: anywhere; }
.sn-media-caption { color: var(--sn-muted); font-size: 0.72rem; }

/* ---- Header label (centered small caps; 76% ink so it clears AA on the
   default peach, 70% sat at 4.4:1), text (pre-wrap, on the page), divider ---- */
.sn-label {
  width: 100%;
  padding-top: 6px;
  color: color-mix(in srgb, var(--sn-ink) 76%, transparent);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.18em;
  text-align: center;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}
.sn-text {
  width: 100%;
  max-width: 40ch;
  margin: 0 auto;
  color: var(--sn-ink);
  font-size: 14px;
  line-height: 1.55;
  text-align: center;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.sn-divider {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 4px 0;
  color: var(--sn-divider-color, var(--sn-muted));
}
.sn-divider > span { display: block; width: 100%; height: 1px; background: var(--sn-divider-color, var(--sn-line)); }
.sn-divider.sn-divider-chars > span { width: auto; height: auto; background: none; letter-spacing: 0.35em; font-size: 13px; }

/* ---- Socials: centered 44px circles, full-colour marks ---- */
.sn-socials {
  display: flex;
  flex-wrap: wrap;
  min-height: 44px;
  margin: 11px auto 0;
  align-items: center;
  justify-content: center;
  gap: 3px;
  animation: sn-rise 280ms var(--sn-ease) 120ms backwards;
}
.sn-social {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  color: color-mix(in srgb, var(--sn-ink) 63%, transparent);
  font-size: 0.65rem;
  font-weight: 900;
  cursor: pointer;
  transition: background var(--sn-quick) ease, color var(--sn-quick) ease, transform var(--sn-quick) var(--sn-ease);
}
.sn-social:hover { background: color-mix(in srgb, var(--sn-paper) 50%, transparent); color: var(--sn-accent-deep); transform: translateY(-1px); }
.sn-social.is-disabled { cursor: default; opacity: 0.55; }
.sn-social:active { transform: scale(0.95); }
.sn-social img {
  width: 22px;
  height: 22px;
  object-fit: contain;
  /* full-colour brand marks, house convention */
}
/* text fallback for platforms without an icon asset */
.sn-social span { font-size: 0.65rem; line-height: 1; }
/* Bordered icon style (socialsAppearance.style 'badge'): paper circles with
   the inset hairline */
.sn-social.is-badge { background: var(--sn-soft); box-shadow: inset 0 0 0 1px var(--sn-hair); }
.sn-social.is-badge:hover { background: var(--sn-soft-strong); }
.sn-social.is-badge img { width: 20px; height: 20px; }

/* ---- Footer ---- */
.sn-footer {
  display: flex;
  justify-content: center;
  gap: 4px;
  margin: 5px auto 0;
  padding: 2px 0 0;
  color: color-mix(in srgb, var(--sn-ink) 70%, transparent);
  font-size: 0.61rem;
  font-weight: 500;
  text-align: center;
  animation: sn-rise 280ms var(--sn-ease) 150ms backwards;
}
.sn-footer-brand { font-weight: 800; }
a.sn-footer-brand:hover { text-decoration: underline; }


/* ---- Contact blocks: full row; the accent buttons take the Snap 3D shadow ---- */
.sn-contact { width: 100%; }
.sn-root .bncy-c-btn, .sn-root .bncy-g-btn { box-shadow: 0 4px 0 var(--sn-accent-deep); }
.sn-root .bncy-c-btn:active, .sn-root .bncy-g-btn:active { box-shadow: 0 1px 0 var(--sn-accent-deep); transform: translateY(2px); }

/* ---- Empty state (the client may emit it for a fully hidden page) ---- */
.sn-empty {
  width: min(100%, 354px);
  margin: 18px auto;
  padding: 22px 16px;
  border: 1px dashed color-mix(in srgb, var(--sn-ink) 28%, transparent);
  border-radius: 18px;
  background: var(--sn-soft);
  text-align: center;
}
.sn-empty-title { font-family: var(--sn-display); font-size: 15px; font-weight: 700; color: var(--sn-ink); }
.sn-empty-sub { margin-top: 5px; font-size: 12px; color: var(--sn-muted); }

/* ---- Motion: one ease; both keyframes land exactly on the resting rule
   (the print's tilt, the feature's --sn-rise-rot) so a backwards fill
   releases with no snap ---- */
@keyframes sn-print-in {
  from { opacity: 0; transform: rotate(-4deg) translateY(8px) scale(0.985); }
  to { opacity: 1; transform: rotate(var(--sn-tilt, -1.8deg)) translateY(0) scale(1); }
}
@keyframes sn-rise {
  from { opacity: 0; transform: translateY(8px) rotate(var(--sn-rise-rot, 0deg)); }
  to { opacity: 1; transform: translateY(0) rotate(var(--sn-rise-rot, 0deg)); }
}

/* ---- Per-link animations (bounce / pulse / glow / shine): the shared
   pc-anim-* classes (pro-card/noir/canvas/duotone convention, KEEP IN
   PARITY with NewEditor.css). The class sits on the .sn-item wrapper so the
   inner block keeps its sn-rise entrance cascade. ---- */
@keyframes pc-bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
.pc-anim-bounce { animation: pc-bounce 2s ease-in-out infinite; }
@keyframes pc-scale-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.03); } }
.pc-anim-pulse { animation: pc-scale-pulse 2s ease-in-out infinite; }
.pc-anim-shine { position: relative; overflow: hidden; }
.pc-anim-shine::before {
  content: ''; position: absolute; top: -50%; left: -100%; width: 60%; height: 200%;
  background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.03) 25%, rgba(255,255,255,0.12) 50%, rgba(255,255,255,0.03) 75%, transparent 100%);
  transform: skewX(-15deg); animation: pc-shine 4s ease-in-out infinite; z-index: 3; pointer-events: none;
}
@keyframes pc-shine { 0% { left: -100%; opacity: 0; } 10% { opacity: 1; } 50% { left: 100%; opacity: 1; } 55% { opacity: 0; } 100% { left: 100%; opacity: 0; } }
/* Glow: soft pulsing coloured halo; colour from --pc-glow-color (editor control). */
.pc-anim-glow { border-radius: 14px; animation: pc-glow-pulse 2.4s ease-in-out infinite; }
@keyframes pc-glow-pulse {
  0%, 100% { box-shadow: 0 0 12px 2px color-mix(in srgb, var(--pc-glow-color, #e8c6c0) 45%, transparent); }
  50%      { box-shadow: 0 0 28px 6px color-mix(in srgb, var(--pc-glow-color, #e8c6c0) 78%, transparent); }
}

/* ---- NARROW PHONES (the prototype's <= 350px case; the editor's 360px
   frame carried the pill size as its .ne-frame.is-mobile rule) ---- */
@media (max-width: 350px) {
  .sn-col { padding-right: 14px; padding-left: 14px; }
  .sn-pill { font-size: 0.64rem; }
}

/* ---- DESKTOP (>= 760px, the prototype's rule; Spotlight full-bleed model):
   NO card, NO extra scroller. The root already fills the window with the
   gradient and the DOCUMENT keeps scrolling; the column just widens to the
   prototype's desktop values. The photo keeps 20 / 23 (the crop stage)
   rather than the prototype's desktop 4 / 4.5 so the modal's framing always
   matches. ---- */
@media (min-width: 760px) {
  .sn-col {
    width: min(100%, 580px);
    padding: max(28px, env(safe-area-inset-top, 0px)) 18px calc(24px + env(safe-area-inset-bottom, 0px));
  }
  .sn-print { width: min(100%, 410px); }
  .sn-links,
  .sn-empty { width: min(100%, 410px); }
  .sn-cta { width: min(100%, 400px); }
}

/* ============================================================================
   Combined follower counter: themed pill (.ne-fpill, via the --fp-* vars set
   on .sn-col above, centered by --fp-margin) + an ALWAYS DARK breakdown
   sheet (.ne-fsheet-*). KEEP IN PARITY with NewEditor.css.
   ============================================================================ */
.ne-fpill { display: flex; align-items: baseline; justify-content: center; gap: 6px; width: fit-content; margin: var(--fp-margin, 14px auto 0); padding: var(--fp-pad, 8px 16px); background: var(--fp-bg, rgba(0,0,0,0.05)); border: var(--fp-border, 1px solid rgba(0,0,0,0.12)); border-radius: var(--fp-radius, 999px); color: var(--fp-text, inherit); font-family: inherit; line-height: 1; cursor: pointer; transition: border-color .15s, transform .12s, background .15s; }
.ne-fpill:hover { border-color: var(--fp-border-hover, rgba(0,0,0,0.28)); }
.ne-fpill:active { transform: scale(0.97); }
.ne-fpill-num { font-size: 16px; font-weight: 800; letter-spacing: -0.01em; }
.ne-fpill-label { font-size: 12.5px; color: var(--fp-muted, currentColor); opacity: .72; }
.ne-fsheet-overlay { position: fixed; inset: 0; z-index: 9000; display: flex; align-items: flex-end; background: rgba(0,0,0,0.5); -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px); }
.ne-fsheet { width: 100%; max-width: 520px; margin: 0 auto; max-height: 80%; overflow-y: auto; background: #161618; color: #f4f4f6; border-radius: 20px 20px 0 0; padding: 10px 18px calc(18px + env(safe-area-inset-bottom)); box-shadow: 0 -16px 44px rgba(0,0,0,0.5); animation: ne-fsheet-up .3s cubic-bezier(.22,.61,.36,1); }
@keyframes ne-fsheet-up { from { transform: translateY(100%); } to { transform: none; } }
.ne-fsheet-grab { width: 38px; height: 4px; border-radius: 999px; background: rgba(255,255,255,0.22); margin: 2px auto 14px; }
.ne-fsheet-total { text-align: center; font-size: 30px; font-weight: 800; letter-spacing: -0.02em; }
.ne-fsheet-sub { text-align: center; font-size: 12.5px; opacity: .6; margin-top: 2px; }
.ne-fsheet-list { display: flex; flex-direction: column; margin-top: 14px; }
.ne-fsheet-row { display: flex; align-items: center; gap: 12px; padding: 11px 2px; border-top: 1px solid rgba(255,255,255,0.08); }
.ne-fsheet-row:first-child { border-top: none; }
.ne-fsheet-ic { width: 28px; height: 28px; flex: none; display: grid; place-items: center; opacity: .85; }
.ne-fsheet-ic img { width: 24px; height: 24px; object-fit: contain; }
.ne-fsheet-name { flex: 1; min-width: 0; font-size: 14.5px; }
.ne-fsheet-count { font-size: 14.5px; font-weight: 700; }
.ne-fsheet-empty { opacity: .6; font-size: 13px; text-align: center; padding: 14px; }
.ne-fsheet-done { width: 100%; margin-top: 16px; min-height: 46px; border: none; border-radius: 12px; background: #ffffff; color: #111111; font-weight: 700; font-size: 14.5px; cursor: pointer; }

/* ---- Inline 18+ warning (adult-flagged LINK blocks) ----
   The client injects .sn-adult-inline INTO the flagged block itself and adds
   has-adult-warning to it, so the block becomes the positioning context and
   the overlay adopts its rounding via border-radius: inherit (fit-wave
   contract, ADULT_WARNING_FIT.md): it hugs the 999px CTA, the pills' organic
   corners and the square prints alike. Snap skin: PAPER, not canvas's dark
   glass: near-opaque paper + blur over the block, ink title, muted body,
   Cancel as a soft ink pill, the confirm as the accent pill with its 3D
   shadow. Tilt is a non-issue: the overlay lives INSIDE the tilted mini
   print so it rotates with it and reads like a note pinned on the paper.
   The JS measure pass adds is-compact / min-height grow for short hosts
   (the 60px CTA lands in the compact tier, which hides the title). All
   child elements are spans because the gated host may be a span. */
.has-adult-warning { position: relative; overflow: hidden; }
.sn-adult-inline {
  position: absolute; inset: 0; z-index: 8;
  display: flex; align-items: center; justify-content: center;
  min-height: 100%; padding: 10px;
  background: rgba(255, 250, 241, 0.98);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  color: var(--sn-ink, #2b2030); text-align: center; border-radius: inherit;
  font-family: var(--sn-body, 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif);
  font-weight: 500; line-height: 1.3; letter-spacing: 0; text-transform: none;
  cursor: default;
}
.sn-adult-inline-inner { display: flex; flex-direction: column; align-items: center; gap: 7px; width: 100%; max-width: 300px; }
.sn-adult-inline-title { display: block; color: var(--sn-ink, #2b2030); font-family: var(--sn-display, 'Fredoka', ui-rounded, 'Arial Rounded MT Bold', 'Trebuchet MS', Arial, sans-serif); font-size: 12px; font-weight: 800; line-height: 1.15; text-transform: uppercase; letter-spacing: 0.04em; }
.sn-adult-inline-body { display: block; color: var(--sn-muted, #766579); font-size: 11px; font-weight: 500; line-height: 1.28; }
.sn-adult-actions { display: flex; justify-content: center; gap: 8px; width: 100%; }
.sn-adult-btn {
  min-height: 28px; border: none; border-radius: 999px;
  padding: 4px 12px; cursor: pointer; font: inherit;
  font-family: var(--sn-display, 'Fredoka', ui-rounded, 'Arial Rounded MT Bold', 'Trebuchet MS', Arial, sans-serif);
  font-size: 11px; font-weight: 700; line-height: 1.15;
  transition: background var(--sn-quick, 120ms) ease, box-shadow var(--sn-quick, 120ms) ease, transform var(--sn-quick, 120ms) var(--sn-ease, ease);
}
/* Cancel: a soft ink pill (an ink wash + the ink hairline; a paper pill
   would vanish on the paper overlay) */
.sn-adult-btn.secondary {
  background: color-mix(in srgb, var(--sn-ink, #2b2030) 8%, transparent);
  color: var(--sn-ink, #2b2030);
  box-shadow: inset 0 0 0 1px var(--sn-line, rgba(43, 32, 48, 0.14));
}
.sn-adult-btn.secondary:hover { background: color-mix(in srgb, var(--sn-ink, #2b2030) 13%, transparent); }
/* Continue: the accent pill with the CTA's 3D pressed shadow (3px at this
   size), white ink by design (the owner-approved CTA look) */
.sn-adult-btn.primary {
  background: var(--sn-accent, #f45e91);
  color: #ffffff;
  box-shadow: 0 3px 0 var(--sn-accent-deep, #a4456a);
}
.sn-adult-btn.primary:hover { background: color-mix(in srgb, var(--sn-accent, #f45e91) 92%, #2b2030); }
.sn-adult-btn.primary:active { box-shadow: 0 1px 0 var(--sn-accent-deep, #a4456a); transform: translateY(2px); }
/* JS fit pass: is-compact lands ON the overlay for ANY host too short for
   the full variant (the 60px CTA); the title goes, the body may wrap and
   the buttons may stack */
.sn-adult-inline.is-compact { padding: 7px 10px; }
.sn-adult-inline.is-compact .sn-adult-inline-title { display: none; }
.sn-adult-inline.is-compact .sn-adult-inline-inner { gap: 5px; }
.sn-adult-inline.is-compact .sn-adult-inline-body { color: var(--sn-ink, #2b2030); white-space: normal; }
.sn-adult-inline.is-compact .sn-adult-actions { flex-wrap: wrap; }
.sn-adult-inline.is-compact .sn-adult-btn { min-height: 21px; padding: 4px 10px; font-size: 10px; }

/* A gated PILL grows to full width while its warning is open, so the fit
   walk has room and sibling pills reflow around it for the moment. Two
   forms on purpose: the client toggles has-gated on the .sn-item wrapper
   when it opens/closes the warning (every browser), and the :has() form
   covers a host that gained the class without the wrapper toggle. They are
   SEPARATE rules: an unsupported :has() in a selector list would drop the
   class form with it. The ~96px min-height gives the full variant (title,
   body, two buttons) room without the compact tier. */
.sn-item.is-pill.has-gated { flex: 0 0 100%; }
.sn-item.is-pill:has(.has-adult-warning) { flex: 0 0 100%; }
.sn-item.is-pill.has-gated .sn-pill,
.sn-pill.has-adult-warning { min-height: 96px; }

/* FB iOS press-and-hold 18+ confirm (FB_IOS_ADULT_PRESSHOLD.md): the primary
   confirm is a real anchor (long-press opens the native "Open in external
   browser" menu); tap is suppressed and pulses the hint line under the
   buttons. */
.sn-adult-btn.is-holdlink {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  text-decoration: none;
  text-align: center;
  -webkit-touch-callout: default;
}
.sn-adult-holdhint {
  display: block;
  width: 100%;
  margin-top: 6px;
  color: var(--sn-muted, #766579);
  font-size: 10px;
  font-weight: 500;
  line-height: 1.3;
  text-align: center;
}
.sn-adult-holdhint.is-pulsing { animation: bncy-holdpulse 0.6s ease; }
@keyframes bncy-holdpulse {
  0% { transform: scale(1); }
  35% { transform: scale(1.06); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .sn-adult-holdhint.is-pulsing { animation: none; }
}

/* ============================================================================
   18+ age gate: CENTERED popup over the whole page (owner-approved mockups,
   template-prototypes/social-18-gate). Markup is shared across all template
   clients (.bncy-sgate-*); this block skins it for THIS design: the DARK
   glass panel stays (it overlays the whole page, print and peach alike),
   with the Snap accent PILL (white ink, 3D pressed shadow) as the Yes
   button. Used for adult PLATFORM SOCIAL icons (adult-flagged link blocks
   use the inline .sn-adult-inline warning above instead). The vars carry
   literal fallbacks on purpose, so the skin holds wherever the client mounts
   the overlay (inside .sn-root per the contract, or on body).
   ========================================================================== */
.bncy-sgate-overlay {
  position: fixed; inset: 0; z-index: 9990;
  display: flex; align-items: center; justify-content: center; padding: 18px;
  background: rgba(7, 8, 10, 0.6);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.bncy-sgate {
  width: 300px; max-width: 94vw;
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  animation: bncy-sgate-in 0.18s ease;
  background: rgba(16, 17, 22, 0.88);
  -webkit-backdrop-filter: blur(18px) saturate(1.2); backdrop-filter: blur(18px) saturate(1.2);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 20px;
  box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.85);
  padding: 24px 20px 20px;
  text-align: center;
  color: #ffffff;
}
.bncy-sgate-title {
  color: #ffffff;
  font-family: 'Fredoka', ui-rounded, 'Arial Rounded MT Bold', 'Trebuchet MS', Arial, sans-serif;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
.bncy-sgate-body {
  margin-top: 8px;
  color: rgba(255, 255, 255, 0.72);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.5;
}
.bncy-sgate-btns { display: flex; gap: 9px; justify-content: center; margin-top: 16px; }
.bncy-sgate-btns button { flex: 1 1 0; }
.bncy-sgate-no {
  background: rgba(255, 255, 255, 0.09);
  color: rgba(255, 255, 255, 0.85);
  border: 1px solid rgba(255, 255, 255, 0.17);
  border-radius: 999px;
  min-height: 38px;
  padding: 8px 16px;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
}
.bncy-sgate-no:hover { border-color: rgba(255, 255, 255, 0.34); background: rgba(255, 255, 255, 0.15); }
.bncy-sgate-yes {
  background: var(--sn-accent, #f45e91);
  color: #ffffff;
  border: none;
  border-radius: 999px;
  min-height: 38px;
  padding: 8px 18px;
  box-shadow: 0 3px 0 var(--sn-accent-deep, #a4456a);
  font-family: 'Fredoka', ui-rounded, 'Arial Rounded MT Bold', 'Trebuchet MS', Arial, sans-serif;
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
  transition: background 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}
.bncy-sgate-yes:hover { background: color-mix(in srgb, var(--sn-accent, #f45e91) 92%, #2b2030); }
.bncy-sgate-yes:active { box-shadow: 0 1px 0 var(--sn-accent-deep, #a4456a); transform: translateY(2px); }
@keyframes bncy-sgate-in { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: none; } }
/* FB iOS press-and-hold: the Yes control renders as a real anchor + hint. */
a.bncy-sgate-yes { flex: 1 1 0; display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box; text-decoration: none; text-align: center; -webkit-touch-callout: default; }
.bncy-sgate-holdhint { display: block; margin-top: 10px; color: rgba(255, 255, 255, 0.7); font-size: 11px; font-weight: 500; line-height: 1.35; text-align: center; }
.bncy-sgate-holdhint.is-pulsing { animation: bncy-holdpulse 0.6s ease; }
@media (prefers-reduced-motion: reduce) { .bncy-sgate-holdhint.is-pulsing { animation: none; } }

/* ---- Reduced motion kill switch: every sn animation and transition (the
   print-in, the rise cascade, the socials/footer rises, the 120ms presses,
   the 280ms lifts), the hover/active transforms back to their resting
   rules, the per-link loops, and the overlays' pulses ---- */
@media (prefers-reduced-motion: reduce) {
  .sn-root *,
  .sn-root *::before,
  .sn-root *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .sn-root .sn-print:hover { transform: rotate(var(--sn-tilt)); }
  .sn-root .sn-feature:hover,
  .sn-root .sn-feature:active { transform: rotate(1deg); }
  .sn-root .sn-cta:hover,
  .sn-root .sn-cta:active,
  .sn-root .sn-pill:hover,
  .sn-root .sn-pill:active,
  .sn-root .sn-social:hover,
  .sn-root .sn-social:active,
  .sn-root .sn-adult-btn.primary:active,
  .bncy-sgate-yes:active { transform: none; }
  /* per-link animations (noir parity): loops off, glow keeps a static halo */
  .pc-anim-bounce, .pc-anim-pulse { animation: none !important; }
  .pc-anim-shine::before { display: none; }
  .pc-anim-glow { animation: none !important; box-shadow: 0 0 16px 2px color-mix(in srgb, var(--pc-glow-color, #e8c6c0) 55%, transparent); }
  /* overlays that may mount outside .sn-root (sibling parity) */
  .ne-fsheet { animation: none; }
  .bncy-sgate { animation: none; }
  .sn-adult-holdhint.is-pulsing,
  .bncy-sgate-holdhint.is-pulsing { animation: none; }
}
