migrate accent colours from HSL to oklch, inject theme into admin
Phase 1: Replace hex_to_hsl with hex_to_oklch in CSSGenerator, output --t-accent-l/c/h instead of --t-accent-h/s/l. All 46 HSL accent references across theme-semantic.css, theme-layer2-attributes.css, and shop/components.css replaced with oklch/color-mix equivalents. Dead style*= attribute selectors for button variants replaced with proper class-based selectors. Added color-scheme: light/dark to mood output. Phase 2: Add LoadTheme plug to admin pipeline, extend AdminLayoutHook with theme_settings and generated_css assigns, add font preloads and generated CSS injection to admin_root.html.heex. No visual changes to admin yet — .themed wrapper added in next phase. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -131,7 +131,7 @@
|
||||
/* ── Product prices (shared between cards and PDP) ── */
|
||||
|
||||
.product-price--sale {
|
||||
color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
color: var(--t-accent);
|
||||
}
|
||||
|
||||
.product-price--compare {
|
||||
@@ -254,7 +254,7 @@
|
||||
.hero-pre-title {
|
||||
font-family: var(--t-font-heading);
|
||||
font-weight: var(--t-heading-weight);
|
||||
color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
color: var(--t-accent);
|
||||
font-size: var(--t-heading-display);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
@@ -398,7 +398,7 @@
|
||||
}
|
||||
|
||||
.accent-link {
|
||||
color: var(--t-accent-text, hsl(var(--t-accent-h) var(--t-accent-s) 38%));
|
||||
color: var(--t-accent-text);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
font-size: var(--t-text-small);
|
||||
@@ -457,7 +457,7 @@
|
||||
.collection-empty-link {
|
||||
display: inline-block;
|
||||
margin-top: 1rem;
|
||||
color: var(--t-text-accent, hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)));
|
||||
color: var(--t-text-accent, var(--t-accent));
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@@ -518,7 +518,7 @@
|
||||
}
|
||||
|
||||
.pdp-thumbnail-active {
|
||||
border: 2px solid hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
border: 2px solid var(--t-accent);
|
||||
}
|
||||
|
||||
/* ── Variant selector ── */
|
||||
@@ -556,8 +556,8 @@
|
||||
padding: 0;
|
||||
|
||||
&[aria-pressed="true"] {
|
||||
border-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
--tw-ring-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
border-color: var(--t-accent);
|
||||
--tw-ring-color: var(--t-accent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,8 +572,8 @@
|
||||
cursor: pointer;
|
||||
|
||||
&[aria-pressed="true"] {
|
||||
border-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
background: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.1);
|
||||
border-color: var(--t-accent);
|
||||
background: color-mix(in oklch, var(--t-accent) 10%, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -654,7 +654,7 @@
|
||||
}
|
||||
|
||||
.atc-btn {
|
||||
background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
background-color: var(--t-accent);
|
||||
color: var(--t-text-inverse);
|
||||
border-radius: var(--t-radius-button);
|
||||
border: none;
|
||||
@@ -762,7 +762,7 @@
|
||||
/* ── Announcement bar ── */
|
||||
|
||||
.announcement-bar {
|
||||
background-color: var(--t-accent-button, hsl(var(--t-accent-h) var(--t-accent-s) 42%));
|
||||
background-color: var(--t-accent-button);
|
||||
color: var(--t-text-inverse);
|
||||
text-align: center;
|
||||
padding: 0.5rem 1rem;
|
||||
@@ -867,7 +867,7 @@
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
right: -4px;
|
||||
background: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
background: var(--t-accent);
|
||||
color: var(--t-text-inverse);
|
||||
font-size: var(--t-text-caption);
|
||||
font-weight: 600;
|
||||
@@ -889,7 +889,7 @@
|
||||
|
||||
&[aria-current="page"] {
|
||||
color: var(--t-text-primary);
|
||||
border-bottom-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
border-bottom-color: var(--t-accent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -943,9 +943,9 @@
|
||||
}
|
||||
|
||||
&[aria-current="page"] {
|
||||
color: hsl(var(--t-accent-h) var(--t-accent-s) calc(var(--t-accent-l) - 15%));
|
||||
color: color-mix(in oklch, var(--t-accent) 80%, black);
|
||||
font-weight: 600;
|
||||
background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.1);
|
||||
background-color: color-mix(in oklch, var(--t-accent) 10%, transparent);
|
||||
|
||||
& svg {
|
||||
width: 1.5rem;
|
||||
@@ -1273,7 +1273,7 @@
|
||||
padding: 0.75rem 1.5rem;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s ease;
|
||||
background: var(--t-accent-button, hsl(var(--t-accent-h) var(--t-accent-s) 42%));
|
||||
background: var(--t-accent-button);
|
||||
color: var(--t-text-inverse);
|
||||
border-radius: var(--t-radius-button);
|
||||
border: none;
|
||||
@@ -1692,7 +1692,7 @@
|
||||
/* ── Accent email link ── */
|
||||
|
||||
.accent-email {
|
||||
color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
color: var(--t-accent);
|
||||
}
|
||||
|
||||
/* ── Card shared styles (info, tracking, newsletter, social cards) ── */
|
||||
@@ -1767,7 +1767,7 @@
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
color: var(--t-accent);
|
||||
text-decoration: none;
|
||||
|
||||
& svg {
|
||||
@@ -1879,7 +1879,7 @@
|
||||
.trust-badge-icon {
|
||||
flex-shrink: 0;
|
||||
margin-top: 0.125rem;
|
||||
color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
color: var(--t-accent);
|
||||
|
||||
& svg {
|
||||
width: 1.25rem;
|
||||
|
||||
@@ -157,19 +157,21 @@
|
||||
|
||||
/* Button Style Variants */
|
||||
&[data-button-style="outline"] {
|
||||
& button[style*="background-color: hsl(var(--t-accent"],
|
||||
& a[style*="background-color: hsl(var(--t-accent"] {
|
||||
& .themed-button,
|
||||
& .atc-btn,
|
||||
& .cart-drawer-checkout {
|
||||
background-color: transparent !important;
|
||||
color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)) !important;
|
||||
border: 2px solid hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)) !important;
|
||||
color: var(--t-accent) !important;
|
||||
border: 2px solid var(--t-accent) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&[data-button-style="soft"] {
|
||||
& button[style*="background-color: hsl(var(--t-accent"],
|
||||
& a[style*="background-color: hsl(var(--t-accent"] {
|
||||
background-color: hsl(var(--t-accent-h) var(--t-accent-s) 90%) !important;
|
||||
color: hsl(var(--t-accent-h) var(--t-accent-s) 30%) !important;
|
||||
& .themed-button,
|
||||
& .atc-btn,
|
||||
& .cart-drawer-checkout {
|
||||
background-color: color-mix(in oklch, var(--t-accent) 12%, var(--t-surface-base)) !important;
|
||||
color: color-mix(in oklch, var(--t-accent) 80%, black) !important;
|
||||
border: 2px solid transparent !important;
|
||||
}
|
||||
}
|
||||
@@ -231,12 +233,12 @@
|
||||
}
|
||||
|
||||
& .filter-pill-active {
|
||||
background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
background-color: var(--t-accent);
|
||||
color: var(--t-text-inverse);
|
||||
border-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background-color: hsl(var(--t-accent-h) var(--t-accent-s) calc(var(--t-accent-l) - 5%));
|
||||
background-color: var(--t-accent-hover);
|
||||
color: var(--t-text-inverse);
|
||||
}
|
||||
}
|
||||
@@ -250,7 +252,7 @@
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
border-color: var(--t-accent);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
@@ -269,12 +271,12 @@
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
border-color: var(--t-accent);
|
||||
}
|
||||
}
|
||||
|
||||
& .themed-button {
|
||||
background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
background-color: var(--t-accent);
|
||||
color: var(--t-text-inverse);
|
||||
border-radius: var(--t-radius-button);
|
||||
border: none;
|
||||
@@ -322,7 +324,7 @@
|
||||
}
|
||||
|
||||
.badge-new {
|
||||
background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
background-color: var(--t-accent);
|
||||
color: var(--t-text-inverse);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,21 +13,19 @@
|
||||
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%;
|
||||
--t-accent-l: 53%;
|
||||
/* Accent colour — oklch components set dynamically by CSSGenerator */
|
||||
--t-accent-l: 65%;
|
||||
--t-accent-c: 0.2;
|
||||
--t-accent-h: 47;
|
||||
|
||||
--t-accent: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
--t-accent-hover: hsl(var(--t-accent-h) var(--t-accent-s) calc(var(--t-accent-l) - 8%));
|
||||
--t-accent-subtle: hsl(var(--t-accent-h) 40% 95%);
|
||||
--t-accent-ring: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.4);
|
||||
--t-accent: oklch(var(--t-accent-l) var(--t-accent-c) var(--t-accent-h));
|
||||
--t-accent-hover: color-mix(in oklch, var(--t-accent) 85%, black);
|
||||
--t-accent-subtle: color-mix(in oklch, var(--t-accent) 8%, var(--t-surface-base));
|
||||
--t-accent-ring: oklch(var(--t-accent-l) var(--t-accent-c) var(--t-accent-h) / 0.4);
|
||||
|
||||
/* WCAG AA compliant accent variants for better contrast */
|
||||
/* Darker accent for text on light backgrounds (4.5:1 with white) */
|
||||
--t-accent-text: hsl(var(--t-accent-h) var(--t-accent-s) 38%);
|
||||
/* Darker accent for button backgrounds to ensure 4.5:1 with white text */
|
||||
--t-accent-button: hsl(var(--t-accent-h) var(--t-accent-s) 42%);
|
||||
--t-accent-text: color-mix(in oklch, var(--t-accent) 80%, black);
|
||||
--t-accent-button: color-mix(in oklch, var(--t-accent) 85%, black);
|
||||
|
||||
/* Secondary colors */
|
||||
--t-secondary-accent: #ea580c;
|
||||
@@ -117,7 +115,7 @@
|
||||
|
||||
/* Dark mode accent-subtle override */
|
||||
&[data-mood="dark"] {
|
||||
--t-accent-subtle: hsl(var(--t-accent-h) 30% 15%);
|
||||
--t-accent-subtle: color-mix(in oklch, var(--t-accent) 15%, black);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +135,7 @@
|
||||
& 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: 2px solid var(--t-accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
@@ -230,9 +228,9 @@
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.12);
|
||||
color: hsl(var(--t-accent-h) var(--t-accent-s) calc(var(--t-accent-l) - 15%));
|
||||
border-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.25);
|
||||
background-color: color-mix(in oklch, var(--t-accent) 12%, transparent);
|
||||
color: color-mix(in oklch, var(--t-accent) 80%, black);
|
||||
border-color: color-mix(in oklch, var(--t-accent) 25%, transparent);
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
@@ -273,7 +271,7 @@
|
||||
top: -100px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
background: var(--t-accent);
|
||||
color: var(--t-text-inverse);
|
||||
padding: 0.75rem 1.5rem;
|
||||
z-index: 9999;
|
||||
@@ -312,5 +310,5 @@
|
||||
|
||||
/* Active nav underline — must stay unlayered to match the base border above */
|
||||
.shop-nav [aria-current="page"] {
|
||||
border-bottom-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
border-bottom-color: var(--t-accent);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user