/* ═══════════════════════════════════════════════════════════════════════
   Obeta — the site below the poster.

   v2 of this file was a centred 658px column and a set of comments explaining
   why it did not do what the reference does. This is the replication.

   Every number here was MEASURED off https://13studio.framer.website/ on a
   1440x900 viewport, not estimated:

     container      1600px max, 16px gutter        (was: 658px centred)
     alignment      text-align:start everywhere    (was: centred on <body>)
     display type   80px / 600 / -2.4px tracking   (was: 45px / positive)
     lead statement 34px / 500 / -1.02px / lh 35.7
     section title  32px / 600 / -0.64px
     nav + meta     18px / 500 / -0.18px
     body           16px / 400 / -0.32px
     page height    12,772px = 14.2 screens        (was: 8.7)

   Set in Quicksand and Archivo, on Obeta's own palette. Nothing of the
   reference's colour or typeface crosses over; its GEOMETRY is the whole
   point of the exercise.
   ═══════════════════════════════════════════════════════════════════════ */

:root{
  /* ── the shell ────────────────────────────────────────────────────────
     The reference runs near full-bleed: a 1600px cap and a 16px gutter, so
     at 1440 the content is 1408px wide — 97.8% of the window. The v2
     measure was 658px, 45.7%, which left 391px of dead white on each side
     and is the single loudest reason the page did not read like the
     reference. */
  --shell:min(calc(100vw - var(--gut) * 2), 1600px);
  --gut:clamp(16px, 1.11vw, 22px);

  /* ── the type scale ───────────────────────────────────────────────────
     Sizes are the reference's, expressed in vw so they hold their ratio to
     the shell. Each clamp resolves to the measured px at 1440.

     The TRACKING is the change that matters most. Every headline in v2 used
     positive letterspacing, which is what made the page read soft and wide
     rather than editorial and tight. The reference runs negative everywhere
     — -0.03em on display, -0.05em on the stat numbers. */
  --t-display:clamp(40px, 5.55vw, 80px);    /* 80.0px @1440 */
  --t-stat:clamp(44px, 5.55vw, 80px);       /* 80.0px */
  --t-lead:clamp(21px, 2.36vw, 34px);       /* 34.0px */
  --t-title:clamp(23px, 2.22vw, 32px);      /* 32.0px */
  --t-sub:clamp(18px, 1.67vw, 24px);        /* 24.0px */
  --t-nav:clamp(15px, 1.25vw, 18px);        /* 18.0px */
  --t-body:clamp(14px, 1.11vw, 16px);       /* 16.0px */

  /* ── the leading ladder ───────────────────────────────────────────────
     Measured off the reference by scripts/capture-reference.mjs and frozen
     in scripts/fixtures/reference-13studio.json. Before this ladder existed
     the file hardcoded eleven different ratios and left seven roles on
     `normal` — which is what read as "all over the place".

       reference @1440   80px:0.975  55:1.00  34:1.033  32:1.00
                         24:1.20     18:1.20  16:1.20
       @390 agrees: 16 and 18 both run 1.20 at weight 400.

     One deviation, on purpose: body copy runs 1.45, not the reference's
     1.20. The reference's 16px role is 26 short labels; Obeta's .body
     carries sentences to 46ch, and 1.20 on a paragraph is unreadable.
     Every other role matches the measurement. docs/TYPE-SPEC.md rule 6. */
  --lh-display:.98;
  --lh-lead:1.03;
  --lh-title:1;
  --lh-sub:1.2;
  --lh-label:1.2;
  --lh-body:1.45;

  /* ── the weights ──────────────────────────────────────────────────────
     Three, never four. The reference carries two. Weight 600 used to appear
     on 19 rules here, including 11px uppercase text — a rounded face at 600
     everywhere is what reads as bold. */
  --w-display:600;
  --w-lead:500;
  --w-label:500;
  --w-body:400;

  --tr-display:-.03em;
  --tr-stat:-.05em;
  --tr-lead:-.03em;
  --tr-title:-.02em;
  --tr-nav:-.01em;
  --tr-body:-.02em;

  /* vertical rhythm — the reference gives a section a screen, not a band */
  --sec-pad:clamp(80px, 11vh, 150px);

  /* ── motion ───────────────────────────────────────────────────────────
     The spring is sampled out of index.html's own stepSpring(cur,vel,target,
     k,c,m,dt) at zeta .9 — what Framer's bounce .1 resolves to, and what the
     reference carries on both of its text entries. One easing, two durations,
     so the page and the logo intro move in one language. */
  --ease-spring:linear(
    0.0000 0%, 0.0392 4%, 0.1308 8%, 0.2459 12%, 0.3662 16%, 0.4809 20%,
    0.5842 24%, 0.6735 28%, 0.7483 32%, 0.8094 36%, 0.8583 40%, 0.8966 44%,
    0.9260 48%, 0.9483 52%, 0.9648 56%, 0.9769 60%, 0.9855 64%, 0.9914 68%,
    0.9955 72%, 0.9982 76%, 0.9998 80%, 1.0008 84%, 1.0013 88%, 1.0015 92%,
    1.0015 96%, 1 100%);
  --ease-settle:cubic-bezier(.06,.55,.48,.99);
  --dur-text:1s;
  --dur-block:.8s;
}

/* Lenis drives the scroll, so the browser must not also be smoothing it. */
html.lenis,html.lenis body{height:auto}
.lenis.lenis-smooth{scroll-behavior:auto !important}
.lenis.lenis-stopped{overflow:hidden}

/* ── reveals ───────────────────────────────────────────────────────────
   opacity starts at .001 rather than 0 for the reason the reference does it:
   a genuinely zero-opacity layer gets dropped from the compositor and the
   first frame of the transition stutters. */
