/* ============================================================================
   WILL YOU BE MY GROOMSMAN — charcoal, gold foil & a sliver of blush

   The companion to bridesmaid-fh. That one is a LIGHT ground; this one is the
   opposite, taken from the final frame of the card film: charcoal that is
   almost black but warm rather than blue, gold foil lettering, a damask
   pressed into the paper, and the blush envelope lining just visible at the
   top. That blush is the same blush as the bridesmaid piece and is the detail
   that makes the two read as one wedding — it is used in slivers and never as
   a field.

   Two consequences of the dark ground run through this file:

     1. The foil gradient is the LUMINOUS dark-ground variant (#D6B166 →
        #FFF6DC → #D6B166). On blush a near-white highlight makes the letters
        vanish mid-sweep; on charcoal it is the shine, and a deep-bronze
        gradient would instead go muddy. The two files therefore carry
        deliberately different gold, and neither should be copied into the other.
     2. Body copy is a warm ivory, never pure white — white on charcoal glares
        and loses the paper feeling entirely.
   ========================================================================== */

:root{
  /* charcoal — warm, never blue-black */
  --char-950:#0C0A09;
  --char-900:#131010;
  --char-850:#191514;
  --char-800:#1F1A18;
  --char-700:#272120;
  --char-600:#332B28;

  /* gold — DARK-ground variant, luminous end to end */
  --gold:#C9A24B;
  --gold-hi:#FFF6DC;
  --gold-mid:#D6B166;
  --gold-deep:#B98F3C;
  --gold-line:rgba(201,162,75,.30);
  --gold-line-soft:rgba(201,162,75,.14);

  /* blush — the envelope lining. Used in slivers only. */
  --blush:#E5B7A9;
  --blush-deep:#D89C8D;
  --blush-line:rgba(229,183,169,.30);

  /* ink — warm ivory, never white */
  --ivory:#F3EADF;
  --ivory-strong:#FBF5EC;
  --ivory-soft:rgba(243,234,223,.80);
  --ivory-mute:rgba(243,234,223,.56);
  --ivory-faint:rgba(243,234,223,.28);

  --ease:cubic-bezier(.22,1,.36,1);
  --serif:'Cormorant Garamond',Georgia,serif;
  --script:'Pinyon Script',cursive;
  --sans:'Jost',-apple-system,'Segoe UI',sans-serif;

  --maxw:560px;
  --maxw-wide:660px;

  /* keep in step with films.dissolveMs in js/config.js */
  --dissolve:1200ms;

  /* A damask, drawn twice — a light copy offset up-left and a dark copy
     offset down-right — so it reads as pressed INTO the paper rather than
     printed on it, which is what the card in the film actually does.
     The motif is an ogee lattice (the continuous diamond frame that tiles
     edge to edge) with a palmette hung inside it and scroll curls at the
     nodes. A closed single motif tiles as a field of recognisable shapes;
     the lattice is what makes it read as texture instead. Two data-URIs,
     under 2 KB each, no image request.
     Kept very faint: on a near-black ground a damask you can identify is
     too loud — it should be felt, not read. */
  --damask-light:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27180%27%20height%3D%27180%27%20viewBox%3D%270%200%20180%20180%27%3E%3Cg%20fill%3D%27none%27%20stroke%3D%27%23ffffff%27%20stroke-width%3D%271.5%27%20stroke-linecap%3D%27round%27%3E%3Cpath%20d%3D%27M0%2090%20C%2022%2052%2C%2056%2030%2C%2090%200%27%2F%3E%3Cpath%20d%3D%27M90%200%20C%20124%2030%2C%20158%2052%2C%20180%2090%27%2F%3E%3Cpath%20d%3D%27M0%2090%20C%2022%20128%2C%2056%20150%2C%2090%20180%27%2F%3E%3Cpath%20d%3D%27M90%20180%20C%20124%20150%2C%20158%20128%2C%20180%2090%27%2F%3E%3Cpath%20d%3D%27M90%2062%20C%20100%2074%2C%20109%2082%2C%20109%2093%20C%20109%20105%2C%20100%20113%2C%2090%20124%20C%2080%20113%2C%2071%20105%2C%2071%2093%20C%2071%2082%2C%2080%2074%2C%2090%2062%27%2F%3E%3Cpath%20d%3D%27M90%2077%20C%2095%2084%2C%20100%2088%2C%20100%2094%20C%20100%20100%2C%2095%20104%2C%2090%20110%20C%2085%20104%2C%2080%20100%2C%2080%2094%20C%2080%2088%2C%2085%2084%2C%2090%2077%27%2F%3E%3Cpath%20d%3D%27M90%2062%20C%2094%2053%2C%20101%2048%2C%20109%2045%27%2F%3E%3Cpath%20d%3D%27M90%2062%20C%2086%2053%2C%2079%2048%2C%2071%2045%27%2F%3E%3Cpath%20d%3D%27M90%20124%20C%2095%20134%2C%20102%20139%2C%20111%20142%27%2F%3E%3Cpath%20d%3D%27M90%20124%20C%2085%20134%2C%2078%20139%2C%2069%20142%27%2F%3E%3Cpath%20d%3D%27M82%208%20C%2086%2015%2C%2094%2015%2C%2098%208%27%2F%3E%3Cpath%20d%3D%27M82%20172%20C%2086%20165%2C%2094%20165%2C%2098%20172%27%2F%3E%3Cpath%20d%3D%27M8%2082%20C%2015%2086%2C%2015%2094%2C%208%2098%27%2F%3E%3Cpath%20d%3D%27M172%2082%20C%20165%2086%2C%20165%2094%2C%20172%2098%27%2F%3E%3Cpath%20d%3D%27M36%2040%20C%2044%2044%2C%2048%2051%2C%2047%2059%27%2F%3E%3Cpath%20d%3D%27M144%2040%20C%20136%2044%2C%20132%2051%2C%20133%2059%27%2F%3E%3Cpath%20d%3D%27M36%20140%20C%2044%20136%2C%2048%20129%2C%2047%20121%27%2F%3E%3Cpath%20d%3D%27M144%20140%20C%20136%20136%2C%20132%20129%2C%20133%20121%27%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
  --damask-dark:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27180%27%20height%3D%27180%27%20viewBox%3D%270%200%20180%20180%27%3E%3Cg%20fill%3D%27none%27%20stroke%3D%27%23000000%27%20stroke-width%3D%271.5%27%20stroke-linecap%3D%27round%27%3E%3Cpath%20d%3D%27M0%2090%20C%2022%2052%2C%2056%2030%2C%2090%200%27%2F%3E%3Cpath%20d%3D%27M90%200%20C%20124%2030%2C%20158%2052%2C%20180%2090%27%2F%3E%3Cpath%20d%3D%27M0%2090%20C%2022%20128%2C%2056%20150%2C%2090%20180%27%2F%3E%3Cpath%20d%3D%27M90%20180%20C%20124%20150%2C%20158%20128%2C%20180%2090%27%2F%3E%3Cpath%20d%3D%27M90%2062%20C%20100%2074%2C%20109%2082%2C%20109%2093%20C%20109%20105%2C%20100%20113%2C%2090%20124%20C%2080%20113%2C%2071%20105%2C%2071%2093%20C%2071%2082%2C%2080%2074%2C%2090%2062%27%2F%3E%3Cpath%20d%3D%27M90%2077%20C%2095%2084%2C%20100%2088%2C%20100%2094%20C%20100%20100%2C%2095%20104%2C%2090%20110%20C%2085%20104%2C%2080%20100%2C%2080%2094%20C%2080%2088%2C%2085%2084%2C%2090%2077%27%2F%3E%3Cpath%20d%3D%27M90%2062%20C%2094%2053%2C%20101%2048%2C%20109%2045%27%2F%3E%3Cpath%20d%3D%27M90%2062%20C%2086%2053%2C%2079%2048%2C%2071%2045%27%2F%3E%3Cpath%20d%3D%27M90%20124%20C%2095%20134%2C%20102%20139%2C%20111%20142%27%2F%3E%3Cpath%20d%3D%27M90%20124%20C%2085%20134%2C%2078%20139%2C%2069%20142%27%2F%3E%3Cpath%20d%3D%27M82%208%20C%2086%2015%2C%2094%2015%2C%2098%208%27%2F%3E%3Cpath%20d%3D%27M82%20172%20C%2086%20165%2C%2094%20165%2C%2098%20172%27%2F%3E%3Cpath%20d%3D%27M8%2082%20C%2015%2086%2C%2015%2094%2C%208%2098%27%2F%3E%3Cpath%20d%3D%27M172%2082%20C%20165%2086%2C%20165%2094%2C%20172%2098%27%2F%3E%3Cpath%20d%3D%27M36%2040%20C%2044%2044%2C%2048%2051%2C%2047%2059%27%2F%3E%3Cpath%20d%3D%27M144%2040%20C%20136%2044%2C%20132%2051%2C%20133%2059%27%2F%3E%3Cpath%20d%3D%27M36%20140%20C%2044%20136%2C%2048%20129%2C%2047%20121%27%2F%3E%3Cpath%20d%3D%27M144%20140%20C%20136%20136%2C%20132%20129%2C%20133%20121%27%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
}

