/* ════════════════════════════════════════════════════════════════════
   HIVE DESIGN SYSTEM — modern fintech premium
   Shared token layer + universal primitives, linked by every page
   (agents.html, dashboard.html, admin.html). Page-specific components
   live in each page's own <style>. Every component color references a
   token here, so theming + cross-page consistency are single-sourced.

   NOTE: each page must also include, in <head> BEFORE this stylesheet:
     1. the anti-FOUC inline script that sets <html data-theme="…">
     2. the Inter font <link> (display=swap)
   and in the header markup: the #theme-toggle button (wired by a tiny
   per-page wireThemeToggle()).
   ════════════════════════════════════════════════════════════════════ */

:root,[data-theme="dark"]{
  color-scheme:dark;
  --bg:#0A0B0D; --surface:#14161A; --surface-raised:#1B1E23;
  --text:#EBEDF0; --text-muted:#99A0A8; --text-subtle:#868D96; /* subtle bumped to AA ~4.7:1 on --bg (was #646B73, 3.6:1) — still a step below muted */
  /* AMBER BEE-YELLOW (2026-07-10). --accent = text/link accent (theme-aware); --accent-fill = universal
     bee-yellow for FILLS (buttons/badges/bee), always yellow with near-black --accent-contrast on it. */
  --accent:#f5c800; --accent-hover:#F8D747; --accent-contrast:#0A0B0D; --accent-soft:rgba(245,200,0,.11);
  --accent-fill:#f5c800; --accent-fill-strong:#EAB900; --amber:var(--accent);
  --success:#3FBE82; --success-soft:rgba(63,190,130,.14);
  --danger:#E96A60;  --danger-soft:rgba(233,106,96,.14);
  --border:#24272D; --border-strong:#313640;
  --shadow-card:0 1px 2px rgba(0,0,0,.45), 0 6px 20px -4px rgba(0,0,0,.40);
  --shadow-raised:0 10px 30px -6px rgba(0,0,0,.55);
}
[data-theme="light"]{
  color-scheme:light;
  --bg:#F4F6F8; --surface:#FFFFFF; --surface-raised:#FBFCFE;
  --text:#161A1F; --text-muted:#586069; --text-subtle:#616870; /* subtle bumped to AA ~5.3:1 on --bg (was #8B929B, 2.7:1) — still a step below muted */
  /* light theme: text/link accent darkens to a deep honey for readability on the light ground (#7A5A00 =
     5.89:1 AA); FILLS stay bee-yellow (--accent-fill) with near-black text, so buttons/bee remain yellow. */
  --accent:#7A5A00; --accent-hover:#6E5200; --accent-contrast:#0A0B0D; --accent-soft:rgba(122,90,0,.10);
  --accent-fill:#f5c800; --accent-fill-strong:#EAB900; --amber:var(--accent);
  --success:#1F9D63; --success-soft:rgba(31,157,99,.12);
  --danger:#D64A42;  --danger-soft:rgba(214,74,66,.10);
  --border:#E4E7EC; --border-strong:#D2D7DE;
  --shadow-card:0 1px 2px rgba(17,24,39,.05), 0 6px 20px -6px rgba(17,24,39,.10);
  --shadow-raised:0 12px 28px -8px rgba(17,24,39,.16);
}
:root{
  --font-sans:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
  --font-mono:ui-monospace,'SF Mono',Menlo,Consolas,monospace;
  --radius-card:14px; --radius-btn:10px; --radius-pill:999px;
}

*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--bg);color:var(--text);font-family:var(--font-sans);font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased;transition:background-color .2s ease,color .2s ease}
.wrap{max-width:1160px;margin:0 auto;padding:0 20px}

