improve(ui): reduce startup stylesheet size (#125539)

* perf(ui): lazy-load settings workspace styles

Amp-Thread-ID: https://ampcode.com/threads/T-01a01277-59ee-703a-b04d-927a3ba733a1

* fix(ui): keep picker styles route scoped

Amp-Thread-ID: https://ampcode.com/threads/T-01a01277-59ee-703a-b04d-927a3ba733a1

---------

Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Peter Steinberger
2026-08-17 21:32:46 -07:00
committed by GitHub
parent d9b69c5b6f
commit ca8bd59df5
15 changed files with 368 additions and 348 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
# Settings Design Language
Every settings surface (the `/settings` takeover pages plus the Plugins/Skills hubs) uses one structural pattern. Styles live in `ui/src/styles/settings.css`; templates are built through the helpers in `ui/src/components/settings-ui.ts`.
Every settings surface (the `/settings` takeover pages plus the Plugins/Skills hubs) uses one structural pattern. Workspace styles live in `ui/src/styles/settings.css`, while controls shared with startup surfaces live in `ui/src/styles/settings-controls.css`; templates are built through the helpers in `ui/src/components/settings-ui.ts`.
## Anatomy
@@ -26,6 +26,7 @@ function readUiCss(): string {
"ui/src/styles/layout.css",
"ui/src/styles/layout.mobile.css",
"ui/src/styles/components.css",
"ui/src/styles/settings-controls.css",
"ui/src/styles/settings.css",
"ui/src/styles/config.css",
"ui/src/styles/usage.css",
+1
View File
@@ -1,5 +1,6 @@
import { html, nothing } from "lit";
import "./web-awesome-select.ts";
import "../styles/select-picker.css";
export type PickerOption = {
value: string;
+2 -2
View File
@@ -1,7 +1,7 @@
// Settings design-language primitives. Every settings surface builds its
// layout through these helpers so pages cannot drift back into bespoke
// card/pill markup. Styles live in ui/src/styles/settings.css; rules in
// ui/docs/settings-design.md.
// card/pill markup. Styles live in ui/src/styles/settings.css and the shared
// ui/src/styles/settings-controls.css; rules in ui/docs/design-system/settings-design.md.
import "@awesome.me/webawesome/dist/components/radio/radio.js";
import "@awesome.me/webawesome/dist/components/radio-group/radio-group.js";
import "@awesome.me/webawesome/dist/components/switch/switch.js";
+1
View File
@@ -2,6 +2,7 @@
// section navigation lives in the takeover sidebar (settings-sidebar.ts).
import { html } from "lit";
import { ifDefined } from "lit/directives/if-defined.js";
import "../styles/settings.css";
export function renderSettingsWorkspace(
body: unknown,
@@ -930,9 +930,9 @@ describeBrowserLayout.concurrent("chat responsive browser layout", () => {
try {
const splitViewCss = readStyleSheet("ui/src/styles/chat/split-view.css");
const boardCss = readStyleSheet("ui/src/styles/chat/board.css");
const settingsCss = readStyleSheet("ui/src/styles/settings.css");
const settingsControlsCss = readStyleSheet("ui/src/styles/settings-controls.css");
await page.setContent(
`<!doctype html><html><head><style>${readUiCss()}\n${settingsCss}\n${splitViewCss}\n${boardCss}</style></head><body>
`<!doctype html><html><head><style>${readUiCss()}\n${settingsControlsCss}\n${splitViewCss}\n${boardCss}</style></head><body>
<div class="chat-split-view__cell" style="width: 320px;">
<div class="chat-pane__header">
<button class="btn btn--ghost btn--icon chat-icon-btn chat-pane__nav-toggle" type="button">N</button>
+1
View File
@@ -1,5 +1,6 @@
import { html } from "lit";
import "../../components/web-awesome-select.ts";
import "../../styles/select-picker.css";
import { SUPPORTED_LOCALES, t, type Locale } from "../../i18n/index.ts";
export function languageLabel(locale: Locale) {
@@ -29,6 +29,7 @@ function readUiCss(): string {
"ui/src/styles/layout.css",
"ui/src/styles/layout.mobile.css",
"ui/src/styles/components.css",
"ui/src/styles/settings-controls.css",
"ui/src/styles/settings.css",
"ui/src/styles/sessions.css",
];
@@ -408,6 +408,21 @@ suite.define(() => {
.locator(".workboard-toolbar__filters .workboard-select")
.nth(1);
const priorityCombobox = prioritySelect.getByRole("combobox");
const directRoutePickerStyles = await prioritySelect.evaluate((select) => {
const label = select.querySelector(".picker-select__label");
const copy = select.querySelector(".picker-select__copy");
if (!label || !copy) {
throw new Error("Workboard picker style probe did not render");
}
return {
copyDisplay: getComputedStyle(copy).display,
labelFontWeight: getComputedStyle(label).fontWeight,
};
});
expect(directRoutePickerStyles).toEqual({
copyDisplay: "grid",
labelFontWeight: "650",
});
await priorityCombobox.focus();
await writable.page.keyboard.press("ArrowDown");
await expect.poll(() => priorityCombobox.getAttribute("aria-expanded")).toBe("true");
+1 -1
View File
@@ -5,7 +5,7 @@
@import "./styles/components.css";
@import "./styles/chat/progress-card.css";
@import "./styles/approval-boot.css";
@import "./styles/settings.css";
@import "./styles/settings-controls.css";
/* Contract read by stale-chunk-reload.ts to detect a failed entry stylesheet load.
* Removing it leaves a fully unstyled page undetected. */
@@ -223,6 +223,7 @@ function readUiCss(): string {
"ui/src/styles/layout.css",
"ui/src/styles/option-card.css",
"ui/src/styles/chat/layout.css",
"ui/src/styles/settings-controls.css",
"ui/src/styles/settings.css",
"ui/src/pages/activity/run-inspector.css",
]
@@ -61,6 +61,7 @@ function readUiCss(): string {
"ui/src/styles/components.css",
"ui/src/styles/layout.css",
"ui/src/styles/sessions.css",
"ui/src/styles/settings-controls.css",
"ui/src/styles/settings.css",
"ui/src/styles/skill-workshop.css",
"ui/src/styles/chat/layout.css",
+129
View File
@@ -0,0 +1,129 @@
wa-select.settings-select {
--wa-form-control-activated-color: var(--primary);
}
wa-select.settings-select::part(combobox) {
min-height: var(--settings-control-height);
padding-inline: 10px;
border: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
border-radius: var(--radius-md);
background: color-mix(in srgb, var(--bg) 80%, var(--bg-elevated) 20%);
color: var(--text);
cursor: var(--cursor-action);
transition: border-color var(--duration-fast) var(--ease-out);
}
/* [open] is required alongside :focus-within: Chromium does not propagate
:focus-within to the host while a slotted option holds focus, so the open
state must key off the reflected attribute or the stock ring leaks through. */
wa-select.settings-select[open]::part(combobox),
wa-select.settings-select:focus-within::part(combobox) {
outline: none;
border-color: color-mix(in srgb, var(--accent) 55%, var(--border) 45%);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 18%, transparent);
}
wa-select.settings-select::part(expand-icon) {
margin-inline-start: var(--space-2);
font-size: var(--control-ui-text-sm);
color: var(--muted);
}
wa-select.settings-select::part(listbox) {
/* Keep Web Awesome's collision-aware bound in the cap; replacing it outright
would let the listbox overflow when the popup has little room to open. */
max-height: min(320px, var(--auto-size-available-height, calc(100vh - 48px)));
padding: 6px;
border: 1px solid color-mix(in srgb, var(--border-strong) 86%, transparent);
border-radius: var(--radius-md);
background: var(--bg-elevated);
box-shadow: var(--shadow-lg);
color: var(--text);
}
wa-select.settings-select wa-option {
padding: 6px 8px;
border-radius: calc(var(--radius-md) - 4px);
font-size: var(--control-ui-text-md);
color: var(--text);
cursor: var(--cursor-action);
}
/* The roving "current" option already carries the accent fill; the global
:focus-visible accent outline on top of it is pure noise. */
wa-select.settings-select wa-option:focus-visible {
outline: none;
}
wa-select.settings-select wa-option:state(current) {
color: var(--primary-foreground);
}
.picker-select__option {
color: var(--text);
}
.picker-select [slot="start"] {
display: inline-flex;
align-items: center;
}
.picker-select__label {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 650;
}
.picker-select__copy {
display: grid;
gap: 2px;
min-width: 0;
}
.picker-select__description {
min-width: 0;
overflow: hidden;
color: var(--muted);
font-size: 0.75rem;
line-height: 1.2;
text-overflow: ellipsis;
white-space: normal;
}
/* The model picker composes the shared picker and loads this same stylesheet. */
.model-picker {
display: grid;
gap: 6px;
min-width: 0;
}
.model-picker__provider-icon {
width: 20px;
height: 20px;
flex: 0 0 20px;
}
.model-picker__provider-icon.provider-brand-icon--fallback {
font-size: 9px;
}
.model-picker__custom[hidden] {
display: none;
}
/* Forced colors suppresses the box-shadow ring and accent fill that stand in
for the outlines removed above, so restore system-color outlines there. */
@media (forced-colors: active) {
wa-select.settings-select[open]::part(combobox),
wa-select.settings-select:focus-within::part(combobox) {
outline: 2px solid SelectedItem;
outline-offset: 2px;
}
wa-select.settings-select wa-option:focus-visible {
outline: 2px solid SelectedItem;
outline-offset: 2px;
}
}
+210
View File
@@ -0,0 +1,210 @@
:root {
--settings-control-height: 32px;
}
/* Settings controls also appear outside the settings workspace: the login
gate, chat board controls, and the chat MCP form all use these primitives. */
/* Segmented keeps its 2px track inset; the buttons fill the inner height.
min-height (not height) so many-option enums can still wrap to two lines. */
.settings-segmented {
min-height: var(--settings-control-height);
box-sizing: border-box;
align-items: stretch;
display: inline-flex;
flex-wrap: wrap;
gap: 2px;
max-width: 100%;
background: color-mix(in srgb, var(--bg) 80%, var(--bg-elevated) 20%);
border: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
border-radius: var(--radius-md);
padding: 2px;
}
.settings-segmented > .settings-segmented__btn {
display: inline-flex;
align-items: center;
padding-block: 0;
}
.settings-control__sr-label {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
wa-radio-group.settings-segmented::part(form-control-label) {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
}
wa-radio-group.settings-segmented::part(radios) {
display: flex;
flex-wrap: wrap;
gap: 2px;
}
.settings-segmented__btn {
font-size: var(--control-ui-text-sm);
font-weight: 550;
padding: 4px 12px;
border: none;
border-radius: calc(var(--radius-md) - 3px);
background: transparent;
color: var(--muted);
white-space: nowrap;
cursor: var(--cursor-action);
transition:
color var(--duration-normal) var(--ease-out),
background var(--duration-normal) var(--ease-out),
box-shadow var(--duration-normal) var(--ease-out);
}
.settings-segmented__btn:hover {
color: var(--text);
}
.settings-segmented__btn:focus-visible {
outline: none;
color: var(--text);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 22%, transparent);
}
.settings-segmented__btn--active {
background: var(--bg-elevated);
color: var(--text-strong);
box-shadow: var(--shadow-sm);
}
.settings-segmented__btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
input.settings-input,
select.settings-select:not([multiple]) {
height: var(--settings-control-height);
padding-block: 0;
box-sizing: border-box;
}
.settings-input,
.settings-select {
--control-ui-touch-input-size: var(--control-ui-input-text-size);
width: 100%;
min-width: 0;
font: inherit;
font-size: var(--control-ui-input-text-size);
}
/* Native controls own their box. Web Awesome selects are styled by their
component-owned stylesheet. */
.settings-input,
select.settings-select {
border: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
border-radius: var(--radius-md);
background-color: color-mix(in srgb, var(--bg) 80%, var(--bg-elevated) 20%);
color: var(--text);
padding: 7px 10px;
transition: border-color var(--duration-fast) var(--ease-out);
}
select.settings-select:not([multiple]) {
appearance: none;
-webkit-appearance: none;
padding-right: 36px;
background-image: var(--select-chevron);
background-repeat: no-repeat;
background-position: right 10px center;
}
.settings-input::placeholder {
color: var(--muted);
}
.settings-input:focus-visible,
select.settings-select:focus-visible {
outline: none;
border-color: color-mix(in srgb, var(--accent) 55%, var(--border) 45%);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 18%, transparent);
}
/* Secret inputs also appear in the startup login gate. Keep these selectors
unscoped so the gate's mobile sizing rules retain higher specificity. */
.settings-secret {
position: relative;
display: inline-flex;
align-items: center;
min-width: 0;
}
.settings-secret > input,
.settings-secret > textarea {
width: 100%;
min-width: 0;
padding-right: 36px;
}
.settings-secret__toggle {
position: absolute;
right: 5px;
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
padding: 0;
border: none;
border-radius: var(--radius-sm);
background: transparent;
color: var(--muted);
cursor: var(--cursor-action);
transition: color var(--duration-fast) var(--ease-out);
}
.settings-secret__toggle:hover {
color: var(--text);
}
.settings-secret__toggle:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.settings-secret__toggle:focus-visible {
outline: none;
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 22%, transparent);
}
.settings-secret__toggle svg {
width: 16px;
height: 16px;
fill: none;
stroke: currentColor;
stroke-width: 2px;
stroke-linecap: round;
stroke-linejoin: round;
}
/* Quiet count badge used by settings pages and the Skill Workshop. */
.settings-count {
display: inline-flex;
align-items: center;
padding: 1px 7px;
border-radius: var(--radius-full);
background: color-mix(in srgb, var(--bg-elevated) 80%, var(--border) 20%);
color: var(--muted);
font-size: var(--control-ui-text-xs);
font-weight: 600;
font-variant-numeric: tabular-nums;
}
+1 -342
View File
@@ -1,7 +1,3 @@
:root {
--settings-control-height: 32px;
}
/* ── Settings design language ──────────────────────────────────────────────
*
* One structural pattern for every settings surface:
@@ -441,36 +437,12 @@
Multi-select list boxes and textareas keep their natural height. */
.settings-row__control .btn,
.settings-section__actions .btn,
.settings-group .data-table-search input,
input.settings-input,
select.settings-select:not([multiple]) {
.settings-group .data-table-search input {
height: var(--settings-control-height);
padding-block: 0;
box-sizing: border-box;
}
/* Segmented keeps its 2px track inset; the buttons fill the inner height.
min-height (not height) so many-option enums can still wrap to two lines. */
.settings-segmented {
min-height: var(--settings-control-height);
box-sizing: border-box;
align-items: stretch;
display: inline-flex;
flex-wrap: wrap;
gap: 2px;
max-width: 100%;
background: color-mix(in srgb, var(--bg) 80%, var(--bg-elevated) 20%);
border: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
border-radius: var(--radius-md);
padding: 2px;
}
.settings-segmented > .settings-segmented__btn {
display: inline-flex;
align-items: center;
padding-block: 0;
}
.settings-row__control .btn--icon,
.settings-section__actions .btn--icon {
width: var(--settings-control-height);
@@ -485,18 +457,6 @@ select.settings-select:not([multiple]) {
cursor: var(--cursor-action);
}
.settings-control__sr-label {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
wa-switch.settings-toggle {
/* Web Awesome defaults to brand blue; settings controls follow the active scene. */
--wa-form-control-activated-color: var(--accent);
@@ -504,94 +464,6 @@ wa-switch.settings-toggle {
flex: none;
}
wa-radio-group.settings-segmented::part(form-control-label) {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
}
wa-radio-group.settings-segmented::part(radios) {
display: flex;
flex-wrap: wrap;
gap: 2px;
}
.settings-segmented__btn {
font-size: var(--control-ui-text-sm);
font-weight: 550;
padding: 4px 12px;
border: none;
border-radius: calc(var(--radius-md) - 3px);
background: transparent;
color: var(--muted);
white-space: nowrap;
cursor: var(--cursor-action);
transition:
color var(--duration-normal) var(--ease-out),
background var(--duration-normal) var(--ease-out),
box-shadow var(--duration-normal) var(--ease-out);
}
.settings-segmented__btn:hover {
color: var(--text);
}
.settings-segmented__btn:focus-visible {
outline: none;
color: var(--text);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 22%, transparent);
}
.settings-segmented__btn--active {
background: var(--bg-elevated);
color: var(--text-strong);
box-shadow: var(--shadow-sm);
}
.settings-segmented__btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.settings-input,
.settings-select {
--control-ui-touch-input-size: var(--control-ui-input-text-size);
width: 100%;
min-width: 0;
font: inherit;
font-size: var(--control-ui-input-text-size);
}
/* Native controls own their box. wa-select draws the same box on its shadow
combobox part below; host chrome would double-border the web component. */
.settings-input,
select.settings-select {
border: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
border-radius: var(--radius-md);
/* background-color, not the background shorthand: the shorthand resets the
.field select chevron longhands (image/repeat/position) and tiles the
arrow across Model Providers selects. */
background-color: color-mix(in srgb, var(--bg) 80%, var(--bg-elevated) 20%);
color: var(--text);
padding: 7px 10px;
transition: border-color var(--duration-fast) var(--ease-out);
}
/* Single-value selects draw the themed chevron; the engine's stock arrow
ignores the 32px control box and renders misaligned. Multi-select list
boxes keep native rendering. */
select.settings-select:not([multiple]) {
appearance: none;
-webkit-appearance: none;
padding-right: 36px;
background-image: var(--select-chevron);
background-repeat: no-repeat;
background-position: right 10px center;
}
.settings-row:not(.settings-row--stacked) .settings-row__control > .settings-select {
width: auto;
min-width: min(220px, 100%);
@@ -648,22 +520,6 @@ select.settings-select:not([multiple]) {
/* ── Secret input (inset reveal toggle; no trailing button) ── */
.settings-secret {
position: relative;
display: inline-flex;
align-items: center;
min-width: 0;
}
/* Class-agnostic child selectors: the login gate and config form reuse this
wrapper around their own input/textarea styling. */
.settings-secret > input,
.settings-secret > textarea {
width: 100%;
min-width: 0;
padding-right: 36px;
}
/* Stacked rows (config form arrays/maps) give the control full width; the
wrapper must grow or the inner 100% resolves against fit-content. */
.settings-row--stacked .settings-row__control > .settings-secret {
@@ -679,189 +535,6 @@ select.settings-select:not([multiple]) {
top: 6px;
}
.settings-secret__toggle {
position: absolute;
right: 5px;
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
padding: 0;
border: none;
border-radius: var(--radius-sm);
background: transparent;
color: var(--muted);
cursor: var(--cursor-action);
transition: color var(--duration-fast) var(--ease-out);
}
.settings-secret__toggle:hover {
color: var(--text);
}
.settings-secret__toggle:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.settings-secret__toggle:focus-visible {
outline: none;
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 22%, transparent);
}
.settings-secret__toggle svg {
width: 16px;
height: 16px;
fill: none;
stroke: currentColor;
stroke-width: 2px;
stroke-linecap: round;
stroke-linejoin: round;
}
.settings-input::placeholder {
color: var(--muted);
}
.settings-input:focus-visible,
select.settings-select:focus-visible {
outline: none;
border-color: color-mix(in srgb, var(--accent) 55%, var(--border) 45%);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 18%, transparent);
}
/* ── Web Awesome select ── */
wa-select.settings-select {
--wa-form-control-activated-color: var(--primary);
}
wa-select.settings-select::part(combobox) {
min-height: var(--settings-control-height);
padding-inline: 10px;
border: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
border-radius: var(--radius-md);
background: color-mix(in srgb, var(--bg) 80%, var(--bg-elevated) 20%);
color: var(--text);
cursor: var(--cursor-action);
transition: border-color var(--duration-fast) var(--ease-out);
}
/* [open] is required alongside :focus-within: Chromium does not propagate
:focus-within to the host while a slotted option holds focus, so the open
state must key off the reflected attribute or the stock ring leaks through. */
wa-select.settings-select[open]::part(combobox),
wa-select.settings-select:focus-within::part(combobox) {
outline: none;
border-color: color-mix(in srgb, var(--accent) 55%, var(--border) 45%);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 18%, transparent);
}
wa-select.settings-select::part(expand-icon) {
margin-inline-start: var(--space-2);
font-size: var(--control-ui-text-sm);
color: var(--muted);
}
wa-select.settings-select::part(listbox) {
/* Keep Web Awesome's collision-aware bound in the cap; replacing it outright
would let the listbox overflow when the popup has little room to open. */
max-height: min(320px, var(--auto-size-available-height, calc(100vh - 48px)));
padding: 6px;
border: 1px solid color-mix(in srgb, var(--border-strong) 86%, transparent);
border-radius: var(--radius-md);
background: var(--bg-elevated);
box-shadow: var(--shadow-lg);
color: var(--text);
}
wa-select.settings-select wa-option {
padding: 6px 8px;
border-radius: calc(var(--radius-md) - 4px);
font-size: var(--control-ui-text-md);
color: var(--text);
cursor: var(--cursor-action);
}
/* The roving "current" option already carries the accent fill; the global
:focus-visible accent outline on top of it is pure noise. */
wa-select.settings-select wa-option:focus-visible {
outline: none;
}
wa-select.settings-select wa-option:state(current) {
color: var(--primary-foreground);
}
.picker-select__option {
color: var(--text);
}
.picker-select [slot="start"] {
display: inline-flex;
align-items: center;
}
.picker-select__label {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 650;
}
.picker-select__copy {
display: grid;
gap: 2px;
min-width: 0;
}
.picker-select__description {
min-width: 0;
overflow: hidden;
color: var(--muted);
font-size: 0.75rem;
line-height: 1.2;
text-overflow: ellipsis;
white-space: normal;
}
.model-picker {
display: grid;
gap: 6px;
min-width: 0;
}
.model-picker__provider-icon {
width: 20px;
height: 20px;
flex: 0 0 20px;
}
.model-picker__provider-icon.provider-brand-icon--fallback {
font-size: 9px;
}
.model-picker__custom[hidden] {
display: none;
}
/* Forced colors suppresses the box-shadow ring and accent fill that stand in
for the outlines removed above, so restore system-color outlines there. */
@media (forced-colors: active) {
wa-select.settings-select[open]::part(combobox),
wa-select.settings-select:focus-within::part(combobox) {
outline: 2px solid SelectedItem;
outline-offset: 2px;
}
wa-select.settings-select wa-option:focus-visible {
outline: 2px solid SelectedItem;
outline-offset: 2px;
}
}
textarea.settings-input {
min-height: 88px;
resize: vertical;
@@ -952,20 +625,6 @@ textarea.settings-input {
overflow-wrap: anywhere;
}
/* ── Count badge (quiet; genuine counts/alerts only, not status) ── */
.settings-count {
display: inline-flex;
align-items: center;
padding: 1px 7px;
border-radius: var(--radius-full);
background: color-mix(in srgb, var(--bg-elevated) 80%, var(--border) 20%);
color: var(--muted);
font-size: var(--control-ui-text-xs);
font-weight: 600;
font-variant-numeric: tabular-nums;
}
/* ── Empty state ── */
.settings-empty {