/* ═══════════════════════════════════════════════════════════════════════════════
   Palette — surfaces and status colour for the console.

   WHAT WAS WRONG. Two things, and they had the same root cause: both were defaults
   rather than decisions.

   The status chips used stock web colours — #4ade80, #e0b341, #60a5fa — which are all
   different lightnesses and all fairly saturated, so a card with three of them read as
   three unrelated stickers. And the surfaces were pure neutral grey (#0f0f0f on #0a0a0a)
   separated by a LIGHTER border, which is the one combination that always looks unfinished
   on dark: a flat panel outlined in a brighter line reads as a wireframe of a card rather
   than a card.

   THE FIX IS A SYSTEM, NOT NEW SWATCHES.

   1. Every status hue is derived at ONE lightness and ONE chroma, varying only in hue.
      That is what makes them look like a family: green, amber, red and blue that
      obviously belong to each other because perceptually they differ in nothing but
      colour. Values are pinned as hex rather than computed so they are identical in every
      browser, but they came from oklch(78% 0.125 H) — the H is the only thing that moves.

   2. Surfaces get a hint of the accent's own hue instead of being neutral. It is small
      enough that nobody will say "the cards are blue" and large enough that the greys
      stop looking like an unstyled default.

   3. Cards are LIT FROM ABOVE rather than outlined. A one-pixel highlight along the top
      edge, a barely-there vertical gradient, and a soft shadow beneath. The border stays,
      but it is now DARKER than the surface, not lighter — which is how a raised object
      actually meets the thing behind it. This is the same logic as the glassy buttons and
      the sidebar glass, so the console finally agrees with itself.

   4. Chips become lamps. Translucent tinted fill, a hairline ring of their own hue, and
      the dot gets an actual glow instead of being a flat circle. Same idea as the upload
      beam: a small bright core with a halo around it.

   Loaded after every page's own <style> in the head — but dashboard.html declares some of
   these inside a <style> in the BODY, which lands after every head <link>. So the card and
   chip rules carry a :root prefix: one extra level of specificity, which beats a bare class
   from anywhere without reaching for !important.
   ═══════════════════════════════════════════════════════════════════════════════ */

:root{
  /* ── Status family. oklch(78% 0.125 H); only H differs. ────────────────────── */
  --ok:#4fd6a0;      /* H 162 */
  --warn:#e0b25f;    /* H 75  */
  --danger:#f58e86;  /* H 24  */
  --blue:#8ab2fb;    /* H 262 */

  /* Washes and rings, derived from the hue above so a new hue needs no new constants.
     12% reads as tinted, not filled; 26% is a hairline that describes an edge without
     drawing attention to it. */
  --ok-dim:color-mix(in oklab, var(--ok) 13%, transparent);
  --ok-line:color-mix(in oklab, var(--ok) 26%, transparent);
  --warn-dim:color-mix(in oklab, var(--warn) 13%, transparent);
  --warn-line:color-mix(in oklab, var(--warn) 26%, transparent);
  --danger-dim:color-mix(in oklab, var(--danger) 13%, transparent);
  --danger-line:color-mix(in oklab, var(--danger) 26%, transparent);
  --blue-dim:color-mix(in oklab, var(--blue) 13%, transparent);
  --accent-dim:color-mix(in oklab, var(--accent) 13%, transparent);
  --accent-line:color-mix(in oklab, var(--accent) 30%, transparent);

  /* ── Surfaces. Cool by a few degrees, never blue. ──────────────────────────── */
  --bg:#0a0a0c;
  --bg-raised:#101014;
  --bg-input:#141419;
  --bg-hover:#17171d;
  --bg-code:#0c0c10;
  --card-bg:#101014;

  /* The border is DARKER than the card it bounds — a raised thing casts its edge into
     shadow, it does not outline itself in white. The top highlight below does the
     opposite job on the opposite edge, and between them the card has a direction. */
  --line:#1a1a20;
  --line-strong:#24242c;
  --card-line:#08080a;
  --card-top:rgba(255,255,255,.055);
  --shadow-card:0 1px 2px rgba(0,0,0,.4), 0 10px 26px -8px rgba(0,0,0,.5);

  --fg:#f7f7f9;
  --fg-muted:#9091a0;
  --fg-dim:#5f606e;
  /* Text ON an accent fill. Dark scheme uses a light blue, so the label must be DARK;
     light scheme uses a deep blue, so it must be WHITE. Never hardcode either — .hw-btn
     carried color:#fff in a style block that loaded after buttons.css, so two accent
     buttons could sit in one card with opposite label colours. */
  --on-accent:#07101f;
}

