/* Cyberpunk — a theme file. See themes/README.md for the contract.
   Loaded AFTER public/css/styles.css, so it wins on source order with no
   !important anywhere.

   Derived from the project's published status artifact — and since 2026-08-29
   deliberately matched to it, because the maintainer asked for the two to look
   like one product. See "MATCHING THE MINION DASHBOARD" at the foot of this file.

   IT HAS BOTH VARIANTS NOW. It was dark-only until 2026-08-29 on the reasoning
   that "a light neon interface is not the thing that was asked for" — then it was
   asked for. The light variant is at the foot of this file and is not an
   inversion: neon does not exist in daylight, so it is the same duotone read as
   ink on paper. The forcing to data-theme="dark" is gone, and `darkOnly` in the
   pre-paint script in views/partials/header.ejs is now empty.

   THAT REASONING WAS LOAD-BEARING AND STILL EXPLAINS THE DARK VARIANT.
   styles.css carries 43 component rules selected by
   `:root[data-theme="dark"] .x` — status chips, import states, chart bars, flash,
   audit flags. Guaranteeing this theme is always also dark means every one of
   them applies unchanged, so no component can end up unstyled or showing
   light-mode text on a dark ground. This file then overrides only what it means
   to change. In LIGHT those 43 rules simply do not match and the base rules --
   the ones written for a light interface in the first place -- apply instead, so
   the components are not unstyled there either. Nothing had to be duplicated. Duplicating 43 selectors per theme is how a theme system rots: the
   second theme is permanently one component behind and nobody notices until a
   chip is invisible.
*/

/* --------------------------------------------------------------- Cyberpunk --
   Derived from the published status artifact, and the two decisions worth
   keeping are about restraint rather than colour:

   A DUOTONE, not one neon pop against black. Cyan carries structure — headings,
   links, the active nav item, figures — and magenta is reserved for the thing
   that wants acting on. A single accent on near-black is the look every
   generated "cyberpunk" theme lands on, and it gives you nothing to say
   "this one matters" with.

   SEMANTIC COLOUR IS RE-PITCHABLE, AND THIS THEME HAS NOT DONE IT YET. Until
   2026-08-29 the rule was that available/overdue/error keep the app's own
   teal/amber/salmon in every theme. The maintainer reversed that: a theme may
   re-pitch them into its own palette, provided the three tiers stay
   distinguishable from each other, none of them IS the accent, bad still looks
   worse than caution, and each clears 4.5:1 on the table row it sits on. The
   surviving half of the old rule is the second clause — a chip whose colour
   means "on brand" instead of "this is fine" has stopped being information.
   This file still inherits the defaults; re-pitching it is open work. */
