monowind 0.3.0 → 0.3.1

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.
package/src/styles.css CHANGED
@@ -227,8 +227,11 @@
227
227
  /* select="grid": pointer events pass through the light DOM so a drag
228
228
  * lands on the grid <pre>; the interactives opt back in for clicks,
229
229
  * except during a grid drag, so the selection sweeps through their
230
- * cells. The list repeats the cursor rule's: these rules must be
231
- * important (a library writes inline pointer-events on its layers) and
230
+ * cells, and except where the grid covers one (`data-mw-covered`,
231
+ * element.ts): the box painted over it takes the pointer, hover and
232
+ * cursor included (specs/cell-model.md "Pointer states"), its own
233
+ * subtree with it. The list repeats the cursor rule's: these rules
234
+ * must be important (a library writes inline pointer-events on its layers) and
232
235
  * unlayered, out of the lock layer (an author's `pointer-events-none!`
233
236
  * or `pointer-events-auto!` still wins), the cursor rule layered and
234
237
  * plain (an author's cursor wins). interactive.test.ts holds the two
@@ -268,7 +271,7 @@ mono-wind[select="grid"]:not([data-mw-dragging])
268
271
  [role="slider"],
269
272
  [role="link"],
270
273
  [role="combobox"]
271
- ) {
274
+ ):not([data-mw-covered], [data-mw-covered] *) {
272
275
  pointer-events: auto !important;
273
276
  }
274
277
  /* A modal dialog blocks the page, the grid included (specs/top-layer.md
@@ -317,10 +320,10 @@ mono-wind[select="grid"]:where(:not([data-mw-semantic-selection]))
317
320
  * scrollbar — native bars hidden. Measuring-gated so the authored
318
321
  * scrollbar-width/-color stay readable during the style pass. */
