@stnd/styles 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,23 @@
1
1
  @use "standard-00-variables" as *;
2
2
 
3
+ /**
4
+ * @component Base
5
+ * @category Foundation
6
+ * @description Document root and page chrome, zero classes required: html
7
+ * typography and font features, body padding/max-width/centering, a
8
+ * global reading-measure cap applied to text elements site-wide (not just
9
+ * inside `.prose`), theme-transition rules, and selection/mark highlights.
10
+ *
11
+ * @property html Root element establishing background color, foreground text color, font smoothing, and smooth scrolling.
12
+ * @property body Document container centered at `--body-max-width` with responsive padding and scroll margins.
13
+ * @property .no-body-margin Full-bleed helper applied to `<header>` or `<footer>` to extend edge-to-edge past body padding.
14
+ * @property .container-hero Hero section container with vertical padding and hairline borders.
15
+ * @property ::selection Custom highlight selection using subtle yellow background tint and accent text color.
16
+ *
17
+ * @example html - Full-bleed footer inside a normally-padded body
18
+ * <footer class="no-body-margin">Full-width footer content</footer>
19
+ */
20
+
3
21
  /* =========================== */
4
22
  /* BASE (HTML ROOT) */
5
23
  /* =========================== */
@@ -64,7 +82,7 @@ body {
64
82
  padding: var(--gap-body);
65
83
  padding-top: var(--gap-header);
66
84
  padding-bottom: var(--gap-footer);
67
- max-width: var(--body-max-width, var(--max-width));
85
+ max-width: var(--body-max-width);
68
86
  margin-inline: auto;
69
87
 
70
88
  transition:
@@ -75,8 +93,8 @@ body {
75
93
  margin var(--transition);
76
94
 
77
95
  [id] {
96
+ /* Keeps anchor-linked headings from landing under the sticky header. */
78
97
  scroll-margin-top: calc(var(--space-2) + var(--gap-header));
79
- /* Adjust value as needed background: var(--color-surface-highest); background: var(--color-surface-highest); background: var(--color-surface-highest); background: var(--color-surface-highest); */
80
98
  }
81
99
  }
82
100
 
@@ -127,14 +145,6 @@ hr {
127
145
  block-size: var(--stroke-width, 1px);
128
146
  }
129
147
 
130
- /* Mark highlighting */
131
- mark {
132
- background: oklch(from var(--color-yellow) l c h / 0.3);
133
- color: color-mix(in oklch, var(--color-yellow) 30%, var(--color-foreground));
134
- padding: var(--trim);
135
- padding-top: 0.1em;
136
- }
137
-
138
148
  /* =========================== */
139
149
  /* LAYOUT */
140
150
  /* =========================== */
@@ -165,24 +175,23 @@ dt {
165
175
  /* BODY PADDING NEGATION */
166
176
  /* =========================== */
167
177
 
168
- /**
169
- * Utilities to negate body padding for full-width elements
170
- * Useful for footers, headers, or other elements that should extend to viewport edges
171
- *
172
- * .negate-body-padding — Negates horizontal body padding only
173
- * .negate-body-padding-full — Negates all body padding (horizontal + bottom)
174
- * .negate-body-padding-bottom — Negates extra bottom body padding (1.5× multiplier)
175
- *
176
- * Usage:
177
- * <footer class="negate-body-padding-full">
178
- * Full-width footer content
179
- * </footer>
180
- */
181
-
182
- /**
183
- * Negate horizontal body padding (left/right)
184
- * Allows full-width backgrounds while keeping vertical padding
185
- */
178
+ /* AUDIT NOTE (2026-07-14): this doc previously described a
179
+ .negate-body-padding / .negate-body-padding-full / .negate-body-padding-bottom
180
+ API — those class names don't exist anywhere in this file or the
181
+ codebase (grepped), never did as far as git history in this session
182
+ shows. The real, implemented class is .no-body-margin, and it's far
183
+ narrower than "footers, headers, or other elements" implied: it only
184
+ matches <footer>/<header> that are DIRECT children of <body> AND the
185
+ first/last element of that type. Neither the old (fictional) nor the
186
+ real class name is used anywhere in apps/ today — corrected the docs
187
+ to match reality rather than delete the utility. Moved into the
188
+ @component block above so its example HTML sits inside a fenced
189
+ @example instead of bare in a comment — the previous version was
190
+ valid enough HTML that it would have rendered live on the docs page,
191
+ not shown as a code sample. */
192
+
193
+ /* Negate horizontal body padding (left/right) — allows full-width
194
+ backgrounds while keeping vertical padding. */
186
195
 
187
196
  body > footer.no-body-margin:last-of-type,
188
197
  body > header.no-body-margin:first-of-type {
@@ -194,11 +203,9 @@ body > header.no-body-margin:first-of-type {
194
203
  }
195
204
  }
196
205
 
197
- /**
198
- * Negate bottom body padding (extra 1.5× multiplier)
199
- * Removes the generous bottom padding applied to body elements
200
- * Useful when you want footer to sit flush at bottom
201
- */
206
+ /* Negate bottom body padding (extra 1.5× multiplier) — removes the
207
+ generous bottom padding applied to body elements, for a footer that
208
+ should sit flush at the bottom. */
202
209
  body > footer.no-body-margin:last-of-type {
203
210
  margin-block-end: calc(var(--gap-body) * -1.5);
204
211
 
@@ -207,10 +214,13 @@ body > footer.no-body-margin:last-of-type {
207
214
  }
208
215
  }
209
216
 
217
+ /* Fixed 2026-07-14 — was margin-block-end (wrong property, copy-paste
218
+ typo), now correctly overrides margin-block-start to match the footer's
219
+ symmetric pattern. */
210
220
  body > header.no-body-margin:first-of-type {
211
221
  margin-block-start: calc(var(--gap-body) * -1);
212
222
 
213
223
  @media (max-width: #{$small}) {
214
- margin-block-end: calc(var(--gap-body-mobile) * -1);
224
+ margin-block-start: calc(var(--gap-body-mobile) * -1);
215
225
  }
216
226
  }
@@ -1,15 +1,26 @@
1
1
  @use "standard-00-variables" as *;
2
2
 
3
- /* =========================== */
4
- /* MEDIA */
5
- /* =========================== */
3
+ /**
4
+ * @component Media & Embeds
5
+ * @category Content
6
+ * @description Responsive media containers for images, native video, audio players,
7
+ * and iframes. Applies theme borders, elevation shadows, and rounded corners by default.
8
+ *
9
+ * @property img Responsive image with theme radius and raised surface shadow.
10
+ * @property video Native video element with border and elevation.
11
+ * @property .video-container Responsive 16:9 media embed container for videos and iframes.
12
+ * @property .stnd-icon Icon container unsetting default media borders and shadows to inherit currentColor.
13
+ * @property figure Grid container for media and associated captions.
14
+ * @property figcaption Centered italic caption text for figures.
15
+ * @property img.fx Image explicitly styled with theme border and radius.
16
+ * @property img.nofx Image stripping borders, shadows, and radii.
17
+ */
6
18
 
7
19
  img,
8
20
  video,
9
21
  audio,
10
22
  iframe,
11
- .video,
12
- .video-container {
23
+ .video {
13
24
  max-width: 100%;
14
25
  border-radius: var(--radius);
15
26
  box-shadow: var(--shadow-raised);
@@ -19,29 +30,26 @@ iframe,
19
30
  }
20
31
 
21
32
  /* =========================== */
22
- /* TYPOGRAPHIC NUANCES */
33
+ /* VIDEO EMBEDS */
23
34
  /* =========================== */
24
- .video-container:has(video) {
35
+ .video-container {
25
36
  position: relative;
26
- /* padding-bottom: 56.25%; /* 16:9 aspect ratio */
27
- border: none;
28
- box-shadow: none;
37
+ aspect-ratio: 16 / 9;
38
+ width: 100%;
39
+ max-width: 100%;
29
40
  overflow: hidden;
30
- background: transparent;
41
+ border-radius: var(--radius);
42
+ box-shadow: var(--shadow-raised);
43
+ border: var(--border);
44
+ background: var(--color-surface);
31
45
 
46
+ iframe,
32
47
  video {
33
- border-radius: var(--radius);
34
- border: var(--border);
35
- box-shadow: var(--shadow-raised);
36
- }
37
-
38
- iframe {
39
- position: absolute;
40
- top: 0;
41
- left: 0;
42
48
  width: 100%;
43
49
  height: 100%;
44
50
  border: 0;
51
+ display: block;
52
+ object-fit: cover;
45
53
  }
46
54
  }
47
55
 
@@ -76,12 +84,17 @@ figcaption {
76
84
  }
77
85
 
78
86
  /**
79
- * @component Image System
87
+ * @component Image Zoom & Lightbox
88
+ * @category Content
80
89
  * @description Responsive image handling with interactive zoom functionality.
81
- * This system is progressively enhanced. Without JavaScript, it provides a
82
- * basic zoom-on-click-and-hold. With JavaScript, it provides a full
83
- * feature-rich lightbox experience.
90
+ * Progressively enhanced: without JavaScript, provides click-and-hold zoom.
91
+ * With JavaScript, provides a full frosted-glass lightbox experience.
84
92
  *
93
+ * @property html:not(.js-image-zoom-enabled) img:active Fallback CSS-only zoom on click-and-hold.
94
+ * @property .image-zoom-overlay Fullscreen glassmorphic lightbox overlay created dynamically by JS.
95
+ * @property .image-zoom-overlay.is-visible Active visible state for the lightbox overlay.
96
+ * @property html.image-zoomed-active Body scroll lock class applied when lightbox is active.
97
+ * @property [data-no-zoom] Attribute to prevent zoom interaction on icons or avatars.
85
98
  * @since 0.1.0
86
99
  */
87
100
 
@@ -160,11 +173,10 @@ html:not(.js-image-zoom-enabled):has(img:active)::before {
160
173
  /* lightbox experience with keyboard navigation, etc. */
161
174
  /* ================================================================ */
162
175
 
163
- /* Lock the page scroll when the JS overlay is active
176
+ /* Lock the page scroll when the JS overlay is active */
164
177
  html.image-zoomed-active {
165
- overflow: hidden;
178
+ overflow: hidden;
166
179
  }
167
- */
168
180
  /* The overlay container created by the JS */
169
181
  .image-zoom-overlay {
170
182
  position: fixed;
@@ -175,7 +187,6 @@ html.image-zoomed-active {
175
187
  display: flex;
176
188
  align-items: center;
177
189
  justify-content: center;
178
- padding: var(--gap-body);
179
190
  padding: var(--space-4);
180
191
  margin: 0;
181
192
  opacity: 0;
@@ -208,7 +219,9 @@ html.image-zoomed-active {
208
219
  transform: scale(1);
209
220
  }
210
221
 
211
- @media (min-width: 768px) {
222
+ /* Uses #{$small} — same breakpoint variable as everywhere else in the
223
+ framework. */
224
+ @media (min-width: #{$small}) {
212
225
  /* Global zoomable image cursor */
213
226
  img:not([data-no-zoom]) {
214
227
  cursor: zoom-in !important;
@@ -1,5 +1,26 @@
1
1
  @use "standard-00-variables" as *;
2
2
 
3
+ /**
4
+ * @component Lists
5
+ * @category Content
6
+ * @description Replaces native `<ul>`/`<ol>` markers with custom
7
+ * absolutely-positioned bullets and tabular-nums counters, and spaces items
8
+ * apart via `li + li`. Four density/marker classes are opt-in.
9
+ *
10
+ * @property .no-bullet Hides markers and removes inline padding; cascades to nested lists.
11
+ * @property .tight Tightens list item vertical spacing to `--space-d3`.
12
+ * @property .compact Tightens list item vertical spacing to `--space-d2`.
13
+ * @property .relaxed Widens list item vertical spacing to `--space-2`.
14
+ * @property .task-list-item Applied to task list items (`- [ ]`), displaying interactive or static checkbox.
15
+ * @property .task-field Inline badge representation for Dataview-style `[key:: value]` metadata.
16
+ *
17
+ * @example html - What `- [ ] Ship it [priority:: 1]` becomes
18
+ * <li class="task-list-item">
19
+ * <input type="checkbox" disabled> Ship it
20
+ * <span class="task-field" data-field="priority">priority: 1</span>
21
+ * </li>
22
+ */
23
+
3
24
  /* =========================== */
4
25
  /* LISTS */
5
26
  /* =========================== */
@@ -13,7 +34,7 @@ ol {
13
34
  /* Nested lists */
14
35
  li > ul,
15
36
  li > ol {
16
- padding-inline-start: var(--space);
37
+ padding-inline: var(--space);
17
38
  margin-block-start: var(--space-d2);
18
39
  margin-block-end: 0;
19
40
  }
@@ -62,9 +83,11 @@ ol > li::before {
62
83
  font-size: var(--size-sm);
63
84
  }
64
85
 
86
+ /* Fixed 2026-07-14 — was checking for .display-flex (not a real class
87
+ anywhere), now correctly checks .flex. */
65
88
  /* Inline lists override - protects layouts using flex */
66
- ul:where(.display-flex, [style*="display: flex"], [style*="display:flex"]) li,
67
- ol:where(.display-flex, [style*="display: flex"], [style*="display:flex"]) li {
89
+ ul:where(.flex, [style*="display: flex"], [style*="display:flex"]) li,
90
+ ol:where(.flex, [style*="display: flex"], [style*="display:flex"]) li {
68
91
  margin-block-end: 0;
69
92
  }
70
93
 
@@ -81,23 +104,55 @@ ol:where(.display-flex, [style*="display: flex"], [style*="display:flex"]) li {
81
104
  }
82
105
  }
83
106
 
84
- .compact {
85
- --base-gap: var(--space-d2);
86
- li + li {
87
- margin-block-start: var(--space-d2);
88
- }
107
+ /* FIXED (2026-09-05) — was a bare, unnamespaced .compact/.relaxed that
108
+ collided with _standard-50-utilities.scss's line-height utilities of the
109
+ same name: any element with class="compact" containing <li> children got
110
+ this file's li+li spacing unconditionally, whether or not it was
111
+ actually a list. Qualified to :is(ul, ol) instead, matching the pattern
112
+ _standard-04-grid.scss already uses for its own .compact/.relaxed
113
+ (:is(.grid, [class^="grid-"]).compact) — same class name, each scope's
114
+ meaning applies only in its own context. A <ul class="compact"> now
115
+ picks up both this file's tight item spacing AND utilities.scss's
116
+ compact line-height, which is the combination you'd actually want. */
117
+ :is(ul, ol).compact li + li {
118
+ margin-block-start: var(--space-d2);
89
119
  }
90
120
 
91
- .tight {
92
- --base-gap: var(--space-d3);
93
- li {
94
- margin-block-end: var(--space-d3);
95
- }
121
+ :is(ul, ol).tight li {
122
+ margin-block-end: var(--space-d3);
123
+ }
124
+
125
+ :is(ul, ol).relaxed li {
126
+ margin-block-end: var(--space-2);
96
127
  }
97
128
 
98
- .relaxed {
99
- --base-gap: var(--space-2);
100
- li {
101
- margin-block-end: var(--space-2);
129
+ /* =========================== */
130
+ /* TASK LISTS */
131
+ /* =========================== */
132
+
133
+ /* Rendered by @stnd/press's typography-tasks plugin from `- [ ]` / `- [x]` —
134
+ the checkbox replaces the bullet, it doesn't sit alongside it. */
135
+ .task-list-item {
136
+ &::before {
137
+ display: none;
138
+ }
139
+
140
+ input[type="checkbox"] {
141
+ margin-inline-end: var(--space-d3);
142
+ vertical-align: -0.15em;
143
+ accent-color: var(--color-accent);
102
144
  }
103
145
  }
146
+
147
+ /* Dataview-style `[key:: value]` inline fields, tagged by the same plugin. */
148
+ .task-field {
149
+ display: inline-block;
150
+ font-family: var(--font-monospace);
151
+ font-size: var(--size-3xs);
152
+ color: var(--color-subtle);
153
+ background: var(--color-surface);
154
+ border: var(--border);
155
+ border-radius: var(--radius-sm);
156
+ padding: 0 var(--space-d4);
157
+ margin-inline-end: var(--space-d6);
158
+ }
@@ -1,5 +1,30 @@
1
1
  @use "standard-00-variables" as *;
2
2
 
3
+ /**
4
+ * @component Tables
5
+ * @category Content
6
+ * @description A bare `<table>` gets full styling with no class required:
7
+ * collapsed borders, uppercase small-caps headers, compact cell padding.
8
+ * `.striped` and `.numeric` are the only two opt-in classes.
9
+ *
10
+ * @property table Zero-class collapsed table layout with hairline borders and compact padding.
11
+ * @property th Uppercase small-caps table header with surface background and subtle tracking.
12
+ * @property caption Bold caption element positioned above table with rhythm padding.
13
+ * @property .striped Zebra-stripes even `<tbody>` rows with a 3% foreground tint.
14
+ * @property .numeric Right-aligns content and switches on tabular-nums for numeric columns.
15
+ * @property .properties Table variant keeping leading identifier/token columns unwrapped.
16
+ *
17
+ * @example html - Bare table, zero classes
18
+ * <table>
19
+ * <thead>
20
+ * <tr><th>Name</th><th class="numeric">Count</th></tr>
21
+ * </thead>
22
+ * <tbody>
23
+ * <tr><td>Widgets</td><td class="numeric">42</td></tr>
24
+ * </tbody>
25
+ * </table>
26
+ */
27
+
3
28
  /* =========================== */
4
29
  /* TABLES */
5
30
  /* =========================== */
@@ -9,6 +34,9 @@ table {
9
34
  width: 100%;
10
35
  }
11
36
 
37
+ /* padding/margin on <tr> have no effect — table rows don't support box
38
+ model properties in the CSS table layout spec, browsers ignore these.
39
+ Harmless no-op, not fixing since it's inert either way. */
12
40
  tr {
13
41
  padding: 0;
14
42
  margin: 0;
@@ -21,15 +49,21 @@ td {
21
49
  line-height: var(--line-height-compact);
22
50
  padding: var(--space-d2);
23
51
  font-size: var(--size-sm);
24
- min-height: var(--line-height);
52
+ vertical-align: top;
53
+ /* Fixed 2026-07-14 — was an invalid unitless min-height, now derives a
54
+ real length from the line-height already set above. */
55
+ min-height: calc(1em * var(--line-height-compact));
25
56
  }
26
57
 
27
58
  th {
28
59
  font-weight: var(--font-weight-bold, 600);
29
60
  transition: background var(--transition);
30
- background: var(--color-surface-low);
61
+ background: var(--color-surface);
31
62
  text-transform: uppercase;
32
- letter-spacing: 0.05em;
63
+ letter-spacing: 0.06em;
64
+ font-size: var(--size-3xs);
65
+ color: var(--color-muted);
66
+ vertical-align: middle;
33
67
  }
34
68
  caption {
35
69
  font-weight: var(--font-weight-bold, bold);
@@ -47,3 +81,17 @@ caption {
47
81
  .striped tbody tr:nth-child(even) {
48
82
  background: oklch(from var(--color-foreground) l c h / 0.03);
49
83
  }
84
+
85
+ /* Property & token dictionaries (prevents key column from wrapping) */
86
+ .properties {
87
+ th:not(:last-child),
88
+ td:not(:last-child) {
89
+ white-space: nowrap;
90
+ width: 1%;
91
+ }
92
+
93
+ th:last-child,
94
+ td:last-child {
95
+ width: 100%;
96
+ }
97
+ }
@@ -1,5 +1,35 @@
1
1
  @use "standard-00-variables" as *;
2
2
 
3
+ /**
4
+ * @component Forms
5
+ * @category Content
6
+ * @description Zero-class styling for every native form control:
7
+ * `fieldset`/`legend` layout, text inputs, textarea, a custom-drawn select,
8
+ * checkbox/radio, an ARIA switch variant, and a range slider — plus the
9
+ * adjacency rules that space form parts apart from each other and from
10
+ * whatever follows them.
11
+ *
12
+ * @property fieldset Container grouping form controls with hairline border, radius, and subtle surface background tint.
13
+ * @property legend Bold legend label nested within fieldset.
14
+ * @property input, textarea Zero-class text controls with interface typography, raised shadow, and accent focus rings.
15
+ * @property select Custom styled dropdown with double-chevron indicator and rhythm-aligned padding.
16
+ * @property input[role=switch] Accessible toggle switch with animated sliding thumb.
17
+ * @property --switch-height Primary height sizing knob for toggle switch controls.
18
+ * @property --switch-width Width sizing token for toggle switches (`calc(var(--switch-height) * 2)`).
19
+ * @property --switch-padding Inset padding controlling the toggle switch thumb gap (`2px`).
20
+ * @property --slider-value Percentage value driving custom filled range slider tracks.
21
+ *
22
+ * @example html - A switch (role=switch on a checkbox)
23
+ * <input type="checkbox" role="switch">
24
+ *
25
+ * @example html - Fieldset with adjacent button spacing
26
+ * <fieldset>
27
+ * <legend>Notifications</legend>
28
+ * <label><input type="checkbox"> Email me</label>
29
+ * </fieldset>
30
+ * <button>Save</button>
31
+ */
32
+
3
33
  /* =========================== */
4
34
  /* FORMS */
5
35
  /* =========================== */
@@ -49,9 +79,12 @@ textarea {
49
79
  border-radius: var(--radius-sm);
50
80
  color: var(--color-foreground);
51
81
  background: var(--color-surface);
52
- /* shadcn-style raised effect */
82
+ /* shadcn-style raised effect. */
53
83
  border: var(--border);
54
84
  box-shadow: var(--shadow-raised);
85
+ /* Transparent outline at full width reserves the space a real focus
86
+ outline (set on :focus below) will need — prevents layout shift when
87
+ the outline color actually appears. */
55
88
  outline: var(--stroke-width) solid transparent;
56
89
  outline-offset: var(--stroke-width);
57
90
  transition: all var(--transition-fast);
@@ -66,7 +99,6 @@ textarea {
66
99
  select {
67
100
  width: 100%;
68
101
  font-family: var(--font-interface), system-ui, sans-serif;
69
- font-family: var(--font-interface), system-ui, sans-serif;
70
102
  font-weight: var(--font-weight);
71
103
  padding: var(--space-d8) var(--space-d4);
72
104
  font-size: 1em;
@@ -276,9 +308,11 @@ input[type="checkbox"][role="switch"] {
276
308
  }
277
309
  }
278
310
 
311
+ /* Fixed 2026-07-14 — was a typo (--color-on-cce), corrected to
312
+ --color-on-accent. */
279
313
  &:checked:hover {
280
314
  &::before {
281
- background: var(--color-on-cce) !important;
315
+ background: var(--color-on-accent) !important;
282
316
  }
283
317
  }
284
318
  }
@@ -303,18 +337,17 @@ input[type="range"] {
303
337
  /* Crucial: removes text-input borders */
304
338
  background-origin: border-box;
305
339
 
306
- /*
307
- * THE FILL MAGIC
308
- * uses the --slider-value variable passed in the style attribute
309
- */
340
+ /* Fixed 2026-07-14 — this gradient is real and wired up by
341
+ Slider.astro's JS (sets --slider-value); the flat color below it was
342
+ silently overriding it. Removed the override so the fill effect
343
+ actually renders. */
310
344
  background: linear-gradient(
311
345
  to right,
312
346
  var(--color-background, var(--color-accent)) 0%,
313
- var(--color-background, var(--color-accent)) var(--slider-value),
314
- var(--color-red, var(--color-surface)) var(--slider-value),
347
+ var(--color-background, var(--color-accent)) var(--slider-value, 50%),
348
+ var(--color-red, var(--color-surface)) var(--slider-value, 50%),
315
349
  var(--color-red, var(--color-surface)) 100%
316
350
  );
317
- background: var(--color-surface-lowest);
318
351
  }
319
352
 
320
353
  input[type="range"]::-webkit-slider-thumb {
@@ -1,6 +1,88 @@
1
1
  @use "standard-00-variables" as *;
2
- /* Note: General color utilities (.text-muted, .text-subtle, .text-accent, .bg-surface, .border-*) */
3
- /* moved to standard-98-utilities.scss for better layer organization */
2
+
3
+ /**
4
+ * @component Code Layout & Highlighting
5
+ * @category Content
6
+ * @description Code block container layout, copy buttons, and PrismJS syntax highlighting theme.
7
+ *
8
+ * @property .stnd-code-block Styled code block container with copy button and inset shadows.
9
+ * @property .copy-button Floating copy action button inside code blocks.
10
+ * @property pre Preformatted code block with compact leading and hover transitions.
11
+ * @property .token.keyword Keywords and control-flow statements (`--color-red`).
12
+ * @property .token.string Quoted strings and attribute values (`--color-green`).
13
+ * @property .token.number Numeric literals and boolean values (`--color-cyan`).
14
+ * @property .token.function Function declarations and method invocations (`--color-yellow`).
15
+ * @property .token.property Object keys and CSS property names (`--color-orange`).
16
+ * @property .token.punctuation Brackets, parens, delimiters, and operators (`--color-muted`).
17
+ * @property .token.comment Code comments rendered in muted italic typography (`--color-subtle`).
18
+ * @property .language-* Per-language syntax overrides for YAML, Markdown, Shell/Bash, and Nunjucks.
19
+ *
20
+ * @example html - Standard code block with copy button
21
+ * <div class="stnd-code-block">
22
+ * <button class="copy-button">Copy</button>
23
+ * <pre><code class="language-bash">npm install @stnd/core</code></pre>
24
+ * </div>
25
+ */
26
+
27
+ /* =========================== */
28
+ /* CODE BLOCK CONTAINER */
29
+ /* =========================== */
30
+
31
+ .stnd-code-block {
32
+ position: relative;
33
+ background: var(--color-surface);
34
+ border-radius: var(--radius-sm);
35
+ box-shadow: var(--shadow-inset), var(--shadow-ring);
36
+ transition: all var(--transition);
37
+
38
+ pre {
39
+ padding: var(--space);
40
+ background: transparent;
41
+ box-shadow: none;
42
+ border: none;
43
+ margin: var(--stroke-width);
44
+ overflow-x: auto;
45
+ position: static;
46
+ }
47
+
48
+ &:hover .copy-button {
49
+ opacity: 1;
50
+ }
51
+ }
52
+
53
+ .copy-button {
54
+ position: absolute;
55
+ top: var(--leading);
56
+ right: var(--leading);
57
+ opacity: 0;
58
+
59
+ &:hover {
60
+ opacity: 1 !important;
61
+ color: var(--color-on-accent);
62
+ background-color: var(--color-accent);
63
+ }
64
+
65
+ &.copied {
66
+ color: var(--color-success, #22c55e) !important;
67
+ }
68
+
69
+ &.failed {
70
+ color: var(--color-error, #ef4444) !important;
71
+ }
72
+ }
73
+
74
+ pre {
75
+ line-height: var(--line-height-compact);
76
+
77
+ code {
78
+ opacity: 0.85;
79
+ transition: opacity var(--transition);
80
+ }
81
+
82
+ &:hover code {
83
+ opacity: 1;
84
+ }
85
+ }
4
86
 
5
87
  /* PrismJS syntax highlighting - Language agnostic tokens */
6
88