/* ==========================================================================
   MJ's Studio — premium layer
   Additive, isolated, and fully guarded. Everything here is transform/opacity
   based (GPU-composited) and disabled under reduced-motion / touch.
   Activated by classes the JS adds to <html>: .px-cursor .px-motion
   ========================================================================== */

/* --------------------------------------------------------------------------
   #1 Cinematic intro — gated by html.intro-on (added pre-paint). Self-playing.
   -------------------------------------------------------------------------- */
/* "Gold Rain Resolve": columns of gold code rain down, recede, and lock into the
   "MJ'S STUDIO" wordmark with a flash, then the whole curtain LIFTS to hand off to
   the hero (premium.js adds .hero.ready at lift-start so both rise as one vector).
   JS builds the rain + title; CSS owns the column fall, the dim, and the lift.
   transform / opacity / CSS mask / static gradients only. */
/* cinematic veil — a warm centre falling to near-black at the edges (vignette) gives
   the frame depth + a "luxury title card" feel. */
.intro { position: fixed; inset: 0; z-index: 600; display: none; overflow: hidden; will-change: opacity;
  background: radial-gradient(72% 58% at 50% 44%, #18130b 0%, #0b0905 64%, #060402 100%); }
/* the veil + rain fade out (the wordmark lives on <body>, so it survives this fade and
   glides to the nav brand — see premium.js match-cut). CSS owns this fade so a JS
   failure can't trap the veil. */
html.intro-on .intro { display: block; animation: introFade .5s ease 2.4s forwards; }
/* nav brand hidden during intro — the binary canvas flies there first; it fades in on arrival */
html.intro-on .brand { opacity: 0; }
@keyframes introFade { to { opacity: 0; visibility: hidden; } }

/* the binary rain + convergence is drawn on a single canvas (premium.js builds it). It
   fades with the veil; by then the gilded serif brand has already taken over for the
   match-cut, so the brand owns the frame. */
.intro-canvas { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

/* the wordmark layer lives on <body> (z above the veil) so it survives the veil fade
   and can glide into the nav brand. Two stacked layers: the monospace code (.intro-word)
   that scrambles + locks, then crossfades into the gilded SERIF brand (.intro-mark) — the
   refined material + serif (matching the nav brand) is what reads "expensive". */
.intro-title { position: fixed; inset: 0; z-index: 605; pointer-events: none; }
.intro-mark { position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; }

/* layer 2 — the gilded serif brand the code resolves INTO. Metallic gradient (polished
   gold) + a light sweep. This is what then performs the match-cut glide, landing on the
   nav brand TEXT (serif → serif = seamless; premium.js measures the text, not the box). */
.intro-mark { opacity: 0; transition: opacity .5s var(--ease); }
.intro-mark.show { opacity: 1; }
.intro-mark .mk { position: relative; overflow: hidden; margin: 0; padding: .08em .14em; white-space: nowrap;
  font-family: var(--font-serif); font-weight: 370; font-style: normal; letter-spacing: .012em;
  font-size: clamp(1.9rem, 7vw, 4.1rem); transform-origin: center; will-change: transform, opacity;
  background-image: linear-gradient(176deg, #f9ead0 4%, #ecd49a 30%, #c9a86a 56%, #9c7c40 80%, #e3c98f 100%);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; color: transparent; }
/* the light sweep — a soft specular band that travels across the wordmark once, like
   light catching polished gold. Clipped to the .mk box (overflow hidden). */
.intro-mark .gl { position: absolute; top: 0; bottom: 0; left: -45%; width: 38%;
  background: linear-gradient(105deg, transparent 0%, rgba(255,250,232,.0) 36%, rgba(255,250,232,.85) 50%, rgba(255,250,232,0) 64%, transparent 100%);
  transform: translateX(-160%) skewX(-12deg); }
.intro-mark.sweep .gl { animation: introGlint 1.05s cubic-bezier(.36,0,.18,1) .1s forwards; }
@keyframes introGlint { to { transform: translateX(520%) skewX(-12deg); } }

/* the lock bloom — a single soft radial of warm light (light catching the gold) */
.intro-flash { position: absolute; inset: 0; z-index: 2; pointer-events: none; opacity: 0;
  background: radial-gradient(46% 32% at 50% 50%, rgba(245,227,170,.5), transparent 70%); }
.intro-flash.fire { animation: introFlash .62s ease-out forwards; }
@keyframes introFlash { 0% { opacity: 0; transform: scale(.55); } 34% { opacity: 1; } 100% { opacity: 0; transform: scale(1.35); } }

/* --------------------------------------------------------------------------
   #7 Custom gold cursor (fine pointers only; native cursor hidden via .px-cursor)
   -------------------------------------------------------------------------- */
.px-cursor, .px-cursor a, .px-cursor button, .px-cursor summary, .px-cursor .index-row { cursor: none !important; }
@media (forced-colors: active) {
  .px-cursor, .px-cursor * { cursor: auto !important; }
}
.px-cursor input, .px-cursor textarea { cursor: text !important; }

.cursor-ring, .cursor-dot { position: fixed; top: 0; left: 0; z-index: 9999; pointer-events: none;
  transform: translate3d(-100px, -100px, 0) translate(-50%, -50%); will-change: transform; }
.cursor-ring { width: 38px; height: 38px; border: 1.5px solid var(--gold); border-radius: 50%;
  display: grid; place-items: center; opacity: 0;
  transition: width .28s var(--ease), height .28s var(--ease), opacity .3s,
              background-color .28s, border-color .28s; }
.cursor-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--gold-2); opacity: 0; transition: opacity .3s; }
.cursor-ring.show, .cursor-dot.show { opacity: 1; }
.cursor-ring.hover { width: 66px; height: 66px; background: rgba(201,168,106,.10); border-color: var(--gold-2); }
.cursor-ring.locked { border-color: var(--gold-2); background: rgba(201,168,106,.14); }
.cursor-ring.hover.locked { width: 58px; height: 58px; }
.cursor-ring.hover + .cursor-dot, .cursor-dot.hide { opacity: 0; }
.cursor-ring.zone-hero:not(.hover) { width: 52px; height: 52px; opacity: .65; }
.cursor-ring.zone-pricing.hover { background: rgba(201,168,106,.06); }

.cursor-label { font-family: var(--font-sans); font-size: .58rem; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--gold-2); opacity: 0; transform: scale(.6);
  transition: opacity .2s, transform .2s; }
.cursor-ring.labeled .cursor-label { opacity: 1; transform: scale(1); }

/* #A2 Click ripple — one gold pulse from the click point. left/top set once at
   birth (static); only transform + opacity animate. No box-shadow/blur. Sits
   under the live cursor (9999) and over the trail (9998). */
.cursor-ripple { position: fixed; z-index: 9997; pointer-events: none; width: 18px; height: 18px;
  margin: -9px 0 0 -9px; border: 1.5px solid var(--gold-2); border-radius: 50%; opacity: .9;
  will-change: transform, opacity; animation: cursorRipple .52s var(--ease) forwards; }
@keyframes cursorRipple { 0% { transform: scale(.4); opacity: .9; } 100% { transform: scale(3); opacity: 0; } }

/* #A1 Gold wake — fixed pool of motes. Opacity ramps with pointer speed
   (--trail-k, written by ringRAF) and falls off per-mote (--ti), so the wake
   dies the instant the ring settles. transform/opacity only, no shadow. */
.cursor-trail { position: fixed; top: 0; left: 0; z-index: 9998; pointer-events: none;
  width: 5px; height: 5px; border-radius: 50%; background: var(--gold-2);
  will-change: transform, opacity;
  opacity: calc((1 - var(--ti, 0) / 7) * 0.5 * var(--trail-k, 0));
  transform: translate3d(-100px, -100px, 0) translate(-50%, -50%); }

/* --------------------------------------------------------------------------
   #13 Living light — one slow-drifting warm glow inside the hero (GPU, one element)
   -------------------------------------------------------------------------- */
.live-light { position: absolute; top: 8%; right: 6%; width: 60vw; height: 60vw;
  max-width: 760px; max-height: 760px; border-radius: 50%; z-index: 0; pointer-events: none;
  background: radial-gradient(circle, rgba(201,168,106,.10), transparent 62%);
  filter: blur(20px); will-change: transform; animation: breathe 18s ease-in-out infinite alternate; }
@keyframes breathe {
  from { transform: translate3d(0,0,0) scale(1); opacity: .85; }
  to   { transform: translate3d(-7%, 5%, 0) scale(1.12); opacity: 1; }
}

/* --------------------------------------------------------------------------
   #6 Ambient "gallery at night" — subtle per-section tint (pure CSS, in-flow)
   -------------------------------------------------------------------------- */
#services { background:
  radial-gradient(80% 60% at 12% 0%, rgba(201,168,106,.030), transparent 60%),
  linear-gradient(180deg, transparent, rgba(201,168,106,.016) 50%, transparent); }
#process  { background:
  radial-gradient(80% 60% at 88% 0%, rgba(70,86,120,.040), transparent 62%),
  linear-gradient(180deg, transparent, rgba(70,86,120,.022) 50%, transparent); }
