Platforms
HIG rules and audit
The HIG rules Signal follows, and every surface audited against them.
Rules
HIG as of 1 Oct 2026. The date in brackets is each page's latest change-log entry.
| Topic | HIG rule | v3 value |
|---|---|---|
| Tap targets [Jun 2025] | 44 × 44 pt default, 28 × 28 pt minimum | 44 × 44 minimum on every control |
| Dynamic Type [Dec 2025] | Body 17 pt default, 11 pt minimum. Custom fonts support Dynamic Type and Bold Text. Icons scale with text. Large Title 34, Title 3 20, Body 17, Footnote 13, Caption 2 11. | Display 32 / Title 20 / Body 16 / Sub 13 / Cap 11, each relativeTo: |
| Liquid Glass [Sep 2025] | Glass is for controls and navigation, not the content layer. Use it sparingly on custom controls. | Opaque surfaces |
| Sheets [Mar 2026] | Medium detent on iPhone. A resizable sheet has a grabber, and the grabber works with VoiceOver. Nonmodal is allowed. | No native stop sheet. The Map panel and the pushed stop detail share one FloatingPanel: 132 / 50% / top + 4, with an adjustable grabber |
| Tab bars [Jun 2026] | Navigation only. Visible except under a modal. Floats on Liquid Glass. Search tab at the trailing end. | Native TabView: Home, Map, Search |
| Toolbars [Dec 2025] | Back and Close in the bar. Symbols preferred. Group items. | Settings toolbar item |
| Search [Jun 2026] | Standard search tab: a landing page with the field at the top, keyboard on tap | Search-role tab, unfocused on entry |
| Alerts [Feb 2024] | Don't use an alert merely to provide information | System alert for service alerts |
| Maps [Dec 2024] | System map controls. Custom controls need contrast. | System .mapControls |
| Widgets [Dec 2025] | 16 pt margin. Accented, clear and vibrant modes. Interaction through buttons and toggles only. | Widgets + Live Activities |
| Live Activities [Dec 2025] | 14 pt Lock Screen margin. Essential actions only. StandBy at 2×. | Approved v3 Live Activity spec |
| iPhone Duo [Sep 2026] | Build to resize. Bars move to the side. Respect reserved regions. Don't override the default bar placement. | Readiness checklist |
| Accessibility [Jun 2025] | Contrast in both appearances. Not colour alone. Reduce Motion. Every control labelled. | AA contrast, status as a word |
Surfaces against the HIG
chitransit-app main 82560e7 (#97 map perf, #98 tabs + Map panel); stop detail, Map panel content and grabber rows at 3a3db9c (#102). Paths are relative to chitransit-app/. Rationale: docs/specs/ios-design.md.
CompliantDeviationGapn/a
| Surface | HIG rule | v3 spec | App today | Status | Gap |
|---|---|---|---|---|---|
| Tab bar | Navigation only, Liquid Glass, search tab trailing | TabView: Home, Map, Search | Tab API on iOS 18+ (views/MainView.swift:128-142), .tabItem fallback (:144-158) | Compliant | — |
| Tab bar visibility | Visible except under a modal | — | Visible on every tab, including the stop detail pushed from Home or Search (views/StopView.swift:38-121) | Compliant | G5 (resolved) |
| Search tab | Standard search tab | Search-role tab, unfocused | .searchable(.navigationBarDrawer(.always)) (views/GlobalSearchView.swift:221-226) | Compliant | — |
| Map controls | System controls | System .mapControls | Location, pitch, compass and scale (views/MapView.swift:705-710). The custom overlay is DEBUG-only. | Compliant | — |
| Map panel anchors | Medium detent for progressive disclosure | Low 180 (Nearby 120) · half 50% · full top + 4 | FloatingPanel 3.2.4: .tip 180 absolute (120 on Nearby), .half 0.50 fractional, .full top + 4, all in .safeArea; Search is full only (views/Sheet/SheetPanels.swift:19-44). Removal is disabled (:585). | Compliant | — |
| Map panel grabber | The grabber works with VoiceOver | Grabber 40 × 5 | A 44 pt adjustable element over the grabber: Panel position, Collapsed / Half / Expanded, Expand and Collapse actions, Escape collapses one anchor (views/MapPanelView.swift:222-264) | Compliant | G2 (resolved) |
| Map panel motion | Respect Reduce Motion | Motion off under Reduce Motion | One shared sheet spring (0.42 s, bounce 0.15) for drags, detent moves and the station slide; under Reduce Motion it becomes 0.17 s critically damped, or a 0.17 s fade for the station slide (utils/DesignTokens.swift, views/Sheet/SheetPanels.swift). | Compliant | G10 (resolved) |
| Map panel surface | Glass for controls only. Don't hide system glass. | Paper, 28 pt radius, sheet shadow | Paper, radius 28 with continuous corners, shadow 0 −10 30 at 16% (views/MapView.swift:348-363) | Deviation | G9 (decided) |
| Map panel content | — | Nearby, or the selected station with an X. Peek: summary. Half: direction and its static arrivals. Full: everything (#68). | Three presentations: peek summary, half arrivals, full details (views/StopView.swift:242-258, 409-455, 495). Only full expands timelines. | Compliant | G11 (resolved) |
| Map avoids the panel | Use safe areas | — | .safeAreaPadding(.bottom, panelCoveredHeight), driven by the panel state (views/MapView.swift:504, 605-612) | Compliant | G3 on Duo |
| Stop detail (Home / Search) | Push in the tab’s stack; tab bar stays visible | Pushed page: a map under the shared panel, above the visible tab bar | Pushed StopItemView: a map under the shared FloatingPanel layout and grabber, not removable, opens at half; the tab bar stays visible. Only the 44 pt grabber drags the surface, so the body scrolls and pulls to refresh (views/StopView.swift:22-35, 85-121) | Compliant | G5 (resolved) |
| Station header | 44 pt targets, Dynamic Type | Display title, 44 pt close and actions | Custom SheetHeaderButton X, 44 × 44, labelled “Close stop detail” (views/StopView.swift:524-541) | Compliant | — |
| Toolbar items | Back and Close semantic. Icon and title on each item. | — | Settings .topBarTrailing Label. Custom Back .topBarLeading (views/StopView.swift:77). Done is text-only (views/HomeView.swift:265-275). | Gap | G6 |
| Cards and rows | 44 pt targets | Padding 14, radius 12, rows at least 64 | Matches. Edit / Done uses .padding(.vertical, -12) (views/FavoritesView.swift:212). | Compliant | G16 |
| Live tracking feedback | Communicate in context | Banner removed (#67) | Inline Home sections, no banner (views/FavoritesView.swift:245-285) | Compliant | — |
| Type scale | Body 17, minimum 11, Bold Text | Body 16, Display 32 | Figtree relativeTo:. No legibilityWeight handling. | Deviation | G14 |
| Icon scaling | Icons scale with text | — | Fixed 27 / 22 / 18 / 17 pt (views/StopView.swift:484, 532; views/Lists/ListComponents.swift:63, 222) | Gap | G13 |
| Sub-11 pt text | 11 pt minimum | No text in train circles | 7–8 pt line codes (views/FavoritesView.swift:527; ChiTransitWidget/FavoriteStopWidget.swift:408; ChiTransitWidget/ChiTransitWidgetLiveActivity.swift:248) | Gap | G12 |
| Service alerts | No informational alerts | System alert (approved) | .alert (views/StopView.swift:315-319) | Deviation | G15 |
| Widgets | Rendering modes, buttons | All families, refresh | Small, medium, inline and rectangular. No Button(intent:), no widgetAccentable. | Gap | G17 |
| Live Activities | Timely updates | Push updates (server shipped, CTA-65) | pushType: nil (service/LiveActivityService.swift:477-480) | Gap | G18 |
| Accessibility | Labels, Reduce Motion, colour not alone | Status as a word, AA | Pins are labelled buttons with the selected trait (views/MapView.swift:686). Controls are labelled. | Compliant | G10 |