.js .rv,.js .rv-text{
  opacity:.001;
  transform:translate3d(0,80px,0);
  transition:opacity var(--dur-block) var(--ease-spring) var(--rv-delay,.2s),
             transform var(--dur-block) var(--ease-spring) var(--rv-delay,.2s);
  will-change:opacity,transform;
}
.js .rv-text{
  transform:translate3d(0,20px,0);
  transition-duration:var(--dur-text);
  transition-delay:var(--rv-delay,.1s);
}
.js .rv.in,.js .rv-text.in{opacity:1;transform:none;will-change:auto}

/* ── the custom cursor ─────────────────────────────────────────────────
   The reference tags its six work items with data-framer-cursor and swaps
   the pointer for a labelled disc over them. This is that, in Obeta's red.
   Pointer-coarse devices never get it. */
.cursor{
  position:fixed;top:0;left:0;z-index:9000;
  width:12px;height:12px;border-radius:50%;
  background:var(--red);
  pointer-events:none;
  transform:translate3d(-50%,-50%,0);
  transition:width .32s var(--ease-settle), height .32s var(--ease-settle),
             background-color .32s ease, opacity .3s ease;
  display:grid;place-items:center;
  opacity:0;
  mix-blend-mode:normal;
}
.cursor.on{opacity:1}
.cursor span{
  font-family:var(--display-face);font-weight:var(--w-label);
  font-size:12px;line-height:var(--lh-label);
  letter-spacing:.14em;text-transform:uppercase;
  color:#fff;opacity:0;transition:opacity .2s ease;white-space:nowrap;
}
.cursor.wide{width:82px;height:82px}
.cursor.wide span{opacity:1;transition-delay:.1s}
@media (pointer:coarse){ .cursor{display:none} }

/* ── the nav ───────────────────────────────────────────────────────────
   The reference: logo hard left, links centred, one item hard right, 54px
   tall, transparent over the hero, 18px type. */
.nav{
  position:fixed;inset:0 0 auto 0;z-index:100;
  display:flex;align-items:center;justify-content:space-between;
  gap:var(--gut);
  padding:18px var(--gut);
  font-family:var(--display-face);
  background:transparent;
  transition:background .45s ease, backdrop-filter .45s ease, opacity .7s ease .2s;
}
.nav.stuck{
  background:rgba(255,255,255,.82);
  backdrop-filter:blur(16px) saturate(1.4);
  -webkit-backdrop-filter:blur(16px) saturate(1.4);
}
html.loading .nav{opacity:0;pointer-events:none}

.nav-mark{display:flex;align-items:center;line-height:0;flex:none;min-height:44px}
.nav-mark img{width:clamp(76px, 7vw, 104px);height:auto;display:block}
.nav-mark span{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}

.nav-links{display:flex;align-items:center;gap:clamp(14px,1.6vw,24px);list-style:none}
.nav-links a,.nav-cta,.nav-toggle{
  font-family:var(--display-face);font-weight:var(--w-body);
  font-size:var(--t-nav);line-height:var(--lh-label);
  letter-spacing:var(--tr-nav);
  color:var(--c-rail);text-decoration:none;white-space:nowrap;
  transition:color .25s ease;
}
/* The reference draws the underline from the left on hover rather than
   fading a colour. A background-size transition does it with no extra
   element and no layout cost. */
.nav-links a{
  position:relative;padding:6px 0;
  background-image:linear-gradient(var(--c-display),var(--c-display));
  background-repeat:no-repeat;background-position:0 100%;
  background-size:0% 1.5px;
  transition:background-size .42s var(--ease-settle), color .25s ease;
}
.nav-links a:hover,.nav-links a.active{color:var(--c-display);background-size:100% 1.5px}
.nav-cta{
  font-weight:var(--w-display);color:var(--c-display);flex:none;
  border-bottom:1.5px solid var(--red);padding-bottom:4px;
}
.nav-links a:focus-visible,.nav-cta:focus-visible,
.nav-toggle:focus-visible,.nav-mark:focus-visible{
  outline:2px solid var(--cream);outline-offset:5px;border-radius:2px;
}
.nav-toggle{display:none;background:none;border:0;cursor:pointer;min-height:44px;padding:0}

/* ── the full-bleed hero ───────────────────────────────────────────────
   The reference pins its statement to the BOTTOM of a full-screen image
   (justify-content:flex-end) rather than centring it. The reel that plays
   behind it is ours, already rendered, and until now it sat in press/ and
   appeared on no page at all. */
.hero-full{
  position:relative;height:100svh;min-height:540px;
  display:flex;flex-direction:column;justify-content:flex-end;
  padding:0 var(--gut) clamp(28px,4vh,44px);
  overflow:hidden;isolation:isolate;
}
.hero-full video,.hero-full .hero-still{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;z-index:-2;
}
.hero-full::after{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(180deg,
    rgba(33,58,146,.30) 0%, rgba(33,58,146,.12) 34%, rgba(33,58,146,.78) 100%);
}
.hero-statement{
  font-family:var(--display-face);font-weight:var(--w-lead);
  font-size:var(--t-lead);letter-spacing:var(--tr-lead);
  line-height:var(--lh-lead);color:#fff;
  max-width:min(100%, 22em);
  text-wrap:balance;
}

/* ── sections ──────────────────────────────────────────────────────────
   Left-aligned, shell width. A white section stays transparent so the fixed
   room and its centre light carry the length of the page. */
.sec{
  position:relative;z-index:1;
  padding:var(--sec-pad) var(--gut);
  display:flex;flex-direction:column;align-items:flex-start;
}
.sec-inner{width:var(--shell);margin:0 auto;text-align:start}

/* The inversion. --ink and --cream are the two names every pairing in the
   poster is written against, so swapping them re-skins a whole section with
   two lines — the move the README describes for the SITE, scoped to one
   section. */
