/* ==================================================================
   TAP° 3D — design system
   Brand tokens are lifted from the live tapmediahouse.com homepage so
   this prototype can be dropped in without a re-skin.
================================================================== */
:root{
  --black:#0D0D0D;
  --ink:#070708;
  --cream:#F5F0E8;
  --gold:#C9A84C;
  --gold-hi:#E7CE86;
  --slate:#3A3A4A;
  --line:rgba(201,168,76,.16);
  --hair:rgba(245,240,232,.07);
  --fd:'Cormorant Garamond',Georgia,serif;
  --fb:'Montserrat',system-ui,-apple-system,sans-serif;
  --ease:cubic-bezier(.16,1,.3,1);
  --gut:clamp(20px,5vw,80px);

  /* ── legibility ramp ──────────────────────────────────────────
     Every piece of body and label copy picks one of these three
     instead of hand-rolling an alpha. The old page ran 8.5–10px
     uppercase at .28–.42em tracking on 30–50% alpha; wide tracking
     thins the perceived stroke, so those two choices compounded and
     the result failed to read at all on a phone. Floors, not
     preferences — do not reintroduce a bare rgba() below --t3.      */
  --t1:rgba(245,240,232,.92);   /* primary body copy            */
  --t2:rgba(245,240,232,.74);   /* secondary / supporting copy  */
  --t3:rgba(245,240,232,.58);   /* the dimmest anything may go  */

  /* Micro-labels (uppercase, tracked). Never smaller than --ms. */
  --ms:11.5px;
}

*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:auto;background:var(--ink);overflow-x:hidden}
body{
  margin:0;background:var(--ink);color:var(--cream);
  font-family:var(--fb);font-weight:300;-webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
a{color:inherit;text-decoration:none}
em{font-style:italic}
::selection{background:var(--gold);color:var(--ink)}

/* ── preloader ─────────────────────────────────────────────── */
#preload{
  position:fixed;inset:0;z-index:200;background:var(--ink);
  display:grid;place-content:center;gap:22px;justify-items:center;
  transition:opacity .9s var(--ease),visibility .9s;
}
/* pointer-events matters: `visibility` transitions DISCRETELY, so for the
   full .9s fade this full-screen overlay still swallows every tap — the
   nav looks alive but nothing responds. */
#preload.done{opacity:0;visibility:hidden;pointer-events:none}
.pre-logo{width:clamp(150px,26vw,220px);height:auto;opacity:.94}
.pre-bar{width:min(240px,50vw);height:1px;background:var(--hair);overflow:hidden}
.pre-bar i{display:block;height:100%;width:0;background:var(--gold);transition:width .4s linear}
.pre-note{font-size:var(--ms);letter-spacing:.3em;text-transform:uppercase;color:var(--t3)}

/* ── the fixed WebGL stage ─────────────────────────────────── */
#stage{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden;opacity:0;transition:opacity 1.2s var(--ease)}
#stage.live{opacity:1}
#gl{display:block;width:100%;height:100%;position:relative;z-index:1}
/* backdrop plates sit under the canvas; the canvas only becomes
   transparent when data.js actually declares one */
#plates{position:absolute;inset:0;z-index:0;overflow:hidden;background:var(--ink)}
#plates video{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity .5s linear;filter:saturate(.72) contrast(1.08);
}
/* NOTE: both of these must sit above #gl's z-index:1, or the canvas
   paints over them and the exploded view loses all its labelling. */
#leaders{position:absolute;inset:0;width:100%;height:100%;overflow:visible;z-index:2}
#leaders line{stroke:var(--gold);stroke-width:.6;opacity:.5}
#leaders circle{fill:var(--gold)}

/* exploded-view labels (Act II) — DOM text projected onto 3D points */
#labels{position:absolute;inset:0;z-index:3}
.lbl{
  position:absolute;transform:translate(0,-50%);white-space:nowrap;
  opacity:0;transition:opacity .35s linear;will-change:transform,opacity;
}
.lbl b{
  display:block;font-family:var(--fd);font-size:clamp(18px,1.7vw,25px);
  font-weight:400;letter-spacing:.01em;color:var(--cream);
}
.lbl i{
  display:block;font-style:normal;font-size:var(--ms);letter-spacing:.24em;
  font-weight:500;text-transform:uppercase;color:var(--gold-hi);margin-bottom:6px;
}
.lbl u{
  display:block;text-decoration:none;font-size:13px;letter-spacing:.02em;
  color:var(--t2);margin-top:4px;
}
.lbl.right{transform:translate(-100%,-50%);text-align:right}
/* No room for the second line on a phone — the label alone still reads */
@media(max-width:720px){
  .lbl u{display:none}
  .lbl b{font-size:16px}
  .lbl i{font-size:10px;letter-spacing:.18em;margin-bottom:4px}
}

