/* Vorani glass kit styles. Identical copy in both sites. Pairs with assets/glass.js, which writes the vars.
   Load after royal.css:  <link rel="stylesheet" href="/assets/glass.css?v=20261018">
   Base rules sit in :where() (zero specificity) so component classes always win. Only transform-family
   properties and opacity animate. Reduced motion: JS stays idle and every CSS loop below is off. */

/* ---------- data-tilt: tvOS-style parallax icon ---------- */
/* glass.js adds .is-tilting while the pointer drives the element and while it settles, so at rest there is no
   transform at all (crisp text, no extra layer). Kept flat on purpose: preserve-3d stops the glare's blend
   modes reaching the layers below in Chrome, so depth comes from 2D parallax instead. */
:where([data-tilt]){--rx:0deg;--ry:0deg;--px:0;--py:0;--gx:50%;--gy:50%;--tilt-on:0;position:relative}
[data-tilt][data-tilt].is-tilting{ /* (0,3,0): wins over hover transforms such as .card.is-interactive:hover */
  transform:perspective(var(--tilt-persp,900px)) rotateX(var(--rx)) rotateY(var(--ry));
  scale:calc(1 + var(--tilt-on) * var(--tilt-lift,.03)); /* tvOS focus lift */
  -webkit-backdrop-filter:none;backdrop-filter:none; /* with a 3D transform Chrome renders the blur and the text soft */
}
/* Parallax: layers with data-depth (0..1) slide against the pointer, as if floating above the surface. */
[data-tilt].is-tilting [data-depth]{
  translate:calc(var(--px) * var(--d,0) * -1 * var(--depth-shift,12px)) calc(var(--py) * var(--d,0) * -1 * var(--depth-shift,12px));
}
/* Specular glare: <span class="glare" aria-hidden="true"></span> as the last child. ::before is a soft sheen on
   the glass; ::after (soft-light) makes chrome, silver and white catch the light while black stays black. */
:where([data-tilt]) .glare{position:absolute;inset:0;border-radius:inherit;pointer-events:none}
:where([data-tilt]) .glare::before,:where([data-tilt]) .glare::after{content:"";position:absolute;inset:0;border-radius:inherit;opacity:var(--tilt-on)}
:where([data-tilt]) .glare::before{background:radial-gradient(ellipse 50% 50% at var(--gx) var(--gy),rgba(255,255,255,.11),rgba(255,255,255,.035) 50%,rgba(255,255,255,0) 100%)}
:where([data-tilt]) .glare::after{background:radial-gradient(ellipse 80% 80% at var(--gx) var(--gy),rgba(255,255,255,.75),rgba(255,255,255,.2) 40%,rgba(255,255,255,0) 75%);mix-blend-mode:soft-light}

/* Hero mark: stacked tile + glyph layers + glare on the mark's 1024 canvas
   (tile inset 32/1024 = 3.125%, corner 196.8/960 = 20.5%). Size it with width (or --mark-size). */
.mark3d{position:relative;display:block;width:var(--mark-size,clamp(168px,30vw,320px));aspect-ratio:1;--depth-shift:3.6%}
.mark3d>img{position:absolute;inset:0;display:block;width:100%;height:100%;scale:calc(1 + var(--d,0) * var(--tilt-on,0) * .035)} /* glyph pops forward on focus */
.mark3d>.glare{inset:3.125%;border-radius:20.5%}

/* ---------- data-float: gentle idle float (paused off-screen, while tilting, in hidden tabs) ---------- */
@media (prefers-reduced-motion:no-preference){
  :where([data-float]){animation:gl-float 7s cubic-bezier(.45,0,.55,1) infinite}
}
[data-float].is-tilting,[data-float].is-paused,.tab-hidden [data-float]{animation-play-state:paused}
@keyframes gl-float{0%,100%{translate:0 0}50%{translate:0 calc(-1 * var(--float,7px))}}

/* ---------- data-spotlight: cursor light + border that brightens near the cursor ---------- */
/* glass.js appends <span class="gl-spot" aria-hidden="true"> as the last child, so the element's own ::before and
   ::after stay free (.card and .chrome-border use them). The span is the light, its ::after the ring over a 1px
   border; it sits under the content (z-index -1 in an isolated element). Use --spot-inset:0 if the element clips. */
:where([data-spotlight]){--mx:50%;--my:50%;--spot:0;position:relative;isolation:isolate}
[data-spotlight]>.gl-spot,[data-spotlight]>.gl-spot::after{position:absolute;inset:var(--spot-inset,-1px);margin:0;border-radius:inherit;pointer-events:none}
[data-spotlight]>.gl-spot{
  z-index:-1;opacity:var(--spot);transition:opacity .6s var(--ease-out,cubic-bezier(.16,1,.3,1));
  background:radial-gradient(circle var(--spot-size,520px) at var(--mx) var(--my),rgba(255,255,255,.075),rgba(255,255,255,.025) 40%,rgba(255,255,255,0) 70%);
}
[data-spotlight]>.gl-spot::after{
  content:"";inset:0;padding:1px;
  background:radial-gradient(circle var(--ring-size,260px) at var(--mx) var(--my),rgba(255,255,255,.7),rgba(255,255,255,.18) 45%,rgba(255,255,255,0) 100%);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  mask-composite:exclude;
}

/* ---------- data-magnetic: glass.js sets an inline `translate`; nothing to style ---------- */

/* ---------- Scroll choreography, CSS only (static where unsupported or with reduced motion) ---------- */
/* .sd-rise: rises and fades in over its first 320px of entry.  .sd-recede: scales to .9 and fades as it
   leaves the top (from its top edge reaching the top of the view, which scroll-padding-top lowers, so it is
   whole at rest). Each uses the `animation` shorthand: keep other animations off the same element. */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .sd-rise{animation:gl-rise linear both;animation-timeline:view();animation-range:entry 0% entry 320px}
    .sd-recede{animation:gl-recede linear both;animation-timeline:view();animation-range:exit 0% exit 100%}
  }
}
@keyframes gl-rise{from{opacity:0;translate:0 56px;scale:.98}}
@keyframes gl-recede{to{opacity:0;scale:.9}}
