Shared foundation: The core design ethic, token reference, surface primitives, color system, form primitives, and accessibility requirements are documented in the shared design system. This document covers AiHordeFrontpage-specific extensions and patterns built on top of that foundation. For the CSS class catalog, see component-patterns.md.
- Design System Reference
The site uses a glassmorphism-leaning surface system: translucent layers, restrained blur, and soft depth. The goal is hierarchy and polish, not decoration for its own sake.
- Use translucency deliberately: Surfaces should separate layers without making text or controls hard to read.
- Let elevation come from blur and layered shadow: Stronger blur and heavier shadows signal more important surfaces.
- Keep borders light: Prefer translucent borders over heavy outlines.
- Design light and dark together: Every glass surface needs a paired dark-mode treatment.
- Prefer hierarchy over novelty: Stronger treatments belong on modals, popovers, active tabs, and primary panels — not every element.
/* Glass surfaces */
--color-glass-surface: rgb(255 255 255 / 0.6);
--color-glass-surface-elevated: rgb(255 255 255 / 0.75);
--color-glass-surface-heavy: rgb(255 255 255 / 0.85);
--color-glass-border: rgb(255 255 255 / 0.35);
--color-glass-border-subtle: rgb(255 255 255 / 0.18);
--color-glass-highlight: rgb(255 255 255 / 0.5);
/* Blur radii */
--blur-glass-sm: 8px; /* Inline elements, badges, stat boxes */
--blur-glass-md: 16px; /* Cards, panels, tab bars */
--blur-glass-lg: 24px; /* Modals, overlays */
/* Layered shadows */
--shadow-glass: /* Base resting state */ --shadow-glass-hover:
/* Hovered / interactive state */
--shadow-glass-elevated: /* Modals, popovers, high-elevation */
--shadow-glass-inset: /* Inner top highlight for extra depth */
/* Focus rings */ --shadow-focus-blue: 0 0 0 3px
color-mix(in srgb, var(--color-brand-blue) 30%, transparent);
--shadow-focus-purple: 0 0 0 3px
color-mix(in srgb, var(--color-brand-purple) 30%, transparent);
/* Transition tokens */
--transition-fast: 150ms;
--transition-normal: 200ms;
--transition-slow: 300ms;All tokens are defined in src/styles/_theme.css using Tailwind v4's @theme directive.
| Class | Purpose | Blur |
|---|---|---|
.surface-glass |
Shared frosted base for section-level surfaces | sm |
.surface-glass--elevated |
Stronger glass surface for more prominent containers | sm |
.surface-glass--nested |
Inner field/group surface without blur | none |
.surface-glass--subtle |
Nested panel surface for secondary containment | none |
.surface-glass--hero |
Gradient hero-stage glass surface | md |
.surface-glass--accent |
Gradient accent surface for intro/identity panels | inherited |
.surface-floating |
Shared floating panel surface for menus and popovers | md |
Start from these when building new surfaces. Layer a feature-semantic class on top for domain meaning.
| Class | Purpose |
|---|---|
.details-tabs--glass |
Frosted glass tab bar |
.details-tabs--connected |
Removes bottom margin & radius so tab bar joins panel |
.details-summary--glass |
Frosted summary stat block |
| Class | Purpose |
|---|---|
.tab-content-panel |
Glass container below major tabs — "folder tab" effect |
.tab-sub-panel |
Nested glass-bordered panel wrapping sub-tab content |
.details-toolbar |
Sticky glass action bar for non-tab controls |
These remain valid template-facing APIs. Use the feature name when correct, but build on top of the primitive stack:
- Layout/containers:
.card,.panel,.modal-panel,.tab-content-panel,.tab-sub-panel,.details-toolbar - Messaging/emphasis:
.callout,.callout-accent,.callout-info,.warning-banner,.info-box - Homepage/promo:
.hero-glass-stage,.intro-feature-card,.intro-link-badge,.beginner-banner - Data/list:
.data-item-box,.item-list-row,.network-status-panel,.team-card - Floating/nav:
.nav-shell,.filter-autocomplete-dropdown
Compose a semantic wrapper over an existing primitive. Only add a new material definition when no existing primitive fits.
.my-surface {
border-radius: 1rem;
padding: 1rem;
}- Don't stack blur on nested surfaces without clear reason.
- Don't use
blur(24px)for normal cards — reserve it for overlays. - Don't skip
-webkit-backdrop-filter. - Don't keep translucency if it hurts readability or contrast.
- Don't apply glass treatment to tiny controls just because it's available.
Three layers:
- Tokens (
_theme.css) — glass opacity, borders, gradient endpoints, shadow depth. - Shared primitives (
_cards.css,_forms.css) — reusable surface roles:.surface-glass,.surface-glass--nested,.form-section-shell. - Feature-semantic classes —
.shared-key-form-panel,.hero-glass-stage,.tab-content-panel. Only add domain meaning or local layout.
Feature classes should not invent new glass values when an existing primitive matches. If a new treatment is needed, add or adjust the token and primitive layer first.
| Status | Color Family | Usage |
|---|---|---|
| Danger | red-* |
Errors, destructive actions, critical alerts |
| Warning | amber-* |
Caution, pending actions, maintenance states |
| Info | blue-* |
Informational content, neutral highlights |
| Success | green-* |
Completed actions, healthy states, confirmations |
- Alerts (
_alerts.css):.alert--danger= red,.alert--warning= amber,.alert--info= blue,.alert--success= green - Badges (
_badges.css): Same color mapping. - Worker indicators (
_data-display.css): Same families — red for errors, green for healthy, amber for warnings.
- Domain identities: purple = image, blue = text, green = alchemy
- Brand accents: purple = kudos/premium, indigo = secondary brand
- Categorical badges: teal, pink, orange for tagging without status connotation
| Domain | Color | CSS Classes |
|---|---|---|
| Image generation (Dreamers) | Purple | .domain-tint--image, .domain-label--image |
| Text generation (Scribes) | Blue | .domain-tint--text, .domain-label--text |
| Alchemy (Alchemists) | Green | .domain-tint--alchemy, .domain-label--alchemy |
Domain tinting: subtle left-border accent plus soft gradient background, not full-surface color.
Rules:
- Keep domain tinting light — preserve text contrast.
- Apply consistently across cards, labels, and badges.
- Pair color cues with text (don't rely on color alone).
- Use
.domain-tint--combined(red) for multi-domain cards.
The page alternates between .section-primary and .section-secondary. Keep transitions subtle in light mode and more pronounced in dark mode.
.hero-glass-stage is for hero or orientation surfaces, not routine content blocks. Use sparingly:
.hero-glass-stage {
background: linear-gradient(
135deg,
rgb(255 255 255 / 0.55),
rgb(249 250 251 / 0.4)
);
backdrop-filter: blur(var(--blur-glass-md));
border: 1px solid var(--color-glass-border);
box-shadow: var(--shadow-glass), var(--shadow-glass-inset);
}| Class | Purpose |
|---|---|
.form-section-shell |
Outer section container for a grouped decision area |
.form-section-shell__header |
Header stack: eyebrow, title, framing copy |
.form-section-shell__grid |
Responsive field grid inside a section |
.form-field-shell |
Inner grouped field container |
.form-field-shell--full |
Full-width field card spanning the grid |
.form-field-shell__header |
Label + state badge row |
.form-field-shell__footer |
Helper text + secondary control row |
.form-field-shell__footer--stacked |
Footer variant for presets |
.form-field-shell__footer-row |
Single row inside a stacked footer |
.form-state-badge |
Small status badge for contextual field states |
.form-actions-bar |
Closing actions row with helper copy and buttons |
- Group fields by decision, not by data type.
- Give each section a visible container and short framing text.
- Keep section containers visually stronger than field containers.
- Keep helper text attached to the control it explains.
- Represent states with explicit labels/badges, not hidden conventions.
- Use presets only where they materially reduce decision cost.
- End forms with a clear review-and-act zone.
<form class="domain-form">
<section class="form-section form-section--intro">
<div class="form-section__header">
<p class="form-section__eyebrow">Section</p>
<h4 class="section-title-sm">Form title</h4>
<p class="text-secondary text-sm">Short framing copy.</p>
</div>
<div class="form-group-card form-group-card--full">
<!-- primary identity or context field -->
</div>
</section>
<section class="form-section">
<div class="form-section__header">
<h5 class="section-title-sm">Decision group</h5>
<p class="text-secondary text-sm">Explain the tradeoff.</p>
</div>
<div class="form-section__grid">
<div class="form-group-card">
<label class="form-label">Field</label>
<input class="form-input" type="number" />
<div class="form-group-card__footer">
<p class="text-secondary text-xs">Helper text.</p>
</div>
</div>
</div>
</section>
<div class="form-review-bar">
<!-- helper summary + primary action -->
</div>
</form>Theme tokens are defined in CSS using @theme, not a JavaScript config:
@theme {
--color-brand-blue: #1d4ed8;
--color-surface-primary: rgb(255 255 255);
}Components use @layer components. Custom utilities use @utility.
Reference tokens via CSS variables:
.my-component {
background-color: var(--color-surface-primary);
}Or use auto-generated Tailwind utilities:
<div class="bg-surface-primary border-edge-primary shadow-card"></div>