/* film grain + vignette — the "shot on something expensive" tax */
.grain{
  position:absolute;inset:-120%;opacity:.045;pointer-events:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  animation:grain 1.1s steps(4) infinite;
}
@keyframes grain{
  0%{transform:translate(0,0)}25%{transform:translate(-3%,2%)}
  50%{transform:translate(2%,-3%)}75%{transform:translate(-2%,-2%)}100%{transform:translate(0,0)}
}
.vig{position:absolute;inset:0;background:radial-gradient(120% 90% at 50% 45%,transparent 42%,rgba(3,3,4,.72) 100%)}

/* ── chapters ──────────────────────────────────────────────── */
#chapters{position:fixed;inset:0;z-index:2;pointer-events:none}
.chap{
  position:absolute;inset:0;display:grid;align-content:center;
  padding:0 var(--gut);opacity:0;visibility:hidden;will-change:opacity,transform;
}
.chap.on{visibility:visible}
.chap-in{position:relative;max-width:min(720px,92vw);will-change:transform,opacity}

/* Legibility pool.
   The chapters are DOM over a live WebGL canvas, so nothing in CSS can
   know what is behind them — and at several beats it is a cloud of
   bloom-lit gold shards, which turns cream type into mush. A soft
   ellipse sized to the copy block itself buys guaranteed contrast
   without laying a visible box over the artwork: at closest-side it is
   fully transparent by the time it reaches the corners. The camera lift
   in main.js does the coarse work; this covers what is left. */
.chap-in::before{
  content:'';position:absolute;inset:-16% -12%;z-index:-1;pointer-events:none;
  background:radial-gradient(closest-side ellipse at 50% 50%,
    rgba(5,5,6,.80),rgba(5,5,6,.52) 56%,transparent 82%);
}
/* The low lane already runs a full-width gradient of its own. */
.chap[data-lane=low] .chap-in::before{display:none}
.chap[data-align=center]{justify-items:center;text-align:center}
.chap[data-align=center] .chap-in{max-width:min(880px,94vw)}
.chap[data-align=right]{justify-items:end;text-align:right}
.chap[data-align=right] .chap-in,
.chap[data-align=left]  .chap-in{margin-inline:0}
@media(min-width:900px){
  .chap[data-align=left]  .chap-in{margin-left:2vw}
  .chap[data-align=right] .chap-in{margin-right:2vw}
}

/* ── the low lane (Act III) ───────────────────────────────────────
   A centred headline cannot share the frame with a corridor panel:
   the panel bakes the client's own name into its texture at 74px, so
   two headlines land on the same pixels and neither reads. Chapters
   marked `lane="low"` drop to the bottom band instead — the corridor
   lifts its panels into the upper two thirds to match (see
   acts/corridor.js), so the two never occupy the same rows.

   The scrim is the insurance policy: the panels sway with the camera,
   so a few rows of overlap are always possible on some aspect ratio.  */
.chap[data-lane=low]{align-content:end;padding-bottom:clamp(38px,7vh,86px)}
.chap[data-lane=low] .chap-in{max-width:min(620px,88vw)}
.chap[data-lane=low] .h{font-size:clamp(31px,4.4vw,58px);line-height:1.04}
.chap[data-lane=low] .b{
  margin-top:clamp(12px,1.4vw,18px);max-width:44ch;
  font-size:clamp(13.5px,1.05vw,15.5px);line-height:1.75;
}
.chap[data-lane=low] .k{margin-bottom:clamp(10px,1.2vw,16px)}
.chap[data-lane=low]::before{
  content:'';position:absolute;inset:auto 0 0;height:74%;z-index:-1;
  background:linear-gradient(180deg,transparent,rgba(6,6,7,.62) 42%,rgba(5,5,6,.9));
  pointer-events:none;
}
/* ── under the wordmark (the closing chapter) ──────────────────────
   The reform brings TAP° back together directly above this copy. The
   block stays optically centred; the padding just biases it down far
   enough that the kicker clears the descenders of the mark. */
.chap[data-lane=mark]{padding-top:clamp(80px,16vh,150px)}

