/* ══════════════════════════════════════════════════════════════
   Dacha Party — implementation of "Dacha Party.dc.html"
   Design tokens come straight from the design's `vibe` /
   `loudness` / `scrapbook` props. Switch them on <html>:
     data-vibe="sunbaked-noon" | "golden-hour" | "night-pool"
     data-loud="quiet" | "playful" | "loud-poster"
     data-scrapbook="on" | "off"
   ══════════════════════════════════════════════════════════════ */

/* ── vibe: colour ─────────────────────────────────────────── */
:root,
[data-vibe="sunbaked-noon"] {
  --dp-bg: #fff6e9;      --dp-card: #fff6e9;   --dp-card2: #fff0d0;
  --dp-ink: #24303a;     --dp-muted: #5c6a75;  --dp-faint: #7b8a95;
  --dp-accent: #12b3cf;  --dp-accent-d: #0a90a8;
  --dp-accent2: #e2521a; --dp-accent2-d: #b0621a;
  --dp-sun: #ffd45e;     --dp-onsun: #7a3d00;  --dp-deep: #24303a;
  --dp-nav: rgba(255, 246, 233, 0.92);
  --dp-bar: linear-gradient(160deg, #12b3cf 0%, #0a90a8 100%);
  --dp-gift: linear-gradient(155deg, #ff8a3d 0%, #e2521a 100%);
  --dp-hero-scrim: linear-gradient(180deg, rgba(18,179,207,0.22) 0%, rgba(255,120,40,0.14) 45%, rgba(226,82,26,0.88) 100%);
}

[data-vibe="golden-hour"] {
  --dp-bg: #ffece0;      --dp-card: #fff4ea;   --dp-card2: #ffe2c8;
  --dp-ink: #3a2318;     --dp-muted: #7a5b4b;  --dp-faint: #a3897a;
  --dp-accent: #d94f6a;  --dp-accent-d: #ae3853;
  --dp-accent2: #e2521a; --dp-accent2-d: #8f3a10;
  --dp-sun: #ffc85c;     --dp-onsun: #5e2a00;  --dp-deep: #3a2318;
  --dp-nav: rgba(255, 240, 230, 0.92);
  --dp-bar: linear-gradient(160deg, #d94f6a 0%, #8a2f5c 100%);
  --dp-gift: linear-gradient(155deg, #ff9a4d 0%, #d2401f 100%);
  --dp-hero-scrim: linear-gradient(180deg, rgba(120,55,130,0.20) 0%, rgba(255,140,60,0.20) 45%, rgba(150,40,55,0.90) 100%);
}

[data-vibe="night-pool"] {
  --dp-bg: #0e1b26;      --dp-card: #16293b;   --dp-card2: #1d3550;
  --dp-ink: #eaf3f8;     --dp-muted: #a8c0cf;  --dp-faint: #7e97a6;
  --dp-accent: #2fd6e8;  --dp-accent-d: #17a9be;
  --dp-accent2: #ff8a4c; --dp-accent2-d: #ffb069;
  --dp-sun: #ffd45e;     --dp-onsun: #14222c;  --dp-deep: #091320;
  --dp-nav: rgba(14, 27, 38, 0.90);
  --dp-bar: linear-gradient(160deg, #0f7f96 0%, #093c53 100%);
  --dp-gift: linear-gradient(155deg, #ff8a4c 0%, #c9451c 100%);
  --dp-hero-scrim: linear-gradient(180deg, rgba(8,26,44,0.40) 0%, rgba(15,60,90,0.35) 45%, rgba(7,17,28,0.93) 100%);
}

/* ── loudness: scale ──────────────────────────────────────── */
:root,
[data-loud="playful"] {
  --dp-h1: 62px; --dp-script: 52px; --dp-h2-lg: 44px; --dp-h2: 36px;
  --dp-kick: 34px; --dp-cd: 30px;
  --dp-r-card: 28px; --dp-r-tile: 24px; --dp-r-med: 22px; --dp-r-sm: 18px;
  --dp-sh: 0 12px 30px rgba(36, 48, 58, 0.12);
  --dp-sh-t: 0 8px 20px rgba(36, 48, 58, 0.16);
}

[data-loud="quiet"] {
  --dp-h1: 46px; --dp-script: 38px; --dp-h2-lg: 34px; --dp-h2: 29px;
  --dp-kick: 26px; --dp-cd: 26px;
  --dp-r-card: 18px; --dp-r-tile: 16px; --dp-r-med: 14px; --dp-r-sm: 12px;
  --dp-sh: 0 5px 16px rgba(36, 48, 58, 0.08);
  --dp-sh-t: 0 4px 12px rgba(36, 48, 58, 0.10);
}

[data-loud="loud-poster"] {
  --dp-h1: 82px; --dp-script: 64px; --dp-h2-lg: 58px; --dp-h2: 46px;
  --dp-kick: 40px; --dp-cd: 38px;
  --dp-r-card: 36px; --dp-r-tile: 30px; --dp-r-med: 28px; --dp-r-sm: 22px;
  --dp-sh: 0 20px 48px rgba(36, 48, 58, 0.22);
  --dp-sh-t: 0 14px 32px rgba(36, 48, 58, 0.26);
}

/* ── scrapbook: tilted, bordered tiles ────────────────────── */
:root, [data-scrapbook="off"] { --dp-tilt: 0deg; --dp-tile-b: 0px; }
[data-scrapbook="on"]         { --dp-tilt: 1.8deg; --dp-tile-b: 7px; }

/* ══ base ═════════════════════════════════════════════════ */
*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  background: var(--dp-bg);
  /* Needed because the scattered snapshots hang past the page edge. But
     `overflow-x: hidden` turns the element into a scroll container, and that
     is what breaks `position: sticky` on the nav in some engines. `clip` cuts
     the overflow without creating one. */
  overflow-x: hidden;
}

@supports (overflow-x: clip) {
  html, body { overflow-x: clip; }
}

body {
  color: var(--dp-ink);
  font-family: Nunito, system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.6;
  -webkit-text-size-adjust: 100%;
}

p { margin: 0; }
/* ol as well as ul: the timeline is an <ol>, and the UA stylesheet was giving
   it 40px of indent and a stray bottom margin that no other block had. */
ul, ol { margin: 0; padding: 0; list-style: none; }
a { color: var(--dp-accent2); }
a:hover { color: var(--dp-accent2-d); }
::selection { background: var(--dp-sun); color: var(--dp-onsun); }

img { display: block; max-width: 100%; }

:focus-visible {
  outline: 3px solid var(--dp-sun);
  outline-offset: 3px;
}

.page {
  --snap-scale: 1;
  max-width: 560px;
  margin: 0 auto;
  padding: 0 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* ══ nav ══════════════════════════════════════════════════ */
.nav {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 18px;
  margin: 10px 0 0;
  border-radius: 999px;
  background: var(--dp-nav);
  backdrop-filter: blur(8px);
  box-shadow: 0 8px 22px rgba(36, 48, 58, 0.14);
}

.nav__brand {
  font-family: Caveat, cursive;
  font-size: 26px;
  font-weight: 700;
  color: var(--dp-accent2);
  white-space: nowrap;
}

.nav__date {
  font-family: Rubik, sans-serif;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 0.04em;
  padding: 8px 16px;
  border-radius: 999px;
  background: var(--dp-accent);
  color: #fff;
  white-space: nowrap;
}

/* ══ image slots ══════════════════════════════════════════ */
/* An <img> that fills its frame. If the file is missing, JS drops the
   img and the wrapper shows its `data-ph` caption instead — same
   empty-state role the design's <image-slot> plays. */
.slot {
  position: absolute;
  inset: 0;
  background: var(--dp-card2);
  overflow: hidden;
}

.slot__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.slot::after {
  content: attr(data-ph);
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 12px;
  text-align: center;
  font-size: 13px;
  line-height: 1.35;
  color: var(--dp-faint);
  background: repeating-linear-gradient(45deg,
    transparent 0 10px, rgba(123, 138, 149, 0.10) 10px 20px);
}
.slot--empty::after { display: flex; }

/* ══ scattered snapshots ══════════════════════════════════
   Loose photos pinned to the corners of a card and tilted, each
   hanging past the card edge rather than sitting in a grid.
   Per-instance geometry comes in as custom properties:
     --w --h   size    --x   how far past the edge (negative = out)
     --y       offset from the card's top (or bottom)  --rot  tilt
   Pair .snap--l / .snap--r with .snap--bottom as needed. */
.snap {
  position: absolute;
  z-index: 5;
  display: none;
  margin: 0;
  width: calc(var(--w, 140px) * var(--snap-scale, 1));
  height: calc(var(--h, 180px) * var(--snap-scale, 1));
  top: var(--y, -24px);
  padding: 6px 6px 6px;
  background: #fffdf8;
  border-radius: 3px;
  box-shadow: 0 12px 26px rgba(36, 48, 58, 0.30);
  transform: rotate(var(--rot, 0deg));
}
.snap.is-ready { display: block; }
.snap--l { left: var(--x, -28px); }
.snap--r { right: var(--x, -28px); }
.snap--bottom { top: auto; bottom: var(--y, -24px); }
.snap img { width: 100%; height: 100%; object-fit: cover; border-radius: 1px; }

/* A snapshot always straddles the heading, never the body copy: headings
   narrow gracefully, paragraphs do not. The heading gives up the width the
   photo needs; everything below it runs the full column. */
.clear-r { padding-right: var(--snap-gutter, 124px); }
.clear-l { padding-left: var(--snap-gutter, 124px); }

/* ══ hero ═════════════════════════════════════════════════ */
.hero {
  position: relative;
  height: 620px;
  /* Chrome on Android freezes `vh` to the toolbar-hidden viewport, so this
     guard resolves once and never moves. Firefox and Samsung Internet keep
     `vh` tied to the *live* viewport instead: as the address bar slides away,
     86vh changes, the hero resizes, and because the countdown is pulled up
     onto it with a negative margin, the whole top of the page jumps. On a
     ~720px-tall viewport 86vh lands right on 620px, so it flickers across the
     threshold. `svh` is the small-viewport unit — static in every engine that
     has it; anything older keeps the old behaviour via the vh line above. */
  max-height: 86vh;
  max-height: 86svh;
  min-height: 480px;
  flex: none;
  border-radius: var(--dp-r-card);
  overflow: hidden;
  box-shadow: 0 14px 34px rgba(36, 48, 58, 0.18);
}

.hero__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: var(--dp-hero-scrim);
}

.hero__copy {
  /* Width the headline actually gets: the page caps at 560, minus its own
     24px of padding and the 44px this block adds. The old cap was a share of
     100vw, which ignored those 68px — so "СВАДЕБНАЯ", a word that cannot
     break, ran 52px past the edge on a 412px phone and got sliced off by the
     hero's overflow:hidden. Dividing by the word's own width in ems makes it
     fit by construction at any width. */
  --fit: calc(min(100vw, 560px) - 68px);
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  /* 44 rather than 32: the countdown eats the hero's bottom 30px, and the
     calendar button sits lower than the date line it shares a row with. */
  padding: 0 22px 44px;
  pointer-events: none;
}

.hero__kicker {
  display: inline-block;
  padding: 7px 16px;
  margin-bottom: 14px;
  border-radius: 999px;
  background: var(--dp-sun);
  color: var(--dp-onsun);
  font-family: Rubik, sans-serif;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.hero__title {
  margin: 0;
  font-family: Rubik, sans-serif;
  font-weight: 900;
  /* "СВАДЕБНАЯ" measures 6.4em; 6.7 leaves room for font-version differences */
  font-size: min(var(--dp-h1), calc(var(--fit) / 6.7));
  line-height: 0.92;
  letter-spacing: -0.03em;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 6px 24px rgba(120, 40, 0, 0.45);
}

.hero__script {
  margin: -4px 0 14px;
  font-family: Caveat, cursive;
  font-weight: 700;
  /* "нетакусиков" measures 4.48em */
  font-size: min(var(--dp-script), calc(var(--fit) / 4.7));
  line-height: 1;
  color: var(--dp-sun);
  text-shadow: 0 4px 18px rgba(120, 40, 0, 0.35);
}

.hero__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px 14px;
  flex-wrap: wrap;
}

.hero__date {
  font-family: Rubik, sans-serif;
  font-weight: 700;
  font-size: 20px;
  color: #fff;
}

/* .hero__copy is click-through so the photo underneath stays reachable;
   the one interactive thing in it has to opt back in. */
.hero__cal {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 17px;
  border-radius: 999px;
  background: #fff;
  color: var(--dp-ink);
  font-family: Rubik, sans-serif;
  font-weight: 700;
  font-size: 14px;
  text-decoration: none;
  white-space: nowrap;
  box-shadow: 0 8px 20px rgba(36, 48, 58, 0.28);
  transition: background 0.2s ease, color 0.2s ease;
}
.hero__cal:hover { background: var(--dp-sun); color: var(--dp-onsun); }

.hero__cal svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}

/* ══ countdown ════════════════════════════════════════════ */
.countdown {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin-top: -44px;
  padding: 0 6px;
  position: relative;
  z-index: 10;
}

.cd {
  background: #fff;
  border-radius: var(--dp-r-sm);
  padding: 14px 4px;
  text-align: center;
  box-shadow: 0 10px 24px rgba(36, 48, 58, 0.14);
}

.cd__n {
  display: block;
  font-family: Rubik, sans-serif;
  font-weight: 900;
  font-size: var(--dp-cd);
  line-height: 1;
  color: var(--dp-accent);
  font-variant-numeric: tabular-nums;
}

.cd__l {
  display: block;
  margin-top: 4px;
  font-size: 11px;
  font-weight: 700;
  color: #7b8a95;
}

/* ══ cards ════════════════════════════════════════════════ */
.card {
  position: relative;
  background: var(--dp-card);
  border-radius: var(--dp-r-card);
  padding: 30px 22px;
  box-shadow: var(--dp-sh);
}

.card--flush { padding: 28px 0 30px; overflow: hidden; }
.card__head { padding: 0 22px; }

.kicker {
  margin: 0;
  font-family: Caveat, cursive;
  font-weight: 700;
  font-size: var(--dp-kick);
  line-height: 1;
  color: var(--dp-accent2);
}
.kicker--sun { color: var(--dp-sun); }
.kicker--lg { font-size: var(--dp-h2); }
/* On cards with no big heading, the handwritten line carries the title on its
   own and takes over the spacing the .h2 used to provide. */
.kicker--solo { margin-bottom: 15px; }

.h2 {
  margin: 2px 0 12px;
  font-family: Rubik, sans-serif;
  font-weight: 900;
  font-size: var(--dp-h2);
  line-height: 1;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}
.h2--onbar { color: #fff; }
.h2--lg {
  margin: 4px 0 14px;
  font-size: var(--dp-h2-lg);
  line-height: 0.95;
  letter-spacing: -0.03em;
}

.lead { font-size: 22px; line-height: 1.4; font-weight: 700; }
.muted { color: var(--dp-muted); }
.lead + .muted { margin-top: 14px; }
.card > p + p { margin-top: 13px; }
.hint { font-size: 14px; color: var(--dp-faint); }
.card__head .h2 { margin-bottom: 6px; }
.card__head .hint { margin-bottom: 18px; }
.card__head .muted { margin-bottom: 8px; }

/* ══ rails ════════════════════════════════════════════════ */
.rail {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding: 0 22px 6px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.rail::-webkit-scrollbar { display: none; }

.tile {
  position: relative;
  flex: none;
  width: 258px;
  height: 336px;
  border-radius: var(--dp-r-tile);
  overflow: hidden;
  scroll-snap-align: center;
  box-shadow: var(--dp-sh-t);
  border: var(--dp-tile-b) solid var(--dp-card);
  transition: transform 0.3s ease;
}
.tile--gal { height: 320px; }

/* Video tiles carry native controls and preload="none": nothing at all is
   fetched until someone presses play. preload="metadata" was the obvious
   choice, but it only stays cheap when the host answers Range requests — and
   when it does not, every visitor silently pulls all five files. The drawn
   poster is a data URI, so the tile still looks deliberate at zero cost. */
.tile--video { background: #14222c; }
.tile--video video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.rail > .tile:nth-child(odd)  { transform: rotate(var(--dp-tilt)); }
.rail > .tile:nth-child(even) { transform: rotate(calc(-1 * var(--dp-tilt))); }

/* ══ dress code ═══════════════════════════════════════════ */
.card .muted + .chips { margin-top: 18px; }

.chips { display: flex; flex-wrap: wrap; gap: 9px; }

.chip {
  padding: 9px 18px;
  border-radius: 999px;
  background: var(--dp-sun);
  color: var(--dp-onsun);
  font-family: Rubik, sans-serif;
  font-weight: 700;
  font-size: 14px;
}
.chip--accent { background: var(--dp-accent); color: #fff; }

/* ══ почему это не свадьба ════════════════════════════════ */
.beats { display: grid; gap: 12px; margin-top: 4px; }

.beats li {
  display: grid;
  grid-template-columns: 22px 1fr;
  gap: 10px;
  align-items: baseline;
  font-size: 19px;
  line-height: 1.35;
}

.beats li::before {
  content: ">";
  font-family: Rubik, sans-serif;
  font-weight: 900;
  font-size: 22px;
  color: var(--dp-accent);
  line-height: 1;
}

.beats li:last-child {
  font-weight: 700;
  color: var(--dp-accent2);
}

/* ══ коротко для зумеров ══════════════════════════════════ */
.facts { margin: 4px 0 0; display: grid; gap: 0; }

.facts__row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 12px;
  align-items: baseline;
  padding: 11px 0;
  border-bottom: 2px dotted color-mix(in srgb, var(--dp-faint) 45%, transparent);
}
.facts__row:last-child { border-bottom: 0; }

.facts dt {
  font-family: Rubik, sans-serif;
  font-weight: 700;
  font-size: 16px;
  color: var(--dp-muted);
}

.facts dd {
  margin: 0;
  font-family: Rubik, sans-serif;
  font-weight: 700;
  font-size: 17px;
  text-align: right;
}
.facts dd.yes { color: var(--dp-accent); }
.facts dd.no { color: var(--dp-accent2); }


/* ══ расписание ═══════════════════════════════════════════ */
.days { display: grid; gap: 22px; margin-top: 6px; }

.days .day {
  position: relative;
  padding-left: 22px;
  display: grid;
  gap: 8px;
}

.days .day::before {
  content: "";
  position: absolute;
  left: 0;
  top: 9px;
  bottom: 2px;
  width: 4px;
  border-radius: 999px;
  background: var(--dp-sun);
}

.day__t {
  font-family: Rubik, sans-serif;
  font-weight: 900;
  font-size: 17px;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  color: var(--dp-accent2);
}

.day__note {
  padding: 10px 14px;
  border-radius: var(--dp-r-sm);
  background: var(--dp-card2);
  font-size: 15px;
  font-weight: 700;
}

/* ══ что взять с собой ════════════════════════════════════ */
/* Multi-column, not a two-column grid. A grid aligns rows across both
   columns, so a two-line item ("Гигиенические принадлежности") left a hole
   beside its one-line neighbour. Columns just flow. */
.pack {
  margin-top: 16px;
  column-gap: 18px;
}

.pack li {
  display: flex;
  gap: 11px;
  align-items: baseline;
  margin-bottom: 9px;
  break-inside: avoid;
}

.pack li::before {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--dp-accent2);
}

@media (min-width: 400px) { .pack { columns: 2; } }

/* Still on the list, just not announcing itself. */
.pack li.ghost { opacity: 0.01; }
.pack li.ghost::before { background: transparent; }

.aside {
  margin-top: 18px;
  font-family: Caveat, cursive;
  font-size: 24px;
  line-height: 1.25;
  color: var(--dp-muted);
}
.card--gift .aside, .card--bar .aside { color: rgba(255, 255, 255, 0.9); }

/* ══ where ════════════════════════════════════════════════ */
.address {
  margin-bottom: 6px;
  font-family: Rubik, sans-serif;
  font-weight: 900;
  font-size: 19px;
  line-height: 1.25;
}

.map {
  margin-top: 18px;
  border-radius: var(--dp-r-med);
  overflow: hidden;
  background: #e8e2d6;
  box-shadow: 0 8px 20px rgba(36, 48, 58, 0.14);
}
.map iframe { display: block; border: 0; width: 100%; height: 300px; }

.btn {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 15px 20px;
  border-radius: 999px;
  font-family: Rubik, sans-serif;
  font-weight: 700;
  font-size: 15px;
  text-decoration: none;
  transition: background 0.2s ease;
}
.btn--accent { margin-top: 14px; background: var(--dp-accent); color: #fff; }
.btn--accent:hover { background: var(--dp-accent-d); color: #fff; }

/* ══ gifts ════════════════════════════════════════════════ */
.card--gift { background: var(--dp-gift); color: #fff; padding: 40px 22px; }
.gift__body {
  font-size: 18px;
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.92);
  white-space: pre-line;
}

/* ══ footer ═══════════════════════════════════════════════ */
.card--footer {
  background: var(--dp-deep);
  color: #fff;
  padding: 36px 22px 40px;
  text-align: center;
}

.footer__chat {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  padding: 16px 28px;
  border-radius: 999px;
  background: var(--dp-accent);
  color: #fff;
  font-family: Rubik, sans-serif;
  font-weight: 700;
  font-size: 17px;
  text-decoration: none;
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.3);
  transition: background 0.2s ease, color 0.2s ease;
}
.footer__chat:hover { background: var(--dp-sun); color: var(--dp-onsun); }

.footer__chat svg { width: 22px; height: 22px; fill: currentColor; }

.footer__meta { margin-top: 20px; font-size: 13px; color: rgba(255, 255, 255, 0.45); }

/* ══ narrow phones ════════════════════════════════════════
   The design is drawn at 560px. Below ~420px the poster type
   would overflow, so the display sizes step down. */
/* Below ~430px the date and the calendar button no longer fit on one line, so
   the button drops to its own row — straight into the countdown, which overlaps
   the hero by 30px. Give the copy block back the room it needs. */
@media (max-width: 440px) {
  .hero__copy { padding-bottom: 56px; }
}

@media (max-width: 420px) {
  /* .hero__title and .hero__script size themselves from --fit at every width
     now, so they are not repeated here. */
  .kicker       { font-size: min(var(--dp-kick), 8.5vw); }
  .h2           { font-size: min(var(--dp-h2), 9vw); }
  .h2--lg       { font-size: min(var(--dp-h2-lg), 11.5vw); }
  .kicker--lg   { font-size: min(var(--dp-h2), 9vw); }
  .tile { width: 78vw; }
  .cd__l { font-size: 10px; }
}

/* The scattered snapshots shrink rather than being repositioned, so the
   per-instance tilt and bleed survive on a phone. The bleed itself is
   pulled in, because past the card edge there is screen edge rather than
   margin, and anything beyond it is cropped away for good. */
@media (max-width: 480px) {
  .page { --snap-scale: 0.72; --snap-gutter: 100px; }
  .snap--l { left: calc(var(--x, -28px) * 0.45); }
  .snap--r { right: calc(var(--x, -28px) * 0.45); }
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
}
