@getvitops/generator 2.1.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +411 -0
  2. package/assets/bricks/elements/color-scheme-toggle.php +3 -3
  3. package/assets/bricks/elements/copy-button.php +3 -3
  4. package/assets/bricks/elements/multi-field.php +3 -3
  5. package/assets/css/animation.css +90 -0
  6. package/assets/css/global.css +10 -0
  7. package/assets/css/index.css +5 -0
  8. package/assets/css/layout-utilities.css +46 -0
  9. package/assets/css/layout.css +87 -2
  10. package/assets/css/patterns/anchor-link.css +36 -0
  11. package/assets/css/patterns/code.css +24 -0
  12. package/assets/css/patterns/consent.css +14 -3
  13. package/assets/css/patterns/details.css +28 -16
  14. package/assets/css/patterns/dialog.css +13 -31
  15. package/assets/css/patterns/drawer.css +27 -66
  16. package/assets/css/patterns/dropdown.css +15 -1
  17. package/assets/css/patterns/lightbox.css +3 -3
  18. package/assets/css/patterns/marquee.css +33 -5
  19. package/assets/css/patterns/nav.css +27 -79
  20. package/assets/css/patterns/navbar.css +86 -0
  21. package/assets/css/patterns/navshell.css +383 -0
  22. package/assets/css/patterns/popover.css +56 -8
  23. package/assets/css/patterns/scroll-target.css +18 -4
  24. package/assets/css/patterns/sitenav.css +253 -408
  25. package/assets/css/patterns/split-link.css +3 -3
  26. package/assets/css/patterns/tree.css +118 -8
  27. package/assets/js/consent.js +1 -1
  28. package/assets/js/elements.js +26 -26
  29. package/{site.schema.json → config.schema.json} +2364 -2264
  30. package/dist/index.d.mts +1269 -541
  31. package/dist/index.d.mts.map +1 -1
  32. package/dist/index.mjs +4542 -3010
  33. package/dist/index.mjs.map +1 -1
  34. package/package.json +5 -5
@@ -17,10 +17,32 @@
17
17
  * OR click (native `[open]` pins it). Top-level submenus drop below their item;
18
18
  * deeper (megamenu) submenus fly out to the inline-end side.
19
19
  *
20
- * `.sitenav__disclosure` is `display: contents` so the `<summary>` (caret) and the
21
- * submenu `<ul>` participate directly in the branch item's grid — that is what lets
22
- * the caret sit inline with the link while the submenu spans full width on its own
23
- * row. Native `[open]` toggling is unaffected by `display: contents`.
20
+ * The `<details>` is grid-placed at column 2 and the submenu `<ul>` is its SIBLING,
21
+ * a real grid child of the branch item — that is what lets the caret sit inline with
22
+ * the link while the submenu spans full width on its own row.
23
+ *
24
+ * ── TWO BRANCHES, NOT BASE-PLUS-OVERRIDE ──
25
+ *
26
+ * `@container` contributes ZERO specificity, so a rule inside the wide block competes
27
+ * at its bare selector weight. A bare `.sitenav--drawer-end .sitenav__panel` (0,2,0)
28
+ * therefore beat the wide block's `.sitenav__panel` (0,1,0) reset *in the wide state*:
29
+ * the promoted navbar shipped translated a full panel-width off-screen, and the
30
+ * accordion's `overflow: hidden` clipped away every third-level megamenu. Before the
31
+ * four per-breakpoint blocks were folded into one style query, those resets carried a
32
+ * `.sitenav--bp-*` class and won the tie on source order; folding them removed it.
33
+ *
34
+ * So the rule is: **a narrow-state rule that is MORE SPECIFIC than its wide-state
35
+ * counterpart lives inside `@container style(--_sitenav-wide: 0)`.** Rules at (0,1,0)
36
+ * — the panel's box, the lists, the links — stay unscoped, because that same work is
37
+ * what neutralises the UA `[popover]` sheet, which applies in BOTH states; scoping it
38
+ * would mean writing it twice. `src/css/state-branch.test.ts` asserts the invariant.
39
+ *
40
+ * Both branches read an INHERITED flag, so every part must live inside `.sitenav`,
41
+ * which declares it. Note the file mixes two unnamed query kinds that resolve against
42
+ * DIFFERENT containers: `style()` against the nearest ancestor ELEMENT (every element
43
+ * is a style container — no `container-type` needed, and it resolves for a panel
44
+ * promoted to the top layer), the `(min-width:)` queries below against `body`
45
+ * (layout.css). That asymmetry is why the flag has to be a custom property.
24
46
  *