@media (prefers-color-scheme: light){
  :root{
    /* Same hues, dropped to oklch(56% 0.13 H) so they carry on white. */
    --ok:#12996a;
    --warn:#9a6c12;
    --danger:#cf4a41;
    --blue:#2f6ae0;

    --bg:#f5f6f8;
    --bg-raised:#ffffff;
    --bg-input:#f8f9fb;
    --bg-hover:#eef0f4;
    --bg-code:#f3f4f7;
    --card-bg:#ffffff;

    /* On light the border is the DARKER of the two again — same rule, inverted context. */
    --line:#e7e9ee;
    --line-strong:#d6d9e1;
    --card-line:#dfe2e9;
    --card-top:rgba(255,255,255,.9);
    --shadow-card:0 1px 2px rgba(17,24,39,.05), 0 8px 22px -10px rgba(17,24,39,.14);

    --fg:#14161c;
    --fg-muted:#5a616e;
    --fg-dim:#969cab;
    --on-accent:#ffffff;
  }
}

/* ── Cards ────────────────────────────────────────────────────────────────────
   The gradient is deliberately almost invisible — about 2% at the top. Any more and it
   becomes a "gradient card", which dates instantly. The work is done by the 1px inset
   highlight, which is what tells the eye where the light is. */
:root .card, :root .set-block, :root .hw-tile, :root .selfhost-card, :root .proj-card{
  background:linear-gradient(180deg,
    color-mix(in oklab, var(--card-bg) 97%, white) 0%,
    var(--card-bg) 58%);
  border:1px solid var(--card-line);
  box-shadow:inset 0 1px 0 0 var(--card-top), var(--shadow-card);
}

/* Rows sit INSIDE cards, so they get the same treatment an octave quieter — no shadow of
   their own, or a list of eight starts to look like a stack of floating panels. */
:root .hw-row{
  background:linear-gradient(180deg,
    color-mix(in oklab, var(--bg-raised) 97%, white) 0%,
    var(--bg-raised) 60%);
  border:1px solid var(--card-line);
  box-shadow:inset 0 1px 0 0 color-mix(in oklab, var(--card-top) 60%, transparent);
}
:root .hw-row:hover{ border-color:var(--line-strong); }

/* THE CURRICULUM LESSON IS THE SAME OBJECT AS EVERY OTHER ROW.
   It never got this treatment, so a course's most-edited screen was the one list on the
   console rendered flat: a hairline of --line instead of --card-line, no gradient, no top
   highlight. Next to member uploads and form submissions — which are lit — the lessons
   read as disabled, and the titles read as grey even though .les-title and .r-name are
   the identical colour and weight. The difference was never the text; it was that the
   surface under it was not catching any light.

   Same rule as .hw-row, applied to .les, so the two cannot drift again. */
:root .les{
  background:linear-gradient(180deg,
    color-mix(in oklab, var(--bg-raised) 97%, white) 0%,
    var(--bg-raised) 60%);
  border:1px solid var(--card-line);
  box-shadow:inset 0 1px 0 0 color-mix(in oklab, var(--card-top) 60%, transparent);
}
:root .les:hover{ border-color:var(--line-strong); }
/* An open lesson is a panel, not a row — it has a form inside it. Let it sit slightly
   prouder so the thing being edited is obviously the thing in front. */
:root .les.open{ border-color:var(--line-strong);box-shadow:inset 0 1px 0 0 var(--card-top), var(--shadow-card); }

/* ── The row you are actually dragging ────────────────────────────────────────
   Opacity alone said "this is being moved" by making it look switched off, which is the
   same signal this console uses for disabled. A ring says it instead: the row stays
   fully legible — you need to read it to know where to drop it — and gains an accent
   outline plus a lifted shadow, so it reads as picked UP rather than faded OUT. */
:root .les.drag-src{
  opacity:1;
  border-color:var(--accent);
  box-shadow:0 0 0 1px var(--accent), var(--shadow-card);
}
/* A whole module can be dragged too, by the handle in its heading. Same language. */
:root .cur-mod.drag-src{
  opacity:1;
  border-color:var(--accent);
  box-shadow:0 0 0 1px var(--accent), var(--shadow-card);
}

