@webority/theme 0.95.0 → 0.98.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/theme",
3
- "version": "0.95.0",
3
+ "version": "0.98.0",
4
4
  "description": "Webority shared design system — Bootstrap 5.3 SCSS overrides, --wui-* tokens, and shared component CSS. The single source of brand chrome for React portals and Razor sites.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "publishConfig": {
@@ -29,17 +29,14 @@
29
29
  "./scss/*": "./scss/_*.scss",
30
30
  "./css": "./dist/webority-theme.css",
31
31
  "./css/flags": "./dist/webority-flags.css",
32
- "./css/brand-signal": "./dist/webority-brand-signal.css",
33
32
  "./css/runtime-brand": "./dist/webority-runtime-brand.css",
34
33
  "./purge-safelist.json": "./dist/purge-safelist.json",
35
34
  "./token-meanings.json": "./token-meanings.json",
36
35
  "./postcss/forced-states": "./dist/postcss/forced-states.mjs",
36
+ "./runtime": "./dist/runtime.mjs",
37
37
  "./logos/*": "./logos/*",
38
38
  "./package.json": "./package.json"
39
39
  },
40
- "bin": {
41
- "webority-theme-export": "./dist/webority-theme-export.mjs"
42
- },
43
40
  "sass": "index.scss",
44
41
  "style": "dist/webority-theme.css",
45
42
  "dependencies": {
@@ -56,6 +53,6 @@
56
53
  "vite": "^8.0.12"
57
54
  },
58
55
  "scripts": {
59
- "build": "sass index.scss dist/webority-theme.css --load-path=node_modules --style=compressed --no-source-map --quiet-deps --silence-deprecation=if-function && sass scss/_flags.scss dist/webority-flags.css --style=compressed --no-source-map --quiet && sass scss/_brand-signal.scss dist/webority-brand-signal.css --style=compressed --no-source-map --quiet && sass scss/_runtime-brand.scss dist/webority-runtime-brand.css --style=compressed --no-source-map --quiet && node ../../scripts/force-state-selectors.mjs dist/webority-theme.css dist/webority-brand-signal.css && node ../../scripts/gen-purge-safelist.mjs && node ../../scripts/sync-rcl-assets.mjs theme && vite build --config vite.cli.config.js && node scripts/exportCanvasTheme.mjs"
56
+ "build": "sass index.scss dist/webority-theme.css --load-path=node_modules --style=compressed --no-source-map --quiet-deps --silence-deprecation=if-function && sass scss/_flags.scss dist/webority-flags.css --style=compressed --no-source-map --quiet && sass scss/_runtime-brand.scss dist/webority-runtime-brand.css --style=compressed --no-source-map --quiet && node ../../scripts/force-state-selectors.mjs dist/webority-theme.css && node ../../scripts/gen-purge-safelist.mjs && node ../../scripts/sync-rcl-assets.mjs theme && vite build --config vite.cli.config.js && node scripts/exportCanvasTheme.mjs"
60
57
  }
61
58
  }
@@ -601,8 +601,6 @@
601
601
  // The thin thumb matches the shared rail (--wui-scrollbar*), like .wui-scroll.
602
602
  max-height: calc(100vh - 5rem);
603
603
  overflow-y: auto;
604
- scrollbar-width: thin;
605
- scrollbar-color: var(--wui-scrollbar) transparent;
606
604
  }
607
605
  .dropdown-menu::-webkit-scrollbar {
608
606
  width: 8px;
@@ -620,6 +618,13 @@
620
618
  background-color: var(--wui-scrollbar-hover);
621
619
  background-clip: padding-box;
622
620
  }
621
+ // Chrome 121+ ignores the WebKit scrollbar rules once a standard scrollbar property is set, and draws arrow buttons; the standard properties are for browsers without the WebKit rules.
622
+ @supports not selector(::-webkit-scrollbar) {
623
+ .dropdown-menu {
624
+ scrollbar-width: thin;
625
+ scrollbar-color: var(--wui-scrollbar) transparent;
626
+ }
627
+ }
623
628
 