25
47
  * Per-breakpoint depth caps come pre-resolved from PHP as item classes:
26
48
  * `.sitenav__item--desktop-branch` — caret + submenu shown only ≥ breakpoint;
@@ -30,6 +52,10 @@
30
52
 
31
53
  /* ── Container + mobile chrome ─────────────────────────────────────────────── */
32
54
  .sitenav {
55
+ /* Reset first — the flag inherits, so a nested sitenav must resolve against
56
+ itself rather than an outer instance's promoted state. */
57
+ --_sitenav-wide: 0;
58
+
33
59
  display: flex;
34
60
  align-items: center;
35
61
  }
@@ -71,6 +97,19 @@
71
97
  inset-block: 0;
72
98
  inline-size: min(100dvw, var(--sitenav-drawer-size, 20rem));
73
99
  max-inline-size: 100dvw;
100
+
101
+ /* The UA `[popover]` sheet supplies `margin: auto` and `height: fit-content`, and
102
+ neither was being undone — so `inset-block: 0` bought nothing and the "drawer"
103
+ rendered as a content-height card floating in the vertical centre, while at
104
+ width the auto margins absorbed the free space of any stretched `.sitenav`.
105
+ `drawer.css` resets margin for exactly this reason; this panel doesn't compose
106
+ it. Both live in the base block because the UA sheet applies in BOTH states:
107
+ against `position: fixed` + `inset-block: 0` an auto block-size stretches to
108
+ the drawer's full height, and against the wide branch's `position: static` the
109
+ same declaration sizes the navbar to its content. */
110
+ margin: 0;
111
+ block-size: auto;
112
+
74
113
  padding: 1.5rem;
75
114
  padding-block-start: 3.5rem; /* clearance for the close button */
76
115
  background: var(--color-bg-surface);
@@ -102,30 +141,42 @@
102
141
  }
103
142
  }
104
143
 
