/* PLAIN — white ground, black ink, visible borders ============================================================================================ Not a design. An instrument. Every value here is white, black, or a grey, and every surface is flat and square. So when the app is rendered under this theme, ANY colour still on the screen is a component painting itself instead of asking the theme — a hardcoded `text-emerald-400`, a `bg-black/10`, a hex literal. The leaks light up. That makes it the acceptance test for the whole decoupling effort, and a much better one than reading code: the survey found ~985 raw Tailwind palette usages and ~119 hex literals, and no amount of grepping tells you which of those are load-bearing. A screenshot does. It is also the honest starting point for a third-party author — copy this, and every value you change is one you have decided about, with nothing inherited from someone else's brand. Deliberately NOT beautiful. A pleasant neutral theme would hide small leaks in its own greys; stark black on stark white hides nothing. */ [data-theme='plain'] { /* ── Brand slots ────────────────────────────────────────────────────────────────────────────── All black. The `duck-*` utilities resolve through these, so anything still using them renders as flat black rather than teal — visible as "this should have been a semantic token" without being colourful enough to be mistaken for intent. */ --brand-primary: #000000; --brand-accent: #000000; --brand-warm: #000000; --brand-deep: #000000; --ink: #000000; --surface-warm: #ffffff; /* ── Legacy variable names, for direct `var()` consumers ────────────────────────────────────── The `duck-*` UTILITIES are remapped in base.css, but a stylesheet reading `var(--duck-teal)` gets nothing from that — it wants the variable itself. `prose.css` does exactly this eleven times for chat markdown (links, blockquotes, inline code, checkboxes), and the rename silently emptied all of them. Caught by diffing computed variables between the old and new builds, not by reading. Kept as aliases rather than as values: there is one source of truth above, and these follow it. They retire when nothing reads them — the same migration as the utility names. */ --duck-teal: var(--brand-primary); --duck-dark: var(--ink); --duck-yellow: var(--brand-accent); --duck-forest: var(--brand-deep); --duck-beige: var(--surface-warm); --duck-orange: var(--brand-warm); /* ── The page ───────────────────────────────────────────────────────────────────────────────── Flat white and no grid. If a pixel grid or a wallpaper appears under this theme, something is drawing it from outside the theme layer. */ --page-bg: #ffffff; --pixel-grid-color: transparent; /* ── The wallpaper, the header and the mark ─────────────────────────────────────────────────── No wallpaper, no blur, a hard border. If an image appears behind the panels under this theme, something is still drawing it from outside the theme layer. */ /* Empty means no wallpaper — see the note in the Duck themes. */ --page-bg-src: ''; --header-bg: #ffffff; --header-border: #000000; --header-fg: #000000; --header-blur: 0px; --logo-src: '/officer-logo.svg'; /* ── Surfaces ───────────────────────────────────────────────────────────────────────────────── Opaque white with a hard black border, and square corners. The app's panels are translucent with rounded corners and a grid fill, so any panel that still looks like that under Plain is styling itself rather than reading `--panel-*`. */ --glass-bg: #ffffff; --glass-border: #000000; --panel-bg: #ffffff; --panel-border: #000000; --panel-radius: 0; --panel-header-bg: #f2f2f2; --panel-header-fg: #000000; --panel-accent: #000000; --panel-grid-color: transparent; --dock-bg: #ffffff; --dock-border: #000000; --dock-tooltip-bg: #000000; --card-bg: #ffffff; --card-grid-color: transparent; /* ── Semantic colour ────────────────────────────────────────────────────────────────────────── Greys only. The state tones (success/warning/destructive/info) are greys too, which is wrong for a real theme and right for this one: it proves the app is asking for a token rather than reaching for a green it likes. A theme that wanted real state colour would simply set them. */ --background: 0 0% 100%; --foreground: 0 0% 0%; --card: 0 0% 100%; --card-foreground: 0 0% 0%; --popover: 0 0% 100%; --popover-foreground: 0 0% 0%; --primary: 0 0% 0%; --primary-foreground: 0 0% 100%; --secondary: 0 0% 95%; --secondary-foreground: 0 0% 0%; --muted: 0 0% 95%; --muted-foreground: 0 0% 35%; --accent: 0 0% 90%; --accent-foreground: 0 0% 0%; --destructive: 0 0% 25%; --destructive-foreground: 0 0% 100%; --success: 0 0% 25%; --success-foreground: 0 0% 100%; --brand: 0 0% 0%; --brand-foreground: 0 0% 100%; --brand-muted: 0 0% 90%; --warning: 0 0% 45%; --warning-foreground: 0 0% 100%; --info: 0 0% 35%; --info-foreground: 0 0% 100%; --border: 0 0% 0%; --input: 0 0% 0%; --ring: 0 0% 0%; --cta: 0 0% 0%; --cta-foreground: 0 0% 100%; --ctahover: 0 0% 20%; --naturegreen: 0 0% 0%; --naturegreen-foreground: 0 0% 100%; /* Square everything. Rounded corners surviving under Plain means a hardcoded `rounded-xl`, which is a shape leak rather than a colour one — worth seeing too. */ --radius: 0; /* ── Data visualisation and status ────────────────────────────────────────────────────────────── */ --chart-primary: 0 0% 20%; --chart-secondary: 0 0% 60%; --status-success: 0 0% 25%; --status-warning: 0 0% 45%; --status-in-progress: 0 0% 35%; /* ── Chrome ───────────────────────────────────────────────────────────────────────────────────── */ --scrollbar-thumb: #000000; --scrollbar-thumb-hover: #333333; --scrollbar-thin-thumb: rgb(0 0 0 / 0.4); --scrollbar-thin-thumb-hover: rgb(0 0 0 / 0.7); }