/* ===========================================================================
   Vostylo - vostylo.com
   ---------------------------------------------------------------------------
   Art direction: every photograph in this site was shot on the same near-black
   ground (#131313), so the page is set to almost exactly that value and the
   cold open's photograph is scrimmed into it with a gradient. The result is a
   hero with no visible edge: the subject stands in the page rather than in a
   picture box. Where an image does need a defined edge, it is because the
   image is being examined (act one) or wiped (act three), and the edge is
   carrying meaning.

   Structural device: the eyebrow label is a detection reticle (corner ticks),
   because the product is a machine noticing what you are wearing. It is the
   same shape the AI draws around each garment in act one. It earns its place;
   it is not decoration.

   Motion: transform, opacity and clip-path only, and nothing pins. Each act
   is one screen in normal flow whose choreography plays on the approach, so
   the page reads top to bottom at the right length before any JS runs.
   =========================================================================== */

/* ---------- tokens ---------- */
:root {
  --ink:      #0D0E11;   /* the photographs' own ground */
  --ink-2:    #08090C;
  --ink-3:    #131418;
  --navy:     #16223A;
  --gold:     #B8863B;
  --gold-lit: #E3BC7C;
  --camel:    #C79A5E;
  --cream:    #F3EFE8;
  --mute:     #918D86;
  /* 4.77:1 on --ink. The quieter grey still has to clear AA, because it
     carries field labels, captions and the footer, not just decoration. */
  --mute-2:   #827E74;
  --line:     rgba(243, 239, 232, .11);
  --line-2:   rgba(243, 239, 232, .2);
  --good:     #6FB292;
  --flag:     #D0805A;

  --ui:   'Archivo', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --disp: 'Bodoni Moda', 'Didot', Georgia, serif;

  --gut:  clamp(1.25rem, 5vw, 5rem);
  --maxw: 1320px;
  --ease: cubic-bezier(.22, 1, .36, 1);

  /* -------------------------------------------------------------------------
     One content edge for the whole page.

     Two container idioms were in use and they do not agree. A full-bleed band
     with `padding-inline: var(--gut)` puts its content at the gutter; a
     centred block with `max-width: var(--maxw)` AND the same gutter padding
     puts its content at the gutter PLUS half the leftover. Above 1320px those
     are different numbers, so the nav mark, the act headings and the closet
     heading each started at a different x -- three left edges on one page,
     drifting further apart the wider the window got.

     `--pad` is the single answer: hold the gutter until the viewport outgrows
     the measure, then centre. Used as padding on a full-bleed element it needs
     no max-width and no auto margin, so it cannot disagree with itself. The
     percentage is deliberate -- 100vw would include the scrollbar and shift
     every band half a scrollbar left of where the fixed nav sits.
  ------------------------------------------------------------------------- */
  --pad: max(var(--gut), (100% - var(--maxw)) / 2);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  /* `clip` here as well as on body. Entrance tweens slide tiles in from
     x:-44px, which is further than the 20px gutter on a phone, so the page
     grew 24px wider than the window: Chrome then zoomed the whole document out
     to fit and the site could be panned sideways. Body's clip alone does not
     stop that, because the UA propagates body's overflow to the viewport and
     leaves the html box itself unclipped. */
  overflow-x: clip;
}
/* Anchors are the browser's job now. `scroll-padding-top` is what makes them
   land correctly: without it a target scrolls flush to y=0 and the fixed bar
   sits on top of the heading you just asked for. Sized to clear the tallest
   the bar gets, plus a little air. */
html { scroll-behavior: smooth; scroll-padding-top: 5.5rem; }
body {
  margin: 0;
  background: var(--ink);
  color: var(--cream);
  font: 400 clamp(.95rem, .35vw + .88rem, 1.05rem)/1.65 var(--ui);
  -webkit-font-smoothing: antialiased;
  /* `clip`, not `hidden`. overflow-x:hidden makes the body a scroll
     container, which changes what every viewport-relative unit on the page
     measures against. `clip` trims the same overflow without creating one. */
  overflow-x: clip;
}
img, svg, picture { display: block; max-width: 100%; }
img { height: auto; }
h1, h2, h3 { margin: 0; font-family: var(--disp); font-weight: 400; }
p, ul, ol, dl, dd, figure, fieldset { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--gold-lit);
  outline-offset: 3px;
  border-radius: 2px;
}

.sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip {
  position: fixed; top: .6rem; left: .6rem; z-index: 999;
  padding: .7rem 1.1rem; background: var(--cream); color: var(--ink);
  font-size: .85rem; border-radius: 3px;
  transform: translateY(-160%);
}
.skip:focus { transform: none; }

/* ---------- shared type ---------- */
h1 {
  font-size: clamp(2.7rem, 6.6vw, 5.15rem);
  line-height: 1.06;
  letter-spacing: -.015em;
}
h2 {
  font-size: clamp(2.05rem, 4.4vw, 3.5rem);
  line-height: 1.1;
  letter-spacing: -.012em;
}
h3 { font-size: clamp(1.3rem, 1.8vw, 1.6rem); line-height: 1.2; }
em { font-style: italic; color: var(--gold-lit); }

.sub {
  color: var(--mute);
  max-width: 46ch;
  line-height: 1.66;
}
.lede {
  font-family: var(--disp);
  font-size: clamp(1.15rem, 1.7vw, 1.42rem);
  font-style: italic;
  color: var(--camel);
  max-width: 30ch;
}