.sec-invert{
  --ink:#213A92; --cream:#FFFFFF;
  --c-display:rgba(255,255,255,1);
  --c-rail:rgba(255,255,255,.88);
  --c-body:rgba(255,255,255,.84);
  --c-quiet:rgba(255,255,255,.72);
  --c-hair:rgba(255,255,255,.26);
  --c-edge:rgba(255,255,255,.62);
  /* The one token the inversion used to miss. #CB262E on #213A92 measures
     1.85:1, so on a navy screen the form's only error message and the ask
     link's underline were both below the 3:1 floor for a control edge, let
     alone 4.5:1 for text. Same hue, lower saturation, 4.77:1 — computed, not
     eyeballed. */
  --red:#FF9499;
  background:#213A92;color:var(--c-body);
}

.eyebrow{
  font-family:var(--display-face);font-weight:var(--w-label);
  font-size:var(--t-body);line-height:var(--lh-label);
  letter-spacing:.2em;text-transform:uppercase;
  color:var(--c-quiet);
  display:flex;align-items:center;gap:.8em;
}
.eyebrow::before{content:"";width:38px;height:1.5px;background:var(--red);flex:none}
.sec-invert .eyebrow::before{background:var(--cream)}

/* The reference's display line: 80px, weight 600, tracking -0.03em, line
   height equal to the size. Set in Quicksand. */
.h-display{
  font-family:var(--display-face);font-weight:var(--w-display);
  font-size:var(--t-display);letter-spacing:var(--tr-display);
  line-height:var(--lh-display);color:var(--c-display);
  margin-top:.34em;max-width:18ch;text-wrap:balance;
}
.h-lead{
  font-family:var(--display-face);font-weight:var(--w-lead);
  font-size:var(--t-lead);letter-spacing:var(--tr-lead);
  line-height:var(--lh-lead);color:var(--c-display);
  max-width:26ch;text-wrap:balance;
}
.body{
  font-family:var(--sans);font-weight:var(--w-body);
  font-size:var(--t-body);letter-spacing:var(--tr-body);
  line-height:var(--lh-body);color:var(--c-body);
  max-width:46ch;text-wrap:pretty;
}
.sec-inner > * + *{margin-top:clamp(20px,2.4vw,34px)}
.h-display + .body,.h-lead + .body{margin-top:clamp(24px,2.8vw,40px)}

/* the count marker the reference sets as a superscript beside its title */
.count{
  font-size:.34em;font-weight:var(--w-label);letter-spacing:0;
  line-height:var(--lh-label);
  vertical-align:super;color:var(--c-quiet);
}

/* ── the sticky deck ───────────────────────────────────────────────────
   The reference's signature: a 100vh sticky track holding a centre card
   column, a label held on the left and a label that swaps on the right.
   Its cards measure 718x778; ours hold the same proportion. */
.deck{padding:0;display:block}
/* The sticky track pins inside THIS, so the pin releases when the cards end
   rather than running on over the module list. */
.deck-wrap{position:relative}
.deck-track{
  position:sticky;top:0;height:100svh;
  display:grid;grid-template-columns:1fr auto 1fr;
  align-items:center;gap:var(--gut);
  padding:0 var(--gut);
  pointer-events:none;
}
.deck-flank{
  font-family:var(--display-face);font-weight:var(--w-display);
  font-size:var(--t-title);letter-spacing:var(--tr-title);
  line-height:var(--lh-title);color:var(--c-display);
}
.deck-flank.right{text-align:left;position:relative;min-height:1.2em}
.deck-flank.right b{
  position:absolute;left:0;top:0;font-weight:inherit;white-space:nowrap;
  opacity:0;transform:translateY(8px);
  transition:opacity .45s ease, transform .45s var(--ease-settle);
}
.deck-flank.right b.on{opacity:1;transform:none}
.deck-slot{width:min(42vw, 718px);aspect-ratio:718/778}

.deck-cards{position:relative;z-index:1;margin-top:-100svh;pointer-events:none}
.deck-card{height:100svh;display:flex;align-items:center;justify-content:center}
.card{
  width:min(42vw, 718px);aspect-ratio:718/778;
  border-radius:10px;overflow:hidden;position:relative;
  background:var(--c-hair);pointer-events:auto;
  display:block;
}
.card img{
  width:100%;height:100%;object-fit:cover;display:block;
  transform:scale(1.02);
  transition:transform 1.1s var(--ease-settle), filter .6s ease;
}
.card:hover img{transform:scale(1.07)}
.card::after{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(178deg, rgba(33,58,146,.14) 0%, rgba(33,58,146,.52) 100%);
  mix-blend-mode:multiply;
  transition:opacity .6s ease;
}
.card:hover::after{opacity:.55}
.card figcaption{
  position:absolute;left:4%;right:4%;bottom:4%;z-index:2;
  display:flex;align-items:center;gap:.7em;
  background:rgba(255,255,255,.94);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  border-radius:99px;padding:14px 22px;
  font-family:var(--display-face);font-weight:var(--w-label);
  font-size:var(--t-body);line-height:var(--lh-label);
  letter-spacing:.14em;text-transform:uppercase;
  color:#213A92;
}
.card figcaption::before{content:"";width:.5em;height:.5em;border-radius:50%;background:var(--red);flex:none}

/* ── the gallery ───────────────────────────────────────────────────────
   The reference's Selected Works is not a grid of equal tiles; it is a
   four-row asymmetric scatter with an 840px row pitch, measured item by
   item on a 1440 viewport:

     row 1   x 70  718x778      x 798  572x515
     row 2   x 216 1009x741
     row 3   x 70  572x515      x 652  718x778
     row 4   x 216 1009x741

   A 12-column grid over the shell reproduces those positions and stays
   responsive, which absolute percentages would not. */
