/* ==========================================================================
   TORINO — holding page
   Single stylesheet; no build step, so one request beats many.
   Mobile-first: the base rules are the small-screen layout, with a single
   desktop breakpoint at 48em.

   Contents
   1.  Tokens
   2.  Fonts
   3.  Reset
   4.  Utilities
   5.  Links + focus
   6.  Backdrop (carousel)
   7.  Stage grid
   8.  Lockup
   9.  Social
   10. Overlay + wipe
   11. Sign-up form
   12. Load-in sequence
   13. Desktop
   14. Reduced motion
   ========================================================================== */


/* 1. Tokens ================================================================
   --c-cream is confirmed: it's the fill in the supplied wordmark and in all
   three social icon discs. --c-red is taken from the glyph colour in those
   same icons, so it's strong evidence but still worth confirming it's the
   intended sign-up screen background rather than an icon-specific tone.
   ------------------------------------------------------------------------ */
:root {
  --c-red:    #ad0000;
  --c-cream:  #fdf8db;
  --c-ink:    #14100e;

  --font-display: 'GT Pressura', Helvetica, Arial, sans-serif;
  --font-body:    'Faire', Helvetica, Arial, sans-serif;

  --pad-inline: clamp(1.25rem, 4vw, 3rem);
  --pad-block:  clamp(1.5rem, 4vh, 2.75rem);

  --fade-dur:  1400ms;
  --cycle-ms:  5000;

  /* easeOutExpo — quick off the mark, decelerating hard into place. */
  --wipe-dur:  900ms;
  --wipe-ease: cubic-bezier(0.16, 1, 0.3, 1);

  /* Load-in sequence (section 12). The delays are measured from the moment the
     first backdrop frame lands, not from page load.
     --enter-shift must stay at or below the floor of --pad-block (1.5rem):
     the footer band starts that far *down*, and anything larger would push
     past the bottom of the stage and briefly make the page scrollable. */
  --enter-dur:           700ms;
  --enter-ease:          cubic-bezier(0.22, 1, 0.36, 1);
  --enter-shift:         1.25rem;
  --enter-delay-lockup:  250ms;
  --enter-delay-bands:   900ms;
}


/* 2. Fonts ================================================================= 
   ASSET SWAP: uncomment and point at the licensed webfonts when they land,
   then update --font-display / --font-body above. Nothing else changes.
*/

@font-face {
  font-family: 'GT Pressura';
  src: url('../assets/fonts/GT-Pressura-Standard-Bold.woff2') format('woff2');
  font-weight: 700;
  font-display: swap;
}