/* the detection reticle - this site's structural device */
.tag {
  display: inline-block;
  position: relative;
  padding: .62rem .85rem;
  font: 500 .69rem/1 var(--ui);
  letter-spacing: .21em;
  text-transform: uppercase;
  color: var(--gold-lit);
}
.tag::before, .tag::after {
  content: '';
  position: absolute;
  width: 7px; height: 7px;
  border: 1px solid var(--gold);
  opacity: .75;
}
.tag::before { top: 0; left: 0; border-right: 0; border-bottom: 0; }
.tag::after  { bottom: 0; right: 0; border-left: 0; border-top: 0; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 50px;
  padding: .85rem 1.6rem;
  background: var(--cream); color: var(--ink);
  font: 500 .9rem/1 var(--ui); letter-spacing: .01em;
  border: 1px solid var(--cream); border-radius: 2px;
  cursor: pointer;
  transition: background .3s var(--ease), color .3s var(--ease),
              transform .3s var(--ease);
}
.btn:hover { background: var(--gold-lit); border-color: var(--gold-lit); transform: translateY(-2px); }
.btn--sm  { min-height: 40px; padding: .55rem 1.05rem; font-size: .81rem; }
.btn--ghost {
  background: none; color: var(--cream); border-color: var(--line-2);
}
.btn--ghost:hover { background: none; border-color: var(--gold-lit); color: var(--gold-lit); }

.link {
  display: inline-flex; align-items: center; min-height: 50px;
  font-size: .9rem; color: var(--mute);
  border-bottom: 1px solid transparent;
  transition: color .3s var(--ease), border-color .3s var(--ease);
}
.link:hover { color: var(--cream); border-color: var(--gold); }

/* ---------- store pills ---------- */
.stores { display: flex; flex-wrap: wrap; gap: .6rem; }
.store {
  display: inline-grid;
  grid-template: 'i b' auto 'i s' auto / auto 1fr;
  align-items: center;
  gap: 0 .6rem;
  padding: .5rem .95rem;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: rgba(243, 239, 232, .022);
}
.store svg { grid-area: i; width: 21px; height: 21px; color: var(--mute); }
.store b { grid-area: b; font: 500 .82rem/1.25 var(--ui); color: var(--cream); }
.store i { grid-area: s; font: 400 .66rem/1.25 var(--ui); font-style: normal;
           letter-spacing: .1em; text-transform: uppercase; color: var(--gold); }

