/* ════════════════════════════════════════════════════════════════════
   VEXLOTEX — GATEWAY (index.html) · v12
   Full-screen chooser: no hero, no marketing scroll.
   nav → prompt → three glow cards → logo ticker → trust → footer,
   all over the warm-paper Three.js ember scene.
   Requires css/shared.css v7
   ════════════════════════════════════════════════════════════════════ */

/* ── The gateway section — the film releases directly onto it. Opaque warm
   paper (the merged homepage body stays cinema-dark for the film above),
   with its own text color since .film-page sets the light-on-dark palette. ── */
.gateway {
  position: relative; z-index: 2;
  background: var(--bg); color: var(--text);
  outline: none;   /* focus target for the skip control */
}

/* ── 3D canvas — accent layer scoped to the gateway, behind its content.
   Sticky inside an absolute full-height wrapper: visually equivalent to the
   old fixed canvas while the gateway is on screen, but it never paints (or
   costs GPU) behind the opaque film that now sits above it on the page. ── */
.gw-canvas-wrap {
  position: absolute; inset: 0; z-index: 0;
  overflow: clip; pointer-events: none;
}
#canvas {
  position: sticky; top: 0; display: block;
  width: 100%; height: 100vh;
  opacity: 0.58;
}

/* ── Screen frame: sized to come close to one viewport on desktop, not a
   guarantee — see the 2026-07-30 note below .path-band for the real number. ── */
.gw-screen {
  position: relative; z-index: 2;
  min-height: 100svh;
  display: grid;
  grid-template-rows: 1fr auto auto auto;
}
@media (max-width: 1024px) {
  .gw-screen { min-height: 0; display: block; }
}

/* ── Chooser ── */
.gw-choose {
  width: 100%; max-width: 1240px; margin-inline: auto;
  padding: var(--sp-2) var(--sp-4);
  display: flex; flex-direction: column; justify-content: center;
}
.gw-prompt {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(1.6rem, 3.2vw, 2.5rem);
  line-height: 1.08; letter-spacing: -0.02em;
  text-align: center; text-wrap: balance;
  position: relative; z-index: 1;
  max-width: 30ch; margin-inline: auto;
  text-shadow: 0 1px 0 rgba(245,241,232,0.78);
}
.gw-prompt .accent-line { color: var(--ember); }
.gw-prompt-sub {
  text-align: center; color: var(--muted);
  font-size: var(--fs-small);
  margin: var(--sp-1) auto var(--sp-3);
}
.gw-choose .trust-bar { margin-bottom: var(--sp-4); }

.gw-cards {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-3);
  align-items: stretch;
}
@media (max-width: 1024px) { .gw-cards { grid-template-columns: 1fr; max-width: 640px; margin-inline: auto; } }