105
- /* Slide from the chosen edge (default inline-end). */
106
- .sitenav--drawer-end .sitenav__panel {
107
- inset-inline-end: 0;
108
- inset-inline-start: auto;
109
- translate: 100% 0;
110
- }
111
- .sitenav--drawer-start .sitenav__panel {
112
- inset-inline-start: 0;
113
- inset-inline-end: auto;
114
- translate: -100% 0;
115
- }
116
- .sitenav__panel:popover-open {
117
- opacity: 1;
118
- translate: 0 0;
119
- }
120
- @starting-style {
121
- .sitenav--drawer-end .sitenav__panel:popover-open {
122
- opacity: 0;
144
+ /* ── Drawer geometry + transition — NARROW ONLY ─────────────────────────────
145
+ Scoped rather than bare because these are (0,2,0)/(0,3,0) and would outrank the
146
+ wide block's (0,1,0) panel reset. `:popover-open` and the `@starting-style`
147
+ pair are one transition system with the edge modifiers, so they travel with
148
+ them: both are inert at width only by coincidence (the panel is always
149
+ displayed there, and their values happen to match the reset's), which is the
150
+ same shape of accident as the bug itself. ── */
151
+ @container style(--_sitenav-wide: 0) {
152
+ /* Slide from the chosen edge (default inline-end). The insets also undo the UA
153
+ `[popover] { inset: 0 }`; the wide branch does that job with `inset: auto`. */
154
+ .sitenav--drawer-end .sitenav__panel {
155
+ inset-inline-end: 0;
156
+ inset-inline-start: auto;
123
157
  translate: 100% 0;
124
158
  }
125
- .sitenav--drawer-start .sitenav__panel:popover-open {
126
- opacity: 0;
159
+ .sitenav--drawer-start .sitenav__panel {
160
+ inset-inline-start: 0;
161
+ inset-inline-end: auto;
127
162
  translate: -100% 0;
128
163
  }
164
+
165
+ .sitenav__panel:popover-open {
166
+ opacity: 1;
167
+ translate: 0 0;
168
+ }
169
+
170
+ @starting-style {
171
+ .sitenav--drawer-end .sitenav__panel:popover-open {
172
+ opacity: 0;
173
+ translate: 100% 0;
174
+ }
175
+ .sitenav--drawer-start .sitenav__panel:popover-open {
176
+ opacity: 0;
177
+ translate: -100% 0;
178
+ }
179
+ }
129
180
  }
130
181
 
131
182
  /* ── Lists + links ─────────────────────────────────────────────────────────── */
@@ -163,31 +214,7 @@
163
214
  font-style: italic;
164
215
  }
165
216
 
166
- /* ── Branch item — mobile accordion ────────────────────────────────────────
167
- The item is a grid: [link | caret] on row 1, the submenu spanning row 2. The
168
- <details> holds only the caret <summary>; the submenu <ul> is its sibling and a
169
- real grid child of the item. The row-2 track animates 0fr→1fr when the details is
170
- open (the classic no-JS accordion, driven by `:has`), so the submenu pushes the
171
- content below rather than overlaying it. */
172
- .sitenav__item--branch {
173
- display: grid;
174
- grid-template-columns: 1fr auto;
175
- grid-template-rows: auto 0fr;
176
- align-items: center;
177
- column-gap: 0.5rem;
178
- transition: grid-template-rows 0.25s ease;
179
- }
180
-
181
- .sitenav__item--branch > .split-link__link {
182
- grid-column: 1;
183
- grid-row: 1;
184
- }
185
-
186
- /* <details> is only the caret; keep its box out of the flow's height. */
187
- .sitenav__disclosure {
188
- grid-column: 2;
189
- grid-row: 1;
190
- }
217
+ /* ── Branch item — the two rules both presentations share ──────────────────── */
191
218
 
192
219
  /* The <summary>. `.split-link__toggle` supplies the flush look, hover + focus, and
193
220
  the caret transition; only the disclosure-marker reset is added here. */
@@ -200,383 +227,201 @@
200
227
  }
201
228
  }
202
229
 
203
- .sitenav__item--branch > .sitenav__submenu {
204
- grid-column: 1 / -1;
205
- grid-row: 2;
206
- /* Stretch to the row-2 track (not content-sized) so the 0fr collapsed state
207
- actually clips to 0 — the item's own align-self must beat the grid's
208
- `align-items: center`, or overflow:hidden has nothing to clip against. */
209
- align-self: stretch;
210
- min-block-size: 0;
211
- overflow: hidden;
212
- padding-inline-start: 1rem;
213
- }
214
-
215
- .sitenav__item--branch:has(> .sitenav__disclosure[open]) {
216
- grid-template-rows: auto 1fr;
217
- }
218
-
219
- /* Caret flips while the disclosure is open (summary carries no aria-expanded). */
230
+ /* Caret flips while the disclosure is open (summary carries no aria-expanded).
231
+ Unscoped: at width the same native `[open]` pins a dropdown, so the flip is
232
+ wanted in both states. */
220
233
  .sitenav__disclosure[open] > .sitenav__subtoggle .split-link__caret {
221
234
  rotate: 180deg;
222
235
  }
223
236
 
