@aortl/admin-css 0.16.1 → 0.16.2

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 (45) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/admin.css +0 -4
  3. package/dist/admin.min.css +1 -1
  4. package/dist/admin.scoped.css +0 -4
  5. package/dist/admin.scoped.min.css +0 -1
  6. package/package.json +3 -2
  7. package/src/components/accordion.css +4 -13
  8. package/src/components/alert.css +6 -21
  9. package/src/components/app-shell.css +2 -4
  10. package/src/components/badge.css +1 -5
  11. package/src/components/breadcrumbs.css +2 -11
  12. package/src/components/button-group.css +7 -19
  13. package/src/components/button.css +7 -23
  14. package/src/components/card.css +10 -26
  15. package/src/components/chart.css +26 -83
  16. package/src/components/checkbox.css +3 -9
  17. package/src/components/code-block.css +2 -4
  18. package/src/components/container.css +3 -7
  19. package/src/components/dialog.css +11 -18
  20. package/src/components/field.css +3 -7
  21. package/src/components/footer.css +2 -3
  22. package/src/components/indicator.css +9 -28
  23. package/src/components/input-group.css +3 -6
  24. package/src/components/input.css +2 -5
  25. package/src/components/kbd.css +7 -13
  26. package/src/components/link.css +2 -8
  27. package/src/components/menu.css +9 -24
  28. package/src/components/navbar.css +3 -7
  29. package/src/components/pagination.css +1 -4
  30. package/src/components/progress.css +3 -7
  31. package/src/components/property-list.css +5 -14
  32. package/src/components/prose.css +6 -24
  33. package/src/components/radio.css +3 -7
  34. package/src/components/select.css +4 -11
  35. package/src/components/sidebar.css +2 -7
  36. package/src/components/spinner.css +1 -4
  37. package/src/components/stat-card.css +5 -16
  38. package/src/components/switch.css +3 -5
  39. package/src/components/table.css +15 -34
  40. package/src/components/tabs.css +14 -32
  41. package/src/components/textarea.css +3 -7
  42. package/src/components/tooltip.css +6 -16
  43. package/src/fonts.css +8 -28
  44. package/src/theme.css +32 -100
  45. package/src/utilities.css +11 -37
