- Fix Alpine "Invalid or unexpected token" on file/service/key actions: @js()
does NOT compile inside a Blade component (x-btn) attribute, so a literal
@js(...) reached the DOM and Alpine choked on it. Switched all 10 wire:click
arguments to loop-index lookups (files: open/go/download/edit/confirmDelete;
services: confirm; keys: confirmKeyRemoval) — the component resolves the value
server-side by index. {{ $loop->index }} compiles in component attributes; @js
does not.
- Self-host fonts (R14): Chakra Petch / Space Grotesk / JetBrains Mono as local
.woff2 in resources/fonts/, declared via @font-face in app.css, Vite-bundled
with relative urls so they resolve in dev AND the prod build. No Google Fonts
/ CDN link or @import. New rule R14 added to rules.md + CLAUDE.md.
- Auth redesign (split-brand, per reference): new auth layout with a brand panel
(faux terminal + glow mesh, hidden below lg) + redesigned login,
two-factor-challenge, two-factor-setup, password-change forms.
- x-btn: add size="lg" (h-11, >=44px touch target) for the full-width auth CTA;
one shared button component, no bespoke styles.
- Remove unused Laravel welcome.blade.php (was full of raw hex — R3 cleanup).
Verified (R12): /login 200 / 0 console errors, fonts load (Chakra+Grotesk+JB),
brand panel visible @1440; file-editor REAL click -> modal opens, textarea
renders, 0 Alpine errors; editor load/save roundtrip (/etc/hostname='debian');
all 7 routes 200 / 0 console errors. Full rules audit R1-R14 clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Route switching was slow because each page did its SSH reads inside mount(),
blocking the response. Now mount() only sets cheap shell state and the SSH read
runs in load() via wire:init — the page shell + skeletons render instantly and
content streams in.
- Lazy-load Dashboard (services), Services, Files, Server-Details: SSH moved from
mount() to load(); skeleton placeholders (new <x-skeleton>) while !$ready.
- Modal container: z-10 -> z-50 (was rendering *under* the z-40 sidebar) and a
real max-w-lg (the dynamic modalWidth classes were never generated by Tailwind,
so modals spanned full width). This also fixes the "flash + disappear".
- Modal/action buttons: normalize size (min-h-11 uppercase font-display -> h-9
text-sm font-medium) and add a wire:loading spinner + disabled-while-running on
the confirm/save actions (no double-submit, clear feedback).
- Server-Details gauges keep wire:poll (live) but no longer block initial render.
Verified: every page renders ready=false + skeleton with no SSH, then load()
populates real data; modal buttons carry the spinner.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
From clusev-template/reference: void background with a fine dot-grid + orange top
vignette, panel elevation (shadow-panel token), tonal scrollbars, a left accent
bar + accent icon on the active nav item, status-dot + brandmark glows, and a
motion-safe ping. @theme/tokens only — no inline styles.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Focus-visible token ring + prefers-reduced-motion guard (app.css).
- Lift ink-3/ink-4 to WCAG-AA text contrast.
- Touch targets >=44px (topbar, sidebar, dashboard buttons).
- Off-canvas drawer removed from tab order when closed (breakpoint-aware inert)
+ sidebar aria-label.
- Live chart: NaN guard on incoming cpu; Echo.leave('metrics') + unbind on
destroy (no subscription leak under wire:navigate).
- KPI progress bar follows the tone (status triad), not always accent.
- Resource rings bound to real server data with threshold-based tone.
- docs/v1-ui-review.md: full adversarial review.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>