:root[data-palette="cyberpunk"] {
  /* The palette itself, named by role so the mappings below read as decisions. */
  --cp-void:      #06090f;
  --cp-ground:    #0a0f18;
  --cp-surface:   #0e1522;
  --cp-surface-2: #131d2e;
  --cp-ink:       #dfeaf6;
  --cp-ink-2:     #93a8c2;
  --cp-ink-3:     #5f7693;
  --cp-rule:      #1c2a3c;
  --cp-rule-firm: #2c4160;
  --cp-cyan:      #2ad4ee;
  --cp-cyan-deep: #0e5f72;
  --cp-cyan-dim:  #0b2f3a;
  --cp-magenta:   #f8479f;

  /* Type. Chakra Petch is angular and technical without being Orbitron, which
     is the face every neon mockup uses. Body stays Karla — it is already loaded,
     it is the most legible thing here, and a dense asset table is read all day.
     JetBrains Mono is for figures, so numbers in a column line up. */
  /* This theme opts into the optional UI sound. public/js/toast.js and
     public/js/themeToggle.js both read this one declaration, so "does this theme
     have sound" is answered in the theme's own file rather than by a list of
     names duplicated across two scripts. Still off until the user turns it on. */
  --theme-sound: 1;
  --theme-voice: console;

  --heading-font-family: 'Chakra Petch', 'Outfit', var(--pico-font-family-sans-serif);
  --cp-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --pico-background-color: var(--cp-ground);
  --pico-color: var(--cp-ink);
  --pico-muted-color: var(--cp-ink-2);
  --pico-h1-color: #fff;
  --pico-h2-color: var(--cp-ink);
  --pico-h3-color: var(--cp-ink);
  --pico-h4-color: var(--cp-ink);
  --pico-h5-color: var(--cp-ink);
  --pico-h6-color: var(--cp-ink);

  --pico-primary: var(--cp-cyan);
  /* THE FILL IS THE BRIGHT CYAN, NOT `--cp-cyan-deep`, AND THAT WAS THE BUG.
     Measured 2026-08-31: the primary button rendered #04121a ink on a #0e5f72
     fill — 2.62:1, against a 4.5:1 floor, on the control that carries the
     primary action on every form in the app.

     The ink was never wrong; the fill token was. The comment below has always
     said "dark text ON the cyan button", which is correct reasoning for a bright
     fill — but `--pico-primary-background` was pointed at `--cp-cyan-deep`, so
     Pico painted a DARK button and then wrote near-black on it. Two decisions
     that are each defensible and cannot both hold.

     Resolved in the direction the comment already intended, which also matches
     the light variant's stated inverse (deep fill + white ink there, bright fill
     + dark ink here) and gives this theme the glowing primary a neon palette
     wants. Re-measured after the change: 10.36:1. */
  --pico-primary-background: var(--cp-cyan);
  --pico-primary-underline: rgba(42, 212, 238, 0.45);
  --pico-primary-hover: #7de6f7;
  /* Hover has to get BRIGHTER now that the base fill is the bright cyan. It was
     #12758c, which is darker than #2ad4ee — with the fill corrected that would
     have made the button dim on hover and dropped the dark ink back toward the
     same failure. */
  --pico-primary-hover-background: #7de6f7;
  --pico-primary-focus: rgba(42, 212, 238, 0.4);
  /* Dark text ON the cyan button: cyan is bright enough that white on it fails
     contrast, which is the usual casualty of a neon primary. */
  --pico-primary-inverse: #04121a;

  --pico-secondary: var(--cp-ink-2);
  --pico-secondary-background: var(--cp-surface-2);
  --pico-secondary-hover: var(--cp-ink);
  --pico-secondary-hover-background: #1b283c;
  --pico-secondary-focus: rgba(147, 168, 194, 0.25);
  --pico-secondary-inverse: var(--cp-ink);

  /* <mark> is the "look here" highlight (expiry dates, overdue marks), so it
     takes the magenta rather than the structural cyan. */
  --pico-mark-background-color: #3c0f27;
  --pico-mark-color: #ffd6ea;

  --pico-card-background-color: var(--cp-surface);
  --pico-card-sectioning-background-color: var(--cp-surface-2);
  --pico-card-border-color: var(--cp-rule-firm);
  --pico-border-color: var(--cp-rule-firm);
  --pico-muted-border-color: var(--cp-rule);

  --pico-form-element-background-color: var(--cp-surface-2);
  --pico-form-element-selected-background-color: var(--cp-surface-2);
  --pico-form-element-border-color: var(--cp-rule-firm);
  --pico-form-element-color: var(--cp-ink);
  --pico-form-element-placeholder-color: var(--cp-ink-3);
  --pico-form-element-active-background-color: var(--cp-surface-2);
  --pico-form-element-active-border-color: var(--cp-cyan);
  --pico-form-element-focus-color: var(--cp-cyan);

  --pico-table-border-color: var(--cp-rule);
  --pico-table-row-stripped-background-color: rgba(42, 212, 238, 0.035);

  --pico-code-background-color: var(--cp-void);
  --pico-code-color: var(--cp-cyan);
  --pico-blockquote-border-color: var(--cp-cyan);
  --pico-dropdown-background-color: var(--cp-surface);
  --pico-dropdown-border-color: var(--cp-rule-firm);
  --pico-dropdown-hover-background-color: var(--cp-surface-2);
  --pico-switch-background-color: var(--cp-rule-firm);
  --pico-switch-checked-background-color: var(--cp-cyan-deep);
  --pico-range-thumb-color: var(--cp-cyan);

  /* The sidebar is the one surface that is already dark in both SCP variants, so
     here it goes DARKER than the page rather than lighter — the page glows and
     the chrome recedes, which is the artifact's arrangement. */
  --sidebar-bg: var(--cp-void);
  --sidebar-ink: var(--cp-ink);
  /* NOT --cp-ink-3, which is this palette's third ink and is tuned for the PAGE.
     On the sidebar it was the worst contrast in the whole theme set: measured
     2026-09-05 across all twelve theme/variant combinations, the group labels
     ("Overview", "Insights", "Admin") came out at 4.27:1 here and 3.73:1 in the
     light variant, both under AA, and both visibly murky in the screenshots.
     --cp-ink-3 is left alone because it is also the form-placeholder colour,
     where it is correct; the sidebar gets its own value against the surface it
     actually sits on. 5.11:1 on --cp-void (#06090f). */
  --sidebar-muted: #6b83a1;
  --sidebar-link: var(--cp-ink-2);
  --sidebar-link-active: #fff;
  --sidebar-hover-bg: var(--cp-surface-2);
  --sidebar-active-bg: var(--cp-cyan-deep);

  --scroll-shadow-color: rgba(42, 212, 238, 0.18);
}

