/* ==========================================================================
   Genia Styles — Coming Soon
   Direction: "After Dark". Every value here comes from the Design Tokens
   section of design/design_handoff_coming_soon/README.md. Do not re-derive or
   round them; several of the odd-looking ones are deliberate and documented.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Fonts — self-hosted, latin subset, from Google Fonts (all OFL; licenses in
   fonts/OFL-*.txt).
   -------------------------------------------------------------------------- */

@font-face {
  font-family: 'Anton';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/anton-latin.woff2') format('woff2');
}

@font-face {
  font-family: 'Bebas Neue';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/bebasneue-latin.woff2') format('woff2');
}

/* Variable font — one file covers the 400/500/600 the page uses. */
@font-face {
  font-family: 'Chivo Mono';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/fonts/chivomono-latin.woff2') format('woff2-variations'),
       url('/fonts/chivomono-latin.woff2') format('woff2');
}

/* --------------------------------------------------------------------------
   Tokens
   -------------------------------------------------------------------------- */

:root {
  --ground: #08080A;
  --off-white: #F2F2EF;
  --lime: #C7F702;
  --pink: #FF2E88;          /* link hover only; retained as the future accent */
  --type-70: rgba(242, 242, 239, 0.7);
  --type-50: rgba(242, 242, 239, 0.5);

  --pad-x: clamp(22px, 4vw, 56px);
  --pad-top: clamp(28px, 3.4vw, 48px);
  --pad-bottom: clamp(32px, 4vw, 56px);

  --fs-micro: clamp(10px, 1.1vw, 11px);   /* kicker + meta row */
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

*,
*::before,
*::after { box-sizing: border-box; }

html { background: var(--ground); }

body {
  margin: 0;
  background: var(--ground);
}

/* There are no links in this layout. The rule exists so that any link added
   later is never browser-default blue. */
a { color: var(--lime); text-decoration: none; }
a:hover { color: var(--pink); }

.page {
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  background: var(--ground);
  color: var(--off-white);
  font-family: 'Chivo Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* --------------------------------------------------------------------------
   Layout

   This single rule is the entire responsive mechanism: two columns above
   roughly 800px, one column below. There are no viewport breakpoints anywhere
   in this stylesheet, by design — everything else scales with clamp().
   -------------------------------------------------------------------------- */

.body-grid {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(400px, 100%), 1fr));

  /* Lets the photo scrim respond to the *same* width the grid above responds
     to, rather than to a guessed viewport number. See .photo__scrim. */
  container-type: inline-size;
  container-name: bodygrid;
}

.copy {
  padding: var(--pad-top) var(--pad-x) var(--pad-bottom);
  display: flex;
  flex-direction: column;
  justify-content: space-between;   /* pins wordmark / headline / meta */
  gap: clamp(32px, 5vh, 52px);
}

/* --------------------------------------------------------------------------
   Wordmark — "Block & Spine"
   -------------------------------------------------------------------------- */

.wordmark {
  display: flex;
  align-items: stretch;   /* load-bearing — see .wordmark__spine */
  gap: 10px;
  align-self: flex-start;
}

.wordmark__block {
  background: var(--lime);
  color: var(--ground);
  font: 400 clamp(38px, 5.4vw, 58px)/0.8 'Anton', sans-serif;
  letter-spacing: -0.015em;
  text-transform: uppercase;

  /* The asymmetry is deliberate. Anton's line box leaves roughly 2.7px more
     room below the caps than above at 24px, so equal padding reads
     bottom-heavy. Do not "tidy" these values. Expressed in em so the block
     scales with the type. */
  padding: 0.26em 0.28em 0.155em;
}

/* STYLES running down the right side of the block, one rotated letter per span.
   `writing-mode: vertical-rl` + letter-spacing was the obvious approach and was
   wrong twice: letter-spacing leaves a trailing gap after the final S so the run
   measures taller than its ink, and an em-based spread never matches the block's
   height. Because the wrapper is `align-items: stretch` this flex item is
   exactly the block's height, and `space-between` distributes the six letters
   across it — first flush to the top edge, last flush to the bottom, at any
   size. Keep the per-letter rotation: without it the letters stack upright and
   the mark changes character. */
.wordmark__spine {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  font: 500 clamp(8px, 1.05vw, 11px)/1 'Chivo Mono', monospace;
  text-transform: uppercase;
  color: var(--off-white);
}

.wordmark__spine > span {
  display: block;
  transform: rotate(90deg);
}

/* --------------------------------------------------------------------------
   Headline group
   -------------------------------------------------------------------------- */

.headline-group {
  display: flex;
  flex-direction: column;
  gap: clamp(16px, 2.4vw, 26px);
}

.kicker {
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--lime);
}

.headline {
  margin: 0;
  font: 400 clamp(68px, 11.5vw, 132px)/0.82 'Bebas Neue', sans-serif;
  letter-spacing: 0.005em;
}

