lib-theme-grape: initial import (bold/identity-forward set, 2026-07)
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>
This commit is contained in:
62
README.md
Normal file
62
README.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# lib-theme-grape
|
||||
|
||||
**Grape — violet night-lounge.** A bold, identity-forward Crema theme where the
|
||||
committed color IS the surface: the entire world is a deep luminous
|
||||
grape-violet field (hue 300) — Skyrise's violet ancestry taken to a full
|
||||
drench, without glass or iridescence. There are no white cards; cards are
|
||||
clearly-lighter violet panels lifted off the field, popovers a step above
|
||||
cards, the sidebar a deeper violet stripe, and everything separates with
|
||||
white-alpha hairlines — light, not darkness. Ink is near-white with a violet
|
||||
tint.
|
||||
|
||||
One counterpoint does all the pointing: a hot coral-pink primary
|
||||
(`oklch(0.7 0.19 20)`) carrying dark wine ink, spent on the action, the
|
||||
selection, the focus ring, and the user's chat bubble. Destructive stays a
|
||||
*deep crimson fill with a light label* — a different lightness class and
|
||||
construction from the bright coral primary, so the two hue-20 neighbours never
|
||||
read as the same swatch. Success is mint, warning amber, info cool cyan — all
|
||||
bright swatches with dark ink, tuned to read on violet panels.
|
||||
|
||||
The theme is violet in **both** modes. `.dark` is simply *later that night*:
|
||||
the field deepens (`0.38 → 0.26 L`), the panels keep the same visible step
|
||||
above it, and the coral burns slightly brighter. The dark violet ladder keeps
|
||||
muted above popover: bg `0.26` → card `0.32` → popover `0.34` → muted `0.36`.
|
||||
|
||||
Radius is a soft-lounge `1.125rem`. Motion is languid-confident
|
||||
(160/320/480/640ms) with a real gentle spring on the emphasized ease. Shadows
|
||||
are deep violet-black pools. Consumer type register: 1rem body at 1.6
|
||||
line-height.
|
||||
|
||||
All contract contrast floors verified in both modes on both surfaces (field
|
||||
and card) — including the risky one in an all-violet world,
|
||||
`muted-foreground`, which lands ≥5:1 on field, card, and the muted wash in
|
||||
both modes. `✓ PASS` from `validate-theme.mjs`.
|
||||
|
||||
## Fonts
|
||||
|
||||
Load in the **consuming app's** entry CSS (very top, before anything else —
|
||||
themes never `@import` fonts themselves):
|
||||
|
||||
```css
|
||||
@import url("https://fonts.googleapis.com/css2?family=Instrument+Serif&family=Instrument+Sans:wght@400;500;600;700&family=Geist+Mono:wght@400;500;600&display=swap");
|
||||
```
|
||||
|
||||
| Role | Family | Notes |
|
||||
|---|---|---|
|
||||
| Headings | **Instrument Serif** | Single weight (400) — the serif itself is the emphasis; the theme pins headings to `font-weight: 400; letter-spacing: -0.01em` and never fakes bold. |
|
||||
| Body / UI | **Instrument Sans** | 400 / 500 / 600 / 700. Warm modern grotesque; buttons sit at 500. |
|
||||
| Code | **Geist Mono** | 400 / 500 / 600. Inline code renders as a white-alpha tint chip with foreground ink. |
|
||||
|
||||
## Usage
|
||||
|
||||
```css
|
||||
/* app entry CSS */
|
||||
@import url("https://fonts.googleapis.com/css2?family=Instrument+Serif&family=Instrument+Sans:wght@400;500;600;700&family=Geist+Mono:wght@400;500;600&display=swap");
|
||||
@import "../../lib-theme-grape/theme.css";
|
||||
```
|
||||
|
||||
Validate:
|
||||
|
||||
```bash
|
||||
node create-crema-app/scripts/validate-theme.mjs lib-theme-grape/theme.css
|
||||
```
|
||||
431
theme.css
Normal file
431
theme.css
Normal file
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user