319
322
  @layer theme {
320
- mono-wind:not([measuring]) [data-mw-scroll] {
323
+ mono-wind [data-mw-scroll]:not([data-mw-measuring]) {
321
324
  scrollbar-width: none !important;
322
325
  }
323
- mono-wind:not([measuring]) [data-mw-scroll]::-webkit-scrollbar {
326
+ mono-wind [data-mw-scroll]:not([data-mw-measuring])::-webkit-scrollbar {
324
327
  display: none !important;
325
328
  }
326
329
  }
@@ -334,7 +337,7 @@ mono-wind[select="grid"]:where(:not([data-mw-semantic-selection]))
334
337
  * invisible scroll. Rounding can still put the ceiling a pixel either
335
338
  * side of max, so the engine reads "at the ceiling" as "at max". An
336
339
  * axis without range parks the spacer in the first cell (render.ts). */
337
- mono-wind:not([measuring]) [data-mw-scroll]::after {
340
+ mono-wind [data-mw-scroll]:not([data-mw-measuring])::after {
338
341
  content: "";
339
342
  position: absolute;
340
343
  pointer-events: none;
@@ -379,8 +382,10 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
379
382
  @media (forced-colors: none) {
380
383
  @layer theme {
381
384
  mono-wind:not([measuring])[data-mw-leaf]::selection,
382
- mono-wind:not([measuring])
383
- :where(:not(input, textarea, select, [contenteditable], [contenteditable] *))::selection {
385
+ mono-wind
386
+ :where(:not(input, textarea, select, [contenteditable], [contenteditable] *)):not(
387
+ [data-mw-measuring]
388
+ )::selection {
384
389
  color: transparent !important;
385
390
  text-shadow: none !important;
386
391
  background: transparent !important;
@@ -391,8 +396,10 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
391
396
  * transparent, from the rule above): its own rule swaps its colors as
392
397
  * the grid swaps a selected cell's, from the ink and ground the engine
393
398
  * measured and wrote on it (render.ts). */
394
- mono-wind:not([measuring])
395
- :where(input, textarea, select, [contenteditable], [contenteditable] *)::selection {
399
+ mono-wind
400
+ :where(input, textarea, select, [contenteditable], [contenteditable] *):not(
401
+ [data-mw-measuring]
402
+ )::selection {
396
403
  color: var(--mw-ground, var(--mw-bg, canvas));
397
404
  background: var(--mw-ink, var(--mw-fg, canvastext));
398
405
  }
@@ -400,6 +407,14 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
400
407
 
401
408
  /* === Typography locks and measuring gates ============================ */
402
409
 
410
+ /* A gate on a light element is the element's own flag — `data-mw-measuring`,
411
+ * then `data-mw-settling`, which the layout sets on every light element
412
+ * as it sets the host's `measuring` and `settling` — never the host's
413
+ * attribute read through a descendant combinator: that would make each
414
+ * flip of the host's attribute invalidate its whole subtree, the shadow
415
+ * grid's every span walked four times a layout. The host's attributes
416
+ * gate the host's own rules alone. An element inserted since the last
417
+ * layout has no flag, and so takes the locks until its first. */
403
418
  @layer theme {
404
419
  /* Lock the font on descendants so the grid metrics stay consistent —
405
420
  * `!important` because user classes (`.text-2xl` etc.) would otherwise beat
@@ -427,9 +442,9 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
427
442
  * respected — background fades, which can never run natively, are
428
443
  * synthesized by the engine instead. */
429
444
  mono-wind[measuring],
430
- mono-wind[measuring] *,
445
+ mono-wind [data-mw-measuring],
431
446
  mono-wind[settling],
432
- mono-wind[settling] * {
447
+ mono-wind [data-mw-settling] {
433
448
  transition-property:
434
449
  color, border-color, opacity, transform, translate, rotate, scale, filter !important;
435
450
  }
@@ -439,7 +454,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
439
454
  * no position-try fallback of its own (from its pixel geometry, not the
440
455
  * cells') and `position-area` reads as authored
441
456
  * (specs/anchor-positioning.md). */
442
- mono-wind[measuring] * {
457
+ mono-wind [data-mw-measuring] {
443
458
  anchor-scope: all !important;
444
459
  }
445
460
 
@@ -447,8 +462,8 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
447
462
  * (specs/top-layer.md): on them, and them alone, the mask keeps
448
463
  * display and overlay alive across the passes — no lock toggles either
449
464
  * there, while the grid-template read assist below toggles display. */
450
- mono-wind[measuring] :is([popover], dialog),
451
- mono-wind[settling] :is([popover], dialog) {
465
+ mono-wind :is([popover], dialog)[data-mw-measuring],
466
+ mono-wind :is([popover], dialog)[data-mw-settling] {
452
467
  transition-property:
453
468
  color, border-color, opacity, transform, translate, rotate, scale, filter, display, overlay !important;
454
469
  }
@@ -460,13 +475,13 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
460
475
  * attribute for the duration of the read; blockifying the element makes
461
476
  * getComputedStyle return the COMPUTED value, structure intact.
462
477
  * `!important` so inline `style="display: grid"` can't defeat the read. */
463
- mono-wind[measuring] [data-mw-degrid] {
478
+ mono-wind [data-mw-degrid][data-mw-measuring] {
464
479
  display: block !important;
465
480
  }
466
481
 
467
482
  /* Grid-quantized typography and the wrap model (specs/cell-model.md). Gated
468
- * on `measuring` (unlike the font lock above) so the style reader sees the
469
- * AUTHORED white-space / letter-spacing / line-height — that's how nowrap,
483
+ * on the measuring flag (unlike the font lock above) so the style reader
484
+ * sees the AUTHORED white-space / letter-spacing / line-height — that's how nowrap,
470
485
  * tracking, and leading are detected without echoing our own output.
471
486
  *
472
487
  * letter-spacing: the root's own (`--mw-rls`, part of the cell) plus
@@ -476,7 +491,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
476
491
  * the parent's grid-exact value. line-height is inherited from the
477
492
  * laid-out ancestor (which sets the row multiple below) — `leading-*` on
478
493
  * inline elements is ignored by design. */
479
- mono-wind:not([measuring]) * {
494
+ mono-wind :not([data-mw-measuring]) {
480
495
  /* Baseline-shift lock (cell-model): gated like the rest, so the style
481
496
  * reader sees the authored/UA vertical-align (table cells read it). */
482
497
  vertical-align: baseline !important;
@@ -511,8 +526,8 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
511
526
 
512
527
  /* A top-layer element's backdrop is a box of the grid's beneath its
513
528
  * own (specs/top-layer.md), read during [measuring] like backgrounds. */
514
- mono-wind:not([measuring]) [popover]::backdrop,
515
- mono-wind:not([measuring]) dialog::backdrop {
529
+ mono-wind [popover]:not([data-mw-measuring])::backdrop,
530
+ mono-wind dialog:not([data-mw-measuring])::backdrop {
516
531
  background: transparent !important;
517
532
  backdrop-filter: none !important;
518
533
  }
@@ -531,7 +546,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
531
546
  * rule that shapes a leaf's native text carries this host variant —
532
547
  * render.ts writes the host's flags. */
533
548
  mono-wind:not([measuring])[data-mw-leaf],
534
- mono-wind:not([measuring]) *:not(input):not(textarea):not(select) {
549
+ mono-wind :not(input):not(textarea):not(select):not([data-mw-measuring]) {
535
550
  -webkit-text-fill-color: transparent !important;
536
551
  text-decoration-color: transparent !important;
537
552
  }
@@ -540,9 +555,9 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
540
555
  * exclusion above: text-fill-color inherits and has no UA default on
541
556
  * controls (unlike `color`), so without this reset an input under any
542
557
  * locked ancestor would inherit transparent ink. */
543
- mono-wind:not([measuring]) input,
544
- mono-wind:not([measuring]) textarea,
545
- mono-wind:not([measuring]) select {
558
+ mono-wind input:not([data-mw-measuring]),
559
+ mono-wind textarea:not([data-mw-measuring]),
560
+ mono-wind select:not([data-mw-measuring]) {
546
561
  -webkit-text-fill-color: currentColor !important;
547
562
  }
548
563
 
@@ -550,7 +565,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
550
565
  * box for unwrapped hard lines, so the browser must not wrap either. Wins
551
566
  * over the lock above on specificity. */
552
567
  mono-wind:not([measuring])[data-mw-nowrap],
553
- mono-wind:not([measuring]) [data-mw-nowrap] {
568
+ mono-wind [data-mw-nowrap]:not([data-mw-measuring]) {
554
569
  white-space: nowrap !important;
555
570
  }
556
571
 
@@ -560,24 +575,28 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
560
575
  * collapse text inside nested spans). Later than the nowrap rule, so it
561
576
  * wins on the leaf itself at equal specificity. */
562
577
  mono-wind:not([measuring])[data-mw-pre],
563
- mono-wind:not([measuring])[data-mw-pre] *,
564
- mono-wind:not([measuring]) [data-mw-pre],
565
- mono-wind:not([measuring]) [data-mw-pre] * {
578
+ mono-wind[data-mw-pre] :not([data-mw-measuring]),
579
+ mono-wind [data-mw-pre]:not([data-mw-measuring]),
580
+ mono-wind [data-mw-pre] *:not([data-mw-measuring]) {
566
581
  white-space: pre !important;
567
582
  }
568
583
 
569
- /* Truncation (`truncate` = nowrap + clip + text-overflow: ellipsis): use
570
- * `hidden` rather than the normalized `clip` for this combo some engines
571
- * only apply `text-overflow` to scroll containers, which `clip` boxes are
572
- * not. Wins over the `[data-mw-clip]` rule below on specificity. */
573
- mono-wind:not([measuring]) [data-mw-nowrap][data-mw-clip] {
584
+ /* Truncation (`truncate` = nowrap + clip + text-overflow: ellipsis)
585
+ * keeps `hidden` rather than the normalized `clip`: a clip box is no
586
+ * scroll container, so focus can never reveal what the ellipsis hides
587
+ * a link past the cut stays off screen for a keyboard (measured:
588
+ * Chromium and Firefox scroll it into view under `hidden`, neither
589
+ * does under `clip`; WebKit reveals it under neither). `text-overflow`
590
+ * itself works the same either way in all three. Wins over the
591
+ * `[data-mw-clip]` rule below on specificity. */
592
+ mono-wind [data-mw-nowrap][data-mw-clip]:not([data-mw-measuring]) {
574
593
  overflow: hidden !important;
575
594
  }
576
595
 
577
596
  /* === Engine-owned geometry =========================================== */
578
597
 
579
598
  /* Every CSS property the engine has taken over on laid-out elements.
580
- * Gated on the `measuring` attribute so the style reader still sees the
599
+ * Gated on the measuring flag so the style reader still sees the
581
600
  * authored values during its read pass. In the lock layer (the file's
582
601
  * header) the `!important` beats every utility, `!` modifier included,
583
602
  * inline `style=""` attributes (hand-written or CSS-in-JS), and
@@ -596,7 +615,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
596
615
  *
597
616
  * Left alone: flex/grid/gap/justify/align — laid-out children are all
598
617
  * position:absolute (out of flow), so nothing consumes them anyway. */
599
- mono-wind:not([measuring]) [data-mw-laid-out] {
618
+ mono-wind [data-mw-laid-out]:not([data-mw-measuring]) {
600
619
  position: absolute !important;
601
620
  /* An anchored box is the engine's to place (specs/anchor-positioning.md):
602
621
  * the browser's own anchored placement stays off. */
@@ -629,7 +648,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
629
648
  /* A top-layer element's box is the viewport's (specs/top-layer.md):
630
649
  * its cells count from the grid's client origin, a `:host` rule of the
631
650
  * shadow's in px, kept current through page scrolls. */
632
- mono-wind:not([measuring]) [data-mw-laid-out][data-mw-top] {
651
+ mono-wind [data-mw-laid-out][data-mw-top]:not([data-mw-measuring]) {
633
652
  position: fixed !important;
634
653
  left: calc(
635
654
  var(--mw-ox, 0px) + (var(--mw-x, 0) + var(--mw-sx, 0)) * var(--mw-cw, 1px)
@@ -642,11 +661,11 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
642
661
  /* Shared cell geometry for engine-sized boxes — engine-POSITIONED
643
662
  * elements, in-flow atomic inline boxes, and in-flow multicol spanners
644
663
  * (below). */
645
- mono-wind:not([measuring]) [data-mw-laid-out],
646
- mono-wind:not([measuring]) [data-mw-inline-box],
647
- mono-wind:not([measuring]) [data-mw-multicol-flow-span],
648
- mono-wind:not([measuring]) [data-mw-flow],
649
- mono-wind:not([measuring]) [data-mw-float] {
664
+ mono-wind [data-mw-laid-out]:not([data-mw-measuring]),
665
+ mono-wind [data-mw-inline-box]:not([data-mw-measuring]),
666
+ mono-wind [data-mw-multicol-flow-span]:not([data-mw-measuring]),
667
+ mono-wind [data-mw-flow]:not([data-mw-measuring]),
668
+ mono-wind [data-mw-float]:not([data-mw-measuring]) {
650
669
  box-sizing: border-box !important;
651
670
  /* A sticky shift (specs/sticky.md) belongs to the box the engine wrote
652
671
  * it on: custom properties inherit, so every box resets them, plainly,
@@ -708,7 +727,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
708
727
  * children; `vertical-align: top` pins the box's top to its line's first
709
728
  * row (the global baseline lock would hang an abspos-only box below the
710
729
  * line) — a box taller than one row grows its line, per CSS. */
711
- mono-wind:not([measuring]) [data-mw-inline-box] {
730
+ mono-wind [data-mw-inline-box]:not([data-mw-measuring]) {
712
731
  position: relative !important;
713
732
  /* A sticky inline box's shift for the scroll (specs/sticky.md; the
714
733
  * vars are absent otherwise) and the same half-leading lift as
@@ -724,7 +743,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
724
743
  * in every engine (probed), so it passes through; the engine drops the
725
744
  * line's text to the box's last row to match. baseline is off-grid and
726
745
  * behaves as top (cell-model deviation). */
727
- mono-wind:not([measuring]) [data-mw-inline-box][data-mw-vbottom] {
746
+ mono-wind [data-mw-inline-box][data-mw-vbottom]:not([data-mw-measuring]) {
728
747
  vertical-align: bottom !important;
729
748
  }
730
749
  /* Authored `vertical-align: middle`: a whole-row baseline length the
@@ -732,7 +751,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
732
751
  * box's own baseline to its line's text row, plus the row's baseline
733
752
  * for a box whose baseline is its bottom edge — so the line's text
734
753
  * lands on the box's middle row in every engine (probed). */
735
- mono-wind:not([measuring]) [data-mw-inline-box][data-mw-vmiddle] {
754
+ mono-wind [data-mw-inline-box][data-mw-vmiddle]:not([data-mw-measuring]) {
736
755
  vertical-align: calc(
737
756
  var(--mw-va, 0) * var(--mw-ch, 1px) + var(--mw-vb, 0) * var(--mw-base, 0px)
738
757
  ) !important;
@@ -746,7 +765,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
746
765
  * initial value of 2 vetoes single-line column endings the engine's
747
766
  * model allows (probed: Chromium then breaks [3, 2, 2] where the engine
748
767
  * says [3, 3, 1]), so both reset to 1. */
749
- mono-wind:not([measuring]) [data-mw-multicol] {
768
+ mono-wind [data-mw-multicol]:not([data-mw-measuring]) {
750
769
  column-count: var(--mw-colc, 1) !important;
751
770
  column-width: auto !important;
752
771
  column-gap: calc(var(--mw-colg, 0) * var(--mw-cw, 1px)) !important;
@@ -782,7 +801,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
782
801
  * natural height is full line boxes, exactly what fragmentation counts;
783
802
  * typography quantization and the color/background locks come from the
784
803
  * universal rules, and line-height inherits from the container. */
785
- mono-wind:not([measuring]) [data-mw-multicol-flow] {
804
+ mono-wind [data-mw-multicol-flow]:not([data-mw-measuring]) {
786
805
  position: static !important;
787
806
  display: block !important;
788
807
  box-sizing: border-box !important;
@@ -805,10 +824,10 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
805
824
  * text drifts out from under the grid's paint. Rewrite it in cells so
806
825
  * the two agree — selection ranges land exactly where the glyphs are. */
807
826
  mono-wind:not([measuring])[data-mw-leaf],
808
- mono-wind:not([measuring]) [data-mw-laid-out],
809
- mono-wind:not([measuring]) [data-mw-multicol-flow],
810
- mono-wind:not([measuring]) [data-mw-flow],
811
- mono-wind:not([measuring]) [data-mw-float] {
827
+ mono-wind [data-mw-laid-out]:not([data-mw-measuring]),
828
+ mono-wind [data-mw-multicol-flow]:not([data-mw-measuring]),
829
+ mono-wind [data-mw-flow]:not([data-mw-measuring]),
830
+ mono-wind [data-mw-float]:not([data-mw-measuring]) {
812
831
  text-indent: calc(var(--mw-ti, 0) * var(--mw-cw, 1px)) !important;
813
832
  }
814
833
 
@@ -820,9 +839,9 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
820
839
  * fragment around. `relative` makes them the containing block for
821
840
  * their absolutized descendants and carries the half-leading lift;
822
841
  * the engine owns every inset, so an authored one stays inert. */
823
- mono-wind:not([measuring]) [data-mw-flow],
824
- mono-wind:not([measuring]) [data-mw-float],
825
- mono-wind:not([measuring]) [data-mw-multicol-flow-span] {
842
+ mono-wind [data-mw-flow]:not([data-mw-measuring]),
843
+ mono-wind [data-mw-float]:not([data-mw-measuring]),
844
+ mono-wind [data-mw-multicol-flow-span]:not([data-mw-measuring]) {
826
845
  position: relative !important;
827
846
  top: calc(var(--mw-lhs, 0) * var(--mw-ch, 1px)) !important;
828
847
  right: auto !important;
@@ -833,7 +852,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
833
852
  margin-bottom: calc(var(--mw-mb, 0) * var(--mw-ch, 1px)) !important;
834
853
  margin-left: calc(var(--mw-ml, 0) * var(--mw-cw, 1px)) !important;
835
854
  }
836
- mono-wind:not([measuring]) [data-mw-multicol-flow-span] {
855
+ mono-wind [data-mw-multicol-flow-span]:not([data-mw-measuring]) {
837
856
  column-span: all !important;
838
857
  }
839
858
  /* A formatting-context root among flow children — a container, or a leaf
@@ -841,7 +860,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
841
860
  * inside it, where the engine put that child (the shadow slot does the
842
861
  * same for the host's, element.ts), and it steps aside from a float
843
862
  * rather than passing under (specs/float.md). */
844
- mono-wind:not([measuring]) [data-mw-flow="box"] {
863
+ mono-wind [data-mw-flow="box"]:not([data-mw-measuring]) {
845
864
  contain: layout !important;
846
865
  }
847
866
  /* A float (specs/float.md): the browser floats the engine's box, and
@@ -853,17 +872,17 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
853
872
  * tracking allowance and, as a quarter pixel, the layout-unit headroom.
854
873
  * A root or a later float that fits the engine's band exactly then
855
874
  * fits natively too, and a line beside a float keeps its headroom. */
856
- mono-wind:not([measuring]) [data-mw-float],
857
- mono-wind:not([measuring]) [data-mw-flow="box"] {
875
+ mono-wind [data-mw-float]:not([data-mw-measuring]),
876
+ mono-wind [data-mw-flow="box"]:not([data-mw-measuring]) {
858
877
  margin-right: calc(
859
878
  (var(--mw-mr, 0) - max(0, var(--mw-ls, 0) - var(--mw-pr, 0) - var(--mw-br, 0))) *
860
879
  var(--mw-cw, 1px) - 0.25px
861
880
  ) !important;
862
881
  }
863
- mono-wind:not([measuring]) [data-mw-float="left"] {
882
+ mono-wind [data-mw-float="left"]:not([data-mw-measuring]) {
864
883
  float: left !important;
865
884
  }
866
- mono-wind:not([measuring]) [data-mw-float="right"] {
885
+ mono-wind [data-mw-float="right"]:not([data-mw-measuring]) {
867
886
  float: right !important;
868
887
  }
869
888
 
@@ -871,7 +890,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
871
890
  * (probed pixel-exact in all three engines under quantized inputs):
872
891
  * `column-fill: balance` and the natural height replace the
873
892
  * fill-to-computed-height reconstruction of the base multicol rule. */
874
- mono-wind:not([measuring]) [data-mw-multicol][data-mw-multicol-balance] {
893
+ mono-wind [data-mw-multicol][data-mw-multicol-balance]:not([data-mw-measuring]) {
875
894
  column-fill: balance !important;
876
895
  height: auto !important;
877
896
  }
@@ -887,7 +906,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
887
906
  * look. WebKit slice-spills padding at breaks instead, and its gate
888
907
  * (multicol.ts detectGluedPreBreak) keeps margined spanner containers
889
908
  * on atomic distribution there. */
890
- mono-wind:not([measuring]) [data-mw-multicol-balance] > [data-mw-multicol-flow] {
909
+ mono-wind [data-mw-multicol-balance] > [data-mw-multicol-flow]:not([data-mw-measuring]) {
891
910
  margin-top: 0 !important;
892
911
  margin-bottom: 0 !important;
893
912
  padding-top: calc(var(--mw-mt, 0) * var(--mw-ch, 1px)) !important;
@@ -906,10 +925,10 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
906
925
  * `--mw-it/ir/ib/il` and this rule applies them on the grid. A side
907
926
  * without its var is invalid at computed-value time and falls back to
908
927
  * `auto` — so authored subsets work and the author's raw off-grid values
909
- * never apply. Gated on `measuring` so the style reader sees the authored
910
- * values (no echo loop). Also pins `position: relative` — sticky behaves
928
+ * never apply. Gated on the measuring flag so the style reader sees the
929
+ * authored values (no echo loop). Also pins `position: relative` — sticky behaves
911
930
  * as relative until the scrolling milestone. */
912
- mono-wind:not([measuring]) [data-mw-inline-inset] {
931
+ mono-wind [data-mw-inline-inset]:not([data-mw-measuring]) {
913
932
  position: relative !important;
914
933
  top: calc(var(--mw-it) * var(--mw-ch, 1px)) !important;
915
934
  right: calc(var(--mw-ir) * var(--mw-cw, 1px)) !important;
@@ -921,7 +940,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
921
940
 
922
941
  /* Misparented table content (no anonymous boxes, specs/table.md) and
923
942
  * <col>/<colgroup> boxes: fully hidden, subtree included. */
924
- mono-wind:not([measuring]) [data-mw-table-hidden] {
943
+ mono-wind [data-mw-table-hidden]:not([data-mw-measuring]) {
925
944
  display: none !important;
926
945
  }
927
946
 
@@ -929,10 +948,10 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
929
948
  * (stray text in a div-table, specs/table.md): the runs have no element
930
949
  * to hide, so the container hides its text, and its laid-out children
931
950
  * — the rows or cells — show through the inherited value. */
932
- mono-wind:not([measuring]) [data-mw-hidden-runs] {
951
+ mono-wind [data-mw-hidden-runs]:not([data-mw-measuring]) {
933
952
  visibility: hidden !important;
934
953
  }
935
- mono-wind:not([measuring]) [data-mw-hidden-runs] > [data-mw-laid-out] {
954
+ mono-wind [data-mw-hidden-runs] > [data-mw-laid-out]:not([data-mw-measuring]) {
936
955
  visibility: visible !important;
937
956
  }
938
957
 
@@ -940,7 +959,7 @@ mono-wind:not([measuring]) [data-mw-scroll]::after {
940
959
  * `end`/`center` all land on whole cells (offset = (W - N) × cell width);
941
960
  * `justify` produces fractional per-line offsets we can't snap to the grid. */
942
961
  mono-wind:not([measuring])[data-mw-text-align-blocked],
943
- mono-wind:not([measuring]) [data-mw-text-align-blocked] {
962
+ mono-wind [data-mw-text-align-blocked]:not([data-mw-measuring]) {
944
963
  text-align: start !important;
945
964
  }
946
965
  }
package/src/variants.css CHANGED
@@ -6,10 +6,16 @@
6
6
  * peer-* compose from them automatically. A consumer redefining a
7
7
  * variant later wins (last definition counts) — their selector must
8
8
  * include the data attribute to keep grid-mode states. The block form
9
- * preserves Tailwind's own (hover: hover) gate for hover. */
9
+ * preserves Tailwind's own (hover: hover) gate for hover.
10
+ *
11
+ * A covered element's own :hover is none of ours: the grid shows
12
+ * another box on those cells, and the browser drops the hover with the
13
+ * element's pointer events — WebKit a quarter second later, which the
14
+ * :where() covers at once, costing no specificity so no utility
15
+ * outranks another. */
10
16
  @custom-variant hover {
11
17
  @media (hover: hover) {
12
- &:is(:hover, [data-mw-hover]) {
18
+ &:is(:hover:where(:not([data-mw-covered])), [data-mw-hover]) {
13
19
  @slot;
14
20
  }
15
21
  }