One of four divergent candidates for the bold consumer theme family (committed saturated color at 30-60% surface coverage, strong display type). Includes the post-diverge fixes: heading color:inherit so brand slabs keep their foreground pairing, plus per-theme refinements. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
432 lines
16 KiB
CSS
432 lines
16 KiB
CSS
/*
|
|
* Grape — violet night-lounge.
|
|
*
|
|
* A committed, identity-forward theme: the surface itself is the brand. The
|
|
* whole world is a deep luminous grape-violet FIELD (hue 300) — Skyrise's
|
|
* violet ancestry taken to a full drench, with no glass and no iridescence.
|
|
* There are no white cards anywhere: cards are clearly-lighter violet panels
|
|
* lifted off the field, popovers a step above cards, the sidebar a deeper
|
|
* violet stripe. Ink is near-white with a violet tint; hairlines are
|
|
* white-alpha. The one action glows: a hot coral-pink primary (hue 20) with
|
|
* dark ink on top, the single warm counterpoint in an otherwise violet room.
|
|
*
|
|
* Dark mode is later that night — the same lounge with the lights turned
|
|
* down: the field deepens, the panels follow, and the coral burns slightly
|
|
* brighter against it. The theme is violet in BOTH modes; .dark only changes
|
|
* the hour.
|
|
*
|
|
* Status colors are tuned to read on violet panels: destructive stays a deep
|
|
* crimson fill with a light label (a different lightness class from the
|
|
* bright coral primary, so the two hue-20 swatches never read as siblings);
|
|
* success is mint, warning amber, info cool cyan — all bright swatches with
|
|
* dark ink.
|
|
*
|
|
* Type is a lounge voice: Instrument Serif (single weight 400) for headings,
|
|
* Instrument Sans for body, Geist Mono for code. Consumer register — 1rem
|
|
* body with a generous 1.6 line-height. Radius is a soft 1.125rem; motion is
|
|
* languid-confident with a real gentle spring on the emphasized ease; shadows
|
|
* are deep violet-black pools.
|
|
*
|
|
* Token contract matches lib-theme-caffe-florian/theme.css (Crema v1).
|
|
*/
|
|
|
|
/*
|
|
* Fonts: consuming apps load Instrument Serif + Instrument Sans + Geist Mono
|
|
* at the top of their entry CSS (where @import statements are allowed), via
|
|
* the Google Fonts URL documented in this theme's README. Embedding the
|
|
* @import here — or smuggling the URL in a comment for a build script to
|
|
* lift — breaks PostCSS's ordering rules, so neither is done in this file.
|
|
*/
|
|
|
|
:root {
|
|
--font-sans: "Instrument Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
--font-heading: "Instrument Serif", Georgia, "Times New Roman", serif;
|
|
--font-mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
|
|
|
/* Tailwind utility families. Distinct names so a consuming app's
|
|
* `@theme inline` can indirect to these (--font-heading/--font-sans collide
|
|
* with Tailwind's own font-* namespace). Mirror --font-heading/--font-sans. */
|
|
--heading-family: "Instrument Serif", Georgia, "Times New Roman", serif;
|
|
--body-family: "Instrument Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
|
|
/* ── Colors ── the grape field. Background is a deep luminous violet;
|
|
* cards are clearly-lighter violet panels (+0.06 L — the step must be
|
|
* visible); ink is near-white with a violet tint. NOT white cards — the
|
|
* whole world is violet. */
|
|
--background: oklch(0.38 0.13 300);
|
|
--foreground: oklch(0.97 0.012 300);
|
|
|
|
--card: oklch(0.44 0.12 300);
|
|
--card-foreground: oklch(0.97 0.012 300);
|
|
|
|
--popover: oklch(0.46 0.115 300);
|
|
--popover-foreground: oklch(0.97 0.012 300);
|
|
|
|
/* Primary — the hot coral-pink counterpoint. One warm glow against the
|
|
* violet, carrying a deep wine-dark ink (bright-swatch/dark-ink pairing,
|
|
* ~6.3:1) so the action reads at label sizes. */
|
|
--primary: oklch(0.7 0.19 20);
|
|
--primary-foreground: oklch(0.2 0.06 20);
|
|
|
|
--secondary: oklch(0.5 0.11 300);
|
|
--secondary-foreground: oklch(0.97 0.012 300);
|
|
|
|
/* Muted — a recessed violet wash sitting between field and card, so muted
|
|
* chrome sinks rather than lifts. Muted ink is a pale lavender, verified
|
|
* ≥4.5:1 on field, card, AND the muted wash itself. */
|
|
--muted: oklch(0.42 0.115 300);
|
|
--muted-foreground: oklch(0.85 0.045 300);
|
|
|
|
/* Accent — a lighter violet wash with near-white ink: hover/selection
|
|
* lift inside the violet family, never a second warm fill. */
|
|
--accent: oklch(0.52 0.12 300);
|
|
--accent-foreground: oklch(0.98 0.01 300);
|
|
|
|
/* ── Status ── tuned to read on violet panels. All four are BRIGHT
|
|
* swatches with dark ink: on a mid-lightness violet world, status-colored
|
|
* text (badge chips render `text-destructive` on a 10% tint) can only
|
|
* clear 4.5:1 if the status color itself is light. Destructive is a
|
|
* luminous rose (hue 5) — separated from the coral primary (hue 20) by
|
|
* hue and by a visibly higher lightness. */
|
|
--destructive: oklch(0.84 0.11 5);
|
|
--destructive-foreground: oklch(0.2 0.04 5);
|
|
--success: oklch(0.75 0.13 160);
|
|
--success-foreground: oklch(0.2 0.05 160);
|
|
--warning: oklch(0.8 0.13 85);
|
|
--warning-foreground: oklch(0.22 0.05 85);
|
|
--info: oklch(0.75 0.1 220);
|
|
--info-foreground: oklch(0.2 0.04 220);
|
|
|
|
/* White-alpha hairlines — the violet world separates with light, not
|
|
* darkness. */
|
|
--border: oklch(1 0 0 / 0.16);
|
|
--input: oklch(1 0 0 / 0.2);
|
|
--ring: oklch(0.7 0.19 20 / 0.6);
|
|
|
|
/* Chart palette — coral lead, then mint / amber / cyan / pale orchid:
|
|
* spaced hues that all read on violet panels, adjacent-index lightness
|
|
* varied. */
|
|
--chart-1: oklch(0.72 0.18 20);
|
|
--chart-2: oklch(0.78 0.13 160);
|
|
--chart-3: oklch(0.85 0.12 85);
|
|
--chart-4: oklch(0.72 0.11 220);
|
|
--chart-5: oklch(0.86 0.08 320);
|
|
|
|
/* Sidebar — a deeper violet stripe against the field. */
|
|
--sidebar: oklch(0.33 0.12 300);
|
|
--sidebar-foreground: oklch(0.97 0.012 300);
|
|
--sidebar-primary: oklch(0.7 0.19 20);
|
|
--sidebar-primary-foreground: oklch(0.2 0.06 20);
|
|
--sidebar-accent: oklch(0.44 0.12 300);
|
|
--sidebar-accent-foreground: oklch(0.98 0.01 300);
|
|
--sidebar-border: oklch(1 0 0 / 0.12);
|
|
--sidebar-ring: oklch(0.7 0.19 20 / 0.6);
|
|
|
|
/* Syntax — bright, tuned to read on violet card panels. */
|
|
--syntax-keyword: oklch(0.82 0.12 350);
|
|
--syntax-string: oklch(0.85 0.1 160);
|
|
--syntax-number: oklch(0.87 0.1 85);
|
|
--syntax-comment: oklch(0.76 0.04 300);
|
|
--syntax-function: oklch(0.83 0.09 220);
|
|
--syntax-type: oklch(0.88 0.06 300);
|
|
|
|
/* ── Chat surfaces ──
|
|
* Contract for lib-agent-chat-ui / lib-agent-dock-ui. User bubble is the
|
|
* coral glow with dark ink (the user's turn IS the action); assistant
|
|
* bubble is a violet card panel with a white-alpha hairline. */
|
|
--chat-user-bg: oklch(0.7 0.19 20);
|
|
--chat-user-fg: oklch(0.2 0.06 20);
|
|
--chat-assistant-bg: oklch(0.44 0.12 300);
|
|
--chat-assistant-fg: oklch(0.97 0.012 300);
|
|
--chat-assistant-border: oklch(1 0 0 / 0.16);
|
|
|
|
/* Soft-lounge radius. */
|
|
--radius: 1.125rem;
|
|
|
|
/* ── Motion ── languid-confident. Slower than a product theme on
|
|
* purpose — the lounge doesn't rush — with a real gentle spring on the
|
|
* emphasized ease and the spring family. */
|
|
--duration-fast: 160ms;
|
|
--duration-base: 320ms;
|
|
--duration-slow: 480ms;
|
|
--duration-slower: 640ms;
|
|
--duration-spring: 480ms;
|
|
|
|
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
|
--ease-decelerate: cubic-bezier(0, 0, 0, 1);
|
|
--ease-accelerate: cubic-bezier(0.3, 0, 1, 1);
|
|
--ease-emphasized: cubic-bezier(0.34, 1.24, 0.54, 1);
|
|
|
|
--ease-spring-gentle: cubic-bezier(0.38, 1.18, 0.58, 1);
|
|
--ease-spring-snappy: cubic-bezier(0.3, 1.35, 0.5, 1);
|
|
--ease-spring-bouncy: cubic-bezier(0.3, 1.55, 0.42, 1);
|
|
|
|
/* ── Typography ── consumer register, fixed rem, full role ramp. */
|
|
--text-hero-size: 3.5rem;
|
|
--text-hero-lh: 1.05;
|
|
--text-display-size: 2.75rem;
|
|
--text-display-lh: 1.1;
|
|
--text-headline-size: 2rem;
|
|
--text-headline-lh: 1.2;
|
|
--text-title-size: 1.5rem;
|
|
--text-title-lh: 1.3;
|
|
--text-subtitle-size: 1.1875rem;
|
|
--text-subtitle-lh: 1.45;
|
|
--text-body-size: 1rem;
|
|
--text-body-lh: 1.6;
|
|
--text-label-size: 0.875rem;
|
|
--text-label-lh: 1.25rem;
|
|
--text-caption-size: 0.75rem;
|
|
--text-caption-lh: 1.0625rem;
|
|
|
|
/* ── Elevation ── deep violet-black pools; on a dark field the shadows
|
|
* carry more alpha than a daylight theme's. */
|
|
--elevation-0: none;
|
|
--elevation-1: 0 1px 2px oklch(0.12 0.06 300 / 0.3);
|
|
--elevation-2: 0 2px 4px oklch(0.12 0.06 300 / 0.34), 0 1px 2px oklch(0.12 0.06 300 / 0.24);
|
|
--elevation-3: 0 6px 12px -2px oklch(0.12 0.06 300 / 0.38), 0 2px 4px -2px oklch(0.12 0.06 300 / 0.26);
|
|
--elevation-4: 0 14px 28px -6px oklch(0.1 0.05 300 / 0.44), 0 4px 10px -4px oklch(0.1 0.05 300 / 0.28);
|
|
--elevation-5: 0 24px 48px -8px oklch(0.1 0.05 300 / 0.55);
|
|
|
|
--spacing: 0.25rem;
|
|
|
|
--border-width-thin: 0.5px;
|
|
--border-width-base: 1px;
|
|
--border-width-thick: 2px;
|
|
--border-width-heavy: 4px;
|
|
|
|
/* No glass — inert values so consuming apps referencing these get no-ops. */
|
|
--glass-blur: 0px;
|
|
--glass-saturate: 100%;
|
|
--glass-brightness: 1;
|
|
--glass-contrast: 1;
|
|
}
|
|
|
|
/*
|
|
* Dark mode — later that night. The field deepens toward violet-black, the
|
|
* panels keep the same visible step above it, and the coral counterpoint
|
|
* burns slightly brighter. The ladder keeps muted ABOVE popover
|
|
* (bg 0.26 → card 0.32 → popover 0.34 → muted 0.36) so muted chrome still
|
|
* reads as a lift on the darker field.
|
|
*/
|
|
.dark {
|
|
--background: oklch(0.26 0.1 300);
|
|
--foreground: oklch(0.97 0.012 300);
|
|
|
|
--card: oklch(0.32 0.1 300);
|
|
--card-foreground: oklch(0.97 0.012 300);
|
|
|
|
--popover: oklch(0.34 0.1 300);
|
|
--popover-foreground: oklch(0.97 0.012 300);
|
|
|
|
--primary: oklch(0.73 0.19 20);
|
|
--primary-foreground: oklch(0.2 0.06 20);
|
|
|
|
--secondary: oklch(0.36 0.1 300);
|
|
--secondary-foreground: oklch(0.97 0.012 300);
|
|
|
|
--muted: oklch(0.36 0.1 300);
|
|
--muted-foreground: oklch(0.83 0.05 300);
|
|
|
|
--accent: oklch(0.4 0.11 300);
|
|
--accent-foreground: oklch(0.98 0.01 300);
|
|
|
|
--destructive: oklch(0.84 0.11 5);
|
|
--destructive-foreground: oklch(0.2 0.04 5);
|
|
--success: oklch(0.77 0.13 160);
|
|
--success-foreground: oklch(0.2 0.05 160);
|
|
--warning: oklch(0.82 0.13 85);
|
|
--warning-foreground: oklch(0.22 0.05 85);
|
|
--info: oklch(0.77 0.1 220);
|
|
--info-foreground: oklch(0.2 0.04 220);
|
|
|
|
--border: oklch(1 0 0 / 0.14);
|
|
--input: oklch(1 0 0 / 0.18);
|
|
--ring: oklch(0.73 0.19 20 / 0.6);
|
|
|
|
--chart-1: oklch(0.74 0.18 20);
|
|
--chart-2: oklch(0.8 0.13 160);
|
|
--chart-3: oklch(0.87 0.12 85);
|
|
--chart-4: oklch(0.74 0.11 220);
|
|
--chart-5: oklch(0.88 0.08 320);
|
|
|
|
--sidebar: oklch(0.22 0.09 300);
|
|
--sidebar-foreground: oklch(0.97 0.012 300);
|
|
--sidebar-primary: oklch(0.73 0.19 20);
|
|
--sidebar-primary-foreground: oklch(0.2 0.06 20);
|
|
--sidebar-accent: oklch(0.32 0.1 300);
|
|
--sidebar-accent-foreground: oklch(0.98 0.01 300);
|
|
--sidebar-border: oklch(1 0 0 / 0.1);
|
|
--sidebar-ring: oklch(0.73 0.19 20 / 0.6);
|
|
|
|
--syntax-keyword: oklch(0.84 0.12 350);
|
|
--syntax-string: oklch(0.87 0.1 160);
|
|
--syntax-number: oklch(0.89 0.1 85);
|
|
--syntax-comment: oklch(0.74 0.04 300);
|
|
--syntax-function: oklch(0.85 0.09 220);
|
|
--syntax-type: oklch(0.9 0.06 300);
|
|
|
|
/* ── Chat surfaces (dark) ── */
|
|
--chat-user-bg: oklch(0.73 0.19 20);
|
|
--chat-user-fg: oklch(0.2 0.06 20);
|
|
--chat-assistant-bg: oklch(0.32 0.1 300);
|
|
--chat-assistant-fg: oklch(0.97 0.012 300);
|
|
--chat-assistant-border: oklch(1 0 0 / 0.14);
|
|
|
|
--elevation-1: 0 1px 2px oklch(0 0 0 / 0.35);
|
|
--elevation-2: 0 2px 4px oklch(0 0 0 / 0.4), 0 1px 2px oklch(0 0 0 / 0.28);
|
|
--elevation-3: 0 6px 12px -2px oklch(0 0 0 / 0.45), 0 2px 4px -2px oklch(0 0 0 / 0.3);
|
|
--elevation-4: 0 14px 28px -6px oklch(0 0 0 / 0.5), 0 4px 10px -4px oklch(0 0 0 / 0.3);
|
|
--elevation-5: 0 24px 48px -8px oklch(0 0 0 / 0.6);
|
|
}
|
|
|
|
/*
|
|
* @layer base — Grape's night-lounge philosophy.
|
|
*
|
|
* One drenched violet field, panels lifted with light (white-alpha hairlines
|
|
* and lighter violet), a serif voice for headings, and the coral glow spent
|
|
* only on the action, the selection, and the focus ring. Nothing rushes.
|
|
*/
|
|
@layer base {
|
|
body {
|
|
min-height: 100vh;
|
|
-webkit-font-smoothing: antialiased;
|
|
-moz-osx-font-smoothing: grayscale;
|
|
letter-spacing: -0.004em;
|
|
font-family: var(--font-sans);
|
|
font-size: var(--text-body-size);
|
|
line-height: var(--text-body-lh);
|
|
}
|
|
|
|
/* Headings — Instrument Serif, a single weight (400): the serif itself
|
|
* is the emphasis, so no faux-bold. */
|
|
h1, h2, h3, h4,
|
|
[data-slot="card-title"],
|
|
[data-slot="dialog-title"],
|
|
[data-slot="sheet-title"],
|
|
[data-slot="alert-dialog-title"] {
|
|
font-family: var(--font-heading);
|
|
font-weight: 400;
|
|
letter-spacing: -0.01em;
|
|
/* inherit, not var(--foreground): identity themes put headings on
|
|
* colored slabs (bg-primary heroes) — forcing the field ink there
|
|
* breaks the slab's own foreground pairing. */
|
|
color: inherit;
|
|
}
|
|
|
|
code, kbd, samp, pre,
|
|
[data-slot="code"],
|
|
[data-slot="code-block"] {
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
/* Inline code — a white-alpha tint chip with foreground ink, neutral
|
|
* inside the violet world. */
|
|
:not(pre) > code {
|
|
padding: 0.1em 0.35em;
|
|
border-radius: calc(var(--radius) * 0.5);
|
|
background: oklch(1 0 0 / 0.12);
|
|
color: var(--foreground);
|
|
font-size: 0.9em;
|
|
}
|
|
|
|
/* Selection — the coral glow. */
|
|
::selection {
|
|
background: color-mix(in oklch, var(--primary) 40%, transparent);
|
|
color: var(--foreground);
|
|
}
|
|
|
|
/* Links — coral-warmed, underline-on-hover. */
|
|
a {
|
|
color: color-mix(in oklch, var(--primary) 75%, var(--foreground));
|
|
text-decoration-color: color-mix(in oklch, var(--primary) 45%, transparent);
|
|
text-underline-offset: 0.2em;
|
|
transition: text-decoration-color var(--duration-fast) var(--ease-standard);
|
|
}
|
|
a:hover {
|
|
text-decoration-color: var(--primary);
|
|
}
|
|
|
|
[data-slot="sidebar"] {
|
|
background: var(--sidebar);
|
|
border-right: var(--border-width-base) solid var(--sidebar-border);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Focus-visible — the coral ring, offset (not inset), for keyboard users.
|
|
* Placed outside @layer base so it beats Tailwind's default ring utilities.
|
|
*/
|
|
[data-slot="button"]:focus-visible,
|
|
[data-slot="input"]:focus-visible,
|
|
[data-slot="textarea"]:focus-visible,
|
|
[data-slot="select-trigger"]:focus-visible {
|
|
outline: 2px solid var(--primary);
|
|
outline-offset: 2px;
|
|
box-shadow: none;
|
|
}
|
|
|
|
/* Buttons — confident weight; opacity absorb on press with a languid ease. */
|
|
[data-slot="button"] {
|
|
font-weight: 500;
|
|
letter-spacing: -0.004em;
|
|
}
|
|
|
|
/* Card titles — pinned to the subtitle role so the scale is the theme's
|
|
* decision, not the card primitive's default. */
|
|
[data-slot="card-title"] {
|
|
font-size: var(--text-subtitle-size);
|
|
line-height: var(--text-subtitle-lh);
|
|
}
|
|
|
|
/* Touch targets — desktop keeps the lounge density ladder; coarse pointers
|
|
* get the 44px floor on every control. */
|
|
@media (pointer: coarse) {
|
|
[data-slot="button"] {
|
|
min-height: 2.75rem;
|
|
min-width: 2.75rem;
|
|
}
|
|
[data-slot="input"],
|
|
[data-slot="select-trigger"] {
|
|
min-height: 2.75rem;
|
|
}
|
|
}
|
|
[data-slot="button"]:hover:not(:disabled) {
|
|
opacity: 0.92;
|
|
}
|
|
[data-slot="button"]:active:not(:disabled) {
|
|
opacity: 0.84;
|
|
transform: scale(0.99);
|
|
}
|
|
|
|
/* Inputs — card-violet panels, white-alpha hairline, coral focus as a flush
|
|
* ring. */
|
|
[data-slot="input"],
|
|
[data-slot="textarea"],
|
|
[data-slot="select-trigger"] {
|
|
background: var(--card);
|
|
border: var(--border-width-base) solid var(--border);
|
|
border-radius: var(--radius);
|
|
color: var(--foreground);
|
|
transition:
|
|
border-color var(--duration-fast) var(--ease-standard),
|
|
box-shadow var(--duration-fast) var(--ease-standard);
|
|
}
|
|
[data-slot="input"]::placeholder,
|
|
[data-slot="textarea"]::placeholder {
|
|
color: var(--muted-foreground);
|
|
opacity: 0.8;
|
|
}
|
|
[data-slot="input"]:hover:not(:disabled),
|
|
[data-slot="textarea"]:hover:not(:disabled),
|
|
[data-slot="select-trigger"]:hover:not(:disabled) {
|
|
border-color: oklch(1 0 0 / 0.32);
|
|
}
|
|
[data-slot="input"]:focus,
|
|
[data-slot="textarea"]:focus,
|
|
[data-slot="select-trigger"]:focus {
|
|
border-color: var(--primary);
|
|
box-shadow: 0 0 0 1px var(--primary);
|
|
outline: none;
|
|
}
|