/* ---------- nav ---------- */
.nav {
  position: fixed; inset: 0 0 auto; z-index: 90;
  display: flex; align-items: center; gap: 1.5rem;
  padding: .8rem var(--pad);
  background: linear-gradient(to bottom, rgba(13, 14, 17, .9), rgba(13, 14, 17, 0));
  transition: transform .45s var(--ease), background .45s var(--ease);
}
.nav.is-solid {
  background: rgba(9, 10, 13, .88);
  border-bottom: 1px solid var(--line);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.nav.is-away { transform: translateY(-104%); }

.nav__mark {
  display: inline-flex; align-items: center;
  min-height: 40px;           /* it is a link back to the top, so it is a target */
}
/* The wordmark is set in Arial Black and carries about 12% of trailing
   whitespace inside its own viewBox, so it reads heavier and wider than its
   height suggests -- which is why it is set against the nav links rather than
   against the bar. It still has to hold its own on a large screen, so it
   scales with the viewport instead of sitting at one size everywhere. */
.nav__mark img { height: clamp(14px, 1.05vw, 17px); width: auto; display: block; }
.nav__links { display: flex; gap: 1.7rem; margin-left: auto; }
.nav__links a {
  display: inline-flex; align-items: center; min-height: 44px;
  font-size: .84rem; color: var(--mute);
  transition: color .3s var(--ease);
}
.nav__links a:hover { color: var(--cream); }
.nav__links a.nav__links-cta { display: none; }

.nav__toggle {
  display: none;
  flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  width: 42px; height: 38px;
  /* A bare set of hairlines on a dark photograph is easy to miss, and this is
     the only way into the menu once the inline links are gone. The outline
     makes it read as a control. */
  background: rgba(243, 239, 232, .04);
  border: 1px solid var(--line-2); border-radius: 3px;
  padding: 0; cursor: pointer;
  transition: border-color .3s var(--ease), background .3s var(--ease);
}
.nav__toggle:hover { border-color: var(--gold); }
.nav__toggle span {
  display: block; width: 17px; height: 1.5px; background: var(--cream);
  transition: transform .3s var(--ease), opacity .2s var(--ease);
}
.nav__toggle.is-open span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.nav__toggle.is-open span:nth-child(2) { opacity: 0; }
.nav__toggle.is-open span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

/* ===========================================================================
   act 00 - cold open
   =========================================================================== */
.open {
  position: relative;
  min-height: 100svh;
  display: grid;
  grid-template-columns: 1fr;
  align-items: center;
  padding: clamp(6.5rem, 12vh, 9rem) var(--pad) clamp(4rem, 9vh, 6rem);
  isolation: isolate;
}
.open__media {
  position: absolute; z-index: -1;
  top: 0; bottom: 0; right: 0;
  width: min(62%, 780px);
  /* the Ken Burns tween scales the photograph past its own box, so the box
     has to clip or the image bleeds off the right edge of the page */
  overflow: hidden;
}
/* The <img> lives inside a <picture>. A percentage height resolves against the
   parent, and <picture> has no height of its own, so without this the image
   falls back to its intrinsic ratio: object-fit never runs, and on a phone the
   photograph stops 259px short of the bottom of the hero. */
.open__media picture { display: block; width: 100%; height: 100%; }
.open__media img {
  width: 100%; height: 100%;
  /* 0% vertically: the frame is 2:3 and the column is taller than it is wide,
     so cover crops from the bottom. Anchoring the top keeps the head clear of
     the nav on every window height instead of drifting into it. */
  object-fit: cover; object-position: 52% 0%;
}
/* the photograph's ground is #131313, so it fades into the page, not a box */
.open__media::after {
  content: '';
  position: absolute; inset: 0;
  background:
    linear-gradient(to right, var(--ink) 2%, rgba(13, 14, 17, .55) 34%, transparent 64%),
    linear-gradient(to top, var(--ink) 1%, transparent 22%);
}
.open__copy { max-width: 40rem; }
.open__copy > * + * { margin-top: 1.5rem; }
.open__copy .tag { margin-bottom: -.2rem; }

/* Bodoni's descenders sit below the line box, so a tight mask beheads every
   "y" and "g". The mask is padded to clear them and pulled back by the same
   amount, which keeps the leading exactly as set. */
.lines span {
  display: block;
  overflow: hidden;
  padding-bottom: .16em;
  margin-bottom: -.16em;
}
.lines i { display: block; font-style: normal; }

.cta { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem 1.6rem; }
.open .stores { margin-top: 2.1rem; }

.cue {
  position: absolute; left: var(--pad); bottom: clamp(1.4rem, 4vh, 2.4rem);
  display: flex; align-items: center; gap: .8rem;
  font: 500 .66rem/1 var(--ui); letter-spacing: .24em;
  text-transform: uppercase; color: var(--mute-2);
}
.cue i {
  display: block; width: 54px; height: 1px;
  background: linear-gradient(to right, var(--gold), transparent);
  transform-origin: left;
  animation: cue 2.4s var(--ease) infinite;
}
@keyframes cue {
  0%, 100% { transform: scaleX(.35); opacity: .45; }
  50%      { transform: scaleX(1);   opacity: 1; }
}

/* ---------------------------------------------------------------------------
   The hero scanner
   The pointer is the AI's eye. A reticle hunts across the photograph and snaps
   onto whichever garment is under the cursor; the readout names it and counts
   how many of the four have been found. Finding all four resolves into the
   score. It is the product, performed by the visitor, before they have read a
   word about it.

   Every corner of the reticle is its own element moved with `translate`, so
   the box can resize to any garment without the corner ticks stretching and
   without anything leaving the compositor.
--------------------------------------------------------------------------- */
.ret {
  position: absolute; inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  transition: opacity .5s var(--ease);
}
.ret.is-live { opacity: 1; }
.ret.is-lock .ret__c { border-color: var(--gold-lit); width: 17px; height: 17px; }

.ret__c {
  position: absolute; top: 0; left: 0;
  width: 13px; height: 13px;
  border: 1.5px solid var(--gold);
  will-change: transform;
  transition: width .3s var(--ease), height .3s var(--ease),
              border-color .3s var(--ease);
}
.ret__c--tl { border-right: 0; border-bottom: 0; }
.ret__c--tr { border-left: 0;  border-bottom: 0; }
.ret__c--br { border-left: 0;  border-top: 0; }
.ret__c--bl { border-right: 0; border-top: 0; }

.readout {
  position: absolute; z-index: 3;
  right: var(--pad); bottom: clamp(1.4rem, 4vh, 2.4rem);
  width: min(19rem, 42vw);
  text-align: right;
  pointer-events: none;
  /* it sits over the photograph, and the photograph has lit areas */
  text-shadow: 0 1px 14px rgba(8, 9, 12, .9), 0 0 30px rgba(8, 9, 12, .6);
}
.readout__hint {
  font: 400 .74rem/1.4 var(--ui);
  color: var(--mute);
  transition: opacity .4s var(--ease);
}
.readout__name {
  display: flex; align-items: center; justify-content: flex-end; gap: .55rem;
  min-height: 1.5rem;
  font-family: var(--disp);
  font-size: clamp(1rem, 1.5vw, 1.28rem);
  color: var(--cream);
  opacity: 0;
  transition: opacity .3s var(--ease);
}
.readout__name i {
  width: 11px; height: 11px; border-radius: 50%;
  background: currentColor;
  /* an outer ring, not an inner one: the charcoal swatch is nearly the page
     colour and an inset shadow only buried it further */
  box-shadow: 0 0 0 1px rgba(243, 239, 232, .45);
}
.readout__meta {
  min-height: 1.1rem;
  font: 400 .7rem/1.4 var(--ui); letter-spacing: .12em; text-transform: uppercase;
  color: var(--mute-2);
  opacity: 0;
  transition: opacity .3s var(--ease);
}
.readout.is-on .readout__hint  { opacity: 0; }
.readout.is-on .readout__name,
.readout.is-on .readout__meta  { opacity: 1; }

.readout__count {
  margin-top: .7rem; padding-top: .7rem;
  border-top: 1px solid var(--line);
  font: 400 .7rem/1 var(--ui); letter-spacing: .13em; text-transform: uppercase;
  color: var(--mute-2);
  transition: opacity .4s var(--ease);
}
.readout__count b { color: var(--gold-lit); font-weight: 500; }

/* the payoff, once all four have been found */
.readout__score {
  display: flex; align-items: baseline; justify-content: flex-end; gap: .5rem;
  margin-top: .7rem; padding-top: .7rem;
  border-top: 1px solid var(--line);
  opacity: 0; transform: translateY(6px);
  transition: opacity .5s var(--ease), transform .5s var(--ease);
}
.readout__score span {
  font: 500 .64rem/1 var(--ui); letter-spacing: .17em; text-transform: uppercase;
  color: var(--gold-lit);
}
.readout__score b {
  font-family: var(--disp); font-size: 1.8rem; font-weight: 500; line-height: 1;
  color: var(--cream);
}
.readout__score em {
  font-family: var(--disp); font-size: .88rem; font-style: italic;
  color: var(--mute);
}
.readout.is-done .readout__count { opacity: 0; height: 0; margin: 0; padding: 0; border: 0; }
.readout.is-done .readout__score { opacity: 1; transform: none; }
/* once every piece has been read, the prompt has been answered. Bringing it
   back when the pointer leaves would ask for work already done. */
.readout.is-done .readout__hint { opacity: 0; }

/* ===========================================================================
   acts 01-03 - one screen each

   These were sticky stages sitting inside rails 1.5 to 1.8 screens tall, and
   the pin was the thing making the scroll feel broken. Measured: an act rose
   through a whole screen of scrolling with its reveal still at 0%, arrived
   filling the viewport completely empty, and only then -- with the page locked
   under the pin -- did the garment list and the score card play catch-up. Two
   gestures to see one step, the second of them against a frozen screen.

   So there is no pin. Each act is one screen in normal flow, and its timeline
   is bound to the approach instead of to the pin (see script.js): the content
   assembles as the act rises and is finished at the moment it fills the
   screen. One gesture, arriving complete. The choreography is untouched -- the
   boxes still draw, the ring still fills, the wipe still travels -- it just no
   longer needs the viewport held still to do it.
   =========================================================================== */
.act__rail { position: relative; }

.stage {
  min-height: 100svh;
  display: grid; place-items: center;
  padding: clamp(4.5rem, 10vh, 6.5rem) var(--pad) clamp(2rem, 6vh, 4rem);
}
.wrap {
  width: 100%; max-width: var(--maxw);
  display: grid; align-items: center;
  gap: clamp(2rem, 5vw, 5rem);
}
.side > * + * { margin-top: 1.35rem; }
.side .tag { margin-bottom: -.35rem; }

/* --- act 01, the read --- */
.wrap--read { grid-template-columns: minmax(0, .82fr) minmax(0, 1fr); }
.frame {
  position: relative;
  /* The scan sweep travels 1170% of its own height, so something has to clip
     it or it paints a loose gold slab below the picture. It used to get that
     from the stage's `overflow: hidden`, which went with the pin. The frame is
     where it belonged anyway -- the sweep is an event inside the photograph. */
  overflow: hidden;
  justify-self: center;
  width: 100%; max-width: 430px;
  aspect-ratio: 2 / 3;
}
.frame picture, .frame img { width: 100%; height: 100%; object-fit: cover; }
.frame img { border-radius: 2px; }

.scan {
  position: absolute; left: 0; right: 0; top: 0;
  height: 128px;
  background: linear-gradient(to bottom,
    transparent, rgba(227, 188, 124, .07) 62%, rgba(227, 188, 124, .5) 97%, var(--gold-lit));
  opacity: 0;
  pointer-events: none;
}
.boxes { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.boxes .b-rect {
  fill: none;
  stroke: rgba(227, 188, 124, .34);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.boxes .b-tick {
  fill: none;
  stroke: var(--gold-lit);
  stroke-width: 1.6;
  vector-effect: non-scaling-stroke;
}

.found { counter-reset: f; }
.found li {
  position: relative;
  display: grid;
  grid-template: 'sw name' auto 'sw meta' auto / 15px 1fr;
  align-items: center;
  gap: 0 .85rem;
  padding: .78rem 0;
  border-top: 1px solid var(--line);
}
.found li:last-child { border-bottom: 1px solid var(--line); }
.found i {
  grid-area: sw;
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--sw);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .45);
}
.found b { grid-area: name; font: 500 .95rem/1.35 var(--ui); }
.found span { grid-area: meta; font-size: .76rem; color: var(--mute-2); letter-spacing: .04em; }

/* --- act 02, the verdict --- */
.wrap--verdict { grid-template-columns: minmax(0, .88fr) minmax(0, 1.12fr); }
.card {
  position: relative;
  padding: clamp(1.5rem, 2.6vw, 2.3rem);
  border: 1px solid var(--line);
  border-radius: 4px;
  background:
    radial-gradient(120% 90% at 88% 0%, rgba(184, 134, 59, .1), transparent 62%),
    rgba(243, 239, 232, .028);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.card__top {
  display: flex; align-items: center; gap: clamp(1.1rem, 2.2vw, 1.9rem);
  padding-bottom: 1.5rem;
  border-bottom: 1px solid var(--line);
}
.ring { position: relative; flex: none; width: clamp(94px, 9vw, 116px); }
.ring svg { width: 100%; transform: rotate(-90deg); }
.ring__bg { fill: none; stroke: rgba(243, 239, 232, .1); stroke-width: 5; }
.ring__fg {
  fill: none; stroke: var(--gold-lit); stroke-width: 5; stroke-linecap: round;
  stroke-dasharray: 333; stroke-dashoffset: 333;
}
.ring__n {
  position: absolute; inset: 0;
  display: grid; grid-auto-flow: column;
  place-content: center; align-items: baseline;
  gap: 1px;
}
.ring__n b {
  font-family: var(--disp); font-size: clamp(1.85rem, 2.4vw, 2.3rem);
  font-weight: 500; line-height: 1;
}
.ring__n span { font-size: .68rem; color: var(--mute-2); }
.card__head .tag { margin-bottom: .35rem; }
.card__line {
  font-family: var(--disp); font-style: italic;
  font-size: clamp(1.02rem, 1.35vw, 1.24rem);
  line-height: 1.42; color: var(--cream);
}

.bars { padding: 1.35rem 0; border-bottom: 1px solid var(--line); }
.bars li {
  display: grid;
  grid-template-columns: minmax(8.5rem, auto) 1fr 2.2rem;
  align-items: center; gap: 1rem;
  padding: .43rem 0;
  font-size: .84rem;
}
.bars li > span { color: var(--mute); }
.bars i {
  position: relative; height: 2px; background: rgba(243, 239, 232, .1);
}
.bars i::after {
  content: '';
  position: absolute; inset: 0 auto 0 0;
  width: calc(var(--w, 0) * 1%);
  background: var(--gold-lit);
}
.bars li:nth-child(2) i::after { background: var(--flag); }
.bars b { font-weight: 500; text-align: right; font-variant-numeric: tabular-nums; }

.notes {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem 2rem;
  padding-top: 1.35rem;
}
.notes__h {
  margin-bottom: .7rem;
  font: 500 .68rem/1 var(--ui); letter-spacing: .17em; text-transform: uppercase;
}
.notes__c--good .notes__h { color: var(--good); }
.notes__c--flag .notes__h { color: var(--flag); }
.notes__c li {
  position: relative;
  padding-left: 1.3rem;
  font-size: .855rem; line-height: 1.55; color: var(--mute);
}
.notes__c li + li { margin-top: .65rem; }
.notes__c li::before {
  content: '';
  position: absolute; left: 0; top: .55em;
  width: 8px; height: 8px; border-radius: 50%;
}
.notes__c--good li::before { background: var(--good); }
.notes__c--flag li::before { background: var(--flag); }

/* --- act 03, the fix --- */
.wrap--fix {
  grid-template-columns: minmax(0, 1fr) minmax(0, .95fr) minmax(0, 1fr);
  align-items: center;
}
.side--lead { max-width: 24rem; }

.pair {
  position: relative;
  justify-self: center;
  width: 100%; max-width: 400px;
  aspect-ratio: 2 / 3;
}
.pair picture, .pair img { width: 100%; height: 100%; object-fit: cover; }
.pair__a { border-radius: 2px; }
.pair__b {
  position: absolute; inset: 0;
  border-radius: 2px; overflow: hidden;
  /* the reveal: a hard horizontal edge that travels down the frame */
  clip-path: inset(0 0 100% 0);
}
.pair__wipe {
  position: absolute; left: -2%; right: -2%; top: 0;
  height: 1px;
  background: var(--gold-lit);
  box-shadow: 0 0 22px 3px rgba(227, 188, 124, .5);
  opacity: 0;
}
.pair figcaption { position: absolute; inset: auto 0 0; }
.pair__lbl {
  position: absolute; bottom: .85rem;
  padding: .34rem .62rem;
  font: 500 .64rem/1 var(--ui); letter-spacing: .18em; text-transform: uppercase;
  background: rgba(8, 9, 12, .78);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  border-radius: 2px;
}
.pair__lbl--a { left: .85rem; color: var(--mute); }
.pair__lbl--b { right: .85rem; color: var(--gold-lit); opacity: 0; }

.fixnote > * + * { margin-top: 1.05rem; }
.fixnote__do {
  font-family: var(--disp);
  font-size: clamp(1.35rem, 2.1vw, 1.9rem);
  line-height: 1.24;
  color: var(--cream);
}
.fixnote__why { color: var(--mute); font-size: .93rem; max-width: 28ch; }
.fixnote__alt { color: var(--mute-2); font-size: .84rem; max-width: 28ch; }

.tick {
  display: inline-flex; align-items: center; gap: .7rem;
  padding: .62rem .95rem;
  border: 1px solid var(--line);
  border-radius: 3px;
}
.tick span {
  font: 500 .64rem/1 var(--ui); letter-spacing: .18em;
  text-transform: uppercase; color: var(--mute-2);
}
.tick b {
  font-family: var(--disp); font-size: 1.45rem; font-weight: 500; line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--mute);
}
.tick svg { width: 17px; height: 17px; color: var(--mute-2); }
.tick__new { color: var(--gold-lit) !important; }

/* ===========================================================================
   act 04 - three rooms
   =========================================================================== */
.rooms { padding: clamp(6rem, 14vh, 10rem) 0 0; }
.rooms__intro { padding: 0 var(--pad) clamp(2.5rem, 6vh, 4rem); }
.rooms__intro > * + * { margin-top: 1.35rem; }
.rooms__intro .tag { margin-bottom: -.35rem; }

/* On desktop this is a three-up, not the pinned horizontal rail the plan
   called for. Three cards do not exceed a 1440px viewport, so a horizontal
   scroll would have had roughly 120px of travel spread over three screens of
   scrolling: a pinned section that appears to do nothing. The three-up shows
   all three verdicts at once, which is the actual argument ("same you, three
   answers"), and each column drifts at its own rate on scroll instead. Below
   820px the three cards genuinely overflow, so there it becomes a real
   swipeable carousel. */
.rooms__rail { position: relative; }
.rooms__track {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 3vw, 3rem);
  padding: 0 var(--pad);
}
.room { display: grid; gap: 1.35rem; align-content: start; }
.room img {
  width: 100%; aspect-ratio: 3 / 4; object-fit: cover; object-position: 50% 26%;
  border-radius: 2px;
}
.room__body > * + * { margin-top: .7rem; }
.room__body .tag { margin-bottom: -.3rem; }
.room__body p { font-size: .9rem; color: var(--mute); }
.room h3 { font-size: clamp(1.55rem, 2.3vw, 2rem); }

