/* ============================================================
   brand.css — single source of truth for the color system.
   RGV Games on Wheelz — cyberpunk neon-on-navy gaming palette,
   derived per CLAUDE.md "Brand color system".
   Recolor a client by editing ONLY the tokens in the first
   :root block below; everything else references these.

   TWO-TIER DARK SYSTEM (CLAUDE.md FROZEN) — the brand reads near-black, not navy:
     tier 1 base     --color-black       #060713  every dark SECTION background
     tier 2 elevated --color-primary     #0D1135  cards, panels, glass surfaces
     tier 3 floating --color-primary-mid #1A2060  hover, raised cards
   Tier 2 on tier 1 is only 1.09:1 — elevation is carried by a glowing cyan border +
   blur + shadow, NEVER by the fill alone. No fourth dark hex may drift in.

   ⚠ MAGENTA IS SPLIT BY LIGHT BACKGROUND, exactly like the two muted tokens.
     --color-accent-deep      #E5007A → on --color-bg  #FFFFFF = 4.55:1 PASS
     --color-accent-deep      #E5007A → on --color-bg-2 #F2F4FA = 4.14:1 FAIL (small text)
     --color-accent-deep-tint #D8006F → on --color-bg-2 #F2F4FA = 4.60:1 PASS
   CLAUDE.md verified magenta only against WHITE and froze it "never lighten"; the
   #F2F4FA tint pairing was never measured and does not clear AA for small text. The
   tint token is DARKER (never lighter), so the frozen rule holds. Small magenta text
   sitting directly on a .section-mid background must use the -tint variant; magenta
   inside a white card on that section keeps --color-accent-deep.
   SIGNED OFF: --color-accent-deep-tint is in the CLAUDE.md token table (FROZEN).

   Contrast check (verified this pass):
     accent-deep  #E5007A vs bg      #FFFFFF = 4.55:1  (hairline pass — never lighten)
     accent-deep  #E5007A vs black   #060713 = 4.40:1  FAILS — not an on-dark text color
     accent-brt   #00D4FF vs black   #060713 = 11.3:1  PASS
     white        #FFFFFF vs black   #060713 = 20.0:1  PASS
     muted        #C9D0E5 vs black   #060713 = 13.0:1  PASS (ON DARK ONLY — 1.5:1 on white)
     muted-light  #5C6478 vs bg      #FFFFFF = 5.92:1  PASS
     muted-light  #5C6478 vs bg-2    #F2F4FA = 5.38:1  PASS
   ============================================================ */
