Files
platform/src/workspaces/theme/css/themes/duck-dark.css
T
pastilhasandClaude Opus 5 12f1e93c4a panels are a themed surface, not three literal rgba pairs
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>
2026-08-16 23:22:41 +00:00

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);
}