# Claudecore — Lucian Labs look E

A vending machine humming in a dark arcade. Near-black glass, a navy hairline,
sky-blue neon for the chrome, gold on the goods, everything floating in its own
soft glow. Shipped as the `ll-shop` widget and as elijahlucian.ca's widget
system (the radio, the badges, the docks). Read `AGENT.md` first — the ban
list there applies to this look, with the exceptions named below.

- Stylesheet: `https://lucianlabs.ca/branding/claudecore.css`
- Reference render: `https://lucianlabs.ca/branding/claudecore.html`
- Tokens as JSON: `https://lucianlabs.ca/branding/brands.json`

This look is under iteration. It was extracted from running code rather than
designed first, so the numbers here are what shipped, not what was decided.
Where the spec and the widget disagree, the widget is the reference until this
page says otherwise.

## Where it came from

Two sources, one dialect:

| | ll-shop (the machine) | elijahlucian.ca (the widgets) |
| --- | --- | --- |
| Ground | `#0a0a0a` in a `#2a4a70` hairline | `rgba(0,0,0,.8)` in a 2px `#303030` frame |
| Chrome | `#060a10` header, `#5d8fc9` labels | dot-grid texture at 50% over the body |
| Voice colour | `#4fc3f7` sky blue | per-widget: pink, blue, teal, green |
| Sell colour | gold gradient on the goods | — |
| The circle | the orb, `#397fd9` sphere | the badge, flat disc + hard pixel shadow |
| The canvas | — | the radio's black sketch, hue picked by the song |
| Motion | genie in and out of the orb | juice: spring out, ease-in back, bloom on hover |
| Type | Finlandica, tiny uppercase tracked | Finlandica body, Space Mono readouts |

Claudecore is the machine's palette with the widgets' depth and motion. The
orb is the look's circle; the badge is its cousin for docks.

## Use it for

Floating things. Corner widgets, docks, mini-players, pop-over shops, anything
that sits *on top of* someone else's page and has to hold its own against an
unknown background. The glow and the hairline are there so it separates from
whatever is under it.

Also: the personal site. Anything that is Elijah's rather than a product's —
the radio, the thought bubbles, the live chat.

## The three rules that make it this look

1. **It floats.** Every panel carries the three-layer shadow — drop for weight,
   blue glow, inset highlight on the top edge — and blooms on hover. This is the
   one dark look with shadows, and it has them because it lives over other
   people's pages. `--radius` is 8px on panels, 4px on anything inside them.
2. **Labels are blue.** Chrome text is `--label` (`#5d8fc9`), not grey. Tiny,
   uppercase, tracked 0.14–0.18em, Finlandica 700. The wordmark is the same
   thing with one word in `--accent`. If a label reads grey, it's not this look.
3. **The goods wear gold, the chrome wears blue, and the sketch wears whatever
   the content says.** Sky blue speaks (tabs, links, the nudge, the family
   rule); gold sells (the slots, the one CTA, the hire strip). The sketch canvas
   is the one place a third hue appears, and it is the content's — the song
   picks it — never yours.

## Type ramp

| Role | Face | Size | Treatment |
| --- | --- | --- | --- |
| h1 | Finlandica 700 | 2.4rem | uppercase, 0.1em |
| h2 | Finlandica 700 | 1.5rem | uppercase, 0.08em |
| h3 | Finlandica 700 | 1.05rem | uppercase, 0.08em |
| wordmark | Finlandica 300 + 700 | 0.8rem | uppercase, 0.14em, `--label` with one word `--accent` |
| label / tab / overline | Finlandica 700 | 0.62–0.72rem | uppercase, 0.16–0.18em, `--label` |
| body | Finlandica 300 | 1rem / 1.5 | `--ink` on prose, `--muted` in panels |
| small | Finlandica | 0.8–0.85rem | `--muted` |
| readout / price / bracket | Space Mono | 0.68–0.85em | tabular |

One family does display and body. What separates chrome from copy is weight
and tracking, not face. **Space Mono** is the mono — inherited from
elijahlucian.ca and the look's one exception to the house Inconsolata rule,
same standing as Field Notes' Fira Code. `[3/12]`, `03:41`, `$4.99 — iOS` are
all Space Mono.

In the widget itself the labels run at 0.42rem. That is a 176px panel's
problem, not a rule — at page scale use the ramp above.

## Accent budget

`--accent` (sky `#4fc3f7`) — the voice. Wordmark, selected tab, links, the
family rule, the nudge, hover on any chrome. Not a fill: it is text, a 2px
underline, a hairline. The one exception is the focus ring.

