--- version: alpha name: rink-and-roll-design description: "A deep purple-black canvas (#0d0618) with lavender-white ink (#f5eefc), electric magenta (#ff2fd4) and electric cyan (#00e5ff) as loud, always-visible brand accents, not the sparse single-accent restraint every other dark-canvas system in this gallery reaches for. Bungee carries every headline at full chunk, Inter carries anything meant to be read quickly. The homepage's hero is a disco ball actually running a light show: four colored beams sweep in from the ball in sequence and land on the session they announce." --- ## Brand Positioning Rink & Roll exists because most nightlife-adjacent sites either go full restrained-minimalist (one accent, acres of black, a single moody photo) or full chaos (auto-playing music, a hundred emoji, a marquee tag). Neither is what a roller rink actually is: loud, but organized, a real light rig running a real show on a real schedule. So the homepage doesn't describe the vibe, it runs a small version of the actual show, a disco ball with four colored beams that sweep in on scroll and land on the session they're announcing, the same way the real rig cues a session change. If a component performs "party" without being tied to an actual session, a real time, or a real price, it doesn't belong here. colors: accent: "#ff2fd4" accent-alt: "#00e5ff" ink: "#f5eefc" ink-muted: "#a996c2" canvas: "#0d0618" ## Logo / Wordmark System The mark is a wheel, four spokes radiating from a hub inside a ring, canted at a slight angle the way a skate wheel leans mid-stride. It is not a generic gear or a disco-ball icon, it's specifically a roller-skate wheel, the one part of this business every other roller-rink icon (a disco ball, a pair of skates head-on) skips past. ```svg ``` - **Lockup**: mark, then a `0.5rem` gap, then "Rink & Roll" in Bungee, mark always left of the wordmark, never stacked, never reversed. - **Minimum size**: mark not smaller than `18px`, below that the four spokes merge into the ring. Wordmark not smaller than `0.85rem`. - **Clearspace**: empty margin equal to the mark's own height on all four sides. - **Don't**: don't straighten the cant, the 12-degree lean is the point, an upright wheel reads as a generic gear. Don't recolor the hub or spokes, magenta hub, cyan spokes, always. Don't add a shoe or boot to the mark, it's the wheel alone. Don't use it as a bullet or divider. ## Color System ### Roles | Role | Token | Value | Used for | |---|---|---|---| | Canvas | `--bg` | `#0d0618` | Page background | | Surface | `--panel` | `#170f28` | Nav, session cards, form fields | | Surface raised | `--raised` | `#211736` | Hover state, input focus fill | | Border | `--border` | `#2f2247` | Card edges, dividers, input outlines | | Ink | `--ink` | `#f5eefc` | Primary text, headlines | | Ink muted | `--dim` | `#a996c2` | Secondary text, meta lines, placeholders | | Magenta | `--accent` | `#ff2fd4` | Primary button fill, focus ring, the mark's hub, "open" status | | Cyan | `--accent-alt` | `#00e5ff` | Secondary confirmations, the mark's spokes, "members only" status | **Unlike every other dark-canvas system in this gallery, both accents stay loud and visible throughout, not rationed to one sparse moment.** A roller rink's whole visual identity is a two-color light rig running continuously, restraining it to a single accent used once per view (Patchline, Wren Dalca's own precedent) would undersell the actual brand. The beams in the hero go further still, using a small illustrative light-show palette (magenta, cyan, a warm yellow, a violet) beyond the two UI tokens, the same exception Harborview's sky gradient and Pearl & Pop's drink colors already establish for this gallery: real light shows and real drinks have more colors than a two-token UI system, and those illustrative colors never leak into buttons, links, or status. ### Contrast (computed from the hex values above via WCAG relative luminance) | Pairing | Ratio | Passes | |---|---|---| | `--ink` on `--bg` | 17.53:1 | AAA | | `--dim` on `--bg` | 7.41:1 | AAA | | `--ink` on `--panel` | 16.31:1 | AAA | | `--dim` on `--panel` | 6.89:1 | AAA | | `--dim` on `--raised` | 6.31:1 | AA | | `--accent` on `--bg` (links, status) | 6.26:1 | AA | | `--accent-alt` on `--bg` (links, status) | 12.92:1 | AAA | | `--bg` label on `--accent` fill (primary button) | 6.26:1 | AA | | `--bg` label on `--accent-alt` fill | 12.92:1 | AAA | | `--ink` label on `--accent` fill | 2.80:1 | Fails, never done | | `--ink` label on `--accent-alt` fill | 1.36:1 | Fails badly, never done | The rule this table exists to enforce, same as every dark-canvas system in this gallery: a filled accent surface labels itself in `--bg`, never `--ink`. Cyan is bright enough that white-on-cyan is an easy mistake to make and it fails at 1.36:1, worse than magenta's own 2.80:1 failure, so the discipline matters more here, not less. typography: display: fontFamily: Bungee fontWeight: 400 body: fontFamily: Inter fontWeight: 400 ## Type Scale | Token | Size | Weight | Family | Line-height | Letter-spacing | Used for | |---|---|---|---|---|---|---| | `--text-display` | `clamp(2.25rem, 5.5vw, 3.75rem)` | 400 | Bungee | 1.1 | 0 | Homepage H1 only | | `--text-h2` | `1.5rem` | 400 | Bungee | 1.2 | 0 | Section headings | | `--text-h3` | `1.1rem` | 400 | Bungee | 1.3 | 0 | Session names | | `--text-body` | `1rem` | 400 | Inter | 1.65 | 0 | Paragraph copy | | `--text-small` | `0.85rem` | 400 | Inter | 1.5 | 0 | Nav, footer, helper text, meta lines | | `--text-label` | `0.75rem` | 600 | Inter | 1 | 0.06em, uppercase | Kickers, badges, form labels | Bungee has one weight and it's already maximal, so it never competes with Inter for a "which font is bold" decision the way a two-weight display face would, Bungee is the loud one, Inter is the quiet one, always. Rule holds exactly as every other system in this gallery: display carries headlines and named things (session names), Inter carries anything read as a sentence or clicked as a control. ## 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 `--radius: 10px` on cards, panels, and inputs. `--radius-pill: 999px` on buttons and badges. One consistent scale, the loudness here lives in color and type, not in an inconsistent shape system, a maximalist palette still needs a disciplined shape language underneath it. ## Iconography No icon library. The only non-text graphics are the logo mark and the hero's own disco ball and light beams (hand-built, not a stock disco-ball emoji or icon). A session's "members only" note is a plain-language badge, not a lock glyph. ## Motion Principles The disco ball hangs static at the top of the hero, a light rig doesn't spin on its own, it's cued. Scroll sweeps four colored beams in from the ball in sequence, each one fading in and widening from a thin line to its full landing shape as it reaches the session it announces, on the floor grid below. The moment a beam lands, the session card for that slot slides in. This is a one-shot reveal (`toggleActions: play none none reverse`), nothing loops or auto-plays, and every session is written out in plain markup at all times regardless of scroll or script state, the beams announce a real schedule, they don't gate it. The scroll trigger's start/end bounds are checked to verify `0` progress at scroll position `0` before shipping, per the lesson Second Hand's own critique surfaced. `prefers-reduced-motion: reduce` renders all four beams already landed and every card already visible. ## Voice & Tone Direct, a little cocky, specific about the actual schedule and price, never a marquee-caps announcer voice. In practice: - **Button label**: "Reserve a session", not "Get ready to ROLL!!!" - **Session description**: "All ages, all skill levels, rental skates included in the door price.", not "The ultimate skating experience!" - **Age note**: "21+ after 9pm, ID checked at the door, no exceptions.", not a vague "please bring ID" - **Empty state**: "No sessions open right now, check back for next week's schedule.", not "Oops, nothing to see here!" ## Accessibility Baseline - Focus ring: `2px solid var(--accent-alt)`, `2px` offset, applied via `:focus-visible` on every interactive element. Cyan rather than magenta, cyan measures 12.92:1 against canvas, the highest-contrast token available, and stays visible against either accent nearby. - Reduced motion: every beam sweep and card reveal checks `prefers-reduced-motion: reduce` and renders the finished state immediately. - Minimum tap target: `44px` in the smallest dimension for every button and input. - Color is never the only signal: session badges pair "Open" or "21+" with the word, never color alone, an illustrative beam color is never the only way a session is identified, its name and time are always printed under it. - Every session the beam sweep can reveal is also written out in plain markup at all times, see Motion Principles. ## Components ### Navigation Single-line bar, `64px` tall, `--panel` background with a `--border` bottom hairline, sticky to the top. Left: the mark + wordmark lockup. Right: a "Sessions" link plus one primary button ("Reserve a session"). No dropdown, a two-page rink has nothing to collapse into a menu. ### Buttons Three variants, one radius (`--radius-pill`): - **Primary**: `--accent` fill, `--bg` label, used once per view for the real action ("Reserve a session"). - **Secondary**: transparent fill, `1px solid --border`, `--ink` label. Same-page anchors. - **Ghost**: text-only, `--dim` label, `--ink` on hover. Tertiary jumps. All variants define `:hover` (brightness/border shift), `:active` (`transform: scale(0.97)`), `:disabled` (`opacity: .45`, `pointer-events: none`), and `:focus-visible`. ### The light rig (signature interaction) Documented in full under Motion Principles. Structurally: a static disco-ball SVG (a faceted circle, cross-hatch lines suggesting mirror tiles) hung from a short cable, four beam paths fanning down to a floor grid, each beam scroll-driven from `opacity: 0`/zero-width to its full landing shape. A kicker line states the mechanism plainly: "Four sessions, four real beams landing on them, this is the actual light rig, small." ### Session card A flat `.panel`: `--panel` background, `1px solid --border`, `--radius`, no shadow. Holds the session name (Bungee), day/time and price (Inter), a one-line honest note, and an age/access badge. Revealed by its beam landing above, present in the DOM at all times. ### Badge `--radius-pill`, `1px solid` the semantic color, semantic-color text on transparent fill: `--accent` for "Open," `--accent-alt` for "21+ / Members." Never filled solid, filled would compete with the primary button's exclusive use of a solid `--accent` fill. ### Footer One row: rink name/tagline on the left, real page links on the right (Sessions, back to gallery). No invented legal text. ## Do's and Don'ts ### Do - Keep both accents loud and visible throughout, this brand doesn't ration color the way this gallery's other dark-canvas systems do. - Tie every beam to a real session, a real time, and a real price, never a decorative light with nothing under it. - Label any accent-filled surface in `--bg`, cyan fails worse than magenta if this is gotten backwards, see Contrast. - Write every session the beam sweep can reveal into plain markup at all times. - Keep the disco ball static, it's cued, not auto-spinning, that's a rig doing its job, not ambient decoration. ### Don't - Don't auto-play music, flashing effects beyond the one-shot beam sweep, or anything on a timer. - Don't let the illustrative beam palette leak into buttons, links, or status badges, those stay strictly `--accent`/`--accent-alt`. - Don't write in marquee-announcer caps or stack exclamation points, the voice is confident, not shouting. - Don't replay the beam sweep on every scroll pass, it plays once, like a real cue. - Don't add a lock icon or shield glyph for "members only," a plain-language badge carries it. ## Known Constraints - Two routes exist (homepage, sessions). There is no checkout and no authenticated state, "Reserve a session" is not wired to anything real, this is a concept demo. - The beam sweep holds exactly four beams because that's the current session schedule. A fifth session means a fifth beam on the shared rig, not a separate list. - No responsive breakpoint table beyond a single-column mobile collapse of the light rig and session cards. ## Process Built through the impeccable-audited anti-slop workflow: never-list written before any HTML, page structure derived from the signature interaction (a small real light rig, not a decorative one) rather than a template, mechanical detector run clean, and the scroll trigger's start/end bounds checked to verify `0` progress at scroll position `0` before this system was considered done.