:root {
  /* — Core palette (hex) — */
  --color-black:        #060713;  /* TIER 1 — canonical dark-section background, site-wide */
  --color-primary:      #0D1135;  /* TIER 2 — elevated navy surface (cards/panels/glass) */
  --color-primary-mid:  #1A2060;  /* TIER 3 — floating (hover, raised cards, dividers on dark) */
  --color-accent:       #00D4FF;  /* electric cyan — CTAs, icons, eyebrows, highlights */
  --color-accent-deep:  #E5007A;  /* hot magenta — on-LIGHT accent fallback (4.55:1 on white) */
  --color-accent-deep-tint: #D8006F; /* magenta for the bg-2 TINT — see note below (4.60:1 on #F2F4FA) */
  --color-accent-bright:#00D4FF;  /* on-DARK accent — every accent use on --color-black (11.3:1) */
  --color-dark:         #060713;  /* ALIAS of --color-black. Template selectors and every
                                     rgba(var(--color-dark-rgb),…) shadow key off this.
                                     Must NEVER diverge from --color-black. */
  /* NOTE: the template's --color-dark-3 was REMOVED. It was a fourth dark hex with no
     consumer once the tier-2 glass surface took over card fills, and the FROZEN rule
     allows exactly three dark tokens. Pages still carrying a `dark: { 3: ... }` Tailwind
     mapping should drop it as they are rebuilt. */
  --color-ink:          #08091F;  /* near-black navy — headings + body text on light */
  --color-muted:        #C9D0E5;  /* muted text ON DARK ONLY — fails 4.5:1 on white.
                                     Lifted from #9AA3C2 in the homepage-no-cards pass:
                                     13.0:1 on --color-black, comfortably past AA. */
  --color-muted-light:  #5C6478;  /* muted text ON LIGHT — the on-white counterpart */
  --color-silver:       #6B7BA4;  /* muted blue-gray — chrome trim, secondary on dark */
  --color-line:         #D6DAE8;  /* hairlines / borders on light (derived, cool) */
  --color-bg:           #FFFFFF;  /* page background */
  --color-bg-2:         #F2F4FA;  /* light section tint (derived, cool — holds 5.38:1 vs muted-light) */
  --color-lime:         #39FF14;  /* neon lime — wordmark/tertiary accent ONLY, used sparingly */
  --color-gold:         #FFD700;  /* gold — star/sparkle accents only, not a brand primary */
  --color-rating:       #FFD700;  /* star-rating fill — functional (= gold per CLAUDE.md) */

  /* — Channel triplets (R, G, B) for rgba() tinting — */
  --color-black-rgb:        6, 7, 19;
  --color-primary-rgb:      13, 17, 53;
  --color-primary-mid-rgb:  26, 32, 96;
  --color-accent-rgb:       0, 212, 255;
  --color-accent-deep-rgb:  229, 0, 122;
  --color-accent-deep-tint-rgb: 216, 0, 111;
  --color-accent-bright-rgb:0, 212, 255;
  --color-dark-rgb:         6, 7, 19;   /* alias — tracks --color-black-rgb */
  --color-ink-rgb:          8, 9, 31;
  --color-silver-rgb:       107, 123, 164;
  --color-lime-rgb:         57, 255, 20;
  --color-gold-rgb:         255, 215, 0;

  /* — Nebula ground (foundation pass) — shared by every page that runs
     js/nebula.js. Sections drop their fills so the shader is the one
     continuous page surface; where legibility needs a veil, it is an
     rgba() of tier 1 (--color-black-rgb), never a new hex (FROZEN).
     index.html's "NEBULA SHADER LAYER" block is the reference consumer. */
  --color-section-fill: rgba(0, 0, 0, 0);                    /* every dark section over the nebula */
  --color-footer-veil:  rgba(var(--color-black-rgb), 0.85);  /* footer — heaviest small-text density */
  --color-nav-veil:     rgba(var(--color-black-rgb), 0.95);  /* scrolled nav bar */
  --color-menu-veil:    rgba(var(--color-black-rgb), 0.97);  /* nav dropdowns / mobile menu */

  /* Size the nav off the client logo — see CLAUDE.md logo rules.
     PENDING: brand_assets/logo.png does not exist yet. These remain at the
     template defaults; re-size all three from the real logo when it lands. */
  --nav-height:         96px;   /* nav bar height — starting point, not fixed */
  --nav-logo-height:    72px;   /* client logo <img> height in the nav */
  --footer-logo-height: 116px;  /* client logo <img> height in the footer */
}

/* ============================================================
   Uniform content-photo container — used for EVERY content photo
   site-wide. One ratio (4:3) so no photo differs in size from
   another. Never use a fixed h-[Npx]. The ONLY exception is
   people/owner portraits: add --portrait (3:4, top-anchored).
   ============================================================ */
.photo-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: 16px;
  background: var(--color-bg-2);
  box-shadow: 0 20px 45px -24px rgba(var(--color-dark-rgb), 0.60),
              0 0 0 1px rgba(var(--color-dark-rgb), 0.06) inset;
}
.photo-frame > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
.photo-frame--portrait { aspect-ratio: 3 / 4; }
.photo-frame--portrait > img { object-position: center top; }