/* Phones: the floating WhatsApp button and the contact dock both live in
   the bottom-right corner the low lane now occupies. Clear them. */
@media(max-width:760px){
  .chap[data-lane=low]{padding-bottom:calc(148px + env(safe-area-inset-bottom))}
  .chap[data-lane=low] .chap-in{max-width:100%}
  .chap[data-lane=low] .h{font-size:clamp(28px,7.4vw,40px)}
}

/* The chapter number ("01 — The premise") is the one label that has to
   read against a moving, bloom-lit canvas rather than flat black, so it
   gets the gold highlight and a weight bump on top of the size floor —
   at 10px/.42em/--gold it was reported as simply not visible. */
.k{
  font-size:clamp(11.5px,1vw,13px);letter-spacing:.3em;text-transform:uppercase;
  font-weight:500;color:var(--gold-hi);margin:0 0 clamp(14px,2vw,24px);
  text-shadow:0 1px 14px rgba(7,7,8,.9);
}
.h{
  font-family:var(--fd);font-weight:300;margin:0;
  font-size:clamp(38px,6.6vw,92px);line-height:.98;letter-spacing:-.015em;
  text-wrap:balance;
}
.chap[data-size=xl] .h{font-size:clamp(46px,9vw,140px)}
.chap[data-size=lg] .h{font-size:clamp(42px,7.6vw,110px)}
.h em{display:block;color:var(--gold);font-style:italic}
.chap[data-align=center] .h em{display:inline}
.b{
  margin:clamp(18px,2.6vw,30px) 0 0;max-width:52ch;
  font-size:clamp(14.5px,1.25vw,17.5px);line-height:1.85;font-weight:300;
  color:var(--t2);text-shadow:0 1px 16px rgba(7,7,8,.85);
}
.chap[data-align=center] .b{margin-inline:auto}
.chap[data-align=right]  .b{margin-left:auto}

/* word-by-word reveal — the mask needs headroom for descenders,
   otherwise "gy" gets guillotined by overflow:hidden */
.h .w{display:inline-block;overflow:hidden;vertical-align:top;
      padding-bottom:.14em;margin-bottom:-.14em}
.h .w>span{display:inline-block;transform:translateY(102%);transition:transform .9s var(--ease)}
.chap.on .h .w>span{transform:translateY(0)}

.scroll-hint{
  margin-top:clamp(30px,5vw,54px);display:inline-flex;align-items:center;gap:12px;
  font-size:11px;letter-spacing:.3em;text-transform:uppercase;color:var(--t3);
}
.scroll-hint i{display:block;width:44px;height:1px;background:var(--hair);position:relative;overflow:hidden}
.scroll-hint i::after{
  content:'';position:absolute;inset:0;background:var(--gold);
  transform:translateX(-100%);animation:sweep 2.4s var(--ease) infinite;
}
@keyframes sweep{0%{transform:translateX(-100%)}60%,100%{transform:translateX(100%)}}

.chap-cta{margin-top:clamp(26px,4vw,44px);display:flex;gap:14px;flex-wrap:wrap;justify-content:center;pointer-events:auto}

/* ── nav ───────────────────────────────────────────────────── */
#nav{
  position:fixed;top:0;left:0;right:0;z-index:20;
  display:flex;align-items:center;justify-content:space-between;gap:20px;
  padding:16px var(--gut);
  opacity:0;transform:translateY(-12px);pointer-events:none;
  transition:opacity .7s var(--ease),transform .7s var(--ease);
  /* A scrim, not mix-blend-mode: difference would invert the raster
     logo to something unrecognisable over the gold shards. The blur is
     what keeps section copy from reading straight through the nav once
     you are past the film. */
  background:linear-gradient(180deg,rgba(7,7,8,.94),rgba(7,7,8,.72) 58%,rgba(7,7,8,.28));
  backdrop-filter:blur(14px);
  -webkit-backdrop-filter:blur(14px);
}
/* Over the opaque page below the film, go fully solid. */
#nav.solid{
  background:rgba(8,8,9,.97);
  border-bottom:1px solid var(--hair);
}
#nav.show{opacity:1;transform:none;pointer-events:auto}
#nav .brand{display:block;flex:0 0 auto}
#nav .brand img{display:block;width:auto;height:clamp(30px,3.4vw,40px)}
/* The nav used to vanish entirely below 1080px — a common laptop width —
   leaving a bare logo. It now tightens in stages and only collapses to
   the burger on genuinely narrow screens. */