.path-card {
  position: relative;
  display: flex; flex-direction: column; gap: var(--sp-2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: var(--sp-3) var(--sp-3) var(--sp-2);
  min-height: 0;
  cursor: pointer;
  text-align: left;
  color: inherit;
  text-decoration: none;
  /* Property only, on purpose: shared.css normalises .path-card (among
     others) to a uniform 0.3s ease via transition-duration/-timing-function
     longhands. The shorthand this used to be here (each with its own
     var(--motion-hover) duration + mixed easing) implicitly reset those
     same longhands, and won the cascade since gateway.css loads after
     shared.css at equal specificity -- so .path-card silently transitioned
     at 250ms with the wrong curve instead of the sitewide-standard 0.3s. */
  transition-property: transform, border-color, box-shadow;
}
.path-card:hover, .path-card:focus-visible {
  transform: translateY(-6px) scale(1.005);
  border-color: var(--ember-30);
  box-shadow: var(--shadow-hover);
}

/* ── Photo band — the decision-maker's moment, at the top of each card.
   Rounded on the <img> itself rather than clipped by overflow:hidden on the
   card, because .stat-float deliberately sits at top:-16px and an overflow
   clip would cut the pill in half. The negative inline margin pulls the band
   out to the card's edges through its padding. ── */
.path-card { padding-top: 0; }
.path-band {
  display: block;
  width: calc(100% + 2 * var(--sp-3));
  max-width: none;   /* shared.css:129 sets img{max-width:100%}, which would
                        clamp the width above straight back to the content box */
  margin-inline: calc(-1 * var(--sp-3));
  aspect-ratio: 12 / 5;
  max-height: var(--sp-12);
  object-fit: cover;
  border-radius: calc(var(--radius-card) - 1px) calc(var(--radius-card) - 1px) 0 0;
}
/* Measured 2026-07-26: .gw-screen's natural content floor was ~995px even with
   the bands hidden -- 95px over a 1440x900 laptop, ~295px over at 1280x700.
   2026-07-30: trimmed it down (band max-height 160->96px, tightened card/footer/
   ticker/trust spacing, fixed a .field-error[hidden] bug that was silently
   reserving 19px under every email field, cut card copy to match the other
   cards' line count, removed footer text that duplicated the trust badges
   directly above it) -- content floor was ~967px at 1440x900 (67px over,
   down from 95) and ~879px at 1280x700 (179px over, down from 295).
   2026-07-30 (later): dropped the .card-tags persona pills (they duplicated
   the audience already named in each card's own copy) -- content floor is now
   ~900px at 1440x900 (fits exactly) and ~801px at 1280x700 (101px over, down
   from 179). The headline stays untouched; it's the primary conversion
   element and a font-size cut doesn't reduce its line count at this
   max-width anyway. 1280x700 still overflows some -- that's a shorter/older
   laptop than the 1440x900 primary target, and closing it needs another real
   creative call (see the media query below, which already goes further for
   short viewports). Scoped to >=1025px so a phone in landscape keeps its
   band. */
@media (min-width: 1025px) and (max-height: 780px) {
  .path-band { display: none; }
  .path-card { padding-top: var(--sp-2); }
  /* 2026-07-30 (later, later, later): the headline's own 30ch cap forces a
     3rd wrapped line it doesn't need at this bucket's widths -- the full
     string measures 2634px at the base clamp's 40px (canvas-measured), more
     than even the full 1176px .gw-choose width can fit on one line, so a
     3rd line was unavoidable at that size. Dropping to a smaller clamp and
     removing the ch cap (so it uses the full container width instead of a
     font-relative one) wraps it to 2 lines at every width this query
     covers -- tested live down to the query's own 1025px floor, not just
     the 1280px target. Saves ~70px alone; untouched outside this query, so
     the 1440x900 primary target keeps its full-size headline exactly as
     before. */
  .gw-prompt { font-size: clamp(1.5rem, 2.2vw, 1.75rem); line-height: 1.15; max-width: none; }
  .gw-prompt-sub { margin-bottom: var(--sp-2); }
  .gw-choose { padding-block: var(--sp-1); }
  /* 2026-08-05: 1025x700 (a real, shorter-than-1280x700-primary bucket this
     query also covers) still overflowed by 43.5px -- .gw-cards' cB2B card
     wraps its description to 6 lines vs the other two cards' 5 at this width,
     tipping .gw-screen to 743.5px. Verified live via direct style mutation +
     getBoundingClientRect remeasurement, in 0.5px steps, that this exact
     combination closes it to 0px overflow with a little slack (13.5px font
     alone wasn't enough; --sp-1 for .path-card gap tested against a
     non-token 10px and both land at 0px, so use the token). The .card-desc
     font-size piece of this fix lives in its own query further down, after
     the base .card-desc rule -- see the note there. Untouched outside this
     query -- 1440x900 and 1280x700 confirmed unaffected. */
  .gw-choose .trust-bar { margin-bottom: var(--sp-2); }
  .gw-cards { gap: var(--sp-2); }
  .path-card { gap: var(--sp-1); }
}

.path-card .stat-float {
  position: absolute; top: -16px; right: var(--sp-3);
  z-index: 1;   /* above the band */
}

.card-index {
  font-family: var(--font-mono); font-size: var(--fs-tiny);
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ember-ink);
}
.card-title {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(1.4rem, 2.2vw, 1.75rem); line-height: 1.12;
  letter-spacing: -0.01em;
  margin-top: 6px;
}
.card-desc { color: var(--muted); font-size: var(--fs-small); line-height: 1.6; margin-top: var(--sp-1); }
/* Placed after the base rule above, not in the earlier short-viewport query --
   that rule loads later in the file at equal specificity and would silently
   win over an override placed before it (same bug class as .gw-footer-inner
   below). Part of the 2026-08-05 1025x700-overflow fix. */
@media (min-width: 1025px) and (max-height: 780px) {
  .card-desc { font-size: 13px; }
}

.card-cta {
  margin-top: auto;
  display: flex; align-items: center; justify-content: space-between;
}
.card-enter {
  font-size: var(--fs-small); font-weight: 500;
  color: var(--text); text-decoration: none; letter-spacing: 0.04em;
  display: inline-flex; align-items: center;
  min-height: 44px; padding-inline: 4px;   /* WCAG tap target */
}
.cta-btn {
  width: 44px; height: 44px; border-radius: 50%;
  border: 1px solid var(--border-strong);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text);
  transition: background var(--motion-hover) var(--ease-in-out),
              border-color var(--motion-hover) var(--ease-in-out),
              color var(--motion-hover) var(--ease-in-out),
              transform var(--motion-hover) var(--ease-snap);
}
.path-card:hover .cta-btn {
  background: var(--ember); border-color: var(--ember); color: #FFF;
  transform: translateX(4px);
}

/* ── Logo ticker row — compact on the one-screen gateway ── */
.gw-ticker { background: rgba(245,241,232,0.7); padding-block: 6px; }
.gw-ticker .ticker-track img { height: 30px; max-width: 120px; object-fit: contain; }