#pricing  { background:
  radial-gradient(80% 60% at 12% 10%, rgba(201,168,106,.034), transparent 60%),
  linear-gradient(180deg, transparent, rgba(201,168,106,.020) 50%, transparent); }
#faq      { background:
  radial-gradient(70% 60% at 88% 0%, rgba(70,86,120,.034), transparent 62%),
  linear-gradient(180deg, transparent, rgba(70,86,120,.018) 50%, transparent); }

/* --------------------------------------------------------------------------
   #3 Kinetic split-text headlines — words mask-rise + stagger on enter
   -------------------------------------------------------------------------- */
/* the title container must stay visible; the words carry the animation */
.px-motion .split { opacity: 1 !important; transform: none !important; transition: none !important; }
.px-motion .split .word { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: .2em; margin-bottom: -.18em; perspective: 800px; }
.px-motion .split .word > span { display: inline-block; transform: translateY(120%) rotateX(35deg); transform-origin: bottom center; will-change: transform;
  font-variation-settings: 'opsz' 72, 'wght' 300;
  transition: transform .55s var(--ease) calc(var(--i, 0) * 32ms); }
.px-motion .split.in .word > span { transform: translateY(0) rotateX(0); font-variation-settings: 'opsz' 72, 'wght' 340; }
/* #D Variable-font settle: the line firms from 300 -> 340 as it rises; each
   gold-em word lands a touch heavier (380) so the emphasis reads as it lands. */