/* ── Chips, as lamps ──────────────────────────────────────────────────────────
   Tinted wash, hairline ring of the same hue, and a dot that actually emits. currentColor
   throughout, so one rule serves every variant and a new status needs no new CSS. */
:root .badge, :root .hw-chip, :root .mode-chip, :root .status-pill{
  background:color-mix(in oklab, currentColor 13%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in oklab, currentColor 22%, transparent);
  border:0;
}
:root .badge .dot, :root .hw-chip .dot, :root .mode-chip .dot, :root .status-pill .dot, :root .chip .dot{
  background:currentColor;
  /* The glow is the whole point — a flat circle is a bullet, this is a lamp. Two stops so
     it has a core and a falloff, like every other light in this console. */
  box-shadow:0 0 4px color-mix(in oklab, currentColor 85%, transparent),
             0 0 9px color-mix(in oklab, currentColor 45%, transparent);
}
/* The neutral chip must NOT glow: "not started" is the absence of a state, and a lamp
   that is lit to say nothing is happening is a contradiction. */
:root .badge.dim, :root .mode-chip.off, :root .status-pill.off{
  color:var(--fg-dim);
  background:color-mix(in oklab, var(--fg-dim) 10%, transparent);
  box-shadow:inset 0 0 0 1px var(--line-strong);
}
:root .badge.dim .dot, :root .mode-chip.off .dot, :root .status-pill.off .dot{ box-shadow:none; opacity:.75; }

/* Variants only assign the hue now; the shape and the glow come from the rules above. */
:root .badge.ok, :root .hw-chip.ok, :root .mode-chip.live, :root .mode-chip.role, :root .status-pill.on{ color:var(--ok); }
:root .badge.warn, :root .hw-chip.warn, :root .mode-chip.setup{ color:var(--warn); }
:root .badge.test, :root .mode-chip.link{ color:var(--blue); }
:root .badge.err, :root .status-pill.err{ color:var(--danger); }

@media (prefers-reduced-transparency: reduce){
  /* color-mix against transparent is still a solid composite here, but the dot glow is
     pure decoration and the first thing to go. */
  :root .badge .dot, :root .hw-chip .dot, :root .mode-chip .dot, :root .status-pill .dot{ box-shadow:none; }
}

/* ═══════════════════════════════════════════════════════════════════════════════
   Controls — the surfaces the palette above hadn't reached yet.

   The tokens changed everywhere at once, but anything that drew its own box rather than
   using --card-bg kept its old shape: Plan & Billing, the setup steps, the segmented
   switches, the toggles, the inputs. They were the right COLOUR and the wrong SURFACE,
   which is the most obviously unfinished state of all — near enough to look intentional,
   off enough to look broken.

   Everything below reuses exactly the two ideas already established, and adds none:
   lit from above (1px top highlight + darker border + soft shadow) for raised things,
   and recessed (inset shadow, no highlight) for things you type or choose inside.
   ═══════════════════════════════════════════════════════════════════════════════ */

/* ── Cards that draw their own box ────────────────────────────────────────────
   Billing panels and setup steps, brought onto the same surface as every other card. */
:root .bm-card,
:root .step,
:root .setup-choice{
  background:linear-gradient(180deg,
    color-mix(in oklab, var(--card-bg) 97%, white) 0%,
    var(--card-bg) 58%);
  border:1px solid var(--card-line);
  box-shadow:inset 0 1px 0 0 var(--card-top), var(--shadow-card);
}
:root .setup-choice:hover{ border-color:var(--accent-line); }

/* ── Fields ───────────────────────────────────────────────────────────────────
   RECESSED, the exact inverse of a card: the highlight moves to the bottom edge and a
   soft inset shadow sits under the top, so a field reads as cut into the surface rather
   than sitting on it. That contrast is what makes a form legible at a glance — raised
   things are pressable, sunken things are fillable. */
