Design.

theme

A living reference for the studio.chat design system — tokens, type, components, and inputs. Both surfaces live here: the public site and this office shell share the same tokens.

colors_

bg

--color-bg

Page background

bg-muted

--color-bg-muted

Alternating section background

fg

--color-fg

Primary text and solid fills

fg-muted

--color-fg-muted

Secondary text, labels, intros

fg-subtle

--color-fg-subtle

Faint text, corner marks, numerals

line

--color-line

Borders and dividers

Tokens flip with light / dark mode (defaults to your system; use the switch at the top to preview either). Use the Tailwind aliases: bg-bg, text-fg, text-fg-muted, border-line, etc.

typography_

display — var(--font-display)

Aa Bb Cc 123

Headings and large display text.

mono — var(--font-mono)

Aa Bb Cc 123

Labels, eyebrows, captions, UI chrome.

Page title
display text-5xl sm:text-7xl lg:text-8xl

studio.chat

Section heading
display text-4xl sm:text-6xl lg:text-7xl

Tell us what you're making.

Card / step title
font-display text-xl tracking-tight

Quote within a day.

Body (large)
text-base sm:text-lg text-fg-muted

Audiovisual production in Medellín, end to end.

Body
text-sm text-fg

Daily and weekly rates per item.

Label
.label

featured_

Caption
.caption

Sony A7R V, FE 50mm F1.2 GM

buttons_and_links_

CtaButton — external (mailto / tel / off-site)

CtaButton — onClick (in-page action)

CtaButton — button (form submit)

CtaButton — disabled

Forward affordance — 〉

view catalog 〉

Logo — homepage + header wordmark

LocaleSwitch — language toggle

enes

PageSizeSelect — paginated listings per-page picker

focus_states_

Browsers default to a blue glow on :focus-visible. We replace it with two patterns: text-only elements (<a>, <button>, the toggle button, filter chips) get a 4-px-offset fg underline; bordered controls (.input fields, selects, framed buttons) flip the bottom border to fg. Editorial components (FramedLink, CtaButton) opt out and shift their corner brackets to fg. Composite cards wrapped in a Link (homepage services, project cards) wrap non-title text in inline-block so only the title underlines. Mouse clicks never trigger a focus ring — only keyboard navigation.

button — bottom border flips to fg

toggle button — fg underline at 4-px offset (E-mail / WhatsApp)

E-mailWhatsApp

CtaButton — corners flip fg-subtle → fg (they sit outside the rounded pill, on page bg)

Get in touch

filter chip — fg underline at 4-px offset (catalog page)

camera body6

page-size select — bottom border flips to fg

.input — bottom border flips to fg (contact form fields)

inputs_

text / email — .input

select — .input

textarea — .input

Textarea (office) — filled box, not an underline

segmented toggle (Email / WhatsApp)

E-mail
E-mailWhatsApp

Enter a valid email

page_components_

SectionHeader — big display title + eyebrow + intro

eyebrow__

projects__

Selected work, from social shorts to feature-length productions.

PageHero — label + display headline + intro (/services pages)

rentals__

A small shelf of the gear we shoot with.

We rent from the same kit we shoot with — cameras, lenses, lighting, and audio.

CtaSection — closing call-to-action band

request_a_quote__

Tell us what you're shooting.

Section — default (no fill, top border, lg spacing)

section_

Standard content band.

Section — muted tone (bg-bg-muted)

section_

Alternating band; reads as a different layer of content.

Section — spacings (xs / md / lg / xl)

xs — py-12 sm:py-16

md — py-16 sm:py-24

lg — py-20 sm:py-28 (default)

xl — py-24 sm:py-32

StatusScreen — 404 (not-found.tsx)

not_found_

We can't find that page.

The link may be broken, or the page may have moved.

StatusScreen — 500 (error.tsx / global-error.tsx); retry is a CtaButton in the live boundary

error_

Something went wrong on our end.

An unexpected error stopped this page from loading.

content_cards_

The cards that render catalog, project, and editorial content from real data (here, seeded placeholders). Hover the rental cell to scrub its frames, and the gallery thumbs to preview.

RentalItemCard — catalog cell (live · text-only · sold · coming soon)

FX6

Sony

FX6

Full-frame cinema camera; the workhorse body. Hover to scrub angles.

Matthews

C-stand

40 in grip stand with arm. Text-only — no photo on file.

Ronin 2
Sold

DJI

Ronin 2

Pro gimbal stabilizer. Marked sold — diagonal X at rest.

Alexa 35
Coming soon

ARRI

Alexa 35

