Citelight · internal

The design system, locked.

VERSION · SHIP CANDIDATE B · AUG 2026 · TOKENS ON THIS PAGE ARE COPIED FROM index.html AT BUILD TIME

00

Reading this document

This page is the single source of truth for the design and brand system of citelight.ai as shipped in this version. It is written for whoever touches the site next: designer, engineer, or Andy in six months. Everything here was extracted from the live build, not reconstructed from memory. The :root token block in this page’s own stylesheet is copied verbatim from index.html at build time, and every swatch and specimen below renders from those variables. If this page looks wrong, the system has drifted; fix the drift, then rebuild this page.

“Locked” means: these decisions were made deliberately, tested at both breakpoints, and survived review. Changing a locked value is allowed, but it is a design decision with site-wide consequences, not a tweak. Section 13 defines what is open.

01

Brand core

Premise. Citelight measures whether AI platforms (ChatGPT, Perplexity, Gemini, AI Overview: always these four, always this order) cite a real estate agent when buyers and sellers ask who to work with. The product’s emotional engine is exclusion and its resolution: the agent discovers they are absent from answers their competitors live in, then watches the light move to them.

The metaphor is citation-light. Gold is not decoration; it is the light of being cited. This single rule governs every use of aurum on the site: a gold element must represent citation, presence, or the action that earns them. A gold divider for taste is a violation.

Two registers, one world. The paper world (bone grounds, ink text) is where the agent reads, decides, buys. The vessel (the dark gradient) is inside the machine: streamed answers, audits, the takeover. Paper is calm and editorial; the vessel is where things happen to you. Crossing between them is an event, never a casual background change.

Lexicon. Speak the system’s language in code and conversation: bone (paper grounds), ink (text on paper), aurum (citation gold), void (vessel palette), vessel (the dark surface itself), pmark (platform mark), absence salmon (the not-cited tone), the ledger and the search (the mobile audit mechanics).

02

Language laws

Copy is part of the design system and carries hard rules. These apply to UI text, marketing copy, study pages, emails, and code comments alike.

No em-dashes, no en-dashes. U+2014 and U+2013 are banned everywhere. Substitutes, in order of preference: the period (two sentences), the colon, the middot (·, U+00B7) for label separators. This is enforceable by grep and should be grepped before every ship.
No curly quotes in code. Straight quotes in HTML/CSS/JS source. Typographic quotes are permitted in rendered copy via entities.
The Veracity Test. No claim ships without data behind it. Statistics carry attribution; a single-source figure names its source. Figures measured under different definitions are never presented as one number. Fictional or sample data is always marked ILLUSTRATION. The study gate scripts/check-studies.mjs encodes these rules and must exit 0 before any study page ships.
Banned patterns (the AI-tell list). Repeated kickers saying the same word, fragment-period headline chains, sliding-fill button hovers, counter animations as ornament, uniform fade-up-on-scroll on every element, decorative technical annotations. If a surface reads as replicable by default settings, it gets a concept rebuild, not a patch.

Casing. Spaced-caps registers (eyebrows, marquee, mono labels) use text-transform:uppercase, except where a brand’s casing is its identity: eXp is exempted via .brokq__item--case. Never re-case a brand name.

03

Typography

One family speaks for the brand: Söhne (Klim Type Foundry), with Söhne Mono as the machine’s voice. Sans carries reading and display; Mono is reserved for genuine data registers: labels, timestamps, counts, queries, machine output. Mono used decoratively is a violation.

License scope. Klim order 26051140 licenses Söhne for desktop seats plus web on the citelight.ai domain only. Do not deploy these font files to any other production domain. A new domain requires a new Klim web license first. The files live in assets/fonts/soehne-*.woff2 behind assets/fonts.css.

Faces in the build

Söhne Buch 400 · body, ledes, long reading

Söhne Kräftig 500 · every heading and button on the site

Söhne Halbfett 600 · rare emphasis inside data surfaces

Söhne Mono Buch 400 · labels · queries · counts

Söhne Mono Halbfett 600 · emphasized data

Display weight is 500, not 600+. Headlines set in Kräftig with tight negative tracking read as the brand; Halbfett headlines read as shouting. 600 exists for small emphasis inside data surfaces only.

Scale as shipped