/* Headings get the letter-spacing and weight the face is drawn for. Scoped to
   the palette so Street Culture is untouched. */
:root[data-palette="cyberpunk"] h1,
:root[data-palette="cyberpunk"] h2,
:root[data-palette="cyberpunk"] h3 {
  letter-spacing: 0.01em;
}

:root[data-palette="cyberpunk"] h1 {
  text-shadow: 0 0 24px rgba(42, 212, 238, 0.25);
}

/* Figures in mono with tabular digits: the dashboard tiles and any numeric
   column only read as a column when the digits line up. */
:root[data-palette="cyberpunk"] .stat-tile-value,
:root[data-palette="cyberpunk"] .numeric-input,
:root[data-palette="cyberpunk"] .nowrap {
  font-family: var(--cp-mono);
  font-variant-numeric: tabular-nums;
}

:root[data-palette="cyberpunk"] .stat-tile-value {
  color: var(--cp-cyan);
  text-shadow: 0 0 18px rgba(42, 212, 238, 0.28);
}

/* An uppercase mono label is the artifact's one strong typographic move, and it
   is applied only where the text is genuinely a label rather than content. */
:root[data-palette="cyberpunk"] .stat-tile-label,
:root[data-palette="cyberpunk"] .sidebar-group-label,
:root[data-palette="cyberpunk"] table thead th {
  font-family: var(--cp-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-size: 0.68rem;
}

:root[data-palette="cyberpunk"] table thead th {
  color: var(--cp-cyan);
  background: var(--cp-void);
}

/* Scanlines, at the threshold of visible. An overlay you can see is a costume;
   one you can only sense is texture. `pointer-events: none` so it never eats a
   click.

   THE OLD COMMENT HERE WAS WRONG IN BOTH HALVES and is corrected rather than
   trusted (2026-08-31). It claimed `z-index: 1` "keeps it under the sidebar
   (which is positioned)". `.sidebar` in styles.css sets no `position` and no
   `z-index` — it is a plain flex child painted in normal flow — so a
   `position: fixed` layer at `z-index: 1` paints ABOVE it, not under it. The
   wash therefore covers the sidebar too, which is the opposite of what the
   sentence promised.

   Left at `z-index: 1` deliberately. At `rgba(..., 0.022)` on 1 of every 3
   pixel rows the difference between painting above and below the sidebar is not
   perceptible, and lowering it to sit genuinely underneath would risk the layer
   vanishing behind other content for no visible gain. So this is a comment
   corrected to describe what the rule really does, which is the whole fix —
   this project treats a wrong comment as a real defect, because the next reader
   will believe it. */
:root[data-palette="cyberpunk"] body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background: repeating-linear-gradient(
    to bottom,
    rgba(42, 212, 238, 0.022) 0px,
    rgba(42, 212, 238, 0.022) 1px,
    transparent 1px,
    transparent 3px
  );
}