/* header */
header{border-bottom:1px solid var(--border);position:sticky;top:0;background:var(--bg);z-index:10;transition:background-color .2s ease,border-color .2s ease}
@supports (backdrop-filter:blur(1px)){ header{background:color-mix(in srgb,var(--bg) 82%,transparent);backdrop-filter:blur(10px)} }
.bar{display:flex;align-items:center;justify-content:space-between;height:60px}
.brand{display:flex;align-items:center;gap:10px;font-weight:700;font-size:15px;letter-spacing:.14em;text-transform:uppercase;color:var(--text);text-decoration:none}
.brand svg,.brand img{display:block}

/* HIVE ICON SET (owner 2026-08-02). Brand glyphs from frontend/shared/hive-icons.svg, inlined per page by
   deploy/inline-icon-sprite.js and referenced with <use href="#i-…">. The symbols carry their own gold
   gradient, so NOTHING here may set fill/stroke on their contents: the landing page once had
   `.brand svg polygon{fill:…}` and it repainted the bee's mask rects, which are read by LUMINANCE, and the
   stripes disappeared. Size and alignment only. */
.hv-ic{display:inline-block;vertical-align:-0.15em;width:1em;height:1em;flex:0 0 auto}
.hv-ic-lg{width:1.35em;height:1.35em;vertical-align:-0.28em}

/* THE .brand svg FILL OVERRIDES WERE REMOVED 2026-07-31. They read:
     .brand svg polygon,.brand svg rect{fill:var(--accent-fill)}
     .brand svg ellipse,.brand svg circle{fill:var(--bg)}
   and were written for the 2024 flat-polygon mark, whose shapes carried no fills of their own. Every mark
   since has set its own fills, so these rules stopped helping and started silently repainting the art:
   on the Classic bee they forced the BODY rect to gold (invisible against the gold hexagon), forced the
   wings and head to var(--bg) (near-white in light theme), and — worst — repainted the two rects inside
   <mask id="hiveStripes"> gold as well. A mask is read by LUMINANCE, so once its white "show" rect and its
   black "stripe" rects were all the same gold, the mask cut nothing and the stripes ceased to exist.
   The result was a gold hexagon with two pale wing shapes and no bee, on every page, in both themes.
   The logo drift gate never saw it: the gate rendered the SVG standalone through sharp, and standalone the
   markup is perfect. Only the browser applies this stylesheet. Do not reintroduce blanket fill rules that
   target bare SVG element names — style the mark at its source, never from the page. */
.bar-right{display:flex;align-items:center;gap:8px}
.navlink{font-family:var(--font-sans);font-size:13px;font-weight:500;color:var(--text-muted);text-decoration:none;border-radius:var(--radius-btn);padding:7px 12px;background:transparent;border:none;cursor:pointer;transition:color .15s,background-color .15s}
@media (hover: hover){.navlink:hover{color:var(--text);background:var(--surface)}}
.signout{font-family:var(--font-sans);font-size:13px;font-weight:500;cursor:pointer;color:var(--text-muted);background:transparent;border:1px solid var(--border);border-radius:var(--radius-btn);padding:7px 12px;transition:color .15s,border-color .15s}
@media (hover: hover){.signout:hover{color:var(--text);border-color:var(--border-strong)}}
.theme-toggle{display:grid;place-items:center;width:36px;height:36px;cursor:pointer;color:var(--text-muted);background:transparent;border:1px solid var(--border);border-radius:var(--radius-btn);transition:color .15s,border-color .15s,background-color .15s}
@media (hover: hover){.theme-toggle:hover{color:var(--text);border-color:var(--border-strong);background:var(--surface)}}
.theme-toggle .ic{display:none}
[data-theme="dark"] .theme-toggle .ic-sun{display:block}
[data-theme="light"] .theme-toggle .ic-moon{display:block}

/* section titles */
.section-title{font-family:var(--font-sans);font-size:13px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--text-muted);margin:28px 0 12px}

