/* ============================================================
   JAQFRUIT — DESIGN SYSTEM / BASE
   Tokens, reset, typography, motion primitives
   ============================================================ */

@layer tokens, reset, type, motion, utils;

@layer tokens {
  :root {
    /* Brand */
    --yellow:      #FFD400;
    --yellow-deep: #E6BE00;
    --yellow-soft: #FFF4B8;
    --orange:      #FF8327;   /* from the Jaqfruit logomark */
    --orange-deep: #E86D12;

    /* Neutrals */
    --ink:   #0B0B0B;
    --black: #000000;
    --white: #FFFFFF;
    --off:   #FAFAF8;
    --g-90:  #141414;
    --g-70:  #333333;
    --g-50:  #666666;
    --g-30:  #999999;
    --g-15:  #CCCCCC;
    --g-08:  #E5E5E5;
    --g-04:  #F2F2F0;

    /* Semantic */
    --bg:        var(--yellow);
    --fg:        var(--ink);
    --muted:     var(--g-50);
    --rule:      rgba(0, 0, 0, .10);
    --rule-dark: rgba(255, 255, 255, .12);

    /* Type families */
    --font-display: "Fraunces", "Times New Roman", serif;
    --font-poster:  "Anton", "Arial Narrow", Impact, sans-serif;
    --font-ui:      "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

    /* Fluid type scale */
    --fs-mega:    clamp(3.2rem, 11vw, 11rem);
    --fs-h1:      clamp(2.6rem, 6.2vw, 6rem);
    --fs-h2:      clamp(1.9rem, 3.6vw, 3.4rem);
    --fs-h3:      clamp(1.25rem, 1.9vw, 1.65rem);
    --fs-lead:    clamp(1rem, 1.35vw, 1.2rem);
    --fs-body:    1rem;
    --fs-sm:      .875rem;
    --fs-xs:      .75rem;
    --fs-eyebrow: .66rem;

    /* Space */
    --gut:  5vw;
    --sp-1: .25rem;  --sp-2: .5rem;   --sp-3: .75rem;  --sp-4: 1rem;
    --sp-5: 1.5rem;  --sp-6: 2rem;    --sp-7: 3rem;    --sp-8: 4rem;
    --sp-9: 6rem;    --sp-10: 8rem;

    /* Radii */
    --r-sm: 10px; --r-md: 18px; --r-lg: 26px; --r-xl: 38px; --r-pill: 999px;

    /* Elevation */
    --sh-1: 0 1px 3px rgba(0,0,0,.05), 0 4px 14px rgba(0,0,0,.05);
    --sh-2: 0 4px 12px rgba(0,0,0,.07), 0 12px 34px rgba(0,0,0,.09);
    --sh-3: 0 10px 26px rgba(0,0,0,.10), 0 28px 66px rgba(0,0,0,.14);
    --sh-4: 0 20px 50px rgba(0,0,0,.16), 0 46px 100px rgba(0,0,0,.20);

    /* Motion */
    --ease:        cubic-bezier(.25,.46,.45,.94);
    --ease-out:    cubic-bezier(.16,1,.3,1);
    --ease-spring: cubic-bezier(.34,1.56,.64,1);
    --dur-fast: .18s; --dur: .34s; --dur-slow: .62s;

    --nav-h: 66px;
  }

  @media (max-width: 720px) {
    :root { --gut: 6vw; --nav-h: 58px; }
  }
}

@layer reset {
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

  html {
    scroll-behavior: smooth;
    -webkit-text-size-adjust: 100%;
    scroll-padding-top: calc(var(--nav-h) + 16px);
  }

  body {
    font-family: var(--font-ui);
    font-size: var(--fs-body);
    line-height: 1.6;
    color: var(--fg);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
    text-rendering: optimizeLegibility;
  }

  /* height:auto matters — every img carries width/height attributes (they
     reserve space and prevent layout shift), and without this the attribute
     height wins over the CSS width and the image renders stretched. */
  img, video, svg { display: block; max-width: 100%; height: auto; }
  a { color: inherit; text-decoration: none; }
  button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
  ul, ol { list-style: none; }

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

  ::selection { background: var(--ink); color: var(--yellow); }
}

@layer type {
  .display {
    font-family: var(--font-display);
    font-weight: 900;
    line-height: .95;
    letter-spacing: -.03em;
    text-wrap: balance;
  }

  .poster {
    font-family: var(--font-poster);
    font-weight: 400;
    line-height: .88;
    letter-spacing: -.01em;
    text-transform: uppercase;
    text-wrap: balance;
  }

  .t-mega { font-size: var(--fs-mega); }
  .t-h1   { font-size: var(--fs-h1); }
  .t-h2   { font-size: var(--fs-h2); }
  .t-h3   { font-size: var(--fs-h3); font-weight: 700; letter-spacing: -.015em; line-height: 1.2; }
  .t-lead { font-size: var(--fs-lead); line-height: 1.65; color: var(--muted); text-wrap: pretty; }
  .t-body { font-size: var(--fs-body); line-height: 1.7; color: var(--muted); text-wrap: pretty; }
  .t-sm   { font-size: var(--fs-sm); line-height: 1.6; }

  .eyebrow {
    display: inline-flex;
    align-items: center;
    gap: .6em;
    font-size: var(--fs-eyebrow);
    font-weight: 700;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--muted);
  }

  .eyebrow::before {
    content: "";
    width: 22px;
    height: 2px;
    background: currentColor;
    opacity: .55;
    flex: none;
  }

  .measure    { max-width: 62ch; }
  .measure-sm { max-width: 46ch; }
}