.gallery-grid{
  width:var(--shell);margin:0 auto;
  display:grid;grid-template-columns:repeat(12,1fr);
  column-gap:var(--gut);row-gap:clamp(40px,6vh,62px);
  align-items:start;
}
.g-item{display:block;position:relative;text-decoration:none}
.g-item:nth-child(1){grid-column:1 / span 6;  aspect-ratio:718/778}
.g-item:nth-child(2){grid-column:8 / span 5;  aspect-ratio:572/515}
.g-item:nth-child(3){grid-column:3 / span 8;  aspect-ratio:1009/741}
.g-item:nth-child(4){grid-column:1 / span 5;  aspect-ratio:572/515}
.g-item:nth-child(5){grid-column:7 / span 6;  aspect-ratio:718/778}
.g-item:nth-child(6){grid-column:3 / span 8;  aspect-ratio:1009/741}

.g-frame{position:absolute;inset:0;overflow:hidden;border-radius:10px;background:var(--c-hair)}
/* The image is oversized so the scroll-linked parallax has room to move it
   without ever exposing an edge. */
.g-frame img{
  width:100%;height:118%;object-fit:cover;display:block;
  position:absolute;left:0;top:-9%;
  transform:translate3d(0,var(--par,0px),0) scale(1.01);
  transition:transform .18s linear, filter .6s ease;
  filter:grayscale(.18) contrast(1.06);
}
.g-item:hover .g-frame img{filter:grayscale(0) contrast(1.12)}
.g-meta{
  position:absolute;left:0;right:0;top:calc(100% + 14px);
  display:flex;align-items:baseline;gap:.8em;
}
.g-meta b{
  font-family:var(--display-face);font-weight:var(--w-label);
  font-size:var(--t-nav);line-height:var(--lh-label);
  letter-spacing:var(--tr-nav);color:var(--c-display);
}
.g-meta span{
  font-family:var(--sans);font-size:var(--t-nav);line-height:var(--lh-label);
  letter-spacing:var(--tr-nav);color:var(--c-quiet);
}

/* ── the stat row ──────────────────────────────────────────────────────
   Four pairs across one row, the number at 80px with -0.05em. Ships only
   when real figures exist; the markup carries none by default. */
.stats{
  width:var(--shell);margin:0 auto;
  display:grid;grid-template-columns:repeat(4,1fr);
  column-gap:var(--gut);row-gap:46px;
}
.stat b{
  display:block;
  font-family:var(--display-face);font-weight:var(--w-display);
  font-size:var(--t-stat);letter-spacing:var(--tr-stat);
  line-height:var(--lh-display);color:var(--c-display);
}
.stat span{
  display:block;margin-top:.6em;
  font-family:var(--sans);font-size:var(--t-body);
  letter-spacing:var(--tr-body);line-height:1.45;color:var(--c-quiet);
  max-width:18ch;
}

/* ── the announcement row ──────────────────────────────────────────────
   The reference's News: a dated row per item, hairline separated. */
.posts{width:var(--shell);margin:0 auto;list-style:none}
.posts li{
  display:grid;grid-template-columns:minmax(120px,1fr) 3fr;
  gap:var(--gut);align-items:baseline;
  padding:clamp(24px,3vh,38px) 0;
  border-top:1px solid var(--c-hair);
}
.posts li:last-child{border-bottom:1px solid var(--c-hair)}
.posts .when{
  font-family:var(--display-face);font-weight:var(--w-label);
  font-size:var(--t-body);line-height:var(--lh-label);
  letter-spacing:.14em;text-transform:uppercase;
  color:var(--red);
}
.posts .what{
  font-family:var(--display-face);font-weight:var(--w-display);
  font-size:var(--t-sub);letter-spacing:var(--tr-title);
  line-height:var(--lh-title);color:var(--c-display);
}
.posts .what em{display:block;font-style:normal;font-family:var(--sans);
  font-weight:var(--w-body);font-size:var(--t-body);letter-spacing:var(--tr-body);
  line-height:var(--lh-body);color:var(--c-quiet);margin-top:.7em;max-width:52ch}

/* ── the modules ───────────────────────────────────────────────────────
   These rules were written as `.who-list` for a section that no longer has
   that markup, while `.modlist` — the class the module list actually
   carries — had no rule at all. The <ol> therefore rendered the browser's
   own decimal markers BESIDE the hand-written 01/02/03: "1. 01 Demo".
   Same declarations, correct selector, list-style off. */
.modlist{list-style:none;width:100%;display:grid;padding:0;margin:0}
.modlist li{
  display:grid;grid-template-columns:auto 1fr;
  align-items:baseline;gap:clamp(18px,2.4vw,40px);
  padding:clamp(20px,2.6vh,32px) 0;
  border-top:1px solid var(--c-hair);
}
.modlist li:last-child{border-bottom:1px solid var(--c-hair)}
.modlist .n{font-family:var(--display-face);font-weight:var(--w-label);
  font-size:var(--t-body);line-height:var(--lh-label);
  letter-spacing:.12em;color:var(--c-quiet);font-variant-numeric:tabular-nums}
.modlist .t{font-family:var(--sans);font-weight:var(--w-body);
  font-size:var(--t-sub);letter-spacing:var(--tr-body);
  line-height:var(--lh-sub);color:var(--c-body);max-width:52ch}
.modlist .t b{font-weight:var(--w-display);color:var(--c-display)}

/* The list used to be the last child of .deck-cards, which carries
   margin-top:-100svh and pointer-events:none — so it was dragged a full
   viewport up into the card overlap and could not be clicked. It is a
   sibling of the deck now, and takes the page's own gutter, because
   .deck{padding:0} gives its children none. */
/* No bottom padding: #gallery brings its own --sec-pad, and two full section
   pads stacked left a screen of empty white between the list and "The work". */