/* buttons — primary (filled gold) + ghost + small secondary */
.btn{font-family:var(--font-sans);font-size:13px;font-weight:600;letter-spacing:.01em;cursor:pointer;background:var(--accent-fill);color:var(--accent-contrast);border:1px solid transparent;border-radius:var(--radius-btn);padding:10px 18px;box-shadow:0 1px 2px rgba(0,0,0,.12);transition:background-color .15s,transform .12s,box-shadow .15s}
@media (hover: hover){.btn:hover{background:var(--accent-fill-strong);transform:translateY(-1px)}}
.btn:disabled{background:var(--surface-raised);color:var(--text-subtle);border-color:var(--border);cursor:not-allowed;transform:none;box-shadow:none}
.btn.ghost{background:transparent;color:var(--text);border-color:var(--border);box-shadow:none}
@media (hover: hover){.btn.ghost:hover{background:var(--surface-raised);border-color:var(--border-strong)}}
.btn-sm{font-family:var(--font-sans);font-size:12px;font-weight:600;cursor:pointer;background:var(--surface-raised);color:var(--text);border:1px solid var(--border);border-radius:var(--radius-btn);padding:8px 14px;transition:background-color .15s,border-color .15s}
@media (hover: hover){.btn-sm:hover{background:var(--surface);border-color:var(--border-strong)}}
.btn-sm:disabled{color:var(--text-subtle);cursor:not-allowed}

/* form fields */
.field{display:flex;flex-direction:column;gap:6px}
.field label{font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:.07em;color:var(--text-muted)}
.field input,.field select{font-family:var(--font-sans);font-size:13px;background:var(--bg);color:var(--text);border:1px solid var(--border);border-radius:var(--radius-btn);padding:9px 11px;min-width:200px;outline:none;transition:border-color .15s}
.field input:focus,.field select:focus{border-color:var(--accent)}

/* modal — overlay scrim + fade/slide animation (animate in/out of display:none;
   handlers only toggle [hidden]). Pages may override layout (alignment/padding/
   max-width) in their own <style>; this is the shared base. */
.modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;z-index:50;padding:20px;opacity:1;transition:opacity .18s ease, display .18s allow-discrete}
.modal-overlay[hidden]{display:none;opacity:0}
@starting-style{ .modal-overlay:not([hidden]){opacity:0} }
.modal{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-card);max-width:480px;width:100%;padding:22px;max-height:90vh;overflow:auto;box-shadow:var(--shadow-raised);transition:transform .18s ease, opacity .18s ease}
.modal-overlay[hidden] .modal{transform:translateY(8px);opacity:0}
@starting-style{ .modal-overlay:not([hidden]) .modal{transform:translateY(8px);opacity:0} }
@media (prefers-reduced-motion: reduce){ .modal-overlay,.modal-overlay .modal{transition:none} }
.modal-head{font-family:var(--font-sans);font-size:14px;font-weight:600;letter-spacing:.02em;color:var(--text);margin-bottom:18px}
.modal .field{margin-bottom:12px}
.modal .field input,.modal .field select{width:100%}
.modal-actions{display:flex;gap:10px;justify-content:flex-end;margin:18px 0 4px}

/* tooltips (body-level fixed so modal overflow can't clip them) */
.tip{display:inline-block;margin-left:4px;font-size:11px;color:var(--text-subtle);cursor:help;user-select:none}
.tip:focus{color:var(--accent);outline:none}
@media (hover: hover){.tip:hover{color:var(--accent);outline:none}}
#tooltip{position:fixed;max-width:260px;background:var(--surface);border:1px solid var(--border);border-radius:10px;color:var(--text);font-family:var(--font-sans);font-size:11px;line-height:1.5;padding:8px 10px;z-index:100;pointer-events:none;box-shadow:var(--shadow-raised)}
#tooltip[hidden]{display:none}