/* Focus is magenta, so it never disappears into the cyan structure. */
:root[data-palette="cyberpunk"] :focus-visible {
  outline: 2px solid var(--cp-magenta);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  :root[data-palette="cyberpunk"] h1,
  :root[data-palette="cyberpunk"] .stat-tile-value {
    text-shadow: none;
  }
}

/* --------------------------------------------------- Appearance popup --------
   The Appearance control's rules used to live HERE, unscoped — this was the
   first theme built and the base stylesheet had nothing for that component, so
   every other theme rendered through these rules by accident (backlog T1).
   Since 2026-09-02 the structure and the default look live once in
   packages/hub-chrome/public/css/chrome.css, and this theme, like every other,
   may add only colour and material for it — which Cyberpunk does not need: its
   panel is the default card on the theme's own tokens. */

/* --------------------------------------------- Sidebar density
   With Appearance gone the column fits, but only just, so the nav itself is
   tightened. TIGHTENED, NOT COLLAPSED: hiding the five Admin links behind a
   disclosure would fit even more and costs an extra click on every admin visit,
   which is the wrong trade for a tool used daily by people who know exactly
   where they are going. Nothing here reduces the click target below its text
   row; it removes slack, not surface. */
.sidebar-nav a {
  padding: 0.42rem 0.6rem;
}

.sidebar-group-label {
  margin: 1rem 0 0.35rem 0.6rem;
}

/* ===========================================================================
   CYBERPUNK — LIGHT
   ===========================================================================

   Added 2026-08-29. Until then this theme forced dark, and the header comment
   above says why: styles.css carries ~43 component rules selected by
   `:root[data-theme="dark"] .x`, and guaranteeing dark meant every one applied.

   THAT REASONING STILL HOLDS, AND IS WHY THIS WORKS. In light those 43 rules
   simply do not match, and the BASE rules in styles.css — the ones written for a
   light interface in the first place — apply instead. So the components are not
   unstyled here; they fall back to the styling they were designed with. Nothing
   had to be duplicated. What this block changes is the palette underneath them.

   THE IDEA, because "light cyberpunk" is a real design problem rather than an
   inversion: neon does not exist in daylight. A bright #2ad4ee on white is both
   illegible (1.9:1) and characterless. So the light variant is not the dark one
   flipped — it is the same duotone read as INK ON PAPER: a cool blue-grey stock,
   deep cyan for structure, deep magenta reserved for the thing to act on, and the
   glows removed entirely, because a glow on white is just a smudge.

   The sidebar stays dark, as it does in Street Culture's light mode. That is the
   app's existing shape and a dark rail against a light workspace is the right
   frame for the accent to sit in. */
