refactor: consolidate CSS to use .themed class with native nesting
- Add .themed class as shared selector for both shop and preview - Move visual/behavioral styles from .preview-frame to .themed - Keep .preview-frame only for CSS variable switching (editor live preview) - Update CSSGenerator to target .themed instead of .shop-root - Refactor CSS files to use native CSS nesting syntax - Update tests to reflect new class structure This improves maintainability by: - Eliminating duplicate selectors (.shop-root + .preview-frame) - Using modern CSS nesting (94%+ browser support) - Clear separation: .preview-frame = vars, .themed = styles Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,18 @@
|
||||
/* ========================================
|
||||
THEME SEMANTIC - Layer 3
|
||||
Semantic aliases for easy usage
|
||||
|
||||
Uses .themed class as the common selector for both:
|
||||
- .preview-frame (theme editor)
|
||||
- .shop-root (public shop pages)
|
||||
======================================== */
|
||||
|
||||
.preview-frame, .shop-root {
|
||||
.themed {
|
||||
/* Apply base theme colors */
|
||||
background-color: var(--t-surface-base);
|
||||
color: var(--t-text-primary);
|
||||
font-family: var(--t-font-body);
|
||||
|
||||
/* Accent color - HSL components set dynamically by CSS generator */
|
||||
--t-accent-h: 24;
|
||||
--t-accent-s: 95%;
|
||||
@@ -28,19 +37,19 @@
|
||||
* Body: caption, small, base, large
|
||||
* Display: xl, 2xl (for headings and hero text)
|
||||
*/
|
||||
--t-text-caption: 0.75em; /* ~12px at 16px base, ~14px at 18px base */
|
||||
--t-text-small: 0.875em; /* ~14px at 16px base, ~16px at 18px base */
|
||||
--t-text-base: 1em; /* matches base font size setting */
|
||||
--t-text-large: 1.125em; /* ~18px at 16px base, ~20px at 18px base */
|
||||
--t-text-xl: 1.25em; /* ~20px at 16px base, ~22px at 18px base */
|
||||
--t-text-2xl: 1.5em; /* ~24px at 16px base, ~27px at 18px base */
|
||||
--t-text-caption: 0.75em;
|
||||
--t-text-small: 0.875em;
|
||||
--t-text-base: 1em;
|
||||
--t-text-large: 1.125em;
|
||||
--t-text-xl: 1.25em;
|
||||
--t-text-2xl: 1.5em;
|
||||
|
||||
/* Fluid heading sizes - scale smoothly between mobile and desktop */
|
||||
--t-heading-sm: clamp(1.125rem, 1rem + 0.5vw, 1.25rem); /* 18-20px */
|
||||
--t-heading-md: clamp(1.25rem, 1rem + 1vw, 1.5rem); /* 20-24px */
|
||||
--t-heading-lg: clamp(1.5rem, 1rem + 2vw, 2rem); /* 24-32px */
|
||||
--t-heading-xl: clamp(1.875rem, 1.25rem + 2.5vw, 2.5rem); /* 30-40px */
|
||||
--t-heading-display: clamp(2.25rem, 1.5rem + 3vw, 3rem); /* 36-48px */
|
||||
--t-heading-sm: clamp(1.125rem, 1rem + 0.5vw, 1.25rem);
|
||||
--t-heading-md: clamp(1.25rem, 1rem + 1vw, 1.5rem);
|
||||
--t-heading-lg: clamp(1.5rem, 1rem + 2vw, 2rem);
|
||||
--t-heading-xl: clamp(1.875rem, 1.25rem + 2.5vw, 2.5rem);
|
||||
--t-heading-display: clamp(2.25rem, 1.5rem + 3vw, 3rem);
|
||||
|
||||
/* Layout */
|
||||
--t-layout-max-width: 1400px;
|
||||
@@ -99,11 +108,11 @@
|
||||
--transition-fast: var(--p-duration-fast) var(--p-ease-out);
|
||||
--transition-normal: var(--p-duration-normal) var(--p-ease-out);
|
||||
--transition-bounce: var(--p-duration-normal) var(--p-ease-out-back);
|
||||
}
|
||||
|
||||
/* Dark mode accent-subtle override */
|
||||
.preview-frame[data-mood="dark"], .shop-root[data-mood="dark"] {
|
||||
--t-accent-subtle: hsl(var(--t-accent-h) 30% 15%);
|
||||
/* Dark mode accent-subtle override */
|
||||
&[data-mood="dark"] {
|
||||
--t-accent-subtle: hsl(var(--t-accent-h) 30% 15%);
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -111,25 +120,84 @@
|
||||
Visible focus indicators for all interactive elements
|
||||
======================================== */
|
||||
|
||||
/* Base focus ring style */
|
||||
.shop-container a:focus-visible,
|
||||
.shop-container button:focus-visible,
|
||||
.shop-container input:focus-visible,
|
||||
.shop-container select:focus-visible,
|
||||
.shop-container textarea:focus-visible,
|
||||
.shop-container [tabindex]:focus-visible,
|
||||
.shop-container details summary:focus-visible {
|
||||
outline: 2px solid hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.shop-container {
|
||||
line-height: 1.5;
|
||||
|
||||
/* Remove default browser outlines when using focus-visible */
|
||||
.shop-container a:focus:not(:focus-visible),
|
||||
.shop-container button:focus:not(:focus-visible),
|
||||
.shop-container input:focus:not(:focus-visible),
|
||||
.shop-container select:focus:not(:focus-visible),
|
||||
.shop-container textarea:focus:not(:focus-visible) {
|
||||
outline: none;
|
||||
/* Base focus ring style */
|
||||
& a:focus-visible,
|
||||
& button:focus-visible,
|
||||
& input:focus-visible,
|
||||
& select:focus-visible,
|
||||
& textarea:focus-visible,
|
||||
& [tabindex]:focus-visible,
|
||||
& details summary:focus-visible {
|
||||
outline: 2px solid hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Remove default browser outlines when using focus-visible */
|
||||
& a:focus:not(:focus-visible),
|
||||
& button:focus:not(:focus-visible),
|
||||
& input:focus:not(:focus-visible),
|
||||
& select:focus:not(:focus-visible),
|
||||
& textarea:focus:not(:focus-visible) {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Minimum touch target size (44x44px) */
|
||||
& .header-icon-btn {
|
||||
min-width: 44px;
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
& .filter-pill {
|
||||
min-height: 44px;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
/* Heading line-heights - tighter for large text */
|
||||
& h1 {
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
|
||||
& h2 {
|
||||
line-height: 1.15;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
& h3 {
|
||||
line-height: 1.2;
|
||||
letter-spacing: -0.015em;
|
||||
}
|
||||
|
||||
& h4,
|
||||
& h5,
|
||||
& h6 {
|
||||
line-height: 1.25;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
/* Small text - slightly wider tracking for readability */
|
||||
& .text-xs,
|
||||
& .text-sm,
|
||||
& .t-caption,
|
||||
& .t-small {
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
/* Prose content - ideal 65ch for comfortable reading */
|
||||
& .prose,
|
||||
& .product-description,
|
||||
& .about-content {
|
||||
max-width: 65ch;
|
||||
}
|
||||
|
||||
/* Slightly wider for collection/category descriptions */
|
||||
& .collection-description {
|
||||
max-width: 75ch;
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip link for keyboard navigation */
|
||||
@@ -146,22 +214,10 @@
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
transition: top 0.2s ease;
|
||||
}
|
||||
|
||||
.skip-link:focus {
|
||||
top: 1rem;
|
||||
}
|
||||
|
||||
/* Ensure minimum touch target size (44x44px) */
|
||||
.shop-container .header-icon-btn {
|
||||
min-width: 44px;
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.shop-container .filter-pill {
|
||||
min-height: 44px;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
&:focus {
|
||||
top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Nav link styling with active state indicator */
|
||||
@@ -169,71 +225,13 @@
|
||||
padding: 0.5rem 0;
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: border-color 0.2s ease, color 0.2s ease;
|
||||
}
|
||||
|
||||
.shop-nav a:hover {
|
||||
color: var(--t-text-primary);
|
||||
}
|
||||
|
||||
.shop-nav a[aria-current="page"] {
|
||||
color: var(--t-text-primary);
|
||||
border-bottom-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
TYPOGRAPHY - Line Heights & Letter Spacing
|
||||
Research-backed values for optimal readability
|
||||
======================================== */
|
||||
|
||||
/* Body text line-height - WCAG 1.5 minimum */
|
||||
.shop-container {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Heading line-heights - tighter for large text (inverse relationship) */
|
||||
.shop-container h1 {
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
|
||||
.shop-container h2 {
|
||||
line-height: 1.15;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.shop-container h3 {
|
||||
line-height: 1.2;
|
||||
letter-spacing: -0.015em;
|
||||
}
|
||||
|
||||
.shop-container h4,
|
||||
.shop-container h5,
|
||||
.shop-container h6 {
|
||||
line-height: 1.25;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
/* Small text - slightly wider tracking for readability */
|
||||
.shop-container .text-xs,
|
||||
.shop-container .text-sm,
|
||||
.shop-container .t-caption,
|
||||
.shop-container .t-small {
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
TYPOGRAPHY - Measure (Line Length)
|
||||
Optimal readability: 45-75 characters
|
||||
======================================== */
|
||||
|
||||
/* Prose content - ideal 65ch for comfortable reading */
|
||||
.shop-container .prose,
|
||||
.shop-container .product-description,
|
||||
.shop-container .about-content {
|
||||
max-width: 65ch;
|
||||
}
|
||||
|
||||
/* Slightly wider for collection/category descriptions */
|
||||
.shop-container .collection-description {
|
||||
max-width: 75ch;
|
||||
|
||||
&:hover {
|
||||
color: var(--t-text-primary);
|
||||
}
|
||||
|
||||
&[aria-current="page"] {
|
||||
color: var(--t-text-primary);
|
||||
border-bottom-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user