/* ==========================================================================
   GVEC DESIGN SYSTEM — token + primitive layer
   --------------------------------------------------------------------------
   Phase 1 of the modernization. This file is ADDITIVE and deliberately ships
   with zero visual change: it declares tokens and opt-in utility classes, and
   restyles nothing that already exists. Nothing on the site consumes these
   classes until a page is migrated to them, so it can be deployed safely
   ahead of any redesign work.

   Load order matters. It must come AFTER styles.min.css and
   page-enhancements.css so the @layer block below can sit under them without
   fighting the existing !important override layer.

   WHY @layer: page-enhancements.css is a ~1,100-line !important override
   sheet retrofitting a dark theme onto light-theme base CSS. Unlayered rules
   always beat layered ones, so putting the system in a layer guarantees it
   cannot accidentally win against existing page styles during migration.
   As pages move over, their old rules get deleted and the layer takes effect
   naturally — no specificity arms race, no !important escalation.

   Author: Vivere Web · https://vivereweb.com
   ========================================================================== */

@layer gv.tokens, gv.base, gv.primitives, gv.motion;

/* ==========================================================================
   TOKENS
   ========================================================================== */
@layer gv.tokens {
  :root {
    /* ---- BRAND SEED --------------------------------------------------
       Every gold on the site derives from one seed. Today the codebase has
       two competing golds (#c5a059 and #d4af37) used interchangeably, plus
       dozens of hand-picked rgba() tints. Deriving with relative OKLCH means
       hover/active/tint states are computed, perceptually even, and can never
       drift out of sync with the brand.                                    */
    --gv-gold: #c5a059;          /* primary brand gold (matches existing --gold) */
    --gv-gold-bright: #d4af37;   /* existing --gold-bright, kept for parity      */

    /* ---- GRANITE / SURFACE RAMP -------------------------------------- */
    --gv-ink-900: #05070b;       /* deepest, page ground                        */
    --gv-ink-800: #0a0a0a;       /* current body background                     */
    --gv-ink-700: #111214;
    --gv-ink-600: #17181b;
    --gv-ink-500: #1f2126;

    --gv-paper: #f3ecdd;         /* warm off-white, matches promo/video work    */
  }

  /* Relative-colour derivations. Split into @supports so browsers without
     relative colour syntax still get sane literal fallbacks above/below
     rather than an invalid-value cascade failure. */
  :root {
    --gv-gold-100: rgba(197, 160, 89, 0.10);
    --gv-gold-200: rgba(197, 160, 89, 0.22);
    --gv-gold-400: rgba(197, 160, 89, 0.45);
    --gv-gold-600: #b08c46;
    --gv-gold-hover: #e0bd72;
  }
  @supports (color: oklch(from red l c h)) {
    :root {
      --gv-gold-100: oklch(from var(--gv-gold) l c h / 0.10);
      --gv-gold-200: oklch(from var(--gv-gold) l c h / 0.22);
      --gv-gold-400: oklch(from var(--gv-gold) l c h / 0.45);
      --gv-gold-600: oklch(from var(--gv-gold) calc(l - 0.08) c h);
      --gv-gold-hover: oklch(from var(--gv-gold) calc(l + 0.10) calc(c + 0.01) h);
    }
  }

  :root {
    /* ---- TEXT ---------------------------------------------------------
       --text-secondary was referenced across events.html but never declared
       anywhere, so it fell back to #444 on near-black (~2:1). Declared here
       as part of a proper ramp.                                            */
    --gv-text: rgba(255, 255, 255, 0.92);
    --gv-text-soft: rgba(255, 255, 255, 0.78);
    --gv-text-mute: rgba(255, 255, 255, 0.62);
    --gv-text-faint: rgba(255, 255, 255, 0.45); /* decorative only — fails AA on body copy */

    /* ---- FLUID TYPE ---------------------------------------------------
       Utopia-style clamp ramp, 320px → 1440px. Replaces breakpoint jumps. */
    --gv-step--1: clamp(0.83rem, 0.80rem + 0.15vw, 0.92rem);
    --gv-step-0:  clamp(1.00rem, 0.95rem + 0.25vw, 1.13rem);
    --gv-step-1:  clamp(1.20rem, 1.11rem + 0.45vw, 1.42rem);
    --gv-step-2:  clamp(1.44rem, 1.29rem + 0.75vw, 1.78rem);
    --gv-step-3:  clamp(1.73rem, 1.49rem + 1.20vw, 2.22rem);
    --gv-step-4:  clamp(2.07rem, 1.71rem + 1.82vw, 2.78rem);
    --gv-step-5:  clamp(2.49rem, 1.95rem + 2.68vw, 3.47rem);
    --gv-step-6:  clamp(2.99rem, 2.21rem + 3.88vw, 4.34rem);

    /* ---- FLUID SPACE -------------------------------------------------- */
    --gv-space-3xs: clamp(0.25rem, 0.24rem + 0.06vw, 0.31rem);
    --gv-space-2xs: clamp(0.50rem, 0.48rem + 0.11vw, 0.63rem);
    --gv-space-xs:  clamp(0.75rem, 0.71rem + 0.17vw, 0.94rem);
    --gv-space-s:   clamp(1.00rem, 0.95rem + 0.23vw, 1.25rem);
    --gv-space-m:   clamp(1.50rem, 1.43rem + 0.35vw, 1.88rem);
    --gv-space-l:   clamp(2.00rem, 1.90rem + 0.46vw, 2.50rem);
    --gv-space-xl:  clamp(3.00rem, 2.86rem + 0.70vw, 3.75rem);
    --gv-space-2xl: clamp(4.00rem, 3.81rem + 0.93vw, 5.00rem);

    /* ---- ELEVATION ----------------------------------------------------
       Two shadows per level: a tight contact shadow that reads at rest, and
       a wide ambient shadow that reads as height. The current site uses one
       flat border everywhere, which is why nothing feels layered.          */
    --gv-elev-1: 0 1px 2px rgba(0, 0, 0, 0.45),
                 0 2px 6px rgba(0, 0, 0, 0.30);
    --gv-elev-2: 0 1px 3px rgba(0, 0, 0, 0.50),
                 0 8px 22px rgba(0, 0, 0, 0.38);
    --gv-elev-3: 0 1px 3px rgba(0, 0, 0, 0.55),
                 0 18px 46px rgba(0, 0, 0, 0.48);
    --gv-elev-4: 0 2px 4px rgba(0, 0, 0, 0.60),
                 0 32px 74px rgba(0, 0, 0, 0.55);

    /* ---- RADII / BORDER ---------------------------------------------- */
    --gv-radius-s: 8px;
    --gv-radius-m: 12px;
    --gv-radius-l: 16px;
    --gv-radius-xl: 22px;
    --gv-hairline: 1px solid var(--gv-gold-200);

    /* ---- LAYOUT ------------------------------------------------------- */
    --gv-measure: 65ch;          /* readable line length for prose          */
    --gv-container: 1180px;      /* matches existing slider/promo max-width  */
    --gv-nav-offset: 80px;       /* overridden at runtime by ResizeObserver  */

    /* ---- MOTION ------------------------------------------------------- */
    --gv-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
    --gv-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
    --gv-dur-fast: 0.18s;
    --gv-dur: 0.28s;
    --gv-dur-slow: 0.5s;
  }

  @media (min-width: 1024px) {
    :root { --gv-nav-offset: 96px; }
  }
}

