/* =============================================================================
   onyx-cards.css — ONE cohesive card language for the whole site. UNGATED.

   ⚠ GATING DECISION (owner call, 2026-08-19). The chasing-reflection border was
   already LIVE and UNGATED — an inline <style> in index.html, shipping on the
   homepage since the 2026-08-08 punch list. Per the owner's rule ("if it's already
   live, extend it ungated so all cards are cohesive immediately"), this file is
   loaded WITHOUT the ?fx flag. The NEWER effects — tilt, magnetic buttons, seeded
   backdrops, view transitions, number decode, wordmark liquefy — stay behind ?fx.

   ⚠ ONE IMPLEMENTATION, NOT TWO. The rules below are the ORIGINAL homepage rules,
   MOVED here verbatim — same conic stops, same 7s timing, same mask-composite, same
   reduced-motion handling. index.html's inline copy was DELETED in the same commit
   and replaced with a pointer. A second copy would drift, and "extend the effect"
   would quietly become "two effects that used to match".

   The homepage selectors (.ol-card, .olc, .ovh, .eco-card, .odl-panel) are kept
   exactly as they were so the homepage renders identically; the site-wide card
   classes are ADDED alongside them.
   ========================================================================== */


/* ── #4 CHASING-BORDER: bigger borders with a traveling cyan/gold reflection.
   Drawn as a 2px masked conic ring in a ::after overlay, so every card keeps its
   own background/border untouched. GPU-composited; static ring under
   prefers-reduced-motion or where @property is unsupported. ── */
@property --obang { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
.onyx-live .ol-card, .olc, .ovh, .eco-card, #onyx-daily-loop-mount .odl-panel,
.svc-card, .game-card, .spotlight-card, .card, .stat-card, .core-deep-card, .tw-card, .ab-card,
.onyx-frame {
  position: relative;
}
.onyx-live .ol-card::after, .olc::after, .ovh::after, .eco-card::after,
#onyx-daily-loop-mount .odl-panel::after,
.svc-card::after, .game-card::after, .spotlight-card::after, .card::after,
.stat-card::after, .core-deep-card::after, .tw-card::after, .ab-card::after,
.onyx-frame::after {
  content: ""; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  border-radius: inherit; padding: 2px;
  background: conic-gradient(from var(--obang),
    rgba(164,125,255,.16) 0deg, rgba(34,211,238,.85) 28deg, rgba(164,125,255,.16) 66deg,
    rgba(164,125,255,.16) 198deg, rgba(243,201,105,.5) 228deg, rgba(164,125,255,.16) 264deg,
    rgba(164,125,255,.16) 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  /* ⚠ NO animation here. See the is-animating rule below — the ring paints as a
     STATIC gradient frame until onyx-frames.js says the element is on screen. */
}

/* ── ON-SCREEN ONLY ──────────────────────────────────────────────────────────
   The single most important perf rule in this file. Extending the running colour
   from a handful of homepage cards to every framed display site-wide multiplies
   the animated-element count by an order of magnitude, and an off-screen conic
   gradient animating a custom property costs exactly as much as an on-screen one.
   onyx-frames.js drives `is-animating` from ONE IntersectionObserver and strips it
   from everything when the tab is backgrounded.
   Degradation is deliberate and safe: if that script never runs, nothing animates
   and every frame keeps its static gradient — cohesive, just still. */
.onyx-live .ol-card.is-animating::after, .olc.is-animating::after,
.ovh.is-animating::after, .eco-card.is-animating::after,
#onyx-daily-loop-mount .odl-panel.is-animating::after,
.svc-card.is-animating::after, .game-card.is-animating::after,
.spotlight-card.is-animating::after, .card.is-animating::after,
.stat-card.is-animating::after, .core-deep-card.is-animating::after,
.tw-card.is-animating::after, .ab-card.is-animating::after,
.onyx-frame.is-animating::after {
  animation: obchase 7s linear infinite;
}
@keyframes obchase { to { --obang: 360deg; } }
@media (prefers-reduced-motion: reduce) {
  .onyx-live .ol-card::after, .olc::after, .ovh::after, .eco-card::after,
  #onyx-daily-loop-mount .odl-panel::after,
  .svc-card::after, .game-card::after, .spotlight-card::after, .card::after,
  .stat-card::after, .core-deep-card::after, .tw-card::after, .ab-card::after { animation: none; }
}

/* ── COHESION: one radius / border language across every card surface ────────
   The chasing ring inherits border-radius, so surfaces with different radii read
   as different components even wearing the same ring. Deliberately gentle — a
   radius and a hairline, NOT a re-theme: each page keeps its own background and
   spacing, so nothing re-flows and no page loses its identity. */
.svc-card, .game-card, .spotlight-card, .stat-card,
.core-deep-card, .tw-card, .ab-card {
  border-radius: 14px;
  border: 1px solid rgba(164,125,255,.14);
}
/* ⚠ `.card` deliberately gets the RING but NOT the radius/border. It is a generic
   class name (explorer uses it, and it is common enough to appear on surfaces this
   pass never looked at), so it receives inert decoration only — never a forced
   border that could fight a layout I did not audit. */

@media (max-width: 420px) {
  .svc-card, .game-card, .spotlight-card, .stat-card,
  .core-deep-card, .tw-card, .ab-card { border-radius: 12px; }
}