.px-motion .split .gold-em { font-variation-settings: 'opsz' 72, 'wght' 300; }
.px-motion .split.in .gold-em { font-variation-settings: 'opsz' 72, 'wght' 380; }

/* --------------------------------------------------------------------------
   #4 Depth parallax — driven by one rAF handler writing --py (transform only)
   -------------------------------------------------------------------------- */
.px-motion [data-parallax] { will-change: transform; transform: translate3d(0, var(--py, 0px), 0); }

/* --------------------------------------------------------------------------
   #14 Self-drawing gold rules (eyebrow lines + section top rules)
   -------------------------------------------------------------------------- */
.px-motion .eyebrow::before { transform: scaleX(0); transform-origin: left; }
.px-motion .reveal.visible .eyebrow::before,
.px-motion .eyebrow.reveal.visible::before { animation: ruleDraw .7s var(--ease) .15s forwards; }
@keyframes ruleDraw { to { transform: scaleX(1); } }

/* --------------------------------------------------------------------------
   #8 3D tilt + soft cursor-light on card surfaces (form card, guarantee)
   -------------------------------------------------------------------------- */
.tilt { transform-style: preserve-3d; transition: transform .4s var(--ease); position: relative; }
.tilt > .tilt-glow { position: absolute; inset: 0; border-radius: inherit; pointer-events: none; z-index: 0;
  opacity: 0; transition: opacity .3s;
  background: radial-gradient(220px circle at var(--mx, 50%) var(--my, 50%), rgba(201,168,106,.14), transparent 70%); }
.tilt:hover .tilt-glow { opacity: 1; }
.tilt > * { position: relative; z-index: 1; }

/* --------------------------------------------------------------------------
   #18b Scroll-progress rail — a 2px gold hairline pinned to the viewport top edge,
   filled left->right by page scroll. MOBILE/NARROW ONLY (below 681px), exactly where
   the circular .scroll-gem meter is hidden, so the two never show together. Reuses
   y/docH already computed in frame(); frame() writes :root{--scroll-frac} consumed
   here as transform:scaleX() only. No new listener, no layout property animated.
   -------------------------------------------------------------------------- */
.scroll-rail { display: none; }
@media (max-width: 680px) {
  .scroll-rail { display: block; position: absolute; top: 0; left: 0; right: 0;
    height: 2px; z-index: 2; pointer-events: none; background: var(--line); opacity: .5; }
  .scroll-rail > i { display: block; height: 100%; transform-origin: left;
    transform: scaleX(var(--scroll-frac, 0));
    background: linear-gradient(90deg, var(--gold-deep), var(--gold) 55%, var(--gold-2)); }
  .px-motion .scroll-rail > i { will-change: transform; }
}

/* --------------------------------------------------------------------------
   #2 Scroll-progress gem in the nav (appears once you leave the hero)
   -------------------------------------------------------------------------- */
.scroll-gem { position: relative; width: 34px; height: 34px; display: none; place-items: center;
  margin-left: 4px; opacity: 0; transform: scale(.6) rotate(-30deg); transition: opacity .4s, transform .4s var(--ease); }