rolesizetrackingnotes
h1 (hero)clamp(2.65rem,6.6vw,5.5rem)-.03em classline-height 1.02, text-wrap balance
.h-sectionclamp(1.9rem,3.8vw,3.1rem)-.028emweight 500, ink-0
.ledeclamp(1rem,1.35vw,1.16rem)defaultmax-width 52ch, ink-2, text-wrap pretty
.eyebrow.72rem mono.16em capsink-2, inline-flex with .6em gap
body1rem/1.6+defaultink-1 on paper, void-fg-1 in vessel
credits caps (marquee)clamp(.86rem,1.5vw,1.02rem).24em (.18em ≤640)weight 500, ink-2
Numbers that change are tabular. font-variant-numeric:tabular-nums on every count, percentage, timer, and score. A rolling count in proportional figures is a defect.
04

Color

Four families and one rule of scarcity: the page is bone and ink; aurum appears only as citation-light; the vessel is its own world with its own foreground ramp. Platform tints exist solely to identify the four platforms in data marks.

Bone · paper grounds

--bone-0#F1EEE8Page ground. The default paper.
--bone-1#EAE7E0Raised paper: cards on the ground, one step lighter-warm.
--bone-2#E3DFD5Recessed paper: wells, input grounds.
--bone-3#D9D4C8Deep recess. Rare; use before reaching for a border.

Ink · text on paper

--ink-0#1A1613Display and headline ink. Never for long body.
--ink-1#37322BBody ink on paper.
--ink-2#6E685EMuted ink: ledes, descriptions, marquee names.
--ink-3#9C9589Whisper ink: leads, ornament labels. Below AA alone; only for non-essential text.

Hairlines on paper

--linergba(26,22,19,.10)Hairline on paper.
--line-2rgba(26,22,19,.17)Hairline, emphasized (hover, active edges).

Aurum · citation-light

--aurum-300#F6D378Light aurum: chips, CTA fills on the vessel, marks on dark.
--aurum-400#F4C95DMid aurum: gradients, glows.
--aurum-500#E5B53EBrand aurum: bars, lit dots, citation-light on paper.
--aurum-600#B8913ADeep aurum: gradient anchors.
--aurum-ink#8A6B22Aurum as TEXT on paper (contrast-corrected). Never use 300-500 for text on bone.
--aurum-glowrgba(229,181,62,.30)Glow at strength (lit dots, focus moments).
--aurum-glow-softrgba(229,181,62,.09)Ambient glow. Backgrounds only.

Void · the vessel

--void-0#141009Vessel floor (gradient end).
--void-1#1C1710Vessel body (gradient start rgb(28,23,16) pairs with this family).
--void-2#262016Raised element inside the vessel.
--void-fg-0#EDE7DCPrimary text in the vessel.
--void-fg-1#B7AF9FBody text in the vessel.
--void-fg-2#928A7CMuted text in the vessel.
--void-linergba(246,211,120,.13)Hairline inside the vessel: aurum at 13%, never grey.

Platform tints

--t-gpt150,195,165ChatGPT tint (r,g,b triplet).
--t-plx60,165,195Perplexity tint.
--t-gem130,145,235Gemini tint.
--t-aio235,155,85AI Overview tint.

Absence has a color: salmon, used only for the not-cited state. Text rgba(222,138,107,.95), borders rgba(222,138,107,.3). It exists in the vessel only.

Text color is never hand-set on dual-ground elements. Any element that can sit on both light and dark grounds inherits: muted text uses color:inherit with opacity, never a named grey. Where text sits on imagery, its color derives from the measured luminance of what is actually behind it, re-derived when the ground can change; if the composite cannot be sampled honestly, the element gets its own opaque scrim. Naming a color here has broken this site before.
05

Surfaces & depth

Bands. Sections are .band blocks with vertical rhythm --band-y: clamp(88px,12vh,164px). Grounds change by band class; content is centered by .band__in (max-width --max, inline padding --gut).

Paper surfaces. Cards use the fill-delta recipe: interior panels are one bone step away from their parent, hairline --line, and at most two shadow layers (a 1px contact shadow plus one long soft drop). No third material inside a card.

The vessel. linear-gradient(rgb(28,23,16), rgb(20,16,9)). Inside it, hairlines are --void-line (aurum at 13%), never grey; text uses the void-fg ramp; raised elements use --void-2.

Radii

--r-lg22pxLarge surfaces: cards, exhibits.
--r-md14pxInterior elements.
--r-sm9pxSmall interior chips, wells.
--r-pill999pxButtons, chips, stamps, bars.
Concentric radii. A child’s radius equals its parent’s radius minus the gap between them. Nested equal radii read as a mistake at the corners.
Hairlines below 1px do not exist. 0.5px renders nothing on 1x screens. Thinner lines are made with 1px at lower alpha.
06