@font-face {
  font-family: 'Faire';
  src: url('../assets/fonts/FAIRE-PrintSans-Regular.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}


/* 3. Reset ================================================================= */
*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background-color: var(--c-ink);
  color: var(--c-cream);
  font-family: var(--font-body);
  /* 17px at the 375 comp, 24px at the 1440 comp, fluid between. */
  font-size: clamp(1rem, 0.909rem + 0.657vw, 1.25rem);
  line-height: 1;
  letter-spacing: 0.03em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, p, figure, ul { margin: 0; }
ul { padding: 0; list-style: none; }

img, svg { display: block; max-width: 100%; }

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

input { font: inherit; }


/* 4. Utilities ============================================================= */

/* Off-screen but still announced. */
.u-vh {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Holds the <symbol> definition; must stay in the render tree for <use>. */
.u-sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* Set while the overlay is open so a short viewport can't scroll behind it. */
.is-locked,
.is-locked body { overflow: hidden; }


/* 5. Links + focus ========================================================= */
.link {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.28em;
  transition: opacity 200ms ease;
}

.link:hover { opacity: 0.7; }

:focus-visible {
  outline: 2px solid var(--c-cream);
  outline-offset: 4px;
  border-radius: 2px;
}


/* 6. Backdrop ==============================================================
   Fixed and sized to the *large* viewport so no gap appears behind the
   mobile browser chrome as it collapses.
   ------------------------------------------------------------------------ */
.backdrop {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  height: 100lvh;
  z-index: 0;
  overflow: hidden;
  background-color: var(--c-ink);
}

.backdrop__frames {
  position: absolute;
  inset: 0;
}

/* Crossfade without a luminance dip: the outgoing frame holds at full opacity
   underneath (.is-prev) while the incoming one fades in above it. */
.backdrop__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  opacity: 0;
  z-index: 0;
  transition: opacity var(--fade-dur) ease-in-out;
}

.backdrop__frame.is-prev {
  opacity: 1;
  z-index: 1;
  transition: none;
}

.backdrop__frame.is-active {
  opacity: 1;
  z-index: 2;
}

/* There is deliberately no scrim over the photography. The renders arrive
   already tinted, and tools/check-contrast.py confirms cream type holds
   5.6:1 against the worst region of the worst frame with nothing on top —
   clear of the 4.5:1 AA requirement for small text.

   If untinted photography is ever supplied, re-run that script before
   assuming this still holds; it takes a flat tint value as an argument so
   you can find the smallest one that recovers AA. */


/* 7. Stage grid ============================================================
   `1fr` on the lockup row is what makes the layout flex to viewport height:
   it soaks up all free space so the wordmark tracks the centre, while the
   intro and footer stay at natural height. Once free space runs out the grid
   grows past the viewport and the page scrolls, so the bands can never
   overlap each other.
   ------------------------------------------------------------------------ */
.stage {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: auto auto 1fr auto auto;
  grid-template-areas:
    "intro"
    "mail"
    "lockup"
    "social"
    "team";
  justify-items: center;
  min-height: 100vh;
  min-height: 100dvh;
  padding: var(--pad-block) var(--pad-inline);
  text-align: center;
}

.stage__intro { grid-area: intro; line-height: 1.2; }

/* Reads as the third line of the intro paragraph at this size. */
.stage__mail {
  grid-area: mail;
  margin-top: 0.15rem;
}

.stage__lockup {
  grid-area: lockup;
  align-self: center;
  padding-block: clamp(1.25rem, 4vh, 3rem);
}

.stage__social {
  grid-area: social;
  margin-bottom: 1.15rem;
}

.stage__team { grid-area: team; }


/* 8. Lockup ================================================================ */
.lockup {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* 22px at the 375 comp, 44px at the 1440 comp, fluid between. */
  gap: clamp(1.375rem, 0.891rem + 2.066vw, 2.75rem);
}

.lockup__kicker,
.lockup__descriptor {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  line-height: 1.2;
  /* 20px at the 375 comp, 37px at the 1440 comp, fluid between. */
  font-size: clamp(1.25rem, 0.876rem + 1.596vw, 2.3125rem);
}

.lockup__kicker {
  letter-spacing: 0.01em;
  /* Optical centring: tracking adds trailing space after the last glyph. */
  text-indent: 0.01em;
}

.lockup__descriptor {
  letter-spacing: 0.01em;
  text-indent: 0.01em;
}

.lockup__and {
  font-size: 0.78em;
  letter-spacing: 0.1em;
}

.lockup__mark { margin: 0; }

/* Width only, per the supplied comp sizes. The artwork's true ratio is
   592/133, so height:auto lands on 72.6 and 132.8 — within a pixel of the
   specified 72 and 133. Pinning both would force a slight distortion, since
   the rounded comp values don't share an identical ratio.
   The inherited svg { max-width: 100% } covers the one failure case: below
   about 350px the mobile width would overflow, and instead scales down. */
.lockup__glyph {
  width: 323px;
  height: auto;
  color: var(--c-cream);
}


/* 9. Social ================================================================
   Circular icons at this size; the text labels take over on desktop. Both
   live in the same anchor, so the accessible name never changes.
   ------------------------------------------------------------------------ */
.social {
  display: flex;
  align-items: center;
  gap: 0.5em;
}

.social__list {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

.social__item {
  display: flex;
  align-items: center;
  gap: 0.5em;
}

.social__link {
  display: block;
  color: inherit;
  text-decoration: none;
}

.social__label,
.social__name { display: none; }

/* Mobile shows the icon discs; desktop swaps to the text names below. */
.social__icon {
  display: block;
  width: 39px;
  height: 39px;
}


/* 10. Overlay + wipe =======================================================
   translateY on a fixed panel: compositor-driven, so the wipe stays smooth
   without a JS tween ticking every frame.
   ------------------------------------------------------------------------ */
.overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  z-index: 10;
  background-color: var(--c-red);
  color: var(--c-cream);
  transform: translateY(100%);
  transition: transform var(--wipe-dur) var(--wipe-ease);
  will-change: transform;
  overflow-y: auto;
}

.overlay.is-open { transform: translateY(0); }

.overlay__inner {
  display: grid;
  grid-template-rows: auto 1fr auto;
  min-height: 100%;
  padding: var(--pad-block) var(--pad-inline);
}

.overlay__head { text-align: center; }

.overlay__mark {
  width: 263px;
  height: auto;
  margin-inline: auto;
  color: var(--c-cream);
}

.overlay__body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding-block: clamp(1.5rem, 5vh, 3rem);
}

.overlay__foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  text-align: center;
}

/* Contents settle in just behind the leading edge of the wipe. The delays are
   scoped to .is-open so closing clears everything immediately. */
.overlay__head,
.overlay__body,
.overlay__foot {
  opacity: 0;
  transform: translateY(1.5rem);
  transition: opacity 500ms ease, transform 500ms ease;
}

.overlay.is-open .overlay__head,
.overlay.is-open .overlay__body,
.overlay.is-open .overlay__foot {
  opacity: 1;
  transform: none;
}