.modules{padding:var(--sec-pad) var(--gut) 0}


/* ── the facts table ───────────────────────────────────────────────────*/
.facts{list-style:none;width:100%;max-width:none}
.facts li{
  display:flex;align-items:baseline;justify-content:space-between;
  gap:var(--gut);padding:clamp(18px,2.4vh,30px) 0;
  border-top:1px solid var(--c-hair);
}
.facts li:last-child{border-bottom:1px solid var(--c-hair)}
.facts .k{font-family:var(--display-face);font-weight:var(--w-display);
  font-size:var(--t-sub);line-height:var(--lh-title);
  letter-spacing:var(--tr-title);color:var(--c-display)}
.facts .v{font-family:var(--display-face);font-weight:var(--w-label);
  font-size:var(--t-body);line-height:var(--lh-label);
  letter-spacing:.14em;text-transform:uppercase;
  color:var(--red);white-space:nowrap;display:flex;align-items:center;gap:.6em}
.facts .v::before{content:"";width:.45em;height:.45em;border-radius:50%;background:var(--red);flex:none}

/* ── the closing ask ───────────────────────────────────────────────────
   A link, never a second form. One capture field feeds one endpoint. */

/* ── the footer ────────────────────────────────────────────────────────
   The reference closes on a four-column sitemap, not two lines of legal
   type. */
.site-foot{
  position:relative;z-index:1;
  padding:clamp(56px,7vh,90px) var(--gut) clamp(34px,4vh,52px);
  border-top:1px solid var(--c-hair);
}
.foot-grid{
  width:var(--shell);margin:0 auto;
  display:grid;grid-template-columns:2fr 1fr 1fr 1fr;
  gap:clamp(28px,3vw,50px);align-items:start;
}
.foot-brand img{width:clamp(96px,9vw,150px);height:auto;display:block}
.foot-brand p{
  margin-top:1.2em;font-family:var(--sans);font-size:var(--t-body);
  letter-spacing:var(--tr-body);line-height:var(--lh-body);color:var(--c-quiet);max-width:30ch;
}
.foot-col h3{
  font-family:var(--display-face);font-weight:var(--w-label);
  font-size:var(--t-body);line-height:var(--lh-label);
  letter-spacing:.16em;text-transform:uppercase;
  color:var(--c-quiet);margin-bottom:1.1em;
}
.foot-col ul{list-style:none;display:flex;flex-direction:column;gap:.75em}
.foot-col a{
  font-family:var(--display-face);font-weight:var(--w-body);
  font-size:var(--t-nav);line-height:var(--lh-label);
  letter-spacing:var(--tr-nav);
  color:var(--c-display);text-decoration:none;
  display:inline-flex;align-items:center;min-height:32px;
  background-image:linear-gradient(var(--c-display),var(--c-display));
  background-repeat:no-repeat;background-position:0 100%;background-size:0% 1.5px;
  transition:background-size .42s var(--ease-settle);
}
.foot-col a:hover{background-size:100% 1.5px}
.foot-col a:focus-visible{outline:2px solid var(--cream);outline-offset:4px}
.foot-base{
  width:var(--shell);margin:clamp(40px,5vh,70px) auto 0;
  padding-top:22px;border-top:1px solid var(--c-hair);
  display:flex;justify-content:space-between;gap:var(--gut);flex-wrap:wrap;
  font-family:var(--sans);font-size:var(--t-body);line-height:var(--lh-body);
  letter-spacing:var(--tr-body);color:var(--c-quiet);
}

/* ── breakpoints ───────────────────────────────────────────────────────
   The reference's three bands, to the pixel. */
@media (max-width:1199.98px){
  .deck-slot,.card{width:min(54vw, 560px)}
  .stats{grid-template-columns:repeat(2,1fr)}
  .foot-grid{grid-template-columns:1fr 1fr 1fr}
  .foot-brand{grid-column:1 / -1}
}

@media (max-width:809.98px){
  .nav-links{display:none}
  .nav-cta{display:none}
  .nav-toggle{display:block}

  /* The reference's phone menu is a FULL-SCREEN overlay carrying the items
     at display size, one per line, left-aligned — not a dropdown strip. It
     slides in rather than snapping, which display:none can never do. */
  .nav-links{
    position:fixed;inset:0;z-index:95;
    display:flex;flex-direction:column;align-items:flex-start;
    /* .06em on a 48px link is 3px — the items read as one solid block.
       A stacked menu needs real space between tap targets. */
    justify-content:center;gap:clamp(10px,1.8vh,18px);
    padding:0 var(--gut);
    background:var(--ink);
    transform:translate3d(-100%,0,0);
    visibility:hidden;
    transition:transform .62s var(--ease-settle), visibility 0s .62s;
    pointer-events:none;
  }
  /* :checked is the script-free path; .open is the scripted one. Either opens it. */
  .nav-check:checked ~ .nav-links,
  .nav.open .nav-links{
    transform:none;pointer-events:auto;
    visibility:visible;transition:transform .62s var(--ease-settle), visibility 0s 0s;
  }
  .nav-links a,.nav.open .nav-cta{
    /* 10vw put "Who this training is for" past the right edge at 402px.
       8vw holds the longest label inside the gutter at every phone width. */
    font-size:clamp(26px,8vw,48px);
    line-height:var(--lh-lead);
    letter-spacing:var(--tr-display);
    text-transform:none;font-weight:var(--w-lead);color:var(--c-display);
    background-image:none;padding:.06em 0;
  }
  /* The CTA reads first in the overlay, and reads as a button rather than a
     56px link — at phone size an action set like a heading is not an action. */
  .nav.open .nav-cta{
    display:inline-flex;align-self:flex-start;border-bottom:0;
    background:var(--red);color:#fff;
    font-size:var(--t-nav);line-height:var(--lh-label);
    font-weight:var(--w-display);
    letter-spacing:.14em;text-indent:.14em;text-transform:uppercase;
    border-radius:4px;padding:.72em 1.6em;margin-bottom:clamp(14px,3vh,28px);
    min-height:44px;align-items:center;
  }
  .nav-toggle{position:relative;z-index:96}

  .sec{padding:clamp(64px,9vh,110px) var(--gut)}
  .deck-track{position:static;height:auto;display:block;padding-top:clamp(64px,9vh,110px)}
  .deck-flank.right,.deck-slot{display:none}
  .deck-cards{margin-top:0}
  .deck-card{height:auto;padding:14px 0}
  .card{width:100%}

  /* The scatter cannot hold on a phone; it becomes one column, and the size
     variation survives as alternating aspect ratios rather than as offsets. */
  .gallery-grid{grid-template-columns:1fr;row-gap:clamp(64px,9vh,96px)}
  .g-item:nth-child(n){grid-column:1 / -1}
  .stats{grid-template-columns:1fr 1fr}
  .posts li{grid-template-columns:1fr;gap:.6em}
  .foot-grid{grid-template-columns:1fr 1fr}
  .foot-brand{grid-column:1 / -1}
  .modlist li{grid-template-columns:1fr;gap:.4em}
  .hero-statement{max-width:100%}
}

