/* ═══ GradeOS-X v4 — the shared futuristic layer for every console ════════
   Additive only: atmosphere, motion, interaction physics + (v4) the
   hardware-era POLISH layer: field focus hairlines, chips, ledger tables,
   native control accenting. No layout changes. Pages opt in with:
     <link rel="stylesheet" href="/gradeos-x.css?v=4">
     <script defer src="/gradeos-x.js?v=3"></script>                         */

/* premium black: the page bg moves to <html>; body goes transparent so the
   fixed atmosphere layer (z:-1) shows through behind every panel. */
html{background:#0a0a0b !important}
body{background:transparent !important}

/* ── atmosphere (injected by gradeos-x.js as #gxAtmo, position:fixed z:-1) ──
   v3: deeper radial light staging — a cool key light from above, a faint lime
   floor bounce low-left, over the original center wash. All static gradients:
   rasterized once, zero ongoing cost. */
#gxAtmo{position:fixed;inset:0;z-index:-1;pointer-events:none;overflow:hidden;
  background:
    radial-gradient(ellipse 120% 60% at 50% -18%,#1a1e25 0%,rgba(26,30,37,0) 56%),
    radial-gradient(ellipse 64% 44% at 10% 106%,rgba(38,46,26,.42) 0%,rgba(38,46,26,0) 62%),
    radial-gradient(ellipse 58% 40% at 94% 110%,rgba(24,36,42,.38) 0%,rgba(24,36,42,0) 60%),
    radial-gradient(circle at 50% 22%,#15181d 0%,#0c0d11 46%,#0a0a0b 80%)}
/* Static aurora — a 70px-blurred layer rotating forever re-rasterized the
   whole screen every frame (a top lag source). Smaller blur, no animation:
   rasterized ONCE, then just composited. Same ambiance, ~zero ongoing cost. */
#gxAtmo .gx-aurora{position:absolute;inset:-15%;opacity:.42;filter:blur(44px);
  background:conic-gradient(from 0deg at 50% 50%,rgba(200,255,0,.06),transparent 26%,rgba(150,210,40,.035) 52%,transparent 78%,rgba(200,255,0,.06))}
/* v3 · breathing horizon — a low gradient band whose hue/opacity drift over
   MINUTES (not seconds), so the room feels alive without ever flickering.
   No blur on this layer (blur+animation re-rasterizes — forbidden here);
   hue-rotate/opacity keyframes are compositor-driven. */
#gxAtmo .gx-horizon{position:absolute;left:-8%;right:-8%;bottom:-10%;height:58%;
  will-change:opacity,filter;opacity:.5;
  background:
    radial-gradient(ellipse 86% 96% at 50% 104%,rgba(200,255,0,.05) 0%,rgba(200,255,0,.018) 40%,transparent 66%),
    linear-gradient(180deg,transparent 0%,rgba(140,220,255,.016) 52%,rgba(200,255,0,.038) 100%);
  animation:gxHorizon 240s ease-in-out infinite}
@keyframes gxHorizon{
  0%,100%{opacity:.38;filter:hue-rotate(0deg)}
  28%{opacity:.62;filter:hue-rotate(-16deg)}
  54%{opacity:.45;filter:hue-rotate(9deg)}
  80%{opacity:.58;filter:hue-rotate(-7deg)}}
#gxAtmo .gx-vig{position:absolute;inset:0;background:radial-gradient(ellipse 125% 95% at 50% 40%,transparent 52%,rgba(0,0,0,.6) 100%)}
/* v3 · refined grain: larger tile (less visible repeat), a touch quieter */
#gxAtmo .gx-grain{position:absolute;inset:0;opacity:.045;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.78' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  animation:gxGrain .5s steps(2) infinite}
@keyframes gxGrain{0%{transform:translate(0,0)}50%{transform:translate(-2.5%,1.5%)}100%{transform:translate(1.5%,-2%)}}
#gxAtmo .gx-scan{position:absolute;left:0;right:0;top:0;height:140px;will-change:transform;
  background:linear-gradient(180deg,transparent,rgba(200,255,0,.035) 45%,rgba(200,255,0,.06) 50%,rgba(200,255,0,.035) 55%,transparent);
  animation:gxScan 24s cubic-bezier(.16,1,.3,1) infinite}
