/* * Harbor — cool neutral, warm spark. * * The most neutral of the warm-consumer set. The whole surface is a calm, * faintly-COOL light grey — morning harbor light on soft slate, a whisper of * blue-grey that reads as clean neutral, never cream, never SaaS blue. All the * warmth in the theme is delivered by ONE honey/amber accent (hue ~78), spent * surgically on the primary action, selection, and focus ring — grey stone * warmed by lamplight. Ink is a deep, very-slightly-cool charcoal; the amber * carries dark ink on top (the bright-swatch/dark-ink pairing) so it lands high * above the contrast floor while staying quiet everywhere else. * * Dark mode is the harbor at night: a deep cool-neutral charcoal (low chroma, * faint cool hue ~250, not pure black and never warm-brown) with the same amber * glowing warm against it. Crisp, quiet, trustworthy — a calm utility that is * warm only at the touchpoints. Built for me.sky-ai.com back-of-house. * * Type is crisp modern-neutral: Inter Tight for text, Geist for headings, Geist * Mono for code. Product register — fixed rem sizes, no serif. Radius is a * crisp 0.75rem; shadows are low and neutral; motion is product-fast. * * Token contract matches lib-theme-caffe-florian/theme.css (Crema v1). */ /* * Fonts: consuming apps load Inter Tight + Geist + 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: "Inter Tight", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-heading: "Geist", "Inter Tight", -apple-system, BlinkMacSystemFont, sans-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: "Geist", "Inter Tight", -apple-system, BlinkMacSystemFont, sans-serif; --body-family: "Inter Tight", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; /* ── Colors ── soft faintly-cool light-grey surface (harbor light), clean * white cards, deep cool-neutral charcoal ink, one honey/amber accent. */ --background: oklch(0.975 0.005 248); --foreground: oklch(0.22 0.008 255); --card: oklch(1 0 0); --card-foreground: oklch(0.22 0.008 255); --popover: oklch(0.995 0.003 248); --popover-foreground: oklch(0.22 0.008 255); /* Primary — the sole warmth. Honey/amber deepened a touch toward orange * (74°, L0.77) so it's rich rather than blinding, with a near-black warm * ink (L0.17, low chroma) on top — crisp, not amber-brown-on-amber. ~9:1. */ --primary: oklch(0.77 0.145 74); --primary-foreground: oklch(0.17 0.02 74); --secondary: oklch(0.94 0.006 250); --secondary-foreground: oklch(0.3 0.008 255); --muted: oklch(0.94 0.006 250); --muted-foreground: oklch(0.46 0.011 253); /* Accent — the warm spark as a hover/selection tint: a soft amber wash with * deep amber ink, not a second competing fill. */ --accent: oklch(0.93 0.03 80); --accent-foreground: oklch(0.38 0.09 72); /* ── Status ── dark ink on the bright status hues (harbor's bright-swatch * pattern), except destructive/info which carry light labels on deeper * fills for alarm legibility. Warning is pulled toward amber-ORANGE * (hue 52) and set darker than the honey primary (hue 78) so the two never * read as the same swatch. */ --destructive: oklch(0.55 0.21 27); --destructive-foreground: oklch(0.98 0.01 27); --success: oklch(0.6 0.14 150); --success-foreground: oklch(0.17 0.03 150); --warning: oklch(0.68 0.17 52); --warning-foreground: oklch(0.23 0.05 52); --info: oklch(0.54 0.15 248); --info-foreground: oklch(0.98 0.01 248); --border: oklch(0.22 0.008 255 / 0.1); --input: oklch(0.22 0.008 255 / 0.12); --ring: oklch(0.77 0.145 74 / 0.55); /* Chart palette — amber lead, then cool blue / teal / violet / rose. * Warm spark against a cool spectrum; hues spaced, adjacent lightness * varied. */ --chart-1: oklch(0.76 0.15 78); --chart-2: oklch(0.58 0.14 248); --chart-3: oklch(0.68 0.1 190); --chart-4: oklch(0.55 0.15 300); --chart-5: oklch(0.68 0.15 25); --sidebar: oklch(0.955 0.006 250); --sidebar-foreground: oklch(0.22 0.008 255); --sidebar-primary: oklch(0.8 0.14 78); --sidebar-primary-foreground: oklch(0.26 0.05 78); --sidebar-accent: oklch(0.93 0.03 80); --sidebar-accent-foreground: oklch(0.38 0.09 72); --sidebar-border: oklch(0.22 0.008 255 / 0.08); --sidebar-ring: oklch(0.8 0.14 78 / 0.55); /* Syntax — cool base with a warm keyword, matching the harbor palette. */ --syntax-keyword: oklch(0.55 0.15 300); --syntax-string: oklch(0.5 0.12 150); --syntax-number: oklch(0.55 0.14 52); --syntax-comment: oklch(0.55 0.01 253); --syntax-function: oklch(0.5 0.15 248); --syntax-type: oklch(0.52 0.1 190); /* ── Chat surfaces ── * Contract for lib-agent-chat-ui / lib-agent-dock-ui. User bubble is a deep * cool-charcoal panel with light text (neutral, so amber stays scarce); * assistant bubble is a clean card with a hairline border. */ --chat-user-bg: oklch(0.28 0.012 253); --chat-user-fg: oklch(0.97 0.005 250); --chat-assistant-bg: oklch(1 0 0); --chat-assistant-fg: oklch(0.22 0.008 255); --chat-assistant-border: oklch(0.22 0.008 255 / 0.1); /* Crisp-modern radius. */ --radius: 0.75rem; /* ── Motion ── crisp, product-fast. Springs alias to the standard eases so * the theme stays quiet — personality lives in the speed, not in bounce. */ --duration-fast: 160ms; --duration-base: 280ms; --duration-slow: 400ms; --duration-slower: 560ms; --duration-spring: 280ms; --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.2, 0, 0, 1); --ease-spring-gentle: var(--ease-standard); --ease-spring-snappy: var(--ease-decelerate); --ease-spring-bouncy: var(--ease-standard); /* ── Typography ── crisp product register, fixed rem, full role ramp. */ --text-hero-size: 3.5rem; --text-hero-lh: 1.05; --text-display-size: 3rem; --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.25rem; --text-subtitle-lh: 1.5; --text-body-size: 1.0625rem; --text-body-lh: 1.6; --text-label-size: 0.9375rem; --text-label-lh: 1.25rem; --text-caption-size: 0.8125rem; --text-caption-lh: 1.125rem; /* ── Elevation ── crisp, low, neutral cool shadows. */ --elevation-0: none; --elevation-1: 0 1px 2px oklch(0.22 0.008 255 / 0.06); --elevation-2: 0 1px 3px oklch(0.22 0.008 255 / 0.08), 0 1px 2px oklch(0.22 0.008 255 / 0.05); --elevation-3: 0 4px 8px -2px oklch(0.22 0.008 255 / 0.08), 0 2px 4px -2px oklch(0.22 0.008 255 / 0.05); --elevation-4: 0 12px 24px -6px oklch(0.22 0.008 255 / 0.1), 0 4px 8px -4px oklch(0.22 0.008 255 / 0.05); --elevation-5: 0 20px 40px -8px oklch(0.22 0.008 255 / 0.16); --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 — harbor at night. Deep cool-neutral charcoal (faint cool hue ~250, * low chroma, not pure black, never warm-brown); the same honey/amber glows * warm against it with dark ink on top. Crisp and calm. */ .dark { --background: oklch(0.2 0.008 252); --foreground: oklch(0.94 0.006 250); --card: oklch(0.26 0.008 252); --card-foreground: oklch(0.94 0.006 250); --popover: oklch(0.28 0.008 252); --popover-foreground: oklch(0.94 0.006 250); --primary: oklch(0.80 0.145 74); --primary-foreground: oklch(0.17 0.02 74); --secondary: oklch(0.28 0.008 252); --secondary-foreground: oklch(0.9 0.006 250); --muted: oklch(0.28 0.008 252); --muted-foreground: oklch(0.72 0.011 250); --accent: oklch(0.33 0.05 78); --accent-foreground: oklch(0.86 0.1 78); --destructive: oklch(0.56 0.21 27); --destructive-foreground: oklch(0.98 0.01 27); --success: oklch(0.7 0.15 150); --success-foreground: oklch(0.17 0.03 150); --warning: oklch(0.74 0.16 52); --warning-foreground: oklch(0.23 0.05 52); --info: oklch(0.66 0.15 248); --info-foreground: oklch(0.16 0.03 248); --border: oklch(0.95 0.006 250 / 0.12); --input: oklch(0.95 0.006 250 / 0.14); --ring: oklch(0.80 0.145 74 / 0.55); --chart-1: oklch(0.8 0.15 78); --chart-2: oklch(0.68 0.14 248); --chart-3: oklch(0.74 0.1 190); --chart-4: oklch(0.66 0.15 300); --chart-5: oklch(0.72 0.15 25); --sidebar: oklch(0.22 0.008 252); --sidebar-foreground: oklch(0.94 0.006 250); --sidebar-primary: oklch(0.81 0.14 78); --sidebar-primary-foreground: oklch(0.24 0.05 78); --sidebar-accent: oklch(0.33 0.05 78); --sidebar-accent-foreground: oklch(0.86 0.1 78); --sidebar-border: oklch(0.95 0.006 250 / 0.09); --sidebar-ring: oklch(0.81 0.14 78 / 0.55); --syntax-keyword: oklch(0.72 0.13 300); --syntax-string: oklch(0.74 0.12 150); --syntax-number: oklch(0.78 0.14 52); --syntax-comment: oklch(0.6 0.01 250); --syntax-function: oklch(0.72 0.14 248); --syntax-type: oklch(0.72 0.1 190); /* ── Chat surfaces (dark) ── */ --chat-user-bg: oklch(0.34 0.012 252); --chat-user-fg: oklch(0.96 0.006 250); --chat-assistant-bg: oklch(0.26 0.008 252); --chat-assistant-fg: oklch(0.94 0.006 250); --chat-assistant-border: oklch(0.95 0.006 250 / 0.12); --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 8px -2px oklch(0 0 0 / 0.4), 0 2px 4px -2px oklch(0 0 0 / 0.25); --elevation-4: 0 12px 24px -6px oklch(0 0 0 / 0.45), 0 4px 8px -4px oklch(0 0 0 / 0.25); --elevation-5: 0 20px 40px -8px oklch(0 0 0 / 0.55); } /* * @layer base — Harbor's crisp, quiet product philosophy. * * No glass, no editorial flourish. Clean grotesque type, calm neutral surfaces * hairline-separated, and the amber spark reserved for focus, selection, and the * primary action. Everything else stays cool and out of the way. */ @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); } /* Headings — Geist, crisp and tight. */ 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: 600; letter-spacing: -0.02em; color: var(--foreground); } code, kbd, samp, pre, [data-slot="code"], [data-slot="code-block"] { font-family: var(--font-mono); } /* Inline code — cool-neutral chip. */ :not(pre) > code { padding: 0.1em 0.35em; border-radius: calc(var(--radius) * 0.5); background: color-mix(in oklch, var(--foreground) 6%, transparent); color: var(--foreground); font-size: 0.9em; } /* Selection — the amber spark. */ ::selection { background: color-mix(in oklch, var(--primary) 30%, transparent); color: var(--foreground); } /* Links — amber, underline-on-hover. */ a { color: color-mix(in oklch, var(--primary) 70%, var(--foreground)); text-decoration-color: color-mix(in oklch, var(--primary) 40%, 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 amber 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 — quiet weight; opacity absorb on press, product-fast. */ [data-slot="button"] { font-weight: 500; letter-spacing: -0.006em; } /* 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 crisp 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.9; } [data-slot="button"]:active:not(:disabled) { opacity: 0.82; transform: scale(0.99); } /* Inputs — clean card surface, hairline border, amber 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: color-mix(in oklch, var(--foreground) 22%, transparent); } [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; }