/* ── motion off ────────────────────────────────────────────────────────
   Content still arrives; it does not travel. The logo intro already works
   this way — it skips the overlay entirely rather than shortening it. */
@media (prefers-reduced-motion:reduce){
  .rv,.rv-text,.g-frame img,.card img,.stat b.struck::after,
  .deck-flank.right b,.nav,.nav-links,.nav-links a,.foot-col a,
  .cursor,.rise,.plx-light,.plx-air{
    transition:none !important;animation:none !important;
  }
  /* .rise settles to its natural styles, so killing the animation is enough */
  .rise{opacity:1;transform:none}
  .stat b.struck::after{transform:scaleX(1)}
  .rv,.rv-text{opacity:1;transform:none}
  .plx-light,.plx-air{display:none}
  .g-frame img{transform:none}
  .cursor{display:none}
}

/* ── anchors ───────────────────────────────────────────────────────────
   The nav is fixed, so a target landing at y=0 lands underneath it. */
#question,#answer,#services,#gallery,#hours,#who,#ready,#news,#enroll,#capture{
  scroll-margin-top:96px;
}
#capture{scroll-margin-top:calc(50svh - 160px)}
#top{scroll-margin-top:0}

/* ── the hero photograph ───────────────────────────────────────────────
   The reference's hero is a full-bleed image with the content over it. The
   poster's type is navy on white, so the image carries a graduated veil:
   near-opaque where the wordmark and the seal sit, clearing toward the foot
   so the room is plainly a photograph and not a texture.

   .plate (index.html) still runs page-wide at 8% behind everything; this is
   the hero's own, at strength. */
.hero{position:relative;isolation:isolate;overflow:hidden}
.hero-bg{position:absolute;inset:0;z-index:-2;pointer-events:none;overflow:hidden}
.hero-bg picture,.hero-bg img{width:100%;display:block;object-fit:cover}
/* Overscan absorbs the parallax travel. At 134% the image can move -18% of
   its own height against the scroll and never expose an edge. */
.hero-bg img{height:134%;position:absolute;inset:-17% 0 auto 0;will-change:translate}

/* ── the living background ─────────────────────────────────────────────
   Three depths over the photograph, driven by the one job bus in site.js:
   the image travels against the scroll, a warm light crosses diagonally,
   and a mote layer runs with the scroll and faster. The page reads as a
   space rather than as a picture with text on it.

   Ported from philgoodesthestics.com, where the rates were tuned on video
   rather than on translate deltas — a still cannot show amplitude. */
.plx-light,.plx-air{
  position:absolute;left:0;right:0;pointer-events:none;will-change:translate;
}
.plx-light{
  top:-14%;bottom:-14%;z-index:2;
  background:radial-gradient(48% 40% at 58% 38%,
    rgba(255,148,153,.20), rgba(255,148,153,0) 72%);
  mix-blend-mode:screen;
}
.plx-air{
  top:-18%;bottom:-18%;z-index:3;opacity:.16;filter:blur(.7px);
  background-image:
    radial-gradient(3px 3px at 18% 32%, rgba(255,255,255,.50), transparent 65%),
    radial-gradient(2px 2px at 64% 12%, rgba(255,255,255,.40), transparent 65%),
    radial-gradient(2.5px 2.5px at 83% 57%, rgba(255,148,153,.38), transparent 65%),
    radial-gradient(2px 2px at 37% 76%, rgba(255,255,255,.34), transparent 65%),
    radial-gradient(3px 3px at 52% 46%, rgba(255,255,255,.28), transparent 65%),
    radial-gradient(2px 2px at 8% 88%, rgba(255,255,255,.30), transparent 65%);
  background-size:620px 620px;background-repeat:repeat;
}
/* The motes drift at rest on their own clock. `translate` carries the scroll
   and `background-position` carries the drift, so the two never fight. */
@media (prefers-reduced-motion:no-preference){
  .plx-air{animation:plx-drift 38s linear infinite}
  @keyframes plx-drift{from{background-position:0 0}to{background-position:0 -620px}}
}
.hero-bg::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,
    rgba(255,255,255,.965) 0%,
    rgba(255,255,255,.945) 38%,
    rgba(255,255,255,.86)  62%,
    rgba(255,255,255,.60)  82%,
    rgba(255,255,255,.34) 100%);
}
.hero .sheet{position:relative;z-index:1}

