/* =====================================================================
   THEME PRESETS — private

   Everything here is a preset in the sense theme.css defines: a restated
   token list under a :root[data-theme] selector, and nothing else. No
   rules are added to the shared components, and no module stylesheet is
   touched. If a preset needs a component to be structurally different,
   the component grows a token in theme.css and every preset answers.

   WHY THIS FILE LIVES OUTSIDE THE WEB ROOT
   The Dockerfile moves web/_private out of wwwroot, so nothing can serve
   this by accident; it is reachable only through the auth-gated route in
   ThemesModule.cs. That is what makes the gate real rather than
   decorative: an anonymous visitor who forges the stored preference gets
   a 404 for this stylesheet, so `data-theme` matches no rule and the
   page falls back to `crt`. A colour scheme is not a secret — the point
   is that "private feature" means the feature is actually absent, not
   merely unadvertised.

   PALETTE
   Catppuccin Mocha, official values (catppuccin/palette). Reference:

     base     #1e1e2e   surface0 #313244   text     #cdd6f4
     mantle   #181825   surface1 #45475a   subtext1 #bac2de
     crust    #11111b   surface2 #585b70   subtext0 #a6adc8
     overlay0 #6c7086   overlay1 #7f849c   overlay2 #9399b2
     blue     #89b4fa   lavender #b4befe   sapphire #74c7ec
     sky      #89dceb   teal     #94e2d5   green    #a6e3a1
     yellow   #f9e2af   peach    #fab387   maroon   #eba0ac
     red      #f38ba8   mauve    #cba6f7   pink     #f5c2e7

   The existing site palette turned out to be Catppuccin-adjacent
   already: --text-muted #a6adb8 sits one byte from subtext0 #a6adc8, and
   --text-faint #737a86 is within a step of overlay1. The mapping below
   is therefore a sharpening, not a transplant.
   ===================================================================== */


/* =====================================================================
   PRESET: mocha-flat — Catppuccin Mocha, texture off.

   The same site, in Catppuccin, with the CRT layer switched off: no
   scanlines, no phosphor glow. Structure is untouched — selection is
   still the tinted border, chrome is still an elevated panel.

   This is the readability preset. The two things that actually fight
   text on this site are the 0.22 overlay painting OVER body copy and
   the glow smearing every glyph; both are gone, and nothing else had to
   move to do it. It is honestly not a "BBS" look — it is Catppuccin,
   flat — and it is named accordingly.
   ===================================================================== */