/* transform (GPU-composited) instead of animating `top` (which forces layout every frame).
   MOTION LANGUAGE (2026-07-16): the sweep BEGINS below the hero fold (26vh) so it
   never crosses a headline mid-read, and rests dark for a third of its period. */
@keyframes gxScan{0%{transform:translateY(26vh);opacity:0}6%{opacity:.9}56%{opacity:.9}
  64%{transform:translateY(102vh);opacity:0}100%{transform:translateY(102vh);opacity:0}}
#gxAtmo canvas{position:absolute;inset:0;opacity:.5}

/* ── choreographed page entrance ──
   v4 FIX: the entrance must END at transform:none (not translateY(0)) and
   gradeos-x.js removes .gx-in on animationend. A lingering identity transform
   made <body> a permanent stacking context, so #gxAtmo's opaque gradients
   painted OVER every root-level z:-1 pane (bg3d / atmos) — the background
   substrates were silently occluded. */
body.gx-in{animation:gxBodyIn .8s cubic-bezier(.16,1,.3,1) both}
@keyframes gxBodyIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}

/* ── interaction physics ── */
.gx-ripple{position:absolute;border-radius:50%;background:rgba(200,255,0,.28);
  transform:translate(-50%,-50%) scale(0);pointer-events:none;animation:gxRip .6s cubic-bezier(.16,1,.3,1) forwards}
@keyframes gxRip{to{transform:translate(-50%,-50%) scale(7);opacity:0}}
button:not(.gx-no-fx),.btn:not(.gx-no-fx){transition:transform .16s cubic-bezier(.16,1,.3,1),box-shadow .25s cubic-bezier(.16,1,.3,1)}
button:not(.gx-no-fx):hover,.btn:not(.gx-no-fx):hover{box-shadow:0 0 0 1px rgba(200,255,0,.28),0 6px 24px rgba(200,255,0,.10)}
button:not(.gx-no-fx):active,.btn:not(.gx-no-fx):active{transform:scale(.96)}
:focus-visible{outline:1.5px solid rgba(200,255,0,.6);outline-offset:2px}