Coming to the shelf soon.

ProjectCard — square project tile (cover + deliverables stamp + title / type)

ProductGallery — detail-page main frame + thumbnail filmstrip (hover previews · click pins)

Sample product, multiple angles

feedback_

UnderConstruction — red banner for unfinished / stub pages (full-bleed at the top of a page)

under construction — this page is a work in progress

layout_

Page content sits in a centered container: mx-auto max-w-[1600px] px-4 sm:px-8. Section vertical rhythm is py-20 sm:py-28 for content bands and py-24 sm:py-32 for hero/CTA bands. Alternating sections use bg-bg-muted with a border-t border-line.

office_components_

The staff surface (/office) composes its own small set of primitives from @/components/office/ui. Same tokens and type as the public site, but labels render as plain text (no eyebrow _), and stat panels / tables draw their hairlines from cell borders so incomplete rows stay transparent.

Badge — status pill (all tones)

draftpaidpendingoverduereservedout

StatCard in a HairlineGrid — the empty 4th slot stays transparent (hairlines drawn from cell borders, not a bg-line backdrop)

reservations

42

this month

overdue

3

needs follow-up

accounts

128

view all

Panel — bordered section (title + actions), and a framed={false} tile

recent activity

live

Composed content — tables, forms, summaries.

A plain tile (framed={false}) for use inside a HairlineGrid.

Table — listing rows (Th / Td), with a Badge cell

clientdatesstatus
Ada LovelaceJun 3 – Jun 5, 2026paid
Grace HopperJun 8 – Jun 9, 2026pending

Pagination — listing pager (prev · n of N · next + trailing counter)

CornerFrame — ⌝ ⌞ default (navigation) vs ⌜ ⌝ ⌞ ⌟ full (actions)

defaultfull

Select — the house underline select: native dropdown glyph + the reservation time-picker spacing (px-1 py-1.5). FilterSelect and the schedule editor compose it

FilterField / FilterSelect — shared list-page filter toolbar fields (search · select)

FilterField, controlled — instant client-side filtering (docs index); same field, no form roundtrip

brand.md · i18n.md · office/00-architecture.md

DatePicker — field-styled trigger opening a calendar popover (react-day-picker, house-themed); replaces native date inputs. Forms pass a `name` (hidden input); controlled mode pairs value/onChange; `min`/`max` disable out-of-range days.

controlled

no date selected

bounded (today onward)

past days disabled · uncontrolled (emits a hidden input)

FilterSubmit — list-page filter button; disabled until the form changes, so an unchanged filter can't push a duplicate history entry

SearchSelect — autocomplete over the catalog (reservation gear picker, blackout targets, account impersonation); disabled entries explain themselves. Optional showAllWhenEmpty (focus reveals a small list), busy (the shared rainbow underline while a pick applies in place), and blurOnPick (single-shot pickers defocus after a pick instead of re-focusing for the next). Pass an empty label (plus ariaLabel) to drop the eyebrow when the field sits under its own heading.

DirectoryTree — master-detail sidebar (copy console, library): header rows, connector lines, dim entries, status dots; the right-edge divider drags to resize

CollapsibleRail — collapsible side rail (office nav, conversations menu); the ‹/› handle rides the neighboring column's divider and the choice persists per browser

main column — owns the divider the handle rides

EmptyState — dashed placeholder for an empty list

No reservations yet.

Toast — transient save feedback for ON-CHANGE controls (auto-saving selects/toggles); button forms keep the inline SavedNote

SavedNote — inline post-save confirmation next to the submitting control (default · soft-action · detail variants)

Saved.Updated.Added.Saved. 3 fields updated.

FormResult — inline success/error for button-submit forms (wraps SavedNote on ok, a red note on error; renders nothing while pending or before submit)

Saved.Added.That email already has access.

SegmentedToggle — per-user display setting (theme / currency / table layout)

theme

async save (simulated)

Switch — a single boolean setting (e.g. a session's public/private share); same async-save ring as SegmentedToggle

RainbowUnderline — async-save indicator for border-b selects/inputs (rename field, permissions selects); a 1px hue-cycling line while saving

RainbowRing — async-save indicator for rounded controls (the ring behind SegmentedToggle / Switch); a 1px hue-cycling ring while saving

rounded control

SignatureCanvas — draw-to-sign pad (asset-report counter e-signature); black ink on white paper regardless of theme, mirrored into a hidden input as a PNG data URL

Sign above with a finger, stylus, or mouse.

pad is empty

OfficeMark — square monogram stamp (mobile menu-trigger label)

SDCMDECOL