/* ------------------------------------------------------------------
   Cosmic Jam — coming soon
   Palette + geometry are sampled directly from the brand artwork.
   ------------------------------------------------------------------ */

/* The brand face, self-hosted from the same variable woff2 the launch posters
   embed (cosmic-jam-launch-social/brand/). Latin subset only — the one line set
   in it is ASCII. The weight and stretch ranges have to be declared here or the
   browser clamps the axes and `wdth 78` renders at the default width. */
@font-face {
  font-family: "Special Gothic";
  font-style: normal;
  font-weight: 400 700;
  font-stretch: 75% 125%;
  font-display: swap;
  src: url("assets/fonts/special-gothic.woff2") format("woff2");
}

:root {
  --ink:        #05051E;
  --ink-deep:   #02020C;
  --violet:     #2722A2;
  --blue:       #1837F3;
  --blue-lit:   #3B6BFF;
  --lavender:   #9A9AFF;
  --ice:        #C9D6FF;
  --text:       #FFFFFF;
  --muted:      #A9AEE0;

  --pad: clamp(22px, 4.4vw, 76px);
  --social: clamp(15px, 1.2vw, 19px);
  --lockup-w: clamp(212px, 30vw, 500px);

  /* Placement of the jam texture rect — the wide-desktop framing from frameFor() in
     app.js, expressed in viewport units so the composition is already correct before
     (and without) JavaScript. The gel is sized from viewport *height*, hence vh. */
  --jam-w: 71.639vh;
  --jam-h: 96.809vh;
  --jam-x: calc(30vw - 47.774vh);
  --jam-y: 7.344vh;
  --jam-a: -16deg;

  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)'/%3E%3C/svg%3E");

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-gel: cubic-bezier(0.18, 1.16, 0.32, 1);
}

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

html, body {
  height: 100%;
  margin: 0;
}

body {
  background: var(--ink);
  color: var(--text);
  font-family: "Space Grotesk", ui-sans-serif, system-ui, -apple-system,
               "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow: hidden;
  overscroll-behavior: none;
}

.vh {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}

/* ---------------------------------------------------------------- stage */

.stage {
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: var(--ink);
  isolation: isolate;
}

/* ------------------------------------------------------------ backdrop */

.bg { position: absolute; inset: 0; pointer-events: none; }

.bg__glow {
  position: absolute;
  left: -10%; top: -30%;
  width: 100%; height: 120%;
  background:
    radial-gradient(48% 42% at 42% 46%, rgba(24, 55, 243, 0.34), rgba(24, 55, 243, 0) 68%),
    radial-gradient(38% 34% at 62% 30%, rgba(154, 154, 255, 0.14), rgba(154, 154, 255, 0) 70%);
  filter: blur(24px);
  opacity: 0;
  transition: opacity 1600ms var(--ease-out) 120ms;
  will-change: opacity, transform;
}

.bg__stars {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 2200ms ease 500ms;
}
.bg__stars i {
  position: absolute;
  width: 1px; height: 1px;
  border-radius: 50%;
  background: var(--ice);
}
.bg__stars--far i { background: var(--lavender); }

.bg__grain {
  position: absolute;
  inset: -50%;
  pointer-events: none;
  opacity: 0.055;
  mix-blend-mode: overlay;
  background-image: var(--grain);
  background-size: 220px 220px;
  z-index: 4;
}

.bg__vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 3;
  background:
    radial-gradient(120% 100% at 50% 42%, rgba(0,0,0,0) 42%, rgba(2,2,12,0.55) 100%);
}

/* ----------------------------------------------------------------- jam */