*,*::before,*::after{ box-sizing:border-box }

/* The `hidden` attribute is applied by the UA stylesheet as `display:none`,
   which ANY author `display` declaration silently overrides. Several things
   here are flex/grid containers that are ALSO toggled with `hidden` — the
   caught-you panel, the accepted panel, the banking card, the sizes
   confirmation, the scroll hint. Without this rule they stay in the layout,
   and a full-bleed one sits invisibly over the page swallowing every click,
   "Tap To Open" included. This has to beat all of them. */
[hidden]{ display:none !important }

html,body{ margin:0; padding:0 }
html{ -webkit-text-size-adjust:100%; scroll-behavior:auto }

body{
  background:var(--char-900);
  color:var(--ivory);
  font-family:var(--serif);
  font-weight:300;
  line-height:1.6;
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
}
img{ max-width:100%; display:block }
button{ font:inherit; color:inherit; cursor:pointer; border:0; background:none }
a{ color:var(--gold-mid); text-decoration:none }

html.intro-lock, html.intro-lock body{
  overflow:hidden !important; height:100%;
  touch-action:none; overscroll-behavior:none;
}

::selection{ background:rgba(201,162,75,.30); color:var(--ivory-strong) }

/* ── type primitives ─────────────────────────────────────────────────────── */
.eyebrow{
  font-family:var(--sans); font-weight:200;
  font-size:clamp(.6rem,2.4vw,.68rem);
  letter-spacing:.42em; text-indent:.42em; text-transform:uppercase;
  color:var(--gold-mid); margin:0;
}
.micro{
  font-family:var(--sans); font-weight:200;
  font-size:clamp(.6rem,2.3vw,.66rem);
  letter-spacing:.24em; text-indent:.24em; text-transform:uppercase;
  color:var(--ivory-mute); margin:0;
}
.body{
  font-size:clamp(.98rem,3.7vw,1.06rem); line-height:1.8;
  color:var(--ivory-soft); margin:0; font-weight:300; max-width:46ch;
}
.lede{
  font-size:clamp(1.05rem,4.2vw,1.2rem); line-height:1.72;
  color:var(--ivory-soft); font-style:italic; margin:0; max-width:34ch;
}

.script{
  font-family:var(--script); font-weight:400;
  font-size:clamp(2.4rem,10.5vw,3.4rem);
  /* Script faces draw ink OUTSIDE their line box, and background-clip:text
     only paints inside it — any overshoot renders transparent, which looks
     like the letters have been sliced. Room on all four sides, and never a
     tight line-height. */
  line-height:1.2;
  padding:.18em .12em .2em;
  margin:0;
}
.script.xl{ font-size:clamp(2.9rem,12.5vw,4.4rem) }

/* Foil for DARK grounds. It stays luminous end to end, so the sweep varies
   WARMTH rather than brightness and contrast never drops.
   No `filter` on foil text: a filter forces a composited layer that Chrome
   rasterises once and rescales, and type painted through background-clip then
   goes permanently soft. */