/* ── the hero, committed ───────────────────────────────────────────────
   The veiled version read as neither a photograph nor a clean poster. The
   reference's hero IS the image, so the image runs at strength and the
   poster’s marks invert to white over it. The signup left the hero for its
   own screen; the mark, the rails and the seal stay, so the logo intro
   still flies onto a seal that is on screen at load. */
.hero-bg::after{
  background:linear-gradient(180deg,
    rgba(20,30,64,.62) 0%,
    rgba(16,24,52,.66) 34%,
    rgba(16,24,52,.74) 72%,
    rgba(12,18,40,.90) 100%);
}
.hero{
  --c-display:#fff; --c-rail:#fff;
  --c-body:rgba(255,255,255,.96); --c-quiet:rgba(255,255,255,.90);
  --c-hair:rgba(255,255,255,.42); --c-edge:rgba(255,255,255,.78);
  justify-content:space-between;
  padding:calc(64px + 4vh) var(--gut) clamp(28px,4vh,46px);
}
/* The artwork is navy; over a photograph it has to be white. brightness(0)
   flattens it to black, invert(1) lifts it to white — one filter, no second
   copy of the asset to keep in sync with build-logo-parts.mjs. */
.hero .display img,.hero .ring img{filter:brightness(0) invert(1)}
.hero .ring{border-color:rgba(255,255,255,.9)}
.hero .rail-top i{color:#fff}
.hero .sheet{padding-top:0;padding-bottom:0}
.hero .poster{margin-top:clamp(12px,2vh,28px)}

.hero-statement{
  margin-top:clamp(20px,3.4vh,44px);
  font-family:var(--display-face);font-weight:var(--w-lead);
  font-size:var(--t-lead);letter-spacing:var(--tr-lead);
  line-height:var(--lh-lead);color:#fff;
  max-width:20ch;text-wrap:balance;
}

/* ── the capture screen ────────────────────────────────────────────────
   The poster's form, now on its own navy screen. The form's own rules are
   written against --ink/--cream, so the section's inversion re-skins it
   with no per-field override. */
.capture-wrap{width:100%;max-width:520px}
.capture-wrap .capture{width:100%;align-items:flex-start;text-align:start}
.capture-foot{width:100%;margin-top:clamp(28px,4vh,52px)}
.capture-foot .foot{display:flex;flex-direction:column;align-items:flex-start;gap:1.1em}
.capture-foot .social{justify-content:flex-start}
.capture-foot .fine{text-align:start}

/* ── nav inversion ─────────────────────────────────────────────────────
   v2 of this file carried a comment arguing the nav could not invert
   because "the hero is WHITE, so there is nothing to invert from." The hero
   is a dark photograph now, so the argument is void and the reference's
   behaviour applies: white over the image, navy once the image is gone. */
.nav:not(.stuck) .nav-links a,
.nav:not(.stuck) .nav-cta,
.nav:not(.stuck) .nav-toggle{color:rgba(255,255,255,.94)}
.nav:not(.stuck) .nav-links a{background-image:linear-gradient(#fff,#fff)}
.nav:not(.stuck) .nav-links a:hover,
.nav:not(.stuck) .nav-links a.active{color:#fff}
.nav:not(.stuck) .nav-mark img{filter:brightness(0) invert(1)}
@media (max-width:809.98px){
  /* the overlay paints its own ground, so the toggle over it is navy again */
  .nav.open .nav-toggle{color:var(--c-display)}
  .nav.open:not(.stuck) .nav-mark img{filter:none}
}

/* ── the open menu owns its own colours ────────────────────────────────
   The nav inverts to white over the photographic hero. The overlay paints an
   opaque white ground, so those same rules rendered white links on white.
   These come last so the open state wins on source order. */
@media (max-width:809.98px){
  .nav-check:checked ~ .nav-links,
  .nav.open .nav-links{background:#fff}
  .nav-check:checked ~ .nav-links a,
  .nav.open .nav-links a{color:#213A92;background-image:none}
  .nav.open .nav-links a:hover,.nav.open .nav-links a.active{color:#213A92}
  /* The CTA is a filled red button in the overlay, so its LABEL is white.
     This rule used to set color:var(--red) — red text inside a red box,
     which rendered as an empty red rectangle on a 402px screen. */
  .nav-check:checked ~ .nav-links .nav-cta,
  .nav.open .nav-cta{color:#fff;border-bottom:0}
  .nav-check:checked ~ .nav-toggle,
  .nav.open .nav-toggle{color:#213A92}
  .nav-check:checked ~ .nav-mark img,
  .nav.open .nav-mark img{filter:none}
}
@media (max-width:809.98px){
  /* the overlay is a child of .nav, so it paints over its siblings unless
     the mark is lifted with it */
  .nav-mark{position:relative;z-index:96}
}
/* the list takes focus only to anchor the trap; it is not an interactive
   target, so it does not draw a ring around the whole screen */
.nav-links:focus{outline:none}

/* ── the deck's opening pane ───────────────────────────────────────────
   The client's question and its answer used to be two standalone sections
   ahead of the deck, which pushed the reference's signature scroll behaviour
   two screens later than the reference puts it. Folding them into the deck
   restores the beat order and gives the deck the four screens the reference
   gives its own. */
.deck-lead{
  min-height:100svh;
  display:flex;flex-direction:column;justify-content:center;
  padding:var(--sec-pad) var(--gut);
}

/* ── the numbers band ──────────────────────────────────────────────────
   The reference carries a four-pair stat row here. Every pair on this page
   is a fact it can already stand behind; no enrolment or graduate figure
   exists, so none is printed. */
#numbers{min-height:100svh;justify-content:center}
.stat b.struck{position:relative;display:inline-block}
.stat b.struck::after{
  content:"";position:absolute;left:-3%;right:-3%;top:52%;height:max(4px,.05em);
  background:var(--red);border-radius:99px;
  transform:scaleX(0);transform-origin:left center;
  transition:transform .9s var(--ease-settle) .4s;
}
.rv.in .stat b.struck::after,.stat b.struck.in::after{transform:scaleX(1)}

/* the announcement band holds three rows like the reference's news row */
#news{min-height:100svh;justify-content:center}


/* the social row belongs in the footer, not orphaned above it */
.foot-col .social{display:flex;gap:.4em;align-items:center}
.foot-col .social a{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:36px;min-height:36px;border-radius:50%;
  color:var(--c-display);background-image:none;
}
.foot-col .social a:hover{background:var(--c-hair)}
.foot-col .social svg{width:17px;height:auto;fill:currentColor;display:block}

/* the hero's instruction is a real target, not a sentence */
.tag a{color:inherit;text-decoration:none;border-bottom:1.5px solid var(--red);padding-bottom:.18em}
.tag a:hover{border-bottom-color:currentColor}
.tag a:focus-visible{outline:2px solid currentColor;outline-offset:4px}

/* A display line at 80px with line-height 1 has descenders that reach into
   whatever follows. The stat row and the announcement rows both landed on top
   of it; they need a real gap, not the default stack step. */
.h-display + .stats,
.h-display + .posts,
.h-display + .facts{margin-top:clamp(44px,5.4vw,78px) !important}
.h-display + .gallery-grid{margin-top:clamp(36px,4vw,60px)}

/* ── the second pinned interaction: tried, reverted ───────────────────
   A cross-audit seat noted the reference closes on a 1.6-screen sticky
   testimonial stack, and that dropping testimonials (there are no graduates
   to quote) also dropped the back half's only scroll interaction.

   Stacking the four who-it's-for rows was the obvious substitute and it does
   not work: the rows sit in a grid, so each sticks only within its own track,
   and on the inverted section every card paints navy over navy. The result
   was one visible row above a half-screen void — measurably worse than the
   flat list. A panel's suggestion is not a mandate; this is recorded as tried
   and rejected rather than silently skipped.

   The honest version needs distinct cards on a contrasting ground, which
   means real testimonials. It waits for a graduate. */

.nav-toggle{cursor:pointer;user-select:none}

@media (max-width:809.98px){
  /* The label follows the list in source order so the sibling combinator can
     reach the list; flex order puts it back on the right of the bar. */
  .nav-toggle{order:3}
  .nav-mark{order:1}
  .nav-links{order:2}
}



/* ── Phil's memo round ─────────────────────────────────────────────────
   Memo 7, in his order: the white over the photograph was unreadable, the
   ask was a sentence rather than a button, and the seal said "Ohio /
   Academy" where his credential belongs. */

/* The ask is a call to action now: white on the ring red, not a link. */
.tag .cta-button{
  display:inline-block;
  background:var(--red);
  color:#fff;
  border:0;
  border-radius:4px;
  padding:.62em 1.5em;
  font-family:var(--display-face);font-weight:var(--w-display);
  font-size:var(--t-nav);line-height:var(--lh-label);
  letter-spacing:.14em;text-indent:.14em;text-transform:uppercase;
  text-decoration:none;
  transition:background .25s ease, transform .2s var(--ease-settle);
}
.tag .cta-button:hover{background:#B01F26;transform:translateY(-1px)}
.tag .cta-button:focus-visible{outline:3px solid #fff;outline-offset:3px}

/* His credential, under the seal, where he asked for it. */
.credential{
  margin-top:calc(var(--d) * .30);
  font-family:var(--display-face);font-weight:var(--w-label);
  font-size:max(12px, var(--t-body));
  letter-spacing:.14em;text-indent:.14em;text-transform:uppercase;
  line-height:var(--lh-label);color:#fff;
}
.credential .lic{
  display:block;font-weight:var(--w-body);
  letter-spacing:.18em;text-indent:.18em;
  color:rgba(255,255,255,.92);
}

/* The address he gave in memo 6, on the front page. */
.hero-address{
  align-self:flex-start;
  font-family:var(--display-face);font-weight:var(--w-label);
  font-size:max(12px, var(--t-body));line-height:var(--lh-label);
  letter-spacing:.1em;color:#fff;
}

/* The address ran straight into the headline and wrapped mid-city. It gets
   its own air and enough width to hold one line. */
.hero-address{
  align-self:center;
  margin-top:calc(var(--d) * .62);
  white-space:nowrap;
}

/* PHIL, memo 7: "which I can't really see the Obeta in it, the way you got it
   with the white." The inverted mark lost the Ohio shape at ring size. The
   ring grows until the state and the wordmark inside it read. */
.hero .seal{margin-top:calc(var(--d) * .46)}
.hero .ring{width:calc(var(--d) * 1.45);height:calc(var(--d) * 1.45)}
.hero .ring img{width:95%}

/* Phil calls all three "vital questions that all cosmetologists want to know".
   Rendered at body size under a 56px headline they read as footnotes. */
.qlist{list-style:none;width:100%;max-width:calc(var(--u) * 40);margin-top:clamp(28px,3.4vw,48px) !important}
.qlist li{
  display:grid;grid-template-columns:auto 1fr;gap:.7em;
  font-family:var(--display-face);font-weight:var(--w-body);
  font-size:var(--t-sub);letter-spacing:var(--tr-body);
  line-height:var(--lh-sub);color:var(--c-display);
  padding:.62em 0;border-top:1px solid var(--c-hair);
}
.qlist li:last-child{border-bottom:1px solid var(--c-hair)}
.qlist li::before{content:"";width:.42em;height:.42em;border-radius:50%;
  background:var(--red);margin-top:.5em}
#questions .h-lead{margin-top:clamp(30px,3.6vw,52px) !important}