:root[data-palette="cyberpunk"][data-theme="light"] {
  /* Same role names, re-pitched for paper. `void` is no longer the deepest dark
     but the firmest surface — the one a sticky table header sits on. */
  --cp-void:      #dce5f0;
  --cp-ground:    #eef2f8;
  --cp-surface:   #ffffff;
  --cp-surface-2: #e4ebf5;
  --cp-ink:       #0d1b2a;
  --cp-ink-2:     #3d5570;
  --cp-ink-3:     #61758c;
  /* The light variant flips the sidebar to paper (--cp-void is the firmest light
     surface here), so the dark block's --sidebar-muted would sit near-invisible
     on it — 3.73:1 measured, the worst ratio in the audit. Re-pitched for this
     ground: 5.51:1 on #dce5f0. */
  --sidebar-muted: #4a5a72;
  --cp-rule:      #cdd9e8;
  --cp-rule-firm: #a8bcd4;

  /* Both accents are darkened until they pass on white, and only then checked
     against each other so the duotone still reads as two colours rather than two
     shades of navy. Deep cyan #05687d is 5.9:1 on #ffffff and 4.6:1 on the
     firmest surface a sticky table header sits on (#dce5f0), which is the case
     that actually set this value -- at #06788f the header measured 4.04:1 and
     failed. Deep magenta #b31069 is 6.1:1. The bright originals survive only as `--cp-*-glow` for the few
     places a saturated edge is still wanted on a dark chip. */
  --cp-cyan:      #05687d;
  --cp-cyan-deep: #06788f;
  --cp-cyan-dim:  #d3ecf3;
  --cp-magenta:   #b31069;

  --pico-h1-color: var(--cp-ink);

  /* On light, the primary button is a deep cyan fill with WHITE text — the exact
     inverse of the dark variant, where the fill is bright enough that it needs
     dark text. Same rule applied to a different ground, not a copied value. */
  --pico-primary-background: #06788f;
  --pico-primary-hover: #04596b;
  --pico-primary-hover-background: #055f72;
  --pico-primary-inverse: #ffffff;
  --pico-primary-underline: rgba(6, 120, 143, 0.4);
  --pico-primary-focus: rgba(6, 120, 143, 0.28);

  --pico-secondary-hover-background: #d5dfec;

  /* <mark> keeps its job — the "look here" highlight — as magenta ink on a pale
     magenta wash rather than pale ink on a dark one. */
  --pico-mark-background-color: #fbdcec;
  --pico-mark-color: #7d0b49;

  --pico-table-row-stripped-background-color: rgba(6, 120, 143, 0.045);
  --pico-code-color: #05637a;

  --scroll-shadow-color: rgba(13, 27, 42, 0.16);
}

/* Glows off in light. Every one of these is a cyan halo tuned for near-black;
   on a pale ground the same shadow reads as a printing error. */
:root[data-palette="cyberpunk"][data-theme="light"] h1,
:root[data-palette="cyberpunk"][data-theme="light"] h2,
:root[data-palette="cyberpunk"][data-theme="light"] .stat-tile-value,
:root[data-palette="cyberpunk"][data-theme="light"] .sidebar-brand {
  text-shadow: none;
}

/* The scanline wash is a dark hairline on light instead of a cyan one, kept at
   the same near-invisible weight — texture, not costume. */
:root[data-palette="cyberpunk"][data-theme="light"] body::before {
  background: repeating-linear-gradient(
    to bottom,
    rgba(13, 27, 42, 0.02) 0px,
    rgba(13, 27, 42, 0.02) 1px,
    transparent 1px,
    transparent 3px
  );
}

/* Panels lift off paper with a soft, low shadow rather than the heavy one that
   reads as depth against near-black. */
:root[data-palette="cyberpunk"][data-theme="light"] .appearance-panel {
  box-shadow: 0 10px 30px rgba(13, 27, 42, 0.14);
}

/* ===========================================================================
   MATCHING THE MINION DASHBOARD
   ===========================================================================

   The maintainer's brief: this theme should look like the published minion
   dashboard (docs/minion-dashboard.html), adapted to an app rather than copied —
   so the identity carries over, the oversized display figures do not. An asset
   table read all day cannot use a 3.4rem numeral.

   Four things carry that identity, and they are the four this block adds. The
   palette and the type pairing were already shared; these are what made the two
   still look like different products.

   1. SQUARE CORNERS. The dashboard has no rounded anything, and that is the
      single most defining trait — it is what makes the interface read as an
      instrument panel rather than a web app. Pico's global 0.5rem radius is
      overridden at the token, so every component follows without being listed.
   2. THE SECTION HEADING. A left cyan bar plus a bottom rule, uppercase and
      letter-spaced. It is the dashboard's most recognisable component.
   3. CHIPS OUTLINED IN THEIR OWN COLOUR. `border: 1px solid currentColor` means
      a status chip's outline is always its semantic colour without a rule per
      status — and semantic colour stays semantic, which the header comment at
      the top of this file already commits to.
   4. TABULAR MONO FIGURES. Numbers in a column line up. Applied to the dashboard
      tiles and money cells, not blown up. */