@@ -1,8 +1,6 @@
1
1
  @layer components {
2
- /* Page content region a centered, max-width column that also owns the
3
- vertical rhythm between stacked page sections. Drop it inside the bare
4
- `.app-shell-main` (which has no padding of its own). Width presets just
5
- set `--container-max`; override the var per-instance to deviate. */
2
+ /* Goes inside the bare `.app-shell-main` (no padding of its own); override
3
+ `--container-max` per-instance to deviate from the presets. */
6
4
  .container {
7
5
  @apply flex flex-col gap-6 w-full mx-auto px-6 py-6;
8
6
  max-width: var(--container-max, 90rem);
@@ -16,17 +14,15 @@
16
14
  --container-max: 115rem;
17
15
  }
18
16
 
19
- /* Full-bleed: edge-to-edge within `main`, padding retained. */
20
17
  .container-fluid {
21
18
  --container-max: none;
22
19
  }
23
20
 
24
- /* Denser vertical rhythm + tighter block padding for packed screens. */
25
21
  .container-compact {
26
22
  @apply gap-4 py-4;
27
23
  }
28
24
 
29
- /* Less horizontal padding on small viewports — reuses the shell breakpoint. */
25
+ /* Reuses the shell breakpoint. */
30
26
  @media (max-width: 48rem) {
31
27
  .container {
32
28
  @apply px-4;
@@ -9,9 +9,8 @@
9
9
  width: calc(100% - 2rem);
10
10
  max-width: 32rem;
11
11
  max-height: calc(100dvh - 2rem);
12
- /* Long titles/descriptions (filenames, IDs) break instead of pushing past
13
- the fixed max-width. Inherited by title + description; `.dialog-title`
14
- additionally needs `min-width: 0` below since it's a flex item. */
12
+ /* Long tokens (filenames, IDs) break instead of pushing past max-width;
13
+ inherited by title + description. */
15
14
  overflow-wrap: break-word;
16
15
  opacity: 1;
17
16
  transform: translateY(0) scale(1);
@@ -22,9 +21,8 @@
22
21
  transform 150ms ease-out;
23
22
  }
24
23
 
25
- /* `display: flex` only when open — without this gate, our flex rule would
26
- override the UA `dialog:not([open]) { display: none }` and the dialog
27
- would render in-flow before showModal() was ever called. */
24
+ /* Gate on [open]an unconditional flex would override the UA's
25
+ `dialog:not([open]) { display: none }` and render the dialog in-flow. */
28
26
  .dialog[open] {
29
27
  display: flex;
30
28
  }
@@ -37,7 +35,6 @@
37
35
  background 150ms ease-out;
38
36
  }
39
37
 
40
- /* Entry — animate from these values up to the open state. */
41
38
  @starting-style {
42
39
  .dialog[open] {
43
40
  opacity: 0;
@@ -64,8 +61,7 @@
64
61
 
65
62
  .dialog-title {
66
63
  @apply flex-1 flex items-center gap-2 text-lg font-semibold leading-tight m-0;
67
- /* `flex-1` flex item let it shrink so a long title wraps rather than
68
- blowing the header past the dialog's max-width. */
64
+ /* Let a long title shrink and wrap rather than widen the header. */
69
65
  min-width: 0;
70
66
  }
71
67
 
@@ -73,16 +69,14 @@
73
69
  @apply px-5 -mt-2 mb-3 text-sm text-text-muted;
74
70
  }
75
71
 
76
- /* `flex-1 min-h-0` lets the body fill the remaining height and shrink below
77
- its content (a flex item's default `min-height: auto` would refuse to), so
78
- tall content scrolls here while the header/footer stay pinned. */
72
+ /* min-h-0 beats the flex default `min-height: auto` so tall content scrolls
73
+ here while the header/footer stay pinned. */
79
74
  .dialog-body {
80
75
  @apply flex-1 min-h-0 px-5 py-3 overflow-y-auto flex flex-col gap-3;
81
76
  }
82
77
 
83
- /* When the body is wrapped in a `<form>` (the form-dialog pattern), the form
84
- becomes the dialog's sole flex child make it the flex column so the body's
85
- `flex-1 min-h-0` still resolves and scrolls. */
78
+ /* In the form-dialog pattern the form is the sole flex child; it must carry
79
+ the flex column so the body's `flex-1 min-h-0` still scrolls. */
86
80
  .dialog > form {
87
81
  @apply flex flex-col min-h-0 flex-1;
88
82
  }
@@ -92,9 +86,8 @@
92
86
  px-5 py-3
93
87
  border-t border-border
94
88
  bg-surface-muted;
95
- /* Inherits the dialog's bottom-corner radius so the muted background
96
- doesn't square off past the parent's rounded corners previously
97
- handled by `overflow: hidden` on `.dialog`, which clipped popups. */
89
+ /* Keep the muted background inside the parent's rounded corners don't
90
+ use `overflow: hidden` on `.dialog` for this; it clips popups. */
98
91
  border-bottom-left-radius: inherit;
99
92
  border-bottom-right-radius: inherit;
100
93
  }
@@ -1,14 +1,11 @@
1
1
  @layer components {
2
2
  .field {
3
3
  @apply flex flex-col gap-1.5;
4
- /* Label/description/error are often operator- or validation-supplied let
5
- long tokens break instead of overflowing a narrow form column. Inherited
6
- by all three. Mirrors `.alert`. */
4
+ /* Long operator-/validation-supplied tokens break instead of overflowing;
5
+ inherited by label, description, and error. */
7
6
  overflow-wrap: break-word;
8
7
  }
9
8
 
10
- /* Horizontal layout — pairs a control (typically a switch) with its label
11
- on one row. Use when the label belongs beside the control, not above it. */
12
9
  .field-row {
13
10
  @apply flex-row items-center gap-3;
14
11
  }
@@ -34,8 +31,7 @@
34
31
  @apply text-xs text-danger leading-relaxed;
35
32
  }
36
33
 
37
- /* When the field is in an invalid state, tint the contained control.
38
- Base UI applies data-invalid on the Field root once validation fails. */
34
+ /* Base UI sets data-invalid on the Field root when validation fails. */
39
35
  .field[data-invalid] .input,
40
36
  .field[data-invalid] .textarea,
41
37
  .field[data-invalid] .select,
@@ -1,7 +1,6 @@
1
1
  @layer components {
2
- /* 2px top stripe mirrors the navbar's bottom stripe both default to
3
- a neutral gray via `--color-system-accent` and brand-shift together
4
- when the consuming app overrides that variable at :root. */
2
+ /* The top stripe mirrors the navbar's bottom stripe; both brand-shift
3
+ together when the app overrides `--color-system-accent` at :root. */
5
4
  .footer {
6
5
  @apply flex flex-wrap items-center justify-between gap-3 px-4 py-3
7
6
  bg-surface-muted text-text-muted
@@ -1,23 +1,13 @@
1
1
  @layer components {
2
- /*
3
- * Wrapper for placing a small floating element (badge, count, status dot)
4
- * at a corner or edge of another element — notification badges on icon
5
- * buttons, status dots on avatars, "new" markers on tiles.
6
- *
7
- * Composition is driven by CSS custom properties so a horizontal modifier
8
- * (start/center/end) and a vertical modifier (top/middle/bottom) compose
9
- * naturally without needing a 3×3 grid of explicit selectors.
10
- */
2
+ /* Floats a small element (badge, dot) at a corner/edge of an anchor.
3
+ Placement is var-driven so a horizontal and a vertical modifier compose
4
+ without a 3×3 grid of selectors. */
11
5
  .indicator {
12
6
  @apply relative inline-flex w-max;
13
7
  }
14
8
 
15
- /*
16
- * Auto-offset for common rounded anchors so the indicator aligns with the
17
- * visual corner instead of the geometric box corner. Roughly half the
18
- * anchor's border-radius. Override per-instance by passing the `offset`
19
- * prop or setting `--indicator-offset` inline.
20
- */
9
+ /* Auto-offset (~half the anchor's border-radius) aligns with the visual
10
+ corner of rounded anchors; override `--indicator-offset` inline. */
21
11
  .indicator:has(> .btn),
22
12
  .indicator:has(> .input) {
23
13
  --indicator-offset: 2px;
@@ -32,14 +22,9 @@
32
22
  bottom: var(--indicator-bottom, auto);
33
23
  inset-inline-start: var(--indicator-start, auto);
34
24
  inset-inline-end: var(--indicator-end, 0);
35
- /*
36
- * Two composed translates: the first half-overlaps the corner; the second
37
- * pulls the item back toward the anchor center by `--indicator-offset`
38
- * (default 0). The pull direction is set per-modifier so it tracks the
39
- * placement automatically — e.g. `top-end` pulls left-and-down. Useful
40
- * for anchors with rounded corners: try `--indicator-offset: 4px` for a
41
- * `rounded-md` button.
42
- */
25
+ /* The first translate half-overlaps the corner; the second pulls back
26
+ toward the anchor centre by `--indicator-offset`, direction set
27
+ per-modifier. */
43
28
  transform: translate(var(--indicator-tx, 50%), var(--indicator-ty, -50%))
44
29
  translate(
45
30
  var(--indicator-offset-x, calc(-1 * var(--indicator-offset, 0px))),
@@ -87,11 +72,7 @@
87
72
  --indicator-offset-y: calc(-1 * var(--indicator-offset, 0px));
88
73
  }
89
74
 
90
- /*
91
- * Status dot — a small saturated circle for label-less presence/status.
92
- * A `.badge` with no content is still a pill (fixed height, horizontal
93
- * padding); a dot needs to actually be round.
94
- */
75
+ /* Status dot — an empty `.badge` is still a pill; a dot must be round. */
95
76
  .indicator-dot {
96
77
  @apply inline-block w-2 h-2 rounded-full bg-text-muted;
97
78
  }
@@ -3,9 +3,8 @@
3
3
  @apply inline-flex w-full;
4
4
  }
5
5
 
6
- /* Clear all corners, then re-apply the outer ones on the first/last
7
- child. Equal-specificity rules win because input-group.css imports
8
- after input.css. */
6
+ /* Equal-specificity override of `.input`'s radius works only because
7
+ input-group.css imports after input.css. */
9
8
  .input-group > * {
10
9
  @apply rounded-none;
11
10
  }
@@ -18,13 +17,11 @@
18
17
  @apply rounded-r-lg;
19
18
  }
20
19
 
21
- /* Collapse the shared edge between adjacent children. */
22
20
  .input-group > :not(:first-child) {
23
21
  margin-left: -1px;
24
22
  }
25
23
 
26
- /* Float the focused element so its outline ring and accented border
27
- can't be clipped by its neighbour's overlapping edge. */
24
+ /* Lift above the neighbour's overlapping edge so the focus ring isn't clipped. */
28
25
  .input-group > :focus,
29
26
  .input-group > :focus-within {
30
27
  @apply relative z-10;
@@ -18,8 +18,7 @@
18
18
  @apply border-danger hover:border-danger focus-visible:outline-danger;
19
19
  }
20
20
 
21
- /* Status variants border + focus outline only; text stays `text-text`, so
22
- warning's yellow accent (which fails AA as text) is fine here. */
21
+ /* Status variants tint border + outline only warning's yellow fails AA as text. */
23
22
  .input-info {
24
23
  @apply border-info hover:border-info focus-visible:outline-info;
25
24
  }
@@ -41,9 +40,7 @@
41
40
  @apply text-base px-4 py-2.5;
42
41
  }
43
42
 
44
- /* Native date/time picker glyph. The browser handles dark-mode coloring
45
- via the inherited `color-scheme` set on [data-theme]; we just tone the
46
- glyph down at rest and brighten it on hover so it reads as interactive. */
43
+ /* Dark-mode glyph coloring comes free via the inherited `color-scheme`. */
47
44
  .input::-webkit-calendar-picker-indicator {
48
45
  @apply opacity-60 cursor-pointer hover:opacity-100;
49
46
  }
@@ -1,6 +1,5 @@
1
1
  @layer components {
2
- /* A single keyboard chip one modifier or key. Stack inside a `.kbd-group`
3
- for multi-key chords. */
2
+ /* One key per chip; stack inside `.kbd-group` for chords. */
4
3
  .kbd {
5
4
  @apply inline-flex items-center justify-center
6
5
  min-w-[1.25em] h-[1.4em] px-[0.35em]
@@ -10,15 +9,12 @@
10
9
  whitespace-nowrap tabular-nums;
11
10
  }
12
11
 
13
- /* Cluster of `.kbd` chips. Always emitted by the React `<Kbd>` component so
14
- selectors can target the whole binding as a unit. */
12
+ /* Always emitted by the React `<Kbd>` so selectors can target the whole binding. */
15
13
  .kbd-group {
16
14
  @apply inline-flex items-center gap-1 align-middle;
17
15
  }
18
16
 
19
- /* Inside an action surface (button, menu item), the chip derives its
20
- colour from the host so it stays legible on any variant without
21
- fighting the surrounding chrome. */
17
+ /* Derive the chip colour from the host so it stays legible on any variant. */
22
18
  .btn .kbd,
23
19
  .menu-item .kbd {
24
20
  color: currentColor;
@@ -26,20 +22,18 @@
26
22
  border-color: color-mix(in srgb, currentColor 22%, transparent);
27
23
  }
28
24
 
29
- /* Subtle dimming for the leading cluster on a button so the label keeps
30
- visual priority. The cluster, not each chip, so a `Ctrl S` reads as
31
- a single unit. */
25
+ /* Dim the cluster (not each chip, so the chord reads as one unit) to keep
26
+ the label's visual priority. */
32
27
  .btn > .kbd-group {
33
28
  opacity: 0.85;
34
29
  }
35
30
 
36
- /* Right-pin the binding inside menu items — matches native menu convention. */
31
+ /* Matches native menu convention. */
37
32
  .menu-item > .kbd-group {
38
33
  margin-inline-start: auto;
39
34
  }
40
35
 
41
- /* Right-pin inside vertical button groups only. Standalone buttons keep the
42
- inline-trailing layout (chip sits next to the label). */
36
+ /* Vertical groups only standalone buttons keep the chip beside the label. */
43
37
  .btn-group-vertical > .btn > .kbd-group {
44
38
  margin-inline-start: auto;
45
39
  }
@@ -5,21 +5,15 @@
5
5
  rounded-sm transition-colors duration-150
6
6
  hover:text-link-hover
7
7
  focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus;
8
- /* Links are often the URL itself — let the long token break across lines
9
- instead of overflowing a narrow row, sidebar, or table cell. The leading
10
- icon stays `flex-shrink: 0` below. */
8
+ /* Links are often the URL itself — break instead of overflowing a narrow cell. */
11
9
  overflow-wrap: break-word;
12
10
  }
13
11
 
14
- /* Keep a leading icon from squishing when the link text wraps. The trailing
15
- external arrow is already `flex: none` below. */
16
12
  .link > :is(i, svg) {
17
13
  flex-shrink: 0;
18
14
  }
19
15
 
20
- /* External affordance: a trailing rendered from CSS so it ships identically
21
- in both bundles — no JS, no icon-font dependency. The arrow is a masked box
22
- tinted with `currentColor`, so it tracks the link's color (incl. hover). */
16
+ /* Trailing drawn in CSS no JS or icon-font dependency in either bundle. */
23
17
  .link-external {
24
18
  --link-external-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17 7 7 17'/%3E%3Cpath d='M8 7h9v9'/%3E%3C/svg%3E");
25
19
  }
@@ -1,12 +1,10 @@
1
1
  @layer components {
2
- /* Native <details> drives open state — no JS needed. The popup is a
3
- position: absolute child of the relative .menu root. */
2
+ /* Native <details> drives open state — no JS. */
4
3
  .menu {
5
4
  @apply relative inline-block;
6
5
  }
7
6
 
8
- /* Behaviour — applied always so the trigger works regardless of
9
- additional visual classes (e.g. `btn btn-primary` for a split button). */
7
+ /* Behaviour only visual classes (e.g. `btn btn-primary`) may stack on top. */
10
8
  .menu-trigger {
11
9
  @apply inline-flex items-center gap-1.5
12
10
  cursor-pointer select-none
@@ -19,17 +17,14 @@
19
17
  display: none;
20
18
  }
21
19
 
22
- /* Default appearance — bows out when `.btn` is also on the trigger so
23
- button classes (bg, hover, padding, text colour) take over cleanly. */
20
+ /* Default appearance — bows out when `.btn` supplies its own. */
24
21
  .menu-trigger:not(.btn) {
25
22
  @apply px-2.5 py-1.5 rounded-md text-sm leading-none
26
23
  text-text bg-transparent
27
24
  hover:bg-surface-strong;
28
25
  }
29
26
 
30
- /* Chevron uses currentColor so it tracks the trigger's text colour —
31
- muted text on the default trigger, content colour on a btn-primary
32
- split button, etc. Sized in em so it scales with btn-sm / btn-lg. */
27
+ /* em-sized so the chevron scales with btn-sm / btn-lg. */
33
28
  .menu-trigger::after {
34
29
  content: "";
35
30
  width: 0.5em;
@@ -41,8 +36,7 @@
41
36
  flex-shrink: 0;
42
37
  }
43
38
 
44
- /* Icon-only triggers (e.g. the dropdown half of a split button) center
45
- their chevron instead of letting it sit at the start. */
39
+ /* A text-less trigger (split-button dropdown half) centers its chevron. */
46
40
  .menu-trigger:empty {
47
41
  @apply justify-center;
48
42
  }
@@ -59,15 +53,9 @@
59
53
  border border-border rounded-lg shadow-md;
60
54
  }
61
55
 
62
- /* CSS anchor positioning makes the popup `position: fixed` so it escapes
63
- ancestor `overflow: hidden`/`overflow: auto` clipping necessary when
64
- the menu lives inside a `<dialog>` (top-layer + overflow: hidden) or a
65
- scroll-clipped surface like a card body. `anchor-scope` keeps each
66
- menu's anchor lookups isolated so multiple menus on the page don't
67
- cross-target, and `position-try-fallbacks` flips the popup above the
68
- trigger when there isn't room below. Browsers without anchor
69
- positioning (Firefox, as of early 2026) fall back to the absolute
70
- rules above and clip as before. */
56
+ /* Anchor positioning makes the popup fixed so it escapes ancestor overflow
57
+ clipping (e.g. inside a <dialog>); browsers without it (Firefox, early
58
+ 2026) fall back to the absolute rules above and clip as before. */
71
59
  @supports (anchor-name: --x) {
72
60
  .menu {
73
61
  anchor-scope: --menu-trigger;
@@ -100,9 +88,7 @@
100
88
  hover:bg-surface-muted
101
89
  focus-visible:bg-surface-muted focus-visible:outline-none
102
90
  disabled:opacity-50 disabled:cursor-not-allowed;
103
- /* The popup has no max-width, so let a long label (entity name, file path)
104
- break and shrink rather than grow the popup horizontally. Item icons stay
105
- `flex-shrink: 0` below. */
91
+ /* The popup has no max-width break long labels instead of growing it. */
106
92
  overflow-wrap: break-word;
107
93
  min-width: 0;
108
94
  }
@@ -111,7 +97,6 @@
111
97
  @apply opacity-50 cursor-not-allowed;
112
98
  }
113
99
 
114
- /* Don't let a constrained menu width squish a leading/trailing icon. */
115
100
  .menu-trigger > :is(i, svg),
116
101
  .menu-item > :is(i, svg) {
117
102
  flex-shrink: 0;
@@ -1,7 +1,6 @@
1
1
  @layer components {
2
- /* 2px bottom stripe is always rendered defaults to a neutral gray via
3
- `--color-system-accent` and brand-shifts when the consuming app overrides
4
- that variable at :root (see also `.footer` and `.brand-tile`). */
2
+ /* The bottom stripe brand-shifts when the consuming app overrides
3
+ `--color-system-accent` at :root (see also `.footer` and `.brand-tile`). */
5
4
  .navbar {
6
5
  @apply flex items-center gap-3 px-4 h-12
7
6
  bg-surface-muted text-text
@@ -31,19 +30,16 @@
31
30
  @apply bg-primary-muted text-primary;
32
31
  }
33
32
 
34
- /* Keep brand/item icons at their intrinsic size in a crowded bar. */
35
33
  .navbar-brand > :is(i, svg),
36
34
  .navbar-item > :is(i, svg) {
37
35
  flex-shrink: 0;
38
36
  }
39
37
 
40
- /* Right-aligned slot for actions: shop selector, user menu, etc. */
41
38
  .navbar-actions {
42
39
  @apply flex items-center gap-2 ml-auto;
43
40
  }
44
41
 
45
- /* Hamburger; hidden above the md breakpoint. The three lines are drawn
46
- with one element + two box-shadow strokes — no SVG needed. */
42
+ /* Hamburger three lines from one element + two box-shadow strokes. */
47
43
  .navbar-mobile-toggle {
48
44
  @apply inline-flex items-center justify-center size-9 -ml-2
49
45
  rounded-md text-text bg-transparent
@@ -8,7 +8,6 @@
8
8
  @apply inline-flex;
9
9
  }
10
10
 
11
- /* Square button shared by number, prev/next, and ellipsis containers. */
12
11
  .page-link {
13
12
  @apply inline-flex items-center justify-center
14
13
  min-w-8 h-8 px-2
@@ -23,8 +22,7 @@
23
22
  disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none;
24
23
  }
25
24
 
26
- /* Current page — same surface as a sidebar's active item so the visual
27
- metaphor is consistent. */
25
+ /* Same surface as a sidebar's active item. */
28
26
  .page-link.active,
29
27
  .page-link[aria-current="page"] {
30
28
  @apply bg-primary-muted text-primary border-primary-muted;
@@ -34,7 +32,6 @@
34
32
  @apply opacity-50 cursor-not-allowed pointer-events-none;
35
33
  }
36
34
 
37
- /* Ellipsis — non-interactive placeholder between groups of pages. */
38
35
  .page-ellipsis {
39
36
  @apply inline-flex items-center justify-center
40
37
  min-w-8 h-8 px-2
@@ -1,7 +1,5 @@
1
1
  @layer components {
2
- /* Native <progress> styled across engines. `appearance: none` strips the
3
- platform default; the track is the element itself, the fill comes from
4
- ::-webkit-progress-value / ::-moz-progress-bar. */
2
+ /* The track is the element itself; the fill is the engine-specific value pseudo. */
5
3
  .progress {
6
4
  appearance: none;
7
5
  -webkit-appearance: none;
@@ -32,7 +30,6 @@
32
30
  transition: inline-size 200ms ease;
33
31
  }
34
32
 
35
- /* Sizes */
36
33
  .progress-sm {
37
34
  height: 0.25rem;
38
35
  }
@@ -54,9 +51,8 @@
54
51
  color: var(--color-danger);
55
52
  }
56
53
 
57
- /* Indeterminate no value attribute. WebKit hides the value pseudo, Firefox
58
- draws it full-width; in both cases we paint an animated gradient on the
59
- bar itself. */
54
+ /* When indeterminate, WebKit hides the value pseudo and Firefox draws it
55
+ full-width blank both and animate a gradient on the bar itself. */
60
56
  .progress:indeterminate {
61
57
  background-image: linear-gradient(
62
58
  90deg,
@@ -1,6 +1,4 @@
1
1
  @layer components {
2
- /* Outer section — owns striped, hide-if-empty modifiers. Title
3
- (optional) and the items grid stack vertically. */
4
2
  .property-list {
5
3
  @apply flex flex-col text-sm text-text;
6
4
  }
@@ -9,8 +7,7 @@
9
7
  @apply text-sm font-bold text-text mb-2;
10
8
  }
11
9
 
12
- /* The <dl> itself is the two-track grid; <dt> auto-flows into column 1
13
- and <dd> into column 2. */
10
+ /* The <dl> is the grid; <dt>/<dd> auto-flow into the two tracks. */
14
11
  .property-list-items {
15
12
  display: grid;
16
13
  grid-template-columns: max-content 1fr;
@@ -25,15 +22,12 @@
25
22
  @apply text-text-muted;
26
23
  }
27
24
 
28
- /* `min-w-0` lets the value's grid track shrink below its content; pair it
29
- with `break-words` so long unbreakable values (IDs, hashes, emails, URLs,
30
- file paths) break instead of overflowing the column. */
25
+ /* `min-w-0` lets the track shrink below its content so long unbreakable
26
+ values break instead of overflowing the column. */
31
27
  .property-list-value {
32
28
  @apply gap-2 min-w-0 break-words;
33
29
  }
34
30
 
35
- /* Compact density — tighter rows for sidebar info blocks or very many
36
- short attributes. */
37
31
  .property-list-compact .property-list-title {
38
32
  @apply mb-1;
39
33
  }
@@ -43,7 +37,6 @@
43
37
  @apply px-2 py-0.5 min-h-6;
44
38
  }
45
39
 
46
- /* Numeric — right-align + tabular-nums on the value. */
47
40
  .property-list-value-numeric {
48
41
  justify-content: flex-end;
49
42
  @apply tabular-nums;
@@ -60,8 +53,7 @@
60
53
  display: none;
61
54
  }
62
55
 
63
- /* Copy button — always emitted by the Value but kept out of layout entirely
64
- unless this specific value opts in. */
56
+ /* Always emitted by the Value; kept out of layout unless the value opts in. */
65
57
  .property-list-copy {
66
58
  @apply inline-flex items-center justify-center
67
59
  ml-auto rounded
@@ -82,8 +74,7 @@
82
74
  pointer-events: none;
83
75
  }
84
76
 
85
- /* Reveal on hover of either the label or the value of a copyable row, on
86
- button focus, or while feedback is active. */
77
+ /* Reveal on hover of the row's label or value, on focus, or during feedback. */
87
78
  .property-list-label:has(+ .property-list-value-copyable):hover
88
79
  + .property-list-value
89
80
  .property-list-copy,
@@ -1,23 +1,13 @@
1
1
  @layer components {
2
- /*
3
- * Long-form rendered HTML markdown output, CMS bodies, anything you can't
4
- * annotate with the system's semantic class names. The global reset strips
5
- * margins, list markers, and link styling from bare elements (so admin chrome
6
- * stays neutral); `.prose` re-establishes them for its descendants only, using
7
- * the semantic tokens so it follows dark mode and `--color-*` overrides.
8
- *
9
- * Descendant rules use `:where()` to stay at specificity 0 — a consumer's own
10
- * `.prose a { … }` wins without `!important`.
11
- */
2
+ /* Styles rendered HTML (markdown, CMS bodies) that can't carry the system's
3
+ class names re-establishes what the global reset strips. Descendant rules
4
+ use `:where()` so a consumer's own `.prose a { }` wins without `!important`. */
12
5
  .prose {
13
6
  @apply text-sm leading-normal text-text;
14
- /* Long URLs/tokens in flow text break instead of overflowing a narrow
15
- column. Inherited by p/li/a/td/blockquote; the deliberately-scrolling
16
- `<pre>` keeps its own `white-space: pre` + `overflow-x: auto`. */
7
+ /* Break long URLs/tokens; the scrolling `<pre>` keeps its own `white-space: pre`. */
17
8
  overflow-wrap: break-word;
18
9
  }
19
10
 
20
- /* Vertical rhythm — space between flow blocks, none at the container edges. */
21
11
  .prose :where(p, ul, ol, blockquote, pre, table, figure) {
22
12
  @apply my-3;
23
13
  }
@@ -28,8 +18,7 @@
28
18
  margin-bottom: 0;
29
19
  }
30
20
 
31
- /* Headings — base.css already sizes h1–h3; here we add h4–h6 and the
32
- sectioning rhythm. The edge reset above zeroes a leading heading's margin. */
21
+ /* base.css already sizes h1–h3; add h4–h6 and the sectioning rhythm. */
33
22
  .prose :where(h1, h2, h3, h4, h5, h6) {
34
23
  @apply mt-6 mb-2 font-semibold leading-tight;
35
24
  }
@@ -40,7 +29,6 @@
40
29
  @apply text-xs uppercase tracking-wide text-text-muted;
41
30
  }
42
31
 
43
- /* Lists — restore the markers the reset removes. */
44
32
  .prose :where(ul) {
45
33
  @apply list-disc ps-5;
46
34
  }
@@ -54,7 +42,6 @@
54
42
  .prose :where(li) :where(p) {
55
43
  @apply my-1;
56
44
  }
57
- /* Nested lists hug their parent item rather than taking full block spacing. */
58
45
  .prose :where(li > ul, li > ol) {
59
46
  @apply my-1;
60
47
  }
@@ -66,15 +53,13 @@
66
53
  focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus;
67
54
  }
68
55
 
69
- /* Inline code — a tinted chip. */
70
56
  .prose :where(code) {
71
57
  @apply rounded border border-border bg-code-surface px-1 py-0.5
72
58
  font-mono text-code-text;
73
59
  font-size: 0.85em;
74
60
  }
75
61
 
76
- /* Code blocks — the .code-block surface; strip the inline chip off nested
77
- <code> so a highlighter's own tokens show through. */
62
+ /* Mirrors .code-block; nested <code> sheds the chip so highlighter tokens show. */
78
63
  .prose :where(pre) {
79
64
  @apply rounded-lg bg-code-surface p-3 font-mono text-sm text-code-text;
80
65
  white-space: pre;
@@ -85,12 +70,10 @@
85
70
  font-size: inherit;
86
71
  }
87
72
 
88
- /* Blockquote — a quiet inline-start rule. */
89
73
  .prose :where(blockquote) {
90
74
  @apply border-s-2 border-border-strong ps-3 text-text-muted;
91
75
  }
92
76
 
93
- /* Thematic break. */
94
77
  .prose :where(hr) {
95
78
  @apply my-6 border-0 border-t border-border;
96
79
  }
@@ -106,7 +89,6 @@
106
89
  @apply font-semibold text-text-muted;
107
90
  }
108
91
 
109
- /* Media + emphasis. */
110
92
  .prose :where(img) {
111
93
  @apply h-auto max-w-full rounded-md;
112
94
  }