The cornerstone of the layout was the least themeable thing in it. Measured before touching anything, which is the only reason this is the right fix: duck-dark radius=8px bg=rgba(255,255,255,0.12) border=rgba(0,0,0,0.25) blur=24px plain radius=0px bg=rgba(255,255,255,0.12) border=rgba(0,0,0,0.25) blur=24px So the RADIUS was already following `--radius` and I had been telling the owner otherwise — the rounding in the Plain screenshot was something else. What did not follow anything was the surface: three literal rgba pairs and a fixed `backdrop-blur-xl` in the component. Now: plain radius=0px bg=rgb(255,255,255) border=rgb(0,0,0) blur=0px Two distinctions the old code drew in literals are kept as tokens rather than flattened, because both are real and a theme should be able to revisit them. `--panel-raised-*` is the fullscreen surface: DENSER glass, not darker, because panel chrome is dark text and a heavy dark fill hid every icon. `--panel-border-bare` is for a panel with no header, which has nothing else separating it from what it sits on. `--panel-blur` earns its place beyond theming: a flat theme was paying for a 24px backdrop blur it did not want, and on a solid panel the compositor does that work for nothing. ── A near miss worth recording ── The first attempt silently changed nothing. The patch matched on four spaces of indentation where the file has two, `str.replace` reported no error, the build succeeded, and `panel-blur` DID apply — so the class landed while the surface did not. It looked like a partial success and would have shipped as one. Caught by measuring computed styles again rather than trusting the edit; the fix now asserts the replacement changed the file. 950 pass / 7 fail unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
162 lines
7.6 KiB
CSS
162 lines
7.6 KiB
CSS
/*
|
|
DUCK — DARK
|
|
============================================================================================
|
|
|
|
A sibling of Duck Light, not a variant of it. The owner's decision: light and dark are two themes, which
|
|
removes "colour mode" from the application as a concept.
|
|
|
|
It is written out in full rather than as a diff against light. Overriding would be shorter and would
|
|
reintroduce exactly the coupling this refactor removes — a theme that only makes sense in the presence of
|
|
another is not something a third party can author or a customer can buy. A complete file is also the only
|
|
way an author can see what they have to supply.
|
|
|
|
`applyDarkClass` is set for this theme in the registry, so the 396 `dark:` utilities still written into
|
|
components keep resolving. That is a compatibility shim with a known end date, not part of the design.
|
|
|
|
Values are the `.dark` block of the original `globals.css`, unchanged. Where light defined something that
|
|
the original dark block did not override (`--duck-yellow`, `--duck-orange`), the light value is repeated
|
|
here — that is what the browser was computing before, made explicit.
|
|
*/
|
|
|
|
[data-theme='duck-dark'] {
|
|
/* ── Brand — lightened for contrast on a dark ground ──────────────────────────────────────────
|
|
`--ink` flipping to near-white is the clearest evidence that `duck-dark` was never a brand colour. */
|
|
--brand-primary: #22d3ee;
|
|
--brand-accent: #f4c430;
|
|
--brand-warm: #ea580c;
|
|
--brand-deep: #4ade80;
|
|
--ink: #f1f5f9;
|
|
--surface-warm: #292524;
|
|
|
|
/* ── 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 ─────────────────────────────────────────────────────────────────────────────────── */
|
|
--page-bg: hsl(222.2 84% 4.9%);
|
|
--pixel-grid-color: rgba(200, 230, 210, 0.08);
|
|
|
|
/* ── The wallpaper, the header and the mark ───────────────────────────────────────────────────
|
|
All three were drawn by components: `Background.tsx` hardcoded `/landscape1.webp`, the header
|
|
carried `rgba(255,255,255,0.25)` in an inline style, and the logo was an `<img src>`. None of them
|
|
could be changed by a theme, which is most of what "the app looks like Officer" actually means.
|
|
|
|
Complete CSS values, so a theme can use an image, a gradient, or nothing at all. */
|
|
/* A quoted PATH, not a `url()`. Bun's CSS bundler resolves `url()` at build time and this file is
|
|
served from `public/` at runtime, so a url() token fails the build outright. `Background.tsx` wraps
|
|
it. A theme wanting a gradient instead sets `--page-bg` above and leaves this empty. */
|
|
--page-bg-src: '/landscape1.webp';
|
|
--header-bg: rgba(255, 255, 255, 0.25);
|
|
--header-border: rgba(255, 255, 255, 0.35);
|
|
--header-fg: #1d2724;
|
|
--header-blur: 24px;
|
|
--logo-src: '/officer-logo.svg';
|
|
|
|
/* ── Surfaces ─────────────────────────────────────────────────────────────────────────────────── */
|
|
--glass-bg: rgba(0, 0, 0, 0.2);
|
|
--glass-border: rgba(255, 255, 255, 0.1);
|
|
|
|
--panel-bg: rgba(255, 255, 255, 0.12);
|
|
--panel-border: rgba(255, 255, 255, 0.2);
|
|
--panel-border-bare: rgba(0, 0, 0, 0.25);
|
|
--panel-raised-bg: rgba(255, 255, 255, 0.25);
|
|
--panel-raised-border: rgba(255, 255, 255, 0.35);
|
|
--panel-blur: 24px;
|
|
--panel-radius: 0.75rem;
|
|
--panel-header-bg: rgba(0, 0, 0, 0.15);
|
|
--panel-header-fg: hsl(var(--foreground));
|
|
--panel-accent: var(--brand-primary);
|
|
--panel-grid-color: rgba(200, 230, 210, 0.06);
|
|
|
|
--dock-bg: rgba(0, 0, 0, 0.3);
|
|
--dock-border: rgba(255, 255, 255, 0.08);
|
|
--dock-tooltip-bg: rgba(0, 0, 0, 0.85);
|
|
|
|
--card-bg: rgba(10, 20, 15, 0.9);
|
|
--card-grid-color: rgba(200, 230, 210, 0.06);
|
|
|
|
/* ── Semantic colour ──────────────────────────────────────────────────────────────────────────── */
|
|
--background: 222.2 84% 4.9%;
|
|
--foreground: 210 40% 98%;
|
|
|
|
--card: 222.2 84% 4.9%;
|
|
--card-foreground: 210 40% 98%;
|
|
|
|
--popover: 222.2 84% 4.9%;
|
|
--popover-foreground: 210 40% 98%;
|
|
|
|
--primary: 210 40% 98%;
|
|
--primary-foreground: 222.2 47.4% 11.2%;
|
|
|
|
--secondary: 217.2 32.6% 17.5%;
|
|
--secondary-foreground: 210 40% 98%;
|
|
|
|
--muted: 217.2 32.6% 17.5%;
|
|
--muted-foreground: 215 20.2% 65.1%;
|
|
|
|
--accent: 211 82% 64%;
|
|
--accent-foreground: 0 0% 100%;
|
|
|
|
--destructive: 0 62.8% 30.6%;
|
|
--destructive-foreground: 210 40% 98%;
|
|
|
|
--success: 142.1 76.2% 36.3%;
|
|
--success-foreground: 355.7 100% 97.3%;
|
|
|
|
--brand: 145 60% 45%;
|
|
--brand-foreground: 0 0% 100%;
|
|
--brand-muted: 145 30% 25%;
|
|
|
|
--warning: 43 96% 56%;
|
|
--warning-foreground: 0 0% 0%;
|
|
|
|
/* Lifted well above the light value — 50% lightness violet on a near-black background reads as muddy
|
|
grey at 12px, which is exactly the size it is used at. */
|
|
--info: 263 90% 70%;
|
|
--info-foreground: 0 0% 100%;
|
|
|
|
/* Busy: running, queued, in flight. See base.css. */
|
|
--busy: 43 96% 56%;
|
|
--busy-foreground: 20 14% 8%;
|
|
--busy-ink: 43 96% 70%;
|
|
|
|
--border: 217.2 32.6% 17.5%;
|
|
--input: 217.2 32.6% 17.5%;
|
|
--ring: 212.7 26.8% 83.9%;
|
|
|
|
/* The original dark block never overrode these, so the light values were in force. Written out because
|
|
a theme that silently inherits from another is the thing this file exists to stop. */
|
|
--cta: 211 74.77% 45.58%;
|
|
--cta-foreground: 0 0% 100%;
|
|
--ctahover: 211 91.53% 34.82%;
|
|
|
|
--naturegreen: 145 79% 38%;
|
|
--naturegreen-foreground: 0 0% 100%;
|
|
|
|
--radius: 0.5rem;
|
|
|
|
/* ── Data visualisation and status ────────────────────────────────────────────────────────────── */
|
|
--chart-primary: 211 82% 64%;
|
|
--chart-secondary: 211 82% 84%;
|
|
--status-success: 142 76% 36%;
|
|
--status-warning: 43 96% 56%;
|
|
--status-in-progress: 211 82% 64%;
|
|
|
|
/* ── Chrome ───────────────────────────────────────────────────────────────────────────────────── */
|
|
--scrollbar-thumb: #444;
|
|
--scrollbar-thumb-hover: #555;
|
|
--scrollbar-thin-thumb: rgb(128 128 128 / 0.3);
|
|
--scrollbar-thin-thumb-hover: rgb(128 128 128 / 0.5);
|
|
}
|