`--accent-2` (gold `#ffa40a`) — the sale. One primary CTA per view, the hire
strip, section heads inside the CV. The slots wear the deeper gold gradient
(`--gold-a` → `--gold-b`) because they are the goods. Gold never appears on
chrome.

`--orb` (`#397fd9`) — the sphere only. It is a deeper blue than the accent on
purpose: the orb is an object, the accent is light.

`--good` / `--bad` — tags only.

**Gradients.** The ban list forbids multi-stop gradients on buttons and text.
This look's two-stop 135° gradient on the slots and the primary CTA is the
named exception; it comes from the machine and stays on the goods. Two stops,
one angle, never on chrome, never on text.

**Product colours.** A slot may carry its product's own colour (LAOE teal,
Tide teal, Infininote violet). The look dresses the machine, not the goods on
the shelf. Those colours are the product's, and the ban list's violet clause
does not reach them.

## Boundary

`--border` is **1.5px** — a half-step between Console's 1 and Punch Clock's 2,
in navy `--line` (`#2a4a70`). Inner dividers are 1px `--line-2` (`#1a2c44`).
The sketch and the elijahlucian.ca widget bodies use a 2px grey `--line-sketch`
(`#303030`) — the one grey edge, and it frames content, never chrome.

## Depth

`--shadow` on every panel: `0 4px 20px rgba(0,0,0,.6)`, `0 0 14px
rgba(57,127,217,.18)`, `inset 0 1px 0 rgba(255,255,255,.04)`. Hover swaps to
`--shadow-bloom` (wider, the glow at 42%). The badge takes `--shadow-hard`
(`1px 1px 0 0 rgba(0,0,0,.5)`) — a pixel offset, not a blur.

Widget bodies on the personal site also carry `--tex`, a 4px dot grid at 50%
opacity over the panel. The machine does not.

## Motion

This is the juice system from elijahlucian.ca, and it is transform + opacity
only. No width, height or position transitions.

| Name | Value | Used for |
| --- | --- | --- |
| `--spring` | `cubic-bezier(0.32, 0.9, 0.3, 1)` · 420ms | anything opening, lifting, arriving |
| `--ease-in` | `cubic-bezier(0.4, 0, 0.6, 1)` · 250ms | anything closing or retreating |
| `--micro` | 180ms ease | colour, border, shadow |

- **Hover:** 2px outward nudge (`translateY(-2px)`), shadow to bloom. Slots
  nudge 1px.
- **Press:** `scale(0.96)`, micro duration.
- **Focus:** 2px `--accent` ring, 2px gap. Never omitted.
- **The orb:** `scale(1.12)` on hover, `0.95` on press, glow to 70%.
- **The badge:** inverts on hover — white disc, coloured letter — and on the
  personal site runs a starfield inside itself while hovered.
- **The teleport.** Open and close are a flip and a zoom: the panel arrives
  edge-on at 90° — invisible — and turns to face you while it grows to size,
  380ms on `cubic-bezier(0.16, 1, 0.3, 1)` with a 3% overshoot at three
  quarters; closing is the same run backwards, 260ms on
  `cubic-bezier(0.7, 0, 0.84, 0)`. Transform and opacity only. Only on a user
  toggle — never on first paint. In `ll-dock` the same flip carries every
  window and toast, and new windows land near the centre of the screen in the
  first spot that overlaps nothing.
- **The orb.** Every look collapses to its own icon (`branding/orbs.css`): this
  look's is the blue sphere. Console is a pulsing block cursor, House Pour a
  violet swirl behind an ivory rim, Punch Clock a green pip that glitches every
  seven seconds, Field Notes the blog's codex mark ◈ with a Fira Code label.
- **The skin swap.** A look change is mood's wipe (`skin-swap.md`), scoped to
  the widget: the old skin is snapshotted and held, the new one sweeps in
  behind a sinusoidal front at a freshly randomised angle, 600ms (`move`) on
  `cubic-bezier(0.4, 0, 0.2, 1)`. That is Claudecore's own entry; every other
  look arrives its own way — see *Transition* below. Every ll-* widget on the page is its own
  view-transition group, so one front sweeps all of them. Tweens are frozen
  for the duration; the chosen pip pops on landing. Without View Transitions
  the wordmark blurs through the face change and the colour tweens morph the
  rest.
- **Reduced motion:** every spring becomes a 150ms opacity fade; the genie and
  the teleport are skipped and the panel cuts, and the orbs hold still.

