Design system reference

Alpine Lodge

The Wooden Hotel Kazbegi design system. Outdoorsy and earthy — bark wood, deep forest, alpine stone and harvest gold — with every color pairing meeting WCAG 2.1 AA contrast. All tokens live in public/css/styles.css under :root.

Color

Four families: bark (wood browns) for dark surfaces and headings, forest greens for actions, stone neutrals for backgrounds, and gold for warm accents. Feedback colors handle success, warning and danger states.

Bark — dark surfaces & headings

#221b14
Wood 900--wood-900Footer, page headings
#32291f
Wood 800--wood-800Header bars, trust band, dark panels
#4f4232
Wood 700--wood-700Chip text, secondary emphasis on light
#71624e
Wood 500--wood-500Rarely — muted brown accents

Forest — actions & brand green

#3d6450
Forest 500--forest-500Primary buttons, links, focus rings
#2c4639
Forest 700--forest-700Button hover, reviews band, outline-button text

Gold — warm accent (two rules, one exception)

#c79a53
Gold 500--gold-500Badges & logo mark. On dark surfaces only
#d8b46e
Gold 400--gold-400Icons & link hovers on dark surfaces only
#7d6029
Gold 700 (ochre)--gold-700The only gold allowed as text on light backgrounds
DoUse gold-500/400 on wood or forest surfaces; use gold-700 for eyebrows, weekend price tags and gold text on stone or white.
Don'tPut gold-500 or gold-400 text on a light background — both fail WCAG contrast (≈2.4:1). Exception: gold-500 as a badge fill with wood-900 text is fine (6:1).

Stone — neutrals (no yellow)

#ffffff
White--whiteCards, panels, modal surfaces
#f7f7f3
Stone 50--stone-50Page background, text on dark surfaces
#edeee7
Stone 100--stone-100Soft panels, chips, secondary buttons
#dfe1d6
Stone 200--stone-200Hover states, deeper panels
#24251f
Ink--inkBody text
#5a5b51
Ink soft--ink-softSecondary text — AA on stone 50 & 100
#d9dbce
Line--lineHairline dividers only — never text
#e7ebe4
Field--fieldSage-mist input fill

Feedback

#2c6b45
Success 700--success-700Confirmation text
#e2f0e8
Success 100--success-100Success tint, own message bubbles
#96591b
Amber 700--amber-700Warnings, low availability, pending
#f5e9d7
Amber 100--amber-100Warning tint
#a83a2e
Danger 700--danger-700Error text
#b3453b
Danger 500--danger-500Destructive buttons (hover: --danger-600)
#f7e4de
Danger 100--danger-100Error / cancelled tint (wash: --danger-50)

Typography

Fraunces (serif) for headings and prices — warm and characterful. Inter (sans) for everything else. Body line-height is 1.6; headings 1.12.

--font-serif 600
clamp(2.5–4.4rem) · hero only
Sleep beneath Kazbek
--font-serif 600
clamp(1.9–2.8rem) · section titles
Rooms with a view
--font-serif 600
1.2–1.4rem · card & panel titles
Junior Suite with Mountain View
--font-sans 400 · 1rem
color --ink
Body copy. Our family has hosted travellers at the foot of Mt Kazbek for two generations — book direct and the savings stay in the valley.
--font-sans 400 · 0.9–0.95rem
color --ink-soft
Secondary text for hints, captions and supporting detail. Never smaller than 0.72rem.
--font-sans 600 · 0.8rem
letter-spacing 0.16em · --gold-700
Eyebrow · section kicker
--font-sans 600 · 0.78rem
letter-spacing 0.06em · --ink-soft
Form label

Spacing

A 4px base scale. Odd values in older code are being migrated to the nearest step.

4px
Icon-to-text gaps
8px
Chip gaps, tight stacks
12px
Related items in a group
16px
Default gap between elements
20px
Card grid gaps, page gutter
24px
Card padding
32px
Between component groups
40px
Section head to content
56px
Large section breaks
72px
Section vertical padding (52px mobile)