.scroll-gem.show { opacity: 1; transform: scale(1) rotate(0); }
.scroll-gem svg { width: 100%; height: 100%; overflow: visible; }
.scroll-gem .gem-track { fill: none; stroke: var(--line-2); stroke-width: 1.5; }
.scroll-gem .gem-prog { fill: none; stroke: var(--gold); stroke-width: 1.5; stroke-linecap: round;
  stroke-dasharray: 100; stroke-dashoffset: calc(100 - var(--scrollpct, 0) * 1); transition: stroke-dashoffset .1s linear; }
.scroll-gem .gem-core { fill: var(--gold); transform-box: fill-box; transform-origin: center;
  transform: rotate(calc(var(--scrollpct, 0) * 3.6deg)); }

@media (min-width: 681px) { .scroll-gem.enabled { display: grid; } }

/* --------------------------------------------------------------------------
   #5 Scroll-scrubbed process connector (overrides the in-view draw with scrub)
   -------------------------------------------------------------------------- */
.px-motion .process.scrub::after { width: 100%; transform-origin: left; transition: none;
  transform: scaleX(var(--procf, 0)); }
/* Promote the scrubbed connector + tick-rules to their own layers ONLY while the
   section is live in the viewport (toggled by JS), so the per-frame scaleX is pure
   compositing; the layers are released the moment the section leaves view. */
.px-motion .process.proc-live::after,
.px-motion .process.proc-live .pstep::after { will-change: transform; }
.px-motion .process.scrub .pstep::after { transform: scaleX(var(--tick, 0)); }
.px-motion .process.scrub .pstep .pstep-node { border-color: var(--line-2); color: var(--bone);
  background: var(--bg); box-shadow: none; font-weight: 360;
  /* font-weight intentionally NOT transitioned: interpolating the variable-font wght
     axis re-rasterizes + re-measures the numeral every frame (reflow). It snaps 360->500
     instead — imperceptible under the colour/gradient shift, and keeps the scrub on the
     compositor/paint path only. */
  transition: border-color .4s, color .4s, background .4s, box-shadow .4s; }
.px-motion .process.scrub .pstep.lit .pstep-node { border-color: var(--gold); color: #241a09;
  background: linear-gradient(180deg, var(--gold-2), var(--gold)); box-shadow: 0 0 24px rgba(201,168,106,.35); font-weight: 500; }

/* Glowing nib — rides the leading edge of the drawn connector line */
.proc-nib { display: none; position: absolute; top: 21px; z-index: 2; pointer-events: none;
  left: calc(var(--procf, 0) * 100%);
  width: 10px; height: 10px; margin-top: -5px; margin-left: -5px;
  border-radius: 50%; background: var(--gold-2);
  box-shadow: 0 0 7px 3px rgba(201,168,106,.6), 0 0 18px 7px rgba(201,168,106,.22);
  transition: opacity .35s; }
.px-motion .process.scrub .proc-nib { display: block; }
.px-motion .process.scrub.proc-done .proc-nib { opacity: 0; }
@media (max-width: 680px) { .proc-nib { display: none !important; } }

/* --------------------------------------------------------------------------
   #15 Signature gem brand mark — draws in on load, brightens on hover.
   Reuses the intro-gem facet language. Load + hover only; no scroll coupling,
   no new listeners, no animated filter. Gated by .px-motion so the no-JS
   baseline stays fully drawn & static.
   -------------------------------------------------------------------------- */
.px-motion .brand-gem .bg-line { stroke-dasharray: 340; stroke-dashoffset: 340;
  animation: bgDraw 1.1s var(--ease) .2s forwards; }
@keyframes bgDraw { to { stroke-dashoffset: 0; } }
.px-motion .brand-gem .bg-fill { opacity: 0; animation: bgFill .7s var(--ease) .9s forwards; }
@keyframes bgFill { to { opacity: 1; } }
.px-motion .brand-gem svg { transform-box: fill-box; transform-origin: center;
  transition: transform .5s var(--ease); }
.px-motion .brand:hover .brand-gem svg { transform: rotate(90deg) scale(1.06); }
.px-motion .brand:hover .brand-gem .bg-fill { opacity: 1; }

/* --------------------------------------------------------------------------
   #15b Ambient depth field — page-wide dimensional "gallery at night" light.
   ONE fixed element promoted to its own compositor layer; paints once and stays
   put on scroll (no background-attachment:fixed). Warm ceiling + cool lower-right
   counter-light + faint floor. frame() writes :root{--depth} (0..1); consumed only
   via opacity/transform on this already-composited layer. JS off => static wash.
   -------------------------------------------------------------------------- */
