@mastors/core 1.1.0 → 2.0.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.
Files changed (50) hide show
  1. package/README.md +12 -121
  2. package/dist/mastors-core.css +62 -1615
  3. package/dist/mastors-core.css.map +1 -1
  4. package/package.json +6 -8
  5. package/scss/abstracts/_maps.scss +9 -0
  6. package/scss/accessibility/_index.scss +0 -1
  7. package/scss/accessibility/_screen-reader.scss +1 -4
  8. package/scss/api/_index.scss +0 -1
  9. package/scss/base/_reset.scss +1 -1
  10. package/scss/config/_flags.scss +9 -9
  11. package/scss/functions/_color.scss +15 -32
  12. package/scss/functions/_em.scss +2 -2
  13. package/scss/functions/_index.scss +0 -6
  14. package/scss/functions/_math.scss +0 -19
  15. package/scss/functions/_string.scss +0 -35
  16. package/scss/generators/_class-generator.scss +42 -31
  17. package/scss/generators/_responsive-generator.scss +4 -0
  18. package/scss/helpers/_visually-hidden.scss +14 -27
  19. package/scss/mixins/_breakpoint.scss +3 -3
  20. package/scss/mixins/_transition.scss +1 -1
  21. package/scss/responsive/_engine.scss +5 -3
  22. package/scss/responsive/_fluid-type.scss +9 -8
  23. package/scss/semantic/_colors.scss +15 -15
  24. package/scss/semantic/_spacing.scss +5 -5
  25. package/scss/semantic/_typography.scss +5 -5
  26. package/scss/themes/_base-theme.scss +5 -0
  27. package/scss/themes/_dark.scss +7 -8
  28. package/scss/tokens/_color.scss +4 -8
  29. package/scss/tokens/_shadows.scss +9 -7
  30. package/scss/tokens/_sizing.scss +6 -3
  31. package/scss/tokens/_typography.scss +10 -9
  32. package/scss/utilities/_borders.scss +6 -4
  33. package/scss/utilities/_colors.scss +1 -1
  34. package/scss/utilities/_index.scss +0 -4
  35. package/scss/utilities/_sizing.scss +2 -2
  36. package/scss/variables/_global.scss +4 -4
  37. package/scss/variables/_grid.scss +3 -3
  38. package/scss/vendors/_index.scss +2 -0
  39. package/src/index.ts +11 -0
  40. package/src/tokens.ts +314 -0
  41. package/src/types.ts +52 -0
  42. package/postinstall.js +0 -41
  43. package/scripts/generate-tokens.js +0 -259
  44. package/scss/accessibility/_print.scss +0 -52
  45. package/scss/config/_index.scss +0 -12
  46. package/scss/functions/_vars.scss +0 -49
  47. package/scss/utilities/_animation.scss +0 -125
  48. package/scss/utilities/_interaction.scss +0 -156
  49. package/scss/utilities/_layout.scss +0 -162
  50. package/scss/utilities/_typography.scss +0 -163
