diff --git a/.agents/skills/kilo-design/AGENTS.md b/.agents/skills/kilo-design/AGENTS.md new file mode 100644 index 0000000000..f6e1048918 --- /dev/null +++ b/.agents/skills/kilo-design/AGENTS.md @@ -0,0 +1,27 @@ +# Kilo Design Skill Maintenance + +## Purpose + +Keep frontend design work aligned with root `DESIGN.md` while translating its contract into practical web, mobile, Storybook, accessibility, responsive, interaction, motion, and UX-writing guidance. + +## How the skill works + +1. `SKILL.md` loads root `DESIGN.md` first. +2. `reference/kilo-brand.md` maps the contract to repository implementation. +3. Concern-specific references add focused guidance without redefining tokens. +4. Existing CSS and components are implementation evidence, not higher-priority sources. Differences from `DESIGN.md` are drift. + +## Validation + +After changing this skill: + +- Search all skill Markdown for retired token values and stale implementation claims. +- Check compact Markdown table padding with `bun run script/check-md-table-padding.ts`. +- Run `git diff --check` for changed skill files. + +## Change guidelines + +- Update root `DESIGN.md` before changing canonical token names, values, domain mappings, typography metrics, radius, or spacing. +- Keep exact token values in `DESIGN.md`; references should link roles to implementation and avoid duplicating the full contract. +- Preserve Kilo-specific defaults: dark-first product UI, one primary CTA per surface, six-role surface ladder, fixed status domains, Inter/Roboto Mono roles, compact rhythm, Radix/shadcn primitives, restrained motion, and direct UX copy. +- When implementation migrates, remove stale warnings immediately. Do not preserve resolved issues as historical guidance. diff --git a/.agents/skills/kilo-design/SKILL.md b/.agents/skills/kilo-design/SKILL.md index 82a5f88772..1626f84daf 100644 --- a/.agents/skills/kilo-design/SKILL.md +++ b/.agents/skills/kilo-design/SKILL.md @@ -1,6 +1,6 @@ --- name: kilo-design -description: Use when designing, reviewing, polishing, adapting, or implementing Kilo Code frontend UI. Applies Kilo brand rules, shadcn/Radix component conventions, OKLCH tokens, Inter/Roboto Mono/JetBrains Mono typography, compact product rhythm, restrained motion, and Kilo voice guidelines. Triggers on web app screens (apps/web), Storybook components, React Native mobile surfaces (apps/mobile), marketing/landing pages, onboarding, empty states, forms, dialogs, dashboards, billing, sidebar, theming, accessibility, and visual QA. Triggers on terms like "design", "redesign", "polish", "critique", "audit", "typeset", "typography", "fonts", "color", "palette", "brand", "spacing", "layout", "grid", "motion", "animate", "transitions", "interaction", "forms", "focus", "responsive", "mobile", "breakpoints", "UX copy", "microcopy", "error states", "empty states", "on-brand", "Kilo voice". Not for backend-only work. +description: Use when designing, reviewing, polishing, adapting, or implementing Kilo Code frontend UI. Applies the DESIGN.md token contract, Kilo brand rules, shadcn/Radix component conventions, exact color tokens, Inter/Roboto Mono/JetBrains Mono typography, compact product rhythm, restrained motion, and Kilo voice guidelines. Triggers on web app screens (apps/web), Storybook components, React Native mobile surfaces (apps/mobile), marketing/landing pages, onboarding, empty states, forms, dialogs, dashboards, billing, sidebar, theming, accessibility, and visual QA. Triggers on terms like "design", "redesign", "polish", "critique", "audit", "typeset", "typography", "fonts", "color", "palette", "brand", "spacing", "layout", "grid", "motion", "animate", "transitions", "interaction", "forms", "focus", "responsive", "mobile", "breakpoints", "UX copy", "microcopy", "error states", "empty states", "on-brand", "Kilo voice". Not for backend-only work. license: Apache 2.0 derivative of pbakaus/impeccable, adapted for Kilo Code. See NOTICE.md. --- @@ -10,21 +10,16 @@ Design guidance for the Kilo Code frontend. Use this skill whenever the task involves how something looks, how it behaves, how it reads, or how it adapts. -## Canonical rule: Kilo brand first +## Canonical rule: design contract first -The overlay in `reference/kilo-brand.md` is the source of truth. When any -other reference in this skill conflicts with `kilo-brand.md`, -`kilo-brand.md` wins. +Root `DESIGN.md` is the source of truth for token names, exact values, domain mappings, typography roles, radius, and spacing. `reference/kilo-brand.md` explains how to apply that contract. When guidance, existing CSS, or a component conflicts with `DESIGN.md`, treat it as implementation drift rather than precedent. -Load `reference/kilo-brand.md` on every invocation of this skill before -picking tokens, typography, layout, or motion. It captures: +Load `DESIGN.md` and `reference/kilo-brand.md` on every invocation before picking tokens, typography, layout, or motion. Together they define: -- Kilo's dark-first web theme, mobile light/dark token split, and existing - CSS tokens. -- Brand yellow-green `primary` token as the primary CTA color, used once - per surface. -- Typography (Inter / Roboto Mono / JetBrains Mono) and the known - font-token mismatch. +- Kilo's dark-first web theme and six-role surface ladder. +- Brand yellow-green `primary` token as the primary CTA color, used once per surface. +- Fixed status-domain mappings, syntax colors, and diff colors. +- Inter / Roboto Mono typography roles and editor-only JetBrains Mono usage. - Spacing, radius, component, and motion conventions. - Kilo-specific anti-patterns to reject on sight. @@ -45,7 +40,7 @@ When unclear, treat the surface as Product UI. Given a user prompt that invokes this skill: -1. Always load `reference/kilo-brand.md`. +1. Always load root `DESIGN.md`, then `reference/kilo-brand.md`. 2. Identify the dominant concern from the prompt and load the matching reference(s): @@ -73,12 +68,8 @@ Given a user prompt that invokes this skill: Follow these on every task: -1. **Inspect before editing.** Open `apps/web/src/app/globals.css`, the - relevant component under `apps/web/src/components/`, and any - Storybook story before proposing visual changes. -2. **Prefer existing tokens, utilities, and components.** Before adding - a new color, font, radius, or primitive, confirm no existing one - solves the problem. +1. **Inspect before editing.** Open root `DESIGN.md`, `apps/web/src/app/globals.css`, the relevant component under `apps/web/src/components/`, and any Storybook story before proposing visual changes. +2. **Prefer compliant tokens, utilities, and components.** Reuse existing implementation only when it maps to `DESIGN.md`. If it differs, report or fix the drift instead of copying it. 3. **Do not rename or restructure the shadcn UI layer** unless the user explicitly asks for a design-system refactor. 4. **Use the `primary` token for primary CTAs.** The product primary is the @@ -94,24 +85,19 @@ Follow these on every task: tablet/laptop (~768–1024px), wide desktop (~1440px+). 9. **Use Kilo voice** (see `reference/ux-writing.md`) for any copy you add or rewrite. -10. **Surface conflicts.** If the user's ask conflicts with - `kilo-brand.md`, raise the conflict and propose a path forward - before silently overriding the brand system. +10. **Surface conflicts.** If the user's ask conflicts with `DESIGN.md`, raise the conflict and propose a path forward before silently overriding the design contract. ## Implementing code changes When producing code: -- Use Tailwind utilities that map to semantic tokens - (`bg-background`, `text-foreground`, `border-border`, `bg-primary`, - `text-primary-foreground`, etc.) before reaching for hex. +- Use Tailwind utilities that map to semantic tokens before hex: `bg-background`, `text-foreground`, `border-border`, `bg-primary`, and `text-primary-foreground` for broad semantics; `bg-surface-inset`, `bg-surface-raised`, `bg-surface-overlay`, `bg-surface-hover`, and `bg-surface-selected` for exact surface roles; syntax, diff, and status utilities for those domains. - Extend `cva` variants in existing `ui/` primitives rather than cloning. -- Icons: `lucide-react`, typically `size-4`, inheriting `currentColor`. +- Icons: `lucide-react`, typically `size-4`, inheriting `currentColor`; use `size-icon-sm` for canonical 14px compact/status icons. - Add `aria-label` to icon-only buttons. - Use Radix + shadcn wrappers for overlays (dialog, dropdown, popover, tooltip, sheet) — do not hand-roll positioning. -- Match compact rhythm: `h-8` / `h-9` / `h-10` controls, `h-14` topbar, - `p-6` cards. +- Match compact rhythm: `h-8` / `h-control-default` / `h-10` controls, `h-14` topbar, and `p-6` cards. Use `h-control-touch` or `size-control-touch` where touch targets need 44px. - Prefer `gap-*` over ad-hoc margins. ## Running a design review @@ -148,18 +134,17 @@ This skill is intentionally scoped. It does **not**: - Run automated anti-pattern scans. - Run or expose Impeccable's "live mode." -- Generate a root `DESIGN.md`. -- Rewrite the font-token mismatch or migrate every legacy hardcoded blue - CTA. Those are real follow-ups but belong in separate, - design-system-scoped PRs. +- Generate or redefine root `DESIGN.md`; it must still enforce the existing contract. +- Migrate every legacy hardcoded blue CTA unless the owning surface is being updated. Broad migrations belong in separate design-system-scoped PRs. ## Reference map | File | What it covers | |---|---| -| `reference/kilo-brand.md` | Kilo-specific tokens, components, rules. Load first, always. | +| Root `DESIGN.md` | Canonical token contract and application rules. Load first, always. | +| `reference/kilo-brand.md` | Kilo-specific implementation guidance. Load after `DESIGN.md`, always. | | `reference/typography.md` | Inter/mono usage, hierarchy, tabular nums, OpenType polish. | -| `reference/color-and-contrast.md` | OKLCH tokens, brand vs action color, dark-first contrast rules. | +| `reference/color-and-contrast.md` | Exact palette, brand vs action color, dark-first contrast rules. | | `reference/spatial-design.md` | Spacing, radius scale, grid patterns, optical alignment. | | `reference/motion-design.md` | Durations, easings, reduced motion, Kilo brand flourishes. | | `reference/interaction-design.md` | Focus, forms, overlays, destructive actions, keyboard nav. | diff --git a/.agents/skills/kilo-design/reference/color-and-contrast.md b/.agents/skills/kilo-design/reference/color-and-contrast.md index 1094ccfd21..777771d1e9 100644 --- a/.agents/skills/kilo-design/reference/color-and-contrast.md +++ b/.agents/skills/kilo-design/reference/color-and-contrast.md @@ -5,8 +5,7 @@ ## Kilo application -Kilo's palette is already expressed in OKLCH CSS variables. Do not -introduce a parallel palette. +Kilo's exact hex palette is defined in root `DESIGN.md` and implemented as CSS variables. Do not introduce a parallel palette or derive replacement values in another color space. ### Use tokens, not hex @@ -18,9 +17,7 @@ Tailwind bindings are in the `@theme inline` block. ### Primary and brand accent use -`--brand-primary` / `text-brand-primary` / `bg-brand-primary` (electric -yellow-green, `oklch(95% 0.15 108)`) is the same swatch as the semantic -`primary` token. It is both brand and primary action color. Hold it under +`--brand-primary` / `text-brand-primary` / `bg-brand-primary` (`#F7F586`) is the same swatch as the semantic `primary` token. It is both brand and primary action color. Hold it under 10% of pixel weight on any given surface. Reserve for: - Logo, wordmark, and logo-adjacent affordances. @@ -40,10 +37,10 @@ Do **not** use yellow-green as: The primary product CTA is the brand yellow-green semantic token: -- Background `primary` / `--brand-primary` / `oklch(95% 0.15 108)` -- Foreground `primary-foreground` (near-black) -- Hover: slightly darker yellow-green -- Focus ring: semantic `ring` or low-alpha yellow-green +- Background `primary` / `--brand-primary`: `#F7F586` +- Foreground `primary-foreground`: `#1F1F1F` +- Hover `primary-hover`: `#E6E475` +- Focus ring `ring` / `brand-primary-ring`: `#F7F58659` Hardcoded blue buttons (`#2B6AD2`, Tailwind `blue-*` fills) are legacy drift. Migrate them to `primary` when touching the owning component or flow. Blue is @@ -80,40 +77,29 @@ tree actually react to theme changes. --- -## Color Spaces: Use OKLCH +## Color-space discipline -OKLCH is perceptually uniform — equal steps in lightness look equal. HSL -is not. Kilo's tokens are already OKLCH. - -`oklch(lightness chroma hue)` where lightness is 0–100%, chroma ~0–0.4, -hue 0–360. Hold chroma+hue roughly constant and vary lightness to build -variants, but **reduce chroma as lightness approaches 0 or 100** — high -chroma at the extremes reads as garish. +The canonical palette uses exact hex values. Do not convert tokens to OKLCH, HSL, or generated shades during feature work: conversion and interpolation can alter contract values. Color-space experiments belong in an explicit design-system change that updates `DESIGN.md` first. ## Building Functional Palettes -### Tinted Neutrals +### Neutral surfaces -Pure gray is dead. Add a tiny chroma value (0.005–0.015) to neutrals, -hued toward the brand hue. Kilo already does this: `--color-kilo-gray` -is `oklch(0.24 0.007 1)`. Tailwind's shadcn neutral tokens carry 0 -chroma; that's acceptable for the dense product shell, but when you -create a new branded surface, lean on `kilo-gray` rather than a pure gray. +Use the six exact surface tokens rather than deriving tinted neutrals: inset `#101010`, background `#151515`, raised `#202020`, overlay `#333333`, hover `#3A3A3A`, and selected `#454545`. `kilo-gray` aliases exist for compatibility, not as permission to invent additional neutrals. -### Palette Structure +### Palette structure -A complete system needs: +Kilo's complete system already provides: | Role | Purpose | Example | |---|---|---| | **Brand** | Rare, voice-carrying accent | 1 color, 1–2 shades | | **Action** | Primary call-to-action | 1 color, 3 states | | **Neutral** | Text, backgrounds, borders | 9–11 shade scale | -| **Semantic** | Success, error, warning, info | 4 colors, 2–3 shades each | -| **Surface** | Cards, modals, overlays | 2–3 elevation levels | +| **Semantic** | Fixed status domains | Eight families, four shades each | +| **Surface** | Inset, canvas, cards, overlays, interaction states | Six fixed roles | -Skip secondary/tertiary unless you need them. Most apps work fine with -one accent and one action color. +Do not extend this structure from a feature component. Update `DESIGN.md` first when a genuinely new role is required. ### The 60-30-10 Rule (Applied Correctly) @@ -137,9 +123,7 @@ That shared role should still stay near 10% visual weight. | Large text (18px+ or 14px bold) | 3:1 | 4.5:1 | | UI components, icons | 3:1 | 4.5:1 | -The gotcha: placeholder text still needs 4.5:1. Check Kilo's -`placeholder:text-muted-foreground` against `bg-input/30` on real screens -before lowering opacity further. +Placeholder text still needs 4.5:1. Check `placeholder:text-muted-foreground` against canonical `bg-input-background`; do not apply another opacity modifier to the already translucent input background. ### Dangerous Color Combinations @@ -165,10 +149,7 @@ Don't trust your eyes. Use: ### Dark Mode Is Not Inverted Light Mode -Kilo is dark-first for a reason. If you design something for light mode -first and "flip" it, you'll introduce bad shadows, under-contrast accents, -and oversaturated hues. Design on the real `background` / `card` / -`muted` surfaces, not on `#fff`. +Kilo is dark-first for a reason. If you design something for light mode first and "flip" it, you'll introduce bad shadows, under-contrast accents, and oversaturated hues. Design on the exact `surface.background`, `surface.raised`, `surface.overlay`, `surface.hover`, and `surface.selected` roles, not on `#fff`. | Light mode principle | Dark mode behavior | |---|---| @@ -177,23 +158,18 @@ and oversaturated hues. Design on the real `background` / `card` / | Vibrant accents | Desaturate accents slightly | | White backgrounds | Never pure black — dark gray (OKLCH 12–18%) | -Depth in dark mode comes from surface lightness, not shadow. Kilo's scale -is already: `background` → `card`/`popover` → `muted`/`secondary`/`accent`. +Depth in dark mode comes from surface roles, not shadow: `surface.inset` → `surface.background` → `surface.raised` → `surface.overlay`, with `surface.hover` and `surface.selected` reserved for interaction states. ### Token Hierarchy -Use two layers: primitive tokens (`--blue-500`) and semantic tokens -(`--color-primary: var(--blue-500)`). In Kilo, primitives live inline in -OKLCH; semantic tokens map through `@theme inline`. Redefine the semantic -layer for theme changes, never the primitive layer per component. +Use two layers: contract primitives such as `--status-blue-500` and semantic aliases such as `--primary`, `--card`, and `--popover`. Tailwind mappings live in `@theme inline`. Components consume semantic or role-specific utilities; they never redefine primitives locally. ## Alpha Is A Design Smell Heavy use of transparency (`rgba`, `hsla`) usually means an incomplete palette. Alpha creates unpredictable contrast, performance overhead, and inconsistency. Define explicit overlay colors for each context instead. -Kilo's borders use `oklch(1 0 0 / 10%)` deliberately; that's fine. Don't -stack five more alpha layers on top of it. +Kilo's `border.default` (`#FFFFFF1A`) and `border.strong` (`#FFFFFF2E`) use deliberate alpha. Do not stack additional alpha layers on top. --- diff --git a/.agents/skills/kilo-design/reference/kilo-brand.md b/.agents/skills/kilo-design/reference/kilo-brand.md index 7540e89e6c..ccae4ecf23 100644 --- a/.agents/skills/kilo-design/reference/kilo-brand.md +++ b/.agents/skills/kilo-design/reference/kilo-brand.md @@ -1,12 +1,8 @@ # Kilo Brand -The canonical overlay for every other reference in this skill. When any of -the general design references below conflict with this document, **this -document wins**. +Canonical application overlay for every other reference in this skill. Root `DESIGN.md` wins for token contracts; this document wins when general references conflict on Kilo-specific application guidance. -This is not a style guide rewrite. It captures what the Kilo Code codebase -already does, so design changes stay coherent instead of drifting into -generic AI-flavored "modern SaaS." +Root `DESIGN.md` owns exact token values and roles. This reference explains how to apply that contract in the Kilo Code codebase so changes stay coherent instead of drifting into generic AI-flavored "modern SaaS." If implementation differs from `DESIGN.md`, treat it as drift. ## Sources of Truth @@ -15,7 +11,8 @@ files directly: | Concern | File | |---|---| -| Web tokens & base theme | `apps/web/src/app/globals.css` | +| Canonical token contract | `DESIGN.md` | +| Web token implementation | `apps/web/src/app/globals.css` | | Font loading & variables | `apps/web/src/app/layout.tsx` | | shadcn config | `apps/web/components.json` | | Core UI primitives | `apps/web/src/components/ui/*.tsx` | @@ -23,8 +20,7 @@ files directly: | Storybook canvas | `apps/storybook/.storybook/preview.ts` and `storybook.css` | | Mobile tokens | `apps/mobile/src/global.css` | -If a token or component already exists, **use it**. Do not reintroduce a -parallel system. +If a compliant token or component already exists, **use it**. Do not reintroduce a parallel system. If existing code conflicts with `DESIGN.md`, report or fix the drift rather than copying it. ## Register @@ -62,15 +58,18 @@ token (e.g. `bg-background`, `text-foreground`, `border-border`) over hex. | Token | Role | |---|---| -| `background` | Page/body surface. Near-black `oklch(0.145 0 0)`. | -| `foreground` | Default text. Near-white `oklch(0.985 0 0)`. | -| `card`, `popover` | Elevated dark surface `oklch(0.205 0 0)`. | -| `card-foreground` | Text on card. | -| `primary` | Brand yellow-green primary CTA token. | -| `primary-foreground` | Near-black text on primary yellow-green. | -| `secondary`, `muted`, `accent` | Mid-dark surfaces `oklch(0.269 0 0)` for chips, hovers. | -| `muted-foreground` | Secondary text `oklch(0.708 0 0)`. | -| `border`, `input`, `ring` | Hairline borders and focus rings. | +| `background` | Alias of `surface.background` (`#151515`) for the page/body canvas. | +| `foreground` | Alias of `foreground.default` (`#FAFAFA`). | +| `card` | Alias of `surface.raised` (`#202020`). | +| `popover` | Alias of `surface.overlay` (`#333333`). | +| `card-foreground`, `popover-foreground` | Default foreground on those surfaces. | +| `primary` | Brand yellow-green primary CTA token (`#F7F586`). | +| `primary-foreground` | Near-black text on primary (`#1F1F1F`). | +| `secondary` | Alias of `surface.overlay`; neutral action surface. | +| `muted` | Alias of `surface.raised`; de-emphasized region. | +| `accent` | Alias of `surface.hover`; interaction hover state. | +| `muted-foreground` | Alias of `foreground.muted` (`#A3A3A3`). | +| `border`, `input`, `ring` | Default border, strong input border, and brand focus ring. | | `destructive` | Red error/danger state. | | `sidebar-*` | Sidebar app-shell tokens. | | `chart-1`..`chart-5` | Data viz palette. | @@ -79,9 +78,11 @@ token (e.g. `bg-background`, `text-foreground`, `border-border`) over hex. | Token | Value | Use | |---|---|---| -| `--brand-primary` / `brand-primary` | `oklch(95% 0.15 108)` (electric yellow-green) | Alias of primary for brand roles | -| `--color-kilo-gray` | `oklch(0.24 0.007 1)` | Kilo-branded neutral surface | -| `--color-kilo-gray-lighter` | Derived via `oklch(from ... calc(l + 0.1) c h)` | Paired with `kilo-gray` | +| `--brand-primary` / `brand-primary` | `#F7F586` | Alias of primary for brand roles | +| `--brand-primary-hover` | `#E6E475` | Primary hover | +| `--brand-primary-ring` | `#F7F58659` | Brand focus ring | +| `--color-kilo-gray` | `surface.raised` (`#202020`) | Compatibility alias | +| `--color-kilo-gray-lighter` | `surface.overlay` (`#333333`) | Compatibility alias | | `--ease-out-strong` | `cubic-bezier(0.23, 1, 0.32, 1)` | Preferred easing for transitions | ### Primary action color @@ -91,16 +92,22 @@ semantic `primary` token and `--brand-primary` alias: | Role | Value | |---|---| -| Background | `oklch(95% 0.15 108)` (`#EDFF00`-ish) | -| Hover | Slightly darker yellow-green | -| Text | Near-black via `primary-foreground` | -| Focus ring | Low-alpha yellow-green / semantic `ring` | +| Background | `#F7F586` via `primary` / `brand-primary` | +| Hover | `#E6E475` via `primary-hover` / `brand-primary-hover` | +| Text | `#1F1F1F` via `primary-foreground` | +| Focus ring | `#F7F58659` via `ring` / `brand-primary-ring` | Use it for the main action on a surface, exactly once. Blue is no longer a primary CTA color; treat hardcoded `#2B6AD2` buttons as legacy drift and migrate them to semantic `primary` when the owning surface is updated. Blue remains acceptable for inline links and historical references only. +## Surface and Domain Tokens + +Use the six-role surface ladder exactly: `surface.inset` for terminal and recessed regions, `surface.background` for canvas, `surface.raised` for cards and persistent chrome, `surface.overlay` for floating UI, `surface.hover` for hover, and `surface.selected` for selected neutral states. + +Status domain assignments are fixed: Cloud blue, VS Code purple, CLI gray, Slack teal, Agent Manager orange, success green, warning yellow, destructive red. Do not rename teal to emerald or gray to zinc. Use syntax tokens only on code-oriented surfaces and dedicated diff text/surface pairs with non-color `+`/`-` cues. + ## Brand Accent Discipline The yellow-green primary is load-bearing precisely because it is rare. @@ -126,38 +133,30 @@ Font loading is in `apps/web/src/app/layout.tsx`: | Family | CSS variable | Use | |---|---|---| -| Inter | `--font-sans` | Default UI text | -| Roboto Mono | `--font-mono` | Code, identifiers, metadata | +| Inter | `--font-sans-loaded` / Tailwind `font-sans` | Default UI text | +| Roboto Mono | `--font-mono-loaded` / Tailwind `font-mono` | Code, identifiers, metadata | | JetBrains Mono | `--font-jetbrains` | Terminal-like and code-editor surfaces (`.font-jetbrains`) | -Known issue to be aware of (do not fix casually): `globals.css` currently -maps Tailwind's font tokens to `--font-geist-sans` / `--font-geist-mono`, -while `layout.tsx` defines `--font-sans` / `--font-mono`. This means the -Tailwind `font-sans` / `font-mono` utilities may fall back to the browser -default unless the element consumes `--font-sans` directly through the -`` variable. If you are asked to fix this, raise it as a focused -design-system cleanup PR rather than bundling it into an unrelated change. +`globals.css` maps Tailwind font tokens to the variables loaded by `layout.tsx`. Do not add per-component font fallbacks. Type scale rules for product UI: -- Prefer fewer sizes with stronger hierarchy. Do not stack 14/15/16/17. -- Common sizes used in the codebase: `text-xs`, `text-sm`, `text-base`, - `text-lg`, `text-3xl` (logo wordmark). -- Use `font-medium` for buttons/controls, `font-bold` for logos and - top-level page titles. +- Prefer canonical utilities: `type-title`, `type-heading`, `type-body-lg`, `type-body`, `type-label`, `type-eyebrow`, and `type-code`. +- Do not stack near-duplicate sizes or replace exact typography roles with arbitrary Tailwind combinations. +- Use `type-label` for buttons and controls, `type-title` for top-level page titles, and existing lockup styling for logos. - Use `tabular-nums` for billing, usage counters, metrics, and anything that aligns in columns. ## Shape and Radius -Base radius: `--radius: 0.625rem` in `globals.css`. Derived tokens: +Use the exact radius contract: | Token | Value | Typical use | |---|---|---| -| `--radius-sm` | `calc(var(--radius) - 4px)` | Tight inline chips | -| `--radius-md` | `calc(var(--radius) - 2px)` | Buttons, inputs | -| `--radius-lg` | `var(--radius)` | Popovers, medium containers | -| `--radius-xl` | `calc(var(--radius) + 4px)` | Cards, dialogs | +| `--radius-sm` | `4px` | Tight inline chips | +| `--radius-md` | `8px` | Buttons, inputs | +| `--radius-lg` | `10px` | Popovers, medium containers | +| `--radius-xl` | `14px` | Cards, dialogs | | (pill) | `rounded-full` | Badges, avatars, status pills | Follow existing shadcn primitives. Buttons/inputs `rounded-md`, cards @@ -167,8 +166,8 @@ Follow existing shadcn primitives. Buttons/inputs `rounded-md`, cards The app-shell rhythm in the current codebase: -- Controls are compact: `h-8` (sm), `h-9` (default), `h-10` (lg). -- Icons in controls are `size-4`. +- Controls are compact: `h-8` (sm), `h-control-default` / 36px (default), `h-10` (lg). Touch surfaces use `h-control-touch` or `size-control-touch` for 44px targets. +- Icons in controls are usually `size-4`; compact/status icons use `size-icon-sm` (14px). - Topbars are `h-14`. - Cards use `p-6` for header/content/footer, `gap-1.5` between title and description. diff --git a/.agents/skills/kilo-design/reference/motion-design.md b/.agents/skills/kilo-design/reference/motion-design.md index 00a973bb1c..13718006a0 100644 --- a/.agents/skills/kilo-design/reference/motion-design.md +++ b/.agents/skills/kilo-design/reference/motion-design.md @@ -20,8 +20,7 @@ Kilo motion is **purposeful and subtle** in product UI, with occasional `pulse-glow` / `animate-pulse-once`, `pulse-opacity`, `pulse-opacity-dim`. Reuse these instead of inventing new glow/pulse effects. -- Brand accent color for glow: `rgba(237, 255, 0, ...)` mirrors - `--brand-primary`. +- Brand glow uses `--brand-primary-ring` (`#F7F58659`) or alpha derived from `--brand-primary` (`#F7F586`). Never copy legacy `rgba(237, 255, 0, ...)` values. ### Kilo-specific motion rules diff --git a/.agents/skills/kilo-design/reference/spatial-design.md b/.agents/skills/kilo-design/reference/spatial-design.md index 0c7f034891..a412cf6ef6 100644 --- a/.agents/skills/kilo-design/reference/spatial-design.md +++ b/.agents/skills/kilo-design/reference/spatial-design.md @@ -17,8 +17,7 @@ app shell with marketing-scale spacing. - Cards use `p-6` for header/content/footer, `gap-1.5` between card title and description (`apps/web/src/components/ui/card.tsx`). - App topbars run at `h-14`; avoid arbitrary topbar heights. -- Controls stay compact: `h-8` (sm), `h-9` (default), `h-10` (lg). Match - this rhythm when adding new interactive elements. +- Controls stay compact: `h-8` (sm), `h-control-default` / 36px (default), `h-10` (lg). Use `h-control-touch` or `size-control-touch` for 44px touch targets. - Mobile (React Native) has its own safe-area behavior — use the tokens in `apps/mobile/`, not web-only `env(safe-area-inset-*)`. @@ -28,11 +27,10 @@ Kilo defines a radius scale: | Token | Value | Use | |---|---|---| -| `--radius` | `0.625rem` | Base | -| `--radius-sm` | `calc(var(--radius) - 4px)` | Tight inline chips | -| `--radius-md` | `calc(var(--radius) - 2px)` | Buttons, inputs | -| `--radius-lg` | `var(--radius)` | Popovers, medium containers | -| `--radius-xl` | `calc(var(--radius) + 4px)` | Cards, dialogs | +| `--radius-sm` | `4px` | Tight inline chips | +| `--radius-md` | `8px` | Buttons, inputs | +| `--radius-lg` | `10px` | Popovers, medium containers | +| `--radius-xl` | `14px` | Cards, dialogs | | (full) | `rounded-full` | Badges, avatars, status pills | Do not introduce new radius values. diff --git a/.agents/skills/kilo-design/reference/typography.md b/.agents/skills/kilo-design/reference/typography.md index 76877d4bb0..760f585cc0 100644 --- a/.agents/skills/kilo-design/reference/typography.md +++ b/.agents/skills/kilo-design/reference/typography.md @@ -24,24 +24,16 @@ Kilo-specific rules: billing, usage counters, tables, KPIs, timers. - **Disable code ligatures** (`font-variant-ligatures: none;`) only on surfaces where glyph-accurate code matters (terminals, diff views). -- **Dark-first line-height bump.** Kilo's default theme is dark. Light text - on dark reads as lighter weight — prefer the upper end of `line-height` - ranges (1.55–1.65 for body). -- Logo wordmark is `text-3xl font-bold`; topbars/pages derive their scale - from there. -- Known token mismatch: `globals.css` maps Tailwind to `--font-geist-*` - variables that no longer exist. `font-sans` / `font-mono` utilities may - fall back to system fonts until this is fixed. For now, rely on the font - variables Inter/Roboto Mono apply via the `` classList in - `layout.tsx`. Do not paper over this mismatch per component; it is a - design-system issue. +- **Use exact role metrics.** `type-title`, `type-heading`, `type-body-lg`, `type-body`, `type-label`, `type-eyebrow`, and `type-code` implement `DESIGN.md`; do not independently bump line-height or weight. +- Page titles use `type-title` (`1.5rem / 600 / 1.2`). Logo lockups may retain their existing brand-specific styling. +- `globals.css` maps `font-sans` and `font-mono` to the variables loaded by `layout.tsx`. Do not add per-component font fallbacks. Absolute rejects in Kilo product UI: - New font families outside the three listed above. - Gradient text. - ALL-CAPS body copy (short labels/eyebrows OK with added tracking). -- Font sizes not on the Tailwind scale. +- Font sizes outside canonical `type-*` utilities or an approved brand/marketing scale. - Fluid `clamp()` in product UI. --- @@ -78,9 +70,7 @@ and commit. Do not mix multiple scales. Cap body width in the 45–75ch band (`max-width: 65ch`). Narrow columns need tighter leading; wide columns need more. -**Dark mode compensation.** Light text on dark reads lighter than dark on -light. Bump line-height by 0.05–0.1, add a trace of letter-spacing (0.01em), -and step body weight up one notch if the text looks thin. +**Dark mode compensation.** Light text on dark can read lighter than dark on light. Kilo's canonical type roles already account for product density. Do not alter their line-height, tracking, or weight per component; propose a contract change if readability testing shows a systemic issue. **Paragraph rhythm.** Use either space between paragraphs or first-line indent. Never both. Product UI uses space. @@ -173,15 +163,13 @@ to `0.12em`). ## Typography System Architecture -Name tokens semantically (`--text-body`, `--text-heading`), not by value -(`--font-size-16`). In Kilo, prefer Tailwind's `text-*` scale and the -`--font-sans` / `--font-mono` / `--font-jetbrains` variables directly. +Name tokens semantically, not by value. In Kilo product UI, prefer canonical `type-*` utilities. Use `font-sans`, `font-mono`, or `.font-jetbrains` only when a complete role utility does not apply. ## Accessibility - **Never disable zoom.** `user-scalable=no` breaks accessibility. - **Use `rem`/`em` for font sizes.** Never `px` for body text. -- **Minimum 16px body text.** Smaller than this fails WCAG on mobile. +- **Mobile readability.** Use the `type-body-lg` utility for long-form mobile reading. Keep form controls at 16px where needed to prevent browser zoom. The canonical compact product `body` role remains 14px. - **Adequate touch targets.** Text links need padding or line-height that yields a 44px+ tap target. diff --git a/AGENTS.md b/AGENTS.md index 67af245796..191eb43b3c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -44,7 +44,7 @@ Target a specific test file: `pnpm test -- `. Run tests for a specific ser ## apps/web UI Work -When editing UI files in `apps/web` — React components, pages, layouts, or styles (`.tsx`/`.css`) — use the `/kilo-design` skill. +When editing UI files in `apps/web` — React components, pages, layouts, or styles (`.tsx`/`.css`) — use the `kilo-design` skill. ## Coding Standards diff --git a/DESIGN.md b/DESIGN.md index ceed1d04a9..bfc8397b24 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -1,134 +1,147 @@ --- -version: alpha +version: 0.2.0 name: Kilo Cloud -description: Dark-first, utilitarian developer surface for Kilo Code — the open-source AI coding agent. Near-black backgrounds, white-at-low-alpha borders. The Kilo yellow-green is the primary action color — it's the brand and the CTA at once. Blue is a legacy link/inline-accent role only. -colors: - # Foundations — the near-black ladder - background: '#121212' - surface: '#2B2B2B' - surface-raised: '#333333' - muted: '#3D3D3D' - - # Foreground — the white ladder - foreground: '#FAFAFA' - foreground-muted: '#A3A3A3' - foreground-subtle: '#7A7A7A' - foreground-on-red: '#FFFFFF' - - # Borders — the most characteristic move (white at low alpha) - border: '#FFFFFF1A' # 10% — default - border-strong: '#FFFFFF2E' # 18% — inputs, focused chrome - input-bg: '#FFFFFF0A' - - # Primary action — the Kilo yellow-green. Brand and CTA in one. - primary: '#EDFF00' - primary-hover: '#D6E600' - primary-ring: '#EDFF0059' # 35% alpha brand glow - on-primary: '#1F1F1F' # near-black for AA contrast on yellow - - # Secondary action — dark-gray, quiet, the workhorse against cards. - secondary: '#3D3D3D' - secondary-hover: '#4D4D4D' - on-secondary: '#FAFAFA' - - # Brand accent — alias of primary. Same swatch, used in atmospheric roles - # (logo tile, focus rings, text selection, agent glow, status lights). - brand: '#EDFF00' - brand-dim: '#B8C800' - on-brand: '#1F1F1F' - - # Link / inline-accent blue — legacy role only. Never a button background. - link: '#3B82F6' - link-hover: '#60A5FA' - - # Status palette — every status follows the same translucent /20 pattern. - # The 500-step is the swatch; consumers compose with /20 bg + /20 ring + 400 text. - blue-500: '#3B82F6' # Cloud / neutral default / link role - blue-400: '#60A5FA' - purple-500: '#A855F7' # VS Code Extension - purple-400: '#C084FC' - emerald-500: '#10B981' # Slack - emerald-400: '#34D399' - zinc-500: '#71717A' # CLI - zinc-400: '#A1A1AA' - orange-500: '#F97316' # Agent Manager - orange-400: '#FB923C' - green-500: '#22C55E' # Success / "new" - green-400: '#4ADE80' - yellow-500: '#EAB308' # Warnings - yellow-400: '#FACC15' - red-500: '#EF4444' # Destructive - red-400: '#F87171' +description: Dark-first, utilitarian developer surface for Kilo Code. Near-black layered surfaces and low-alpha white borders carry hierarchy. Kilo yellow-green is both brand and primary action color. Blue is reserved for links and the Cloud status domain. +color: + brand: + primary: '#F7F586' + primaryHover: '#E6E475' + primaryRing: '#F7F58659' + foreground: '#1F1F1F' + + status: + blue300: '#93C5FD' + blue400: '#60A5FA' + blue500: '#3B82F6' + blue600: '#2563EB' + purple300: '#D8B4FE' + purple400: '#C084FC' + purple500: '#A855F7' + purple600: '#9333EA' + teal300: '#4CE7D7' + teal400: '#00D4C2' + teal500: '#00BAA9' + teal600: '#009689' + gray300: '#D4D4D8' + gray400: '#A1A1AA' + gray500: '#71717A' + gray600: '#52525B' + orange300: '#FDBA74' + orange400: '#FB923C' + orange500: '#F97316' + orange600: '#EA580C' + green300: '#86EFAC' + green400: '#4ADE80' + green500: '#22C55E' + green600: '#16A34A' + yellow300: '#FDD94A' + yellow400: '#FBC51C' + yellow500: '#F0A900' + yellow600: '#D28100' + red300: '#FCA5A5' + red400: '#F87171' + red500: '#EF4444' + red600: '#DC2626' + + surface: + inset: '#101010' + background: '#151515' + raised: '#202020' + overlay: '#333333' + hover: '#3A3A3A' + selected: '#454545' + + foreground: + default: '#FAFAFA' + muted: '#A3A3A3' + subtle: '#7A7A7A' + onSecondary: '#FAFAFA' + onDestructive: '#FFFFFF' + + border: + default: '#FFFFFF1A' + strong: '#FFFFFF2E' + inputBg: '#FFFFFF0A' + + syntax: + plain: '#E8E8E8' + comment: '#7A7A7A' + keyword: '#FF9AE2' + string: '#ECF58C' + number: '#F2B36B' + function: '#93E9F6' + type: '#00CEB9' + property: '#9CDCFE' + constant: '#C792EA' + operator: '#A3A3A3' + + diff: + addText: '#9BCD97' + addSurface: '#1A2919' + deleteText: '#FC533A' + deleteSurface: '#42120B' + +statusDomain: + cloud: blue + vscode: purple + cli: gray + slack: teal + agentManager: orange + success: green + warning: yellow + destructive: red typography: - display: - fontFamily: Inter - fontSize: 3rem - fontWeight: 700 - lineHeight: 1.15 - letterSpacing: '-0.015em' - h1: - fontFamily: Inter - fontSize: 1.875rem - fontWeight: 700 - lineHeight: 1.15 - letterSpacing: '-0.015em' - h2: + title: fontFamily: Inter fontSize: 1.5rem fontWeight: 600 - lineHeight: 1.3 + lineHeight: 1.2 letterSpacing: '-0.015em' - h3: + heading: fontFamily: Inter - fontSize: 1.25rem + fontSize: 1.125rem fontWeight: 600 - lineHeight: 1.3 - body: + lineHeight: 1.25 + letterSpacing: '-0.01em' + bodyLg: fontFamily: Inter - fontSize: 0.875rem + fontSize: 1rem fontWeight: 400 lineHeight: 1.5 - body-strong: + body: fontFamily: Inter fontSize: 0.875rem - fontWeight: 500 + fontWeight: 400 lineHeight: 1.5 label: fontFamily: Inter fontSize: 0.75rem fontWeight: 500 - lineHeight: 1.3 + lineHeight: 1.4 eyebrow: fontFamily: Inter fontSize: 0.6875rem - fontWeight: 600 - lineHeight: 1.3 - letterSpacing: '0.06em' + fontWeight: 500 + lineHeight: 1.2 + letterSpacing: '0.08em' + textTransform: uppercase code: fontFamily: Roboto Mono - fontSize: 0.8125rem - fontWeight: 400 - lineHeight: 1.5 - terminal: - fontFamily: Roboto Mono - fontSize: 0.8125rem + fontSize: 0.875rem fontWeight: 400 lineHeight: 1.5 - fontFeature: '"calt", "ss01"' -rounded: - none: 0 - sm: 6px +radius: + none: '0' + sm: 4px md: 8px lg: 10px xl: 14px full: 9999px spacing: - '0-5': 2px '1': 4px - '1-5': 6px '2': 8px '3': 12px '4': 16px @@ -137,254 +150,280 @@ spacing: '8': 32px '10': 40px '12': 48px + '0_5': 2px + '1_5': 6px components: - # Primary action — the yellow button. Brand and CTA in one. Earned, used once per surface. - button-primary: - backgroundColor: '{colors.primary}' - textColor: '{colors.on-primary}' - typography: '{typography.body-strong}' - rounded: '{rounded.sm}' + buttonPrimary: + backgroundColor: '{color.brand.primary}' + textColor: '{color.brand.foreground}' + typography: '{typography.label}' + radius: '{radius.md}' height: 36px padding: '0 14px' - button-primary-hover: - backgroundColor: '{colors.primary-hover}' - - # Secondary — dark-gray with white text + 10%-white border. The workhorse. - button-secondary: - backgroundColor: '{colors.secondary}' - textColor: '{colors.on-secondary}' - typography: '{typography.body-strong}' - rounded: '{rounded.sm}' + buttonPrimaryHover: + backgroundColor: '{color.brand.primaryHover}' + buttonPrimaryFocus: + ringColor: '{color.brand.primaryRing}' + + buttonSecondary: + backgroundColor: '{color.surface.overlay}' + textColor: '{color.foreground.onSecondary}' + borderColor: '{color.border.default}' + typography: '{typography.label}' + radius: '{radius.md}' height: 36px padding: '0 14px' - button-secondary-hover: - backgroundColor: '{colors.secondary-hover}' - - # Ghost — underlined white text, no chrome at rest. For inline links and table-row affordances. - button-ghost: - backgroundColor: 'transparent' - textColor: '{colors.foreground}' - rounded: '{rounded.sm}' + buttonSecondaryHover: + backgroundColor: '{color.surface.hover}' + + buttonGhost: + backgroundColor: transparent + textColor: '{color.foreground.default}' + typography: '{typography.label}' + radius: '{radius.md}' height: 36px - padding: '0 4px' - - # Destructive — red, only inside dialogs and confirms. - button-destructive: - backgroundColor: '{colors.red-500}' - textColor: '{colors.foreground-on-red}' - typography: '{typography.body-strong}' - rounded: '{rounded.sm}' + padding: '0 8px' + buttonGhostHover: + backgroundColor: '{color.surface.hover}' + + buttonDestructive: + backgroundColor: '{color.status.red500}' + textColor: '{color.foreground.onDestructive}' + typography: '{typography.label}' + radius: '{radius.md}' height: 36px padding: '0 14px' + buttonDestructiveHover: + backgroundColor: '{color.status.red600}' - # Card — the containing surface for almost everything in the dashboard. card: - backgroundColor: '{colors.surface}' - borderColor: '{colors.border}' - rounded: '{rounded.xl}' + backgroundColor: '{color.surface.raised}' + borderColor: '{color.border.default}' + radius: '{radius.xl}' padding: 24px - # Input — text fields, search, composer. input: - backgroundColor: '{colors.input-bg}' - textColor: '{colors.foreground}' - rounded: '{rounded.sm}' + backgroundColor: '{color.border.inputBg}' + textColor: '{color.foreground.default}' + borderColor: '{color.border.strong}' + radius: '{radius.md}' height: 36px padding: '0 12px' - # Status badge — the most characteristic micro-pattern in the system. - # Translucent fill + matching ring + brighter foreground text. - badge-status: - backgroundColor: '{colors.blue-500}' - textColor: '{colors.blue-400}' + badgeStatus: typography: '{typography.label}' - rounded: '{rounded.sm}' + radius: '{radius.full}' padding: '2px 8px' - # Brand badge — for the logo lockup and earned highlights. - badge-brand: - backgroundColor: '{colors.brand}' - textColor: '{colors.on-brand}' + badgeBrand: + backgroundColor: '{color.brand.primary}' + textColor: '{color.brand.foreground}' typography: '{typography.label}' - rounded: '{rounded.sm}' + radius: '{radius.full}' padding: '2px 8px' - # Sidebar — fixed-width, dense nav. sidebar: - backgroundColor: '{colors.surface}' - textColor: '{colors.foreground-muted}' + backgroundColor: '{color.surface.raised}' + textColor: '{color.foreground.muted}' width: 256px padding: '12px 8px' - # Topbar — sticky, single-breadcrumb chrome. topbar: - backgroundColor: '{colors.background}' - textColor: '{colors.foreground}' + backgroundColor: '{color.surface.background}' + textColor: '{color.foreground.default}' + borderColor: '{color.border.default}' height: 56px padding: '0 16px' - # Tooltip / popover. popover: - backgroundColor: '{colors.surface-raised}' - textColor: '{colors.foreground}' - rounded: '{rounded.md}' + backgroundColor: '{color.surface.overlay}' + textColor: '{color.foreground.default}' + radius: '{radius.lg}' padding: 12px - # Dialog / modal. dialog: - backgroundColor: '{colors.surface}' - textColor: '{colors.foreground}' - rounded: '{rounded.xl}' + backgroundColor: '{color.surface.raised}' + textColor: '{color.foreground.default}' + radius: '{radius.xl}' padding: 24px - # Terminal / agent atmospheric surface. terminal: - backgroundColor: '{colors.background}' - textColor: '{colors.foreground}' - typography: '{typography.terminal}' - rounded: '{rounded.lg}' + backgroundColor: '{color.surface.inset}' + textColor: '{color.syntax.plain}' + typography: '{typography.code}' + radius: '{radius.lg}' padding: 16px --- ## Overview -**Trustworthy infra tool, not a marketing site.** Kilo Cloud is the developer-facing web product around Kilo Code, an open-source AI coding agent that lives primarily as a VS Code / JetBrains extension. The cloud surface manages organizations, usage and billing, headless agent sessions, and developer ops. The aesthetic is **dark-first, near-black, utilitarian** — dense tables, calm chrome, low ornamentation. Speak to developers in second person, plain English, with concrete nouns. +**Trustworthy infrastructure tool, not a generic SaaS dashboard.** Kilo Cloud is the developer-facing product around Kilo Code. It manages organizations, usage and billing, agent sessions, and developer operations. Product UI is dark-first, compact, and utilitarian: dense tables, calm chrome, low ornamentation, and concrete language. + +The cloud-agent surface may use terminal typography, syntax color, a restrained brand focus glow, and inset surfaces. Elsewhere, utility takes precedence over decoration. + +**Three rules ground every screen.** -The single concession to atmosphere is the cloud-agent chat surface — terminal-styled mono, a thin yellow-green focus glow, glass on sticky chrome. Everywhere else: utility over delight. +1. **Build depth with the surface ladder.** Use `surface.background` for the app canvas, `surface.raised` for cards and shell chrome, `surface.overlay` for floating UI, and `surface.inset` for terminal or recessed regions. Use `surface.hover` and `surface.selected` only for interaction states. +2. **Use low-alpha white borders.** `border.default` is standard chrome; `border.strong` distinguishes inputs and emphasized boundaries. Do not introduce solid gray borders. +3. **Yellow acts; neutrals carry everything else.** `brand.primary` is both brand and primary action color. Use one primary action per surface. Blue is for inline links and the Cloud status domain, not button backgrounds. -**Three rules to ground every screen.** +## Color -1. **Never pure black, never a gradient.** Background is `#121212`. Cards step up to `#2B2B2B`. The lift comes from a one-step background change plus a 10%-white border, not from drop shadows or blur. -2. **Borders are white at low alpha.** This is the single most characteristic move. `#FFFFFF1A` on every card, `#FFFFFF2E` on every input. No solid grey borders. -3. **Yellow acts. Greys carry everything else.** The Kilo yellow-green (`#EDFF00`) is the primary action color — brand and CTA collapsed into one swatch. Use it exactly once per surface for the thing the user is here to do, and again atmospherically for the logo tile, focus ring, text selection, and agent-surface glow. Secondary actions are dark gray. Blue is a legacy link role only — never a button background. +### Surfaces -## Colors +The six surface tokens have fixed roles: -**Foundations are a four-step near-black ladder.** `background → surface → surface-raised → muted`. Compose UI by stacking surfaces against background; the visual hierarchy is built from value steps, not color shifts. Cards sit on background. Popovers sit on cards. Inputs sit inside cards but drop _down_ into translucency (`input-bg` is white-on-card at 4% — a recess, not a lift). +| Token | Value | Role | +|---|---|---| +| `surface.inset` | `#101010` | Terminal, code, and recessed regions | +| `surface.background` | `#151515` | App canvas | +| `surface.raised` | `#202020` | Cards, sidebar, dialogs, persistent chrome | +| `surface.overlay` | `#333333` | Popovers, dropdowns, tooltips | +| `surface.hover` | `#3A3A3A` | Pointer and ghost-control hover | +| `surface.selected` | `#454545` | Selected rows, active neutral controls | -- **`background` (`#121212`)** — the app canvas. Always behind everything. Never gradient, never patterned. -- **`surface` (`#2B2B2B`)** — cards, sidebar, dialogs, sticky chrome. The default container. -- **`surface-raised` (`#333333`)** — popovers, tooltips, menus. One step above cards. -- **`muted` (`#3D3D3D`)** — hover states on rows and ghost buttons. Inactive tab backgrounds. +Stack surfaces by role. Do not substitute arbitrary grays, gradients, or per-component surface colors. Floating UI may use a restrained shadow, but normal hierarchy comes from surface changes and borders. -**Foreground is a three-step white ladder.** Body text is near-white (`#FAFAFA`), not pure white — pure white vibrates against `#121212`. Use `foreground-muted` (`#A3A3A3`) for secondary text, captions, and metadata. `foreground-subtle` (`#7A7A7A`) is for disabled and tertiary copy only. +### Foreground and borders -**Borders carry the elevation.** White at 10% alpha for the default border, 18% for inputs and focused chrome. Because borders are translucent, they read correctly on every surface step without needing per-context overrides. Never use a solid grey for borders. +- `foreground.default` is default text. +- `foreground.muted` is secondary copy and metadata. +- `foreground.subtle` is tertiary or disabled copy. Confirm contrast before using it for essential information. +- `foreground.onSecondary` is text on neutral action surfaces. +- `foreground.onDestructive` is text on destructive fills. +- `border.default` is the standard 10%-white boundary. +- `border.strong` is the 18%-white emphasized boundary. +- `border.inputBg` is a recessed input fill, not a border color. -**Action hierarchy is colored, not sized.** +Never use color alone to communicate state. Pair status color with labels, icons, or other visible structure. -- **`primary` (`#EDFF00`)** — the Kilo yellow-green. The primary action color _and_ the brand mark — they're the same swatch. Used exactly once per surface for the thing the user is here to do (Create session, Save, Install, Continue). Hover darkens to `#D6E600` (not lighter, not translucent). The on-color is near-black (`#1F1F1F`); white text on yellow fails AA. -- **`secondary` (`#3D3D3D`)** — dark-gray with white text and a 10%-white border. The workhorse. Use freely. -- **`ghost`** — underlined white text, no chrome at rest. The decoration is the affordance: `text-decoration-color: rgba(255,255,255,0.35)` at rest, opaque on hover. For inline links, table-row actions, and dialog Cancel buttons. -- **`destructive` (`red-500`)** — red fill, white text. Only inside dialogs and confirm flows. Never on a primary listing screen. -- **`link` (`#3B82F6`)** — legacy blue, inline only. Used for links inside running prose. Never a button background, never a section accent. +### Brand and actions -**Status colors follow one rigid pattern.** Every status badge is `bg-{color}-500/20 text-{color}-400 ring-1 ring-{color}-500/20`. The translucent fill + matching ring + brighter foreground is the system's most recognizable micro-pattern. Color assignments are fixed by domain, not by mood: +`brand.primary` (`#F7F586`) is scarce and load-bearing. Reserve it for the logo, one primary CTA per surface, and deliberate brand moments. Use `brand.foreground` (`#1F1F1F`) on primary fills. Hover darkens to `brand.primaryHover` (`#E6E475`). Keyboard focus uses `brand.primaryRing` (`#F7F58659`) or the semantic focus-ring token supplied by the implementation. -| Color | Domain | +Secondary actions use neutral surfaces and `foreground.onSecondary`. Ghost actions have no fill at rest and use `surface.hover` on hover. Destructive actions use red only when semantics are destructive; prefer reversible undo flows over confirmation dialogs when possible. + +### Status domains + +Status colors are assigned by domain, never by mood: + +| Domain | Family | |---|---| -| Blue | Cloud sessions (neutral default) | -| Purple | VS Code Extension | -| Zinc | CLI | -| Emerald | Slack | -| Orange | Agent Manager | -| Green | Success, "new" badges | -| Yellow | Warnings | -| Red | Destructive, errors | +| Cloud | Blue | +| VS Code | Purple | +| CLI | Gray | +| Slack | Teal | +| Agent Manager | Orange | +| Success | Green | +| Warning | Yellow | +| Destructive | Red | -Do not invent new status hues. Do not use status colors outside this badge pattern (e.g. don't use `red-500` as a button background — use `destructive` semantics through the dialog system). +Use the 500 step as the base swatch, 400 for dark-surface foreground emphasis, 300 for lighter emphasis, and 600 for darker interaction or high-emphasis states. Status badges may compose a low-alpha 500 background and border with 400 text. Preserve a non-color cue and verify contrast in context. -## Typography +Do not invent status hues or substitute `emerald` for teal or `zinc` for gray. Blue remains acceptable for inline links, but not primary action fills. -**Two faces, with discipline.** Inter for all UI. Roboto Mono for code, terminal output, agent tool readouts, dollar amounts in dense tables, and timestamps. Never mix mono into prose UI for emphasis — emphasis is weight (`500`/`600`), not face. +### Syntax and diffs -**Default body is `14px / 1.5`.** This is the floor for everything that isn't a heading or a label. Page titles use `tracking-tight` (`-0.015em`) — Inter at 24px+ is too wide-set without it. Eyebrows are uppercase + `tracking-wide` (`0.06em`). +Use syntax tokens only in code, terminal, and editor-like surfaces: + +- `syntax.plain` for unclassified source text. +- `syntax.comment` for comments and de-emphasized code. +- `syntax.keyword`, `syntax.string`, `syntax.number`, `syntax.function`, `syntax.type`, `syntax.property`, `syntax.constant`, and `syntax.operator` for their matching grammar scopes. + +Diffs use `diff.addText` on `diff.addSurface` and `diff.deleteText` on `diff.deleteSurface`. Always retain `+`/`-` markers or equivalent structure so additions and deletions do not depend on color alone. + +## Typography -**Heading scale is compact.** This is a dashboard, not a marketing page. Page-level h1 is `30px / 700`. The `display` size (`48px`) is reserved for empty-state hero moments and onboarding — not normal app chrome. +Use Inter for UI and Roboto Mono for code, identifiers, terminal output, timestamps, and dense numerical data. Do not introduce another family. JetBrains Mono may remain on existing editor-specific surfaces, but it is not part of this token contract. -**Casing is sentence case for everything user-visible.** Buttons, nav, section titles, badges. Title Case is wrong. The exceptions are the eyebrow style (uppercase tracking-wide) and the rare role badge (`KILO ADMIN`). +The product scale is intentionally compact: -**Numbers in dense data lean mono.** Dollar amounts, latencies, token counts, timestamps in the audit log — all Roboto Mono. This is functional, not decorative: mono digits align across rows. +- `title`: page titles, `24px / 600 / 1.2`. +- `heading`: section and card headings, `18px / 600 / 1.25`. +- `bodyLg`: lead or emphasized prose, `16px / 400 / 1.5`. +- `body`: default product copy, `14px / 400 / 1.5`. +- `label`: controls, compact metadata, and badges, `12px / 500 / 1.4`. +- `eyebrow`: short uppercase category labels, `11px / 500 / 1.2`, with `0.08em` tracking. +- `code`: code and terminal text, `14px / 400 / 1.5`. -## Layout +Use sentence case for user-visible copy. Eyebrows are the exception because the token explicitly transforms them to uppercase. Use `tabular-nums` for values aligned in columns. Do not use monospace as prose emphasis. -**Shell is sidebar + main, both dark, with a sticky topbar.** Sidebar is fixed `256px` expanded, `48px` icon-only collapsed. The toggle is `cmd/ctrl+B`. State persists via cookie. +## Layout and spacing -- **Topbar** — `56px` tall, `border-b` (the 10%-white border), single breadcrumb on the left, sidebar toggle on the right. Sticky. -- **Page content** — `w-full flex-1` under the topbar. Page-level padding is `24px`. -- **Card stacks** — dashboards are vertical stacks of `Card` components with `gap-y-6` (`24px`). No multi-column page-level grids; multi-column lives _inside_ a card. +Use the supplied 4px-based spacing ladder. `spacing.2`, `spacing.3`, `spacing.4`, and `spacing.6` cover most product layout. `spacing.8`, `spacing.10`, and `spacing.12` create section separation. `spacing.0_5` and `spacing.1_5` are for tight optical adjustments and compact component internals, not general page layout. -**Spacing is a 4px ladder.** Pull from the `spacing` scale; do not invent intermediate values. `2/3/4/6` (8/12/16/24px) covers ~90% of layout decisions. `8/10/12` (32/40/48px) is for section gaps and empty-state breathing room. Anything tighter than `2` is a bug — except for `0-5` (2px) which exists for icon-text optical alignment. +- Topbar height is `56px`; use `border.default` along its lower edge. +- Expanded sidebar width is `256px`; use the existing sidebar primitive for responsive collapse. +- Default page padding and card padding are `24px`. +- Default controls are `36px` tall; small and large variants may use `32px` and `40px`. +- Table rows target `48px` in dense desktop UI. +- Prefer `gap` over ad hoc margins. +- Never nest cards. Use spacing, dividers, headings, or inset regions for internal grouping. -**Density is compact.** Buttons are `36px` tall by default, `32px` for the small variant. Inputs match buttons at `36px`. Table rows are `48px`. Cards get `24px` of inner padding. This is a tool that admins live in for hours; sparseness wastes their time. +Product UI must reflow at narrow widths. Test around 375px, 768–1024px, and 1440px. Required actions cannot depend on hover. On touch surfaces, preserve at least a 44px target even when the visual control is compact. -## Elevation & Depth +## Shape -**Lift is a value step, not a shadow.** Cards aren't elevated by drop-shadow — they're elevated by being one step lighter than background plus a 10%-white border. This is the system's signature. Reach for shadows only when an element genuinely floats above the page (popover, tooltip, dialog). +Use radius by role: -- **`shadow-xs`** — used on inputs to suggest a recessed depth. Whisper-soft. -- **`shadow`** — used on default cards in rare cases (focus, drag). -- **`shadow-md`** — popovers, tooltips, dropdowns. -- **`shadow-lg`** — dialogs over the `bg-black/80` overlay. +- `radius.none` for edge-to-edge or intentionally square regions. +- `radius.sm` (`4px`) for tight chips and compact inline elements. +- `radius.md` (`8px`) for buttons and inputs. +- `radius.lg` (`10px`) for popovers and medium containers. +- `radius.xl` (`14px`) for cards and dialogs. +- `radius.full` for badges, avatars, and status pills. -**Glass is reserved for sticky chrome.** `backdrop-blur-xl` only on the topbar lockup or persistent overlays. Never on cards or content surfaces — translucent content surfaces become unreadable in dense tables. +Do not introduce one-off radii. Follow existing shadcn primitives when their semantic radius already matches these roles. -**The agent surface gets one extra move: the brand glow.** A thin yellow-green inner shadow on focused composers and live-streaming chrome (`0 0 24px {colors.brand}/35%`). Does not appear in dashboards, billing, or admin. +## Components and interaction -## Shapes +**Buttons.** Primary uses `brand.primary` with `brand.foreground`, once per surface. Secondary uses `surface.overlay`, `foreground.onSecondary`, and `border.default`. Ghost uses no fill at rest and `surface.hover` on hover. Destructive uses `status.red500`, darkening to `status.red600`. Do not scale buttons on press. -**Five radii, applied by role.** +**Cards.** Use `surface.raised`, `border.default`, `radius.xl`, and `24px` padding. Cards represent distinct content or interaction boundaries, not every grouping. -- **`rounded.sm` (6px)** — controls. Buttons, inputs, badges, status pills, menu items. -- **`rounded.md` (8px)** — popovers, dropdowns, secondary surfaces. -- **`rounded.lg` (10px)** — cards in non-dashboard contexts (auth, marketing). -- **`rounded.xl` (14px)** — the dashboard `Card`. The most common surface. -- **`rounded.full`** — avatars and the rare pill nav. +**Inputs.** Use `border.inputBg`, `border.strong`, `radius.md`, and visible labels. Focus must remain visible. Errors pair a red boundary or icon with explanatory text connected through `aria-describedby`. -Never round above `xl` for a card; never round below `sm` for a control. The system gets its calm cohesion from radius consistency. +**Status badges.** Use the fixed domain mapping, a full radius, and `typography.label`. Include text or an icon so meaning survives color-vision differences. -## Components +**Sidebar.** Use `surface.raised`, sidebar semantic tokens where available, and `foreground.muted` for inactive items. Active rows use `surface.selected`; hover uses `surface.hover`. Use the existing responsive sidebar or Sheet behavior instead of creating another mobile navigation tree. -The token table above defines the canonical surface. Notes on application: +**Topbar.** Use `surface.background`, `border.default`, and a 56px height. Keep primary page actions in page content rather than persistent chrome. -**Buttons.** `button-primary` is the yellow CTA with near-black text — one per surface. `button-secondary` is the dark-gray workhorse on cards. `button-ghost` is underlined white text with no chrome at rest — for inline links, table-row actions, and dialog Cancel. `button-destructive` is red, only inside dialogs. Press states are not represented by transforms — buttons don't shrink or scale. Disabled is `opacity-50 + pointer-events-none`. Focus is the brand-glow ring (`#EDFF00` at 35% alpha) on `:focus-visible` only — never on hover. +**Overlays.** Popovers and menus use `surface.overlay`; dialogs use `surface.raised`. Build them with existing Radix and shadcn primitives for focus trapping, keyboard navigation, dismissal, portals, and stacking. -**Card.** Always `surface` background, always 10%-white border, always `rounded.xl`, always `24px` padding. The header gets `pb-2` (less bottom padding) so the title sits closer to its content. +**Terminal and code.** Use `surface.inset`, `typography.code`, and the syntax palette. Disable ligatures where exact glyph representation matters. Diff views use the dedicated diff tokens. -**Input.** Translucent fill (`input-bg`), 18%-white border, `rounded.sm`, `36px` tall. Focus state adds the brand yellow-green halo via `:focus-visible` — never via hover. Errors flip the border to `destructive` and surface a description below. +Every interactive component must account for default, hover, focus-visible, active, disabled, loading, error, and success states where relevant. Hover is supplementary. Focus indicators need at least 3:1 contrast against adjacent colors and must not be removed without a replacement. -**Status badges.** The translucent /20 pattern is non-negotiable. Layout: `gap-1` between icon and label, label in sentence case, icon in `size-3` (12px) — smaller than other inline icons because the badge itself is small. +## Motion -**Sidebar.** Fixed `256px`. Section headers are eyebrow-style uppercase + tracking-wide. Active row gets `accent` background, inactive rows get `accent` only on hover. Icon at `size-4`, label at `body-strong`. The Kilo logo lives at the top in a `40×40` brand tile. +Product motion is short and functional. Use opacity and transform transitions around 100–200ms for direct feedback and 200–300ms for overlays or state changes. Reuse the established strong ease-out curve. Avoid bounce, elastic motion, and casual animation of layout properties. -**Topbar.** Single breadcrumb, no logo (the logo lives in the sidebar). Right side gets the sidebar toggle, a search omnibox, and an avatar. Never put primary actions in the topbar — those belong in the page body. +Brand flourishes belong only in deliberate brand moments. Respect `prefers-reduced-motion`; preserve function while removing nonessential movement. Use existing Radix/shadcn transitions for dialogs, dropdowns, sheets, and tooltips. -**Dialog.** `bg-black/80` overlay, centered card, max width `28rem` for confirms / `40rem` for forms. Close button is a ghost icon button in the top-right. Primary action is on the right of the footer, secondary on the left of _that_; cancel is a ghost button on the left of the footer. +## Voice -**Terminal / agent.** `background` color (not `surface` — terminals stay flush with the canvas), Roboto Mono, `text-sm`. Streaming output is rendered with a blinking caret. Tool-call cards inside the chat are `surface` cards with a 12-px icon + tool name eyebrow + a one-line summary. +Kilo voice is clear, technical, calm, and direct. Use concrete verbs and specific nouns. Buttons use verb + object (`Save changes`, `Create workspace`, `Delete project`) rather than `Submit`, `OK`, or `Yes`. Error copy states what happened and what the user can do next. Do not use hype, jokes in errors, emoji in product chrome, or inconsistent terminology. -## Do's and Don'ts +## Do and don't **Do** -- **Stack value, not color.** Build hierarchy by stepping `background → surface → surface-raised`, not by tinting. -- **Use the brand yellow for the primary action.** One per surface. Earn it. -- **Use translucent borders everywhere.** White at 10% / 18% — never solid grey. -- **Use Roboto Mono for numbers in dense data.** Tables, billing, audit logs, latencies. -- **Stick to sentence case for all user-visible copy.** Including buttons. -- **Use Lucide for every icon.** 1.5–2px stroke, 16px in buttons / badges, 16–20px elsewhere. -- **Apply the translucent /20 pattern for every status badge.** No exceptions. -- **Let cards lift via border + value step.** Reach for shadows only for floating chrome. +- Use semantic implementation tokens that map to this contract before raw hex values. +- Build hierarchy with the six-role surface ladder and low-alpha borders. +- Keep brand yellow-green scarce and reserve it for primary action and brand roles. +- Use fixed domain mappings for statuses. +- Use syntax and diff colors only on code-oriented surfaces. +- Use Inter for UI, Roboto Mono for code and aligned technical data. +- Preserve keyboard, screen-reader, reduced-motion, touch, and responsive behavior. **Don't** -- **Don't use pure black or gradients for backgrounds.** Always `#121212`, always flat. -- **Don't put more than one yellow button on a screen.** If you feel the urge, the second one is a `button-secondary`. The yellow has to stay scarce to keep its meaning. -- **Don't use blue as a button background.** Blue is reserved for inline links inside running prose. The primary action is yellow. -- **Don't introduce new status hues.** The eight assigned colors cover the entire taxonomy. -- **Don't use emoji in product chrome.** Lucide only. Emoji are reserved for user-authored content. -- **Don't add per-element drop shadows to cards.** The border + value step does the lift. -- **Don't mix Inter and Roboto Mono in the same line of running text.** Mono in tables, code, terminals — never as inline emphasis. -- **Don't use Title Case anywhere user-facing.** Sentence case throughout. -- **Don't tint borders to convey state.** State changes background (`muted` on hover), not the border color. +- Use pure black, gradients, or arbitrary surface grays. +- Put multiple yellow primary buttons on one surface. +- Use blue as a primary button background. +- Rename teal to emerald or gray to zinc in the token contract. +- Invent status colors, spacing values, radii, or typography roles. +- Nest cards or use shadows as the default source of depth. +- Depend on color, hover, placeholders, or icon shape alone to convey meaning. diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css index 515d8d5b59..a8ed1c0d5e 100644 --- a/apps/web/src/app/globals.css +++ b/apps/web/src/app/globals.css @@ -424,15 +424,15 @@ @keyframes pulse-glow { 0% { transform: scale(1); - box-shadow: 0 0 0 rgba(237, 255, 0, 0); + box-shadow: 0 0 0 transparent; } 50% { transform: scale(1.02); - box-shadow: 0 0 20px rgba(237, 255, 0, 0.4); + box-shadow: 0 0 20px color-mix(in srgb, var(--brand-primary) 40%, transparent); } 100% { transform: scale(1); - box-shadow: 0 0 20px rgba(237, 255, 0, 0.3); + box-shadow: 0 0 20px color-mix(in srgb, var(--brand-primary) 30%, transparent); } }