224
- /* Depth cap (mobile side): a desktop-only branch shows just its parent link. */
225
- .sitenav__item--desktop-branch > .sitenav__disclosure,
226
- .sitenav__item--desktop-branch > .sitenav__submenu {
227
- display: none;
228
- }
237
+ /* ── Mobile accordion — NARROW ONLY ─────────────────────────────────────────
238
+ The item is a grid: [link | caret] on row 1, the submenu spanning row 2. The
239
+ <details> holds only the caret <summary>; the submenu <ul> is its sibling and a
240
+ real grid child of the item. The row-2 track animates 0fr→1fr when the details is
241
+ open (the classic no-JS accordion, driven by `:has`), so the submenu pushes the
242
+ content below rather than overlaying it.
243
+
244
+ Scoped because these selectors are (0,2,0)/(0,3,0). Most of what is in here is
245
+ inert at width anyway — grid placement on a flex item, `align-self` on an
246
+ absolutely positioned box, `min-block-size: 0` where `auto` already computes to
247
+ 0 — but `overflow: hidden` and `padding-inline-start` are NOT, and leaking them
248
+ into the navbar is what clipped the megamenus. ── */
249
+ @container style(--_sitenav-wide: 0) {
250
+ .sitenav__item--branch {
251
+ display: grid;
252
+ grid-template-columns: 1fr auto;
253
+ grid-template-rows: auto 0fr;
254
+ align-items: center;
255
+ column-gap: 0.5rem;
256
+ transition: grid-template-rows 0.25s ease;
257
+ }
258
+
259
+ .sitenav__item--branch > .split-link__link {
260
+ grid-column: 1;
261
+ grid-row: 1;
262
+ }
263
+
264
+ /* <details> is only the caret; keep its box out of the flow's height. */
265
+ .sitenav__disclosure {
266
+ grid-column: 2;
267
+ grid-row: 1;
268
+ }
269
+
270
+ .sitenav__item--branch > .sitenav__submenu {
271
+ grid-column: 1 / -1;
272
+ grid-row: 2;
273
+ /* Stretch to the row-2 track (not content-sized) so the 0fr collapsed state
274
+ actually clips to 0 — the item's own align-self must beat the grid's
275
+ `align-items: center`, or overflow:hidden has nothing to clip against. */
276
+ align-self: stretch;
277
+ min-block-size: 0;
278
+ overflow: hidden;
279
+ padding-inline-start: 1rem;
280
+ }
281
+
282
+ .sitenav__item--branch:has(> .sitenav__disclosure[open]) {
283
+ grid-template-rows: auto 1fr;
284
+ }
229
285
 
230
- /* ── Desktop promotion — one block per framework breakpoint ─────────────────
231
- Only the min-width threshold + `.sitenav--bp-*` scope differ; the nested ruleset
232
- is identical. CSS has no mixins, so the four blocks are intentionally parallel —
233
- edit them together. Each: hide the mobile chrome, force the [popover] panel back
234
- inline as a navbar, turn the list horizontal, and promote submenus to dropdowns. */
286
+ /* Depth cap (mobile side): a desktop-only branch shows just its parent link.
287
+ Scoped, so the wide branch needs no counter-rule — it simply stops applying. */
288
+ .sitenav__item--desktop-branch > .sitenav__disclosure,
289
+ .sitenav__item--desktop-branch > .sitenav__submenu {
290
+ display: none;
291
+ }
292
+ }
293
+ /* ── Desktop promotion.
294
+ *
295
+ * Four thresholds, ONE ruleset. This used to be four ~86-line blocks that had to
296
+ * be kept in step by hand, and the file said so: "CSS has no mixins, so the four
297
+ * blocks are intentionally parallel — edit them together."
298
+ *
299
+ * They were not in step. `md`, `lg` and `xl` were byte-identical; `sm` had drifted
300
+ * onto an older markup shape, selecting `.sitenav__disclosure > .sitenav__submenu`
301
+ * where the submenu is actually the disclosure's SIBLING (see the accordion
302
+ * comment above, and bricks/elements/sitenav.php). So `.sitenav--bp-sm` shipped a
303
+ * navbar whose dropdowns could never open, and nothing failed loudly enough to
304
+ * notice. One shared block makes that class of drift unrepresentable.
305
+ *
306
+ * The mechanism is a style query on an inherited flag, the same one
307
+ * patterns/navshell.css uses. `.sitenav` resets the flag so a nested sitenav
308
+ * resolves against ITSELF rather than inheriting an outer instance's "I'm wide".
309
+ *
310
+ * Note the wide state is a navbar in everything but name — a horizontal row of
311
+ * links. It does not literally compose `patterns/navbar.css`, because the panel
312
+ * has to be a COLUMN in its drawer state, and a class can't be conditional; the
313
+ * flip would have to be undone at mobile, which costs more than the two
314
+ * declarations it saves. Use `.navbar` directly for a link row that is only ever
315
+ * a row.
316
+ * ── */
235
317
  @container (min-width: 30rem) {
236
318
  .sitenav--bp-sm {
237
- & > .sitenav__toggle,
238
- & .sitenav__close {
239
- display: none;
240
- }
241
- /* [popover] is UA/polyfill display:none while closed; !important forces the
242
- navbar body back inline (the hamburger is gone, so it never re-hides). */
243
- & .sitenav__panel {
244
- display: flex !important;
245
- flex-direction: row;
246
- align-items: center;
247
- position: static;
248
- inset: auto;
249
- inline-size: auto;
250
- max-inline-size: none;
251
- block-size: auto;
252
- padding: 0;
253
- translate: none;
254
- opacity: 1;
255
- overflow: visible;
256
- background: none;
257
- color: inherit;
258
- box-shadow: none;
259
- z-index: auto;
260
- }
261
- & .sitenav__panel::backdrop {
262
- display: none;
263
- }
264
- & .sitenav__list {
265
- flex-direction: row;
266
- flex-wrap: wrap;
267
- align-items: center;
268
- }
269
- & .sitenav__item--branch {
270
- position: relative;
271
- display: flex;
272
- align-items: center;
273
- grid-template-columns: none;
274
- grid-template-rows: none;
275
- }
276
- & .sitenav__submenu {
277
- position: absolute;
278
- inset-block-start: 100%;
279
- inset-inline-start: 0;
280
- min-inline-size: 13rem;
281
- padding: 0.5rem;
282
- overflow: visible;
283
- background: var(--color-bg-surface);
284
- color: var(--color-text-surface);
285
- border: var(--b-panel);
286
- border-radius: var(--br-panel);
287
- box-shadow: var(--ds-panel);
288
- z-index: var(--z-tier-overlay);
289
- opacity: 0;
290
- visibility: hidden;
291
- pointer-events: none;
292
- translate: 0 0.25rem;
293
- transition:
294
- opacity 0.15s ease,
295
- translate 0.15s ease,
296
- visibility 0.15s allow-discrete;
297
- }
298
- /* deeper submenus (inside a panel) fly out to the side, not downward */
299
- & .sitenav__submenu .sitenav__item--branch > .sitenav__disclosure > .sitenav__submenu {
300
- inset-block-start: 0;
301
- inset-inline-start: 100%;
302
- translate: 0.25rem 0;
303
- }
304
- & .sitenav__item--branch:hover > .sitenav__disclosure > .sitenav__submenu,
305
- & .sitenav__item--branch:focus-within > .sitenav__disclosure > .sitenav__submenu,
306
- & .sitenav__item--branch > .sitenav__disclosure[open] > .sitenav__submenu {
307
- opacity: 1;
308
- visibility: visible;
309
- pointer-events: auto;
310
- translate: 0 0;
311
- }
312
- /* depth caps flip at the breakpoint */
313
- & .sitenav__item--desktop-branch > .sitenav__disclosure > .sitenav__subtoggle {
314
- display: inline-flex;
315
- }
316
- & .sitenav__item--mobile-branch > .sitenav__disclosure > .sitenav__subtoggle,
317
- & .sitenav__item--mobile-branch > .sitenav__disclosure > .sitenav__submenu {
318
- display: none;
319
- }
319
+ --_sitenav-wide: 1;
320
320
  }
321
321
  }