/* Fallback first: a solid fill at reduced opacity, for anything without
   -webkit-text-stroke. */
.headline__outline {
  color: rgba(242, 242, 239, 0.45);
}

@supports (-webkit-text-stroke: 2px #F2F2EF) {
  .headline__outline {
    -webkit-text-stroke: 2px var(--off-white);
    color: transparent;
  }
}

.lede {
  margin: 0;
  max-width: 34ch;
  font-size: clamp(14px, 1.4vw, 15px);
  line-height: 1.65;
  color: var(--type-70);
}

/* --------------------------------------------------------------------------
   Meta row
   -------------------------------------------------------------------------- */

.meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(14px, 2vw, 26px);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--type-50);
}

/* --------------------------------------------------------------------------
   Photo
   -------------------------------------------------------------------------- */

/* Stacked, the photo sits below the copy and the two share one screen, so its
   floor is the mobile reference's 330px. Side by side it has the column to
   itself and takes the desktop token. Using 52vh in the stacked case pushes the
   marquee off the bottom of a 402x874 screen — the mobile design is specified
   to fit one screen with no scrolling. Both numbers are the design's own. */
.photo {
  position: relative;
  min-height: 330px;
  overflow: hidden;
}

@container bodygrid (min-width: 800px) {
  .photo { min-height: clamp(340px, 52vh, 620px); }
}

.photo picture { display: contents; }

/* Positioned rather than in-flow. A `height: 100%` in-flow image cannot resolve
   its percentage against this auto-height panel, so it falls back to its
   intrinsic ratio (at a 713px column that is 950px tall), which then drives the
   grid row past the viewport and makes the page scroll. Taking it out of flow
   lets the panel be sized by its own min-height and the grid row, and the image
   fill whatever that turns out to be. */
.photo__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 62% 24%;
  display: block;
}

/* The scrim fades the photo into the copy rather than butting it against it,
   so its direction has to follow whichever edge the copy sits on.

   Default (stacked, one column): copy is *above*, so the scrim runs vertically.
   Two-column: copy is to the *left*, so it runs horizontally.

   The container query fires on the grid's own inline size at the width its
   `minmax(min(400px, 100%), 1fr)` flips between one and two tracks — the same
   number, expressed in the same terms, so the two can never drift apart. */
.photo__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(8, 8, 10, 0.85) 0%,
    rgba(8, 8, 10, 0.05) 42%,
    rgba(8, 8, 10, 0) 100%
  );
}

@container bodygrid (min-width: 800px) {
  .photo__img { object-position: 62% 28%; }

  .photo__scrim {
    background: linear-gradient(
      90deg,
      rgba(8, 8, 10, 0.9) 0%,
      rgba(8, 8, 10, 0.1) 40%,
      rgba(8, 8, 10, 0) 100%
    );
  }
}

/* --------------------------------------------------------------------------
   Marquee
   -------------------------------------------------------------------------- */

.marquee {
  flex: none;
  background: var(--lime);
  color: var(--ground);
  overflow: hidden;
  padding: clamp(9px, 1.2vw, 13px) 0;

  /* Puts the iOS home indicator on lime rather than on the photo. Replaces the
     fixed 34px spacer used in the mobile design reference. */
  padding-bottom: calc(clamp(9px, 1.2vw, 13px) + env(safe-area-inset-bottom, 0px));
}

.marquee__track {
  display: flex;
  width: max-content;
  animation: gs-marquee-cs 26s linear infinite;
}

/* Exactly two identical lists — the -50% translate depends on it for a
   seamless loop. */
@keyframes gs-marquee-cs {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

.marquee__list {
  display: flex;
  margin: 0;
  padding: 0;
  list-style: none;
  font: 400 clamp(19px, 2.4vw, 26px)/1 'Bebas Neue', sans-serif;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.marquee__list li {
  white-space: nowrap;
}

/* The design's separator is ✱ (U+2731 HEAVY ASTERISK), which Bebas Neue does
   not contain — in the reference it silently falls back to whatever system font
   covers it, so it renders differently on every OS. Drawn here instead, so it
   is identical everywhere and costs no extra font file. */
.marquee__list li::after {
  content: '';
  display: inline-block;
  width: 0.62em;
  height: 0.62em;
  margin: 0 0.5em;
  vertical-align: 0.03em;
  background: no-repeat center/contain
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cg fill='%2308080A'%3E%3Crect x='42.5' y='2' width='15' height='96' rx='2'/%3E%3Crect x='42.5' y='2' width='15' height='96' rx='2' transform='rotate(60 50 50)'/%3E%3Crect x='42.5' y='2' width='15' height='96' rx='2' transform='rotate(120 50 50)'/%3E%3C/g%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   Motion

   The marquee is the only motion on the page and it runs indefinitely, so
   honouring this preference is required. This is the sole media query in the
   stylesheet, and it is a preference query — not a breakpoint.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .marquee__track {
    animation: none;
  }
}
