Enforcement Directive Copied!
This document is the authoritative source of truth for UI implementation in this project.
- Strict Adherence: Strictly follow all rules, constraints, and architectural principles defined here.
- Aesthetic Priority: Maintain a clean and minimalistic style in all UI generations.
- Token Priority: Prioritize design token usage, DaisyUI conventions, and structural integrity.
- No Silent Overrides: Break rules only if explicitly and intentionally instructed. If instructed to override:
- State the overridden rule.
- Explain the architectural impact.
- Confirm intent, then proceed.
Core Principles & Layout Copied!
Aesthetic: Clean & Minimalistic (“Less is More”) Copied!
- Whitespace: Use generous padding/margins. Avoid cluttered layouts.
- Visual Weight: Favor thin borders and subtle shadows over heavy gradients/patterns.
- Typography: Use weight and token colors (Content vs. Content-Secondary) for hierarchy, not just size.
- Interaction: Animations must be subtle, smooth, and fast (150ms-200ms transitions).
Responsive Design & Breakpoints Copied!
Enforce the use of tokens for adjusting design across viewports.
- Large Breakpoint: Use
--breakpoint-lg(CSS equivalent:@media (min-width: 1024px)orlg:modifier in Tailwind). - Max Site Width: Use
--breakpoint-2xl(CSS equivalent:@media (min-width: 1536px)or2xl:modifier). - Centering: As a secondary measure for bounding maximum width on specific components, enforce
mx-auto(e.g.,max-w-screen-2xl mx-auto).
Single Source of Truth & Theme Awareness Copied!
- NEVER hardcode Hex colors or Tailwind gray scales.
- ALWAYS use DaisyUI semantic classes (
bg-base-200,text-base-content) or CSS variables (--color-*). - Every component must automatically adapt to
darkandlightthemes via these tokens. - See Global Theme Configuration section to see all the DaisyUI theme settings.
Class Application & Ordering Copied!
Directly apply CSS utility classes to HTML tags as the primary styling method. Do not abstract into custom CSS unless strictly necessary.
Tailwind/DaisyUI Class Ordering Convention: To maintain readability and token efficiency, order classes logically:
- DaisyUI Base: (
btn,card,menu) - DaisyUI Modifiers: (
btn-primary,card-body) - Layout & Display: (
block,flex,grid,absolute) - Spacing & Sizing: (
w-full,max-w-md,p-4,m-2) - Typography: (
text-lg,font-bold,text-center) - Colors & Backgrounds: (
bg-base-100,text-base-content) - Borders & Effects: (
border,border-theme,shadow-sm) - Responsive & States: (
hover:bg-base-200,lg:p-8,focus-visible:ring)
Class logic extracted for clarity and strict ordering. Order: Base -> Modifiers -> Layout -> Spacing -> Typography -> Colors -> Borders -> States.
Theme & Token Rules Copied!
Contrast & Semantic Pairing Copied!
To ensure accessibility and visual harmony, always pair background semantic colors with their corresponding content tokens. Never use a base content color on a primary background.
As example:
| Color Name | CSS Variable | Usage |
|---|---|---|
| primary | --color-primary | Primary brand color; main accent for the brand. |
| primary-content | --color-primary-content | Foreground content color to use strictly on primary. |
Requirement: If a component uses
bg-primary, any text or icons within it must usetext-primary-contentto guarantee correct contrast ratios.
Custom CSS & Overrides (Astro + Tailwind + DaisyUI) Copied!
First, enforce the use of standard CSS classes. If complex design requires explicitly overriding DaisyUI structure, custom rules must be created under the following constraints:
Safe Customization Pattern Copied!
Custom CSS helpers must complement the framework, not compete with it.
- Keep rules single-responsibility.
- Scope them to theme token alignment.
- Avoid shorthand properties that override multiple CSS behaviors at once.
- Always pair custom helpers with Tailwind directional utilities, never override them.
Component-Level Overrides Copied!
If a component requires structural layout changes:
- Implement them in a component-scoped class (e.g., inside an Astro
<style>block). - Document why the change is required.
- Guiding Question: Does this align the component with the theme system—or does it override how DaisyUI intended the component to behave? If it alters intended behavior, it must be scoped locally and carefully reviewed.
What Must Be Avoided Copied!
- Clutter: Crowding elements without sufficient whitespace padding.
- Hardcoded Values: Hex colors or non-theme structural values.
- Inaccessibility: Missing
aria-labelsor poor contrast ratios (e.g., usingtext-base-contentonbg-primary). - Poor Responsive Design: Missing breakpoint rules or failing to cap widths with
--breakpoint-2xlandmx-auto.
PR Checklist Copied!
- Is the design clean, minimalistic, and utilizing adequate whitespace?
- Are HTML tags styled directly using the correct class ordering convention?
- Are colors correctly paired for contrast (e.g.,
primary+primary-content)? - Does the visual check pass seamlessly in both Light and Dark themes?
- Are structural overrides strictly component-scoped and not leaking globally?
- Is the design fully responsive, respecting
lgand2xlmax-width breakpoints? - Are interactive elements keyboard accessible (
:focus-visible)?
Enforcement Philosophy Copied!
The design system must be theme-driven, consistent, and predictable. If a new design requirement conflicts with these rules, update the theme tokens—not the individual components.
Would you like me to create a reusable Astro component snippet that implements the primary/primary-content pairing and the max-width layout tokens?
Configuration Files Copied!
Shared Theme Definitions Copied!
src/styles/theme.css
@theme {
--font-sans: "Montserrat", ui-sans-serif, system-ui;
--font-display: "NotoSansDisplay", sans-serif;
--font-mono: "FiraCode", ui-monospace, monospace;
--radius-selector: 1rem;
--radius-field: 0.25rem;
--radius-box: 0.5rem;
--size-selector: 0.25rem;
--size-field: 0.25rem;
--border: 1px;
--depth: 1;
--noise: 0;
--dark-mode: selector([data-theme="dark"]);
}Global Theme Configuration Copied!
src/styles/global.css
@import "tailwindcss";
@import "./theme.css";
@plugin "daisyui" {
themes: light, dark;
include:
"button", "card", "drawer", "navbar", "swap", "badge", "menu", "dropdown",
"divider", "timeline", "mockup";
}
@plugin "daisyui/theme" {
name: "dark";
color-scheme: dark;
--color-base-100: oklch(0.15 0.0001 263.28);
--color-base-200: oklch(0.2393 0.0001 263.28);
--color-base-300: oklch(0.3092 0.0001 263.28);
--color-base-content: oklch(0.928 0.0001 263.28);
--color-primary: oklch(0.5333 0.2151 28.1);
--color-primary-content: oklch(1 0.0001 263.28);
--color-secondary: oklch(0.7628 0.1626 69.36);
--color-secondary-content: oklch(0.15 0.0021 286.01);
--color-accent: oklch(0.8338 0.1248 66.87);
--color-accent-content: oklch(0.15 0.0021 286.01);
--color-neutral: oklch(0.285 0.0001 263.28);
--color-neutral-content: oklch(0.928 0.0001 263.28);
--color-info: oklch(0.6531 0.1348 242.7);
--color-info-content: oklch(1 0.0001 263.28);
--color-success: oklch(0.6629 0.1602 152.39);
--color-success-content: oklch(1 0.0001 263.28);
--color-warning: oklch(0.8358 0.1689 91.77);
--color-warning-content: oklch(0.15 0.0021 286.01);
--color-error: oklch(0.6307 0.194 29.43);
--color-error-content: oklch(1 0.0001 263.28);
--color-border: oklch(0.285 0.0001 263.28);
}
@plugin "daisyui/theme" {
name: "light";
color-scheme: light;
--color-base-100: oklch(1 0.0001 263.28);
--color-base-200: oklch(0.9551 0.0001 263.28);
--color-base-300: oklch(0.8945 0.0001 263.28);
--color-base-content: oklch(0.2221 0.0001 263.28);
--color-primary: oklch(0.5434 0.174 29.69);
--color-primary-content: oklch(1 0.0001 263.28);
--color-secondary: oklch(0.7628 0.1626 69.36);
--color-secondary-content: oklch(0.2221 0.0001 263.28);
--color-accent: oklch(0.8338 0.1248 66.87);
--color-accent-content: oklch(0.2221 0.0001 263.28);
--color-neutral: oklch(0.8576 0.0001 263.28);
--color-neutral-content: oklch(0.2221 0.0001 263.28);
--color-info: oklch(0.6531 0.1348 242.7);
--color-info-content: oklch(1 0.0001 263.28);
--color-success: oklch(0.6629 0.1602 152.39);
--color-success-content: oklch(1 0.0001 263.28);
--color-warning: oklch(0.8358 0.1689 91.77);
--color-warning-content: oklch(0.2221 0.0001 263.28);
--color-error: oklch(0.6307 0.194 29.43);
--color-error-content: oklch(1 0.0001 263.28);
--color-border: oklch(0.8576 0.0001 263.28);
}Article Theme Configuration Copied!
src/styles/typography-bundle.css
@import "tailwindcss";
@import "./theme.css";
@plugin "@tailwindcss/typography";
.prose {
font-family: var(--font-sans);
--tw-prose-body: var(--color-base-content);
--tw-prose-headings: var(--color-base-content);
--tw-prose-lead: var(--color-base-content);
--tw-prose-links: var(--color-primary);
--tw-prose-bold: var(--color-base-content);
--tw-prose-counters: var(--color-base-content);
--tw-prose-bullets: var(--color-base-content);
--tw-prose-hr: var(--color-base-300);
--tw-prose-quotes: var(--color-base-content);
--tw-prose-quote-borders: var(--color-primary);
--tw-prose-captions: var(--color-base-content);
--tw-prose-code: var(--color-secondary);
--tw-prose-pre-code: var(--color-base-content);
--tw-prose-pre-bg: var(--color-base-200);
--tw-prose-th-borders: var(--color-base-300);
--tw-prose-td-borders: var(--color-base-200);
}Mockup Code Theme Configuration Copied!
src/styles/mockup-code.css
.mockup-code {
position: relative;
overflow: hidden;
}
.mockup-code .line {
display: block !important;
white-space: pre-wrap !important;
word-break: break-word !important;
padding-left: 3.5rem !important;
padding-right: 20px !important;
text-indent: -3.5rem !important;
line-height: 1.5 !important;
}
.mockup-code .line::before {
content: attr(data-line) !important;
display: inline-block !important;
width: 3.5rem !important;
min-width: 3.5rem !important;
padding-right: 1.25rem !important;
text-align: right !important;
font-size: 0.95em !important;
vertical-align: top !important;
user-select: none;
opacity: 0.4;
}
.mockup-code pre,
.mockup-code code {
background: transparent !important;
padding: 0 !important;
border: none !important;
}
.mockup-code code::before,
.mockup-code code::after {
content: none !important;
}
[data-theme="light"] .mockup-code {
background-color: #f0f2f4 !important;
border-color: #d1d5db !important;
color: #444c56;
}
[data-theme="light"] .mockup-code::before {
content: "";
opacity: 1 !important;
box-shadow:
1.2em 0 0 rgba(0, 0, 0, 0.1),
2.8em 0 0 rgba(0, 0, 0, 0.1),
4.4em 0 0 rgba(0, 0, 0, 0.1) !important;
}
[data-theme="dark"] .mockup-code {
background-color: #121212 !important;
border-color: #2a2a2a !important;
color: #e7e7e7;
}
[data-theme="dark"] .mockup-code span {
color: var(--shiki-dark) !important;
font-style: var(--shiki-dark-font-style) !important;
text-decoration: var(--shiki-dark-text-decoration) !important;
}
[data-theme="dark"] .mockup-code::before {
opacity: 1 !important;
box-shadow:
1.2em 0 0 rgba(160, 160, 160, 0.35),
2.8em 0 0 rgba(160, 160, 160, 0.35),
4.4em 0 0 rgba(160, 160, 160, 0.35) !important;
}Custom Glass Design Copied!
src/styles/glass.css
.glass-surface {
--glass-border-fallback: rgba(0, 0, 0, 0.1);
--glass-bg-fallback: rgba(255, 255, 255, 0.5);
--glass-border-opacity: 0.15;
--glass-bg-opacity: 0.4;
position: relative;
overflow: hidden;
isolation: isolate;
border: 1px solid var(--glass-border-fallback);
border-color: color-mix(
in srgb,
var(--color-base-content, #000),
transparent calc(100% - (var(--glass-border-opacity) * 100%))
);
background-color: var(--glass-bg-fallback);
background-color: color-mix(
in srgb,
var(--color-base-200, #fff),
transparent calc(100% - (var(--glass-bg-opacity) * 100%))
);
background-image: none !important;
-webkit-backdrop-filter: blur(14px);
backdrop-filter: blur(14px);
will-change: transform, box-shadow;
transition:
transform 0.4s cubic-bezier(0.25, 1, 0.5, 1),
box-shadow 0.4s ease,
border-color 0.3s ease;
}
:global([data-theme="dark"]) .glass-surface {
--glass-border-fallback: rgba(255, 255, 255, 0.1);
--glass-bg-fallback: rgba(0, 0, 0, 0.3);
--glass-border-opacity: 0.1;
--glass-bg-opacity: 0.25;
}
@media (hover: hover) and (pointer: fine) {
.glass-interactive:hover {
transform: translateY(-6px);
box-shadow:
0 20px 40px -10px rgba(0, 0, 0, 0.25),
0 0 0 1px color-mix(in srgb, var(--color-primary), transparent 85%);
}
.metric-card:hover {
transform: scale(1.03);
}
}
@media (pointer: coarse) {
.glass-interactive:active {
transform: scale(0.98);
transition: transform 0.1s ease;
}
}
.metric-card {
transition:
transform 0.3s ease,
background-color 0.3s ease;
}
.glass-surface :where(div, span, section) {
border-color: inherit;
}