493 lines
13 KiB
CSS
493 lines
13 KiB
CSS
/* 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 <summary> 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);
|
||
}
|