@keenmate/web-multiselect 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,964 +1,969 @@
1
- /* ==============================================================================
2
- CSS CUSTOM PROPERTIES (:host level)
3
- ==============================================================================
4
- This file defines all CSS custom properties at the :host level, making them:
5
- - Inspectable in browser DevTools
6
- - Overridable from outside Shadow DOM
7
- - Self-documenting in compiled CSS
8
-
9
- Usage from outside Shadow DOM:
10
- multi-select {
11
- --ms-accent-color: #10b981;
12
- --ms-input-border-radius: 0.5rem;
13
- }
14
- ============================================================================== */
15
-
16
- :host {
17
- /* Block layout — the wrapper-host pattern paints chrome via .ms__input,
18
- but :host still needs an explicit display so consumers placing the
19
- element in inline contexts see the expected layout. */
20
- display: block;
21
-
22
- /* ==========================================================================
23
- COLOR SCHEME
24
- ==========================================================================
25
- `color-scheme` is INHERITED on this element — we deliberately do NOT
26
- declare it on `:host`. Reason: every hardcoded color fallback below is
27
- wrapped in `light-dark(<light>, <dark>)`, which picks one of the two
28
- based on the host's used color-scheme. Declaring `color-scheme: light dark`
29
- here would *override* whatever the consumer's app declared on <html>,
30
- <body>, or an ancestor — flipping forced-dark apps back to "follow OS",
31
- and breaking visual coherence with the surrounding page.
32
- By letting it inherit:
33
- - dhl-style apps that set `body { color-scheme: dark }` propagate it
34
- into our shadow DOM unchanged, and `light-dark()` resolves to dark.
35
- - apps that set `html { color-scheme: light dark }` get OS-preference
36
- switching, end-to-end.
37
- - apps that declare nothing get the historical default (light), same
38
- as before this fallback set was introduced — no behavior change.
39
- Consumers who want explicit per-multiselect control can still set
40
- `style="color-scheme: dark"` on the <web-multiselect> element.
41
-
42
- ========================================================================== */
43
-
44
- /* ==========================================================================
45
- BASE SIZING UNIT
46
- ==========================================================================
47
- All sizing values are based on this unit for consistent scaling.
48
- Bridges to the shared --base-rem knob so a theme scales every KeenMate
49
- component from one variable; falls back to 10px when no base layer is loaded.
50
- Default: 10px produces standard pixel values
51
- Pure Admin: Set --base-rem to 1rem (inherits from html { font-size: 10px })
52
- Custom: Set --base-rem (or --ms-rem for this component only) to scale all sizes */
53
- --ms-rem: var(--base-rem, 10px);
54
-
55
- /* ==========================================================================
56
- FONT FAMILY (set at :host so all shadow DOM content inherits)
57
- ========================================================================== */
58
- font-family: var(--ms-font-family, var(--base-font-family, inherit));
59
-
60
- /* ==========================================================================
61
- COLORS & THEME
62
- ==========================================================================
63
- Color variables follow this priority chain:
64
- 1. External override: --ms-accent-color: #custom
65
- 2. Base theme value: var(--base-accent-color)
66
- 3. Hardcoded default fallback */
67
-
68
- /* Accent Colors */
69
- --ms-accent-color: var(--base-accent-color, #3b82f6);
70
- --ms-accent-color-hover: var(--base-accent-color-hover, #2563eb);
71
- --ms-accent-color-active: var(--base-accent-color-active, #1d4ed8);
72
-
73
- /* Accent Color Light Variants (for backgrounds)
74
- Dark variants are muted dark-blue tints that read like "accent-tinted dark surface" rather than
75
- "near-white", keeping badge / +X more / popover-header backgrounds visible on a dark page. */
76
- --ms-accent-color-light: var(--base-accent-color-light, light-dark(#eff6ff, #1e3a5f));
77
- --ms-accent-color-light-hover: var(--base-accent-color-light-hover, light-dark(#e0f2fe, #264a73));
78
-
79
- /* Text Color Levels (FluentUI-style hierarchy)
80
- Light mode = the original dark-on-light palette (#111827 → #a0a3a9).
81
- Dark mode = the same hierarchy inverted (#f5f5f5 → #737373) so heading/body/secondary/disabled
82
- keep the same relative contrast steps. text-color-on-accent stays white in both modes — the
83
- accent color is the same blue in both, and white-on-blue reads in both. */
84
- --ms-text-color-1: var(--base-text-color-1, light-dark(#111827, #f5f5f5));
85
- --ms-text-color-2: var(--base-text-color-2, light-dark(#353b47, #d4d4d4));
86
- --ms-text-color-3: var(--base-text-color-3, light-dark(#6b7280, #a3a3a3));
87
- --ms-text-color-4: var(--base-text-color-4, light-dark(#a0a3a9, #737373));
88
- --ms-text-color-on-accent: var(--base-text-color-on-accent, #ffffff);
89
-
90
- /* Legacy aliases (for backward compatibility) */
91
- --ms-text-primary: var(--ms-text-color-1);
92
- --ms-text-secondary: var(--ms-text-color-3);
93
-
94
- /* Background Colors
95
- --ms-primary-bg paints hover/focus states (option hover, action-button hover, counter
96
- hover, etc.); --ms-primary-bg-hover is one step stronger (selected-active, counter badge).
97
- The color-mix fallback keeps the hover visible on dark themes — a flat var(--base-main-bg)
98
- substrate used to make hover collapse onto the panel background. */
99
- --ms-primary-bg: var(--base-hover-bg, color-mix(in srgb, var(--ms-text-color-1) 8%, var(--base-main-bg, light-dark(#ffffff, #1a1a1a))));
100
- --ms-primary-bg-hover: var(--base-active-bg, color-mix(in srgb, var(--ms-text-color-1) 14%, var(--base-main-bg, light-dark(#ffffff, #1a1a1a))));
101
-
102
- /* Border Base Variables */
103
- /* Default border colour. The previous fallbacks (#e5e7eb light / #3a3a3a dark) were very
104
- low contrast against white / near-black surfaces — the 1px input/panel edge nearly
105
- vanished, especially on phones. Bumped to a clearly-visible gray on each side (still
106
- soft, not harsh). Consumers with `--base-border-color` set are unaffected. */
107
- --ms-border-color: var(--base-border-color, light-dark(#cbd5e1, #52525b));
108
- --ms-border: var(--base-border, 1px solid var(--ms-border-color));
109
-
110
- /* ==========================================================================
111
- SEMANTIC VARIABLES - Component-Specific Theming
112
- ==========================================================================
113
- Pattern: --ms-{component}-{property}-{state}
114
- Example: --ms-input-bg, --ms-option-text-color-hover */
115
-
116
- /* Input Component Semantic Variables */
117
- --ms-input-bg: var(--base-input-bg, light-dark(#ffffff, #1a1a1a));
118
- --ms-input-color: var(--base-input-color, var(--ms-text-color-1));
119
- --ms-input-border: var(--base-input-border, 1px solid var(--ms-border-color));
120
- --ms-input-border-hover: var(--base-input-border-hover, 1px solid var(--ms-accent-color));
121
- --ms-input-border-focus: var(--base-input-border-focus, 1px solid var(--ms-accent-color));
122
- --ms-input-placeholder-color: var(--base-input-placeholder-color, var(--ms-text-color-4));
123
- --ms-input-bg-disabled: var(--base-input-bg-disabled, rgba(107, 114, 128, 0.05));
124
-
125
- /* Toggle Icon Semantic Variables */
126
- --ms-toggle-icon-color: var(--ms-text-color-3);
127
- --ms-toggle-icon-color-open: var(--ms-text-color-3);
128
- --ms-toggle-icon-size: calc(1.6 * var(--ms-rem));
129
- /* Toggle chevron rotation, closed vs open. Defaults orient the directional right-pointing
130
- --base-icon-chevron (90° → points down when closed, -90° → up when open). Override BOTH
131
- when a theme supplies a PRE-ORIENTED chevron glyph: `0deg` / `0deg` for a static glyph,
132
- or `0deg` / `180deg` for a down-glyph that flips up on open. */
133
- --ms-toggle-rotate-closed: 90deg;
134
- --ms-toggle-rotate-open: -90deg;
135
-
136
- /* Counter Badge (in Input) Semantic Variables */
137
- --ms-counter-badge-bg: var(--ms-accent-color);
138
- --ms-counter-badge-bg-hover: var(--ms-accent-color-hover);
139
- --ms-counter-badge-color: var(--ms-text-color-on-accent);
140
-
141
- /* Floating Hint Semantic Variables */
142
- --ms-hint-bg: var(--base-main-bg, light-dark(#ffffff, #1a1a1a));
143
- --ms-hint-color: var(--ms-text-color-4);
144
- --ms-hint-border-color: var(--ms-border-color);
145
-
146
- /* Dropdown Semantic Variables */
147
- --ms-dropdown-bg: var(--base-dropdown-bg, var(--base-elevated-bg, light-dark(#ffffff, #1a1a1a)));
148
- --ms-dropdown-text-color: var(--ms-text-color-1);
149
- --ms-dropdown-border-color: var(--ms-border-color);
150
- --ms-dropdown-box-shadow-semantic: var(--base-dropdown-box-shadow, 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1));
151
-
152
- /* Dropdown Actions Semantic Variables */
153
- --ms-actions-bg: var(--base-main-bg, light-dark(#ffffff, #1a1a1a));
154
- --ms-actions-border-color: var(--ms-border-color);
155
-
156
- /* Action Button Semantic Variables */
157
- --ms-action-button-bg: transparent;
158
- --ms-action-button-bg-hover: var(--ms-primary-bg);
159
- --ms-action-button-border-color: var(--ms-border-color);
160
- --ms-action-button-border-color-hover: var(--ms-accent-color);
161
- --ms-action-button-color: var(--ms-text-color-1);
162
-
163
- /* Group Semantic Variables */
164
- --ms-group-border-color: var(--ms-border-color);
165
- --ms-group-label-color: var(--ms-text-color-3);
166
-
167
- /* Option Semantic Variables */
168
- --ms-option-text-color: var(--ms-text-color-1);
169
- --ms-option-bg: transparent;
170
- --ms-option-bg-hover: var(--ms-primary-bg);
171
- --ms-option-color-hover: inherit;
172
- --ms-option-bg-focused: var(--ms-primary-bg);
173
- --ms-option-color-focused: inherit;
174
- --ms-option-outline-color-focused: var(--ms-accent-color);
175
- --ms-option-bg-selected: color-mix(in srgb, var(--ms-accent-color) 10%, transparent);
176
- --ms-option-bg-matched: color-mix(in srgb, var(--ms-accent-color) 8%, transparent);
177
- --ms-option-color-matched: inherit;
178
- --ms-option-border-matched-color: color-mix(in srgb, var(--ms-accent-color) 40%, transparent);
179
-
180
- /* Option Content Semantic Variables */
181
- --ms-option-title-color: var(--ms-text-color-1);
182
- --ms-option-subtitle-color: var(--ms-text-color-3);
183
- --ms-option-mark-bg: color-mix(in srgb, var(--ms-accent-color) 20%, transparent);
184
- --ms-option-mark-color: inherit;
185
-
186
- /* Empty/Loading State Semantic Variables */
187
- --ms-empty-color: var(--ms-text-color-3);
188
- --ms-loading-color: var(--ms-text-color-3);
189
-
190
- /* Badge Semantic Variables */
191
- --ms-badge-bg: var(--ms-accent-color-light);
192
- /* Hover DEEPENS the badge's OWN rest background toward its OWN text colour.
193
- Deliberately self-referential: NOT --base-hover-bg (a generic surface token →
194
- accent pill flipped near-white in dark/neon), and NOT --ms-accent-color-light-hover
195
- (a separate accent-tint token themes forget to set when they change the accent →
196
- a black brutalist pill fell back to the hardcoded blue tint on hover). Mixing 12%
197
- of the text colour into the rest bg is a subtle, always-readable nudge that follows
198
- whatever bg/text pair a theme sets. */
199
- --ms-badge-bg-hover: color-mix(in srgb, var(--ms-badge-bg) 88%, var(--ms-badge-text-color) 12%);
200
- --ms-badge-bg-active: var(--ms-accent-color-light-hover);
201
-
202
- /* Badge Text Semantic Variables */
203
- --ms-badge-text-bg: var(--ms-accent-color-light);
204
- --ms-badge-text-color: var(--ms-accent-color);
205
- --ms-badge-text-bg-hover: color-mix(in srgb, var(--ms-badge-text-bg) 88%, var(--ms-badge-text-color) 12%);
206
- --ms-badge-text-color-hover: var(--ms-badge-text-color);
207
-
208
- /* Badge Remove Button Semantic Variables */
209
- --ms-badge-remove-bg: var(--ms-accent-color);
210
- --ms-badge-remove-bg-hover: var(--ms-accent-color-hover);
211
- --ms-badge-remove-color: var(--ms-text-color-on-accent);
212
-
213
- /* Badge Counter Variant Semantic Variables
214
- Neutral/gray styling to distinguish from accent-coloured selection badges.
215
- Self-contained: the pill is a translucent tint of the strong text colour, and
216
- text/glyph use the text-colour hierarchy — so contrast holds even when a theme
217
- omits --base-main-bg (the old --ms-primary-bg-hover chain collapsed to
218
- light-on-light there). The counter must NOT inherit the accent-coloured hover
219
- of regular badges — its text stays neutral; only the surface deepens. */
220
- --ms-badge-counter-border-color: var(--ms-border-color);
221
- --ms-badge-counter-text-bg: color-mix(in srgb, var(--ms-text-color-1) 10%, transparent);
222
- --ms-badge-counter-text-bg-hover: color-mix(in srgb, var(--ms-text-color-1) 16%, transparent);
223
- --ms-badge-counter-text-color: var(--ms-text-color-1);
224
- --ms-badge-counter-text-color-hover: var(--ms-text-color-1);
225
- --ms-badge-counter-remove-bg: color-mix(in srgb, var(--ms-text-color-1) 10%, transparent);
226
- --ms-badge-counter-remove-bg-hover: color-mix(in srgb, var(--ms-text-color-1) 16%, transparent);
227
- /* Neutral glyph (text-3 at rest → text-1 on hover), NOT white-on-accent — the old
228
- on-accent glyph vanished once the hover bg became a light text colour. */
229
- --ms-badge-counter-remove-color: var(--ms-text-color-3);
230
- --ms-badge-counter-remove-color-hover: var(--ms-text-color-1);
231
-
232
- /* Count Display Semantic Variables */
233
- --ms-counter-wrapper-bg: transparent;
234
- --ms-counter-wrapper-bg-hover: var(--ms-primary-bg);
235
- --ms-counter-wrapper-border-color: var(--ms-border-color);
236
- --ms-counter-wrapper-border-color-hover: var(--ms-accent-color);
237
- --ms-count-text-color: var(--ms-text-color-1);
238
- --ms-count-clear-bg: transparent;
239
- --ms-count-clear-bg-hover: var(--ms-accent-color);
240
- --ms-count-clear-color: var(--ms-text-color-3);
241
- --ms-count-clear-color-hover: var(--ms-text-color-on-accent);
242
-
243
- /* Tooltip Semantic Variables
244
- Tooltips invert relative to the page: dark tooltip on light page, light tooltip on dark page.
245
- This keeps the tooltip distinct from its surrounding surface in both modes. */
246
- --ms-tooltip-bg: var(--base-tooltip-bg, var(--base-inverse-bg, light-dark(#333333, #f5f5f5)));
247
- --ms-tooltip-text-color: var(--base-tooltip-text-color, light-dark(#ffffff, #1a1a1a));
248
-
249
- /* Selected Popover Semantic Variables */
250
- --ms-selected-popover-bg: var(--base-dropdown-bg, var(--base-elevated-bg, light-dark(#ffffff, #1a1a1a)));
251
- --ms-selected-popover-border-color: var(--ms-border-color);
252
- --ms-selected-popover-header-bg: color-mix(in srgb, var(--ms-accent-color) 10%, transparent);
253
- --ms-selected-popover-header-color: var(--ms-text-color-1);
254
- --ms-selected-popover-header-border-color: var(--ms-border-color);
255
- --ms-selected-popover-close-bg: transparent;
256
- --ms-selected-popover-close-bg-hover: var(--ms-accent-color);
257
- --ms-selected-popover-close-color: var(--ms-text-color-3);
258
- --ms-selected-popover-close-color-hover: var(--ms-text-color-on-accent);
259
-
260
- /* ==========================================================================
261
- INPUT COMPONENT
262
- ========================================================================== */
263
- --ms-input-padding-h: calc(1.2 * var(--ms-rem)); /* field shell inline padding */
264
- --ms-input-gap: calc(0.6 * var(--ms-rem)); /* gap between input + trailing decorations */
265
- --ms-input-height: calc(var(--base-input-size-md-height, 3.5) * var(--ms-rem));
266
- --ms-input-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
267
- --ms-input-border-width: 1px;
268
- --ms-input-border-radius: var(--ms-border-radius-md);
269
- --ms-input-text: var(--ms-text-color-1);
270
- /* Prefers the shared --base token (light-dark aware, so it adapts on dark themes);
271
- the flat gray is the standalone fallback. */
272
- --ms-input-bg-disabled: var(--base-input-bg-disabled, rgba(107, 114, 128, 0.05));
273
-
274
- /* ==========================================================================
275
- INPUT SIZE VARIANTS — currently unused (commented out)
276
- ==========================================================================
277
- Preset size tiers (xs/sm/md/lg/xl) for the input. Read only by the
278
- .ms__input--* classes in controls.css, which nothing toggles (no `size`
279
- attribute), so this whole chain is inert. Commented out to drop dead theming
280
- surface — kept, not deleted, in case a future `size` attribute turns it into a
281
- named-preset API; no case has needed it yet. Size via --ms-rem (global) or the
282
- individual --ms-input-* vars (targeted) instead. Heights reference
283
- --base-input-size-*-height for cross-component consistency (px in parens):
284
-
285
- --ms-input-size-xs-font: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
286
- --ms-input-size-xs-padding-v: calc(0.4 * var(--ms-rem));
287
- --ms-input-size-xs-padding-h: calc(0.8 * var(--ms-rem));
288
- --ms-input-size-xs-height: calc(var(--base-input-size-xs-height, 3.1) * var(--ms-rem)); (31px)
289
-
290
- --ms-input-size-sm-font: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
291
- --ms-input-size-sm-padding-v: calc(0.5 * var(--ms-rem));
292
- --ms-input-size-sm-padding-h: calc(1.0 * var(--ms-rem));
293
- --ms-input-size-sm-height: calc(var(--base-input-size-sm-height, 3.3) * var(--ms-rem)); (33px)
294
-
295
- --ms-input-size-md-font: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
296
- --ms-input-size-md-padding-v: calc(0.8 * var(--ms-rem));
297
- --ms-input-size-md-padding-h: calc(1.2 * var(--ms-rem));
298
- --ms-input-size-md-height: calc(var(--base-input-size-md-height, 3.5) * var(--ms-rem)); (35px)
299
-
300
- --ms-input-size-lg-font: calc(var(--base-font-size-base, 1.6) * var(--ms-rem));
301
- --ms-input-size-lg-padding-v: calc(1.0 * var(--ms-rem));
302
- --ms-input-size-lg-padding-h: calc(1.4 * var(--ms-rem));
303
- --ms-input-size-lg-height: calc(var(--base-input-size-lg-height, 3.8) * var(--ms-rem)); (38px)
304
-
305
- --ms-input-size-xl-font: calc(var(--base-font-size-lg, 1.8) * var(--ms-rem));
306
- --ms-input-size-xl-padding-v: calc(1.2 * var(--ms-rem));
307
- --ms-input-size-xl-padding-h: calc(1.6 * var(--ms-rem));
308
- --ms-input-size-xl-height: calc(var(--base-input-size-xl-height, 4.1) * var(--ms-rem)); (41px)
309
- */
310
-
311
- /* ==========================================================================
312
- TOGGLE ICON
313
- ========================================================================== */
314
- --ms-toggle-color: var(--ms-text-color-3);
315
- --ms-transform-rotate-180: 180deg;
316
-
317
- /* ==========================================================================
318
- INPUT CLEAR (✕)
319
- ========================================================================== */
320
- --ms-input-clear-size: calc(2.4 * var(--ms-rem));
321
- --ms-input-clear-icon-size: calc(1.4 * var(--ms-rem));
322
- --ms-input-clear-color: var(--base-input-clear-color, var(--ms-text-secondary));
323
- --ms-input-clear-bg-hover: var(--base-input-clear-bg-hover, var(--ms-option-bg-matched, transparent));
324
- --ms-input-clear-border-radius: var(--ms-border-radius); /* matches the input; square when radius is 0 */
325
-
326
- /* ==========================================================================
327
- COUNT BADGE (in input)
328
- ========================================================================== */
329
- --ms-counter-padding: calc(0.2 * var(--ms-rem)) calc(0.4 * var(--ms-rem));
330
- --ms-counter-bg: var(--ms-accent-color);
331
- --ms-counter-color: var(--ms-text-color-on-accent);
332
- --ms-counter-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
333
- --ms-counter-font-weight: var(--base-font-weight-semibold, 600);
334
- --ms-counter-border-radius: var(--ms-border-radius-sm);
335
- --ms-counter-bg-hover: var(--ms-accent-color-hover);
336
- --ms-transform-scale-hover: 1.1;
337
-
338
- /* ==========================================================================
339
- FLOATING HINT
340
- ========================================================================== */
341
- --ms-hint-padding: calc(0.8 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
342
- --ms-hint-border: 1px solid var(--ms-hint-border-color);
343
- --ms-hint-border-radius: var(--ms-border-radius-lg);
344
- --ms-hint-box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
345
- --ms-hint-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
346
-
347
- /* ==========================================================================
348
- DROPDOWN
349
- ========================================================================== */
350
- --ms-dropdown-border: var(--base-dropdown-border, 1px solid var(--ms-dropdown-border-color));
351
- --ms-dropdown-border-radius: var(--ms-border-radius-lg);
352
- /* Inner content clip radius — a hair tighter than the panel so a highlighted
353
- first/last row (or the sticky Select-All/Clear actions bar) follows the panel's
354
- rounded corners instead of its square background bleeding ~1px past the rounded
355
- border (the classic rounded-parent + bordered-box corner artifact). Assumes the
356
- default 1px --ms-dropdown-border; if you theme a thicker border, override this to
357
- match (panel radius − border width). Clamped at 0 so a squared panel stays square. */
358
- --ms-dropdown-inner-border-radius: max(0px, calc(var(--ms-dropdown-border-radius) - 1px));
359
- /* Prefers the shared --base token (light-dark aware — deepens on dark themes); the
360
- flat two-layer shadow is the standalone fallback. */
361
- --ms-dropdown-box-shadow: var(--base-dropdown-box-shadow, 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1));
362
- /* Live input width, published by JS each positioning frame. It's the only panel
363
- dimension CSS can't measure itself, so panels that "match the input" read it. */
364
- --ms-input-current-width: auto;
365
- /* Options dropdown width. Defaults to the input width; override at app/theme level
366
- (web-multiselect { --ms-dropdown-width: 60rem }) or per-instance via the
367
- dropdown-width attribute. dropdown-min-width / dropdown-max-width still clamp it. */
368
- --ms-dropdown-width: var(--ms-input-current-width);
369
- --ms-options-max-height: calc(32 * var(--ms-rem));
370
- --ms-option-color: var(--ms-text-color-1);
371
- --ms-z-index-dropdown: 9999;
372
- --ms-z-index-sticky: 1;
373
-
374
- /* ==========================================================================
375
- FULLSCREEN OVERLAY (touch / phone presentation)
376
- Used when a panel is presented as a full-viewport overlay — the options
377
- dropdown (`.ms__dropdown--fullscreen`) AND the selected-items popover
378
- (`.ms__selected-popover--fullscreen`). Both share ONE header-bar + close-
379
- button treatment so the mobile view is consistent. Driven by the element's
380
- environmentChanged hook on phones. Everything defaults to the dropdown's own
381
- theming so a fullscreen panel looks like the same component.
382
- ========================================================================== */
383
- --ms-z-index-fullscreen: 10001; /* above dropdown (9999) + popover/tooltip (10000) */
384
- /* The truncated-label reveal is triggered from INSIDE the fullscreen overlay, so it
385
- must sit above it (the plain option tooltip at 10000 renders behind the 10001 panel). */
386
- --ms-z-index-fullscreen-tooltip: 10002;
387
- /* Size of the phone view. Every size in the component is calc(N × --ms-rem), so the
388
- fullscreen panels override --ms-rem with this to scale rows, text, checkboxes,
389
- padding, header and search up together (~1.2× → comfortable ~44–48px touch rows).
390
- A plain length (not calc(1.2 × --ms-rem)) so assigning it to --ms-rem on the panel
391
- can't form a cyclic var() reference. Set it larger for chunkier touch targets. */
392
- --ms-fullscreen-rem: 12px;
393
- /* These overlay-only vars are sized in --ms-fullscreen-rem (NOT --ms-rem): a custom
394
- property bakes its var() at its declaration site, so declaring them here against
395
- --ms-fullscreen-rem gives the enlarged phone-view sizes wherever they're consumed. */
396
- --ms-fullscreen-bg: var(--ms-dropdown-bg);
397
- --ms-fullscreen-text-color: var(--ms-dropdown-text-color);
398
- --ms-fullscreen-header-bg: var(--ms-dropdown-bg);
399
- --ms-fullscreen-header-border: 1px solid var(--ms-dropdown-border-color);
400
- --ms-fullscreen-header-gap: calc(0.8 * var(--ms-fullscreen-rem));
401
- /* Split into v/h so the close button can reclaim this exact padding with negative
402
- margins to reach the sheet's physical corner (see .ms__fullscreen-close). */
403
- --ms-fullscreen-header-padding-v: calc(0.8 * var(--ms-fullscreen-rem));
404
- --ms-fullscreen-header-padding-h: calc(1.2 * var(--ms-fullscreen-rem));
405
- --ms-fullscreen-header-padding: var(--ms-fullscreen-header-padding-v) var(--ms-fullscreen-header-padding-h);
406
- --ms-fullscreen-header-min-height: calc(5.6 * var(--ms-fullscreen-rem)); /* consistent bar height: search vs title */
407
- --ms-fullscreen-title-font-size: calc(1.7 * var(--ms-fullscreen-rem));
408
- --ms-fullscreen-title-font-weight: var(--base-font-weight-semibold, 600);
409
- --ms-fullscreen-search-border: var(--ms-input-border);
410
- --ms-fullscreen-search-border-radius: var(--ms-input-border-radius);
411
- --ms-fullscreen-search-padding: calc(0.8 * var(--ms-fullscreen-rem)) calc(1.2 * var(--ms-fullscreen-rem));
412
- --ms-fullscreen-search-font-size: calc(1.6 * var(--ms-fullscreen-rem));
413
- /* Inline clear (✕) inside the fullscreen search field: a small round mask-icon
414
- button pinned to the trailing edge, shown only while there's a term. The gutter
415
- reserves trailing padding on the input so typed text never runs under it. */
416
- --ms-fullscreen-search-clear-size: calc(2.8 * var(--ms-fullscreen-rem));
417
- --ms-fullscreen-search-clear-icon-size: calc(1.4 * var(--ms-fullscreen-rem));
418
- --ms-fullscreen-search-clear-inset: calc(0.4 * var(--ms-fullscreen-rem));
419
- --ms-fullscreen-search-clear-gutter: calc(3.4 * var(--ms-fullscreen-rem));
420
- --ms-fullscreen-search-clear-color: var(--ms-text-muted-color, var(--ms-dropdown-text-color));
421
- --ms-fullscreen-search-clear-bg-hover: var(--ms-option-bg-matched, transparent);
422
- /* Leading search-mode toggle (opt-in): a small round mask-icon button at the field's
423
- leading edge, sized like the clear button. Icon swaps by mode (see the [data-mode]
424
- rules in floating.css). */
425
- --ms-fullscreen-mode-toggle-size: calc(2.8 * var(--ms-fullscreen-rem));
426
- --ms-fullscreen-mode-toggle-icon-size: calc(1.5 * var(--ms-fullscreen-rem));
427
- /* Gap between the leading toggle and the search field. Defaults to the header gap so it
428
- matches the field↔close spacing on the trailing side (symmetric bar); override to
429
- decouple. */
430
- --ms-fullscreen-mode-toggle-gap: var(--ms-fullscreen-header-gap);
431
- --ms-fullscreen-mode-toggle-color: var(--ms-text-muted-color, var(--ms-dropdown-text-color));
432
- --ms-fullscreen-mode-toggle-bg: transparent;
433
- --ms-fullscreen-mode-toggle-bg-hover: var(--ms-option-bg-matched, transparent);
434
- --ms-fullscreen-close-size: calc(3.6 * var(--ms-fullscreen-rem));
435
- --ms-fullscreen-close-icon-size: calc(1.6 * var(--ms-fullscreen-rem));
436
- --ms-fullscreen-close-color: var(--ms-dropdown-text-color);
437
- /* Visible close chip. Defaults to a borderless, transparent, round hit-glyph (so it
438
- reads as a bare ✕), but these turn it into a bordered "button" like a command-
439
- palette close — e.g. --ms-fullscreen-close-border: 1px solid var(--ms-border-color);
440
- --ms-fullscreen-close-border-radius: calc(0.8 * var(--ms-fullscreen-rem));
441
- --ms-fullscreen-close-bg: var(--ms-input-bg);. The tap target stays larger than the
442
- chip (see the ::after in floating.css), so bordering it doesn't shrink what's
443
- clickable. */
444
- --ms-fullscreen-close-bg: transparent;
445
- --ms-fullscreen-close-border: none;
446
- --ms-fullscreen-close-border-radius: 50%;
447
- --ms-fullscreen-close-bg-hover: var(--ms-option-bg-matched, transparent);
448
- /* Corner tap target. The visible chip stays --close-size (so it never inflates the
449
- header height), but a transparent ::after extends the *hit* area into the sheet's
450
- top-trailing corner — the dead header padding around a centered button was the "tap
451
- here → nothing happens" zone, and the corner is the easiest place to hit.
452
- --edge-nudge is a negative inline-end margin that slides the whole button (and its
453
- glyph) that much closer to the physical edge. */
454
- --ms-fullscreen-close-edge-nudge: calc(0.8 * var(--ms-fullscreen-rem));
455
- /* Truncated-label info affordance (fullscreen only). A circled "i" revealed at the
456
- trailing edge of a row whose label is clipped, so the full label is one tap away
457
- on touch (where hover tooltips never fire). Sized in --ms-fullscreen-rem. */
458
- --ms-fullscreen-info-size: calc(2.8 * var(--ms-fullscreen-rem));
459
- --ms-fullscreen-info-icon-size: calc(1.8 * var(--ms-fullscreen-rem));
460
- --ms-fullscreen-info-color: var(--ms-accent-color);
461
- --ms-fullscreen-info-bg-hover: var(--ms-option-bg-matched, transparent);
462
- /* Navigate-mode match navigator under the fullscreen search box: a muted result
463
- count plus round prev/next buttons that step through matches (the touch stand-in
464
- for desktop's Ctrl+Arrow). Sized in --ms-fullscreen-rem like the rest of the overlay. */
465
- --ms-fullscreen-nav-gap: calc(0.6 * var(--ms-fullscreen-rem));
466
- --ms-fullscreen-nav-padding-top: calc(0.6 * var(--ms-fullscreen-rem));
467
- --ms-fullscreen-nav-count-font-size: calc(1.3 * var(--ms-fullscreen-rem));
468
- --ms-fullscreen-nav-count-color: var(--ms-text-muted-color, var(--ms-dropdown-text-color));
469
- --ms-fullscreen-nav-btn-size: calc(3.2 * var(--ms-fullscreen-rem));
470
- --ms-fullscreen-nav-btn-icon-size: calc(1.6 * var(--ms-fullscreen-rem));
471
- --ms-fullscreen-nav-btn-color: var(--ms-dropdown-text-color);
472
- --ms-fullscreen-nav-btn-bg: var(--ms-option-bg-matched, transparent);
473
- /* Hover = a stronger accent tint than the resting state (8%). A translucent color-mix
474
- of the accent adapts to any panel background — unlike --ms-accent-color-light, which is
475
- a fixed light-dark() pair that resolves to its pale light branch on dark themes that set
476
- --base-* colors but not color-scheme (e.g. the neon example), producing a jarring near-white
477
- chip. Stays fully themeable via this variable. */
478
- --ms-fullscreen-nav-btn-bg-hover: color-mix(in srgb, var(--ms-accent-color) 22%, transparent);
479
- /* Pager match-navigator glyph (the prev/next ^ ⌄ buttons). Defaults to the shared
480
- --ms-icon-chevron, so it follows the base chevron out of the box. The pager rotates this
481
- source -90° (prev → up) / 90° (next → down), so it expects a RIGHT-pointing glyph — override
482
- it here if a theme points --base-icon-chevron somewhere else (e.g. a pre-oriented toggle
483
- caret) and you don't want that leaking into the pager. */
484
- --ms-fullscreen-nav-btn-icon: var(--ms-icon-chevron);
485
- /* Chevron glyph — the dropdown toggle's affordance, and the default source for the pager
486
- (via --ms-fullscreen-nav-btn-icon above). Wired to the --base-icon contract
487
- (--base-icon-chevron, a Lucide angle that fills its viewBox, so it renders at full optical
488
- size — unlike the small solid caret) with an inline right-pointing chevron as the standalone
489
- fallback. It points RIGHT at rest; consumers rotate it into place (toggle: 90° closed → down,
490
- -90° open → up — themeable via --ms-toggle-rotate-*; pager: -90° → up, 90° → down). Override
491
- --ms-icon-chevron (or --base-icon-chevron globally) to re-skin both at once, or override
492
- --ms-fullscreen-nav-btn-icon alone to diverge the pager. */
493
- --ms-icon-chevron: var(--base-icon-chevron, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m9 18 6-6-6-6'/></svg>"));
494
- /* SVG "i-in-a-circle" glyph — rendered via mask so it inherits the info color via
495
- currentColor. Override with any mask-friendly url() SVG. */
496
- --ms-icon-info: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='9' fill='none' stroke='black' stroke-width='2'/><circle cx='12' cy='7.5' r='1.3' fill='black'/><path d='M12 11v6' stroke='black' stroke-width='2' stroke-linecap='round' fill='none'/></svg>");
497
- /* Tighter tree indent for the phone overlay so deep nodes leave room for the label.
498
- Sized in --ms-fullscreen-rem (like the rest of the overlay) so it scales with the
499
- phone view: at the 12px default this is ~8.4px base + ~14.4px/level, vs the
500
- floating default's real-rem 0.75rem/1.25rem (tree.css). Raise --ms-fullscreen-rem
501
- and the indent grows with the rows. */
502
- --ms-fullscreen-tree-base-indent: calc(0.7 * var(--ms-fullscreen-rem));
503
- --ms-fullscreen-tree-indent: calc(1.2 * var(--ms-fullscreen-rem));
504
-
505
- /* ==========================================================================
506
- DROPDOWN ACTIONS
507
- ========================================================================== */
508
- --ms-actions-gap: calc(0.4 * var(--ms-rem));
509
- --ms-actions-padding: calc(0.8 * var(--ms-rem));
510
- --ms-actions-border-bottom: 1px solid var(--ms-actions-border-color);
511
-
512
- /* Action Button */
513
- --ms-action-btn-padding: calc(0.4 * var(--ms-rem)) calc(0.8 * var(--ms-rem));
514
- --ms-action-btn-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
515
- --ms-action-btn-border: var(--ms-border);
516
- --ms-action-btn-border-radius: var(--ms-border-radius-sm);
517
- --ms-action-btn-bg: transparent;
518
- --ms-action-btn-color: inherit;
519
- --ms-action-btn-bg-hover: var(--ms-primary-bg);
520
- --ms-action-btn-border-color-hover: var(--ms-accent-color);
521
- --ms-transform-scale-active: 0.98;
522
-
523
- /* ==========================================================================
524
- OPTIONS CONTAINER & GROUPS
525
- ========================================================================== */
526
- --ms-options-padding: 0;
527
-
528
- /* Group */
529
- --ms-group-border-top: 1px solid var(--ms-group-border-color);
530
- --ms-group-margin-top: calc(0.4 * var(--ms-rem));
531
- --ms-group-padding-top: calc(0.4 * var(--ms-rem));
532
-
533
- /* Group Label */
534
- --ms-group-label-padding: calc(0.4 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
535
- --ms-group-label-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
536
- --ms-group-label-font-weight: var(--base-font-weight-semibold, 600);
537
- --ms-group-label-color: var(--ms-text-color-3);
538
- --ms-group-label-transform: uppercase;
539
- --ms-group-label-letter-spacing: 0.05em;
540
-
541
- /* ==========================================================================
542
- INDIVIDUAL OPTIONS
543
- ==========================================================================
544
- Per-component theming colors live in the SEMANTIC VARIABLES block above
545
- (--ms-option-bg, --ms-option-bg-hover, --ms-option-bg-focused,
546
- --ms-option-bg-matched, --ms-option-bg-selected, --ms-option-outline-color-focused,
547
- --ms-option-border-matched-color). This block holds layout-only sizing. */
548
- --ms-option-gap: calc(0.8 * var(--ms-rem));
549
- --ms-option-padding: calc(0.8 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
550
- --ms-option-padding-h: calc(1.2 * var(--ms-rem));
551
- /* Adjustable row height for non-virtual rows (flat + tree). Default `auto` =
552
- content-driven (padding + line-height), matching web-treeview's node rows.
553
- Set a length for a consistent minimum row height; rows still grow if their
554
- content is taller (unless you also truncate the title, below). Virtual-scroll
555
- rows use the fixed `--ms-option-height` instead. */
556
- --ms-option-min-height: auto;
557
- --ms-option-outline-focused: 2px solid var(--ms-option-outline-color-focused);
558
- --ms-option-focus-outline-offset: -2px;
559
- --ms-option-border-matched: 3px solid var(--ms-option-border-matched-color);
560
-
561
- /* Option State Combinations */
562
- --ms-option-bg-focused-hover: var(--ms-primary-bg);
563
- --ms-option-bg-matched-hover: color-mix(in srgb, var(--ms-accent-color) 12%, transparent);
564
- --ms-option-bg-selected-focused: color-mix(in srgb, var(--ms-accent-color) 15%, transparent);
565
- --ms-option-bg-selected-matched: color-mix(in srgb, var(--ms-accent-color) 15%, transparent);
566
- --ms-option-disabled-bg: var(--base-disabled-bg, transparent);
567
- --ms-option-bg-disabled-selected: color-mix(in srgb, var(--ms-accent-color) 10%, transparent);
568
-
569
- --ms-disabled-opacity: 0.5;
570
-
571
- /* ==========================================================================
572
- OPTION CONTENT
573
- ========================================================================== */
574
- --ms-option-content-gap: calc(0.8 * var(--ms-rem));
575
-
576
- /* Option Icon */
577
- --ms-option-icon-size: calc(2 * var(--ms-rem));
578
- --ms-option-icon-font-size: calc(var(--base-font-size-base, 1.6) * var(--ms-rem));
579
-
580
- /* Option Title (--ms-option-mark-bg / --ms-option-mark-color live in the SEMANTIC VARIABLES block above) */
581
- --ms-option-title-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
582
- --ms-option-mark-font-weight: var(--base-font-weight-semibold, 600);
583
- /* Long-title handling. Default = wrap (multi-line), matching the treeview
584
- packages, which leave `.wtv__node-label` / `.stv__node-label` unstyled. To
585
- truncate to a single line with an ellipsis, flip all three (a length is only
586
- needed if you didn't already fix the row height):
587
- --ms-option-title-white-space: nowrap;
588
- --ms-option-title-overflow: hidden;
589
- --ms-option-title-text-overflow: ellipsis;
590
- `.ms__option-title` is the label hook (analogous to `.wtv__node-label`); its
591
- flex ancestors already set `min-width: 0`, so ellipsis works without extra CSS.
592
- Pair with `enable-option-tooltips` to reveal the full text on hover. */
593
- --ms-option-title-white-space: normal;
594
- --ms-option-title-overflow: visible;
595
- --ms-option-title-text-overflow: clip;
596
-
597
- /* Option Subtitle */
598
- --ms-option-subtitle-margin-top: calc(0.4 * var(--ms-rem));
599
- --ms-option-subtitle-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
600
- --ms-option-subtitle-line-height: var(--base-line-height-tight, 1.25);
601
-
602
- /* Checkbox */
603
- /* Zero by default: the row centers the checkbox via `align-items: center`, so any
604
- top margin would decenter it (the checkbox sat ~1px low against the label — most
605
- visible in fullscreen where --ms-rem is larger). The small top nudge is only
606
- meaningful when the checkbox aligns to the top of a wrapping label; it's applied
607
- there via [data-checkbox-align="top"] in options.css. */
608
- --ms-checkbox-margin-top: 0;
609
- --ms-checkbox-margin-right: 0;
610
- --ms-checkbox-margin-bottom: 0;
611
- --ms-checkbox-margin-left: 0;
612
- --ms-checkbox-size: calc(1.6 * var(--ms-rem));
613
- --ms-checkbox-scale: 1;
614
- --ms-checkbox-align: center;
615
-
616
- /* Checkbox Styling */
617
- --ms-checkbox-bg: var(--ms-input-bg);
618
- /* Unchecked border — deliberately stronger than the faint generic --ms-border so
619
- the box reads as a real, clickable control. Tune weight/colour with these two. */
620
- --ms-checkbox-border-width: 1px;
621
- --ms-checkbox-border-color: var(--base-checkbox-border-color, #8f8f8f);
622
- --ms-checkbox-border: var(--ms-checkbox-border-width) solid var(--ms-checkbox-border-color);
623
- --ms-checkbox-border-radius: calc(0.3 * var(--ms-rem));
624
- /* Checkmark stroke width — bump for a bolder tick. */
625
- --ms-checkbox-checkmark-thickness: 2.5px;
626
- --ms-checkbox-checked-bg: var(--ms-accent-color);
627
- --ms-checkbox-checked-border: var(--ms-checkbox-border-width) solid var(--ms-accent-color);
628
- --ms-checkbox-checkmark-color: var(--ms-text-color-on-accent);
629
- --ms-checkbox-hover-border-color: var(--ms-accent-color);
630
- --ms-checkbox-disabled-bg: var(--ms-primary-bg);
631
- --ms-checkbox-disabled-border: var(--ms-checkbox-border-width) solid var(--ms-border-color);
632
-
633
- /* Checkbox State Combinations */
634
- --ms-checkbox-checked-bg-hover: var(--ms-accent-color-hover);
635
- --ms-checkbox-checked-border-color-hover: var(--ms-accent-color-hover);
636
-
637
- /* ==========================================================================
638
- EMPTY & LOADING STATES
639
- ========================================================================== */
640
- /* Shared footprint so the dropdown doesn't jump when swapping the empty
641
- ("No data") block for the loader (spinner + text) during async search.
642
- Sized to contain a small spinner + gap + one text line; override if a
643
- consumer's loader is taller. */
644
- --ms-state-min-height: calc(8 * var(--ms-rem));
645
- --ms-empty-padding: calc(1.6 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
646
- --ms-empty-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
647
- --ms-empty-color: var(--ms-text-color-3);
648
-
649
- /* "Add new" prompt (empty state when isAddNewAllowed + typed text). A clickable
650
- row keyed off the accent so it reads as an action, not a dead message. */
651
- --ms-add-new-padding: var(--ms-option-padding);
652
- --ms-add-new-gap: var(--ms-option-gap);
653
- --ms-add-new-font-size: var(--ms-empty-font-size);
654
- --ms-add-new-color: var(--ms-accent-color);
655
- --ms-add-new-color-hover: var(--ms-accent-color);
656
- --ms-add-new-bg-hover: var(--ms-option-bg-hover);
657
- --ms-add-new-icon-size: calc(1.6 * var(--ms-rem));
658
-
659
- /* Loader */
660
- --ms-loader-padding: calc(1.6 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
661
- --ms-loader-gap: calc(0.8 * var(--ms-rem));
662
-
663
- /* Loading Text */
664
- --ms-loading-text-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
665
- --ms-loading-text-color: var(--ms-text-color-3);
666
-
667
- /* ==========================================================================
668
- BADGES DISPLAY
669
- ========================================================================== */
670
- --ms-badges-gap: calc(0.8 * var(--ms-rem));
671
- --ms-badges-margin-bottom: calc(0.8 * var(--ms-rem));
672
- --ms-badges-margin-top: calc(0.8 * var(--ms-rem));
673
- --ms-badges-margin-left: calc(0.4 * var(--ms-rem));
674
- --ms-badges-margin-right: calc(0.4 * var(--ms-rem));
675
-
676
- /* Vertical alignment for inline (left/right) badge positioning */
677
- /* Options: center (default), flex-start (top), flex-end (bottom) */
678
- --ms-inline-align: center;
679
-
680
- /* Individual Badge (--ms-badge-bg / --ms-badge-bg-hover / --ms-badge-bg-active live in the SEMANTIC VARIABLES block above) */
681
- --ms-badge-gap: calc(0.8 * var(--ms-rem));
682
- --ms-badge-height: calc(2.7 * var(--ms-rem));
683
- --ms-badge-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
684
- --ms-badge-font-weight: var(--base-font-weight-semibold, 600);
685
- --ms-badge-border-radius: var(--ms-border-radius-sm);
686
- --ms-order-first: -1;
687
-
688
- /* ==========================================================================
689
- BADGE TEXT & REMOVE BUTTON
690
- ========================================================================== */
691
- /* Badge Text */
692
- --ms-badge-text-padding: 0 calc(0.8 * var(--ms-rem));
693
- --ms-badge-text-bg: var(--ms-accent-color-light);
694
- --ms-badge-text-color: var(--ms-accent-color);
695
- --ms-badge-text-border: none;
696
-
697
- /* Badge Remove Button */
698
- --ms-badge-remove-width: calc(2.7 * var(--ms-rem));
699
- --ms-badge-remove-bg: var(--ms-accent-color);
700
- --ms-badge-remove-color: var(--ms-text-color-on-accent);
701
- --ms-badge-remove-border: none;
702
- --ms-badge-remove-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
703
- --ms-badge-remove-bg-hover: var(--ms-accent-color-hover);
704
- --ms-badge-remove-box-shadow-focus: 0 0 0 2px color-mix(in srgb, var(--ms-accent-color) 50%, transparent);
705
- /* Matches the input-clear / count-clear ✕ glyphs (also 1.4×rem) so all three read at the
706
- same size; the old 1.0×rem was fine for the default stroke `x` but rendered a filled
707
- custom --base-icon-remove glyph (square-with-x) too small inside the mask box. */
708
- --ms-badge-remove-icon-size: calc(1.4 * var(--ms-rem));
709
- /* SVG X glyph (Lucide `x`) — rendered via mask so it inherits --ms-badge-remove-color via
710
- currentColor. Drives the badge remove (×) and the fullscreen/popover close (✕). Follows the
711
- shared --base-icon contract: prefers --base-icon-remove, then --base-icon-close, so a theme
712
- re-skinning its close/remove glyph re-skins these too; the inline Lucide `x` is the standalone
713
- fallback (no base layer loaded). Override --ms-icon-remove to diverge from the base contract. */
714
- --ms-icon-remove: var(--base-icon-remove, var(--base-icon-close, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M18 6 6 18'/><path d='m6 6 12 12'/></svg>")));
715
- /* SVG "clear search" glyph (Lucide `search-x`: a magnifier with an x) used by the
716
- fullscreen search field's clear button. Deliberately NOT the bare X of
717
- --ms-icon-remove so it doesn't read as a second close button beside the overlay
718
- ✕. Rendered via mask, so it inherits its color via currentColor; override with any
719
- mask-friendly SVG url(). */
720
- --ms-icon-search-clear: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m13.5 8.5-5 5'/><path d='m8.5 8.5 5 5'/><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>");
721
- /* Mode-toggle glyphs for the fullscreen search-mode switch. The button shows the
722
- CURRENT mode: a plain magnifier (Lucide `search`) for navigate, a funnel (Lucide
723
- `filter`) for filter. Rendered via mask (inherit color via currentColor); override
724
- with any mask-friendly SVG url(). */
725
- --ms-icon-search: var(--base-icon-search, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>"));
726
- --ms-icon-filter: var(--base-icon-filter, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polygon points='22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3'/></svg>"));
727
- /* Checkbox glyphs — the checkmark (checked) and dash (indeterminate/tri-state),
728
- rendered as masks so they inherit --ms-checkbox-checkmark-color and follow the
729
- shared --base-icon-* contract. Override either to diverge from the base. */
730
- --ms-icon-check: var(--base-icon-check, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M20 6 9 17l-5-5'/></svg>"));
731
- --ms-icon-indeterminate: var(--base-icon-indeterminate, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M5 12h14'/></svg>"));
732
- /* "Add new" glyph (empty-state create prompt) — a plus, rendered as a mask so it
733
- inherits the row's currentColor. Follows the shared --base-icon-* contract:
734
- prefers --base-icon-plus, then --base-icon-add, then an inline "+" fallback. */
735
- --ms-icon-add-new: var(--base-icon-plus, var(--base-icon-add, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M5 12h14'/><path d='M12 5v14'/></svg>")));
736
-
737
- /* Badge Counter Indicator (layout-only properties, colors come from semantic section) */
738
- --ms-badge-counter-bg: transparent;
739
- --ms-badge-counter-border: 1px solid var(--ms-badge-counter-border-color);
740
- --ms-badge-counter-border-radius: var(--ms-border-radius-sm);
741
-
742
- /* ==========================================================================
743
- "+X MORE" BADGE
744
- ========================================================================== */
745
- --ms-more-badge-bg: var(--ms-accent-color-light);
746
- --ms-more-badge-hover-bg: var(--ms-badge-bg-hover);
747
- --ms-more-badge-active-bg: var(--ms-accent-color-light-hover);
748
-
749
- /* ==========================================================================
750
- COUNT DISPLAY MODE
751
- ========================================================================== */
752
- --ms-count-display-margin-bottom: calc(0.8 * var(--ms-rem));
753
- --ms-count-display-margin-top: calc(0.8 * var(--ms-rem));
754
- --ms-count-display-margin-left: calc(0.8 * var(--ms-rem));
755
- --ms-count-display-margin-right: calc(0.8 * var(--ms-rem));
756
-
757
- /* Count Badge Wrapper */
758
- --ms-counter-wrapper-bg: transparent;
759
- --ms-counter-wrapper-border: var(--ms-border);
760
- --ms-counter-wrapper-border-radius: var(--ms-border-radius-sm);
761
- --ms-counter-wrapper-padding: calc(0.4 * var(--ms-rem)) calc(0.8 * var(--ms-rem));
762
- --ms-counter-wrapper-gap: calc(0.4 * var(--ms-rem));
763
- --ms-counter-wrapper-bg-hover: var(--ms-primary-bg);
764
- --ms-counter-wrapper-border-color-hover: var(--ms-accent-color);
765
-
766
- /* ==========================================================================
767
- COUNT TEXT & CLEAR BUTTON
768
- ========================================================================== */
769
- /* Count Text */
770
- --ms-count-text-bg: transparent;
771
- --ms-count-text-border: none;
772
- --ms-count-text-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
773
- --ms-count-text-color: var(--ms-text-color-1);
774
-
775
- /* Count Clear Button */
776
- --ms-count-clear-size: calc(1.6 * var(--ms-rem));
777
- --ms-count-clear-bg: transparent;
778
- --ms-count-clear-color: var(--ms-text-color-3);
779
- --ms-count-clear-font-size: calc(var(--base-font-size-lg, 1.8) * var(--ms-rem));
780
- --ms-count-clear-border-radius: var(--ms-border-radius-sm);
781
- /* Hover fills with SOLID accent and flips the glyph to text-on-accent — mirrors
782
- .ms__badge-remove. The old "accent-tint bg + accent glyph" was same-hue: the ✕
783
- melted into its own hover background (invisible on near-white accents like
784
- minimal-dark, low-contrast blue-on-blue everywhere else). */
785
- --ms-count-clear-bg-hover: var(--ms-accent-color);
786
- --ms-count-clear-color-hover: var(--ms-text-color-on-accent);
787
- --ms-count-clear-icon-size: calc(1.4 * var(--ms-rem));
788
- /* Field-clear ✕ (input clear + count clear). Its own knob in the --base-icon contract:
789
- prefers --base-icon-clear so a theme can diverge field-clear from close/remove, then falls
790
- through to --ms-icon-remove (which itself resolves --base-icon-remove → --base-icon-close →
791
- inline ✕). Same glyph as remove by default; override --base-icon-clear alone to split them. */
792
- --ms-icon-clear: var(--base-icon-clear, var(--ms-icon-remove));
793
-
794
- /* ==========================================================================
795
- TOOLTIPS
796
- ========================================================================== */
797
- --ms-tooltip-color: var(--ms-tooltip-text-color);
798
- --ms-tooltip-padding: calc(0.8 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
799
- --ms-tooltip-border-radius: var(--ms-border-radius-lg);
800
- --ms-tooltip-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
801
- --ms-tooltip-max-width: calc(32 * var(--ms-rem));
802
- --ms-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
803
- --ms-tooltip-z-index: 10000;
804
-
805
- /* Option (dropdown row) tooltip — per-feature hooks default to the shared tooltip surface,
806
- so option tooltips look identical until you override one of these independently. */
807
- --ms-option-tooltip-bg: var(--ms-tooltip-bg);
808
- --ms-option-tooltip-text-color: var(--ms-tooltip-text-color);
809
- --ms-option-tooltip-padding: var(--ms-tooltip-padding);
810
- --ms-option-tooltip-border-radius: var(--ms-tooltip-border-radius);
811
- --ms-option-tooltip-font-size: var(--ms-tooltip-font-size);
812
- --ms-option-tooltip-max-width: var(--ms-tooltip-max-width);
813
- --ms-option-tooltip-shadow: var(--ms-tooltip-shadow);
814
- --ms-option-tooltip-z-index: var(--ms-tooltip-z-index);
815
-
816
- /* ==========================================================================
817
- TRANSIENT MESSAGE / TOAST (showMessage)
818
- Surfaced on top of the component so a veto reason (or any consumer feedback)
819
- is visible even in the fullscreen overlay, where page UI is covered. Sizing is
820
- --ms-rem-based (a fullscreen override rescales it below at :host); per-variant
821
- colours default to sensible tones and are theme-overridable via --base-*.
822
- ========================================================================== */
823
- --ms-message-bg: var(--ms-message-info-bg);
824
- --ms-message-color: var(--ms-message-info-color);
825
- --ms-message-border: 1px solid transparent;
826
- --ms-message-border-radius: var(--ms-border-radius-lg);
827
- --ms-message-padding: calc(1.0 * var(--ms-rem)) calc(1.4 * var(--ms-rem));
828
- --ms-message-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
829
- --ms-message-font-weight: var(--base-font-weight-medium, 500);
830
- --ms-message-max-width: calc(40 * var(--ms-rem));
831
- --ms-message-shadow: 0 4px 16px rgb(0 0 0 / 0.18);
832
- /* Gap from the bottom edge of the viewport in the fullscreen overlay. */
833
- --ms-message-fullscreen-offset: calc(2.4 * var(--ms-fullscreen-rem));
834
- --ms-message-z-index: var(--ms-z-index-fullscreen-tooltip);
835
- /* Variants (bg + text). Info reuses the tooltip surface; the rest are status tones. */
836
- --ms-message-info-bg: var(--ms-tooltip-bg);
837
- --ms-message-info-color: var(--ms-tooltip-text-color);
838
- --ms-message-warning-bg: var(--base-warning-bg, #f59e0b);
839
- --ms-message-warning-color: var(--base-warning-color, #1a1a1a);
840
- --ms-message-error-bg: var(--base-danger-bg, #ef4444);
841
- --ms-message-error-color: var(--base-danger-color, #ffffff);
842
- --ms-message-success-bg: var(--base-success-bg, #10b981);
843
- --ms-message-success-color: var(--base-success-color, #ffffff);
844
-
845
- /* ==========================================================================
846
- SELECTED POPOVER
847
- ========================================================================== */
848
- --ms-z-index-popover: 10000;
849
- /* Selected-items ("badges") popover width — tracks the live field width by default (same
850
- as the dropdown, so the two panels line up under the control). Override at app/theme
851
- level or per-instance via the selected-popover-width attribute — e.g. a fixed
852
- calc(32 * var(--ms-rem)) for a constant width independent of the field. */
853
- --ms-selected-popover-width: var(--ms-input-current-width);
854
- --ms-selected-popover-max-height: calc(32 * var(--ms-rem));
855
- --ms-selected-popover-border: 1px solid var(--ms-selected-popover-border-color);
856
- --ms-selected-popover-border-radius: var(--ms-border-radius-lg);
857
- --ms-selected-popover-box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
858
-
859
- /* Popover Header */
860
- --ms-selected-popover-header-padding: calc(0.8 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
861
- --ms-selected-popover-header-bg: color-mix(in srgb, var(--ms-accent-color) 10%, transparent);
862
- --ms-selected-popover-header-border-bottom: 1px solid var(--ms-selected-popover-header-border-color);
863
- --ms-selected-popover-header-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
864
- --ms-selected-popover-header-font-weight: var(--base-font-weight-semibold, 600);
865
- --ms-selected-popover-header-color: var(--ms-text-color-1);
866
-
867
- /* ==========================================================================
868
- POPOVER CLOSE BUTTON
869
- ========================================================================== */
870
- --ms-popover-close-size: calc(2.4 * var(--ms-rem));
871
- --ms-selected-popover-close-bg: transparent;
872
- --ms-selected-popover-close-color: var(--ms-text-color-3);
873
- --ms-selected-popover-close-font-size: calc(var(--base-font-size-xl, 2) * var(--ms-rem));
874
- --ms-selected-popover-close-border-radius: var(--ms-border-radius-sm);
875
- /* Solid accent fill + on-accent glyph (see .ms__count-clear note) — avoids the
876
- same-hue "accent glyph on accent-tint" melt on hover. */
877
- --ms-selected-popover-close-bg-hover: var(--ms-accent-color);
878
- --ms-selected-popover-close-color-hover: var(--ms-text-color-on-accent);
879
- --ms-selected-popover-close-icon-size: calc(1.4 * var(--ms-rem));
880
-
881
- /* ==========================================================================
882
- POPOVER BODY
883
- ========================================================================== */
884
- --ms-selected-popover-body-gap: calc(0.4 * var(--ms-rem));
885
- --ms-selected-popover-body-padding: calc(0.8 * var(--ms-rem));
886
- --ms-selected-popover-body-max-height: calc(28.8 * var(--ms-rem));
887
-
888
- /* ==========================================================================
889
- TYPOGRAPHY SCALE
890
- ========================================================================== */
891
- /* Font Sizes (unitless multipliers × --ms-rem) */
892
- --ms-font-size-2xs: calc(var(--base-font-size-2xs, 1) * var(--ms-rem));
893
- --ms-font-size-xs: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
894
- --ms-font-size-sm: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
895
- --ms-font-size-base: calc(var(--base-font-size-base, 1.6) * var(--ms-rem));
896
- --ms-font-size-lg: calc(var(--base-font-size-lg, 1.8) * var(--ms-rem));
897
-
898
- /* Font Weights */
899
- --ms-font-weight-normal: var(--base-font-weight-normal, 400);
900
- --ms-font-weight-medium: var(--base-font-weight-medium, 500);
901
- --ms-font-weight-semibold: var(--base-font-weight-semibold, 600);
902
-
903
- /* Line Heights */
904
- --ms-line-height-none: 1;
905
- --ms-line-height-tight: var(--base-line-height-tight, 1.25);
906
- --ms-line-height-normal: var(--base-line-height-normal, 1.5);
907
- --ms-line-height-relaxed: var(--base-line-height-relaxed, 1.75);
908
-
909
- /* ==========================================================================
910
- BORDER RADIUS SCALE
911
- ========================================================================== */
912
- --ms-border-radius-sm: calc(var(--base-border-radius-sm, 0.4) * var(--ms-rem));
913
- --ms-border-radius-md: calc(var(--base-border-radius-md, 0.6) * var(--ms-rem));
914
- --ms-border-radius-lg: calc(var(--base-border-radius-lg, 0.8) * var(--ms-rem));
915
- --ms-border-radius: var(--ms-border-radius-md);
916
-
917
- /* ==========================================================================
918
- SPACING & SIZING
919
- ========================================================================== */
920
- --ms-spacing-xs: calc(0.4 * var(--ms-rem));
921
- --ms-spacing-sm: calc(0.8 * var(--ms-rem));
922
- --ms-spacing-md: calc(1.2 * var(--ms-rem));
923
- --ms-spacing-lg: calc(1.6 * var(--ms-rem));
924
-
925
- /* ==========================================================================
926
- TRANSITIONS & EFFECTS
927
- ========================================================================== */
928
- /* Durations stay local: the --ms scale (150/200ms) doesn't line up with --base-duration-*
929
- (fast 100ms / normal 150ms / medium 250ms), so wiring would silently change timings. */
930
- --ms-transition-fast: 150ms;
931
- --ms-transition-normal: 200ms;
932
- /* Easing is an exact match for --base-ease-standard, so it flows from the shared token. */
933
- --ms-easing-snappy: var(--base-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
934
-
935
- /* ==========================================================================
936
- OPACITY VALUES
937
- ========================================================================== */
938
- --ms-placeholder-opacity: 0.6;
939
- --ms-disabled-input-opacity: 0.6;
940
-
941
- /* ==========================================================================
942
- SCROLLBAR
943
- ========================================================================== */
944
- --ms-scrollbar-width: 8px;
945
- --ms-scrollbar-track-bg: transparent;
946
- --ms-scrollbar-thumb-bg: var(--ms-border-color);
947
- --ms-scrollbar-thumb-bg-hover: var(--ms-text-color-3);
948
- --ms-scrollbar-thumb-border-radius: 4px;
949
-
950
- /* ==========================================================================
951
- DEBUG PANEL (dev-only)
952
- ========================================================================== */
953
- --ms-debug-bg: var(--base-elevated-bg, light-dark(#f9fafb, #2b2b2b));
954
- --ms-debug-border-color: var(--ms-border-color);
955
- --ms-debug-text-color: var(--ms-text-color-1);
956
- --ms-debug-border-radius: var(--ms-border-radius-md);
957
- --ms-debug-summary-color: var(--ms-accent-color);
958
- --ms-debug-summary-bg-hover: var(--ms-primary-bg);
959
- --ms-debug-summary-outline-color: var(--ms-accent-color);
960
- --ms-debug-summary-border-radius: var(--ms-border-radius-sm);
961
- --ms-debug-stats-bg: var(--base-main-bg, light-dark(#ffffff, #1a1a1a));
962
- --ms-debug-stats-border-radius: var(--ms-border-radius-sm);
963
- --ms-debug-bullet-color: var(--ms-accent-color);
964
- }
1
+ /* ==============================================================================
2
+ CSS CUSTOM PROPERTIES (:host level)
3
+ ==============================================================================
4
+ This file defines all CSS custom properties at the :host level, making them:
5
+ - Inspectable in browser DevTools
6
+ - Overridable from outside Shadow DOM
7
+ - Self-documenting in compiled CSS
8
+
9
+ Usage from outside Shadow DOM:
10
+ multi-select {
11
+ --ms-accent-color: #10b981;
12
+ --ms-input-border-radius: 0.5rem;
13
+ }
14
+ ============================================================================== */
15
+
16
+ :host {
17
+ /* Block layout — the wrapper-host pattern paints chrome via .ms__input,
18
+ but :host still needs an explicit display so consumers placing the
19
+ element in inline contexts see the expected layout. */
20
+ display: block;
21
+
22
+ /* ==========================================================================
23
+ COLOR SCHEME
24
+ ==========================================================================
25
+ `color-scheme` is INHERITED on this element — we deliberately do NOT
26
+ declare it on `:host`. Reason: every hardcoded color fallback below is
27
+ wrapped in `light-dark(<light>, <dark>)`, which picks one of the two
28
+ based on the host's used color-scheme. Declaring `color-scheme: light dark`
29
+ here would *override* whatever the consumer's app declared on <html>,
30
+ <body>, or an ancestor — flipping forced-dark apps back to "follow OS",
31
+ and breaking visual coherence with the surrounding page.
32
+ By letting it inherit:
33
+ - dhl-style apps that set `body { color-scheme: dark }` propagate it
34
+ into our shadow DOM unchanged, and `light-dark()` resolves to dark.
35
+ - apps that set `html { color-scheme: light dark }` get OS-preference
36
+ switching, end-to-end.
37
+ - apps that declare nothing get the historical default (light), same
38
+ as before this fallback set was introduced — no behavior change.
39
+ Consumers who want explicit per-multiselect control can still set
40
+ `style="color-scheme: dark"` on the <web-multiselect> element.
41
+
42
+ ========================================================================== */
43
+
44
+ /* ==========================================================================
45
+ BASE SIZING UNIT
46
+ ==========================================================================
47
+ All sizing values are based on this unit for consistent scaling.
48
+ Bridges to the shared --base-rem knob so a theme scales every Keenmate
49
+ component from one variable; falls back to 10px when no base layer is loaded.
50
+ Default: 10px produces standard pixel values
51
+ Pure Admin: Set --base-rem to 1rem (inherits from html { font-size: 10px })
52
+ Custom: Set --base-rem (or --ms-rem for this component only) to scale all sizes */
53
+ --ms-rem: var(--base-rem, 10px);
54
+
55
+ /* ==========================================================================
56
+ FONT FAMILY (set at :host so all shadow DOM content inherits)
57
+ ========================================================================== */
58
+ font-family: var(--ms-font-family, var(--base-font-family, inherit));
59
+
60
+ /* ==========================================================================
61
+ COLORS & THEME
62
+ ==========================================================================
63
+ Color variables follow this priority chain:
64
+ 1. External override: --ms-accent-color: #custom
65
+ 2. Base theme value: var(--base-accent-color)
66
+ 3. Hardcoded default fallback */
67
+
68
+ /* Accent Colors */
69
+ --ms-accent-color: var(--base-accent-color, #3b82f6);
70
+ --ms-accent-color-hover: var(--base-accent-color-hover, #2563eb);
71
+ --ms-accent-color-active: var(--base-accent-color-active, #1d4ed8);
72
+
73
+ /* Accent Color Light Variants (for backgrounds)
74
+ Dark variants are muted dark-blue tints that read like "accent-tinted dark surface" rather than
75
+ "near-white", keeping badge / +X more / popover-header backgrounds visible on a dark page. */
76
+ --ms-accent-color-light: var(--base-accent-color-light, light-dark(#eff6ff, #1e3a5f));
77
+ --ms-accent-color-light-hover: var(--base-accent-color-light-hover, light-dark(#e0f2fe, #264a73));
78
+
79
+ /* Text Color Levels (FluentUI-style hierarchy)
80
+ Light mode = the original dark-on-light palette (#111827 → #a0a3a9).
81
+ Dark mode = the same hierarchy inverted (#f5f5f5 → #737373) so heading/body/secondary/disabled
82
+ keep the same relative contrast steps. text-color-on-accent stays white in both modes — the
83
+ accent color is the same blue in both, and white-on-blue reads in both. */
84
+ --ms-text-color-1: var(--base-text-color-1, light-dark(#111827, #f5f5f5));
85
+ --ms-text-color-2: var(--base-text-color-2, light-dark(#353b47, #d4d4d4));
86
+ --ms-text-color-3: var(--base-text-color-3, light-dark(#6b7280, #a3a3a3));
87
+ --ms-text-color-4: var(--base-text-color-4, light-dark(#a0a3a9, #737373));
88
+ --ms-text-color-on-accent: var(--base-text-color-on-accent, #ffffff);
89
+
90
+ /* Legacy aliases (for backward compatibility) */
91
+ --ms-text-primary: var(--ms-text-color-1);
92
+ --ms-text-secondary: var(--ms-text-color-3);
93
+
94
+ /* Background Colors
95
+ --ms-primary-bg paints hover/focus states (option hover, action-button hover, counter
96
+ hover, etc.); --ms-primary-bg-hover is one step stronger (selected-active, counter badge).
97
+ The color-mix fallback keeps the hover visible on dark themes — a flat var(--base-main-bg)
98
+ substrate used to make hover collapse onto the panel background. */
99
+ --ms-primary-bg: var(--base-hover-bg, color-mix(in srgb, var(--ms-text-color-1) 8%, var(--base-main-bg, light-dark(#ffffff, #1a1a1a))));
100
+ --ms-primary-bg-hover: var(--base-active-bg, color-mix(in srgb, var(--ms-text-color-1) 14%, var(--base-main-bg, light-dark(#ffffff, #1a1a1a))));
101
+
102
+ /* Border Base Variables */
103
+ /* Default border colour. The previous fallbacks (#e5e7eb light / #3a3a3a dark) were very
104
+ low contrast against white / near-black surfaces — the 1px input/panel edge nearly
105
+ vanished, especially on phones. Bumped to a clearly-visible gray on each side (still
106
+ soft, not harsh). Consumers with `--base-border-color` set are unaffected. */
107
+ --ms-border-color: var(--base-border-color, light-dark(#cbd5e1, #52525b));
108
+ --ms-border: var(--base-border, 1px solid var(--ms-border-color));
109
+
110
+ /* ==========================================================================
111
+ SEMANTIC VARIABLES - Component-Specific Theming
112
+ ==========================================================================
113
+ Pattern: --ms-{component}-{property}-{state}
114
+ Example: --ms-input-bg, --ms-option-text-color-hover */
115
+
116
+ /* Input Component Semantic Variables */
117
+ --ms-input-bg: var(--base-input-bg, light-dark(#ffffff, #1a1a1a));
118
+ --ms-input-color: var(--base-input-color, var(--ms-text-color-1));
119
+ --ms-input-border: var(--base-input-border, 1px solid var(--ms-border-color));
120
+ --ms-input-border-hover: var(--base-input-border-hover, 1px solid var(--ms-accent-color));
121
+ --ms-input-border-focus: var(--base-input-border-focus, 1px solid var(--ms-accent-color));
122
+ --ms-input-placeholder-color: var(--base-input-placeholder-color, var(--ms-text-color-4));
123
+ --ms-input-bg-disabled: var(--base-input-bg-disabled, rgba(107, 114, 128, 0.05));
124
+
125
+ /* Toggle Icon Semantic Variables */
126
+ --ms-toggle-icon-color: var(--ms-text-color-3);
127
+ --ms-toggle-icon-color-open: var(--ms-text-color-3);
128
+ --ms-toggle-icon-size: calc(1.6 * var(--ms-rem));
129
+ /* Toggle chevron rotation, closed vs open. Defaults orient the directional right-pointing
130
+ --base-icon-chevron (90° → points down when closed, -90° → up when open). Override BOTH
131
+ when a theme supplies a PRE-ORIENTED chevron glyph: `0deg` / `0deg` for a static glyph,
132
+ or `0deg` / `180deg` for a down-glyph that flips up on open. */
133
+ --ms-toggle-rotate-closed: 90deg;
134
+ --ms-toggle-rotate-open: -90deg;
135
+
136
+ /* Counter Badge (in Input) Semantic Variables */
137
+ --ms-counter-badge-bg: var(--ms-accent-color);
138
+ --ms-counter-badge-bg-hover: var(--ms-accent-color-hover);
139
+ --ms-counter-badge-color: var(--ms-text-color-on-accent);
140
+
141
+ /* Floating Hint Semantic Variables */
142
+ --ms-hint-bg: var(--base-main-bg, light-dark(#ffffff, #1a1a1a));
143
+ --ms-hint-color: var(--ms-text-color-4);
144
+ --ms-hint-border-color: var(--ms-border-color);
145
+
146
+ /* Dropdown Semantic Variables */
147
+ --ms-dropdown-bg: var(--base-dropdown-bg, var(--base-elevated-bg, light-dark(#ffffff, #1a1a1a)));
148
+ --ms-dropdown-text-color: var(--ms-text-color-1);
149
+ --ms-dropdown-border-color: var(--ms-border-color);
150
+ --ms-dropdown-box-shadow-semantic: var(--base-dropdown-box-shadow, 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1));
151
+
152
+ /* Dropdown Actions Semantic Variables */
153
+ --ms-actions-bg: var(--base-main-bg, light-dark(#ffffff, #1a1a1a));
154
+ --ms-actions-border-color: var(--ms-border-color);
155
+
156
+ /* Action Button Semantic Variables */
157
+ --ms-action-button-bg: transparent;
158
+ --ms-action-button-bg-hover: var(--ms-primary-bg);
159
+ --ms-action-button-border-color: var(--ms-border-color);
160
+ --ms-action-button-border-color-hover: var(--ms-accent-color);
161
+ --ms-action-button-color: var(--ms-text-color-1);
162
+
163
+ /* Group Semantic Variables */
164
+ --ms-group-border-color: var(--ms-border-color);
165
+ --ms-group-label-color: var(--ms-text-color-3);
166
+
167
+ /* Option Semantic Variables */
168
+ --ms-option-text-color: var(--ms-text-color-1);
169
+ --ms-option-bg: transparent;
170
+ --ms-option-bg-hover: var(--ms-primary-bg);
171
+ --ms-option-color-hover: inherit;
172
+ --ms-option-bg-focused: var(--ms-primary-bg);
173
+ --ms-option-color-focused: inherit;
174
+ --ms-option-outline-color-focused: var(--ms-accent-color);
175
+ --ms-option-bg-selected: color-mix(in srgb, var(--ms-accent-color) 10%, transparent);
176
+ --ms-option-bg-matched: color-mix(in srgb, var(--ms-accent-color) 8%, transparent);
177
+ --ms-option-color-matched: inherit;
178
+ --ms-option-border-matched-color: color-mix(in srgb, var(--ms-accent-color) 40%, transparent);
179
+
180
+ /* Option Content Semantic Variables */
181
+ --ms-option-title-color: var(--ms-text-color-1);
182
+ --ms-option-subtitle-color: var(--ms-text-color-3);
183
+ --ms-option-mark-bg: color-mix(in srgb, var(--ms-accent-color) 20%, transparent);
184
+ --ms-option-mark-color: inherit;
185
+
186
+ /* Empty/Loading State Semantic Variables */
187
+ --ms-empty-color: var(--ms-text-color-3);
188
+ --ms-loading-color: var(--ms-text-color-3);
189
+
190
+ /* Badge Semantic Variables */
191
+ --ms-badge-bg: var(--ms-accent-color-light);
192
+ /* Hover DEEPENS the badge's OWN rest background toward its OWN text colour.
193
+ Deliberately self-referential: NOT --base-hover-bg (a generic surface token →
194
+ accent pill flipped near-white in dark/neon), and NOT --ms-accent-color-light-hover
195
+ (a separate accent-tint token themes forget to set when they change the accent →
196
+ a black brutalist pill fell back to the hardcoded blue tint on hover). Mixing 12%
197
+ of the text colour into the rest bg is a subtle, always-readable nudge that follows
198
+ whatever bg/text pair a theme sets. */
199
+ --ms-badge-bg-hover: color-mix(in srgb, var(--ms-badge-bg) 88%, var(--ms-badge-text-color) 12%);
200
+ --ms-badge-bg-active: var(--ms-accent-color-light-hover);
201
+
202
+ /* Badge Text Semantic Variables */
203
+ --ms-badge-text-bg: var(--ms-accent-color-light);
204
+ --ms-badge-text-color: var(--ms-accent-color);
205
+ --ms-badge-text-bg-hover: color-mix(in srgb, var(--ms-badge-text-bg) 88%, var(--ms-badge-text-color) 12%);
206
+ --ms-badge-text-color-hover: var(--ms-badge-text-color);
207
+
208
+ /* Badge Remove Button Semantic Variables */
209
+ --ms-badge-remove-bg: var(--ms-accent-color);
210
+ --ms-badge-remove-bg-hover: var(--ms-accent-color-hover);
211
+ --ms-badge-remove-color: var(--ms-text-color-on-accent);
212
+
213
+ /* Badge Counter Variant Semantic Variables
214
+ Neutral/gray styling to distinguish from accent-coloured selection badges.
215
+ Self-contained: the pill is a translucent tint of the strong text colour, and
216
+ text/glyph use the text-colour hierarchy — so contrast holds even when a theme
217
+ omits --base-main-bg (the old --ms-primary-bg-hover chain collapsed to
218
+ light-on-light there). The counter must NOT inherit the accent-coloured hover
219
+ of regular badges — its text stays neutral; only the surface deepens. */
220
+ --ms-badge-counter-border-color: var(--ms-border-color);
221
+ --ms-badge-counter-text-bg: color-mix(in srgb, var(--ms-text-color-1) 10%, transparent);
222
+ --ms-badge-counter-text-bg-hover: color-mix(in srgb, var(--ms-text-color-1) 16%, transparent);
223
+ --ms-badge-counter-text-color: var(--ms-text-color-1);
224
+ --ms-badge-counter-text-color-hover: var(--ms-text-color-1);
225
+ --ms-badge-counter-remove-bg: color-mix(in srgb, var(--ms-text-color-1) 10%, transparent);
226
+ --ms-badge-counter-remove-bg-hover: color-mix(in srgb, var(--ms-text-color-1) 16%, transparent);
227
+ /* Neutral glyph (text-3 at rest → text-1 on hover), NOT white-on-accent — the old
228
+ on-accent glyph vanished once the hover bg became a light text colour. */
229
+ --ms-badge-counter-remove-color: var(--ms-text-color-3);
230
+ --ms-badge-counter-remove-color-hover: var(--ms-text-color-1);
231
+
232
+ /* Count Display Semantic Variables */
233
+ --ms-counter-wrapper-bg: transparent;
234
+ --ms-counter-wrapper-bg-hover: var(--ms-primary-bg);
235
+ --ms-counter-wrapper-border-color: var(--ms-border-color);
236
+ --ms-counter-wrapper-border-color-hover: var(--ms-accent-color);
237
+ --ms-count-text-color: var(--ms-text-color-1);
238
+ --ms-count-clear-bg: transparent;
239
+ --ms-count-clear-bg-hover: var(--ms-accent-color);
240
+ --ms-count-clear-color: var(--ms-text-color-3);
241
+ --ms-count-clear-color-hover: var(--ms-text-color-on-accent);
242
+
243
+ /* Tooltip Semantic Variables
244
+ Tooltips invert relative to the page: dark tooltip on light page, light tooltip on dark page.
245
+ This keeps the tooltip distinct from its surrounding surface in both modes. */
246
+ --ms-tooltip-bg: var(--base-tooltip-bg, var(--base-inverse-bg, light-dark(#333333, #f5f5f5)));
247
+ --ms-tooltip-text-color: var(--base-tooltip-text-color, light-dark(#ffffff, #1a1a1a));
248
+
249
+ /* Selected Popover Semantic Variables */
250
+ --ms-selected-popover-bg: var(--base-dropdown-bg, var(--base-elevated-bg, light-dark(#ffffff, #1a1a1a)));
251
+ --ms-selected-popover-border-color: var(--ms-border-color);
252
+ --ms-selected-popover-header-bg: color-mix(in srgb, var(--ms-accent-color) 10%, transparent);
253
+ --ms-selected-popover-header-color: var(--ms-text-color-1);
254
+ --ms-selected-popover-header-border-color: var(--ms-border-color);
255
+ --ms-selected-popover-close-bg: transparent;
256
+ --ms-selected-popover-close-bg-hover: var(--ms-accent-color);
257
+ --ms-selected-popover-close-color: var(--ms-text-color-3);
258
+ --ms-selected-popover-close-color-hover: var(--ms-text-color-on-accent);
259
+
260
+ /* ==========================================================================
261
+ INPUT COMPONENT
262
+ ========================================================================== */
263
+ --ms-input-padding-h: calc(1.2 * var(--ms-rem)); /* field shell inline padding */
264
+ --ms-input-gap: calc(0.6 * var(--ms-rem)); /* gap between input + trailing decorations */
265
+ --ms-input-height: calc(var(--base-input-size-md-height, 3.5) * var(--ms-rem));
266
+ --ms-input-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
267
+ --ms-input-border-width: 1px;
268
+ --ms-input-border-radius: var(--ms-border-radius-md);
269
+ --ms-input-text: var(--ms-text-color-1);
270
+ /* Prefers the shared --base token (light-dark aware, so it adapts on dark themes);
271
+ the flat gray is the standalone fallback. */
272
+ --ms-input-bg-disabled: var(--base-input-bg-disabled, rgba(107, 114, 128, 0.05));
273
+
274
+ /* ==========================================================================
275
+ INPUT SIZE VARIANTS — currently unused (commented out)
276
+ ==========================================================================
277
+ Preset size tiers (xs/sm/md/lg/xl) for the input. Read only by the
278
+ .ms__input--* classes in controls.css, which nothing toggles (no `size`
279
+ attribute), so this whole chain is inert. Commented out to drop dead theming
280
+ surface — kept, not deleted, in case a future `size` attribute turns it into a
281
+ named-preset API; no case has needed it yet. Size via --ms-rem (global) or the
282
+ individual --ms-input-* vars (targeted) instead. Heights reference
283
+ --base-input-size-*-height for cross-component consistency (px in parens):
284
+
285
+ --ms-input-size-xs-font: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
286
+ --ms-input-size-xs-padding-v: calc(0.4 * var(--ms-rem));
287
+ --ms-input-size-xs-padding-h: calc(0.8 * var(--ms-rem));
288
+ --ms-input-size-xs-height: calc(var(--base-input-size-xs-height, 3.1) * var(--ms-rem)); (31px)
289
+
290
+ --ms-input-size-sm-font: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
291
+ --ms-input-size-sm-padding-v: calc(0.5 * var(--ms-rem));
292
+ --ms-input-size-sm-padding-h: calc(1.0 * var(--ms-rem));
293
+ --ms-input-size-sm-height: calc(var(--base-input-size-sm-height, 3.3) * var(--ms-rem)); (33px)
294
+
295
+ --ms-input-size-md-font: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
296
+ --ms-input-size-md-padding-v: calc(0.8 * var(--ms-rem));
297
+ --ms-input-size-md-padding-h: calc(1.2 * var(--ms-rem));
298
+ --ms-input-size-md-height: calc(var(--base-input-size-md-height, 3.5) * var(--ms-rem)); (35px)
299
+
300
+ --ms-input-size-lg-font: calc(var(--base-font-size-base, 1.6) * var(--ms-rem));
301
+ --ms-input-size-lg-padding-v: calc(1.0 * var(--ms-rem));
302
+ --ms-input-size-lg-padding-h: calc(1.4 * var(--ms-rem));
303
+ --ms-input-size-lg-height: calc(var(--base-input-size-lg-height, 3.8) * var(--ms-rem)); (38px)
304
+
305
+ --ms-input-size-xl-font: calc(var(--base-font-size-lg, 1.8) * var(--ms-rem));
306
+ --ms-input-size-xl-padding-v: calc(1.2 * var(--ms-rem));
307
+ --ms-input-size-xl-padding-h: calc(1.6 * var(--ms-rem));
308
+ --ms-input-size-xl-height: calc(var(--base-input-size-xl-height, 4.1) * var(--ms-rem)); (41px)
309
+ */
310
+
311
+ /* ==========================================================================
312
+ TOGGLE ICON
313
+ ========================================================================== */
314
+ --ms-toggle-color: var(--ms-text-color-3);
315
+ --ms-transform-rotate-180: 180deg;
316
+
317
+ /* ==========================================================================
318
+ INPUT CLEAR (✕)
319
+ ========================================================================== */
320
+ --ms-input-clear-size: calc(2.4 * var(--ms-rem));
321
+ --ms-input-clear-icon-size: calc(1.4 * var(--ms-rem));
322
+ --ms-input-clear-color: var(--base-input-clear-color, var(--ms-text-secondary));
323
+ --ms-input-clear-bg-hover: var(--base-input-clear-bg-hover, var(--ms-option-bg-matched, transparent));
324
+ --ms-input-clear-border-radius: var(--ms-border-radius); /* matches the input; square when radius is 0 */
325
+
326
+ /* ==========================================================================
327
+ COUNT BADGE (in input)
328
+ ========================================================================== */
329
+ --ms-counter-padding: calc(0.2 * var(--ms-rem)) calc(0.4 * var(--ms-rem));
330
+ --ms-counter-bg: var(--ms-accent-color);
331
+ --ms-counter-color: var(--ms-text-color-on-accent);
332
+ --ms-counter-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
333
+ --ms-counter-font-weight: var(--base-font-weight-semibold, 600);
334
+ --ms-counter-border-radius: var(--ms-border-radius-sm);
335
+ --ms-counter-bg-hover: var(--ms-accent-color-hover);
336
+ --ms-transform-scale-hover: 1.1;
337
+
338
+ /* ==========================================================================
339
+ FLOATING HINT
340
+ ========================================================================== */
341
+ --ms-hint-padding: calc(0.8 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
342
+ --ms-hint-border: 1px solid var(--ms-hint-border-color);
343
+ --ms-hint-border-radius: var(--ms-border-radius-lg);
344
+ --ms-hint-box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
345
+ --ms-hint-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
346
+
347
+ /* ==========================================================================
348
+ DROPDOWN
349
+ ========================================================================== */
350
+ --ms-dropdown-border: var(--base-dropdown-border, 1px solid var(--ms-dropdown-border-color));
351
+ --ms-dropdown-border-radius: var(--ms-border-radius-lg);
352
+ /* Inner content clip radius — a hair tighter than the panel so a highlighted
353
+ first/last row (or the sticky Select-All/Clear actions bar) follows the panel's
354
+ rounded corners instead of its square background bleeding ~1px past the rounded
355
+ border (the classic rounded-parent + bordered-box corner artifact). Assumes the
356
+ default 1px --ms-dropdown-border; if you theme a thicker border, override this to
357
+ match (panel radius − border width). Clamped at 0 so a squared panel stays square. */
358
+ --ms-dropdown-inner-border-radius: max(0px, calc(var(--ms-dropdown-border-radius) - 1px));
359
+ /* Prefers the shared --base token (light-dark aware — deepens on dark themes); the
360
+ flat two-layer shadow is the standalone fallback. */
361
+ --ms-dropdown-box-shadow: var(--base-dropdown-box-shadow, 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1));
362
+ /* Live input width, published by JS each positioning frame. It's the only panel
363
+ dimension CSS can't measure itself, so panels that "match the input" read it. */
364
+ --ms-input-current-width: auto;
365
+ /* Options dropdown width. Defaults to the input width; override at app/theme level
366
+ (web-multiselect { --ms-dropdown-width: 60rem }) or per-instance via the
367
+ dropdown-width attribute. dropdown-min-width / dropdown-max-width still clamp it. */
368
+ --ms-dropdown-width: var(--ms-input-current-width);
369
+ --ms-options-max-height: calc(32 * var(--ms-rem));
370
+ --ms-option-color: var(--ms-text-color-1);
371
+ --ms-z-index-dropdown: 9999;
372
+ --ms-z-index-sticky: 1;
373
+
374
+ /* ==========================================================================
375
+ FULLSCREEN OVERLAY (touch / phone presentation)
376
+ Used when a panel is presented as a full-viewport overlay — the options
377
+ dropdown (`.ms__dropdown--fullscreen`) AND the selected-items popover
378
+ (`.ms__selected-popover--fullscreen`). Both share ONE header-bar + close-
379
+ button treatment so the mobile view is consistent. Driven by the element's
380
+ environmentChanged hook on phones. Everything defaults to the dropdown's own
381
+ theming so a fullscreen panel looks like the same component.
382
+ ========================================================================== */
383
+ --ms-z-index-fullscreen: 10001; /* above dropdown (9999) + popover/tooltip (10000) */
384
+ /* The truncated-label reveal is triggered from INSIDE the fullscreen overlay, so it
385
+ must sit above it (the plain option tooltip at 10000 renders behind the 10001 panel). */
386
+ --ms-z-index-fullscreen-tooltip: 10002;
387
+ /* Size of the phone view. Every size in the component is calc(N × --ms-rem), so the
388
+ fullscreen panels override --ms-rem with this to scale rows, text, checkboxes,
389
+ padding, header and search up together (~1.2× → comfortable ~44–48px touch rows).
390
+ A plain length (not calc(1.2 × --ms-rem)) so assigning it to --ms-rem on the panel
391
+ can't form a cyclic var() reference. Set it larger for chunkier touch targets. */
392
+ --ms-fullscreen-rem: 12px;
393
+ /* These overlay-only vars are sized in --ms-fullscreen-rem (NOT --ms-rem): a custom
394
+ property bakes its var() at its declaration site, so declaring them here against
395
+ --ms-fullscreen-rem gives the enlarged phone-view sizes wherever they're consumed. */
396
+ --ms-fullscreen-bg: var(--ms-dropdown-bg);
397
+ --ms-fullscreen-text-color: var(--ms-dropdown-text-color);
398
+ --ms-fullscreen-header-bg: var(--ms-dropdown-bg);
399
+ --ms-fullscreen-header-border: 1px solid var(--ms-dropdown-border-color);
400
+ --ms-fullscreen-header-gap: calc(0.8 * var(--ms-fullscreen-rem));
401
+ /* Split into v/h so the close button can reclaim this exact padding with negative
402
+ margins to reach the sheet's physical corner (see .ms__fullscreen-close). */
403
+ --ms-fullscreen-header-padding-v: calc(0.8 * var(--ms-fullscreen-rem));
404
+ --ms-fullscreen-header-padding-h: calc(1.2 * var(--ms-fullscreen-rem));
405
+ --ms-fullscreen-header-padding: var(--ms-fullscreen-header-padding-v) var(--ms-fullscreen-header-padding-h);
406
+ --ms-fullscreen-header-min-height: calc(5.6 * var(--ms-fullscreen-rem)); /* consistent bar height: search vs title */
407
+ --ms-fullscreen-title-font-size: calc(1.7 * var(--ms-fullscreen-rem));
408
+ --ms-fullscreen-title-font-weight: var(--base-font-weight-semibold, 600);
409
+ --ms-fullscreen-search-border: var(--ms-input-border);
410
+ --ms-fullscreen-search-border-radius: var(--ms-input-border-radius);
411
+ --ms-fullscreen-search-padding: calc(0.8 * var(--ms-fullscreen-rem)) calc(1.2 * var(--ms-fullscreen-rem));
412
+ --ms-fullscreen-search-font-size: calc(1.6 * var(--ms-fullscreen-rem));
413
+ /* Inline clear (✕) inside the fullscreen search field: a small round mask-icon
414
+ button pinned to the trailing edge, shown only while there's a term. The gutter
415
+ reserves trailing padding on the input so typed text never runs under it. */
416
+ --ms-fullscreen-search-clear-size: calc(2.8 * var(--ms-fullscreen-rem));
417
+ --ms-fullscreen-search-clear-icon-size: calc(1.4 * var(--ms-fullscreen-rem));
418
+ --ms-fullscreen-search-clear-inset: calc(0.4 * var(--ms-fullscreen-rem));
419
+ --ms-fullscreen-search-clear-gutter: calc(3.4 * var(--ms-fullscreen-rem));
420
+ --ms-fullscreen-search-clear-color: var(--ms-text-muted-color, var(--ms-dropdown-text-color));
421
+ --ms-fullscreen-search-clear-bg-hover: var(--ms-option-bg-matched, transparent);
422
+ /* Leading search-mode toggle (opt-in): a small round mask-icon button at the field's
423
+ leading edge, sized like the clear button. Icon swaps by mode (see the [data-mode]
424
+ rules in floating.css). */
425
+ --ms-fullscreen-mode-toggle-size: calc(2.8 * var(--ms-fullscreen-rem));
426
+ --ms-fullscreen-mode-toggle-icon-size: calc(1.5 * var(--ms-fullscreen-rem));
427
+ /* Gap between the leading toggle and the search field. Defaults to the header gap so it
428
+ matches the field↔close spacing on the trailing side (symmetric bar); override to
429
+ decouple. */
430
+ --ms-fullscreen-mode-toggle-gap: var(--ms-fullscreen-header-gap);
431
+ --ms-fullscreen-mode-toggle-color: var(--ms-text-muted-color, var(--ms-dropdown-text-color));
432
+ --ms-fullscreen-mode-toggle-bg: transparent;
433
+ --ms-fullscreen-mode-toggle-bg-hover: var(--ms-option-bg-matched, transparent);
434
+ --ms-fullscreen-close-size: calc(3.6 * var(--ms-fullscreen-rem));
435
+ --ms-fullscreen-close-icon-size: calc(1.6 * var(--ms-fullscreen-rem));
436
+ --ms-fullscreen-close-color: var(--ms-dropdown-text-color);
437
+ /* Visible close chip. Defaults to a borderless, transparent, round hit-glyph (so it
438
+ reads as a bare ✕), but these turn it into a bordered "button" like a command-
439
+ palette close — e.g. --ms-fullscreen-close-border: 1px solid var(--ms-border-color);
440
+ --ms-fullscreen-close-border-radius: calc(0.8 * var(--ms-fullscreen-rem));
441
+ --ms-fullscreen-close-bg: var(--ms-input-bg);. The tap target stays larger than the
442
+ chip (see the ::after in floating.css), so bordering it doesn't shrink what's
443
+ clickable. */
444
+ --ms-fullscreen-close-bg: transparent;
445
+ --ms-fullscreen-close-border: none;
446
+ --ms-fullscreen-close-border-radius: 50%;
447
+ --ms-fullscreen-close-bg-hover: var(--ms-option-bg-matched, transparent);
448
+ /* Corner tap target. The visible chip stays --close-size (so it never inflates the
449
+ header height), but a transparent ::after extends the *hit* area into the sheet's
450
+ top-trailing corner — the dead header padding around a centered button was the "tap
451
+ here → nothing happens" zone, and the corner is the easiest place to hit.
452
+ --edge-nudge is a negative inline-end margin that slides the whole button (and its
453
+ glyph) that much closer to the physical edge. */
454
+ --ms-fullscreen-close-edge-nudge: calc(0.8 * var(--ms-fullscreen-rem));
455
+ /* Truncated-label info affordance (fullscreen only). A circled "i" revealed at the
456
+ trailing edge of a row whose label is clipped, so the full label is one tap away
457
+ on touch (where hover tooltips never fire). Sized in --ms-fullscreen-rem. */
458
+ --ms-fullscreen-info-size: calc(2.8 * var(--ms-fullscreen-rem));
459
+ --ms-fullscreen-info-icon-size: calc(1.8 * var(--ms-fullscreen-rem));
460
+ --ms-fullscreen-info-color: var(--ms-accent-color);
461
+ --ms-fullscreen-info-bg-hover: var(--ms-option-bg-matched, transparent);
462
+ /* Navigate-mode match navigator under the fullscreen search box: a muted result
463
+ count plus round prev/next buttons that step through matches (the touch stand-in
464
+ for desktop's Ctrl+Arrow). Sized in --ms-fullscreen-rem like the rest of the overlay. */
465
+ --ms-fullscreen-nav-gap: calc(0.6 * var(--ms-fullscreen-rem));
466
+ --ms-fullscreen-nav-padding-top: calc(0.6 * var(--ms-fullscreen-rem));
467
+ --ms-fullscreen-nav-count-font-size: calc(1.3 * var(--ms-fullscreen-rem));
468
+ --ms-fullscreen-nav-count-color: var(--ms-text-muted-color, var(--ms-dropdown-text-color));
469
+ --ms-fullscreen-nav-btn-size: calc(3.2 * var(--ms-fullscreen-rem));
470
+ --ms-fullscreen-nav-btn-icon-size: calc(1.6 * var(--ms-fullscreen-rem));
471
+ --ms-fullscreen-nav-btn-color: var(--ms-dropdown-text-color);
472
+ --ms-fullscreen-nav-btn-bg: var(--ms-option-bg-matched, transparent);
473
+ /* Hover = a stronger accent tint than the resting state (8%). A translucent color-mix
474
+ of the accent adapts to any panel background — unlike --ms-accent-color-light, which is
475
+ a fixed light-dark() pair that resolves to its pale light branch on dark themes that set
476
+ --base-* colors but not color-scheme (e.g. the neon example), producing a jarring near-white
477
+ chip. Stays fully themeable via this variable. */
478
+ --ms-fullscreen-nav-btn-bg-hover: color-mix(in srgb, var(--ms-accent-color) 22%, transparent);
479
+ /* Pager match-navigator glyph (the prev/next ^ ⌄ buttons). Defaults to the shared
480
+ --ms-icon-chevron, so it follows the base chevron out of the box. The pager rotates this
481
+ source -90° (prev → up) / 90° (next → down), so it expects a RIGHT-pointing glyph — override
482
+ it here if a theme points --base-icon-chevron somewhere else (e.g. a pre-oriented toggle
483
+ caret) and you don't want that leaking into the pager. */
484
+ --ms-fullscreen-nav-btn-icon: var(--ms-icon-chevron);
485
+ /* Chevron glyph — the dropdown toggle's affordance, and the default source for the pager
486
+ (via --ms-fullscreen-nav-btn-icon above). Wired to the --base-icon contract
487
+ (--base-icon-chevron, a Lucide angle that fills its viewBox, so it renders at full optical
488
+ size — unlike the small solid caret) with an inline right-pointing chevron as the standalone
489
+ fallback. It points RIGHT at rest; consumers rotate it into place (toggle: 90° closed → down,
490
+ -90° open → up — themeable via --ms-toggle-rotate-*; pager: -90° → up, 90° → down). Override
491
+ --ms-icon-chevron (or --base-icon-chevron globally) to re-skin both at once, or override
492
+ --ms-fullscreen-nav-btn-icon alone to diverge the pager. */
493
+ --ms-icon-chevron: var(--base-icon-chevron, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m9 18 6-6-6-6'/></svg>"));
494
+ /* SVG "i-in-a-circle" glyph — rendered via mask so it inherits the info color via
495
+ currentColor. Override with any mask-friendly url() SVG. */
496
+ --ms-icon-info: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='9' fill='none' stroke='black' stroke-width='2'/><circle cx='12' cy='7.5' r='1.3' fill='black'/><path d='M12 11v6' stroke='black' stroke-width='2' stroke-linecap='round' fill='none'/></svg>");
497
+ /* Tighter tree indent for the phone overlay so deep nodes leave room for the label.
498
+ Sized in --ms-fullscreen-rem (like the rest of the overlay) so it scales with the
499
+ phone view: at the 12px default this is ~8.4px base + ~14.4px/level, vs the
500
+ floating default's real-rem 0.75rem/1.25rem (tree.css). Raise --ms-fullscreen-rem
501
+ and the indent grows with the rows. */
502
+ --ms-fullscreen-tree-base-indent: calc(0.7 * var(--ms-fullscreen-rem));
503
+ --ms-fullscreen-tree-indent: calc(1.2 * var(--ms-fullscreen-rem));
504
+
505
+ /* ==========================================================================
506
+ DROPDOWN ACTIONS
507
+ ========================================================================== */
508
+ --ms-actions-gap: calc(0.4 * var(--ms-rem));
509
+ --ms-actions-padding: calc(0.8 * var(--ms-rem));
510
+ --ms-actions-border-bottom: 1px solid var(--ms-actions-border-color);
511
+
512
+ /* Action Button */
513
+ --ms-action-btn-padding: calc(0.4 * var(--ms-rem)) calc(0.8 * var(--ms-rem));
514
+ --ms-action-btn-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
515
+ --ms-action-btn-border: var(--ms-border);
516
+ --ms-action-btn-border-radius: var(--ms-border-radius-sm);
517
+ --ms-action-btn-bg: transparent;
518
+ --ms-action-btn-color: inherit;
519
+ --ms-action-btn-bg-hover: var(--ms-primary-bg);
520
+ --ms-action-btn-border-color-hover: var(--ms-accent-color);
521
+ --ms-transform-scale-active: 0.98;
522
+
523
+ /* ==========================================================================
524
+ OPTIONS CONTAINER & GROUPS
525
+ ========================================================================== */
526
+ --ms-options-padding: 0;
527
+
528
+ /* Group */
529
+ --ms-group-border-top: 1px solid var(--ms-group-border-color);
530
+ --ms-group-margin-top: calc(0.4 * var(--ms-rem));
531
+ --ms-group-padding-top: calc(0.4 * var(--ms-rem));
532
+
533
+ /* Group Label */
534
+ --ms-group-label-padding: calc(0.4 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
535
+ --ms-group-label-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
536
+ --ms-group-label-font-weight: var(--base-font-weight-semibold, 600);
537
+ --ms-group-label-color: var(--ms-text-color-3);
538
+ --ms-group-label-transform: uppercase;
539
+ --ms-group-label-letter-spacing: 0.05em;
540
+
541
+ /* ==========================================================================
542
+ INDIVIDUAL OPTIONS
543
+ ==========================================================================
544
+ Per-component theming colors live in the SEMANTIC VARIABLES block above
545
+ (--ms-option-bg, --ms-option-bg-hover, --ms-option-bg-focused,
546
+ --ms-option-bg-matched, --ms-option-bg-selected, --ms-option-outline-color-focused,
547
+ --ms-option-border-matched-color). This block holds layout-only sizing. */
548
+ --ms-option-gap: calc(0.8 * var(--ms-rem));
549
+ --ms-option-padding: calc(0.8 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
550
+ --ms-option-padding-h: calc(1.2 * var(--ms-rem));
551
+ /* Adjustable row height for non-virtual rows (flat + tree). Default `auto` =
552
+ content-driven (padding + line-height), matching web-treeview's node rows.
553
+ Set a length for a consistent minimum row height; rows still grow if their
554
+ content is taller (unless you also truncate the title, below). Virtual-scroll
555
+ rows use the fixed `--ms-option-height` instead. */
556
+ --ms-option-min-height: auto;
557
+ --ms-option-outline-focused: 2px solid var(--ms-option-outline-color-focused);
558
+ --ms-option-focus-outline-offset: -2px;
559
+ --ms-option-border-matched: 3px solid var(--ms-option-border-matched-color);
560
+
561
+ /* Option State Combinations */
562
+ --ms-option-bg-focused-hover: var(--ms-primary-bg);
563
+ --ms-option-bg-matched-hover: color-mix(in srgb, var(--ms-accent-color) 12%, transparent);
564
+ --ms-option-bg-selected-focused: color-mix(in srgb, var(--ms-accent-color) 15%, transparent);
565
+ --ms-option-bg-selected-matched: color-mix(in srgb, var(--ms-accent-color) 15%, transparent);
566
+ --ms-option-disabled-bg: var(--base-disabled-bg, transparent);
567
+ --ms-option-bg-disabled-selected: color-mix(in srgb, var(--ms-accent-color) 10%, transparent);
568
+
569
+ --ms-disabled-opacity: 0.5;
570
+
571
+ /* ==========================================================================
572
+ OPTION CONTENT
573
+ ========================================================================== */
574
+ --ms-option-content-gap: calc(0.8 * var(--ms-rem));
575
+
576
+ /* Option Icon */
577
+ --ms-option-icon-size: calc(2 * var(--ms-rem));
578
+ --ms-option-icon-font-size: calc(var(--base-font-size-base, 1.6) * var(--ms-rem));
579
+
580
+ /* Option Title (--ms-option-mark-bg / --ms-option-mark-color live in the SEMANTIC VARIABLES block above) */
581
+ --ms-option-title-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
582
+ --ms-option-mark-font-weight: var(--base-font-weight-semibold, 600);
583
+ /* Long-title handling. Default = wrap (multi-line), matching the treeview
584
+ packages, which leave `.wtv__node-label` / `.stv__node-label` unstyled. To
585
+ truncate to a single line with an ellipsis, flip all three (a length is only
586
+ needed if you didn't already fix the row height):
587
+ --ms-option-title-white-space: nowrap;
588
+ --ms-option-title-overflow: hidden;
589
+ --ms-option-title-text-overflow: ellipsis;
590
+ `.ms__option-title` is the label hook (analogous to `.wtv__node-label`); its
591
+ flex ancestors already set `min-width: 0`, so ellipsis works without extra CSS.
592
+ Pair with `enable-option-tooltips` to reveal the full text on hover. */
593
+ --ms-option-title-white-space: normal;
594
+ --ms-option-title-overflow: visible;
595
+ --ms-option-title-text-overflow: clip;
596
+
597
+ /* Option Subtitle */
598
+ --ms-option-subtitle-margin-top: calc(0.4 * var(--ms-rem));
599
+ --ms-option-subtitle-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
600
+ --ms-option-subtitle-line-height: var(--base-line-height-tight, 1.25);
601
+
602
+ /* Checkbox */
603
+ /* Zero by default: the row centers the checkbox via `align-items: center`, so any
604
+ top margin would decenter it (the checkbox sat ~1px low against the label — most
605
+ visible in fullscreen where --ms-rem is larger). The small top nudge is only
606
+ meaningful when the checkbox aligns to the top of a wrapping label; it's applied
607
+ there via [data-checkbox-align="top"] in options.css. */
608
+ --ms-checkbox-margin-top: 0;
609
+ --ms-checkbox-margin-right: 0;
610
+ --ms-checkbox-margin-bottom: 0;
611
+ --ms-checkbox-margin-left: 0;
612
+ --ms-checkbox-size: calc(1.6 * var(--ms-rem));
613
+ --ms-checkbox-scale: 1;
614
+ --ms-checkbox-align: center;
615
+
616
+ /* Checkbox Styling */
617
+ --ms-checkbox-bg: var(--ms-input-bg);
618
+ /* Unchecked border — deliberately stronger than the faint generic --ms-border so
619
+ the box reads as a real, clickable control. Tune weight/colour with these two. */
620
+ --ms-checkbox-border-width: 1px;
621
+ --ms-checkbox-border-color: var(--base-checkbox-border-color, #8f8f8f);
622
+ --ms-checkbox-border: var(--ms-checkbox-border-width) solid var(--ms-checkbox-border-color);
623
+ --ms-checkbox-border-radius: calc(0.3 * var(--ms-rem));
624
+ /* Checkmark stroke width — bump for a bolder tick. */
625
+ --ms-checkbox-checkmark-thickness: 2.5px;
626
+ --ms-checkbox-checked-bg: var(--ms-accent-color);
627
+ --ms-checkbox-checked-border: var(--ms-checkbox-border-width) solid var(--ms-accent-color);
628
+ --ms-checkbox-checkmark-color: var(--ms-text-color-on-accent);
629
+ --ms-checkbox-hover-border-color: var(--ms-accent-color);
630
+ --ms-checkbox-disabled-bg: var(--ms-primary-bg);
631
+ --ms-checkbox-disabled-border: var(--ms-checkbox-border-width) solid var(--ms-border-color);
632
+
633
+ /* Checkbox State Combinations */
634
+ --ms-checkbox-checked-bg-hover: var(--ms-accent-color-hover);
635
+ --ms-checkbox-checked-border-color-hover: var(--ms-accent-color-hover);
636
+
637
+ /* ==========================================================================
638
+ EMPTY & LOADING STATES
639
+ ========================================================================== */
640
+ /* Shared footprint so the dropdown doesn't jump when swapping the empty
641
+ ("No data") block for the loader (spinner + text) during async search.
642
+ Sized to contain a small spinner + gap + one text line; override if a
643
+ consumer's loader is taller. */
644
+ --ms-state-min-height: calc(8 * var(--ms-rem));
645
+ --ms-empty-padding: calc(1.6 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
646
+ --ms-empty-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
647
+ --ms-empty-color: var(--ms-text-color-3);
648
+
649
+ /* "Add new" prompt (empty state when isAddNewAllowed + typed text). A clickable
650
+ row keyed off the accent so it reads as an action, not a dead message. */
651
+ --ms-add-new-padding: var(--ms-option-padding);
652
+ --ms-add-new-gap: var(--ms-option-gap);
653
+ --ms-add-new-font-size: var(--ms-empty-font-size);
654
+ --ms-add-new-color: var(--ms-accent-color);
655
+ --ms-add-new-color-hover: var(--ms-accent-color);
656
+ --ms-add-new-bg-hover: var(--ms-option-bg-hover);
657
+ --ms-add-new-icon-size: calc(1.6 * var(--ms-rem));
658
+
659
+ /* Loader */
660
+ --ms-loader-padding: calc(1.6 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
661
+ --ms-loader-gap: calc(0.8 * var(--ms-rem));
662
+
663
+ /* Loading Text */
664
+ --ms-loading-text-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
665
+ --ms-loading-text-color: var(--ms-text-color-3);
666
+
667
+ /* ==========================================================================
668
+ BADGES DISPLAY
669
+ ========================================================================== */
670
+ --ms-badges-gap: calc(0.8 * var(--ms-rem));
671
+ --ms-badges-margin-bottom: calc(0.8 * var(--ms-rem));
672
+ --ms-badges-margin-top: calc(0.8 * var(--ms-rem));
673
+ --ms-badges-margin-left: calc(0.4 * var(--ms-rem));
674
+ --ms-badges-margin-right: calc(0.4 * var(--ms-rem));
675
+
676
+ /* Vertical alignment for inline (left/right) badge positioning */
677
+ /* Options: center (default), flex-start (top), flex-end (bottom) */
678
+ --ms-inline-align: center;
679
+
680
+ /* Individual Badge (--ms-badge-bg / --ms-badge-bg-hover / --ms-badge-bg-active live in the SEMANTIC VARIABLES block above) */
681
+ --ms-badge-gap: calc(0.8 * var(--ms-rem));
682
+ --ms-badge-height: calc(2.7 * var(--ms-rem));
683
+ --ms-badge-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
684
+ --ms-badge-font-weight: var(--base-font-weight-semibold, 600);
685
+ --ms-badge-border-radius: var(--ms-border-radius-sm);
686
+ --ms-order-first: -1;
687
+
688
+ /* ==========================================================================
689
+ BADGE TEXT & REMOVE BUTTON
690
+ ========================================================================== */
691
+ /* Badge Text */
692
+ --ms-badge-text-padding: 0 calc(0.8 * var(--ms-rem));
693
+ --ms-badge-text-bg: var(--ms-accent-color-light);
694
+ --ms-badge-text-color: var(--ms-accent-color);
695
+ --ms-badge-text-border: none;
696
+
697
+ /* Badge Remove Button */
698
+ --ms-badge-remove-width: calc(2.7 * var(--ms-rem));
699
+ --ms-badge-remove-bg: var(--ms-accent-color);
700
+ --ms-badge-remove-color: var(--ms-text-color-on-accent);
701
+ --ms-badge-remove-border: none;
702
+ --ms-badge-remove-font-size: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
703
+ --ms-badge-remove-bg-hover: var(--ms-accent-color-hover);
704
+ --ms-badge-remove-box-shadow-focus: 0 0 0 2px color-mix(in srgb, var(--ms-accent-color) 50%, transparent);
705
+ /* Matches the input-clear / count-clear ✕ glyphs (also 1.4×rem) so all three read at the
706
+ same size; the old 1.0×rem was fine for the default stroke `x` but rendered a filled
707
+ custom --base-icon-remove glyph (square-with-x) too small inside the mask box. */
708
+ --ms-badge-remove-icon-size: calc(1.4 * var(--ms-rem));
709
+ /* SVG X glyph (Lucide `x`) — rendered via mask so it inherits --ms-badge-remove-color via
710
+ currentColor. Drives the badge remove (×) and the fullscreen/popover close (✕). Follows the
711
+ shared --base-icon contract: prefers --base-icon-remove, then --base-icon-close, so a theme
712
+ re-skinning its close/remove glyph re-skins these too; the inline Lucide `x` is the standalone
713
+ fallback (no base layer loaded). Override --ms-icon-remove to diverge from the base contract. */
714
+ --ms-icon-remove: var(--base-icon-remove, var(--base-icon-close, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M18 6 6 18'/><path d='m6 6 12 12'/></svg>")));
715
+ /* SVG "clear search" glyph (Lucide `search-x`: a magnifier with an x) used by the
716
+ fullscreen search field's clear button. Deliberately NOT the bare X of
717
+ --ms-icon-remove so it doesn't read as a second close button beside the overlay
718
+ ✕. Rendered via mask, so it inherits its color via currentColor; override with any
719
+ mask-friendly SVG url(). */
720
+ --ms-icon-search-clear: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m13.5 8.5-5 5'/><path d='m8.5 8.5 5 5'/><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>");
721
+ /* Mode-toggle glyphs for the fullscreen search-mode switch. The button shows the
722
+ CURRENT mode: a plain magnifier (Lucide `search`) for navigate, a funnel (Lucide
723
+ `filter`) for filter. Rendered via mask (inherit color via currentColor); override
724
+ with any mask-friendly SVG url(). */
725
+ --ms-icon-search: var(--base-icon-search, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>"));
726
+ --ms-icon-filter: var(--base-icon-filter, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polygon points='22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3'/></svg>"));
727
+ /* Checkbox glyphs — the checkmark (checked) and dash (indeterminate/tri-state),
728
+ rendered as masks so they inherit --ms-checkbox-checkmark-color and follow the
729
+ shared --base-icon-* contract. Override either to diverge from the base. */
730
+ --ms-icon-check: var(--base-icon-check, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M20 6 9 17l-5-5'/></svg>"));
731
+ --ms-icon-indeterminate: var(--base-icon-indeterminate, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M5 12h14'/></svg>"));
732
+ /* mask-size for the checkmark/dash glyph inside the checkbox box. Defaults to the
733
+ shared --base-icon-check-size (the SAME knob pure-admin's .pa-checkbox reads), so a
734
+ theme rescales the mark once for both; override --ms-icon-check-size to diverge just
735
+ this component. 68% assumes a Lucide-style glyph that fills its viewBox edge-to-edge. */
736
+ --ms-icon-check-size: var(--base-icon-check-size, 68%);
737
+ /* "Add new" glyph (empty-state create prompt) — a plus, rendered as a mask so it
738
+ inherits the row's currentColor. Follows the shared --base-icon-* contract:
739
+ prefers --base-icon-plus, then --base-icon-add, then an inline "+" fallback. */
740
+ --ms-icon-add-new: var(--base-icon-plus, var(--base-icon-add, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M5 12h14'/><path d='M12 5v14'/></svg>")));
741
+
742
+ /* Badge Counter Indicator (layout-only properties, colors come from semantic section) */
743
+ --ms-badge-counter-bg: transparent;
744
+ --ms-badge-counter-border: 1px solid var(--ms-badge-counter-border-color);
745
+ --ms-badge-counter-border-radius: var(--ms-border-radius-sm);
746
+
747
+ /* ==========================================================================
748
+ "+X MORE" BADGE
749
+ ========================================================================== */
750
+ --ms-more-badge-bg: var(--ms-accent-color-light);
751
+ --ms-more-badge-hover-bg: var(--ms-badge-bg-hover);
752
+ --ms-more-badge-active-bg: var(--ms-accent-color-light-hover);
753
+
754
+ /* ==========================================================================
755
+ COUNT DISPLAY MODE
756
+ ========================================================================== */
757
+ --ms-count-display-margin-bottom: calc(0.8 * var(--ms-rem));
758
+ --ms-count-display-margin-top: calc(0.8 * var(--ms-rem));
759
+ --ms-count-display-margin-left: calc(0.8 * var(--ms-rem));
760
+ --ms-count-display-margin-right: calc(0.8 * var(--ms-rem));
761
+
762
+ /* Count Badge Wrapper */
763
+ --ms-counter-wrapper-bg: transparent;
764
+ --ms-counter-wrapper-border: var(--ms-border);
765
+ --ms-counter-wrapper-border-radius: var(--ms-border-radius-sm);
766
+ --ms-counter-wrapper-padding: calc(0.4 * var(--ms-rem)) calc(0.8 * var(--ms-rem));
767
+ --ms-counter-wrapper-gap: calc(0.4 * var(--ms-rem));
768
+ --ms-counter-wrapper-bg-hover: var(--ms-primary-bg);
769
+ --ms-counter-wrapper-border-color-hover: var(--ms-accent-color);
770
+
771
+ /* ==========================================================================
772
+ COUNT TEXT & CLEAR BUTTON
773
+ ========================================================================== */
774
+ /* Count Text */
775
+ --ms-count-text-bg: transparent;
776
+ --ms-count-text-border: none;
777
+ --ms-count-text-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
778
+ --ms-count-text-color: var(--ms-text-color-1);
779
+
780
+ /* Count Clear Button */
781
+ --ms-count-clear-size: calc(1.6 * var(--ms-rem));
782
+ --ms-count-clear-bg: transparent;
783
+ --ms-count-clear-color: var(--ms-text-color-3);
784
+ --ms-count-clear-font-size: calc(var(--base-font-size-lg, 1.8) * var(--ms-rem));
785
+ --ms-count-clear-border-radius: var(--ms-border-radius-sm);
786
+ /* Hover fills with SOLID accent and flips the glyph to text-on-accent — mirrors
787
+ .ms__badge-remove. The old "accent-tint bg + accent glyph" was same-hue: the ✕
788
+ melted into its own hover background (invisible on near-white accents like
789
+ minimal-dark, low-contrast blue-on-blue everywhere else). */
790
+ --ms-count-clear-bg-hover: var(--ms-accent-color);
791
+ --ms-count-clear-color-hover: var(--ms-text-color-on-accent);
792
+ --ms-count-clear-icon-size: calc(1.4 * var(--ms-rem));
793
+ /* Field-clear ✕ (input clear + count clear). Its own knob in the --base-icon contract:
794
+ prefers --base-icon-clear so a theme can diverge field-clear from close/remove, then falls
795
+ through to --ms-icon-remove (which itself resolves --base-icon-remove → --base-icon-close →
796
+ inline ✕). Same glyph as remove by default; override --base-icon-clear alone to split them. */
797
+ --ms-icon-clear: var(--base-icon-clear, var(--ms-icon-remove));
798
+
799
+ /* ==========================================================================
800
+ TOOLTIPS
801
+ ========================================================================== */
802
+ --ms-tooltip-color: var(--ms-tooltip-text-color);
803
+ --ms-tooltip-padding: calc(0.8 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
804
+ --ms-tooltip-border-radius: var(--ms-border-radius-lg);
805
+ --ms-tooltip-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
806
+ --ms-tooltip-max-width: calc(32 * var(--ms-rem));
807
+ --ms-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
808
+ --ms-tooltip-z-index: 10000;
809
+
810
+ /* Option (dropdown row) tooltip — per-feature hooks default to the shared tooltip surface,
811
+ so option tooltips look identical until you override one of these independently. */
812
+ --ms-option-tooltip-bg: var(--ms-tooltip-bg);
813
+ --ms-option-tooltip-text-color: var(--ms-tooltip-text-color);
814
+ --ms-option-tooltip-padding: var(--ms-tooltip-padding);
815
+ --ms-option-tooltip-border-radius: var(--ms-tooltip-border-radius);
816
+ --ms-option-tooltip-font-size: var(--ms-tooltip-font-size);
817
+ --ms-option-tooltip-max-width: var(--ms-tooltip-max-width);
818
+ --ms-option-tooltip-shadow: var(--ms-tooltip-shadow);
819
+ --ms-option-tooltip-z-index: var(--ms-tooltip-z-index);
820
+
821
+ /* ==========================================================================
822
+ TRANSIENT MESSAGE / TOAST (showMessage)
823
+ Surfaced on top of the component so a veto reason (or any consumer feedback)
824
+ is visible even in the fullscreen overlay, where page UI is covered. Sizing is
825
+ --ms-rem-based (a fullscreen override rescales it below at :host); per-variant
826
+ colours default to sensible tones and are theme-overridable via --base-*.
827
+ ========================================================================== */
828
+ --ms-message-bg: var(--ms-message-info-bg);
829
+ --ms-message-color: var(--ms-message-info-color);
830
+ --ms-message-border: 1px solid transparent;
831
+ --ms-message-border-radius: var(--ms-border-radius-lg);
832
+ --ms-message-padding: calc(1.0 * var(--ms-rem)) calc(1.4 * var(--ms-rem));
833
+ --ms-message-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
834
+ --ms-message-font-weight: var(--base-font-weight-medium, 500);
835
+ --ms-message-max-width: calc(40 * var(--ms-rem));
836
+ --ms-message-shadow: 0 4px 16px rgb(0 0 0 / 0.18);
837
+ /* Gap from the bottom edge of the viewport in the fullscreen overlay. */
838
+ --ms-message-fullscreen-offset: calc(2.4 * var(--ms-fullscreen-rem));
839
+ --ms-message-z-index: var(--ms-z-index-fullscreen-tooltip);
840
+ /* Variants (bg + text). Info reuses the tooltip surface; the rest are status tones. */
841
+ --ms-message-info-bg: var(--ms-tooltip-bg);
842
+ --ms-message-info-color: var(--ms-tooltip-text-color);
843
+ --ms-message-warning-bg: var(--base-warning-bg, #f59e0b);
844
+ --ms-message-warning-color: var(--base-warning-color, #1a1a1a);
845
+ --ms-message-error-bg: var(--base-danger-bg, #ef4444);
846
+ --ms-message-error-color: var(--base-danger-color, #ffffff);
847
+ --ms-message-success-bg: var(--base-success-bg, #10b981);
848
+ --ms-message-success-color: var(--base-success-color, #ffffff);
849
+
850
+ /* ==========================================================================
851
+ SELECTED POPOVER
852
+ ========================================================================== */
853
+ --ms-z-index-popover: 10000;
854
+ /* Selected-items ("badges") popover width — tracks the live field width by default (same
855
+ as the dropdown, so the two panels line up under the control). Override at app/theme
856
+ level or per-instance via the selected-popover-width attribute — e.g. a fixed
857
+ calc(32 * var(--ms-rem)) for a constant width independent of the field. */
858
+ --ms-selected-popover-width: var(--ms-input-current-width);
859
+ --ms-selected-popover-max-height: calc(32 * var(--ms-rem));
860
+ --ms-selected-popover-border: 1px solid var(--ms-selected-popover-border-color);
861
+ --ms-selected-popover-border-radius: var(--ms-border-radius-lg);
862
+ --ms-selected-popover-box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
863
+
864
+ /* Popover Header */
865
+ --ms-selected-popover-header-padding: calc(0.8 * var(--ms-rem)) calc(1.2 * var(--ms-rem));
866
+ --ms-selected-popover-header-bg: color-mix(in srgb, var(--ms-accent-color) 10%, transparent);
867
+ --ms-selected-popover-header-border-bottom: 1px solid var(--ms-selected-popover-header-border-color);
868
+ --ms-selected-popover-header-font-size: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
869
+ --ms-selected-popover-header-font-weight: var(--base-font-weight-semibold, 600);
870
+ --ms-selected-popover-header-color: var(--ms-text-color-1);
871
+
872
+ /* ==========================================================================
873
+ POPOVER CLOSE BUTTON
874
+ ========================================================================== */
875
+ --ms-popover-close-size: calc(2.4 * var(--ms-rem));
876
+ --ms-selected-popover-close-bg: transparent;
877
+ --ms-selected-popover-close-color: var(--ms-text-color-3);
878
+ --ms-selected-popover-close-font-size: calc(var(--base-font-size-xl, 2) * var(--ms-rem));
879
+ --ms-selected-popover-close-border-radius: var(--ms-border-radius-sm);
880
+ /* Solid accent fill + on-accent glyph (see .ms__count-clear note) — avoids the
881
+ same-hue "accent glyph on accent-tint" melt on hover. */
882
+ --ms-selected-popover-close-bg-hover: var(--ms-accent-color);
883
+ --ms-selected-popover-close-color-hover: var(--ms-text-color-on-accent);
884
+ --ms-selected-popover-close-icon-size: calc(1.4 * var(--ms-rem));
885
+
886
+ /* ==========================================================================
887
+ POPOVER BODY
888
+ ========================================================================== */
889
+ --ms-selected-popover-body-gap: calc(0.4 * var(--ms-rem));
890
+ --ms-selected-popover-body-padding: calc(0.8 * var(--ms-rem));
891
+ --ms-selected-popover-body-max-height: calc(28.8 * var(--ms-rem));
892
+
893
+ /* ==========================================================================
894
+ TYPOGRAPHY SCALE
895
+ ========================================================================== */
896
+ /* Font Sizes (unitless multipliers × --ms-rem) */
897
+ --ms-font-size-2xs: calc(var(--base-font-size-2xs, 1) * var(--ms-rem));
898
+ --ms-font-size-xs: calc(var(--base-font-size-xs, 1.2) * var(--ms-rem));
899
+ --ms-font-size-sm: calc(var(--base-font-size-sm, 1.4) * var(--ms-rem));
900
+ --ms-font-size-base: calc(var(--base-font-size-base, 1.6) * var(--ms-rem));
901
+ --ms-font-size-lg: calc(var(--base-font-size-lg, 1.8) * var(--ms-rem));
902
+
903
+ /* Font Weights */
904
+ --ms-font-weight-normal: var(--base-font-weight-normal, 400);
905
+ --ms-font-weight-medium: var(--base-font-weight-medium, 500);
906
+ --ms-font-weight-semibold: var(--base-font-weight-semibold, 600);
907
+
908
+ /* Line Heights */
909
+ --ms-line-height-none: 1;
910
+ --ms-line-height-tight: var(--base-line-height-tight, 1.25);
911
+ --ms-line-height-normal: var(--base-line-height-normal, 1.5);
912
+ --ms-line-height-relaxed: var(--base-line-height-relaxed, 1.75);
913
+
914
+ /* ==========================================================================
915
+ BORDER RADIUS SCALE
916
+ ========================================================================== */
917
+ --ms-border-radius-sm: calc(var(--base-border-radius-sm, 0.4) * var(--ms-rem));
918
+ --ms-border-radius-md: calc(var(--base-border-radius-md, 0.6) * var(--ms-rem));
919
+ --ms-border-radius-lg: calc(var(--base-border-radius-lg, 0.8) * var(--ms-rem));
920
+ --ms-border-radius: var(--ms-border-radius-md);
921
+
922
+ /* ==========================================================================
923
+ SPACING & SIZING
924
+ ========================================================================== */
925
+ --ms-spacing-xs: calc(0.4 * var(--ms-rem));
926
+ --ms-spacing-sm: calc(0.8 * var(--ms-rem));
927
+ --ms-spacing-md: calc(1.2 * var(--ms-rem));
928
+ --ms-spacing-lg: calc(1.6 * var(--ms-rem));
929
+
930
+ /* ==========================================================================
931
+ TRANSITIONS & EFFECTS
932
+ ========================================================================== */
933
+ /* Durations stay local: the --ms scale (150/200ms) doesn't line up with --base-duration-*
934
+ (fast 100ms / normal 150ms / medium 250ms), so wiring would silently change timings. */
935
+ --ms-transition-fast: 150ms;
936
+ --ms-transition-normal: 200ms;
937
+ /* Easing is an exact match for --base-ease-standard, so it flows from the shared token. */
938
+ --ms-easing-snappy: var(--base-ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
939
+
940
+ /* ==========================================================================
941
+ OPACITY VALUES
942
+ ========================================================================== */
943
+ --ms-placeholder-opacity: 0.6;
944
+ --ms-disabled-input-opacity: 0.6;
945
+
946
+ /* ==========================================================================
947
+ SCROLLBAR
948
+ ========================================================================== */
949
+ --ms-scrollbar-width: 8px;
950
+ --ms-scrollbar-track-bg: transparent;
951
+ --ms-scrollbar-thumb-bg: var(--ms-border-color);
952
+ --ms-scrollbar-thumb-bg-hover: var(--ms-text-color-3);
953
+ --ms-scrollbar-thumb-border-radius: 4px;
954
+
955
+ /* ==========================================================================
956
+ DEBUG PANEL (dev-only)
957
+ ========================================================================== */
958
+ --ms-debug-bg: var(--base-elevated-bg, light-dark(#f9fafb, #2b2b2b));
959
+ --ms-debug-border-color: var(--ms-border-color);
960
+ --ms-debug-text-color: var(--ms-text-color-1);
961
+ --ms-debug-border-radius: var(--ms-border-radius-md);
962
+ --ms-debug-summary-color: var(--ms-accent-color);
963
+ --ms-debug-summary-bg-hover: var(--ms-primary-bg);
964
+ --ms-debug-summary-outline-color: var(--ms-accent-color);
965
+ --ms-debug-summary-border-radius: var(--ms-border-radius-sm);
966
+ --ms-debug-stats-bg: var(--base-main-bg, light-dark(#ffffff, #1a1a1a));
967
+ --ms-debug-stats-border-radius: var(--ms-border-radius-sm);
968
+ --ms-debug-bullet-color: var(--ms-accent-color);
969
+ }