322
-
323
322
  @container (min-width: 48rem) {
324
323
  .sitenav--bp-md {
325
- & > .sitenav__toggle,
326
- & .sitenav__close {
327
- display: none;
328
- }
329
- & .sitenav__panel {
330
- display: flex !important;
331
- flex-direction: row;
332
- align-items: center;
333
- position: static;
334
- inset: auto;
335
- inline-size: auto;
336
- max-inline-size: none;
337
- block-size: auto;
338
- padding: 0;
339
- translate: none;
340
- opacity: 1;
341
- overflow: visible;
342
- background: none;
343
- color: inherit;
344
- box-shadow: none;
345
- z-index: auto;
346
- }
347
- & .sitenav__panel::backdrop {
348
- display: none;
349
- }
350
- & .sitenav__list {
351
- flex-direction: row;
352
- flex-wrap: wrap;
353
- align-items: center;
354
- }
355
- & .sitenav__item--branch {
356
- position: relative;
357
- display: flex;
358
- align-items: center;
359
- grid-template-columns: none;
360
- grid-template-rows: none;
361
- }
362
- & .sitenav__submenu {
363
- position: absolute;
364
- inset-block-start: 100%;
365
- inset-inline-start: 0;
366
- min-inline-size: 13rem;
367
- padding: 0.5rem;
368
- overflow: visible;
369
- background: var(--color-bg-surface);
370
- color: var(--color-text-surface);
371
- border: var(--b-panel);
372
- border-radius: var(--br-panel);
373
- box-shadow: var(--ds-panel);
374
- z-index: var(--z-tier-overlay);
375
- opacity: 0;
376
- visibility: hidden;
377
- pointer-events: none;
378
- translate: 0 0.25rem;
379
- transition:
380
- opacity 0.15s ease,
381
- translate 0.15s ease,
382
- visibility 0.15s allow-discrete;
383
- }
384
- & .sitenav__submenu .sitenav__item--branch > .sitenav__submenu {
385
- inset-block-start: 0;
386
- inset-inline-start: 100%;
387
- translate: 0.25rem 0;
388
- }
389
- & .sitenav__item--branch:hover > .sitenav__submenu,
390
- & .sitenav__item--branch:focus-within > .sitenav__submenu,
391
- & .sitenav__item--branch:has(> .sitenav__disclosure[open]) > .sitenav__submenu {
392
- opacity: 1;
393
- visibility: visible;
394
- pointer-events: auto;
395
- translate: 0 0;
396
- }
397
- /* depth caps flip at the breakpoint: desktop-only branches reveal their caret +
398
- dropdown; mobile-only branches collapse to a plain link. */
399
- & .sitenav__item--desktop-branch > .sitenav__disclosure,
400
- & .sitenav__item--desktop-branch > .sitenav__submenu {
401
- display: block;
402
- }
403
- & .sitenav__item--mobile-branch > .sitenav__disclosure,
404
- & .sitenav__item--mobile-branch > .sitenav__submenu {
405
- display: none;
406
- }
324
+ --_sitenav-wide: 1;
407
325
  }
408
326
  }
