/* * Modena — Editorial design system theme. * * Content-presentation tokens + base typography. Designed for blogs, * articles, documentation, and long-form essays. Editorial minimalism: * the UI disappears so the content takes center stage. * * Ports the relevant subset of the Modena reference into a Crema-style * theme.css that: * • Defines the standard Crema design tokens (--background, --primary, * --foreground, etc.) so all shadcn/lib-* components keep working. * • Adds Modena-specific tokens (--mod-prose-*, --mod-text-*, etc.) * consumed by lib-modena-ui components and the article surface. * • Applies base typography to h1-h4, [data-slot="article"], and * [data-slot="prose"] so any consumer of @crema/content-ui * automatically picks up the editorial look. * * Pairs with: @crema/content-ui (article primitives), lib-modena-ui * (Modena-specific extra components). */ /* Newsreader for the editorial serif. Pulled at theme-import time so * consumers don't have to remember to import the font separately. */ @import url("https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;0,6..72,700;1,6..72,400&family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap"); :root { /* ── Crema-shaped tokens (apps and shadcn components consume these) ── */ --background: oklch(1 0 0); --foreground: oklch(0.16 0.02 255); --card: oklch(1 0 0); --card-foreground: oklch(0.16 0.02 255); --popover: oklch(1 0 0); --popover-foreground: oklch(0.16 0.02 255); --primary: oklch(0.55 0.22 260); --primary-foreground: oklch(0.99 0.005 80); --secondary: oklch(0.96 0.005 250); --secondary-foreground: oklch(0.20 0.025 255); --muted: oklch(0.97 0.003 250); --muted-foreground: oklch(0.50 0.015 250); --accent: oklch(0.95 0.01 260); --accent-foreground: oklch(0.18 0.02 255); --destructive: oklch(0.55 0.22 25); --destructive-foreground: oklch(0.99 0.005 80); --success: oklch(0.65 0.18 145); --success-foreground: oklch(0.99 0.005 80); --warning: oklch(0.72 0.16 70); --warning-foreground: oklch(0.15 0.02 70); --border: oklch(0.92 0.005 250); --input: oklch(0.92 0.005 250); --ring: oklch(0.55 0.22 260); /* ── Chat surfaces ── * Contract for lib-agent-chat-ui / lib-agent-dock-ui. User bubble is * a filled, deep, high-contrast panel with light text; assistant * bubble is a card-like surface with a hairline border. */ --chat-user-bg: oklch(0.48 0.2 260); --chat-user-fg: oklch(0.99 0.005 80); --chat-assistant-bg: oklch(0.98 0.003 250); --chat-assistant-fg: oklch(0.16 0.02 255); --chat-assistant-border: oklch(0.92 0.005 250); --radius: 0.5rem; --sidebar: oklch(0.985 0.003 250); --sidebar-foreground: oklch(0.16 0.02 255); --sidebar-accent: oklch(0.94 0.005 250); --sidebar-accent-foreground: oklch(0.20 0.025 255); --sidebar-border: oklch(0.92 0.005 250); --sidebar-ring: oklch(0.55 0.22 260); --sidebar-primary: oklch(0.55 0.22 260); --sidebar-primary-foreground: oklch(0.99 0.005 80); /* ── Modena-specific tokens ─────────────────────────────────────── */ /* Accent — duplicate of --primary so Modena components can read * either. Override --mod-accent at the app/site level to brand. */ --mod-accent: var(--primary); /* Gray scale (11 steps, matches Modena's reference). */ --mod-gray-50: oklch(0.985 0.002 250); --mod-gray-100: oklch(0.965 0.003 250); --mod-gray-200: oklch(0.92 0.004 250); --mod-gray-300: oklch(0.86 0.006 250); --mod-gray-400: oklch(0.70 0.012 250); --mod-gray-500: oklch(0.55 0.018 250); --mod-gray-600: oklch(0.45 0.020 250); --mod-gray-700: oklch(0.36 0.022 250); --mod-gray-800: oklch(0.24 0.024 250); --mod-gray-900: oklch(0.17 0.025 250); --mod-gray-950: oklch(0.10 0.025 250); /* Text */ --mod-text: var(--foreground); --mod-text-secondary: oklch(0.42 0.020 250); --mod-text-muted: var(--muted-foreground); --mod-text-faint: oklch(0.68 0.012 250); /* Prose */ --mod-prose-color: oklch(0.22 0.022 250); --mod-prose-size: clamp(1.1875rem, 1.0625rem + 0.4vw, 1.3125rem); --mod-prose-line-height: 1.7; --mod-prose-max-width: 720px; --mod-prose-tracking: -0.011em; /* Inline code */ --mod-code-color: oklch(0.55 0.22 350); --mod-code-bg: var(--muted); --mod-code-border: var(--border); /* Code block (dark always) */ --mod-bg-code: oklch(0.16 0.020 250); --mod-bg-code-fg: oklch(0.92 0.010 80); --mod-bg-code-header: oklch(0.13 0.020 250); /* Status colors */ --mod-info: oklch(0.55 0.22 260); --mod-info-bg: color-mix(in oklch, oklch(0.55 0.22 260) 6%, transparent); --mod-info-border: color-mix(in oklch, oklch(0.55 0.22 260) 20%, transparent); --mod-success: oklch(0.65 0.18 145); --mod-success-bg: color-mix(in oklch, oklch(0.65 0.18 145) 6%, transparent); --mod-success-border: color-mix(in oklch, oklch(0.65 0.18 145) 20%, transparent); --mod-warning: oklch(0.72 0.16 70); --mod-warning-bg: color-mix(in oklch, oklch(0.72 0.16 70) 6%, transparent); --mod-warning-border: color-mix(in oklch, oklch(0.72 0.16 70) 20%, transparent); --mod-danger: oklch(0.55 0.22 25); --mod-danger-bg: color-mix(in oklch, oklch(0.55 0.22 25) 6%, transparent); --mod-danger-border: color-mix(in oklch, oklch(0.55 0.22 25) 20%, transparent); /* Fonts */ --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-heading: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-mono: "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace; --mod-font-body: "Newsreader", "Source Serif 4", Georgia, "Times New Roman", serif; --font-ai-prose: var(--mod-font-body); /* Letter-spacing scale */ --mod-tracking: -0.011em; --mod-tracking-tight: -0.02em; --mod-tracking-heading: -0.025em; --mod-tracking-wide: 0.04em; /* Spacing (Modena's 4px grid) */ --mod-space-1: 4px; --mod-space-2: 8px; --mod-space-3: 12px; --mod-space-4: 16px; --mod-space-5: 20px; --mod-space-6: 24px; --mod-space-8: 32px; --mod-space-10: 40px; --mod-space-12: 48px; --mod-space-16: 64px; /* Radius scale */ --mod-radius-sm: 4px; --mod-radius: 6px; --mod-radius-md: 8px; --mod-radius-lg: 12px; --mod-radius-xl: 16px; --mod-radius-pill: 9999px; /* Type scale (Crema-shaped) */ --text-display-size: clamp(2.5rem, 2rem + 2vw, 3.25rem); --text-display-lh: 1.1; --text-headline-size: clamp(2rem, 1.7rem + 1.2vw, 2.5rem); --text-headline-lh: 1.15; --text-title-size: 1.5rem; --text-title-lh: 1.3; --text-body-size: 1rem; --text-body-lh: 1.6; --text-label-size: 0.875rem; --text-label-lh: 1.4; --text-caption-size: 0.75rem; --text-caption-lh: 1.4; /* Motion */ --duration-fast: 120ms; --duration-base: 200ms; --duration-slow: 300ms; --ease-standard: cubic-bezier(0.25, 0.1, 0.25, 1); --ease-decelerate: cubic-bezier(0, 0, 0.25, 1); /* Elevation */ --elevation-0: none; --elevation-1: 0 1px 2px rgba(0, 0, 0, 0.04); --elevation-2: 0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.03); --elevation-3: 0 4px 8px -2px rgba(0, 0, 0, 0.06), 0 2px 4px -2px rgba(0, 0, 0, 0.03); --elevation-4: 0 12px 24px -4px rgba(0, 0, 0, 0.08), 0 4px 8px -4px rgba(0, 0, 0, 0.03); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } /* ── DARK MODE ──────────────────────────────────────────────────── */ .dark { --background: oklch(0.13 0.018 250); --foreground: oklch(0.95 0.010 250); --card: oklch(0.17 0.020 250); --card-foreground: oklch(0.95 0.010 250); --popover: oklch(0.17 0.020 250); --popover-foreground: oklch(0.95 0.010 250); --primary: oklch(0.65 0.22 260); --primary-foreground: oklch(0.99 0.005 80); --secondary: oklch(0.22 0.020 250); --secondary-foreground: oklch(0.92 0.010 250); --muted: oklch(0.20 0.020 250); --muted-foreground: oklch(0.65 0.020 250); --accent: oklch(0.24 0.022 250); --accent-foreground: oklch(0.92 0.010 250); --border: oklch(0.27 0.020 250); --input: oklch(0.27 0.020 250); --ring: oklch(0.65 0.22 260); /* ── Chat surfaces (dark) ── */ --chat-user-bg: oklch(0.55 0.2 260); --chat-user-fg: oklch(0.99 0.005 80); --chat-assistant-bg: oklch(0.20 0.020 250); --chat-assistant-fg: oklch(0.95 0.010 250); --chat-assistant-border: oklch(0.27 0.020 250); --sidebar: oklch(0.11 0.018 250); --sidebar-foreground: oklch(0.92 0.010 250); --sidebar-accent: oklch(0.22 0.022 250); --sidebar-accent-foreground: oklch(0.92 0.010 250); --sidebar-border: oklch(0.25 0.020 250); --sidebar-primary: oklch(0.65 0.22 260); --sidebar-primary-foreground: oklch(0.99 0.005 80); --mod-text: var(--foreground); --mod-text-secondary: oklch(0.65 0.020 250); --mod-text-muted: oklch(0.55 0.020 250); --mod-text-faint: oklch(0.40 0.018 250); --mod-prose-color: oklch(0.86 0.012 250); --mod-code-color: oklch(0.78 0.22 350); --mod-code-bg: oklch(0.22 0.020 250); --mod-code-border: oklch(0.30 0.020 250); } /* ── BASE TYPOGRAPHY ───────────────────────────────────────────── * Caffe Florian's theme applies serif font-heading to h1-h4 globally; * Modena keeps headings in Inter sans. Apply explicitly so it sticks * regardless of cascade order with other themes' base layers. */ html { font-family: var(--font-sans); } 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-sans); font-weight: 700; letter-spacing: var(--mod-tracking-heading); } /* ── ARTICLE SURFACE ───────────────────────────────────────────── * Targets @crema/content-ui's data-slot attributes. Anyone using *
...
* automatically picks up the editorial look. Outside [data-slot="article"] * Prose stays neutral (so comment bodies don't get drop-cap/serif). */ [data-slot="article"] { max-width: var(--mod-prose-max-width); margin-inline: auto; padding-inline: var(--mod-space-6); color: var(--mod-text); } [data-slot="article"] [data-slot="article-header"] { text-align: center; padding-top: var(--mod-space-16); margin-bottom: 3vmin; border: none; } [data-slot="article"] [data-slot="article-header"] h1 { font-family: var(--font-sans); font-size: var(--text-display-size); line-height: var(--text-display-lh); letter-spacing: var(--mod-tracking-heading); font-weight: 800; margin-top: 0.5rem; color: var(--mod-text); } [data-slot="article"] [data-slot="article-header"] p { font-family: var(--mod-font-body); font-optical-sizing: auto; font-size: clamp(1.125rem, 1rem + 0.4vw, 1.375rem); line-height: 1.5; color: var(--mod-text-secondary); margin: 0.75em auto 0; max-width: 36rem; } [data-slot="article"] [data-slot="article-header"] > div:first-child { font-size: 0.875rem; font-weight: 600; letter-spacing: var(--mod-tracking-wide); text-transform: uppercase; color: var(--mod-accent); } [data-slot="article"] [data-slot="article-meta"] { justify-content: center; padding-top: var(--mod-space-6); margin-top: var(--mod-space-6); font-size: 0.875rem; color: var(--mod-text-muted); } [data-slot="article"] [data-slot="prose"] { font-family: var(--mod-font-body); font-optical-sizing: auto; font-size: var(--mod-prose-size); line-height: var(--mod-prose-line-height); letter-spacing: var(--mod-prose-tracking); color: var(--mod-prose-color); } [data-slot="article"] [data-slot="prose"] > * + * { margin-top: 1.5em; } [data-slot="article"] [data-slot="prose"] :where(p) { margin: 0; } [data-slot="article"] [data-slot="prose"] :where(h1, h2, h3, h4, h5, h6) { font-family: var(--font-sans); font-weight: 700; line-height: 1.2; letter-spacing: var(--mod-tracking-heading); color: var(--mod-text); } [data-slot="article"] [data-slot="prose"] :where(h2) { font-size: 1.875rem; margin-top: 2.4em; margin-bottom: 0.6em; } [data-slot="article"] [data-slot="prose"] :where(h3) { font-size: 1.5rem; margin-top: 2em; margin-bottom: 0.5em; } [data-slot="article"] [data-slot="prose"] :where(h4) { font-size: 1.25rem; margin-top: 1.8em; margin-bottom: 0.4em; } [data-slot="article"] [data-slot="prose"] :where(strong) { font-weight: 700; color: var(--mod-text); } [data-slot="article"] [data-slot="prose"] :where(ul, ol) { padding-left: 1.5em; margin: 0; } [data-slot="article"] [data-slot="prose"] :where(li + li) { margin-top: 0.4em; } [data-slot="article"] [data-slot="prose"] :where(li::marker) { color: var(--mod-text-faint); } [data-slot="article"] [data-slot="prose"] :where(blockquote) { position: relative; font-size: 1.25em; font-weight: 500; line-height: 1.5; color: var(--mod-text); padding: 0 0 0 1.5em; margin: 2em 0; border: none; font-style: normal; } [data-slot="article"] [data-slot="prose"] :where(blockquote)::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--mod-accent); border-radius: 2px; } [data-slot="article"] [data-slot="prose"] :where(blockquote p) { margin: 0; } [data-slot="article"] [data-slot="prose"] :where(blockquote p + p) { margin-top: 0.6em; } [data-slot="article"] [data-slot="prose"] :where([data-slot="pullquote"]) { font-family: var(--mod-font-body); font-size: 1.625em; font-style: italic; font-weight: 400; line-height: 1.5; text-align: center; padding: 0; color: var(--mod-text); margin: 2.5em 0; } [data-slot="article"] [data-slot="prose"] :where([data-slot="pullquote"])::before { display: none; } [data-slot="article"] [data-slot="prose"] :where(hr) { border: none; border-top: 1px solid var(--border); opacity: 0.6; margin: 3em 0; width: auto; height: auto; background: transparent; } [data-slot="article"] [data-slot="prose"] :where(:not(pre) > code) { font-family: var(--font-mono); font-size: 0.85em; color: var(--mod-code-color); background: var(--mod-code-bg); border: 1px solid var(--mod-code-border); border-radius: var(--mod-radius-sm); padding: 0.1em 0.35em; } [data-slot="article"] [data-slot="prose"] :where(pre) { font-family: var(--font-mono); font-size: 0.875rem; line-height: 1.65; background: var(--mod-bg-code); color: var(--mod-bg-code-fg); border-radius: var(--mod-radius-md); padding: var(--mod-space-5); overflow-x: auto; margin: 2em 0; } [data-slot="article"] [data-slot="prose"] :where(pre code) { background: transparent; color: inherit; border: none; padding: 0; border-radius: 0; font-size: inherit; } [data-slot="article"] [data-slot="prose"] :where(a) { color: var(--mod-accent); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; transition: color var(--duration-fast) var(--ease-standard); } [data-slot="article"] [data-slot="prose"] :where(a:hover) { color: color-mix(in oklch, var(--mod-accent) 75%, var(--foreground)); }