/* ==========================================================================
   BASE — opt-in only, scoped to .gv-scope so nothing existing is touched
   ========================================================================== */
@layer gv.base {
  .gv-scope {
    color: var(--gv-text);
    font-size: var(--gv-step-0);
    line-height: 1.65;
  }

  /* Headlines never orphan a word; body copy breaks sensibly. Free polish,
     supported everywhere current, ignored harmlessly where not. */
  .gv-scope :is(h1, h2, h3, .gv-title) { text-wrap: balance; line-height: 1.14; }
  .gv-scope :is(p, li, .gv-prose) { text-wrap: pretty; }
  .gv-prose { max-width: var(--gv-measure); }

  /* Any column of figures should align on the decimal. */
  .gv-tabular { font-variant-numeric: tabular-nums; }
}

/* ==========================================================================
   PRIMITIVES
   ========================================================================== */
@layer gv.primitives {

  /* ---- CONTAINER ------------------------------------------------------ */
  .gv-container {
    max-width: var(--gv-container);
    margin-inline: auto;
    padding-inline: var(--gv-space-s);
    box-sizing: border-box;
  }

  /* ---- SURFACE / CARD -------------------------------------------------
     One card recipe replaces ten near-identical ones. Elevation is a
     modifier, not a redeclaration — this is what gives the site hierarchy
     instead of one flat plane.                                            */
  .gv-surface {
    position: relative;
    background: linear-gradient(180deg, var(--gv-ink-600) 0%, var(--gv-ink-800) 100%);
    border: var(--gv-hairline);
    border-radius: var(--gv-radius-l);
    box-shadow: var(--gv-elev-2);
  }
  .gv-surface--flat  { box-shadow: var(--gv-elev-1); }
  .gv-surface--raised{ box-shadow: var(--gv-elev-3); }
  .gv-surface--hero  { box-shadow: var(--gv-elev-4); border-color: var(--gv-gold-400); }

  /* Interactive surfaces lift. Transform/opacity only — never layout props. */
  .gv-surface--interactive {
    transition: transform var(--gv-dur) var(--gv-ease-out),
                box-shadow var(--gv-dur) var(--gv-ease-out),
                border-color var(--gv-dur) var(--gv-ease-out);
  }
  .gv-surface--interactive:where(:hover, :focus-within) {
    transform: translateY(-3px);
    box-shadow: var(--gv-elev-3);
    border-color: var(--gv-gold-400);
  }

  /* ---- GLASS ----------------------------------------------------------
     Solid fallback first; the translucent treatment only applies where
     backdrop-filter actually works, so no browser gets an unreadable panel. */
  .gv-glass {
    background: rgba(10, 10, 10, 0.92);
    border: var(--gv-hairline);
  }
  @supports ((backdrop-filter: blur(8px)) or (-webkit-backdrop-filter: blur(8px))) {
    .gv-glass {
      background: rgba(10, 10, 10, 0.58);
      -webkit-backdrop-filter: blur(10px) saturate(140%);
      backdrop-filter: blur(10px) saturate(140%);
    }
  }

  /* ---- EYEBROW / KICKER ----------------------------------------------
     Replaces 8+ competing class names. Note the colour: several existing
     eyebrows sit at 45% white or 55% gold and fail AA — this one passes.  */
  .gv-eyebrow {
    display: block;
    font-size: var(--gv-step--1);
    font-weight: 700;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--gv-gold);
    margin: 0 0 var(--gv-space-2xs);
  }

  /* ---- BUTTONS --------------------------------------------------------
     Replaces seven competing button systems. 44px min target — the venue
     ticker's Buy Tickets control currently measures ~16.5px tall, which is
     the single most important control on the site.                        */
  .gv-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--gv-space-2xs);
    min-height: 44px;
    padding: var(--gv-space-2xs) var(--gv-space-m);
    border: 1px solid transparent;
    border-radius: var(--gv-radius-s);
    font: inherit;
    font-size: var(--gv-step--1);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-decoration: none;
    cursor: pointer;
    transition: transform var(--gv-dur-fast) var(--gv-ease-out),
                box-shadow var(--gv-dur-fast) var(--gv-ease-out),
                background-color var(--gv-dur-fast) var(--gv-ease-out);
  }
  .gv-btn--gold {
    background: linear-gradient(135deg, var(--gv-gold-hover), var(--gv-gold));
    color: #14100a;
    box-shadow: var(--gv-elev-1);
  }
  .gv-btn--gold:where(:hover, :focus-visible) {
    transform: translateY(-2px);
    box-shadow: var(--gv-elev-2);
  }
  .gv-btn--ghost {
    background: transparent;
    color: var(--gv-gold-hover);
    border-color: var(--gv-gold-400);
  }
  .gv-btn--ghost:where(:hover, :focus-visible) {
    background: var(--gv-gold-100);
    color: var(--gv-gold-hover);
  }
  .gv-btn:focus-visible {
    outline: 2px solid var(--gv-gold-hover);
    outline-offset: 3px;
  }

  /* ---- BENTO GRID -----------------------------------------------------
     The fix for `repeat(auto-fit, minmax(...))` rows of identical tiles.
     Children opt into span sizes, which is what creates hierarchy.        */
  .gv-bento {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--gv-space-s);
  }
  @media (min-width: 900px) {
    .gv-bento { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .gv-bento__item--wide { grid-column: span 2; }
    .gv-bento__item--hero { grid-column: span 2; grid-row: span 2; }
  }

  /* Aligns card internals across a row — headings and CTAs land on the
     same baseline regardless of title length. */
  @supports (grid-template-rows: subgrid) {
    .gv-subgrid { display: grid; grid-template-rows: subgrid; grid-row: span 3; }
  }

  /* ---- MEDIA FRAME ----------------------------------------------------
     Explicit ratio per slot. This is the direct lesson from the landing-page
     showcase failure: mixing intrinsic aspect ratios inside one grid row
     leaves dead space. Ratio is declared by the slot, never inherited from
     whatever the content happens to be.                                    */
  .gv-media { position: relative; overflow: hidden; background: var(--gv-ink-900); }
  .gv-media > :is(img, video, iframe) {
    display: block; width: 100%; height: 100%;
    border: 0; object-fit: cover;
  }
  .gv-media--16x9 { aspect-ratio: 16 / 9; }
  .gv-media--4x3  { aspect-ratio: 4 / 3; }
  .gv-media--1x1  { aspect-ratio: 1 / 1; }
  .gv-media--4x5  { aspect-ratio: 4 / 5; }   /* portrait card slot */
  .gv-media--3x4  { aspect-ratio: 3 / 4; }
  .gv-media--9x16 { aspect-ratio: 9 / 16; }
  /* Portrait source that must not be cropped (e.g. phone-shot performance
     footage) — letterboxes inside the slot instead of losing the subject. */
  .gv-media--contain > :is(img, video) { object-fit: contain; }

  /* ---- DIVIDER -------------------------------------------------------- */
  .gv-rule {
    height: 1px; border: 0; margin: var(--gv-space-l) 0;
    background: linear-gradient(90deg,
      transparent, var(--gv-gold-400) 22%, var(--gv-gold-400) 78%, transparent);
  }

  /* ---- VISUALLY HIDDEN (kept focusable) ------------------------------- */
  .gv-sr-only {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap; border: 0;
  }
}