#nav nav{display:none;gap:clamp(10px,1.5vw,28px);flex-wrap:nowrap;justify-content:center;min-width:0}
@media(min-width:880px){#nav nav{display:flex}}
#nav nav a{font-size:12px;letter-spacing:.15em;text-transform:uppercase;color:#fff;transition:color .3s;white-space:nowrap}
/* The full set no longer fits at 12px until ~1320px. Shedding the two
   lowest-value items buys the size back rather than shrinking the whole
   bar to something nobody can read — they stay in the footer and the
   mobile sheet, so nothing becomes unreachable. */
@media(max-width:1320px){
  #nav nav a:nth-child(7),      /* Campus  */
  #nav nav a:nth-child(9){display:none}   /* FAQ */
  #nav nav{gap:clamp(10px,1.3vw,18px)}
  #nav nav a{font-size:11px;letter-spacing:.12em}
}
@media(max-width:1080px){
  #nav nav a:nth-child(4){display:none}   /* Portfolio */
}
#nav nav a:hover{color:var(--gold-hi)}
.nav-right{display:flex;align-items:center;gap:10px;flex:0 0 auto}
.nav-ico{
  display:none;place-items:center;width:36px;height:36px;border-radius:50%;
  border:1px solid var(--line);color:rgba(245,240,232,.72);transition:.35s var(--ease);
}
@media(min-width:600px){.nav-ico{display:grid}}
.nav-ico:hover{border-color:var(--gold);color:var(--gold-hi)}
.nav-cta{
  font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;white-space:nowrap;
  border:1px solid var(--line);padding:11px 18px;border-radius:100px;
  transition:border-color .4s,color .4s;
}
.nav-cta:hover{border-color:var(--gold);color:var(--gold-hi)}

/* sign in — always reachable, including on a phone. Burying the account
   behind the burger is how "sign in isn't there on mobile" happens. */
.signin{position:relative;display:block}
.nav-signin{
  display:flex;align-items:center;gap:8px;cursor:pointer;
  background:none;border:1px solid var(--line);border-radius:100px;
  padding:10px 16px;color:var(--t1);font-family:var(--fb);
  font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;
  transition:.4s var(--ease);
}
.nav-signin:hover{border-color:var(--gold);color:var(--gold-hi)}
.signin-menu{
  position:absolute;right:0;top:calc(100% + 12px);width:290px;
  background:rgba(12,12,13,.97);backdrop-filter:blur(18px);
  border:1px solid var(--line);padding:8px;display:grid;gap:1px;
  box-shadow:0 30px 70px -30px rgba(0,0,0,.9);
  max-height:min(74vh,620px);overflow:auto;
}
.signin-menu[hidden]{display:none}
.menu-head{padding:12px 14px 14px;border-bottom:1px solid var(--hair);margin-bottom:6px}
.menu-head b{display:block;font-family:var(--fd);font-size:19px;font-weight:400}
.menu-head span{display:block;margin-top:3px;font-size:12px;letter-spacing:.03em;color:var(--t2)}
.menu-item{
  display:flex;align-items:flex-start;gap:11px;width:100%;text-align:left;
  padding:11px 13px;background:none;border:0;cursor:pointer;color:inherit;
  font-family:var(--fb);transition:background .3s;
}
.menu-item:hover{background:rgba(201,168,76,.1)}
.menu-ic{font-style:normal;font-size:14px;line-height:1.5;width:18px;flex:0 0 auto;text-align:center}
.menu-t b{display:block;font-family:var(--fd);font-size:17.5px;font-weight:400;line-height:1.25}
.menu-t>span{display:block;margin-top:3px;font-size:11.5px;letter-spacing:.02em;color:var(--t2)}
.menu-item.danger .menu-t b{color:#E08A7A}
.menu-sep{height:1px;background:var(--hair);margin:6px 0}
.menu-demo{
  margin-top:8px;width:100%;background:none;border:1px dashed var(--line);
  color:var(--t3);cursor:pointer;padding:11px 10px;
  font-family:var(--fb);font-size:10px;letter-spacing:.18em;text-transform:uppercase;
  transition:.35s;
}
.menu-demo:hover{border-color:var(--gold);color:var(--gold-hi)}

/* mobile menu */
/* Made unmistakable — as two bare hairlines it read as "nothing there". */
.nav-burger{
  display:grid;gap:5px;place-content:center;background:none;cursor:pointer;
  border:1px solid var(--line);border-radius:100px;
  width:44px;height:44px;margin-left:4px;flex:0 0 auto;
  transition:border-color .35s,background .35s;
}
.nav-burger:hover{border-color:var(--gold)}
@media(min-width:880px){.nav-burger{display:none}}
.nav-burger i{display:block;width:18px;height:1px;background:var(--cream)}
#navSheet{
  position:fixed;inset:0;z-index:30;background:rgba(7,7,8,.96);
  backdrop-filter:blur(14px);
  display:grid;align-content:center;justify-items:center;gap:6px;padding:80px 24px;
}
#navSheet[hidden]{display:none}
#navSheet a{
  font-family:var(--fd);font-size:clamp(24px,6vw,34px);font-weight:300;
  color:var(--cream);padding:8px 16px;
}
#navSheet a:active{color:var(--gold)}
.sheet-portals{
  display:flex;flex-wrap:wrap;gap:8px;justify-content:center;
  margin-top:26px;padding-top:24px;border-top:1px solid var(--hair);width:min(420px,88vw);
}
.sheet-portals a{
  font-family:var(--fb)!important;font-size:11px!important;letter-spacing:.16em;
  text-transform:uppercase;color:var(--t1)!important;
  border:1px solid var(--line);border-radius:100px;padding:12px 17px!important;
}