:root[data-palette="cyberpunk"] {
  --pico-border-radius: 0;
}

:root[data-palette="cyberpunk"] .stat-tile,
:root[data-palette="cyberpunk"] .table-wrap,
:root[data-palette="cyberpunk"] article,
:root[data-palette="cyberpunk"] .appearance-panel,
:root[data-palette="cyberpunk"] button,
:root[data-palette="cyberpunk"] .btn-compact,
:root[data-palette="cyberpunk"] input,
:root[data-palette="cyberpunk"] select,
:root[data-palette="cyberpunk"] textarea {
  border-radius: 0;
}

/* The dashboard's section heading, applied to the app's own section headings.
   `h2` only: h1 is the page title and keeps its scale, and h3 downward are
   sub-headings inside a section where a second bar would be noise. */
:root[data-palette="cyberpunk"] main h2 {
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 1.15rem;
  padding: 0 0 0.5rem 0.85rem;
  border-left: 3px solid var(--cp-cyan);
  border-bottom: 1px solid var(--cp-rule-firm);
}

/* Chips take their outline from their own text colour, so every status keeps the
   colour it already means and none of them needs a rule here.
   D7, fixed 2026-09-04: this named `.status-chip` and `.chip`, neither of which
   any view emits (the real class is `.status-badge`) — so on Cyberpunk the
   filter chips got this treatment and the status badges 100px below them on
   the same screen did not. `.status-badge` is the base class every status pill
   carries (colour comes from `.status-<value>`, set elsewhere and untouched by
   this rule), matching halloween.css and matrix.css, both of which already
   target it correctly. */
:root[data-palette="cyberpunk"] .status-badge,
:root[data-palette="cyberpunk"] .filter-chip {
  border: 1px solid currentColor;
  border-radius: 0;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-family: var(--cp-mono);
  font-size: 0.68rem;
}

/* Figures line up in a column. Mono with tabular numerals on the dashboard tiles
   and on money, which is where a mis-aligned digit actually costs you something.
   Deliberately NOT the dashboard's 3.4rem — this is a working screen. */
/* .stat-tile-value already gets this treatment from the rule near the top of
   this file; `.stat-tile strong` matches no real markup (the figure is a div,
   not a <strong>) -- both were dead here (D7). */
:root[data-palette="cyberpunk"] td.num,
:root[data-palette="cyberpunk"] .money {
  font-family: var(--cp-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* The sticky table header sits on the deepest surface, as it does on the
   dashboard, so rows sliding under it stay clearly behind. */
:root[data-palette="cyberpunk"] thead th {
  background: var(--cp-void);
}

/* ===========================================================================
   THE COLOURED TILES KEEP THE BASE'S WHITE TEXT.

   `.stat-tile-teal/amber/salmon/grey` carry FIXED backgrounds set in the app's
   own stylesheet, chosen so that full white clears AA on each (6.03 / 6.05 /
   6.99 / 7.21:1). They do not follow the theme. So a theme that recolours
   `.stat-tile-value` globally — which this file does, to cyan, for the tiles
   that DO follow the theme — silently repaints the figure on those four as
   well, and cyan on the amber ground measured 1.06:1 in light: the number was
   simply not there. Found 2026-09-05 by measuring every theme against the
   coloured tile rather than against the page.
   =========================================================================== */
:root[data-palette="cyberpunk"] .stat-tile-teal .stat-tile-value,
:root[data-palette="cyberpunk"] .stat-tile-amber .stat-tile-value,
:root[data-palette="cyberpunk"] .stat-tile-salmon .stat-tile-value,
:root[data-palette="cyberpunk"] .stat-tile-grey .stat-tile-value {
  color: #ffffff;
  text-shadow: none;
}