:root[data-theme="mocha-flat"] {
  --panel-outer-width: 0;
  --panel-outer-style: solid;
  --color-scheme: dark;
  --theme-name: "mocha-flat";

  /* Surface. base is the page, surface0 the lifted panel — preserving
     crt's relationship, where elevated reads LIGHTER than the page. */
  --bg: #1e1e2e;
  --bg-elevated: #313244;
  --scrim: rgba(17, 17, 27, 0.55);   /* crust */

  /* Text ramp, lightest to dimmest. */
  --text: #cdd6f4;         /* text */
  --text-muted: #a6adc8;   /* subtext0 */
  --text-faint: #7f849c;   /* overlay1 */
  --text-dim: #585b70;     /* surface2 — the build stamp, dimmer again */

  --border: #45475a;       /* surface1 */
  --accent: #89b4fa;       /* blue */
  /* Selection tint. Derived rather than a literal so it stays correct if
     --accent is ever retuned: the same 14% wash over the page colour
     that crt's #1f2a38 is over its own. */
  --accent-soft: color-mix(in srgb, #89b4fa 14%, #1e1e2e);

  /* Semantic. --attention takes maroon rather than red: the crt value it
     replaces (#d98a8a) is a soft warning, not an alarm, and red #f38ba8
     would have shouted where the old one spoke. */
  --warn: #fab387;         /* peach */
  --warn-soft: color-mix(in srgb, #fab387 16%, #1e1e2e);
  --link: #bac2de;         /* subtext1 */
  --good: #a6e3a1;         /* green */
  --stable: #f9e2af;       /* yellow */
  --attention: #eba0ac;    /* maroon */

  /* Reading pane: the same three-step descent as crt, one notch below
     the page ramp so type sits IN the panel. */
  --pane-text: #bac2de;    /* subtext1 */
  --pane-prose: #a6adc8;   /* subtext0 */
  --pane-meta: #9399b2;    /* overlay2 */

  /* Category hues — ten distinct Mocha accents, matched to the crt
     palette's order and rough hue so an edition's sections keep their
     relative colouring. */
  --cat-1: #89b4fa;   /* blue */
  --cat-2: #cba6f7;   /* mauve */
  --cat-3: #a6e3a1;   /* green */
  --cat-4: #fab387;   /* peach */
  --cat-5: #eba0ac;   /* maroon */
  --cat-6: #89dceb;   /* sky */
  --cat-7: #94e2d5;   /* teal */
  --cat-8: #f9e2af;   /* yellow */
  --cat-9: #f5c2e7;   /* pink */
  --cat-10: #b4befe;  /* lavender */

  /* Texture off. `none` is a valid background-image layer, so the
     .selectable hover rule's two-layer value degrades cleanly to
     `none, linear-gradient(tint, tint)` and selection keeps working.
     --scan-attach is meaningless with no image but must stay a valid
     keyword, because the shared components still declare it. */
  --scan-heavy: none;
  --scan-light: none;
  --scan-clean: none;
  --glow: none;
  --glow-accent: none;

  /* Geometry and selection idiom unchanged from crt: rounded corners, 1px
     panel edges, the tinted wash rather than inverse video. That is what
     makes this the "same site, texture off" preset. Stated rather than
     inherited — a preset is its whole token list, and a value that is
     right only because nobody overrode it is right by accident. */
  --radius-scale: 1;
  --panel-border-width: 1px;
  --panel-border-style: solid;
  --sel-invert: 0;
  --sel-ink: #cdd6f4;
}


/* =====================================================================
   PRESET: black-ansi-green — the loud one.

   The plan for this step said "ANSI chrome per module", and that was the
   step most likely to break the contract: writing box-drawn toolbars into
   five stylesheets would have put the theme inside the modules and undone
   the rule theme.css has carried from the beginning — modules must not
   hand-roll their own look. It turned out not to be necessary. Everything
   below is tokens, and not one module stylesheet was touched.

   Three things separate it from bbs-classic:

   1. TEXTURE. The scan tokens are not scanline-specific; they are just
      background images. Where crt paints horizontal lines and the flat
      presets paint nothing, this one paints a 2px cross-hatch — the CSS
      that reads closest to ANSI's ▒ and ░ shade blocks. Built from two
      repeating-linear-gradients rather than a conic checkerboard because
      those carry their own lengths: --scan-light is also consumed by
      `background-image` on <input>/<select>, which cannot take the
      `/ size` syntax a conic pattern would need.

   2. PALETTE. Still Catppuccin, but pushed to the saturated end and
      reorganised around ANSI habits: near-black crust as the page, bright
      cyan as the accent (the colour every board used for headers), and
      an --attention that is genuinely red. On the other presets red would
      shout where the old value spoke; here shouting is the point.

   3. GEOMETRY. --radius-scale: 0 squares all 29 radii at once.
   ===================================================================== */
:root[data-theme="black-ansi-green"] {
  --color-scheme: dark;
  --theme-name: "black-ansi-green";

  /* Neutral near-black, NOT Catppuccin's crust. Mocha's dark end carries a
     violet undertone that is lovely in an editor and wrong here: on a
     large panel it reads as a purple wash rather than as an unlit CRT.
     A board's background was neutral, so these three are the one place
     this preset leaves the palette behind. mocha-ansi is the faithful
     reading; this one is the ANSI reading, and the surfaces are where the
     difference shows. Accent and category hues stay Catppuccin. */
  --bg: #0b0d0e;
  --bg-elevated: #17191c;
  --scrim: rgba(0, 0, 0, 0.7);

  --text: #cdd6f4;
  --text-muted: #a6adc8;
  --text-faint: #7f849c;
  --text-dim: #3d4348;     /* neutral, matching the surfaces */

  --border: #5a6167;       /* a step up: a dashed rule lays down less ink
                            than a solid one and reads weaker at the same value */
  --accent: #89dceb;       /* sky: the bright cyan of every BBS header */
  --accent-soft: color-mix(in srgb, #89dceb 16%, #0b0d0e);

  --warn: #f9e2af;         /* yellow */
  --warn-soft: color-mix(in srgb, #f9e2af 18%, #0b0d0e);
  --link: #89dceb;
  --good: #a6e3a1;
  --stable: #f9e2af;
  --attention: #f38ba8;    /* red, and meant as red */

  --pane-text: #cdd6f4;
  --pane-prose: #bac2de;
  --pane-meta: #a6adc8;

  /* Ten saturated hues, maximally separated — an ANSI board colour-coded
     by hue rather than by shade. */
  --cat-1: #89dceb;   /* sky */
  --cat-2: #cba6f7;   /* mauve */
  --cat-3: #a6e3a1;   /* green */
  --cat-4: #fab387;   /* peach */
  --cat-5: #f38ba8;   /* red */
  --cat-6: #74c7ec;   /* sapphire */
  --cat-7: #94e2d5;   /* teal */
  --cat-8: #f9e2af;   /* yellow */
  --cat-9: #f5c2e7;   /* pink */
  --cat-10: #b4befe;  /* lavender */

  /* ▒ and ░ as a 2px cross-hatch. Same three roles, same three
     intensities, different mark. */
  --scan-heavy:
    repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.30) 0 1px, transparent 1px 2px),
    repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.30) 0 1px, transparent 1px 2px);
  --scan-light:
    repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.18) 0 1px, transparent 1px 2px),
    repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.18) 0 1px, transparent 1px 2px);
  --scan-clean:
    repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.10) 0 1px, transparent 1px 2px),
    repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.10) 0 1px, transparent 1px 2px);

  /* No phosphor: a hatch under a glow reads as dirt. */
  --glow: none;
  --glow-accent: none;

  --radius-scale: 0;
  --panel-border-width: 1px;
  --panel-border-style: solid;
  /* Two hairlines with a gap of page colour between them: the double
     frame drawn rather than bevelled. */
  --panel-outer-width: 1px;
  --panel-outer-style: solid;

  --sel-invert: 1;
  --sel-ink: #0b0d0e;   /* the page colour — it lagged behind when the surfaces went neutral */
}