.jam {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

.jam__gl {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: none;
}
.has-gl .jam__gl { display: block; }
.has-gl .jam__css { display: none; }

/* CSS-only fallback: same geometry, gentler motion */
.jam__css {
  position: absolute;
  left: var(--jam-x);
  top: var(--jam-y);
  width: var(--jam-w);
  height: var(--jam-h);
  transform-origin: 0 0;
  rotate: var(--jam-a);
}
.jam__inner {
  position: absolute;
  inset: 0;
  transform-origin: 50% 50%;
  opacity: 0;
  will-change: transform, opacity, filter;
}
.jam__img,
.jam__sheen {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.jam__img { object-fit: fill; }

.jam__sheen {
  /* Only shown once app.js has pointed --jam-src at whichever variant the browser
     actually chose. Without that the gradient would paint as a bare rectangle. */
  display: none;
  background: linear-gradient(
    104deg,
    rgba(59,107,255,0) 34%,
    rgba(120,160,255,0.30) 47%,
    rgba(200,220,255,0.42) 50%,
    rgba(120,160,255,0.30) 53%,
    rgba(59,107,255,0) 66%);
  background-size: 260% 260%;
  mix-blend-mode: screen;
  -webkit-mask-image: var(--jam-src);
  mask-image: var(--jam-src);
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  opacity: 0.85;
}

/* ------------------------------------------------------------- content */

.has-mask .jam__sheen { display: block; }

.content {
  position: absolute;
  right: var(--pad);
  bottom: calc(var(--pad) + env(safe-area-inset-bottom, 0px));
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  text-align: right;
  max-width: min(88vw, 560px);
}

.tagline {
  margin: 0 0 clamp(16px, 1.9vw, 30px);
  font-family: "Special Gothic", "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  /* the wght/wdth axes driven through real properties, not font-variation-settings,
     so a fallback face still renders bold instead of dropping to body weight */
  font-weight: 700;
  font-stretch: 78%;
  /* the vh term is what keeps three lines inside a short window — at 84px flat
     the top line rides off the viewport once the window drops under ~600px tall.
     In portrait and near-square ratios the vw term is always the smaller of the
     two, so this only bites where it has to: wide and short. */
  font-size: clamp(32px, min(9.5vw, 14vh), 84px);
  line-height: 0.84;
  letter-spacing: -0.042em;
  text-transform: uppercase;
  color: var(--text);
  /* the same lift the lockup uses, so the line holds up where the gel runs under it */
  filter: drop-shadow(0 10px 34px rgba(3, 4, 26, 0.72));
}

/* Each line masks its own reveal — the same move the logotype makes, reusing its
   keyframes and easing so the two read as one gesture. The mask window is the
   line box, so a line is fully hidden before it rises. */
.tagline__line {
  display: block;
  overflow: hidden;
}
.tagline__line > span {
  display: block;
  transform: translate3d(0, 116%, 0) scaleY(1.34);
  transform-origin: 50% 100%;
  opacity: 0;
}

.lockup {
  margin: 0;
  width: var(--lockup-w);
  color: var(--text);
  filter: drop-shadow(0 10px 34px rgba(3, 4, 26, 0.72));
}

.lockup__line {
  display: block;
  overflow: hidden;
}
.lockup__line--jam {
  width: 63.4%;          /* JAM measures 63.4% of COSMIC in the original lockup */
  margin: 1.27% auto 0;  /* original interline gap */
}
.lockup__svg {
  display: block;
  width: 100%;
  height: auto;
  transform: translate3d(0, 116%, 0) scaleY(1.34);
  transform-origin: 50% 100%;
  opacity: 0;
}

.footer {
  position: absolute;
  left: var(--pad);
  bottom: calc(var(--pad) + env(safe-area-inset-bottom, 0px));
  z-index: 5;
  display: flex;
  align-items: center;
  /* wide enough that the two padded hit areas below never touch */
  gap: clamp(20px, 1.8vw, 30px);
  opacity: 0;
}
.footer a {
  /* padding buys a real tap target; the matching negative margin keeps both
     marks sitting on the layout margin and the row the height of the artwork */
  display: block;
  padding-block: 9px;
  margin-block: -9px;
  color: var(--muted);
  transition: color 240ms ease;
}
.footer a:hover { color: var(--ice); }
.footer__mark {
  display: block;
  width: clamp(124px, 11.5vw, 178px);
  height: auto;
}
.social {
  padding-inline: 12px;
  margin-inline: -12px;
}
.social__icon {
  display: block;
  width: var(--social);
  height: var(--social);
}

a:focus-visible {
  outline: 2px solid var(--lavender);
  outline-offset: 4px;
  border-radius: 3px;
}

/* --------------------------------------------------------- choreography */

.is-ready .bg__glow  { opacity: 1; animation: glow-pulse 17s ease-in-out 1.8s infinite; }
.is-ready .bg__stars { opacity: 0.55; animation: twinkle 9s ease-in-out 2s infinite; }
.is-ready .bg__stars--far { opacity: 0.3; animation: twinkle 13s ease-in-out 3.4s infinite reverse; }

.is-ready .jam__inner { animation: jam-in-css 1500ms var(--ease-gel) 120ms forwards, jam-breathe 15s ease-in-out 1.7s infinite; }
.is-ready .jam__sheen { animation: sheen-sweep 11s ease-in-out 2.2s infinite; }

/* One beat per line on a ~140ms cadence, the wordmark picking up the rhythm where
   the statement leaves off: 360 / 500 / 640, then 780, then 960 with the wider beat
   the two lockup lines always had. The third statement line added a beat, so the
   wordmark and footer moved back by one to keep the handoff intact. */
.is-ready .lockup__line:nth-of-type(2) .lockup__svg { animation: line-in 1150ms var(--ease-gel) 780ms forwards; }
.is-ready .lockup__line:nth-of-type(3) .lockup__svg { animation: line-in 1150ms var(--ease-gel) 960ms forwards; }

.is-ready .tagline__line > span    { animation: line-in 1150ms var(--ease-gel) 360ms forwards; }
.is-ready .tagline__line--2 > span { animation-delay: 500ms; }
.is-ready .tagline__line--3 > span { animation-delay: 640ms; }
.is-ready .footer  { animation: rise-in 900ms var(--ease-out) 1340ms forwards; }

@keyframes jam-in-css {
  0%   { opacity: 0; transform: scale(1.12) rotate(-4deg); filter: blur(18px); }
  55%  { opacity: 1; }
  100% { opacity: 1; transform: scale(1) rotate(0deg); filter: blur(0); }
}

@keyframes sheen-sweep {
  0%, 12%   { background-position: 130% 0; }
  62%, 100% { background-position: -50% 0; }
}

@keyframes jam-breathe {
  0%, 100% { scale: 1 1; }
  33%      { scale: 1.022 0.988; }
  66%      { scale: 0.99 1.016; }
}

@keyframes line-in {
  0%   { opacity: 0; transform: translate3d(0, 116%, 0) scaleY(1.34); }
  55%  { opacity: 1; }
  100% { opacity: 1; transform: translate3d(0, 0, 0) scaleY(1); }
}

@keyframes rise-in {
  from { opacity: 0; transform: translate3d(0, 14px, 0); }
  to   { opacity: 1; transform: none; }
}

@keyframes glow-pulse {
  0%, 100% { opacity: 1;    transform: scale(1)    translate(0, 0); }
  50%      { opacity: 0.78; transform: scale(1.07) translate(1.5%, -1%); }
}

@keyframes twinkle {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 0.22; }
}

/* ------------------------------------------------ statement, wide screens */

/* Landscape with the height to carry it: the statement leaves the bottom cluster
   and takes the empty upper right, which is exactly where frameFor() has already
   pushed the gel off to the left. Below either threshold it stays in the column
   above the wordmark, the only place it fits. The top offset clears the social
   mark, which shares this corner and paints under .content. */
@media (min-aspect-ratio: 21/20) and (min-height: 560px) {
  .content {
    top: calc(var(--pad) + env(safe-area-inset-top, 0px) + var(--social) + clamp(18px, 1.6vw, 30px));
    max-width: min(60vw, 1400px);
    justify-content: space-between;
  }
  .tagline {
    margin: 0;
    /* vw sets the measure; the vh term keeps the lines off the wordmark when the
       window is wide but short. 15vh is the three-line equivalent of the 17vh
       this held at two lines — below ~770px tall the vh term is what binds. */
    font-size: min(8.2vw, 15vh);
  }
}

/* --------------------------------------------------------- portrait */

@media (max-aspect-ratio: 9/10) {
  :root {
    --lockup-w: min(72vw, 420px);
    --jam-w: 42.332vh;
    --jam-h: 57.205vh;
    --jam-x: calc(50vw - 26.650vh);
    --jam-y: 10.423vh;
    --jam-a: -12deg;
  }
  .content {
    right: var(--pad);
    left: var(--pad);
    bottom: calc(var(--pad) + 30px + env(safe-area-inset-bottom, 0px));
    max-width: none;
  }
  .footer { left: auto; right: var(--pad); }
}

/* --------------------------------------------------------- narrow */

/* Adding the LinkedIn mark widened the footer row past the point where it and the
   wordmark can share the bottom line: at 320px the two need 371px of a 276px
   measure. Below this width the column clears the footer instead of sitting on it. */
@media (max-width: 560px) {
  .content {
    bottom: calc(var(--pad) + 34px + env(safe-area-inset-bottom, 0px));
  }
}

/* ---------------------------------------------------------- mobile */

/* Phone portrait only. The asymmetric composition needs width to read as
   deliberate rather than crowded, and it has none here — so the column
   centres under the gel, which frameFor() has already centred at these
   ratios. Deliberately not applied to a narrow landscape window: there the
   gel sits left of centre and centred copy would land on top of it. */
@media (max-width: 560px) and (max-aspect-ratio: 9/10) {
  .content {
    align-items: center;
    text-align: center;
  }
  .footer {
    left: var(--pad);
    justify-content: center;
  }
}

/* --------------------------------------------------- reduced motion */

@media (prefers-reduced-motion: reduce) {
  .bg__glow, .bg__stars { transition: none; }

  /* these have to repeat the :nth-of-type() selectors below — a plain
     `.is-ready .lockup__svg` loses on specificity and the wordmarks keep sliding */
  .is-ready .lockup__line:nth-of-type(2) .lockup__svg,
  .is-ready .lockup__line:nth-of-type(3) .lockup__svg {
    animation: none;
    opacity: 1;
    transform: none;
  }

  .is-ready .bg__glow,
  .is-ready .bg__stars,
  .is-ready .bg__stars--far,
  .is-ready .jam__inner,
  .is-ready .jam__sheen { animation: none; }

  .is-ready .bg__glow  { opacity: 1; }
  .is-ready .bg__stars { opacity: 0.5; }
  .is-ready .jam__inner { opacity: 1; animation: none; }
  .jam__sheen { opacity: 0.35; background-position: 40% 0; }
  .is-ready .lockup__svg,
  .is-ready .tagline__line > span,
  .is-ready .footer {
    opacity: 1;
    transform: none;
    animation: none;
  }
}