package/README.md CHANGED
@@ -20,7 +20,6 @@
20
20
  - [Feature flags](#feature-flags)
21
21
  - [Dark mode strategy](#dark-mode-strategy)
22
22
  - [Class prefix](#class-prefix)
23
- - [Config via public API](#config-via-public-api)
24
23
  - [Design Tokens](#design-tokens)
25
24
  - [Color](#color)
26
25
  - [Spacing](#spacing)
@@ -31,7 +30,6 @@
31
30
  - [Opacity](#opacity)
32
31
  - [Transitions](#transitions)
33
32
  - [Functions](#functions)
34
- - [vars()](#vars)
35
33
  - [Mixins](#mixins)
36
34
  - [Breakpoints](#breakpoints)
37
35
  - [Theme](#theme)
@@ -61,7 +59,7 @@
61
59
  `@mastors/core` is the only required package in the Mastors ecosystem. It provides:
62
60
 
63
61
  - **Design tokens** — color, spacing, typography, radius, shadows, z-index, opacity, and transitions as SCSS maps
64
- - **Functions** — `rem()`, `em()`, `color()`, `spacing()`, `tint()`, `shade()`, `alpha()`, `contrast()`, `fluid()`, `map-deep-get()`, `map-collect()`, `str-replace()`, `vars()`
62
+ - **Functions** — `rem()`, `em()`, `color()`, `spacing()`, `tint()`, `shade()`, `alpha()`, `contrast()`, `fluid()`, `map-deep-get()`, `map-collect()`, `str-replace()`
65
63
  - **Mixins** — `bp()`, `dark-mode()`, `light-mode()`, `theme()`, `elevation()`, `transition()`, `container()`, `pseudo()`
66
64
  - **Generator engine** — `generate-utilities()`, `emit-custom-properties()`, and responsive-generator mixins used by all utility packages
67
65
  - **Reset** — modern CSS reset and document defaults
@@ -69,8 +67,7 @@
69
67
  - **Responsive engine** — breakpoint-aware utility variant generation (`sm:`, `md:`, `lg:`, `xl:`, `2xl:`)
70
68
  - **Container queries** — `.cq-inline`, `.cq-size`, `cq()` mixin for `@container` rules
71
69
  - **Fluid typography** — `fluid-type()` mixin and function using `clamp()`
72
- - **Utility classes** — display, position, overflow, spacing, sizing, colors, borders (full directional radius scale), shadows, opacity, cursor, z-index, transforms, typography, animation, interaction, layout (aspect-ratio, object-fit/position, blend modes)
73
- - **Accessibility** — focus ring, reduced-motion, screen-reader utilities, print layer
70
+ - **Utility classes** — display, position, overflow, spacing, sizing, colors, borders (full directional radius scale), shadows, opacity, cursor, z-index, transforms
74
71
  - **TypeScript types and runtime token mirror**
75
72
 
76
73
  All other `@mastors/*` packages consume `@mastors/core/api` for shared tokens, functions, and mixins.
@@ -101,7 +98,7 @@ Import the complete compiled stylesheet — reset, tokens, themes, utilities, he
101
98
 
102
99
  ### Public API (zero output)
103
100
 
104
- Import only the public API surface. No CSS is emitted — you get access to all tokens, functions, mixins, and config:
101
+ Import only the public API surface. No CSS is emitted — you get access to all tokens, functions, and mixins for use in your own components:
105
102
 
106
103
  ```scss
107
104
  @use "@mastors/core/api" as m;
@@ -110,8 +107,7 @@ Import only the public API surface. No CSS is emitted — you get access to all
110
107
  padding: m.spacing(6);
111
108
  background-color: m.color("neutral", 50);
112
109
  border-radius: m.radius("xl");
113
- box-shadow: m.vars(shadow-md);
114
- transition: box-shadow m.vars(duration-200) m.vars(ease-out);
110
+ box-shadow: m.shadow("md");
115
111
 
116
112
  @include m.bp("lg") {
117
113
  padding: m.spacing(10);
@@ -209,22 +205,6 @@ $mastors-config: ("prefix": "m-") !default;
209
205
  // .m-flex, .m-block, .m-grid-cols-3, ...
210
206
  ```
211
207
 
212
- ### Config via public API
213
-
214
- As of v1.2, both the `$mastors-config` map / `config()` accessor and all `$enable-*` flags are forwarded through the public API surface. Downstream consumers no longer need a direct partial import to read them:
215
-
216
- ```scss
217
- @use "@mastors/core/api" as m;
218
-
219
- // Read a config value
220
- $prefix: m.config("prefix");
221
-
222
- // Read feature flags
223
- @if m.$enable-responsive {
224
- // emit responsive variants
225
- }
226
- ```
227
-
228
208
  ---
229
209
 
230
210
  ## Design Tokens
@@ -378,49 +358,8 @@ m.easing("bounce") // cubic-bezier(0.34, 1.56, 0.64, 1)
378
358
  | `map-deep-get($map, $keys...)` | Deep nested map access | `map-deep-get($tokens, "primary", "600")` |
379
359
  | `map-collect($maps...)` | Shallow-merge multiple maps | `map-collect($a, $b)` |
380
360
  | `str-replace($str, $search)` | Replace substring | `str-replace("a-b", "-", "_")` |
381
- | `vars($token, $fallback?)` | CSS custom property reference | `vars(shadow-md)` -> `var(--mastors-shadow-md)` |
382
-
383
- (1) `contrast()` uses a simplified linear luminance approximation without sRGB gamma expansion. The threshold is set to `0.35` (not the WCAG `0.179`) to compensate for the missing gamma step — this gives correct results across the neutral scale. Suitable for UI decisions; implement full sRGB linearisation for strict WCAG 2.1 contrast-ratio auditing.
384
-
385
- ### vars()
386
-
387
- `vars()` lets you reference any emitted design token as a CSS custom property by name, without hard-coding the `--mastors-` prefix. If the token name ever changes or the prefix is reconfigured, only the function implementation needs to update — all call sites stay the same.
388
-
389
- ```scss
390
- @use "@mastors/core/api" as m;
391
-
392
- .button {
393
- // Basic token reference
394
- color: m.vars(accent);
395
- box-shadow: m.vars(shadow-sm);
396
-
397
- // With CSS fallback (passed through verbatim)
398
- background: m.vars(surface-raised, #f9fafb);
399
- transition: opacity m.vars(duration-150) m.vars(ease-out);
400
-
401
- &:hover {
402
- box-shadow: m.vars(shadow-md);
403
- transform: translateY(-1px);
404
- }
405
- }
406
-
407
- // Composes cleanly with other values in shorthand properties
408
- .chip {
409
- border: 1px solid m.vars(border);
410
- padding: m.rem(4px) m.rem(10px);
411
- }
412
- ```
413
361
 
414
- Token names follow the same `--mastors-{name}` convention used in `:root`. Common examples:
415
-
416
- | Call | Emits |
417
- |---|---|
418
- | `m.vars(accent)` | `var(--mastors-accent)` |
419
- | `m.vars(surface)` | `var(--mastors-surface)` |
420
- | `m.vars(shadow-lg)` | `var(--mastors-shadow-lg)` |
421
- | `m.vars(duration-200)` | `var(--mastors-duration-200)` |
422
- | `m.vars(ease-in-out)` | `var(--mastors-ease-in-out)` |
423
- | `m.vars(border, #e5e7eb)` | `var(--mastors-border, #e5e7eb)` |
362
+ (1) `contrast()` uses a simplified linear luminance approximation, not the full WCAG 2.1 gamma-expanded formula. Suitable for UI decisions, not for strict accessibility audits.
424
363
 
425
364
  ---
426
365
 
@@ -508,9 +447,7 @@ Mobile-first, min-width media queries using the named breakpoint map.
508
447
 
509
448
  ## Responsive Engine
510
449
 
511
- The engine in `responsive/_engine.scss` wraps utility maps in breakpoint media queries. Sub-packages can call `@include engine.run($utilities)` directly for standalone use.
512
-
513
- For the standard workflow, responsive variant generation is built into `generate-utilities()` — any utility entry that declares `responsive: true` automatically emits both base classes and breakpoint-prefixed variants in a single call. No separate invocation is required.
450
+ The engine in `responsive/_engine.scss` wraps utility maps in breakpoint media queries. Sub-packages call `@include engine.run($utilities)` in their responsive layer.
514
451
 
515
452
  Generated class pattern: `.{breakpoint}\:{class}`
516
453
 
@@ -526,7 +463,8 @@ Generated class pattern: `.{breakpoint}\:{class}`
526
463
  ```
527
464
 
528
465
  Utilities with responsive support at v1.0: `display`, `position`.
529
- Additional responsive utilities added in v1.2: `text-align`, `float`, `flex-direction` (via flexer), `grid-template-columns` (via gridder).
466
+
467
+ > Spacing, sizing, and color utilities use direct `@each` loops in v1.0 and do not generate responsive variants by default. Responsive variants for those groups are planned for a future minor release.
530
468
 
531
469
  ---
532
470
 
@@ -639,16 +577,6 @@ Use semantic custom properties directly in your CSS for automatic theme switchin
639
577
  }
640
578
  ```
641
579
 
642
- Or use `vars()` in SCSS for the same result without the prefix noise:
643
-
644
- ```scss
645
- .card {
646
- background-color: m.vars(surface);
647
- color: m.vars(text);
648
- border-color: m.vars(border);
649
- }
650
- ```
651
-
652
580
  Custom themes can be applied with any `data-theme` attribute:
653
581
 
654
582
  ```scss
@@ -703,12 +631,8 @@ When importing the full stylesheet, core emits these utility classes:
703
631
  | Pointer events | `.pointer-events-none` `.pointer-events-auto` |
704
632
  | Z-index | `.z-base` `.z-dropdown` `.z-modal` `.z-tooltip` etc. |
705
633
  | Transforms | `.translate-x-*` `.translate-y-*` `.rotate-*` `.scale-*` `.origin-*` `.transform-gpu` `.transform-none` |
706
- | Typography | `.text-{left\|center\|right\|justify\|start\|end}` (responsive) · `.text-{xs…9xl}` · `.font-{thin…black}` · `.font-{sans\|mono\|display}` · `.italic` `.not-italic` · `.leading-*` · `.tracking-*` · `.underline` `.overline` `.line-through` `.no-underline` · `.decoration-{solid\|dashed\|dotted\|double\|wavy}` · `.decoration-{1\|2\|4\|8}` · `.uppercase` `.lowercase` `.capitalize` `.normal-case` · `.text-ellipsis` `.text-clip` · `.whitespace-*` · `.break-normal` `.break-words` `.break-all` `.break-keep` · `.align-{baseline\|top\|middle\|bottom}` · `.list-none` `.list-disc` `.list-decimal` · `.antialiased` `.subpixel-antialiased` |
707
- | Animation | `.transition` `.transition-{colors\|opacity\|shadow\|transform\|none\|all}` · `.duration-*` · `.ease-*` · `.delay-*` · `.animate-{spin\|ping\|pulse\|bounce\|fade-in\|fade-out\|slide-up\|slide-down\|scale-in\|none}` · `.fill-{none\|forwards\|backwards\|both}` · `.animation-{running\|paused}` · `.animate-repeat-{0\|1\|infinite}` |
708
- | Interaction | `.select-{none\|text\|all\|auto}` · `.resize-{none\|x\|y}` `.resize` · `.scroll-{auto\|smooth}` · `.snap-{none\|x\|y\|both\|mandatory\|proximity}` · `.snap-{start\|end\|center}` · `.snap-stop-{always\|normal}` · `.scroll-m-*` `.scroll-p-*` · `.touch-{auto\|none\|pan-x\|pan-y\|manipulation}` · `hover:opacity-*` `hover:bg-accent` `hover:underline` `hover:shadow-lg` `hover:scale-{105\|110}` `hover:-translate-y-1` · `focus:ring` `focus:ring-2` `focus:ring-offset-2` `focus:ring-none` · `disabled:opacity-50` `disabled:cursor-not-allowed` `disabled:pointer-events-none` |
709
- | Layout | `.aspect-{auto\|square\|video\|4-3\|3-2\|21-9\|9-16\|golden}` · `.object-{contain\|cover\|fill\|none\|scale-down}` · `.object-{center\|top\|bottom\|left\|right\|…}` · `.float-{left\|right\|none\|start\|end}` (responsive) · `.clear-*` · `.isolate` `.isolation-auto` · `.mix-blend-*` · `.bg-blend-*` · `.box-decoration-{clone\|slice}` · `.appearance-{none\|auto}` · `.will-change-{auto\|scroll\|contents\|transform}` |
710
634
 
711
- Display and position utilities support responsive prefixes (`sm:`, `md:`, `lg:`, `xl:`, `2xl:`). Text-align and float also support responsive prefixes.
635
+ Display and position utilities support responsive prefixes (`sm:`, `md:`, `lg:`, `xl:`, `2xl:`).
712
636
 
713
637
  ---
714
638
 
@@ -744,16 +668,6 @@ Display and position utilities support responsive prefixes (`sm:`, `md:`, `lg:`,
744
668
  | `:focus-visible` | 2px primary-500 ring, 2px offset — keyboard only |
745
669
  | `:focus:not(:focus-visible)` | Removes ring for mouse/pointer users |
746
670
  | `prefers-reduced-motion: reduce` | Collapses all animation/transition durations to 0.01ms |
747
- | `.print\:hidden` | `display: none` inside `@media print` |
748
- | `.screen\:hidden` | `display: none` outside `@media print` (print-only element) |
749
- | `.print\:break-inside-avoid` | Prevents page breaks inside the element when printing |
750
- | `.print\:break-before` | Forces a page break before the element |
751
- | `.print\:break-after` | Forces a page break after the element |
752
- | `.print\:text-black` | Forces `color: #000` for print output |
753
- | `.print\:bg-white` | Forces `background: #fff` for print output |
754
- | `.print\:border-none` | Removes borders for print output |
755
- | `.print\:shadow-none` | Removes box-shadow for print output |
756
- | `a[href]::after` *(print)* | Appends `(url)` after links so destinations are visible on paper |
757
671
 
758
672
  ---
759
673
 
@@ -765,10 +679,6 @@ The three generator mixins are the engine behind all utility class output in the
765
679
 
766
680
  Generates utility classes from a configuration map. Used by `@mastors/flexer`, `@mastors/gridder`, and all core utility partials.
767
681
 
768
- The mixin runs in two passes:
769
- - **Pass 1** — emits base (unprefixed) classes for every entry.
770
- - **Pass 2** — for every entry with `responsive: true`, iterates all breakpoints (skipping `xs`/0px) and emits breakpoint-prefixed variants inside `@media` blocks. Respects the `$enable-responsive` flag and the global prefix/`!important` config.
771
-
772
682
  ```scss
773
683
  @use "@mastors/core/scss/generators/class-generator" as gen;
774
684
 
@@ -784,8 +694,6 @@ The mixin runs in two passes:
784
694
  ),
785
695
  ),
786
696
  ));
787
- // Emits: .text-left, .text-center, .text-right
788
- // And: .sm\:text-left, .md\:text-left, … for all breakpoints
789
697
  ```
790
698
 
791
699
  ### `emit-custom-properties($map, $prefix)`
@@ -870,17 +778,14 @@ These stubs are documented in each file's header comment.
870
778
  /* Full stylesheet — reset + tokens + themes + utilities */
871
779
  @use "@mastors/core/scss";
872
780
 
873
- /* Public API — zero CSS output, all tokens/mixins/functions/config */
781
+ /* Public API — zero CSS output, all tokens/mixins/functions */
874
782
  @use "@mastors/core/api" as m;
875
783
 
876
784
  /* Individual partials */
877
785
  @use "@mastors/core/scss/tokens/color" as ct;
878
786
  @use "@mastors/core/scss/mixins/breakpoint" as bp;
879
787
  @use "@mastors/core/scss/functions/rem" as r;
880
- @use "@mastors/core/scss/functions/vars"; /* vars() standalone */
881
788
  @use "@mastors/core/scss/responsive/fluid-type" as ft;
882
- @use "@mastors/core/scss/config/settings"; /* $mastors-config, config() */
883
- @use "@mastors/core/scss/config/flags"; /* $enable-* flags */
884
789
  ```
885
790
 
886
791
  ```ts
@@ -903,31 +808,17 @@ import type { MastorsConfig, Breakpoint, ThemeMode, Tokens } from '@mastors/core
903
808
 
904
809
  ## Changelog
905
810
 
906
- ### v1.2.0
907
-
908
- - **Added:** `vars($token, $fallback?)` function in `functions/_vars.scss` — wraps the `--mastors-` namespace so downstream consumers reference tokens as `var(--mastors-{name})` without hard-coding the prefix. Namespace stored in `$-namespace: "mastors" !default`. Forwarded through `functions/_index.scss` and exposed via `@use "@mastors/core/api"`.
909
- - **Added:** `config/_index.scss` shim — `@forward`s both `_settings.scss` and `_flags.scss`. `api/_index.scss` now includes `@forward "../config/index"`, exposing `config()` accessor and all `$enable-*` flags through the public API surface without a direct partial import.
910
- - **Added:** `utilities/_typography.scss` — full typography utility surface covering text-align (responsive), font-size (token-driven `@each`), font-weight (token-driven), font-family (token-driven), font-style (`.italic` / `.not-italic`), line-height / leading (token-driven), letter-spacing / tracking (token-driven), text-decoration (line + style + thickness), text-transform, text-overflow, white-space, word-break, text-indent, vertical-align, list-style, font-smoothing.
911
- - **Added:** `utilities/_animation.scss` — transition-property presets (`.transition`, `.transition-colors`, `.transition-opacity`, `.transition-shadow`, `.transition-transform`, `.transition-none`, `.transition-all`), token-driven `.duration-*` and `.delay-*`, token-driven `.ease-*`, named animation presets (`.animate-spin/ping/pulse/bounce/fade-in/fade-out/slide-up/slide-down/scale-in/none`), full `@keyframes` definitions prefixed `mastors-*`, animation fill-mode / play-state / iteration utilities.
912
- - **Added:** `utilities/_interaction.scss` — user-select, resize, scroll-behavior (`.scroll-auto` / `.scroll-smooth`), scroll-snap (type + align + stop + scroll-margin/padding), touch-action, and state-variant pseudo-class utilities: `hover:opacity-*`, `hover:bg-accent`, `hover:text-accent`, `hover:underline`, `hover:no-underline`, `hover:shadow-lg`, `hover:scale-105`, `hover:scale-110`, `hover:-translate-y-1`, `focus:ring`, `focus:ring-2`, `focus:ring-offset-2`, `focus:ring-none`, `disabled:opacity-50`, `disabled:cursor-not-allowed`, `disabled:pointer-events-none`.
913
- - **Added:** `utilities/_layout.scss` — aspect-ratio block (`.aspect-auto`, `.aspect-square`, `.aspect-video`, `.aspect-4-3`, `.aspect-3-2`, `.aspect-21-9`, `.aspect-9-16`, `.aspect-golden`; the `$-aspect-ratios` map is `!default`-overridable). Documented alongside object-fit and object-position which were already present.
914
- - **Added:** `accessibility/_print.scss` — `print:hidden`, `screen:hidden`, `print:break-inside-avoid`, `print:break-before`, `print:break-after`, `print:text-black`, `print:bg-white`, `print:border-none`, `print:shadow-none`, automatic `a[href]::after` link expansion, suppression for `#` and `javascript:` links.
915
-
916
811
  ### v1.0.0
917
812
 
918
813
  - Initial public release
919
814
  - Full token system: color, spacing, typography, radii, shadows, z-index, opacity, transitions, sizing
920
815
  - Complete functions layer: `rem`, `em`, `color`, `spacing`, `radius`, `shadow`, `z`, `opacity`, `duration`, `easing`, `tint`, `shade`, `alpha`, `contrast`, `fluid`, `map-deep-get`, `map-collect`, `str-replace`
921
816
  - Complete mixins layer: `bp`, `respond-to`, `breakpoint-up`, `breakpoint-down`, `dark-mode`, `light-mode`, `theme`, `elevation`, `transition`, `container`, `pseudo`
922
- - **Fixed:** `generate-utilities()` now runs a two-pass emit — Pass 1 outputs base classes, Pass 2 automatically emits breakpoint-prefixed responsive variants for all entries with `responsive: true`. Previously responsive variants were silently not emitted.
923
- - **Fixed:** `generators/_responsive-generator.scss` replaced the `@content`-based no-op stub with a thin wrapper that correctly delegates to `engine.run()` for backward compatibility.
924
- - **Fixed:** `contrast()` luminance threshold corrected from `0.179` (WCAG linearised) to `0.35` (calibrated for the simplified non-gamma-expanded approximation in use). Prevents wrong light/dark decisions on mid-grey backgrounds.
925
- - **Added:** `stylelint` linting with `stylelint-config-standard-scss` — `pnpm lint` now runs real SCSS style checks. `postcss-scss`, `stylelint`, and `stylelint-config-standard-scss` added to `devDependencies`; `.stylelintrc.json` added to `packages/core`.
926
- - Generator engine: `generate-utilities` (with integrated responsive Pass 2), `emit-custom-properties`, `emit-nested-custom-properties`
817
+ - Generator engine: `generate-utilities`, `emit-custom-properties`, `emit-nested-custom-properties`
927
818
  - Responsive engine with correct numeric breakpoint escaping (`2xl:` prefix)
928
819
  - Container queries: `.cq-inline`, `.cq-size`, `.cq-normal`, `[data-container]`, `cq()` mixin
929
820
  - Fluid typography: `fluid-type()` mixin + function + `fluid-scale()` preset
930
- - Full directional border-radius utility scale — all four sides x all token steps
821
+ - Full directional border-radius utility scale — all four sides x all token steps (fixed from partial `lg`-only coverage)
931
822
  - Light and dark themes via CSS custom property semantic contract (15 semantic props)
932
823
  - Modern CSS reset — no duplicate `box-sizing` declarations
933
824
  - Accessibility layer: `:focus-visible` ring, `prefers-reduced-motion` override, `.sr-only`, `.visually-hidden`