:root .hw-input,
:root .email-field input,
:root .field input,
:root .field select,
:root .field textarea,
:root input[type="text"],
:root input[type="email"],
:root input[type="url"],
:root input[type="password"],
:root input[type="number"],
:root textarea,
:root select{
  background:var(--bg-input);
  border:1px solid var(--card-line);
  box-shadow:inset 0 1px 2px 0 rgba(0,0,0,.28), inset 0 -1px 0 0 var(--card-top);
  transition:border-color .14s, box-shadow .14s;
}
@media (prefers-color-scheme: light){
  :root .hw-input, :root .email-field input, :root .field input, :root .field select,
  :root .field textarea, :root input[type="text"], :root input[type="email"],
  :root input[type="url"], :root input[type="password"], :root input[type="number"],
  :root textarea, :root select{
    border-color:var(--line-strong);
    box-shadow:inset 0 1px 2px 0 rgba(17,24,39,.06);
  }
}
:root .hw-input:focus, :root .email-field input:focus, :root .field input:focus,
:root .field select:focus, :root .field textarea:focus, :root input:focus, :root textarea:focus,
:root select:focus{
  outline:none;
  border-color:var(--accent-line);
  /* A ring rather than a glow — a field that blooms competes with the buttons, which are
     the only things here allowed to throw light. */
  box-shadow:inset 0 1px 2px 0 rgba(0,0,0,.24), 0 0 0 3px var(--accent-dim);
}
:root input.invalid, :root .email-field input.invalid{ border-color:var(--warn-line); }

/* ── Segmented switches (Manual/Autopilot, Lemon Squeezy/Stripe) ──────────────
   The track is recessed like a field; the selected thumb is raised like a small card.
   That is the whole metaphor — one option is lifted out of a groove — and it costs one
   inset shadow plus one highlight. */
:root .seg, :root #setupToggle, :root #ppToggle{
  background:var(--bg-input);
  border:1px solid var(--card-line);
  box-shadow:inset 0 1px 2px 0 rgba(0,0,0,.26);
}
/* The THUMB, wherever it is drawn — a real pseudo-element on the two toggles that
   slide, and the selected button itself on .seg, which has no thumb of its own.
   #setupToggle's selected button is deliberately absent: it now has a sliding ::before
   doing the drawing, and painting both would leave a stationary block behind the thumb. */
:root .seg button.on,
:root .seg .seg-pill,
:root #setupToggle::before,
:root #ppToggle::before{
  background:linear-gradient(180deg,
    color-mix(in oklab, var(--bg-raised) 94%, white) 0%,
    var(--bg-raised) 100%);
  box-shadow:inset 0 1px 0 0 var(--card-top), 0 1px 2px rgba(0,0,0,.34);
}

/* ── Toggles ──────────────────────────────────────────────────────────────────
   Same two ideas again: the track is a groove, the knob is a raised thing in it. On is
   the only place a control is allowed to glow, and it is a small one — this switch turns
   a Worker on, so it should read as live without becoming the brightest thing on screen. */
:root .switch .slider{
  background:var(--bg-input);
  border:1px solid var(--card-line);
  box-shadow:inset 0 1px 2px 0 rgba(0,0,0,.3);
}
:root .switch .slider:before{
  background:linear-gradient(180deg, color-mix(in oklab, var(--fg-muted) 92%, white), var(--fg-muted));
  box-shadow:0 1px 2px rgba(0,0,0,.4), inset 0 1px 0 rgba(255,255,255,.25);
}
:root .switch input:checked + .slider{
  background:color-mix(in oklab, var(--accent) 22%, transparent);
  border-color:var(--accent-line);
  box-shadow:inset 0 1px 2px 0 rgba(0,0,0,.22);
}
:root .switch input:checked + .slider:before{
  background:linear-gradient(180deg, color-mix(in oklab, var(--accent) 88%, white), var(--accent));
  box-shadow:0 1px 3px rgba(0,0,0,.4),
             0 0 8px color-mix(in oklab, var(--accent) 45%, transparent),
             inset 0 1px 0 rgba(255,255,255,.35);
}

/* ── Billing buttons ──────────────────────────────────────────────────────────
   Resume plan and Update card were their own species. They are buttons; they get the
   button treatment, primary and ghost, from buttons.css semantics. */
