/* ==========================================================================
   Esagames Hosting Shield — theme.css
   Design tokens, self-hosted fonts, reset, base typography.
   Tokens are copied verbatim from the esagames.ro design system (CONTRACT.md).
   Owned by agent 1. Components live in app.css.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. FONTS — self-hosted, zero external requests.
   Inter ships as a single variable file per subset (weight axis 100..900).
   Poppins ships as static weights 600/700/800 (headings only).
   -------------------------------------------------------------------------- */
@font-face{
  font-family:'Inter';
  font-style:normal;
  font-weight:100 900;
  font-display:swap;
  src:url('../fonts/inter-var-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,
    U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Inter';
  font-style:normal;
  font-weight:100 900;
  font-display:swap;
  src:url('../fonts/inter-var-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,
    U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,
    U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face{
  font-family:'Poppins';font-style:normal;font-weight:600;font-display:swap;
  src:url('../fonts/poppins-600-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,
    U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Poppins';font-style:normal;font-weight:600;font-display:swap;
  src:url('../fonts/poppins-600-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,
    U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,
    U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face{
  font-family:'Poppins';font-style:normal;font-weight:700;font-display:swap;
  src:url('../fonts/poppins-700-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,
    U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Poppins';font-style:normal;font-weight:700;font-display:swap;
  src:url('../fonts/poppins-700-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,
    U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,
    U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face{
  font-family:'Poppins';font-style:normal;font-weight:800;font-display:swap;
  src:url('../fonts/poppins-800-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,
    U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Poppins';font-style:normal;font-weight:800;font-display:swap;
  src:url('../fonts/poppins-800-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,
    U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,
    U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* --------------------------------------------------------------------------
   2. TOKENS — exact values from CONTRACT.md §"Design tokens".
   Do not change these. Anything derived is namespaced --esa-*.
   -------------------------------------------------------------------------- */
:root{
  /* brand */
  --brand:#7c6cff;
  --brand2:#6950fa;
  --brand-rgb:124,108,255;
  --brand-ink:#ffffff;

  /* surfaces */
  --bg:#0d1121;
  --bg-2:#151a2d;
  --surface:#1c2238;
  --surface-2:#242a43;
  --field:#242a43;

  /* hairlines */
  --line:rgba(148,163,184,.10);
  --line-2:rgba(148,163,184,.18);

  /* ink */
  --ink:#d9dde7;
  --ink-mute:#bac0d5;
  --ink-dim:#989fb7;

  /* geometry */
  --radius:16px;
  --radius-sm:12px;

  /* elevation */
  --shadow:0 18px 50px rgba(0,0,0,.45);
  --shadow-sm:0 8px 24px rgba(0,0,0,.35);
  --glow:0 0 0 1px rgba(124,108,255,.22), 0 18px 50px rgba(124,108,255,.12);

  /* status */
  --ok:#22c55e;
  --warn:#f59e0b;
  --crit:#ef4444;
  --info:#22d3ee;

  /* ---- derived (agent 1) ------------------------------------------------ */
  --brand-soft:rgba(var(--brand-rgb),.12);
  --brand-line:rgba(var(--brand-rgb),.25);
  --ok-soft:rgba(34,197,94,.12);   --ok-line:rgba(34,197,94,.30);
  --warn-soft:rgba(245,158,11,.12);--warn-line:rgba(245,158,11,.30);
  --crit-soft:rgba(239,68,68,.12); --crit-line:rgba(239,68,68,.32);
  --info-soft:rgba(34,211,238,.12);--info-line:rgba(34,211,238,.30);
  --idle:#7b829c;
  --idle-soft:rgba(148,163,184,.10);--idle-line:rgba(148,163,184,.22);

  /* ---- chart series slots (docs/FRONTEND.md §3.9) ------------------------
     Two slots, and only two. charts.js reads them off :root and falls back to
     these same values when the stylesheet is missing. Validated with the
     dataviz validator in dark mode against all three panel surfaces
     (#0d1121 / #1c2238 / #242a43), --pairs all:
       lightness band PASS · chroma floor PASS · contrast PASS (>= 3:1)
       CVD separation PASS  worst pair dE 14.0 (deutan), tritan 7.5
       normal vision  PASS  worst pair dE 19.5
     Tritan is below the 8.0 target, which is exactly why the traffic chart
     mirrors: direction is carried by POSITION (out above the zero rule, in
     below it) and by direct labels, never by hue alone.
     NEITHER slot is a status token, so a series can never impersonate a
     health colour, and --ok/--warn/--crit/--info are never used for series. */
  --viz-out:#7c6cff;   /* outbound — our node → the customer's server */
  --viz-in:#189cb8;    /* inbound  — the customer's server → our node */
  --viz-out-soft:rgba(124,108,255,.14);
  --viz-in-soft:rgba(24,156,184,.14);

  --radius-xs:8px;
  --radius-pill:999px;
  --radius-lg:22px;

  /* spacing rhythm — the site works in 4px steps, sections breathe at 64px */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:22px;
  --sp-6:28px; --sp-7:36px; --sp-8:46px; --sp-9:64px;

  /* ---- THE RHYTHM (2026-08-28) ------------------------------------------
     Three levels, and only three. Every page used to separate its SECTIONS
     with 16px (`u-mt-4`) while a single stat tile padded its own inside with
     22px, so a new section read as one more tile in the previous one and the
     whole page came out as a single dense block. The relationship is now
     fixed in tokens instead of at the call sites:

       --sp-tight     12px  inside one component (chips, list rows)
       --sp-group     22px  peers inside ONE group: cards in a grid, tiles in
                            a stat row. Deliberately equal to the card's own
                            padding — a gap that matches the padding is what
                            makes a grid read as one object.
       --sp-section   36px  between SECTIONS of a page. 1.6x the group gap, so
                            "next section" is never mistaken for "next tile".

     Below 680px the card padding drops to 16px, so the pair steps down with
     it (16 / 28) and section separation actually widens to 1.75x the group
     gap. The ordering tight < group < section therefore holds at EVERY width;
     see the media query below and app.css §1. Nothing may hardcode a section
     gap again — use these, not --sp-4 / --sp-6. */
  --sp-tight:var(--sp-3);
  --sp-group:var(--sp-5);
  --sp-section:var(--sp-7);

  --shell-max:1320px;
  --topbar-h:64px;
  --sidebar-w:248px;

  --font-ui:'Inter',system-ui,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',
    Arial,'Noto Sans',sans-serif,'Apple Color Emoji','Segoe UI Emoji';
  --font-head:'Poppins','Inter',system-ui,-apple-system,'Segoe UI',Roboto,
    'Helvetica Neue',Arial,sans-serif;
  --font-mono:ui-monospace,SFMono-Regular,'SF Mono',Menlo,Monaco,Consolas,
    'Liberation Mono','Courier New',monospace;

  --ease:cubic-bezier(.22,.61,.36,1);
  --focus:0 0 0 3px rgba(var(--brand-rgb),.45), 0 0 0 1px var(--bg);

  color-scheme:dark;
}

/* The one place the rhythm changes: at 680px `.esa-card__body` padding drops
   from 22px to 16px (app.css §4), so the group and section steps drop with it.
   Redefining the two tokens here moves every consumer at once — page padding,
   the section rhythm, the page-head, every grid gap — and keeps section > card
   padding true on a phone. Do NOT re-tune the individual components instead:
   that is how the rhythm inverted the first time. */
@media (max-width:680px){
  :root{ --sp-group:var(--sp-4); --sp-section:var(--sp-6); }
}

/* --------------------------------------------------------------------------
   3. RESET
   -------------------------------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%}
body{
  margin:0;
  min-height:100%;
  /* explicit paint — never inherit the host background */
  background-color:var(--bg);
  background-image:
    radial-gradient(1200px 520px at 50% -240px, rgba(var(--brand-rgb),.10), transparent 70%),
    radial-gradient(900px 460px at 100% 0, rgba(34,211,238,.045), transparent 65%);
  background-attachment:fixed;
  background-repeat:no-repeat;
  color:var(--ink);
  font-family:var(--font-ui);
  font-size:15px;
  line-height:1.6;
  font-weight:450;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  font-variant-ligatures:none;
  text-rendering:optimizeLegibility;
}
h1,h2,h3,h4,h5,h6{margin:0;font-family:var(--font-head);font-weight:700;
  color:#fff;letter-spacing:-.01em;line-height:1.2}
h1{font-size:clamp(24px,2.6vw,32px);font-weight:800}
h2{font-size:clamp(20px,2.2vw,26px);font-weight:800}
h3{font-size:18px}
h4{font-size:16px}
h5{font-size:14px}
h6{font-size:13px}
p{margin:0 0 var(--sp-3);color:var(--ink-mute)}
p:last-child{margin-bottom:0}
ul,ol{margin:0 0 var(--sp-3);padding-left:1.2em;color:var(--ink-mute)}
ul:last-child,ol:last-child{margin-bottom:0}
li+li{margin-top:var(--sp-1)}
small{font-size:12.5px}
strong,b{font-weight:700;color:var(--ink)}
hr{border:0;border-top:1px solid var(--line);margin:var(--sp-5) 0}
img,svg,video,canvas{max-width:100%;height:auto;vertical-align:middle}
svg{display:inline-block}

a{color:var(--brand);text-decoration:none;
  transition:color .18s var(--ease),opacity .18s var(--ease)}
a:hover{color:var(--brand2);text-decoration:underline;text-underline-offset:3px}

button,input,select,textarea{font:inherit;color:inherit;margin:0}
button{background:none;border:0;padding:0;cursor:pointer;text-align:inherit}
button:disabled,[disabled]{cursor:not-allowed}
textarea{resize:vertical}

code,kbd,samp,pre{font-family:var(--font-mono);font-size:.9em}
pre{margin:0;overflow:auto}

table{border-collapse:collapse;border-spacing:0}
th{text-align:left;font-weight:700}

fieldset{margin:0;padding:0;border:0;min-width:0}
legend{padding:0}

dialog{color:inherit}

/* --------------------------------------------------------------------------
   3b. [hidden] MUST WIN
   The UA sheet's `[hidden]{display:none}` is specificity (0,1,0) and is beaten
   by any component rule that sets a display — and 111 of ours do
   (.esa-banner{display:flex}, .esa-signal{display:grid}, .esa-stat, .esa-card__head,
   every flex/grid component). A region toggled with `el.hidden = true` therefore
   stayed on screen showing its placeholder dashes.

   That shipped as a real bug in the first preview build, on the health banner —
   the element that tells a customer their tunnel has never received a packet.
   Patching the 111 rules would fix today and break again on the next component,
   so the rule lives here, once, and outranks all of them.

   Contract for JS (assets/js/live.js, app.js, charts.js, ui.js):
   to SHOW a hidden element, clear the attribute (`el.hidden = false` or
   removeAttribute). An inline `style.display` will NOT override this rule —
   `!important` in a stylesheet beats a non-important inline declaration. Every
   current caller already clears the attribute, so inline display writes are
   belt-and-braces, not load-bearing.
   -------------------------------------------------------------------------- */
[hidden]{ display:none !important; }

/* The one exception: `hidden="until-found"` must stay laid out so the browser
   can find-in-page it and fire beforematch. Supporting engines only. */
[hidden="until-found"]{ display:revert !important; content-visibility:hidden; }

/* --------------------------------------------------------------------------
   3c. ANCHORS MUST NOT LAND UNDER THE STICKY TOPBAR
   .esa-topbar is `position:sticky; top:0` and 64px tall, so a jump to
   `/support#selftest` used to scroll the target to y=0 — i.e. underneath the
   bar, half-covered by its blur. Reserve the bar plus one group step.
   -------------------------------------------------------------------------- */
:target{ scroll-margin-top:calc(var(--topbar-h) + var(--sp-group)); }

/* --------------------------------------------------------------------------
   4. FOCUS — always visible, never removed
   -------------------------------------------------------------------------- */
:focus-visible{outline:2px solid var(--brand);outline-offset:2px;border-radius:4px}
a:focus-visible,button:focus-visible,summary:focus-visible,
[tabindex]:focus-visible,input:focus-visible,select:focus-visible,
textarea:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
:focus:not(:focus-visible){outline:none}

/* --------------------------------------------------------------------------
   5. SELECTION, SCROLLBARS, PLACEHOLDERS
   -------------------------------------------------------------------------- */
::selection{background:rgba(var(--brand-rgb),.35);color:#fff}
::placeholder{color:var(--ink-dim);opacity:1}
*{scrollbar-width:thin;scrollbar-color:rgba(148,163,184,.28) transparent}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:rgba(148,163,184,.24);
  border:3px solid transparent;background-clip:content-box;border-radius:999px}
::-webkit-scrollbar-thumb:hover{background:rgba(148,163,184,.42);
  border:3px solid transparent;background-clip:content-box}

/* --------------------------------------------------------------------------
   6. BASE UTILITIES (kept small on purpose — components live in app.css)
   -------------------------------------------------------------------------- */
.esa-sr-only,
.u-sr{
  position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}
/* .u-sr is the spelling views/client/_helpers.php uses for the signal tile's
   screen-reader mirror. It was defined nowhere, so the day anyone cleared its
   `hidden` attribute the text would have rendered visibly inside the tile. */
.esa-skip{
  position:absolute;left:var(--sp-3);top:-64px;z-index:200;
  padding:10px 16px;border-radius:var(--radius-sm);
  background:var(--brand);color:var(--brand-ink);font-weight:700;
  transition:top .18s var(--ease);
}
.esa-skip:focus{top:var(--sp-3);text-decoration:none}

.u-mute{color:var(--ink-mute)!important}
.u-dim{color:var(--ink-dim)!important}
.u-ink{color:var(--ink)!important}
.u-brand{color:var(--brand)!important}
.u-ok{color:var(--ok)!important}
.u-warn{color:var(--warn)!important}
.u-crit{color:var(--crit)!important}
.u-info{color:var(--info)!important}
.u-mono{font-family:var(--font-mono);font-size:.92em;letter-spacing:-.01em}
.u-num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
.u-nowrap{white-space:nowrap}
.u-break{overflow-wrap:anywhere;word-break:break-word}
.u-center{text-align:center}
.u-right{text-align:right}
.u-upper{text-transform:uppercase;letter-spacing:.12em;font-size:11px;font-weight:700}
.u-mt-0{margin-top:0!important}   .u-mt-2{margin-top:var(--sp-2)!important}
.u-mt-3{margin-top:var(--sp-3)!important} .u-mt-4{margin-top:var(--sp-4)!important}
.u-mt-6{margin-top:var(--sp-6)!important} .u-mt-9{margin-top:var(--sp-9)!important}
.u-mb-0{margin-bottom:0!important} .u-mb-3{margin-bottom:var(--sp-3)!important}
.u-mb-4{margin-bottom:var(--sp-4)!important} .u-mb-6{margin-bottom:var(--sp-6)!important}
.u-full{width:100%!important}
.u-flex1{flex:1 1 auto!important;min-width:0}

@media (max-width:760px){ .u-hide-sm{display:none!important} }
@media (min-width:761px){ .u-only-sm{display:none!important} }

/* --------------------------------------------------------------------------
   7. MOTION SAFETY
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important;
  }
}

/* --------------------------------------------------------------------------
   8. PRINT — panel pages are occasionally printed for tickets
   -------------------------------------------------------------------------- */
@media print{
  body{background:#fff!important;color:#111}
  .esa-topbar,.esa-sidebar,.esa-toast-region,.esa-copy{display:none!important}
}
