Close the design guard's family-table gaps on real application markup

Plan step 41 review: run over SealShare's and ReStride's views, family (i)
missed about a quarter of the class tokens, most of them 1.x's own
utilities (type-body-md, text-meta, rounded-corner-lg, focus-ring, link)
and common Tailwind families (relative, inset-0, z-10, overflow-hidden,
border, opacity-50, shrink-0, -mx-4, cursor-pointer, font-mono). Each now
has a hint, and the ones with a layout component name its prop: gap-4 is
gap="space200" (16px), a step between two of M3's names both, items-center
align="center", grid-cols-3 :columns="3"; variants say which selector or
media query replaces them. Shapes are tightened to real Tailwind values,
so an application class such as content-header or p-card is not matched.

Class lists are also read from wire:*.class, x-transition:*, unquoted
:class keys, double-quoted PHP strings, 'class' => '…' and plain PHP
files; a string compared in a condition (view === 'grid') is skipped,
and each token carries its own line in a multi-line list.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold / reini
2026-09-15 08:43:29 +02:00
co-authored by Claude Opus 5
parent d5972b8ddb
commit 9595722f35
10 changed files with 348 additions and 108 deletions
+104 -37
View File
@@ -23,9 +23,10 @@ it('finds what compiles to nothing', function () {
expect(fixtureRelative($violations))->toBe([
'app/Status.php:14 colour the theme does not declare `text-red-500`',
"views/page.blade.php:2 Tailwind spacing utility `p-4` compiles to nothing — use a layout component's `gap`/`padding` prop (`<x-stack gap>`, `<x-surface padding>`), or `var(--md-sys-measurement-space*)` in your own CSS",
'views/page.blade.php:2 Tailwind spacing utility `p-4` compiles to nothing — use `padding="space200"` (16px) on `<x-surface>`, or `var(--md-sys-measurement-space200)` in your own CSS',
'views/page.blade.php:6 Tailwind colour utility `text-tertiary` compiles to nothing — use `var(--md-sys-color-tertiary)` in your own CSS',
'views/page.blade.php:8 Tailwind sizing utility `size-4` compiles to nothing — M3 keeps no size scale; write the literal length in your own CSS, or use `<x-pane width>`/`<x-grid min-item>` where it fits',
'views/page.blade.php:6 1.x utility `focus-ring` compiles to nothing — use `md-focus-ring` (interaction.css)',
"views/page.blade.php:8 Tailwind sizing utility `size-4` compiles to nothing — M3 keeps no size scale: `<x-pane width>` sets a content column's measure, `<x-icon size>` an icon's; anything else is a length in your own CSS",
'views/page.blade.php:3 unknown Material Symbol `o-home`',
'views/page.blade.php:4 unknown Material Symbol `not_a_symbol`',
'views/page.blade.php:8 Blade directive `@class` inside a component tag, where it does not compile',
@@ -52,10 +53,10 @@ it('names the 2.0.0 replacement for a pseudo-class variant, but leaves a breakpo
$violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/tailwind/variant.blade.php'))->violations());
expect($violations)->toBe([
"tailwind/variant.blade.php:1 Tailwind variant class `hover:underline` compiles to nothing — a state is `:has()`/`aria-*`/`data-md-*` in your own CSS, a breakpoint a layout component's `hide-below`/`hide-from`/`stack-below` prop",
"tailwind/variant.blade.php:1 Tailwind variant class `dark:opacity-50` compiles to nothing — a state is `:has()`/`aria-*`/`data-md-*` in your own CSS, a breakpoint a layout component's `hide-below`/`hide-from`/`stack-below` prop",
"tailwind/variant.blade.php:2 Tailwind variant class `group-hover:flex` compiles to nothing — a state is `:has()`/`aria-*`/`data-md-*` in your own CSS, a breakpoint a layout component's `hide-below`/`hide-from`/`stack-below` prop",
"tailwind/variant.blade.php:2 Tailwind variant class `focus:md:gap-2` compiles to nothing — a state is `:has()`/`aria-*`/`data-md-*` in your own CSS, a breakpoint a layout component's `hide-below`/`hide-from`/`stack-below` prop",
"tailwind/variant.blade.php:1 Tailwind variant class `hover:underline` compiles to nothing — M3's hover, focus and press states are `md-state-layer` and `md-focus-ring` (interaction.css); any other state rule is `:hover`/`:focus-visible` in your own CSS",
"tailwind/variant.blade.php:1 Tailwind variant class `dark:opacity-50` compiles to nothing — the roles already switch with the theme; a dark-only rule is `[data-theme='dark'] …` in your own CSS",
'tailwind/variant.blade.php:2 Tailwind variant class `group-hover:flex` compiles to nothing — `:has()` or a descendant selector in your own CSS',
"tailwind/variant.blade.php:2 Tailwind variant class `focus:md:gap-2` compiles to nothing — M3's hover, focus and press states are `md-state-layer` and `md-focus-ring` (interaction.css); any other state rule is `:hover`/`:focus-visible` in your own CSS",
"tailwind/variant.blade.php:2 Tailwind breakpoint `md:` compiles to nothing — M3's medium (600px) is a layout component's `hide-below`/`hide-from`/`stack-below` prop, or `@media (width >= 600px)` in your own CSS",
]);
});
@@ -189,50 +190,44 @@ it('names the md-ink-*, divider/surface or token replacement for a dead M3 role
]);
});
it('sends flex, grid and gap utilities to the layout components', function () {
it('sends flex, grid and gap utilities to the layout component and prop that replaces each', function () {
$violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/tailwind/layout.blade.php'))->violations());
$hint = 'compiles to nothing — use `<x-row>`, `<x-grid>` or `<x-stack>` and their `gap`/`align`/`justify`/`columns` props';
expect($violations)->toBe([
"tailwind/layout.blade.php:1 Tailwind layout utility `flex` {$hint}",
"tailwind/layout.blade.php:1 Tailwind layout utility `grid` {$hint}",
"tailwind/layout.blade.php:1 Tailwind layout utility `inline-flex` {$hint}",
"tailwind/layout.blade.php:1 Tailwind layout utility `flex-col` {$hint}",
"tailwind/layout.blade.php:2 Tailwind layout utility `grid-cols-3` {$hint}",
"tailwind/layout.blade.php:2 Tailwind layout utility `col-span-2` {$hint}",
"tailwind/layout.blade.php:2 Tailwind layout utility `items-center` {$hint}",
"tailwind/layout.blade.php:2 Tailwind layout utility `justify-between` {$hint}",
"tailwind/layout.blade.php:2 Tailwind layout utility `gap-4` {$hint}",
'tailwind/layout.blade.php:1 Tailwind layout utility `flex` compiles to nothing — use `<x-row>` (`gap`, `align`, `justify`, `wrap`, `stack-below`), or `<x-stack>` for a column',
'tailwind/layout.blade.php:1 Tailwind layout utility `grid` compiles to nothing — use `<x-grid>` (`:columns` per breakpoint, `gap`, `min-item`), or `<x-feed>` for a grid of cards',
'tailwind/layout.blade.php:1 Tailwind layout utility `inline-flex` compiles to nothing — use `<x-row>` (`gap`, `align`, `justify`, `wrap`, `stack-below`), or `<x-stack>` for a column',
'tailwind/layout.blade.php:1 Tailwind layout utility `flex-col` compiles to nothing — use `<x-stack>` (`gap`, `align`)',
"tailwind/layout.blade.php:2 Tailwind layout utility `grid-cols-3` compiles to nothing — use `<x-grid :columns=\"3\">`, or a per-breakpoint map (`:columns=\"['compact' => 1, 'medium' => 3]\"`)",
"tailwind/layout.blade.php:2 Tailwind flex/grid item utility `col-span-2` compiles to nothing — the layout components arrange their children; an item's own `flex`, `order` or `grid-column` is a rule in your own CSS",
'tailwind/layout.blade.php:2 Tailwind layout utility `items-center` compiles to nothing — use `align="center"` on `<x-row>` or `<x-stack>`',
'tailwind/layout.blade.php:2 Tailwind layout utility `justify-between` compiles to nothing — use `justify="between"` on `<x-row>`',
'tailwind/layout.blade.php:2 Tailwind spacing utility `gap-4` compiles to nothing — use `gap="space200"` (16px) on `<x-row>`, `<x-stack>`, `<x-grid>` or `<x-feed>`',
]);
});
it('sends padding, margin and space-between utilities to a layout component\'s gap/padding prop', function () {
it('sends padding, margin and space-between utilities to the M3 spacing step they are (gap-4 is space200)', function () {
$violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/tailwind/spacing.blade.php'))->violations());
$hint = "compiles to nothing — use a layout component's `gap`/`padding` prop (`<x-stack gap>`, `<x-surface padding>`), or `var(--md-sys-measurement-space*)` in your own CSS";
expect($violations)->toBe([
"tailwind/spacing.blade.php:1 Tailwind spacing utility `p-4` {$hint}",
"tailwind/spacing.blade.php:1 Tailwind spacing utility `px-2` {$hint}",
"tailwind/spacing.blade.php:1 Tailwind spacing utility `mt-2` {$hint}",
"tailwind/spacing.blade.php:1 Tailwind spacing utility `space-y-4` {$hint}",
"tailwind/spacing.blade.php:2 Tailwind spacing utility `m-4` {$hint}",
"tailwind/spacing.blade.php:2 Tailwind spacing utility `space-x-2` {$hint}",
'tailwind/spacing.blade.php:1 Tailwind spacing utility `p-4` compiles to nothing — use `padding="space200"` (16px) on `<x-surface>`, or `var(--md-sys-measurement-space200)` in your own CSS',
'tailwind/spacing.blade.php:1 Tailwind spacing utility `px-2` compiles to nothing — use `padding="space100"` (8px) on `<x-surface>`, or `var(--md-sys-measurement-space100)` in your own CSS',
"tailwind/spacing.blade.php:1 Tailwind spacing utility `mt-2` compiles to nothing — space between siblings is a layout component's `gap=\"space100\"` (8px); any other margin is `var(--md-sys-measurement-space100)` in your own CSS",
'tailwind/spacing.blade.php:1 Tailwind spacing utility `space-y-4` compiles to nothing — use `<x-stack>` with `gap="space200"` (16px)',
"tailwind/spacing.blade.php:2 Tailwind spacing utility `m-4` compiles to nothing — space between siblings is a layout component's `gap=\"space200\"` (16px); any other margin is `var(--md-sys-measurement-space200)` in your own CSS",
'tailwind/spacing.blade.php:2 Tailwind spacing utility `space-x-2` compiles to nothing — use `<x-row>` with `gap="space100"` (8px)',
]);
});
it('sends width and height utilities to a literal length, since M3 keeps no size scale', function () {
$violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/tailwind/sizing.blade.php'))->violations());
$hint = 'compiles to nothing — M3 keeps no size scale; write the literal length in your own CSS, or use `<x-pane width>`/`<x-grid min-item>` where it fits';
expect($violations)->toBe([
"tailwind/sizing.blade.php:1 Tailwind sizing utility `w-full` {$hint}",
"tailwind/sizing.blade.php:1 Tailwind sizing utility `h-screen` {$hint}",
"tailwind/sizing.blade.php:1 Tailwind sizing utility `min-w-0` {$hint}",
"tailwind/sizing.blade.php:1 Tailwind sizing utility `max-w-md` {$hint}",
"tailwind/sizing.blade.php:2 Tailwind sizing utility `size-4` {$hint}",
"tailwind/sizing.blade.php:1 Tailwind sizing utility `w-full` compiles to nothing — M3 keeps no size scale: `<x-pane width>` sets a content column's measure, `<x-icon size>` an icon's; anything else is a length in your own CSS",
"tailwind/sizing.blade.php:1 Tailwind sizing utility `h-screen` compiles to nothing — M3 keeps no size scale: `<x-pane width>` sets a content column's measure, `<x-icon size>` an icon's; anything else is a length in your own CSS",
"tailwind/sizing.blade.php:1 Tailwind sizing utility `min-w-0` compiles to nothing — M3 keeps no size scale: `<x-pane width>` sets a content column's measure, `<x-icon size>` an icon's; anything else is a length in your own CSS",
"tailwind/sizing.blade.php:1 Tailwind sizing utility `max-w-md` compiles to nothing — M3 keeps no size scale: `<x-pane width>` sets a content column's measure, `<x-icon size>` an icon's; anything else is a length in your own CSS",
"tailwind/sizing.blade.php:2 Tailwind sizing utility `size-4` compiles to nothing — M3 keeps no size scale: `<x-pane width>` sets a content column's measure, `<x-icon size>` an icon's; anything else is a length in your own CSS",
]);
});
@@ -240,7 +235,7 @@ it('sends hidden to hide-below/hide-from and every other display utility to a pl
$violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/tailwind/display.blade.php'))->violations());
expect($violations)->toBe([
"tailwind/display.blade.php:1 Tailwind's `hidden` compiles to nothing — use a layout component's `hide-below`/`hide-from` prop, or the reset's `[hidden]` attribute",
"tailwind/display.blade.php:1 Tailwind's `hidden` compiles to nothing — use a layout component's `hide-below`/`hide-from` prop, the `hidden` attribute (the reset keeps it hidden), or `x-show`",
'tailwind/display.blade.php:1 Tailwind display utility `block` compiles to nothing — write the `display` rule in your own CSS',
'tailwind/display.blade.php:2 Tailwind display utility `inline-block` compiles to nothing — write the `display` rule in your own CSS',
'tailwind/display.blade.php:2 Tailwind display utility `invisible` compiles to nothing — write the `display` rule in your own CSS',
@@ -264,7 +259,7 @@ it('exempts a class the application\'s own CSS declares, even when it is Tailwin
$violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/exempt'))->violations());
expect($violations)->toBe([
"exempt/view.blade.php:1 Tailwind spacing utility `mt-2` compiles to nothing — use a layout component's `gap`/`padding` prop (`<x-stack gap>`, `<x-surface padding>`), or `var(--md-sys-measurement-space*)` in your own CSS",
"exempt/view.blade.php:1 Tailwind spacing utility `mt-2` compiles to nothing — space between siblings is a layout component's `gap=\"space100\"` (8px); any other margin is `var(--md-sys-measurement-space100)` in your own CSS",
]);
});
@@ -274,7 +269,9 @@ it('reports an arbitrary [] value once, whatever utility it modifies, and strips
expect($violations)->toBe([
'tailwind/arbitrary.blade.php:1 Tailwind arbitrary value `top-[10px]` compiles to nothing — write the literal value in your own CSS, or use an M3 token',
'tailwind/arbitrary.blade.php:1 Tailwind arbitrary value `grid-cols-[1fr_2fr]` compiles to nothing — write the literal value in your own CSS, or use an M3 token',
'tailwind/arbitrary.blade.php:2 Tailwind layout utility `flex` compiles to nothing — use `<x-row>`, `<x-grid>` or `<x-stack>` and their `gap`/`align`/`justify`/`columns` props',
'tailwind/arbitrary.blade.php:2 Tailwind layout utility `flex` compiles to nothing — use `<x-row>` (`gap`, `align`, `justify`, `wrap`, `stack-below`), or `<x-stack>` for a column',
'tailwind/arbitrary.blade.php:4 Tailwind arbitrary property `[--material-bottom-bar:5rem]` compiles to nothing — write `--material-bottom-bar` in your own CSS',
"tailwind/arbitrary.blade.php:4 Tailwind arbitrary property `[font-variation-settings:'ROND'_100]` compiles to nothing — write `font-variation-settings` in your own CSS",
]);
});
@@ -304,6 +301,76 @@ it('leaves every role alone until an application forbids one', function () {
]);
});
it('names the md-* class or token for a 1.x utility that compiled through the package\'s Tailwind theme', function () {
$violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/tailwind/one-x.blade.php'))->violations());
expect($violations)->toBe([
'tailwind/one-x.blade.php:1 1.x utility `type-body-md` compiles to nothing — use `md-type-body-md` (text.css)',
'tailwind/one-x.blade.php:1 1.x utility `type-emphasized-title-lg` compiles to nothing — use `md-type-emphasized-title-lg` (text.css)',
'tailwind/one-x.blade.php:1 1.x utility `focus-ring` compiles to nothing — use `md-focus-ring` (interaction.css)',
'tailwind/one-x.blade.php:1 1.x utility `state-layer` compiles to nothing — use `md-state-layer` (interaction.css)',
'tailwind/one-x.blade.php:1 1.x utility `link` compiles to nothing — use `md-link` (interaction.css)',
'tailwind/one-x.blade.php:2 1.x utility `rounded-corner-lg` compiles to nothing — use `var(--md-sys-shape-corner-lg)` in your own CSS, or `<x-surface corner="lg">`',
'tailwind/one-x.blade.php:2 1.x utility `rounded-t-corner-xl-increased` compiles to nothing — use `var(--md-sys-shape-corner-xl-increased)` in your own CSS, or `<x-surface corner="xl-increased">`',
'tailwind/one-x.blade.php:2 1.x utility `shadow-elevation-2` compiles to nothing — use `var(--md-sys-elevation-2)` in your own CSS',
'tailwind/one-x.blade.php:2 1.x utility `ease-spatial-fast` compiles to nothing — pair `var(--md-sys-motion-spatial-fast)` with `var(--md-sys-motion-spatial-fast-duration)` in your own `transition`',
'tailwind/one-x.blade.php:2 1.x utility `ease-emphasized-decelerate` compiles to nothing — use `var(--md-sys-motion-easing-emphasized-decelerate)` in your own `transition`',
'tailwind/one-x.blade.php:2 Tailwind custom-property utility `duration-(--md-sys-motion-spatial-fast-duration)` compiles to nothing — write `var(--md-sys-motion-spatial-fast-duration)` in your own CSS',
]);
});
it('reports position, border, effect, interactivity and text utilities with the rule to write instead', function () {
$violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/tailwind/utilities.blade.php'))->violations());
expect($violations)->toBe([
"tailwind/utilities.blade.php:1 Tailwind position utility `relative` compiles to nothing — write `position` in your own CSS (a FAB goes in `<x-scaffold>`'s `fab` slot)",
'tailwind/utilities.blade.php:1 Tailwind inset utility `inset-0` compiles to nothing — write the offset in your own CSS, from `var(--md-sys-measurement-space*)` where it is a spacing step',
'tailwind/utilities.blade.php:1 Tailwind inset utility `-top-2` compiles to nothing — write the offset in your own CSS, from `var(--md-sys-measurement-space*)` where it is a spacing step',
'tailwind/utilities.blade.php:1 Tailwind z-index utility `z-10` compiles to nothing — write `z-index` in your own CSS',
'tailwind/utilities.blade.php:1 Tailwind overflow utility `overflow-hidden` compiles to nothing — write `overflow` in your own CSS',
"tailwind/utilities.blade.php:1 Tailwind flex/grid item utility `shrink-0` compiles to nothing — the layout components arrange their children; an item's own `flex`, `order` or `grid-column` is a rule in your own CSS",
"tailwind/utilities.blade.php:1 Tailwind flex/grid item utility `col-start-2` compiles to nothing — the layout components arrange their children; an item's own `flex`, `order` or `grid-column` is a rule in your own CSS",
"tailwind/utilities.blade.php:1 Tailwind flex/grid item utility `justify-self-end` compiles to nothing — the layout components arrange their children; an item's own `flex`, `order` or `grid-column` is a rule in your own CSS",
"tailwind/utilities.blade.php:1 Tailwind's `container` compiles to nothing — use `<x-pane width>`, which sets M3's margins and a measure",
'tailwind/utilities.blade.php:2 Tailwind border utility `border` compiles to nothing — a line is `<x-divider>` or `<x-surface outlined>`; any other border is your own CSS, in `var(--md-sys-color-outline-variant)`',
'tailwind/utilities.blade.php:2 Tailwind border utility `border-t-2` compiles to nothing — a line is `<x-divider>` or `<x-surface outlined>`; any other border is your own CSS, in `var(--md-sys-color-outline-variant)`',
'tailwind/utilities.blade.php:2 Tailwind radius utility `rounded` compiles to nothing — use `var(--md-sys-shape-corner-xs)` in your own CSS, or `<x-surface corner="xs">`',
'tailwind/utilities.blade.php:2 Tailwind shadow utility `shadow` compiles to nothing — use `var(--md-sys-elevation-*)` in your own CSS',
"tailwind/utilities.blade.php:2 Tailwind outline utility `outline-none` compiles to nothing — M3's focus indicator is `md-focus-ring` (interaction.css); any other outline is your own CSS",
"tailwind/utilities.blade.php:2 Tailwind outline utility `ring-2` compiles to nothing — M3's focus indicator is `md-focus-ring` (interaction.css); any other outline is your own CSS",
'tailwind/utilities.blade.php:2 Tailwind motion utility `transition` compiles to nothing — pair `var(--md-sys-motion-spatial-*)`/`var(--md-sys-motion-effects-*)` with its `-duration` in your own `transition` or `animation`',
"tailwind/utilities.blade.php:2 Tailwind opacity utility `opacity-50` compiles to nothing — write `opacity` in your own CSS (M3's disabled content is 38 %)",
'tailwind/utilities.blade.php:2 Tailwind effect utility `-rotate-45` compiles to nothing — write the rule in your own CSS',
'tailwind/utilities.blade.php:2 Tailwind interactivity utility `cursor-pointer` compiles to nothing — write the rule in your own CSS',
'tailwind/utilities.blade.php:2 Tailwind interactivity utility `select-none` compiles to nothing — write the rule in your own CSS',
'tailwind/utilities.blade.php:3 Tailwind media utility `aspect-video` compiles to nothing — write `aspect-ratio`/`object-fit` in your own CSS',
'tailwind/utilities.blade.php:3 Tailwind media utility `object-cover` compiles to nothing — write `aspect-ratio`/`object-fit` in your own CSS',
'tailwind/utilities.blade.php:3 Tailwind text utility `font-mono` compiles to nothing — write the rule in your own CSS',
"tailwind/utilities.blade.php:3 Tailwind's `font-sans` compiles to nothing — the foundation already sets the brand typeface; any other `font-family` is your own CSS",
"tailwind/utilities.blade.php:3 Tailwind's `underline` compiles to nothing — `md-link` draws a link (interaction.css); any other decoration is your own CSS",
'tailwind/utilities.blade.php:3 Tailwind text utility `uppercase` compiles to nothing — write the rule in your own CSS',
"tailwind/utilities.blade.php:3 Tailwind's `text-end` compiles to nothing — use `md-text-end` (text.css)",
'tailwind/utilities.blade.php:3 Tailwind text utility `list-disc` compiles to nothing — write the rule in your own CSS',
'tailwind/utilities.blade.php:3 Tailwind display utility `table` compiles to nothing — write the `display` rule in your own CSS',
'tailwind/utilities.blade.php:3 Tailwind background utility `bg-clip-text` compiles to nothing — write the rule in your own CSS',
]);
});
it('reads class lists in Alpine, Livewire and PHP bindings, but not a string compared in a condition', function () {
$violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/tailwind/bindings.blade.php'))->violations());
expect($violations)->toBe([
"tailwind/bindings.blade.php:1 Tailwind's `hidden` compiles to nothing — use a layout component's `hide-below`/`hide-from` prop, the `hidden` attribute (the reset keeps it hidden), or `x-show`",
"tailwind/bindings.blade.php:1 Tailwind opacity utility `opacity-50` compiles to nothing — write `opacity` in your own CSS (M3's disabled content is 38 %)",
'tailwind/bindings.blade.php:2 Tailwind motion utility `transition` compiles to nothing — pair `var(--md-sys-motion-spatial-*)`/`var(--md-sys-motion-effects-*)` with its `-duration` in your own `transition` or `animation`',
'tailwind/bindings.blade.php:2 Tailwind effect utility `scale-95` compiles to nothing — write the rule in your own CSS',
'tailwind/bindings.blade.php:3 Tailwind spacing utility `gap-2` compiles to nothing — use `gap="space100"` (8px) on `<x-row>`, `<x-stack>`, `<x-grid>` or `<x-feed>`',
"tailwind/bindings.blade.php:4 Tailwind spacing utility `mt-2` compiles to nothing — space between siblings is a layout component's `gap=\"space100\"` (8px); any other margin is `var(--md-sys-measurement-space100)` in your own CSS",
'tailwind/bindings.blade.php:6 Tailwind layout utility `flex` compiles to nothing — use `<x-row>` (`gap`, `align`, `justify`, `wrap`, `stack-below`), or `<x-stack>` for a column',
'tailwind/bindings.blade.php:2 value outside the M3 scale `ease-out` — pair `var(--md-sys-motion-spatial-*)`/`var(--md-sys-motion-effects-*)` with its `-duration` in your own `transition`',
]);
});
it('bans any further pattern', function () {
$violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/views'))
->forbid('/\bfocus-ring\b/', 'a retired utility')