409
-
410
327
  @container (min-width: 64rem) {
411
328
  .sitenav--bp-lg {
412
- & > .sitenav__toggle,
413
- & .sitenav__close {
414
- display: none;
415
- }
416
- & .sitenav__panel {
417
- display: flex !important;
418
- flex-direction: row;
419
- align-items: center;
420
- position: static;
421
- inset: auto;
422
- inline-size: auto;
423
- max-inline-size: none;
424
- block-size: auto;
425
- padding: 0;
426
- translate: none;
427
- opacity: 1;
428
- overflow: visible;
429
- background: none;
430
- color: inherit;
431
- box-shadow: none;
432
- z-index: auto;
433
- }
434
- & .sitenav__panel::backdrop {
435
- display: none;
436
- }
437
- & .sitenav__list {
438
- flex-direction: row;
439
- flex-wrap: wrap;
440
- align-items: center;
441
- }
442
- & .sitenav__item--branch {
443
- position: relative;
444
- display: flex;
445
- align-items: center;
446
- grid-template-columns: none;
447
- grid-template-rows: none;
448
- }
449
- & .sitenav__submenu {
450
- position: absolute;
451
- inset-block-start: 100%;
452
- inset-inline-start: 0;
453
- min-inline-size: 13rem;
454
- padding: 0.5rem;
455
- overflow: visible;
456
- background: var(--color-bg-surface);
457
- color: var(--color-text-surface);
458
- border: var(--b-panel);
459
- border-radius: var(--br-panel);
460
- box-shadow: var(--ds-panel);
461
- z-index: var(--z-tier-overlay);
462
- opacity: 0;
463
- visibility: hidden;
464
- pointer-events: none;
465
- translate: 0 0.25rem;
466
- transition:
467
- opacity 0.15s ease,
468
- translate 0.15s ease,
469
- visibility 0.15s allow-discrete;
470
- }
471
- & .sitenav__submenu .sitenav__item--branch > .sitenav__submenu {
472
- inset-block-start: 0;
473
- inset-inline-start: 100%;
474
- translate: 0.25rem 0;
475
- }
476
- & .sitenav__item--branch:hover > .sitenav__submenu,
477
- & .sitenav__item--branch:focus-within > .sitenav__submenu,
478
- & .sitenav__item--branch:has(> .sitenav__disclosure[open]) > .sitenav__submenu {
479
- opacity: 1;
480
- visibility: visible;
481
- pointer-events: auto;
482
- translate: 0 0;
483
- }
484
- /* depth caps flip at the breakpoint: desktop-only branches reveal their caret +
485
- dropdown; mobile-only branches collapse to a plain link. */
486
- & .sitenav__item--desktop-branch > .sitenav__disclosure,
487
- & .sitenav__item--desktop-branch > .sitenav__submenu {
488
- display: block;
489
- }
490
- & .sitenav__item--mobile-branch > .sitenav__disclosure,
491
- & .sitenav__item--mobile-branch > .sitenav__submenu {
492
- display: none;
493
- }
329
+ --_sitenav-wide: 1;
494
330
  }
495
331
  }
