--- version: alpha name: glowball-design description: "A deep, saturated magenta-plum canvas (#3d0a2e), dark but jewel-toned rather than a neutral near-black, with light pink-white ink (#fdf1f8) carrying all body text. Neon green (#39ff88) and neon yellow (#ffe14d) are bright enough to work as on-canvas link and small-text color directly, a first in this batch, but need their own separate dark fill-label color when used as a button or badge fill, since the page's light ink fails against them. Bungee carries every headline, Inter carries anything meant to be read quickly. The homepage's hero is one glowing ball rolling through four obstacle holes as one continuous path, not four parallel elements." --- ## Brand Positioning Glowball runs an indoor blacklight mini-golf course, and it exists because most mini-golf sites either go generic-family-fun (windmill clip art, primary-color balloons) or lean so hard into "extreme neon" that the page becomes unreadable strobe noise. Glowball's bet: commit to one real dark, saturated canvas, real neon accents used with restraint, and stay completely plain about the thing that matters, which hole does what, how long the round takes, what it costs. If a component performs "electric energy" without being tied to a real hole, a real price, or the glowing ball itself, it doesn't belong here. colors: accent: "#39ff88" accent-fill-ink: "#0d1a12" accent-alt: "#ffe14d" accent-alt-fill-ink: "#241d02" ink: "#fdf1f8" ink-muted: "#e2a9cf" canvas: "#3d0a2e" ## Logo / Wordmark System The mark is a single golf ball mid-glow, a circle with a soft radial highlight and three short motion-trail arcs behind it, the exact look of a real glow ball caught rolling under blacklight, not a static dimpled-ball icon. ```svg ``` - **Lockup**: mark, then a `0.5rem` gap, then "Glowball" in Bungee, mark always left of the wordmark. - **Minimum size**: mark not smaller than `18px` tall, below that the trail arcs disappear into noise. - **Clearspace**: empty margin equal to the mark's own height on all four sides. - **Don't**: don't recolor the ball, it's always `--accent`, never `--accent-alt` or a third color. Don't drop the motion trail, without it the mark is just a plain circle. Don't add a second ball or a club, the mark is the ball alone, mid-roll. ## Color System ### Roles | Role | Token | Value | Used for | |---|---|---|---| | Canvas | `--bg` | `#3d0a2e` | Page background, a real saturated jewel tone, not a neutral near-black | | Surface | `--panel` | `#4a0f38` | Nav, hole cards, form fields, a lighter step of the same magenta family | | Surface raised | `--raised` | `#5a1544` | Hover state, input focus fill | | Border | `--border` | `#6b2352` | Card edges, dividers, input outlines | | Ink | `--ink` | `#fdf1f8` | Primary text on canvas and panel, headlines | | Ink muted | `--dim` | `#e2a9cf` | Secondary text, meta lines, placeholders | | Neon green | `--accent` | `#39ff88` | Primary button fill, links/small text on canvas, the mark's ball, "open" status | | Green fill-ink | `--accent-fill-ink` | `#0d1a12` | Label color for text sitting on an `--accent` fill only | | Neon yellow | `--accent-alt` | `#ffe14d` | Secondary button fill, links/small text on canvas, "almost full" status | | Yellow fill-ink | `--accent-alt-fill-ink` | `#241d02` | Label color for text sitting on an `--accent-alt` fill only | **This palette's accents work as on-canvas text directly**, unlike every prior light-canvas system in this batch: `--accent` measures 12.36:1 and `--accent-alt` measures 12.59:1 against `--bg`, both comfortably AAA, because a dark jewel-tone canvas and a bright neon share almost no lightness overlap. The inverse problem shows up instead: `--ink` (light) fails badly as a label on top of either accent fill (1.21:1), so filled buttons and badges need their own dedicated dark label color, `--accent-fill-ink` or `--accent-alt-fill-ink`, never `--ink`. **The hole markers and obstacle colors are illustrative, not tokens**, the same exception every other system in this batch already establishes: real obstacle paint comes in real colors, orange, cyan, hot pink, not a two-token gradient wearing a golf-hole shape. `--accent` and `--accent-alt` never appear as obstacle fills in the hero, they're reserved for the interface and the ball itself. ### Contrast (computed from the hex values above via WCAG relative luminance) | Pairing | Ratio | Passes | |---|---|---| | `--ink` on `--bg` | 14.92:1 | AAA | | `--dim` on `--bg` | 8.44:1 | AAA | | `--accent` on `--bg` (links, on-canvas text) | 12.36:1 | AAA | | `--accent-alt` on `--bg` (links, on-canvas text) | 12.59:1 | AAA | | `--accent-fill-ink` label on `--accent` fill | 13.49:1 | AAA | | `--accent-alt-fill-ink` label on `--accent-alt` fill | 13.74:1 | AAA | | `--ink` label on `--accent` fill (why it's not used) | 1.21:1 | Fails | The last row is recorded deliberately: it's the computed proof for why filled buttons need a dedicated dark fill-ink token instead of reusing the page's light `--ink`, the opposite failure mode from this batch's light-canvas systems, which needed a dark-fill-label because their raw accents were too pale for white. 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.1rem, 5vw, 3.4rem)` | 400 | Bungee | 1.1 | 0 | Homepage H1 only | | `--text-h2` | `1.4rem` | 400 | Bungee | 1.2 | 0 | Section headings | | `--text-h3` | `1.05rem` | 400 | Bungee | 1.25 | 0 | Hole 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's solid blocky weight reads clean under a dark, saturated canvas the way a real course sign does, reserved for the headline, section headings, and hole names. Inter carries anything read as a sentence or clicked as a control, including every price and round length. ## 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: 16px` on cards, panels, and inputs. `--radius-pill: 999px` on buttons, badges, and the ball itself. A soft `drop-shadow` glow (`filter: drop-shadow(0 0 8px var(--accent))`) is the one effect exclusive to the ball and the mark, never applied to cards or buttons, so glow reads as this system's single signature effect rather than a default applied everywhere. ## Iconography No icon library. The only non-text graphics are the logo mark and the hero's own ball-and-course path (hand-built SVG). Round length and price notes are plain text, not a trophy or flag icon next to unrelated words. ## Motion Principles Scroll rolls one glowing ball through four obstacle holes as a single continuous path, bouncing hole to hole, not four parallel elements, the same structural answer Tumble Town already established for this batch. Each landing reveals that hole's info card below. One-shot reveal, nothing loops, every hole is written out in plain markup at all times regardless of scroll or script state. Scroll trigger uses a fixed pixel-distance range ("top top" / "+=…"), not a viewport-percentage range, after Sunsplit's pre-elapsed-trigger bug proved percentage triggers are unsafe for hero elements sitting close to the viewport top at load; verified at exactly `0` progress at scroll position `0`. `prefers-reduced-motion: reduce` renders the ball at the final hole and every card already visible. ## Voice & Tone Confident, a little theatrical about the dark-course gimmick, plainspoken about price and length. In practice: - **Button label**: "See the course", not "Enter the glow zone!" - **Hole description**: "A blind uphill shot around the waterfall, most groups take two extra strokes here.", not "An ELECTRIFYING challenge!" - **Round note**: "Eighteen holes runs about 45 minutes for a group of four.", not a vague "fun for the whole family" - **Empty state**: "Fully booked till 9pm tonight, next opening is 9:15.", not "Sorry, we're slammed!" ## Accessibility Baseline - Focus ring: `2px solid var(--accent)`, `2px` offset, applied via `:focus-visible` on every interactive element. - Reduced motion: the ball-roll sequence and every card reveal check `prefers-reduced-motion: reduce` and render the finished state immediately. - Minimum tap target: `44px` in the smallest dimension for every button and input. - Color is never the only signal: a hole's badge pairs "Open" or "Popular" with the word, never color alone. - Every hole the ball can reach is also written out in plain markup at all times, see Motion Principles. - Filled buttons and badges always use `--accent-fill-ink` or `--accent-alt-fill-ink`, never `--ink`, see the Color System proof row. ## 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 "Course" link plus one primary button ("See the course"). ### Buttons Three variants, one radius (`--radius-pill`): - **Primary**: `--accent` fill, `--accent-fill-ink` label, used once per view for the real action. - **Secondary**: transparent fill, `1px solid --border`, `--ink` label. - **Ghost**: text-only, `--dim` label, `--ink` on hover. All variants define `:hover`, `:active` (`transform: scale(0.97)`), `:disabled` (`opacity: .45`), and `:focus-visible`. ### The course (signature interaction) Documented in full under Motion Principles. Structurally: a hand-drawn SVG path with four obstacle markers, one glowing ball (`filter: drop-shadow`) scroll-driven along the path in a continuous hop-to-hop motion, real obstacle colors. ### Hole card A flat `.panel`: `--panel` background, `1px solid --border`, `--radius`, no shadow. Holds the hole name (Bungee), a real difficulty note, the par, and an open/popular badge. Revealed by the ball landing above, present in the DOM at all times. ### Badge `--radius-pill`, `1px solid` the semantic color, semantic-color text on transparent fill (never a solid fill, since a solid neon fill this small would glare): `--accent` for "Open," `--accent-alt` for "Popular." ### Footer One row: course name/tagline on the left, real page links on the right (Course, back to gallery). ## Do's and Don'ts ### Do - Keep the canvas a real saturated jewel tone, not a neutral near-black standing in for "dark mode." - Reserve the glow `drop-shadow` effect for the ball and the mark only, nothing else glows. - Use `--accent-fill-ink` or `--accent-alt-fill-ink`, never `--ink`, on top of a filled accent surface. - Let the ball roll as one continuous path, not four parallel elements. - State the real round length and price, not a vague "fun for the whole family" line. ### Don't - Don't use a stock glow-in-the-dark stock photo, a strobe-light GIF, or a windmill clip-art icon anywhere. - Don't perform "ELECTRIFYING" or "glow zone" copy, name the actual hole and obstacle instead. - Don't apply the glow effect to buttons, cards, or badges, it's the ball's signature alone. - Don't replay the ball's roll on every scroll pass, it plays once, like a real round. ## Known Constraints - Two routes exist (homepage, holes). There is no checkout and no authenticated state, "See the course" and the booking form are not wired to anything real, this is a concept demo. - The course shows exactly four holes because that's the current featured stretch. The real course has eighteen, this page is a preview, not the full scorecard. - No responsive breakpoint table beyond a single-column mobile collapse of the course stage and hole cards. ## Process Built through the impeccable-audited anti-slop workflow: never-list written before any HTML, page structure derived from the signature interaction (one real ball, actually rolling) 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, using a fixed-pixel-distance trigger from the outset given the pre-elapsed-trigger lesson from Sunsplit earlier in this batch.