:root .bm-btn{
  border-radius:10px; font-weight:600; font-family:var(--font);
  background:var(--accent); color:var(--on-accent); border:1px solid transparent;
  box-shadow:inset 0 1px 0 0 rgba(255,255,255,.45),
             inset 0 -1px 2px 0 rgba(0,0,0,.12),
             0 5px 14px -2px color-mix(in srgb, var(--accent) 40%, transparent);
  transition:box-shadow .16s var(--ease-out, cubic-bezier(.22,.61,.36,1)), filter .16s ease, transform .1s ease;
}
:root .bm-btn:hover:not(:disabled){
  filter:brightness(1.06);
  box-shadow:inset 0 1px 0 0 rgba(255,255,255,.5),
             inset 0 -1px 2px 0 rgba(0,0,0,.12),
             0 8px 20px -2px color-mix(in srgb, var(--accent) 52%, transparent);
}
:root .bm-btn:active:not(:disabled){
  transform:translateY(1px); filter:brightness(.98);
  box-shadow:inset 0 2px 4px 0 rgba(0,0,0,.18), inset 0 1px 0 0 rgba(255,255,255,.18);
}
/* Ghost and warn keep the bevel and drop the bloom — the glow marks the primary action,
   and "Cancel plan" is never that. */
:root .bm-btn.ghost, :root .bm-btn.warn{
  background:var(--bg-input); color:var(--fg);
  border:1px solid var(--line-strong);
  box-shadow:inset 0 1px 0 0 rgba(255,255,255,.06),
             inset 0 -1px 2px 0 rgba(0,0,0,.14),
             0 1px 2px 0 rgba(0,0,0,.18);
}
:root .bm-btn.warn{ color:var(--warn); border-color:var(--warn-line); }
:root .bm-btn.ghost:hover:not(:disabled), :root .bm-btn.warn:hover:not(:disabled){
  filter:none; background:var(--bg-hover);
  box-shadow:inset 0 1px 0 0 rgba(255,255,255,.09), inset 0 -1px 2px 0 rgba(0,0,0,.14), 0 2px 6px 0 rgba(0,0,0,.22);
}

/* ── Setup-step icons ─────────────────────────────────────────────────────────
   Sized and muted to sit with the label rather than compete with it; the active step
   lights its icon, which is the one place the nav says "you are here" twice. */
:root .nav-item .setup-ico{ width:15px; height:15px; flex:0 0 15px; display:inline-flex;
  color:var(--fg-dim); transition:color .12s; }
:root .nav-item .setup-ico svg{ width:15px; height:15px; display:block; }
:root .nav-item:hover .setup-ico{ color:var(--fg-muted); }
:root .nav-item.active .setup-ico{ color:var(--accent); }


/* ── Inline code inside steps ─────────────────────────────────────────────────
   These are UI directions — "go to Storage & databases, then R2" — so the boxed words
   are the parts you go and look for on someone else's screen. They were --bg-input on a
   card, which in light mode is a visible chip and in dark mode is a 4% difference
   nobody can see: the emphasis simply vanished in the theme most people use.

   Given a surface of its own instead. A tinted accent wash with a hairline ring reads as
   a distinct object at any brightness, and it borrows the colour already used for "this
   is a thing you act on" rather than inventing a highlight. */
:root .step-body code,
:root .step code,
:root .sb-desc code,
:root .hw-desc code,
:root .guide-body code{
  /* MONOCHROME ON PURPOSE. These were accent fill, accent border and accent text, which
     is the console's link vocabulary — so `yourcourse.com` in a sentence read as
     something to click, and the sentence around it grew a row of fake links. A code chip
     is a QUOTATION: it marks "this exact string", and it should recede.

     Everything is mixed from --fg rather than a fixed grey, which is what makes one
     declaration correct in both schemes: --fg is near-white on the dark page, so the
     wash lifts AWAY from a dark background, and near-black on the light page, so the
     same percentage darkens away from a white one. Deviation from the surface in the
     right direction, automatically, including on cards that are not the page colour. */
  background:color-mix(in oklab, var(--fg) 10%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in oklab, var(--fg) 22%, transparent);
  color:var(--fg);
  border-radius:5px;
  padding:1.5px 6px;
  font-weight:550;
  white-space:nowrap;
}
@media (prefers-color-scheme: light){
  :root .step-body code, :root .step code, :root .sb-desc code,
  :root .hw-desc code, :root .guide-body code{
    /* A touch more fill and a touch less border on white: the same alpha reads lighter
       against a pale surface, and a 22% edge on white is a harder line than it is on
       black. */
    background:color-mix(in oklab, var(--fg) 7%, transparent);
    box-shadow:inset 0 0 0 1px color-mix(in oklab, var(--fg) 17%, transparent);
  }
}
