| @@ -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 |
| @@ -411,8 +455,20 @@ | ||
| 411 | 455 | --os-ui-field-bg: #33303a; |
| 412 | 456 | --os-ui-field-border: #4d4a52; |
| 413 | 457 | --os-ui-field-fg: #fffbff; |
| 414 | 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 | + | |
| 415 | 471 | /* Text — Starlight down through the Shade ramp. */ |
| 416 | 472 | --os-ui-fg: #fffbff; |
| 417 | 473 | --os-ui-fg-muted: #b3afb5; |
| 418 | 474 | --os-ui-fg-faint: #66636b; |
| @@ -476,8 +532,18 @@ | ||
| 476 | 532 | --os-ui-selection-fg: #fffbff; |
| 477 | 533 | |
| 478 | 534 | /* Accent — the identity moment. */ |
| 479 | 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; | |
| 480 | 546 | --os-ui-accent-strong: #ec9bff; |
| 481 | 547 | --os-ui-accent-soft: color-mix(in srgb, var(--os-ui-accent-dim) 14%, transparent); |
| 482 | 548 | /* |
| 483 | 549 | * Pulse, one step back — and the single knob for how loud the |
| @@ -596,8 +662,47 @@ | ||
| 596 | 662 | |
| 597 | 663 | /* The fill itself. Holomesh, so the mesh is the default look. */ |
| 598 | 664 | --os-ui-holo-fill: var(--os-mesh-holo); |
| 599 | 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 | + /* | |
| 600 | 705 | * Glyphs and text ON that fill. Void, not Starlight — every mesh |
| 601 | 706 | * in the brand is a LIGHT surface (its darkest stop, Holomesh's |
| 602 | 707 | * #afa2e8, still sits at 62% luminance), so Starlight on it is a |
| 603 | 708 | * white-on-lilac 1.4:1 that looks fine in a mock and is unreadable |
| @@ -679,22 +784,21 @@ | ||
| 679 | 784 | * satisfy WCAG 1.4.11. |
| 680 | 785 | */ |
| 681 | 786 | --os-ui-holo-track-edge: #66636b; |
| 682 | 787 | /* |
| 683 | - * Focus. One ring for the whole kit — Pulse, offset, over a soft | |
| 684 | - * 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 | |
| 685 | 790 | * of a legacy theme alike. |
| 686 | 791 | * |
| 687 | - * Note which layer dims and which does not. The RING is full Pulse | |
| 688 | - * and stays there: it is the only thing on screen saying where the | |
| 689 | - * keyboard is, and a focus indicator is the last place to trade | |
| 690 | - * legibility for calm. Only the bloom behind it comes down, from | |
| 691 | - * 45% to 30%, and onto the dim — which is the layer that was | |
| 692 | - * 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. | |
| 693 | 798 | */ |
| 694 | 799 | --os-ui-focus-ring: 0 0 0 2px rgba(12, 11, 15, 0.9), |
| 695 | - 0 0 0 4px var(--os-ui-accent, #f252fc), | |
| 696 | - 0 0 12px 2px color-mix(in srgb, var(--os-ui-accent-dim) 30%, transparent); | |
| 800 | + 0 0 0 4px var(--os-ui-accent, #f252fc); | |
| 697 | 801 | /* |
| 698 | 802 | * …and one for FIELDS, which is a different problem. A text input |
| 699 | 803 | * already has a border to thicken and it sits in a column of other |
| 700 | 804 | * inputs, so the ring above — designed to survive landing on a |
| @@ -710,27 +814,27 @@ | ||
| 710 | 814 | * The selected row of a VERTICAL `<os-tabs>`: the sidebar in |
| 711 | 815 | * OpenStation Preferences, and any native window that lays its |
| 712 | 816 | * pages down the side rather than across the top. |
| 713 | 817 | * |
| 714 | - * Three layers, and the split is the whole point. Colour repeated | |
| 715 | - * down nine rows is wallpaper, so the accent is spent as a | |
| 716 | - * two-pixel EDGE and the row itself gets only a wash that falls | |
| 717 | - * away: it appears where it is cheap to look at and expensive to | |
| 718 | - * ignore. | |
| 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. | |
| 719 | 824 | * |
| 720 | - * `-edge` is the accent the user picked, flat. It used to be | |
| 721 | - * Miomesh, and a mesh does hold up at 2px where a radial one | |
| 722 | - * would crop to an arbitrary lilac — but the edge is the loudest | |
| 723 | - * thing on the page that says "this row", and a row that says it | |
| 724 | - * in Pulse while the controls beside it say it in the chosen | |
| 725 | - * accent reads as two systems. | |
| 726 | - * | |
| 727 | - * `-wash` and `-bloom` are AMBIENT accent, so both resolve through | |
| 728 | - * `--os-ui-accent-dim` like every other glow in the kit. Turning | |
| 729 | - * the station down is still one edit. The Starlight stop in the | |
| 730 | - * middle of the wash is what keeps the row from reading as a pink | |
| 731 | - * smear: it lifts the surface under the label rather than tinting | |
| 732 | - * it, and it is gone by the time the row ends. | |
| 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. | |
| 733 | 837 | */ |
| 734 | 838 | --os-ui-tab-edge: linear-gradient( |
| 735 | 839 | var(--os-ui-accent, #f252fc), |
| 736 | 840 | var(--os-ui-accent, #f252fc) |
| @@ -736,10 +840,15 @@ | ||
| 736 | 840 | var(--os-ui-accent, #f252fc) |
| 737 | 841 | ); |
| 738 | 842 | --os-ui-tab-wash: linear-gradient( |
| 739 | 843 | 90deg, |
| 740 | - color-mix(in srgb, var(--os-ui-accent-dim) 16%, transparent) 0%, | |
| 741 | - rgba(255, 251, 255, 0.04) 42%, | |
| 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%, | |
| 742 | 851 | transparent 100% |
| 743 | 852 | ); |
| 744 | 853 | --os-ui-tab-bloom: linear-gradient( |
| 745 | 854 | 90deg, |
| @@ -745,10 +854,64 @@ | ||
| 745 | 854 | 90deg, |
| 746 | 855 | color-mix(in srgb, var(--os-ui-accent-dim) 26%, transparent), |
| 747 | 856 | transparent |
| 748 | 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; | |
| 749 | 864 | |
| 750 | 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 | + /* | |
| 751 | 914 | * ---- Motion -------------------------------------------------- |
| 752 | 915 | * |
| 753 | 916 | * Four durations and three curves, and every animated thing in the |
| 754 | 917 | * kit picks from them. Not for tidiness: a panel where the switch |
| @@ -898,10 +1061,10 @@ | ||
| 898 | 1061 | * only from the component's own `::slotted( a )`. See the comment |
| 899 | 1062 | * there: a slotted link is a document-tree element, so wp-admin's |
| 900 | 1063 | * bare `a` rule outranks anything the shadow root says about it. |
| 901 | 1064 | */ |
| 902 | - --os-ui-notice-link: #ec9bff; | |
| 903 | - --os-ui-notice-link-hover: #fffbff; | |
| 1065 | + --os-ui-notice-link: #fffbff; | |
| 1066 | + --os-ui-notice-link-hover: #ccc8ce; | |
| 904 | 1067 | --os-ui-badge-danger-bg: rgba(255, 90, 90, 0.16); |
| 905 | 1068 | --os-ui-badge-success-bg: rgba(147, 240, 198, 0.16); |
| 906 | 1069 | --os-ui-badge-warning-bg: rgba(248, 242, 182, 0.16); |
| 907 | 1070 | --os-ui-badge-info-bg: rgba(194, 241, 241, 0.16); |
| @@ -996,9 +1159,8 @@ | ||
| 996 | 1159 | /* Search-match highlight inside a label. A WASH, not a fill: the |
| 997 | 1160 | text keeps its own colour, so the wash has to stay light enough |
| 998 | 1161 | for Starlight to carry over it. */ |
| 999 | 1162 | --os-ui-search-highlight-bg: rgba(248, 242, 182, 0.3); |
| 1000 | - --os-ui-color-accent: #f252fc; | |
| 1001 | 1163 | /* |
| 1002 | 1164 | * The content graph's cluster hue is NOT retinted. Graph node |
| 1003 | 1165 | * colours are composed artwork that encodes meaning — the docs list |
| 1004 | 1166 | * them under "what stays fixed" — and moving this one to Nebula put |
| @@ -1004,18 +1166,82 @@ | ||
| 1004 | 1166 | * them under "what stays fixed" — and moving this one to Nebula put |
| 1005 | 1167 | * white cluster labels on a pale lilac chip at 1.9:1. It keeps its |
| 1006 | 1168 | * own colour, and the label keeps carrying on it. |
| 1007 | 1169 | * |
| 1008 | - * The graph's toolbar is chrome, though, and it does follow. The | |
| 1009 | - * count pill on an ACTIVE filter chip is a 70%-white fill, and it | |
| 1010 | - * was carrying `--os-ui-accent-strong` numerals — Nebula on white, | |
| 1011 | - * ~1.7:1. It is one more bright fill naming its own dark text, the | |
| 1012 | - * same escape hatch `--os-ui-ribbon-fg` and `--os-ui-step-chip-fg` | |
| 1013 | - * 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. | |
| 1014 | 1184 | */ |
| 1015 | - --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; | |
| 1016 | 1193 | |
| 1017 | 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 | + /* | |
| 1018 | 1244 | * ---- Typography -------------------------------------------- |
| 1019 | 1245 | * |
| 1020 | 1246 | * Geist for everything human — headlines, UI copy, body text — and |
| 1021 | 1247 | * Geist Mono for the instrument voice: labels, metadata, statuses, |
| @@ -1189,17 +1415,36 @@ | ||
| 1189 | 1415 | * rule and so must read the same two tokens). |
| 1190 | 1416 | */ |
| 1191 | 1417 | --os-dock-width: 56px; |
| 1192 | 1418 | --os-dock-icon-size: 20px; |
| 1419 | + /* | |
| 1420 | + * The indicator line a dynamic dock collapses into while parked | |
| 1421 | + * (Preferences → Appearance → Desktop layout → Dock behavior): | |
| 1422 | + * the iOS home indicator, painted in the accent at partial alpha | |
| 1423 | + * so it reads as a mark on the wallpaper rather than a control. | |
| 1424 | + * `-length` runs along the rail's edge, `-thickness` across it; a | |
| 1425 | + * theme retunes any of the three. | |
| 1426 | + */ | |
| 1427 | + --os-dock-indicator-length: 180px; | |
| 1428 | + --os-dock-indicator-thickness: 5px; | |
| 1429 | + --os-dock-indicator-bg: color-mix( in srgb, var( --os-ui-accent, #f252fc ) 72%, transparent ); | |
| 1193 | 1430 | --os-dock-bg: rgba(12, 11, 15, 0.72); |
| 1194 | 1431 | --os-dock-icon-color: rgba(255, 251, 255, 0.72); |
| 1195 | 1432 | --os-dock-icon-color-hover: #fffbff; |
| 1196 | - --os-dock-item-bg-hover: rgba(242, 82, 252, 0.18); | |
| 1433 | + --os-dock-item-bg-hover: rgba(255, 251, 255, 0.08); | |
| 1197 | 1434 | /* |
| 1435 | + * The tile whose window is in front sits on a lit plate: the same | |
| 1436 | + * Starlight wash the hover uses, one step brighter, so "this is the | |
| 1437 | + * app you are in" reads as depth rather than as a coloured mark. | |
| 1438 | + * The running dot under every open app stays; a lit plate says | |
| 1439 | + * which one is in front, the dots say which ones are open. | |
| 1440 | + */ | |
| 1441 | + --os-dock-item-bg-focused: rgba(255, 251, 255, 0.1); | |
| 1442 | + /* | |
| 1198 | 1443 | * The status indicator and the focus ring, and both say "this |
| 1199 | 1444 | * one" about a tile the user chose — so they read the accent |
| 1200 | - * rather than a fixed Pulse. Pulse is still what an untouched | |
| 1201 | - * install shows, because that is what the picker starts on. | |
| 1445 | + * rather than a fixed colour. Starlight is what an untouched | |
| 1446 | + * install shows, because that is the accent the picker starts on. | |
| 1202 | 1447 | */ |
| 1203 | 1448 | --os-dock-item-outline: var(--os-ui-accent, #f252fc); |
| 1204 | 1449 | /* |
| 1205 | 1450 | * Hairline between the dock and the desktop. Reaches the side |
| @@ -1238,8 +1483,30 @@ | ||
| 1238 | 1483 | --os-dock-floating-highlight: rgba(255, 251, 255, 0.1); |
| 1239 | 1484 | --os-dock-floating-shadow: rgba(0, 0, 0, 0.55); |
| 1240 | 1485 | |
| 1241 | 1486 | /* |
| 1487 | + * The phone layer (`mobile.css`). Its surfaces are the dock's | |
| 1488 | + * family — translucent glass over the wallpaper, light glyphs — | |
| 1489 | + * and read the dock tokens above for fill, text and lines. What | |
| 1490 | + * the dock has no word for is declared here: the glass a tile, a | |
| 1491 | + * round control and a switcher card are cut from, its pressed | |
| 1492 | + * state, the shadow under a tile, the scrim behind the switcher, | |
| 1493 | + * and the label shadow that keeps text legible over any wallpaper. | |
| 1494 | + * A desktop theme that reskins the dock reskins the phone with it; | |
| 1495 | + * one that wants the phone alone has these. | |
| 1496 | + */ | |
| 1497 | + --os-mobile-glass: rgba(255, 251, 255, 0.1); | |
| 1498 | + --os-mobile-glass-strong: rgba(255, 251, 255, 0.16); | |
| 1499 | + --os-mobile-glass-border: rgba(255, 251, 255, 0.14); | |
| 1500 | + --os-mobile-tile-shadow: 0 8px 20px rgba(0, 0, 0, 0.35); | |
| 1501 | + --os-mobile-card-shadow: 0 -8px 24px rgba(0, 0, 0, 0.4); | |
| 1502 | + --os-mobile-sheet-shadow: 0 -12px 40px rgba(0, 0, 0, 0.45); | |
| 1503 | + --os-mobile-window-shadow: 0 12px 32px rgba(0, 0, 0, 0.45); | |
| 1504 | + --os-mobile-scrim: rgba(0, 0, 0, 0.55); | |
| 1505 | + --os-mobile-top-scrim: rgba(0, 0, 0, 0.45); | |
| 1506 | + --os-mobile-label-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); | |
| 1507 | + | |
| 1508 | + /* | |
| 1242 | 1509 | * ---- The OpenStation layout --------------------------------- |
| 1243 | 1510 | * |
| 1244 | 1511 | * The constellation: the flyout that fans a menu's submenu out of |
| 1245 | 1512 | * its tile on hover, on every rail in every layout. The rail's |
| @@ -1359,8 +1626,21 @@ | ||
| 1359 | 1626 | rgba(255, 90, 90, 0.16) |
| 1360 | 1627 | ); |
| 1361 | 1628 | --os-ai-panel-bg: rgba(26, 23, 33, 0.97); |
| 1362 | 1629 | /* |
| 1630 | + * The Site assistant, the same split as selection everywhere else: | |
| 1631 | + * its header tint and mark, search icon, lit row and icon tiles still | |
| 1632 | + * mix from the accent, and so does its send button; --os-ai-accent | |
| 1633 | + * says how much. This palette | |
| 1634 | + * answers 0%, so the chrome is neutral and a lit row is the flat 8% | |
| 1635 | + * Starlight of the Preferences sidebar; Legacy answers 100%. The | |
| 1636 | + * command icons keep the accent here too: they read it directly, so | |
| 1637 | + * the colour stays in the pictures and out of the chrome. | |
| 1638 | + */ | |
| 1639 | + --os-ai-accent: 0%; | |
| 1640 | + --os-ai-row-fill: rgba(255, 251, 255, 0.08); | |
| 1641 | + --os-ai-tile-fill: rgba(255, 251, 255, 0.06); | |
| 1642 | + /* | |
| 1363 | 1643 | * ---- Window tab strip --------------------------------------- |
| 1364 | 1644 | * |
| 1365 | 1645 | * A window with sub-pages reads as three surfaces stacked in |
| 1366 | 1646 | * depth, and the values below are that ramp: Astro on the focused |
| @@ -1439,46 +1719,54 @@ | ||
| 1439 | 1719 | #f4eff9 0%, |
| 1440 | 1720 | #ffffff 58% |
| 1441 | 1721 | ); |
| 1442 | 1722 | /* |
| 1443 | - * The crown. Holomesh, masked away before the joint for the same | |
| 1444 | - * reason. It is on exactly ONE tab at a time — that is what keeps | |
| 1445 | - * the mesh an identity moment instead of wallpaper, and it is the | |
| 1446 | - * rule the rest of the kit follows. Set it to `none` to get the | |
| 1447 | - * plain frosted plate back. | |
| 1723 | + * The crown. Holomesh over the top of the plate, masked away before | |
| 1724 | + * the joint, on exactly ONE tab at a time. Off in this palette: the | |
| 1725 | + * plain frosted plate is the tab, and the one identity moment on a | |
| 1726 | + * window is left to the wallpaper behind it. A theme that wants the | |
| 1727 | + * mesh back declares `var(--os-mesh-holo)` here, at around 0.3. | |
| 1448 | 1728 | */ |
| 1449 | - --os-tabs-active-crown: var(--os-mesh-holo); | |
| 1729 | + --os-tabs-active-crown: none; | |
| 1450 | 1730 | --os-tabs-active-crown-opacity: 0.3; |
| 1451 | 1731 | /* |
| 1452 | 1732 | * The rail: one continuous line around the silhouette of |
| 1453 | - * page-plus-tab. | |
| 1733 | + * page-plus-tab, painted as a background-image through a mask, | |
| 1734 | + * which is why it is a gradient and not a colour. It is the accent | |
| 1735 | + * the user picked, flat, and it stays derived so the pick reaches | |
| 1736 | + * it on every theme. | |
| 1454 | 1737 | * |
| 1455 | - * This is the one place the accent is spent on the tab strip, and | |
| 1456 | - * spending it here is what lets the tab itself stay uncoloured — | |
| 1457 | - * so it is the accent the user picked, flat, and not Pulsemesh. | |
| 1458 | - * A mesh here would be the accent everywhere else on the tab | |
| 1459 | - * strip disagreeing with the one line that carries it. Written as | |
| 1460 | - * a gradient rather than a colour because the rail is painted as | |
| 1461 | - * a background-image through a mask. | |
| 1462 | - * | |
| 1463 | - * Set it to `none` for the plain frosted plate with no line. | |
| 1738 | + * On this palette it is drawn at 0 opacity. The plate already | |
| 1739 | + * reads as "this tab" by being the one white shape on an Obsidian | |
| 1740 | + * strip that joins the page below it; a coloured line around that | |
| 1741 | + * silhouette was saying the same thing a second time, on every | |
| 1742 | + * window on the desk. The opacity is the literal a theme answers | |
| 1743 | + * (Legacy: 1), and the width stays at 2px because the strip's | |
| 1744 | + * geometry is built on it: the plate sits on the rail whether or | |
| 1745 | + * not the rail is visible, so turning it back on costs no seam. | |
| 1464 | 1746 | */ |
| 1465 | 1747 | --os-tabs-rail: linear-gradient( |
| 1466 | 1748 | var(--os-ui-accent, #f252fc), |
| 1467 | 1749 | var(--os-ui-accent, #f252fc) |
| 1468 | 1750 | ); |
| 1751 | + --os-tabs-rail-opacity: 0; | |
| 1469 | 1752 | --os-tabs-rail-width: 2px; |
| 1470 | 1753 | --os-media-tile-bg: rgba(255, 251, 255, 0.05); |
| 1471 | 1754 | --os-media-visual-bg: rgba(255, 251, 255, 0.04); |
| 1472 | 1755 | --os-skeleton-low: rgba(255, 251, 255, 0.05); |
| 1473 | 1756 | --os-skeleton-high: rgba(255, 251, 255, 0.13); |
| 1474 | - --os-drop-preview-bg: rgba(242, 82, 252, 0.1); | |
| 1475 | - --os-drop-preview-border: rgba(242, 82, 252, 0.55); | |
| 1757 | + --os-drop-preview-bg: rgba(255, 251, 255, 0.08); | |
| 1758 | + --os-drop-preview-border: rgba(255, 251, 255, 0.45); | |
| 1476 | 1759 | |
| 1477 | 1760 | /* |
| 1478 | 1761 | * File tiles — anywhere a `.os-file-tile` (or sibling |
| 1479 | 1762 | * canvas tile) renders. The defaults match the desk: Starlight |
| 1480 | - * labels over a dark sky, with a Pulse selection wash. | |
| 1763 | + * labels over a dark sky, and a selected tile is a lifted | |
| 1764 | + * Starlight plate, the same language as the selected row in the | |
| 1765 | + * Preferences sidebar, one step brighter than the hover wash so | |
| 1766 | + * the two states stay apart. The accent ring around it is a | |
| 1767 | + * derived colour with a literal width; this palette sets the | |
| 1768 | + * width to 0 (Legacy keeps 1px) so selection is depth, not colour. | |
| 1481 | 1769 | * |
| 1482 | 1770 | * Surfaces that are light in their own right override these in |
| 1483 | 1771 | * their own scope, e.g.: |
| 1484 | 1772 | * |
| @@ -1492,9 +1780,10 @@ | ||
| 1492 | 1780 | */ |
| 1493 | 1781 | --os-tile-fg: var(--os-fg, #fffbff); |
| 1494 | 1782 | --os-tile-fg-muted: rgba(255, 251, 255, 0.7); |
| 1495 | 1783 | --os-tile-hover-bg: rgba(255, 251, 255, 0.12); |
| 1496 | - --os-tile-selected-bg: rgba(242, 82, 252, 0.24); | |
| 1784 | + --os-tile-selected-bg: rgba(255, 251, 255, 0.16); | |
| 1785 | + --os-tile-selected-ring-width: 0px; | |
| 1497 | 1786 | --os-tile-focus-ring: var(--wp-admin-theme-color, #f252fc); |
| 1498 | 1787 | --os-tile-shortcut-bg: rgba(12, 11, 15, 0.7); |
| 1499 | 1788 | --os-tile-shortcut-fg: #fffbff; |
| 1500 | 1789 | --os-tile-shortcut-shadow: 0 1px 3px rgba(0, 0, 0, 0.6); |
| @@ -1549,8 +1838,15 @@ | ||
| 1549 | 1838 | * the dock (200) so it never covers navigation. |
| 1550 | 1839 | */ |
| 1551 | 1840 | --os-z-mio: 190; |
| 1552 | 1841 | /* |
| 1842 | + * The desktop-name caption. Same reasoning as Mio, one step up: | |
| 1843 | + * above every window so a maximized Dashboard cannot hide it, and | |
| 1844 | + * above the companion, since a momentary message should not be | |
| 1845 | + * the thing that gets perched on. Still under the dock (200). | |
| 1846 | + */ | |
| 1847 | + --os-z-desktop-name: 195; | |
| 1848 | + /* | |
| 1553 | 1849 | * The notch — on the desk, under the windows (100 + stack index), |
| 1554 | 1850 | * above the window-link wires (50) so a tie never draws across the |
| 1555 | 1851 | * pill. It hangs over the strip a window's title bar occupies, and |
| 1556 | 1852 | * a pill floating above someone's window is the shell talking over |
| @@ -1634,4 +1930,42 @@ | ||
| 1634 | 1930 | * user who wants their admin scheme's hue picks it in the same panel. |
| 1635 | 1931 | * The `data-os-scheme` attribute is still stamped on the |
| 1636 | 1932 | * shell root for plugins and themes that key off it. |
| 1637 | 1933 | */ |
| 1934 | + | |
| 1935 | +/* The chat is a MIO surface even when its owning window wears a light theme. | |
| 1936 | + * Component colours remain reachable through the public MIO token family. */ | |
| 1937 | +body.os-active .os-mio-chat, | |
| 1938 | +body.os-active .os-mio-chat-launcher { | |
| 1939 | + --os-ui-fg: var(--os-mio-chat-fg, #1d2327); | |
| 1940 | + --os-ui-fg-muted: var(--os-mio-chat-muted, #646970); | |
| 1941 | + --os-window-bg: var(--os-mio-chat-bg, #fff); | |
| 1942 | + --os-ui-border: var(--os-mio-chat-border, #c3c4c7); | |
| 1943 | +} | |
| 1944 | + | |
| 1945 | +/* Ghost labels sit on the chat; the hero button owns a lighter mesh. */ | |
| 1946 | +body.os-active .os-mio-chat os-button[variant="ghost"], | |
| 1947 | +body.os-active .os-mio-chat-launcher { | |
| 1948 | + --os-ui-button-fg: var(--os-mio-chat-fg, #1d2327); | |
| 1949 | + --os-ui-button-bg-hover: var(--os-mio-chat-hover-bg, #f0f0f1); | |
| 1950 | +} | |
| 1951 | + | |
| 1952 | +body.os-active .os-mio-chat os-button[variant="primary"], | |
| 1953 | +body.os-active .os-mio-chat os-button[variant="holo"] { | |
| 1954 | + --os-ui-button-fg: var(--os-ui-holo-ink, #1d2327); | |
| 1955 | +} | |
| 1956 | + | |
| 1957 | +/* The component owns the launcher's single border and rounded surface. */ | |
| 1958 | +body.os-active .os-mio-chat-launcher { | |
| 1959 | + --os-ui-button-bg: var(--os-mio-launcher-bg, #ffffffa0); | |
| 1960 | + --os-ui-button-border: 1px solid var(--os-mio-chat-border, #c3c4c7); | |
| 1961 | + --os-ui-button-border-radius: var(--os-mio-chat-radius, 22px); | |
| 1962 | +} | |
| 1963 | + | |
| 1964 | +body.os-active .os-mio-callout { | |
| 1965 | + --os-ui-button-border: 0; | |
| 1966 | + --os-ui-button-border-radius: 50%; | |
| 1967 | + --os-ui-button-padding: 0; | |
| 1968 | + --os-ui-button-bg: transparent; | |
| 1969 | + --os-ui-button-fg: var(--os-mio-callout-fg, #382b38); | |
| 1970 | + --os-ui-button-bg-hover: color-mix(in srgb, var(--os-mio-callout-fg, #382b38) 10%, transparent); | |
| 1971 | +} | |