/* =====================================================================
   PRESET: mocha-ansi — the ANSI idiom, in Catppuccin's own colours.

   black-ansi-green reorganises the palette around ANSI habits: crust as the page,
   bright cyan as the accent, red that means red. That is faithful to a
   BBS and unfaithful to Catppuccin.

   This one keeps every ANSI idiom — the ▒ cross-hatch, square corners,
   doubled panel edges, inverse-video selection — and puts them on Mocha
   as published: base as the page, blue as the accent, the standard
   accent set for categories. Same behaviour, Catppuccin's own reading.
   ===================================================================== */
:root[data-theme="mocha-ansi"] {
  --panel-outer-width: 0;
  --panel-outer-style: solid;
  --color-scheme: dark;
  --theme-name: "mocha-ansi";

  --bg: #1e1e2e;           /* base */
  --bg-elevated: #313244;  /* surface0 */
  --scrim: rgba(17, 17, 27, 0.6);
  --text: #cdd6f4;
  --text-muted: #a6adc8;
  --text-faint: #7f849c;
  --text-dim: #585b70;
  --border: #45475a;       /* surface1 */
  --accent: #89b4fa;       /* blue — Catppuccin's own, not ANSI cyan */
  --accent-soft: color-mix(in srgb, #89b4fa 14%, #1e1e2e);

  --warn: #fab387;
  --warn-soft: color-mix(in srgb, #fab387 16%, #1e1e2e);
  --link: #b4befe;         /* lavender */
  --good: #a6e3a1;
  --stable: #f9e2af;
  --attention: #eba0ac;    /* maroon: a warning, not an alarm */

  --pane-text: #bac2de;
  --pane-prose: #a6adc8;
  --pane-meta: #9399b2;

  --cat-1: #89b4fa;   /* blue */
  --cat-2: #cba6f7;   /* mauve */
  --cat-3: #a6e3a1;   /* green */
  --cat-4: #fab387;   /* peach */
  --cat-5: #eba0ac;   /* maroon */
  --cat-6: #89dceb;   /* sky */
  --cat-7: #94e2d5;   /* teal */
  --cat-8: #f9e2af;   /* yellow */
  --cat-9: #f5c2e7;   /* pink */
  --cat-10: #b4befe;  /* lavender */

  /* The ANSI texture, unchanged from black-ansi-green: ▒ and ░ as a 2px
     cross-hatch, at the same three intensity roles. */
  --scan-heavy:
    repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.30) 0 1px, transparent 1px 2px),
    repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.30) 0 1px, transparent 1px 2px);
  --scan-light:
    repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.18) 0 1px, transparent 1px 2px),
    repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.18) 0 1px, transparent 1px 2px);
  --scan-clean:
    repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.10) 0 1px, transparent 1px 2px),
    repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.10) 0 1px, transparent 1px 2px);
  --glow: none;
  --glow-accent: none;

  --radius-scale: 0;
  --panel-border-width: 3px;
  --panel-border-style: double;

  --sel-invert: 1;
  --sel-ink: #1e1e2e;
}


