Styling (Tailwind v4)

Tailwind v4 is auto-loaded in every web app's Vite pipeline. The mandatory @source glob, @theme design tokens, and the two silent-failure gotchas (the framework root is .framework/, not src/; a second @theme after @layer is dropped).

Every Voltro web app's Vite pipeline auto-loads @tailwindcss/vite. Apps that don't use Tailwind pay no runtime cost (the plugin emits nothing when no @import "tailwindcss" appears in any CSS file).

To use it:

/* src/globals.css */
@import "tailwindcss";

/* IMPORTANT: the framework's Vite root is `<app>/.framework/`, not
   `<app>/src/`. Without @source, Tailwind's content scanner misses every .tsx
   file under src/ — you get an empty `@layer utilities` and zero applied
   styles. The path is relative to THIS css file. */
@source "./**/*.{tsx,ts,jsx,js}";

@theme {
  --color-background: #0a0a0a;
  --color-foreground: #fafafa;
  --radius: 0.5rem;
}
// src/pages/layout.tsx
import '../globals.css'

Tailwind v4's @theme block doubles as the framework's design-tokens surface — define your colours / radii / fonts there once and they become available as bg-background, text-foreground, etc. The shadcn convention works directly on top: copy a component's source, the classes resolve.

Gotcha: keep ALL @theme blocks ABOVE any @layer rules in the same stylesheet. A second @theme block placed AFTER @layer base is silently dropped by Tailwind v4 — none of its tokens are emitted.

Using @voltro/ui-shadcn — the kit @source is mandatory

If your app imports @voltro/ui-shadcn/tokens.css, you MUST declare a SECOND @source pointing at the kit's source — otherwise every class that exists ONLY inside a kit component (animations like motion-safe:animate-mesh-drift-a, motion-safe:animate-twinkle, kit-internal prose variants) is silently dropped from the generated CSS. The components mount and the keyframes register, but the animate-* utility classes never resolve — no warning is emitted.

/* src/globals.css — app uses kit compositions */
@import "@voltro/ui-shadcn/tokens.css";

@source "./**/*.{tsx,ts,jsx,js}";
@source "../node_modules/@voltro/ui-shadcn/src/**/*.{tsx,ts,jsx,js}";

Why: the kit's tokens.css ships its own @source "./**/*", but @source paths resolve relative to the IMPORTING css file — so once your globals.css imports the kit, the kit's ./**/* glob expands to YOUR app's src, not the kit's. The kit's own components are then never scanned. Declaring the explicit kit path closes the gap — the published package ships its src/ precisely so this glob matches (workspace link and npm install alike).

How to verify: curl -sS http://localhost:<port>/@fs/<abs>/src/globals.css | grep animate- should list every kit animation utility you use. If a class is missing, the @source is misconfigured.