@layer motion {
  /* --- scroll reveal ---
     No `will-change` here. It is tempting, but a page has dozens of .rv
     elements and a permanent will-change promotes every one of them to its own
     compositor layer for the whole session — which exhausts layer memory and
     leaves stale, mis-painted tiles behind. opacity/transform transitions are
     already GPU-accelerated without the hint. */
     Scoped to .js (set by an inline script in <head>) so that if JavaScript
     fails to load or errors, nothing is ever hidden — the page renders as plain
     content instead of going completely blank. */
  .js .rv {
    opacity: 0;
    transform: translate3d(0, 26px, 0);
    transition:
      opacity var(--dur-slow) var(--ease-out),
      transform var(--dur-slow) var(--ease-out);
  }
  .js .rv.in { opacity: 1; transform: none; }

  .rv-scale { transform: translate3d(0, 26px, 0) scale(.97); }
  .rv-left  { transform: translate3d(-30px, 0, 0); }
  .rv-right { transform: translate3d(30px, 0, 0); }

  .d1 { transition-delay: .07s; } .d2 { transition-delay: .14s; }
  .d3 { transition-delay: .21s; } .d4 { transition-delay: .28s; }
  .d5 { transition-delay: .35s; } .d6 { transition-delay: .42s; }

  /* --- line-by-line headline reveal ---
     Deliberately NOT the classic overflow:hidden slide-up mask. This site sets
     display type at line-height .88–.95, so glyph ascenders and descenders sit
     outside the line box and a clipping mask shears the letters apart. A
     staggered fade-and-rise reads just as well and never touches the glyphs. */
  .reveal-lines { display: block; }
  .reveal-lines .ln { display: block; }

  /* Each word arrives on its own beat, tipped slightly off-axis and
     springing level — performers walking on to take their spot. */
  .js .reveal-lines .wd {
    display: inline-block;
    opacity: 0;
    transform: translateY(.5em) rotate(-5deg);
    transform-origin: 50% 100%;
    transition:
      opacity .45s var(--ease-out),
      transform .6s var(--ease-spring);
    transition-delay: calc(var(--i, 0) * 52ms);
  }
  .js .reveal-lines.in .wd { opacity: 1; transform: none; }

  @keyframes marquee   { from { transform: translateX(0); }  to { transform: translateX(-50%); } }
  @keyframes float-y   { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }
  @keyframes spin-slow { to { transform: rotate(360deg); } }
  @keyframes fade-up   { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
  @keyframes blink     { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }

  @keyframes pulse-ring {
    0%   { box-shadow: 0 0 0 0 rgba(255, 212, 0, .55); }
    70%  { box-shadow: 0 0 0 16px rgba(255, 212, 0, 0); }
    100% { box-shadow: 0 0 0 0 rgba(255, 212, 0, 0); }
  }

  @media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
      animation-duration: .001ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: .001ms !important;
    }
    .rv,
    .reveal-lines .wd { opacity: 1 !important; transform: none !important; }
  }
}

@layer utils {
  .wrap       { padding-inline: var(--gut); }
  .section    { padding: clamp(3.5rem, 7vw, 7rem) var(--gut); }
  .section-lg { padding: clamp(5rem, 10vw, 10rem) var(--gut); }
  .section-sm { padding: clamp(2.5rem, 4.5vw, 4rem) var(--gut); }

  .bg-yellow { background: var(--yellow); --muted: var(--g-70); --rule: rgba(0,0,0,.12); }
  .bg-black  { background: var(--ink); color: var(--white); --muted: rgba(255,255,255,.58); --rule: var(--rule-dark); }
  .bg-white  { background: var(--white); }
  .bg-off    { background: var(--off); }

  .stack > * + * { margin-top: var(--sp-4); }
  .center { text-align: center; }
  .rel    { position: relative; }

  @media (max-width: 760px) { .hide-sm { display: none !important; } }

  .sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  .skip-link {
    position: absolute;
    top: -100px;
    left: var(--gut);
    z-index: 2000;
    background: var(--ink);
    color: var(--yellow);
    padding: .75rem 1.25rem;
    border-radius: var(--r-pill);
    font-size: var(--fs-sm);
    font-weight: 700;
  }
  .skip-link:focus { top: 12px; }

  /* Subtle film grain — keeps the flat brand colour from going lifeless.
     Deliberately NOT mix-blend-mode: a blended full-section overlay forces the
     compositor to re-blend the layer every frame, which stalls badly next to the
     looping hero video and the marquees. Plain low-opacity noise is visually
     equivalent over flat brand colour and costs nothing to composite. */
  .grain::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: .05;
    z-index: 0;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
  }

  /* keep section content above the grain layer */
  .grain > * { position: relative; z-index: 1; }
}
