--- version: alpha name: salt-and-iron-design description: "A warm charcoal canvas (#1a1512) with cream ink (#efe6da), rust (#b5502e) and ember (#e8823a) as the only accents, no cool colors anywhere, no white background, ever. Playfair Display carries display type at weight 700; Inter carries body copy. The system reads as durable-goods honest: plainspoken, physical, unhurried, an object you buy once." --- ## Brand Positioning Salt & Iron makes one thing: a cast-iron skillet designed to be the last one you ever buy. It exists because cookware marketing sells a lifestyle, a kitchen aesthetic, a Sunday-morning fantasy, when what a cook actually wants is a pan that works and keeps working. Salt & Iron's bet: the object itself is the whole pitch. No influencer photography, no seasonal colorways, no loyalty points. Every visual decision below serves that one bet. If a component performs delight instead of describing the object honestly, or if it borrows glossy e-commerce chrome (star ratings, coupon banners, cart badges, countdown timers), it doesn't belong in this system. There is no shop here, only the object, and the warm ember light it sits under. colors: accent: "#b5502e" accent-alt: "#e8823a" accent-text: "#c96a44" ink: "#efe6da" ink-muted: "#a89684" canvas: "#1a1512" surface: "#231c17" surface-raised: "#2c231c" border: "#3a2f26" focus-ring: "#e8823a" ## Logo / Wordmark System The mark is the pan seen from directly above: an iron rim with two rings of built-up seasoning inside it, heat radiating inward from raw iron at the edge to full ember at the center, a stub handle exiting to the right. It is not a generic skillet icon, it's a literal cross-section of what the signature interaction shows happening to the pan as you scroll. ```svg ``` - **Lockup**: mark, then a `0.6rem` gap, then the wordmark "Salt & Iron" in Playfair Display 700, mark always left of the wordmark, never stacked, never reversed. - **Ring order is fixed**: outer rim in `--ink` (the raw iron body), middle ring in `--accent` (rust, seasoning taking hold), inner ring in `--accent-alt` (ember, fully cured). This is heat radiating inward. Reversing the order, or making the center the coolest ring, breaks the metaphor and is never done. - **Minimum size**: mark not smaller than `20px` tall, below that the two inner rings blur into one line. Wordmark not smaller than `0.85rem`. - **Clearspace**: empty margin equal to the mark's own width (26px at default size) on all sides of the lockup. - **Don't**: recolor the rings, the sequence is load-bearing. Don't fill the pan circle solid, it represents the open cooking surface, a void, not a disc. Don't mirror the lockup so the handle points left. Don't use the mark alone as a bullet or decorative list marker. Don't render it on anything but `--bg` or `--surface`. ## Color System ### Roles | Role | Token | Value | Used for | |---|---|---|---| | Canvas | `--bg` | `#1a1512` | Page background, the only background this site has | | Surface | `--surface` | `#231c17` | Cards, form fields, nav bar, panels | | Surface raised | `--surface-raised` | `#2c231c` | Hover state on a surface, input focus background | | Border | `--border` | `#3a2f26` | Card edges, dividers, input outlines, table rules | | Ink | `--ink` | `#efe6da` | Primary text, headlines, the pan rim in the mark | | Ink muted | `--dim` | `#a89684` | Secondary text, captions, placeholders, neutral status ("Waitlist") | | Rust | `--accent` | `#b5502e` | Structural accent: borders, dividers, large display type, the mark's middle ring, the "raw / attention" material state | | Rust, text-safe tint | `--accent-text` | `#c96a44` | The only place rust appears as small readable text (error copy), see the contrast note below | | Ember | `--accent-alt` | `#e8823a` | Primary button fill, focus ring, links, the mark's inner ring, the "seasoned / positive" material state | There is deliberately no third hue for "warning" or "info." Every state this brand needs to show, raw or seasoned, waiting or ready, invalid or confirmed, already exists in the material itself: rust reads as attention, ember reads as done. Adding a blue "info" chip or a green "success" checkmark would cool the palette, which the brand's own Don't list forbids outright. Availability copy that isn't rust or ember (a neutral "still waiting" state) uses `--dim`, never gray-blue. ### Neutral / surface scale `--bg` (`#1a1512`) is darkest, `--surface` (`#231c17`) sits one step up for anything that needs to read as a distinct panel, `--surface-raised` (`#2c231c`) is the hover/focus step above that, `--border` (`#3a2f26`) is the lightest neutral and is reserved for hairlines, never fills. All four are warm browns, none dip toward gray or blue at any lightness step. ### Contrast (computed from the hex values above via WCAG relative luminance) | Pairing | Ratio | Passes | |---|---|---| | `--ink` text on `--bg` | ~14.7:1 | AAA | | `--ink-muted` text on `--bg` | ~6.35:1 | AA (body text) | | `--accent-alt` text on `--bg` (links, focus glow, ember status) | ~6.63:1 | AA, near AAA | | `--accent` text on `--bg` (rust) | ~3.58:1 | Large text / non-text UI only (3:1), fails body text | | `--bg` label on `--accent-alt` fill (primary button) | ~6.63:1 | AA, near AAA | | `--ink` on `--surface` | ~13.6:1 | AAA | | `--ink-muted` on `--surface` | ~5.89:1 | AA | | `--accent-alt` on `--surface` | ~6.15:1 | AA | | `--accent` on `--surface` | ~3.32:1 | Large text / non-text UI only | | `--accent-text` on `--bg` (error copy) | ~4.85:1 | AA (body text) | | `--ink` on `--border` | ~10.5:1 | AAA | The rule this table exists to enforce: `--accent` (rust) only clears the 3:1 threshold, not 4.5:1, so it is never used for small body copy or button labels, only for borders, large display type (24px and up), and the mark. Anywhere rust needs to appear as small readable text (the error state on the waitlist form), it uses `--accent-text`, a lightened tint of the same hue tuned specifically to clear AA, not a new color. Every fill-and-label pairing on this page uses `--accent-alt` fill with `--bg` label, the one combination proven above the AA line regardless of font size. typography: display: fontFamily: Playfair Display fontWeight: 700 body: fontFamily: Inter fontWeight: 400 ## Type Scale | Token | Size | Weight | Family | Line-height | Letter-spacing | Used for | |---|---|---|---|---|---|---| | `--text-display` | `clamp(2.75rem, 6vw, 5rem)` | 700 | Playfair Display | 1.05 | -0.01em | Hero H1 only | | `--text-h2` | `clamp(1.75rem, 3vw, 2.25rem)` | 700 | Playfair Display | 1.15 | 0 | Section headings | | `--text-h3` | `1.25rem` | 600 | Playfair Display | 1.3 | 0 | Card/entry titles | | `--text-spec-value` | `clamp(1.75rem, 3vw, 2.25rem)` | 700 | Playfair Display | 1.1 | 0 | The large number in a specification card | | `--text-body` | `1rem` | 400 | Inter | 1.65 | 0 | Paragraph copy | | `--text-small` | `0.85rem` | 400 | Inter | 1.5 | 0.01em | Nav utility links, footer, labels, helper/error text | | `--text-button` | `0.95rem` | 500 | Inter | 1 | 0.01em | Button and badge labels | Rule for Playfair vs. Inter: Playfair Display is reserved for display moments, the hero headline, the wordmark, section headings, card and entry titles, and the big number in a specification card. Body copy, nav links, button labels, form labels and inputs, and table cells are always Inter. If the content is a piece of copy meant to be read quickly, it's Inter. If it's a moment meant to feel like the object itself (a heading, the brand name, a spec number), it's Playfair. ## Spacing Scale Base unit `8px`. Tokens in use: `--space-2: 0.5rem`, `--space-3: 1rem`, `--space-4: 1.5rem`, `--space-6: 2rem`, `--space-8: 3rem`, `--space-12: 4rem`. ## Shape One radius, `--radius: 6px`, used everywhere: buttons, cards, inputs, spec tiles. This is a deliberate departure from the pill-shaped buttons a generic marketing site reaches for. A fully rounded pill button reads as soft, friendly, consumer-SaaS, exactly the glossy chrome this brand's Don't list rules out. A small, even chamfer reads as forged and cut, not molded plastic. Nothing on this page rounds further than `6px`, and nothing is sharp-cornered either, cast iron has an eased edge, not a knife edge. ## Iconography No icon library. The only non-text graphics on the page are the logo mark and a single small status dot used on the availability indicator, ring-colored to match the mark's inner ring (`--accent-alt` when ready, `--dim` when waiting). That dot is the one place this system uses a decorative-looking glyph, and it only appears there because it carries real state, not as page furniture. If a future page needs more iconography, the fallback is Phosphor, filled/duotone style at `1.5` stroke rather than thin outline, warm-toned to match the brand rather than left at library default black. That decision hasn't been needed yet. ## Motion Principles Scroll cross-fades the cast-iron pan through its seasoning states, raw, seasoning, fully seasoned and glowing, via a WebGL material shader tied directly to scroll position, roughness and metalness shifting together with color so it reads as a real physical transformation, not a color crossfade. The pan's rotation only advances as far as the reader has scrolled; it never spins on its own faster than that. This is the one signature animation on the page and it is left exactly as built. Every other motion on the page (buttons, inputs, nav, form states) uses only `:hover`/`:active`/`:focus-visible` CSS transitions, no scroll-triggered reveals anywhere else. Under `prefers-reduced-motion: reduce`, the scene skips the scroll listener and the ambient idle rotation entirely and renders once, statically, in the fully-seasoned end state, the same "render the end state immediately" rule every other system in this gallery follows. ### Never-list (written before the impeccable-pass fix) 1. No CTA button inside the hero copy, the object and the material transformation are the whole pitch, the primary action already lives once in the nav. 2. No new hue for the reduced-motion static state, reuse the documented rust/ember palette only. 3. No scroll- or autoplay-driven motion left unguarded by `prefers-reduced-motion`, this pass closes that gap. 4. No seventh specification card, six is the deliberate ceiling. 5. No chrome overlapping the WebGL canvas beyond the nav and footer. ## Voice & Tone Plainspoken, durable, a little stubborn. This is a tool, not a lifestyle brand, so copy stays short and says the plain thing. In practice: - **Button label**: "Join the waitlist", not "Unlock early access to the collection" - **Edge-case message**: "Enter a real email.", not "Oops! That doesn't look quite right" - **Empty / waiting state**: "Waitlist open. Next batch in about six weeks.", not "Stay tuned, exciting things are coming!" - **Success message**: "You're on the list. We'll write when it's ready.", not "Woohoo! You're all set!" ## Accessibility Baseline - Focus ring: `2px solid var(--accent-alt)`, `2px` offset, applied via `:focus-visible` on every interactive element (links, buttons, inputs), never removed without a visible replacement. Ember was chosen deliberately over a generic blue, it's the brand's own "hot" color, so even the focus state stays in-palette. - Reduced motion: all CSS transitions and the skeleton/loading treatment respect `prefers-reduced-motion: reduce`, and, as of the impeccable pass, so does the WebGL seasoning scene, see Motion Principles. - Minimum tap target: `44px` in the smallest dimension for every button and input on touch viewports. - Color is never the only signal: the waitlist form pairs its error border with an inline message, not just a rust outline; the availability dot pairs its color with a plain-language word ("Waitlist open" / "In stock"), never color alone. ## Components ### Navigation Single-line bar, `68px` tall, `--surface` background at high opacity with a `--border` bottom hairline, sticky to the top, sits above the WebGL canvas so page chrome stays legible regardless of what the pan is doing behind it. Left: the mark + wordmark lockup. Right: a "Care & Specifications" link, a "Back to gallery" utility link, and one primary button ("Join the waitlist"). No dropdown, no hamburger, this is a two-page site. ### Buttons Three variants, one radius (`--radius`), no pill shape: - **Primary**: `--accent-alt` fill, `--bg` label, used once per view for the real action ("Join the waitlist"). - **Secondary**: transparent fill, `1px solid var(--accent)`, `--ink` label. Same-page anchor jumps ("See specifications"). - **Ghost**: text-only, `--dim` label, `--ink` on hover. Tertiary actions like "Back to gallery." All variants define `:hover` (fill brightens or border shifts to `--accent-alt`), `:active` (`transform: scale(0.98)`, a physical push), `:disabled` (`opacity: .45`, `pointer-events: none`, never color alone), and `:focus-visible` (`--accent-alt` outline). Button and badge labels always use the fill/label pairing proven in the contrast table above. ### Cards / panels A flat `.panel`: `--surface` background, `1px solid var(--border)`, `--radius`, no shadow, no gradient, no glass. Used for specification tiles and the availability panel. Elevation reads through the border and background step, never a drop shadow. ### Specification cards Not a hairline-row spec table. Six specs, each its own card in a 2-column grid on desktop (1-column under `768px`): a small `--dim` label at top, a large `--text-spec-value` number in Playfair, and one short `--text-body` line underneath explaining why that number matters to a cook, not just stating it. This is the deliberate alternative to a long `border-b`-per-row table, which reads as a spreadsheet, not an object description. ### Waitlist / availability form Label above input in `--text-small`/`--dim`. Input: `--surface` background, `1px solid var(--border)`, `--radius`, `--ink` text, `--dim` placeholder, never placeholder-as-label. On `:focus`, border becomes `--accent-alt`, background steps to `--surface-raised`, and the focus ring applies. On error, the border becomes `--accent` (rust) and the helper text switches to `--accent-text`, the AA-safe rust tint, with a plain-language message. On success, border and helper text move to `--accent-alt` (ember, the "seasoned" positive color) and the input disables. A small availability line sits above the form using the same warm palette only: `--dim` for "Waitlist open," `--accent-alt` for "In stock," never a blue or gray-blue "info" tone. ### Footer Two rows: brand name and tagline on the left, real page links on the right (Care & Specifications, Back to gallery). A short line about the philosophy of the object (no warranty language, no shipping/returns policy chrome) rather than invented legal text. ### Care page typography The Care & Specifications page reuses the exact type scale and specification-card component off the hero, proving the tokens hold up in a plain reading layout: a page header (`--text-h2`, not the giant hero display), body paragraphs at `--text-body`/65ch measure, a short ritual list using plain verb labels (Wash, Dry, Oil, Store) rather than "Step 1/2/3" numbering, and the same spec-card grid reused for the pan's physical facts. ## Do's and Don'ts ### Do - Let material states (raw to seasoned to glowing) read as a real physical transformation, roughness and metalness shifting together, not just a color crossfade. - Keep copy plainspoken and short, this is a tool, not a lifestyle brand. - Use warm, low, ember-toned lighting throughout, even at rest. - Reserve `--accent` (rust) for large display type, borders, and non-text UI, never for small body or button text, where it fails AA contrast. - Fill primary actions with `--accent-alt` (ember) and label them in `--bg`, the one fill/label pairing proven readable at every size. - Keep the shape language forged, not soft: one small chamfer radius everywhere, no pill buttons, no fully rounded chips. - Let availability speak in `--dim` (neutral, waiting) or `--accent-alt` (ember, ready), never a blue or green status color. ### Don't - Don't add glossy e-commerce chrome, star ratings, coupon banners, cart badges, there is no shop here, only the object. - Don't rotate the 3D object faster than the scroll implies, motion should feel earned by the reader's own scrolling, not autoplaying. - Don't cool the palette, no blues, no white backgrounds, ever, not even for a status indicator. - Don't reach for a pill-shaped button or badge, that fully rounded shape reads as glossy consumer software, not forged iron. - Don't add a shop cart, price tag, or checkout flow, the waitlist form is the only "commerce" this brand shows. - Don't use `--accent` (rust) as small body or button text, it only clears AA at large/bold display sizes or as a border/icon. - Don't invent a fourth hue for error or warning states, reuse `--accent` (raw, attention) and `--accent-alt` (seasoned, positive) the same way the material states already carry meaning. ## Known Constraints - Two routes now exist (product home, Care & Specifications), still no pricing/checkout page and no responsive breakpoint table beyond a single-column mobile collapse for the spec grid and nav. - The waitlist form is not wired to anything real, this is a concept demo.