@@ -433,15 +433,156 @@ are arrays of `StyleVariable` overrides. Theme CSS rendered via
433433` render_theme_style() ` with higher specificity (default ` :root:root ` ) to
434434override bundled theme variables regardless of CSS insertion order.
435435
436+ ## Component Styling Philosophy
437+
438+ The fuz stack's core styling principle: ** components should have minimal custom
439+ CSS, delegating styling to fuz_css** . Most components need zero or near-zero
440+ lines in their ` <style> ` block. The design system exists so components don't
441+ reinvent layout, spacing, color, or typography.
442+
443+ ### What "Minimal Styles" Looks Like
444+
445+ Well-designed fuz components (fuz_ui, zzz, fuz_code, fuz_gitops) share these
446+ traits:
447+
448+ - ** Many components have no ` <style> ` block at all** — all styling comes from
449+ utility classes and semantic HTML
450+ - ** When ` <style> ` exists, it's 5-30 lines** — only component-specific layout
451+ logic (positioning, complex pseudo-states, responsive breakpoints)
452+ - ** All colors, spacing, typography come from design tokens** — never hardcoded
453+ values
454+ - ** Layout uses composites and utilities** — ` box ` , ` row ` , ` column ` , ` panel ` ,
455+ ` p_md ` , ` gap_lg ` instead of manual flex declarations
456+
457+ ``` svelte
458+ <!-- GOOD: No <style> block needed — utility classes handle everything -->
459+ <div class="column gap_md p_lg">
460+ <header class="row gap_sm">
461+ <h2>{title}</h2>
462+ <small class="text_50">{subtitle}</small>
463+ </header>
464+ <div class="panel p_md">{@render children()}</div>
465+ </div>
466+ ```
467+
468+ ### Anti-Patterns
469+
470+ These patterns indicate a component is doing too much styling work:
471+
472+ #### Writing flex layout in ` <style> ` instead of using composites
473+
474+ ``` svelte
475+ <!-- BAD: manual flex in <style> -->
476+ <div class="container">...</div>
477+ <div class="header">...</div>
478+ <style>
479+ .container { display: flex; flex-direction: column; gap: var(--space_md); }
480+ .header { display: flex; align-items: center; }
481+ </style>
482+
483+ <!-- GOOD: utility classes -->
484+ <div class="column gap_md">...</div>
485+ <div class="row">...</div>
486+ ```
487+
488+ #### Referencing design tokens in ` <style> ` when a utility class exists
489+
490+ ``` svelte
491+ <!-- BAD: token reference in <style> for something a class does -->
492+ <span class="subtitle">...</span>
493+ <style>
494+ .subtitle { color: var(--text_70); font-size: var(--font_size_sm); }
495+ </style>
496+
497+ <!-- GOOD: utility classes (or semantic HTML) -->
498+ <small class="text_70">...</small>
499+ ```
500+
501+ #### Repeating the same layout patterns across components
502+
503+ If multiple components each define their own ` .sidebar ` , ` .header ` ,
504+ ` .content ` classes with the same flex/padding/border patterns, those
505+ should be utility classes, project ` style.css ` classes, or composites.
506+
507+ #### Hardcoding pixel values
508+
509+ ``` svelte
510+ <!-- BAD: hardcoded pixels -->
511+ <style>
512+ .sidebar { width: 220px; padding-top: 40px; }
513+ </style>
514+
515+ <!-- GOOD: design tokens or CSS custom properties -->
516+ <style>
517+ .sidebar { width: var(--sidebar_width); padding-top: var(--space_xl2); }
518+ </style>
519+ ```
520+
521+ ### When Custom CSS IS Justified
522+
523+ Custom ` <style> ` blocks are appropriate for:
524+
525+ - ** Complex interactive states** — multi-property hover/active/selected
526+ combinations, especially with ` color-mix ` shadows or parent-child selectors
527+ like ` .parent:hover .child ` . Examples: tab shadow state machines,
528+ hover-to-reveal controls.
529+ - ** Structural behavior** — ` flex-direction: column-reverse ` for bottom-up
530+ scrolling, ` position: sticky/absolute/fixed ` with calculated offsets
531+ - ** Responsive layouts** — ` @media ` queries for structural layout changes
532+ - ** Animations/transitions** — ` @keyframes ` , ` transition ` definitions
533+ - ** Rendering contexts** — canvas, 3D, or other surfaces with inherently
534+ custom layout
535+
536+ Even justified custom CSS should use design tokens (` var(--space_md) ` ,
537+ ` var(--border_color) ` ) rather than hardcoded values.
538+
539+ ### Project ` style.css ` for Shared App Patterns
540+
541+ When a pattern recurs across multiple components in one app but isn't
542+ general enough for fuz_css, put it in the project's ` style.css ` (e.g.,
543+ ` src/routes/style.css ` ). This is the right place for app-scoped shared
544+ classes — button variants, layout columns, drag indicators, scroll
545+ shadows, etc.
546+
547+ Mark patterns with ` // TODO upstream ` if they might belong in fuz_css.
548+ This keeps component ` <style> ` blocks focused on truly component-specific
549+ logic while avoiding premature generalization into the design system.
550+
551+ ### Class Naming Conventions
552+
553+ Two naming systems coexist:
554+
555+ - ** fuz_css design tokens** : ` snake_case ` — ` p_md ` , ` color_a_50 ` , ` gap_lg ` ,
556+ ` font_size_sm ` . These are the global vocabulary.
557+ - ** Component-local classes** : ` kebab-case ` — ` nav-separator ` , ` edit-sidebar ` ,
558+ ` character-entry ` . Distinguishes component-scoped styles from design
559+ system classes at a glance.
560+
561+ ``` svelte
562+ <!-- snake_case = fuz_css utility, kebab-case = component-local -->
563+ <div class="column gap_md site-header">
564+ <nav class="row gap_sm nav-links">...</nav>
565+ </div>
566+
567+ <style>
568+ .site-header { position: sticky; top: 0; z-index: 10; }
569+ .nav-links { border-bottom: var(--border_width_1) var(--border_style) var(--border_color); }
570+ </style>
571+ ```
572+
573+ This convention is aspirational — existing components use ` snake_case ` for
574+ component-local classes too. A cross-repo audit will migrate to kebab-case
575+ over time.
576+
436577## When to Use Classes vs Styles
437578
438- | Need | Style tag | Utility class | Inline style |
439- | ---------------------- | --------- | ------------- | ------------ |
440- | Style own elements | ** Best ** | OK | OK |
441- | Style child components | No | ** Yes ** | Limited |
442- | Hover/focus/responsive | Yes | ** Yes** | No |
443- | Runtime dynamic values | No | No | ** Yes** |
444- | IDE autocomplete | ** Yes ** | No | Partial |
579+ | Need | Utility class | Style tag | Inline style |
580+ | ---------------------- | ------------- | --------- | ------------ |
581+ | Style own elements | ** Preferred ** | Complex cases | OK |
582+ | Style child components | ** Yes ** | No | Limited |
583+ | Hover/focus/responsive | ** Yes** | Yes | No |
584+ | Runtime dynamic values | No | No | ** Yes** |
585+ | IDE autocomplete | No | ** Yes ** | Partial |
445586
446587### Rules of Thumb
447588
@@ -453,8 +594,10 @@ override bundled theme variables regardless of CSS insertion order.
453594 and colors (` color_a_50 ` ) maintain consistency; avoid hardcoded values
454595- ** Inline ` style:prop ` for runtime values** — dynamic widths, computed
455596 colors, CSS variable overrides
456- - ** Keep class strings manageable** — if a ` <div> ` accumulates 5+ utility
457- classes, consider a ` <style> ` rule
597+ - ** Utility class strings are fine at length** — 6-12 classes per element is
598+ common and works well. Only move to ` <style> ` when readability suffers
599+ (complex responsive logic, multi-property pseudo-elements) not just because
600+ the class list is long
458601- ** ` <style> ` for responsive layouts** — ` @media ` queries in component styles
459602 are conventional; reserve responsive modifiers for simple one-off overrides
460603
0 commit comments