.pill {
  display: inline-block;
  padding: .42rem .8rem;
  font: 500 .72rem/1 var(--ui); letter-spacing: .06em;
  border: 1px solid currentColor; border-radius: 100px;
}
.pill--good { color: var(--good); }
.pill--flag { color: var(--flag); }

/* ===========================================================================
   act 05 - the closet
   =========================================================================== */
.closet { padding: clamp(7rem, 16vh, 11rem) var(--pad) clamp(5rem, 10vh, 7rem); }
.closet__copy { max-width: 34rem; }
.closet__copy > * + * { margin-top: 1.35rem; }
.closet__copy .tag { margin-bottom: -.35rem; }

.count {
  display: flex; align-items: baseline; gap: .9rem;
  padding-top: .6rem;
}
.count b {
  font-family: var(--disp); font-size: clamp(3rem, 6vw, 4.6rem);
  font-weight: 400; line-height: .9; color: var(--gold-lit);
  font-variant-numeric: tabular-nums;
}
.count span { font-size: .84rem; color: var(--mute-2); max-width: 20ch; line-height: 1.4; }

.grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: clamp(.5rem, 1.2vw, 1rem);
  margin-top: clamp(2.5rem, 6vh, 4rem);
}
.tile {
  position: relative;
  padding: clamp(.7rem, 1.3vw, 1.1rem);
  border: 1px solid var(--line);
  border-radius: 3px;
  background: rgba(243, 239, 232, .022);
  transition: border-color .35s var(--ease), background .35s var(--ease);
}
.tile:hover { border-color: var(--line-2); background: rgba(243, 239, 232, .045); }
.tile img { width: 100%; aspect-ratio: 1; object-fit: contain; }
.tile figcaption {
  margin-top: .55rem;
  font-size: .7rem; letter-spacing: .05em; color: var(--mute-2);
  text-align: center;
}
.closet__foot {
  margin-top: clamp(2.5rem, 6vh, 3.5rem);
  max-width: 40ch;
  font-family: var(--disp); font-style: italic;
  font-size: clamp(1.05rem, 1.5vw, 1.3rem);
  color: var(--camel);
}