.foil{
  background-image:linear-gradient(100deg,
    #B98F3C 0%, #D6B166 14%, #EFD79E 30%,
    #FFF6DC 46%, #EFD79E 62%, #D0A957 80%, #B98F3C 100%);
  background-size:260% 100%;
  -webkit-background-clip:text; background-clip:text;
  -webkit-text-fill-color:transparent; color:transparent;
  animation:foilSweep 11s ease-in-out infinite;
  text-rendering:geometricPrecision;
}
@keyframes foilSweep{
  0%,100%{ background-position:0% 50% }
  50%    { background-position:100% 50% }
}

/* The FH monogram, painted through the artwork's alpha channel so it picks up
   the same living foil sweep as the headings. `../assets/…` is correct: a
   relative url() in CSS resolves against the STYLESHEET's location, not the
   document's. */
.foil-mask{
  display:block;
  background-image:linear-gradient(100deg,
    #B98F3C 0%, #D6B166 14%, #EFD79E 30%,
    #FFF6DC 46%, #EFD79E 62%, #D0A957 80%, #B98F3C 100%);
  background-size:260% 100%;
  animation:foilSweep 11s ease-in-out infinite;
  -webkit-mask-image:url("../assets/monogram.png"); mask-image:url("../assets/monogram.png");
  -webkit-mask-size:contain;   mask-size:contain;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-position:center;  mask-position:center;
}
@supports not ((-webkit-mask-image:url("")) or (mask-image:url(""))){
  .foil-mask{
    background-image:url("../assets/monogram-gold.png");
    background-size:contain; background-repeat:no-repeat; background-position:center;
    animation:none;
  }
}

.rule{
  display:block; width:min(230px,62%); height:1px; position:relative;
  background:linear-gradient(90deg,transparent,var(--gold-line),transparent);
  margin:.25rem 0 .35rem;
}
.rule::after{
  content:""; position:absolute; left:50%; top:50%;
  width:5px; height:5px; transform:translate(-50%,-50%) rotate(45deg);
  background:var(--gold); box-shadow:0 0 8px rgba(201,162,75,.6);
}

/* the small flourish under the hero question — the same lozenge-and-rule
   device the card film uses above and below the question */
.orn{ display:block; width:170px; height:10px; position:relative }
.orn::before,.orn::after{
  content:""; position:absolute; top:50%; width:68px; height:1px;
  background:linear-gradient(90deg,transparent,rgba(214,177,102,.85));
}
.orn::before{ left:0 }
.orn::after{ right:0; transform:scaleX(-1) }
.orn i{
  position:absolute; left:50%; top:50%; width:6px; height:6px;
  transform:translate(-50%,-50%) rotate(45deg);
  background:var(--gold-mid); box-shadow:0 0 9px rgba(201,162,75,.55);
}

/* ── stages ──────────────────────────────────────────────────────────────── */
/* Every ground here is a CSS gradient painted on the section itself, and a
   gradient always fills its own box exactly — so sections may hug their
   content without the background stopping short. Nothing on this page uses a
   photograph as a section background, which is what would force 100svh. */
.stage{
  position:relative; width:100%;
  min-height:60svh;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  text-align:center; overflow:hidden;
  padding:clamp(3.6rem,10vh,5.4rem) clamp(1.4rem,6vw,4rem);
}
.stage>.inner{
  max-width:var(--maxw); width:100%; position:relative; z-index:2;
  display:flex; flex-direction:column; align-items:center;
  gap:clamp(.55rem,1.6vh,.9rem);
}
.stage>.inner.wide{ max-width:var(--maxw-wide) }

.bg-deep{
  background:
    radial-gradient(92% 60% at 50% 0%,   rgba(214,177,102,.055) 0%, rgba(214,177,102,0) 62%),
    radial-gradient(120% 78% at 14% 100%, rgba(216,156,141,.055) 0%, rgba(216,156,141,0) 58%),
    linear-gradient(180deg,#171514 0%,#121010 54%,#0E0D0C 100%);
}
.bg-mid{
  background:
    radial-gradient(96% 58% at 50% 2%,   rgba(255,246,220,.06) 0%, rgba(255,246,220,0) 60%),
    radial-gradient(120% 80% at 86% 100%, rgba(201,162,75,.07) 0%, rgba(201,162,75,0) 58%),
    linear-gradient(180deg,#242120 0%,#1C1A19 54%,#171514 100%);
}

/* Damask pressed into the paper. On a dark ground the light copy does almost
   all the work; the dark copy only deepens the shadow side of each stroke. */
.stage::before,.hero-damask{
  content:""; position:absolute; inset:0; z-index:0; pointer-events:none;
  background-image:var(--damask-light),var(--damask-dark);
  background-position:1px 1px, -1px -1px;
  background-size:180px 180px, 180px 180px;
  opacity:.038;
}
/* feathered seam so neighbouring grounds melt instead of banding */
.stage::after{
  content:""; position:absolute; left:0; right:0; bottom:0;
  height:clamp(48px,9vh,100px); z-index:0; pointer-events:none;
  background:linear-gradient(180deg,rgba(8,6,5,0),rgba(8,6,5,.55));
}

/* The blush envelope lining, just visible at the top edge — the detail that
   ties this to the bridesmaid piece. A sliver, never a field. */
.hero-lining{
  position:absolute; left:0; right:0; top:0; z-index:1; pointer-events:none;
  height:clamp(96px,17vh,168px);
  background:linear-gradient(180deg,
    rgba(216,156,141,.52) 0%,
    rgba(216,156,141,.20) 22%,
    rgba(216,156,141,.05) 58%,
    rgba(216,156,141,0) 100%);
}
.hero-lining::before{
  content:""; position:absolute; left:0; right:0; top:0; height:3px;
  background:linear-gradient(90deg,
    rgba(216,156,141,.18) 0%, rgba(232,183,170,.9) 26%,
    rgba(232,183,170,.9) 74%, rgba(216,156,141,.18) 100%);
}

/* ── reveals ─────────────────────────────────────────────────────────────── */
.reveal{
  opacity:0; transform:translateY(18px); filter:blur(4px);
  transition:opacity 1.4s var(--ease), transform 1.7s var(--ease), filter 1.4s var(--ease);
  will-change:opacity,transform;
}
/* `filter:none`, NOT `blur(0)`. A zero-radius blur is still an active filter,
   so the element keeps its composited layer and the foil headings stay
   permanently soft. `none` drops the layer and the type snaps back sharp. */
.reveal.in{ opacity:1; transform:none; filter:none; will-change:auto }
/* Foil never reveals through a blur — see the note on .foil. */
.reveal.foil{ filter:none }

/* ══════════════════ 1 · OPENING ══════════════════ */
.opening-scene{
  position:relative; height:100svh; height:100dvh; overflow:hidden;
  background:var(--char-900); cursor:pointer;
}
.opening-sticky{ position:absolute; inset:0; overflow:hidden }
.opening-video{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; pointer-events:none; background:var(--char-900);
  z-index:2;
  transition:opacity var(--dissolve) cubic-bezier(.42,0,.35,1);
}
.opening-video.faded{ opacity:0 }

/* The designed hero the film dissolves INTO. It sits underneath the film in
   the same palette, so what the guest sees is the question gaining his name
   rather than one picture cutting to another. */
.hero-plate{
  position:absolute; inset:0; z-index:1;
  display:flex; align-items:center; justify-content:center;
  background:
    radial-gradient(84% 58% at 50% 36%, rgba(214,177,102,.10) 0%, rgba(214,177,102,0) 64%),
    radial-gradient(120% 82% at 50% 108%, rgba(0,0,0,.6) 0%, rgba(0,0,0,0) 60%),
    linear-gradient(178deg,#1F1D1C 0%,#171514 48%,#0F0E0D 100%);
  overflow:hidden;
}
.hero-plate .hero-damask{ opacity:.042; z-index:0 }
/* a soft vignette so the type sits on paper, not on a flat swatch */
.hero-plate::after{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:radial-gradient(118% 78% at 50% 44%, rgba(0,0,0,0) 44%, rgba(0,0,0,.55) 100%);
}

.hero-type{
  position:relative; z-index:2;
  display:flex; flex-direction:column; align-items:center;
  text-align:center; gap:.2rem;
  padding:clamp(1.2rem,4vh,2rem) clamp(1.2rem,6vw,2rem);
  max-width:min(680px,92vw);
}
/* Opacity and transform only — no blur. A filter on foil type leaves it
   permanently soft (see .foil). */
.hero-type [data-r]{
  opacity:0; transform:translateY(16px);
  transition:opacity 1.15s var(--ease), transform 1.4s var(--ease);
}
.hero-mono{
  width:clamp(70px,16vw,104px); height:clamp(70px,16vw,104px);
  margin-bottom:clamp(.7rem,2.6vh,1.2rem);
}
/* His name — the one thing the card itself does not say. */
.hero-name{
  margin:0 0 .6rem; font-family:var(--serif); font-weight:400; font-style:italic;
  font-size:clamp(1.4rem,6.2vw,2rem); line-height:1.3;
  letter-spacing:.02em; color:var(--blush);
}
.hero-lead{
  margin:0; font-family:var(--sans); font-weight:300;
  font-size:clamp(.72rem,3.1vw,.92rem);
  letter-spacing:.46em; text-indent:.46em; text-transform:uppercase;
  color:var(--gold-mid);
}
.hero-script{
  font-family:var(--script); font-weight:400; margin:0;
  font-size:clamp(3.1rem,15vw,5.4rem);
  line-height:1.2; padding:.16em .12em .2em;
}
.hero-type .orn{ margin-top:.5rem }

/* ── buffering gate ──────────────────────────────────────────────────────
   The prompt is withheld until the film is wholly in memory, so a tap can
   never land on an unbuffered file. This is only safe because readiness
   cannot hang — see initOpening() for the fetch-error fallback, the stall
   detector, the post-download watchdog and the absolute ceiling. */
.film-loader{
  position:absolute; left:50%; bottom:clamp(112px,20vh,172px);
  transform:translateX(-50%); z-index:7;
  display:flex; flex-direction:column; align-items:center; gap:.65rem;
  pointer-events:none;                       /* never swallows a tap */
  transition:opacity .7s var(--ease), transform .7s var(--ease);
}
.film-loader.gone{ opacity:0; transform:translateX(-50%) translateY(6px) }
.loader-ring{ width:clamp(44px,10.5vw,56px); height:clamp(44px,10.5vw,56px); overflow:visible }
.lr-track{ fill:none; stroke:rgba(243,234,223,.16); stroke-width:2.4 }
/* NOTE: the -90° start is in the SVG transform attribute, never in CSS — a
   CSS transform-origin would stack on top of it and skew the arc. */
.lr-arc{
  fill:none; stroke:var(--gold-mid); stroke-width:2.4; stroke-linecap:round;
  transition:stroke-dashoffset .45s linear;
}
.loader-pct{
  font-family:var(--serif); font-weight:400; font-size:1rem;
  letter-spacing:.06em; color:var(--ivory-strong);
  text-shadow:0 1px 12px rgba(0,0,0,.85);
}
.loader-label{
  font-family:var(--sans); font-weight:300;
  font-size:.56rem; letter-spacing:.34em; text-indent:.34em; text-transform:uppercase;
  color:var(--ivory-mute); text-shadow:0 1px 12px rgba(0,0,0,.85);
}

/* A solid gold pill with dark type — the highest-contrast thing on the
   screen, so the prompt is never lost in the artwork behind it. */
.tap-cue{
  position:absolute; left:50%; bottom:clamp(30px,5.5vh,58px);
  transform:translateX(-50%); z-index:8;
  opacity:0; pointer-events:none;
  transition:opacity .8s var(--ease);
}
.opening-scene.is-ready .tap-cue{ opacity:1; pointer-events:auto }
.film-cue{ transition:opacity .9s var(--ease), transform .9s var(--ease) }
.tap-cue .label{
  display:inline-block;
  font-family:var(--sans); font-weight:400;
  font-size:.68rem; letter-spacing:.38em; text-indent:.38em; text-transform:uppercase;
  color:#241A16; padding:.9rem 1.9rem; border-radius:999px;
  background:linear-gradient(100deg,#B98F3C 0%,#D6B166 30%,#F6E4B4 50%,#D6B166 70%,#B98F3C 100%);
  background-size:200% 100%;
  border:1px solid rgba(255,246,220,.45);
  animation:tapBreathe 3s ease-in-out infinite;
}
@keyframes tapBreathe{
  0%,100%{ box-shadow:0 16px 40px -18px rgba(0,0,0,.95), 0 0 0 6px rgba(201,162,75,.16) }
  50%    { box-shadow:0 16px 40px -18px rgba(0,0,0,.95), 0 0 0 16px rgba(201,162,75,0) }
}
.opening-scene.is-playing .film-cue{ opacity:0; transform:translateX(-50%) scale(.94) }

.scroll-hint{
  position:absolute; left:50%; bottom:1.4rem; transform:translateX(-50%);
  z-index:7; display:flex; flex-direction:column; align-items:center; gap:.45rem;
  opacity:0; transition:opacity 1.2s var(--ease);
  font-family:var(--sans); font-weight:300; font-size:.56rem;
  letter-spacing:.36em; text-indent:.36em; text-transform:uppercase; color:var(--ivory-mute);
}
.scroll-hint.in{ opacity:1 }
.scroll-hint i{
  width:1px; height:32px; display:block;
  background:linear-gradient(180deg,transparent,rgba(214,177,102,.9));
  animation:hintDrop 2.4s ease-in-out infinite;
}
@keyframes hintDrop{
  0%,100%{ transform:scaleY(.5); transform-origin:top; opacity:.4 }
  50%    { transform:scaleY(1);  transform-origin:top; opacity:1 }
}

/* ══════════════════ 2 · THE ASK ══════════════════ */
#s-ask{ min-height:80svh }
#s-ask .lede{ margin-top:.4rem }
[data-ask-question]{ font-size:clamp(2.2rem,9.5vw,3.2rem) }

/* The No button drifts inside this box. Giving it a fixed minimum height means
   the page never reflows as it moves — the section would otherwise jump under
   the guest's finger, which is exactly the "broken button" feeling to avoid. */
.ask-field{
  position:relative; width:100%;
  min-height:clamp(170px,30vh,220px);
  margin-top:clamp(.8rem,3vh,1.4rem);
  display:flex; align-items:center; justify-content:center;
  gap:clamp(.8rem,4vw,1.6rem);
  flex-wrap:wrap;
}
.btn-gold{
  position:relative;
  padding:1.05rem 2.2rem; border-radius:999px;
  font-family:var(--sans); font-weight:400;
  font-size:.68rem; letter-spacing:.3em; text-indent:.3em; text-transform:uppercase;
  color:#241A16;
  background:linear-gradient(100deg,#B98F3C 0%,#D6B166 30%,#F6E4B4 50%,#D6B166 70%,#B98F3C 100%);
  background-size:200% 100%;
  box-shadow:0 20px 38px -24px rgba(0,0,0,.95), 0 0 0 1px rgba(255,246,220,.35);
  transition:background-position .9s var(--ease), transform .5s var(--ease), box-shadow .5s var(--ease);
}
.btn-gold:hover{ background-position:100% 50%; transform:translateY(-1px) }
.btn-gold:active{ transform:translateY(0) scale(.985) }
.btn-gold:focus-visible{ outline:2px solid var(--gold-mid); outline-offset:3px }

.btn-quiet{
  padding:.95rem 1.9rem; border-radius:999px;
  font-family:var(--sans); font-weight:300;
  font-size:.66rem; letter-spacing:.28em; text-indent:.28em; text-transform:uppercase;
  color:var(--ivory-soft);
  background:rgba(255,246,235,.045);
  border:1px solid var(--gold-line);
  box-shadow:0 14px 28px -22px rgba(0,0,0,.9);
  transition:transform .45s var(--ease), border-color .45s var(--ease), color .45s var(--ease);
}
.btn-quiet:hover{ border-color:var(--gold-mid); color:var(--ivory-strong) }
.btn-quiet:focus-visible{ outline:2px solid var(--gold-mid); outline-offset:3px }

.btn-yes{ font-size:.74rem; padding:1.15rem 2.6rem }

/* Once it starts dodging the No button is taken out of flow and positioned
   inside .ask-field, so its drift cannot push anything else around. */
.btn-no.loose{
  position:absolute; margin:0;
  transition:left .52s var(--ease), top .52s var(--ease), transform .52s var(--ease);
  will-change:left,top;
}
.btn-no.caught{ transition:left .3s var(--ease), top .3s var(--ease) }

.ask-hint{
  margin:.2rem 0 0; min-height:1.3em;
  font-family:var(--sans); font-weight:300; font-size:.68rem;
  letter-spacing:.2em; text-transform:uppercase; color:var(--ivory-mute);
  opacity:0; transition:opacity .5s var(--ease);
}
.ask-hint.on{ opacity:1 }

.ask-caught{
  width:100%; max-width:34rem; margin-top:clamp(.6rem,2.4vh,1.1rem);
  display:flex; flex-direction:column; align-items:center; gap:.7rem;
  padding:clamp(1.4rem,5vw,2rem) clamp(1.2rem,5vw,1.8rem);
  background:linear-gradient(168deg, rgba(255,246,235,.07), rgba(255,246,235,.025));
  border:1px solid var(--gold-line); border-radius:4px;
  box-shadow:0 30px 56px -44px rgba(0,0,0,1);
  opacity:0; transform:translateY(10px);
  transition:opacity .7s var(--ease), transform .8s var(--ease);
}
.ask-caught.in{ opacity:1; transform:none }
.caught-title{ font-size:clamp(1.9rem,8vw,2.4rem); margin:0 }
.ask-caught .body{ text-align:center }

.ask-done{
  width:100%; display:flex; flex-direction:column; align-items:center; gap:.5rem;
  padding-top:clamp(.6rem,2.4vh,1rem);
  opacity:0; transform:translateY(12px);
  transition:opacity .8s var(--ease), transform .9s var(--ease);
}
.ask-done.in{ opacity:1; transform:none }
.seal-mark{ width:78px; height:78px; margin-bottom:.4rem }
.ask-done .script{ font-size:clamp(2.4rem,10vw,3.2rem) }
.ask-done .body{ text-align:center }
.accept-badge{
  margin-top:.5rem; padding:.5rem 1.2rem; border-radius:999px;
  border:1px solid var(--gold-line); color:var(--gold-mid);
  background:rgba(255,246,235,.05);
}

/* ══════════════════ 3 · A WORD FROM THE GROOM ══════════════════ */
.note-quote{
  margin:.4rem 0 0; max-width:38ch;
  font-family:var(--serif); font-weight:300; font-style:italic;
  font-size:clamp(1.1rem,4.6vw,1.32rem); line-height:1.72;
  color:var(--ivory);
}
.note-sign{
  margin:.9rem 0 0; font-family:var(--script);
  font-size:clamp(1.5rem,6vw,1.9rem); line-height:1.3; padding:.1em .1em .16em;
  color:var(--blush);
}

/* ══════════════════ 4 · THE DATES ══════════════════ */
.day-cards{
  width:100%; margin-top:clamp(1rem,3.5vh,1.6rem);
  display:grid; grid-template-columns:1fr; gap:clamp(.9rem,3vw,1.2rem);
}
@media (min-width:640px){ .day-cards{ grid-template-columns:1fr 1fr } }
.day-card{
  position:relative; padding:clamp(1.5rem,5.5vw,2rem) clamp(1.1rem,4.5vw,1.6rem);
  background:linear-gradient(168deg, rgba(255,246,235,.065), rgba(255,246,235,.02));
  border:1px solid var(--gold-line); border-radius:4px;
  box-shadow:0 1px 0 rgba(255,246,220,.06) inset, 0 30px 52px -42px rgba(0,0,0,1);
  display:flex; flex-direction:column; align-items:center; gap:.35rem;
  opacity:0; transform:translateY(16px);
  transition:opacity 1.1s var(--ease), transform 1.3s var(--ease);
}
.day-card.in{ opacity:1; transform:none }
.day-card::after{
  content:""; position:absolute; inset:6px; border-radius:2px;
  border:1px solid var(--gold-line-soft); pointer-events:none;
}
.day-tag{
  font-family:var(--sans); font-weight:300; margin:0;
  font-size:.58rem; letter-spacing:.34em; text-indent:.34em; text-transform:uppercase;
  color:var(--gold-mid);
}
.day-num{
  font-family:var(--serif); font-weight:300; margin:0;
  font-size:clamp(3rem,13vw,3.8rem); line-height:1; color:var(--ivory-strong);
  letter-spacing:.02em;
}
.day-when{
  margin:0; font-family:var(--serif); font-size:clamp(1rem,4vw,1.1rem);
  color:var(--ivory-soft); letter-spacing:.04em;
}
.day-note{
  margin:.3rem 0 0; font-family:var(--sans); font-weight:300;
  font-size:.66rem; letter-spacing:.14em; color:var(--ivory-mute); line-height:1.7;
}
[data-dates-count]{ margin-top:clamp(.9rem,3vh,1.3rem); color:var(--gold-mid) }
.dates-note{ text-align:center }

/* ══════════════════ 5 · YOUR KIT ══════════════════ */
.total-line{
  display:flex; flex-direction:column; align-items:center; gap:.2rem;
  margin:clamp(.6rem,2.4vh,1rem) 0 .3rem;
}
.total-label{
  font-family:var(--sans); font-weight:300;
  font-size:.6rem; letter-spacing:.4em; text-indent:.4em; text-transform:uppercase;
  color:var(--ivory-mute);
}
.total-amount{
  font-family:var(--serif); font-weight:400;
  font-size:clamp(2.6rem,12vw,3.6rem); line-height:1.15; letter-spacing:.01em;
  padding:.04em .06em .06em;
}

/* Two photographed groups, side by side. Not nine cards — this is a much
   shorter package than the bridesmaids' and it should look it. */
.kit-grid{
  width:100%; margin-top:clamp(1.2rem,4vh,1.8rem);
  display:grid; grid-template-columns:1fr; gap:clamp(.9rem,3vw,1.3rem);
}
@media (min-width:600px){ .kit-grid{ grid-template-columns:1fr 1fr } }
.kit-card{
  position:relative; overflow:hidden; border-radius:4px;
  border:1px solid var(--gold-line);
  background:linear-gradient(168deg, rgba(255,246,235,.06), rgba(255,246,235,.02));
  box-shadow:0 1px 0 rgba(255,246,220,.06) inset, 0 28px 50px -40px rgba(0,0,0,1);
  display:flex; flex-direction:column;
  opacity:0; transform:translateY(18px);
  transition:opacity 1.1s var(--ease), transform 1.3s var(--ease);
}
.kit-card.in{ opacity:1; transform:none }
.kit-figure{ position:relative; margin:0; aspect-ratio:4/5; overflow:hidden; background:var(--char-800) }
.kit-figure img{
  width:100%; height:100%; object-fit:cover; object-position:50% 36%;
  transition:transform 1.6s var(--ease);
}
.kit-card:hover .kit-figure img{ transform:scale(1.035) }
/* The photographs are bright daylight studio shots on a near-black page. A
   graded scrim on the image layer settles them into the ground — never a dark
   box behind the caption, which would bleed into the section below. */
.kit-figure::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(180deg, rgba(12,10,9,.10) 0%, rgba(12,10,9,0) 34%, rgba(12,10,9,.42) 100%);
}
.kit-body{ padding:.95rem 1rem 1.1rem; display:flex; flex-direction:column; gap:.25rem; text-align:left }
.kit-name{
  margin:0; font-family:var(--serif); font-weight:400;
  font-size:clamp(1.05rem,4.2vw,1.18rem); line-height:1.3; color:var(--ivory-strong);
}
.kit-caption{
  margin:0; font-family:var(--sans); font-weight:300;
  font-size:.62rem; letter-spacing:.1em; line-height:1.7; color:var(--ivory-mute);
}

/* Items with no photograph render as a text row. No placeholder frames — an
   empty box reads as a broken image, which is worse than no image at all. */
.kit-rows{
  list-style:none; margin:clamp(1.2rem,4vh,1.7rem) 0 0; padding:0; width:100%;
  display:flex; flex-direction:column;
}
.kit-row{
  display:flex; align-items:baseline; gap:.9rem;
  padding:1.05rem .3rem; text-align:left;
  border-top:1px solid var(--gold-line-soft);
  border-bottom:1px solid var(--gold-line-soft);
  opacity:0; transform:translateY(10px);
  transition:opacity 1s var(--ease), transform 1.15s var(--ease);
}
.kit-row.in{ opacity:1; transform:none }
.kit-row i{
  flex:0 0 auto; width:6px; height:6px; transform:rotate(45deg) translateY(-1px);
  background:var(--gold-mid); box-shadow:0 0 8px rgba(201,162,75,.5);
}
.kit-row b{
  font-family:var(--serif); font-weight:400;
  font-size:clamp(1.05rem,4.2vw,1.18rem); color:var(--ivory-strong); letter-spacing:.02em;
}
.kit-row em{
  font-family:var(--sans); font-weight:300; font-style:normal;
  font-size:.62rem; letter-spacing:.1em; line-height:1.7; color:var(--ivory-mute);
}
.kit-row .kit-row-body{ display:flex; flex-direction:column; gap:.2rem }

/* ══════════════════ 6 · PAYMENT ══════════════════ */
/* The schedule is carried across from the bridesmaid brief and is NOT
   confirmed for groomsmen. That has to be visible on the page, not only in a
   config comment — a guest reading provisional dates as settled is the
   expensive version of this mistake. */
.provisional{
  margin:.2rem 0 .2rem; padding:.55rem 1.1rem; border-radius:999px;
  font-family:var(--sans); font-weight:300;
  font-size:.58rem; letter-spacing:.22em; text-transform:uppercase;
  color:var(--blush);
  border:1px dashed var(--blush-line);
  background:rgba(216,156,141,.07);
}

.pay-steps{
  list-style:none; margin:clamp(1.2rem,4vh,1.8rem) 0 0; padding:0; width:100%;
  display:flex; flex-direction:column; gap:0;
}
.pay-step{
  position:relative; display:grid;
  grid-template-columns:30px 1fr; gap:0 clamp(.9rem,4vw,1.4rem);
  text-align:left; padding-bottom:clamp(1.4rem,5vh,2rem);
  opacity:0; transform:translateY(14px);
  transition:opacity 1.1s var(--ease), transform 1.25s var(--ease);
}
.pay-step.in{ opacity:1; transform:none }
.pay-step:last-child{ padding-bottom:0 }
.pay-node{ position:relative; display:flex; justify-content:center }
.pay-node b{
  position:relative; z-index:2; width:30px; height:30px; border-radius:50%;
  display:grid; place-items:center; margin-top:.15rem;
  font-family:var(--sans); font-weight:400; font-size:.7rem; color:#241A16;
  background:linear-gradient(140deg,#F6E4B4,#D6B166 55%,#B98F3C);
  box-shadow:0 0 0 1px rgba(255,246,220,.35), 0 10px 20px -12px rgba(0,0,0,1);
}
.pay-step:not(:last-child) .pay-node::after{
  content:""; position:absolute; left:50%; top:34px; bottom:-4px; width:1px;
  transform:translateX(-50%);
  background:linear-gradient(180deg,var(--gold-line),rgba(201,162,75,.05));
}
.pay-label{
  margin:0; font-family:var(--sans); font-weight:300;
  font-size:.6rem; letter-spacing:.3em; text-indent:.3em; text-transform:uppercase;
  color:var(--gold-mid);
}
.pay-amount{
  margin:.2rem 0 0; font-family:var(--serif); font-weight:400;
  font-size:clamp(1.7rem,7.5vw,2.1rem); line-height:1.2; color:var(--ivory-strong);
}
.pay-due{
  margin:.15rem 0 0; font-family:var(--serif); font-weight:300; font-style:italic;
  font-size:clamp(.95rem,3.7vw,1.04rem); color:var(--ivory-soft);
}
.pay-closing{ margin-top:clamp(.6rem,2.4vh,1rem); text-transform:none; letter-spacing:.1em;
  font-size:.78rem; font-style:italic; font-family:var(--serif); text-indent:0 }

/* ══════════════════ 7 · BANKING · shared paper card ══════════════════ */
.paper-card{
  position:relative; width:100%; margin-top:clamp(1rem,3.5vh,1.6rem);
  padding:clamp(1.8rem,6vw,2.4rem) clamp(1.3rem,5vw,2rem);
  background:linear-gradient(168deg, rgba(255,246,235,.075), rgba(255,246,235,.025));
  border:1px solid var(--gold-line); border-radius:4px;
  box-shadow:0 1px 0 rgba(255,246,220,.07) inset, 0 34px 60px -46px rgba(0,0,0,1);
  text-align:left;
}
.paper-card::after{
  content:""; position:absolute; inset:6px; border-radius:2px;
  border:1px solid var(--gold-line-soft); pointer-events:none;
}
.ec-corner{ position:absolute; width:13px; height:13px; pointer-events:none; z-index:3 }
.ec-corner::before,.ec-corner::after{ content:""; position:absolute; background:var(--gold); opacity:.6 }
.ec-corner::before{ width:100%; height:1px }
.ec-corner::after { width:1px; height:100% }
.ec-corner.tl{ left:12px; top:12px }
.ec-corner.tr{ right:12px; top:12px } .ec-corner.tr::after{ right:0 }
.ec-corner.bl{ left:12px; bottom:12px } .ec-corner.bl::before{ bottom:0 }
.ec-corner.br{ right:12px; bottom:12px } .ec-corner.br::before{ bottom:0 } .ec-corner.br::after{ right:0 }

.bank-card.sealed{ opacity:0; transform:translateY(-8px) }
.bank-card.unsealed{
  opacity:1; transform:none;
  transition:opacity .7s var(--ease), transform .8s var(--ease);
}
.bank-rows{ margin:0; display:flex; flex-direction:column; gap:.1rem }
.bank-row{
  display:flex; align-items:baseline; justify-content:space-between; gap:1rem;
  padding:.68rem 0; border-bottom:1px solid var(--gold-line-soft);
}
.bank-row:last-child{ border-bottom:0 }
.bank-row dt{
  font-family:var(--sans); font-weight:300;
  font-size:.58rem; letter-spacing:.24em; text-transform:uppercase; color:var(--ivory-mute);
}
.bank-row dd{
  margin:0; font-family:var(--serif); font-weight:400;
  font-size:clamp(1rem,4vw,1.1rem); color:var(--ivory-strong); text-align:right;
  letter-spacing:.03em;
}
/* An account number is the one string on this page that must be transcribed
   perfectly, and the serif here is an oldstyle face: its 1 sits at x-height and
   its 3 descends, so "62111063111" becomes a row of ambiguous marks. These rows
   get the sans, lining tabular figures and wider tracking — plainer than the
   rest of the card, and deliberately so. */
.bank-row dd.num{
  font-family:var(--sans); font-weight:300;
  font-variant-numeric:lining-nums tabular-nums;
  font-feature-settings:"lnum" 1,"tnum" 1;
  font-size:clamp(1.02rem,4.1vw,1.14rem);
  letter-spacing:.14em;
}

/* a value nobody has supplied — obviously unfinished, not invented */
.bank-row dd.pending{
  font-style:italic; font-size:.86rem; color:var(--blush);
  border-bottom:1px dashed var(--blush-line); padding-bottom:1px;
}
.bank-foot{ margin-top:1rem; text-align:center; text-indent:0; letter-spacing:.16em }

/* ══════════════════ 8 · YOUR SIZES ══════════════════ */
.sizes-card{ display:flex; flex-direction:column; gap:.35rem }
.answer-chip{
  align-self:flex-start; margin:0 0 .7rem;
  padding:.45rem 1rem; border-radius:999px;
  font-family:var(--sans); font-weight:300; font-size:.58rem;
  letter-spacing:.22em; text-transform:uppercase; color:var(--gold-mid);
  border:1px solid var(--gold-line); background:rgba(255,246,235,.05);
}
.field{ position:relative }
.field input,.field textarea,.field select{
  width:100%; padding:1.25rem .1rem .5rem; border:0;
  border-bottom:1px solid var(--gold-line);
  background:transparent; color:var(--ivory-strong);
  font-family:var(--serif); font-weight:400; font-size:1.02rem; line-height:1.4;
  border-radius:0; outline:none; resize:none;
  transition:border-color .5s var(--ease);
}
.field select{ appearance:none; -webkit-appearance:none; cursor:pointer }
/* The native dropdown list is painted by the OS, not by this stylesheet — a
   dark page with a default white list is the giveaway that nobody checked. */
.field select option{ background:#1F1A18; color:var(--ivory-strong) }
.field-select::after{
  content:""; position:absolute; right:.35rem; bottom:1.05rem; width:7px; height:7px;
  border-right:1px solid var(--gold-mid); border-bottom:1px solid var(--gold-mid);
  transform:rotate(45deg); pointer-events:none;
}
.field label{
  position:absolute; left:.1rem; top:1.15rem; pointer-events:none;
  font-family:var(--sans); font-weight:300; font-size:.78rem;
  letter-spacing:.16em; text-transform:uppercase; color:var(--ivory-mute);
  transition:transform .45s var(--ease), color .45s var(--ease);
  transform-origin:left top;
}
.field input:focus~label,.field textarea:focus~label,
.field input:not(:placeholder-shown)~label,.field textarea:not(:placeholder-shown)~label,
.field select~label{
  transform:translateY(-1.1rem) scale(.78); color:var(--gold-mid);
}
.field input:focus,.field textarea:focus,.field select:focus{ border-bottom-color:var(--gold-mid) }
.field.invalid input,.field.invalid textarea,.field.invalid select{ border-bottom-color:#C4746B }

.field-pair{ display:grid; grid-template-columns:1fr 1fr; gap:0 clamp(.9rem,4vw,1.4rem) }
.form-aside{ margin-top:1.1rem; text-transform:none; letter-spacing:.08em; text-indent:0;
  font-family:var(--serif); font-style:italic; font-size:.84rem; color:var(--ivory-mute) }
.sizes-card .btn-gold{ margin-top:clamp(1.2rem,4vh,1.8rem); align-self:center }
.form-error{
  margin:.7rem 0 0; text-align:center;
  font-family:var(--sans); font-weight:300; font-size:.68rem;
  letter-spacing:.16em; color:#D98D82;
}

.sizes-done{
  width:100%; margin-top:clamp(1rem,3.5vh,1.6rem);
  display:flex; flex-direction:column; align-items:center; gap:.5rem;
  padding:clamp(2rem,7vw,2.8rem) 1.2rem;
}
.done-seal{
  width:58px; height:58px; border-radius:50%; display:grid; place-items:center;
  border:1px solid var(--gold-line); margin-bottom:.5rem;
  background:radial-gradient(circle at 38% 32%, rgba(214,177,102,.28), rgba(201,162,75,.05));
}
.done-seal svg{ width:24px; height:24px }
.done-seal svg path{
  fill:none; stroke:var(--gold-mid); stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round;
  stroke-dasharray:26; stroke-dashoffset:26; animation:tickDraw .8s var(--ease) .25s forwards;
}
@keyframes tickDraw{ to{ stroke-dashoffset:0 } }
.sizes-done .script{ font-size:clamp(2rem,9vw,2.8rem) }
.sizes-done .body{ text-align:center }
.sizes-done .btn-gold{ margin-top:1.2rem }

/* ══════════════════ 9 · FINALE ══════════════════ */
.finale-scene{
  position:relative; width:100%; min-height:92svh;
  display:flex; align-items:center; justify-content:center; overflow:hidden;
  background:
    radial-gradient(88% 58% at 50% 26%, rgba(214,177,102,.085) 0%, rgba(214,177,102,0) 62%),
    radial-gradient(130% 82% at 50% 108%, rgba(0,0,0,.7) 0%, rgba(0,0,0,0) 60%),
    linear-gradient(180deg,#1E1C1B 0%,#141312 52%,#0C0B0B 100%);
}
.finale-scene .hero-damask{ opacity:.042 }
.finale-type{
  position:relative; z-index:2; width:100%; max-width:var(--maxw);
  display:flex; flex-direction:column; align-items:center; gap:.5rem;
  text-align:center; padding:clamp(3rem,10vh,5rem) 1.4rem;
}
.finale-mono{
  width:clamp(62px,14vw,86px); height:clamp(62px,14vw,86px);
  margin-bottom:clamp(.6rem,2.4vh,1.1rem);
  opacity:0; transform:translateY(16px);
  transition:opacity 1.2s var(--ease), transform 1.4s var(--ease);
}
.finale-mono.in{ opacity:1; transform:none }
.fin-sub{
  margin:0; font-family:var(--serif); font-style:italic; font-weight:300;
  font-size:clamp(1rem,4vw,1.14rem); color:var(--ivory-soft); letter-spacing:.04em;
}

/* The wedding hashtag — the last thing on the page, and the only element here
   set in mixed case. Everything else in this family is uppercased and widely
   letterspaced; a hashtag must not be, because the camel case is what makes
   "#FHLockedIn" readable and people copy it by eye. Hence no text-transform
   and only enough tracking to sit comfortably in the chip. */
.fin-hash{
  margin:clamp(1.1rem,3.6vh,1.7rem) 0 0;
  padding:.6rem 1.3rem; border-radius:999px;
  font-family:var(--sans); font-weight:300;
  font-size:clamp(.72rem,3vw,.82rem); letter-spacing:.08em;
  color:var(--gold-mid);
  border:1px solid var(--gold-line);
  background:rgba(255,246,235,.05);
  white-space:nowrap;
}

/* ══════════════════ scroll progress ══════════════════ */
.progress-rail{
  position:fixed; left:0; right:0; bottom:0; height:2px; z-index:60;
  background:rgba(243,234,223,.08); pointer-events:none;
}
.progress-rail i{
  display:block; height:100%; width:0;
  background:linear-gradient(90deg,#B98F3C,#D6B166 40%,#F6E4B4 70%,#B98F3C);
  box-shadow:0 0 10px rgba(201,162,75,.55);
}

/* ══════════════════ reduced motion ══════════════════ */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important; animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
  .reveal,.hero-type [data-r],.day-card,.kit-card,.kit-row,.pay-step,.finale-mono{
    opacity:1 !important; transform:none !important; filter:none !important;
  }
}