/* status pills (badges + tags) + lifecycle led */
.badge,.tag{font-family:var(--font-sans);font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;padding:3px 10px;border-radius:var(--radius-pill);white-space:nowrap}
.badge.running,.tag.running{background:var(--success-soft);color:var(--success)}
.badge.paused,.tag.paused{background:var(--surface-raised);color:var(--text-muted);border:1px solid var(--border)}
.badge.grounded,.tag.grounded{background:transparent;color:var(--text-subtle);border:1px solid var(--border)}
/* idle = enabled lifecycle but no verified live-execution signal (neutral, not green) */
.badge.idle,.tag.idle{background:var(--surface-raised);color:var(--text-muted);border:1px solid var(--border)}
/* active = the owner explicitly STARTED it (lifecycle intent) — amber outline, deliberately NOT
   green: green stays reserved for a future runtime heartbeat that proves live execution. */
.badge.active,.tag.active{background:transparent;color:var(--accent);border:1px solid var(--accent)}
.led{color:var(--success);font-size:9px;line-height:1}
.led.active{color:var(--accent)}
.led.paused,.led.grounded,.led.off,.led.idle{color:var(--text-subtle)}

/* shared states */
.empty{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-card);box-shadow:var(--shadow-card);padding:32px;text-align:center;color:var(--text-muted);margin-bottom:24px}
.err{border:1px solid var(--danger);background:var(--danger-soft);color:var(--danger);border-radius:var(--radius-card);padding:14px 16px;margin-bottom:20px;font-size:13px}
footer{color:var(--text-subtle);font-size:12px;text-align:center;padding:40px 0 24px;letter-spacing:.03em}

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   HIVE PULSE — the live "what she's doing right now" status line. SHARED (owner 2026-07-17).
   ══════════════════════════════════════════════════════════════════════════════════════════════════
   THE SINGLE SOURCE for every surface that renders a status line: the agent DETAIL page header, the
   portfolio CARDS, and anything added later. It lives here because two independent copies had already
   drifted — the detail page had the full treatment (ping tempo + animated ellipsis + shimmer) while
   the cards had only a lone ping, with a separate `acpulsering` keyframe nobody remembered to update.
   A shared component is the only thing that stops that recurring. Do NOT re-declare these rules in a
   page's <style>; add page-specific LAYOUT (margin/size) against .hive-pulse instead.

   Contract — the markup a page must render:
     <div class="hive-pulse [is-live] [pulse-STATE]">
       <span class="hp-dot"></span>
       <span class="hp-text" role="status" aria-live="polite">Scanning markets</span>
       <span class="hp-ell" aria-hidden="true"><i>.</i><i>.</i><i>.</i></span>   (only if the state text ended in an ellipsis)
     </div>
   STATE ∈ scanning | watching | analyzing | checking | placing | reconnecting | paused | resting.
   `is-live` = a real, fresh signal. Never decorate a stale one — a frozen fake is worse than nothing.
*/
.hive-pulse{display:flex;align-items:center;gap:8px;min-height:16px;font-size:12px;color:var(--text-muted);transition:color .4s ease}
.hive-pulse[hidden]{display:none}                    /* explicit: beats display:flex so [hidden] hides */
.hive-pulse .hp-dot{flex:0 0 auto;width:7px;height:7px;border-radius:50%;background:var(--text-subtle);position:relative;transition:background .4s ease}
.hive-pulse .hp-text{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;transition:opacity .3s ease}
/* LIVE — amber dot with a soft expanding sonar ring. Calm base; TEMPO below is the only state coupling. */
.hive-pulse.is-live{color:var(--text)}
.hive-pulse.is-live .hp-dot{background:var(--accent)}
.hive-pulse.is-live .hp-dot::after{content:"";position:absolute;inset:0;border-radius:50%;background:var(--accent);opacity:.5;animation:hpRing 2.5s ease-out infinite}
@keyframes hpRing{0%{transform:scale(1);opacity:.5}70%{transform:scale(2.6);opacity:0}100%{transform:scale(2.6);opacity:0}}
/* TEMPO — real work beats faster than calm observation. Same states, different pace. No new states. */
.hive-pulse.pulse-analyzing .hp-dot::after,.hive-pulse.pulse-checking .hp-dot::after{animation-duration:1.7s}
.hive-pulse.pulse-placing .hp-dot::after{animation-duration:1.3s}
/* RECONNECTING — amber-muted fade: data is stale and says so. No fake liveness. */
.hive-pulse.pulse-reconnecting{color:var(--text-muted)}
.hive-pulse.pulse-reconnecting .hp-dot{background:var(--accent);opacity:.55;animation:hpFade 1.6s ease-in-out infinite}
@keyframes hpFade{0%,100%{opacity:.3}50%{opacity:.7}}
/* PAUSED / RESTING — still, muted dot. An agent that isn't hunting must not look like it is. */
.hive-pulse.pulse-paused .hp-dot,.hive-pulse.pulse-resting .hp-dot{background:var(--text-subtle)}
/* ANIMATED ELLIPSIS — the state text carries a literal '…'; JS strips it and these three dots pulse in
   sequence. OUTSIDE .hp-text so aria-live reads clean prose and the shimmer needn't cross it. */
