with one click
styling
CSS and Tailwind, cn(), flex layouts. Use for "style this", "fix the CSS", "add classes", "not scrolling", "overflow", Tailwind utilities.
Menu
CSS and Tailwind, cn(), flex layouts. Use for "style this", "fix the CSS", "add classes", "not scrolling", "overflow", Tailwind utilities.
| name | styling |
| description | CSS and Tailwind, cn(), flex layouts. Use for "style this", "fix the CSS", "add classes", "not scrolling", "overflow", Tailwind utilities. |
| metadata | {"author":"epicenter","version":"1.0"} |
When styling behavior depends on shadcn-svelte component structure, class merging, variants, or Bits UI composition, use source-backed grounding before relying on memory. If DeepWiki MCP is available, ask a narrow question against huntabyte/shadcn-svelte; for extras component behavior, ask against ieedan/shadcn-svelte-extras. If DeepWiki is unavailable or the repo is not indexed, use upstream source or official docs directly. Treat DeepWiki as orientation, then verify decisive details against local @epicenter/ui wrappers, installed types, source, or official docs before changing code.
Skip DeepWiki for ordinary Tailwind utilities and repo-local layout rules already documented below.
Use this pattern when you need to:
disabled and Tailwind variants.Avoid creating unnecessary wrapper divs. If classes can be applied directly to an existing semantic element with the same outcome, prefer that approach.
<main class="flex-1 mx-auto max-w-7xl">
{@render children()}
</main>
<main class="flex-1">
<div class="mx-auto max-w-7xl">
{@render children()}
</div>
</main>
This principle applies to all elements where the styling doesn't conflict with the element's semantic purpose or create layout issues.
cn() utility from $lib/utils for combining classes conditionallytailwind-variants for component variant systemsbackground/foreground convention for colorsdisabled + Tailwind VariantsWhen an interactive element can be non-interactive (empty section, loading state, no items), use the HTML disabled attribute instead of JS conditional guards. Pair it with Tailwind's enabled: and group-disabled: variants.
disabled Over JS Guardsdisabled natively blocks clicks: no if (!hasItems) return needed:disabled CSS pseudo-class for stylingenabled: and group-disabled: variants compose cleanly<!-- The button disables itself when count is 0 -->
<button
class="group enabled:cursor-pointer enabled:hover:opacity-80"
disabled={item.count === 0}
onclick={toggle}
>
{item.label} ({item.count})
<ChevronIcon class="group-disabled:invisible" />
</button>
enabled:cursor-pointer: pointer cursor only when clickableenabled:hover:bg-accent/50: hover effects only when interactivegroup-disabled:invisible: hide child elements (e.g., expand chevron) when parent is disableddisabled:opacity-50: dim the element when disabled<!-- Don't do this: JS guard duplicates what disabled does natively -->
<button
class="cursor-pointer hover:opacity-80"
onclick={() => { if (item.count > 0) toggle(); }}
>
The JS guard leaves cursor-pointer and hover:opacity-80 active on a non-interactive element. The user sees a clickable button that does nothing. Use disabled and let the browser + CSS handle it.
When a flex child uses h-full (height: 100%) but shares a flex column with siblings (headers, toolbars, footers), it computes to the full parent height: overflowing past siblings instead of taking the remaining space. The content gets clipped or pushes the layout past the viewport, and scroll areas inside never activate.
This is the single most common layout bug in this codebase. It appears whenever you have:
Resizable.Pane (paneforge) that needs to scrollScrollArea.Root (bits-ui) or overflow-auto div inside a flex column with a header/toolbar siblingflex-1 min-h-0 overflow-hiddenReplace h-full with these three utilities on the flex child that contains scrollable content. Each solves a distinct problem:
| Utility | What it does | Why it's needed |
|---|---|---|
flex-1 | Take remaining space after siblings | h-full = 100% of parent, ignoring siblings. flex-1 = remaining space. |
min-h-0 | Allow shrinking below content size | Flex items default to min-height: auto, preventing them from being smaller than their content. |
overflow-hidden | Establish a bounded height context | Without this, children with overflow-auto or ScrollArea have no height ceiling to scroll against. |
All three are required. Missing any one breaks the fix:
flex-1: element is still 100% of parent, overflows siblingsmin-h-0: element refuses to shrink, content pushes it talleroverflow-hidden: inner scroll containers have no bounded ancestor, so they expand instead of scrolling<!-- BROKEN: h-full = 100% of parent, ignores the toolbar sibling -->
<main class="flex h-full flex-col overflow-hidden">
<div class="border-b px-4 py-2">Toolbar</div>
<MyScrollableContent class="h-full" /> <!-- overflows past main -->
</main>
<!-- FIXED: flex-1 takes remaining space, overflow-hidden bounds it -->
<main class="flex h-full flex-col overflow-hidden">
<div class="border-b px-4 py-2">Toolbar</div>
<MyScrollableContent class="flex-1 min-h-0 overflow-hidden" />
</main>
Paneforge Pane components set width via flex ratios but do not constrain height or clip overflow. Any scrollable content inside a Pane needs the full flex-1 min-h-0 overflow-hidden chain on its root element:
<Resizable.Pane defaultSize={80}>
<!-- Pane provides no height constraint or overflow clipping -->
<div class="flex flex-1 min-h-0 flex-col overflow-hidden">
<div class="border-b">Header</div>
<div class="flex-1 overflow-y-auto">
<!-- this content now scrolls -->
</div>
</div>
</Resizable.Pane>
ScrollArea.Root renders with position: relative and its viewport uses height: 100%. This breaks the flex sizing chain: the viewport's percentage height resolves against the relative parent, which has no explicit height in a flex context. The content expands instead of scrolling.
Two options:
overflow-y-auto on a div with flex-1 min-h-0 (simpler, always works)ScrollArea.Root in a div with flex-1 min-h-0 overflow-hidden to give it a bounded ancestor<!-- Option 1: Plain overflow (preferred) -->
<div class="flex-1 overflow-y-auto">
{#each items as item}
<div>{item.name}</div>
{/each}
</div>
<!-- Option 2: ScrollArea with bounded wrapper -->
<div class="flex-1 min-h-0 overflow-hidden">
<ScrollArea.Root class="h-full">
{#each items as item}
<div>{item.name}</div>
{/each}
</ScrollArea.Root>
</div>
If you write h-full on a flex child that has siblings in the same flex column, stop and replace it with flex-1 min-h-0 overflow-hidden. The h-full pattern only works when the element is the sole child of its flex parent.
Autumn billing in Epicenter: `autumn.config.ts`, `autumn-js` credit checks, `atmn` CLI, plan gates, and metered AI usage. Use when changing billing, pricing, credits, plan access, refunds, or usage events.
Epicenter UI component selection and composition patterns for Svelte apps using packages/ui. Use when choosing or reviewing @epicenter/ui components, loading states, empty states, skeletons, spinners, command empty states, action pending UI, table/list no-row states, button tooltips, wrapper minimization, or replacing ad hoc UI such as Loading... text, custom loading dots, raw animate-pulse placeholders, or one-off centered status markup.
Visual design direction for new or redesigned frontend surfaces: layout, typography, color, motion, and anti-generic aesthetics. Use when designing pages, dashboards, posters, marketing surfaces, or exploratory UI variations.
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
Drizzle ORM patterns: schema definitions, Drizzle Kit migrations, query builders, type branding, custom types, SQLite, Postgres, D1, and Turso/libSQL boundaries. Use when mentioning Drizzle, drizzle-orm, DB schemas, migrations, branded column types, or typed SQL queries.
Encryption: HKDF, XChaCha20-Poly1305, blob formats, key hierarchy/rotation. Use for "encrypt this", "key management", crypto primitives, EncryptedBlob.