Nothing animates on page load. The panel starts minimized and the visitor
opens it.

### Transition — arriving in Claudecore

A look change moves the way the look you are going **into** moves. This is how
a swap into Claudecore arrives.

| Kind | Duration | Curve |
| --- | --- | --- |
| `curve` | 600ms · move | emphasised · `cubic-bezier(0.4, 0, 0.2, 1)` |

Claudecore keeps mood's wipe, and it is the **default**: any look without a transition of its own, or with a kind a renderer does not know, arrives this way. A sinusoidal front sweeps across at a freshly randomised angle, so no two swaps look alike.

**Frames:** Three `clip-path: polygon()` frames at sweep positions −260, 0, +260, the phase advancing 1.4 each step so the curve travels. See [skin-swap.md](/branding/skin-swap.md) for the full derivation.

**Reduced motion:** no sweep. The swap degrades to the 600ms token tween —
colour and opacity still change, so the choice still visibly lands.

Implemented once in `v2/ll-brand.js` (`LLBrand.transition('claudecore')` returns the
frames), mirrored in `v2/ll-shop.js`, and recorded in `brands.json` under
`looks.claudecore.widget.transition`.

## The sketch

The radio's visualiser is part of the identity: a black canvas in a 2px grey
frame where the song builds a landscape as it plays. Parallax ridgelines drawn
in the song's hue reveal left to right with progress; a road converges to the
horizon; a finish pole advances as the track nears its end; a ship bobs on the
beat. 30fps, paused when hidden or collapsed.

Rules for any canvas in this look: black ground, `#2a2a2f` horizon, trailing
fade at `#0a0a0eaa`, neon strokes at 1–1.5px, the hue seeded from the content.
Fill shapes black and stroke them in colour — the wireframe is the drawing.

## Voice

Terse, lowercase-comfortable, a little cheeky. The machine talks to you.

- Tabs: `shop`, `devlog` — one word.
- Slots: name in caps, one-line pitch, price with platform: `$4.99 — iOS`.
- The strip: `hire the guy who built these ↗`
- The nudge: `buy something.` / `support this app <3`
- Empty: `no posts yet.` Error: `couldn't load posts.` — lowercase, full stop,
  no apology.
- Readouts: `[3/12]`, `random`, `continuous`, `shuffle`, `repeat`.

No exclamation marks. `<3` is allowed; emoji are not.

## Components in the stylesheet

`.page` `.section` `.section-copy` `.grid` · `.machine` `.machine .header`
`.machine .body` · `.widget` `.sketch` · `.tabs` `.tab` · `.orb` `.badge` ·
`.slot` · `.button` `.button.primary` `.button.strip` `.button.ghost`
`.button-row` · `.input-field` `.field-label` `.checkbox` · `.tag` `.tag.good`
`.tag.bad` · `.entry` `.nudge` `.pips` `.pip` · `.wordmark` `.section-rule`
`.readout` `.mono` · `.nav` `.text-link` `.site-footer` · bare `table`.

## Filling gaps

Follow `AGENT.md` step 4. For this look specifically:

- **Dock / drawer** — `.widget` styling, slides on transform by its own width,
  `--spring` out and `--ease-in` back, an 8° perspective tilt on the panel
  while closed. The tab rides the panel's outer edge.
- **Tooltip** — `--panel`, 1px `--line-2`, Space Mono at 0.75rem, 4px radius,
  `--shadow-thin`.
- **Progress** — a 1px white line on black, drawn on canvas, growing left to
  right. The audio player's bar, not a `<progress>`.
- **Toggle** — a native checkbox with `accent-color: var(--accent)` and a
  lowercase label. The radio's `continuous · shuffle · repeat` row.
- **Chart** — it's a sketch. Black ground, one hue from the data, strokes not
  fills.

## Behaviour

`UX.md` applies. Where Claudecore differs:

**It starts closed.** A floating widget arrives as an orb and waits. It may
auto-open on a cadence (the shop opens itself every fifth page load) but never
on the first visit and never mid-interaction.

**State survives.** Minimized or open, which tab, which look, the playlist
index — all in `localStorage`, all restored on the next load. A visitor who
closed it finds it closed.

**It fits its corner.** A panel that would hang off the viewport flips to the
side with more room, measured after first layout, re-measured on resize and on
any content change.

**It reports.** Every touch is an analytics event — open, close, tab, look
change, click-out — with the page path as label. The widget is a funnel and
knows it.