/* ── Trust badges ── */
.gw-trust {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: var(--sp-2);
  width: 100%; max-width: 1240px; margin-inline: auto;
  padding: 6px var(--sp-4);
}
.trust-badge {
  font-size: var(--fs-tiny); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--faint);
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  padding: var(--sp-1) 18px; background: rgba(255,255,255,0.5);
}

/* ── Gateway footer ── */
.gw-footer {
  border-top: 1px solid var(--border);
  background: rgba(245,241,232,0.85);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.gw-footer-inner {
  max-width: 1240px; margin-inline: auto;
  padding: 10px var(--sp-4);
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-1) var(--sp-3);
  font-size: var(--fs-small); color: var(--muted);
}
.gw-footer-inner .spacer { flex: 1; }
/* Placed after the base rule above, not in the earlier short-viewport query --
   that rule loads later in the file at equal specificity and would silently
   win over an override placed before it (same bug class as the .path-card
   transition/.field-error[hidden] issues elsewhere in this file). */
@media (min-width: 1025px) and (max-height: 780px) {
  .gw-footer-inner { padding-block: 6px; }
}
.gw-footer a { color: var(--muted); text-decoration: none; transition: color var(--motion-micro) var(--ease-in-out); padding: 12px 4px; display: inline-block; }
.gw-footer a:hover { color: var(--ember-ink); }
.gw-footer-form { display: inline-flex; align-items: flex-end; gap: var(--sp-1); }
.gw-footer-form .field { gap: 4px; }
.gw-footer-form .input { min-height: 44px; width: 210px; }
.gw-footer-form .btn { min-height: 44px; padding: 0 20px; }
.gw-form-note { flex-basis: 100%; font-size: var(--fs-tiny); color: var(--faint); }
.gw-form-note a { padding: 0; text-decoration: underline; text-underline-offset: 3px; }
.form-honey { position: absolute; left: -9999px; width: 1px; height: 1px; }
@media (max-width: 640px) {
  #canvas { opacity: 0.3; }
  .gw-choose { padding-top: var(--sp-2); }
  .gw-prompt { font-size: clamp(2rem, 10vw, 2.65rem); line-height: 0.98; }
  .gw-prompt-sub { max-width: 30ch; }
  .gw-cards { padding-top: var(--sp-2); }
  .gw-footer-inner { flex-direction: column; align-items: flex-start; }
  .gw-footer-form { width: 100%; }
  .gw-footer-form .field { flex: 1; }
  .gw-footer-form .input { width: 100%; }
}

/* ── Entrance choreography: prompt → cards → ticker → footer ──
   On the merged homepage the film sits above: in cinematic mode (body.is-cine,
   set by js/film.js) the stagger holds paused until the film's crossing arms it
   with body.gw-live, so the cards are landing as the pin releases. In static /
   reduced / no-JS modes is-cine is never set and the animation plays at load,
   long before the visitor scrolls down to it — effectively just visible. ── */
.gw-prompt, .gw-prompt-sub, .path-card, .gw-ticker, .gw-trust, .gw-footer {
  opacity: 0;
  animation: gwIn var(--motion-entrance-base) var(--ease-out-expo) forwards;
}
body.is-cine:not(.gw-live) .gw-prompt,
body.is-cine:not(.gw-live) .gw-prompt-sub,
body.is-cine:not(.gw-live) .path-card,
body.is-cine:not(.gw-live) .gw-ticker,
body.is-cine:not(.gw-live) .gw-trust,
body.is-cine:not(.gw-live) .gw-footer {
  animation-play-state: paused;
}
.gw-prompt                 { animation-delay: 240ms; }
.gw-prompt-sub             { animation-delay: 300ms; }
.gw-cards .path-card:nth-child(1) { animation-delay: 330ms; }
.gw-cards .path-card:nth-child(2) { animation-delay: 420ms; }
.gw-cards .path-card:nth-child(3) { animation-delay: 510ms; }
.gw-ticker                 { animation-delay: 650ms; }
.gw-trust                  { animation-delay: 700ms; }
.gw-footer                 { animation-delay: 740ms; }
@keyframes gwIn {
  from { opacity: 0; transform: translateY(16px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}

/* ── Transition overlay (enter animation handoff) ── */
.transition-veil {
  /* Must outrank every other overlay on this page, not just today's known
     ones — this is a full outbound-navigation wipe, so nothing should be
     able to show through it. Was z:80, numerically tied with film.css's
     .film-grain and *below* .film-scan/.film-vignette (81/82); harmless
     only because --atmos (which drives all three) has always decayed to 0
     by the time a path-card triggers this, not because the stacking order
     was actually correct. 210 clears film.css's own highest layer, the
     .film-preloader at z:200. */
  position: fixed; inset: 0; z-index: 210; pointer-events: none;
  background: var(--bg); opacity: 0;
  transition: opacity 400ms ease-in;
}

@media (prefers-reduced-motion: reduce) {
  .gw-prompt, .gw-prompt-sub, .path-card, .gw-ticker, .gw-trust, .gw-footer {
    opacity: 1; animation: none;
  }
}