/* ── forensic loader (shared) ── */
.gx-loader{position:relative;width:64px;height:64px;margin:0 auto}
.gx-loader i{position:absolute;inset:0;border:1px solid rgba(200,255,0,.5);border-radius:50%;animation:gxRing 1.8s cubic-bezier(.16,1,.3,1) infinite}
.gx-loader i:nth-child(2){animation-delay:.6s}.gx-loader i:nth-child(3){animation-delay:1.2s}
@keyframes gxRing{0%{transform:scale(.28);opacity:.9}100%{transform:scale(1);opacity:0}}
.gx-loader b{position:absolute;left:50%;top:50%;width:8px;height:8px;margin:-4px;border-radius:50%;background:#c8ff00;box-shadow:0 0 12px #c8ff00,0 0 26px rgba(200,255,0,.5);animation:gxCore 1.8s ease-in-out infinite}
@keyframes gxCore{0%,100%{transform:scale(.8);opacity:.8}50%{transform:scale(1.25);opacity:1}}

/* ── premium chrome: scrollbars + selection ── */
::-webkit-scrollbar{width:9px;height:9px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:#23262c;border-radius:8px;border:2px solid #0a0a0b}
::-webkit-scrollbar-thumb:hover{background:rgba(200,255,0,.4)}
::selection{background:rgba(200,255,0,.25)}

/* reduced motion: keep the look, drop the movement */
@media (prefers-reduced-motion:reduce){
  #gxAtmo .gx-aurora,#gxAtmo .gx-grain,#gxAtmo .gx-scan,#gxAtmo .gx-horizon{animation:none}
  body.gx-in{animation:none}
}

/* ═══ v4 · HARDWARE-ERA POLISH — the "feel" layer every page inherits ═══════
   Lime hairline language on every native control; opt-in chip + ledger-table
   primitives. Additive, no layout changes; opt out per-element: .gx-no-fx  */

/* native controls carry the brand: caret, checkboxes, radios, ranges */
input,select,textarea{caret-color:#c8ff00;accent-color:#c8ff00}
::placeholder{color:#5a5a63;opacity:1}

/* field focus = tight lime hairline (fields hug the ring; buttons keep the
   generic offset ring from :focus-visible above) */
input:not(.gx-no-fx):focus-visible,
select:not(.gx-no-fx):focus-visible,
textarea:not(.gx-no-fx):focus-visible{
  outline:1.5px solid rgba(200,255,0,.45);outline-offset:0}
input:not(.gx-no-fx),select:not(.gx-no-fx),textarea:not(.gx-no-fx){
  transition:border-color .22s cubic-bezier(.16,1,.3,1),box-shadow .22s cubic-bezier(.16,1,.3,1)}
input:not(.gx-no-fx):hover,select:not(.gx-no-fx):hover,textarea:not(.gx-no-fx):hover{
  border-color:rgba(200,255,0,.22)}

/* ── chip — mono instrument tag; .on = engaged state ── */
.gx-chip{display:inline-flex;align-items:center;gap:7px;padding:4px 11px;border-radius:999px;
  font:500 11px 'JetBrains Mono',ui-monospace,monospace;letter-spacing:.08em;
  color:#9a9aa3;background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.09);
  cursor:pointer;user-select:none;-webkit-user-select:none;
  transition:color .2s,border-color .2s,box-shadow .25s cubic-bezier(.16,1,.3,1)}
.gx-chip::before{content:"";width:5px;height:5px;border-radius:50%;flex:none;
  background:currentColor;opacity:.45;transition:opacity .2s}
.gx-chip:hover{color:#e8e8ea;border-color:rgba(200,255,0,.3)}
.gx-chip.on{color:#c8ff00;border-color:rgba(200,255,0,.5);background:rgba(200,255,0,.07);
  box-shadow:0 0 14px rgba(200,255,0,.08)}
.gx-chip.on::before{opacity:1;box-shadow:0 0 8px rgba(200,255,0,.8)}

/* ── ledger table (opt-in .gx-table) — hairline rows; the hovered row reads
   like a carriage position on a rail: 2px lime inset edge + faint lift ── */
.gx-table{width:100%;border-collapse:collapse}
.gx-table th{font:600 10px 'JetBrains Mono',ui-monospace,monospace;letter-spacing:.22em;
  text-transform:uppercase;color:#5a5a63;text-align:left;padding:9px 14px;
  border-bottom:1px solid rgba(255,255,255,.1)}
.gx-table td{padding:11px 14px;font-size:13px;color:#c9c9cf;
  border-bottom:1px solid rgba(255,255,255,.05)}
.gx-table tbody tr{transition:background .18s ease,box-shadow .18s ease}
.gx-table tbody tr:hover{background:rgba(255,255,255,.025);
  box-shadow:inset 2px 0 0 #c8ff00}
.gx-table tbody tr:hover td:first-child{color:#e8e8ea}
.gx-table .num{font-family:'JetBrains Mono',ui-monospace,monospace;
  font-variant-numeric:tabular-nums;text-align:right}

/* ── scroll chrome completeness ── */
::-webkit-scrollbar-corner{background:transparent}
*{scrollbar-width:thin;scrollbar-color:#23262c transparent}

/* ── kbd — command-palette hints etc. ── */
kbd.gx-kbd{display:inline-block;padding:2px 7px;border-radius:5px;
  font:500 11px 'JetBrains Mono',ui-monospace,monospace;color:#9a9aa3;
  background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.1);
  border-bottom-width:2px}