/* ── progress rail ─────────────────────────────────────────── */
#rail{
  position:fixed;right:calc(var(--gut) * .5);top:50%;transform:translateY(-50%);
  z-index:20;width:1px;height:min(280px,32vh);background:var(--hair);
  opacity:0;transition:opacity .6s var(--ease);
}
#rail.show{opacity:1}
#rail i{position:absolute;top:0;left:-1px;width:3px;height:0;background:var(--gold);transition:height .1s linear}
/* The rail used to carry the chapter index ("08") beside the handle.
   Floating two digits in the right margin of a film reads as a page
   number, and viewers asked what page eight of what they were on. The
   bar alone says "you are this far" without inviting the question. */
@media(max-width:720px){#rail{display:none}}

/* ── the film spacer ───────────────────────────────────────── */
#film{display:block;position:relative;z-index:1;pointer-events:none}

/* screen-reader / no-JS mirror of the film's content */
.sr-film{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}

/* ── the page under the film ───────────────────────────────── */
/* ── fallback ──────────────────────────────────────────────── */
#fallback{display:none}
html.no-gl #stage,html.no-gl #chapters,html.no-gl #film,html.no-gl #rail{display:none}
html.no-gl #fallback{
  display:grid;place-content:center;text-align:center;
  min-height:88vh;padding:0 var(--gut);
  background:radial-gradient(90% 70% at 50% 30%,#16161a,#070708 70%);
}
html.no-gl #fallback h2{font-family:var(--fd);font-weight:300;font-size:clamp(40px,8vw,90px);margin:0}
html.no-gl .fb-b{max-width:46ch;margin:24px auto 0;font-size:13px;line-height:1.9;color:rgba(245,240,232,.5)}
html.no-gl #nav{opacity:1;transform:none;pointer-events:auto;position:sticky}

/* ── motion preferences ────────────────────────────────────── */
@media(prefers-reduced-motion:reduce){
  .grain{animation:none}
  .scroll-hint i::after{animation:none}
  .h .w>span{transition:none;transform:none}
  .rv{opacity:1;transform:none;transition:none}
}

/* ── phones: compact account button + full-width account sheet ──── */
@media(max-width:760px){
  /* keep the controls grouped on the right, next to the burger, rather
     than stranded in the middle by space-between */
  #nav .nav-right{margin-left:auto}
  /* icon-only so it fits beside the logo and the burger */
  .nav-signin{width:42px;height:42px;padding:0;justify-content:center;border-radius:50%}
  .nav-signin span{display:none}
  /* the dropdown becomes a bottom sheet — a 290px panel anchored to the
     right edge of a 430px screen overflows and clips its own items */
  .signin-menu{
    position:fixed;left:10px;right:10px;top:auto;
    bottom:calc(10px + env(safe-area-inset-bottom));
    width:auto;max-height:74vh;
  }
  /* the START A PROJECT pill is the first thing to sacrifice for room */
  #nav .nav-cta{display:none}
}
@media(max-width:400px){
  #nav .nav-ico{display:none}   /* WhatsApp lives in the float button */
}
