Internal reference

Design system

Every token, component and state the site is allowed to use. If a pattern is not on this page it does not exist yet. Add it to src/styles/global.css or a component in src/components/, then show it here.

390 px

Check 390 first. The reference phone width is 390 px and the hard floor is 360 px. Nothing may scroll sideways at either size. Test every grid, table and button row at 390 before you call a page done.

Tokens

Color

The LST family palette. Green acts, blue identifies, ink carries the words. Nothing else enters the page.

brand-green #5B9428

Primary action. Buttons, spread, confirmations.

brand-green-light #99CA3B

Accent on dark grounds only. Never a button.

brand-blue #029DE0

Identity. Links, eyebrows, focus ring, active nav.

brand-blue-dark #0277A8

Blue text on white. Passes contrast.

ink #344346

Body text, dark grounds, footer, admin rail.

slate #677B7C

Secondary text, labels, captions.

panel #D3DDDE

Hairlines, borders, dividers, quiet chips.

surface #F6F8F8

Alternating section ground.

danger #C0392B

Destructive actions and errors.

warn #FFA900

Pending status and star ratings.

Shadow

--shadow-card

Shadow

--shadow-lift

Signature rule

.state-rule

Tokens

Type scale

Playfair Display 700 for headings, Inter 400 and 600 for everything else. Both self hosted, both preloaded. Sizes are fluid, so never hardcode a pixel size.

--t-display

Hero only. One per page.

Display: Louisville and Southern Indiana

--t-h1

Page title.

Heading 1: Louisville and Southern Indiana

--t-h2

Section title.

Heading 2: Louisville and Southern Indiana

--t-h3

Card and block title.

Heading 3: Louisville and Southern Indiana

--t-h4

Inline subhead.

Heading 4: Louisville and Southern Indiana

--t-lead

Standfirst under a heading.

Lead: Louisville and Southern Indiana

--t-body

Inter 400 at 1.65 line height.

Body: Louisville and Southern Indiana

--t-small

Captions, helper text.

Small: Louisville and Southern Indiana

--t-micro

Eyebrows and ledger labels.

Micro label: Louisville and Southern Indiana

Eyebrow with rule

Section heading pattern

Eyebrow, heading, lead. Use <Section> and you get this spacing for free.

Eyebrow without rule

Numbers set tabular

$114,900 / $186,000 / $38,400

Add .tnum to any figure so columns line up.

Components

Buttons

Four variants, three sizes. Solid fills, 12 px radius, 44 px minimum touch target. Primary is the only green thing on the screen.

Variants at default size

Sizes

Links render as anchors

Disabled and full width

On a dark ground

Components

Status badges

Status wording lives in Badge.astro so every grid, detail page and admin table says the same thing.

Outline, for text rows

Available Pending Sold New Listing Draft Needs Review

<Badge status="available" dot />

Solid, for photo overlays

Available Pending Sold New Listing

<Badge status="new" solid /> sits on the first photo of a card.

Custom label, status color

Short sale Draft Featured Needs review

Signature

The deal ledger

Investors read numbers, not prose. Every deal card and deal page shows the same ruled underwriting block, with the spread called out. This is the thing the competition does not have.

Asking $114,900
ARV $186,000
Est. repairs $32,700
Est. spread $38,400
Est. rent $1,450 / mo

How to use it

Wrap rows in .ledger. The first row takes .ledger-row-lead so the asking price reads largest. The derived spread takes .ledger-row-accent. Values carry tabular figures automatically, so a column of prices always lines up.

Spread is ARV minus asking minus estimated repairs. Omit the row when any input is missing rather than printing a zero.

Property fact row

Beds 3 Baths 2 Sqft 1,348 Built 1952

Components

Surfaces and grounds

Four grounds, in this order down a page: white, surface, white, ink. Cards never sit on cards.

.card

White, hairline border, soft ink shadow. The default container.

.card-interactive

Adds the hover lift. Only for cards that are a link.

.panel-quiet

Surface ground with a border. For notes and side rails.

Components

ReviewStrip

One set of trust numbers, read from TRUST in constants.ts. Never type a rating into a page.

variant="bar" on surface, then on ink, then variant="cards".

500+ Transactions completed Across Kentucky and Indiana
13+ Years buying Same local team since 2013
4.6 Google rating Read the reviews A+ BBB rating Accredited profile
500+ Transactions completed Across Kentucky and Indiana
13+ Years buying Same local team since 2013
4.6 Google rating Read the reviews A+ BBB rating Accredited profile
500+ Transactions completed Across Kentucky and Indiana
13+ Years buying Same local team since 2013
4.6 Google rating Read the reviews A+ BBB rating Accredited profile

Components

Form fields

Plain classes, no component wrapper, so server rendered forms stay simple. Every control is at least 44 px tall and every label is a real label.

As it should appear on the contract.

Enter a 10 digit number we can text.

Choices


Filter chips


Flash messages

You are on the list. Deals are unlocked.

That email or password did not match. Try again.

Components

Gating affordances

Logged out visitors see a masked card. The server never sends the street number, the description or the second photo. These classes only dress what is already safe.

New Listing

Single family home

$114,900

00000 Street Name

Louisville, KY 40214

Address and numbers locked

Free account, instant access.

Unlock this deal

Redacted text

1556 E 8th St 3 bed

.redacted paints a flat panel bar. It is a visual placeholder for data that was never rendered, not a blur over real text.

Lock panel alone

Members only

Photos, deal sheet and map.

Create a free account

Components

FaqAccordion

Native details and summary. Keyboard operable, no JavaScript, animated open where the browser supports it.

What does it cost to join the buyer list?

Nothing. Creating an account is free and there is no membership tier. You pay the contract price plus your own closing costs.

How fast do I need to move on a deal?

Most properties go under contract within 48 hours of hitting the list. Earnest money is due within 24 hours of acceptance and closings run 21 days or less.

Can I walk the property before I commit?

Yes. Every listing shows a showing window. Book a walkthrough from the deal page and we will meet you there or send lockbox details.

Pass schema on one block per page to emit FAQPage structured data, and exclusive when only one item should stay open.

Shells

Layouts

Three shells cover the whole site. Pages never write their own html head.

BaseLayout

Header, footer, skip link, flash messages, SEO. Every public page.

title, description, canonical, ogImage, noindex

AuthLayout

Centered card on a brand gradient, with an optional proof panel beside it. Signup, login, password reset.

heading, lead, wide, slot "aside"

AdminLayout

Ink rail on the left, dense work area on the right, tab strip on mobile. Noindex by default.

heading, lead, slot "actions"

Section

Owns vertical rhythm and the heading block. Grounds: white, surface, panel, ink. Spacing: tight, default, loose, none. Everything on this page is wrapped in one.

Dark ground

Chrome restyles itself on ink

Add data-ground="dark" to any dark container. Eyebrows, secondary buttons, ghost buttons and the focus ring all switch automatically.

New Listing Pending

Copy

Writing rules

Do

  • Name the action. "Get free access", not "Submit".
  • Keep the same verb through a flow. Publish leads to Published.
  • Use periods, commas or parentheses for a pause.
  • Pull every phone number and rating from constants.ts.
  • Say what is locked and what it costs to unlock. Nothing.

Do not

  • No em dashes anywhere in public copy. The copy lint fails the build.
  • No placeholder text and no unfinished work markers in src/pages.
  • No second set of trust numbers.
  • No street address in logged out markup, including alt text and slugs.
  • No new green. The palette is closed.