/* ==========================================================================
   MOTION
   --------------------------------------------------------------------------
   Everything here is progressive enhancement. The default state of every
   animated element is its FINAL state, so a browser without support — or a
   visitor with reduced motion — sees finished, correctly-positioned content
   with zero layout shift. Animation only ever removes itself.
   ========================================================================== */
@layer gv.motion {

  /* Scroll-driven reveal. Pure CSS, runs off the main thread, no JS, no
     IntersectionObserver, no CLS. */
  @supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
      .gv-reveal {
        animation: gv-rise linear both;
        animation-timeline: view();
        animation-range: entry 0% entry 55%;
      }
      .gv-reveal--fade {
        animation: gv-fade linear both;
        animation-timeline: view();
        animation-range: entry 0% entry 40%;
      }
    }
  }
  @keyframes gv-rise { from { opacity: 0; transform: translateY(26px); } }
  @keyframes gv-fade { from { opacity: 0; } }

  /* Zero-JS scroll progress bar. */
  @supports (animation-timeline: scroll(root)) {
    @media (prefers-reduced-motion: no-preference) {
      .gv-progress {
        position: fixed; inset: 0 0 auto 0; height: 3px; z-index: 200;
        transform-origin: 0 50%;
        background: linear-gradient(90deg, var(--gv-gold), var(--gv-gold-hover));
        animation: gv-progress linear both;
        animation-timeline: scroll(root);
      }
    }
  }
  @keyframes gv-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }

  /* Parallax drift for hero media. */
  @supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
      .gv-parallax {
        animation: gv-drift linear both;
        animation-timeline: view();
        animation-range: cover;
        will-change: transform;
      }
    }
  }
  @keyframes gv-drift { from { transform: translateY(-4%) scale(1.06); }
                          to { transform: translateY(4%)  scale(1.06); } }

  /* Belt and braces: if any of the above ever runs where it shouldn't,
     reduced-motion users get the finished state instantly. */
  @media (prefers-reduced-motion: reduce) {
    .gv-reveal, .gv-reveal--fade, .gv-parallax, .gv-progress {
      animation: none !important;
      opacity: 1 !important;
      transform: none !important;
    }
    .gv-progress { display: none; }
  }
}