/* =====================================================================
   PRESET: latte-flat — Catppuccin Latte. The light one.

   The first preset that is not dark, which is why `color-scheme` had to
   become a token: without it the browser keeps painting scrollbars, form
   controls and the caret for a dark page.

   The surface relationship is kept, not the literal lightness. crt reads
   "elevated is LIGHTER than the page", so here the page takes crust and
   the lifted panels take base — the panels still come forward. Using base
   as the page and surface0 as the panel would have inverted that and made
   every toolbar read as a hole.

   Texture off. A scanline is a dark line, and a dark grid over a light
   page reads as dirt rather than as phosphor; there is no light-theme
   equivalent worth having.
   ===================================================================== */
:root[data-theme="latte-flat"] {
  --panel-outer-width: 0;
  --panel-outer-style: solid;
  --theme-name: "latte-flat";
  --color-scheme: light;

  --bg: #eff1f5;           /* base — the page */
  --bg-elevated: #ffffff;  /* panels come forward, as on crt */
  --scrim: rgba(76, 79, 105, 0.4);   /* text, at low alpha */

  /* On a light page the ramp descends by getting DARKER-toward-mid, not
     lighter: overlay1 over crust measured 2.42, well under the 4.19 the
     site's own crt gives the same elements. One step down each. */
  --text: #4c4f69;         /* text */
  --text-muted: #5c5f77;   /* subtext1 */
  --text-faint: #6c6f85;   /* subtext0 */
  --text-dim: #8c8fa1;     /* overlay1 */

  --border: #bcc0cc;       /* surface1 */
  --accent: #1e66f5;       /* blue */
  --accent-soft: color-mix(in srgb, #1e66f5 12%, #eff1f5);

  /* Latte's accents are far more saturated than Mocha's, which is what
     makes it read cheerful — but --warn and --attention have to stay
     legible AS TEXT on a light page, so both take the deeper end. */
  --warn: #df8e1d;         /* yellow */
  --warn-soft: color-mix(in srgb, #df8e1d 18%, #eff1f5);
  --link: #7287fd;         /* lavender */
  --good: #40a02b;         /* green */
  --stable: #df8e1d;       /* yellow */
  --attention: #d20f39;    /* red — on white it reads as emphasis, not alarm */

  --pane-text: #4c4f69;
  --pane-prose: #5c5f77;   /* subtext1 */
  --pane-meta: #6c6f85;    /* subtext0 */

  --cat-1: #1e66f5;   /* blue */
  --cat-2: #8839ef;   /* mauve */
  --cat-3: #40a02b;   /* green */
  --cat-4: #fe640b;   /* peach */
  --cat-5: #e64553;   /* maroon */
  --cat-6: #04a5e5;   /* sky */
  --cat-7: #179299;   /* teal */
  --cat-8: #df8e1d;   /* yellow */
  --cat-9: #ea76cb;   /* pink */
  --cat-10: #7287fd;  /* lavender */

  --scan-heavy: none;
  --scan-light: none;
  --scan-clean: none;
  --glow: none;
  --glow-accent: none;

  --radius-scale: 1;
  --panel-border-width: 1px;
  --panel-border-style: solid;
  --sel-invert: 0;
  --sel-ink: #4c4f69;
}


/* =====================================================================
   PRESET: latte-ansi — Latte, with every ANSI idiom.

   The same palette as latte-flat, wearing what black-ansi-green wears: square
   corners, doubled panel edges, inverse-video selection, and the ▒
   cross-hatch. The hatch is the one thing that had to be re-thought
   rather than copied — on a dark page it reads as phosphor, on a light
   one a black grid reads as dirt. Here it is drawn in the text colour at
   a low alpha, which reads as newsprint half-tone instead.

   Inverse video needs its own answer too: the item floods with a
   saturated Latte accent, so the ink goes to the page colour rather than
   the text colour, or it would be dark-on-dark.
   ===================================================================== */
:root[data-theme="latte-ansi"] {
  --panel-outer-width: 0;
  --panel-outer-style: solid;
  --theme-name: "latte-ansi";
  --color-scheme: light;

  --bg: #eff1f5;
  --bg-elevated: #ffffff;
  --scrim: rgba(76, 79, 105, 0.45);
  --text: #4c4f69;
  --text-muted: #5c5f77;
  --text-faint: #6c6f85;
  --text-dim: #8c8fa1;
  --border: #acb0be;       /* surface2 — the doubled frame has to read */
  --accent: #1e66f5;
  --accent-soft: color-mix(in srgb, #1e66f5 12%, #eff1f5);
  --warn: #df8e1d;
  --warn-soft: color-mix(in srgb, #df8e1d 18%, #eff1f5);
  --link: #1e66f5;
  --good: #40a02b;
  --stable: #df8e1d;
  --attention: #d20f39;
  --pane-text: #4c4f69;
  --pane-prose: #5c5f77;
  --pane-meta: #6c6f85;
  --cat-1: #1e66f5;
  --cat-2: #8839ef;
  --cat-3: #40a02b;
  --cat-4: #fe640b;
  --cat-5: #e64553;
  --cat-6: #04a5e5;
  --cat-7: #179299;
  --cat-8: #df8e1d;
  --cat-9: #ea76cb;
  --cat-10: #7287fd;

  /* Half-tone in the text colour, not black: a dark grid over a light
     page reads as dirt. */
  --scan-heavy:
    repeating-linear-gradient(0deg, rgba(76, 79, 105, 0.16) 0 1px, transparent 1px 2px),
    repeating-linear-gradient(90deg, rgba(76, 79, 105, 0.16) 0 1px, transparent 1px 2px);
  --scan-light:
    repeating-linear-gradient(0deg, rgba(76, 79, 105, 0.10) 0 1px, transparent 1px 2px),
    repeating-linear-gradient(90deg, rgba(76, 79, 105, 0.10) 0 1px, transparent 1px 2px);
  --scan-clean:
    repeating-linear-gradient(0deg, rgba(76, 79, 105, 0.06) 0 1px, transparent 1px 2px),
    repeating-linear-gradient(90deg, rgba(76, 79, 105, 0.06) 0 1px, transparent 1px 2px);
  --glow: none;
  --glow-accent: none;

  --radius-scale: 0;
  --panel-border-width: 3px;
  --panel-border-style: double;

  --sel-invert: 1;
  /* Pure white, not base: against Latte's blue #1e66f5 the base colour
     measured 4.34 and white clears 4.5. On a saturated flood the extra
     step is free — there is no surface for it to blend into. */
  --sel-ink: #ffffff;
}
