---
version: alpha
name: afterburn-design
description: "A near-black studio panel built on a #0d0906 canvas and #f5efe8 text, with burner orange (#ff4d2e) as the working accent and signal amber (#ffcf5c) as the reading accent. Anton carries every number and headline, Work Sans carries the prose and every control label. Nothing rounds. The page is laid out around a vertical intensity gauge that reads the studio floor live, so the gauge, not a centered headline, decides where everything sits."
---
## Brand Positioning
Afterburn is a strength and conditioning studio for people who have already been sold on exercise and are tired of being sold on it again. It exists because most gym sites are a stock photo of a stranger mid-burpee, a blurred room behind a "Book a class" button, and a wall of class times that tells you nothing about what the hour will actually cost you. Afterburn's bet: the one number a member needs is intensity, so put a gauge on the page, wire it to the real timetable, and let it drive the layout instead of decorating it. Every decision below serves that bet. The gauge is the structure: the ticker sits at its top, the headline sits at its baseline, and the class board opens one card at a time as the gauge climbs past each class's own reading. If a component does not help someone judge how hard an hour will be, or does not come from a real studio interaction (a timetable, a spot count, a waitlist), it does not belong in this system.
colors:
accent: "#ff4d2e"
accent-hot: "#ff6a4f"
accent-alt: "#ffcf5c"
ink: "#f5efe8"
ink-muted: "#a89a90"
canvas: "#0d0906"
surface: "#17100b"
surface-raised: "#221710"
border: "#33241a"
border-strong: "#4a3527"
border-ui: "#7a5c45"
focus-ring: "#ffcf5c"
## Logo / Wordmark System
The mark is the gauge, at 16 by 24. A `--border-strong` stroked portrait rectangle, an orange block filling its lower half, and one amber rule crossing near the top at the redline. It is not a flame, a dumbbell, or a heartbeat line. It is a 1:1 miniature of the intensity gauge component the whole page is built around, so the mark and the product are literally the same object at two sizes.
```svg
```
- **Lockup**: mark, then a `0.55rem` gap, then the wordmark "Afterburn" in Anton at `1.15rem`, `.05em` tracking, uppercase. The mark is always left of the wordmark and always portrait. Never stacked, never reversed, never laid on its side.
- **Minimum size**: mark not smaller than `14px` wide by `21px` tall, below that the fill block and the amber redline collapse into one smudge. Wordmark not smaller than `0.9rem`.
- **Clearspace**: empty margin equal to the mark's own width (16px at default size) on all four sides of the lockup. The nav's edge padding counts against this, nothing else docks closer.
- **Don't**: don't recolor the mark for a light background, it only ever renders on `--panel` or `--bg`. Don't fill the block past the amber rule, a permanently redlined mark contradicts the gauge it is a picture of. Don't rotate it to landscape. Don't use the mark alone as a bullet or a list marker, it means "this is Afterburn," not "here is an item." Don't swap the two accents, orange is always the fill and amber is always the rule.
## Color System
### Roles
| Role | Token | Value | Used for |
|---|---|---|---|
| Canvas | `--bg` | `#0d0906` | Page background, table body rows, legend cells |
| Surface | `--panel` | `#17100b` | Nav, ticker, class cards, table header, footer, notice, empty state |
| Surface raised | `--surface-raised` | `#221710` | Row hover, input focus background, unlit meter segments |
| Border | `--border` | `#33241a` | Card edges, table rules, dividers, hairlines |
| Border strong | `--border-strong` | `#4a3527` | Card and panel edges that carry no interaction |
| Border UI | `--border-ui` | `#7a5c45` | Every interactive boundary: gauge track, secondary button, input, select, day filter frame, ghost underline |
| Ink | `--ink` | `#f5efe8` | Headlines, body copy, table cells, gauge readout |
| Ink muted | `--dim` | `#a89a90` | Labels, coach names, meta lines, helper text, footer hours |
| Working accent | `--accent` | `#ff4d2e` | Gauge fill, primary button, card intensity bars, "few spots left", form errors |
| Working accent hot | `--accent-hot` | `#ff6a4f` | Primary button hover only |
| Reading accent | `--accent-alt` | `#ffcf5c` | Gauge cap line, gauge zone readout, intensity numbers, "spots open", focus ring |
The two accents split by job, not by decoration. Orange is effort: it is what the gauge fills with, what a class's intensity bar is drawn in, and what the one primary button is. Amber is the reading: it is the line marking where the gauge is, the number naming the intensity, and the confirmation that a spot is open. There is deliberately no green. A studio that paints "9 spots left" green and "3 spots left" amber has invented a traffic light that says nothing about training, so availability is carried by the word and the count, with amber for open and orange only when the count is genuinely low.
Orange doubles as the form error color. That is not an accident and not a shortage: this brand has one alarm color, and a bad email and a redline effort are both "stop and look at this."
### Contrast (computed from the hex values above via WCAG relative luminance)
| Pairing | Ratio | Passes |
|---|---|---|
| `--ink` on `--bg` (headlines, body copy) | 17.4:1 | AAA |
| `--ink` on `--panel` (card copy, table cells) | 16.5:1 | AAA |
| `--ink` on `--surface-raised` (hovered table row) | 15.4:1 | AAA |
| `--dim` on `--bg` (labels, ledes) | 7.3:1 | AAA |
| `--dim` on `--panel` (coach names, footer hours) | 6.9:1 | AA |
| `--dim` on `--surface-raised` (hovered row meta) | 6.4:1 | AA |
| `--accent-alt` on `--bg` (zone readout, intensity numbers) | 13.5:1 | AAA |
| `--accent-alt` on `--panel` (open-spot status, focus ring) | 12.9:1 | AAA |
| `--accent` on `--bg` (low-spot status, error text) | 6.0:1 | AA |
| `--accent` on `--panel` (low-spot status inside a card) | 5.7:1 | AA |
| `--accent` on `--surface-raised` (low-spot status, hovered row) | 5.3:1 | AA |
| `--bg` label on `--accent` fill (primary button, selected day) | 6.0:1 | AA |
| `--bg` label on `--accent-hot` fill (primary button hover) | 7.0:1 | AAA |
| `--border-ui` control edge on `--bg` (non-text) | 3.3:1 | AA (1.4.11) |
| `--border-ui` control edge on `--panel` (non-text) | 3.1:1 | AA (1.4.11) |
| `--dim` label on `--panel` (disabled button) | 6.9:1 | AA |
`--border-strong` at 1.7:1 is deliberately kept for decorative edges only. Anything a person can click, type in, or drag gets `--border-ui`, which clears the 3:1 non-text minimum. That split is the reason there are two border tokens rather than one.
The rule this table exists to enforce: anything filled with `--accent` labels itself in `--bg`, never in `--ink` and never in white. `--ink` on `--accent` measures 2.9:1 and fails outright. The second rule: the focus ring is `--accent-alt`, not `--accent`, because the ring has to stay visible when it lands on the orange primary button, and amber on orange is the only pair here that reads.
typography:
display:
fontFamily: Anton
fontWeight: 400
body:
fontFamily: Work Sans
fontWeight: 400
## Type Scale
| Token | Size | Weight | Family | Line-height | Letter-spacing | Used for |
|---|---|---|---|---|---|---|
| `--text-mast` | `clamp(2.9rem, 8vw, 6.25rem)` | 400 | Anton | 0.88 | 0.005em | Homepage H1 only |
| `--text-page-h1` | `clamp(2.4rem, 6vw, 4rem)` | 400 | Anton | 0.92 | 0 | Second-page H1 |
| `--text-h2` | `clamp(1.4rem, 3vw, 2.4rem)` | 400 | Anton | 1.0 | 0 | Section headings |
| `--text-readout` | `3rem` | 400 | Anton | 0.8 | 0 | The gauge's live number |
| `--text-h3` | `1.75rem` | 400 | Anton | 1.0 | 0.02em | Class names on the board |
| `--text-clock` | `1.95rem` | 400 | Anton | 1.0 | 0.02em | Class start times |
| `--text-body` | `1rem` | 400 | Work Sans | 1.6 | 0 | Paragraph copy |
| `--text-small` | `0.86rem` | 400 | Work Sans | 1.55 | 0 | Table cells, footer links, meta lines |
| `--text-label` | `0.7rem` | 600 | Work Sans | 1 | 0.16em | Section eyebrows, form labels, footer headings |
| `--text-control` | `0.78rem` | 600 | Work Sans | 1 | 0.1em | Button and nav labels, uppercase |
| `--text-micro` | `0.6rem` | 700 | Work Sans | 1 | 0.08em | Gauge zone names, meter zone names |
Rule for Anton versus Work Sans: Anton is reserved for headlines and for numbers that mean something, the gauge readout, a class's start time, an intensity value, a zone range. Everything a person reads as a sentence or clicks as a control is Work Sans. Anton has one weight and no italic, so hierarchy inside a heading comes from size and from color, never from a fake bold. Work Sans carries all four weights it needs: 400 for prose, 600 for labels and controls, 700 for micro-type that has to hold at `0.6rem`.
Anton is a condensed all-caps display face, so it is never set below `1.7rem` and never used for more than two lines of copy. Below that size it stops being emphatic and starts being hard to read.
## Spacing Scale
Base unit `8px`. Tokens in use: `--space-1: .25rem`, `--space-2: .5rem`, `--space-3: 1rem`, `--space-4: 1.5rem`, `--space-6: 2rem`, `--space-8: 3rem`, `--space-12: 4rem`. Two structural constants sit outside the scale because they are measured, not spaced: `--rail-w: 168px` (the gauge column, `82px` below 720px) and `--measure: 1040px` (the widest a class card or the zone legend is allowed to grow, so the right-hand time column never drifts away from the copy on a wide screen).
## Shape
There is no radius scale, because there is no radius. `border-radius: 0` on every button, input, card, panel, badge, and filter segment. The only non-rectangular edges on either page are the two diagonal hatch fields: the gauge's redline zone and the closed-day banding on the empty state, both drawn with `repeating-linear-gradient` at 135 degrees. Depth comes from a 1px `--border` hairline and a background step from `--bg` to `--panel` to `--surface-raised`. No shadows, no glows, no glass.
## Iconography
No icon library, and no hand-drawn pictograms. The only non-text marks in the system are structural:
- the logo mark, which is the gauge in miniature,
- the gauge fill and its amber cap line,
- the five-segment intensity meter, on class cards vertically and in table rows horizontally,
- a 7px solid square before every status word, colored by the status,
- the 135 degree hazard hatch, used twice: the gauge redline and the closed-day band,
- one `←` in the "Gallery" utility link.
If a future page needs true iconography, the fallback is a stroked geometric set at `1.75` weight and square caps, never rounded caps, and never a filled or duotone style. That decision has not been needed yet.
## Motion Principles
There are exactly two scripted motions on the homepage, and one of them is the product.
**The gauge.** A vertical track is pinned to the left of the page for the full height of ``. Its fill has a live floor and a scrolled climb. The floor is read off the same class list the ticker renders: if a class is on the floor right now, the gauge sits at that class's intensity; if the floor is empty, it rests at 16 and warms toward 34 as the next class gets closer. From there the fill climbs with scroll, mapped from the top of `` to just past the bottom of the class board, so the gauge is at 100 exactly when the last class has been read and stays redlined through the zone legend. The readout number, the lit zone name, and the amber cap line all move together, because they are one instrument, not three widgets. The fill animates with `transform: scaleY()` on a bottom origin, never with `height`, so the climb stays off the layout thread; the cap line counter-scales to hold its 2px.
**The board reveal.** Each class card carries its own intensity as a threshold. The card's box, its border, and its top intensity bar are always drawn, so an un-reached class reads as a slot the gauge has not got to yet, never as a hole in the page. Only the card's contents are transparent and offset 24px toward the gauge, landing when the gauge's reading passes that card's number. Two rules keep this from becoming a trap: the reveal is **latched**, so a card that has opened never closes again on scroll-up, and an un-reached card is `pointer-events: none`, so nothing invisible is ever clickable. The cards are in the DOM and readable from the first byte; the reveal is opacity and transform only.
**The ticker.** The upcoming-class strip loops horizontally at 46 seconds a lap. It pauses on hover, on focus within, and on an explicit Pause control in its own header. Pausing resets the track's transform so every item is reachable rather than half-scrolled off, switches the strip to manual horizontal scroll, and suspends the 30 second refresh, because content must not rewrite itself under a reader who has deliberately stopped it. While running, it re-reads the clock every 30 seconds so the countdowns stay true. The loop needs a second copy of the row to scroll into; that copy is `aria-hidden`, so assistive tech reads the schedule once, not twice.
Everything else, buttons, day filters, table rows, nav links, is a `:hover` / `:active` / `:focus-visible` color or border transition at 140ms. No scroll-triggered reveals outside the board. No parallax. No counting-up numbers.
Under `prefers-reduced-motion: reduce`, the page renders the resolved state instead of the journey, and no scroll listener is attached at all. The gauge shows its **honest live floor reading**, not a fake 100: a motionless instrument still has to tell the truth about the studio, and pinning it to redline would report a full room to exactly the visitors least able to check. Every class card is fully visible with no transition, the ticker stops looping and becomes a horizontally scrollable strip with its Pause control hidden, the status pulse stops blinking, and button transitions are removed.
## Voice & Tone
High-intensity, direct, coach-like, no fitness-guru positivity spam. Afterburn talks like a coach who is already counting, not like an app that is proud of you. In practice:
- **Primary button**: "Take a spot", not "Start your fitness journey today"
- **Full class**: "Waitlist only", not "Sorry, this class is fully booked, check back soon"
- **Closed day**: "The studio is closed. Recovery is programmed, it is not a gap in the timetable. Come back Monday at 05:45.", not "No classes today, enjoy your rest day"
- **Form error**: "That email will not reach you. Check it and send again.", not "Oops, something went wrong"
- **Cancellation policy**: "Inside 4 hours it does not, because someone on the waitlist could have taken the spot.", not "Late cancellations may incur a fee"
The tell that a sentence is off-brand: it praises the reader, it apologizes, or it hedges. Afterburn states the rule and gives the reason.
## Accessibility Baseline
- **Focus ring**: `2px solid var(--accent-alt)` at `2px` offset via `:focus-visible` on every link, button, input, and select, and never removed. Amber, not orange, so the ring survives landing on the orange primary button.
- **Reduced motion**: honored on both scripted motions and the ticker, as described under Motion Principles. The gauge's scroll listener is never attached when reduce is set, so there is no scroll-linked movement at all.
- **The gauge is `aria-hidden`.** It is a continuously changing graphic tied to scroll position, and reading it aloud on every frame would be noise. Nothing is communicated by the gauge alone: every class card states its own zone and number in text ("Build, gauge 45"), the zone legend defines all four bands in words, and the class board is fully present and readable regardless of gauge state.
- **Tap targets**: `44px` minimum height on every button, nav link, form control, and day filter segment. Footer links carry vertical padding to clear `24px` so they meet the target-size minimum on their own, not only through spacing.
- **Moving content**: the ticker starts automatically, so it ships an explicit Pause control, not only a hover pause a touch user could never reach. Pausing also stops the timed refresh, so held content stays held.
- **Skip link**: both pages open with a skip link to their main content. It is `position: fixed`, deliberately, so it can never widen the document the way an absolutely positioned off-screen element inside a wide scroll container can.
- **Changes are announced**: the day filter writes a `role="status"` line ("3 classes on Friday, 2 running", or "No classes on Sunday. The studio is closed."), and the waitlist helper text is a `role="status"` associated to its input by `aria-describedby`. The gauge and the ticker are deliberately **not** announced: they change on scroll and on a timer, and narrating them would bury everything else.
- **Focus is never dropped**: on a successful waitlist submit, focus moves to the confirmation message before the submit button is disabled, and the email field is set `readonly` rather than `disabled`, so focus is never dumped back to the document root.
- **Color is never the only signal**: every status pairs its square with a word ("9 spots", "Waitlist only", "Cancelled"). A cancelled row also dims its text and disables its button. A form error sets `aria-invalid`, changes the border, and replaces the helper text with a sentence.
- **Structure**: one `
` per page, headings in order with no skipped level, `nav` / `main` / `footer` landmarks on both pages, a real `
` on the schedule table naming the day in view, `scope="col"` on every header cell, and `aria-current="page"` on the active nav link.
- **Controls carry state**: the day filter is a group of real buttons with `aria-pressed`, and the ticker Pause toggle reports `aria-pressed` and swaps its own label.
## Components
### Navigation
Single line, `64px`, `--panel` with a `--border` bottom hairline, sticky. Left: a "Gallery" utility link and the mark plus wordmark lockup. Right: three section links and exactly one primary button. No hamburger and no dropdown, a two-page studio site has nothing to collapse. Below 720px the section links drop and the primary button stays, because the primary button is the only thing in the nav a member actually came for; below 430px the Gallery link drops too. Nothing is lost by either: the wordmark lockup is always a link home, the two dropped section links are in-page anchors on a page you are already scrolling, and the footer carries the full route list at every width. The nav's primary is labelled for what it actually does on each page, "Take a spot" on the floor page where it leads to the booking tool, "Join a waitlist" on the schedule page where it leads to the waitlist form.
### Buttons
Three variants, zero radius, `44px` minimum height:
- **Primary**: `--accent` fill, `--bg` label, `--accent-hot` on hover. Used once per view, in the nav, for the single real action.
- **Secondary**: transparent, `1px solid --border-ui`, `--ink` label, edge and label both going `--accent` on hover. Every class-level action ("Reserve", "Waitlist", "Retry", "Join the waitlist") is secondary, which is what keeps the one-primary-per-view rule true on a page with eight bookable things on it.
- **Ghost**: text only, `--dim` label, `--ink` plus an accent underline rule on hover. Tertiary jumps only.
All three define `:hover`, `:active` (`translateY(1px)`, a press, not a bounce), `:disabled` (a `--dim` label at 6.9:1 on a 135 degree out-of-service hatch, plus `pointer-events: none` and `cursor: not-allowed`, never a low-opacity fade that drops the label under 3:1), and `:focus-visible` (amber ring). A `btn--tight` size modifier exists for table rows at `38px`, used only inside a row where a full-height button would stretch the line.
### Intensity gauge (signature)
A sticky rail: readout on top, then the zone ladder and the track, then a "Floor intensity" caption. The readout is the number, the zone name, and a "Next: Heat 45 at 68" line naming what the amber tick on the track actually marks, so no mark on the instrument is unlabelled. The track carries a hatched redline band across its top quarter, hairline boundary ticks at 25, 50, and 75, an amber tick at the next class's intensity, and the orange fill. Documented in full under Motion Principles. Below 720px the rail narrows to `82px` and drops its zone ladder, keeping the number, the zone name, the next-class line, and the track with its boundary ticks.
### Class ticker
A `--panel` strip across the top of the lead block, pinned directly under the nav so it lands at the top of the gauge. Header row: a pulsing square, an "On the floor next" label, and a Pause toggle. Body: a looping row of upcoming classes, each showing start time, class name, room, and a live countdown. A class currently running renders first with orange time-remaining text instead of a countdown.
### Class card
The board is marketing, not the booking tool, so a card's action is a link through to the schedule page rather than a button that fakes a reservation. Grid of three columns: a vertical five-segment intensity meter, the class body, and a right rail with the start time, its days, its status, and one secondary button. The card's own intensity is drawn to scale as an orange bar across its top edge, with the card's full width as the 0 to 100 scale, so the same reading appears three ways on one card: as the bar, as the meter segments, and as the words "Build, gauge 45". Cards do not use a colored left border. Capped at `--measure` so the time column stays next to the copy.
### Zone legend
A four-cell hairline grid defining the bands in ranges and in sentences. This is the component that makes the gauge legible without reading it aloud, which is what lets the gauge itself be `aria-hidden`.
### Day filter (second page)
Seven real buttons in one hard-edged frame, one border between segments, no gaps and no pills. Selected segment is an `--accent` fill with a `--bg` label and `aria-pressed="true"`. Opens on today's day, not on Monday. Below 760px it becomes a seven-column grid so the week stays one unbroken row instead of orphaning Saturday and Sunday onto a second line at double width. Every change writes a count into the status line beneath it.
### Schedule table (second page)
`--panel` header row in `--text-label`, `--bg` body rows, one `--border` rule between rows, `--surface-raised` on row hover, a `
` naming the day. Columns: time, class, coach, intensity, spots, book. The intensity cell is the gauge laid flat: five segments, the number in amber Anton, and the zone name in words.
**Below 760px the table stops being a table.** Six columns cannot fit honestly at that width, and a horizontal scroll container hides half of them behind a gesture with no affordance, so the rows restack into one bordered block per class, each cell labelled from its own `data-label`. Nothing is hidden and the page never scrolls sideways. Between 760px and the point the table fits, the scroll container is a focusable labelled region so a keyboard user can reach it.
### Status states
- **Open**: amber square plus "9 of 16 left".
- **Tight**: orange square plus the count, at three spots or fewer.
- **Full**: muted square plus "Waitlist only", and the row's button becomes a link to the waitlist form.
- **Cancelled**: a hatched square plus "Cancelled", the whole row's text drops to `--dim`, and the button is disabled.
- **Empty**: a `--panel` block with a hazard band across its head, a real heading, and a sentence that says why ("The studio is closed. Recovery is programmed"). No illustration and no shrug.
- **Notice**: a `--panel` block with a 2px `--accent` top rule carrying the booking and cancellation rules, with a ghost button to the waitlist.
### Form (second page)
Label above control in `--text-label`. Select and input share the same `--panel` fill, `1px solid --border-ui`, zero radius, `44px` height, and `--surface-raised` plus an orange border on focus. Helper text sits below at a reserved minimum height so validating does not shift the layout. An empty field and a malformed address get different sentences, because "you left it blank" and "you mistyped it" are different mistakes. On error the border goes orange, `aria-invalid` is set, focus returns to the field, and the helper is replaced with a sentence that says what to do. On success the helper goes amber, names the class the visitor actually picked back to them, and takes focus before the submit disables.
### Footer
Four columns: brand block with the lockup and an honest note that the studio is fictional, a Studio link list, real opening hours, and an Elsewhere list linking back to the gallery and to this file. A bottom bar carries the tagline. No invented legal text and no links to pages that do not exist.
## Do's and Don'ts
### Do
- Let the gauge decide the layout. The ticker sits at its top, the headline sits at its baseline, and the class board opens against it.
- State an intensity three ways on anything that has one: the bar, the segments, and the words.
- Use `--bg` as the label color on any `--accent` fill, and `--accent-alt` for the focus ring.
- Keep the single primary button in the nav and make every in-page action secondary.
- Give a moving thing an explicit stop, not only a hover pause.
- Say why a rule exists in the same sentence as the rule.
- Latch a progressive reveal. Content that has been earned stays earned.
- Draw the empty slot. A gate should read as "not yet", never as a broken page.
- Give every mark on an instrument a label, or take the mark off.
### Don't
- Don't use a centered hero with a stock photo of someone mid-exercise.
- Don't float a "Book a class" button over a blurred gym photo.
- Don't reach for a pastel, lavender, or mint wellness palette. This is athletic, not spa.
- Don't round anything. Edges read like equipment, not like a wellness app.
- Don't put more than one primary CTA in the same view.
- Don't lead with a static grid of class times. The gauge and the ticker come first, the board comes after.
- Don't add a green "all good" color. Availability is a word and a count, not a traffic light.
- Don't set Anton below `1.7rem` or run it past two lines.
- Don't put a thick colored bar down the left edge of a card. A class's accent is its intensity bar across the top, drawn to scale, or it is nothing.
- Don't hide table columns behind a horizontal scroll on a phone. Restack the rows or cut the data honestly.
- Don't render a disabled control as a low-opacity ghost. Keep the label legible and mark it out of service with the hatch.
- Don't let a motionless build lie. Under reduced motion the gauge reports the real floor, not a decorative 100.
### Deliberate exception
The impeccable detector flags the class ticker under its `marquee` rule, on the grounds that continuously auto-scrolling content demands attention it has not earned. That flag is consciously overruled here, on this project's established precedent that a system's own rules win where they conflict with a generic pattern. The ticker is not decoration: it is half of this system's declared signature interaction, it is the gauge's live data source, and the never-list written before any HTML existed explicitly forbids leading with a static grid of class times instead. The legitimate harms behind the rule are answered rather than ignored: the strip pauses on hover, on focus within, and on an explicit Pause control that touch users can reach; it stops looping entirely under `prefers-reduced-motion` and becomes a scrollable strip; and nothing in it is unique to it, since every class it names appears in full on the schedule page and on the class board below.
## Known Constraints
- Two routes exist (studio floor, schedule). There is no coaches page, no pricing, no membership flow, and no authenticated state. "Take a spot", "Reserve", and the waitlist form are not wired to anything real, this is a concept demo.
- The schedule page's table is rendered by script from an in-page week object. Monday's three rows are present in the markup as a static fallback, but the other six days are not, so a no-script visitor sees Monday only. The homepage has no such gap: its gauge, board, and legend are all fully present without script, and only the ticker's contents and the reveal timing depend on it.
- "Reserve" does not reserve. On the board it links through to the schedule page, and on the schedule page it is inert. The waitlist form is the only control on either page that produces a state change, and it changes nothing beyond the current tab. A real studio would need a price, an address, a first-visit path, and a booking backend; none of that is in scope for a design-system demo, and inventing a price list would put fake facts on a fictional business.
- The critique flagged that the schedule has no week-at-a-glance view and no way to sort or filter by intensity, which a returning member would want. Both are real product gaps and both were left alone deliberately: this system exists to prove the gauge drives the layout, and a second competing view of the same data would dilute exactly that.
- The gauge's "live" floor reads the visitor's own device clock against a fixed weekly timetable. There is no backend, so it is honest about a schedule but not about actual attendance.
- Responsive behavior is a small set of breakpoints (720px and 430px on the floor page, 760px and 430px on the schedule page) plus fluid type. There is no tablet-specific layout, and the gauge rail keeps its vertical orientation at every width rather than flipping horizontal, because a horizontal gauge would stop being the thing the page is built around.
## Process
Built through the impeccable-audited anti-slop workflow: never-list written
before any HTML, page structure derived from the signature interaction
rather than a template, `/impeccable audit` and `/impeccable critique` run
against the built page before this system was considered done.