.hive-pulse .hp-ell{flex:0 0 auto;margin-left:-3px;letter-spacing:.05em;color:inherit}
.hive-pulse .hp-ell i{font-style:normal;opacity:.22;animation:hpEll 1.4s ease-in-out infinite}
.hive-pulse .hp-ell i:nth-child(2){animation-delay:.18s}
.hive-pulse .hp-ell i:nth-child(3){animation-delay:.36s}
@keyframes hpEll{0%,62%,100%{opacity:.22}30%{opacity:1}}
.hive-pulse.pulse-analyzing .hp-ell i,.hive-pulse.pulse-checking .hp-ell i{animation-duration:1.1s}
.hive-pulse.pulse-placing .hp-ell i{animation-duration:.85s}
/* SHIMMER — one amber glint travels the text ~every 6s (sweep ~1.7s, then rests). LIVE states only.
   FAIL-SAFE: every var() carries a literal fallback. If a token failed to resolve, the gradient would
   be invalid, background-image would drop, and -webkit-text-fill-color:transparent would SURVIVE —
   leaving the status line INVISIBLE. The line reporting what a live money agent is doing must never be
   able to vanish for a cosmetic effect, so the gradient is always valid by construction. */
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .hive-pulse.is-live .hp-text{
    background-image:linear-gradient(100deg,var(--text,#7A7F87) 0%,var(--text,#7A7F87) 40%,var(--accent,#f5c800) 50%,var(--text,#7A7F87) 60%,var(--text,#7A7F87) 100%);
    background-size:280% 100%;-webkit-background-clip:text;background-clip:text;
    -webkit-text-fill-color:transparent;animation:hpShimmer 6s ease-in-out infinite}
}
@keyframes hpShimmer{0%,72%{background-position:130% 0}100%{background-position:-30% 0}}
/* REDUCED MOTION — collapse to the honest static dot. The shimmer MUST hand the text its solid colour
   back, or it renders invisible. */
@media (prefers-reduced-motion:reduce){
  .hive-pulse .hp-dot::after,.hive-pulse.pulse-reconnecting .hp-dot,.hive-pulse .hp-ell i{animation:none}
  .hive-pulse.pulse-reconnecting .hp-dot{opacity:.7}
  .hive-pulse .hp-ell i{opacity:.55}
  .hive-pulse.is-live .hp-text{animation:none;background-image:none;-webkit-text-fill-color:currentColor;color:var(--text)}
}

/* ── Keyboard focus ring — site-wide a11y (2026-07-18). :focus-visible fires ONLY on keyboard nav,
   never on mouse click, so this gives keyboard users a clear ring without affecting pointer users.
   Bare pseudo-class → covers every focusable element (buttons, links, inputs, tabs, [tabindex]). ── */
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
