@anyblades/blades 3.1.0-alpha.2 → 3.1.0-beta.4

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 (93) hide show
  1. package/README.md +48 -23
  2. package/css/blades.css +301 -593
  3. package/css/blades.min.css +4 -148
  4. package/css/blades.ninja.css +4204 -0
  5. package/css/blades.ninja.min.css +12 -0
  6. package/css/float-label.css +207 -0
  7. package/css/float-label.min.css +6 -0
  8. package/css/{pico.layered.css → layered/blades.layered.css} +589 -17
  9. package/css/layered/blades.layered.min.css +14 -0
  10. package/css/layered/compact.css +54 -0
  11. package/css/layered/components/accordion.css +85 -0
  12. package/css/layered/components/card.css +48 -0
  13. package/css/layered/components/dropdown.css +191 -0
  14. package/css/layered/components/group.css +208 -0
  15. package/css/layered/components/loading.css +61 -0
  16. package/css/layered/components/modal.css +158 -0
  17. package/css/layered/components/nav.css +117 -0
  18. package/css/layered/components/progress.css +76 -0
  19. package/css/layered/components/tooltip.css +176 -0
  20. package/css/layered/components.css +1099 -0
  21. package/css/layered/content/button.css +208 -0
  22. package/css/layered/content/code.css +64 -0
  23. package/css/layered/content/embedded-content.css +41 -0
  24. package/css/layered/content/figure.css +15 -0
  25. package/css/layered/content/link.css +84 -0
  26. package/css/layered/content/misc.css +22 -0
  27. package/css/layered/content/table.css +33 -0
  28. package/css/layered/content/typography.css +159 -0
  29. package/css/layered/content.css +611 -0
  30. package/css/layered/forms/basics.css +338 -0
  31. package/css/layered/forms/checkbox-radio-switch.css +164 -0
  32. package/css/layered/forms/input-color.css +20 -0
  33. package/css/layered/forms/input-datetime.css +57 -0
  34. package/css/layered/forms/input-file.css +29 -0
  35. package/css/layered/forms/input-range.css +121 -0
  36. package/css/layered/forms/input-search.css +66 -0
  37. package/css/layered/forms.css +778 -0
  38. package/css/layered/layout/container.css +42 -0
  39. package/css/layered/layout/document.css +48 -0
  40. package/css/layered/layout/grid.css +22 -0
  41. package/css/layered/layout/landmarks.css +12 -0
  42. package/css/layered/layout/overflow-auto.css +9 -0
  43. package/css/layered/layout/section.css +9 -0
  44. package/css/layered/layout.css +119 -0
  45. package/css/layered/utilities.css +35 -0
  46. package/css/layered/variables.css +365 -0
  47. package/css/pico.conditional.css +34 -16
  48. package/css/pico.conditional.min.css +2 -111
  49. package/css/pico.css +34 -16
  50. package/css/pico.min.css +2 -111
  51. package/package.json +16 -12
  52. package/src/blades/_compact.css +51 -0
  53. package/src/blades/_dropdown-popover.css +107 -0
  54. package/src/blades/_index.css +28 -0
  55. package/src/blades/_modal.css +26 -0
  56. package/src/blades/float-label/_index.css +2 -0
  57. package/src/{standalone/forms/_float-label.theme.css → blades/float-label/_theme.css} +5 -1
  58. package/src/blades.css +2 -2
  59. package/src/blades.ninja.css +3 -0
  60. package/src/float-label.css +1 -0
  61. package/src/ninja/LICENSE +22 -0
  62. package/src/ninja/README.md +1 -0
  63. package/src/ninja/_index.css +19 -0
  64. package/src/{standalone → ninja}/_theme.css +0 -2
  65. package/src/{ninja.css → ninja/_utilities.css} +55 -6
  66. package/src/pico/_variables.css +6 -5
  67. package/src/pico/components/_loading.css +27 -1
  68. package/src/pico/content/_button.css +1 -1
  69. package/src/pico/layout/_document.css +9 -0
  70. package/src/pico/layout/_index.css +0 -1
  71. package/src/pico/layout/_landmarks.css +1 -9
  72. package/src/pico.css +1 -0
  73. package/css/blades.standalone.css +0 -860
  74. package/css/blades.standalone.min.css +0 -37
  75. package/css/ninja.css +0 -83
  76. package/css/ninja.min.css +0 -5
  77. package/css/pico.layered.min.css +0 -118
  78. package/src/blades.standalone.css +0 -2
  79. package/src/standalone/_core.css +0 -32
  80. package/src/standalone/_utilities.css +0 -55
  81. package/src/standalone/forms/_float-label.css +0 -2
  82. /package/src/{standalone/content → blades}/_code.css +0 -0
  83. /package/src/{standalone/layout → blades}/_columns.css +0 -0
  84. /package/src/{standalone/components/_icon-helper.css → blades/_icon.css} +0 -0
  85. /package/src/{standalone/components → blades}/_timeline.css +0 -0
  86. /package/src/{standalone → blades}/_variables.css +0 -0
  87. /package/src/{standalone/forms/_float-label.core.css → blades/float-label/_core.css} +0 -0
  88. /package/src/{standalone/layout/_breakout.css → ninja/_container-breakout.css} +0 -0
  89. /package/src/{standalone/content/_typography.css → ninja/_heading-anchor.css} +0 -0
  90. /package/src/{standalone/content/_list.css → ninja/_list-helpers.css} +0 -0
  91. /package/src/{standalone/layout/_scroller.css → ninja/_page-anchors.css} +0 -0
  92. /package/src/{standalone/content/_table.css → ninja/_table-helpers.css} +0 -0
  93. /package/src/{standalone/content → ninja}/_table-responsive.css +0 -0