/* ===========================================================================
   act 06 - in your hand
   =========================================================================== */
.hand {
  padding: clamp(4rem, 9vh, 6rem) var(--pad) clamp(6rem, 13vh, 9rem);
  overflow: hidden;
}
.hand__copy { max-width: 34rem; }
.hand__copy > * + * { margin-top: 1.35rem; }
.hand__copy .tag { margin-bottom: -.35rem; }

.phones {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  align-items: center;
  gap: clamp(.9rem, 2.4vw, 2.2rem);
  margin-top: clamp(3rem, 8vh, 5rem);
}
.phone { position: relative; }
.phone--hero { transform: scale(1.1); z-index: 2; }
.phone--far  { opacity: .82; }

.phone__screen {
  position: relative;
  display: block;
  padding: 7px;
  border: 1px solid rgba(243, 239, 232, .16);
  border-radius: 26px;
  background: linear-gradient(150deg, rgba(243, 239, 232, .1), rgba(243, 239, 232, .015));
  box-shadow: 0 30px 70px -30px rgba(0, 0, 0, .9);
}
.phone__screen img { width: 100%; border-radius: 19px; }
.phone figcaption {
  margin-top: 1rem;
  font: 500 .7rem/1 var(--ui); letter-spacing: .18em;
  text-transform: uppercase; color: var(--mute-2);
  text-align: center;
}

