:root{
  --font-head:'Orbitron',sans-serif;       /* headings, labels, buttons */
  --font-pixel:'Press Start 2P',monospace; /* pixel accents */
  --font-mono:'Space Mono',monospace;      /* body + meta */
}
*{box-sizing:border-box}
body{margin:0;background:#08060f;font-family:var(--font-mono);-webkit-font-smoothing:antialiased}
/* Boot gate (set by the blocking head script in index.html). Pre-hides exactly
   the layers applyBoot(0) hides so first paint IS the intro's start frame, not
   its settled end — see the head-script comment. site.js clears .nk-booting
   right after applyBoot(0); from then its inline opacities drive the flicker-in.
   If JS is disabled the class is never added and the hero renders normally. */
.nk-booting #nk-grid,.nk-booting #nk-haze,.nk-booting #nk-bloom,
.nk-booting #nk-sunwrap,.nk-booting #nk-horizon,.nk-booting #nk-word,
.nk-booting #nk-nef,.nk-booting #nk-pyr,.nk-booting #nk-palms{opacity:0}
.nk-booting #nk-horizon{transform:scaleX(0)}
/* The palm sprout is CSS-keyframed from parse time, so on a slow load it would
   bloom alone against the empty sky and land out of sync with the JS-driven
   horizon it's tuned to rise with. Pausing freezes it at frame 0 (with its
   `both` fill) until .nk-booting clears at boot start, so its .748s delay and
   1.8s sprout begin in step with the boot clock. play-state doesn't touch the
   mask-composite mode, so it can't trip the Safari square-box artifact. */
.nk-booting .nk-palm{animation-play-state:paused}
@keyframes nk-grid{from{background-position:0 0}to{background-position:0 76px}}
@keyframes nk-bob{0%,100%{transform:translate(-50%,0)}50%{transform:translate(-50%,-7px)}}
@keyframes nk-twinkle{0%,100%{opacity:.25}50%{opacity:1}}
@keyframes nk-float{0%,100%{transform:translateY(0)}50%{transform:translateY(-10px)}}
@keyframes nk-word-breathe{from{opacity:.35}to{opacity:.75}}
/* Breathing NAKHLA halo: a duplicate of the pink SVG behind the crisp tube, heavy
   halo baked into a static filter, opacity-only animation (animating the filter
   itself repaints every frame and composites wrong in Safari).
   COUPLED NUMBERS: the base opacity here is the trough of nk-word-breathe — it is
   what reduced-motion users and animation-suppressed contexts (screenshot suite)
   see, and together with the crisp tube's inline 16px halo alpha (.25, index.html
   #nk-word) it was tuned to match the old static glow. Move them together. */
.nk-word-glow{position:absolute;inset:0;width:100%;height:auto;opacity:.35;filter:drop-shadow(0 0 6px rgba(255,46,151,.95)) drop-shadow(0 0 20px rgba(255,46,151,.7)) drop-shadow(0 0 38px rgba(255,46,151,.4));animation:nk-word-breathe 3.6s ease-in-out infinite alternate}
@media (prefers-reduced-motion:reduce){.nk-word-glow{animation:none}}
@keyframes nk-emblem-pulse{0%,100%{filter:drop-shadow(0 0 2px rgba(255,46,151,.45)) drop-shadow(0 0 5px rgba(123,77,255,.25))}50%{filter:drop-shadow(0 0 5px rgba(255,122,60,.7)) drop-shadow(0 0 12px rgba(255,46,151,.5))}}
.nk-brandtext{font-family:var(--font-head);font-weight:800;font-size:13px;letter-spacing:2px;color:#ff2e97;white-space:nowrap}
/* Header lockup handoff (ported from the Ring Glance pages, 2026-07-12,
   REVERSING the earlier scroll-scrubbed text fade): the whole lockup (emblem +
   text) hides while the hero wordmark is on screen, then rises into the bar
   once it slips under the header. site.js toggles the class via two-observer
   hysteresis — the asymmetric reveal/hide the old comment warned about is now
   deliberate: each scroll direction gets its own trigger line, which is what
   makes a time-based transition feel right under momentum. */
.nk-lockup{transition:opacity .4s,transform .4s,visibility 0s 0s}
.nk-lockup.nk-lockup-hidden{opacity:0;transform:translateY(14px);visibility:hidden;transition:opacity .4s,transform .4s,visibility 0s .4s}
/* The emblem's pulse lives here (not inline) so it can pause while the lockup
   is hidden — visibility:hidden does NOT stop CSS animations, and the resting
   state at page top would otherwise repaint an invisible drop-shadow forever.
   The paused rule repeats the #nk-header id to outrank the shorthand (which
   resets animation-play-state). */
#nk-header .nk-lockup img{animation:nk-emblem-pulse 3.4s ease-in-out infinite}
#nk-header .nk-lockup.nk-lockup-hidden img{animation-play-state:paused}
@media (prefers-reduced-motion:reduce){
  .nk-lockup{transition:none}
  /* must repeat the hidden state at its own specificity — that rule
     re-specifies transition and would win over a plain .nk-lockup reset */
  .nk-lockup.nk-lockup-hidden{transform:none;transition:none}
  /* same treatment the .nk-word-glow halo already gets under reduce */
  #nk-header .nk-lockup img{animation:none}
}
/* Palm sprout — two stages, one silhouette. The reveal is the UNION (mask-composite
   add) of a narrow trunk column (grows bottom->up, stops below the crown) and a disc
   that swells out to the crown center (50% 32.8%). Three rules keep the handoff
   seamless (it used to read as an "invisible separation" between trunk and bud):
   - OVERLAP: the disc is seeded at 24% — while the trunk is still rising — from
     position 50% 47%, just above the rising trunk's reach; the trunk climbs through
     it over the next beats, so the bud reads as swelling out of the trunk and
     motion never fully stops between the stages. For the first ~130ms the mask
     union ALONE still has a shallow translucent seam at the junction — by design
     it hides under the trunk beam's glow (nk-palm-beamv holds opacity 1 parked
     over exactly that spot); from ~30% the union itself is fused. The seam-only-
     under-lit-beam contract is regression-pinned in behavior.spec.ts.
   - ROUND: both radial masks are sized against CLOSEST-SIDE so their fades complete
     inside their own mask boxes. A plain `circle` measures stops against the
     farthest CORNER; the old 74%/60% outer stops poked past the box half-width and
     the box edge clipped the reveal square mid-bloom (flat edges slicing fronds).
     Same crown coverage therefore needs a ~2x larger box (104% final vs the old 52%).
   - CROSSFADE: the trunk beam (nk-palm-beamv) stays lit to 36% and fades by 42%
     while the frond ring (nk-palm-beamr) ramps in over 30-36% — combined glow never
     drops out at the junction (regression-pinned in behavior.spec.ts).
   Started at .748s so the trunk rises with the horizon draw; the burst lands as the
   boot settles (~2.2s). */
@keyframes nk-palm-fill{
  0%  {-webkit-mask-size:13% 18%,0% 0%;    mask-size:13% 18%,0% 0%;    -webkit-mask-position:50% 100%,50% 47%;mask-position:50% 100%,50% 47%;     animation-timing-function:linear}
  24% {-webkit-mask-size:13% 49.5%,0% 0%;  mask-size:13% 49.5%,0% 0%;  -webkit-mask-position:50% 100%,50% 47%;mask-position:50% 100%,50% 47%;     animation-timing-function:linear}
  32% {-webkit-mask-size:13% 60%,28% 28%;  mask-size:13% 60%,28% 28%;  -webkit-mask-position:50% 100%,50% 44.5%;mask-position:50% 100%,50% 44.5%; animation-timing-function:cubic-bezier(.3,.55,.28,1)}
  40% {-webkit-mask-size:13% 60%,44% 44%;  mask-size:13% 60%,44% 44%;  -webkit-mask-position:50% 100%,50% 39%;mask-position:50% 100%,50% 39%;     animation-timing-function:cubic-bezier(.3,.55,.28,1)}
  60% {-webkit-mask-position:50% 100%,50% 32.8%;mask-position:50% 100%,50% 32.8%}
  88% {-webkit-mask-size:13% 60%,104% 104%;mask-size:13% 60%,104% 104%;-webkit-mask-position:50% 100%,50% 32.8%;mask-position:50% 100%,50% 32.8%}
  100%{-webkit-mask-size:13% 60%,104% 104%;mask-size:13% 60%,104% 104%;-webkit-mask-position:50% 100%,50% 32.8%;mask-position:50% 100%,50% 32.8%}}
@keyframes nk-palm-beamv{
  0%  {-webkit-mask-position:50% 82%;mask-position:50% 82%;opacity:0}
  5%  {opacity:1}
  30% {-webkit-mask-position:50% 47%;mask-position:50% 47%;opacity:1}
  36% {opacity:1}
  42% {-webkit-mask-position:50% 43%;mask-position:50% 43%;opacity:0}
  100%{-webkit-mask-position:50% 43%;mask-position:50% 43%;opacity:0}}
/* the ring is already at size 22% and fading in while the fill disc is still
   swelling (24->40%), so the glow wraps the emerging crown instead of trailing
   it — and overlaps the trunk beam's 36-42% fade-out (no glow gap).
   NOTE: the beam waypoints here (and in nk-palm-beamv above) are re-cut in
   nk-tap-beamv/nk-tap-beamr below for the tap ripple — retune both together. */
@keyframes nk-palm-beamr{
  0%  {-webkit-mask-size:0% 0%;mask-size:0% 0%;opacity:0}
  30% {-webkit-mask-size:22% 22%;mask-size:22% 22%;opacity:0;animation-timing-function:cubic-bezier(.3,.55,.28,1)}
  36% {opacity:1}
  82% {opacity:1}
  88% {-webkit-mask-size:96% 96%;mask-size:96% 96%;opacity:0}
  100%{-webkit-mask-size:96% 96%;mask-size:96% 96%;opacity:0}}
/* shared framing for the stacked palm layers (was inline on each <img>) */
.nk-palm{position:absolute;bottom:-147px;left:50%;width:580px;height:580px;display:block;transform:translateX(-50%)}
.nk-palm-etch{
  filter:drop-shadow(1.4px 0 0 rgba(0,240,255,.55)) drop-shadow(-1.4px 0 0 rgba(255,46,151,.5)) drop-shadow(0 0 7px rgba(0,240,255,.25)) drop-shadow(0 3px 10px rgba(0,0,0,.45));
  -webkit-mask-image:linear-gradient(to top,#000 80%,transparent),radial-gradient(circle closest-side at 50% 32.8%,#000 60%,transparent 94%);
  mask-image:linear-gradient(to top,#000 80%,transparent),radial-gradient(circle closest-side at 50% 32.8%,#000 60%,transparent 94%);
  -webkit-mask-repeat:no-repeat,no-repeat;mask-repeat:no-repeat,no-repeat;
  -webkit-mask-position:50% 100%,50% 32.8%;mask-position:50% 100%,50% 32.8%;
  -webkit-mask-size:13% 18%,0% 0%;mask-size:13% 18%,0% 0%;
  -webkit-mask-composite:source-over;mask-composite:add;
  animation:nk-palm-fill 1.8s linear .748s both}
/* Both beam layers render uploads/palm-cyan.png — their bright cyan tint +
   glow BAKED to a raster (regenerate with tools/bake_palm_cyan.mjs; the
   why + dead ends live in that script and the tap-ripple spec). Runtime
   beams must stay filter-free — a live filter re-rasterizing under the
   cloned, mask-animated tap beams overwhelmed iOS Safari's compositor
   (regression-pinned in behavior.spec.ts) — and still no mix-blend-mode:
   real Safari composites blended layers to invisible inside the transparent
   clip-path'd #nk-palms group. (.nk-palm-beam survives in the markup as the
   shared marker class for beam imgs; it needs no rule.) */
.nk-palm-beamv{opacity:0;
  -webkit-mask-image:linear-gradient(0deg,transparent,#000,transparent);mask-image:linear-gradient(0deg,transparent,#000,transparent);
  -webkit-mask-size:14% 12%;mask-size:14% 12%;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-position:50% 82%;mask-position:50% 82%;animation:nk-palm-beamv 1.8s linear .748s both}
/* The ring is a wrapper div (animated circular ring mask) around a nested img
   (static inverted-ellipse "hole" over the trunk column). Nesting intersects the
   two masks so the bloom sweeps every frond but never ripples DOWN the trunk after
   the beam went up it. Do NOT merge these into one two-layer mask combined with an
   INTERSECT mask-composite (source-in/destination-in): Safari/WebKit renders that
   as a square-box artifact when animated. (The etch's ADD composite is fine.) */
.nk-palm-beamr{opacity:0;
  -webkit-mask-image:radial-gradient(circle closest-side at 50% 32.8%,transparent 0 52%,#000 70%,transparent 94%);
  mask-image:radial-gradient(circle closest-side at 50% 32.8%,transparent 0 52%,#000 70%,transparent 94%);
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:50% 32.8%;mask-position:50% 32.8%;
  -webkit-mask-size:0% 0%;mask-size:0% 0%;animation:nk-palm-beamr 1.8s linear .748s both}
.nk-beamr-img{width:100%;height:100%;display:block;
  -webkit-mask-image:radial-gradient(ellipse 8% 34% at 50% 78%,transparent 0 86%,#000 100%);
  mask-image:radial-gradient(ellipse 8% 34% at 50% 78%,transparent 0 86%,#000 100%);
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-size:100% 100%;mask-size:100% 100%}
/* Tap ripple — tapping the palm's circle re-fires the sprout's energy sweep
   and rocks the tree on a damped spring (see the tap-ripple IIFE in site.js).
   - .nk-palm-sway pivots at the trunk base; the spring writes an inline
     rotate() while live and clears it at rest, so the idle DOM is untouched.
   - The tap keyframes are ~0.9s re-cuts of the boot beams with the 0-24%
     trunk-reveal wait removed: same mask-position/size/opacity mechanics the
     boot already proved Safari-safe (no new composite modes, no blends).
     GEOMETRY IS SHARED with nk-palm-beamv/nk-palm-beamr above (trunk sweep
     50% 82%→47%→43%, ring 22%→96%, same bezier) — retune both together.
   - site.js applies these to PER-TAP CLONES of the beam layers via INLINE
     animation (not a class rule), so the clones' inherited boot `animation`
     is overridden regardless of stylesheet order; .nk-tap-* classes exist on
     the clones purely as markers.
   - touch-action:manipulation keeps mobile spam-taps from double-tap zooming;
     user-select/user-drag off so a press-drag never lifts an image ghost
     (Firefox ignores -webkit-user-drag — site.js also suppresses dragstart). */
#nk-palms{touch-action:manipulation;user-select:none;-webkit-user-select:none}
#nk-palms img{-webkit-user-drag:none}
.nk-palm-sway{position:absolute;inset:0;transform-origin:50% 100%}
@keyframes nk-tap-beamv{
  0%  {-webkit-mask-position:50% 82%;mask-position:50% 82%;opacity:0}
  8%  {opacity:1}
  55% {-webkit-mask-position:50% 47%;mask-position:50% 47%;opacity:1}
  72% {-webkit-mask-position:50% 43%;mask-position:50% 43%;opacity:0}
  100%{-webkit-mask-position:50% 43%;mask-position:50% 43%;opacity:0}}
@keyframes nk-tap-beamr{
  0%  {-webkit-mask-size:0% 0%;mask-size:0% 0%;opacity:0}
  45% {-webkit-mask-size:22% 22%;mask-size:22% 22%;opacity:0;animation-timing-function:cubic-bezier(.3,.55,.28,1)}
  55% {opacity:1}
  82% {opacity:1}
  100%{-webkit-mask-size:96% 96%;mask-size:96% 96%;opacity:0}}
@keyframes nk-holo-flicker{0%,100%{opacity:.95}8%{opacity:.58}8.6%{opacity:.95}32.6%{opacity:.9}33%{opacity:.5}33.7%{opacity:.93}61%{opacity:.97}61.4%{opacity:.66}62%{opacity:.95}84%{opacity:.9}84.3%{opacity:.6}85%{opacity:.95}}
@keyframes nk-holo-scan{0%{-webkit-mask-position:0 -48%;mask-position:0 -48%}100%{-webkit-mask-position:0 148%;mask-position:0 148%}}
@keyframes nk-fadein{from{opacity:0}to{opacity:.72}}
/* while dragging a 3D model, nothing on the page is selectable */
html.nk-no-select,html.nk-no-select *{user-select:none!important;-webkit-user-select:none!important}
.nk-nefwrap{position:absolute;z-index:20;text-align:center;pointer-events:none;transition:left .4s ease,right .4s ease,top .4s ease,width .4s ease}
/* "duck to the corners": when the sun grows/screen narrows so a hologram would
   touch the sun, JS adds .nk-corner and it tucks into its nearest top corner,
   shrinking to a small accent so it frames the sun instead of sitting on it.
   Two-class specificity (0,2,0) overrides both the base rule and the media query. */
.nk-nef-hero.nk-corner{left:10px;right:auto;top:30px;width:clamp(88px,26vw,132px)}
.nk-pyr-hero.nk-corner{right:10px;left:auto;top:30px;width:clamp(88px,26vw,132px)}
.nk-nef-hero.nk-corner model-viewer,
.nk-pyr-hero.nk-corner model-viewer{height:clamp(103px,30vw,154px)}
/* user-select:none so dragging to orbit never starts a page text selection.
   position:relative lifts the model above its .nk-holo-glow canvas sibling.
   tap-highlight:transparent kills iOS Safari's grey flash over the element's
   full (mostly transparent) box on a stationary tap. */
.nk-nefwrap model-viewer{position:relative;pointer-events:auto;width:100%;background:transparent;--poster-color:transparent;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent;transition:height .4s ease}
/* the neon halo, painted by site.js (Safari drops CSS/SVG filters on the
   model-viewer WebGL canvas, so drop-shadow can't be used for this). The
   canvas is 150% of the model's box so the blur has room to spread beyond
   the silhouette — a canvas clips at its edges, unlike a drop-shadow. */
.nk-nefwrap .nk-holo-glow{position:absolute;left:-25%;top:-25%;width:150%;height:150%;pointer-events:none;transition:opacity .3s ease}
/* while a hologram is held its captures pause (GPU readbacks fight the drag)
   — fade that halo so the pause reads as the hologram dimming in-hand */
.nk-nefwrap.nk-glow-hold .nk-holo-glow{opacity:0}
/* while a hologram is dragged (html.nk-no-select spans exactly that window)
   the FREE one goes pointer-inert: in real Safari, hovering its WebGL canvas
   mid-drag hit-tests the accelerated layer and intermittently drops it (the
   vanishing-mesh bug, seen manually 2026-07-02). The held one keeps pointer
   events via its .nk-glow-hold marker. */
html.nk-no-select .nk-nefwrap:not(.nk-glow-hold) model-viewer{pointer-events:none}
/* ...and the idle float is fully torn down for the same window: the
   wrappers' infinite transform keyframes make each hologram a perpetually-
   animating composited layer, and real Safari drops the glow-canvas
   sublayer inside one under drag + cursor-juggling pressure (bisected
   manually 2026-07-02 — animation:none stops it; play-state:paused does
   NOT, the layer stays in animated mode). site.js pins each wrapper at its
   measured position (inline top) and bakes the bob's phase into an inline
   NEGATIVE animation-delay, so on release the animation restarts already
   mid-cycle. Declarative on purpose — a JS currentTime restore races
   Safari's compositor thread and stutters. */
html.nk-no-select .nk-nefwrap{animation:none}
/* hide model-viewer's default loading bar (the black bar on top during load) */
.nk-nefwrap model-viewer::part(default-progress-bar),
.nk-nefwrap model-viewer::part(default-progress-mask){display:none}
/* flanking size is fluid: full 232px on wide screens, shrinking to fit beside
   the sun as the screen narrows (mirrored by flankWidth() in the JS below). */
.nk-nef-hero{left:7%;top:calc(261px - clamp(151px,20vw,270px)/2);width:clamp(130px,17vw,232px);animation:nk-float 7.5s ease-in-out infinite}
.nk-nef-hero model-viewer{height:clamp(151px,20vw,270px)}
/* pyramid — mirror of the Nefertiti head on the right */
.nk-pyr-hero{right:7%;top:calc(261px - clamp(151px,20vw,270px)/2);width:clamp(130px,17vw,232px);animation:nk-float 8.4s ease-in-out infinite}
.nk-pyr-hero model-viewer{height:clamp(151px,20vw,270px)}
@media(max-width:760px){.nk-nef-hero{left:3%;top:150px;width:150px}.nk-nef-hero model-viewer{height:180px}.nk-pyr-hero{right:3%;top:150px;width:150px}.nk-pyr-hero model-viewer{height:180px}}

/* Card lift on hover — was the dc-builder style-hover attribute. */
.nk-card:hover{transform:translateY(-6px);box-shadow:0 0 0 1px #00f0ff,0 16px 44px rgba(255,46,151,.35)}

/* App-icon glyphs — inline SVG paths lifted from Noto's Egyptian Hieroglyphs
   (U+13080 Wedjat, U+131F3 sun/Ra), so they render identically everywhere
   (iOS/Android lack a hieroglyph font). Each filled with a site-neon glow. */
.nk-wedjat{fill:#00f0ff;filter:drop-shadow(0 0 6px rgba(0,240,255,.8)) drop-shadow(0 0 18px rgba(0,240,255,.4))}
/* tiny wedjat beside the Ring Glance codename tag (a <use> of the big glyph's
   path — see the index.html comment). Glow scaled way down: the full-size
   6px/18px halo swamps a 12px mark. */
.nk-wedjat-mini{fill:#00f0ff;filter:drop-shadow(0 0 3px rgba(0,240,255,.55));vertical-align:-2px;margin-left:2px}
.nk-ra{fill:#ff2e97;filter:drop-shadow(0 0 6px rgba(255,46,151,.8)) drop-shadow(0 0 18px rgba(255,46,151,.4))}
.nk-mmh{fill:#a24bff;filter:drop-shadow(0 0 6px rgba(162,75,255,.85)) drop-shadow(0 0 18px rgba(162,75,255,.45))}
.nk-weres{fill:#ffc24b;filter:drop-shadow(0 0 6px rgba(255,194,75,.85)) drop-shadow(0 0 18px rgba(255,194,75,.45))}

/* Ring Glance mirage reveal (markup in index.html, trigger + heat shimmer in
   site.js's .nk-rg-mirage IIFE). Split of labor: JS animates ONLY the SVG
   filter attributes (feDisplacementMap scale / feTurbulence baseFrequency —
   not reachable from CSS), while everything CSS can own lives here as
   class-driven transitions, so the screenshot suite's animations:'disabled'
   fast-forwards them to a deterministic end state once the class is on.
   - .nk-rg-melting: the glyph sinks and squashes into the box's bottom edge
     (transform-origin bottom — a melt pools downward, it doesn't shrink in
     place) while the banner crossfades in beneath it. The transform delay
     gives the JS shimmer ~.25s to build before the glyph visibly lets go.
   - .nk-rg-melted: latches the end state; visibility (not display) so the
     glyph also leaves the a11y tree once the banner carries the card.
   - overflow:visible on the svg: displaced pixels must bleed past the tight
     viewBox mid-melt instead of clipping at the svg viewport (the mirage box
     itself clips the drip via its inline overflow:hidden). No visual effect
     while unfiltered — the glyph fits its viewBox.
   - reduced motion: no drip, no shimmer (site.js skips its rAF too), just a
     slow opacity handoff — the reveal stays, the vestibular wobble goes. */
.nk-rg-banner{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;background:#1a1815;opacity:0}
/* The glyph joins the head script's pre-paint boot gate: site.js is a module
   (executes only after full parse, behind the model-viewer fetch), so the
   parser paints the catalog long before the mirage IIFE can decide
   glyph-vs-banner — on a tall-window refresh that painted the glyph for the
   whole pre-script window, then swapped it (user-reported flash, Safari +
   Chrome, 2026-07-12). Hidden while undecided, and since the boot IIFE
   drops .nk-booting in the same script-execution task in which the mirage
   IIFE latches, the first post-script paint already shows the settled
   answer. No JS: the head script never runs, the class never exists, the
   glyph renders as always (and the load-event failsafe covers a site.js
   that 404s after the class was set). */
.nk-booting .nk-rg-mirage .nk-wedjat{opacity:0}
.nk-rg-mirage .nk-wedjat{overflow:visible;transform-origin:50% 100%}
.nk-rg-melting .nk-rg-banner{opacity:1;transition:opacity .8s ease .45s}
.nk-rg-melting .nk-wedjat{opacity:0;transform:translateY(26px) scale(1.08,.5);transition:opacity .95s ease .3s,transform 1.1s cubic-bezier(.6,.05,.9,.4) .25s}
/* the latch also strips the spent transitions: a finished opacity transition
   can leave the banner on its own compositor layer, and the card's rounded-
   corner clip anti-aliases a hair differently over a promoted layer (seen as
   a 1px corner diff under the screenshot suite's worker contention) */
.nk-rg-melted .nk-rg-banner,.nk-rg-melted .nk-wedjat{transition:none}
.nk-rg-melted .nk-wedjat{visibility:hidden}
@media (prefers-reduced-motion:reduce){
  .nk-rg-melting .nk-rg-banner{transition:opacity 1.2s ease}
  .nk-rg-melting .nk-wedjat{transform:none;transition:opacity 1.2s ease}
}

/* Catalog status pill. Default is cyan "COMING SOON" for unreleased apps; the
   redesign modifier recolours it violet and stacks it on two lines (REDESIGN /
   SOON) for a rebuild of an already-shipped app (Meet Me Halfway) — folding the
   "redesign" signal into the status instead of adding a 2nd badge.
   z-index:1 because the badge precedes its card's art box in the DOM and the
   Ring Glance box is now positioned (.nk-rg-mirage) — without it, two
   positioned siblings at z-index:auto paint in DOM order and the banner
   covers the pill. */
.nk-soon-badge{position:absolute;top:12px;right:12px;z-index:1;font-family:var(--font-head);font-weight:700;font-size:9px;letter-spacing:2px;color:#0d0221;background:#00f0ff;padding:5px 9px;border-radius:20px;box-shadow:0 0 14px rgba(0,240,255,.6)}
.nk-soon-badge.nk-badge-redesign{background:#a24bff;box-shadow:0 0 14px rgba(162,75,255,.6);text-align:center;line-height:1.15}