.depth-field { position: fixed; inset: 0; z-index: -3; pointer-events: none;
  transform: translateZ(0); will-change: transform;
  background:
    radial-gradient(120% 60% at 50% -16%, rgba(201,168,106,.10), transparent 58%),
    radial-gradient(70% 70% at 86% 88%, rgba(70,86,120,.085), transparent 64%),
    radial-gradient(90% 50% at 50% 118%, rgba(120,86,40,.075), transparent 60%); }

.depth-drift { position: absolute; top: 14%; left: 8%; width: 52vw; height: 52vw;
  max-width: 680px; max-height: 680px; border-radius: 50%;
  background: radial-gradient(circle, rgba(201,168,106,.055), transparent 64%);
  will-change: transform, opacity; }
.px-motion .depth-drift { animation: depthDrift 26s ease-in-out infinite alternate; }
@keyframes depthDrift {
  from { transform: translate3d(0,0,0) scale(1); opacity: .5; }
  to   { transform: translate3d(9%, -6%, 0) scale(1.18); opacity: .85; }
}

.vignette { position: fixed; inset: 0; z-index: -1; pointer-events: none;
  transform: translateZ(0);
  background: radial-gradient(125% 105% at 50% 38%, transparent 56%, rgba(8,6,3,.32) 100%); }

/* --------------------------------------------------------------------------
   #16 Scroll hero hand-off — REMOVED per client request. The hero copy + stats
   and the crystal canvas used to drift up and fade out on scroll (--hero-p /
   --hero-cv); the client wants NO fading away on scroll, so the hero content now
   just scrolls normally at full opacity. (frame() still writes the vars but
   nothing consumes them — harmless.)
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   #17 Guarantee as a moment — the hero promise becomes a sealed pill. The
   check-path inks in, the shield gives one warm pulse, and a hairline gold
   rule wipes under the sentence — once, on .hero.ready, then static. SVG
   stroke-dashoffset + transform only (no background-position/filter sheen).
   Base (no-JS / reduced-motion) renders the pill fully drawn & still.
   -------------------------------------------------------------------------- */
.px-motion .hero.ready .hg-check { stroke-dasharray: 14; stroke-dashoffset: 14;
  animation: hgCheck .55s var(--ease) 1.5s forwards; }
@keyframes hgCheck { to { stroke-dashoffset: 0; } }
.px-motion .hero.ready .hg-shield { animation: hgShield .8s var(--ease) 1.35s forwards; }
@keyframes hgShield { 0% { stroke: var(--gold); } 55% { stroke: var(--gold-2); } 100% { stroke: var(--gold); } }
.px-motion .hg-text::after { transform: scaleX(0); }
.px-motion .hero.ready .hg-text::after { animation: hgRule .7s var(--ease) 1.7s forwards; }
@keyframes hgRule { to { transform: scaleX(1); } }

/* --------------------------------------------------------------------------
   #18 Crystal light-bloom on load — ONE warm bloom behind the hero crystal as it
   first catches light. One composited element; transform + opacity only. Fires once
   off the existing .hero.ready class (no new JS/listener/rAF). Resolves to opacity:0
   so it never stacks a second permanent glow on the always-on .live-light. NO
   will-change (.ready is never removed, so it would persist); a one-shot transform
   tween self-promotes for its duration, which is enough.
   -------------------------------------------------------------------------- */
.crystal-bloom { position: absolute; top: 6%; right: 4%;
  width: 60vw; height: 60vw; max-width: 660px; max-height: 660px;
  z-index: 0; pointer-events: none; border-radius: 50%; transform-origin: center;
  background:
    radial-gradient(circle, rgba(230,207,149,.16), transparent 44%),
    radial-gradient(circle, rgba(201,168,106,.10), transparent 68%);
  opacity: 0; transform: translate3d(0,0,0) scale(.6); }
.px-motion .hero.ready .crystal-bloom { animation: crystalBloom 2.2s var(--ease) .9s forwards; }
@keyframes crystalBloom {
  0%   { opacity: 0;   transform: translate3d(0,0,0) scale(.5); }
  22%  { opacity: .30; }
  55%  { opacity: .34; transform: translate3d(0,0,0) scale(1.04); }
  100% { opacity: 0;   transform: translate3d(0,0,0) scale(.86); }
}
@media (max-width: 680px) {
  .crystal-bloom { top: 2%; right: -10%; width: 84vw; height: 84vw; max-width: 520px; max-height: 520px;
    background:
      radial-gradient(circle, rgba(230,207,149,.12), transparent 46%),
      radial-gradient(circle, rgba(201,168,106,.08), transparent 70%); }
  .px-motion .hero.ready .crystal-bloom { animation: crystalBloomSm 2.2s var(--ease) .9s forwards; }
}
@keyframes crystalBloomSm {
  0%   { opacity: 0;   transform: translate3d(0,0,0) scale(.55); }
  22%  { opacity: .22; }
  55%  { opacity: .26; transform: translate3d(0,0,0) scale(1.02); }
  100% { opacity: 0;   transform: translate3d(0,0,0) scale(.86); }
}

