1.6.0
2026-09-07Reworked transport terminology and status handling on Calls and Clinic — "Transporting" now reads "Transporting to" with a house-plus icon, and "Rolled from Scene" is now "Transferred to" with an ambulance icon and prompts for a transport unit number the same way the clinic's transport flow already does (logged as "Transferred to ambulance, unit #: X"). A new "Pending" (ambulance icon) status is available on both Calls and the clinic's outcome dropdown — it marks a patient as awaiting transport without resolving the call, and both sides count toward the same combined pending-transport surge threshold. The clinic's "Transported" outcome is now labeled "Transferred to" (ambulance icon) to match, and both it and a call resolved directly via "Transferred to" now count together in the event summary's "Transports" stat (renamed from "Transported"). Resolving a call by any one team (Delivered, Refusal, NMM, Unable to Locate, or Transferred to ambulance) now reliably returns every other team, supervisor, and piece of equipment still on that call back to post, instead of only the reporting team — this also fixes supervisors not being released when a call resolved via Unable to Locate or Rolled from Scene.
Added
- • Reworked transport terminology and status handling on Calls and Clinic — "Transporting" now reads "Transporting to" with a house-plus icon, and "Rolled from Scene" is now "Transferred to" with an ambulance icon and prompts for a transport unit number the same way the clinic's transport flow already does (logged as "Transferred to ambulance, unit #: X"). A new "Pending" (ambulance icon) status is available on both Calls and the clinic's outcome dropdown — it marks a patient as awaiting transport without resolving the call, and both sides count toward the same combined pending-transport surge threshold. The clinic's "Transported" outcome is now labeled "Transferred to" (ambulance icon) to match, and both it and a call resolved directly via "Transferred to" now count together in the event summary's "Transports" stat (renamed from "Transported"). Resolving a call by any one team (Delivered, Refusal, NMM, Unable to Locate, or Transferred to ambulance) now reliably returns every other team, supervisor, and piece of equipment still on that call back to post, instead of only the reporting team — this also fixes supervisors not being released when a call resolved via Unable to Locate or Rolled from Scene.
- • Configurable surge criteria in event creation's Advanced settings — the number of patients pending transport (combining Calls and Clinic, default 3) and the number of minutes an unassigned call may sit before triggering surge (default 2:00) are now per-event settings with hover tooltips, alongside the existing Surge Limit percentage. Both were previously hardcoded.
- • Ending an event now actually stops data collection — a new "End Event" nav item (after Event Summary, on the dispatch page, visible only to the event's creator or a site admin) opens a confirmation modal that requires typing "End Event" to submit, warning that data collection and logs will stop immediately and cannot be undone. Confirming locks the event (every write that goes through the dispatch board — calls, team/supervisor status, equipment — is rejected from that point on, whether ended manually or because its designated End Time passed and an hour went by with no dispatch activity logged since, a backup for events nobody remembers to end) and takes the dispatcher straight to the Event Summary. Anyone who opens an already-ended event's dispatch board directly now sees a flat grey overlay over the whole board explaining the event has ended, with a button to the summary. The venue selection page's event table (and mobile card list) gained a Status column showing "Active" (green) or a clickable "Event Summary" link for an ended event, and clicking an ended event now goes straight to its summary instead of the (now read-only) dispatch board.
- • Summary charts/stats now always represent an event's full real activity — the reporting window's end is whichever comes later of the event's designated End Time and one hour past its last dispatch log entry, instead of stopping dead at a stale scheduled end (or, for a very old/forgotten event, potentially staying unbounded). Explicitly ending an event uses the actual moment it was ended instead.
- • Exported dispatch logs (CSV) now show a full date + time per entry instead of a raw timestamp number, so an event that runs past midnight still reads in clear chronological order. The dispatch board's own on-screen logs are unchanged (still time-only).
- • Clarifying tooltips across event and venue setup — Start Time, End Time, the posting repost interval, Posts, Locations, and Equipment (in both the event and venue creation flows), the team modal's Lead checkbox, and the supervisor modal's Call Sign field now show a hover tooltip explaining what the field does, most notably that an event's End Time doesn't end it automatically — it stays open until marked finished or an hour passes with no dispatch activity after that time. The Lite landing page's tagline was also removed.
- • Venue and event creation wizards: keyboard and screen-reader polish — moving between steps (via a progress dot, or either flow's own Continue/Back) now moves focus to the new step's content instead of leaving it on a control that's no longer there, so keyboard and screen-reader users don't lose their place. The progress dots have a visible focus ring, and a short doc (docs/COMPONENTS.md, "Wizard step shell") explains the step-config pattern for adding a step to either wizard.
- • Venue creation is now a 5-step wizard — Basics, Map & floors, Locations, Equipment, and Review & save, with a dot-line-dot progress indicator at the top. A completed step's dot can be clicked to jump straight there without losing anything entered elsewhere. Locations can still be placed directly on the uploaded map (in addition to typing a name) right from the Locations step, no separate step needed. The Review & save step's save action now offers starting a new event at the venue immediately, alongside the existing path back to venue selection.
- • Faster team entry modal — the Add/Edit Team modal (event creation, and the dispatch board's Add Team / Edit Team) is now a row-based grid instead of one-member-at-a-time entry: press Enter in a member's name field to commit that row and open a new one below it, with focus and certification carried over automatically. The team name field auto-fills with the next name in sequence (Medic 4 → Medic 5, or Team 1 for the first team) and, when creating, two actions — Save & add another (keeps the modal open, resets for the next team) and Save & close — replace the old single submit button. A team now saves with zero members. A centered "+" control between the member rows and the footer now also lets a row be added explicitly, instead of relying on pressing Enter in the last row.
- • Event creation stepper restructure — steps are now Event Configuration, Staff Assignments, Equipment, Post schedule, and Review & launch (folding the old standalone Basics/Surge criteria/Teams & supervisors steps into these). Event Configuration now also captures the event's Start Time and End Time alongside the date (an End Time at or before Start Time is treated as crossing into the next day), with Surge Limit moved behind a collapsible "Advanced settings" disclosure. The venue map panel now only appears during the Equipment and Post schedule steps, so every other step gets the full column width. Staff Assignments now splits Teams and Supervisors side-by-side with a vertical divider instead of stacking them in separate bordered cards; a team card can be edited in place via a new pencil icon, which reopens the team modal pre-filled as "Edit Team".
- • The wizard's dot-line-dot progress indicator's connecting lines now run flush between adjacent dots instead of stopping short with a visible gap on either side.
- • Event-only equipment — the Equipment step can now add an item that exists only for this event (an "Event only" chip marks it), instead of being limited to checking off items already defined on the venue. Equipment cards also got the same sharp corners as the Staff Assignments cards and now use nearly the full width of their column.
- • Event creation's map now reuses the dispatch page's own venue map rendering (VenueMapWithPosts, shared with VenueMapModal) instead of a separate, simplified implementation — the same post/equipment icons and pan/zoom behavior apply in both places. Equipment given a default location shows the correct equipment icon (gurney, wheelchair, AED, etc.) next to that location's marker, same as it'll appear once the event is live. The map panel is now half the screen (was 2/3) on Equipment, Post schedule, and Review, and the map image now merges flush with the layer control bar beneath it — genuinely sharp corners only where they don't touch (VenueMapWithPosts gained an imageRadiusClassName override for this), square where they meet — instead of two separately-rounded, gapped boxes; the venue-name header above the map and the divider line between the wizard and map columns were also removed. The letterboxed area outside the map image itself now shows a subtle checkerboard instead of a flat, ambiguous fill.
- • Team, Supervisor, and Equipment cards, the map's layer control bar, and the flow's other non-accent buttons (Add Team/Supervisor, "Save & add another", the team-modal row-add "+") now use the same bg-default/40 flat background as the wizard's own Back button, instead of several different dark, hard-to-read greys. Checkboxes in this flow (Enable Posts, equipment selection, team member Lead) also render their checked state in the app's actual accent blue instead of a dark grey.
- • Fixed the Team/Supervisor cards and the map's layer control bar still rendering their old near-black background despite the bg-default/40 fix above: all three used HeroUI <Card isBlurred>, whose isBlurred variant adds a dark:bg-background/20 class (background is pure black in this theme) with no non-dark: counterpart for a plain override class to conflict with — Tailwind's class-merging only drops a competing class in the same variant context, so the unprefixed bg-default/40 coexisted with, and lost to, dark:bg-background/20 in the browser's dark mode. None of the last several rounds of background-color changes on these three elements could ever have taken visible effect while isBlurred stayed on; removed it (it wasn't adding anything meaningful on a plain list card over an already-dark page anyway).
- • Venue creation now matches event creation's stepper aesthetics — steps renamed to Venue Configuration, Map, Locations, Equipment, and Review (were Basics, Map & floors, and Review & save); Back and the primary action (Continue, or Create Venue/Save & Start Event on the last step) now sit in the same bottom-left/bottom-right corners as event creation, and Cancel now only appears (bottom-left) on the first step, replaced by Back everywhere else. The Map, Locations, Equipment, and Review steps now show the map alongside them (half the screen) whenever the current floor has one, same as event creation; Equipment and Review use the same read-only VenueMapWithPosts panel event creation uses (proper post/equipment icons), while Map and Locations keep their own interactive marker-placement/dragging map, now sharing the same checkerboard background, sharp corners, and solid flush-merged layer control bar treatment (extracted as MAPCHECKERBG in src/lib/mapStyles.ts, shared by both pages). Location and equipment list cards also switched to the same sharp-corner, bg-default/40 card style as event creation's Staff Assignments/Equipment cards.
- • Configurable default equipment location in venue creation — the Equipment step can now assign each item a default location (the same location Select used in event creation), instead of that being event-only. Adding that equipment to an event now starts from the venue's configured default instead of blank, still adjustable per event from there.
- • The Map step in venue creation now shows its map at full width — "Venue Map" (label no longer says "(Optional)"), the floor name, and Add Markers stay in their header row above it, but the map no longer shares the row with a half-width column the way Locations/Equipment/Review do (there's nothing to put beside it on this step).
- • Fixed venue creation's own interactive map (Map and Locations steps) barely panning at the default zoom level: it clamped drag position to the image's actual edges, which at the default 1x zoom (image already fits its container) left almost no room to drag at all. Dropped the clamp so it pans freely, matching VenueMapWithPosts's (and event creation's) behavior.
- • Fixed the Equipment and Review steps' read-only map showing nothing for a map that had just been uploaded but not yet saved: that panel read mapUrl straight from the venue's saved layer data, which doesn't have the new map until the venue is actually saved, while the Map step's own interactive view was already showing it via a local preview URL. The read-only panel now uses that same pending preview when there is one.
- • Fixed venue creation's page being a few pixels taller than the actual viewport (forcing a vertical scrollbar): its height was computed as 100vh - 3rem, 8px short of the navbar's real 3.5rem height — now 100dvh - 3.5rem, the same calculation event creation already used.
- • Venue and event actions gated by ownership (edit, delete, share, starting a new event at a venue you don't own) now disable themselves in the UI with an explanation, instead of failing after the fact.
- • Admins can designate an event as an "org event" from its 3-dot menu, making it visible to and dispatchable by every org member, the same way org venues already work.
- • Pending-call surge alerts — the "Pending" chip shown in place of a team before a call is assigned now ticks a live mm:ss timer, and starts blinking between grey and a new true-orange status-alarm color once a call has been pending 1+ minute. Crossing 1 minute also fires a one-time toast, and the call log now notes how long a call sat pending once it's finally assigned. Clinic calls have a new "Pending Transport" status (for patients awaiting transport); a second surge toast fires whenever 3 or more clinic calls are marked Pending Transport at once.
- • Calls/Clinic panel: sticky layout, granular insights, manual surge button — the tab bar, stat row, and Add Call/Add Patient button now stay pinned to the top of the panel, as does the table's column-label row; only the rows scroll (with the app's thin scrollbar) once they exceed the available height. The old single "Total Calls"/"Total Patients" line is replaced with an inline stat row — Total Calls Logged / Active / Pending / On Scene / Transporting for Calls, Total Patients / In Clinic / Transported / Pending Transport for Clinic. A new Surge button next to the tabs lets a dispatcher manually declare a team-wide surge, ticking a live elapsed timer and pulsing with the same alarm animation as the Pending call chip while active; it also auto-activates the moment the existing percent-on-calls threshold (surgeLimitPercent) is crossed, without clobbering an already-running timer, and disabling it now asks for confirmation.
- • Event Name and Event Date are now required before advancing past Event Configuration, matching venue creation's existing name requirement — the other steps' progress dots stay locked until both are filled, and Create Event itself checks the name too.
- • Venue creation's Locations, Equipment, and Review steps now give the map 2/3 of the screen (was half), matching how much room venue creation gave it before this whole restructure — event creation's own map-showing steps are unchanged at half.
- • Review step label/value pairs (both venue and event creation) use a slightly larger font, and both now have a "Review" heading matching the other section headers. Section headers in every step that shows the map alongside it (Equipment/Post schedule/Review in event creation; Locations/Equipment/Review in venue creation) are now a consistent, larger size.
- • Deleting a venue's only floor now clears its map instead of being blocked — a venue always needs at least one layer, so this used to just show a "Cannot delete the last layer" alert; it now resets that floor back to "no map uploaded" (after confirming), the same as if you'd never uploaded one.
- • Event creation now skips the Equipment step entirely for a venue with no equipment of its own defined, instead of showing an empty tab.
- • Reduced the padding between the left column's content and the map column on every split-screen step (both venue and event creation), giving the left column more usable width.
- • Venue creation's Locations step now shows the same simple, read-only floor indicator as Equipment/Review instead of the full layer control bar (replace map, add/delete layer) — adding, replacing, or deleting a layer is Map-step-only now.
- • Lite mode event creation now matches cloud event creation's wizard — Event Configuration, Locations, Staff Assignments, Equipment, Post schedule, and Review, reusing the same step shell, progress indicator, and Team/Supervisor/Equipment/Posts/Schedule section components as the cloud flow, instead of its own bespoke tabbed layout. No map/floor logic is included, since Lite mode has never had one; a new Locations step lets Lite events define their own ad-hoc location and equipment catalog in place of picking a pre-existing venue.
- • The dispatch page navbar's "Posting Schedule" button now only appears when the current event actually has a posting schedule configured, instead of always showing regardless of setup. (The "Venue Map" nav button this line used to also cover no longer exists — see the new Map tab, below.)
- • Venue maps can now be imported from GIS data — the venue Map step gained an "Import GIS map" option (next to Add Layer) that takes a flattened background image plus a GeoJSON FeatureCollection of named Point features (each becomes a post, with isClinic optionally flagging it as a clinic) and a bbox giving the image's real-world extent; the importer projects each point onto the image using that extent and shows a live marker-over-image preview before committing, so a mismatched bbox is obvious before import instead of after. Works both as a venue's first floor and as an added one.
- • The dispatch board's venue map is now a Map tab beside Calls/Clinic instead of a modal opened from the navbar — always one click away, filling the whole panel below the tab strip. Its own thin header bar shows the current floor's name with prev/next arrows (multi-floor venues only) and a location search that jumps to the right floor and calls out the matching post with a bouncing arrow. Clicking any post or team marker shows a small "Add Call" button just beneath it, prefilled with that location or team respectively (dismisses on an outside click); the Add Call form now focuses whichever field is first, in on-screen order, still empty, instead of always Location. Team cards (normal and condensed) gained a map-icon button, shown only when the venue has a map, that jumps to this tab and calls out that team the same way.
- • Every marker on the venue map (dispatch, event creation, venue management) redesigned — a single filled pin/icon with a white outline and drop-shadow, sized independently of the map's zoom level, instead of a low-opacity colored circle behind a plain icon that grew or shrank with zoom. Post pins use CrowdCAD's brand blue; team and equipment markers keep their existing status/equipment colors but now carry them on the icon itself instead of a background ring (the wheelchair/gurney equipment icons are separate raster assets and can't take a fill color the same way, so they're unchanged aside from the shared drop-shadow). A team's stagger offset from its post now shrinks as you zoom in instead of growing.
- • Event posts now start with none selected instead of every venue post pre-selected, with a new "Enable All" button beside the Posts select for picking them all in one click when that's what's wanted.
- • Venue map markers gained a supervisor pin and equipment status badges — a new supervisor marker (shield icon) renders at a supervisor's post using the same status-color mapping as team markers, positioned so it doesn't stack with a team or equipment marker sharing that post; equipment markers now sit inside a colored status badge instead of a bare recolored icon. Team and equipment marker offsets from their post now scale correctly at every zoom level (equipment's previously grew when zooming in instead of shrinking), teams sharing the exact same post now stagger apart instead of rendering on top of each other, and a team's "Add Call" map popup disables itself when that team already has an active call.
- • Map markers now hover-enlarge and support "view on map" from every card type — team, supervisor, and equipment pins all share the same hover/selected enlarge treatment (previously team-only), and equipment/supervisor cards gained their own "view on map" button, matching team cards. All three buttons disable themselves, with an explanation, when that entity's current location isn't an actual mapped post (e.g. Roaming, In Clinic).
- • Mobile dispatch UI overhaul — a sticky top bar keeps the team availability strip visible while scrolling; the bottom tab bar was rebuilt with sharp corners, larger tap targets, and a new five-tab Teams/Equipment/Calls/Clinic/Map layout; Teams gained a Teams/Supervisors switcher dropdown and Clinic a dropdown in place of per-clinic tabs; Calls and Clinic gained header "Add Call"/"Add Patient" buttons and switched their mobile cards to the same divider-list pattern Teams already used, with slide open/close animations for cards and "hide resolved" sections. Also fixes a stray unthemed blue on light-mode "selected" nav states, which now derives from the app's accent token.
- • Surge now auto-activates on every configured threshold — previously only the percent-on-calls threshold auto-activated the surge indicator; the pending-transport-count and unassigned-call-time thresholds now do too, without clobbering an already-running timer. The +Team/Supervisor/Equipment button on a call now disables once that call is resolved, re-enabling only if the team whose status change actually resolved it is reverted. Status icons were removed from dropdown menus (the pill display keeps its icon; menu options now spell out the status as text, e.g. "Transporting to Clinic") and the resolved-call status list is now defined in one place instead of three.
- • Venue map: pinch/scroll zoom and review-step redesign — the dispatch Map tab and venue management's editing map gained ctrl/cmd+scroll zoom and touch pinch-to-zoom/one-finger-pan, alongside a fix for a team/supervisor/equipment highlight replaying incorrectly when navigating back to the Map tab. Event creation, venue creation, and Lite mode's Review steps now render as side-by-side columns (one per wizard step) instead of one long list. The Map tab's keyboard shortcut moved from Ctrl+M to Alt+M, the Add Call popup now opens above its pin instead of below, and new black wheelchair/gurney icon variants keep status-pill icons legible in light mode.
- • Add Team/Supervisor/Call modals switched to a flat, unbordered input style (previously variant="bordered"), with a corrected primary color shade scale; condensed team cards gained spacing above the "Team Members"/"Activity Log" titles and their timer; and every small (size="sm") Button/ButtonGroup now uses a fully-rounded radius consistently.
- • Event summary page charts rebuilt — the calls-by-team pie chart was replaced with a per-team stacked bar (Available / On Break / In Clinic / On Calls) plus attached-calls on a secondary axis, and calls-per-hour was replaced with a Total Team Availability chart bucketed every 10 minutes. The page dropped its diagonal background streaks for the shared "boxy grid" look, and chart tooltips now use a themed dark background with per-series text color instead of Recharts' default white tooltip. An event's schedule From/To is now persisted as scheduleStart/scheduleEnd and used directly as the summary's reporting window.
Changed
- • Replaced the repo's abbreviated AGPL-3.0 license notice with the full GNU Affero General Public License v3.0 text.
Fixed
- • Firestore rules: a non-admin organization member could previously update, share, or delete any other member's venue just by being in the same org. Only the venue's creator or a site admin can do that now; other org members still have read access.
- • Firestore rules: creating a venue or event required an orgId field the app never actually sets, which made creation impossible once these rules were deployed. Creating one now only requires being signed in and naming yourself as the owner.
- • Profile page: an admin account was sometimes not recognized as admin on first load, only appearing after a manual reload. The admin check now uses a live subscription instead of a one-time fetch, so it self-corrects instead of getting stuck.
- • Firestore rules: any query (as opposed to a single-document read) against venues or events — e.g. the admin "delete user and their data" flow — failed outright with a rules evaluation error. Caused by a rule that read its own document via get() instead of the already-bound resource.data, which Firestore doesn't support for list queries.
- • Dispatch page: a non-admin org member opening a show designated as an "org event" was booted to the login screen instead of the dispatch view. The page's own authorization check only recognized the event owner, admins, and users explicitly listed in sharedWith — it never accounted for isOrgEvent, even though Firestore rules and the venue selection screen already treated org events as visible to every member.
- • Firestore rules: even after fixing the dispatch page's client-side check above, a shared or org-event member who got into the dispatch view still couldn't do anything there — every dispatch write (assigning a team, changing a call's status, the page's own on-load clinic sync) failed with permission-denied. The events update rule only allowed the owner or a true orgId org member (which the app never sets); it never considered sharedWith or isOrgEvent. Update now also allows a user listed in sharedWith or any member when the event is flagged isOrgEvent; delete remains owner/admin-only.
- • Firestore rules: that broadened update rule went too far — a shared or org-event member could write to any field on the event doc via a direct Firestore call, including userId, sharedWith, isOrgEvent, ended, and endedAt, none of which the app's own UI ever lets a non-owner touch (those buttons enforced it client-side only, which a direct write bypasses). That meant a shared or org-event member could invite outside people into a private event, flip isOrgEvent to expose someone else's private event to the whole org, or end an event out from under its owner. A non-owner, non-admin dispatcher can still write ordinary dispatch fields (calls, staff/supervisor status, equipment) as before, but those five fields are now owner/admin-only, matching the intent the client-side checks already had. Venues were unaffected — their update rule was already owner/admin-only for every field.
- • Firestore rules: any signed-in user could grant themselves admin — the /users/{userId} rule let a user write any field on their own doc, including isAdmin, which isRequestingUserAdmin() treats as the source of truth everywhere else in this file (editing/deleting any venue or event, managing other admins, etc.). Self-writes can no longer touch isAdmin (on create or update); only an existing admin may grant or revoke it, for themselves or anyone else — matching what the Profile > Admin panel's own UI already implied but never actually enforced.
- • PocketBase: the self-hosted backend had no equivalent of any of the above — scripts/setup-pocketbase.js (the one-time provisioning script every self-hoster forking this repo runs) created venues and events with PocketBase's default "any signed-in user" rule for every operation, i.e. not even scoped to owner or org member, and never touched the built-in users collection's rules at all (a manual admin-UI step the script only ever printed a reminder about). Both are now owner/admin-scoped to match firestore.rules exactly — including the field-level restriction on events' userId/sharedWith/isOrgEvent/ended/endedAt and the isAdmin self-escalation guard — and are applied automatically, re-asserted on every run (including against a collection that already existed under the old rules), so a fresh or already-running self-hosted deployment gets these guarantees without a manual step. Also fixes two related PocketBase-only bugs this surfaced: the events collection was missing the isOrgEvent/ended/endedAt fields entirely (PocketBase silently drops fields not in a collection's schema, so "Designate as org event" and "End Event" would appear to work but never actually persist), and dispatchLogs was missing userId (the field the app already queries it by).
- • useCertifications queried the (auth-gated) settings collection on mount without waiting for Firebase Auth to finish restoring the session, so a hard refresh of the event-create, dispatch, or admin-certifications screens could throw "Missing or insufficient permissions" before the user's session was recognized. The hook now waits for auth to be ready, skips the query entirely when signed out (falling back to the built-in certification list, same as lite/local mode), and no longer lets a transient read failure surface as an unhandled error.
- • Expanding a call's or clinic patient's Notes/Log panel could shave a pixel or two off the bottom border of the Log textarea, same sub-pixel grid-track-rounding issue already fixed for team cards. The expand animation now switches to overflow: visible once fully open here too (overflowVisibleWhenOpen on DispatchMotionCell), instead of only in teamcard.tsx/teamcard-condensed.tsx.
- • Restored the app's actual accent blue on the loading spinner, the "Start Lite Mode" button, and the profile page's admin/preferences Switches, which had all silently gone grey when dark-mode primary was repurposed into a near-black grey ramp for a modal button surface (#39) — color="primary"/color="default" are both grey in this theme now, so these specific controls point at the real accent token instead. Also sharpened the remaining rounded-2xl corners #42 missed: profile page list-row cards, and the Lite event creator's Locations/Equipment (and Teams/Supervisors/Posts/Equipment) tabs, the location/equipment name input+Add button combo, and their added-item row cards.
- • Calls/Clinic panel stat row (TrackingInsightsRow): the space between each label's colon and its count relied on a single literal space character in the label text, which read as too cramped next to the count. Adds a small flex gap on top of it for real visual breathing room.
- • Team/Supervisor/Location card labels in the Staff Assignments and Lite Locations steps were rendering with the bottoms of descenders (lowercase y, g, etc.) clipped off — the page-level leading-none these steps sit under shrank the text's line box tighter than the font's actual glyph height, and the label's own overflow-hidden (from truncate) then cropped it. Labels now set their own normal line height, without changing the card's height (already governed by its taller edit/delete buttons). Delete buttons across these cards now render in red instead of the same grey as Edit, matching venue management's existing delete buttons. Lite mode event creation also no longer shows the diagonal-streaks background other Lite pages use — it clashed with the new wizard layout.
- • Every rounded-square component in the app — inputs, buttons, cards, modals, dropdowns, chips — could render at a visibly different corner radius depending on which of HeroUI's small/medium/large tiers (or Tailwind's own xl/2xl/3xl) it happened to request, since nothing tied those tiers to the same value. All non-none/non-full tiers now collapse to the one Button already used by default, so corners match everywhere without having to special-case every call site (rounded-none and rounded-full are untouched — those are a different shape, not a scale mismatch).
- • Venue selection: a venue's own card in the venue list rendered with no background at rest (only on hover), while the event rows/cards shown once a venue is selected already had one — the venue cards now share that same background.
- • Cloud event creation's posting schedule was always generated regardless of whether "Enable Posts" was checked (lite mode already respected it), so the navbar's Posting Schedule button showed up for every event instead of only ones that actually enabled posts.
- • The repost-from-schedule button above the Calls/Clinic tabs now disables when the event has no posting schedule configured, instead of being clickable with nothing to actually refresh from.
- • Enabling surge now asks for confirmation, matching disabling it.
- • Setting a team's status to Available no longer touches its location — teamcard.tsx/teamcard-condensed.tsx already compute the right destination (its original post, a pending assignment, or its last valid location) and apply it themselves right before the status change; a second, cruder fallback inside the status-change handler was overwriting that immediately after, which is why moving a team from On Break to Available incorrectly relocated it to "Roaming".
- • Team cards briefly showed a page scrollbar when opening or closing — their expand animation's overflow: visible switch (needed once fully open, so a bordered box like the Log textarea doesn't get a pixel shaved off its bottom edge by height-rounding) was applied the instant the state flipped, before the height transition had actually finished growing the row, so the still-clipped content's real height poked out for the whole ~300ms animation. Now waits for the transition's own end event.
- • Fixed a sitewide dark-mode contrast bug: several Input/Select/TimeInput/DatePicker/Chip/Spinner instances passed color="primary", but this theme's dark palette repurposes primary into a near-black grey for button surfaces — so an unstyled text/icon slot using it (a Select's chevron, a Chip's label) rendered nearly invisible. Switched to color="default" for these, leaving actual Button/Chip surface uses of primary untouched.