496
-
497
332
  @container (min-width: 80rem) {
498
333
  .sitenav--bp-xl {
499
- & > .sitenav__toggle,
500
- & .sitenav__close {
501
- display: none;
502
- }
503
- & .sitenav__panel {
504
- display: flex !important;
505
- flex-direction: row;
506
- align-items: center;
507
- position: static;
508
- inset: auto;
509
- inline-size: auto;
510
- max-inline-size: none;
511
- block-size: auto;
512
- padding: 0;
513
- translate: none;
514
- opacity: 1;
515
- overflow: visible;
516
- background: none;
517
- color: inherit;
518
- box-shadow: none;
519
- z-index: auto;
520
- }
521
- & .sitenav__panel::backdrop {
522
- display: none;
523
- }
524
- & .sitenav__list {
525
- flex-direction: row;
526
- flex-wrap: wrap;
527
- align-items: center;
528
- }
529
- & .sitenav__item--branch {
530
- position: relative;
531
- display: flex;
532
- align-items: center;
533
- grid-template-columns: none;
534
- grid-template-rows: none;
535
- }
536
- & .sitenav__submenu {
537
- position: absolute;
538
- inset-block-start: 100%;
539
- inset-inline-start: 0;
540
- min-inline-size: 13rem;
541
- padding: 0.5rem;
542
- overflow: visible;
543
- background: var(--color-bg-surface);
544
- color: var(--color-text-surface);
545
- border: var(--b-panel);
546
- border-radius: var(--br-panel);
547
- box-shadow: var(--ds-panel);
548
- z-index: var(--z-tier-overlay);
549
- opacity: 0;
550
- visibility: hidden;
551
- pointer-events: none;
552
- translate: 0 0.25rem;
553
- transition:
554
- opacity 0.15s ease,
555
- translate 0.15s ease,
556
- visibility 0.15s allow-discrete;
557
- }
558
- & .sitenav__submenu .sitenav__item--branch > .sitenav__submenu {
559
- inset-block-start: 0;
560
- inset-inline-start: 100%;
561
- translate: 0.25rem 0;
562
- }
563
- & .sitenav__item--branch:hover > .sitenav__submenu,
564
- & .sitenav__item--branch:focus-within > .sitenav__submenu,
565
- & .sitenav__item--branch:has(> .sitenav__disclosure[open]) > .sitenav__submenu {
566
- opacity: 1;
567
- visibility: visible;
568
- pointer-events: auto;
569
- translate: 0 0;
570
- }
571
- /* depth caps flip at the breakpoint: desktop-only branches reveal their caret +
572
- dropdown; mobile-only branches collapse to a plain link. */
573
- & .sitenav__item--desktop-branch > .sitenav__disclosure,
574
- & .sitenav__item--desktop-branch > .sitenav__submenu {
575
- display: block;
576
- }
577
- & .sitenav__item--mobile-branch > .sitenav__disclosure,
578
- & .sitenav__item--mobile-branch > .sitenav__submenu {
579
- display: none;
580
- }
334
+ --_sitenav-wide: 1;
335
+ }
336
+ }
337
+
338
+ @container style(--_sitenav-wide: 1) {
339
+ .sitenav > .sitenav__toggle,
340
+ .sitenav__close {
341
+ display: none;
342
+ }
343
+ .sitenav__panel {
344
+ display: flex !important;
345
+ flex-direction: row;
346
+ align-items: center;
347
+ position: static;
348
+ inset: auto;
349
+ inline-size: auto;
350
+ max-inline-size: none;
351
+ block-size: auto;
352
+ padding: 0;
353
+ translate: none;
354
+ opacity: 1;
355
+ overflow: visible;
356
+ background: none;
357
+ color: inherit;
358
+ box-shadow: none;
359
+ z-index: auto;
360
+ }
361
+ .sitenav__panel::backdrop {
362
+ display: none;
363
+ }
364
+ .sitenav__list {
365
+ flex-direction: row;
366
+ flex-wrap: wrap;
367
+ align-items: center;
368
+ }
369
+ .sitenav__item--branch {
370
+ position: relative;
371
+ display: flex;
372
+ align-items: center;
373
+ /* Restated, not inherited: this used to leak in from the accordion rule, which
374
+ is now narrow-scoped. Without it the caret hugs the link at width. */
375
+ column-gap: 0.5rem;
376
+ }
377
+ .sitenav__submenu {
378
+ position: absolute;
379
+ inset-block-start: 100%;
380
+ inset-inline-start: 0;
381
+ min-inline-size: 13rem;
382
+ padding: 0.5rem;
383
+ background: var(--color-bg-surface);
384
+ color: var(--color-text-surface);
385
+ border: var(--b-panel);
386
+ border-radius: var(--br-panel);
387
+ box-shadow: var(--ds-panel);
388
+ z-index: var(--z-tier-overlay);
389
+ opacity: 0;
390
+ visibility: hidden;
391
+ pointer-events: none;
392
+ translate: 0 0.25rem;
393
+ transition:
394
+ opacity 0.15s ease,
395
+ translate 0.15s ease,
396
+ visibility 0.15s allow-discrete;
397
+ }
398
+ /* Third level (megamenu) flies out to the inline-end side. Its containing block
399
+ is the inner `.sitenav__item--branch` (position: relative, above), which sits
400
+ INSIDE the parent submenu — so nothing between the two may clip. The
401
+ accordion's `overflow: hidden` used to leak in here at (0,2,0) and beat this
402
+ branch's (0,1,0) reset, and every megamenu was invisible at width. It is now
403
+ scoped to `style(--_sitenav-wide: 0)` and cannot. */
404
+ .sitenav__submenu .sitenav__item--branch > .sitenav__submenu {
405
+ inset-block-start: 0;
406
+ inset-inline-start: 100%;
407
+ translate: 0.25rem 0;
408
+ }
409
+ .sitenav__item--branch:hover > .sitenav__submenu,
410
+ .sitenav__item--branch:focus-within > .sitenav__submenu,
411
+ .sitenav__item--branch:has(> .sitenav__disclosure[open]) > .sitenav__submenu {
412
+ opacity: 1;
413
+ visibility: visible;
414
+ pointer-events: auto;
415
+ translate: 0 0;
416
+ }
417
+ /* Depth cap (desktop side): a mobile-only branch collapses to a plain link. Its
418
+ mirror — hiding a DESKTOP-only branch below the breakpoint — lives in the
419
+ narrow branch, so there is nothing to undo here. A `display: block`
420
+ counter-rule used to sit alongside this one and, at (0,2,0), beat the base
421
+ `.sitenav__submenu`'s `display: flex` (0,1,0) — costing every desktop-only
422
+ dropdown its column direction and gap. */
423
+ .sitenav__item--mobile-branch > .sitenav__disclosure,
424
+ .sitenav__item--mobile-branch > .sitenav__submenu {
425
+ display: none;
581
426
  }
582
427
  }