/* --------------------------------------------------------------------------
   #19 Cascade-text hover (footer nav links) — ported to vanilla from a React
   "cascade text" component. Each glyph rolls up one-by-one to reveal an identical
   GOLD duplicate, painted by text-shadow one roll-height below, staggered per char.
   The mask is 1.3em (not the source's 1em) so descenders (y/g/p/j) clear the clip
   edge and the footer can stay mixed-case (the source forced UPPERCASE to dodge
   this — the descender-clip law forbids that shortcut here). Compositor transform
   on :hover/:focus-visible only — no per-frame JS, no static will-change. The
   char spans exist ONLY when premium.js runs (fine pointer + motion allowed), so
   touch and reduced-motion keep the plain colour hover.
   -------------------------------------------------------------------------- */
.footer-links a .cascade { display: inline-block; white-space: nowrap; overflow: hidden;
  height: 1.3em; line-height: 1.3; vertical-align: middle; }
.cascade-ch { display: inline-block; text-shadow: 0 1.3em var(--gold-2);
  transition: transform .3s var(--ease); transition-delay: calc(var(--i, 0) * 22ms); }
.footer-links a:hover .cascade-ch,
.footer-links a:focus-visible .cascade-ch { transform: translateY(-1.3em); }


/* --------------------------------------------------------------------------
   #20 Glassmorphism — frosted-gold surface on key cards
   GPU-composited (backdrop-filter); degrades gracefully to existing background
   on browsers without support. No layout change, no paint change.
   -------------------------------------------------------------------------- */
