--- version: alpha name: patchline-design description: "A near-black terminal panel built around a #0b0d10 canvas and #e6e6e0 text, with git-diff green (#3ddc84) and red (#ff5f56) as the only chromatic accents. JetBrains Mono carries every literal code moment at weight 600; Inter carries the surrounding prose. The system reads as a working developer tool, not a marketing page, quiet until the diff animates in." --- ## Brand Positioning Patchline is for engineers who review code every day and are tired of review tools that perform "delight" at them. It exists because most code-review UI borrows SaaS marketing chrome (gradients, mascots, confetti on merge) that has nothing to do with reading a diff. Patchline's bet: a review tool should look like the terminal the reviewer already trusts, and the only motion on the page should be the same motion a real review has, lines resolving from red to green. Every visual decision below serves that one bet. If a component doesn't help someone read a diff faster or doesn't come from a real developer-tool interaction (nav, form, table, status), it doesn't belong in this system. colors: accent: "#3ddc84" accent-alt: "#ff5f56" ink: "#e6e6e0" ink-muted: "#8a8f98" canvas: "#0b0d10" surface: "#121519" border: "#232830" focus-ring: "#3ddc84" ## Logo / Wordmark System The mark is a rounded-square diff gutter: a `--border`-stroked square containing two horizontal bars, a longer green bar over a shorter red bar, literally the add/delete lines the product is built around. It is not a generic icon, it's a 1:1 miniature of the diff-panel component. ```svg ``` - **Lockup**: mark, then a `0.5rem` gap, then the wordmark "patchline" in mono/600, mark always left of the wordmark, never stacked or reversed. - **Minimum size**: mark not smaller than `16px` square, below that the two bars stop reading as separate lines. Wordmark not smaller than `0.8rem`. - **Clearspace**: empty margin equal to the mark's own height (22px at default size) on all four sides of the lockup, nothing else docks closer than that, including the nav's edge padding. - **Don't**: recolor the mark for a light or busy background, it only ever renders on `--panel`/`--bg`. Don't stretch it non-uniformly. Don't rotate it. Don't use the mark alone as a decorative bullet or list marker, it means "this is patchline," not "here is an item." Don't swap the bar colors, green is always the top/add line. ## Color System ### Roles | Role | Token | Value | Used for | |---|---|---|---| | Canvas | `--bg` | `#0b0d10` | Page background | | Surface | `--panel` | `#121519` | Panels, nav, cards, table header | | Surface raised | `--surface-raised` | `#171b20` | Hover state on a surface (input focus bg, row hover) | | Border | `--border` | `#232830` | Panel edges, dividers, input outlines, table rules | | Ink | `--ink` | `#e6e6e0` | Primary text | | Ink muted | `--dim` | `#8a8f98` | Secondary text, timestamps, helper text, placeholders | | Positive / add | `--accent` | `#3ddc84` | Diff additions, primary button fill, success status, focus ring | | Negative / delete | `--accent-alt` | `#ff5f56` | Diff deletions, error status, invalid form state | There is deliberately no `warning` or `info` color. Patchline only ever shows two states that matter to a reviewer, working and broken. Anything in between (a pending sync, a draft note) is rendered in `--dim` text with a word, not a third accent color. This is a constraint, not a gap, adding amber "warning" chips is exactly the kind of dashboard-UI noise the brand exists to avoid. ### Contrast (computed from the hex values above via WCAG relative luminance) | Pairing | Ratio | Passes | |---|---|---| | `--ink` text on `--bg` | ~13:1 | AAA | | `--dim` text on `--bg` | ~6:1 | AA (body text) | | `--accent` text on `--bg` (diff add lines, cursor) | ~11:1 | AAA | | `--accent-alt` text on `--bg` (diff del lines) | ~6.3:1 | AA (body text) | | `--bg` label on `--accent` fill (primary button) | ~10.9:1 | AAA | | `--ink` on `--panel` | ~11.5:1 | AAA | The one rule this table exists to enforce: a button or badge filled with `--accent` always labels itself in `--bg`, never in white or `--ink`. White-on-green and `--ink`-on-green both undershoot AA. typography: display: fontFamily: JetBrains Mono fontWeight: 600 body: fontFamily: Inter fontWeight: 400 ## Type Scale | Token | Size | Weight | Family | Line-height | Letter-spacing | Used for | |---|---|---|---|---|---|---| | `--text-display` | `clamp(2.5rem, 6vw, 4.5rem)` | 600 | Mono | 1.05 | -0.01em | Hero H1 only | | `--text-h2` | `1.5rem` | 600 | Mono | 1.2 | 0 | Section headings | | `--text-h3` | `1.125rem` | 600 | Mono | 1.3 | 0 | Card/entry titles | | `--text-body` | `1rem` | 400 | Inter | 1.6 | 0 | Paragraph copy | | `--text-small` | `0.85rem` | 400 | Inter | 1.5 | 0.01em | Footer, nav utility links, timestamps, helper/error text | | `--text-code` | `0.9rem` | 400 (600 for `+`/`-` prefixes) | Mono | 1.5 | 0 | Diff and code blocks | Rule for mono vs. Inter: mono is reserved for the hero headline, section headings, card titles, and anything that is literally code. Body copy, nav labels, button labels, form labels, and table cells are Inter. If a component's whole content is a piece of copy meant to be read quickly (a paragraph, a form label), it's Inter, if it's a moment meant to look like the tool doing its job (a heading, a diff, a status glyph), it's mono. ## Spacing Scale Base unit `8px`. Tokens in use: `--space-2: 0.5rem`, `--space-3: 1rem`, `--space-4: 1.5rem`, `--space-6: 2rem`, `--space-8: 3rem`, `--space-12: 4rem`. ## Shape One radius scale: `--radius: 10px` for panels, cards, inputs, and table containers. `--radius-pill: 999px` for buttons and status badges. Nothing else rounds. ## Iconography No icon library. The only non-text glyphs on the page are the logo mark and two Unicode status glyphs, `✓` (resolved/success) and `×` (failed/error), set in mono at the same size as the text they sit next to. This matches a real terminal's output and avoids importing an icon set for two symbols. If a future page needs more than pass/fail iconography, the fallback is Phosphor (line style, `1.5` stroke), not hand-drawn SVG paths, that decision just hasn't been needed yet. ## Motion Principles Scroll reveals a live git diff typing itself in, red and green lines animating, with a blinking terminal cursor tracking the changes. This is the only scripted animation on the page, everything else (buttons, inputs, table rows) uses only `:hover`/`:active`/`:focus-visible` CSS transitions, no scroll-triggered reveals outside the diff component. The diff reveal plays once per view (`toggleActions: play none none reverse`), never replays on every scroll pass, and fully honors `prefers-reduced-motion` by rendering the end state immediately with no animation. ### Never-list (written before the impeccable-pass rebuild) 1. No centered hero headline sitting above the diff panel, the terminal is the hero, the headline lives inside it as a comment line. 2. No two-button CTA row floating free of the terminal chrome, the primary action reads as a terminal prompt line. 3. No decorative window-chrome traffic-light dots on the terminal header. 4. No third accent color, no gradients, no glassmorphism, no drop shadows. 5. No component wall on the homepage, exactly one new proof component (recent activity table), not a stacked gallery of every pattern. 6. No replaying the diff animation more than once per view. ## Voice & Tone terse, technical, confident, no marketing fluff. In practice: - **Button label**: "Request access", not "Get started for free today" - **Error message**: "Sync failed. Retry.", not "Oops! Something went wrong on our end" - **Empty state**: "No open reviews.", not "You're all caught up! Nothing to see here" - **Success status**: "Synced 2m ago", not "All systems go! 🎉" ## Accessibility Baseline - Focus ring: `2px solid var(--accent)`, `2px` offset, applied via `:focus-visible` on every interactive element (links, buttons, inputs), never removed without a visible replacement. - Reduced motion: the diff reveal and cursor blink both check `prefers-reduced-motion: reduce` and render fully resolved with no animation when it's set. - Minimum tap target: `44px` in the smallest dimension for every button and input on touch viewports, including icon-only or ghost buttons. - Color is never the only signal: form errors pair red with an inline message, not just a red border, status pairs the glyph (`✓`/`×`) with a word, not just a color. ## Components ### Navigation Single-line bar, `64px` tall, `--panel` background with a `--border` bottom hairline, sticky to the top. Left: a small "back to gallery" utility link in `--text-small`/`--dim`. Center-left: the mark + wordmark lockup. Right: one primary button. No dropdown, no hamburger, a one-product site has nothing to collapse into a menu. ### Buttons Three variants, one radius (`--radius-pill`), one accent: - **Primary**: `--accent` fill, `--bg` label, used once per view for the single real action ("Request access"). - **Secondary**: transparent fill, `1px solid --border`, `--ink` label. Same-page anchor jumps, never the primary conversion action. - **Ghost**: text-only, `--dim` label, `--ink` on hover. Tertiary actions like "back." All variants define `:hover` (brightness/border shift), `:active` (`transform: scale(0.98)`), `:disabled` (`opacity: .4`, `pointer-events: none`), and `:focus-visible` (accent outline). Disabled state never relies on color alone, opacity carries it too. ### Forms Label above input, `--text-small`/`--dim`. Input: `--panel` background, `1px solid --border`, `--radius`, `--ink` text, `--dim` placeholder (never placeholder-as-label). On `:focus`, border becomes `--accent` and the focus ring applies. Helper text sits below in `--text-small`/`--dim`. On error, the border becomes `--accent-alt` and the helper text is replaced with a red error message, the same red the diff uses for deletions, reused here because it's genuinely negative-semantic, not decorative. ### Cards / panels A flat `.panel`: `--panel` background, `1px solid --border`, `--radius`, no shadow, no gradient. Used for the code/diff block and for changelog entries. Elevation is communicated by the border, never a drop shadow, per the brand's "no glossy panels" rule. ### Code / diff block (terminal hero) A `.terminal` panel is the homepage's hero, not a section beneath one: a header (real file path plus the branch the diff lives on, not decorative window-chrome dots), a body that types the animated diff in on scroll, and a prompt row where the primary button lives inline with a terminal-styled `$ ` line instead of floating in a separate centered CTA row. ### Table Header row in `--panel`/`--dim`/uppercase-free Inter labels, body rows in `--bg`, one `--border` rule between rows (not both top and bottom), row hover to `--surface-raised`. Status cells pair the `✓`/`×` glyph with a plain-language word. Proven twice: a "Recent activity" table on the homepage (the one component the hero earns beyond the terminal) and the provider-status table on `/changelog/`. ### Status / feedback states - **Loading**: a skeleton shaped like the real content (bars matching text line-heights), not a spinner. - **Empty**: a plain sentence in `--dim`, no illustration, per Voice & Tone above. - **Error**: an inline `--accent-alt` message with a retry action, never a silent failure. - **Success / status badge**: `--radius-pill`, `1px solid` the semantic color, semantic-color text on transparent fill (not a filled badge, filled would compete with the primary button's use of `--accent` as a fill). ### Footer One row: product name/tagline on the left, real page links on the right (Changelog, back to gallery). No invented legal text, no links to pages that don't exist. ## Do's and Don'ts ### Do - Keep diff syntax literal and readable, real +/- prefixes, monospace alignment, nothing stylized. - Reserve `--accent`/`--accent-alt` for genuinely semantic uses, diff add/delete, form valid/invalid, status success/error, never purely decorative. - Let the blinking cursor be the only continuously-moving element outside the scroll-triggered reveal. - Use `--bg` as the label color on any `--accent`-filled surface. - Pair every color-coded state with text or a glyph, not color alone. ### Don't - Don't add gradients, glassmorphism, or glossy rounded panels, this is a builder tool, not a marketing site. - Don't replay the diff animation on every scroll pass, reveal once per view, like a real code review. - Don't introduce a third accent color for "warning" or "info", route those to `--dim` text instead. - Don't stack more than one primary button in the same view, one conversion action per screen. - Don't fill a status badge solid, badges are outlined so the primary button remains the only solid-green element on screen. - Don't put a centered marketing headline above the terminal, the terminal is the hero. ## Known Constraints - Two routes now exist (marketing home, changelog), still no docs/pricing pages, no responsive breakpoint table beyond a single-column mobile collapse, no authenticated states (the "Request access" flow is not wired to anything real, this is a concept demo).