Some checks failed
validate theme / validate (push) Has been cancelled
Lifted from skyai-finance into a standalone theme once the choices stabilised. New name earns itself twice: the literal glass refraction, and the hue spectrum the corner glows span (lavender → peach → cyan → mint). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
620 lines
23 KiB
CSS
620 lines
23 KiB
CSS
/*
|
||
* prism — crystal-clear glass theme.
|
||
*
|
||
* Iridescent multi-hue palette (lavender → peach → cyan → mint) refracted
|
||
* through frosted-glass surfaces. Earns its name twice: once for the
|
||
* literal glass refraction, once for the hue spectrum the corner glows
|
||
* span. Born in skyai-finance; lifted into a standalone theme when the
|
||
* shape stabilised.
|
||
*
|
||
* Forked from skyrise (lib-theme-skyrise) with four product-driven
|
||
* changes that became theme-wide:
|
||
*
|
||
* 1. Bakes in --warning + --warning-foreground (skyrise had them;
|
||
* pristine did not). Any product that displays health/risk needs
|
||
* warning semantics in both modes.
|
||
* 2. Adds a --text-hero size step (3.5rem) above display, for KPI
|
||
* heroes and editorial mastheads.
|
||
* 3. Ships a `.num` utility that sets tabular-nums + slashed-zero +
|
||
* letter-spacing:0 — non-negotiable on money numbers, useful
|
||
* anywhere digits matter.
|
||
* 4. Redesigns the dark-mode background. Skyrise's dark blobs sat at
|
||
* L≈0.18 with chroma≈0.12, near OKLCH gamut edges, which clipped
|
||
* to muddy gray. Here the corner glows are pushed to L≈0.30 with
|
||
* lower chroma, paired with a cleaner near-black base — they read
|
||
* as soft brand-accent light instead of tinted fog.
|
||
*
|
||
* Also dropped: the 11 background atmospheres and 4 surface tints
|
||
* skyrise shipped for white-label flexibility. Prism picks one brand
|
||
* surface (light + dark) and ships it. If alternates return, re-import
|
||
* from skyrise.
|
||
*
|
||
* Fonts loaded by the consuming app via Google Fonts URL @import at the
|
||
* very top of its entry CSS — see README. Do NOT @import them here.
|
||
*/
|
||
|
||
:root {
|
||
/* ── Colors ──
|
||
* Light mode rests on an iridescent lavender→peach→mint→rose gradient
|
||
* (defined in @layer base below). Glass surfaces sit at low alpha so the
|
||
* gradient reads through; foreground is pushed to L=0.16 for vivid,
|
||
* never-faint text against translucent surfaces. */
|
||
--background: oklch(0.97 0.015 295);
|
||
--foreground: oklch(0.16 0.025 285);
|
||
|
||
--card: oklch(1 0 0 / 0.58);
|
||
--card-foreground: oklch(0.16 0.025 285);
|
||
|
||
--popover: oklch(1 0 0 / 0.74);
|
||
--popover-foreground: oklch(0.16 0.025 285);
|
||
|
||
--primary: oklch(0.55 0.22 295);
|
||
--primary-foreground: oklch(1 0 0);
|
||
|
||
--secondary: oklch(0.96 0.012 290);
|
||
--secondary-foreground: oklch(0.22 0.025 285);
|
||
|
||
--muted: oklch(0.95 0.012 290);
|
||
--muted-foreground: oklch(0.42 0.02 285);
|
||
|
||
--accent: oklch(0.93 0.04 295);
|
||
--accent-foreground: oklch(0.25 0.05 295);
|
||
|
||
--destructive: oklch(0.6 0.24 25);
|
||
--success: oklch(0.5 0.18 150);
|
||
--success-foreground: oklch(1 0 0);
|
||
--warning: oklch(0.7 0.18 75);
|
||
--warning-foreground: oklch(0.18 0.04 75);
|
||
|
||
--border: oklch(0 0 0 / 0.09);
|
||
--input: oklch(0 0 0 / 0.09);
|
||
--ring: oklch(0.55 0.22 295 / 0.55);
|
||
|
||
/* Charts: violet → blue-cyan → amber → rose → emerald. Hues spread ≥60°
|
||
* apart and lightness is varied between adjacent indices so adjacent
|
||
* series stay perceptually distinct in multi-line / stacked charts. */
|
||
--chart-1: oklch(0.55 0.24 295);
|
||
--chart-2: oklch(0.62 0.2 230);
|
||
--chart-3: oklch(0.82 0.18 80);
|
||
--chart-4: oklch(0.72 0.2 350);
|
||
--chart-5: oklch(0.5 0.18 150);
|
||
|
||
--sidebar: oklch(1 0 0 / 0.5);
|
||
--sidebar-foreground: oklch(0.16 0.025 285);
|
||
--sidebar-primary: oklch(0.55 0.22 295);
|
||
--sidebar-primary-foreground: oklch(1 0 0);
|
||
--sidebar-accent: oklch(0.93 0.04 295);
|
||
--sidebar-accent-foreground: oklch(0.25 0.05 295);
|
||
--sidebar-border: oklch(0 0 0 / 0.07);
|
||
--sidebar-ring: oklch(0.55 0.22 295 / 0.55);
|
||
|
||
--syntax-keyword: oklch(0.5 0.22 295);
|
||
--syntax-string: oklch(0.5 0.16 150);
|
||
--syntax-number: oklch(0.55 0.18 35);
|
||
--syntax-comment: oklch(0.52 0.02 285);
|
||
--syntax-function: oklch(0.48 0.18 235);
|
||
--syntax-type: oklch(0.48 0.14 195);
|
||
|
||
/* ── Radius ── Generous, premium feel. */
|
||
--radius: 1rem;
|
||
|
||
/* ── Motion ── Apple-style spring physics. */
|
||
--duration-fast: 180ms;
|
||
--duration-base: 320ms;
|
||
--duration-slow: 450ms;
|
||
--duration-slower: 600ms;
|
||
--duration-spring: 520ms;
|
||
|
||
--ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
|
||
--ease-decelerate: cubic-bezier(0, 0, 0.2, 1);
|
||
--ease-accelerate: cubic-bezier(0.4, 0, 1, 1);
|
||
|
||
--ease-spring-gentle: linear(0, 0.04 8%, 0.12 15%, 0.23 22%, 0.37 30%, 0.51 38%, 0.63 46%, 0.74 54%, 0.83 62%, 0.89 70%, 0.94 78%, 0.97 86%, 0.99 94%, 1);
|
||
--ease-spring-snappy: linear(0, 0.06 6%, 0.18 12%, 0.33 18%, 0.5 25%, 0.65 32%, 0.8 40%, 0.9 48%, 0.98 56%, 1.015 64%, 1.02 72%, 1.015 80%, 1.005 88%, 1);
|
||
--ease-spring-bouncy: linear(0, 0.08 8%, 0.22 16%, 0.4 24%, 0.58 32%, 0.75 40%, 0.88 48%, 0.98 56%, 1.04 64%, 1.06 72%, 1.04 80%, 1.01 86%, 0.995 92%, 1);
|
||
|
||
--ease-emphasized: var(--ease-spring-snappy);
|
||
|
||
/* ── Typography ── Bumped one notch from typical sizes for readability.
|
||
* Body sits at 17px (1.0625rem) — never-faint text. All scales ride
|
||
* along proportionally. Hero is the finance KPI step above display. */
|
||
--text-hero-size: 3.5rem;
|
||
--text-hero-lh: 3.75rem;
|
||
--text-display-size: 3rem;
|
||
--text-display-lh: 3.25rem;
|
||
--text-headline-size: 2rem;
|
||
--text-headline-lh: 2.375rem;
|
||
--text-title-size: 1.5rem;
|
||
--text-title-lh: 1.875rem;
|
||
--text-body-size: 1.0625rem;
|
||
--text-body-lh: 1.625rem;
|
||
--text-label-size: 0.9375rem;
|
||
--text-label-lh: 1.25rem;
|
||
--text-caption-size: 0.8125rem;
|
||
--text-caption-lh: 1.125rem;
|
||
|
||
/* ── Elevation ── Soft layered shadows in line with glass philosophy. */
|
||
--elevation-0: none;
|
||
--elevation-1: 0 1px 2px oklch(0 0 0 / 0.06);
|
||
--elevation-2: 0 2px 8px oklch(0 0 0 / 0.07), 0 1px 2px oklch(0 0 0 / 0.04);
|
||
--elevation-3: 0 4px 16px oklch(0 0 0 / 0.08), 0 2px 4px oklch(0 0 0 / 0.04);
|
||
--elevation-4: 0 12px 36px oklch(0.5 0.18 295 / 0.14), 0 4px 12px oklch(0 0 0 / 0.06);
|
||
--elevation-5: 0 20px 56px oklch(0.5 0.18 295 / 0.18), 0 8px 20px oklch(0 0 0 / 0.08);
|
||
|
||
--spacing: 0.25rem;
|
||
|
||
--border-width-thin: 0.5px;
|
||
--border-width-base: 1px;
|
||
--border-width-thick: 2px;
|
||
--border-width-heavy: 4px;
|
||
|
||
/* ── Glass vibrancy ── Heavy frost, like the skyrise reference. */
|
||
--glass-blur: 32px;
|
||
--glass-saturate: 220%;
|
||
--glass-brightness: 1.06;
|
||
--glass-contrast: 1.02;
|
||
|
||
/* ── Font stacks ── Loaded by the consuming app. */
|
||
--font-sans: "Inter", "Inter Variable", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||
--font-heading: "Instrument Sans", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||
--font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, "Cascadia Mono", Consolas, monospace;
|
||
}
|
||
|
||
/*
|
||
* Dark mode — clean deep-violet base. Foreground stays high-L for the
|
||
* vivid, never-faint feel. Corner accents live in the body bg block below.
|
||
*/
|
||
.dark {
|
||
--background: oklch(0.10 0.015 285);
|
||
--foreground: oklch(0.97 0.005 280);
|
||
|
||
--card: oklch(0.22 0.04 290 / 0.55);
|
||
--card-foreground: oklch(0.97 0.005 280);
|
||
|
||
--popover: oklch(0.22 0.04 290 / 0.78);
|
||
--popover-foreground: oklch(0.97 0.005 280);
|
||
|
||
--primary: oklch(0.7 0.2 295);
|
||
--primary-foreground: oklch(0.14 0.04 295);
|
||
|
||
--secondary: oklch(0.26 0.03 290);
|
||
--secondary-foreground: oklch(0.95 0.005 280);
|
||
|
||
--muted: oklch(0.26 0.03 290);
|
||
--muted-foreground: oklch(0.78 0.015 285);
|
||
|
||
--accent: oklch(0.32 0.06 295);
|
||
--accent-foreground: oklch(0.95 0.04 295);
|
||
|
||
--destructive: oklch(0.7 0.22 25);
|
||
--success: oklch(0.74 0.16 150);
|
||
--success-foreground: oklch(0.12 0.02 150);
|
||
--warning: oklch(0.78 0.16 75);
|
||
--warning-foreground: oklch(0.16 0.04 75);
|
||
|
||
--border: oklch(1 0 0 / 0.1);
|
||
--input: oklch(1 0 0 / 0.1);
|
||
--ring: oklch(0.7 0.2 295 / 0.55);
|
||
|
||
--chart-1: oklch(0.68 0.24 295);
|
||
--chart-2: oklch(0.72 0.2 230);
|
||
--chart-3: oklch(0.88 0.18 80);
|
||
--chart-4: oklch(0.82 0.2 350);
|
||
--chart-5: oklch(0.6 0.18 150);
|
||
|
||
--sidebar: oklch(0.2 0.04 290 / 0.55);
|
||
--sidebar-foreground: oklch(0.97 0.005 280);
|
||
--sidebar-primary: oklch(0.7 0.2 295);
|
||
--sidebar-primary-foreground: oklch(0.14 0.04 295);
|
||
--sidebar-accent: oklch(0.32 0.06 295);
|
||
--sidebar-accent-foreground: oklch(0.95 0.04 295);
|
||
--sidebar-border: oklch(1 0 0 / 0.08);
|
||
--sidebar-ring: oklch(0.7 0.2 295 / 0.55);
|
||
|
||
--syntax-keyword: oklch(0.78 0.18 295);
|
||
--syntax-string: oklch(0.8 0.16 150);
|
||
--syntax-number: oklch(0.82 0.16 35);
|
||
--syntax-comment: oklch(0.65 0.02 285);
|
||
--syntax-function: oklch(0.78 0.16 235);
|
||
--syntax-type: oklch(0.78 0.14 195);
|
||
|
||
--elevation-1: 0 1px 2px oklch(0 0 0 / 0.4);
|
||
--elevation-2: 0 2px 8px oklch(0 0 0 / 0.4), 0 1px 2px oklch(0 0 0 / 0.3);
|
||
--elevation-3: 0 4px 16px oklch(0 0 0 / 0.45), 0 2px 4px oklch(0 0 0 / 0.3);
|
||
--elevation-4: 0 12px 36px oklch(0.4 0.16 295 / 0.18), 0 4px 12px oklch(0 0 0 / 0.5);
|
||
--elevation-5: 0 20px 56px oklch(0.4 0.16 295 / 0.22), 0 8px 20px oklch(0 0 0 / 0.55);
|
||
|
||
--glass-brightness: 0.92;
|
||
--glass-saturate: 200%;
|
||
}
|
||
|
||
@layer base {
|
||
body {
|
||
background-attachment: fixed;
|
||
min-height: 100vh;
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
letter-spacing: -0.011em;
|
||
font-family: var(--font-sans);
|
||
font-size: var(--text-body-size);
|
||
line-height: var(--text-body-lh);
|
||
}
|
||
|
||
/* Themed text selection — keeps the violet identity. */
|
||
::selection {
|
||
background-color: oklch(0.55 0.22 295 / 0.28);
|
||
color: var(--foreground);
|
||
}
|
||
.dark ::selection {
|
||
background-color: oklch(0.7 0.2 295 / 0.4);
|
||
color: var(--foreground);
|
||
}
|
||
|
||
/* Themed scrollbars (Firefox + Chromium; macOS overlay ignores both). */
|
||
* {
|
||
scrollbar-width: thin;
|
||
scrollbar-color: oklch(0 0 0 / 0.18) transparent;
|
||
}
|
||
.dark * {
|
||
scrollbar-color: oklch(1 0 0 / 0.18) transparent;
|
||
}
|
||
::-webkit-scrollbar { width: 10px; height: 10px; }
|
||
::-webkit-scrollbar-track { background: transparent; }
|
||
::-webkit-scrollbar-thumb {
|
||
background-color: oklch(0 0 0 / 0.18);
|
||
border-radius: 999px;
|
||
border: 2px solid transparent;
|
||
background-clip: padding-box;
|
||
}
|
||
::-webkit-scrollbar-thumb:hover {
|
||
background-color: oklch(0 0 0 / 0.28);
|
||
background-clip: padding-box;
|
||
}
|
||
.dark ::-webkit-scrollbar-thumb {
|
||
background-color: oklch(1 0 0 / 0.18);
|
||
background-clip: padding-box;
|
||
}
|
||
.dark ::-webkit-scrollbar-thumb:hover {
|
||
background-color: oklch(1 0 0 / 0.28);
|
||
background-clip: padding-box;
|
||
}
|
||
|
||
/* Headings get the display family — Instrument Sans's tighter counters
|
||
* against Inter's open body feel. */
|
||
h1, h2, h3, h4, h5, h6,
|
||
[data-slot="card-title"],
|
||
[data-slot="dialog-title"],
|
||
[data-slot="alert-dialog-title"],
|
||
[data-slot="sheet-title"],
|
||
[data-slot="drawer-title"] {
|
||
font-family: var(--font-heading);
|
||
letter-spacing: -0.02em;
|
||
font-weight: 600;
|
||
}
|
||
|
||
/*
|
||
* ── Light-mode body ── iridescent drift, the brand surface.
|
||
*/
|
||
body,
|
||
body[data-bg="drift"],
|
||
.bg-variant-drift {
|
||
background-image:
|
||
radial-gradient(ellipse 80% 60% at 12% 8%, oklch(0.92 0.09 295 / 0.7), transparent 60%),
|
||
radial-gradient(ellipse 70% 60% at 88% 14%, oklch(0.93 0.1 350 / 0.7), transparent 55%),
|
||
radial-gradient(ellipse 80% 60% at 92% 88%, oklch(0.93 0.1 200 / 0.7), transparent 60%),
|
||
radial-gradient(ellipse 70% 60% at 8% 92%, oklch(0.94 0.09 145 / 0.65), transparent 55%),
|
||
linear-gradient(180deg, oklch(0.985 0.02 295), oklch(0.96 0.025 320));
|
||
}
|
||
|
||
/*
|
||
* ── Dark-mode body ── deep clean base + four soft corner glows.
|
||
*
|
||
* Design: blob L pushed to ~0.30 (vs skyrise's 0.18) so they sit well
|
||
* above the L=0.10 base — perceived as *light* rather than coloured
|
||
* fog. Chroma dropped to 0.06–0.09 (vs 0.12–0.14) to stay inside OKLCH
|
||
* dark-gamut sweet-spot and avoid the gray clip. Base gradient is
|
||
* near-monochrome (chroma 0.01–0.02) so the accents do all the colour
|
||
* work — same hue palette as light (purple→pink→cyan→mint), but
|
||
* articulated through light, not stain.
|
||
*/
|
||
html.dark body,
|
||
html.dark body[data-bg="drift"],
|
||
html.dark .bg-variant-drift {
|
||
background-image:
|
||
radial-gradient(ellipse 70% 55% at 10% 8%, oklch(0.32 0.09 295 / 0.65), transparent 60%),
|
||
radial-gradient(ellipse 60% 50% at 90% 14%, oklch(0.30 0.09 340 / 0.60), transparent 55%),
|
||
radial-gradient(ellipse 70% 55% at 92% 90%, oklch(0.28 0.07 200 / 0.55), transparent 60%),
|
||
radial-gradient(ellipse 60% 50% at 8% 92%, oklch(0.30 0.06 145 / 0.50), transparent 55%),
|
||
linear-gradient(180deg, oklch(0.10 0.012 285), oklch(0.08 0.018 295));
|
||
}
|
||
|
||
/*
|
||
* Animated drift layer — two large radial-blob fields that translate
|
||
* and rotate slowly, driving the chroma the glass refracts.
|
||
*/
|
||
[data-slot="aurora-field"] { display: none; }
|
||
body[data-bg="drift"] [data-slot="aurora-field"],
|
||
body:not([data-bg]) [data-slot="aurora-field"] { display: block; }
|
||
|
||
.aurora-blob {
|
||
position: absolute;
|
||
inset: -25%;
|
||
background-repeat: no-repeat;
|
||
will-change: transform;
|
||
}
|
||
|
||
.aurora-blob-1 {
|
||
background-image:
|
||
radial-gradient(ellipse 44% 36% at 22% 28%, oklch(0.9 0.13 295 / 0.85), transparent 60%),
|
||
radial-gradient(ellipse 38% 32% at 78% 22%, oklch(0.9 0.13 350 / 0.8), transparent 55%);
|
||
animation: prism-drift-a 32s ease-in-out infinite;
|
||
}
|
||
|
||
.aurora-blob-2 {
|
||
background-image:
|
||
radial-gradient(ellipse 48% 38% at 82% 74%, oklch(0.9 0.14 200 / 0.8), transparent 60%),
|
||
radial-gradient(ellipse 42% 34% at 16% 80%, oklch(0.92 0.12 145 / 0.75), transparent 55%);
|
||
animation: prism-drift-b 40s ease-in-out infinite;
|
||
}
|
||
|
||
/* Dark variant of the drifting aurora — same L/chroma discipline as
|
||
* the static dark base above. Same hues, tame chroma, well above base. */
|
||
html.dark .aurora-blob-1 {
|
||
background-image:
|
||
radial-gradient(ellipse 44% 36% at 22% 28%, oklch(0.32 0.09 295 / 0.55), transparent 60%),
|
||
radial-gradient(ellipse 38% 32% at 78% 22%, oklch(0.30 0.10 340 / 0.50), transparent 55%);
|
||
}
|
||
html.dark .aurora-blob-2 {
|
||
background-image:
|
||
radial-gradient(ellipse 48% 38% at 82% 74%, oklch(0.28 0.08 200 / 0.50), transparent 60%),
|
||
radial-gradient(ellipse 42% 34% at 16% 80%, oklch(0.30 0.07 145 / 0.45), transparent 55%);
|
||
}
|
||
|
||
@keyframes prism-drift-a {
|
||
0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); }
|
||
33% { transform: translate3d(5%, -3%, 0) rotate(10deg) scale(1.07); }
|
||
66% { transform: translate3d(-3%, 4%, 0) rotate(-8deg) scale(0.96); }
|
||
}
|
||
@keyframes prism-drift-b {
|
||
0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); }
|
||
33% { transform: translate3d(-5%, 4%, 0) rotate(-12deg) scale(1.09); }
|
||
66% { transform: translate3d(4%, -3%, 0) rotate(8deg) scale(0.94); }
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.aurora-blob { animation: none; }
|
||
}
|
||
|
||
/*
|
||
* ── Glass surfaces ── Apple-vibrancy stack on every shadcn surface
|
||
* that exposes a [data-slot]. blur softens, saturate pumps the
|
||
* gradient chroma the glass is sampling, brightness/contrast keep
|
||
* edges legible.
|
||
*/
|
||
[data-slot="card"],
|
||
[data-slot="popover-content"],
|
||
[data-slot="dropdown-menu-content"],
|
||
[data-slot="context-menu-content"],
|
||
[data-slot="menubar-content"],
|
||
[data-slot="hover-card-content"],
|
||
[data-slot="select-content"],
|
||
[data-slot="combobox-content"],
|
||
[data-slot="command"],
|
||
[data-slot="tooltip-content"],
|
||
[data-slot="sheet-content"],
|
||
[data-slot="dialog-content"],
|
||
[data-slot="alert-dialog-content"],
|
||
[data-slot="drawer-content"],
|
||
[data-slot="sidebar"] {
|
||
position: relative;
|
||
backdrop-filter:
|
||
blur(var(--glass-blur))
|
||
saturate(var(--glass-saturate))
|
||
brightness(var(--glass-brightness))
|
||
contrast(var(--glass-contrast));
|
||
-webkit-backdrop-filter:
|
||
blur(var(--glass-blur))
|
||
saturate(var(--glass-saturate))
|
||
brightness(var(--glass-brightness))
|
||
contrast(var(--glass-contrast));
|
||
transition-timing-function: var(--ease-spring-snappy);
|
||
animation-timing-function: var(--ease-spring-snappy);
|
||
animation-duration: var(--duration-spring);
|
||
}
|
||
|
||
/* Springy press feel on interactive bits. */
|
||
[data-slot="button"],
|
||
[data-slot="chip"],
|
||
[data-slot="toggle"],
|
||
[data-slot="item"] {
|
||
transition-timing-function: var(--ease-spring-bouncy);
|
||
transition-duration: var(--duration-fast);
|
||
}
|
||
|
||
/*
|
||
* Premium primary button — violet→fuchsia gradient + top-edge sheen.
|
||
*/
|
||
[data-slot="button"].bg-primary {
|
||
background-image: linear-gradient(
|
||
135deg,
|
||
oklch(0.56 0.24 290) 0%,
|
||
oklch(0.6 0.26 320) 50%,
|
||
oklch(0.58 0.24 350) 100%
|
||
);
|
||
position: relative;
|
||
isolation: isolate;
|
||
}
|
||
[data-slot="button"].bg-primary::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: inherit;
|
||
pointer-events: none;
|
||
background: linear-gradient(
|
||
180deg,
|
||
oklch(1 0 0 / 0.35) 0,
|
||
oklch(1 0 0 / 0.08) 45%,
|
||
oklch(1 0 0 / 0) 60%
|
||
);
|
||
mix-blend-mode: plus-lighter;
|
||
}
|
||
.dark [data-slot="button"].bg-primary {
|
||
background-image: linear-gradient(
|
||
135deg,
|
||
oklch(0.66 0.22 290) 0%,
|
||
oklch(0.7 0.24 320) 50%,
|
||
oklch(0.66 0.22 350) 100%
|
||
);
|
||
}
|
||
.dark [data-slot="button"].bg-primary::after {
|
||
background: linear-gradient(
|
||
180deg,
|
||
oklch(1 0 0 / 0.18) 0,
|
||
oklch(1 0 0 / 0.04) 45%,
|
||
oklch(1 0 0 / 0) 60%
|
||
);
|
||
}
|
||
|
||
/*
|
||
* Premium card padding — roomy 24px vs the lib's compact 16px.
|
||
*/
|
||
[data-slot="card"],
|
||
[data-slot="dialog-content"],
|
||
[data-slot="alert-dialog-content"],
|
||
[data-slot="sheet-content"],
|
||
[data-slot="drawer-content"],
|
||
[data-slot="popover-content"] {
|
||
--card-padding: calc(var(--spacing) * 6);
|
||
gap: calc(var(--spacing) * 5);
|
||
}
|
||
[data-slot="card-header"],
|
||
[data-slot="card-content"],
|
||
[data-slot="card-footer"] {
|
||
padding-inline: var(--card-padding, calc(var(--spacing) * 6));
|
||
}
|
||
|
||
/*
|
||
* AI orb avatar — any avatar fallback marked `data-ai` gets the
|
||
* rainbow gradient signature.
|
||
*/
|
||
[data-slot="avatar-fallback"][data-ai] {
|
||
background-image: conic-gradient(
|
||
from 210deg at 50% 50%,
|
||
oklch(0.6 0.24 295) 0deg,
|
||
oklch(0.7 0.22 350) 90deg,
|
||
oklch(0.78 0.18 35) 180deg,
|
||
oklch(0.7 0.18 200) 270deg,
|
||
oklch(0.6 0.24 295) 360deg
|
||
);
|
||
background-color: transparent;
|
||
color: oklch(1 0 0);
|
||
font-weight: 600;
|
||
position: relative;
|
||
}
|
||
[data-slot="avatar-fallback"][data-ai]::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: inherit;
|
||
pointer-events: none;
|
||
background: linear-gradient(
|
||
180deg,
|
||
oklch(1 0 0 / 0.3) 0,
|
||
oklch(1 0 0 / 0) 50%
|
||
);
|
||
mix-blend-mode: plus-lighter;
|
||
}
|
||
.dark [data-slot="avatar-fallback"][data-ai] {
|
||
background-image: conic-gradient(
|
||
from 210deg at 50% 50%,
|
||
oklch(0.7 0.22 295) 0deg,
|
||
oklch(0.78 0.2 350) 90deg,
|
||
oklch(0.84 0.16 35) 180deg,
|
||
oklch(0.78 0.16 200) 270deg,
|
||
oklch(0.7 0.22 295) 360deg
|
||
);
|
||
}
|
||
|
||
/*
|
||
* Inner top highlight — the wet-glass sheen Apple uses on surfaces.
|
||
*/
|
||
[data-slot="card"]::after,
|
||
[data-slot="popover-content"]::after,
|
||
[data-slot="dropdown-menu-content"]::after,
|
||
[data-slot="context-menu-content"]::after,
|
||
[data-slot="menubar-content"]::after,
|
||
[data-slot="hover-card-content"]::after,
|
||
[data-slot="select-content"]::after,
|
||
[data-slot="combobox-content"]::after,
|
||
[data-slot="command"]::after,
|
||
[data-slot="tooltip-content"]::after,
|
||
[data-slot="sheet-content"]::after,
|
||
[data-slot="dialog-content"]::after,
|
||
[data-slot="alert-dialog-content"]::after,
|
||
[data-slot="drawer-content"]::after,
|
||
[data-slot="sidebar"]::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: inherit;
|
||
pointer-events: none;
|
||
background:
|
||
linear-gradient(
|
||
180deg,
|
||
oklch(1 0 0 / 0.6) 0,
|
||
oklch(1 0 0 / 0) 1.5px,
|
||
oklch(1 0 0 / 0.14) 1.5px,
|
||
oklch(1 0 0 / 0) 35%
|
||
);
|
||
mix-blend-mode: plus-lighter;
|
||
}
|
||
.dark [data-slot="card"]::after,
|
||
.dark [data-slot="popover-content"]::after,
|
||
.dark [data-slot="dropdown-menu-content"]::after,
|
||
.dark [data-slot="context-menu-content"]::after,
|
||
.dark [data-slot="menubar-content"]::after,
|
||
.dark [data-slot="hover-card-content"]::after,
|
||
.dark [data-slot="select-content"]::after,
|
||
.dark [data-slot="combobox-content"]::after,
|
||
.dark [data-slot="command"]::after,
|
||
.dark [data-slot="tooltip-content"]::after,
|
||
.dark [data-slot="sheet-content"]::after,
|
||
.dark [data-slot="dialog-content"]::after,
|
||
.dark [data-slot="alert-dialog-content"]::after,
|
||
.dark [data-slot="drawer-content"]::after,
|
||
.dark [data-slot="sidebar"]::after {
|
||
background:
|
||
linear-gradient(
|
||
180deg,
|
||
oklch(1 0 0 / 0.2) 0,
|
||
oklch(1 0 0 / 0) 1.5px,
|
||
oklch(1 0 0 / 0.05) 1.5px,
|
||
oklch(1 0 0 / 0) 35%
|
||
);
|
||
}
|
||
|
||
/*
|
||
* ── `.num` utility ── Apply to any element that displays money or
|
||
* counts. Forces tabular monospaced digits, the unambiguous slashed-
|
||
* zero stylistic set Inter ships, and resets the body's negative
|
||
* tracking that would otherwise crash digits into each other.
|
||
*/
|
||
.num {
|
||
font-feature-settings: "tnum", "ss01", "cv01";
|
||
font-variant-numeric: tabular-nums;
|
||
letter-spacing: 0;
|
||
}
|
||
}
|
||
|
||
/* ── Root size & font-scale ──
|
||
* 18px root by default. Body lands ~19px once the --text-body-size
|
||
* 1.0625rem multiplier applies. The data-font-scale hook lets the
|
||
* consuming app expose a user-facing size toggle. */
|
||
@layer base {
|
||
html { font-size: 18px; }
|
||
html[data-font-scale="sm"] { font-size: 16px; }
|
||
html[data-font-scale="md"] { font-size: 18px; }
|
||
html[data-font-scale="lg"] { font-size: 20px; }
|
||
html[data-font-scale="xl"] { font-size: 22px; }
|
||
}
|