/* ============================================================
   BINNACLE · design tokens
   A reusable house style. Drop into any project, keep the
   principles, swap only the accent if a subject demands it.
   Fonts: Space Grotesk (display) · Inter (UI) · IBM Plex Mono (data)
   ============================================================ */

:root{
  /* ---- surfaces (instrument-panel dark) ---- */
  --ink:      #0E1419;   /* app background / desk surface   */
  --panel:    #151E27;   /* raised section card             */
  --panel-2:  #1B2731;   /* input control / inset field     */
  --well:     #101922;   /* recessed well / code / console  */

  /* ---- structure ---- */
  --line:     #26333E;   /* hairline divider                */
  --line-2:   #334353;   /* stronger border / control edge  */

  /* ---- accents ---- */
  --amber:      #E8A33D; /* PRIMARY — the action you're taking now, focus, the signature */
  --amber-soft: #F0C079; /* amber text on dark / hover       */
  --cyan:       #4FD1C5; /* GOOD-STATE — done, verified, active, links */
  --cyan-dim:   #2E7E77; /* cyan borders / de-emphasised     */
  --neutral:    #8FA0AE; /* HELD — paused, stalled, queued, disabled, skipped */
  --neutral-dim:#4A5A68; /* neutral borders / hatching       */
  --danger:     #E06C5A; /* ERROR / missing only — use sparingly */

  /* ---- text ramp ---- */
  --text:    #E7EEF4;    /* primary text                    */
  --muted:   #93A4B2;    /* secondary text                  */
  --muted-2: #67798A;    /* captions, labels, disabled      */

  /* ---- type roles ---- */
  --font-disp: "Space Grotesk", system-ui, sans-serif;   /* headings, product name, big numbers */
  --font-ui:   "Inter", system-ui, sans-serif;           /* body, labels, everything UI */
  --font-mono: "IBM Plex Mono", ui-monospace, monospace; /* data, code, times, paths, hex */

  /* ---- type scale ---- */
  --t-display: 76px;  /* hero / cover only        */
  --t-h2:      22px;
  --t-h3:      15px;
  --t-body:    14px;
  --t-small:   12.5px;
  --t-label:   11px;  /* uppercase eyebrows/labels, track +0.14–0.18em */

  /* ---- radius ---- */
  --r-card:  10px;
  --r-ctrl:  8px;
  --r-pill:  20px;

  /* ---- spacing base (4px grid) ---- */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px;
  --sp-4: 16px; --sp-5: 20px; --sp-6: 26px;

  /* ---- motion ---- */
  --ease: cubic-bezier(.2,.7,.3,1);
  --dur:  .15s;
}

/* ============================================================
   BASE COMPONENTS — the recurring grammar
   ============================================================ */

body{
  background:var(--ink); color:var(--text);
  font-family:var(--font-ui); line-height:1.6;
  -webkit-font-smoothing:antialiased;
}

/* section card: header with a mono index + tracked label, then body */
.card{ background:var(--panel); border:1px solid var(--line); border-radius:var(--r-card); }
.card > .card-h{
  display:flex; align-items:center; gap:10px;
  padding:12px 16px; border-bottom:1px solid var(--line);
}
.card-h .idx{ font-family:var(--font-mono); font-size:11px; color:var(--amber); opacity:.85; }
.card-h .k{ font-size:11px; letter-spacing:.18em; text-transform:uppercase;
  color:var(--muted-2); font-weight:700; }

/* eyebrow / field label */
.label{ font-size:var(--t-label); letter-spacing:.16em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600; }