package/css/blades.css CHANGED
@@ -234,7 +234,8 @@ details summary[role="button"]:not(.outline)::after {
234
234
  --pico-primary-hover-background: light-dark(#02659a, #017fc0);
235
235
  --pico-primary-hover-border: var(--pico-primary-hover-background);
236
236
  --pico-primary-hover-underline: var(--pico-primary-hover);
237
- --pico-primary-focus: light-dark(rgba(2, 154, 232, 0.5), rgba(1, 170, 255, 0.375));
237
+ /* Focus rings are opaque: at 25–50% alpha they composite below 3:1 (SC 1.4.11), see #167 */
238
+ --pico-primary-focus: light-dark(rgb(2, 138, 212), rgb(1, 170, 255));
238
239
  --pico-primary-inverse: #fff;
239
240
  --pico-secondary: light-dark(#5d6b89, #969eaf);
240
241
  --pico-secondary-background: #525f7a;
@@ -244,7 +245,7 @@ details summary[role="button"]:not(.outline)::after {
244
245
  --pico-secondary-hover-background: light-dark(#48536b, #5d6b89);
245
246
  --pico-secondary-hover-border: var(--pico-secondary-hover-background);
246
247
  --pico-secondary-hover-underline: var(--pico-secondary-hover);
247
- --pico-secondary-focus: light-dark(rgba(93, 107, 137, 0.25), rgba(144, 158, 190, 0.25));
248
+ --pico-secondary-focus: light-dark(rgb(93, 107, 137), rgb(144, 158, 190));
248
249
  --pico-secondary-inverse: #fff;
249
250
  --pico-contrast: light-dark(#181c25, #dfe3eb);
250
251
  --pico-contrast-background: light-dark(#181c25, #eff1f4);
@@ -257,7 +258,7 @@ details summary[role="button"]:not(.outline)::after {
257
258
  var(--pico-secondary-hover),
258
259
  var(--pico-contrast-hover)
259
260
  );
260
- --pico-contrast-focus: light-dark(rgba(93, 107, 137, 0.25), rgba(207, 213, 226, 0.25));
261
+ --pico-contrast-focus: light-dark(rgb(93, 107, 137), rgb(207, 213, 226));
261
262
  --pico-contrast-inverse: light-dark(#fff, #000);
262
263
  --pico-box-shadow: 0 0.5rem 2.5rem light-dark(rgba(129, 145, 181, 0.2), rgba(7, 8.5, 12, 0.2));
263
264
  --pico-h1-color: light-dark(#2d3138, #f0f1f3);
@@ -291,11 +292,11 @@ details summary[role="button"]:not(.outline)::after {
291
292
  --pico-form-element-disabled-opacity: 0.5;
292
293
  --pico-form-element-invalid-border-color: light-dark(
293
294
  rgb(183.5, 105.5, 106.5),
294
- rgb(149.5, 74, 80)
295
+ rgb(200.25, 79.25, 72.25)
295
296
  );
296
297
  --pico-form-element-invalid-active-border-color: light-dark(
297
298
  rgb(200.25, 79.25, 72.25),
298
- rgb(183.25, 63.5, 59)
299
+ rgb(214, 92, 86)
299
300
  );
300
301
  --pico-form-element-invalid-focus-color: var(--pico-form-element-invalid-active-border-color);
301
302
  --pico-form-element-valid-border-color: light-dark(rgb(76, 154.5, 137.5), #2a7b6f);
@@ -406,9 +407,6 @@ progress,
406
407
  tab-size: 4;
407
408
  }
408
409
 
409
- /**
410
- * Landmarks
411
- */
412
410
  body {
413
411
  width: 100%;
414
412
  margin: 0;
@@ -418,12 +416,6 @@ main {
418
416
  display: block;
419
417
  }
420
418
 
421
- body > header,
422
- body > main,
423
- body > footer {
424
- padding-block: var(--pico-block-spacing-vertical);
425
- }
426
-
427
419
  /**
428
420
  * Section
429
421
  */
@@ -767,7 +759,7 @@ button,
767
759
  background-color: var(--pico-background-color);
768
760
  box-shadow: var(--pico-box-shadow);
769
761
  color: var(--pico-color);
770
- font-weight: var(--pico-font-weight);
762
+ font-weight: var(--pico-button-font-weight, var(--pico-font-weight));
771
763
  font-size: 1rem;
772
764
  line-height: var(--pico-line-height);
773
765
  text-align: center;
@@ -2411,7 +2403,11 @@ label > details.dropdown {
2411
2403
  --pico-loading-spinner-opacity: 0.5;
2412
2404
  }
2413
2405
 
2414
- [aria-busy="true"]:not(input, select, textarea, html, form) {
2406
+ [aria-busy="true"]:not(input, select, textarea, html, form):not(
2407
+ :where(button, [type="submit"], [type="button"], [type="reset"], [role="button"])
2408
+ ) {
2409
+ /* :where() zeroes the specificity of the button list inside :not(), so this rule stays
2410
+ * low-specificity and doesn't override the more specific button rules below */
2415
2411
  white-space: nowrap;
2416
2412
  }
2417
2413
  [aria-busy="true"]:not(input, select, textarea, html, form)::before {
@@ -2440,6 +2436,19 @@ a[aria-busy="true"] {
2440
2436
  pointer-events: none;
2441
2437
  }
2442
2438
 
2439
+ /* Buttons keep their size: the label stays in place but hidden, the spinner sits on top */
2440
+ button[aria-busy="true"]:not(:empty), [type="submit"][aria-busy="true"]:not(:empty), [type="button"][aria-busy="true"]:not(:empty), [type="reset"][aria-busy="true"]:not(:empty), [role="button"][aria-busy="true"]:not(:empty) {
2441
+ position: relative;
2442
+ color: transparent;
2443
+ }
2444
+ button[aria-busy="true"]:not(:empty) > *, [type="submit"][aria-busy="true"]:not(:empty) > *, [type="button"][aria-busy="true"]:not(:empty) > *, [type="reset"][aria-busy="true"]:not(:empty) > *, [role="button"][aria-busy="true"]:not(:empty) > * {
2445
+ opacity: 0;
2446
+ }
2447
+ button[aria-busy="true"]:not(:empty)::before, [type="submit"][aria-busy="true"]:not(:empty)::before, [type="button"][aria-busy="true"]:not(:empty)::before, [type="reset"][aria-busy="true"]:not(:empty)::before, [role="button"][aria-busy="true"]:not(:empty)::before {
2448
+ position: absolute;
2449
+ margin: auto;
2450
+ inset: 0;
2451
+ }
2443
2452
  /**
2444
2453
  * Modal (<dialog>)
2445
2454
  */
@@ -3021,135 +3030,6 @@ progress::-moz-progress-bar {
3021
3030
 
3022
3031
  /* Layout */
3023
3032
 
3024
- /*
3025
- \3c !--section:code-->
3026
- ```css */
3027
- .breakout,
3028
- .breakout-all {
3029
- max-width: calc(10% + 65ch + 10%);
3030
- /* Prepare the container for breakout elements */
3031
- padding-inline: 10%;
3032
- }
3033
- @media (width < 768px) {
3034
- .breakout,
3035
- .breakout-all {
3036
- max-width: calc(1rem + 65ch + 1rem);
3037
- padding-inline: 1rem
3038
- }
3039
- }
3040
- /* Breakout direct children only */
3041
- .breakout > *:is(
3042
- table,
3043
- pre,
3044
- figure, video, iframe, canvas,
3045
- img, picture,
3046
-
3047
- .breakout-item,
3048
- .breakout-item-max
3049
- ),
3050
- .breakout-all > *:is(
3051
- table,
3052
- pre,
3053
- figure, video, iframe, canvas,
3054
- img, picture,
3055
-
3056
- .breakout-item,
3057
- .breakout-item-max
3058
- ) {
3059
- width: -moz-fit-content;
3060
- width: fit-content;
3061
- min-width: 100%;
3062
- max-width: min(125%, 100dvw);
3063
- margin-left: 50%;
3064
- transform: translateX(-50%);
3065
- }
3066
- /* Respect img/picture min-width */
3067
- .breakout > *:is(img, picture):not(.does-not-exist), .breakout-all > *:is(img, picture):not(.does-not-exist) /* soft win specificity over .breakout-item above */ {
3068
- min-width: auto;
3069
- }
3070
- /* Max out the width of the element */
3071
- .breakout > *.breakout-item-max, .breakout-all > *.breakout-item-max {
3072
- width: min(125%, 100dvw) !important;
3073
- /* !important is for cases like figure.breakout-item-max @TODO */
3074
- }
3075
-
3076
- .breakout-all > *:is(h2, h3, h4, h5, h6, hr):not([class]) {
3077
- position: relative;
3078
- }
3079
-
3080
- .breakout-all > *:is(h2, h3, h4, h5, h6, hr):not([class])::before {
3081
- display: block;
3082
- position: absolute;
3083
- background: gray;
3084
- content: "";
3085
- opacity: 12.5%;
3086
- }
3087
-
3088
- .breakout-all > *:is(h2, h3, h4, h5, h6):not([class])::before {
3089
- top: 50%;
3090
- right: 100%;
3091
- width: 10em;
3092
- height: 0.25em;
3093
- margin-right: 0.8ch;
3094
- transform: translateY(-50%);
3095
- background: linear-gradient(to left, gray, transparent);
3096
- }
3097
-
3098
- /* @TODO: add to tricks-wiki why `*` works here, but `&` fails */
3099
-
3100
- .breakout-all > *:is(h2, h3, h4, h5, h6):not([class]):where(hr:not([class]) + *)::before {
3101
- display: none !important;
3102
- }
3103
-
3104
- .breakout-all > *:is(hr):not([class]) {
3105
- height: 0.5rem;
3106
- overflow: visible;
3107
- border: none;
3108
- }
3109
-
3110
- .breakout-all > *:is(hr):not([class])::before {
3111
- left: 50%;
3112
- width: 100dvw;
3113
- height: 100%;
3114
- transform: translateX(-50%);
3115
- }
3116
- /*```
3117
- \3c !--section:docs-->
3118
-
3119
- The `.breakout` layout allows images, tables, and other figures to automatically extend or bleed beyond their parent container’s width.
3120
-
3121
- Break out a wide image from the text flow:
3122
-
3123
- <div>\3c !-- Dummy div to avoid p tag in Markdown --></div><img
3124
- src="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='3000' height='300'><rect width='100%' height='100%' fill='gray'/></svg>">
3125
-
3126
- Or table:
3127
-
3128
- | Imagine<hr> | a<hr> | really<hr> | wide<hr> | table<hr> | here<hr> |
3129
- | ----------- | ----- | ---------- | -------- | --------- | -------- |
3130
- | ... |
3131
-
3132
- Or code block:
3133
-
3134
- ```html
3135
- <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quod. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quod.</p>
3136
- ```
3137
-
3138
- Or anything else:
3139
-
3140
- <article class="breakout-item-max" data-theme="dark">
3141
-
3142
- Using `.breakout-item` and `.breakout-item-max` helpers {style=margin:0}
3143
- </article>
3144
-
3145
- <div><hr></div>
3146
-
3147
- `.breakout-all` also visually breaks out headings and horizontal rules:
3148
-
3149
- <h2>Heading 2</h2><h3>Heading 3</h3><h4>Heading 4</h4><h5>Heading 5</h5><h6>Heading 6</h6>
3150
- <hr>
3151
-
3152
- \3c !--section--> */
3153
3033
  /*\3c !--section:docs-->
3154
3034
 
3155
3035
  `.columns` automatically creates columns with at least 30 characters each:
@@ -3177,250 +3057,9 @@ Useful for tables of contents and long lists.
3177
3057
  -moz-column-break-inside: avoid;
3178
3058
  break-inside: avoid;
3179
3059
  }
3180
- /*```\3c !--section:docs-->
3181
-
3182
- `<a href="#top">` is automatically fixed to the bottom-right corner with extra top padding for easier clicking:
3183
- ```css */
3184
- [href="#top"] {
3185
- position: fixed;
3186
- right: 0;
3187
- bottom: 0;
3188
- padding-top: 50vh;
3189
- }
3190
3060
  /* Content */
3191
3061
  /*\3c !--section:docs-->
3192
3062
 
3193
- ## Heading anchors
3194
-
3195
- Links with `href="#..."` inside headings are automatically displayed as anchors:
3196
-
3197
- <article>
3198
- <h2 style="margin: 0 0 0 1.5rem">Heading with anchor <a aria-hidden="true" style="visibility: visible">#</a></h2>
3199
- </article>
3200
-
3201
- How it works:
3202
- ```css */
3203
- h1,
3204
- h2,
3205
- h3,
3206
- h4,
3207
- h5,
3208
- h6 {
3209
- position: relative;
3210
- }
3211
- h1 a[aria-hidden="true"], h2 a[aria-hidden="true"], h3 a[aria-hidden="true"], h4 a[aria-hidden="true"], h5 a[aria-hidden="true"], h6 a[aria-hidden="true"] {
3212
- visibility: hidden;
3213
- position: absolute;
3214
- top: 50%;
3215
- right: 100%;
3216
- padding-right: 0.2ch;
3217
- transform: translateY(-50%);
3218
- color: silver;
3219
- text-decoration: none;
3220
- }
3221
- @media /* to avoid double-tap on touch devices */ (hover: hover) {
3222
- h1:hover a[aria-hidden="true"], h2:hover a[aria-hidden="true"], h3:hover a[aria-hidden="true"], h4:hover a[aria-hidden="true"], h5:hover a[aria-hidden="true"], h6:hover a[aria-hidden="true"] {
3223
- visibility: visible;
3224
- }
3225
- }
3226
- /*\3c !--section:docs-->
3227
-
3228
- ## Custom markers
3229
-
3230
- Customize markers using inline `style="--list-marker:..."` on `<ul>/<ol>` or even individual `<li>`:
3231
-
3232
- <article>
3233
-
3234
- - you
3235
- - can
3236
- - make
3237
- - really
3238
- - cool markers {style="--list-marker:'🧊 '"}
3239
- - with
3240
- - *Bl*ades {style="--list-marker:'🥷 '"}
3241
-
3242
- {style="--list-marker:'→ '"}
3243
- </article>
3244
-
3245
- How it works:
3246
- ```css */
3247
- ul[style*="--list-marker:"], ol[style*="--list-marker:"] {
3248
- list-style-type: var(--list-marker);
3249
- }
3250
- ul[style*="--list-marker:"] > li, ol[style*="--list-marker:"] > li {
3251
- list-style-type: inherit;
3252
- }
3253
- ul li[style*="--list-marker:"], ol li[style*="--list-marker:"] {
3254
- list-style-type: var(--list-marker);
3255
- }
3256
- ul li[data-marker]::marker, ol li[data-marker]::marker {
3257
- content: attr(data-marker) " "; /* ⚠️ Chrome and Firefox only */
3258
- }
3259
- /*```
3260
-
3261
- ## Markerless
3262
-
3263
- `.markerless` removes markers and reduces padding:
3264
-
3265
- <article>
3266
-
3267
- - 1️⃣ so you can use
3268
- - 2️⃣ emojis or images
3269
- - 3️⃣ instead of bullets
3270
-
3271
- {.markerless}
3272
- </article>
3273
-
3274
- How it works:
3275
- ```css */
3276
- ul.markerless, ol.markerless {
3277
- padding-inline-start: 1.25rem;
3278
- }
3279
- ul.markerless li, ol.markerless li {
3280
- list-style: none;
3281
- }
3282
- /*```
3283
-
3284
- ## Unlist
3285
-
3286
- `.unlist` removes list styling at all:
3287
-
3288
- <article>
3289
-
3290
- - One: <article>1</article>
3291
- - Two: <article>2</article>
3292
- - Three: <article>3</article>
3293
-
3294
- {.unlist .grid style=margin:0}
3295
- </article>
3296
-
3297
- `.unlist-all` removes styling from all nested lists too.
3298
-
3299
- How it works:
3300
- ```css */
3301
- ul.unlist,
3302
- ul.unlist-all,
3303
- .unlist-all ul,
3304
- ol.unlist,
3305
- ol.unlist-all,
3306
- .unlist-all ol {
3307
- padding-inline-start: 0;
3308
- }
3309
- ul.unlist > li, ul.unlist-all > li, .unlist-all ul > li, ol.unlist > li, ol.unlist-all > li, .unlist-all ol > li {
3310
- list-style: none;
3311
- }
3312
- /*\3c !--section:docs-->
3313
-
3314
- ## Column expanders
3315
-
3316
- Place `<hr>` element inside `<th>` column to expand it horizontally:
3317
-
3318
- <article>
3319
-
3320
- | Column with `<hr>`<hr> | Same column without `<hr>` | ... {style=width:100%} |
3321
- | --- | --- | --- |
3322
- | (012) 345-6789 | (012) 345-6789 |
3323
- </article>
3324
-
3325
- Living examples of big tables with `<hr>`-expanders: \3c !--A-Z-->
3326
- - https://blades.ninja/ai/ide/
3327
- - https://blades.ninja/build-awesome-11ty/starters/
3328
- - https://blades.ninja/css/frameworks/
3329
- - https://blades.ninja/ssg/
3330
-
3331
- How it works:
3332
- ```css */
3333
- th hr {
3334
- visibility: hidden;
3335
- width: 12ch; /* min ~65/12 = ~5 cols */
3336
- height: 0;
3337
- margin: 0;
3338
- }
3339
- th hr.lg {
3340
- width: 18ch;
3341
- }
3342
- th hr.x2 {
3343
- width: 24ch;
3344
- }
3345
- /*```
3346
-
3347
- ## Borderless table
3348
-
3349
- `.borderless` removes all default borders:
3350
-
3351
- <article>
3352
-
3353
- | Less | borders |
3354
- | ---- | ------- |
3355
- | More | fun |
3356
-
3357
- {.borderless}
3358
- </article>
3359
-
3360
- \3c !--section-->*/
3361
- table.borderless th,
3362
- table.borderless td {
3363
- border: none;
3364
- }
3365
- /*
3366
- \3c !--section:code-->
3367
- ```css */
3368
- table.responsive,
3369
- .breakout > table:not(.does-not-exist),
3370
- .breakout-all > table:not(.does-not-exist) {
3371
-
3372
- /* Let them scroll */
3373
- display: block;
3374
-
3375
- /* Let them full-bleed */
3376
- width: -moz-max-content;
3377
- width: max-content;
3378
- min-width: auto;
3379
- max-width: 100dvw;
3380
- /* Center horizontally */
3381
- margin-left: 50%;
3382
- padding-inline: 7.5%;
3383
- overflow-x: auto;
3384
- transform: translateX(-50%);
3385
- -webkit-overflow-scrolling: touch; /* Smooth scroll for iOS */
3386
- }
3387
- table.responsive th,
3388
- table.responsive td,
3389
- .breakout > table:not(.does-not-exist) th,
3390
- .breakout > table:not(.does-not-exist) td,
3391
- .breakout-all > table:not(.does-not-exist) th,
3392
- .breakout-all > table:not(.does-not-exist) td {
3393
- padding-inline-start: 0;
3394
- }
3395
- /*```
3396
- `table:not(.does-not-exist)` trick (inspired by postcss) is used here to increase specificity against selectors like `&:is(table, .table)`
3397
-
3398
- \3c !--section:summary-->
3399
-
3400
- `.responsive` makes a table full-bleed and scroll on mobile, without a need for a redundant wrapper (finally).
3401
- Tables inside https://blades.ninja/css/breakout/ are responsive by default.
3402
-
3403
- \3c !--section:docs-->
3404
-
3405
- ### Demo table
3406
-
3407
- | Term | Description <hr class="x2"> | Link |
3408
- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
3409
- | Responsive design | Approach to web design that aims to make web pages render well on a variety of devices and window or screen sizes from minimum to maximum display size to ensure usability and satisfaction. | https://en.wikipedia.org/wiki/Responsive_web_design |
3410
-
3411
- {.responsive}
3412
-
3413
- ---
3414
-
3415
- Living examples: \3c !--A-Z-->
3416
- - https://blades.ninja/ai/ide/
3417
- - https://blades.ninja/build-awesome-11ty/starters/
3418
- - https://blades.ninja/css/frameworks/
3419
- - https://blades.ninja/ssg/
3420
-
3421
- \3c !--section--> */
3422
- /*\3c !--section:docs-->
3423
-
3424
3063
  The `<pre><code>` blocks are Prism-compatible and support captions via `data-caption="..."` attribute:
3425
3064
 
3426
3065
  ```treeview {data-caption="Blades CSS ships:"}
@@ -3551,7 +3190,139 @@ The `:has(*:placeholder-shown:not(:focus))` trick allows this input state inform
3551
3190
  Historically, this was not possible: the float label had to be placed after the input field to be targeted using the `input:focus + label` selector.
3552
3191
 
3553
3192
  */
3193
+ label:has(> span):has(
3194
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3195
+ textarea,
3196
+ select
3197
+ ),
3198
+ .has-float-label {
3199
+
3200
+ /* Enlarged state */
3201
+ }
3202
+ /* Default/fallback state */
3203
+ label:has(> span):has(
3204
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3205
+ textarea,
3206
+ select
3207
+ ) > span,
3208
+ label:has(> span):has(
3209
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3210
+ textarea,
3211
+ select
3212
+ ) label,
3213
+ .has-float-label > span,
3214
+ .has-float-label label {
3215
+ padding-inline-start: calc(1rem + 1px); /* match Pico's padding + border */
3216
+ padding-block-start: 0.25rem;
3217
+ opacity: 75%;
3218
+ transition: all 0.25s;
3219
+ }
3220
+ label:has(> span):has(
3221
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3222
+ textarea,
3223
+ select
3224
+ ) input,
3225
+ label:has(> span):has(
3226
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3227
+ textarea,
3228
+ select
3229
+ ) textarea,
3230
+ label:has(> span):has(
3231
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3232
+ textarea,
3233
+ select
3234
+ ) select,
3235
+ .has-float-label input,
3236
+ .has-float-label textarea,
3237
+ .has-float-label select {
3238
+ margin-block-start: 0; /* reset Pico */
3239
+ padding-inline-start: 1rem; /* match Pico */
3240
+ padding-block: 1.125rem 0.375rem; /* match Pico's total: 2 x 0.75rem = 1.5rem */
3241
+ }
3242
+ label:has(> span):has(
3243
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3244
+ textarea,
3245
+ select
3246
+ ) input::-moz-placeholder, label:has(> span):has(
3247
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3248
+ textarea,
3249
+ select
3250
+ ) textarea::-moz-placeholder, label:has(> span):has(
3251
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3252
+ textarea,
3253
+ select
3254
+ ) select::-moz-placeholder, .has-float-label input::-moz-placeholder, .has-float-label textarea::-moz-placeholder, .has-float-label select::-moz-placeholder {
3255
+ opacity: 100%;
3256
+ -moz-transition: all 0.25s;
3257
+ transition: all 0.25s;
3258
+ }
3259
+ label:has(> span):has(
3260
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3261
+ textarea,
3262
+ select
3263
+ ) input::placeholder, label:has(> span):has(
3264
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3265
+ textarea,
3266
+ select
3267
+ ) textarea::placeholder, label:has(> span):has(
3268
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3269
+ textarea,
3270
+ select
3271
+ ) select::placeholder, .has-float-label input::placeholder, .has-float-label textarea::placeholder, .has-float-label select::placeholder {
3272
+ opacity: 100%;
3273
+ transition: all 0.25s;
3274
+ }
3275
+ label:has(> span):has(
3276
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3277
+ textarea,
3278
+ select
3279
+ ):has(*:-moz-placeholder:not(:focus)) > span, label:has(> span):has(
3280
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3281
+ textarea,
3282
+ select
3283
+ ):has(*:-moz-placeholder:not(:focus)) label, .has-float-label:has(*:-moz-placeholder:not(:focus)) > span, .has-float-label:has(*:-moz-placeholder:not(:focus)) label {
3284
+ padding-block: 0.75rem; /* match Pico */
3285
+ }
3286
+ label:has(> span):has(
3287
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3288
+ textarea,
3289
+ select
3290
+ ):has(*:placeholder-shown:not(:focus)) > span,
3291
+ label:has(> span):has(
3292
+ input:not([type="checkbox"], [type="radio"], [type="range"]),
3293
+ textarea,
3294
+ select
3295
+ ):has(*:placeholder-shown:not(:focus)) label,
3296
+ .has-float-label:has(*:placeholder-shown:not(:focus)) > span,
3297
+ .has-float-label:has(*:placeholder-shown:not(:focus)) label {
3298
+ padding-block: 0.75rem; /* match Pico */
3299
+ }
3554
3300
  /* Components */
3301
+ /*\3c !--section:docs-->
3302
+
3303
+ A `<dialog>` opened with `dialog.showModal()` fades in and its `<article>` zooms in, without JS classes.
3304
+ Pico's modal JS (`.modal-is-open`, `.modal-is-opening`, `.modal-is-closing`) still works on top of it.
3305
+
3306
+ - `dialog.close()` closes it at once, as before.
3307
+ - `<dialog open>` in markup and non-modal `dialog.show()` aren't animated.
3308
+ - Browsers without `@starting-style`, and reduced motion, open it at once.
3309
+
3310
+ \3c !--section:code-->```css */
3311
+ dialog:modal {
3312
+ transition: opacity var(--pico-transition);
3313
+ }
3314
+ dialog:modal > article {
3315
+ transition: transform var(--pico-transition);
3316
+ }
3317
+ @starting-style {
3318
+ dialog:modal {
3319
+ opacity: 0;
3320
+ }
3321
+
3322
+ dialog:modal > article {
3323
+ transform: scale(0.96);
3324
+ }
3325
+ }
3555
3326
  /* Extends https://github.com/picocss/pico/blob/main/scss/content/_link.scss
3556
3327
  \3c !--section:code-->
3557
3328
  ```css */
@@ -3611,241 +3382,178 @@ How we made it: https://codepen.io/editor/anydigital/pen/019d2b94-5616-75dc-a23e
3611
3382
  \3c !--section--> */
3612
3383
  /*\3c !--section:docs-->
3613
3384
 
3614
- Use `dl.timeline` or wrap a `<dl>` with `.has-timeline` to style it as a
3615
- vertical timeline — each `<dd>` gets a left border strip acting as the track:
3385
+ A `<ul>` or `<menu>` with the `popover` attribute is styled like a dropdown and opens next to the button
3386
+ that toggles it, with no JS:
3616
3387
 
3617
- <article class="has-timeline">
3618
-
3619
- May 11, 2026
3620
- : First Blades CSS stable release (v2.2.0).
3621
-
3622
- Mar 15, 2025
3623
- : Last Pico CSS update (v2.1.1).
3388
+ ```html
3389
+ <button popovertarget="actions">Actions</button>
3390
+ <ul id="actions" popover>
3391
+ <li><a href="#">Edit</a></li>
3392
+ <li><a href="#">Duplicate</a></li>
3393
+ </ul>
3394
+ ```
3624
3395
 
3625
- </article>
3396
+ - Clicking outside or pressing Esc closes it, and it's drawn on top of everything (no `z-index`, no clipping by `overflow`).
3397
+ - It opens below the button (on the reading side, also in RTL) and flips when there's no room.
3398
+ Open it with `popovertarget`, `commandfor` or `showPopover({ source })`, so it knows its button.
3399
+ - Browsers without CSS anchor positioning show it in the middle of the screen instead, like a plain popover.
3400
+ - It uses the dropdown colours (`--pico-dropdown-*`, from `components/dropdown`).
3626
3401
 
3627
3402
  \3c !--section:code-->```css */
3628
- dl.timeline dd, .has-timeline > dl dd {
3629
- margin-block: 0;
3630
- padding: 0.25rem 0 0.75rem 1rem;
3631
- border-inline-start: 0.25rem solid var(--blades-timeline-border-color);
3632
- }
3633
- /* Utilities */
3634
- /*\3c !--section:docs-->
3635
-
3636
- ## Dark auto
3637
-
3638
- `.dark-auto` automatically creates a simple dark version of any element:
3639
-
3640
- <article data-theme="dark">
3641
- <p>Look how cool <big class="dark-auto">🔥🕷️🐦‍⬛🐄🦓</big> can look in the dark!</p>
3642
- </article>
3643
-
3644
- How it works:
3645
- ```css */
3646
- /* Per https://picocss.com/docs/css-variables#css-variables-for-color-schemes */
3647
- :root {
3648
- --blades-dark-filter: invert(100%) hue-rotate(180deg);
3649
- }
3650
- .dark-auto {
3651
- /* Dark color scheme (Forced) */
3652
- }
3653
- /* Dark color scheme (Auto) */
3654
- @media (prefers-color-scheme: dark) {
3655
- .dark-auto {
3656
- filter: var(--blades-dark-filter)
3657
- }
3658
- }
3659
- .dark-auto[data-theme="dark"],
3660
- .dark-auto:where([data-theme="dark"] *) {
3661
- filter: var(--blades-dark-filter);
3662
- }
3663
- /*```
3664
-
3665
- ## Faded
3666
-
3667
- `.faded` reduces the opacity of an element:
3668
-
3669
- <article class="faded">
3670
- Hover to unfade me!
3671
- </article>
3672
-
3673
- How it works:
3674
- ```css */
3675
- .faded {
3676
- opacity: 50%;
3403
+ :is(ul, menu)[popover] {
3404
+ min-width: -moz-fit-content;
3405
+ min-width: fit-content;
3406
+ margin: auto;
3407
+ padding: 0;
3408
+ border: var(--pico-border-width) solid var(--pico-dropdown-border-color);
3409
+ border-radius: var(--pico-border-radius);
3410
+ background-color: var(--pico-dropdown-background-color);
3411
+ box-shadow: var(--pico-dropdown-box-shadow);
3412
+ color: var(--pico-dropdown-color);
3413
+ white-space: nowrap;
3414
+ opacity: 0;
3415
+ transition:
3416
+ opacity var(--pico-transition),
3417
+ overlay var(--pico-transition) allow-discrete,
3418
+ display var(--pico-transition) allow-discrete;
3677
3419
  }
3678
- .faded:hover {
3679
- opacity: 87.5%;
3680
- }
3681
- /*```
3682
- \3c !--section--> */
3683
-
3684
- /* Fix the scrollbar color when inverted by https://tailwindcss.com/docs/filter-invert */
3685
- .invert ::-webkit-scrollbar {
3686
- filter: invert(1) !important;
3420
+ /* Beats `nav ul` / `aside ul`, which would otherwise show the closed menu */
3421
+ :is(ul, menu)[popover]:not(:popover-open) {
3422
+ display: none;
3687
3423
  }
3688
- /*\3c !--section:code-->```css */
3689
- /* Default/fallback state */
3690
- label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) > span,
3691
- label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) label,
3692
- .has-float-label > span,
3693
- .has-float-label label {
3694
- padding-inline-start: calc(1rem + 1px); /* match Pico's padding + border */
3695
- padding-block-start: 0.25rem;
3696
- opacity: 75%;
3697
- transition: all 0.25s;
3424
+ :is(ul, menu)[popover]:popover-open {
3425
+ display: block;
3426
+ opacity: 1;
3698
3427
  }
3699
- label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) input,
3700
- label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) textarea,
3701
- label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) select,
3702
- .has-float-label input,
3703
- .has-float-label textarea,
3704
- .has-float-label select {
3705
- margin-block-start: 0; /* reset Pico */
3706
- padding-inline-start: 1rem; /* match Pico */
3707
- padding-block: 1.125rem 0.375rem; /* match Pico's total: 2 x 0.75rem = 1.5rem */
3428
+ :is(ul, menu)[popover] li {
3429
+ display: block;
3430
+ margin-bottom: 0;
3431
+ padding: calc(var(--pico-form-element-spacing-vertical) * 0.5)
3432
+ var(--pico-form-element-spacing-horizontal);
3433
+ list-style: none;
3708
3434
  }
3709
- label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) input::-moz-placeholder, label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) textarea::-moz-placeholder, label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) select::-moz-placeholder, .has-float-label input::-moz-placeholder, .has-float-label textarea::-moz-placeholder, .has-float-label select::-moz-placeholder {
3710
- opacity: 100%;
3711
- -moz-transition: all 0.25s;
3712
- transition: all 0.25s;
3435
+ :is(ul, menu)[popover] li:first-of-type {
3436
+ margin-top: calc(var(--pico-form-element-spacing-vertical) * 0.5);
3713
3437
  }
3714
- label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) input::placeholder, label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) textarea::placeholder, label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) select::placeholder, .has-float-label input::placeholder, .has-float-label textarea::placeholder, .has-float-label select::placeholder {
3715
- opacity: 100%;
3716
- transition: all 0.25s;
3438
+ :is(ul, menu)[popover] li:last-of-type {
3439
+ margin-bottom: calc(var(--pico-form-element-spacing-vertical) * 0.5);
3717
3440
  }
3718
- /* Enlarged state */
3719
- label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select):has(*:-moz-placeholder:not(:focus)) > span, label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select):has(*:-moz-placeholder:not(:focus)) label, .has-float-label:has(*:-moz-placeholder:not(:focus)) > span, .has-float-label:has(*:-moz-placeholder:not(:focus)) label {
3720
- padding-block: 0.75rem; /* match Pico */
3441
+ :is(ul, menu)[popover] li:has(label):hover {
3442
+ background-color: var(--pico-dropdown-hover-background-color);
3721
3443
  }
3722
- label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select):has(*:placeholder-shown:not(:focus)) > span,
3723
- label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select):has(*:placeholder-shown:not(:focus)) label,
3724
- .has-float-label:has(*:placeholder-shown:not(:focus)) > span,
3725
- .has-float-label:has(*:placeholder-shown:not(:focus)) label {
3726
- padding-block: 0.75rem; /* match Pico */
3444
+ :is(ul, menu)[popover] li a {
3445
+ display: block;
3446
+ margin: calc(var(--pico-form-element-spacing-vertical) * -0.5)
3447
+ calc(var(--pico-form-element-spacing-horizontal) * -1);
3448
+ padding: calc(var(--pico-form-element-spacing-vertical) * 0.5)
3449
+ var(--pico-form-element-spacing-horizontal);
3450
+ overflow: hidden;
3451
+ border-radius: 0;
3452
+ color: var(--pico-dropdown-color);
3453
+ text-decoration: none;
3454
+ text-overflow: ellipsis;
3455
+ }
3456
+ :is(ul, menu)[popover] li a:is(:hover, :focus, :active, :focus-visible, [aria-current]:not([aria-current="false"])) {
3457
+ background-color: var(--pico-dropdown-hover-background-color);
3727
3458
  }
3728
- html {
3729
- /* Prevent horizontal overflow and scrolling, modern way. */
3730
- overflow-x: clip;
3731
-
3732
- /* Enable font smoothing */
3733
- -webkit-font-smoothing: antialiased;
3734
- -moz-osx-font-smoothing: grayscale;
3735
- }
3736
-
3737
- body {
3738
-
3739
- /* Make the `body` a flex container with column layout, and `main` to automatically fill available space. This is useful for creating sticky footers and full-height layouts. */
3740
- display: flex;
3741
- flex-direction: column;
3742
- /* Ensure `body` takes at least the full height of the viewport (using dynamic viewport height for better mobile support). */
3743
- min-height: 100dvh;
3744
-
3745
- /* Evaluates the last ~4 lines of text blocks to prevent a single word from sitting on the final line. */
3746
-
3747
- /* Enable global hyphenation */
3748
- /* ... except for links and tables which are better (safer) without hyphenation */
3749
- }
3750
-
3751
- body > main {
3752
- flex-grow: 1;
3459
+ :is(ul, menu)[popover] li label {
3460
+ width: 100%;
3753
3461
  }
3754
-
3755
- body {
3756
- hyphens: auto;
3757
- text-wrap: pretty;
3462
+ /* Beats Pico's `nav ul:first-of-type` / `:last-of-type` margins */
3463
+ nav :is(ul, menu)[popover] {
3464
+ margin: auto;
3758
3465
  }
3759
-
3760
- body a,
3761
- body table {
3762
- hyphens: none;
3466
+ @starting-style {
3467
+ :is(ul, menu)[popover]:popover-open {
3468
+ opacity: 0;
3763
3469
  }
3470
+ }
3764
3471
 
3765
- a:not([href^="#"]) {
3766
- text-decoration-thickness: 1px;
3472
+ /* Next to the button that opened it (its implicit anchor) */
3473
+ @supports (position-area: bottom) {
3474
+ :is(ul, menu)[popover],
3475
+ nav :is(ul, menu)[popover] {
3476
+ position-area: bottom span-right;
3477
+ position-try-fallbacks: flip-block, flip-inline;
3478
+ margin: 0;
3479
+ margin-top: var(--pico-outline-width);
3480
+ inset: auto;
3767
3481
  }
3768
3482
 
3769
- a:not([href^="#"]):hover {
3770
- text-decoration-thickness: 2px;
3483
+ :is(ul, menu)[popover]:dir(rtl), nav :is(ul, menu)[popover]:dir(rtl) {
3484
+ position-area: bottom span-left;
3771
3485
  }
3772
-
3773
- h1,
3774
- h2,
3775
- h3,
3776
- h4,
3777
- h5,
3778
- h6 {
3779
- text-wrap: balance;
3780
3486
  }
3781
- h1 {
3782
- margin-bottom: 1rem; /* for tw-typography */
3783
- font-size: 2.5em; /* for pico.css & tw-typography */
3784
- }
3785
-
3786
- hr {
3787
- margin-block: 2em; /* for pico.css & tw-typography */
3788
- }
3789
-
3790
- ul ul {
3791
- font-size: 87.5%;
3792
- }
3793
-
3794
- dl dt {
3795
- margin-block: 0.25rem;
3796
- font-weight: 500;
3797
- }
3487
+ /*\3c !--section:docs-->
3798
3488
 
3799
- dl dd {
3800
- margin-block-end: 1rem;
3801
- }
3489
+ Use `dl.timeline` or wrap a `<dl>` with `.has-timeline` to style it as a
3490
+ vertical timeline — each `<dd>` gets a left border strip acting as the track:
3802
3491
 
3803
- pre small {
3804
- font-weight: lighter;
3805
- opacity: 75%;
3806
- }
3492
+ <article class="has-timeline">
3807
3493
 
3808
- pre:has(code) {
3809
- background: #181c25 !important;
3810
- }
3494
+ May 11, 2026
3495
+ : First Blades CSS stable release (v2.2.0).
3811
3496
 
3812
- table th {
3813
- font-weight: bold;
3814
- vertical-align: bottom;
3815
- }
3497
+ Mar 15, 2025
3498
+ : Last Pico CSS update (v2.1.1).
3816
3499
 
3817
- table td {
3818
- vertical-align: top;
3819
- }
3500
+ </article>
3820
3501
 
3821
- table pre {
3822
- margin-bottom: 0.25rem;
3502
+ \3c !--section:code-->```css */
3503
+ dl.timeline dd, .has-timeline > dl dd {
3504
+ margin-block: 0;
3505
+ padding: 0.25rem 0 0.75rem 1rem;
3506
+ border-inline-start: 0.25rem solid var(--blades-timeline-border-color);
3823
3507
  }
3824
-
3825
- [href="#top"] {
3826
- opacity: 25%;
3508
+ /* Compact version (opt-in via `data-compact` attr anywhere) */
3509
+ /*
3510
+ * Compact: opt-in denser sizing and a more current look, applied under `data-compact` on
3511
+ * <html> (whole page) or on any element such as a single <form>. Without the attribute it
3512
+ * changes nothing. Part of blades.css (and blades.layered.css); with per-part imports, import it
3513
+ * last (in the same layer as the other parts).
3514
+ *
3515
+ * The extra selectors keep the values winning where Pico re-declares them at the same
3516
+ * specificity: nested [data-theme] sections, the `.pico` root when combined with the conditional build,
3517
+ * and a shadow host.
3518
+ */
3519
+ [data-compact],
3520
+ [data-compact] :is([data-theme], .pico),
3521
+ .pico[data-compact],
3522
+ :host([data-compact]),
3523
+ :host([data-compact]) [data-theme] {
3524
+ --pico-border-radius: 0.5rem;
3525
+ --pico-outline-width: 0.1875rem;
3526
+ --pico-block-spacing-vertical: 1.5rem;
3527
+ --pico-block-spacing-horizontal: 1.5rem;
3528
+ --pico-form-element-spacing-vertical: 0.375rem;
3529
+ --pico-form-element-spacing-horizontal: 0.75rem;
3530
+ --pico-form-label-font-weight: 500;
3531
+ --pico-button-font-weight: 500;
3532
+ --pico-form-element-background-color: light-dark(#fff, rgb(28, 33, 43.5));
3533
+ --pico-card-border-color: var(--pico-muted-border-color);
3534
+ --pico-card-box-shadow:
3535
+ 0 0 0 var(--pico-border-width) var(--pico-card-border-color), 0 1px 2px rgba(0, 0, 0, 0.05);
3536
+ --pico-card-sectioning-background-color: var(--pico-card-background-color);
3537
+ }
3538
+
3539
+ /* Search fields keep their pill shape */
3540
+ [data-compact]:is([role="search"], [type="search"]) {
3541
+ --pico-border-radius: 5rem;
3827
3542
  }
3828
3543
 
3829
- [href="#top"]:hover {
3830
- opacity: 75%;
3831
- }
3832
-
3833
- [href="#top"] > i {
3834
- display: inline-block;
3835
- margin: 0.5rem;
3836
- padding: 0.25rem 0.375rem;
3837
- border-color: black;
3838
- color: black;
3839
- font-size: 0.75rem;
3840
- }
3544
+ /* Page-level only: everything is sized in rem, so the root size can't change per element */
3545
+ :root[data-compact],
3546
+ :host([data-compact]) {
3547
+ --pico-font-size: 100%;
3548
+ }
3841
3549
 
3842
- .breakout > img,
3843
- .breakout > figure,
3844
- .breakout-all > img,
3845
- .breakout-all > figure {
3846
- margin-bottom: 1rem;
3847
- }
3550
+ [data-compact] :is(h1, h2, h3, h4, h5, h6),
3551
+ :host([data-compact]) :is(h1, h2, h3, h4, h5, h6) {
3552
+ --pico-font-weight: 600;
3553
+ }
3848
3554
 
3849
- .faded a {
3850
- text-decoration-style: dotted;
3851
- }
3555
+ /* Keep helper text at the normal weight under the 500-weight labels */
3556
+ [data-compact] :where(input, select, textarea, fieldset, .grid) + small,
3557
+ :host([data-compact]) :where(input, select, textarea, fieldset, .grid) + small {
3558
+ font-weight: var(--pico-font-weight);
3559
+ }