/* ============================================================
   OMBRE HALO — WebKit first-paint rasterization fix (SHARED)
   ------------------------------------------------------------
   The halo itself (background/blur/opacity/radius) stays defined in
   each page's gradient-treatment block. What lives HERE is only the
   compositing fix, because it must hold on every page that ever wraps
   a photo in .photo-ombre — including the Stage-2 clones, which
   inherit it through this file without touching their markup.

   THE BUG: a filter: blur() layer that composites inside a subtree
   being animated on scroll-in (opacity + transform) is what WebKit
   sometimes fails to rasterize on first composite — it paints a
   hard-edged box until the next repaint. This is the same race that
   was fixed on index.html's .video-feature::before; the later ombre
   treatment reused the blur idiom without inheriting that fix.

   THE FIX has two halves and needs BOTH:
     1. MARKUP (per page): the scroll reveal must sit on the INNER
        .photo-frame, never on .photo-ombre or an ancestor of it, so
        the blurred ::before is never inside an animated subtree.
        Mirrors .anim-scale-in living on .video-frame, not
        .video-feature. Clones must copy that nesting.
     2. THIS RULE: force the blur onto its own pre-rasterized GPU
        layer, independent of whatever compositing the reveal on
        .photo-frame triggers next to it.

   ⚠ Scope discipline: translateZ(0) goes on the blurred ::before ONLY
   — not on .photo-ombre, not on .photo-frame, and no will-change
   anywhere. Over-promoting costs memory and buys nothing here.

   ⚠ transform makes the ::before its own stacking context, but its
   z-index: -1 still paints it behind the frame inside .photo-ombre's
   isolate. Same combination .video-feature::before already ships.
   ============================================================ */
.photo-ombre::before {
  transform: translateZ(0);
  -webkit-transform: translateZ(0);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

/* ============================================================
   NEBULA BACKGROUND — seamless section surface
   ------------------------------------------------------------
   With the nebula shader as the page ground, every section fill was
   matched to rgba(0,0,0,0) so nothing seams. The per-section corner
   washes on .atmo::after / .atmo-dark::after were the last remaining
   source of per-section variation — five measurable boundary deltas
   (Δ22 to Δ34) — so they are switched off here.

   INTENTIONAL AND SHARED (foundation pass): every page runs the nebula
   via js/nebula.js, so every page wants these washes off. Do not move
   this rule back into a page-level <style> block and do not re-enable
   the washes per page — the nebula is the single continuous surface,
   and any wash on top of it reads as a seam.

   ⚠ CLAUDE.md lists "radial gradient glows" as one of exactly three
   sanctioned depth sources on dark. With these off, depth on dark
   comes from the elevation ladder and card borders alone.
   ============================================================ */
.atmo::after,
.atmo-dark::after { background: none !important; }

/* ============================================================
   PHONE CTA — visible tracking number inside the call buttons
   ------------------------------------------------------------
   The 67 "Call to Book" buttons carry the GHL tracking number in the
   button face as well as the tel: href, so the number is readable
   without tapping. The separator rule is drawn in the button's own ink
   (btn-primary sets color: var(--color-dark) on the brand gradient), so
   it stays legible through the cyan→magenta fill and the magenta hover.

   nowrap is load-bearing: the number must never break across two lines
   inside a pill. tabular-nums keeps the digits from shifting width.

   NOTE: these buttons deliberately carry NO aria-label. The number is
   visible text, so an aria-label would override the visible label and
   break WCAG 2.5.3 (Label in Name). Do not re-add one here.
   ============================================================ */
.cta-phone {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  letter-spacing: 0.005em;
  border-left: 1.5px solid rgba(var(--color-dark-rgb), 0.34);
  padding-left: 9px;
}

/* nowrap here too, or the narrow desktop-nav pill breaks the label into
   "Call to / Book" and the pill grows to two lines. */
.cta-label { white-space: nowrap; }

/* 768–1023px: the desktop nav is live (md:flex) but the row is tight, and a
   full label + number pill pushes against the viewport edge. The label yields;
   the number never does. The mobile menu is exempt — it is a full-width
   stacked button with room for both, and its ID beats these selectors. */
@media (max-width: 1023px) {
  nav .btn-primary .cta-label { display: none; }
  nav .btn-primary .cta-phone { border-left: 0; padding-left: 0; }

  #mobile-menu .btn-primary .cta-label { display: inline; }
  #mobile-menu .btn-primary .cta-phone {
    border-left: 1.5px solid rgba(var(--color-dark-rgb), 0.34);
    padding-left: 9px;
  }
}

/* Below 380px the hero/final-CTA pill runs out of room for icon + label +
   number on one line. The label gives way, never the number. */
@media (max-width: 379px) {
  .cta-label { display: none; }
  .cta-phone { border-left: 0; padding-left: 0; }
}