/* ===========================================================================
   act 07 - privacy (deliberately still)
   =========================================================================== */
.privacy {
  position: relative;
  padding: clamp(6rem, 14vh, 9rem) var(--pad);
  background: var(--ink-2);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.privacy::before {
  content: '';
  position: absolute; inset: 0;
  background: url('assets/tex-backdrop-1100.webp') center / cover no-repeat;
  opacity: .3;
}
.privacy__inner { position: relative; }
.privacy__inner > * + * { margin-top: 1.35rem; }
.privacy__inner .tag { margin-bottom: -.35rem; }

.pledge {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: clamp(1.5rem, 3vw, 2.6rem);
  margin-top: clamp(2.5rem, 6vh, 3.6rem) !important;
}
.pledge > div { padding-top: 1.1rem; border-top: 1px solid var(--line-2); }
.pledge dt { font: 500 .95rem/1.4 var(--ui); }
.pledge dd { margin-top: .5rem; font-size: .86rem; line-height: 1.6; color: var(--mute); }

/* ===========================================================================
   act 08 - waitlist
   =========================================================================== */
.wait {
  position: relative;
  padding: clamp(7rem, 17vh, 12rem) var(--pad);
  text-align: center;
  overflow: hidden;
}
.wait::before {
  content: '';
  position: absolute; inset: -20% -10% auto;
  height: 130%;
  background: url('assets/tex-weave-1440.webp') center / cover no-repeat;
  opacity: .14;
  filter: saturate(.85);
}
.wait::after {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(70% 78% at 50% 46%, transparent, var(--ink) 76%);
}
.wait__inner { position: relative; z-index: 1; max-width: 46rem; margin: 0 auto; }
.wait__inner > * + * { margin-top: 1.5rem; }
.wait__inner .sub { margin-inline: auto; }

.wform { margin-top: 2.5rem !important; }
.wform__row {
  display: flex; gap: .6rem;
  max-width: 30rem; margin: 0 auto;
}
.wform input[type=email] {
  flex: 1; min-width: 0; min-height: 50px;
  padding: .8rem 1rem;
  background: rgba(8, 9, 12, .6);
  border: 1px solid var(--line-2); border-radius: 2px;
  font-size: .95rem;
}
.wform input[type=email]::placeholder { color: var(--mute-2); }
.wform input[type=email]:focus { border-color: var(--gold); }

.plat { display: flex; justify-content: center; gap: 1.4rem; margin-top: 1.1rem; border: 0; padding: 0; }
.plat label { display: inline-flex; align-items: center; gap: .5rem; cursor: pointer; font-size: .85rem; color: var(--mute); }
.plat input { accent-color: var(--gold); width: 15px; height: 15px; }

.msg { min-height: 1.4rem; margin-top: 1rem; font-size: .85rem; color: var(--gold-lit); }
.msg[data-err] { color: var(--flag); }

/* ===========================================================================
   act 09 - contact
   =========================================================================== */
.contact {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2.5rem, 6vw, 6rem);
  padding: clamp(5rem, 11vh, 7.5rem) var(--pad);
  border-top: 1px solid var(--line);
}
.contact__copy > * + * { margin-top: 1.35rem; }
.contact__copy .tag { margin-bottom: -.35rem; }
.contact__list { margin-top: 2.2rem !important; }
.contact__list li {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  padding: .85rem 0;
  border-top: 1px solid var(--line);
  font-size: .9rem;
}
.contact__list li:last-child { border-bottom: 1px solid var(--line); }
.contact__list span { color: var(--mute-2); font-size: .75rem; letter-spacing: .14em; text-transform: uppercase; }
.contact__list a { display: inline-block; padding: .25rem 0; color: var(--cream); border-bottom: 1px solid transparent; transition: border-color .3s var(--ease); }
.contact__list a:hover { border-color: var(--gold); }

