/* HTMX Component Classes * Semantic component classes used by Minijinja (j2) templates. * All values reference CSS custom properties from design-system.css. */ /* ─── Layout: Page Structure ─────────────────────────────────────────────── */ .ds-page-header { padding: var(--space-12, 3rem) 0 var(--space-8, 2rem); } .ds-page-body { padding: var(--space-8, 2rem) 0; } /* ─── Layout: Sections ────────────────────────────────────────────────────── */ .ds-hero { padding: var(--space-20, 5rem) 0; background-color: var(--color-neutral-50); text-align: center; } .dark .ds-hero { background-color: var(--color-neutral-950); } .ds-section { padding: var(--space-16, 4rem) 0; background-color: var(--color-neutral-50); } .dark .ds-section { background-color: var(--color-neutral-950); } .ds-section-alt { background-color: var(--color-neutral-100); } .dark .ds-section-alt { background-color: var(--color-neutral-900); } .ds-section-cta { background-color: var(--color-brand-primary); color: var(--color-neutral-50); } .ds-section-cta .ds-text-lead, .ds-section-cta .ds-text-muted { color: color-mix(in srgb, var(--color-neutral-50) 85%, transparent); } /* ─── Layout: Grid ────────────────────────────────────────────────────────── */ .ds-grid { display: grid; gap: var(--space-6, 1.5rem); } .ds-grid-2 { grid-template-columns: repeat(1, 1fr); } .ds-grid-3 { grid-template-columns: repeat(1, 1fr); } @media (min-width: 768px) { .ds-grid-2 { grid-template-columns: repeat(2, 1fr); } .ds-grid-3 { grid-template-columns: repeat(2, 1fr); } } @media (min-width: 1024px) { .ds-grid-3 { grid-template-columns: repeat(3, 1fr); } } /* ─── Layout: Alignment helpers ──────────────────────────────────────────── */ .ds-align-center { align-items: center; } .ds-justify-center { justify-content: center; } .ds-justify-between { justify-content: space-between; } .ds-text-center { text-align: center; } .ds-w-full { width: 100%; } /* ─── Typography ─────────────────────────────────────────────────────────── */ .ds-heading-xl { font-size: var(--text-4xl, 2.25rem); font-weight: var(--font-bold, 700); color: var(--color-neutral-900); line-height: 1.2; margin-bottom: var(--space-4, 1rem); } .dark .ds-heading-xl { color: var(--color-neutral-50); } .ds-heading-lg { font-size: var(--text-3xl, 1.875rem); font-weight: var(--font-semibold, 600); color: var(--color-neutral-900); line-height: 1.25; margin-bottom: var(--space-4, 1rem); } .dark .ds-heading-lg { color: var(--color-neutral-50); } .ds-heading-sm { font-size: var(--text-xl, 1.25rem); font-weight: var(--font-semibold, 600); color: var(--color-neutral-900); line-height: 1.4; margin-bottom: var(--space-2, 0.5rem); } .dark .ds-heading-sm { color: var(--color-neutral-50); } .ds-tagline { font-size: var(--text-sm, 0.875rem); font-weight: var(--font-semibold, 600); text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-brand-primary); margin-bottom: var(--space-3, 0.75rem); } .ds-text-lead { font-size: var(--text-lg, 1.125rem); color: var(--color-neutral-600); line-height: 1.7; margin-bottom: var(--space-4, 1rem); } .dark .ds-text-lead { color: var(--color-neutral-400); } /* ─── Buttons ─────────────────────────────────────────────────────────────── */ .ds-button { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2, 0.5rem); padding: var(--space-2, 0.5rem) var(--space-5, 1.25rem); font-size: var(--text-sm, 0.875rem); font-weight: var(--font-medium, 500); border-radius: var(--radius-md, 0.375rem); border: 1px solid transparent; cursor: pointer; text-decoration: none; transition: background-color 0.15s, border-color 0.15s, color 0.15s; white-space: nowrap; } .ds-button-primary { background-color: var(--color-brand-primary, #3b82f6); color: var(--color-neutral-50, #f9fafb); border-color: var(--color-brand-primary, #3b82f6); } .ds-button-primary:hover { background-color: color-mix(in srgb, var(--color-brand-primary) 85%, black); } .ds-button-secondary { background-color: var(--color-neutral-200, #e5e7eb); color: var(--color-neutral-900, #111827); border-color: var(--color-neutral-200, #e5e7eb); } .ds-button-secondary:hover { background-color: var(--color-neutral-300, #d1d5db); } .dark .ds-button-secondary { background-color: var(--color-neutral-700, #374151); color: var(--color-neutral-50, #f9fafb); border-color: var(--color-neutral-700, #374151); } .dark .ds-button-secondary:hover { background-color: var(--color-neutral-600, #4b5563); } .ds-button-outline { background-color: transparent; color: var(--color-brand-primary, #3b82f6); border-color: var(--color-brand-primary, #3b82f6); } .ds-button-outline:hover { background-color: var(--color-brand-primary, #3b82f6); color: var(--color-neutral-50, #f9fafb); } .ds-button-sm { padding: var(--space-1, 0.25rem) var(--space-3, 0.75rem); font-size: var(--text-xs, 0.75rem); } .ds-button-group { display: flex; flex-wrap: wrap; gap: var(--space-3, 0.75rem); align-items: center; } /* ─── Nav: control group (theme · lang · login) ──────────────────────────── */ /* The three nav controls ship with different framework sizings: the theme toggle and login use .ds-btn-ghost-sm (padding → ~28-32px tall), the language selector's carries daisyUI's .btn-sm (height:2rem → 32px). Unify them to a 24px footprint. Scoped to .nav-ctl-group so the dashboard's .ds-btn-ghost-sm delete buttons are untouched. box-sizing:border-box is global, so 1.5rem == the full 24px box. */ .nav-ctl-group > .ds-btn-ghost-sm, .nav-ctl-group > .language-selector > summary { height: 1.5rem; min-height: 1.5rem; padding-top: 0; padding-bottom: 0; } /* Icon-only controls → square 24×24. The login button keeps content width (it holds text) but inherits the 24px height above. */ .nav-ctl-group > .ds-btn-ghost-sm[data-theme], .nav-ctl-group > .language-selector > summary { width: 1.5rem; padding-left: 0; padding-right: 0; } /* ─── List ────────────────────────────────────────────────────────────────── */ .ds-list { list-style: none; padding: 0; margin: var(--space-3, 0.75rem) 0; display: flex; flex-direction: column; gap: var(--space-2, 0.5rem); } .ds-list li { color: var(--color-neutral-600); font-size: var(--text-sm, 0.875rem); padding-left: var(--space-4, 1rem); position: relative; } .dark .ds-list li { color: var(--color-neutral-400); } .ds-list li::before { content: "→"; position: absolute; left: 0; color: var(--color-brand-primary); font-size: 0.75rem; line-height: 1.6; } /* ─── Link ────────────────────────────────────────────────────────────────── */ .ds-link { display: inline-flex; align-items: center; gap: var(--space-1, 0.25rem); color: var(--color-brand-primary); font-size: var(--text-sm, 0.875rem); font-weight: var(--font-medium, 500); text-decoration: none; margin-top: var(--space-3, 0.75rem); transition: color 0.15s; } .ds-link:hover { color: color-mix(in srgb, var(--color-brand-primary) 75%, black); text-decoration: underline; } /* ─── Product Page ────────────────────────────────────────────────────────── */ .ds-product-page { max-width: 72rem; margin: 0 auto; padding: var(--space-8, 2rem) var(--space-4, 1rem); } .ds-product-actions { display: flex; flex-wrap: wrap; gap: var(--space-3, 0.75rem); margin: var(--space-6, 1.5rem) 0; } /* ─── Forms ───────────────────────────────────────────────────────────────── */ .ds-form { display: flex; flex-direction: column; gap: var(--space-4, 1rem); max-width: 32rem; } .ds-auth-form { display: flex; flex-direction: column; gap: var(--space-4, 1rem); max-width: 24rem; margin: 0 auto; } .ds-form-group { display: flex; flex-direction: column; gap: var(--space-1, 0.25rem); } .ds-form-row { display: flex; gap: var(--space-3, 0.75rem); align-items: flex-end; } .ds-label { display: block; font-size: var(--text-sm, 0.875rem); font-weight: var(--font-medium, 500); color: var(--color-neutral-700); margin-bottom: var(--space-1, 0.25rem); } .dark .ds-label { color: var(--color-neutral-300); } .ds-checkbox { width: 1rem; height: 1rem; accent-color: var(--color-brand-primary); cursor: pointer; } .ds-checkbox-label { display: inline-flex; align-items: center; gap: var(--space-2, 0.5rem); font-size: var(--text-sm, 0.875rem); color: var(--color-neutral-700); cursor: pointer; } .dark .ds-checkbox-label { color: var(--color-neutral-300); } /* ─── Layout: Container ───────────────────────────────────────────────────── */ .ds-container { margin-left: auto; margin-right: auto; padding-left: var(--space-4, 1rem); padding-right: var(--space-4, 1rem); max-width: 80rem; } .ds-container-sm { margin-left: auto; margin-right: auto; padding-left: var(--space-4, 1rem); padding-right: var(--space-4, 1rem); max-width: 42rem; } .ds-container-md { margin-left: auto; margin-right: auto; padding-left: var(--space-4, 1rem); padding-right: var(--space-4, 1rem); max-width: 56rem; } /* ─── Background ─────────────────────────────────────────────────────────── */ .ds-bg-page { background-color: var(--color-neutral-100); } .dark .ds-bg-page { background-color: var(--color-neutral-900); } /* ─── Typography: Body Text ──────────────────────────────────────────────── */ .ds-text { color: var(--color-neutral-900); } .dark .ds-text { color: var(--color-neutral-50); } .ds-text-muted { color: var(--color-neutral-500); font-size: var(--text-base, 1rem); line-height: 1.6; margin-bottom: var(--space-4, 1rem); } /* ─── Card ───────────────────────────────────────────────────────────────── */ .ds-card { background-color: var(--color-neutral-50); border-radius: var(--radius-lg, 0.5rem); box-shadow: var(--shadow-sm, 0 1px 2px 0 rgb(0 0 0 / 0.05)); border: 1px solid var(--color-neutral-200); padding: var(--space-6, 1.5rem); } .dark .ds-card { background-color: var(--color-neutral-800); border-color: var(--color-neutral-600); } /* ─── Badge ──────────────────────────────────────────────────────────────── */ .ds-badge { display: inline-flex; align-items: center; padding: 0.125rem 0.625rem; border-radius: 9999px; font-size: var(--text-xs, 0.75rem); font-weight: var(--font-medium, 500); background-color: var(--color-brand-primary); color: var(--color-neutral-50); margin-bottom: var(--space-3, 0.75rem); } /* ─── Input ──────────────────────────────────────────────────────────────── */ .ds-input { width: 100%; padding: var(--space-2, 0.5rem) var(--space-3, 0.75rem); font-size: var(--text-sm, 0.875rem); color: var(--color-neutral-900); background-color: var(--color-neutral-50); border: 1px solid var(--color-neutral-300); border-radius: var(--radius-md, 0.375rem); transition: border-color 0.15s, box-shadow 0.15s; outline: none; } .ds-input:focus { border-color: var(--color-brand-primary); box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-brand-primary) 20%, transparent); } .dark .ds-input { color: var(--color-neutral-50); background-color: var(--color-neutral-800); border-color: var(--color-neutral-600); }