Embed Six Flags API IDs directly in the park registry and snapshot
coaster lists from park-meta.json into a TypeScript module. This
eliminates the Playwright-based discovery script, RCDB scraper, and
runtime dependency on park-meta.json — preparing for the backend
API transition.
- Add apiId field to Park type and all 24 park entries
- Create lib/coaster-data.ts with hardcoded coaster lists
- Update page components to use park.apiId and new getCoasterSet()
- Remove scripts/discover.ts, lib/scrapers/rcdb.ts, lib/park-meta.ts
- Remove data/park-meta.json from shared volume
- Remove playwright devDependency and discover npm script
- Simplify scripts/scrape.ts (no RCDB, no discovery checks)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The API without a date param returns today's operating data directly,
invalidating the previous assumption that today's date was always missing.
- Add fetchToday(apiId, revalidate?) to sixflags.ts — calls the dateless
endpoint with optional ISR cache
- Extract parseApiDay() helper shared by scrapeMonth and fetchToday
- Update upsertDay WHERE clause: >= date('now') so today can be updated
(was > date('now'), which froze today after first write)
- scrape.ts: add a today-scrape pass after the monthly loop so each run
always writes fresh today data to the DB
- app/page.tsx: fetch live today data for all parks (5-min ISR) and merge
into the data map before computing open/closing/weatherDelay status
- app/park/[id]/page.tsx: prefer live today data from API for todayData
so weather delays and hour changes surface within 5 minutes
- scrapeRidesForDay: update comment only — role unchanged (QT fallback)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removed flex:1 from left side so ride count has a real minimum width to
trigger wrapping. Added whiteSpace:nowrap so flexbox knows when to wrap it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Padding on the parent main element doesn't work with overflow:auto — the
fix belongs on the scrollable div wrapping the table itself.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Increased pill vertical padding (3px→5px) and internal line gaps (1-2px→2-3px)
so the stacked hours/timezone text feels less cramped.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Open parks get a colored left border (green/amber/blue) instead of a dot.
Region headers lose their accent line; distinguished by "— REGION —" format
with higher-contrast text instead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Dot turns blue (instead of green) during weather delay on homepage
- Mobile card "Open today" badge becomes blue "⛈ Weather Delay"
- Park page LiveRidePanel shows a blue "⛈ Weather Delay — all rides currently closed" badge instead of "Not open yet — check back soon"
- Added --color-weather-* CSS variables (blue palette)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Park open indicator now derives from scheduled hours, not ride counts.
Parks with queue-times coverage but 0 open rides (e.g. storm) show a
"⛈ Weather Delay" notice instead of a ride count on both desktop and mobile.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The actual overflow fix was removing whiteSpace:nowrap from the td.
With that gone, 240px is sufficient and content wraps naturally when tight.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Column uses clamp(220px, 22%, 280px) — scales on small screens, caps at
280px on large ones. Park name gets whiteSpace:nowrap so it stays one line.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause was a hardcoded 240px column width + whiteSpace:nowrap that
prevented content from ever fitting on smaller displays. Now uses 25%
width so the column scales with the viewport, removed nowrap so text
wraps naturally when squeezed, and reverted clamp() back to fixed sizes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removed flex:1/minWidth:0 from name span so dot stays snug to the right
of the park name. Removed flexShrink:0 from ride count so both sides can
compress. All text uses clamp() to scale proportionally with viewport.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Park name, city/state, and ride count all use clamp() so they shrink
proportionally on smaller displays without truncating or overflowing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Let the park name side flex-shrink (minWidth:0, flex:1) so the ride count
always fits in the row without overflowing its column.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes the space-between flex layout that pushed the count to the right
edge of a fixed-width column. Now stacks under city/state so it always
fits within the park name column regardless of screen size.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fire two refreshes per park: one at opening time to flip the open indicator,
and one 30s later to pick up queue-times ride counts once the API updates.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In addition to the 2-minute polling interval, compute milliseconds until
each park's opening time (from hoursLabel + park timezone) and schedule
a setTimeout to fire 30s after opening. This ensures the open indicator
and ride counts appear immediately rather than waiting up to 2 minutes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Uses router.refresh() to re-run server data fetching (ride counts, open
status) without a full page reload. Only runs when viewing the current
week — no need to poll for past/future weeks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mobile cells (~55px wide) can't fit hours text legibly, so show only a
colored dot when open and a dash when no data. Desktop restores the full
pill (hours + tz abbreviation) via Tailwind responsive classes. Row height
is controlled by a new .park-calendar-grid CSS class: 72px fixed on mobile,
minmax(96px, auto) on sm+, keeping desktop cells from looking cramped.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: each week row was its own CSS Grid container, so rows
with open-day pills (hours + separate timezone line) grew taller than
closed rows, making the calendar column lines look staggered/slanted.
- Flatten all day cells into a single grid with gridAutoRows: 76
so every row is exactly the same fixed height
- All cells get overflow: hidden so content can never push height
- Compact the status pill to a single line (hours + tz inline,
truncated with ellipsis) — the stacked two-line pill was the
primary height expander on narrow mobile columns
- Row/column border logic moves from week-wrapper divs to individual
cell borderRight / borderBottom properties
- Nav link touch targets: padding 6×14 → 10×16, minWidth: 44px
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Header:
- Hide "X of Y parks open this week" badge on mobile (hidden sm:inline-flex)
— title + Coaster Mode button fit cleanly on a 390px screen
WeekNav:
- Arrow button padding 6px 14px → 10px 16px, minWidth: 44px for proper
touch targets (Apple HIG recommends 44px minimum)
- Date label minWidth 200px → 140px, prevents crowding on small screens
ParkCard:
- Name container: flex: 1, minWidth: 0 so long park names don't push
the status badge off-screen; name wraps naturally instead of overflowing
- Timezone abbreviation: opacity: 0.6 → color: var(--color-text-dim),
semantic dimming instead of opacity for better accessibility
- Passholder label: 0.58rem → 0.65rem (was below WCAG minimum)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Parks in the 1-hour buffer after scheduled close now show amber instead
of green: the dot on the desktop calendar turns yellow, and the mobile
card badge changes from "Open today" (green) to "Closing" (amber).
- getOperatingStatus() replaces isWithinOperatingWindow's inline logic,
returning "open" | "closing" | "closed"; isWithinOperatingWindow now
delegates to it so all callers are unchanged
- closingParkIds[] is computed server-side and threaded through
HomePageClient → WeekCalendar/MobileCardList → ParkRow/ParkCard
- New --color-closing-* CSS variables mirror the green palette in amber
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
HomePageClient writes the current weekStart to localStorage("lastWeek")
whenever it changes. BackToCalendarLink (new client component) reads
that value on mount and builds the href — falling back to "/" if nothing
is stored (e.g. direct link to a park page).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Moves the coaster toggle out of WeekNav and into the homepage header
top-right as "🎢 Coaster Mode", alongside the parks open badge
- State is stored in localStorage ("coasterMode") so the preference
persists across sessions and page refreshes
- Dropped the ?coasters=1 URL param entirely; the server always fetches
both rideCounts and coasterCounts, and HomePageClient picks which to
display client-side — no flash or server round-trip on toggle
- Individual park pages: LiveRidePanel reads localStorage on mount and
pre-selects the Coasters Only filter when Coaster Mode is active
- Extracted HomePageClient (client component) to own the full homepage
UI; page.tsx is now pure data-fetching
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Attribution now sits on the right end of the "RIDES · Live" bar as a
subtle "via queue-times.com" link, making it clear the live ride data
(not the whole site) is sourced from Queue-Times. Removed the orphaned
attribution block from the bottom of LiveRidePanel.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- "parks open" → "parks open this week" for clarity
- Week calendar cells: stack hours above tz abbreviation (smaller,
dimmer) instead of inline to avoid overflow in tight 130px columns
- Mobile park cards: tz abbreviation inline but smaller/dimmer (60% opacity)
- Month calendar: same two-line stacking in compact day cells
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>