.cform { display: grid; gap: 1.05rem; align-content: start; }
.field { display: grid; gap: .45rem; }
.field label { font-size: .76rem; letter-spacing: .13em; text-transform: uppercase; color: var(--mute-2); }
.field input, .field select, .field textarea {
  min-height: 48px;
  padding: .7rem .9rem;
  background: rgba(8, 9, 12, .6);
  border: 1px solid var(--line); border-radius: 2px;
  font-size: .93rem;
}
.field textarea { min-height: 118px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--gold); }
.cform .btn { justify-self: start; }

/* ===========================================================================
   footer
   =========================================================================== */
.foot {
  border-top: 1px solid var(--line);
  background: var(--ink-2);
}
.foot__top {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1.4fr);
  gap: clamp(2.5rem, 6vw, 5rem);
  padding: clamp(3.5rem, 8vh, 5rem) var(--pad);
}
.foot__mark { display: block; font: 500 1.05rem/1 var(--ui); letter-spacing: .34em; }
.foot__brand p { margin-top: .9rem; font-size: .88rem; color: var(--mute); max-width: 26ch; }
.foot__brand .stores { margin-top: 1.7rem; }

.foot__cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem; }
.foot__cols h3 {
  font-family: var(--ui); font-size: .72rem; font-weight: 500;
  letter-spacing: .17em; text-transform: uppercase; color: var(--mute-2);
  margin-bottom: 1rem;
}
.foot__cols a {
  display: block; padding: .55rem 0;
  font-size: .875rem; color: var(--mute);
  transition: color .3s var(--ease);
}
.foot__cols a:hover { color: var(--cream); }

.foot__bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 1rem;
  padding: 1.4rem var(--pad);
  border-top: 1px solid var(--line);
  font-size: .8rem; color: var(--mute-2);
}
.social { display: flex; gap: .35rem; }
.social a {
  display: grid; place-items: center;
  width: 40px; height: 40px;
  border: 1px solid var(--line); border-radius: 50%;
  color: var(--mute);
  transition: color .3s var(--ease), border-color .3s var(--ease);
}
.social svg { width: 16px; height: 16px; }
.social a:hover { color: var(--gold-lit); border-color: var(--gold); }

/* ===========================================================================
   mobile is designed, not squeezed
   =========================================================================== */
