/* Cascade Layers - Ordered from lowest to highest priority */ /* Base styles (variables, resets) are unlayered for highest priority */ @layer utilities, layouts, components; /* Non-inheriting custom properties */ @property --layout-gap { syntax: "*"; inherits: false; initial-value: 1rem; } /* Typography */ :root { --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; --min-vw: 360; --max-vw: 800; /* Vertical Spacing */ --vs-xs: 0.25rem; --vs-s: 0.5rem; --vs-base: 1rem; --vs-m: 1.5rem; --vs-l: 2rem; --vs-xl: 4rem; --vs-xxl: 6rem; --vs-xxxl: 8rem; /* Border Radius */ --br-xs: 2px; --br-s: 4px; --br-m: 8px; --br-l: 16px; --br-xl: 24px; --br-xxl: 32px; /* Padding */ --pad-xs: 0.25rem; --pad-s: 0.5rem; --pad-m: 0.75rem; --pad-l: 1rem; --pad-xl: 1.5rem; --pad-xxl: 2rem; --pad-xxxl: 4rem; /* Line Height */ --lh-xs: 1; --lh-s: 1.2; --lh: 1.5; --lh-l: 1.8; --lh-xl: 2; /* Shadows - Layered, adaptive shadows with light/dark mode support */ --shadow-1: 0 0 1px 0.5px rgb(0 0 0 / 0.05), 0 2px 2px rgb(0 0 0 / 0.1); --shadow-2: 0 1px 1px 2px rgb(0 0 0 / 0.03), 0 4px 4px rgb(0 0 0 / 0.1); --shadow-3: 0 2px 4px rgb(0 0 0 / 0.05), 0 4px 8px rgb(0 0 0 / 0.1); --shadow-4: 0 4px 8px rgb(0 0 0 / 0.06), 0 8px 16px rgb(0 0 0 / 0.12); --shadow-5: 0 8px 16px rgb(0 0 0 / 0.08), 0 12px 24px rgb(0 0 0 / 0.14); --shadow-6: 0 12px 24px rgb(0 0 0 / 0.1), 0 16px 32px rgb(0 0 0 / 0.16), 0 24px 48px rgb(0 0 0 / 0.18); --box: 0 1px 2px rgb(0 0 0 / 0.04), inset -1px 1px 2px rgb(255 255 255 / 0.1), inset 1px 1px 2px rgb(255 255 255 / 0.1); /* Color System - OKLCH with 1-9 scales */ /* Base colors (scale 5) */ --yellow: oklch(0.88 0.15 95); --amber: oklch(0.78 0.16 80); --orange: oklch(0.75 0.18 65); --red: oklch(0.62 0.22 35); --pink: oklch(0.62 0.25 350); --purple: oklch(0.65 0.24 310); --indigo: oklch(0.55 0.25 275); --blue: oklch(0.5 0.28 270); --teal: oklch(0.82 0.08 185); --green: oklch(0.72 0.18 165); --lime: oklch(0.8 0.16 130); --highlighter: oklch(0.88 0.22 115); --brown: oklch(0.55 0.12 60); /* Yellow scale */ --yellow-1: oklch(from var(--yellow) l c h / 0.1); --yellow-2: oklch(from var(--yellow) l c h / 0.2); --yellow-3: oklch(from var(--yellow) l c h / 0.3); --yellow-4: oklch(from var(--yellow) l c h / 0.4); --yellow-5: oklch(from var(--yellow) l c h / 0.5); --yellow-6: oklch(from var(--yellow) l c h / 0.6); --yellow-7: oklch(from var(--yellow) l c h / 0.75); --yellow-8: oklch(from var(--yellow) l c h / 0.9); --yellow-9: var(--yellow); /* Amber scale */ --amber-1: oklch(from var(--amber) l c h / 0.1); --amber-2: oklch(from var(--amber) l c h / 0.2); --amber-3: oklch(from var(--amber) l c h / 0.3); --amber-4: oklch(from var(--amber) l c h / 0.4); --amber-5: oklch(from var(--amber) l c h / 0.5); --amber-6: oklch(from var(--amber) l c h / 0.6); --amber-7: oklch(from var(--amber) l c h / 0.75); --amber-8: oklch(from var(--amber) l c h / 0.9); --amber-9: var(--amber); /* Orange scale */ --orange-1: oklch(from var(--orange) l c h / 0.1); --orange-2: oklch(from var(--orange) l c h / 0.2); --orange-3: oklch(from var(--orange) l c h / 0.3); --orange-4: oklch(from var(--orange) l c h / 0.4); --orange-5: oklch(from var(--orange) l c h / 0.5); --orange-6: oklch(from var(--orange) l c h / 0.6); --orange-7: oklch(from var(--orange) l c h / 0.75); --orange-8: oklch(from var(--orange) l c h / 0.9); --orange-9: var(--orange); /* Red scale */ --red-1: oklch(from var(--red) l c h / 0.1); --red-2: oklch(from var(--red) l c h / 0.2); --red-3: oklch(from var(--red) l c h / 0.3); --red-4: oklch(from var(--red) l c h / 0.4); --red-5: oklch(from var(--red) l c h / 0.5); --red-6: oklch(from var(--red) l c h / 0.6); --red-7: oklch(from var(--red) l c h / 0.75); --red-8: oklch(from var(--red) l c h / 0.9); --red-9: var(--red); /* Pink scale */ --pink-1: oklch(from var(--pink) l c h / 0.1); --pink-2: oklch(from var(--pink) l c h / 0.2); --pink-3: oklch(from var(--pink) l c h / 0.3); --pink-4: oklch(from var(--pink) l c h / 0.4); --pink-5: oklch(from var(--pink) l c h / 0.5); --pink-6: oklch(from var(--pink) l c h / 0.6); --pink-7: oklch(from var(--pink) l c h / 0.75); --pink-8: oklch(from var(--pink) l c h / 0.9); --pink-9: var(--pink); /* Purple scale */ --purple-1: oklch(from var(--purple) l c h / 0.1); --purple-2: oklch(from var(--purple) l c h / 0.2); --purple-3: oklch(from var(--purple) l c h / 0.3); --purple-4: oklch(from var(--purple) l c h / 0.4); --purple-5: oklch(from var(--purple) l c h / 0.5); --purple-6: oklch(from var(--purple) l c h / 0.6); --purple-7: oklch(from var(--purple) l c h / 0.75); --purple-8: oklch(from var(--purple) l c h / 0.9); --purple-9: var(--purple); /* Purple deep scale */ --purple-deep: #1b1525; --purple-deep-1: oklch(from var(--purple-deep) l c h / 0.1); --purple-deep-2: oklch(from var(--purple-deep) l c h / 0.2); --purple-deep-3: oklch(from var(--purple-deep) l c h / 0.3); --purple-deep-4: oklch(from var(--purple-deep) l c h / 0.4); --purple-deep-5: oklch(from var(--purple-deep) l c h / 0.5); --purple-deep-6: oklch(from var(--purple-deep) l c h / 0.6); --purple-deep-7: oklch(from var(--purple-deep) l c h / 0.75); --purple-deep-8: oklch(from var(--purple-deep) l c h / 0.9); --purple-deep-9: var(--purple-deep); /* Indigo scale */ --indigo-1: oklch(from var(--indigo) l c h / 0.1); --indigo-2: oklch(from var(--indigo) l c h / 0.2); --indigo-3: oklch(from var(--indigo) l c h / 0.3); --indigo-4: oklch(from var(--indigo) l c h / 0.4); --indigo-5: oklch(from var(--indigo) l c h / 0.5); --indigo-6: oklch(from var(--indigo) l c h / 0.6); --indigo-7: oklch(from var(--indigo) l c h / 0.75); --indigo-8: oklch(from var(--indigo) l c h / 0.9); --indigo-9: var(--indigo); /* Green scale */ --green-1: oklch(from var(--green) l c h / 0.1); --green-2: oklch(from var(--green) l c h / 0.2); --green-3: oklch(from var(--green) l c h / 0.3); --green-4: oklch(from var(--green) l c h / 0.4); --green-5: oklch(from var(--green) l c h / 0.5); --green-6: oklch(from var(--green) l c h / 0.6); --green-7: oklch(from var(--green) l c h / 0.75); --green-8: oklch(from var(--green) l c h / 0.9); --green-9: var(--green); /* Lime scale */ --lime-1: oklch(from var(--lime) l c h / 0.1); --lime-2: oklch(from var(--lime) l c h / 0.2); --lime-3: oklch(from var(--lime) l c h / 0.3); --lime-4: oklch(from var(--lime) l c h / 0.4); --lime-5: oklch(from var(--lime) l c h / 0.5); --lime-6: oklch(from var(--lime) l c h / 0.6); --lime-7: oklch(from var(--lime) l c h / 0.75); --lime-8: oklch(from var(--lime) l c h / 0.9); --lime-9: var(--lime); /* Highlighter scale */ --highlighter-1: oklch(from var(--highlighter) l c h / 0.1); --highlighter-2: oklch(from var(--highlighter) l c h / 0.2); --highlighter-3: oklch(from var(--highlighter) l c h / 0.3); --highlighter-4: oklch(from var(--highlighter) l c h / 0.4); --highlighter-5: oklch(from var(--highlighter) l c h / 0.5); --highlighter-6: oklch(from var(--highlighter) l c h / 0.6); --highlighter-7: oklch(from var(--highlighter) l c h / 0.75); --highlighter-8: oklch(from var(--highlighter) l c h / 0.9); --highlighter-9: var(--highlighter); /* Brown scale */ --brown-1: oklch(from var(--brown) l c h / 0.1); --brown-2: oklch(from var(--brown) l c h / 0.2); --brown-3: oklch(from var(--brown) l c h / 0.3); --brown-4: oklch(from var(--brown) l c h / 0.4); --brown-5: oklch(from var(--brown) l c h / 0.5); --brown-6: oklch(from var(--brown) l c h / 0.6); --brown-7: oklch(from var(--brown) l c h / 0.75); --brown-8: oklch(from var(--brown) l c h / 0.9); --brown-9: var(--brown); /* Teal scale */ --teal-1: oklch(from var(--teal) l c h / 0.1); --teal-2: oklch(from var(--teal) l c h / 0.2); --teal-3: oklch(from var(--teal) l c h / 0.3); --teal-4: oklch(from var(--teal) l c h / 0.4); --teal-5: oklch(from var(--teal) l c h / 0.5); --teal-6: oklch(from var(--teal) l c h / 0.6); --teal-7: oklch(from var(--teal) l c h / 0.75); --teal-8: oklch(from var(--teal) l c h / 0.9); --teal-9: var(--teal); /* Blue scale */ --blue-1: oklch(from var(--blue) l c h / 0.1); --blue-2: oklch(from var(--blue) l c h / 0.2); --blue-3: oklch(from var(--blue) l c h / 0.3); --blue-4: oklch(from var(--blue) l c h / 0.4); --blue-5: oklch(from var(--blue) l c h / 0.5); --blue-6: oklch(from var(--blue) l c h / 0.6); --blue-7: oklch(from var(--blue) l c h / 0.75); --blue-8: oklch(from var(--blue) l c h / 0.9); --blue-9: var(--blue); /* Neutral gray scale */ --gray: oklch(0.5 0.02 270); --slate: oklch(0.52 0.04 255); --gray-1: oklch(from var(--gray) l c h / 0.1); --gray-2: oklch(from var(--gray) l c h / 0.2); --gray-3: oklch(from var(--gray) l c h / 0.3); --gray-4: oklch(from var(--gray) l c h / 0.4); --gray-5: oklch(from var(--gray) l c h / 0.5); --gray-6: oklch(from var(--gray) l c h / 0.6); --gray-7: oklch(from var(--gray) l c h / 0.75); --gray-8: oklch(from var(--gray) l c h / 0.9); --gray-9: var(--gray); /* Slate scale */ --slate-1: oklch(from var(--slate) l c h / 0.1); --slate-2: oklch(from var(--slate) l c h / 0.2); --slate-3: oklch(from var(--slate) l c h / 0.3); --slate-4: oklch(from var(--slate) l c h / 0.4); --slate-5: oklch(from var(--slate) l c h / 0.5); --slate-6: oklch(from var(--slate) l c h / 0.6); --slate-7: oklch(from var(--slate) l c h / 0.75); --slate-8: oklch(from var(--slate) l c h / 0.9); --slate-9: var(--slate); /* White - Static color (does not change with light/dark mode) */ --white: oklch(1 0 0); --white-05: oklch(from var(--white) l c h / 0.05); --white-1: oklch(from var(--white) l c h / 0.1); --white-2: oklch(from var(--white) l c h / 0.2); --white-3: oklch(from var(--white) l c h / 0.3); --white-4: oklch(from var(--white) l c h / 0.4); --white-5: oklch(from var(--white) l c h / 0.5); --white-6: oklch(from var(--white) l c h / 0.6); --white-7: oklch(from var(--white) l c h / 0.75); --white-8: oklch(from var(--white) l c h / 0.9); --white-9: var(--white); /* Black - Static color (does not change with light/dark mode) */ --black: oklch(0 0 0); --black-05: oklch(from var(--black) l c h / 0.05); --black-1: oklch(from var(--black) l c h / 0.1); --black-2: oklch(from var(--black) l c h / 0.2); --black-3: oklch(from var(--black) l c h / 0.3); --black-4: oklch(from var(--black) l c h / 0.4); --black-5: oklch(from var(--black) l c h / 0.5); --black-6: oklch(from var(--black) l c h / 0.6); --black-7: oklch(from var(--black) l c h / 0.75); --black-8: oklch(from var(--black) l c h / 0.9); --black-9: var(--black); --fg-light: #050505; --fg-dark: #fff; --fg: light-dark(var(--fg-light), var(--fg-dark)); --fg-05: oklch(from var(--fg) l c h / 0.05); --fg-1: oklch(from var(--fg) l c h / 0.1); --fg-2: oklch(from var(--fg) l c h / 0.2); --fg-3: oklch(from var(--fg) l c h / 0.3); --fg-4: oklch(from var(--fg) l c h / 0.4); --fg-5: oklch(from var(--fg) l c h / 0.5); --fg-6: oklch(from var(--fg) l c h / 0.6); --fg-7: oklch(from var(--fg) l c h / 0.75); --fg-8: oklch(from var(--fg) l c h / 0.9); --fg-9: var(--fg); --bg-light: #fff; --bg-dark: #050505; --bg: light-dark(var(--bg-light), var(--bg-dark)); --bg-05: oklch(from var(--bg) l c h / 0.05); --bg-1: oklch(from var(--bg) l c h / 0.1); --bg-2: oklch(from var(--bg) l c h / 0.2); --bg-3: oklch(from var(--bg) l c h / 0.3); --bg-4: oklch(from var(--bg) l c h / 0.4); --bg-5: oklch(from var(--bg) l c h / 0.5); --bg-6: oklch(from var(--bg) l c h / 0.6); --bg-7: oklch(from var(--bg) l c h / 0.75); --bg-8: oklch(from var(--bg) l c h / 0.9); --bg-9: var(--bg); /* Fluid Type */ --font-size-min: 16; --font-size-max: 18; --font-ratio-min: 1.2; --font-ratio-max: 1.33; --font-width-min: 320; --font-width-max: 1500; /* Border Tokens */ --border-05: solid 1px var(--fg-05); --border-1: solid 1px var(--fg-2); --border-2: solid 2px var(--fg-2); /* Easing Tokens - Using linear() for modern, natural motion */ --ease-smooth: linear( 0, 0.0039, 0.0157, 0.0352, 0.0625 9.09%, 0.1407, 0.25, 0.3908, 0.5625, 0.7654, 1 ); --ease-bounce: linear( 0, 0.004, 0.016, 0.035, 0.063, 0.098, 0.141, 0.191, 0.25, 0.316, 0.391 36.36%, 0.563, 0.766, 1 54.55%, 0.946, 0.908 72.73%, 0.953, 1, 0.994, 0.998, 1 ); --ease-emphasized: linear( 0, 0.0038, 0.0155, 0.0352, 0.0625 9%, 0.1407, 0.25 18%, 0.5625 36%, 0.7655 45%, 1 ); --primary: var(--blue); --error: var(--red); --warning: var(--yellow); --success: var(--green); /* Primary scale */ --primary-1: oklch(from var(--primary) l c h / 0.1); --primary-2: oklch(from var(--primary) l c h / 0.2); --primary-3: oklch(from var(--primary) l c h / 0.3); --primary-4: oklch(from var(--primary) l c h / 0.4); --primary-5: oklch(from var(--primary) l c h / 0.5); --primary-6: oklch(from var(--primary) l c h / 0.6); --primary-7: oklch(from var(--primary) l c h / 0.75); --primary-8: oklch(from var(--primary) l c h / 0.9); --primary-9: var(--primary); /* Error scale */ --error-1: oklch(from var(--error) l c h / 0.1); --error-2: oklch(from var(--error) l c h / 0.2); --error-3: oklch(from var(--error) l c h / 0.3); --error-4: oklch(from var(--error) l c h / 0.4); --error-5: oklch(from var(--error) l c h / 0.5); --error-6: oklch(from var(--error) l c h / 0.6); --error-7: oklch(from var(--error) l c h / 0.75); --error-8: oklch(from var(--error) l c h / 0.9); --error-9: var(--error); /* Warning scale */ --warning-1: oklch(from var(--warning) l c h / 0.1); --warning-2: oklch(from var(--warning) l c h / 0.2); --warning-3: oklch(from var(--warning) l c h / 0.3); --warning-4: oklch(from var(--warning) l c h / 0.4); --warning-5: oklch(from var(--warning) l c h / 0.5); --warning-6: oklch(from var(--warning) l c h / 0.6); --warning-7: oklch(from var(--warning) l c h / 0.75); --warning-8: oklch(from var(--warning) l c h / 0.9); --warning-9: var(--warning); /* Success scale */ --success-1: oklch(from var(--success) l c h / 0.1); --success-2: oklch(from var(--success) l c h / 0.2); --success-3: oklch(from var(--success) l c h / 0.3); --success-4: oklch(from var(--success) l c h / 0.4); --success-5: oklch(from var(--success) l c h / 0.5); --success-6: oklch(from var(--success) l c h / 0.6); --success-7: oklch(from var(--success) l c h / 0.75); --success-8: oklch(from var(--success) l c h / 0.9); --success-9: var(--success); --l: clamp(0, (l / var(--l-threshold, 0.623) - 1) * -infinity, 1); color-scheme: light dark; } html { box-sizing: border-box; scroll-padding-top: 60px; } html, body, body > .body-fill { min-height: 100vh; margin: 0; } body > .body-fill { display: flex; flex-direction: column; } main { flex: 1; } header, main, footer { width: 100%; } *, *::before, *::after { box-sizing: inherit; } body { font-family: var(--font-sans); line-height: var(--lh); margin: 0; min-height: 100vh; color: var(--fg); background: var(--bg); height: stretch; } h1, h2, h3, h4, h5, h6, p, li, .fluid, textarea, input, select, button, a, th, td, label { /* Fluid Typography System * * This system creates responsive font sizes that scale smoothly between viewport sizes. * Set --fl (fluid level) on any element to control its size (-1 to 6). * * How it works: * 1. Calculate min/max font sizes using pow() with modular scale ratios * 2. Find the rate of change (slope) between min and max * 3. Use clamp() to create a fluid value that scales with viewport/container width * * Formula breakdown: * - --fluid-min: Minimum font size = base * ratio^level * - --fluid-max: Maximum font size = base * ratio^level * - --fluid-preferred: Slope of linear interpolation * - --fluid-type: clamp(min, min + slope * viewport, max) */ --fluid-min: calc(var(--font-size-min) * pow(var(--font-ratio-min), var(--fl, 0))); --fluid-max: calc(var(--font-size-max) * pow(var(--font-ratio-max), var(--fl, 0))); --fluid-preferred: calc( (var(--fluid-max) - var(--fluid-min)) / (var(--font-width-max) - var(--font-width-min)) ); --fluid-type: clamp( (var(--fluid-min) / 16) * 1rem, ((var(--fluid-min) / 16) * 1rem) - (((var(--fluid-preferred) * var(--font-width-min)) / 16) * 1rem) + (var(--fluid-preferred) * var(--variable-unit, 100vi)), (var(--fluid-max) / 16) * 1rem ); font-size: var(--fluid-type); line-height: var(--lh); } /* This makes containers, with container queries use a cqi unit instead of vi */ /* FC Fluid Container */ .fluid-text-container, .fc { container-type: inline-size; --variable-unit: 100cqi; } h1, .h1 { margin-block: 0 var(--vs-base); --fl: 5; } h2, .h2 { --fl: 4; } h3, .h3 { --fl: 3; } h4, .h4 { --fl: 2; } h5, .h5 { --fl: 1; } h6, .h6 { --fl: 0; } p, li, body, input, textarea, button, select { --fl: 0; line-height: var(--lh); } .fs-xs { --fl: -1; } .fs-base { --fl: 0; } .fs-s { --fl: 1; } .fs-m, .pull-quote { --fl: 2; } .fs-l { --fl: 3; } .fs-xl { --fl: 4; } .fs-xxl { --fl: 5; } .fs-xxxl { --fl: 6; } img, picture, video, canvas, svg { display: block; max-width: 100%; } button, .button { --button-color: var(--gray-2); appearance: none; margin: 0; cursor: pointer; background: var(--button-color); color: var(--fg); font-weight: 600; display: inline-flex; justify-content: center; gap: var(--gap, 1rem); align-items: center; line-height: var(--lh); border: var(--border-05); border-radius: var(--br-s); padding: var(--pad-s) var(--pad-xl); text-decoration: none; box-shadow: var(--shadow-1); &:hover { background: oklch(from var(--button-color) calc(l + 0.05) c h); } &:active { background: oklch(from var(--button-color) calc(l + 0.1) c h); } &:disabled { opacity: 0.5; cursor: not-allowed; } &:focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; } &.mini { --fl: 0; padding: var(--pad-xs) var(--pad-m); } &:active { translate: 0 1px; } &.primary { --button-color: var(--primary); color: var(--white); } &.error { --button-color: var(--error); color: var(--white); } &.warning { --button-color: var(--warning); color: var(--black); } &.success { --button-color: var(--success); color: var(--white); } &.ghost { --button-color: transparent; border: var(--fg) solid 2px; color: var(--fg); &:hover { background: var(--fg-05); } &:active { background: var(--fg-1); } } &.minimal { --button-color: transparent; border: none; box-shadow: none; color: var(--fg-7); &:hover { background: transparent; color: var(--fg); } &:active { background: transparent; } } } .close { --size: 2rem; width: var(--size); height: var(--size); padding: 0; border: none; box-shadow: var(--shadow-1); color: var(--white); background: var(--red); cursor: pointer; border-radius: 50%; &:hover { background: oklch(from var(--red) calc(l + 0.1) c h); } } a { &:focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; } } input, textarea, select { &:focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; } &[aria-invalid="true"], &.error { border-color: var(--red-6); &:focus-visible { outline-color: var(--red-6); } } &.success { border-color: var(--green-6); &:focus-visible { outline-color: var(--green-6); } } &.warning { border-color: var(--yellow-7); &:focus-visible { outline-color: var(--yellow-7); } } } label { display: block; --fl: -1; } @layer utilities { /* UTILITIES */ .readable { max-width: 900px; width: 100%; } .flex { display: flex; gap: var(--gap, 1rem); } .grid { display: grid; gap: var(--gap, 1rem); &.auto { grid-template-columns: repeat(auto-fit, minmax(var(--grid-min, 150px), 1fr)); } } .split { display: flex; gap: var(--gap, 1rem); align-items: start; justify-content: space-between; &.even { flex: 1 1 auto; } &.vertical { flex-direction: column; height: 100%; } } /* Container query for .split - stacks when in narrow container */ @container (max-width: 500px) { .split { flex-direction: column; } } .visually-hidden { position: absolute; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); height: 1px; width: 1px; margin: -1px; padding: 0px; border: 0px; } .no-list { list-style: none; margin: 0; padding: 0; li { margin: 0; padding: 0; } } .row { margin-block: var(--vs-m); } .circle { --size: 40px; border-radius: var(--size); padding: 0; width: var(--size); height: var(--size); } /* Aspect Ratio Utilities */ .aspect-square { aspect-ratio: 1 / 1; } .aspect-video { aspect-ratio: 16 / 9; } .aspect-4-3 { aspect-ratio: 4 / 3; } .aspect-21-9 { aspect-ratio: 21 / 9; } .aspect-custom { aspect-ratio: var(--aspect, 1 / 1); } /* Focus Ring - Consistent focus styling utility */ .focus-ring:focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; } .focus-ring-inset:focus-visible { outline: 2px solid var(--fg); outline-offset: -2px; } /* Transition Utilities - Use the easing tokens */ .transition { transition: all 0.2s var(--ease-smooth); } .transition-fast { transition: all 0.1s var(--ease-smooth); } .transition-slow { transition: all 0.4s var(--ease-smooth); } .transition-bounce { transition: all 0.3s var(--ease-bounce); } .transition-none { transition: none; } /* END UTILITIES */ } /* END @layer utilities */ @layer layouts { /* LAYOUTS */ /* * Gap Variable Pattern: * - Grid layouts (layout-card, layout-sidebar, etc.): var(--layout-gap, var(--gap, 2rem)) * - Flex layouts (stack, cluster, carousel, reel): var(--layout-gap, var(--gap, 1rem)) * - Components: var(--gap, 1rem) * * This allows: * 1. Global control via --gap * 2. Layout-specific override via --layout-gap * 3. Sensible defaults (2rem for page grids, 1rem for component layouts) */ /* Card Grid Layout - Auto-fill responsive card grid */ .layout-card { display: grid; grid-template-columns: repeat( auto-fill, minmax(var(--layout-min-card-width, var(--min-card-width, 290px)), 1fr) ); gap: var(--layout-gap, var(--gap, 2rem)); } /* Sidebar Layout - Sidebar + main content area */ .layout-sidebar { display: grid; grid-template-columns: 250px 1fr; gap: var(--layout-gap, var(--gap, 2rem)); align-items: start; } .layout-sidebar.narrow { grid-template-columns: 150px 1fr; } .layout-sidebar.wide { grid-template-columns: 350px 1fr; } .layout-sidebar.invert { grid-template-columns: 1fr 250px; /* Place first child (sidebar) in second column, second child (main) in first column */ > :first-child { grid-column: 2; grid-row: 1; } > :nth-child(2) { grid-column: 1; grid-row: 1; } } .layout-sidebar.invert.narrow { grid-template-columns: 1fr 150px; } .layout-sidebar.invert.wide { grid-template-columns: 1fr 350px; } .layout-sidebar.fill { align-items: stretch; /* Sidebar is always :first-child in DOM, even for .invert (CSS grid handles visual placement) */ > :first-child { overflow-y: auto; } } /* Fixed sidebar - stays pinned while main content scrolls */ /* Sidebar is always :first-child in DOM, even for .invert (CSS grid handles visual placement) */ .layout-sidebar.fixed > :first-child { position: sticky; top: 0; align-self: start; max-height: 100dvh; overflow-y: auto; } .layout-sidebar.layout-readable { --max-width: 1400px; } /* Container query version - responds to parent container size */ @container (max-width: 768px) { .layout-sidebar, .layout-sidebar.narrow, .layout-sidebar.wide, .layout-sidebar.invert, .layout-sidebar.invert.narrow, .layout-sidebar.invert.wide { grid-template-columns: 1fr; } .layout-sidebar.invert > :first-child, .layout-sidebar.invert > :nth-child(2) { grid-column: auto; grid-row: auto; } .layout-sidebar.fill > :first-child, .layout-sidebar.fixed > :first-child { position: static; height: auto; max-height: none; overflow-y: visible; } } /* Media query fallback - for when not inside a container */ @media (width < 768px) { .layout-sidebar, .layout-sidebar.narrow, .layout-sidebar.wide, .layout-sidebar.invert, .layout-sidebar.invert.narrow, .layout-sidebar.invert.wide { grid-template-columns: 1fr; } /* Reset grid placement for invert on mobile so items stack in DOM order */ .layout-sidebar.invert > :first-child, .layout-sidebar.invert > :nth-child(2) { grid-column: auto; grid-row: auto; } /* Reset fill/fixed sidebar styles on mobile - sidebar is always :first-child */ .layout-sidebar.fill > :first-child, .layout-sidebar.fixed > :first-child { position: static; height: auto; max-height: none; overflow-y: visible; } } /* Split Layout - 50/50 two column layout */ .layout-split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--layout-gap, var(--gap, 2rem)); align-items: start; } @media (width < 768px) { .layout-split { grid-template-columns: 1fr; } .layout-split.no-stack { grid-template-columns: 1fr 1fr; } } /* Three Column Layout - Three equal columns */ .layout-three-col { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: var(--layout-gap, var(--gap, 2rem)); align-items: start; } @media (width < 1024px) { .layout-three-col { grid-template-columns: 1fr 1fr; } } @media (width < 768px) { .layout-three-col { grid-template-columns: 1fr; } } /* Readable Layout - Max-width for optimal readability */ .layout-readable { width: 100%; max-width: var(--layout-max-width, var(--max-width, 1200px)); padding-inline: var(--layout-padding, var(--padding, 2rem)); margin: 0 auto; } .layout-readable.center { margin-inline: auto; } .layout-readable.end { margin-inline-start: auto; } .layout-holy-grail { display: grid; grid-template-columns: auto 1fr auto; gap: var(--layout-gap, var(--gap, 2rem)); } @media (width < 768px) { .layout-holy-grail { grid-template-columns: 1fr; } } /* Full Bleed - Break out of readable container */ .layout-readable .full-bleed { width: 100vi; margin-inline: calc(50% - 50vi); } /* Stack Layout - Vertical flexbox stack */ .stack { display: flex; flex-direction: column; justify-content: flex-start; gap: var(--layout-gap, var(--gap, 1rem)); } :is(.stack) > * { margin-block: 0; margin-inline: 0; } /* Cluster Layout - Horizontal wrapping list with gap */ .cluster { display: flex; flex-wrap: wrap; gap: var(--layout-gap, var(--gap, 1rem)); align-items: center; } /* Carousel Layout - Horizontal scroll with scroll snap */ .carousel { display: flex; gap: var(--layout-gap, var(--gap, 1rem)); overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: var(--layout-padding, var(--padding, 1rem)); scrollbar-width: thin; > * { scroll-snap-align: start; flex-shrink: 0; } } /* Reel Layout - Vertical scroll with scroll snap */ .reel { display: flex; flex-direction: column; gap: var(--layout-gap, var(--gap, 1rem)); overflow-y: auto; scroll-snap-type: y mandatory; scroll-padding-block: var(--layout-padding, var(--padding, 1rem)); scrollbar-width: thin; max-height: var(--reel-height, 80vh); > * { scroll-snap-align: start; flex-shrink: 0; } } .swipe { container-type: inline-size; display: grid; grid-template-columns: auto 1fr auto; overflow-x: auto; scroll-snap-type: x mandatory; border-block: var(--border-1); -ms-overflow-style: none; scrollbar-width: none; > :nth-child(2) { width: 100cqw; scroll-snap-align: center; padding: var(--pad-l) var(--vs-base); } > button { border-radius: 0; box-shadow: 1px 1px 4px rgb(0 0 0 / 0.5) inset; border: none; width: 200px; } &.stop { > * { &:first-of-type { animation: snap_start_hack 0.001s forwards; } &:last-of-type { scroll-snap-align: end; } } } } /* Thank you Adam Argyle @argyleink for this hack.*/ /* nerdy.dev */ @keyframes snap_start_hack { to { scroll-snap-align: start; } } :where(h1, h2, h3, h4, h5, h6) { view-transition-name: var(--transition-name); text-wrap: balance; } /* END LAYOUTS */ } /* END @layer layouts */ /* Dark mode shadow overrides - Deeper, more intense shadows (unlayered for priority) */ @media (prefers-color-scheme: dark) { :root { --shadow-1: 0 1px 2px rgb(0 0 0 / 0.5), 0 2px 4px rgb(0 0 0 / 0.3); --shadow-2: 0 2px 4px rgb(0 0 0 / 0.6), 0 4px 8px rgb(0 0 0 / 0.4); --shadow-3: 0 4px 8px rgb(0 0 0 / 0.65), 0 8px 16px rgb(0 0 0 / 0.45), 0 2px 4px rgb(0 0 0 / 0.3); --shadow-4: 0 6px 12px rgb(0 0 0 / 0.7), 0 12px 24px rgb(0 0 0 / 0.5), 0 3px 6px rgb(0 0 0 / 0.35); --shadow-5: 0 10px 20px rgb(0 0 0 / 0.75), 0 16px 32px rgb(0 0 0 / 0.55), 0 4px 8px rgb(0 0 0 / 0.4); --shadow-6: 0 16px 32px rgb(0 0 0 / 0.8), 0 24px 48px rgb(0 0 0 / 0.6), 0 32px 64px rgb(0 0 0 / 0.5), 0 6px 12px rgb(0 0 0 / 0.45); } } @layer components { /* COMPONENTS */ /* Boxes */ .box { background: var(--fg-05); padding: var(--pad-m); border-radius: var(--br-s); border: var(--border-1); } .box.ghost { background: transparent; } .box.invisible { background: transparent; border: none; box-shadow: none; } .box.glow { box-shadow: var(--box); } .box.semi-gloss { box-shadow: var(--box), var(--shadow-5); background: linear-gradient(180deg, var(--fg-05) 0%, var(--fg-1) 100%); } /* UI Elements */ .header { display: flex; gap: var(--gap, 1rem); align-items: center; padding: var(--pad-l); justify-content: space-between; > * { margin: 0; } nav { ul { margin: 0; padding: 0; display: flex; gap: var(--gap, 1rem); list-style: none; li { margin: 0; a { color: var(--fg); text-decoration: none; } } } } &.border { border-bottom: var(--border-1); } &.sticky { position: sticky; top: 0; z-index: 10; background: var(--bg); } &.readable { max-width: 1400px; margin: 0 auto; padding-inline: var(--layout-padding, var(--padding, 2rem)); } } .callout { --callout-color: var(--blue-1); --callout-border-color: var(--blue-5); padding: var(--pad-l); border-radius: var(--br-xl); border: var(--callout-border-color) solid 2px; color: var(--fg-8); gap: var(--gap, 1rem); > * { margin: 0; } &.fill { background: var(--callout-color); } &.warning { --callout-color: var(--yellow-1); --callout-border-color: var(--yellow-5); } &.error { --callout-color: var(--red-1); --callout-border-color: var(--red-5); } &.ghost { --callout-color: var(--gray-1); --callout-border-color: var(--gray-5); } &.success { --callout-color: var(--green-1); --callout-border-color: var(--green-5); } &.hard { border-inline-start: 10px solid var(--callout-border-color); } } .table { overflow-x: auto; border: var(--border-2); border-radius: var(--table-border, var(--br-m)); } table { width: 100%; border-collapse: collapse; } td, th { text-align: left; padding: var(--pad-m) var(--vs-base); } thead { border-bottom: var(--border-2); } td { border-bottom: var(--border-1); } tr:last-child { td { border: none; } } /*Forms*/ input, select, textarea { color: var(--fg); line-height: var(--lh-xl); background-color: var(--fg-05); border: var(--border-1); border-radius: var(--br-m); padding-inline: var(--pad-m); width: 100%; &:has(+ small) { margin-block-end: var(--vs-xs); } + small { margin-block-end: var(--vs-base); display: block; } } label { margin-block-end: var(--vs-xs); } select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right var(--pad-m) center; padding-inline-end: calc(var(--pad-m) + 1.5em); } input[type="checkbox"], input[type="radio"] { width: auto; height: auto; inline-size: 1em; block-size: 1em; margin: 0; margin-inline-end: var(--vs-s); vertical-align: middle; accent-color: var(--accent); cursor: pointer; } .search { position: relative; svg { position: absolute; inset-inline-start: var(--pad-m); inset-block: 0; top: 9px; margin-block: 0; block-size: 1.25em; inline-size: 1.25em; color: var(--fg-3); pointer-events: none; } input { padding-inline-start: calc(var(--pad-m) + 1.25em + var(--vs-s)); } } .dropzone { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--vs-s); padding: var(--pad-xxxl); border: 2px dashed var(--fg-2); border-radius: var(--br-l); cursor: pointer; transition: border-color 0.15s var(--ease-smooth), background-color 0.15s var(--ease-smooth); input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; } svg { block-size: 2.5em; inline-size: 2.5em; color: var(--fg-3); transition: color 0.15s var(--ease-smooth), translate 0.15s var(--ease-smooth); } span { color: var(--fg-5); text-align: center; transition: color 0.15s var(--ease-smooth); } &:hover { border-color: var(--fg-3); background-color: var(--fg-05); svg { color: var(--fg-4); translate: 0 -5px; } span { color: var(--fg-6); } } &.dragover { border-color: var(--accent, var(--fg-5)); background-color: var(--fg-1); svg { color: var(--accent, var(--fg-6)); } span { color: var(--fg-7); } } } /* * AUTO-COLOR: Automatic contrast text color for any background * * This class automatically chooses black or white text based on the background * color's perceived lightness, even for transparent/semi-transparent colors. * * HOW IT WORKS: * * 1. EFFECTIVE LIGHTNESS CALCULATION * For transparent colors, the visual lightness depends on what's behind them. * We calculate "effective lightness" by simulating alpha blending: * * Light mode (white bg): effective_l = l * alpha + (1 - alpha) * - Transparent color blends toward white (lightness 1) * - Example: 50% opacity, l=0.5 → 0.5 * 0.5 + 0.5 = 0.75 * * Dark mode (black bg): effective_l = l * alpha * - Transparent color blends toward black (lightness 0) * - Example: 50% opacity, l=0.5 → 0.5 * 0.5 = 0.25 * * 2. THE BINARY SWITCH (clamp trick) * We need to output EITHER dark text OR light text - no in-between. * The formula: clamp(dark, calc((effective_l / threshold - 1) * -infinity), light) * * - If effective_l > threshold: (positive - 1) * -infinity = -infinity → clamp returns dark (0) * - If effective_l < threshold: (negative - 1) * -infinity = +infinity → clamp returns light (1) * * The -infinity multiplier creates extreme values that hit clamp bounds, * effectively making this a binary if/else in pure CSS. * * 3. LIGHT-DARK() FUNCTION * Wraps both calculations so light mode uses the white-bg formula * and dark mode uses the black-bg formula automatically. * * 4. RELATIVE COLOR SYNTAX * `oklch(from var(--bg-color) ...)` extracts l, c, h, alpha from --bg-color * We use `l` (lightness) and `alpha` in our calculation, output new color. * * USAGE: *
Text
* * CUSTOMIZATION: * --threshold: 0.6 (lightness cutoff, 0-1) * --light-text-l: 1 (lightness for light text, usually white) * --dark-text-l: 0 (lightness for dark text, usually black) * * VARIANT: .chroma * Adds 80% opacity to text, letting background color bleed through * for a subtle tinted text effect. */ .auto-color { --threshold: 0.6; --light-text-l: 1; --dark-text-l: 0; background-color: var(--bg-color); color: light-dark( oklch( from var(--bg-color) clamp( var(--dark-text-l), calc(((l * alpha + 1 - alpha) / var(--threshold) - 1) * -infinity), var(--light-text-l) ) 0 0 / 1 ), oklch( from var(--bg-color) clamp( var(--dark-text-l), calc(((l * alpha) / var(--threshold) - 1) * -infinity), var(--light-text-l) ) 0 0 / 1 ) ); &.chroma { color: light-dark( oklch( from var(--bg-color) clamp( var(--dark-text-l), calc(((l * alpha + 1 - alpha) / var(--threshold) - 1) * -infinity), var(--light-text-l) ) 0 0 / 0.8 ), oklch( from var(--bg-color) clamp( var(--dark-text-l), calc(((l * alpha) / var(--threshold) - 1) * -infinity), var(--light-text-l) ) 0 0 / 0.8 ) ); } } /* Disclosure Elements (details/summary) */ details { margin-block: var(--vs-base); } summary { cursor: pointer; padding: var(--pad-s) var(--pad-m); color: var(--fg-7); list-style: none; display: flex; align-items: center; gap: var(--pad-s); user-select: none; &::-webkit-details-marker { display: none; } &::before { content: "›"; rotate: 0deg; transition: rotate 0.2s var(--ease-smooth); flex-shrink: 0; } &:hover { color: var(--fg); } &:focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; } } details[open] > summary::before { rotate: 90deg; } /* Content animation using @starting-style and allow-discrete */ details::details-content { opacity: 1; block-size: auto; overflow: clip; transition: opacity 0.3s var(--ease-smooth), block-size 0.3s var(--ease-smooth), content-visibility 0.3s var(--ease-smooth) allow-discrete; } details:not([open])::details-content { opacity: 0; block-size: 0; } @starting-style { details[open]::details-content { opacity: 0; block-size: 0; } } /* Details content padding and margin reset */ details > :not(summary) { padding: var(--pad-s) var(--pad-m); margin: 0; } /* Right-aligned summary variant (e.g., "Code" toggle) */ details.right > summary, details > summary.right { justify-content: flex-end; &::before { display: none; } &::after { content: "›"; rotate: 0deg; transition: rotate 0.2s var(--ease-smooth); flex-shrink: 0; } } details.right[open] > summary::after, details[open] > summary.right::after { rotate: 90deg; } /* Bordered container variant */ details.bordered { border: var(--border-1); border-radius: var(--br-m); overflow: hidden; > summary { border-bottom: var(--border-1); } &:not([open]) > summary { border-bottom-color: transparent; } > :not(summary) { padding-inline: var(--pad-m); } } /* Minimal variant - just the toggle, no extra styling */ details.minimal > summary { padding: 0; &::before { display: none; } &::after { content: "+"; font-weight: 600; margin-inline-start: var(--pad-s); } } details.minimal[open] > summary::after { content: "−"; } /* Breadcrumbs */ .breadcrumbs { --separator: "/"; & > ul { display: flex; flex-wrap: wrap; align-items: center; gap: var(--pad-s); } & li { display: flex; align-items: center; gap: var(--pad-s); &:not(:first-child)::before { content: var(--separator); color: var(--fg-4); } } & a { color: var(--fg-5); text-decoration: none; margin-block: 0; &:hover { color: var(--fg-7); } &:focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; } } & li[aria-current="page"] { color: var(--fg); font-weight: 500; } } /* Sidebar Navigation */ .sidebar-nav { --sidebar-nav-icon-size: 20px; --sidebar-nav-indent: 1.5rem; display: flex; flex-direction: column; width: 100%; /* Top-level links and summary elements */ > a, > details > summary { display: flex; align-items: center; gap: var(--pad-s); padding: var(--pad-s) var(--pad-m); color: var(--fg-6); text-decoration: none; border-radius: var(--br-s); cursor: pointer; transition: background-color 0.1s var(--ease-smooth); margin: 0; /* Icon sizing */ > svg { width: var(--sidebar-nav-icon-size); height: var(--sidebar-nav-icon-size); flex-shrink: 0; } &:hover { background: var(--fg-05); color: var(--fg); } &:focus-visible { outline: 2px solid var(--fg); outline-offset: -2px; } } /* Active state for links */ > [aria-current="page"], > details > summary.active { background: var(--fg-05); color: var(--fg); } /* Details/summary overrides for sidebar context */ > details { margin: 0; > summary { list-style: none; user-select: none; &::-webkit-details-marker { display: none; } /* Override default details arrow - use subtle chevron after text */ &::before { display: none; } &::after { content: "›"; margin-inline-start: auto; rotate: 0deg; transition: rotate 0.15s var(--ease-smooth); color: var(--fg-4); } } &[open] > summary::after { rotate: 90deg; } /* Nested content - no animation override, uses global details animation */ > a { display: flex; align-items: center; gap: var(--pad-s); padding: var(--pad-s) var(--pad-m); padding-inline-start: calc(var(--pad-m) + var(--sidebar-nav-indent)); color: var(--fg-5); text-decoration: none; border-radius: var(--br-s); margin: 0; transition: background-color 0.1s var(--ease-smooth); &:hover { background: var(--fg-05); color: var(--fg); } &:focus-visible { outline: 2px solid var(--fg); outline-offset: -2px; } &.active { background: var(--fg-05); color: var(--fg); } } } /* Sub-item modifier for top-level links (same style as nested details links) */ > a.sub { padding-inline-start: calc(var(--pad-m) + var(--sidebar-nav-indent)); color: var(--fg-5); } } /* Footer */ .footer { container-type: inline-size; a { text-decoration: none; &:hover { text-decoration: underline; } } /* Ensure nav columns have bottom margin when grid wraps */ .grid > nav { margin-bottom: var(--vs-m); } } /* Footer responds to its own container size */ @container (max-width: 600px) { .footer .grid { grid-template-columns: 1fr; } } /* Dropdown Menu */ .dropdown { position: relative; display: inline-block; anchor-name: var(--anchor); } .dropdown-menu[popover] { position: absolute; position-anchor: var(--anchor); inset: unset; position-area: block-end span-inline-end; margin: 0; margin-block-start: var(--pad-xs); padding: 0; /* Styling */ min-width: 12rem; background: var(--bg); border: var(--border-1); border-radius: var(--br-m); box-shadow: var(--shadow-4); overflow: hidden; /* Animation */ opacity: 1; scale: 1; transform-origin: top left; transition: opacity 0.15s var(--ease-smooth), scale 0.15s var(--ease-smooth), display 0.15s var(--ease-smooth) allow-discrete; /* Menu items - links and buttons */ a, button { display: block; width: 100%; padding: var(--pad-s) var(--pad-m); color: var(--fg-7); text-decoration: none; text-align: start; cursor: pointer; transition: background-color 0.1s var(--ease-smooth); margin: 0; border: none; background: none; font: inherit; box-shadow: none; border-radius: 0; &:hover { background: var(--fg-05); color: var(--fg); opacity: 1; } &:focus-visible { outline: 2px solid var(--fg); outline-offset: -2px; } &:active { background: var(--fg-1); } &[aria-disabled="true"], &.disabled { opacity: 0.5; cursor: not-allowed; pointer-events: none; } } /* Dividers */ hr { height: 0; margin: var(--pad-xs) 0; border: none; border-top: var(--border-1); } } .dropdown-menu[popover]:not(:popover-open) { opacity: 0; scale: 0.95; } @starting-style { .dropdown-menu[popover]:popover-open { opacity: 0; scale: 0.95; } } /* End-aligned variant */ .dropdown.end .dropdown-menu[popover] { position-area: block-end span-inline-start; transform-origin: top right; } .dropdown-header { padding: var(--pad-s) var(--pad-m); color: var(--fg-5); --fl: -1; } /* Tooltip - uses CSS anchor positioning */ .tooltip { anchor-scope: --tooltip; anchor-name: --tooltip; display: inline-block; } .tooltip-content { position: absolute; position-anchor: --tooltip; inset: unset; position-area: block-start center; margin-block-end: var(--vs-xs); padding: var(--pad-xs) var(--pad-s); width: max-content; max-width: 30ch; background: var(--bg); border: var(--border-1); border-radius: var(--br-s); box-shadow: var(--shadow-3); --fl: -1; pointer-events: none; text-align: center; opacity: 0; transition: opacity 0.15s var(--ease-smooth); } .tooltip:hover .tooltip-content, .tooltip:focus-within .tooltip-content { opacity: 1; } /* Position variants */ .tooltip.bottom .tooltip-content { position-area: block-end center; margin-block-end: 0; margin-block-start: var(--vs-xs); } .tooltip.left .tooltip-content { position-area: inline-start center; margin-block-end: 0; margin-inline-end: var(--vs-xs); } .tooltip.right .tooltip-content { position-area: inline-end center; margin-block-end: 0; margin-inline-start: var(--vs-xs); } /* Avatar */ .avatar { --avatar-size: 2.5rem; display: inline-flex; align-items: center; justify-content: center; width: var(--avatar-size); height: var(--avatar-size); border-radius: 50%; overflow: hidden; flex-shrink: 0; background: var(--fg-1); color: var(--fg-6); font-weight: 600; --fl: 0; /* Images fill the circle */ img { width: 100%; height: 100%; object-fit: cover; } /* Optional border */ &.bordered { border: var(--border-1); } /* Size variants */ &.xs { --avatar-size: 1.5rem; --fl: -1; } &.s { --avatar-size: 2rem; --fl: -1; } /* .m is the default (2.5rem) */ &.l { --avatar-size: 3.5rem; --fl: 1; } &.xl { --avatar-size: 5rem; --fl: 2; } /* Button reset for clickable avatars (dropdown triggers, etc.) */ &:is(button) { border: none; box-shadow: none; background: var(--fg-1); padding: 0; cursor: pointer; } } /* Toggle Switch */ input[type="checkbox"].toggle { --toggle-width: 2.75em; --toggle-height: 1.5em; --toggle-knob-size: calc(var(--toggle-height) - 4px); --toggle-knob-offset: 2px; --toggle-color: var(--primary); appearance: none; position: relative; width: var(--toggle-width); height: var(--toggle-height); border-radius: var(--toggle-height); background: var(--fg-2); cursor: pointer; margin: 0; padding: 0; border: none; box-shadow: none; flex-shrink: 0; transition: background-color 0.2s var(--ease-smooth); /* The knob */ &::before { content: ""; position: absolute; inset-block-start: var(--toggle-knob-offset); inset-inline-start: var(--toggle-knob-offset); width: var(--toggle-knob-size); height: var(--toggle-knob-size); border-radius: 50%; background: var(--bg); transition: translate 0.2s var(--ease-smooth); } /* Checked state */ &:checked { background: var(--toggle-color); &::before { translate: calc( var(--toggle-width) - var(--toggle-knob-size) - var(--toggle-knob-offset) * 2 ) 0; } } /* Focus state */ &:focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; } /* Hover state */ &:hover:not(:disabled) { background: var(--fg-3); &:checked { background: oklch(from var(--toggle-color) calc(l - 0.05) c h); } } /* Disabled state */ &:disabled { opacity: 0.5; cursor: not-allowed; } /* Compact variant */ &.compact { --toggle-width: 2em; --toggle-height: 1.125em; } } /* Input Group - Connected input + button */ .input-group { display: flex; align-items: stretch; /* Input takes available space */ > input { flex: 1; min-width: 0; border-start-end-radius: 0; border-end-end-radius: 0; margin: 0; } > button, > .button { border-start-start-radius: 0; border-end-start-radius: 0; margin: 0; flex-shrink: 0; box-shadow: none; &:active { translate: none; } } /* Focus states - ensure outline is visible above siblings */ > input:focus-visible { z-index: 1; } > button:focus-visible, > .button:focus-visible { z-index: 1; } } ::selection { background: var(--primary); } /* Dialog */ dialog { max-width: 40ch; width: calc(100% - var(--pad-xxl) * 2); padding: var(--pad-xl); border: none; border-radius: var(--br-xxl); box-shadow: var(--shadow-5); background: var(--bg); color: var(--fg); overflow: visible; opacity: 1; scale: 1; transition: opacity 0.2s var(--ease-smooth), scale 0.2s var(--ease-smooth), overlay 0.2s var(--ease-smooth) allow-discrete, display 0.2s var(--ease-smooth) allow-discrete; &::backdrop { background-color: rgba(0, 0, 0, 0.9); } > :last-child { margin-block-end: 0; } } dialog:not([open]) { opacity: 0; scale: 0.95; } @starting-style { dialog[open] { opacity: 0; scale: 0.95; } } dialog > .close { position: absolute; inset-block-start: -14px; inset-inline-end: var(--pad-m); } /* Chip */ .chip { display: inline-flex; align-items: center; gap: var(--pad-xs); padding: var(--pad-xs) var(--pad-m); border: var(--border-1); border-radius: var(--br-xxl); cursor: pointer; user-select: none; transition: background-color 0.15s var(--ease-smooth), border-color 0.15s var(--ease-smooth); --fl: -1; margin: 0; /* Reset button styles when used on button element */ &:is(button) { background: transparent; box-shadow: none; font: inherit; } /* Icon sizing */ > svg { width: 1em; height: 1em; flex-shrink: 0; } /* Hover state */ &:hover { background: var(--fg-05); } /* Focus state */ &:focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; } /* Active/pressed state */ &:active { background: var(--fg-1); } /* Selected state - via aria-pressed or .selected class */ &[aria-pressed="true"], &.selected { background: var(--primary); border-color: var(--primary); color: var(--white); &:hover { background: oklch(from var(--primary) calc(l - 0.05) c h); border-color: oklch(from var(--primary) calc(l - 0.05) c h); } &:active { background: oklch(from var(--primary) calc(l - 0.1) c h); border-color: oklch(from var(--primary) calc(l - 0.1) c h); } } /* Disabled state */ &:disabled, &[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; pointer-events: none; } /* Mini variant - even more compact */ &.mini { padding: 2px var(--pad-s); gap: 2px; } } /* Tag - Subtle category/metadata labels */ .tag { --tag-color: var(--primary); display: inline-flex; align-items: center; gap: var(--pad-xs); padding: 2px var(--pad-s); border-radius: var(--br-xxl); background: oklch(from var(--tag-color) l c h / 0.12); color: light-dark( oklch(from var(--tag-color) calc(l - 0.15) c h), oklch(from var(--tag-color) calc(l + 0.15) c h) ); border: 1px solid oklch(from var(--tag-color) l c h / 0.2); --fl: -1; /* Icon sizing */ > svg { width: 1em; height: 1em; flex-shrink: 0; } /* When used as interactive element */ &:is(a, button) { cursor: pointer; text-decoration: none; transition: background-color 0.15s var(--ease-smooth), border-color 0.15s var(--ease-smooth); &:hover { background: oklch(from var(--tag-color) l c h / 0.2); border-color: oklch(from var(--tag-color) l c h / 0.3); } &:focus-visible { outline: 2px solid var(--tag-color); outline-offset: 2px; } &:active { background: oklch(from var(--tag-color) l c h / 0.25); } } /* Reset button styles when used on button element */ &:is(button) { background: oklch(from var(--tag-color) l c h / 0.12); box-shadow: none; font: inherit; margin: 0; } /* Muted variant - colored background, neutral text for better readability */ &.muted { color: var(--fg); } } /* List Navigation - Clickable navigation rows */ .list-nav { display: flex; flex-direction: column; gap: var(--pad-m); > a, > button { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: var(--pad-m); padding: var(--pad-l) var(--pad-l); color: var(--fg); text-decoration: none; cursor: pointer; margin: 0; background: var(--bg); border-radius: var(--br-xxl); box-shadow: var(--shadow-2); transition: box-shadow 0.1s var(--ease-smooth); /* Reset button styles */ &:is(button) { width: 100%; border: none; font: inherit; text-align: start; } /* Icon */ > svg { width: 1.25em; height: 1.25em; color: var(--fg-5); } /* Description below title */ > small { grid-column: 2; color: var(--fg-5); --fl: -1; } /* Hover state */ &:hover { background: var(--fg-05); > svg { color: var(--fg-6); } } /* Focus state */ &:focus-visible { outline: 2px solid var(--fg); outline-offset: -2px; } /* Active/pressed state */ &:active { background: var(--fg-1); } /* Disabled state */ &:is([aria-disabled="true"], :disabled, .disabled) { opacity: 0.5; cursor: not-allowed; pointer-events: none; } } @media (prefers-color-scheme: dark) { & > a, & > button { border: var(--border-1); } } } /* Tabs - Pure CSS tabs using details/summary with grid and subgrid */ .tabs { display: grid; grid-template-columns: repeat(var(--tab-count, 3), minmax(100px, 1fr)); grid-template-rows: auto 1fr; column-gap: var(--gap, 1rem); /* Each details element spans the full grid */ > details { display: grid; grid-template-columns: subgrid; grid-template-rows: subgrid; grid-column: 1 / -1; grid-row: 1 / span 2; margin: 0; /* Summary acts as the tab button */ > summary { grid-row: 1; grid-column: var(--n) / span 1; z-index: 1; display: flex; align-items: center; justify-content: center; padding: var(--pad-s) var(--pad-m); color: var(--fg-5); border-bottom: 2px solid transparent; cursor: pointer; user-select: none; transition: color 0.15s var(--ease-smooth), border-color 0.15s var(--ease-smooth); /* Remove default chevron */ &::before { display: none; } &:hover { color: var(--fg-7); } &:focus-visible { outline: 2px solid var(--fg); outline-offset: -2px; } } /* Active tab styling */ &[open] > summary { color: var(--fg); font-weight: 600; border-bottom-color: var(--primary); } /* Tab panel content */ &::details-content { grid-row: 2; grid-column: 1 / -1; padding: var(--pad-l); /* Override default details animation for tabs */ opacity: 1; block-size: auto; overflow: visible; transition: opacity 0.2s var(--ease-smooth), display 0.2s var(--ease-smooth) allow-discrete; } /* Hidden tab panels */ &:not([open])::details-content { display: none; opacity: 0; } /* Content inside panel - reset margins */ > :not(summary) { padding: 0; margin: 0; } } @starting-style { > details[open]::details-content { opacity: 0; } } /* Boxed variant - card-style tabs that connect to panel */ &.boxed { > details { > summary { border: var(--border-1); border-bottom: none; border-radius: var(--br-m) var(--br-m) 0 0; background: var(--fg-05); margin-inline-end: -1px; position: relative; } /* Active tab connects to panel */ &[open] > summary { background: var(--bg); z-index: 2; /* Create bottom "bridge" to panel */ &::after { content: ""; position: absolute; inset-inline: 0; inset-block-end: -1px; height: 2px; background: var(--bg); } } /* Panel styling */ &::details-content { padding: var(--pad-l); border: var(--border-1); border-radius: 0 0 var(--br-m) var(--br-m); margin-block-start: -1px; } } } /* Pill variant - rounded pill-style tabs */ &.pill { gap: var(--pad-s); column-gap: var(--pad-s); > details > summary { border-radius: var(--br-xxl); border: var(--border-1); border-bottom-width: 1px; margin-block-end: var(--pad-s); &:hover { background: var(--fg-05); } } > details[open] > summary { background: var(--primary); border-color: var(--primary); color: var(--white); } } } /* END COMPONENTS */ } /* END @layer components */ /* ACCESSIBILITY & PRINT (unlayered for highest priority) */ /* Reduced Motion - Respect user preference for reduced motion */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } } /* Print Styles */ @media print { *, *::before, *::after { background: transparent !important; color: black !important; box-shadow: none !important; text-shadow: none !important; } body { font-size: 12pt; line-height: 1.5; } a, a:visited { text-decoration: underline; } a[href]::after { content: " (" attr(href) ")"; font-size: 0.8em; } a[href^="#"]::after, a[href^="javascript:"]::after { content: ""; } img { max-width: 100% !important; page-break-inside: avoid; } h1, h2, h3, h4, h5, h6 { page-break-after: avoid; page-break-inside: avoid; } p, blockquote, ul, ol, dl, table, pre { page-break-inside: avoid; } .no-print { display: none !important; } }