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.
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
<Badge status="available" dot />
Solid, for photo overlays
<Badge status="new" solid /> sits on the first photo of a
card.
Custom label, status color
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.
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
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".
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.
Single family home
$114,900
00000 Street Name
Louisville, KY 40214
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
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.
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.