Rule: default to generous, not tight. The 16px "default gap" is for elements within one group — labels and their inputs, a run of chips. The moment content splits into distinct groups (a room type's checkboxes, a cluster of stat cards, one settings block vs. the next), separate them by at least 32px. Reaching for 8–16px between groups is what makes a screen read as cluttered even when nothing is technically overlapping — leave room to breathe.

Shape & elevation

Flat design — no drop shadows, no decorative borders. Depth comes from surface color steps (white → stone-100 → stone-200). The softly-squared controls (buttons & form fields) carry a 12px radius, plain rounded (no squircle) — they're focusable and a squircle can only be applied by clipping the box, which would cut off the keyboard focus ring. Larger panels/cards (search card, room cards, modals, etc.) aren't focusable, so those get a real squircle curve instead of a plain circular corner, computed and applied as a clip-path by /js/squircle.js (a CSS-only corner-shape property exists for this, but current Chrome parses it without actually painting the curve — it silently renders a hard, un-rounded corner instead of falling back gracefully, so we don't rely on it).

--radius-btn · 12pxButtons, form field inputs (softly squared)
--radius-sm · 10pxAlerts, small tags
--radius · 16pxPanels
--radius-lg · 24pxCards, modals
999px · pillChips, badges

Buttons and form fields are deliberately square-cornered, not pill-shaped — the agency portal (/platform) is a separate product with its own style guide (platform.css) and keeps the pill look; don't cross-pollinate the two.

✕ Wrong
✓ Right

Rule: state reads from fill color alone — never add a border on top of it. A closed calendar day, a restricted-room tag, an error banner, an unpaid notice: color says everything, so a matching-hued outline is always redundant clutter. The only exception is outline buttons, where the border is the button's whole identity (View Rooms on the hero, Update search on the rooms page, Change dates) — never add a border anywhere else.

Buttons

Softly-squared (12px radius, plain rounded), Inter 600, 13px×24px padding (16×30 for large). One primary action per view.

.btn-primary / .btn-forest / .btn-dark forest-500 → forest-700 on hover · .btn-outline-forest green text + outline, no fill · .btn-outline stone fill · .btn-danger danger-500 → 600

Rule: primary buttons are green (forest-500) on every light surface — white/cream cards, panels, modals. That covers almost every button on the site (room cards, booking modal, manage-booking panels). They only switch to gold when they sit directly on a dark surface with no light card behind them — the hero photo before the header scrolls solid, and the reservation page's dark header bar. Never use gold on a light card; never use green directly on a photo or dark bar.

.btn-ghost translucent white fill, white text — only on dark imagery or wood surfaces · .btn-primary flips to gold-400 here (see .site-header:not(.solid) .btn-primary and .res-header .btn-primary) for contrast against dark backgrounds

Form fields

Borderless, softly-squared (12px radius, textareas included) with three interaction tiers. All rings are zero-blur — flat, no glow. Labels are uppercase 0.78rem ink-soft, always outside the field; placeholders are hints, never labels. Try the fields below.

Interaction tiers

Badges, chips & status

Direct booking Mountain view Free WiFi Pending Confirmed Cancelled

Gold badge = the one place gold-500 sits on light layouts (as a fill with wood-900 text, 6:1). Status chips pair a 700-level text tone with its 100-level tint.

Alerts

Your dates have been updated.
Only 2 rooms left for these dates.
That room isn't available for those dates.

Message thread

Sender's own messages sit right in success-100; the other party sits left in stone-100. Meta line is uppercase 0.72rem ink-soft.

You · Jul 7, 9:32 AM
Can you arrange an airport pick-up?
Wooden Hotel · Jul 7, 9:40 AM
Of course — send us your flight number and we'll be there.

Accessibility

Every text/background pairing in this system meets WCAG 2.1 AA (4.5:1 body text, 3:1 large text & UI). Key pairings:

PairingUsed forRatioAA
Aaink / stone-50Body text15.9:1Pass
Aaink-soft / stone-100Secondary text on panels5.9:1Pass
Aastone-50 / forest-500Primary buttons6.2:1Pass
Aaforest-700 / whiteSecondary button text9.8:1Pass
Aagold-700 / stone-50Eyebrows, weekend tags5.5:1Pass
Aawood-900 / gold-500Gold badges6.0:1Pass
Aastone-100 / wood-800Header & footer text12.4:1Pass
Aaamber-700 / amber-100Pending / warning chips4.7:1Pass
Aadanger-700 / danger-100Errors, cancelled chips5.1:1Pass
Aasuccess-700 / success-100Success alerts5.4:1Pass

Rules

Voice & tone