/* recessed well — for code, consoles, command previews */
.well{ background:var(--well); border:1px solid var(--line);
  border-radius:var(--r-ctrl); font-family:var(--font-mono); font-size:11.5px;
  color:#CBD8E1; padding:12px 14px; }

/* status pill
   NB: every state carries a glyph as well as a colour. State must never be
   signalled by hue alone — it has to survive colour-blindness and greyscale. */
.pill{ display:inline-flex; align-items:center; gap:6px;
  font-family:var(--font-mono); font-size:11.5px; color:var(--muted);
  border:1px solid var(--line-2); border-radius:var(--r-pill);
  padding:4px 11px; background:var(--well); }
.pill.ok   { color:var(--cyan);    border-color:rgba(79,209,197,.28);  background:rgba(79,209,197,.08); }
.pill.now  { color:var(--amber);   border-color:rgba(232,163,61,.28);  background:rgba(232,163,61,.08); }
.pill.held { color:var(--neutral); border-color:var(--neutral-dim);    background:rgba(143,160,174,.07); }
.pill.bad  { color:var(--danger);  border-color:rgba(224,108,90,.28);  background:rgba(224,108,90,.08); }
/* glyph pairing — the redundant channel */
.pill.ok::before  { content:"✓"; }
.pill.now::before { content:"▶"; font-size:9px; }
.pill.held::before{ content:"⏸"; }
.pill.bad::before { content:"✕"; }

/* buttons — two tiers only: ghost (secondary) + primary (the one action) */
.btn-ghost{ background:transparent; border:1px solid var(--line-2); color:var(--muted);
  padding:10px 17px; border-radius:var(--r-ctrl); font-size:var(--t-small);
  cursor:pointer; transition:var(--dur) var(--ease); }
.btn-ghost:hover{ color:var(--text); border-color:var(--muted-2); }
.btn-primary{ background:linear-gradient(180deg,var(--amber),#D48F2A); color:#1A1206;
  padding:10px 22px; border-radius:var(--r-ctrl); font-size:var(--t-small); font-weight:700;
  cursor:pointer; box-shadow:0 8px 22px -8px rgba(232,163,61,.55); }

/* progress — amber means in-progress, the thing happening now */
.bar{ height:7px; background:var(--well); border-radius:5px; overflow:hidden; }
.bar > i{ display:block; height:100%; border-radius:5px;
  background:linear-gradient(90deg,var(--amber),var(--amber-soft)); }
/* held: drains to neutral and hatches, so "stopped" reads without colour */
.bar.held > i{ background:repeating-linear-gradient(45deg,
  var(--neutral-dim) 0 5px, transparent 5px 10px), var(--neutral); }

/* focus — always visible, part of the quality floor */
:focus-visible{ outline:2px solid var(--amber); outline-offset:2px; }

@media (prefers-reduced-motion: reduce){
  *{ animation:none !important; transition:none !important; }
}

/* ============================================================
   GLYPHS
   Load binnacle-glyphs.svg once per page, then reference.
   Inherits currentColor, so theme + vision profile apply free.
     <svg class="gl"><use href="#gl-done"/></svg>
   ============================================================ */
.gl{ width:1em; height:1em; flex:none; color:inherit; vertical-align:-.125em; }
.gl-lg{ width:1.5em; height:1.5em; }

/* ============================================================
   FORM CONTROLS
   Function first: use the control that fits the task. These are
   the shared skin so any control that appears looks native here.
   ============================================================ */
.field{
  width:100%; background:var(--panel-2); color:var(--text);
  border:1px solid var(--line-2); border-radius:var(--r-ctrl);
  padding:10px 13px; font-family:var(--font-ui); font-size:var(--t-body);
}
.field::placeholder{ color:var(--muted-2); }
.field:hover{ border-color:var(--muted-2); }
.field:disabled{ color:var(--muted-2); background:var(--well); cursor:not-allowed; }
/* paths, hex, times, code — machine data reads mono */
.field.mono{ font-family:var(--font-mono); font-size:var(--t-small); }
/* invalid pairs colour with a glyph, per §02 */
.field[aria-invalid="true"]{ border-color:var(--danger); }

.field-label{ display:block; font-size:var(--t-label); letter-spacing:.16em;
  text-transform:uppercase; color:var(--muted-2); font-weight:600; margin-bottom:7px; }
.field-hint{ font-size:11.5px; color:var(--muted-2); margin-top:6px; }
.field-error{ font-size:11.5px; color:var(--danger); margin-top:6px;
  display:flex; align-items:center; gap:6px; }

/* checkbox / radio — square vs round is the shape cue for
   multi-select vs single-select. Never restyle one to look like the other. */
.check, .radio{
  appearance:none; width:18px; height:18px; flex:none; cursor:pointer;
  background:var(--panel-2); border:1.5px solid var(--line-2);
  display:inline-grid; place-content:center;
}
.check{ border-radius:5px; }
.radio{ border-radius:50%; }
.check:checked, .radio:checked{ background:var(--amber); border-color:var(--amber); }
.check:checked::before{ content:"✓"; color:var(--ink); font-size:12px; font-weight:700; }
.radio:checked::before{ content:""; width:7px; height:7px; border-radius:50%; background:var(--ink); }
.check:disabled, .radio:disabled{ opacity:.45; cursor:not-allowed; }

/* switch — for immediate on/off, not for form submission */
.switch{ appearance:none; width:36px; height:20px; border-radius:12px; flex:none;
  background:var(--neutral-dim); position:relative; cursor:pointer; transition:var(--dur) var(--ease); }
.switch::after{ content:""; position:absolute; top:2px; left:2px; width:16px; height:16px;
  border-radius:50%; background:var(--text); transition:var(--dur) var(--ease); }
.switch:checked{ background:var(--cyan-dim); }
.switch:checked::after{ left:18px; }

/* ============================================================
   LOADING · EMPTY · SKELETON

   Derived from the tenets, not invented:
     "Show the work"  -> prefer DETERMINATE progress. A real
        percentage or count beats a spinner. Use the
        indeterminate bar only when duration is genuinely
        unknowable, and always pair it with a label saying
        what is happening.
     "Neutral = held" -> skeletons are neutral, never amber.
        A skeleton is content that exists but has not arrived:
        real, but not moving.
     Empty states invite action (§08) — they do not set a mood.
   ============================================================ */

/* skeleton — neutral, quiet, no shimmer by default */
.skel{ background:var(--neutral-dim); opacity:.35; border-radius:6px; }
.skel-text{ height:.85em; margin:.35em 0; }
.skel-text.short{ width:45%; }
@media (prefers-reduced-motion: no-preference){
  .skel.shimmer{
    background:linear-gradient(90deg,var(--neutral-dim) 25%,
      color-mix(in srgb,var(--neutral) 35%,transparent) 50%,var(--neutral-dim) 75%);
    background-size:200% 100%; animation:skel-slide 1.4s linear infinite;
  }
}
@keyframes skel-slide{ to{ background-position:-200% 0; } }

/* indeterminate bar — last resort, when no real progress exists */
.bar.indeterminate > i{ width:35%; animation:bar-slide 1.25s var(--ease) infinite; }
@keyframes bar-slide{ 0%{ margin-left:-35%; } 100%{ margin-left:100%; } }

/* empty state — a prompt, not a shrug */
.empty{ text-align:center; padding:36px 24px; color:var(--muted); }
.empty .gl{ width:26px; height:26px; color:var(--muted-2); margin-bottom:10px; }
.empty .t{ font-family:var(--font-disp); font-size:15px; color:var(--text); margin-bottom:4px; }
.empty .d{ font-size:var(--t-small); max-width:44ch; margin:0 auto 14px; }

/* ============================================================
   RESPONSIVE
   Three widths. Deliberately coarse — the goal is usable on as
   many screens as possible, not pixel-perfect on all of them.

     wide   >1000px   full density, side-by-side
     mid    640-1000   multi-column grids collapse to one
     narrow <640px    single column; tables scroll

   Collapse order when space runs out (drop in this order):
     1. decorative padding      2. multi-column grids
     3. secondary metadata      4. inline labels -> icons
   Never drop: the primary action, state glyphs, or the
   command/data preview. Those are the point.
   ============================================================ */
@media (max-width:1000px){
  .cols, .swatches, .accentrule{ grid-template-columns:1fr 1fr !important; }
  .card > .card-h{ padding:11px 13px; }
}
@media (max-width:640px){
  :root{ --t-display:44px; --t-h2:19px; }
  .cols, .swatches, .accentrule{ grid-template-columns:1fr !important; }
  .card > .card-h{ padding:10px 12px; }
  /* dense tables get a scroll rail rather than being crushed */
  .table-wrap{ overflow-x:auto; -webkit-overflow-scrolling:touch; }
  .btn-primary, .btn-ghost{ padding:12px 18px; }  /* touch target >=44px */
  .field{ font-size:16px; }  /* prevents iOS zoom-on-focus */
}

/* ============================================================
   THEMES & VISION PROFILES

   Every value below is contrast-audited. Minimum AA (4.5:1) for
   all text and accents against their own surface; most are AAA.

   Usage:  <html data-theme="light" data-vision="tritan">
           (no attribute = dark, the default)
   ============================================================ */

/* ---- MEDIUM — mid-tone surface, softened contrast ----
   For rooms/screens where full dark is too stark but light is
   too bright. Accents survive the lift; only muted-2 and danger
   needed raising to clear AA against the lighter panel. */
[data-theme="medium"]{
  --ink:#232F3A;  --panel:#2C3A47;  --panel-2:#354553;  --well:#1C2833;
  --line:#3E4E5C; --line-2:#4E6070;
  --text:#EDF3F8; --muted:#B6C6D2;  --muted-2:#9EB0BF;
  --amber:#E8A33D;   --amber-soft:#F3C68A;
  --cyan:#5AD8CC;    --cyan-dim:#3E9A92;
  --neutral:#A6B6C3; --neutral-dim:#5E7080;
  --danger:#F2907E;
}

/* ---- LIGHT — light surface, dark ink ----
   NOT an inversion. The dark accents fail badly on white
   (amber 2.16:1, cyan 1.87:1), so both are darkened
   substantially. amber-soft inverts its role here: on dark it
   was the lighter amber, on light it must be the *darker* one. */
[data-theme="light"]{
  --ink:#EEF2F6;  --panel:#FFFFFF;  --panel-2:#F3F6F9;  --well:#E9EEF3;
  --line:#D4DDE5; --line-2:#B9C6D1;
  --text:#0E1419; --muted:#4A5A68;  --muted-2:#65788A;
  --amber:#8A5D10;   --amber-soft:#6E4A0C;
  --cyan:#186059;    --cyan-dim:#8FBFB9;
  --neutral:#5A6B79; --neutral-dim:#A8B6C1;
  --danger:#A32C1A;
}
/* the amber fill is dark in light mode, so its label flips to white */
[data-theme="light"] .btn-primary{
  background:linear-gradient(180deg,#8A5D10,#734B0B); color:#FFFFFF;
  box-shadow:0 8px 22px -10px rgba(138,93,16,.5);
}

/* ---- CONTRAST — low-vision profile ----
   True-black surface, brightened accents, stronger borders.
   Everything clears AAA (worst pairing 8.62:1). */
[data-theme="contrast"]{
  --ink:#000000;  --panel:#0A0F14;  --panel-2:#141C24;  --well:#05080B;
  --line:#5A6E7E; --line-2:#8098AC;
  --text:#FFFFFF; --muted:#DCE7EF;  --muted-2:#BCCCD8;
  --amber:#FFC061;   --amber-soft:#FFD79A;
  --cyan:#7BEFE3;    --cyan-dim:#4FB3A8;
  --neutral:#B8C7D3; --neutral-dim:#7A8B99;
  --danger:#FF8E7A;
}
[data-theme="contrast"] :focus-visible{ outline-width:3px; }

/* ============================================================
   VISION PROFILES — colour-vision deficiency

   MEASURED, not guessed: these were tuned against a
   Viénot/Brettel LMS simulation.

   The finding that shaped them: under deuteranopia the default
   amber and cyan simulate to #BEBE34 and #B3B3C7 — a separation
   of 1.04, i.e. near-identical. Hue cannot be recovered, so the
   only channel left is LIGHTNESS. Both profiles therefore push
   cyan much lighter rather than merely shifting its hue.

   Even tuned, red-green separation only reaches ~1.45. That is
   an improvement, not a solution — which is precisely why the
   glyph pairing on .pill is load-bearing rather than decorative.
   ============================================================ */

/* red–green (most common). amber/cyan 1.04 -> 1.45; danger moves
   off red toward magenta so it stops colliding with amber. */
[data-vision="deutan"], [data-vision="protan"]{
  --amber:#EA9F3E;  --amber-soft:#F5C489;
  --cyan:#ADEBE5;   --cyan-dim:#5F9C96;
  --danger:#DD5F7F;
}

/* blue–yellow. amber warms toward orange-red, cyan lightens.
   amber/cyan 1.16 -> 1.64. */
[data-vision="tritan"]{
  --amber:#ED9E5A;  --amber-soft:#F6C39A;
  --cyan:#ADEBE5;   --cyan-dim:#5F9C96;
  --danger:#DD5F63;
}
