PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.11
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.11
1.1.11 1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 All 35 releases
← All changes | assets/css/variables.css +844 -55 1.0.11.1.11 View file →
@@ -82,8 +82,38 @@
82 82 font-display: swap;
83 83 }
84 84
85 85 /*
86 + * ---- Registered, so "undeclared" never means transparent ---------
87 + *
88 + * The scope note below keeps this palette out of iframe documents on
89 + * purpose: an admin page inside a window renders with the values its
90 + * own stylesheets were written with. That promise has one hole CSS
91 + * digs by itself — a stylesheet that consumes
92 + * `var(--wp-admin-theme-color)` with no fallback, in a document where
93 + * nothing declares it, does not fall back to an earlier declaration
94 + * in the cascade. An unresolved `var()` is invalid at computed-value
95 + * time, so the property computes to `initial` — and an unregistered
96 + * custom property's initial value is the guaranteed-invalid value,
97 + * which for a `background` means transparent. Core's own scheme files
98 + * declare the property, but a third-party admin scheme that consumes
99 + * it without declaring it renders `.button-primary` white-on-white
100 + * inside every chromeless window (#702).
101 + *
102 + * Registering the property gives "undeclared" a real answer:
103 + * WordPress's default admin colour, the same value Core's fallbacks
104 + * reach for. Declarations are untouched — a scheme, the palette
105 + * below, or the accent picker's inline style all keep winning exactly
106 + * as before. Registration only decides what the absence of all of
107 + * them computes to.
108 + */
109 +@property --wp-admin-theme-color {
110 + syntax: "<color>";
111 + inherits: true;
112 + initial-value: #3858e9;
113 +}
114 +
115 +/*
86 116 * ---- Scope: the shell document, and nothing else -----------------
87 117 *
88 118 * `body.os-active` rather than `:root`, and that is
89 119 * load-bearing rather than tidy.
@@ -110,8 +140,22 @@
110 140 * Do not remove that dependency; see the note in
111 141 * `openstation_enqueue_desktop_theme_style()`.
112 142 */
113 143 body.os-active {
144 + /* MIO's conversation follows desktop themes through these public tokens. */
145 + --os-mio-chat-bg: var(--os-ui-modal-bg, #15151e);
146 + --os-mio-chat-fg: var(--os-ui-modal-text, #f4f4fb);
147 + --os-mio-chat-muted: var(--os-ui-modal-text-muted, #b4b4c6);
148 + --os-mio-chat-hover-bg: color-mix(in srgb, var(--os-mio-chat-bg, #fff) 90%, var(--os-mio-chat-fg, #1d2327));
149 + --os-mio-chat-border: color-mix(in srgb, var(--os-ui-accent, #a855f7) 40%, transparent);
150 + --os-mio-chat-user-bg: color-mix(in srgb, var(--os-ui-accent, #3f6dff) 15%, transparent);
151 + --os-mio-chat-glow: color-mix(in srgb, var(--os-ui-accent-dim, #ff4fd8) 10%, transparent);
152 + --os-mio-launcher-bg: color-mix(in srgb, var(--os-mio-chat-bg, #fff) 62%, transparent);
153 + --os-mio-callout-bg: var(--os-mio-chat-bg, #15151e);
154 + --os-mio-callout-fg: var(--os-mio-chat-fg, #f4f4fb);
155 + --os-mio-callout-border: color-mix(in srgb, var(--os-ui-accent-dim, #a855f7) 32%, transparent);
156 + --os-mio-chat-radius: max(18px, var(--os-window-radius, 22px));
157 +
114 158 /*
115 159 * ---- Desk --------------------------------------------------
116 160 *
117 161 * `Space`, the brand's quiet deep-space backdrop: a linear
@@ -191,10 +235,22 @@
191 235
192 236 /* Window chrome — Obsidian body inside a Starlight hairline. */
193 237 --os-window-bg: #1a1721;
194 238 --os-window-border: rgba(255, 251, 255, 0.12);
195 - --os-window-radius: 8px;
196 239 /*
240 + * Window corner. Softer than the 8px the shell carried before, so
241 + * a window reads as an object on the desk rather than a panel
242 + * pinned to it.
243 + *
244 + * The tab strip's own radius is deliberately NOT tied to this one.
245 + * A tab is 30px tall, so a corner anywhere near this size eats the
246 + * whole straight edge and turns the tab into a capsule — it stops
247 + * reading as a folder tab attached to the page, which is the one
248 + * thing the tab has to say. `--os-tabs-radius` stays smaller and
249 + * independent on purpose.
250 + */
251 + --os-window-radius: 16px;
252 + /*
197 253 * Shadows stay black and go deeper than they were: on a Void desk
198 254 * a soft grey shadow is invisible, and depth is the only thing
199 255 * separating a window from the sky behind it.
200 256 */
@@ -234,16 +290,21 @@
234 290
235 291 /*
236 292 * ---- Title bar ---------------------------------------------
237 293 *
238 - * Astro when focused, Obsidian when not: the focused window's
239 - * chrome lifts one step up the Shade ramp while its unfocused
240 - * neighbours sit flush with their own bodies. That is the entire
241 - * focus signal, and it costs no colour — which matters, because
242 - * the accent is spoken for.
294 + * Obsidian when focused, Void when not: the focused window's
295 + * chrome sits one step up the Shade ramp while its unfocused
296 + * neighbours sink toward the desk they are lying on. That is the
297 + * entire focus signal, and it costs no colour — which matters,
298 + * because the accent is spoken for.
299 + *
300 + * The pair used to be Astro-over-Obsidian, a step higher. It came
301 + * down so a focused window's title bar and its tab strip are the
302 + * SAME Obsidian, and the only thing lifting out of that surface is
303 + * the tab itself. The step is the same size; the whole ramp moved.
243 304 */
244 - --os-titlebar-bg: #1a1721;
245 - --os-titlebar-bg-focused: #33303a;
305 + --os-titlebar-bg: #0c0b0f;
306 + --os-titlebar-bg-focused: #1a1721;
246 307 --os-titlebar-color: #99969c;
247 308 --os-titlebar-color-focused: #fffbff;
248 309 --os-titlebar-height: 40px;
249 310 /* Hairline between page chrome and window chrome. */
@@ -250,8 +311,35 @@
250 311 --os-titlebar-divider: rgba(255, 251, 255, 0.12);
251 312 --os-titlebar-divider-unfocused: rgba(255, 251, 255, 0.06);
252 313
253 314 /*
315 + * The status ring — leading mark of the title bar, where the app
316 + * icon used to be. Four states: the resting ring is Starlight,
317 + * work and success are both Pulse, failure is the danger colour.
318 + *
319 + * Pulse twice over is not an oversight. In flight and landed
320 + * differ in FILL — an open ring breathing, then a solid disc with
321 + * a check — and failure differs from both in fill AND glyph AND
322 + * hue. Shape carries the distinction that colour alone cannot for
323 + * a user who can't separate the two hues, and the accent stays the
324 + * shell's own voice for "this is your station working".
325 + *
326 + * Failure resolves through `--os-ui-danger` and is the one value
327 + * here that must not be quietened: a failure that whispers is a
328 + * failure the user misses.
329 + *
330 + * The resting ring is one value in both title-bar states, not two:
331 + * the ring reports a phase, and dimming it on an unfocused window
332 + * would make `idle` say something different depending on which
333 + * window you last clicked.
334 + */
335 + --os-titlebar-activity-idle-color: #fffbff;
336 + --os-titlebar-activity-color: var(--os-ui-accent, #2271b1);
337 + --os-titlebar-activity-saved-color: var(--os-ui-accent, #2271b1);
338 + --os-titlebar-activity-failed-color: var(--os-ui-danger, #d63638);
339 + --os-titlebar-activity-size: 16px;
340 +
341 + /*
254 342 * Title-bar control glyphs — minimise / maximise / close, the ⋯
255 343 * menu trigger, and the screen-meta cluster — in each of the two
256 344 * title-bar states.
257 345 *
@@ -342,8 +430,45 @@
342 430 --os-ui-surface-subtle: rgba(255, 251, 255, 0.03);
343 431 --os-ui-bg: #1a1721;
344 432 --os-ui-bg-subtle: rgba(255, 251, 255, 0.03);
345 433
434 + /*
435 + * Fields — the surface an input paints, for markup in the LIGHT
436 + * DOM.
437 + *
438 + * The kit's own controls don't need these: `<os-text-field>` and
439 + * friends resolve `--os-window-bg` inside their shadow roots,
440 + * which the window chrome sets. A plugin writing a plain
441 + * `<input>` into a native window's body has neither, and the
442 + * palette had no general answer — no `surface` variant means
443 + * "input". What it had was `--os-ui-modal-field-bg`, which is a
444 + * MODAL token: right value, wrong scope, and the sort of thing a
445 + * plugin author finds by grepping for a colour that looks close.
446 + *
447 + * Consumers keep the pre-brand WordPress-admin literals as their
448 + * fallbacks — `#fff`, `#8c8f94`, `#2c3338` — so an unstyled page
449 + * lands on the classic admin's own field, not on nothing:
450 + *
451 + * background: var( --os-ui-field-bg, #fff );
452 + * border: 1px solid var( --os-ui-field-border, #8c8f94 );
453 + * color: var( --os-ui-field-fg, #2c3338 );
454 + */
455 + --os-ui-field-bg: #33303a;
456 + --os-ui-field-border: #4d4a52;
457 + --os-ui-field-fg: #fffbff;
458 +
459 + /*
460 + * Field sizing. The kit's own `<os-text-field>` and `<os-textarea>`
461 + * (and every kit control that hosts a typing input) read these for
462 + * the control's type size and corner. The phone layer raises the
463 + * size to 16px — below that, iOS zooms the whole page into a
464 + * focused control and never zooms back — and rounds its search;
465 + * a theme may do the same anywhere.
466 + */
467 + --os-ui-field-font-size: 13px;
468 + --os-ui-field-font-size-compact: 12px;
469 + --os-ui-field-radius: 6px;
470 +
346 471 /* Text — Starlight down through the Shade ramp. */
347 472 --os-ui-fg: #fffbff;
348 473 --os-ui-fg-muted: #b3afb5;
349 474 --os-ui-fg-faint: #66636b;
@@ -407,8 +532,18 @@
407 532 --os-ui-selection-fg: #fffbff;
408 533
409 534 /* Accent — the identity moment. */
410 535 --os-ui-accent: #f252fc;
536 + /*
537 + * Ink on the accent FILL: the tick in a checked box, the dot in a
538 + * radio, the label of a primary button. Distinct from
539 + * `--os-ui-fg-on-accent`, which the shell reads as "light text on
540 + * a dark surface" in seventy-odd places that are not the accent.
541 + * Starlight here for Pulse; the accent picker rewrites it inline
542 + * to Void whenever the chosen accent is light (Starlight, Sirius,
543 + * Nebula, Lagoon), so the pair always agree.
544 + */
545 + --os-ui-accent-ink: #fffbff;
411 546 --os-ui-accent-strong: #ec9bff;
412 547 --os-ui-accent-soft: color-mix(in srgb, var(--os-ui-accent-dim) 14%, transparent);
413 548 /*
414 549 * Pulse, one step back — and the single knob for how loud the
@@ -527,8 +662,47 @@
527 662
528 663 /* The fill itself. Holomesh, so the mesh is the default look. */
529 664 --os-ui-holo-fill: var(--os-mesh-holo);
530 665 /*
666 + * A hero FIELD, as distinct from a hero control.
667 + *
668 + * `--os-ui-holo-fill` is sized for a surface a control wears — a
669 + * button, a chip, a progress bar. Stretch that same value across
670 + * a few hundred square pixels of panel and a theme's answer stops
671 + * working: Legacy's `#f0f6fc -> #f6f7f7` reads as "on" on a 40px
672 + * chip and as nothing at all on a rail, where it lands within a
673 + * few units of the surface behind it.
674 + *
675 + * So a large decorative field reads THIS instead, and a theme
676 + * gets to answer the two cases separately — how a control looks
677 + * when it is on, and how much of itself the station shows in the
678 + * background. Legacy sets a flat pre-brand wash here while
679 + * leaving its control fill alone.
680 + *
681 + * The default is an aurora, and it is built differently from the
682 + * five meshes on purpose. Those are OPAQUE light surfaces — the
683 + * darkest stop in Holomesh still sits above 60% luminance — which
684 + * is right for a control that has to read as lit against whatever
685 + * is behind it. Spread one across a rail and the only way to calm
686 + * it down is `opacity`, which drags every hue toward the surface
687 + * underneath: on Void that is grey, and the mesh dies as a
688 + * grey-mauve smear.
689 + *
690 + * So the alpha lives in the COLOUR STOPS here, over transparent.
691 + * The desk shows through instead of being covered, the hues keep
692 + * their chroma at any strength, and the field stays dark the way
693 + * an aurora is dark — light added to a night sky, not a pale
694 + * sheet laid over one. Hues are the brand's: violet and Nebula
695 + * through the upper curtains, Sirius cyan and Holomesh's mint
696 + * below, one wide Pulse bloom tying them together.
697 + */
698 + --os-ui-hero-mesh:
699 + radial-gradient(ellipse 62% 38% at 34% 20%, rgba(170, 103, 255, 0.58) 0%, rgba(170, 103, 255, 0) 74%),
700 + radial-gradient(ellipse 54% 33% at 58% 36%, rgba(236, 155, 255, 0.45) 0%, rgba(236, 155, 255, 0) 76%),
701 + radial-gradient(ellipse 68% 30% at 26% 50%, rgba(125, 239, 245, 0.32) 0%, rgba(125, 239, 245, 0) 74%),
702 + radial-gradient(ellipse 58% 28% at 46% 66%, rgba(147, 240, 198, 0.26) 0%, rgba(147, 240, 198, 0) 76%),
703 + radial-gradient(ellipse 96% 62% at 40% 42%, rgba(242, 82, 252, 0.18) 0%, rgba(242, 82, 252, 0) 82%);
704 + /*
531 705 * Glyphs and text ON that fill. Void, not Starlight — every mesh
532 706 * in the brand is a LIGHT surface (its darkest stop, Holomesh's
533 707 * #afa2e8, still sits at 62% luminance), so Starlight on it is a
534 708 * white-on-lilac 1.4:1 that looks fine in a mock and is unreadable
@@ -610,21 +784,21 @@
610 784 * satisfy WCAG 1.4.11.
611 785 */
612 786 --os-ui-holo-track-edge: #66636b;
613 787 /*
614 - * Focus. One ring for the whole kit — Pulse, offset, over a soft
615 - * halo, so it reads on Obsidian, on a mesh, and on the near-white
788 + * Focus. One ring for the whole kit — the accent, offset by a Void
789 + * gap, so it reads on Obsidian, on a mesh, and on the near-white
616 790 * of a legacy theme alike.
617 791 *
618 - * Note which layer dims and which does not. The RING is full Pulse
619 - * and stays there: it is the only thing on screen saying where the
620 - * keyboard is, and a focus indicator is the last place to trade
621 - * legibility for calm. Only the bloom behind it comes down, from
622 - * 45% to 30%, and onto the dim — which is the layer that was
623 - * making a focused control look like it was on fire.
792 + * The RING is full accent and stays there: it is the only thing on
793 + * screen saying where the keyboard is, and a focus indicator is the
794 + * last place to trade legibility for calm. The bloom that used to
795 + * sit behind it is gone: it was the layer that made a focused
796 + * control look like it was on fire, and the Void gap already does
797 + * the work of separating the ring from whatever it lands on.
624 798 */
625 - --os-ui-focus-ring: 0 0 0 2px rgba(12, 11, 15, 0.9), 0 0 0 4px #f252fc,
626 - 0 0 12px 2px color-mix(in srgb, var(--os-ui-accent-dim) 30%, transparent);
799 + --os-ui-focus-ring: 0 0 0 2px rgba(12, 11, 15, 0.9),
800 + 0 0 0 4px var(--os-ui-accent, #f252fc);
627 801 /*
628 802 * …and one for FIELDS, which is a different problem. A text input
629 803 * already has a border to thicken and it sits in a column of other
630 804 * inputs, so the ring above — designed to survive landing on a
@@ -632,12 +806,112 @@
632 806 * tightens the field's own edge to Pulse and puts a soft halo
633 807 * outside it: unmistakable, and quiet enough to live in a stack of
634 808 * twelve.
635 809 */
636 - --os-ui-focus-ring-field: 0 0 0 1px #f252fc,
810 + --os-ui-focus-ring-field: 0 0 0 1px var(--os-ui-accent, #f252fc),
637 811 0 0 0 4px color-mix(in srgb, var(--os-ui-accent-dim) 16%, transparent);
638 812
639 813 /*
814 + * The selected row of a VERTICAL `<os-tabs>`: the sidebar in
815 + * OpenStation Preferences, and any native window that lays its
816 + * pages down the side rather than across the top.
817 + *
818 + * The one selection on the station that keeps the accent. The row
819 + * runs full-bleed and says "this one" with a 2px accent line at its
820 + * leading edge, the bloom that line throws back across the row, and
821 + * a wash fading out towards the label. Everywhere else a selection
822 + * is a surface (a grey key, an outline, a flat fill); the sidebar is
823 + * where you are, and the brand marks it.
824 + *
825 + * The three coloured layers are DERIVED from the accent: `-edge` is
826 + * the accent flat, `-wash` and `-bloom` resolve through
827 + * `--os-ui-accent-dim` like every other ambient use, so a picked
828 + * accent reaches the row on this palette and on Legacy alike (see
829 + * `desktopThemesLegacy.php`: a theme cannot answer a derived token,
830 + * so a derivation is shared). How much of each shows, and the row's
831 + * shape, are literals a theme answers on its own: edge width, wash
832 + * and bloom opacity, and a fill, radius and inset that together
833 + * would turn the row into a lifted pill. The wash's opacity scales
834 + * every stop of the gradient, because a background image has no
835 + * opacity of its own and both of the row's pseudo-elements are
836 + * already spent on the edge and the bloom.
837 + */
838 + --os-ui-tab-edge: linear-gradient(
839 + var(--os-ui-accent, #f252fc),
840 + var(--os-ui-accent, #f252fc)
841 + );
842 + --os-ui-tab-wash: linear-gradient(
843 + 90deg,
844 + color-mix(
845 + in srgb,
846 + var(--os-ui-accent-dim) calc(16% * var(--os-ui-tab-wash-opacity, 1)),
847 + transparent
848 + )
849 + 0%,
850 + rgba(255, 251, 255, calc(0.04 * var(--os-ui-tab-wash-opacity, 1))) 42%,
851 + transparent 100%
852 + );
853 + --os-ui-tab-bloom: linear-gradient(
854 + 90deg,
855 + color-mix(in srgb, var(--os-ui-accent-dim) 26%, transparent),
856 + transparent
857 + );
858 + --os-ui-tab-edge-width: 2px;
859 + --os-ui-tab-wash-opacity: 1;
860 + --os-ui-tab-bloom-opacity: 1;
861 + --os-ui-tab-fill: transparent;
862 + --os-ui-tab-radius: 0px;
863 + --os-ui-tab-inset: 0px;
864 +
865 + /*
866 + * `<os-segmented>`, same split again. The thumb and its label still
867 + * mix from the accent, so Legacy and any theme that answers 100%
868 + * keep a coloured pill that follows the picker. This palette answers
869 + * 0%: a Void track with the chosen option as a mid-grey key and a
870 + * Starlight label, whatever accent is picked.
871 + *
872 + * The key's grey is set by contrast, not by taste. The first pass
873 + * used the sidebar row's grey, and it sat at 1.37:1 against the
874 + * track and 1.15:1 against the card around it, so the key read as a
875 + * hole in the track rather than a thing pressed into it. This grey
876 + * clears 3:1 against Void, what a selected state needs against its
877 + * neighbours, and still carries its Starlight label at 5.7:1. A
878 + * small shadow under it and a hairline around the track do the
879 + * rest: without the hairline, a Void track on the page behind the
880 + * dock options measured 1.05:1 and all but disappeared.
881 + *
882 + * Under the pointer an unselected option takes a faint Starlight
883 + * lift instead of the holographic film.
884 + */
885 + --os-ui-segmented-bg: #0c0b0f;
886 + --os-ui-segmented-edge: inset 0 0 0 1px rgba(255, 251, 255, 0.1);
887 + --os-ui-segmented-selected-accent: 0%;
888 + --os-ui-segmented-selected-base: #67636e;
889 + --os-ui-segmented-selected-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
890 + --os-ui-segmented-hover-bg: rgba(255, 251, 255, 0.06);
891 + --os-ui-segmented-hover-sheen: none;
892 +
893 + /*
894 + * The chosen tile in a swatch grid (wallpapers, the theme and
895 + * layout cards in Preferences, and any grid a plugin builds from
896 + * `<os-swatch>`), same split. The ring is the accent and stays
897 + * derived; this palette sets its width to 0 and lifts the tile
898 + * instead: a solid Starlight stroke outlines it, a shadow sets it
899 + * above the grid, and a Starlight disc with a tick cut out of it
900 + * sits in the corner. The stroke is Starlight rather than the
901 + * accent, like the badge, so the chosen tile stands out the same
902 + * way whichever accent is picked; a translucent hairline was too
903 + * faint on the dark theme cards. Legacy answers 2px, no lift, no
904 + * badge. The accent chips in the colour row keep their ring
905 + * whatever these say: a colour is the whole content there, and a
906 + * lift on a 28px square is invisible.
907 + */
908 + --os-ui-swatch-ring-width: 0px;
909 + --os-ui-swatch-lift: 0 0 0 1px #fffbff,
910 + 0 12px 24px -12px rgba(0, 0, 0, 0.8);
911 + --os-ui-swatch-badge-bg: #fffbff;
912 +
913 + /*
640 914 * ---- Motion --------------------------------------------------
641 915 *
642 916 * Four durations and three curves, and every animated thing in the
643 917 * kit picks from them. Not for tidiness: a panel where the switch
@@ -670,8 +944,16 @@
670 944 */
671 945 --os-ui-ease-spring: cubic-bezier(0.32, 1.5, 0.55, 1);
672 946 /* Decelerating. The default for anything arriving. */
673 947 --os-ui-ease-out: cubic-bezier(0.22, 0.9, 0.28, 1);
948 + /*
949 + * Accelerating — the mirror of `out`, and the default for anything
950 + * LEAVING. A surface that eases out on the way in and eases in on
951 + * the way out is the difference between "dismissed" and "undone":
952 + * decelerating into nothing reads as the thing hesitating, which
953 + * is the wrong note when the user has already moved on.
954 + */
955 + --os-ui-ease-in: cubic-bezier(0.4, 0, 1, 1);
674 956 /* Symmetric, for a loop that has to come back where it started. */
675 957 --os-ui-ease-loop: cubic-bezier(0.45, 0, 0.55, 1);
676 958
677 959 /*
@@ -701,9 +983,9 @@
701 983
702 984 /*
703 985 * Dialogs, menus and flyouts.
704 986 *
705 - * The five `--os-ui-modal-*` names below are the escape hatch
987 + * The `--os-ui-modal-*` names below are the escape hatch
706 988 * `<os-modal>` needs. Its dialog surface is dark whatever the
707 989 * admin colour scheme says, so it re-points `--os-ui-fg`,
708 990 * `--os-ui-fg-muted`, `--os-ui-border`, `--os-window-bg` and
709 991 * `--os-ui-button-bg-hover` on its own `:host` — and a declaration
@@ -710,8 +992,22 @@
710 992 * on the host outranks anything the host inherits, which is how
711 993 * the palette used to stop at the dialog's edge. It reads these
712 994 * instead, so the station owns the dialog again and the literals
713 995 * behind them stay as the no-stylesheet floor.
996 + *
997 + * The set has to cover a dark context COMPLETELY, and the four
998 + * added last are the ones that proved it. A dialog re-pointing
999 + * only its text colours is fine while the palette around it is
1000 + * dark too — every unre-pointed token happens to agree. Put a
1001 + * LIGHT palette outside it (any theme in the admin's own colours,
1002 + * Legacy included) and the halves come apart: `--os-ui-surface`
1003 + * stays white, so `<os-select>` inside the dialog painted a white
1004 + * trigger and the re-pointed `--os-ui-fg` wrote near-white text
1005 + * onto it. `--os-ui-hover` was a black wash over a dark row.
1006 + *
1007 + * So the rule for anything added here: if a token names a SURFACE
1008 + * or a wash on one, the dialog owns it. Leaving one out is not
1009 + * "inherit the theme", it is "disagree with the other five".
714 1010 */
715 1011 --os-ui-modal-bg: #1a1721;
716 1012 --os-ui-modal-text: #fffbff;
717 1013 --os-ui-modal-text-muted: #b3afb5;
@@ -717,8 +1013,12 @@
717 1013 --os-ui-modal-text-muted: #b3afb5;
718 1014 --os-ui-modal-border: #4d4a52;
719 1015 --os-ui-modal-field-bg: #33303a;
720 1016 --os-ui-modal-button-bg-hover: rgba(255, 251, 255, 0.14);
1017 + --os-ui-modal-surface: #1a1721;
1018 + --os-ui-modal-surface-elevated: #33303a;
1019 + --os-ui-modal-border-strong: #4d4a52;
1020 + --os-ui-modal-hover: rgba(255, 251, 255, 0.06);
721 1021 --os-ui-confirm-dialog-bg: #1a1721;
722 1022 --os-ui-context-menu-bg: #1a1721;
723 1023 --os-ui-context-menu-separator-color: rgba(255, 251, 255, 0.1);
724 1024 --os-ui-flyout-shadow: 0 16px 48px rgba(0, 0, 0, 0.6);
@@ -761,10 +1061,10 @@
761 1061 * only from the component's own `::slotted( a )`. See the comment
762 1062 * there: a slotted link is a document-tree element, so wp-admin's
763 1063 * bare `a` rule outranks anything the shadow root says about it.
764 1064 */
765 - --os-ui-notice-link: #ec9bff;
766 - --os-ui-notice-link-hover: #fffbff;
1065 + --os-ui-notice-link: #fffbff;
1066 + --os-ui-notice-link-hover: #ccc8ce;
767 1067 --os-ui-badge-danger-bg: rgba(255, 90, 90, 0.16);
768 1068 --os-ui-badge-success-bg: rgba(147, 240, 198, 0.16);
769 1069 --os-ui-badge-warning-bg: rgba(248, 242, 182, 0.16);
770 1070 --os-ui-badge-info-bg: rgba(194, 241, 241, 0.16);
@@ -859,9 +1159,8 @@
859 1159 /* Search-match highlight inside a label. A WASH, not a fill: the
860 1160 text keeps its own colour, so the wash has to stay light enough
861 1161 for Starlight to carry over it. */
862 1162 --os-ui-search-highlight-bg: rgba(248, 242, 182, 0.3);
863 - --os-ui-color-accent: #f252fc;
864 1163 /*
865 1164 * The content graph's cluster hue is NOT retinted. Graph node
866 1165 * colours are composed artwork that encodes meaning — the docs list
867 1166 * them under "what stays fixed" — and moving this one to Nebula put
@@ -867,18 +1166,82 @@
867 1166 * them under "what stays fixed" — and moving this one to Nebula put
868 1167 * white cluster labels on a pale lilac chip at 1.9:1. It keeps its
869 1168 * own colour, and the label keeps carrying on it.
870 1169 *
871 - * The graph's toolbar is chrome, though, and it does follow. The
872 - * count pill on an ACTIVE filter chip is a 70%-white fill, and it
873 - * was carrying `--os-ui-accent-strong` numerals — Nebula on white,
874 - * ~1.7:1. It is one more bright fill naming its own dark text, the
875 - * same escape hatch `--os-ui-ribbon-fg` and `--os-ui-step-chip-fg`
876 - * take, and for the same reason.
1170 + * The graph's toolbar is chrome, though, and it follows the same
1171 + * split as selection everywhere else: the accent stays derived, a
1172 + * literal says how much of it shows. An ON filter chip mixes its
1173 + * edge, wash and text from the accent by `-accent`, towards the
1174 + * neutrals below; this palette answers 0%, so an on chip reads like
1175 + * the selected theme card in Preferences, a Starlight outline around
1176 + * the dark surface. Legacy answers 100%. An OFF chip sits on the
1177 + * toolbar with the strong border as its edge, because the plain
1178 + * border is the toolbar's own colour and a chip drawn with it has no
1179 + * outline at all.
1180 + *
1181 + * The count pill is the strong border's grey on both, with Starlight
1182 + * numerals: muted numerals on that grey land at 4.0:1, under what
1183 + * 12px text needs.
877 1184 */
878 - --os-ui-cg-chip-count-fg-active: #0c0b0f;
1185 + --os-ui-cg-chip-accent: 0%;
1186 + --os-ui-cg-chip-border: #4d4a52;
1187 + --os-ui-cg-chip-border-active: #fffbff;
1188 + --os-ui-cg-chip-fill-active: #1a1721;
1189 + --os-ui-cg-chip-count-bg: #4d4a52;
1190 + --os-ui-cg-chip-count-fg: #fffbff;
1191 + --os-ui-cg-chip-count-bg-active: #4d4a52;
1192 + --os-ui-cg-chip-count-fg-active: #fffbff;
879 1193
880 1194 /*
1195 + * ---- The widget card's public token contract ----------------
1196 + *
1197 + * Five names a third-party widget stylesheet is told to read.
1198 + * The list lives in `src/plugins/starter-widget/styles.css`,
1199 + * which is the file plugin authors copy — so it is a contract,
1200 + * not a convenience, and four of the five were documented
1201 + * without ever being declared. Every consumer fell through to
1202 + * the light-mode grey in its own `var()` fallback, on a card
1203 + * whose glass is dark: Post Stats' metadata measured 3.81:1
1204 + * where `.os-widgets__title` on the same surface measures 18.4.
1205 + *
1206 + * They are mostly literals rather than aliases of the text ramp,
1207 + * and that is the point. `.os-widgets__card` paints a fixed dark
1208 + * glass — `--os-ui-color-surface` below IS that colour, and the
1209 + * card reads it — under every desktop theme, so a name that
1210 + * flips with the theme is the wrong chain here: Legacy's
1211 + * `--os-ui-fg-muted` is `#50575e`, which lands at 2.54:1 on the
1212 + * glass and makes the bug WORSE for anyone wearing it. The two
1213 + * text names below do chain, but through the two names Legacy
1214 + * keeps light — the ones describing the same on-dark chrome
1215 + * this card is.
1216 + *
1217 + * A theme that wants to move a widget card declares these names
1218 + * itself, the way Legacy already declares the accent.
1219 + */
1220 + --os-ui-color-surface: rgba(20, 20, 22, 0.55);
1221 + /* What the card's own `color` already resolves to — so a widget
1222 + asking for "primary text" gets the text it inherited. */
1223 + --os-ui-color-text: var(--os-ui-fg-on-accent, #fffbff);
1224 + /* The shell's muted-on-dark. 9.2:1 on the glass, and Legacy
1225 + keeps it at `rgba( 255, 255, 255, 0.7 )`. */
1226 + --os-ui-color-text-subtle: var(--os-fg-muted, rgba(255, 251, 255, 0.7));
1227 + /* A hairline INSIDE the card, so a touch stronger than the
1228 + card's own 0.08 edge, which is drawn against the wallpaper.
1229 + Literal because no general on-dark hairline exists: the ones
1230 + Legacy keeps light are `--os-dock-border` and
1231 + `--os-cn-border`, and borrowing either is the right value at
1232 + the wrong scope. It reads quieter than what it replaces —
1233 + the widgets' own fallback was `#e5e7eb`, a light-theme
1234 + divider that on dark glass drew the loudest line in the
1235 + station. 0.12 is what the window and dock edges use. */
1236 + --os-ui-color-border: rgba(255, 251, 255, 0.12);
1237 + /* The one name that has to reach the accent picker. It was a
1238 + hard `#f252fc`, so a widget told to "use the accent for
1239 + buttons and links" stayed brand pink after the user chose
1240 + teal, while every control around it moved. */
1241 + --os-ui-color-accent: var(--os-ui-accent, #f252fc);
1242 +
1243 + /*
881 1244 * ---- Typography --------------------------------------------
882 1245 *
883 1246 * Geist for everything human — headlines, UI copy, body text — and
884 1247 * Geist Mono for the instrument voice: labels, metadata, statuses,
@@ -984,21 +1347,26 @@
984 1347 * / -bg / -fg. Falls through to the generic
985 1348 * icon-badge token, so "badges are 22px" reaches
986 1349 * the bin too.
987 1350 *
988 - * The count badges keep their red, and keep it as a LITERAL: a
989 - * badge is a status, not an identity moment, and Pulse next to a
990 - * Pulse-accented dock tile would read as decoration rather than as
991 - * "three things need you". Naming the gradient here also keeps it
992 - * a gradient — both stops used to resolve through `--os-ui-danger`,
993 - * which the palette moved, flattening the badge to one flat red
994 - * and turning its white numerals Void. The bin's neutral badge has
995 - * no such constraint and follows the station.
1351 + * The count badges wear Pulse, and wear it as a LITERAL gradient:
1352 + * both stops used to resolve through `--os-ui-danger`, which the
1353 + * palette moved, flattening the badge to one flat fill and turning
1354 + * its numerals Void by accident. Naming the stops here keeps it a
1355 + * gradient on purpose. The bin's neutral badge is deliberately not
1356 + * part of this: a count of things in the trash is ambient state,
1357 + * not something asking for you.
1358 + *
1359 + * **The numerals are Void, not Starlight, and that is a
1360 + * requirement rather than a preference.** Starlight on Pulse is
1361 + * 2.9:1, which fails AA for text this small; Void on Pulse is
1362 + * 6.8:1. Any future retint of these has to keep the pair legible,
1363 + * so check the ratio before swapping the ink back to white.
996 1364 */
997 - --os-dock-badge-bg: linear-gradient(180deg, #ff5a5a 0%, #d63638 100%);
998 - --os-dock-badge-fg: #fffbff;
999 - --os-icon-badge-bg: linear-gradient(180deg, #ff5a5a 0%, #d63638 100%);
1000 - --os-icon-badge-fg: #fffbff;
1365 + --os-dock-badge-bg: linear-gradient(180deg, #f97dff 0%, #f252fc 100%);
1366 + --os-dock-badge-fg: #0c0b0f;
1367 + --os-icon-badge-bg: linear-gradient(180deg, #f97dff 0%, #f252fc 100%);
1368 + --os-icon-badge-fg: #0c0b0f;
1001 1369 --os-recycle-badge-bg: rgba(26, 23, 33, 0.85);
1002 1370 --os-recycle-badge-fg: rgba(255, 251, 255, 0.96);
1003 1371 --os-dock-recycle-badge-bg: rgba(26, 23, 33, 0.85);
1004 1372 --os-dock-recycle-badge-fg: rgba(255, 251, 255, 0.92);
@@ -1003,13 +1371,68 @@
1003 1371 --os-dock-recycle-badge-bg: rgba(26, 23, 33, 0.85);
1004 1372 --os-dock-recycle-badge-fg: rgba(255, 251, 255, 0.92);
1005 1373
1006 1374 /*
1375 + * ---- Chrome that sits on the wallpaper ---------------------
1376 + *
1377 + * The notch, the desktop icons and the Add widget pill paint
1378 + * straight onto the wallpaper, with no window behind them. Bare
1379 + * Starlight only works there while the wallpaper is dark, and not
1380 + * every one is: on Holomesh the three measured 1.5:1 to 2.2:1.
1381 + *
1382 + * **A plate and an ink are two different answers, and which one a
1383 + * surface gets depends on whether it is an object.**
1384 + *
1385 + * The notch and the Add widget pill are, so they take a PLATE and
1386 + * read on every wallpaper without anyone measuring anything. Each
1387 + * derives it from the glass it sits beside rather than mixing its
1388 + * own: the notch from the bottom dock pill (reaching
1389 + * `--os-dock-bg` second, so a theme that tokenised only its dock
1390 + * strip still moves it), the Add widget pill from the widget card
1391 + * whose stack it trails.
1392 + *
1393 + * Icons, captions and file tiles are not objects — plating each one
1394 + * turns a desk into a sheet of stickers — so they change INK, which
1395 + * needs someone to know how bright the desk is. `--os-desk-fg` is
1396 + * that answer, decided by `src/wallpapers/tone.ts` and carried by
1397 + * the `body.os-wallpaper-light` rule below. Retint the desk by
1398 + * naming the two literals it chooses between, never the chooser.
1399 + *
1400 + * `--os-icon-label-bg` is the belt to that pair of braces, for the
1401 + * wallpaper nobody can measure: it costs nothing on a dark desk
1402 + * (Void on Void), switches off where the tone is light, and holds
1403 + * Starlight up where the tone is simply unknown.
1404 + *
1405 + * The shadows sharpen rather than rescue: a halo moves the glyph
1406 + * edges, not the contrast ratio.
1407 + */
1408 + --os-notch-bg: var(--os-dock-floating-bg, var(--os-dock-bg, rgba(12, 11, 15, 0.62)));
1409 + --os-notch-border: var(--os-dock-floating-border, var(--os-dock-border, rgba(255, 251, 255, 0.12)));
1410 + --os-notch-shadow: var(--os-dock-floating-shadow, rgba(0, 0, 0, 0.55));
1411 + --os-notch-bg-hover: color-mix(
1412 + in srgb,
1413 + var(--os-dock-floating-bg, var(--os-dock-bg, rgba(12, 11, 15, 0.62))) 90%,
1414 + #fffbff
1415 + );
1416 + --os-icon-label-bg: rgba(12, 11, 15, 0.55);
1417 + --os-icon-label-shadow: 0 1px 2px rgba(12, 11, 15, 0.9);
1418 + --os-icon-glyph-shadow: drop-shadow(0 1px 3px rgba(12, 11, 15, 0.75));
1419 + --os-icon-hover-bg: rgba(255, 251, 255, 0.12);
1420 + --os-widgets-add-bg: var(--os-ui-color-surface, rgba(20, 20, 22, 0.55));
1421 + --os-widgets-add-bg-hover: color-mix(
1422 + in srgb,
1423 + var(--os-ui-color-surface, rgba(20, 20, 22, 0.55)) 90%,
1424 + #fffbff
1425 + );
1426 + --os-widgets-add-border: rgba(255, 251, 255, 0.38);
1427 + --os-desk-fg: var(--os-fg, #fffbff);
1428 + --os-desk-ink-light: #1a1721;
1429 +
1430 + /*
1007 1431 * ---- Tooltips ---------------------------------------------
1008 1432 *
1009 - * Two tokens own every tooltip in the shell — the dock tile
1010 - * tooltip, the content-graph satellite tooltip, and the My
1011 - * WordPress entity hover card.
1433 + * Two tokens own every tooltip CHIP in the shell — the dock tile
1434 + * tooltip and the content-graph satellite tooltip.
1012 1435 *
1013 1436 * They are worth naming rather than leaving derived. Without them
1014 1437 * tooltips borrow their colours from unrelated families —
1015 1438 * `--os-ui-scrim` (an overlay BACKDROP) or `--os-ui-surface-elevated`
@@ -1017,10 +1440,16 @@
1017 1440 * pairings come apart the moment the palette moves. On this
1018 1441 * palette `--os-ui-fg-on-accent` is Void, which would have rendered
1019 1442 * near-black text on a near-black chip.
1020 1443 *
1021 - * Secondary text inside the richer tooltips — the hover card's
1022 - * excerpt — still follows `--os-ui-fg-muted`.
1444 + * A chip is deliberately the SAME dark lozenge on every desktop
1445 + * theme, which is why these two are flat values and not derived
1446 + * from anything. That is right for one line of text pinned to a
1447 + * control, and wrong for a rich card: the My WordPress entity
1448 + * hover card used to read them and showed up Obsidian over a white
1449 + * Legacy window. It has its own derived family now —
1450 + * `--os-my-wordpress-card-*`, further down — and it still names
1451 + * these two as its last fallback.
1023 1452 */
1024 1453 --os-tooltip-bg: #33303a;
1025 1454 --os-tooltip-fg: #fffbff;
1026 1455
@@ -1042,14 +1471,39 @@
1042 1471 * rule and so must read the same two tokens).
1043 1472 */
1044 1473 --os-dock-width: 56px;
1045 1474 --os-dock-icon-size: 20px;
1475 + /*
1476 + * The indicator line a dynamic dock collapses into while parked
1477 + * (Preferences → Appearance → Desktop layout → Dock behavior):
1478 + * the iOS home indicator, painted in the accent at partial alpha
1479 + * so it reads as a mark on the wallpaper rather than a control.
1480 + * `-length` runs along the rail's edge, `-thickness` across it; a
1481 + * theme retunes any of the three.
1482 + */
1483 + --os-dock-indicator-length: 180px;
1484 + --os-dock-indicator-thickness: 5px;
1485 + --os-dock-indicator-bg: color-mix( in srgb, var( --os-ui-accent, #f252fc ) 72%, transparent );
1046 1486 --os-dock-bg: rgba(12, 11, 15, 0.72);
1047 1487 --os-dock-icon-color: rgba(255, 251, 255, 0.72);
1048 1488 --os-dock-icon-color-hover: #fffbff;
1049 - --os-dock-item-bg-hover: rgba(242, 82, 252, 0.18);
1050 - --os-dock-item-outline: #f252fc;
1489 + --os-dock-item-bg-hover: rgba(255, 251, 255, 0.08);
1051 1490 /*
1491 + * The tile whose window is in front sits on a lit plate: the same
1492 + * Starlight wash the hover uses, one step brighter, so "this is the
1493 + * app you are in" reads as depth rather than as a coloured mark.
1494 + * The running dot under every open app stays; a lit plate says
1495 + * which one is in front, the dots say which ones are open.
1496 + */
1497 + --os-dock-item-bg-focused: rgba(255, 251, 255, 0.1);
1498 + /*
1499 + * The status indicator and the focus ring, and both say "this
1500 + * one" about a tile the user chose — so they read the accent
1501 + * rather than a fixed colour. Starlight is what an untouched
1502 + * install shows, because that is the accent the picker starts on.
1503 + */
1504 + --os-dock-item-outline: var(--os-ui-accent, #f252fc);
1505 + /*
1052 1506 * Hairline between the dock and the desktop. Reaches the side
1053 1507 * placements (as a single inline-edge border) AND the floating
1054 1508 * bottom pill (as its full outline). Set `transparent` for a
1055 1509 * borderless dock.
@@ -1059,8 +1513,27 @@
1059 1513 * brighter top edge, an inset highlight, a drop shadow. Each falls
1060 1514 * back to the shared value above it.
1061 1515 */
1062 1516 --os-dock-border: rgba(255, 251, 255, 0.1);
1517 +
1518 + /*
1519 + * The dividers INSIDE the rail, which are a different job from the
1520 + * outline around it: they separate tiles that belong to different
1521 + * groups — core menus, plugin apps, and OpenStation's own controls.
1522 + *
1523 + * One treatment for all of them. An earlier pass gave the
1524 + * WordPress-to-OpenStation boundary Pulse and dropped the
1525 + * core-to-plugin one to a hairline, on the theory that only one
1526 + * boundary was worth reading. Two weights in one short rail read as
1527 + * two unrelated ideas instead of one system, so both are now the
1528 + * same line: Pulse at the waist, falling away to nothing at both
1529 + * ends, with a soft glow to hold it against the dock tint.
1530 + *
1531 + * Resolved one step back from the accent through
1532 + * `--os-ui-accent-dim`, where every ambient use of Pulse resolves,
1533 + * so "tone the station down" stays one edit.
1534 + */
1535 + --os-dock-divider: color-mix(in srgb, var(--os-ui-accent-dim) 70%, transparent);
1063 1536 --os-dock-floating-bg: rgba(12, 11, 15, 0.62);
1064 1537 --os-dock-floating-border: rgba(255, 251, 255, 0.12);
1065 1538 --os-dock-floating-border-top: rgba(255, 251, 255, 0.18);
1066 1539 --os-dock-floating-highlight: rgba(255, 251, 255, 0.1);
@@ -1066,8 +1539,67 @@
1066 1539 --os-dock-floating-highlight: rgba(255, 251, 255, 0.1);
1067 1540 --os-dock-floating-shadow: rgba(0, 0, 0, 0.55);
1068 1541
1069 1542 /*
1543 + * The phone layer (`mobile.css`). Its surfaces are the dock's
1544 + * family — translucent glass over the wallpaper, light glyphs —
1545 + * and read the dock tokens above for fill, text and lines. What
1546 + * the dock has no word for is declared here: the glass a tile, a
1547 + * round control and a switcher card are cut from, its pressed
1548 + * state, the shadow under a tile, the scrim behind the switcher,
1549 + * and the label shadow that keeps text legible over any wallpaper.
1550 + * A desktop theme that reskins the dock reskins the phone with it;
1551 + * one that wants the phone alone has these.
1552 + */
1553 + --os-mobile-glass: rgba(255, 251, 255, 0.1);
1554 + --os-mobile-glass-strong: rgba(255, 251, 255, 0.16);
1555 + --os-mobile-glass-border: rgba(255, 251, 255, 0.14);
1556 + --os-mobile-tile-shadow: 0 8px 20px rgba(0, 0, 0, 0.35);
1557 + --os-mobile-card-shadow: 0 -8px 24px rgba(0, 0, 0, 0.4);
1558 + --os-mobile-sheet-shadow: 0 -12px 40px rgba(0, 0, 0, 0.45);
1559 + --os-mobile-window-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
1560 + --os-mobile-scrim: rgba(0, 0, 0, 0.55);
1561 + --os-mobile-top-scrim: rgba(0, 0, 0, 0.45);
1562 + --os-mobile-label-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
1563 +
1564 + /*
1565 + * ---- The OpenStation layout ---------------------------------
1566 + *
1567 + * The constellation: the flyout that fans a menu's submenu out of
1568 + * its tile on hover, on every rail in every layout. The rail's
1569 + * divider used to live here too; it is shared chrome now and reads
1570 + * through `--os-dock-divider`.
1571 + *
1572 + * The constellation's SURFACE is Obsidian, deliberately. The mesh
1573 + * is spent on the row under the pointer and on the head's icon
1574 + * halo — the two moments where the panel is answering the user —
1575 + * and nowhere else. A flyout that was iridescent edge to edge
1576 + * would have nothing left to say when you actually pointed at
1577 + * something in it.
1578 + */
1579 + --os-cn-surface: rgba(26, 23, 33, 0.82);
1580 + --os-cn-border: rgba(255, 251, 255, 0.14);
1581 + --os-cn-shadow: 0 24px 64px rgba(0, 0, 0, 0.62),
1582 + 0 2px 8px rgba(0, 0, 0, 0.4);
1583 + --os-cn-fg: #fffbff;
1584 + --os-cn-fg-muted: rgba(255, 251, 255, 0.62);
1585 + --os-cn-legend: rgba(255, 251, 255, 0.4);
1586 + --os-cn-divider: rgba(255, 251, 255, 0.1);
1587 + /* The row under the pointer — the panel's identity moment. */
1588 + --os-cn-row-fill: var(--os-ui-holo-fill);
1589 + --os-cn-row-ink: var(--os-ui-holo-ink);
1590 + /* Beam: the thread from the panel's underside down to the tile. */
1591 + --os-cn-beam: color-mix(in srgb, var(--os-ui-accent-dim) 80%, transparent);
1592 + --os-cn-radius: 14px;
1593 + /*
1594 + * Above every window and above the dock. Two panels coexist while
1595 + * the pointer moves along the rail — one dismissing, one arriving
1596 + * — and the retiring one is painted one step below so it can
1597 + * never fade out on top of the menu being read.
1598 + */
1599 + --os-cn-z: 2147483000;
1600 +
1601 + /*
1070 1602 * ---- Shell surfaces ----------------------------------------
1071 1603 *
1072 1604 * The panels, tab strips and washes that belong to the shell
1073 1605 * rather than to the component kit. Same Obsidian-on-Void
@@ -1103,22 +1635,194 @@
1103 1635 --os-folder-window-bg: #1a1721;
1104 1636 --os-my-wordpress-bg: #1a1721;
1105 1637 --os-my-wordpress-fg: #fffbff;
1106 1638 --os-my-wordpress-surface: rgba(255, 251, 255, 0.06);
1639 + /*
1640 + * The entity hover card — the "thumb" that floats over a tile with
1641 + * a title, a featured image and an excerpt.
1642 + *
1643 + * It is NOT a dock chip, and it used to be painted as one.
1644 + * `--os-tooltip-bg` is a fixed dark lozenge on every theme by
1645 + * design — one line of text, always the same object, no reason to
1646 + * follow anything. The card borrowed it, so a light desktop theme
1647 + * summoned an Obsidian card over a white window, with a border in
1648 + * `--os-ui-border` and an excerpt in `--os-ui-fg-muted` that both
1649 + * followed the WINDOW instead. Three families, one surface.
1650 + *
1651 + * The card is window furniture: it belongs to the surface it was
1652 + * summoned from, so it follows the theme that paints that surface.
1653 + * Every value below is DERIVED rather than declared flat, which is
1654 + * what makes that true — a theme that names only
1655 + * `--os-my-wordpress-bg` (Legacy names exactly that, `#fff`) moves
1656 + * the card with the window for free, and a theme that wants the
1657 + * card alone names a `-card-` token.
1658 + *
1659 + * A card lands on the same colour as the window under it, so the
1660 + * border and the shadow are the whole reason it reads as a
1661 + * separate object. Neither is decoration here and neither may
1662 + * collapse into the background — which is exactly what the border
1663 + * did: `--os-ui-border` is #33303a on this palette, the SAME value
1664 + * `--os-tooltip-bg` had, so the card had no edge at all.
1665 + *
1666 + * The shadow is the one flat value in the family. A drop shadow is
1667 + * cast light, dark on a light theme and dark on a dark one, so
1668 + * there is no window token for it to follow; it is named so a
1669 + * theme can still reach it.
1670 + */
1671 + --os-my-wordpress-card-bg: var(--os-my-wordpress-bg, #1a1721);
1672 + --os-my-wordpress-card-fg: var(--os-my-wordpress-fg, #fffbff);
1673 + --os-my-wordpress-card-fg-muted: var(--os-ui-fg-muted, #b3afb5);
1674 + --os-my-wordpress-card-border: var(--os-ui-border, #33303a);
1675 + --os-my-wordpress-card-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
1676 + --os-my-wordpress-card-thumb-bg: var(
1677 + --os-media-tile-bg,
1678 + rgba(255, 251, 255, 0.05)
1679 + );
1680 + --os-my-wordpress-card-lock-bg: var(
1681 + --os-ui-badge-danger-bg,
1682 + rgba(255, 90, 90, 0.16)
1683 + );
1107 1684 --os-ai-panel-bg: rgba(26, 23, 33, 0.97);
1108 - --os-tabs-bg: #33303a;
1685 + /*
1686 + * The Site assistant, the same split as selection everywhere else:
1687 + * its header tint and mark, search icon, lit row and icon tiles still
1688 + * mix from the accent, and so does its send button; --os-ai-accent
1689 + * says how much. This palette
1690 + * answers 0%, so the chrome is neutral and a lit row is the flat 8%
1691 + * Starlight of the Preferences sidebar; Legacy answers 100%. The
1692 + * command icons keep the accent here too: they read it directly, so
1693 + * the colour stays in the pictures and out of the chrome.
1694 + */
1695 + --os-ai-accent: 0%;
1696 + --os-ai-row-fill: rgba(255, 251, 255, 0.08);
1697 + --os-ai-tile-fill: rgba(255, 251, 255, 0.06);
1698 + /*
1699 + * ---- Window tab strip ---------------------------------------
1700 + *
1701 + * A window with sub-pages reads as three surfaces stacked in
1702 + * depth, and the values below are that ramp: Astro on the focused
1703 + * title bar, VOID for the track the tabs sit in, then the page
1704 + * itself. The track is the darkest of the three on purpose — it
1705 + * has to stay a distinct band under BOTH title-bar states, and
1706 + * Obsidian would collapse into the unfocused bar (also Obsidian)
1707 + * exactly when a window has the least going on to distinguish it.
1708 + *
1709 + * The active tab is not a colour, it is the page arriving early.
1710 + * `chromeless.css` paints every admin page inside a window `#fff`
1711 + * whatever the admin colour scheme says, so the tab can name that
1712 + * white and the joint between the two is seamless. Retinting the
1713 + * tab means retinting the page it belongs to, and these two move
1714 + * together or the seam comes back.
1715 + *
1716 + * `-color-muted` is the second tone anything nested in an active
1717 + * tab needs — the external tab's detach and close chips. It is
1718 + * the only reason a "muted on light" value exists this far down a
1719 + * dark palette.
1720 + */
1721 + --os-tabs-bg: #1a1721;
1722 + /*
1723 + * The track on an UNFOCUSED window, which follows the title bar
1724 + * down to Void rather than holding Obsidian.
1725 + *
1726 + * A focused window already reads as two surfaces: title bar and
1727 + * track are the same Obsidian, and the tab lifts out of them. Let
1728 + * the track keep that Obsidian while the bar above it dims and
1729 + * the window reads as THREE, with the strip belonging to neither
1730 + * the chrome above nor the page below. Following the bar down
1731 + * keeps the count at two in both states.
1732 + *
1733 + * Both tracks read this: the shell's strip on an iframe window,
1734 + * and `<os-tabs variant="window">` inside a native one. The track
1735 + * is chrome in both cases, so it dims with the chrome; what keeps
1736 + * the tab attached to the content while that happens is the
1737 + * plate's fill, which wears the body's own colour rather than the
1738 + * track's.
1739 + *
1740 + * Note the asymmetry with the title bar's pair, which is
1741 + * deliberate: there, `--os-titlebar-bg` is the unfocused base and
1742 + * `-focused` is the modifier. Here the base is the LIT value,
1743 + * so a theme naming one track colour lands on the state where the
1744 + * track is doing the most work.
1745 + *
1746 + * A theme that sets only `--os-tabs-bg` (Legacy, and anything
1747 + * written before this token existed) resolves through it in both
1748 + * states and keeps its single strip colour.
1749 + */
1750 + --os-tabs-bg-unfocused: #0c0b0f;
1109 1751 --os-tabs-color: #b3afb5;
1752 + --os-tabs-active-bg: #fff;
1753 + --os-tabs-active-color: #0c0b0f;
1754 + --os-tabs-active-color-muted: rgba(12, 11, 15, 0.6);
1755 + /*
1756 + * The plate's own body: a frosted crown resolving to flat page
1757 + * white well before the joint.
1758 + *
1759 + * Every stop is OPAQUE, and that is a requirement rather than a
1760 + * preference. The face used to be translucent over a
1761 + * `backdrop-filter`, which promotes it to its own compositor layer
1762 + * and leaves a faint grey hairline where that layer is clipped —
1763 + * down the plate's sides and across its bottom, which is precisely
1764 + * where this design has a bright rail and needs everything else to
1765 + * be invisible.
1766 + *
1767 + * The last stop must also land above the joint (the bottom
1768 + * `--os-tabs-radius` of the plate), because the joint is painted
1769 + * in flat `--os-tabs-active-bg` and a body still tinted where the
1770 + * two meet draws a seam of its own. If you retune these stops,
1771 + * check the bottom edge first.
1772 + */
1773 + --os-tabs-active-frost: linear-gradient(
1774 + 180deg,
1775 + #f4eff9 0%,
1776 + #ffffff 58%
1777 + );
1778 + /*
1779 + * The crown. Holomesh over the top of the plate, masked away before
1780 + * the joint, on exactly ONE tab at a time. Off in this palette: the
1781 + * plain frosted plate is the tab, and the one identity moment on a
1782 + * window is left to the wallpaper behind it. A theme that wants the
1783 + * mesh back declares `var(--os-mesh-holo)` here, at around 0.3.
1784 + */
1785 + --os-tabs-active-crown: none;
1786 + --os-tabs-active-crown-opacity: 0.3;
1787 + /*
1788 + * The rail: one continuous line around the silhouette of
1789 + * page-plus-tab, painted as a background-image through a mask,
1790 + * which is why it is a gradient and not a colour. It is the accent
1791 + * the user picked, flat, and it stays derived so the pick reaches
1792 + * it on every theme.
1793 + *
1794 + * On this palette it is drawn at 0 opacity. The plate already
1795 + * reads as "this tab" by being the one white shape on an Obsidian
1796 + * strip that joins the page below it; a coloured line around that
1797 + * silhouette was saying the same thing a second time, on every
1798 + * window on the desk. The opacity is the literal a theme answers
1799 + * (Legacy: 1), and the width stays at 2px because the strip's
1800 + * geometry is built on it: the plate sits on the rail whether or
1801 + * not the rail is visible, so turning it back on costs no seam.
1802 + */
1803 + --os-tabs-rail: linear-gradient(
1804 + var(--os-ui-accent, #f252fc),
1805 + var(--os-ui-accent, #f252fc)
1806 + );
1807 + --os-tabs-rail-opacity: 0;
1808 + --os-tabs-rail-width: 2px;
1110 1809 --os-media-tile-bg: rgba(255, 251, 255, 0.05);
1111 1810 --os-media-visual-bg: rgba(255, 251, 255, 0.04);
1112 1811 --os-skeleton-low: rgba(255, 251, 255, 0.05);
1113 1812 --os-skeleton-high: rgba(255, 251, 255, 0.13);
1114 - --os-drop-preview-bg: rgba(242, 82, 252, 0.1);
1115 - --os-drop-preview-border: rgba(242, 82, 252, 0.55);
1813 + --os-drop-preview-bg: rgba(255, 251, 255, 0.08);
1814 + --os-drop-preview-border: rgba(255, 251, 255, 0.45);
1116 1815
1117 1816 /*
1118 1817 * File tiles — anywhere a `.os-file-tile` (or sibling
1119 1818 * canvas tile) renders. The defaults match the desk: Starlight
1120 - * labels over a dark sky, with a Pulse selection wash.
1819 + * labels over a dark sky, and a selected tile is a lifted
1820 + * Starlight plate, the same language as the selected row in the
1821 + * Preferences sidebar, one step brighter than the hover wash so
1822 + * the two states stay apart. The accent ring around it is a
1823 + * derived colour with a literal width; this palette sets the
1824 + * width to 0 (Legacy keeps 1px) so selection is depth, not colour.
1121 1825 *
1122 1826 * Surfaces that are light in their own right override these in
1123 1827 * their own scope, e.g.:
1124 1828 *
@@ -1129,12 +1833,15 @@
1129 1833 *
1130 1834 * Plugin authors can override any of these in their own theme
1131 1835 * to retint tiles globally without touching the rules below.
1132 1836 */
1133 - --os-tile-fg: var(--os-fg, #fffbff);
1837 + /* Through the desk's ink: a file tile sits on the wallpaper as a
1838 + desktop icon does. Folder windows override it in their own scope. */
1839 + --os-tile-fg: var(--os-desk-fg, var(--os-fg, #fffbff));
1134 1840 --os-tile-fg-muted: rgba(255, 251, 255, 0.7);
1135 1841 --os-tile-hover-bg: rgba(255, 251, 255, 0.12);
1136 - --os-tile-selected-bg: rgba(242, 82, 252, 0.24);
1842 + --os-tile-selected-bg: rgba(255, 251, 255, 0.16);
1843 + --os-tile-selected-ring-width: 0px;
1137 1844 --os-tile-focus-ring: var(--wp-admin-theme-color, #f252fc);
1138 1845 --os-tile-shortcut-bg: rgba(12, 11, 15, 0.7);
1139 1846 --os-tile-shortcut-fg: #fffbff;
1140 1847 --os-tile-shortcut-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
@@ -1188,8 +1895,23 @@
1188 1895 * index) so the companion can perch on top of them, but below
1189 1896 * the dock (200) so it never covers navigation.
1190 1897 */
1191 1898 --os-z-mio: 190;
1899 + /*
1900 + * The desktop-name caption. Same reasoning as Mio, one step up:
1901 + * above every window so a maximized Dashboard cannot hide it, and
1902 + * above the companion, since a momentary message should not be
1903 + * the thing that gets perched on. Still under the dock (200).
1904 + */
1905 + --os-z-desktop-name: 195;
1906 + /*
1907 + * The notch — on the desk, under the windows (100 + stack index),
1908 + * above the window-link wires (50) so a tie never draws across the
1909 + * pill. It hangs over the strip a window's title bar occupies, and
1910 + * a pill floating above someone's window is the shell talking over
1911 + * the thing they are working in.
1912 + */
1913 + --os-z-notch: 60;
1192 1914
1193 1915 /*
1194 1916 * Window-link ties (relation splines between windows). The accent
1195 1917 * follows the admin color scheme. Solid colors only — the resting
@@ -1216,8 +1938,37 @@
1216 1938 --os-window-link-glow: rgba(242, 82, 252, 0.45);
1217 1939 }
1218 1940
1219 1941 /*
1942 + * ---- A light desk -------------------------------------------------
1943 + *
1944 + * Stamped by `src/wallpapers/tone.ts` while the active wallpaper is
1945 + * light: either it declared `tone: 'light'` (both meshes do) or, for
1946 + * the two wallpapers the user supplies themselves, the shell measured
1947 + * it brighter than the crossover where Void ink overtakes Starlight.
1948 + *
1949 + * Only things that paint DIRECTLY on the wallpaper flip, so the halos
1950 + * invert with the ink and the caption lozenge switches off. Chrome that
1951 + * carries its own plate does not.
1952 + *
1953 + * The selector carries `.os-active` to sit a class above a theme's
1954 + * `body.os-desktop-theme-<slug>`. A theme retints the desk by naming
1955 + * `--os-fg` / `--os-desk-ink-light`; answering the chooser instead
1956 + * would pin one ink to every wallpaper.
1957 + */
1958 +body.os-active.os-wallpaper-light {
1959 + --os-desk-fg: var(--os-desk-ink-light, #1a1721);
1960 + --os-icon-label-bg: transparent;
1961 + --os-icon-label-shadow: 0 1px 2px rgba(255, 251, 255, 0.55);
1962 + --os-icon-glyph-shadow: drop-shadow(0 1px 2px rgba(255, 251, 255, 0.5));
1963 + --os-icon-hover-bg: rgba(12, 11, 15, 0.12);
1964 + --os-tile-hover-bg: rgba(12, 11, 15, 0.1);
1965 + --os-tile-selected-bg: rgba(12, 11, 15, 0.14);
1966 + --os-tile-fg-muted: rgba(26, 23, 33, 0.72);
1967 + --os-tile-label-shadow: 0 1px 2px rgba(255, 251, 255, 0.55);
1968 +}
1969 +
1970 +/*
1220 1971 * ---- Iframe windows keep a light body -----------------------------
1221 1972 *
1222 1973 * A window hosting a real `wp-admin` page is not a station surface — it
1223 1974 * is a frame around someone else's document, and that document is
@@ -1266,4 +2017,42 @@
1266 2017 * user who wants their admin scheme's hue picks it in the same panel.
1267 2018 * The `data-os-scheme` attribute is still stamped on the
1268 2019 * shell root for plugins and themes that key off it.
1269 2020 */
2021 +
2022 +/* The chat is a MIO surface even when its owning window wears a light theme.
2023 + * Component colours remain reachable through the public MIO token family. */
2024 +body.os-active .os-mio-chat,
2025 +body.os-active .os-mio-chat-launcher {
2026 + --os-ui-fg: var(--os-mio-chat-fg, #1d2327);
2027 + --os-ui-fg-muted: var(--os-mio-chat-muted, #646970);
2028 + --os-window-bg: var(--os-mio-chat-bg, #fff);
2029 + --os-ui-border: var(--os-mio-chat-border, #c3c4c7);
2030 +}
2031 +
2032 +/* Ghost labels sit on the chat; the hero button owns a lighter mesh. */
2033 +body.os-active .os-mio-chat os-button[variant="ghost"],
2034 +body.os-active .os-mio-chat-launcher {
2035 + --os-ui-button-fg: var(--os-mio-chat-fg, #1d2327);
2036 + --os-ui-button-bg-hover: var(--os-mio-chat-hover-bg, #f0f0f1);
2037 +}
2038 +
2039 +body.os-active .os-mio-chat os-button[variant="primary"],
2040 +body.os-active .os-mio-chat os-button[variant="holo"] {
2041 + --os-ui-button-fg: var(--os-ui-holo-ink, #1d2327);
2042 +}
2043 +
2044 +/* The component owns the launcher's single border and rounded surface. */
2045 +body.os-active .os-mio-chat-launcher {
2046 + --os-ui-button-bg: var(--os-mio-launcher-bg, #ffffffa0);
2047 + --os-ui-button-border: 1px solid var(--os-mio-chat-border, #c3c4c7);
2048 + --os-ui-button-border-radius: var(--os-mio-chat-radius, 22px);
2049 +}
2050 +
2051 +body.os-active .os-mio-callout {
2052 + --os-ui-button-border: 0;
2053 + --os-ui-button-border-radius: 50%;
2054 + --os-ui-button-padding: 0;
2055 + --os-ui-button-bg: transparent;
2056 + --os-ui-button-fg: var(--os-mio-callout-fg, #382b38);
2057 + --os-ui-button-bg-hover: color-mix(in srgb, var(--os-mio-callout-fg, #382b38) 10%, transparent);
2058 +}