Layout & breakpoints

tokenvaluemeaning
--max1200pxcontent column ceiling
--gutclamp(20px,5vw,48px)inline gutter, fluid
--band-yclamp(88px,12vh,164px)section vertical padding

Breakpoints and what actually changes

widthchange
≤860pxExhibits stack single-column (copy above surface; flipped exhibits un-flip). Share rows compress their grid.
≤720pxThe device split. Audit submit opens the mobile takeover instead of the inline theater. This is the boundary between the two exclusive audit experiences.
≤640pxMarquee tracking eases to .18em; share names wrap to 2 lines; after-tag reflows to its two-row grid; type floors enforced.
Desktop and mobile are two experiences, not one layout squeezed. Any pass that touches layout or a shared component re-captures every page at both widths and reviews each as its own world before declaring clean.
07

Motion

Two curves, one duration scale, and a doctrine: motion is diegetic. Every animation depicts something the interface is actually doing (extracting a name, searching text, filling a segment of elapsed time). Motion that only decorates is removed.

--ease · the house curve
cubic-bezier(0.16,1,0.3,1)
--ease-soft · utility
cubic-bezier(0.4,0,0.2,1)

Duration scale

--d-micro.16sPress feedback, transforms under the finger.
--d-state.24sHover, color, state changes.
--d-move.32sElements changing place.
--d-long.5sSurfaces arriving or leaving.
--d-epic1.1sReserved: one-time theatrical moments only.
--beat.09sStagger unit between siblings.

Arrival grammar. Entrances use .rv: opacity 0 and 12px rise, .6s on the house curve, staggered by --beat via .rv-2 etc. Arrival is a one-time event with memory; scroll does not scrub it backwards. High-frequency interactions animate at --d-micro/--d-state or not at all.

Counters roll only when something is decided. A count changes at the moment a conclusion lands (a platform finishes, a chip arrives), rendered as a masked digit swap. Ambient counting is banned.

Reduced-motion contract, per component

componentprefers-reduced-motion behavior
.rv revealsElements render settled; no rise, no fade choreography.
Brokerage marqueeStatic centered wall: item-level wrap, mask off, duplicate set hidden.
Audit (mobile + desktop)Theater and takeover never mount; submit goes straight to the done state.
qfield ambient promptsDrift suppressed; field rests composed.
Hero / footer videoPoster frame; video does not autoplay.
08

Marks & walls

Platform marks. Official monochrome marks (OpenAI, Perplexity, Gemini, Google) inlined as .pmark SVGs on currentColor. On paper they run ink-toned and muted; in data contexts they take their platform tint via color:rgb(var(--t-*)). Full-color logo walls are banned: muted marks read as confidence, color reads as a sponsor wall and implies endorsement.

