/* * Porcelain — calm, neutral bone-china surfaces warmed by a single restrained * clay accent. Built as the "iCloud / Apple-Settings calm, but warm" answer for * a back-of-house personal-cloud utility: quiet chrome, confident whitespace, * hairline separation, one warm note that points at the next action. * * Palette rationale. The field is a true off-white porcelain, not a cream band: * chroma is held to a whisper (≤0.004) and the hue leans faintly COOL (~265, * bone china) so the background reads clean-neutral at very high L (0.985) — * deliberately above and to the cool side of the banned AI cream/sand region * (L 0.84–0.97, warm hue 40–100). Cards step up to pure white; separation is a * hairline border plus the faintest neutral elevation. Ink is a warm-leaning * near-black charcoal (hue ~55) — the one place quiet warmth lives in the text. * The lone accent is a muted clay / soft terracotta (hue ~47), a restrained * echo of siena used on ≤10% of the surface: primary action, selection, focus, * links — never as a wash. Status quartet is held clearly apart in hue (clay 47 * / red 27 / green 150 / amber 78 / blue 245) so meaning never muddies against * the warm accent. * * Token contract matches lib-theme-caffe-florian/theme.css (Crema v1). */ /* * Fonts: consuming apps should load Albert Sans + Newsreader + JetBrains 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 * inside this file — or smuggling the URL in a comment for a build script to * lift — breaks PostCSS's ordering rules and is banned by the contract, so * neither is done here. */ :root { --font-sans: "Albert Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-heading: "Newsreader", Georgia, "Times New Roman", serif; --font-mono: "JetBrains Mono", ui-monospace, 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: "Newsreader", Georgia, "Times New Roman", serif; --body-family: "Albert Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; /* ── Colors ── cool bone-china porcelain field, warm charcoal ink, one * muted clay accent. Kept out of the cream band by very low chroma and a * faint cool (bone) hue at high L. */ --background: oklch(0.985 0.004 265); --foreground: oklch(0.21 0.008 55); --card: oklch(1 0 0); --card-foreground: oklch(0.21 0.008 55); --popover: oklch(0.995 0.003 265); --popover-foreground: oklch(0.21 0.008 55); /* Primary — muted clay. Deepened so white label clears the 4.5:1 floor * (5.13:1) while still reading calm and premium, not loud. */ --primary: oklch(0.54 0.11 47); --primary-foreground: oklch(0.99 0.004 60); --secondary: oklch(0.955 0.004 265); --secondary-foreground: oklch(0.30 0.008 55); --muted: oklch(0.955 0.004 265); --muted-foreground: oklch(0.50 0.008 55); /* Accent — faint clay tint surface with deep clay ink. The single warm * note; used for hovers/selection, never a body wash. */ --accent: oklch(0.94 0.02 47); --accent-foreground: oklch(0.42 0.10 47); --destructive: oklch(0.55 0.20 27); --destructive-foreground: oklch(0.99 0.004 60); /* Success — held at hue 150 (well clear of clay 47), dark ink on top. */ --success: oklch(0.57 0.13 150); --success-foreground: oklch(0.16 0.03 150); /* Warning — amber ochre, dark ink on top. */ --warning: oklch(0.75 0.14 78); --warning-foreground: oklch(0.22 0.04 78); /* Info — calm blue, light label on top. */ --info: oklch(0.53 0.145 245); --info-foreground: oklch(0.99 0.004 60); --border: oklch(0.21 0.008 55 / 0.10); --input: oklch(0.21 0.008 55 / 0.10); --ring: oklch(0.54 0.11 47 / 0.5); /* Chart palette — clay lead, then hues spaced ≥60° apart (clay / teal / * blue / violet / green), adjacent lightness varied. Calm, low-shout. */ --chart-1: oklch(0.62 0.11 47); --chart-2: oklch(0.60 0.08 195); --chart-3: oklch(0.55 0.10 255); --chart-4: oklch(0.66 0.09 315); --chart-5: oklch(0.64 0.10 150); --sidebar: oklch(0.97 0.004 265); --sidebar-foreground: oklch(0.21 0.008 55); --sidebar-primary: oklch(0.54 0.11 47); --sidebar-primary-foreground: oklch(0.99 0.004 60); --sidebar-accent: oklch(0.94 0.02 47); --sidebar-accent-foreground: oklch(0.42 0.10 47); --sidebar-border: oklch(0.21 0.008 55 / 0.08); --sidebar-ring: oklch(0.54 0.11 47 / 0.5); --syntax-keyword: oklch(0.50 0.11 47); --syntax-string: oklch(0.50 0.11 150); --syntax-number: oklch(0.54 0.11 78); --syntax-comment: oklch(0.58 0.008 60); --syntax-function: oklch(0.50 0.13 255); --syntax-type: oklch(0.52 0.08 210); /* ── Chat surfaces ── * Contract for lib-agent-chat-ui / lib-agent-dock-ui. User bubble is a * filled deep clay with a light label; assistant bubble is a clean white * card with a hairline border. */ --chat-user-bg: oklch(0.50 0.11 47); --chat-user-fg: oklch(0.99 0.004 60); --chat-assistant-bg: oklch(1 0 0); --chat-assistant-fg: oklch(0.21 0.008 55); --chat-assistant-border: oklch(0.21 0.008 55 / 0.10); /* Calm-modern radius. */ --radius: 0.875rem; /* ── Motion ── calm, product-fast. */ --duration-fast: 150ms; --duration-base: 300ms; --duration-slow: 420ms; --duration-slower: 560ms; --duration-spring: 300ms; --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-emphasized: cubic-bezier(0.2, 0, 0, 1); /* Calm theme — springs alias to standard easings (no overshoot). Personality * lives in the values, never in absence (the avalon rule). */ --ease-spring-gentle: cubic-bezier(0.4, 0, 0.2, 1); --ease-spring-snappy: cubic-bezier(0.4, 0, 0.2, 1); --ease-spring-bouncy: cubic-bezier(0.4, 0, 0.2, 1); /* ── Typography ── product register, fixed rem sizes, full role ramp. * Newsreader supplies a restrained modern-serif heading; Albert Sans is the * humanist body/UI sans. */ --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-subtitle-size: 1.1875rem; --text-subtitle-lh: 1.625rem; --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 ── whisper-soft neutral shadows, near-black at very low * alpha. Calm resting cards, low-key lift. */ --elevation-0: none; --elevation-1: 0 1px 2px oklch(0.21 0.008 55 / 0.04); --elevation-2: 0 1px 3px oklch(0.21 0.008 55 / 0.06), 0 1px 2px oklch(0.21 0.008 55 / 0.03); --elevation-3: 0 4px 10px -3px oklch(0.21 0.008 55 / 0.07), 0 2px 4px -2px oklch(0.21 0.008 55 / 0.04); --elevation-4: 0 12px 28px -6px oklch(0.21 0.008 55 / 0.09), 0 4px 8px -4px oklch(0.21 0.008 55 / 0.04); --elevation-5: 0 24px 48px -12px oklch(0.21 0.008 55 / 0.14); --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 — warm graphite (#232120-ish), not blue-black and not umber-brown. * Very low chroma at a warm hue (~60) keeps it a neutral warm charcoal; the clay * accent brightens just enough and carries dark ink per the contract. */ .dark { --background: oklch(0.20 0.006 60); --foreground: oklch(0.94 0.006 70); --card: oklch(0.26 0.007 60); --card-foreground: oklch(0.94 0.006 70); --popover: oklch(0.275 0.007 60); --popover-foreground: oklch(0.94 0.006 70); --primary: oklch(0.66 0.12 50); --primary-foreground: oklch(0.18 0.02 50); --secondary: oklch(0.28 0.007 60); --secondary-foreground: oklch(0.90 0.006 70); --muted: oklch(0.28 0.007 60); --muted-foreground: oklch(0.70 0.008 65); --accent: oklch(0.32 0.04 50); --accent-foreground: oklch(0.85 0.08 50); --destructive: oklch(0.62 0.19 27); --destructive-foreground: oklch(0.16 0.02 27); --success: oklch(0.70 0.15 150); --success-foreground: oklch(0.16 0.03 150); --warning: oklch(0.80 0.14 78); --warning-foreground: oklch(0.20 0.04 78); --info: oklch(0.72 0.13 245); --info-foreground: oklch(0.18 0.03 245); --border: oklch(0.95 0.006 70 / 0.10); --input: oklch(0.95 0.006 70 / 0.10); --ring: oklch(0.66 0.12 50 / 0.5); --chart-1: oklch(0.70 0.12 50); --chart-2: oklch(0.70 0.08 195); --chart-3: oklch(0.68 0.10 255); --chart-4: oklch(0.74 0.09 315); --chart-5: oklch(0.72 0.11 150); --sidebar: oklch(0.22 0.006 60); --sidebar-foreground: oklch(0.94 0.006 70); --sidebar-primary: oklch(0.66 0.12 50); --sidebar-primary-foreground: oklch(0.18 0.02 50); --sidebar-accent: oklch(0.32 0.04 50); --sidebar-accent-foreground: oklch(0.85 0.08 50); --sidebar-border: oklch(0.95 0.006 70 / 0.08); --sidebar-ring: oklch(0.66 0.12 50 / 0.5); --syntax-keyword: oklch(0.74 0.12 50); --syntax-string: oklch(0.74 0.13 150); --syntax-number: oklch(0.78 0.13 78); --syntax-comment: oklch(0.58 0.008 60); --syntax-function: oklch(0.72 0.13 255); --syntax-type: oklch(0.72 0.08 210); /* ── Chat surfaces (dark) ── deep clay bubble, dark ink label * (dark-ink-on-bright, 5.56:1). */ --chat-user-bg: oklch(0.64 0.115 50); --chat-user-fg: oklch(0.16 0.02 50); --chat-assistant-bg: oklch(0.26 0.007 60); --chat-assistant-fg: oklch(0.94 0.006 70); --chat-assistant-border: oklch(0.95 0.006 70 / 0.10); --elevation-1: 0 1px 2px oklch(0 0 0 / 0.3); --elevation-2: 0 1px 3px oklch(0 0 0 / 0.4), 0 1px 2px oklch(0 0 0 / 0.25); --elevation-3: 0 4px 10px oklch(0 0 0 / 0.35), 0 2px 4px oklch(0 0 0 / 0.25); --elevation-4: 0 12px 28px oklch(0 0 0 / 0.4), 0 4px 8px oklch(0 0 0 / 0.25); --elevation-5: 0 24px 48px oklch(0 0 0 / 0.5); } /* * @layer base — Porcelain's calm-utility philosophy. * * No glass, no offsets. Humanist sans body; restrained modern-serif headings * used sparingly. Cards sit on the porcelain field with a hairline border and a * whisper-soft neutral shadow — calm resting surfaces, not floating chrome. The * clay accent points; everything else is neutral. */ @layer base { body { min-height: 100vh; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; letter-spacing: -0.006em; font-family: var(--font-sans); font-size: var(--text-body-size); line-height: var(--text-body-lh); } /* Serif headings — Newsreader, kept calm (not editorial-loud): moderate * weight, tight-but-gentle tracking. */ 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: 560; letter-spacing: -0.012em; color: var(--foreground); } code, kbd, samp, pre, [data-slot="code"], [data-slot="code-block"] { font-family: var(--font-mono); } /* Inline code — neutral ink on a faint chip; the clay accent stays * reserved for actions, links and focus. */ :not(pre) > code { padding: 0.1em 0.35em; border-radius: calc(var(--radius) * 0.4); background: color-mix(in oklch, var(--foreground) 7%, transparent); color: var(--foreground); font-size: 0.9em; } /* Selection — the one warm note, faint clay wash. */ ::selection { background: color-mix(in oklch, var(--primary) 18%, transparent); color: var(--foreground); } /* Links — clay, quietly underlined on hover. */ a { color: var(--primary); text-decoration-color: color-mix(in oklch, var(--primary) 35%, transparent); text-underline-offset: 0.2em; transition: text-decoration-color var(--duration-fast) var(--ease-standard); } a:hover { text-decoration-color: var(--primary); } /* Card & overlay surfaces — hairline border + whisper elevation so cards * read as calm resting tiles on porcelain. */ [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"] { border: var(--border-width-base) solid var(--border); box-shadow: var(--elevation-2); } .dark [data-slot="card"], .dark [data-slot="popover-content"], .dark [data-slot="dropdown-menu-content"], .dark [data-slot="context-menu-content"], .dark [data-slot="menubar-content"], .dark [data-slot="hover-card-content"], .dark [data-slot="select-content"], .dark [data-slot="combobox-content"], .dark [data-slot="command"], .dark [data-slot="tooltip-content"], .dark [data-slot="sheet-content"], .dark [data-slot="dialog-content"], .dark [data-slot="alert-dialog-content"], .dark [data-slot="drawer-content"] { box-shadow: var(--elevation-3); } [data-slot="button"] { font-weight: 500; } [data-slot="sidebar"] { background: var(--sidebar); border-right: var(--border-width-base) solid var(--sidebar-border); } } /* * Unlayered component polish — placed outside @layer base so it beats Tailwind's * default utility classes shipped with shadcn. Porcelain keeps controls calm and * comfortably sized with clay focus: inputs are ≥44px everywhere; buttons keep * their density under a mouse and clear the 44px floor on coarse pointers. */ [data-slot="button"]:hover:not(:disabled) { opacity: 0.9; } [data-slot="button"]:active:not(:disabled) { opacity: 0.8; transform: scale(0.99); } [data-slot="button"]:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; box-shadow: none; } [data-slot="input"], [data-slot="textarea"], [data-slot="select-trigger"] { min-height: 2.75rem; padding-inline: 0.875rem; font-size: 0.9375rem; background: var(--card); border: 1px 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="textarea"] { min-height: 6.25rem; padding-block: 0.75rem; line-height: 1.55; resize: vertical; } [data-slot="input"]::placeholder, [data-slot="textarea"]::placeholder { color: var(--muted-foreground); opacity: 0.7; } [data-slot="input"]:hover:not(:disabled), [data-slot="textarea"]:hover:not(:disabled), [data-slot="select-trigger"]:hover:not(:disabled) { border-color: color-mix(in oklch, var(--foreground) 22%, transparent); } [data-slot="input"]:focus, [data-slot="input"]:focus-visible, [data-slot="textarea"]:focus, [data-slot="textarea"]:focus-visible, [data-slot="select-trigger"]:focus, [data-slot="select-trigger"]:focus-visible { border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary); outline: none; } [data-slot="card"] { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); transition: border-color var(--duration-base) var(--ease-standard), box-shadow var(--duration-base) var(--ease-standard); } /* 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 — buttons clear the 44px floor on coarse pointers * (inputs are already ≥44px everywhere above). */ @media (pointer: coarse) { [data-slot="button"] { min-height: 2.75rem; min-width: 2.75rem; } }