624
629
  .dropdown-item {
625
630
  display: flex;
@@ -1040,8 +1045,6 @@ button.wui-input-leading:focus-visible {
1040
1045
  html,
1041
1046
  body {
1042
1047
  scrollbar-gutter: stable;
1043
- scrollbar-width: thin;
1044
- scrollbar-color: var(--wui-scrollbar) transparent;
1045
1048
  }
1046
1049
  html::-webkit-scrollbar,
1047
1050
  body::-webkit-scrollbar {
@@ -1077,14 +1080,21 @@ body::-webkit-scrollbar-corner {
1077
1080
  background: transparent;
1078
1081
  }
1079
1082
 
1080
- html.is-scrolling,
1081
- html.is-scrolling body {
1082
- scrollbar-color: var(--wui-scrollbar-hover) transparent;
1083
- }
1084
1083
  html.is-scrolling::-webkit-scrollbar-thumb,
1085
1084
  html.is-scrolling body::-webkit-scrollbar-thumb {
1086
1085
  background-color: var(--wui-scrollbar-hover);
1087
1086
  }
1087
+ @supports not selector(::-webkit-scrollbar) {
1088
+ html,
1089
+ body {
1090
+ scrollbar-width: thin;
1091
+ scrollbar-color: var(--wui-scrollbar) transparent;
1092
+ }
1093
+ html.is-scrolling,
1094
+ html.is-scrolling body {
1095
+ scrollbar-color: var(--wui-scrollbar-hover) transparent;
1096
+ }
1097
+ }
1088
1098
 
1089
1099
  // Hide a scrollbar (marquee / horizontal carousels).
1090
1100
  .scrollbar-hide {
@@ -1,5 +1,5 @@
1
- // Runtime brand: an opt-in layer that lets a product's exported token file (webority-theme-export,
2
- // format webority-theme-tokens/1) restyle the precompiled theme without recompiling it.
1
+ // Runtime brand: an opt-in layer that lets a product's token file (webority-theme-tokens/2, written by
2
+ // `webority brand`) restyle the precompiled theme without recompiling it.
3
3
  //
4
4
  // Loaded AFTER webority-theme.css and BEFORE the token file's values. It holds no colour of its own.
5
5
  // Bootstrap compiles $primary into a few component rules as literals; this layer re-points each of
package/scss/_tokens.scss CHANGED
@@ -35,13 +35,12 @@
35
35
  --wui-text-1: #252F4A;
36
36
  /// meaning: Secondary text for descriptions, sub-labels and muted copy.
37
37
  --wui-text-2: #4B5675;
38
- // Tertiary text — hints, captions, labels, timestamps, placeholders. Was #78829D,
39
- // which measured 3.5:1 on white and 3.1:1 on a tinted panel: below WCAG AA (4.5:1)
40
- // everywhere it was used. A tier meant for readable-but-secondary copy has to BE
41
- // readable, so it darkens to 4.55:1 on every neutral surface. It stays clearly
42
- // lighter than --wui-text-2; --wui-text-4/5 remain for genuinely decorative use.
38
+ // Tertiary text, for hints, captions, labels, timestamps and placeholders. It measures 4.97:1 on
39
+ // the library page background and 4.76:1 on a lightly tinted brand page (#eef1f7), so it stays
40
+ // above the 4.5:1 AA floor on every neutral surface. It stays clearly lighter than --wui-text-2;
41
+ // --wui-text-4/5 remain for genuinely decorative use.
43
42
  /// meaning: Tertiary text for hints, captions, labels, timestamps and placeholders.
44
- --wui-text-3: #687088;
43
+ --wui-text-3: #626A82;
45
44
  /// meaning: Decorative faint ink, not for text a person must read.
46
45
  --wui-text-4: #99A1B7;
47
46
  /// meaning: Faintest ink, for decorative marks.
@@ -184,7 +184,7 @@ $link-color: $wui-primary-ink !default;
184
184
  // $body-bg left at Bootstrap's $white — do not restate pure defaults here.
185
185
  $body-color: #252F4A; // text-1 from locked palette
186
186
  $body-secondary-color: #4B5675;
187
- $body-tertiary-color: #687088; // AA on white (matches --wui-text-3); #78829D was only 3.5:1
187
+ $body-tertiary-color: #626A82; // matches --wui-text-3, AA on every neutral surface
188
188
  $body-secondary-bg: #F9FBFC;
189
189
  $body-tertiary-bg: #F5F6FA;
190
190
 
@@ -1138,7 +1138,7 @@ button.wui-step-tile-body:hover .step-label {
1138
1138
  .form-section-body {
1139
1139
  display: flex;
1140
1140
  flex-direction: column;
1141
- gap: 16px;
1141
+ gap: var(--wui-space-lg);
1142
1142
  }
1143
1143
 
1144
1144
  // layout="side": the title and description take a column beside the fields. Below lg the
@@ -396,10 +396,17 @@
396
396
  }
397
397
 
398
398
  // ── Fitted: tabs share the width equally (no scroll). ──
399
+ // Every tab takes an equal share; a label longer than its share ends in an ellipsis.
399
400
  .app-tabs-fitted .app-tab {
400
401
  flex: 1 1 0;
402
+ min-width: 0;
401
403
  justify-content: center;
402
404
  }
405
+ .app-tabs-fitted .wui-tab-label {
406
+ min-width: 0;
407
+ overflow: hidden;
408
+ text-overflow: ellipsis;
409
+ }
403
410
  .app-tabs-wrap > .app-tabs-fitted {
404
411
  flex: 1 1 auto;
405
412
  }
@@ -15,18 +15,12 @@
15
15
  // Do NOT put layout on backdropClassName — that targets a sibling, not
16
16
  // .modal.
17
17
  .modal-backdrop.wui-modal-dim {
18
- // Frost the page behind the dialog — the blur is the star, so the dim is kept SOFT (a heavy
19
- // scrim would flatten the blur into a muddy grey). A moderate dim over a STRONG blur reads as
20
- // clean frosted glass; the modal is still clearly the one live surface. The dialog sits in
21
- // `.modal` (a higher z-index sibling), so it is never blurred.
22
- //
23
- // Full strength is load-bearing: Bootstrap composites the whole backdrop element at
24
- // `--bs-backdrop-opacity` (0.5 by default), which HALVES both the blur and the dim into a
25
- // weak, patchy wash — the bug this fixes. Pin the opacity to 1 and carry the dim entirely in
26
- // `background`, so the frost renders at its true strength. (The fade-in still animates 0 → 1.)
18
+ // Opacity is pinned to 1 because Bootstrap's 0.5 would halve the dim. The strong scrim guarantees
19
+ // separation in every browser, including over embedded pages Chrome cannot blur; the blur on top
20
+ // is decoration.
27
21
  --bs-backdrop-opacity: 1;
28
22
  opacity: 1;
29
- background: color-mix(in srgb, var(--color-scrim) 85%, transparent);
23
+ background: var(--color-scrim-strong);
30
24
  z-index: var(--wui-z-modal-backdrop);
31
25
  // A little saturation boost is what makes the frost read as glass rather than fog — the
32
26
  // colours behind bloom softly through the blur instead of greying out.
@@ -225,6 +219,14 @@
225
219
  .wui-modal-body .field > .field-error {
226
220
  align-self: stretch;
227
221
  }
222
+
223
+ // Stacked fields in a dialog keep the distance AppFormSection puts between its fields (.form-section-body
224
+ // in _flow.scss). Only fields in normal flow: a child of the body, or of a form in the body. A field in a
225
+ // grid or flex layout takes that layout's gap.
226
+ .wui-modal-body > .field + .field,
227
+ .wui-modal-body > form > .field + .field {
228
+ margin-top: var(--wui-space-lg);
229
+ }
228
230
  .wui-form-section-head {
229
231
  margin-bottom: 16px;
230
232
  }
@@ -32,6 +32,12 @@
32
32
  background: transparent;
33
33
  color: inherit;
34
34
  }
35
+ // The default tooltip sits on the plain surface colour, so its chip takes the plain chip look.
36
+ .tooltip.wui-tooltip:not(.tone-dark):not(.tone-primary):not(.tone-success):not(.tone-danger):not(.tone-warning) .wui-kbd {
37
+ border-color: var(--color-border);
38
+ background: var(--color-bg-muted);
39
+ color: var(--color-text);
40
+ }
35
41
  .btn > .wui-kbd {
36
42
  margin-left: 8px;
37
43
  }
@@ -275,10 +275,8 @@
275
275
 
276
276
  // Disabled — deliberately NOT opacity, and deliberately after the tones.
277
277
  //
278
- // `opacity: .55` fades the whole chip, which scales the LABEL's contrast down with it:
279
- // #687088 on #F5F6FA at .55 alpha resolves to 2.08:1, less than half the 4.5:1 AA floor,
280
- // and axe reports it as a serious violation on both surfaces. Explicit muted tokens read
281
- // as the same state and stay legible at 4.56:1.
278
+ // `opacity: .55` fades the whole chip, label included, so a faded label can fall under the
279
+ // 4.5:1 AA floor. Explicit muted tokens read as the same state and keep the label legible.
282
280
  //
283
281
  // It sits after the tone block on purpose. `.chip.is-disabled` and `.chip.primary` have
284
282
  // equal specificity, so source order decides — declared before them, a disabled primary
@@ -1 +0,0 @@
1
- @font-face{font-family:"Webority Serif";font-style:normal;font-weight:600;font-display:swap;src:url("../fonts/serif/WeboritySerif-DemiBold.woff2") format("woff2")}:root{--wui-signal-violet: #4A0FBF;--wui-signal-violet-hover: #3D0CA0;--wui-signal-tint: #F1EBFF;--wui-signal-ink: #16093A;--wui-signal-heading: #4C1D95;--wui-signal-pink: #B517C8;--wui-signal-dark-fill: #5A22D6;--wui-signal-dark-fill-hover: #6B35E6;--bs-font-sans-serif: "Webority Sans", system-ui, -apple-system, "Segoe UI", sans-serif;--bs-body-font-family: var(--bs-font-sans-serif);--wui-font-display: "Webority Serif", Georgia, "Times New Roman", serif;--wui-primary: #4A0FBF;--wui-primary-hover: #3D0CA0;--wui-primary-pressed: #340A88;--wui-primary-50: #8B66E6;--wui-primary-30: #B9A2F2;--wui-primary-20: #D9CBFA;--wui-primary-15: #E6DCFD;--wui-primary-10: #F1EBFF;--wui-primary-5: #F8F5FF;--wui-primary-text: #FFFFFF;--wui-primary-ink: var(--wui-primary, #4A0FBF);--wui-accent-dark: #340A88;--wui-surface-soft: #F1EBFF;--wui-surface-violet: #E6DCFD;--wui-surface-violet-soft: #F8F5FF;--wui-hero-gradient: radial-gradient(ellipse 120% 80% at 50% 30%, #8B66E6 0%, #4A0FBF 35%, #3D0CA0 75%, #16093A 100%);--wui-cta-gradient: radial-gradient(ellipse 120% 100% at 50% 50%, #2B1150 0%, #16093A 60%, #0E0626 100%);--wui-text-heading: #16093A;--wui-text-1: #2B2B2B;--wui-text-2: #5A5A5A;--wui-text-3: #6A6A6A;--wui-text-4: #9A9A9A;--wui-text-5: #CFC9DE;--wui-ink: #16093A;--wui-bg-page: #F8F6FD;--wui-bg-light: #FFFFFF;--wui-bg-elevated: #FBFAFE;--wui-bg-muted: #F3EFFB;--wui-field-bg: #FBFAFE;--wui-border-light: #E8E4F2;--wui-border-soft: #F3F0FA;--wui-progress-track: #E8E4F2;--wui-neutral-border-dark: #E8E4F2;--wui-neutral-bg-dark: #F3EFFB;--wui-shadow-overlay: 0 8px 28px -6px rgba(22, 9, 58, 0.16);--wui-shadow-overlay-lg: 0 24px 60px -16px rgba(22, 9, 58, 0.30);--wui-dark-bg-page: #000000;--wui-dark-bg-elevated: #0F0F0F;--wui-dark-bg-surface: #161616;--wui-dark-bg-muted: #1E1E1E;--wui-dark-border: #2A2A2A;--wui-dark-border-strong: #333333;--wui-dark-progress-track: #333333;--wui-dark-text: #EDEDED;--wui-dark-text-muted: #C0C0C0;--wui-dark-text-subtle: #A0A0A0;--wui-dark-primary: #A98BFF;--wui-dark-primary-hover: #BFA6FF;--bs-primary: #4A0FBF;--bs-primary-rgb: 74, 15, 191;--bs-link-color: var(--wui-primary-ink, #4A0FBF);--bs-link-color-rgb: var(--wui-primary-ink-rgb, 74, 15, 191);--bs-link-hover-color: var(--wui-primary-hover, #3D0CA0);--bs-link-hover-color-rgb: var(--wui-primary-hover-rgb, 61, 12, 160);--bs-focus-ring-color: rgba(74, 15, 191, 0.3)}.btn-primary{--bs-btn-color: var(--wui-primary-text, #fff);--bs-btn-bg: var(--wui-primary, #4A0FBF);--bs-btn-border-color: var(--wui-primary, #4A0FBF);--bs-btn-hover-color: var(--wui-primary-text, #fff);--bs-btn-hover-bg: var(--wui-primary-hover, #3D0CA0);--bs-btn-hover-border-color: var(--wui-primary-hover, #3D0CA0);--bs-btn-focus-shadow-rgb: var(--bs-primary-rgb, 74, 15, 191);--bs-btn-active-color: var(--wui-primary-text, #fff);--bs-btn-active-bg: var(--wui-primary-pressed, #340A88);--bs-btn-active-border-color: var(--wui-primary-pressed, #340A88);--bs-btn-disabled-color: var(--wui-primary-text, #fff);--bs-btn-disabled-bg: var(--wui-primary, #4A0FBF);--bs-btn-disabled-border-color: var(--wui-primary, #4A0FBF)}.btn-outline-primary{--bs-btn-color: var(--color-primary-ink);--bs-btn-border-color: var(--color-primary);--bs-btn-hover-color: var(--wui-primary-text, #fff);--bs-btn-hover-bg: var(--wui-primary, #4A0FBF);--bs-btn-hover-border-color: var(--wui-primary, #4A0FBF);--bs-btn-active-color: var(--wui-primary-text, #fff);--bs-btn-active-bg: var(--wui-primary-pressed, #340A88);--bs-btn-active-border-color: var(--wui-primary-pressed, #340A88);--bs-btn-focus-shadow-rgb: var(--bs-primary-rgb, 74, 15, 191)}.form-check-input:checked{background-color:var(--color-primary);border-color:var(--color-primary)}.page-title,.result-title{font-family:var(--wui-font-display);font-weight:600;font-style:normal;letter-spacing:-0.01em;color:var(--color-text)}.page-header-sm .page-title,.page-header.page-header-bar .page-title{font-family:inherit}:root[data-theme=dark],:root[data-bs-theme=dark]{--wui-signal-heading: #C4AEFF;--color-primary-soft: color-mix(in srgb, #FFFFFF 8%, transparent);--color-primary: var(--wui-signal-dark-fill, #5A22D6);--color-primary-hover: var(--wui-signal-dark-fill-hover, #6B35E6);--color-primary-text: var(--wui-dark-primary-text, #FFFFFF);--color-primary-hover-text: var(--wui-dark-primary-text, #FFFFFF);--bs-body-bg-rgb: 0, 0, 0;--bs-body-color-rgb: 237, 237, 237;--bs-emphasis-color-rgb: 237, 237, 237;--bs-secondary-color-rgb: 192, 192, 192;--bs-tertiary-color-rgb: 160, 160, 160;--bs-secondary-bg-rgb: 22, 22, 22;--bs-tertiary-bg-rgb: 30, 30, 30;--bs-border-color-rgb: 42, 42, 42;--bs-link-color: var(--wui-dark-primary, #A98BFF);--bs-link-color-rgb: var(--wui-dark-primary-rgb, 169, 139, 255);--bs-link-hover-color: var(--wui-dark-primary-hover, #BFA6FF);--bs-link-hover-color-rgb: var(--wui-dark-primary-hover-rgb, 191, 166, 255);--bs-focus-ring-color: rgba(169, 139, 255, 0.4)}:root[data-theme=dark] .btn-primary,:root[data-bs-theme=dark] .btn-primary{--bs-btn-bg: var(--wui-signal-dark-fill, #5A22D6);--bs-btn-border-color: var(--wui-signal-dark-fill, #5A22D6);--bs-btn-hover-bg: var(--wui-signal-dark-fill-hover, #6B35E6);--bs-btn-hover-border-color: var(--wui-signal-dark-fill-hover, #6B35E6);--bs-btn-active-bg: var(--wui-primary, #4A0FBF);--bs-btn-active-border-color: var(--wui-primary, #4A0FBF);--bs-btn-disabled-bg: var(--wui-signal-dark-fill, #5A22D6);--bs-btn-disabled-border-color: var(--wui-signal-dark-fill, #5A22D6)}:root[data-theme=dark] .btn-outline-primary,:root[data-bs-theme=dark] .btn-outline-primary{--bs-btn-hover-bg: var(--wui-signal-dark-fill, #5A22D6);--bs-btn-hover-border-color: var(--wui-signal-dark-fill, #5A22D6)}:root[data-theme=dark] .form-check-input:checked,:root[data-bs-theme=dark] .form-check-input:checked{background-color:var(--wui-signal-dark-fill, #5A22D6);border-color:var(--wui-signal-dark-fill, #5A22D6)}:where(:root[data-theme=dark],:root[data-bs-theme=dark]) .progress-bar:not([class*=wui-progress-]){color:var(--wui-dark-primary-text, #FFFFFF)}:root[data-theme=dark] :where(.stepper:not(.wizard-stepper)),:root[data-bs-theme=dark] :where(.stepper:not(.wizard-stepper)){--wui-step-accent-fg: var(--wui-signal-ink, #16093A)}:where(:root[data-theme=dark],:root[data-bs-theme=dark]) .struct-card.checked,:where(:root[data-theme=dark],:root[data-bs-theme=dark]) .tpg-arrow:is(:hover,.wui-force-hover):not(:disabled),:where(:root[data-theme=dark],:root[data-bs-theme=dark]) .tpg-page:is(:hover,.wui-force-hover):not(.is-active),:where(:root[data-theme=dark],:root[data-bs-theme=dark]) .u-action:is(:hover,.wui-force-hover):not(:disabled),:where(:root[data-theme=dark],:root[data-bs-theme=dark]) .tbl-empty-icon,:where(:root[data-theme=dark],:root[data-bs-theme=dark]) .u-avatar,:where(:root[data-theme=dark],:root[data-bs-theme=dark]) .wui-file-viewer-audio-art{background:var(--color-primary-soft)}:where(:root[data-theme=dark],:root[data-bs-theme=dark]) .wui-calendar-view-btn[aria-pressed=true],:where(:root[data-theme=dark],:root[data-bs-theme=dark]) .compare-table td.is-highlight{background:color-mix(in srgb, #FFFFFF 8%, var(--color-surface))}:where(:root[data-theme=dark],:root[data-bs-theme=dark]) .table-ledger tbody tr.is-selected:is(:hover,.wui-force-hover){--bs-table-bg-state: color-mix(in srgb, #FFFFFF 12%, transparent)}:where(:root[data-theme=dark],:root[data-bs-theme=dark]) .table-ledger tbody tr.is-selected>:first-child{box-shadow:inset 3px 0 0 0 var(--color-primary),inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}@media(prefers-color-scheme: dark){:root[data-theme=auto]{--wui-signal-heading: #C4AEFF;--color-primary-soft: color-mix(in srgb, #FFFFFF 8%, transparent);--color-primary: var(--wui-signal-dark-fill, #5A22D6);--color-primary-hover: var(--wui-signal-dark-fill-hover, #6B35E6);--color-primary-text: var(--wui-dark-primary-text, #FFFFFF);--color-primary-hover-text: var(--wui-dark-primary-text, #FFFFFF);--bs-body-bg-rgb: 0, 0, 0;--bs-body-color-rgb: 237, 237, 237;--bs-emphasis-color-rgb: 237, 237, 237;--bs-secondary-color-rgb: 192, 192, 192;--bs-tertiary-color-rgb: 160, 160, 160;--bs-secondary-bg-rgb: 22, 22, 22;--bs-tertiary-bg-rgb: 30, 30, 30;--bs-border-color-rgb: 42, 42, 42;--bs-link-color: var(--wui-dark-primary, #A98BFF);--bs-link-color-rgb: var(--wui-dark-primary-rgb, 169, 139, 255);--bs-link-hover-color: var(--wui-dark-primary-hover, #BFA6FF);--bs-link-hover-color-rgb: var(--wui-dark-primary-hover-rgb, 191, 166, 255);--bs-focus-ring-color: rgba(169, 139, 255, 0.4)}:root[data-theme=auto] .btn-primary{--bs-btn-bg: var(--wui-signal-dark-fill, #5A22D6);--bs-btn-border-color: var(--wui-signal-dark-fill, #5A22D6);--bs-btn-hover-bg: var(--wui-signal-dark-fill-hover, #6B35E6);--bs-btn-hover-border-color: var(--wui-signal-dark-fill-hover, #6B35E6);--bs-btn-active-bg: var(--wui-primary, #4A0FBF);--bs-btn-active-border-color: var(--wui-primary, #4A0FBF);--bs-btn-disabled-bg: var(--wui-signal-dark-fill, #5A22D6);--bs-btn-disabled-border-color: var(--wui-signal-dark-fill, #5A22D6)}:root[data-theme=auto] .btn-outline-primary{--bs-btn-hover-bg: var(--wui-signal-dark-fill, #5A22D6);--bs-btn-hover-border-color: var(--wui-signal-dark-fill, #5A22D6)}:root[data-theme=auto] .form-check-input:checked{background-color:var(--wui-signal-dark-fill, #5A22D6);border-color:var(--wui-signal-dark-fill, #5A22D6)}:where(:root[data-theme=auto]) .progress-bar:not([class*=wui-progress-]){color:var(--wui-dark-primary-text, #FFFFFF)}:root[data-theme=auto] :where(.stepper:not(.wizard-stepper)){--wui-step-accent-fg: var(--wui-signal-ink, #16093A)}:where(:root[data-theme=auto]) .struct-card.checked,:where(:root[data-theme=auto]) .tpg-arrow:is(:hover,.wui-force-hover):not(:disabled),:where(:root[data-theme=auto]) .tpg-page:is(:hover,.wui-force-hover):not(.is-active),:where(:root[data-theme=auto]) .u-action:is(:hover,.wui-force-hover):not(:disabled),:where(:root[data-theme=auto]) .tbl-empty-icon,:where(:root[data-theme=auto]) .u-avatar,:where(:root[data-theme=auto]) .wui-file-viewer-audio-art{background:var(--color-primary-soft)}:where(:root[data-theme=auto]) .wui-calendar-view-btn[aria-pressed=true],:where(:root[data-theme=auto]) .compare-table td.is-highlight{background:color-mix(in srgb, #FFFFFF 8%, var(--color-surface))}:where(:root[data-theme=auto]) .table-ledger tbody tr.is-selected:is(:hover,.wui-force-hover){--bs-table-bg-state: color-mix(in srgb, #FFFFFF 12%, transparent)}:where(:root[data-theme=auto]) .table-ledger tbody tr.is-selected>:first-child{box-shadow:inset 3px 0 0 0 var(--color-primary),inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}}
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{readFileSync as e,writeFileSync as t}from"node:fs";var n=`webority-theme-tokens/1`,r=[`--wui-primary`,`--bs-primary`,`--bs-primary-rgb`,`--bs-link-color-rgb`,`--bs-body-font-family`];function i(e){console.error(`webority-theme-export: ${e}`),console.error(`usage: webority-theme-export <compiled.css>... --product <name> [--out <tokens.json>] [--widths 1440,390]`),process.exit(2)}function a(e){let t=[],n,r,a=[];for(let o=0;o<e.length;o++)e[o]===`--product`?n=e[++o]:e[o]===`--out`?r=e[++o]:e[o]===`--widths`?a=(e[++o]??``).split(`,`).map(e=>e.trim()):e[o].startsWith(`--`)?i(`unknown option ${e[o]}`):t.push(e[o]);return t.length===0&&i(`no compiled CSS file given`),(!n||!/^[a-z0-9-]+$/.test(n))&&i(`--product must be the product's lowercase name`),a.some(e=>!/^[1-9]\d*$/.test(e))&&i(`--widths takes whole pixel widths, such as 1440,390`),a.length>0&&!r&&i(`--widths needs --out, the file name each width's file is named after`),{files:t,product:n,out:r,widths:a.map(Number)}}var o=16;function s(e,t){let n=e.trim(),r=/^(clamp|calc|min|max)\((.*)\)$/.exec(n);if(r){let e=l(r[2],`,`).map(e=>s(e,t));return e.some(e=>e===null)?null:r[1]===`calc`?e.length===1?e[0]:null:r[1]===`clamp`?e.length===3?Math.min(Math.max(e[1],e[0]),e[2]):null:r[1]===`min`?Math.min(...e):Math.max(...e)}let i=n.split(/\s+/),a=0,c=1;for(let e=0;e<i.length;e++){if(e%2==1){if(i[e]!==`+`&&i[e]!==`-`)return null;c=i[e]===`+`?1:-1;continue}let n=/^(-?\d*\.?\d+)(px|rem|vw)?$/.exec(i[e]);if(!n||!n[2]&&Number(n[1])!==0)return null;let r=Number(n[1]),s=n[2]===`rem`?r*o:n[2]===`vw`?r*t/100:r;a+=c*s}return i.length%2==1?a:null}function c(e,t){return Object.fromEntries(Object.entries(e).map(([e,n])=>{let r=s(n,t);return[e,r===null?n:`${Math.round(r*100)/100}px`]}))}function l(e,t){let n=[],r=0,i=null,a=0;for(let o=0;o<e.length;o++){let s=e[o];i?s===`\\`?o++:s===i&&(i=null):s===`"`||s===`'`?i=s:s===`(`||s===`[`?r++:s===`)`||s===`]`?r--:s===t&&r===0&&(n.push(e.slice(a,o)),a=o+1)}return n.push(e.slice(a)),n}var u=10,d=/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i,f=/^rgba?\(([\s\S]*)\)$/i,p=/^color-mix\(([\s\S]*)\)$/i,m=/^var\(([\s\S]*)\)$/i;function h(e,t,n=0){if(n>u)return null;let r=e.trim(),i=m.exec(r);if(i){let e=l(i[1],`,`),r=e[0].trim();if(!/^--[a-z0-9-]+$/i.test(r))return null;let a=t(r);if(a!==void 0)return h(a,t,n+1);let o=e.slice(1).join(`,`).trim();return o?h(o,t,n+1):null}let a=d.exec(r);if(a){let e=a[1];e.length<=4&&(e=[...e].map(e=>e+e).join(``)),e.length===6&&(e+=`ff`);let t=t=>Number.parseInt(e.slice(t,t+2),16);return[t(0),t(2),t(4),t(6)/255]}let o=f.exec(r);if(o)return g(o[1]);let s=p.exec(r);if(s)return y(s[1],t,n);let c=r.toLowerCase();return c===`white`?[255,255,255,1]:c===`black`?[0,0,0,1]:c===`transparent`?[0,0,0,0]:null}function g(e){let t=e.trim(),n,r=l(t,`/`);if(r.length>2)return null;r.length===2&&(t=r[0].trim(),n=r[1].trim());let i=l(t,`,`).flatMap(e=>e.trim().split(/\s+/)).filter(Boolean);if(i.length!==3&&i.length!==4)return null;let a=i.slice(0,3).map(e=>/^-?\d*\.?\d+$/.test(e)?Math.min(255,Math.max(0,Number(e))):null);if(a.some(e=>e===null))return null;if(i.length===4){if(n!==void 0)return null;n=i[3]}let o=n===void 0?1:_(n);return o===null?null:[...a,o]}function _(e){let t=e.trim(),n=/^(-?\d*\.?\d+)%$/.exec(t);return n?Math.min(1,Math.max(0,Number(n[1])/100)):/^-?\d*\.?\d+$/.test(t)?Math.min(1,Math.max(0,Number(t))):null}function v(e){let t=e.trim(),n=/\s+(-?\d*\.?\d+)%$/.exec(t);if(!n)return{colour:t};let r=t.slice(0,n.index).trim();return r?{colour:r,percent:Number(n[1])}:null}function y(e,t,n){let r=l(e,`,`);if(r.length!==3||!/^in\s+srgb$/i.test(r[0].trim()))return null;let i=v(r[1]),a=v(r[2]);if(!i||!a)return null;let o=h(i.colour,t,n+1),s=h(a.colour,t,n+1);if(!o||!s)return null;let c=i.percent,u=a.percent,d=1;if(c===void 0&&u===void 0)c=50,u=50;else if(u===void 0)u=100-c;else if(c===void 0)c=100-u;else if(c+u!==100){let e=c+u;e>0?(e<100&&(d=e/100),c=c*100/e,u=u*100/e):(c=0,u=0)}let f=c/100,p=u/100,m=o[3]*f+s[3]*p;return[...[0,1,2].map(e=>m===0?0:(o[e]*o[3]*f+s[e]*s[3]*p)/m),m*d]}function b(e){let t=e.slice(0,3).map(e=>Math.round(Math.min(255,Math.max(0,e))).toString(16).padStart(2,`0`)).join(``),n=Math.round(Math.min(1,Math.max(0,e[3]))*255);return`#${t}${n<255?n.toString(16).padStart(2,`0`):``}`}function x(e){let t=[],n=0,r=null,i=0,a=-1;for(let o=0;o<e.length;o++){let s=e[o];if(r)s===`\\`?o++:s===r&&(r=null);else if(s===`"`||s===`'`)r=s;else if(s===`{`)n===0&&(a=o),n++;else if(s===`}`){if(n--,n===0){let n=e.slice(i,a).trim();n.startsWith(`@`)||t.push({selectors:l(n,`,`).map(S),body:e.slice(a+1,o)}),i=o+1}}else s===`;`&&n===0&&(i=o+1)}return t}function S(e){return e.trim().replace(/\s+/g,` `).replace(/["']/g,``)}var C=new Set([`:root`,`[data-bs-theme=light]`,`:root[data-bs-theme=light]`,`:root[data-theme=light]`]),w=new Set([`:root[data-theme=dark]`,`:root[data-bs-theme=dark]`]),T=new Set([`[data-bs-theme=dark]`]);function E(e){let t=[];for(let n of l(e,`;`)){let e=n.indexOf(`:`);if(e<0)continue;let r=n.slice(0,e).trim();r.startsWith(`--`)&&t.push([r,n.slice(e+1).trim().replace(/\s*!important$/,``)])}return t}function D(e,t){let n=e;for(let e=0;e<8;e+=1){let e=/^var\(\s*(--[\w-]+)\s*\)$/.exec(n);if(!e)return n;if(n=t(e[1]),n===void 0)return null}return null}function O(e,t,n){for(let[r,i]of Object.entries(e)){if(!i.startsWith(`var(`)&&!i.startsWith(`color-mix(`))continue;let a=h(i,t,0);if(a){e[r]=b(a);continue}let o=i.startsWith(`var(`)?D(i,t):null;o!==null&&o!==i?e[r]=o:console.error(`webority-theme-export: ${r} in ${n} left as written: ${i}`)}}var{files:k,product:A,out:j,widths:M}=a(process.argv.slice(2)),N={},P={},F={};for(let t of k){let n=e(t,`utf8`).replace(/\/\*[\s\S]*?\*\//g,``);for(let e of x(n)){let t=t=>e.selectors.some(e=>t.has(e)),n=t(w)?P:t(T)?F:t(C)?N:null;if(n)for(let[t,r]of E(e.body))n[t]=r}}O(N,e=>N[e],`light`),O(P,e=>e in P?P[e]:N[e],`dark`),O(F,e=>e in F?F[e]:e in P?P[e]:N[e],`bootstrapDark`);var I=r.filter(e=>!(e in N));I.length>0&&(console.error(`webority-theme-export: ${k.join(`, `)} declares no ${I.join(`, `)} on :root.`),console.error(`Pass the compiled stylesheet that carries the full theme, not a page or component bundle.`),process.exit(1));var L=e=>Object.fromEntries(Object.entries(e).sort(([e],[t])=>e.localeCompare(t))),R=`${JSON.stringify({format:n,product:A,light:L(N),dark:L(P),bootstrapDark:L(F)},null,2)}\n`;if(M.length>0){let e=j.replace(/\.json$/i,``);for(let r of M){let i=`${e}-${r}.json`,a={light:c(N,r),dark:c(P,r),bootstrapDark:c(F,r)},o={format:n,product:A,width:r,light:L(a.light),dark:L(a.dark),bootstrapDark:L(a.bootstrapDark)};t(i,`${JSON.stringify(o,null,2)}\n`),process.stderr.write(`webority-theme-export: ${Object.keys(N).length} light values at ${r}px -> ${i}\n`)}}else j?(t(j,R),process.stderr.write(`webority-theme-export: ${Object.keys(N).length} light and ${Object.keys(P).length} dark and ${Object.keys(F).length} Bootstrap dark values -> ${j}\n`)):process.stdout.write(R);export{};
@@ -1,249 +0,0 @@
1
- // Signal: an opt-in brand layer, a violet-primary palette with ink headings and a serif display face.
2
- // Its dark mode is pure black with neutral grey surfaces; violet is kept for accents only.
3
- //
4
- // Loaded AFTER webority-theme.css; the default theme never contains these values. It re-points the
5
- // --wui-* tokens, then overrides the few Bootstrap values the theme compiles as literals (button
6
- // variables, link and focus-ring colours, dark-mode rgb triplets), because those are not tokens.
7
- //
8
- // Dark mode must match or beat the theme's own selectors, which are
9
- // :root[data-theme="dark"], :root[data-bs-theme="dark"] and, under @media (prefers-color-scheme: dark),
10
- // :root[data-theme="auto"] (see _wui-aliases.scss). A lone [data-theme=dark] loses to the second and
11
- // third, so the dark block below is emitted under all three.
12
-
13
- // The theme ships the Demi Bold file but declares no weight-600 face for the display family.
14
- @font-face {
15
- font-family: "Webority Serif";
16
- font-style: normal;
17
- font-weight: 600;
18
- font-display: swap;
19
- src: url("../fonts/serif/WeboritySerif-DemiBold.woff2") format("woff2");
20
- }
21
-
22
- :root {
23
- // Named brand constants; the dark fills below read --wui-signal-dark-fill and --wui-signal-dark-fill-hover.
24
- --wui-signal-violet: #4A0FBF;
25
- --wui-signal-violet-hover: #3D0CA0;
26
- --wui-signal-tint: #F1EBFF;
27
- --wui-signal-ink: #16093A;
28
- --wui-signal-heading: #4C1D95;
29
- // Reserved for unread counts (white text on it is 5.6:1); never a button or link colour.
30
- --wui-signal-pink: #B517C8;
31
- // Filled primary controls in dark mode: lighter than the light-mode fill so the edge shows on the ink page.
32
- --wui-signal-dark-fill: #5A22D6;
33
- --wui-signal-dark-fill-hover: #6B35E6;
34
-
35
- --bs-font-sans-serif: "Webority Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
36
- --bs-body-font-family: var(--bs-font-sans-serif);
37
- --wui-font-display: "Webority Serif", Georgia, "Times New Roman", serif;
38
-
39
- --wui-primary: #4A0FBF;
40
- --wui-primary-hover: #3D0CA0;
41
- --wui-primary-pressed: #340A88;
42
- --wui-primary-50: #8B66E6;
43
- --wui-primary-30: #B9A2F2;
44
- --wui-primary-20: #D9CBFA;
45
- --wui-primary-15: #E6DCFD;
46
- --wui-primary-10: #F1EBFF;
47
- --wui-primary-5: #F8F5FF;
48
- --wui-primary-text: #FFFFFF;
49
- // Violet clears 4.5:1 as text on every light surface and its tint, so it is its own ink.
50
- --wui-primary-ink: var(--wui-primary, #4A0FBF);
51
- --wui-accent-dark: #340A88;
52
- --wui-surface-soft: #F1EBFF;
53
- --wui-surface-violet: #E6DCFD;
54
- --wui-surface-violet-soft: #F8F5FF;
55
- --wui-hero-gradient: radial-gradient(ellipse 120% 80% at 50% 30%, #8B66E6 0%, #4A0FBF 35%, #3D0CA0 75%, #16093A 100%);
56
- --wui-cta-gradient: radial-gradient(ellipse 120% 100% at 50% 50%, #2B1150 0%, #16093A 60%, #0E0626 100%);
57
-
58
- --wui-text-heading: #16093A;
59
- --wui-text-1: #2B2B2B;
60
- --wui-text-2: #5A5A5A;
61
- // Muted text: #777777 measures 4.48:1 on white and less on the tints; #6A6A6A clears 4.5:1 on every tint, the violet one included.
62
- --wui-text-3: #6A6A6A;
63
- --wui-text-4: #9A9A9A;
64
- --wui-text-5: #CFC9DE;
65
- --wui-ink: #16093A;
66
-
67
- --wui-bg-page: #F8F6FD;
68
- --wui-bg-light: #FFFFFF;
69
- --wui-bg-elevated: #FBFAFE;
70
- --wui-bg-muted: #F3EFFB;
71
- --wui-field-bg: #FBFAFE;
72
- --wui-border-light: #E8E4F2;
73
- --wui-border-soft: #F3F0FA;
74
- --wui-progress-track: #E8E4F2;
75
- --wui-neutral-border-dark: #E8E4F2;
76
- --wui-neutral-bg-dark: #F3EFFB;
77
- --wui-shadow-overlay: 0 8px 28px -6px rgba(22, 9, 58, 0.16);
78
- --wui-shadow-overlay-lg: 0 24px 60px -16px rgba(22, 9, 58, 0.30);
79
-
80
- // Dark mode is pure black and neutral grey; violet appears only on accents (fills, links, focus, selection marks).
81
- --wui-dark-bg-page: #000000;
82
- --wui-dark-bg-elevated: #0F0F0F;
83
- --wui-dark-bg-surface: #161616;
84
- --wui-dark-bg-muted: #1E1E1E;
85
- --wui-dark-border: #2A2A2A;
86
- --wui-dark-border-strong: #333333;
87
- --wui-dark-progress-track: #333333;
88
- --wui-dark-text: #EDEDED;
89
- --wui-dark-text-muted: #C0C0C0;
90
- --wui-dark-text-subtle: #A0A0A0;
91
- --wui-dark-primary: #A98BFF;
92
- --wui-dark-primary-hover: #BFA6FF;
93
-
94
- // Values the theme compiles as literals rather than tokens.
95
- --bs-primary: #4A0FBF;
96
- --bs-primary-rgb: 74, 15, 191;
97
- // Each link value reads the token a product re-points; a triplet cannot be derived from a hex at
98
- // runtime, so it reads its own -rgb token and a product sets the pair together.
99
- --bs-link-color: var(--wui-primary-ink, #4A0FBF);
100
- --bs-link-color-rgb: var(--wui-primary-ink-rgb, 74, 15, 191);
101
- --bs-link-hover-color: var(--wui-primary-hover, #3D0CA0);
102
- --bs-link-hover-color-rgb: var(--wui-primary-hover-rgb, 61, 12, 160);
103
- --bs-focus-ring-color: rgba(74, 15, 191, 0.3);
104
- }
105
-
106
- // Bootstrap compiles its button variables to literal indigo; re-point them on the classes.
107
- .btn-primary {
108
- --bs-btn-color: var(--wui-primary-text, #fff);
109
- --bs-btn-bg: var(--wui-primary, #4A0FBF);
110
- --bs-btn-border-color: var(--wui-primary, #4A0FBF);
111
- --bs-btn-hover-color: var(--wui-primary-text, #fff);
112
- --bs-btn-hover-bg: var(--wui-primary-hover, #3D0CA0);
113
- --bs-btn-hover-border-color: var(--wui-primary-hover, #3D0CA0);
114
- --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb, 74, 15, 191);
115
- --bs-btn-active-color: var(--wui-primary-text, #fff);
116
- --bs-btn-active-bg: var(--wui-primary-pressed, #340A88);
117
- --bs-btn-active-border-color: var(--wui-primary-pressed, #340A88);
118
- --bs-btn-disabled-color: var(--wui-primary-text, #fff);
119
- --bs-btn-disabled-bg: var(--wui-primary, #4A0FBF);
120
- --bs-btn-disabled-border-color: var(--wui-primary, #4A0FBF);
121
- }
122
-
123
- .btn-outline-primary {
124
- --bs-btn-color: var(--color-primary-ink);
125
- --bs-btn-border-color: var(--color-primary);
126
- --bs-btn-hover-color: var(--wui-primary-text, #fff);
127
- --bs-btn-hover-bg: var(--wui-primary, #4A0FBF);
128
- --bs-btn-hover-border-color: var(--wui-primary, #4A0FBF);
129
- --bs-btn-active-color: var(--wui-primary-text, #fff);
130
- --bs-btn-active-bg: var(--wui-primary-pressed, #340A88);
131
- --bs-btn-active-border-color: var(--wui-primary-pressed, #340A88);
132
- --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb, 74, 15, 191);
133
- }
134
-
135
- .form-check-input:checked {
136
- background-color: var(--color-primary);
137
- border-color: var(--color-primary);
138
- }
139
-
140
- // Display type: Webority Serif Demi Bold only at 24px and above (page and result titles); every
141
- // smaller title stays in Webority Sans.
142
- .page-title,
143
- .result-title {
144
- font-family: var(--wui-font-display);
145
- font-weight: 600;
146
- font-style: normal;
147
- letter-spacing: -0.01em;
148
- color: var(--color-text);
149
- }
150
- // The compact page titles (size sm and the page header bar) are 20px, so they keep the sans face.
151
- .page-header-sm .page-title,
152
- .page-header.page-header-bar .page-title {
153
- font-family: inherit;
154
- }
155
-
156
- @mixin wui-signal-dark {
157
- --wui-signal-heading: #C4AEFF;
158
- // Selected, hover and highlight fills are a neutral lift; the violet stays on the text, border
159
- // or edge that marks the state. check-contrast.mjs mirrors the 8%; change them together.
160
- --color-primary-soft: color-mix(in srgb, #FFFFFF 8%, transparent);
161
- // The published primary pair is the one the primary button paints: deep violet with a white label.
162
- // The lilac --wui-dark-primary stays the ink for text, links and focus on the dark surfaces.
163
- --color-primary: var(--wui-signal-dark-fill, #5A22D6);
164
- --color-primary-hover: var(--wui-signal-dark-fill-hover, #6B35E6);
165
- --color-primary-text: var(--wui-dark-primary-text, #FFFFFF);
166
- --color-primary-hover-text: var(--wui-dark-primary-text, #FFFFFF);
167
- --bs-body-bg-rgb: 0, 0, 0;
168
- --bs-body-color-rgb: 237, 237, 237;
169
- --bs-emphasis-color-rgb: 237, 237, 237;
170
- --bs-secondary-color-rgb: 192, 192, 192;
171
- --bs-tertiary-color-rgb: 160, 160, 160;
172
- --bs-secondary-bg-rgb: 22, 22, 22;
173
- --bs-tertiary-bg-rgb: 30, 30, 30;
174
- --bs-border-color-rgb: 42, 42, 42;
175
- --bs-link-color: var(--wui-dark-primary, #A98BFF);
176
- --bs-link-color-rgb: var(--wui-dark-primary-rgb, 169, 139, 255);
177
- --bs-link-hover-color: var(--wui-dark-primary-hover, #BFA6FF);
178
- --bs-link-hover-color-rgb: var(--wui-dark-primary-hover-rgb, 191, 166, 255);
179
- --bs-focus-ring-color: rgba(169, 139, 255, 0.4);
180
-
181
- .btn-primary {
182
- --bs-btn-bg: var(--wui-signal-dark-fill, #5A22D6);
183
- --bs-btn-border-color: var(--wui-signal-dark-fill, #5A22D6);
184
- --bs-btn-hover-bg: var(--wui-signal-dark-fill-hover, #6B35E6);
185
- --bs-btn-hover-border-color: var(--wui-signal-dark-fill-hover, #6B35E6);
186
- --bs-btn-active-bg: var(--wui-primary, #4A0FBF);
187
- --bs-btn-active-border-color: var(--wui-primary, #4A0FBF);
188
- --bs-btn-disabled-bg: var(--wui-signal-dark-fill, #5A22D6);
189
- --bs-btn-disabled-border-color: var(--wui-signal-dark-fill, #5A22D6);
190
- }
191
-
192
- .btn-outline-primary {
193
- --bs-btn-hover-bg: var(--wui-signal-dark-fill, #5A22D6);
194
- --bs-btn-hover-border-color: var(--wui-signal-dark-fill, #5A22D6);
195
- }
196
-
197
- .form-check-input:checked {
198
- background-color: var(--wui-signal-dark-fill, #5A22D6);
199
- border-color: var(--wui-signal-dark-fill, #5A22D6);
200
- }
201
-
202
- // The untoned bar fills with the deep violet --bs-primary, where the dark-mode label ink fails. The tone
203
- // bars and the count badges sit on the light dark-mode fills and keep --color-progress-label.
204
- :where(&) .progress-bar:not([class*="wui-progress-"]) {
205
- color: var(--wui-dark-primary-text, #FFFFFF);
206
- }
207
-
208
- // The active step's number sits on the lilac ink fill (--wui-step-accent); white is 2.68:1 there.
209
- :where(.stepper:not(.wizard-stepper)) {
210
- --wui-step-accent-fg: var(--wui-signal-ink, #16093A);
211
- }
212
-
213
- // Components that mix their violet fill inline rather than through --color-primary-soft.
214
- // :where(&) keeps each rule at the component's own specificity, so a tone variant still wins.
215
- :where(&) .struct-card.checked,
216
- :where(&) .tpg-arrow:hover:not(:disabled),
217
- :where(&) .tpg-page:hover:not(.is-active),
218
- :where(&) .u-action:hover:not(:disabled),
219
- :where(&) .tbl-empty-icon,
220
- :where(&) .u-avatar,
221
- :where(&) .wui-file-viewer-audio-art {
222
- background: var(--color-primary-soft);
223
- }
224
- :where(&) .wui-calendar-view-btn[aria-pressed="true"],
225
- :where(&) .compare-table td.is-highlight {
226
- background: color-mix(in srgb, #FFFFFF 8%, var(--color-surface));
227
- }
228
- :where(&) .table-ledger tbody tr.is-selected:hover {
229
- --bs-table-bg-state: color-mix(in srgb, #FFFFFF 12%, transparent);
230
- }
231
- // A grey row alone reads as disabled; the violet edge says chosen. One step below the row status
232
- // bar's specificity, so a status row keeps its own colour bar.
233
- :where(&) .table-ledger tbody tr.is-selected > :first-child {
234
- box-shadow:
235
- inset 3px 0 0 0 var(--color-primary),
236
- inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)));
237
- }
238
- }
239
-
240
- :root[data-theme="dark"],
241
- :root[data-bs-theme="dark"] {
242
- @include wui-signal-dark;
243
- }
244
-
245
- :root[data-theme="auto"] {
246
- @media (prefers-color-scheme: dark) {
247
- @include wui-signal-dark;
248
- }
249
- }