.guarantee {
  backdrop-filter: blur(16px) saturate(1.2);
  -webkit-backdrop-filter: blur(16px) saturate(1.2);
}
.tier {
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.tier.featured {
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
}
.faq-list details[open] {
  background: rgba(230,207,149,.028);
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
}

/* --------------------------------------------------------------------------
   #21 Scroll writer — sticky canvas; gold pen writes hero copy on scroll
   -------------------------------------------------------------------------- */
/* A COMPACT section sized to its content (not a full screen of dark space), sitting in
   normal flow close to the surrounding sections — just like the site's other bands. The
   canvas paints on a transparent background so it blends seamlessly into the page (no
   isolated panel, no hard edges). JS plays the hand-writing once, on its own clock, when
   the section scrolls into view. */
.writer-section { position: relative; background: #15110c; padding: 7vh 24px; }
/* height is set by JS to hug the promise text (no dead space inside the canvas on any
   screen); width is fluid up to a cap and centred. */
.writer-canvas  { display: block; width: 100%; max-width: 1080px; margin: 0 auto; pointer-events: none; }

/* --------------------------------------------------------------------------
   Submit button — molten gold wave on hover
   -------------------------------------------------------------------------- */
#submitBtn { position: relative; overflow: hidden; }
#submitBtn::after {
  content: '';
  position: absolute;
  top: -50%; left: 0;
  width: 60%; height: 200%;
  background: linear-gradient(90deg, transparent, rgba(255,252,210,.38), transparent);
  transform: translateX(-220%) skewX(-18deg);
  transition: none;
  pointer-events: none;
}
#submitBtn:not(:disabled):hover::after { transform: translateX(440%) skewX(-18deg); transition: transform .55s ease; }

/* --------------------------------------------------------------------------
   Hero CTA — expanding gold pulse ring
   -------------------------------------------------------------------------- */
@keyframes ctaPulse {
  0%   { transform: scale(1);   opacity: .72; }
  70%  { transform: scale(1.7); opacity: 0; }
  100% { transform: scale(1.7); opacity: 0; }
}
.hero-actions .btn-primary { position: relative; }
.hero-actions .btn-primary::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 2px solid rgba(201,168,106,.6);
  animation: ctaPulse 3.6s cubic-bezier(.4,0,.6,1) infinite;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Floating form labels
   -------------------------------------------------------------------------- */
.fl-field { position: relative; }
.fl-field .form-label {
  position: absolute;
  top: 15px; left: 16px;
  font-size: 1rem;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  color: var(--muted);
  margin: 0;
  pointer-events: none;
  transition: top .2s ease, font-size .2s ease, color .2s ease;
  z-index: 1;
}
.fl-field.fl-active .form-label,
.fl-field.fl-filled .form-label {
  top: 7px;
  font-size: .65rem;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: rgba(201,168,106,.75);
}
.fl-field input,
.fl-field textarea {
  padding-top: 22px !important;
  padding-bottom: 8px !important;
}
.fl-field textarea { padding-top: 28px !important; }
/* Hide placeholder text when the floating label is in resting position to prevent overlap */
.fl-field input::placeholder,
.fl-field textarea::placeholder {
  opacity: 0;
  transition: opacity .15s ease;
}
.fl-field.fl-active input::placeholder,
.fl-field.fl-active textarea::placeholder {
  opacity: 1;
}

/* --------------------------------------------------------------------------
   Sticky bottom conversion pill
   -------------------------------------------------------------------------- */
.sticky-pill {
  position: fixed;
  bottom: max(28px, calc(28px + env(safe-area-inset-bottom)));
  left: 50%;
  transform: translateX(-50%) translateY(100px);
  z-index: 90;
  transition: transform .45s cubic-bezier(.34,1.56,.64,1), opacity .3s ease;
  opacity: 0;
  pointer-events: none;
}
.sticky-pill.sp-visible {
  transform: translateX(-50%) translateY(0);
  opacity: 1;
  pointer-events: auto;
}
.sticky-pill a {
  display: flex;
  align-items: center;
  gap: 14px;
  background: rgba(12,9,5,.94);
  border: 1px solid rgba(201,168,106,.35);
  border-radius: 32px;
  padding: 12px 24px;
  text-decoration: none;
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  box-shadow: 0 8px 32px rgba(0,0,0,.55), 0 0 0 1px rgba(201,168,106,.08);
  white-space: nowrap;
  transition: border-color .2s ease, box-shadow .2s ease, transform .15s ease;
}
.sticky-pill a:hover {
  border-color: rgba(201,168,106,.6);
  box-shadow: 0 8px 40px rgba(0,0,0,.65), 0 0 0 1px rgba(201,168,106,.16);
}
/* Touch press: the primary mobile conversion CTA depresses + commits its arrow the
   instant it's pressed, confirming the tap before the scroll-to-form begins. Scaling
   the <a> is safe — the show/hide translate lives on .sticky-pill, not the anchor. */
.sticky-pill a:active {
  transform: scale(.97);
  border-color: rgba(201,168,106,.7);
  box-shadow: 0 6px 24px rgba(0,0,0,.7), 0 0 0 1px rgba(201,168,106,.22);
}
.sticky-pill a:active .sp-arrow { transform: translateX(6px); }
.sp-price  { font-family: var(--font-serif); font-size: .92rem; font-weight: 500; color: var(--gold); }
.sp-div    { width: 1px; height: 14px; background: rgba(201,168,106,.22); flex: none; }
.sp-label  { font-size: .88rem; color: var(--bone-2); }
.sp-arrow  { flex: none; color: rgba(201,168,106,.65); transition: transform .2s ease; }
.sticky-pill a:hover .sp-arrow { transform: translateX(3px); }

/* --------------------------------------------------------------------------
   Nav & footer brand text — periodic gold shimmer sweep
   -------------------------------------------------------------------------- */
@keyframes brandShimmer {
  0%    { transform: skewX(-15deg) translateX(-220%); opacity: 1; }
  50%   { transform: skewX(-15deg) translateX(210%);  opacity: 1; }
  50.1% { opacity: 0; }
  100%  { transform: skewX(-15deg) translateX(210%);  opacity: 0; }
}
.brand-text {
  position: relative;
  display: inline-block;
  overflow: hidden;
}
.brand-text::after {
  content: '';
  position: absolute;
  top: 0; left: 0;
  width: 55%; height: 100%;
  background: linear-gradient(100deg, transparent 20%, rgba(255,245,200,.55) 50%, transparent 80%);
  transform: skewX(-15deg) translateX(-220%);
  animation: brandShimmer 6s ease-in-out infinite;
  animation-delay: 2s;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Guarantee icon — breathing gold pulse ring
   -------------------------------------------------------------------------- */
@keyframes shieldPulse {
  0%   { transform: scale(1);    opacity: .6; }
  60%  { transform: scale(1.55); opacity: 0; }
  100% { transform: scale(1.55); opacity: 0; }
}
.guarantee-icon { position: relative; }
.guarantee-icon::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
  border: 2px solid rgba(201,168,106,.55);
  animation: shieldPulse 3s ease-out infinite;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Reduced motion / touch — turn the whole premium layer off
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .live-light { animation: none; }
  .depth-drift { animation: none !important; }
  .depth-field, .vignette { opacity: 1 !important; }
  .px-motion #hero .hero-copy,
  .px-motion #hero .hero-copy > *,
  .px-motion #hero h1 .line,
  .px-motion #hero .hero-canvas { transform: none !important; opacity: 1 !important; }
  .px-motion .split .word > span { transform: none !important; font-variation-settings: 'opsz' 72, 'wght' 340 !important; }
  .px-motion .split .gold-em { font-variation-settings: 'opsz' 72, 'wght' 380 !important; }
  .px-motion [data-parallax] { transform: none !important; }
  .px-motion .eyebrow::before { transform: scaleX(1) !important; animation: none !important; }
  .px-motion .hg-check { stroke-dashoffset: 0 !important; animation: none !important; }
  .px-motion .hg-shield { animation: none !important; }
  .px-motion .hg-text::after { transform: scaleX(1) !important; animation: none !important; }
  .cursor-ring, .cursor-dot, .cursor-ripple, .cursor-trail { display: none !important; }
  .ig-line { stroke-dashoffset: 0 !important; animation: none !important; }
  .ig-fill { opacity: .14 !important; animation: none !important; }
  .scroll-rail > i { transform: scaleX(0) !important; }
  .crystal-bloom { animation: none !important; opacity: 0 !important; }
  .cascade-ch { transition: none !important; transform: none !important; }
  .nav-fx, .nav-fx-canvas { display: none !important; }
  .hero-actions .btn-primary::before,
  .guarantee-icon::before,
  .brand-text::after { animation: none !important; }
}
/* Low-power devices: shed the ambient depth drift (set by motion.js capability gate). */
html.low-power .depth-drift { animation: none !important; }

/* Mobile: sticky pill sits below the nav drawer so open nav links are always tappable */
@media (max-width: 680px) {
  .sticky-pill { z-index: 85; }
}

/* ==========================================================================
   #A3 / #C / #D — added depth + delight (all compositor-only, all gated)
   ========================================================================== */

/* #A3 Gold spark burst — flung from each click point (premium.js rides pointerdown).
   One wrapper, N motes; each mote handed --ax/--ay/--sz/--dl and thrown by a single
   transform+opacity keyframe. Warm gold, brief, few — a spark of craft, not confetti. */
.spark-burst { position: fixed; z-index: 9996; left: 0; top: 0; width: 0; height: 0; pointer-events: none; }
.spark-burst > i {
  position: absolute; left: 0; top: 0; width: var(--sz, 3px); height: var(--sz, 3px);
  margin-left: calc(var(--sz, 3px) / -2); margin-top: calc(var(--sz, 3px) / -2);
  border-radius: 50%;
  background: radial-gradient(circle, #fff7dd 0%, var(--gold-2) 42%, var(--gold) 72%, rgba(201,168,106,0) 100%);
  box-shadow: 0 0 6px rgba(230,207,149,.75);
  opacity: 0;
  animation: sparkFly .62s cubic-bezier(.2,.7,.25,1) var(--dl, 0ms) forwards;
}
@keyframes sparkFly {
  0%   { transform: translate3d(0,0,0) scale(1);   opacity: 1; }
  72%  { opacity: 1; }
  100% { transform: translate3d(var(--ax,0), calc(var(--ay,0) + 12px), 0) scale(.15); opacity: 0; }
}

/* #C Hero cursor-depth light — a faint warm glow that drifts toward the cursor, lighting
   the space BEHIND the (unmoving) copy. New dedicated layer so it never fights the
   transform-owning .live-light / .crystal-bloom animations and never touches the copy.
   premium.js writes --hx/--hy on #hero (fine-pointer only); this inherits + translates
   (compositor-only). At rest (--hx/--hy = 0) it sits centred and still. */
.hero-depth {
  position: absolute; top: 30%; left: 34%;
  width: 42vw; height: 42vw; max-width: 540px; max-height: 540px;
  z-index: 0; pointer-events: none; border-radius: 50%;
  background: radial-gradient(circle, rgba(201,168,106,.07), transparent 66%);
  filter: blur(34px); will-change: transform;
  transform: translate3d(calc(var(--hx,0) * 42px), calc(var(--hy,0) * 38px), 0);
}

@media (prefers-reduced-motion: reduce) {
  .spark-burst { display: none !important; }
  .hero-depth { transform: none !important; }
}

/* Touch / small screens: the depth light is a desktop-cursor effect — shed it entirely
   (premium.js never sets --hx/--hy without a fine pointer, but drop the blurred layer's
   paint cost too). The velocity lean stays — it's cheap and feels good on a phone flick. */
@media (max-width: 680px), (pointer: coarse) {
  .hero-depth { display: none !important; }
}