The brokerage wall. Nine official monochrome marks, one ink. The standing ruling holds and is unchanged: official assets or deliberate typographic voice, never in-between, and never a redrawn wordmark. The ruling never banned logos - it gated them on completeness, and the gate is now met, so the wall converted. Every mark is knocked out of its official file and tinted to a single baked ink (#57514A, measured 6.04:1 in situ against the band). Ink is baked rather than applied as CSS opacity, because opacity over the mark lightens the effective colour and invalidates the measurement. Corcoran is the one name held back: the supplied file is a crop with the outer letterforms amputated at the canvas edge, and a shaved wordmark is not an official asset. It returns to the wall when a clean file exists. wall-scan in the decay gate now enforces the ruling: a wall that mixes marks with typographic brand names closes the gate, as does a mark whose file is missing from the deploy. The italic closer is exempt - it is a phrase, not a brand.

09

Component registry

Every named component, its purpose, and its laws. File references are the component’s home; shared pieces live in index.html unless noted.

Navigation

purpose
Persistent brand + single CTA; recedes behind content, never competes with it.
laws
44px hit areas throughout. CTA is the standard pill button. No hover motion beyond --d-state color.

Hero

anatomy
Display h1 on bone, ambient loop video (hero-loop.mp4, mobile variant) behind measured space, palms as depth props.
laws
Video rests at opacity 0 until .playing; poster covers reduced-motion and failed autoplay. Type sits in composed empty space, not over busy imagery.

qfield · the ambient query field

purpose
Shows the questions buyers ask, drifting as ambient whispers that converge when the field is engaged.
laws
Whisper type (~9px) is a documented ornament exemption from the type floor: the whispers are texture, not reading text, and their convergence state is fully legible. Do not “fix” them.

Monitor · platform rows

anatomy
Four rows, official pmarks, cited/not states, position chips.
laws
Order is always ChatGPT, Perplexity, Gemini, AI Overview. Data must reconcile with every other surface (see Data canon).

Exhibits · the product surfaces

anatomy
Three copy+surface pairs: the Monday brief (mail), competitor citation share (ranked bars), coverage grid (prompt dots). Alternating flip layout above 860px.
laws
Gold appears only as citation-light (fix labels, your bar, lit dots). Share percentages sum to 100 and use tabular figures. The flipped exhibit uses a mirrored grid template: order alone squeezes the surface.

The vessel · inside the answer

purpose
First crossing into the machine: a streamed answer with role-anonymized names, then the turn (“yours can be too”).
laws
Vessel material rules from section 05. Prose is readable here; ILLUSTRATION marking applies until real data.

Audit dock · form and states (audit/index.html)

anatomy
Name + market form → experience → done (email capture) → sent. States swap; [hidden]{display:none!important} guards every state against display-rule leaks.
laws
The submit button is the styled 52px pill: a bare UA button shipped once because the page never defined .btn. Any new page using shared class names must import or redefine them.

Desktop audit theater · psurf

anatomy
Four sequential platform surfaces (~12s): query, redacted answer scan, citation chips, conclusion stamps.
laws
Desktop-exclusive (>720px). Slated for replacement by the switchboard (four concurrent panes); until then it is the shipped desktop experience.

Mobile audit takeover · the ledger and the search

anatomy
Full-screen vessel overlay, story segments, per-platform scenes; persistent bottom ledger (three competitor rows + YOU row pinned at salmon 0); name extraction as chip flight; per-answer search beam (“searching for {name}… no mention found”); finale knife and CTA into the done state.
laws
≤720px only. Data-driven renderer over an embedded SPEC (swap for API mode; ILLUSTRATION marks drop). Tap advances via the scene skip with the applied-guard so counts never double. Counts land exactly 4/3/2/0. Scroll locks while open; X and Escape close; 44px close hit; safe-area padded.

Brokerage marquee

anatomy
Duplicated identical sets in a translateX(-50%) track, 42s linear, hover-pause, 12%/88% mask fades, item-level RM wrap.
laws
Seam integrity requires the two sets pixel-identical and the track exactly twice one set. eXp keeps its casing. Roster is curated copy, not a dumping ground.

Report template · /report/

purpose
Mobile-first rendering of a real audit from the #auditData JSON contract; specimen mode shows the fictional market.
laws
The contract is canonical: engineering fills the same shape the takeover SPEC mirrors. Template renders whatever the data says; no hand-edited numbers.

Footer

laws
Dusk imagery register; link hit areas 44px; the footer CTA inherits text color (a named color broke it once).
10

Floors & exemptions

11

Data canon · one coherent world

Until the real audit engine ships, every surface draws from one fictional market so a visitor who reads everything finds a single consistent world. All of it is marked ILLUSTRATION.

entitycanonical value
Competitor 1Las Olas Isles specialist · cited on 4 of 4 platforms
Competitor 2Rio Vista listing agent · 3 of 4 (ChatGPT, Perplexity, AI Overview)
Competitor 3Harbor Beach broker · 2 of 4 (GPT, GEM)
Share table34 / 22 / 17 / You 9 / five others 18 (sums to 100)
QueriesQUERY-BANK.md canon; the scan set is B2, S1, B1, S2
Contracts/report/ #auditData JSON and the takeover SPEC share one shape family; API integration swaps data blobs and drops ILLUSTRATION marks everywhere at once
Never fork the world. A new surface that mentions competitors, counts, or shares must reconcile with this table or change it everywhere, including this page.
12

Verification doctrine

13

Governance

Locked: tokens, type system and license scope, the two registers, motion doctrine and RM contracts, language laws, the data canon, component laws above.

Open: new sections and surfaces, the desktop switchboard build, copy refinement inside the laws, roster curation, real-API data replacing the canon.

The extension bar. A new surface earns its place with one structural idea that only it uses. If a proposed section could be described as two-column copy/image, centered hero, or a rounded rectangle grid sharing one rhythm, it does not ship; it gets a concept. “Feels generic” from Andy triggers a full concept rebuild, never a patch.

Ship gates: check-studies.mjs exits 0; em-dash grep is clean; both breakpoints captured and reviewed; overflow 0; zero console errors; processor-scan passes, meaning every external host in shipped code is named in the privacy policy; deploy via vercel --prod from ~/citelight-deploy/ with hash verification.