.overlay.is-open .overlay__head { transition-delay: 340ms; }
.overlay.is-open .overlay__body { transition-delay: 440ms; }
.overlay.is-open .overlay__foot { transition-delay: 540ms; }


/* 11. Sign-up form ========================================================= */
.signup {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  width: 100%;
  max-width: 40rem;
}

.signup__label {
  white-space: nowrap;
  text-align: center;
}

.signup__input {
  min-width: 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid currentColor;
  border-radius: 0;
  color: inherit;
  padding: 0.25rem 0;
  text-align: center;
  /* Margin, not padding: padding would push the rule away from the text. */
  margin-bottom: 1.25rem;
}

/* Bottom rule is the field chrome; suppress the global focus ring. */
.signup__input:focus,
.signup__input:focus-visible {
  outline: none;
}

.signup__input[aria-invalid="true"] { border-bottom-width: 2px; }

.signup__submit {
  align-self: center;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
}

.signup__status { min-height: 1.5em; }
.signup__status:empty { min-height: 0; }


/* 12. Load-in sequence =====================================================
   Runs once. `is-preload` is set by the inline script in <head> so the start
   state exists before the first paint; main.js swaps it for `is-ready` when
   the first backdrop frame has arrived, which runs:

     1. backdrop fades up from the ink base   (--fade-dur, from 0ms)
     2. lockup fades in                       (--enter-delay-lockup)
     3. intro settles down, footer settles up (--enter-delay-bands)

   With JS unavailable neither class is ever set and everything renders in
   place, so the sequence is purely additive.

   Keyframes rather than transitions: animation-fill-mode holds the start
   state through the delay, whereas a transition would need that state to
   survive the very class swap that triggers it.
   ------------------------------------------------------------------------ */

/* Only the first frame is gated. The rest belong to the carousel, and an
   animation's fill would outrank the class-based opacity it crossfades with,
   so the backdrop fade is left to the transition already on .backdrop__frame. */
.is-preload .backdrop__frame.is-active { opacity: 0; }

.is-preload .stage > * { opacity: 0; }

@keyframes stage-enter {
  from {
    opacity: 0;
    transform: translateY(var(--enter-from, 0px));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* No --enter-from on the lockup, so it fades without travelling. */
.is-ready .stage > * {
  animation: stage-enter var(--enter-dur) var(--enter-ease) var(--enter-delay-bands) both;
}

.is-ready .stage__lockup { animation-delay: var(--enter-delay-lockup); }

/* The two bands arrive together, from opposite directions. .stage__mail is
   grouped with the intro here because on mobile it reads as its third line;
   the desktop block below moves it to the footer, and flips it with it. */
.stage__intro,
.stage__mail { --enter-from: calc(var(--enter-shift) * -1); }

.stage__social,
.stage__team { --enter-from: var(--enter-shift); }


/* 13. Desktop ==============================================================
   Same DOM, different grid areas — the mailing link moves from under the
   intro down to the bottom-left without being duplicated in the markup.
   ------------------------------------------------------------------------ */
@media (min-width: 48em) {

  .stage {
    grid-template-columns: 1fr auto 1fr;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
      "intro  intro  intro"
      "lockup lockup lockup"
      "mail   team   social";
  }

  .stage__mail {
    justify-self: start;
    margin-top: 0;
    /* Part of the footer band at this width, so it rises with it. */
    --enter-from: var(--enter-shift);
  }

  .stage__social {
    justify-self: end;
    margin-bottom: 0;
  }

  .lockup__glyph { width: 591px; }

  .social__list { gap: 0.5em; }

  .social__label,
  .social__name { display: inline; }

  .social__icon { display: none; }

  .social__item + .social__item::before {
    content: "/";
    opacity: 0.75;
  }

  .signup {
    flex-direction: row;
    align-items: baseline;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.75rem 1.25rem;
  }

  .signup__input {
    flex: 1 1 12rem;
    text-align: left;
    margin-bottom: 0;
  }

  .signup__submit { align-self: auto; }

  .overlay__foot {
    flex-direction: row;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1.5rem;
    text-align: left;
  }

  .overlay__terms { text-align: right; }
}


/* 14. Reduced motion ======================================================= */
@media (prefers-reduced-motion: reduce) {

  /* main.js also stops advancing the carousel. */
  .backdrop__frame { transition: none; }

  /* No load-in sequence: the page is simply there. These override section 12
     by order, not specificity, so they must stay after it. */
  .is-preload .backdrop__frame.is-active,
  .is-preload .stage > * { opacity: 1; }

  .is-ready .stage > * { animation: none; }

  .overlay {
    transform: none;
    opacity: 0;
    visibility: hidden;
    transition: opacity 200ms linear, visibility 0s linear 200ms;
  }

  .overlay.is-open {
    opacity: 1;
    visibility: visible;
    transition: opacity 200ms linear, visibility 0s;
  }

  .overlay__head,
  .overlay__body,
  .overlay__foot {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .link { transition: none; }
}