@media (max-width: 1080px) {
  .pledge { grid-template-columns: repeat(2, 1fr); }
  .grid { grid-template-columns: repeat(4, 1fr); }
  .wrap--fix { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .side--lead { grid-column: 1 / -1; max-width: 40rem; }
}

/* ---------------------------------------------------------------------------
   The nav collapses at 860, not at 1080. Four short links and a small button
   need about 620px; collapsing at 1080 put a hamburger on every laptop that
   had 400px of clear space in the bar, and hid the one action the page is
   asking for behind a tap.
--------------------------------------------------------------------------- */
@media (max-width: 860px) {
  .nav .btn--sm { display: none; }
  .nav__toggle { display: inline-flex; margin-left: auto; }
  .nav__links {
    display: flex; flex-direction: column; gap: 0;
    position: absolute; top: 100%; left: 0; right: 0;
    margin-left: 0;
    background: rgba(9, 10, 13, .97);
    border-bottom: 1px solid var(--line);
    backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    /* Compact on purpose. At 48px a row plus a full-size button the panel ran
       to 660px and covered the headline it had dropped over, so opening the
       menu read as the page having gone blank. */
    padding: .3rem var(--pad) .9rem;
    opacity: 0; visibility: hidden; transform: translateY(-8px);
    transition: opacity .25s var(--ease), transform .25s var(--ease), visibility .25s;
  }
  .nav__links.is-open { opacity: 1; visibility: visible; transform: translateY(0); }
  .nav__links a { min-height: 44px; font-size: .9rem; }
  .nav__links a.nav__links-cta {
    display: inline-flex; align-self: flex-start;
    min-height: 38px; margin-top: .55rem;
    /* Outlined, not filled. The hero's own waitlist button is usually still on
       screen behind the open panel, and two identical cream blocks a few
       hundred pixels apart read as the page having repeated itself. */
    background: none; color: var(--cream); border-color: var(--line-2);
  }
  .nav__links a.nav__links-cta:hover { background: none; border-color: var(--gold-lit); color: var(--gold-lit); }
}

@media (max-width: 900px) {
  /* A phone screen is shorter than the content of an act, so the stage stops
     insisting on a full screen and just takes the room it needs. */
  .stage {
    min-height: 0;
    padding-block: clamp(3rem, 7vh, 4.5rem);
  }

  .wrap--read, .wrap--verdict, .wrap--fix {
    grid-template-columns: 1fr;
    gap: clamp(1.6rem, 4vh, 2.4rem);
  }
  /* act 01 on a phone: heading, then the photograph above its findings.
     `.side` goes display:contents so its children join this flex column and
     can be reordered around the photograph. The column gap is zero because
     `.side > * + *` is already supplying the rhythm; letting both apply
     doubled every gap. */
  .wrap--read { display: flex; flex-direction: column; align-items: stretch; gap: 0; }
  .wrap--read .side { display: contents; }
  .wrap--read .tag  { order: 1; align-self: start; }
  .wrap--read h2    { order: 2; }
  .wrap--read .sub  { order: 3; }
  .wrap--read .frame { order: 4; max-width: min(78vw, 360px); align-self: center; margin-top: 2.2rem; }
  .wrap--read .found { order: 5; margin-top: 2.2rem; }

  .pair { max-width: min(78vw, 360px); }
  .notes { grid-template-columns: 1fr; gap: .65rem; }
  .fixnote { text-align: center; }
  .fixnote .tick { margin-inline: auto; }
  .fixnote__why, .fixnote__alt { margin-inline: auto; }

  .contact { grid-template-columns: 1fr; }
  .foot__top { grid-template-columns: 1fr; }
  .phones { grid-template-columns: repeat(2, 1fr); gap: 1.4rem 1rem; }
  .phone--hero { transform: none; }
}

@media (max-width: 820px) {
  /* the cold open becomes a full-bleed photograph with the type over it */
  .open {
    align-items: end;
    min-height: 100svh;
    padding-bottom: clamp(3.5rem, 9vh, 5rem);
  }
  .open__media { width: 100%; }
  .open__media img { object-position: 58% 14%; }
  .open__media::after {
    background:
      linear-gradient(to top, var(--ink) 24%, rgba(13, 14, 17, .82) 44%, transparent 76%),
      linear-gradient(to bottom, rgba(13, 14, 17, .72), transparent 26%);
  }
  .open__copy > * + * { margin-top: 1.15rem; }
  .cue { display: none; }
  /* the copy sits over the photograph here, so the reticle crosses live type.
     Held back a stop, it reads as an overlay on the picture rather than as
     marks on the headline. */
  .ret.is-live { opacity: .6; }
  /* The copy owns the bottom of the hero on a phone, so the readout moves to
     the top of the photograph. It goes left, clear of the waitlist button, and
     drops to caption size: at headline size it read as a second headline and
     fought the one that matters. */
  .readout {
    top: 6.8rem; bottom: auto;
    left: var(--pad); right: auto;
    width: auto; max-width: 58vw;
    text-align: left;
  }
  .readout__hint { display: none; }
  .readout__name {
    justify-content: flex-start;
    font-size: 1.02rem;
    min-height: 1.3rem;
  }
  .readout__name i { width: 9px; height: 9px; }
  .readout__meta { font-size: .62rem; letter-spacing: .1em; }
  .readout__count, .readout__score { margin: 0; padding: 0; border: 0; }
  .readout__count { display: none; }
  .readout__score { justify-content: flex-start; margin-top: .45rem; }
  .readout__score b { font-size: 1.4rem; }
  .readout__score em { display: none; }

  /* full-width primary action in the thumb zone, secondary on its own line */
  .cta { flex-direction: column; align-items: stretch; gap: 0; }
  .cta .btn { width: 100%; }
  .cta .link { justify-content: center; }

  /* act 04 becomes a real carousel here, because three cards genuinely
     overflow a phone and swiping is the native way to compare them */
  .rooms__track {
    display: flex;
    grid-template-columns: none;
    max-width: none;
    margin: 0;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-left: var(--pad);
    padding-bottom: 1rem;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    transform: none !important;
  }
  .rooms__track::-webkit-scrollbar { display: none; }
  .room { flex: none; width: min(76vw, 340px); scroll-snap-align: start; }

  .grid { grid-template-columns: repeat(3, 1fr); }
  .pledge { grid-template-columns: 1fr; }
  .pledge > div { padding-top: .9rem; }
}

@media (max-width: 560px) {
  h1 { font-size: clamp(2.4rem, 11vw, 3.2rem); }
  .nav { padding-block: .7rem; }
  .stores { gap: .45rem; }
  .store { flex: 1 1 auto; padding: .45rem .7rem; }
  .grid { grid-template-columns: repeat(2, 1fr); }
  .wform__row { flex-direction: column; }
  .foot__cols { grid-template-columns: 1fr 1fr; }
  .foot__bar { justify-content: center; text-align: center; }
  .count b { font-size: 3.2rem; }
  .bars li { grid-template-columns: 7.4rem 1fr 1.8rem; gap: .7rem; font-size: .8rem; }
}

/* ===========================================================================
   reduced motion - every act composes statically, nothing is hidden
   =========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .stage { min-height: 0; padding-block: clamp(4rem, 10vh, 6rem); }
  .pair__b { clip-path: inset(0 0 0 50%); }
  .pair__lbl--b { opacity: 1; }
  .scan { display: none; }
  .ret { display: none; }
  .ring__fg { stroke-dashoffset: 47; }
  .bars i::after { width: calc(var(--v, 80) * 1%); }
}
