/* hub.css V5.34 - 2026-10-10, Nolan (§B27 convergence): `.h-xapp`, the small Tools marker on a Tools-owned row (Fuller tools and Staff Administration); `.h-tdoor__path` removed with the step it styled; `.h-toolsret`, Back to H365 Tools on a member record Tools opened. */
/* hub.css V5.33 - 2026-10-08, Nolan (PT-SAFE). U2 N-E-33: under html[data-kiosk="1"] (a locked kiosk door) the app bar, bottom nav and Help layer are not drawn and the door fills the screen at every width; N-E-31: `.h-sa__fs`, the frameless disabled fieldset a read-only staff record sits in. */
/* hub.css V5.32 - 2026-10-08, T09-B. B17: `.h-lr__hint.is-warn`, the amber twin of `.is-bad` (--warn), for a soft warning that never blocks (the waiver editor's short-wording line). */
/* hub.css V5.31 - 2026-10-08, Nolan. B16: `.h-inv__rcpt`, the receipt / confirmation disclosure under a payment, refund or credit row (its own summary marker, spaced off the row above). */
/* hub.css V5.30 - 2026-10-08, CONV-B. The contextual staff actions in the shared staff language: the Staff Hub quick view's tabs as a grid that fits (.h-sh__tabs[data-n], .h-sh__sec, .h-sh__pay, .h-sh__payacts), the Fuller tools destination rows (.h-tdoors, .h-tdoor*), and the door, invoice, member-record and organizer-tools pieces below. */
/* hub.css V5.29 - 2026-10-08, Nolan. The member app bar wordmark: left beside the avatar, two-tone ("Hockey" white, "365" green), scales down only on the narrowest phones (Karl). */
/* hub.css V5.28 - 2026-10-07, CREW builder (Lane B §9.1). .h-sh__reconfirm: the Staff hub's "Changed — please confirm again" line. */
/* hub.css V5.27 - 2026-10-05, Nolan (Karl's walk GD-05). Help & Support: the private search (.h-helpwin__search) and the green form-button rule (.h-helpwin__form button, which also painted the Category choices green) are retired for the globals (.h-searchrow/.h-search, .h-btn); guide results sit as a plain list, the dashed box only frames the empty message. */
/* hub.css V5.26 - 2026-10-05, Nolan. Partners NR-11: the old member directory's .h-pt rules retired (33); the staff .h-pt rules stay. */
/* hub.css V5.25 - 2026-10-05, Nolan. CLEANUP RELEASE: the legacy Avatar Studio rules (.h-as*) and the Locker Room emblem chooser (.h-lr__emblem*) are retired (archived in Hockey365_App_Rebuild/archive/Legacy_Avatar_Studio_2026-10-05/). */
/* hub.css V5.24 - 2026-10-05, Nolan. Spaces: the Basic square (.h-id__plain inside .h-gav--id). */
/* hub.css V5.23 - 2026-10-05, Nolan. B65 final: .h-id__plain, the Basic disc drawn live in the colour set. */
/* hub.css V5.22 - 2026-10-05, Nolan. B65 third pass: Kits button beside the colour dot (strip removed), the button bar lower, Basic disc tint (.h-av--tint). */
/* hub.css V5.21 - 2026-10-05, Nolan. B65 second walk: the studio's Reset / Review pair is a FIXED bottom bar; layers contain their scroll; Review's warning leads; the real Player Card in Review. */
/* hub.css V5.20 - 2026-10-05, Nolan. B65: the identity studio block rewritten (full-height column + bottom-edge Reset/Review, fixed-grid tabs, colour dot, kits / review / Space art pages, personal-only locker tabs). */
/* hub.css V5.19 - 2026-10-05, Nolan. Character + Space: .h-av--id / .h-gav--id / .h-id__* for the one identity renderer. */
/* hub.css V5.18 - 2026-10-05, Nolan. B64: chat sender faces for initials members (9px letters); Prefer a list?'s words grouped (one space). */
/* hub.css V5.17 - 2026-10-05, Nolan. Book a Coach wide screen: the date-range bar's switch keeps its words (its slot collapsed, and the arrow-button rule boxed it). */
/* hub.css V5.16 - 2026-10-05, Nolan. Book a Coach date row: 12px on the right to match the left (the switch sat flush on the edge; pre-walk at 375). */
/* hub.css V5.15 - 2026-10-04, Nolan. Book a Coach: "Prefer a list?" on the date row, right of the selected date (.h-cb__daterow/.h-cb__dlabel). */
/* hub.css V5.14 - 2026-10-04, Nolan. The friends mini-profile (.h-frprofile*) is retired: View member opens the Player Card. */
/* hub.css V5.13 - 2026-10-04, Nolan. ID-31: a sender's name line in Messages is a button (opens the Player Card), dressed as the label it was. */
/* hub.css V5.12 - 2026-10-04, Nolan. Player Card campaign: the Locker Room trading card rules (.h-lr__cardart, .h-lr__cardnote) are retired with `h365RenderCard`. */
/* hub.css V5.11 - 2026-10-04, Nolan. Stats & Three Stars: the old stat grid (.h-es*), stars strip (.h-gs__star*) and score line (.h-gs__score, .h-gs__side) retired; .h-gs__jersey stays (Teams).
/* hub.css V5.10 - 2026-10-04, Nolan. Karl: the Messages composer disappeared in long threads (the dock's chat pane had no min-height: 0, so it grew past the clipped dock). */
/* hub.css V5.09 - 2026-10-04, Nolan. B62 pre-walk: while the Messages dock is open, an open H365UI sheet, its scrim and the toast stack above it (the chat's Remove / Leave / Delete / Block confirms were hidden under the dock on a phone). */
/* hub.css V5.08 - 2026-10-03, Nolan. Relay Campaign 3 (Karl walk PU-11): the one-row Get the app banner above the top bar (.h-getapp), its install sheet and steps. */
/* hub.css V5.06 - 2026-10-03, Nolan. Relay Campaign 2: the coach's travel fee line (.h-cd__fee/.h-cd__lnk) and Can't make it / File report under a session row (.h-cd__li.is-acts/.h-cd__liacts). */
/* hub.css V5.05 - 2026-10-03, Nolan. Karl's walk RY-06: the Report reason list (tick boxes, optional line). */
/* hub.css V5.04 - 2026-10-03, Nolan. The pending line uses the Centre Ice teal tint. */
/* hub.css V5.03 - 2026-10-03, Nolan. CM-08: the post box's teal "Lists on Find when you post" line (.h-ced__why.is-pend). */
/* hub.css V5.02 - 2026-10-03, Nolan. MST-3: the organizer's Stat corrections cards (.h-gs__corr). */
/* hub.css V5.01 - 2026-10-03, Nolan. BL-01 pre-walk: the legend never clips; on the smallest phones the list switch wraps to its own line. */
/* hub.css V5.00 - 2026-10-03, Nolan. B45: the amber fix line's wash is composited over --panel (contrast rule).
/* hub.css V4.99 - 2026-10-03, Nolan. B45: the retired .h-ced__fix rules removed (the amber .h-ced__why replaced them). */
/* hub.css V4.98 - 2026-10-03, Nolan. B45 sweep (Karl): post box × badge (.h-ced__att, .h-ced__x.is-badge), Spotlight / Card icons, switched-off Spotlight (.is-unavail), amber reason + cog fix (.h-ced__why). */
/* hub.css V4.97 - 2026-10-03, Nolan. BL-01: first collapse at 112px (the full words need about 105). */
/* hub.css V4.96 - 2026-10-03, Nolan. BL-01 (Karl's B57 walk): "Prefer a list?" on the legend row with a list icon; its words drop as room runs out, leaving an icon button (.h-cb__keyrow/.h-cb__keysw/.h-cb__listsw). */
/* hub.css V4.95 - 2026-10-03, Nolan. A pending household invitation row wraps on a phone: the words keep their width and Send again / Cancel drop below. */
/* hub.css V4.94 - 2026-10-03, Nolan. Household invitations: Send again beside Cancel (.h-fam__sacts). */
/* hub.css V4.93 - 2026-10-03, Nolan. Book a Coach: Length chips gone (.h-cb__lens retired); the optional "Prefer a list?" view (.h-cb__viewsw, .h-cb__list, .h-cb__lrow). */
/* hub.css V4.92 - 2026-10-03, Nolan. A read-only setup row (`.h-fam__todob.is-static`) for a member the guardian may not edit. */
/* hub.css V4.91 - 2026-10-03, Nolan. `.h-fam__wzleave` retired (Back moved to the wizard header); a child card's setup list uses the end-list rows. */
/* hub.css V4.90 - 2026-10-03, Nolan. The end list's check and Change wear their own colours (the list's `li span` muted rule no longer wins). */
/* hub.css V4.89 - 2026-10-03, Nolan. Add a child: a done row keeps its place with a green check (.h-fam__todob.is-done, .h-fam__todock); Leave for now under the wizard buttons (.h-fam__wzleave). */
/* hub.css V4.88 - 2026-10-03, Nolan. The down jump arrow's resting gap is 12px; coach.js lifts it over the button bar only when that bar covers the bottom. */
/* hub.css V4.87 - 2026-10-02, Nolan. Book a Coach's finished-fixes box is green (.h-cb__warn.is-done). */
/* hub.css V4.86 - 2026-10-02, Nolan. The jump arrow rule says why it is glass (contrast over-wash). */
/* hub.css V4.85 - 2026-10-02, Nolan. Karl's walk: the add-a-child end list is tappable rows (.h-fam__todob); Use me buttons (.h-fam__emguse, .h-cb__emguse); Book a Coach done notes (.h-cb__ok). */
/* hub.css V4.84 - 2026-10-02, Nolan. Karl: the jump arrows are green half-glass, centred; down while there is more below, up at the TOP once at the bottom. */
/* hub.css V4.83 - 2026-10-02, Nolan. Book a Coach Review: the in-place emergency contact for a child (.h-cb__emg). */
/* hub.css V4.82 - 2026-10-02, Nolan. The jump arrow sits in a sticky holder at the end of whichever box scrolls (.h-co__jumpwrap). */
/* hub.css V4.81 - 2026-10-02, Nolan. The jump arrow wears solid panel ink at half strength (contrast), still glass-blurred. */
/* hub.css V4.80 - 2026-10-02, Nolan. Karl's walk pass: jump arrow on booking calendars (.h-co__jump), decline ticks (.h-cd__dsel), post quote in Remove from Find (.h-ced__gone), notifications search (.h-nt__search). */
/* hub.css V4.79 - 2026-10-02, Nolan. BK11: Hockey365 activity block (.h-cb__act, .h-cd__actl). */
/* hub.css V4.78 - 2026-10-02, Nolan. The Attach fold chevron does not animate under Reduce motion. */
/* hub.css V4.77 - 2026-10-02, Nolan. CI-03: Attach row fold control (.h-ced__labrow). */
/* hub.css V4.76 - 2026-10-02, Nolan. .h-cb__selt declared once (pencil room folded in). */
/* hub.css V4.75 - 2026-10-02, Nolan. BD-01: pencil on the selected-session card (.h-cb__pen). */
/* hub.css V4.74 - 2026-10-02, Nolan. BC-07: the under-18 Book a Coach card (.h-co__youth). */
/* hub.css V4.73 - 2026-10-02, Nolan. BC-04/BR-04: e-Transfer icon on Waiting approval, Copy details + Sent it? Let us know in one row (.h-inv__etacts). */
/* hub.css V4.72 - 2026-10-02, Nolan. Walk B49: decline-or-offer panel (.h-cd__ofs/.h-cd__of), amber Decline button, Get help link, member offered times (.h-co__opt). */
/* hub.css V4.71 - 2026-10-02, Nolan. Double Scroll Box option C on Book a Coach Times (.h-cb.is-fill). */
/* hub.css V4.70 - 2026-10-02, Nolan. BD-05 tile avatar is .h-cb__wav (.h-cb__av is the coach row). */
/* hub.css V4.69 - 2026-10-02, Nolan. BD-05: Book a Coach Who step person tiles (.h-cb__who). */
/* hub.css V4.68 - 2026-10-02, Nolan. The opened post (phone) steps aside while a page opened from it is showing. */
/* hub.css V4.67 - 2026-10-02, Nolan. Coaching tabs stay on one line (three for a coach). */
/* hub.css V4.66 - 2026-10-02, Nolan. My sessions groups (.h-co__grp). */
/* hub.css V4.65 - 2026-10-02, Nolan. Direction D phase 2: Booking requests (.h-cd) and the My sessions confirm and suggestion cards. */
/* hub.css V4.64 - 2026-10-01, Nolan. Direction D: washes composited over a solid, the corner ✕ and tip solid. */
/* hub.css V4.63 - 2026-10-01, Nolan. Book a Coach Direction D: the member flow (.h-cb). */
/* hub.css V4.62 - 2026-10-01, Nolan. BC-01: room above Who is this for?. */
/* hub.css V4.61 - 2026-10-01, Nolan. Book a Coach (BC-01): the rate on its own line, the day as a scroll panel opened on the earliest free time, the Next line. */
/* hub.css V4.60 - 2026-10-01, Nolan. Karl's walk: the Slim Search (`.h-slims`, regular-search focus, no box in a box), @ in comments, and the opened post fills a phone screen. */
/* hub.css V4.59 - 2026-10-01, Nolan. Centre Ice CI-3: `.h-men` (a mention in a post), the post box's teal-mention layer, the @ list, the smart tip row, and List on Find on a card. */
/* hub.css V4.58 - 2026-10-01, Nolan. Karl: the post card is V11's quiet card (no green left bar, one edge all round); the feed thread is one line per comment (no avatars or bubbles). */
/* hub.css V4.57 - 2026-10-01, Nolan. Karl: `.h-scope--ci`, the Centre Ice feed tab bar in teal. */
/* hub.css V4.56 - 2026-10-01, Nolan. CI-2: overrides merged into the original .h-cp / .h-post__bar / .h-react__picker rules (one body each); composited teal icon tiles; `.h-face__sq`. */
/* hub.css V4.55 - 2026-10-01, Nolan. Centre Ice V11 CI-2: header-row post cards, Spotlight / Card / Link attachments, the post box as the preview (`.h-ced*`), teal for Centre Ice, motion with Reduced Motion. */
/* hub.css V4.54 - 2026-10-01, Nolan. Book a Coach rulings: `.h-co__gap` (what a child's request is missing, with fix links), `.h-inv__etsent` (Waiting approval), `.h-ainv__etwait` (the admin e-Transfer prompt). */
/* hub.css V4.53 - 2026-10-01, Nolan. Book a Coach pass: `.h-co__bkwho`. */
/* hub.css V4.52 - 2026-10-01, Nolan. 0638 From Hockey365: `.h-nttabs`/`.h-nttab` (the bell's two tabs), `.h-nt--h365` rows, `.h-upd*` (the message card + six artwork presets). */
/* hub.css V4.51 - 2026-10-01, Nolan. Walk v59: a game's panels start 12px under the tabs like a group's (`.gs > .h-room__tabs` margin). */
/* hub.css V4.50 - 2026-10-01, Nolan. Walk v59 (Karl): `.h-phead` (one panel heading) and `.h-tbtn` (TEXT manager buttons like Manage, stacked, truncating first); `.h-sec-act` restyled; `.h-acts`, `.h-sroom__head--act` removed. */
/* hub.css V4.49 - 2026-10-01, Nolan. Header comment closed properly (V4.48's line). */
/* hub.css V4.48 - 2026-10-01, Nolan. `.h-sec-act` shows its button (the label hides overflow), 32px, bottom on the text. */
/* hub.css V4.47 - 2026-10-01, Nolan. Walk v58: `.h-acts`, `.h-sroom__head--act`, `.h-sec-act` (the button rule). */
/* hub.css V4.46 - 2026-10-01, Nolan. Walk v57: `.gs-rhead > .h-mgbtn--roster` (game Roster / Info edit buttons). */
/* hub.css V4.45 - 2026-10-01, Nolan. Walk v54: `.h-skcaltip` (what a calibration was based on). */
/* hub.css V4.44 - 2026-10-01, Nolan. Walk v54: `.h-skbase*` (their own rating + Calibrate on the ratings sheet), `.h-grm__skacts`. */
/* hub.css V4.43 - 2026-10-01, Nolan. LR-06 (walk v54): `.h-inv__howh`, the How to pay heading. */
/* hub.css V4.42 - 2026-10-01, Nolan. The divider under Pay by card; `.h-swpop__k` (the kind icon on a switcher row). */
/* hub.css V4.41 - 2026-10-01, Nolan. `.h-inv__paybtn` (renamed off the invoice box's own class). */
/* hub.css V4.40 - 2026-10-01, Nolan. LR-06 `.h-inv__k`, `.h-inv__link`, `.h-inv__paybtn`; The switcher pop-up list (`.h-swpop`). */
/* hub.css V4.39 - 2026-10-01, Nolan. `.h-na__actcol` / `.h-na__pri` (Priority under the action). */
/* hub.css V4.38 - 2026-10-01, Nolan. LR-06: `.h-inv__et` / `.h-inv__etcopy` (the e-Transfer details to paste). */
/* hub.css V4.37 - 2026-10-01, Nolan. LR-09 `.h-wrowi.is-focus`. GA-05: `.h-gcode--row` / `.h-gcode__btn` (New code + Copy). */
/* hub.css V4.36 - 2026-10-01, Nolan. `.h-swdrop__hint`. */
/* hub.css V4.35 - 2026-10-01, Nolan. Preview v2: the slim tab-bar Manage, the Program title switcher (`.h-swt`, `.h-swdrop`, `.h-swcard`). */
/* hub.css V4.34 - 2026-10-01, Nolan. RE-02 `.h-ginv__acts--pair`; FM-02 `.h-lr__vbar` / `.h-lr__vcol`; Leave household bottom-left. */
/* hub.css V4.33 - 2026-10-01, Nolan. BB-01: `.h-addsec__tip` / `__link`. LR-06: `.h-inv__how`, `.h-inv__sel` (the invoice's How to pay block). */
/* hub.css V4.32 - 2026-10-01, Nolan. `.h-more__badge` (a count on a Manage row). */
/* hub.css V4.31 - 2026-10-01, Nolan. The no-account disc's initials use `--avatar-ghost-ink` (contrast). */
/* hub.css V4.30 - 2026-10-01, Nolan. Walk v45 rings: black (member), black disc + grey ring (no account), grey dotted (waiting to confirm). GA-05 second walk: the Share menu's "?" (`.h-sharepop__head`, `__q`, `__help`). */
/* hub.css V4.29 - 2026-10-01, Nolan. B29: `.h-lr__vleft`, `.h-lr__perm`. RE-01 v45: `.h-grm__av.is-pending`. GA-04 v45: `.h-sharepop` (the Share menu) and `.h-grm__attn.is-quiet` (applications button with none waiting). */
/* hub.css V4.28 - 2026-10-01, Nolan. Walk v45 (phones): a Space's tab-bar Manage is the cog alone under 520px; walk B33: the Discover Loop button + shimmer, `.h-ask__suggests`, `.h-ask__more`; `.h-fam__leave`. */
/* hub.css V4.26 - 2026-09-30, Nolan. GA-05 v45: `.h-room__herobtns` / `.h-codepill` — the group code pill left of Share on the banner. */
/* hub.css V4.25 - 2026-09-30, Nolan. GA-05 v45: `.h-gcode`, the group code chip.
   (V4.24) */
/* hub.css V4.24 - 2026-09-30, Nolan. GA-04 v45: the membership-applications card gets room above and below; the scrapped `.h-rtbar` rules removed. */
/* hub.css V4.23 - 2026-09-30, Nolan. Walk v45: the wizard's Back / Continue are in the flow at the end of the step (no pin, no bar). */
/* hub.css V4.22 - 2026-09-30, Nolan. SP-02 v42: `.h-mpin`, the Staff PIN view in the Menu panel. */
/* hub.css V4.21 - 2026-09-30, Nolan. Walk v42: the wizard bar sticks at `bottom: 0` in the sheet's inner scroller (`.h-sheet--foot`). */
/* hub.css V4.20 - 2026-09-30, Nolan. AN-02 v42: the category dropdown (`.h-annsel*`), the larger message box and its formatting bar (`.h-rtbar`), and formatted posts (`.h-rt__big`, `.h-rt__ul`). */
/* hub.css V4.19 - 2026-09-30, Nolan. PY-10 v42: `.h-rf__tabs`; the wizard bar wears the bottom nav's glass (sheen, edge, tint) while more is below. */
/* hub.css V4.18 - 2026-09-30, Nolan. PY-10: Roster & fees (`.h-rf`, `.h-rf__limit`, `.h-rf__lt`). */
/* hub.css V4.17 - 2026-09-30, Nolan. AN-02: the Social and events category class is `.h-ann--social_event`. */
/* hub.css V4.16 - 2026-09-30, Nolan. AN-02: the category icon wash is composited over the panel (contrast). */
/* hub.css V4.15 - 2026-09-30, Nolan. Walk v41: the wizard bar pinned flush with glass, NOT READY Continue, fixed Spots (the attention ring moved to components.css); AN-02 announcement categories (`.h-ann--*`, `.h-room__ann-*`, `.h-annpick`). */
/* hub.css V4.14 - 2026-09-30, Nolan. MN-03: My Groups' actions on one row. */
/* hub.css V4.13 - 2026-09-30, Nolan. LR-03: the two local skill-number styles give way to the shared `.h-skill__v`. */
/* hub.css V4.12 - 2026-09-30, Nolan. Walk v38: RO-02 tight cog disc and a centred roster button; My Groups actions. */
/* hub.css V4.11 - 2026-09-30, Nolan. WZ-08 game-or-group tiles show their pick (`.h-rfill__kind[aria-pressed]`). */
/* hub.css V4.10 - 2026-09-30, Nolan. CC-09 `.h-ch__minor` notice in a coach room with a minor. */
/* hub.css V4.09 - 2026-09-30, Nolan. Unset Locker Room sliders are no longer faded (the look lives in `.h-range`); GA-02 note label; RR-04 mismatch badge; RO-03 share row; RO-05 locked chips. */
/* hub.css V4.08 - 2026-09-30, Nolan. Walk v37: roster icon with a cog badge (RO-02); composer grows to 40vh (RL-01); roster sub-head without its own back (Double Back Button). */
/* hub.css V4.07 - 2026-09-29, Nolan. Comment correction. */
/* hub.css V4.06 - 2026-09-29, Nolan. Fill your roster Continue is no longer sticky (it floated over the page). */
/* hub.css V4.05 - 2026-09-29, Nolan. Chat with a Coach: the Coach tag on inbox rows, the New-message coach door, the picker rows. */
/* hub.css V4.04 - 2026-09-29, Nolan. Discover's Hockey news rows (`.h-dc__news`, `.h-dc__nrow`). */
/* hub.css V4.03 - 2026-09-29, Nolan. Fill your roster (`.h-rfill*`), the Membership stub (`.h-stub*`), slider scale line, Use me row, Needs you pill under the text. */
/* hub.css V4.02 - 2026-09-29, Nolan. The level chips' selected wash is composited (contrast rule). */
/* hub.css V4.01 - 2026-09-29, Nolan. Skill number boxes at 16px (Auto Zoom on Field Entry); the per-position level chips (`.h-lr__tiers`). */
/* hub.css V4.00 - 2026-09-29, Nolan. `.h-set__tabs` (B26). */
/* hub.css V3.99 - 2026-09-29, Nolan. RO-02 cog, RO-03 header Share, GA-02 lead line, GA-03 Leave group, GM-01 floating Posting to and attach chip, WZ-03/05/06 spots and money boxes, HR-01 amber Family members rule. */
/* hub.css V3.98 - 2026-09-28, Nolan. `--n` declared on `.h-grm__seg` (the rows set it inline); `--gs-tabs` read without a fallback. */
/* hub.css V3.97 - 2026-09-28, Nolan. GB-01 `.h-sch__hero`; RO-01 roster tools moved to the standard search row; GB-08 group schedule panel. */
/* hub.css V3.96 */
/* V3.96 - 2026-09-28, Nolan. `.h-panel__sub` under a panel title (GS-03). */
/* V3.95 - 2026-09-28, Nolan. Switch in the tab bar (`.h-room__switch--tab` / `--mini`). */
/* V3.94 - 2026-09-28, Nolan. B03: a Space's head carries the app's top-right buttons (`.h-detail__icons`); Manage sits right-aligned in the tab bar, amber and outlined, its word never folded. */
/* V3.93 - 2026-09-28, Nolan. The roster manager sits at 46: over the Space panel, under every sheet it opens. */
/* V3.92 - 2026-09-28, Nolan. Roster manager marks are ink on the panel with coloured borders (contrast pass). */
/* V3.91 - 2026-09-28, Nolan. The group roster manager (`.h-grm*`, Sloane's
   approved preview): a full-screen layer over the app's navigation with the
   circular back, count tiles, the applications card, green membership and
   purple hockey-role segments, the glowing search, styled Sort / History menus,
   initials avatars with owner and friend rings, the player record's cards and
   the inline retire / ban confirmation. `.h-rost*` is the Roster tab's head,
   tiles and tools in the same language. */
/* V3.90 - 2026-09-28, Nolan. Karl's walk of the wizard: the − / + nudgers are
   gone and number boxes lose their spinner arrows; the count is an 84px column
   whose edge is the money row's right edge (the $ box is the same 84px, the
   segment takes the rest), so nothing jumps when "They pay" adds the $ box and
   the $ box is the segment's height everywhere. Plus the wizard's multi-select
   chips, "+ Add" links, Remove links and the Invite friends list. */
/* V3.89 - 2026-09-28, Nolan. The drawer's set-apart Cancel keeps ordinary ink (no new failure-state class). */
/* V3.88 - 2026-09-28, Nolan. The wizard's review cards sit apart (`[data-wrev]` gap). */
/* V3.87 - 2026-09-28, Nolan. `.h-wiz__iic` draws its icon in --ink (contrast pass). */
/* V3.86 - 2026-09-28, Nolan. The create-game wizard (`.h-wiz*`, Sloane's flow
   layout: progress bars, step intro, intent cards, cards, sticky foot) and
   MM-01's worded top-bar Manage button (`.h-mgbtn`) with the drawer's set-apart
   Cancel (`.h-mdrawer__danger`). */
/* V3.85 - 2026-09-28, Nolan. The two Find glows are COMPOSITED over --panel2
   (`linear-gradient(tint,tint), var(--panel2)`) so their text contrast is
   measurable — same look, and not added to the translucent-wash backlog. */
/* V3.84 - 2026-09-28, Nolan. Find filters (Karl's P2 walk rulings, LF-04/B11):
   `.h-scope--glow` (the approved GREEN active glow, from Sloane's preview, on
   the Find role row only) and `.h-ffdd` (one equal-width row of three styled
   dropdown tabs; the approved PURPLE glow once set). The corner date
   `.h-find__day` is removed with its markup. Theme-aware via --green-rgb /
   --purple-rgb, which flip with the theme by design. */
/* V3.83 - 2026-09-26, Calder. Help form error line outranks the form's paragraph rule. */
/* V3.82 - 2026-09-26, Calder. Help's Email us form error line. */
/* V3.81 - 2026-09-26, Calder. The profile list's remaining blocks match its rows. */
/* V3.80 - 2026-09-26, Calder. Profile rows are `.h-lr__prow` (`.h-lr__row` is the
   editor's form row). */
/* V3.79 - 2026-09-26, Calder. Stage 2F: Locker Room heading, profile rows and
   the autosave status line. */
/* V3.78 - 2026-09-26, Calder. One `.h-dc__tiles` rule, not two. */
/* V3.77 - 2026-09-26, Calder. Stage 2E: Discover's heading, ask card and doors. */
/* V3.76 - 2026-09-26, Calder. The phone's one-page scroll actually applies
   (specificity over the later base rules). */
/* V3.75 - 2026-09-26, Calder. Phone hides the feed's duplicate scope heading. */
/* V3.74 - 2026-09-26, Calder. Stage 2D: the post's attachment row
   (`.h-post__att*`) replaces the chips; the feed's "Be the first" is a door. */
/* V3.73 - 2026-09-26, Calder. Phone hides the floating Post for real; space
   tiles wrap to two lines instead of cutting names off. */
/* V3.72 - 2026-09-26, Calder. Stage 2C: the Centre Ice frame (`.h-ci__head`,
   `.h-ci__sp*`, `.h-ci__feedhead`) and the phone's one-page scroll. */
/* V3.71 - 2026-09-26, Calder. The Hockey365 H mark loses its tile and grows. */
/* V3.70 - 2026-09-26, Calder. Karl's walk: a Space room has no box or glow —
   its bubbles sit on the page's black — and Send is a round icon button in
   every composer (`.h-ch__send`). */
/* V3.69 - 2026-09-26, Calder. Space between the Hockey365 tab's sections. */
/* V3.68 - 2026-09-26, Calder. The Hockey365 search card's own rule. */
/* V3.67 - 2026-09-26, Calder. Stage 2B: the Hockey365 tab's cards (`.h-h365*`),
   to the approved preview, on the shared tokens. */
/* V3.66 - 2026-09-26, Calder. A Space room fills to the bottom of the screen
   (chat.js `fitEmbed` sets its height; the thread flexes inside it), an empty
   room centres its empty state, and the kicker is the Space's name, not caps. */
/* V3.65 - 2026-09-26, Calder. The Space room heading uses `--font-display`
   directly rather than a shorthand with a fallback. */
/* V3.64 - 2026-09-26, Calder. A Space's rooms, ON the Space (`.h-sroom`, filled by
   chat.js `embed`): a bounded thread with its composer pinned under it. The
   Chat room (`.h-sroom--msgr`) takes the Messenger's own `--hc-*` redirects,
   so it IS the Messenger's blue-black and blue; Announcements keeps the
   Space's look. */
/* V3.63 - 2026-09-26, Calder. Karl: Space chat shares the Messenger's colours now
   that the Messenger is the primary one. `.h-msgr-entry` — every door into a
   chat from a Space or group board — wears Messenger blue; inside the dock the
   requests row and Send take it too, and a group emblem is round. */
/* V3.62 - 2026-09-26, Calder. Stage 1 Messenger. The dock begins BELOW the top
   nav (`--hc-top`, measured by chat.js), slides down to open and back up to
   close (a fade under reduced motion or low effects), owns the full width at
   700px and under, and keeps the adjustable rail above that. New inbox tools
   (always-visible search, New, compact filter listbox), a Group Message ring,
   the group emblem on channel rows, and the Messages badge in Messenger blue.
   Removed: the Hub's inline Messages home (`.h-ch--inline`, `.h-ch__hub*`) and
   the dock's chip row and toggled search it replaced. */
/* V3.61 - 2026-09-25. Add the contextual Help utility window with empty guide
   staging plus real chat and email support paths. */
/* V3.60 - 2026-09-25. Reuse Schedule's green two-view control for Friends and
   add the dedicated header-launched Add friend panel. */
/* V3.59 - 2026-09-25. Size the real shared avatar class in the Friends profile
   and use the shared Messenger-blue token for its Message action. */
/* V3.58 - 2026-09-25. Declare the Friends profile container used by the new
   drawer so the client/CSS contract remains complete. */
/* V3.57 - 2026-09-25. Replace Friends' generic bottom sheet with the approved
   right-side social drawer while preserving the real relationship engine. */
/* V3.51 - 2026-09-25. Correct Schedule's semantic toggle hierarchy: both
   calendar sources use green, List/Calendar uses purple, and the compact phone
   filter keeps its icon, active dots, and a tiny status label. */
/* V3.50 - 2026-09-25. Purple Schedule state uses accessible shared ink. */
/* V3.49 - 2026-09-25. Keep Schedule glow states on opaque premium surfaces. */
/* V3.48 - 2026-09-25. Restore the preview's compact Schedule toolbar,
   restrained green/purple glow hierarchy, and readable list-week strip. */
/* V3.47 - 2026-09-25. Use the approved accessible solid-purple pair for the
   selected Hockey365 Schedule source in both light and dark themes. */
/* V3.46 - 2026-09-25. Use the approved Impact display role on Schedule and
   keep view mode and filtering on separate full-width rows at every width. */
/* V3.45 - 2026-09-25. Keep the Schedule hero photograph visible on mobile:
   the scrim now clears toward the image side instead of dimming it end to end. */
/* V3.44 - 2026-09-25. Premium Schedule presentation over the existing
   six-source calendar: source switch, responsive tools and next-event hero. */
/* V3.43 - 2026-09-25. Name the role-filter active state explicitly so the
   green-first / purple-second filter contract is both visible and testable. */
/* V3.41 - 2026-09-23, Rita. `S2-109` - Karl, on tapping a search box: "we don't need the extra squared outline inside the already existing outline that's around the search. The rounded outline around the search should glow." Discover's ask
   box is a rounded pill (`.h-ask__bar`) with a borderless field inside it, and
   the field was still drawing base.css's ring INSIDE the pill: the squared
   second outline. The field now draws nothing and the pill glows
   (`:focus-within`). The Stats grid's `.h-es__in` gets the same glow on its
   own border. */
/* V3.40 - 2026-09-23, Rita. `S2-108` - the create sheet's count row on Karl's
   iPhone: "cuts off a small portion of the number field for who is playing AND
   the entire plus symbol". `.h-need__b` never set its own padding, so on iOS it
   took WebKit's button default (0 1em = 18px a side at this font size) and a
   36px nudger became ~48. It now zeroes padding and appearance and cannot grow.
   And the row can no longer clip whatever an engine adds: `.h-need__top` wraps,
   and the stepper keeps its right edge on the line below the name rather than
   being cut. At every width Chromium measures, nothing moves. Reasoning at the
   rules. */
/* V3.39 - 2026-09-19, Jackie. `SYS-29` - 73 raw corners -> `var(--r-*)`.
   Of them: 41 pixel-identical, 31 moved 1px, 1 moved 2px.
   The map in `tools/css-radius.mjs` is now EMPTY, so a new raw corner here is
   no longer a number to raise - it is an unrecorded file. Mapped by that
   tool's own SCALE/NEAREST tables, never by eye; measured before and after on
   every visible element of all 26 pages. */
/* - 2026-09-19, Jackie. `S2-12` - the money mode buttons clip
   their own track below ~344px. Scoped to `max-width: 360px`; nothing at 361px
   and above changes by a pixel. The breakpoint comes from the NESTED
   `GAME-11` visitor row, which is 20px narrower than the one above it and had
   never been measured by anything. Guarded by `tools/moneyrow-fit.mjs`. */
/* hub.css V3.37 - 2026-09-19, Cass. `LKR-15` ①/②: `.h-lr__cardart` and
   `.h-lr__cardnote`, the trading card and its frame caption on the Locker Room.
   The art is given a width and left to compute its own height so a future frame
   with a different aspect is not letterboxed. */
/* hub.css V3.36 - 2026-09-18, Meryl. `S2-02`, two of the four screens Karl named.
   A SECTION LABEL HAD NO GAP UNDER IT, AND ITS 2px RULE PAINTS AT THE BOTTOM OF ITS
   OWN BOX - so "the green line actually touches the button" is literal. Measured
   headless at 390px: More label -> first row 1.00px, "Rating" -> hero 0.00px.
   Now 8.00px and 7.00px. Nothing reflows sideways; no row changed width.
   ⛔ SCOPED TO THE TWO NAMED SCREENS ON PURPOSE. The cause is `base.css`'s
   `.h-sec-label { margin: 0 }` and 21 other surfaces share it - that is `SYS-09`,
   which is a project and is not authorised here. See the outbox. */
/* hub.css V3.35 */
/* V3.35 - 2026-09-18, Jackie. PROSE ONLY, and it makes `S2-07` a smaller claim
   than I had been making. `.h-seg` in components.css -- the app's other padded
   segmented control -- ALREADY pairs `--r-md` on the container with `--r-sm` on
   the buttons. `.h-scope` was the odd one out using pills. This row is not
   choosing a corner for filters, it is making the control that disagreed
   agree. Recorded beside the rule. */
/* V3.34 - 2026-09-18, Jackie. PROSE ONLY. My V3.30 note called a 14px corner
   on a filter "a no-op" flatly; `find-card-align` measured it and that is only
   exactly true on `.h-chip--sm`, where it clamps to a perfect pill. Scoped
   rather than left standing, because the next person sizing a control off this
   paragraph deserves the number and not my rounding of it. */
/* V3.33 - 2026-09-18, Jackie. `S2-07`, AND THIS IS THE DECLARATION THAT
   ACTUALLY ANSWERS KARL. `.h-scope__seg`, `.h-scope__s` and `.h-scope__more`
   were `--r-pill`, and THOSE are the filters sitting directly under the four
   Find buttons he compared them to. I had already changed `.h-chip` -- a
   filter chip on other screens -- and `find-card-align`'s vacuity guard is
   what told me there is no `.h-chip` on the Find screen at all. A row that
   squared every filter in the app except the one he was looking at would have
   been green, shipped, and still wrong on his screen. The segment's container
   takes `--r-md` and its buttons `--r-sm`, because the container holds 3px of
   padding and 8 + 3 = 11 is exactly that relationship at the default scale. */
/* V3.32 - 2026-09-18, Jackie. PROSE ONLY, AND IT IS A CORRECTION TO MY OWN
   OVERCLAIM. V3.30 said using a token meant the chips would match the Find
   tiles in every style. Measured in all five: they match at the DEFAULT style
   and diverge in the other four, because the tiles' 14px is raw and does not
   move. The table and the limit are now written beside the rule. No
   declaration changed. */
/* V3.31 - 2026-09-18, Jackie. A ONE-LINE CORRECTION TO V3.30 BELOW, RECORDED
   RATHER THAN FOLDED IN, because `css-stamp` refuses to re-record under an
   unchanged header and it is right to: a bump per content change is the whole
   ratchet. My V3.30 block opened a comment and never closed it, so the V3.29
   entry under it opened a second one INSIDE it. `css-balance` caught it in the
   same pass -- *"the comments still balance by COUNT, which is why nothing
   flagged here until now"* -- and the fix is the shape that file always
   prescribes: give the opening block a close of its own. No rule changed. */
/* V3.30 - 2026-09-18, Jackie. `S2-07`: the filter chips take the Find tiles'
   family of corner instead of being pills. ONE declaration -- `.h-chip` is the
   only rule every filter chip in the app comes through, which is what makes
   Karl's "only if it's a simple global change" condition met rather than
   claimed.
   MEASURED BEFORE SHIPPING, BECAUSE HIS OWN NUMBER WOULD HAVE BEEN A NO-OP:
   the tiles are 88px tall with a 14px corner; a chip is 32px tall, so 14px is
   0.875 of its half-height and still a pill, and on `.h-chip--sm` (25.3px) it
   clamps to a perfect pill -- zero visible change. `--r-sm` is the app's
   existing next step down and reads as a rounded rectangle at the size a chip
   actually is. A TOKEN, so it follows the four theme scales.
   `.h-chip--sm` STAYS A PILL: it already declares `cursor: default` because it
   is a fact about a row, not a control. Karl asked for the FILTER chips.
   The tiles' own raw 14px is untouched -- tokenising every radius is `SYS-29`. */
/* V3.29 - 2026-09-22, Vera. `SYS-51`: the orphaned `.h-rail__item:hover` body
   is deleted from here. Its VALUE was the correct one and now lives, once, in
   components.css — the file the comment three lines above the deletion says has
   owned this component since 08-17z. No render change: this body was the one
   that was already winning. */
/* V3.28 - 2026-09-21, Iris. `FND-09`, the Find result card, both of Karl's
   alignment faults — and both lived entirely inside the `max-width: 400px`
   block, doing exactly what they said. Stacking put `.h-find__right` at the
   card's padding edge (flush with the helmet tile, 51px left of the title) and
   left-packing put Apply against the fee with 106px of empty card beside it,
   MEASURED at 390px by `tools/find-card-align.mjs` before anything moved. The
   fee row is now indented into the TEXT column and the action takes an auto
   margin to the card's right edge. `--find-tile` and `--find-gap` are named on
   `.h-find` so the indent is a `calc()` of the tile rather than a third copy
   of 51 — the tool resizes the tile at runtime and re-reads the chip, so a
   literal cannot pass. Nothing was made smaller: it was never a width problem.
   NOTE: landed on top of Vera's V3.27, re-staged first; different block. */
/* V3.27 - 2026-09-21, Vera. `SET-01`, defect 1 of 3. `.h-frow`'s reset here was
   a second body of the selector and its `border: 0` silently killed
   `components.css:1332`'s `border-top: 1px solid var(--line)`. The row
   separator has therefore never painted anywhere in this app. Reset narrowed to
   the three sides it needs; the top is left to the file that owns the value.
   MEASURED, not read: 11 cards on Settings, 0 separators drawn. */
/* V3.26 - 2026-09-20, Vera. `SYS-38`: `.h-more` reads `--card-edge` and
   `--card-tex`, and its surface moves from the row to the card so the inset
   edge is actually visible — with the declarations alone it measured 0 lit
   pixels. Swept every stylesheet for the row-stack card shape: this is the only
   other one. Reasoning at the rule. */
/* V3.25 - 2026-09-17, Meryl. `Q-02` sweep, REMOVAL AND RETARGETING ONLY: `.h-mback`, `.h-sa__back`,
   `.h-ch__back` and this file's `.h-detail__act` are gone into components.css,
   each leaving a gravestone. Chat's VISIBILITY policy for the control is
   retargeted onto `.h-back--icon` and STAYS HERE, because hiding by default is
   chat's layout rule and not the shared control's -- dropping it would have
   made chat's back button visible in every mode. */
/* V3.24 - 2026-09-16, Meryl. `Q-02` prerequisite, REMOVAL ONLY: this file's
   copy of `.h-detail__back` and its chevron rotation are gone; components.css
   is now the one body, exactly as `.h-detail__head`, `__title` and `__body`
   were moved in 08-17z. Nothing else in this file is touched and nothing
   changes on screen -- the app loads both stylesheets, so the merged rule is
   byte-for-byte what was already winning. The seven pages that load
   components.css WITHOUT this file are the ones that were wrong. */
/* V3.23 - 2026-09-16, Iris. `DSC-06` — the Ask button says when the field
   holds something it has not searched yet. Karl: "when text is typed but not
   submitted, the Ask button must highlight or animate."
   `.h-ask__go.is-dirty` — a ring in `--green`, no colour change on the label,
   so the button is louder without becoming a different control.
   ⚠️ NO ANIMATION BY DEFAULT and the reason is `DSC-02`: Discover now searches
   as you type, so for an ordinary typist this state lasts ~400 ms. A thing that
   pulses on every pause is noise, and this file already argued that once. The
   ring is instant, costs nothing to ignore, and PERSISTS exactly where the
   state is real: one or two characters, which auto-search deliberately will not
   fire on, and a search that came back failed.
   ⛔ AND IT IS A RING, NOT A FADE: `tools/_contrast-dom.mjs` cannot see
   `opacity`, so anything expressed by fading is unguarded — measured on
   2026-09-06 and written down at `.h-ask__stale`. */
/* V3.22 - 2026-09-16, Tony. `GAME-11` - `.h-need__floor`, the visitor-price
   floor line. Karl ruled the floors onto the visitor price and asked for them
   LOUDLY, so this reads heavier than the grey consequence tips beside it. */
/* V3.21 - 2026-09-15, Tony. `GAME-11` - `.h-need__vis` and `.h-need__vl`, the
   visitor-price block nested inside a role row. Reuses `.h-frow__nest` for the
   indent and rule rather than drawing a second nesting treatment. */
/* V3.20 - 2026-09-15, Cass. `LKR-01`: the amber attention dot moves from
   `top:5px right:7px` to `top:-1px right:-1px` on `.h-hub__nav--dot .h-ic
   ::after`. Two values. Its centre was 1.6px from the centre of a 20px icon -
   on the face - and is now 10.6px out at the corner. Position only: no token,
   no colour, no spacing scale, so it does not cross `SYS-14`'s hold. Vera's
   V3.19 `FND-02` step-two words are untouched and step three is still hers. */
/* V3.19 - 2026-09-07, Vera. `FND-02` step two: three fill sites move to
   `--purple-solid` - `.h-co__key.is-mine`, `.h-co__sel`, and the Fill a
   Roster tile `.h-tiles--find .h-tile--hero`. Their `border`/`border-color`
   stay on `--purple`: that is the EDGE job, improved 2.65 -> 4.52 by step
   three. Three words changed, nothing else in this file is mine.
   ⚠️ TONY WAS IN THIS FILE AT THE SAME TIME. His V3.18 landed at 10:42,
   after my edit; mine survived, but by timing rather than by design. */
/* V3.18 - 2026-09-07, Tony. `FND-04` - `.h-sch__top--findh`, the Find
   heading's own pinned row above the filter segment. Tighter padding than
   `--find` because it sits directly on top of it. */
/* V3.17 - 2026-09-07, Tony. `GAME-09` - `.h-frow__nest`, the indent and left
   rule that make the "and they skip the spares wait" switch read as a child of
   the switch above it rather than as a second unrelated question. Sets no
   `display`, so `[hidden]` still wins. */
/* V3.16 - 2026-09-07, Ellie. `MSG-01` — `.h-ch__menu`'s two horizontal anchors
   are SWAPPED. Both were wrong, not just the reported one: outgoing expanded
   rightward off a bubble already at the right edge, incoming expanded leftward
   off a bubble at the left edge, and both overflow on any bubble narrower than
   the menu's 132px minimum. Each now opens INTO the screen, which makes the
   overflow impossible at any width rather than corrected after the fact.
   Reasoning and the arithmetic are at the rule. One class, one renderer, so it
   lands on the lean messenger and the Hub room together — the item, not half
   of it. Seam noted: this file is Meryl's this round (V3.9-V3.15) and Cass has
   a line at :227; my edit is at :3236 and touches neither. */
/* V3.15 - 2026-09-06, Meryl. Recruitment rebuilt onto `.h-grp`, so the two
   row-era `.h-recruit` rules here have no caller and are deleted. Vera: "the
   first card is missing its top border and the other two are not." */
/* V3.14 - 2026-09-06, Meryl. Three routed items, all one-liners in rules I own.
   `FND-01` - the ON tile painted a 148px green BAR behind its icon, measured;
   the chip rule outlived the naked-icon redesign 20 rules below it.
   `MORE-04` - Nora's rings; support takes `--info`, both go to 2px. Coach stays
   green pending a `tokens.css` entry for the schedule's coach pink, which is
   Vera's file - reasoning at the rule.
   `SYS-26` finding 4 (Vera) - `opacity: .6` on retired and banned rows dragged
   their text to 2.72:1; each part is dimmed by choosing a dimmer colour, which
   is what this file already told itself to do 440 lines earlier. */
/* V3.13 - 2026-09-06, Ellie. `HUB-02` ON KARL'S RULING: `.h-nofr`, the
   zero-friends warning in the composer, with the door that is the whole point
   of it — the note it replaces stated a fact a member could do nothing about.
   Plus `HUB-08`'s divider between the post and its thread in the expanded view,
   and the clamp pinned at the 8 lines Karl approved.
   ⚠️ I FIRST WROTE THIS AS V3.9 AND THAT WAS WRONG — Meryl's `FND-07` V3.9
   landed while I was building, so there were briefly TWO V3.9 entries in this
   changelog. Removed and re-filed here on top of hers. My V3.8 below is
   untouched and so are V3.9 through V3.12; nobody's work was overwritten in
   either direction, which is the only reason this was a tidy-up and not a loss.
   Recorded in the same pass, per the ratchet rule. */
/* V3.12 - 2026-09-06, Meryl. Removing a rule of my own from V3.9 that never
   ran. `.h-need__amt[hidden] { display: block; visibility: hidden }` cannot
   beat `base.css:47`'s house-wide `[hidden] { display: none !important }`, and
   the column it was meant to hold is held by the track instead. Measured, not
   reasoned: pill 196 / 266 / 296 at 320 / 390 / 430, identical in both modes,
   with the box hidden the ordinary way. */
/* V3.11 - 2026-09-06, Meryl. `FND-07` (1), second half. `.h-need__c` takes its
   height from `.h-need__step` rather than from a typed figure, because
   `GAME-05`'s 44px nudgers landed in that row minutes after V3.9 and the 9px
   I had just applied left the box six short and floating between them. One
   declaration, `align-self: stretch`, and Tony's rule is untouched. */
/* V3.10 - 2026-09-06, Tony. `GAME-05` - `.h-need__step` and `.h-need__b`, the
   minus/plus either side of each role count on the post-a-game sheet. 44px
   tall for the tap target, 36 wide so three roles keep the same shape at
   320px, and `flex: 0 0` on all three children so a long role name cannot
   squeeze the controls.
   (V3.9 was taken by Meryl's `FND-07` while this was in flight. Hers landed
   first, so this is the next number rather than a renumbering of hers.) */
/* V3.9 - 2026-09-06, Meryl. `FND-07` (1) and (3), Sol's block applied in one
   pass because both move the same row and landing them separately means
   measuring it twice. (2), the mode tip, went in at V3.7.
   (1) THE AMOUNT BOX WAS 11px TALLER THAN THE PILL. `align-items` goes from
   `center` to `stretch` and the box's vertical padding goes to 0, so the pill
   sets the row's height and the box takes it. NOT a font change - a focused
   field under 16px zooms mobile Safari and that floor is `SYS-07`.
   (3) THE PILL CHANGED WIDTH WHEN YOU TAPPED IT. The amount's column is now
   held open on every row - `1fr 84px` rather than `1fr auto`. The rule that
   collapsed the column when the box was hidden is DELETED; it was the defect,
   and it was the only `:has()` in this file. Sol's second half of this - hide
   the box with `visibility` so it keeps occupying the track - is NOT here: see
   the note at the rule, it cannot run and it is not needed.
   THE PRICE, STATED: about 92px of held-open space to the right of the pill on
   a free row. Sol accepted it deliberately and so do I - Karl has reported the
   resize twice, four weeks apart, and has never once reported the gap. If the
   gap reads badly on a phone the fallback is a narrower reserved box, NOT a
   collapsing column. */
/* V3.8 - 2026-09-06, Ellie. `HUB-03` the in-sheet code picker (`.h-attach__pick`
   and friends) replacing a native <select> that iOS drew at the top of the
   window, and `HUB-06` the greyed coming-soon rail section (`.h-rail__sec--soon`,
   `.h-rail__soon`). the friends-warning note style and its two
   modifiers are DELETED — `HUB-02` removed both call sites and hub.js was the
   only emitter. (Its class name is not written out anywhere in this file on
   purpose; see the note at the deletion site.) */
/* V3.7 - 2026-09-06, Meryl. `FND-07` ② only - the mode tip and its wrapper.
   `.h-need__nwrap` and `.h-need__tip` have been emitted by `schedule.js` since
   00:05 with NO RULE ANYWHERE, so the tip rendered at 16px --ink and
   `client-contracts` has been red at 226/2 naming both classes. That suite is
   globbed into `test-all.mjs`, so it was a hold on the DEPLOY GATE rather than
   cosmetic debt - which is why this one item came out of Sol's spec ahead of
   the rest of it. Sol specified the tip; the wrapper is mine, and `flex: 1 1
   auto` moved off `.h-need__n` onto it because the name and tip now STACK and
   the pair is what takes the row's space. Reasoning at the rule.
   The other two thirds of `FND-07` - the $ box height and the pill width -
   ride with `SYS-26`, unchanged. */
/* V3.5 - 2026-09-06, Iris. `DSC-02` — the stale-results state on Discover.
   Karl typed a new search, left the field, and the list underneath went on
   answering the previous question with nothing marking it as old.
   ① `.h-ask__stale` — the notice above the answer, naming the question the
   results DO answer. `--warn` border, `--ink` text at full strength.
   ② `.is-stale .h-ask__answer` — the Orchestrator ruled "dim the result
   block". Built as `background: var(--bg)` so the card flattens into the page
   ground and reads as subordinate, NOT as `opacity`: I mutated the rule to
   `opacity: .35` and all 78 assertions stayed green, because
   `tools/_contrast-dom.mjs` reads `getComputedStyle(el).color` and folds in a
   colour's ALPHA but never the element's `opacity` property. Fading here would
   be unguarded rather than merely risky. Reported on the bus.
   ⚠️ THIS BUMP IS MINE INSIDE MERYL'S SEAM AND THAT IS DELIBERATE, NOT A
   LAND-GRAB. The Orchestrator routed `hub.css` to her by seam; the 04:20 UTC
   change that made V3.4 stale is solely mine and the file is byte-identical to
   what I wrote (`d44af15e…`, untouched for six hours). Only the seat that made
   a change can "say what changed", which is what this ratchet asks for. If
   Meryl lands `FND-07`'s width here, she bumps again over the top. */
/* V3.4 - 2026-09-05, Emily. TWO CHANGES, AND THE SECOND IS WHY THIS BUMP IS
   NOT ONE LINE.
   ① `INV-02` — the invoice description is clamped to three lines with an
   expand: `.h-inv__desc.is-clamped` and `.h-inv__descmore`. Karl asked for a
   snippet people can open. The clamp is HERE and not a `slice()` in the
   client on purpose: how many lines fit is a question about the screen’s
   width, the same call `content.css` already made for guide excerpts.

   ② 🛑 THE HEADER WAS EATING `#hub`, AND IT HAD BEEN SINCE THE V3.3 BUMP.
   Line 1 opened a comment and never closed it, so every version block since
   has been running INSIDE that one comment. The V3.3 block was added as a
   comment of its own, and its closing marker therefore closed the OUTER one —
   leaving all the V3.2 prose below it sitting in the stylesheet AS CSS.
   A browser recovers from that by eating tokens until the next braced block
   and throwing the lot away, and the next braced block was `#hub` — the flex
   rule that lets the Hub fill its height rather than sit at content height.
   📐 MEASURED IN CHROMIUM, NOT REASONED ABOUT: 1512 rules parsed before the
   repair, 1513 after, and the one that came back is `#hub`.
   ✅ Every block now opens and closes on its own, which is `base.css`’s shape.
   ⚠️ `css-stamp --check` did not catch this and cannot: it reads the first
   version token in the first 400 characters, and a stamp is perfectly correct
   inside a comment that closes in the wrong place. Three other stylesheets
   have the same defect and are reported on the bus, not touched here. */
/* V3.3 - 2026-09-05, Meryl. Bug Sweep 1 package A, `SYS-07`.
   `.h-input--sm`, `.h-wv__edit`, `.h-es__in` and `.h-ask__in` raised to 16px:
   each declared its own size under the iOS zoom floor, and `.h-ask__in` did it
   by re-stating a size after `font: inherit` reset one. Visibly larger fields
   on admin email, waiver edit, the gamesheet stat cells and Discover's ask. */
/*
   V3.2 — 2026-09-04, Vera. 41 raw colours -> 16 -> 0 (4 sanctioned: a sandboxed
   iframe of real email HTML, the signature canvas exported onto a certificate,
   and the typed preview that must match that export).
   · THE MESSENGER'S 11 LITERALS became the --dock-* family in tokens.css, with
     `.h-dock` REDIRECTING --hc-* into it the way `.h-chrome` redirects the
     globals. The 95 --hc-* uses and 53 fallbacks are untouched, because the
     messenger has two homes and the inline one must keep falling through.
   · `[data-theme="light"] .h-dock` DELETED — its seven values are the light
     half of --dock-*.
   · Five hand-written shadows tokenised at today's values (--sh-dock,
     --sh-popover, --sh-menu, --sh-chip, --sh-hairline); collapsing them onto
     the ladder's rungs is a later, visible change.
   ============================================================================
   HOCKEY365 — THE HUB

   Ported from Layouts/Hub/Hub CSS.txt + Hub HTML v2.6, re-expressed in our
   tokens. The class names are ours (.h-hub*), the LAYOUT and the BEHAVIOUR are
   the live app's.

   Structure, matching the live DOM:
     .h-hub                       the section host
       .h-hub__strip              sticky section nav (Centre Ice … More)
       .h-hub__sections
         .h-hub__section          one per section; exactly one .is-active
           .h-ci                  Centre Ice: rail + main
             .h-ci__rail          desktop only, 220px, feed filters + spaces
             .h-ci__main
               .h-ci__top         MOBILE ONLY: spaces strip + scope chips
               .h-ci__stage       the Post button + the feed
   ========================================================================== */

/* The Hub fills whatever the app shell gives it, and scrolls INSIDE its
   sections — the strip is sticky and the bottom nav is fixed, so neither may
   be pushed off by feed length. Same rule as .h-app: height, then min-height:0
   on the scrolling descendant. */
/* #hub IS THE FLEX ITEM. .h-app is a full-height column and .h-hub is ready to
   fill it, but the div between them carried no CSS at all — so the whole Hub
   sat at content height and everything inside it stopped short, leaving dead
   space under the messenger. One missing link in an otherwise complete chain. */
#hub { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }

.h-hub { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; max-width: 100%; }
/* Karl's rule, enforced structurally rather than trusted: NOTHING in the Hub
   requires a sideways swipe. Any child that would exceed its parent wraps or
   truncates instead. `min-width: 0` is the load-bearing half — a flex item
   defaults to min-width:auto and refuses to shrink below its content, which is
   how a single long word or a row of pills silently widens a whole surface. */
.h-hub *, .h-lr *, .h-dc * { min-width: 0; }
.h-hub, .h-hub__sections, .h-hub__section, .h-ci, .h-ci__main, .h-ci__stage,
.h-lr, .h-lr__body, .h-dc, .h-dc__body { max-width: 100%; overflow-x: hidden; }

/* ---------------------------------------------------------------------------
   SECTION STRIP
   Sticky under the app bar. The SELECTED section shows its name beside its
   icon; the rest are icons alone. Karl's call — a green pill with no word on
   it tells you where you are only if you already know what the icons mean.
   ------------------------------------------------------------------------ */
.h-hub__strip {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 2px;
  padding: 8px 6px;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
  /* NO overflow-x. Six items have to FIT — on a 320px phone as much as on a
     desktop. The inactive ones are icon-width and the active one takes what is
     left, rather than pushing the strip into a side-scroller. */
  overflow: visible;
}

.h-hub__nav {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  /* Inactive items are ICON-SIZED, not equal shares. The active pill is the
     only one that carries a word, so it is the only one that needs room —
     giving all six an equal share would squeeze the word out at exactly the
     width where it matters most. */
  flex: 0 0 auto; min-width: 0;
  padding: 8px 9px; border: 0; border-radius: var(--r-pill);
  background: transparent; color: var(--muted);
  font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
  position: relative;
  transition: background-color var(--t-fast), color var(--t-fast);
}
.h-hub__nav .h-ic { width: 20px; height: 20px; }
.h-hub__nav:hover { color: var(--ink); }
.h-hub__nav.is-active { background: var(--green); color: var(--on-green); }

/* The name sits BESIDE the selection, at every width. Only the active item
   carries its word — six words and six icons will not fit a 320px phone, and
   the one you are on is the one worth naming. The active pill takes whatever
   is left over and ellipsises rather than pushing the strip wider. */
.h-hub__nav-lb { display: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.h-hub__nav.is-active { flex: 0 1 auto; min-width: 0; }
.h-hub__nav.is-active .h-hub__nav-lb { display: inline; }
/* No "show every label on desktop" override. One rule at every width means the
   strip a member learns on their phone is the strip they get on a laptop; the
   old breakpoint made the same control look like two different controls. */
.h-hub__nav .h-ic { flex: none; }

/* The amber dot on Locker Room when something needs the member. On the icon's
   top-right corner - see `LKR-01` inside the rule, it was NOT on the shoulder
   until 2026-09-15 despite this sentence saying so for a month. The live app MEASURES this with JS on every nav change
   plus two timers; a static ::after does the same job for free. */
.h-hub__nav--dot .h-ic::after {
  /* `LKR-01`. WAS `top: 5px; right: 7px`, which the comment above called the
     shoulder and which is not: a 7px dot at that offset on a 20px icon spans
     x 6..13, y 5..12, putting its CENTRE 1.6px from the icon's centre. That is
     on the face, and Karl's "amber badge over the centre person's face" is
     literally accurate rather than an impression. Corner-relative now, so its
     centre sits 10.6px out, and `markH`'s 28x20 icon needs no special case.
     ✅ CANNOT CLIP, CHECKED RATHER THAN HOPED: with the 2px ring the dot
     reaches x=23, y=-3, against `.h-hub__nav`'s own `padding: 8px 9px`, and
     `.h-hub__strip` is `overflow: visible`. The nearest neighbour is 25px away
     and the halo uses 3px of it.
     ⚖️ POSITION ONLY. No token, no colour, no spacing scale - `SYS-14`'s hold
     is on theme decisions and this is structure, which is the line the 20:30
     round draws. `--warn-solid` and the 2px `--bg` ring are untouched. */
  content: ''; position: absolute; top: -1px; right: -1px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--warn-solid);
  box-shadow: 0 0 0 2px var(--bg);
}
.h-hub__nav .h-ic { position: relative; }

.h-hub__badge {
  position: absolute; top: 2px; right: 4px;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: var(--r-pill);
  background: var(--green); color: var(--on-green);
  font-size: 9px; font-weight: 800; display: grid; place-items: center;
}

/* ---------------------------------------------------------------------------
   SECTIONS
   ------------------------------------------------------------------------ */
.h-hub__sections { flex: 1 1 auto; min-height: 0; display: flex; }
.h-hub__section { display: none; flex: 1 1 auto; min-height: 0; min-width: 0; }
.h-hub__section.is-active { display: flex; }

/* ---------------------------------------------------------------------------
   CENTRE ICE
   ------------------------------------------------------------------------ */
.h-ci { display: flex; flex: 1 1 auto; min-height: 0; width: 100%; }

.h-ci__rail {
  flex: 0 0 220px; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  border-right: 1px solid var(--line);
  padding: 12px 10px 56px;
}
/* The live rail needed overscroll-behavior + a 56px bottom pad because scroll
   chained to the body and rubber-banded the last item out of reach. Kept. */
@media (max-width: 760px) { .h-ci__rail { display: none; } }

.h-ci__main { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; }

.h-ci__top { flex: 0 0 auto; padding: 10px 14px 2px; }
@media (min-width: 761px) { .h-ci__top { display: none; } }

/* ---- STAGE 2C: THE CENTRE ICE FRAME (approved preview, 2026-09-26) ------- */
.h-ci__top small {
  display: block; color: var(--green); font-size: 11px; font-weight: 800;
  letter-spacing: .1em; text-transform: uppercase;
}
.h-ci__top h2, .h-ci__top h3 {
  margin: 3px 0 0; font-family: var(--font-display); font-weight: 400;
  text-transform: uppercase; letter-spacing: .025em; line-height: 1;
}
.h-ci__top h2 { font-size: 28px; }
.h-ci__top h3 { font-size: 19px; }
.h-ci__head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 4px 0 14px; border-bottom: 1px solid var(--line);
}
.h-ci__headpost {
  flex: none; min-height: 38px; display: inline-flex; align-items: center; gap: 6px;
  padding: 0 14px; border: 0; border-radius: var(--r-md);
  background: var(--green); color: var(--on-green); font-size: 13px; font-weight: 800; cursor: pointer;
}
.h-ci__headpost .h-ic { width: 16px; height: 16px; }
.h-ci__sphead, .h-ci__feedhead {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; margin: 16px 2px 10px;
}
.h-ci__feedhead > span { color: var(--muted); font-size: 12px; font-weight: 700; }
.h-ci__all {
  flex: none; min-height: 32px; padding: 0 12px; border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--panel2); color: var(--ink); font-size: 12px; font-weight: 700; cursor: pointer;
}
.h-ci__spgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.h-ci__sp {
  min-width: 0; min-height: 112px; display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  padding: 10px; border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--panel); color: var(--ink); text-align: left; cursor: pointer;
}
.h-ci__sp.is-empty { width: 100%; min-height: 0; flex-direction: row; align-items: center; padding: 14px; }
.h-ci__sp.is-empty > .h-ic { flex: none; width: 18px; height: 18px; color: var(--muted); }
.h-ci__spav {
  width: 38px; height: 38px; flex: none; border-radius: var(--r-md); overflow: hidden;
  display: grid; place-items: center; background: var(--panel2); font-weight: 800; font-size: 12px;
}
.h-ci__spav .h-gav { width: 100%; height: 100%; }
.h-ci__spav.is-program { outline: 2px solid var(--purple); outline-offset: -2px; }
.h-ci__spt { display: flex; flex-direction: column; gap: 2px; min-width: 0; width: 100%; }
.h-ci__spt strong, .h-ci__spt small {
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.h-ci__spt strong { font-size: 13px; font-weight: 800; line-height: 1.25; }
.h-ci__spt small { color: var(--muted); font-size: 11.5px; font-weight: 600; letter-spacing: 0; text-transform: none; }
/* ONE PAGE ON A PHONE: the heading, your spaces and the feed scroll together,
   the way the preview reads. Paging is the Load older button, not scroll
   position, so moving the scroller changes nothing about loading. The
   floating Post is the desktop's; here the heading carries it. */
@media (max-width: 760px) {
  /* `.h-ci` PREFIX ON PURPOSE: the base `.h-ci__stage` / `.h-feed` rules sit
     further down this file and, at equal weight, would win — which is exactly
     how the first cut left the feed scrolling in its own 329px box. */
  .h-ci .h-ci__main { overflow-y: auto; overscroll-behavior: contain; }
  .h-ci .h-ci__stage { flex: 0 0 auto; min-height: auto; }
  .h-ci .h-feed { flex: 0 0 auto; min-height: auto; overflow: visible; }
  .h-ci .h-ci__post { display: none; }   /* beats the base rule further down */
  /* The feed's own "All posts" line: the Your feed header already names it. */
  .h-ci .h-feed__roomhd { display: none; }
}

.h-ci__stage { position: relative; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }

/* The floating Post button. Pinned to the stage, NOT to the feed, so it does
   not scroll away. It fades out while the in-feed composer prompt is on
   screen — an IntersectionObserver toggles .is-cp-onscreen, same as live. */
.h-ci__post {
  position: absolute; top: 6px; right: 14px; z-index: 20;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 14px; border: 0; border-radius: var(--r-pill);
  background: var(--green); color: var(--on-green);
  font: inherit; font-size: 13px; font-weight: 800; cursor: pointer;
  box-shadow: var(--sh-accent);
  transition: opacity var(--t-fast), transform var(--t-fast);
}
.h-ci__post .h-ic { width: 16px; height: 16px; }
.h-ci.is-cp-onscreen .h-ci__post { opacity: 0; pointer-events: none; transform: scale(.9); }

.h-feed { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 12px 16px 28px; }
.h-feed__roomhd {
  font-size: 11px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); font-weight: 700; margin: 4px 0 10px;
}

/* The in-feed composer prompt — the thing a member actually taps. */
.h-cp {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 10px 9px 12px; margin: 10px 0 12px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-pill);
  color: var(--muted); font: inherit; font-size: 14px; text-align: left; cursor: pointer;
}
.h-cp:hover { border-color: rgba(var(--ci-teal-rgb), .55); }
.h-cp__av {
  width: 32px; height: 32px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--panel2); color: var(--ink);
  font-size: 12px; font-weight: 800;
}
.h-cp__ph { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-cp__go {
  flex: none; padding: 7px 14px; border-radius: var(--r-pill);
  background: var(--ci-teal); color: var(--on-ci-teal); font-weight: 800; font-size: 12.5px;
}

/* --- HUB-02: THE ZERO-FRIENDS WARNING, IN THE COMPOSER ONLY -------------
   It replaces the old boxed feed note, and the difference that matters is the
   button: the old one stated a fact a member could do nothing about, which is
   what turned it into furniture. (⚠️ The old class name is deliberately not
   spelled out here — `feed-friends` asserts this file no longer contains it,
   and that witness cannot tell a rule from a comment about a rule. Writing it
   out to be helpful would turn the ratchet red and teach the next seat to
   weaken it. This is the SECOND time in this cluster I have done exactly that.) Amber rather than red — nothing has gone
   wrong, the post will be stored correctly, it just has no audience yet. */
.h-nofr {
  display: flex; align-items: flex-start; flex-wrap: wrap; gap: 8px;
  margin: 8px 0 2px; padding: 10px 12px;
  border: 1px solid var(--warn); border-radius: var(--r-md);
  background: var(--panel2);
  color: var(--ink); font-size: 12.5px; line-height: 1.5;
}
.h-nofr .h-ic { flex: 0 0 auto; width: 15px; height: 15px; margin-top: 2px; color: var(--warn); }
.h-nofr__t { flex: 1 1 160px; min-width: 0; }
.h-nofr__go {
  flex: none; padding: 0; border: 0; background: none;
  color: var(--green); font: inherit; font-size: 12.5px; font-weight: 800;
  text-decoration: underline; cursor: pointer;
}

/* --- HUB-08: THE EXPANDED POST ------------------------------------------
   Covers the hub's own stage, not the whole viewport — the section strip and
   the bottom nav stay reachable, which is how every other overlay in this app
   behaves and is what `SYS-06` is about. Its BODY scrolls, not the page, so a
   long thread cannot take the page's scroll with it. */
.h-postx {
  position: absolute; inset: 0; z-index: 40;
  display: flex; flex-direction: column;
  background: var(--bg);
}
.h-postx__bar {
  flex: none; display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; border-bottom: 1px solid var(--line);
  background: var(--panel);
}
.h-postx__x {
  width: 30px; height: 30px; flex: none;
  border: 1px solid var(--line); border-radius: 50%;
  background: var(--panel2); color: var(--ink);
  font-size: 18px; line-height: 1; cursor: pointer;
}
.h-postx__t {
  font-size: 10.5px; font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted);
}
.h-postx__body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding: 12px 16px 28px;
}
/* Inside the expanded view the card is the screen, so it drops the things that
   made it a card in a list. */
.h-postx__body .h-post { margin-bottom: 0; border-radius: var(--r-lg); }

/* KARL'S SHAPE, VERBATIM: "the post at the top of it, and then the comments
   below just like facebook does." The order was already right — post, then
   reactions, then thread — but nothing SEPARATED them, so a long post ran
   straight into its first comment and the two read as one block. A real
   divider and real breathing room, which is `SYS-26`'s rule applied to the one
   screen where the run of rows is a conversation. */
.h-postx__body .h-cmts {
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--line);
}
.h-postx__body .h-cmt { margin-bottom: 10px; }
/* THE COMPOSER SITS AT THE BOTTOM OF THE THREAD, NOT FLOATING OVER IT. A member
   scrolling a long thread should arrive at the box, the way they do everywhere
   else; a pinned bar would cover the last comment on a short screen. */
.h-postx__body .h-cmt__row { margin-top: 12px; }

/* The clamp the "Read more" button belongs to. CSS decides — it is the only
   part of this that knows how wide the column is. */
.h-post__body.is-clamped {
  display: -webkit-box; -webkit-line-clamp: 8; -webkit-box-orient: vertical;
  overflow: hidden;
}
.h-post__more {
  display: block; margin-top: 4px; padding: 0;
  background: none; border: 0; color: var(--green);
  font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
}

/* --- POST CARD --------------------------------------------------------- */
.h-post {
  /* Centre Ice V11 (Karl, 2026-10-01: "the style in preview is much cleaner"):
     one quiet card, the same thin edge all round — no coloured bar on the
     left. Who it went to is said in words under the name instead. */
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-2xl); padding: 12px 12px 10px; margin-bottom: 12px;
}

/* `.h-post__head` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
/* `.h-post__av` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
.h-post__online {
  position: absolute; right: -1px; bottom: -1px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--success); border: 2px solid var(--panel);
}
.h-post__meta { flex: 1; min-width: 0; }
.h-post__name {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: 13.5px; font-weight: 700; color: var(--ink);
  background: none; border: 0; padding: 0; cursor: pointer; font-family: inherit;
}
.h-post__scope {
  font-size: 9.5px; font-weight: 800; letter-spacing: .4px; text-transform: uppercase;
  padding: 2px 7px; border-radius: var(--r-pill);
  background: var(--panel2); color: var(--muted); border: 1px solid var(--line2);
}
.h-post__scope--global { color: var(--green); border-color: rgba(var(--green-rgb), .4); }
.h-post__scope--area   { color: var(--info); }
.h-post__scope--staff  { color: var(--purple); }
/* `.h-post__when` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */

.h-post__menu { position: relative; flex: none; }
.h-post__menu-btn {
  width: 30px; height: 30px; border-radius: var(--r-sm);
  background: none; border: 0; color: var(--muted); cursor: pointer;
  display: grid; place-items: center;
}
.h-post__menu-btn:hover { background: var(--panel2); color: var(--ink); }
.h-post__menu-list {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 5;
  min-width: 170px; padding: 5px;
  background: var(--panel); border: 1px solid var(--line2);
  border-radius: var(--r-md); box-shadow: var(--sh-2);
}
.h-post__menu-list button {
  display: block; width: 100%; text-align: left;
  padding: 9px 10px; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--ink); font: inherit; font-size: 13px; cursor: pointer;
}
.h-post__menu-list button:hover { background: var(--panel2); }
.h-post__menu-list button.is-danger { color: var(--danger); }

/* `.h-post__body` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */

/* AN ATTACHED GAME OR GROUP IS ONE ROW (Stage 2D, the preview's attachment
   card). A game's code is never printed — it is a private invite; a group's
   join code is meant to be shared and is. */
.h-post__att {
  width: 100%; display: flex; align-items: center; gap: 10px; margin-top: 10px;
  padding: 10px 12px; border: 1px solid var(--line2); border-radius: var(--r-md);
  background: var(--panel2); color: var(--ink); text-align: left; cursor: pointer;
}
.h-post__att:hover { border-color: var(--green); }
.h-post__att + .h-post__att { margin-top: 6px; }
.h-post__atti {
  width: 34px; height: 34px; flex: none; display: grid; place-items: center;
  border-radius: var(--r-sm); background: color-mix(in srgb, var(--green) 12%, var(--panel)); color: var(--green);
}
.h-post__atti .h-ic { width: 17px; height: 17px; }
.h-post__attt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.h-post__attt strong { font-size: 13.5px; font-weight: 800; }
.h-post__attt small { color: var(--muted); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-post__att > b { flex: none; color: var(--green); font-size: 12.5px; font-weight: 800; }

.h-post__counts {
  display: flex; align-items: center; gap: 8px;
  margin-top: 10px; font-size: 12px; color: var(--muted);
}
.h-post__rsum { display: inline-flex; align-items: center; gap: 3px; }
.h-post__cc { margin-left: auto; background: none; border: 0; color: var(--muted); font: inherit; font-size: 12px; cursor: pointer; }
.h-post__cc:hover { color: var(--green); text-decoration: underline; }

.h-post__bar {
  display: flex; align-items: center; gap: 4px;
  margin-top: 10px; margin-left: -6px;
}
.h-bar-btn {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 8px; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--muted); font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
}
.h-bar-btn:hover { background: var(--panel2); color: var(--ink); }
.h-bar-btn.is-on { color: var(--green); }
.h-bar-btn .h-ic { width: 17px; height: 17px; }

.h-react { position: relative; flex: 1; display: flex; }
.h-react__picker {
  position: absolute; bottom: calc(100% + 6px); left: 0;
  display: flex; gap: 2px; padding: 5px; z-index: 6;
  background: var(--panel); border: 1px solid var(--line2);
  border-radius: var(--r-pill); box-shadow: var(--sh-2);
}
.h-react__opt {
  width: 38px; height: 38px; border: 0; border-radius: 50%;
  background: none; font-size: 20px; line-height: 1; cursor: pointer;
  transition: transform var(--t-fast);
}
.h-react__opt:hover { transform: scale(1.25); background: var(--panel2); }

.h-cmts { margin-top: 8px; }
.h-cmt { display: flex; gap: 9px; padding: 7px 0; }
.h-cmt__av {
  width: 28px; height: 28px; border-radius: 50%; flex: none;
  display: grid; place-items: center; background: var(--panel2);
  color: var(--ink); font-size: 11px; font-weight: 800; border: 0; cursor: pointer;
}
.h-cmt__bub { flex: 1; min-width: 0; background: var(--panel2); border-radius: var(--r-md); padding: 8px 11px; }
.h-cmt__n { font-size: 12.5px; font-weight: 700; }
.h-cmt__t { font-size: 13.5px; color: var(--ink); word-break: break-word; }
.h-cmt__more { background: none; border: 0; color: var(--muted); font: inherit; font-size: 12.5px; cursor: pointer; padding: 4px 0; }
.h-cmt__more:hover { color: var(--green); }
.h-cmt__empty { font-size: 13px; color: var(--muted); padding: 4px 0; }
button.h-cmt__empty { background: none; border: 0; font: inherit; font-size: 13px; cursor: pointer; text-align: left; }
button.h-cmt__empty:hover { color: var(--green); }
.h-cmt__row { display: flex; gap: 8px; align-items: center; margin-top: 6px; }
.h-cmt__row .h-input { flex: 1; min-width: 0; }
.h-cmt__send { flex: none; }

/* AN EMPTY STATE INSIDE A PANEL is not an empty FEED. 34px of padding is right
   when it is the whole screen and reads as a hole when it is one section of a
   tab — the group room's "Nothing upcoming." was a paragraph floating in a
   void between a label and a button. Same class, less air, where it is nested
   in a panel or a card. */
.h-feed__empty {
  text-align: center; color: var(--muted); font-size: 14px;
  padding: 34px 18px; line-height: 1.6;
}
.h-detail__body .h-feed__empty,
.h-sp__card .h-feed__empty { padding: 18px 14px; }
.h-feed__loading { text-align: center; color: var(--muted); font-size: 13.5px; padding: 26px; }
.h-feed__end { text-align: center; color: var(--muted); font-size: 12.5px; padding: 18px; }
.h-feed__more { display: block; margin: 8px auto 0; }

/* --- SCOPE CHIPS (mobile) ---------------------------------------------- */
.h-scope { display: flex; align-items: center; gap: 8px; margin: 8px 0 4px; }
/* 🏛 `S2-07` — AND THIS IS THE CONTROL KARL WAS ACTUALLY POINTING AT.
   I went looking for "filter chips", found `.h-chip`, changed it, and then had
   the Find screen refuse to produce one: `find-card-align`'s vacuity guard
   reported `chip: null` beside a perfectly good tile. **There is no `.h-chip`
   on the Find screen at all.** The filters sitting directly under those four
   buttons are these — `Everything / Skaters / Goalies / Refs`, plus the `More`
   control beside them — and all three declared `--r-pill`.
   ⚖️ SO THE ROW'S OWN WORDING SENT ME TO THE WRONG SELECTOR AND THE INSTRUMENT
   SENT ME BACK. `.h-chip` is a filter chip on other screens and Karl said
   *"throughout the entire app"*, so it stays changed; but a row that squared
   every filter in the app EXCEPT the one he was looking at would have been the
   worst possible outcome — green, shipped, and still wrong on his screen.
   🔢 THE SEGMENT NESTS, so the two radii are not the same number: the container
   holds 3px of padding around its buttons, and an outer corner reads as
   concentric with an inner one when it is inner + padding. `--r-sm` is 8 and
   `--r-md` is 11 at the default scale, which is exactly 8 + 3.
   🥇 AND THE PAIR IS NOT INVENTED — `.h-seg` IN `components.css` ALREADY USES
   IT. That control is the same shape as this one (a padded container of
   segment buttons) and it declares `--r-md` on the container and `--r-sm` on
   the buttons. **`.h-scope` was the odd one out, using pills where the app's
   other segmented control had already made this exact call.** So this row is
   not choosing a new corner for a filter, it is making the one that disagreed
   agree — which is a much smaller claim than the one I started with. */
.h-scope__seg {
  display: inline-flex; flex: 1; min-width: 0;
  background: var(--panel2); border: 1px solid var(--line2);
  border-radius: var(--r-md); padding: 3px;
}
.h-scope__s {
  flex: 1; min-width: 0; padding: 7px 8px; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--muted); font: inherit; font-size: 12.5px; font-weight: 700;
  cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.h-scope__s.is-on { background: var(--green); color: var(--on-green); }
.h-scope--role .h-scope__s.is-on { background: var(--green); color: var(--on-green); }
.h-scope--age .h-scope__s.is-on { background: var(--purple-solid); color: var(--on-purple); }
/* Centre Ice's own feed tab bar (Karl, 2026-10-01): teal, the V11 mark. */
.h-scope--ci .h-scope__s.is-on { background: var(--ci-teal); color: var(--on-ci-teal); }
/* ✨ THE APPROVED ACTIVE GLOW (Sloane's preview, `.gs-seg.is-green`): a tinted
   wash, a bright edge and a soft outer glow — never a solid fill. Find's role
   row only for now; other `.h-scope` rows keep theirs until a design pass. */
.h-scope--glow .h-scope__s { border: 1px solid transparent; }
.h-scope--glow .h-scope__s.is-on {
  background: linear-gradient(rgba(var(--green-rgb), .11), rgba(var(--green-rgb), .11)), var(--panel2); color: var(--ink);
  border-color: rgba(var(--green-rgb), .58); box-shadow: 0 0 14px rgba(var(--green-rgb), .12);
}
/* 🎛️ AGE / DAY / PRICE — one equal-width row of three dropdown tabs under the
   role row. Unset reads grey "Any …"; set wears the approved PURPLE glow
   (`.gs-seg.is-purple`). The menu is ours, not a native <select>. */
.h-ffdd { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; margin: 6px 0 10px; }
.h-ffdd--one { grid-template-columns: minmax(0, 1fr); }   /* FG-01: groups have the Age dropdown alone */
.h-ffdd__cell { position: relative; min-width: 0; }
.h-ffdd__t {
  width: 100%; min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 4px;
  padding: 8px 10px; border: 1px solid var(--line2); border-radius: var(--r-md);
  background: var(--panel2); color: var(--muted); font: inherit; font-size: 12.5px; font-weight: 700;
  cursor: pointer;
}
.h-ffdd__l { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-ffdd__c { flex: none; font-size: 11px; opacity: .8; transition: transform .15s; }
.h-ffdd__t[aria-expanded="true"] .h-ffdd__c { transform: rotate(180deg); }
.h-ffdd__t.is-set {
  color: var(--ink); background: linear-gradient(rgba(var(--purple-rgb), .14), rgba(var(--purple-rgb), .14)), var(--panel2);
  border-color: rgba(var(--purple-rgb), .72); box-shadow: 0 0 14px rgba(var(--purple-rgb), .15);
}
.h-ffdd__menu {
  position: absolute; z-index: 40; top: calc(100% + 6px); left: 0; min-width: 100%; width: max-content;
  max-width: 70vw; display: flex; flex-direction: column; gap: 2px; padding: 6px;
  border: 1px solid var(--line2); border-radius: var(--r-lg); background: var(--panel);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .45);
}
.h-ffdd__cell:last-child .h-ffdd__menu { left: auto; right: 0; }
.h-ffdd__opt {
  display: block; width: 100%; text-align: left; padding: 9px 10px; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--ink); font: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
  white-space: nowrap;
}
.h-ffdd__opt:hover, .h-ffdd__opt:focus-visible { background: rgba(var(--purple-rgb), .10); }
.h-ffdd__opt.is-on { background: rgba(var(--purple-rgb), .16); }
.h-scope__more {
  flex: none; display: inline-flex; align-items: center; gap: 4px;
  padding: 8px 12px; border: 1px solid var(--line2); border-radius: var(--r-sm);
  background: var(--panel2); color: var(--muted); font: inherit; font-size: 12.5px;
  font-weight: 700; cursor: pointer;
}
.h-scope__more.is-on { border-color: var(--green); color: var(--green); }

/* --- SPACES RAIL (mobile strip + desktop list) -------------------------- */
.h-ci__spaces:empty { display: none; }
.h-spacebar {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 9px 12px; border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--panel); color: var(--ink); font: inherit; font-size: 13px;
  font-weight: 700; cursor: pointer;
}
.h-spacebar__count {
  background: var(--panel2); border-radius: var(--r-pill);
  padding: 1px 8px; font-size: 11px; color: var(--muted);
}
.h-spacebar__find { margin-left: auto; color: var(--green); font-size: 12px; font-weight: 700; }

/* --- DESKTOP RAIL ------------------------------------------------------- */
/* `.h-rail__item` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
.h-rail__item .h-ic { width: 18px; height: 18px; flex: none; }
/* `SYS-51` — `.h-rail__item:hover` DELETED FROM HERE, 2026-09-22, Vera. It was
   the second body of a selector the comment three lines up says moved to
   components.css in 08-17z: the move took the block and left the `:hover`
   behind. Its VALUE was the correct one and is now the only one, in
   components.css, with the measurement that proves it. */
.h-rail__item.is-active {
  background: linear-gradient(rgba(var(--green-rgb), .12), rgba(var(--green-rgb), .12)), var(--panel);
  color: var(--green);
}
.h-rail__sec { margin-top: 14px; }
.h-rail__sec-h {
  display: flex; align-items: center; gap: 6px; width: 100%;
  padding: 6px 11px; border: 0; background: none; cursor: pointer;
  color: var(--muted); font: inherit;
  font-size: 10.5px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
}
/* `.h-rail__count` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
.h-rail__chev { margin-left: auto; transition: transform var(--t-fast); }
.h-rail__sec.is-collapsed .h-rail__chev { transform: rotate(-90deg); }
.h-rail__sec.is-collapsed .h-rail__sec-body { display: none; }
/* HUB-06 — the coming-soon rail section. Greyed, inert, and STILL A SECTION,
   so a member can see the shape of a feature that is real and not ready.
   `cursor: default` and no hover: nothing here answers a tap, and a heading
   that lights up under the finger promises otherwise. */
.h-rail__sec--soon { opacity: .55; }
.h-rail__sec-h--soon { cursor: default; }
.h-rail__soon {
  margin-left: auto; flex: none;
  padding: 1px 7px; border-radius: var(--r-pill);
  background: var(--panel2); color: var(--muted);
  font-size: 9.5px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
}
.h-rail__empty--soon { font-style: italic; }

.h-rail__empty { padding: 6px 11px; font-size: 12.5px; color: var(--muted); }
.h-rail__empty-btn { display: block; margin-top: 4px; background: none; border: 0; padding: 0; color: var(--green); font: inherit; font-size: 12.5px; font-weight: 700; cursor: pointer; }

/* --- COMPOSER ----------------------------------------------------------- */
.h-compose__head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.h-compose__title { flex: 1; text-align: center; font-weight: 800; font-size: var(--fs-lg); font-family: var(--font-head); }
.h-compose__scope { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; font-size: 13px; color: var(--muted); }
.h-compose__scope-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border: 1px solid var(--line2); border-radius: var(--r-pill);
  background: var(--panel2); color: var(--ink); font: inherit; font-size: 13px;
  font-weight: 700; cursor: pointer;
}
/* GM-01 (Karl): Posting to is a small styled drop list that floats off the
   chip — it never pushes the post box down. */
.h-compose__scopewrap { position: relative; display: inline-block; }
.h-compose__scope-list {
  position: absolute; left: 0; top: calc(100% + 6px); z-index: 5; min-width: 220px; max-width: min(300px, 80vw);
  padding: 5px; border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel2);
  box-shadow: 0 12px 32px var(--scrim, transparent);
}
.h-compose__opt {
  display: flex; align-items: baseline; gap: 8px; width: 100%;
  padding: 9px 10px; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--ink); font: inherit; font-size: 13.5px;
  text-align: left; cursor: pointer;
}
.h-compose__opt:hover { background: var(--panel); }
.h-compose__hint { color: var(--muted); font-size: 11.5px; }
.h-compose__body { width: 100%; min-height: 116px; resize: vertical; }
.h-compose__count { text-align: right; font-size: 11.5px; color: var(--muted); margin-top: 4px; }
.h-compose__count.is-over { color: var(--danger); font-weight: 700; }

/* `.h-attach` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
.h-attach__row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.h-attach__lead { font-size: 12.5px; color: var(--muted); }
/* GM-01: an attached game or group is one full-width line — its kind, its
   name (truncated, never squashed) and a remove button. */
.h-attach__chip {
  display: flex; align-items: center; gap: 8px; width: 100%; min-width: 0;
  padding: 7px 6px 7px 10px; margin-bottom: 8px; border-radius: var(--r-md);
  background: var(--green-dim); border: 1px solid var(--green);
  font-size: 13px; font-weight: 700;
}
.h-attach__chipk { flex: none; font-size: 10px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--green); }
.h-attach__chipn { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-attach__side { display: flex; flex-direction: column; gap: 12px; }
.h-attach__side .h-attach__opts { max-height: none; }
.h-attach__x { width: 22px; height: 22px; border: 0; border-radius: 50%; background: var(--panel); color: var(--muted); cursor: pointer; }
.h-attach__warn { margin-top: 8px; font-size: 12.5px; color: var(--warn); }

/* --- HUB-03: THE CODE PICKER, IN THE SHEET ------------------------------
   It replaces `.h-attach__row` inside `[data-role="attach-slot"]` rather than
   being inserted after it, so the Cancel/Post footer under it does not move.
   `max-height` + its own scroll: a member in eleven groups gets a scrollable
   list, not a sheet that grows past the viewport and pushes Post off-screen —
   which is the same complaint as the one this is fixing.
   NOT a native <select>. iOS draws that as a popover near the top of the
   window, which is Karl's "unstylish drop down that sits far off from the rest
   of what your editing". This sits under the button that opened it. */
.h-attach__pick { display: flex; flex-direction: column; gap: 8px; }
.h-attach__pickhd {
  font-size: 10.5px; font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted);
}
.h-attach__opts {
  display: flex; flex-direction: column; gap: 4px;
  max-height: 168px; overflow-y: auto;
  border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 4px; background: var(--panel);
}
.h-attach__opt {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  padding: 8px 10px; border: 1px solid transparent; border-radius: var(--r-sm);
  background: none; color: var(--ink); font: inherit; font-size: 13px; cursor: pointer;
}
.h-attach__opt:hover { background: var(--panel2); }
.h-attach__opt.is-on { border-color: var(--green); background: var(--green-dim); }
.h-attach__tag {
  flex: none; padding: 1px 6px; border-radius: var(--r-pill);
  background: var(--panel2); color: var(--muted);
  font-size: 9.5px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
}
.h-attach__optn { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-attach__you { flex: none; color: var(--muted); font-size: 11px; }
.h-attach__none { font-size: 12.5px; color: var(--muted); padding: 2px 0; }
.h-attach__free { display: flex; flex-direction: column; gap: 4px; }
.h-attach__freel { font-size: 11.5px; color: var(--muted); }
.h-attach__pickact { display: flex; justify-content: flex-end; gap: 8px; }

/* --- MOTION ------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .h-hub__nav, .h-ci__post, .h-react__opt, .h-rail__chev { transition: none; }
}
html[data-motion="off"] .h-hub__nav,
html[data-motion="off"] .h-ci__post,
html[data-motion="off"] .h-react__opt,
html[data-motion="off"] .h-rail__chev { transition: none; }

/* ---------------------------------------------------------------------------
   LOCKER ROOM
   The member's own space. Needs your attention, the family checklist, the
   Me/Family switch, and the profile editor.
   ------------------------------------------------------------------------ */
.h-lr { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.h-lr__body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 14px 16px 30px; }
/* ---- STAGE 2F: THE LOCKER ROOM (approved preview, 2026-09-26) ------------ */
.h-lr__head { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 16px 4px; }
.h-lr__head small, .h-lr__pk small {
  display: block; color: var(--green); font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
}
.h-lr__head h2 {
  margin: 3px 0 0; font-family: var(--font-display); font-weight: 400; font-size: 28px;
  text-transform: uppercase; letter-spacing: .025em; line-height: 1;
}
.h-lr__headmark { color: var(--green); display: grid; place-items: center; }
.h-lr__headmark .h-ic { width: 30px; height: 30px; }
.h-lr__pk { display: flex; flex-direction: column; }
.h-lr__profile .h-lr__card-h { align-items: flex-end; justify-content: space-between; margin-bottom: 10px; }
.h-lr__profile .h-lr__card-t {
  font-family: var(--font-display); font-weight: 400; font-size: 19px; text-transform: uppercase; letter-spacing: .025em;
}
.h-lr__prow {
  width: 100%; display: flex; align-items: center; gap: 12px; padding: 12px 2px;
  border: 0; border-top: 1px solid var(--line); background: transparent; color: var(--ink);
  text-align: left; cursor: pointer;
}
.h-lr__prow:hover { background: var(--panel2); }
.h-lr__prowi {
  width: 34px; height: 34px; flex: none; display: grid; place-items: center; border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--green) 10%, var(--panel2)); color: var(--green);
}
.h-lr__prowi .h-ic { width: 17px; height: 17px; }
.h-lr__prowt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.h-lr__prowt strong { font-size: 14px; font-weight: 800; }
.h-lr__prowt small { color: var(--muted); font-size: 12px; }
.h-lr__prow > em {
  flex: 0 1 auto; max-width: 42%; font-style: normal; color: var(--muted); font-size: 12.5px; text-align: right;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.h-lr__prowc { flex: none; width: 16px; height: 16px; color: var(--muted); }
/* The autosave sheet's status line: quiet until something happens. */
.h-lr__autostatus { margin: 0 0 10px; color: var(--muted); font-size: 12.5px; font-weight: 600; }
/* Help's Email us form: the one line that says what to fix (Stage 2H). */
.h-helpwin__form .h-helpwin__err { margin: 0; color: var(--danger); font-size: 13px; font-weight: 600; }
/* The two profile entries that stay BLOCKS (How you appear — the studio; Who
   has used this account — a history list) sit in the row list, so they take
   the rows' rhythm: same divider, same padding, same type. */
.h-lr__profile .h-lr__block { border-top: 1px solid var(--line); }
.h-lr__profile .h-lr__block-h { padding: 14px 2px; }
.h-lr__profile .h-lr__block-t { font-size: 14px; font-weight: 800; }
.h-lr__autostatus.is-bad { color: var(--danger); }
@media (max-width: 380px) { .h-lr__prow > em { display: none; } }

.h-lr__tabs {
  flex: 0 0 auto; display: flex; gap: 3px; margin: 12px 16px 0; padding: 3px;
  background: var(--panel2); border: 1px solid var(--line2); border-radius: var(--r-pill);
}
.h-lr__tab {
  flex: 1; padding: 8px; border: 0; border-radius: var(--r-pill);
  background: none; color: var(--muted); font: inherit; font-size: 13px;
  font-weight: 700; cursor: pointer;
}
.h-lr__tab.is-on { background: var(--green); color: var(--on-green); }

/* --- Needs your attention ---------------------------------------------- */
.h-lr__na { padding: 0; overflow: hidden; }
/* `.h-na__head` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
.h-na__bang {
  width: 20px; height: 20px; flex: none; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--warn-solid); color: var(--on-warn);
  font-size: 13px; font-weight: 900;
}
.h-na__caret { margin-left: 4px; color: var(--muted); transition: transform var(--t-fast); }
.h-lr__na:not(.is-collapsed) .h-na__caret { transform: rotate(90deg); }
.h-lr__na.is-collapsed .h-na__inner { display: none; }
.h-na__inner { padding: 0 14px 12px; }

.h-lr__group {
  font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); font-weight: 800; margin: 12px 0 2px;
}
.h-na__dot--high   { background: var(--danger); }
.h-na__dot--medium { background: var(--warn); }
.h-na__dot--low    { background: var(--muted); }
.h-na__text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.h-na__label { font-size: 13.5px; color: var(--ink); }
.h-na__sub   { font-size: 11.5px; color: var(--muted); }
.h-na__x {
  flex: none; width: 26px; height: 26px; margin-left: 4px;
  border: 0; border-radius: var(--r-sm); background: none;
  color: var(--muted); font-size: 16px; line-height: 1; cursor: pointer;
}
.h-na__x:hover { background: var(--panel2); color: var(--ink); }

.h-lr__dismissed-toggle {
  margin-top: 10px; padding: 6px 0; border: 0; background: none;
  color: var(--muted); font: inherit; font-size: 12.5px; font-weight: 700; cursor: pointer;
}
.h-lr__dismissed-toggle:hover { color: var(--green); }
.h-lr__drow {
  display: flex; align-items: center; gap: 10px; padding: 8px 0;
  border-top: 1px solid var(--line); font-size: 13px; color: var(--muted);
}
.h-lr__restore {
  margin-left: auto; border: 0; background: none;
  color: var(--green); font: inherit; font-size: 12px; font-weight: 800; cursor: pointer;
}

/* --- Cards + blocks ----------------------------------------------------- */
.h-lr__card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 14px; margin-top: 14px;
}
.h-lr__card-h { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 6px; }
.h-lr__card-t { font-family: var(--font-head); font-weight: 800; font-size: 15px; }
.h-lr__card-s { font-size: 11.5px; color: var(--muted); margin-left: auto; }

.h-lr__step { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-top: 1px solid var(--line); }
.h-lr__check {
  width: 22px; height: 22px; flex: none; border-radius: 50%;
  border: 1.5px solid var(--line2); display: grid; place-items: center;
  font-size: 12px; font-weight: 900; color: var(--green);
}
.h-lr__step.is-done .h-lr__check { border-color: var(--green); background: rgba(var(--green-rgb), .12); }

.h-lr__block { border-top: 1px solid var(--line); }
.h-lr__block-h {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 12px 0; border: 0; background: none; cursor: pointer;
  color: var(--ink); font: inherit; text-align: left;
}
.h-lr__block-t { font-size: 13.5px; font-weight: 700; flex: none; }
.h-lr__block-s { flex: 1; min-width: 0; font-size: 12.5px; color: var(--muted); text-align: right; }
.h-lr__block-c { color: var(--muted); transition: transform var(--t-fast); flex: none; }
.h-lr__block.is-open .h-lr__block-c { transform: rotate(90deg); }
.h-lr__block-b { padding: 2px 0 14px; }

/* A PROFILE THAT IS NOT OURS TO CHANGE.
   The live app's rule: a profile with its own login is edited only by that
   person. Drawn as a plain row rather than a disabled button — a control that
   still takes focus and still carries aria-expanded but does nothing reads as
   a broken app rather than as a rule about somebody's teenager. */
.h-lr__block-h--ro {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 12px 0; color: var(--muted);
}
.h-lr__block-h--ro .h-lr__block-t { color: var(--muted); }
.h-lr__ro {
  margin: 10px 0 2px; padding: 9px 11px; border-radius: var(--r-md);
  background: var(--panel2); border: 1px solid var(--line);
  color: var(--muted); font-size: 12px; line-height: 1.5;
}

.h-lr__gap  { color: var(--warn); font-weight: 700; }
.h-lr__also { color: var(--muted); }
.h-lr__hint { font-size: 12.5px; color: var(--muted); line-height: 1.5; margin: 0 0 10px; }
.h-lr__count { text-align: right; font-size: 11.5px; color: var(--muted); }

.h-lr__f { display: block; margin-bottom: 10px; }
.h-lr__fl { display: block; font-size: 12px; color: var(--muted); font-weight: 700; margin-bottom: 4px; }
.h-lr__f .h-input, .h-lr__f select, .h-lr__f textarea { width: 100%; }
.h-lr__toggle { display: flex; align-items: center; gap: 9px; font-size: 13.5px; margin-bottom: 12px; cursor: pointer; }
.h-lr__save { display: flex; gap: 8px; justify-content: flex-end; margin-top: 12px; }

/* --- Skill sliders ------------------------------------------------------ */
.h-lr__slider { margin-bottom: 14px; }
.h-lr__slider-h { display: flex; align-items: baseline; gap: 8px; }
.h-lr__slider-l { flex: 1; min-width: 0; font-size: 13.5px; font-weight: 600; }
/* The number box is the shared `.h-skill__v` (components.css, walk v38 LR-03). */
/* The 1-10 scale in words, under the skill sheet's intro. */
.h-lr__scale { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 0 0 10px; font-size: 12px; color: var(--muted); }
.h-lr__scale b { color: var(--ink); font-weight: 800; margin-right: 3px; }
/* The "Needs you" pill rides under the row's text (chip squish, 2026-09-29). */
.h-na__text > .h-na__urgent { display: inline-block; align-self: flex-start; width: max-content; margin-top: 5px; }
/* Karl (walk v45): Priority sits UNDER the action button — a small alert icon
   and the word, no pill — so it never pushes the row onto two lines. */
.h-na__actcol { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 3px; }
.h-na__pri { display: inline-flex; align-items: center; gap: 3px; font-size: 10.5px; font-weight: 800; color: var(--warn); white-space: nowrap; }
.h-na__pri .h-ic { width: 12px; height: 12px; }
.h-lr__useme-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 8px; }
.h-lr__useme-row .h-lr__useme { margin: 0; }
.h-lr__useme { margin: 0 0 8px; }

/* 0629: a position's level chips (our own row; never the native picker). */
.h-lr__lvl { display: flex; flex-direction: column; gap: 4px; margin-bottom: 6px; }
.h-lr__tiers { display: flex; flex-wrap: wrap; gap: 6px; }
.h-lr__tier {
  min-height: 34px; padding: 5px 12px; border-radius: var(--r-pill); cursor: pointer;
  border: 1px solid var(--line2); background: var(--panel2); color: var(--muted);
  font: inherit; font-size: 13px; font-weight: 800;
}
.h-lr__tier.is-on { border-color: var(--green); background: linear-gradient(var(--green-dim), var(--green-dim)), var(--panel2); color: var(--ink); }
.h-lr__slider.is-unset .h-lr__range { opacity: 1; }   /* the unset look lives in `.h-range` (walk v37) */
.h-lr__slider-hint { font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.h-lr__range { width: 100%; margin: 4px 0 0; accent-color: var(--green); }
/* A 44px-tall touch target on a control people will drag on a phone in a
   dressing room. The default range thumb is about 16px. */
.h-lr__range { height: 28px; }

/* --- Family ------------------------------------------------------------- */
.h-lr__member { display: flex; align-items: center; gap: 10px; padding: 10px 0; border-top: 1px solid var(--line); }
.h-lr__member-av {
  width: 34px; height: 34px; flex: none; border-radius: 50%;
  display: grid; place-items: center; background: var(--panel2);
  color: var(--ink); font-size: 13px; font-weight: 800;
}

@media (prefers-reduced-motion: reduce) { .h-na__caret, .h-lr__block-c { transition: none; } }
html[data-motion="off"] .h-na__caret, html[data-motion="off"] .h-lr__block-c { transition: none; }

/* ---------------------------------------------------------------------------
   DISCOVER
   The ask box is the crown jewel per the prototype, so it gets the accent and
   the top of the surface. Rinks below it are the part that works today.
   ------------------------------------------------------------------------ */
.h-dc { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.h-dc__body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 16px 16px 30px; }

.h-ask { display: block; margin: 14px 0 4px; }
.h-ask__bar {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 10px 10px 14px;
  background: var(--panel); border: 1px solid var(--green);
  border-radius: var(--r-pill);
  box-shadow: 0 0 0 3px rgba(var(--green-rgb), .10);
}
.h-ask__ic { width: 22px; height: 22px; flex: none; color: var(--green); }
/* 🔁 Walk B33 (Karl): the Loop is a button, an easter egg. A tap runs a
   shimmer once round it (a conic sweep masked to a ring). */
.h-ask__loop {
  position: relative; flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; margin: -4px -4px -4px -6px; padding: 0;
  border: 0; border-radius: 50%; background: none; color: var(--green); cursor: pointer;
}
.h-ask__loop:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }
.h-ask__loop::before {
  content: ''; position: absolute; inset: 0; border-radius: 50%; opacity: 0; pointer-events: none;
  background: conic-gradient(from 0deg, transparent 0 62%, rgba(var(--green-rgb), .25) 72%, rgba(var(--green-rgb), .95) 86%, transparent 100%);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2.5px));
          mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2.5px));
}
.h-ask__loop.is-spin::before { animation: h-loop-shimmer .85s cubic-bezier(.4, 0, .2, 1) 1; }
.h-ask__loop.is-spin .h-ask__ic { animation: h-loop-glow .85s ease-out 1; }
@keyframes h-loop-shimmer {
  0% { opacity: 0; transform: rotate(0deg); }
  12% { opacity: 1; }
  85% { opacity: 1; }
  100% { opacity: 0; transform: rotate(360deg); }
}
@keyframes h-loop-glow {
  40% { filter: drop-shadow(0 0 5px rgba(var(--green-rgb), .8)); }
}
@media (prefers-reduced-motion: reduce) {
  .h-ask__loop.is-spin::before, .h-ask__loop.is-spin .h-ask__ic { animation: none; }
}
.h-ask__suggests {
  display: flex; align-items: center; gap: 6px; margin: -2px 0 10px;
  font-size: 12px; color: var(--muted);
}
.h-ask__suggests b { color: var(--green); font-weight: 800; }
.h-ask__suggests .h-ic { width: 14px; height: 14px; color: var(--green); flex: none; }
.h-ask__more { margin-top: 10px; }
.h-ask__in {
  flex: 1; min-width: 0; border: 0; background: none;
  color: var(--ink); font: inherit;
  /* SYS-07: was 15px. `font: inherit` resets the size, so this rule had to
     re-state it and re-stated it one pixel under the iOS floor — the Discover
     ask field zoomed the viewport on every tap. */
  font-size: 16px; padding: 4px 0;
}
/* `S2-109` — THE FIELD DRAWS NOTHING; THE PILL AROUND IT GLOWS. The pill
   already wears a faint .10 glow at rest, so focus brightens that same ring
   rather than adding a second shape. */
.h-ask__in:focus { outline: none; box-shadow: none; }
.h-ask__bar:focus-within { box-shadow: 0 0 0 3px rgba(var(--green-rgb), .30); }
.h-ask__in::placeholder { color: var(--muted); }
.h-ask__go { flex: none; }
/* DSC-06. Box-shadow rather than border so the button does not change SIZE when
   the state turns on — a control that resizes as you type is worse than one
   that says nothing. */
.h-ask__go.is-dirty { box-shadow: 0 0 0 3px rgba(var(--green-rgb), .45); }
@media (prefers-reduced-motion: reduce) { .h-ask__go.is-dirty { box-shadow: 0 0 0 3px rgba(var(--green-rgb), .45); } }
.h-ask__hint { font-size: 12px; color: var(--muted); margin: 8px 2px 10px; }

/* WRAP. Never a horizontal scroller — these ran 870px wide and side-scrolled
   at every width below 1280. A member should never have to swipe sideways to
   discover that an option exists. */
.h-ask__chips { display: flex; flex-wrap: wrap; gap: 7px; padding-bottom: 2px; }
.h-ask__chips .h-pill {
  flex: 0 1 auto; min-width: 0; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  text-align: left;
}

/* DSC-02 — THE STALE-RESULTS NOTICE. Sits between the chips and the answer,
   so it is read before the list it is a warning about rather than after it.

   NO OPACITY AND NO COLOUR CHANGE ON THE TEXT, AND THE MEASUREMENT CHANGED MY
   REASON. The obvious treatment for "these results are old" is to fade them. I
   first wrote that fading "can fail the contrast gate", then mutated this rule
   to `opacity: .35` and the whole contrast sweep stayed GREEN — because
   `_contrast-dom.mjs` reads `getComputedStyle(el).color`, which folds in a
   colour's own ALPHA but not the element's `opacity` property. So fading is
   worse than I claimed: not a risk the gate would catch, a risk it cannot see.
   The signal is carried by a `--warn` border on the notice and on the block;
   every character stays `--ink` at full strength.

   The block below stays fully readable and fully pressable on purpose. A stale
   answer is still a true answer about real rows, and the member may well still
   want the row they can already see. */
.h-ask__stale {
  margin-top: 14px;
  padding: 9px 11px;
  font-size: 12.5px; line-height: 1.45; color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--warn); border-left-width: 3px;
  border-radius: var(--r-md);
}
/* KEYED OFF THE STATE CLASS, NOT OFF `.h-ask__out`, AND THAT IS NOT A STYLE
   PREFERENCE. My first version read `.h-ask__stale:not([hidden]) + .h-ask__out
   .h-ask__answer`, which sets no property on `.h-ask__out` at all — it names it
   as an ancestor. `client-contracts` scans for the class NAME and went red
   demanding `h-ask__out` come off its UNSTYLED_ALREADY allowlist: a mention
   read as a use. The guard is right to be strict, so the selector moved instead
   of the allowlist. The notice already carries the top margin, so the block
   must not add a second one and open a gap between a warning and the thing it
   is warning about. */
/* THE ORCHESTRATOR RULED "DIM THE RESULT BLOCK" AND THIS IS THAT, BUILT OUT OF
   TOKENS THE CONTRAST GATE CAN ACTUALLY SEE. The literal reading is
   `opacity`, and I measured that the sweep is blind to it (see the note above),
   so a faded block would be unguarded rather than merely risky.

   Instead the block stops looking RAISED: `--bg` is the page ground, so the
   card flattens into the page and reads as subordinate to the live notice above
   it, while every character stays `--ink` at full strength on a pair this app
   validates everywhere else. Dim in effect, measurable in fact. */
.is-stale .h-ask__answer {
  margin-top: 8px;
  background: var(--bg);
  border-color: var(--warn);
}

.h-ask__answer {
  margin-top: 14px; padding: 14px;
  background: var(--panel); border: 1px solid var(--line2); border-radius: var(--r-lg);
}
.h-ask__answer-q {
  font-family: var(--font-head); font-weight: 800; font-size: 15px;
  color: var(--green); margin-bottom: 8px;
}
.h-ask__answer-b { font-size: 13.5px; color: var(--ink); line-height: 1.55; margin: 0 0 10px; }

/* `.h-dc__tiles` is defined once, in the Stage 2E Discover block (three across). */

.h-dc__rinks { display: flex; flex-direction: column; gap: 9px; }
/* A long rink description must wrap, not widen the card. */
.h-rink__d, .h-rink__n, .h-rink__s { overflow-wrap: anywhere; }
.h-rink {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 12px; background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--r-lg);
}
.h-rink.is-joined { border-color: var(--green); }
.h-rink__pin { width: 20px; height: 20px; flex: none; color: var(--green); margin-top: 1px; }
.h-rink__main { flex: 1; min-width: 0; }
.h-rink__n { font-size: 14px; font-weight: 700; }
.h-rink__s { font-size: 11.5px; color: var(--muted); margin-top: 1px; }
.h-rink__d { font-size: 12.5px; color: var(--muted); margin-top: 5px; line-height: 1.45; }
.h-rink .h-btn { flex: none; align-self: center; }

/* The brand H is a 2:1 mark, not a square glyph — in a 20x20 icon slot it would
   render at half height. Give it the room its aspect ratio needs. */
.h-hub__nav[data-icon-wide] .h-ic,
.h-hub__nav .h-ic[data-icon="markH"] { width: 28px; height: 20px; }
.h-hub__nav .h-ic[data-icon="markH"] svg { width: 100%; height: 100%; }

/* ---------------------------------------------------------------------------
   DETAIL PANEL — spaces, events, joining.
   Slides over the Hub, same shape as the live app's `.detail` and the
   prototype's. Full height so its own body scrolls, never the page.
   ------------------------------------------------------------------------ */
/* `.h-detail` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
.h-detail.is-open { transform: translateX(0); visibility: visible; }
@media (prefers-reduced-motion: reduce) { .h-detail { transition: none; } }
html[data-motion="off"] .h-detail { transition: none; }

/* `.h-detail__head` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
/* `.h-detail__back` MOVED TO components.css ON 2026-09-16, Meryl, and it is the
   SAME MOVE AS ITS THREE SIBLINGS ABOVE AND BELOW -- head, title and body all
   went in 08-17z and this block was the one the sweep walked past. The comment
   directly above this line described `.h-detail__head` and sat over a copy of
   `.h-detail__back`, which is how it stayed invisible for a month.
   The rotation on the chevron went with it: it lived ONLY here, so a Back
   button on any page that does not load hub.css pointed the wrong way. */
/* `.h-detail__title` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
/* `.h-detail__act` MOVED TO components.css ON 2026-09-17, Meryl. THIS body is
   the one that survived -- merged on the rendered reading, because a `<div>`
   that `spaces.js` fills with markup is a container and not a button. The copy
   in components.css styled it as a green text link, from when it WAS a button;
   those six declarations were dropped and the header there lists them. */
/* `.h-detail__body` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
/* THE ACTION ROW. Karl: "the buttons look awkward where they are... i want the
   app to be coherent and premium."

   THEY WERE RAGGED, and that is what he was seeing: natural widths meant
   "+ Create game" and "+ Create schedule" were two different sizes sitting
   left with dead space after them, and a four-button row wrapped into a
   lopsided 3 + 1. `flex: 1 1 auto` with a floor turns both cases into a grid —
   two buttons split the row, four make two even pairs, and every screen in the
   app gets the same shape without a single call site changing.

   `min-width` rather than a fixed basis so a long label still fits; the floor
   is what stops three buttons squeezing into a row of stubs. */
.h-detail__cta { display: flex; gap: 10px; flex-wrap: wrap; margin: 16px 0 6px; }
/* MN-03: My Groups leads with its two actions. */
.h-mygroups__acts { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 8px; margin: 4px 0 14px; }
.h-mygroups__acts .h-btn { min-width: 0; white-space: normal; }
.h-detail__cta .h-btn { flex: 1 1 auto; min-width: 148px; }
.h-detail__cta .h-btn--block { flex: 1 1 100%; }

/* --- space rows + heroes ------------------------------------------------ */
.h-srow {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 11px 0; border: 0; border-bottom: 1px solid var(--line);
  background: none; color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.h-srow:hover .h-srow__n { color: var(--green); }
.h-srow__disc {
  width: 42px; height: 42px; flex: none; border-radius: var(--r-md);
  display: grid; place-items: center; font-weight: 800; font-size: 13px;
}
.h-srow__main { flex: 1; min-width: 0; }
.h-srow__n { display: block; font-size: 14.5px; font-weight: 700; }
.h-srow__s { display: block; font-size: 12px; color: var(--muted); margin-top: 1px; }
.h-srow__go { flex: none; color: var(--muted); font-size: 18px; }

/* `.h-shero` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
.h-shero__disc {
  width: 54px; height: 54px; flex: none; border-radius: 15px;
  display: grid; place-items: center; font-weight: 800; font-size: 16px;
}
.h-shero__n { font-family: var(--font-head); font-weight: 800; font-size: 18px; }
.h-shero__s { font-size: 12.5px; color: var(--muted); margin-top: 2px; }

.h-ehero { margin-bottom: 12px; }
.h-ehero__n { font-family: var(--font-head); font-weight: 800; font-size: 19px; }
.h-ehero__when { font-size: 14px; color: var(--green); font-weight: 700; margin-top: 3px; }
.h-ehero__where { font-size: 13px; color: var(--muted); margin-top: 2px; }

.h-tag {
  display: inline-flex; align-items: center; gap: 5px; margin-top: 8px;
  padding: 4px 10px; border-radius: var(--r-pill);
  background: var(--panel2); border: 1px solid var(--line2);
  color: var(--muted); font: inherit; font-size: 11.5px; font-weight: 700; cursor: pointer;
}
.h-tag--warn { background: transparent; border-color: var(--warn); color: var(--warn); cursor: default; }

/* --- what a game needs -------------------------------------------------- */
.h-needs {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding: 11px 13px; border-radius: var(--r-md);
  background: var(--panel2); border: 1px solid var(--line2);
  font-size: 13.5px; font-weight: 700;
}
.h-needs.is-short { border-color: var(--warn); color: var(--warn); }
.h-needs__c { margin-left: auto; font-size: 12px; font-weight: 500; color: var(--muted); }

/* --- RSVP --------------------------------------------------------------- */
/* `.h-rsvp` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
.h-rsvp__q { flex: 1 1 100%; font-size: 13px; color: var(--muted); font-weight: 700; }
.h-rsvp__in { flex: 1 1 100%; font-size: 14px; font-weight: 700; color: var(--green); }
.h-rsvp__fam { flex: 1 1 100%; display: flex; gap: 8px; flex-wrap: wrap;
               margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }

/* --- roster rows -------------------------------------------------------- */
.h-mrow { display: flex; align-items: center; gap: 11px; padding: 9px 0; border-bottom: 1px solid var(--line); }
.h-mrow:last-child { border-bottom: 0; }
.h-mrow__av {
  width: 32px; height: 32px; flex: none; border-radius: 50%;
  display: grid; place-items: center; background: var(--panel2);
  color: var(--ink); font-size: 12px; font-weight: 800;
}
/* A typed-in name with no account is drawn differently on purpose — an
   organiser must be able to see at a glance who is actually reachable. */
.h-mrow__av.is-ghost {
  background: transparent; border: 1px dashed var(--line2); color: var(--muted);
}

/* --- join --------------------------------------------------------------- */
.h-join { display: flex; gap: 8px; margin-bottom: 12px; }
/* `HUB-09` — the way out for somebody who has no code. Separated by a real
   divider rather than a gap, because "No code?" is a different question from
   the one above it and `SYS-26` is the standing complaint about runs of
   controls with nothing between them. */
.h-join__alt { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line); }
.h-join__altl {
  margin-bottom: 8px;
  font-size: 10.5px; font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted);
}
.h-join__in {
  flex: 1; min-width: 0; text-transform: uppercase;
  letter-spacing: .18em; font-weight: 800; font-size: 17px; text-align: center;
}
.h-join__yes {
  padding: 16px; border-radius: var(--r-lg);
  background: var(--panel); border: 1px solid var(--green);
}
.h-join__no {
  padding: 13px; border-radius: var(--r-md);
  background: var(--panel); border: 1px solid var(--danger); color: var(--danger); font-size: 13.5px;
}
.h-join__lead { font-size: 11.5px; letter-spacing: .07em; text-transform: uppercase;
                color: var(--muted); font-weight: 700; }
.h-join__n { font-family: var(--font-head); font-weight: 800; font-size: 18px; margin-top: 3px; }
.h-join__s { font-size: 13px; color: var(--muted); margin-top: 3px; }
.h-join__yes .h-btn { margin-top: 14px; }

/* --- share -------------------------------------------------------------- */
.h-share__label { font-size: 11px; letter-spacing: .07em; text-transform: uppercase;
                  color: var(--muted); font-weight: 700; margin-bottom: 4px; }
.h-share__code {
  font-family: var(--font-head); font-weight: 800; font-size: 26px;
  letter-spacing: .22em; color: var(--green); margin-bottom: 8px;
}
.h-share__link { font-size: 12.5px; color: var(--ink); overflow-wrap: anywhere; margin-bottom: 8px; }

/* WHO CAME IN THROUGH THE CODE, and what was turned away. `join_code_use` has
   been written faithfully since 0007 and read by nothing until 2026-08-17. */
.h-share__who, .h-share__away { list-style: none; margin: 0; padding: 0; }
.h-share__who li {
  display: flex; justify-content: space-between; gap: 10px; align-items: baseline;
  padding: 7px 0; border-bottom: 1px solid var(--line);
}
.h-share__who li:last-child { border-bottom: 0; }
.h-share__whon { font-weight: 600; font-size: 13.5px; min-width: 0; overflow-wrap: anywhere; }
.h-share__whos { font-size: 11.5px; color: var(--muted); flex: none; }
/* COUNTS, NOT NAMES — and deliberately a quieter block than the list above it.
   Most refusals are somebody mistyping a code meant for a different group. This
   is the SHAPE of what happened, not a list of people to look at. */
.h-share__away li { font-size: 12.5px; color: var(--muted); padding: 3px 0; }

/* ---------------------------------------------------------------------------
   SCHEDULE + FIND — the two bottom-nav tabs.
   ------------------------------------------------------------------------ */
.h-sch { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; max-width: 100%; }
.h-sch * { min-width: 0; }
.h-sch__top { flex: 0 0 auto; padding: 14px 16px 4px; }
.h-sch__body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 8px 16px 30px; }

.h-sch__kicker {
  display: block; color: var(--green); font-size: 10px; font-weight: 900;
  letter-spacing: .12em; text-transform: uppercase;
}
.h-sch__title {
  margin: 3px 0 12px; font-family: var(--font-display); font-size: 28px;
  line-height: 1; letter-spacing: .02em; text-transform: uppercase;
}
.h-sch__source { margin-bottom: 10px; }
.h-sch__source-h365 { flex: 1 1 0; min-width: 0; }
.h-sch__source button.is-on {
  background: var(--active-green-bg); color: var(--active-green-ink);
  box-shadow: inset 0 0 0 1px var(--green), 0 0 20px rgba(var(--green-rgb), .26);
}
.h-sch__tools { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; }
.h-sch__tools > .h-seg, .h-sch__tools > .h-filterbar { margin-bottom: 0; }
.h-sch__tools .h-filterbar { min-width: 0; }
.h-sch__view button.is-on {
  background: var(--active-purple-bg); color: var(--active-purple-ink);
  box-shadow: inset 0 0 0 1px var(--purple), 0 0 20px rgba(var(--purple-rgb), .24);
}
.h-sch__week { margin: 4px 0 7px; }
.h-sch__week-context {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 0 2px 10px; color: var(--muted); font-size: 11px;
}
.h-sch__week-context button {
  padding: 5px 8px; border: 1px solid var(--purple);
  border-radius: var(--r-pill); background: var(--active-purple-bg);
  color: var(--active-purple-ink); font: 800 10px var(--font-body); cursor: pointer;
}
/* GB-01: the Up next card wears the Game Space hero (`.gs-hero`, components.css);
   these lines only let that hero be one button, with its spans laid out as the
   hero's blocks. */
.h-sch__hero {
  width: 100%; margin: 4px 0 16px; border: 1px solid var(--line2); color: var(--ink);
  font: inherit; text-align: left; cursor: pointer; box-shadow: var(--sh-2);
}
.h-sch__hero .gs-hero__title { display: block; }
.h-sch__hero .gs-parent { cursor: inherit; }
.h-sch__hero .h-ic svg { width: 100%; height: 100%; }

@media (max-width: 430px) {
  .h-sch__view-label {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
  }
  .h-sch__view button { min-height: 42px; }
  .h-sch__view .h-ic { width: 18px; height: 18px; }
}



.h-sch__day {
  font-size: 11px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); font-weight: 700; margin: 16px 0 6px;
}
.h-sch__day:first-child { margin-top: 4px; }
/* A game already played is still worth seeing, just not competing for
   attention with the one on Friday. */
.h-scard.is-past { opacity: .55; }
/* GB-08: Upcoming | History over a group's games, on the tab and in the panel. */
.h-room__when { margin: 0 0 10px; }
.h-room__fs { display: flex; flex-direction: column; gap: 8px; }
.h-room__fs .h-room__when { margin-bottom: 4px; }

/* The calendar, the week strip, the agenda, the segmented control, the source
   tag and the menu tiles are ALREADY in components.css sections 10, 12 and 13,
   ported from the prototype in an earlier round. Schedule uses those classes
   rather than growing a parallel set here. What follows is only what the
   prototype's Schedule needs on top of them. */

/* A selected-but-not-today day. The prototype only ever shows `today` because
   its calendar cannot be navigated; ours can, so "the day you are looking at"
   needs to be distinguishable from "the day it actually is". */
.h-cal__cell.is-sel { box-shadow: inset 0 0 0 1px var(--line2); color: var(--ink); }
.h-week__day.is-sel {
  background: var(--active-green-bg); color: var(--active-green-ink);
  box-shadow: inset 0 0 0 1px var(--green), 0 0 14px rgba(var(--green-rgb),.18);
}
.h-cal__cell:hover:not(.is-today), .h-week__day:hover:not(.is-today) { box-shadow: inset 0 0 0 1px var(--green); }

/* Only shown when the cursor has moved off today — a "Go to today" button on
   today is a control that does nothing. */
.h-cal__today {
  display: block; width: 100%; margin: 0 0 10px; padding: 7px; cursor: pointer;
  background: var(--green-dim); border: 1px solid var(--green); color: var(--green);
  border-radius: var(--r-md); font: inherit; font-size: 11.5px; font-weight: 800;
}
.h-cal__head .h-cal__month { min-width: 0; overflow-wrap: anywhere; }
.h-cal__nav { flex: none; }
/* Day / Week / Month sits INSIDE the calendar card's rhythm, so it gets less
   air under it than the List/Calendar switch above the card. */
.h-seg--cal { margin-bottom: 10px; }
.h-agenda__hd { font-weight: 800; font-size: 15px; font-family: var(--font-head); margin: 2px 2px 10px; }
.h-agenda__row { width: 100%; text-align: left; font: inherit; color: var(--ink); cursor: pointer; }
.h-agenda__main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.h-agenda__t, .h-agenda__s { overflow-wrap: anywhere; }

/* Clear all / Select all, from the prototype's filter sheet. */
.h-allrow { display: flex; gap: 9px; margin: 14px 0 2px; }
.h-allrow .h-btn { flex: 1; }
/* A source with no feed behind it yet says why it is quiet. Silence would read
   as "you have nothing on", which is a different and wrong message. */
.h-frow__note { display: block; font-size: 10.5px; font-weight: 600; color: var(--faint); margin-top: 1px; }

.h-sw {
  flex: none; width: 38px; height: 22px; border-radius: var(--r-pill);
  background: var(--panel2); border: 1px solid var(--line2); position: relative;
  transition: background-color var(--t-fast), border-color var(--t-fast);
}
.h-sw::after {
  content: ''; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--muted); transition: transform var(--t-fast), background-color var(--t-fast);
}
.h-sw.is-on { background: rgba(var(--green-rgb), .2); border-color: var(--green); }
.h-sw.is-on::after { transform: translateX(16px); background: var(--green); }
/* `SET-01` — 🔴 THIS LINE DELETED THE ROW SEPARATOR FOR THE WHOLE APP AND
   NOBODY COULD SEE IT FROM EITHER FILE.
   `components.css:1332` declares `.h-frow { border-top: 1px solid var(--line) }`.
   This rule is a SECOND BODY of the same selector, it loads later, it is the
   same specificity (0,1,0), and its `border: 0` won. **So the separator between
   two rows inside a card has never painted, on any screen, since the shell
   shipped.** 🗣️ That is Karl's sentence on `SET-01` word for word: *"the
   different rows kind of run together"* — they run together because there is
   literally nothing between them.
   📌 THE RESET IS STILL NEEDED — `.h-frow` is a `<button>` and the UA paints all
   four sides — so this names the three sides it actually has to kill and leaves
   `border-top` to `components.css`, which owns the value. ONE body for the
   value, which is the `SYS-35` answer rather than a copy of the number here.
   ⛔ AND NOT `border: 0` FOLLOWED BY A RE-DECLARATION: that is two bodies again,
   with the second one in the file that does not own the component. */
.h-frow {
  width: 100%; background: none; font: inherit; color: var(--ink);
  border-right: 0; border-bottom: 0; border-left: 0;
}

/* --- Skill band (Email settings) -----------------------------------------
   The two ends of "adult games between B and A", INDENTED and hanging off the
   switch above them so the pair reads as a qualifier on that subscription
   rather than as two more independent settings. It only exists while the switch
   is on — settings.js does not render it otherwise — so the left rule always
   has something to attach to.
   ------------------------------------------------------------------------ */
.h-band {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  margin: -2px 0 12px 12px; padding-left: 12px;
  border-left: 2px solid var(--line2);
}
.h-band__f { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.h-band__l { font-size: 10.5px; font-weight: 800; color: var(--faint); text-transform: uppercase; }
/* Two selects side by side at 320px are about 120px each, which is enough for
   "Elite" and the arrow and nothing else. Stack instead. */
@media (max-width: 360px) { .h-band { grid-template-columns: 1fr; } }

/* --- Email members (the recruiting blast) ---------------------------------
   One block per role, separated by a rule rather than a card, because these are
   three parts of one decision and three cards would read as three screens.
   ------------------------------------------------------------------------ */
.h-rb { padding-bottom: 14px; margin-bottom: 14px; border-bottom: 1px solid var(--line); }
.h-rb:last-of-type { border-bottom: 0; margin-bottom: 4px; }
/* The count is the whole point of the screen, so it is the largest thing on it. */
.h-rb__count { margin: 0 0 9px; font-size: 14px; color: var(--ink); }
.h-rb__count b { font-size: 19px; }
.h-rb__names { color: var(--muted); font-size: 12px; }
/* Why the send button is not there. Said, not greyed out. */
.h-rb__blocked {
  margin: 0; padding: 9px 11px; font-size: 12.5px; font-weight: 600;
  /* No --warn-rgb token exists, so the tint is color-mix rather than an
     invented variable — a token that only this rule declares is a token the
     theme switch will not follow. */
  color: var(--warn); background: color-mix(in srgb, var(--warn) 12%, transparent);
  border: 1px solid var(--warn); border-radius: var(--r-md, 10px);
}
.h-rb__peek {
  display: block; margin-top: 9px; padding: 0; border: 0; background: none;
  font: inherit; font-size: 12px; font-weight: 700; color: var(--muted);
  text-decoration: underline; cursor: pointer;
}
.h-rb__msg { margin-top: 10px; border: 1px solid var(--line2); border-radius: var(--r-md, 10px); overflow: hidden; }
.h-rb__subj {
  padding: 9px 11px; font-size: 12.5px; font-weight: 700;
  background: var(--panel2); border-bottom: 1px solid var(--line2);
  overflow-wrap: anywhere;
}
/* SANDBOXED, and it has to be. The body is real email HTML; rendering it into
   this document would let an organiser's notes restyle the app. */
.h-rb__frame { display: block; width: 100%; height: 300px; border: 0; background: #fff; } /* raw-colour: a sandboxed iframe renders real email HTML, which is authored for white */

/* --- Find ----------------------------------------------------------------
   Three entry tiles (.h-tiles/.h-tile from components.css), then the open-games
   list. The row is a GRID, not a flex row: the fee pill, the rate and Apply
   form a right-hand column that must not be squeezed by a long game name, and
   at 400px and under the whole right column drops under the name instead of
   forcing a sideways scroll.
   ------------------------------------------------------------------------ */
.h-tiles--find { margin-bottom: 13px; }
.h-tiles--find .h-tile { min-width: 0; font: inherit; color: var(--ink); }
/* The Menu tiles are divs; these are buttons, so the label and the caption have
   to be told to stack — as inline spans they would sit shoulder to shoulder. */
.h-tiles--find .h-tile__name,
.h-tiles--find .h-tile__sub { display: block; overflow-wrap: anywhere; }

/* `FND-09` — 📐 THE TILE AND THE GAP GET NAMES, BECAUSE A THIRD RULE NOW HAS TO
   AGREE WITH THEM.
   Until this item they were two literals in two rules that never had to match
   anything: `.h-find__i`'s 40px and `.h-find__open`'s 11px gap. The phone
   layout at the bottom of this block indents the fee row by their SUM so the
   chip lines up with the title — and the moment that indent is written as
   `51px` there are three copies of one measurement and no gate comparing them.
   A seat who resizes the helmet tile would move the text and leave the chip
   behind, with every gate green and the alignment Karl asked for quietly
   undone.
   ⛔ SO THE NUMBER HAS ONE BODY AND THREE READERS, and `find-card-align.mjs`
   asserts the RELATIONSHIP rather than the value: it resizes the tile at
   runtime and re-reads the chip's offset from the title. A literal indent
   fails that assertion; a `calc()` off these two cannot. */
.h-find {
  --find-tile: 40px;
  --find-gap: 11px;
  display: grid; grid-template-columns: 1fr auto; align-items: start; gap: 10px;
  padding: 11px 12px; margin-bottom: 9px; position: relative;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-lg); border-left: 3px solid var(--warn);
}
.h-find:hover { border-color: var(--green); border-left-color: var(--green); }
.h-find.is-in { border-left-color: var(--green); }
.h-find__open {
  display: flex; align-items: flex-start; gap: var(--find-gap); min-width: 0;
  background: none; border: 0; padding: 0; font: inherit; color: var(--ink);
  text-align: left; cursor: pointer;
}
.h-find__i {
  width: var(--find-tile); height: var(--find-tile); border-radius: var(--r-md); flex: none;
  display: grid; place-items: center; overflow: hidden;
}
.h-find__i svg { width: 24px; height: 24px; }
.h-find__main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.h-find__n { font-size: 14px; font-weight: 700; overflow-wrap: anywhere; padding-right: 42px; }
.h-find__m { font-size: 11.5px; color: var(--muted); overflow-wrap: anywhere; }
/* The shortfall is the reason the row is here, so it is the loudest thing on
   it after the name. */
.h-find__needs { font-size: 12.5px; font-weight: 800; color: var(--warn); margin-top: 3px; }
.h-find__right {
  display: flex; flex-direction: column; align-items: flex-end; gap: 4px;
  min-width: 0; text-align: right;
}
.h-find__rate { font-size: 10.5px; color: var(--muted); overflow-wrap: anywhere; max-width: 120px; }
/* The fee pill is .h-feepill from components.css; inside this column it must
   not push itself to the right with the auto margin it uses in a role row. */
.h-find__right .h-feepill { margin-left: 0; }
/* (`.h-find__day` removed 2026-09-28: a second, smaller copy of the date the
   card already shows, and it sat on top of the badges — Karl, B11.) */
/* 📱 THE PHONE LAYOUT, AND `FND-09` IS ENTIRELY INSIDE IT.

   🗣️ KARL, on `Findlocalgames.png`: ① *"the 'Apply' button should be bottom
   right, not sitting tight to the cost"* and ② *"the 'they pay, free, you pay'
   chip should start in alignment with the rest of the text, not the
   icon/avatar."*

   🔎 BOTH FAULTS WERE THIS BLOCK, AND NEITHER WAS A BUG IN A RULE — they were
   what these three lines correctly do. Collapsing to one column drops
   `.h-find__right` BELOW `.h-find__open`, where it begins at the card's own
   padding edge — the same left edge as the helmet tile, while the title starts
   a tile-and-a-gap to the right of it. Turning that column into a left-packed
   wrapping ROW then puts the chip, the rate and Apply shoulder to shoulder
   from the left, so Apply lands against "$20.00 drop-in fee" with the rest of
   the card empty.

   📏 MEASURED BEFORE ANYTHING WAS CHANGED, `tools/find-card-align.mjs`, real
   cards from the real `findRow()`:
     chip.left 31 · tile.left 31 · title.left 82   — the chip was 51px left of
       the title and flush with the tile, at 320, 360 and 390.
     Apply's right edge 255 against a card edge of 361 at 390px — **106px of
       empty card to its right**, which is the "roughly a third" the item was
       filed with, confirmed rather than eyeballed.

   ✅ THE FIX IS THE TWO THINGS HE ASKED FOR AND NOTHING ELSE. The fee row is
   indented into the TEXT column, so the chip starts where the title starts;
   the action is pushed to the card's right edge with an auto margin, which is
   the free space the row already had and was packing away on the left.
   ⚖️ NOT A WIDTH CHANGE, DELIBERATELY: nothing here was too big to fit, which
   is why nothing is made smaller. The 414px layout is untouched — it already
   measured chip-to-text and Apply flush right.

   🏷️ `.h-tag` TAKES THE MARGIN TOO, NOT JUST `.h-btn`. A card the viewer is
   already on renders "You're in" where Apply would be, and a status that sits
   on the left while every neighbouring card's action sits on the right reads
   as two different layouts in one list. Same corner, whichever it is.

   🧹 AND `align-items` WAS DECLARED TWICE IN THE ROW RULE — `flex-start` then
   `center`. The first never applied. Removed rather than left as a line that
   looks like it decides something. */
@media (max-width: 400px) {
  .h-find { grid-template-columns: 1fr; }
  .h-find__right {
    flex-direction: row; flex-wrap: wrap; align-items: center;
    text-align: left;
    margin-left: calc(var(--find-tile) + var(--find-gap));
  }
  .h-find__right .h-btn,
  .h-find__right .h-tag { margin-left: auto; }
  .h-find__rate { max-width: none; }
}

.h-lr__row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
@media (prefers-reduced-motion: reduce) { .h-sw, .h-sw::after { transition: none; } }
html[data-motion="off"] .h-sw, html[data-motion="off"] .h-sw::after { transition: none; }

/* A bottom-nav tab that is not the Hub. Same box: fills the shell, scrolls
   inside itself, never pushes the nav off the bottom. */
.h-tab { flex: 1 1 auto; min-height: 0; display: flex; max-width: 100%; }
.h-tab[hidden] { display: none !important; }

/* ---------------------------------------------------------------------------
   THE GROUP ROOM
   Six tabs inside the push-detail panel. The head and the tab bar are fixed;
   only the tab body scrolls, so switching tabs never loses your place in the
   chrome. Same rule as the app shell: height, min-height:0, one scroller.
   ------------------------------------------------------------------------ */
.h-room__head {
  display: flex; align-items: center; gap: 11px; padding: 2px 0 12px;
  border-bottom: 1px solid var(--line); margin-bottom: 10px;
}
.h-room__disc {
  width: 44px; height: 44px; border-radius: var(--r-md); flex: none;
  display: grid; place-items: center; font-weight: 800; font-size: 15px;
  font-family: var(--font-head);
}
.h-room__id { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.h-room__n { font-weight: 800; font-size: 16px; font-family: var(--font-head); overflow-wrap: anywhere; }
.h-room__s { font-size: 11.5px; color: var(--muted); margin-top: 1px; overflow-wrap: anywhere; }
.h-room__switch {
  flex: none; display: inline-flex; align-items: center; gap: 4px;
  background: var(--panel2); border: 1px solid var(--line2); color: var(--muted);
  border-radius: var(--r-pill); padding: 6px 10px; font: inherit;
  font-size: 11.5px; font-weight: 700; cursor: pointer;
}
.h-room__switch:hover { color: var(--ink); border-color: var(--green); }
.h-room__switch .h-ic { width: 13px; height: 13px; }
/* B22 note (Karl, 2026-09-28): Switch lives in the tab bar. Worded, it takes
   Manage's spot for a member; for a manager it is a small circle beside Manage. */
.h-room__switch--tab { margin-left: auto; min-height: 34px; padding: 6px 12px; }
.h-room__switch--mini { width: 34px; height: 34px; padding: 0; justify-content: center; margin-left: 6px; }
.h-room__switch--mini .h-ic { width: 15px; height: 15px; }

/* The tab bar. Same rule as the Hub strip: the SELECTED tab wears its name,
   the rest are icons — six words will not fit a 320px phone. */
.h-room__tabs {
  display: flex; align-items: center; gap: 2px; margin-bottom: 12px;
  border-bottom: 1px solid var(--line); padding-bottom: 8px;
}
.h-room__tab {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  flex: 0 0 auto; min-width: 0; position: relative;
  padding: 7px 9px; border: 0; border-radius: var(--r-pill);
  background: transparent; color: var(--muted);
  font: inherit; font-size: 12.5px; font-weight: 700; cursor: pointer;
  transition: background-color var(--t-fast), color var(--t-fast);
}
.h-room__tab .h-ic { width: 18px; height: 18px; flex: none; }
.h-room__tab:hover { color: var(--ink); }
.h-room__tab.is-on { background: var(--green); color: var(--on-green); flex: 0 1 auto; }
.h-room__tab-lb { display: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.h-room__tab.is-on .h-room__tab-lb { display: inline; }
.h-room__badge {
  position: absolute; top: 1px; right: 2px;
  min-width: 15px; height: 15px; padding: 0 4px; border-radius: var(--r-pill);
  background: var(--warn-solid); color: var(--on-warn);
  font-size: 9px; font-weight: 800; display: grid; place-items: center;
}
.h-room__badge--inline { position: static; margin-left: 5px; }

.h-room__body { min-width: 0; }

/* --- overview ------------------------------------------------------------ */
.h-room__card { background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 12px; margin-bottom: 12px; }
.h-room__card--do { border-color: var(--warn); }
.h-room__check {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  background: none; border: 0; padding: 8px 0; font: inherit; font-size: 13px;
  color: var(--ink); cursor: pointer; border-top: 1px solid var(--line);
}
.h-room__check:first-of-type { border-top: 0; }
.h-room__check .h-ic { width: 15px; height: 15px; color: var(--muted); flex: none; }
.h-room__check:hover { color: var(--green); }

.h-room__next {
  background: var(--panel); border: 1px solid var(--line); border-left: 3px solid var(--green);
  border-radius: var(--r-lg); padding: 12px; margin-bottom: 12px;
}
.h-room__next-n { font-weight: 800; font-size: 15px; overflow-wrap: anywhere; }
.h-room__next-m { font-size: 12px; color: var(--muted); margin-top: 2px; overflow-wrap: anywhere; }
.h-room__next-c { font-size: 12.5px; font-weight: 700; color: var(--green); margin-top: 5px; }

.h-room__tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin: 12px 0; }
.h-room__tile {
  background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 10px 8px; text-align: center; cursor: pointer; font: inherit; color: var(--ink);
  min-width: 0; display: flex; flex-direction: column; gap: 1px;
}
.h-room__tile:hover { border-color: var(--green); }
.h-room__tile-b { font-size: 17px; font-weight: 800; font-family: var(--font-head); overflow-wrap: anywhere; }
.h-room__tile-l { font-size: 11px; font-weight: 700; overflow-wrap: anywhere; }
.h-room__tile-s { font-size: 10px; color: var(--faint); overflow-wrap: anywhere; }

.h-room__more {
  width: 100%; margin-top: 10px; padding: 10px; cursor: pointer;
  background: none; border: 1px dashed var(--line2); border-radius: var(--r-md);
  color: var(--muted); font: inherit; font-size: 12.5px; font-weight: 700;
}
.h-room__more:hover { color: var(--green); border-color: var(--green); }

/* --- announcements ------------------------------------------------------- */
/* AN-02 (Karl, walk v41): each category has its own colour, carried by one
   token (`--ann-c`) so the icon, the label and the subject all follow it. */
.h-ann--general   { --ann-c: var(--muted); }
.h-ann--schedule  { --ann-c: var(--info); }
.h-ann--important { --ann-c: var(--warn); }
.h-ann--urgent    { --ann-c: var(--danger); }
.h-ann--forms     { --ann-c: var(--purple); }
.h-ann--social_event { --ann-c: var(--green); }
.h-room__ann {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 11px 12px; margin-bottom: 9px;
  display: flex; gap: 11px; align-items: flex-start;
}
.h-room__ann-main { min-width: 0; flex: 1; }
.h-room__ann-ic {
  flex: none; width: 34px; height: 34px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--ann-c, var(--muted));
  /* Composited over the solid panel, not left translucent: the icon's ink is
     measured against what is actually under it (contrast.test). */
  background: color-mix(in srgb, var(--ann-c, var(--muted)) 16%, var(--panel));
  border: 1px solid color-mix(in srgb, var(--ann-c, var(--muted)) 45%, var(--panel));
}
.h-room__ann-ic .h-ic { width: 17px; height: 17px; }
.h-room__ann-k { font-size: 10.5px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--ann-c, var(--muted)); }
.h-room__ann-t { font-family: var(--font-head); font-weight: 800; font-size: 15.5px; line-height: 1.25; color: var(--ann-c, var(--ink)); margin: 2px 0 4px; overflow-wrap: anywhere; }
.h-ann--general .h-room__ann-t { color: var(--ink); }
/* AN-02 v42: the composer's category is a styled dropdown; its list scrolls. */
.h-annsel { position: relative; }
.h-annsel__btn {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 46px; padding: 6px 12px;
  background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-md);
  color: var(--ink); font: inherit; font-size: 14px; font-weight: 700; text-align: left; cursor: pointer;
}
.h-annsel__btn .h-room__ann-ic { width: 28px; height: 28px; }
.h-annsel__t { flex: 1; min-width: 0; color: var(--ann-c, var(--ink)); }
.h-annsel__chev { width: 16px; height: 16px; color: var(--muted); }
.h-annsel__list {
  display: grid; gap: 6px; margin-top: 6px; padding: 6px; max-height: 196px; overflow-y: auto; overscroll-behavior: contain;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
}
/* The message box takes the room the chips gave back. */
.h-annmsg { min-height: 190px; resize: vertical; }
/* What the formatting looks like on a post (H365UI.richText). */
.h-rt__big { display: block; font-family: var(--font-head); font-weight: 800; font-size: 17px; line-height: 1.3; margin: 2px 0 4px; }
.h-rt__ul { margin: 4px 0; padding-left: 20px; }
.h-rt__ul li { margin: 2px 0; }
.h-annpick__o {
  display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 6px 10px;
  background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-md);
  color: var(--ink); font: inherit; font-size: 12.5px; font-weight: 700; text-align: left; cursor: pointer;
}
.h-annpick__o .h-room__ann-ic { width: 28px; height: 28px; }
.h-annpick__o.is-on { border-color: var(--ann-c); box-shadow: 0 0 0 1px var(--ann-c) inset; }
.h-room__ann.is-pinned { border-left: 3px solid var(--green); }
.h-room__ann-b { font-size: 13.5px; line-height: 1.45; overflow-wrap: anywhere; }
.h-room__ann-m { font-size: 11px; color: var(--faint); margin-top: 5px; overflow-wrap: anywhere; }
/* A notice from before announcements became chat messages. Marked, not hidden:
   it was never emailed to anybody and it cannot be replied to, and letting it
   look like a post that merely reached nobody is the worse of the two. */
.h-room__annold { font-style: italic; }
/* WHAT THE POST BUTTON ACTUALLY DOES. Carries the accent edge rather than the
   muted grey the eye learns to skip — an organiser is one tap from emailing
   the whole roster. Same treatment as .h-ch__announce in the messenger. */
.h-room__annwarn {
  margin: 0 0 12px; padding: 8px 10px; border-radius: var(--r-sm);
  border-left: 3px solid var(--brand-purple);
  background: var(--panel2); color: var(--ink); font-size: 11.5px;
}

/* --- roster -------------------------------------------------------------- */
.h-room__search { position: relative; margin-bottom: 9px; }
.h-room__search .h-ic {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  width: 15px; height: 15px; color: var(--muted); pointer-events: none;
}
.h-room__search .h-input { padding-left: 34px; }
.h-room__filters { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.h-room__filters .h-ic { width: 14px; height: 14px; }
.h-room__clear { background: none; border: 0; color: var(--muted); font: inherit; font-size: 12px; text-decoration: underline; cursor: pointer; }
.h-room__count { margin-left: auto; font-size: 11.5px; color: var(--faint); }
.h-room__pager { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 12px; font-size: 12px; color: var(--muted); }
.h-room__pager .h-btn[disabled] { opacity: .4; cursor: default; }
/* ===========================================================================
   VERA'S FINDING 4, AND THIS FILE FORBADE IT 440 LINES EARLIER IN ITS OWN
   WORDS: "NOT `opacity`, which multiplies through to the text and drags it
   under AA - the same mistake the booking cards made. Each part is dimmed on
   its own, by choosing a dimmer colour."
   📊 HER MEASUREMENTS, WHICH ARE WHY THIS IS A DEFECT AND NOT A PREFERENCE:
      row subtitle, dark        5.41 -> 2.72   bar 4.5  FAIL
      row subtitle, light       6.10 -> 2.59   bar 4.5  FAIL
      banned row warn edge      5.42 -> 2.57   bar 3.0  FAIL
   A retired member's position was unreadable. It is readable now.
   📌 THE DIMMING IS THE NAME AND THE AVATAR ONLY. `.h-mrow__s` is already
   `--faint` at full strength and the "Retired" / "Removed" tag carries the
   state in words - dimming a row that already says what it is twice is how you
   end up dimming it below the bar. Her mock, minus one `font-weight: 600` that
   `components.css` already sets on that class.
   BALANCE HER MOCK ALSO SWAPPED THE BANNED EDGE TO `box-shadow: inset`. NOT
   TAKEN, and the reason is in this file: `.h-mrow.is-you` marks itself with
   exactly this `border-left` + `padding-left` pair. Two ways of drawing one
   kind of edge is the drift her own finding 2 is about. The edge was never the
   defect; the opacity over it was.
   ========================================================================= */
.h-mrow.is-retired .h-mrow__n { color: var(--muted); }
.h-mrow.is-retired .h-mrow__av { background: none; border: 1px solid var(--line2); color: var(--faint); }
.h-mrow.is-banned { border-left: 3px solid var(--warn-solid); padding-left: 9px; }
.h-mrow.is-banned .h-mrow__n { color: var(--muted); }
.h-mrow__edit {
  flex: none; background: none; border: 1px solid var(--line2); color: var(--muted);
  border-radius: var(--r-pill); padding: 5px 11px; font: inherit; font-size: 11.5px;
  font-weight: 700; cursor: pointer;
}
.h-mrow__edit:hover { color: var(--green); border-color: var(--green); }
.h-room__decide { display: flex; gap: 6px; flex: none; }

/* --- chips (roster filters, position pickers) ---------------------------- */
.h-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
/* 🏛 `S2-07`, KARL 2026-09-09: *"the filters use a more rounded corner radius.
   I would prefer if all of these filter chips (throughout the entire app), use
   the same corner radius as those 4 buttons. Only make this change if it's a
   simple global change."*

   ✅ IT IS ONE LINE AND IT IS GLOBAL: every filter chip in the app comes
   through this rule, so the whole of his request is this declaration.

   🔴 BUT `14px` WOULD HAVE BEEN ALL BUT INVISIBLE AND I MEASURED IT RATHER
   THAN SHIPPING IT. (First draft of this note said "a no-op" flatly; the
   instrument made me scope it. It is EXACTLY a no-op on `.h-chip--sm`, where
   14px clamps to a perfect pill, and 0.875 of half-height on `.h-chip` —
   barely distinguishable from the pill it replaces. On the `.h-scope__s`
   filters it would be 0.85 and also barely distinguishable, but it would not
   technically be a pill, so "no-op" was too strong and is corrected here.) "Those 4 buttons" are `.h-tiles--find .h-tile`, measured in chromium at
   **88px tall with a 14px corner** — a third of their half-height, which is why
   they read as rounded rectangles. A chip is **32px tall**, so its half-height
   is 16px: a 14px corner is 0.875 of that and is visually still a pill. On
   `.h-chip--sm` (25.3px) a 14px corner is CLAMPED to 12.6px, which is a perfect
   pill and therefore **exactly zero change**. Copying his number would have
   changed nothing and looked like the row was never done.

   ✅ SO IT IS `--r-sm`, WHICH IS HALF THE CHIP'S HALF-HEIGHT AND READS AS THE
   SAME FAMILY OF CORNER AS THE TILES AT THE SIZE A CHIP ACTUALLY IS. A TOKEN
   rather than a number, so the chip speaks each style's own radius language
   instead of one hard-coded corner — a raw `8px` would go on being 8px in the
   square style while everything around it went to 0.
   📐 MEASURED IN ALL FIVE STYLES, and the last column is a limit I am stating
   rather than hiding:
       default  chip  8px · tile 14px      openice  chip  6px · tile 14px
       gm       chip  0px · tile 14px      street   chip  4px · tile 14px
       pond     chip 10px · tile 14px
   ⚠️ **THE TILES DO NOT FOLLOW, BECAUSE THEIR 14px IS RAW.** So chip and tile
   agree at the default style and DIVERGE in the other four — the chip moves
   with the theme and the tile stands still. That is `SYS-29`'s gap, not this
   row's to close, and pretending otherwise by hard-coding 8px here would only
   trade a visible mismatch for an invisible one.
   ⚖️ KARL OWNS THE NUMBER. The measurement says 14 is invisible and 8 is the
   app's existing next step down; if he wants it squarer or softer it is this
   one declaration.
   ⛔ AND THE TILES ARE NOT TOUCHED. Their raw `14px` stays raw: tokenising
   every radius in the tree is `SYS-29` on the Sweep 1 register and is
   deliberately NOT this row. */
.h-chip {
  background: var(--panel2); border: 1px solid var(--line2); color: var(--muted);
  border-radius: var(--r-sm); padding: 6px 12px; font: inherit; font-size: 12px;
  font-weight: 700; cursor: pointer;
}
.h-chip.is-on { background: var(--green); border-color: var(--green); color: var(--on-green); }

/* --- standings ----------------------------------------------------------- */
.h-stand { width: 100%; border-collapse: collapse; font-size: 13px; }
.h-stand th {
  text-align: left; font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--faint); font-weight: 800; padding: 6px 8px; border-bottom: 1px solid var(--line);
}
.h-stand td { padding: 9px 8px; border-bottom: 1px solid var(--line); overflow-wrap: anywhere; }
.h-stand th:first-child, .h-stand td:first-child { width: 28px; color: var(--muted); }
.h-stand th:last-child, .h-stand td:last-child { width: 46px; text-align: right; font-weight: 800; }

/* --- about --------------------------------------------------------------- */
.h-room__about { font-size: 13.5px; line-height: 1.5; margin: 4px 0 10px; overflow-wrap: anywhere; }
.h-room__meta { font-size: 12.5px; color: var(--muted); margin-bottom: 8px; overflow-wrap: anywhere; }

/* --- the Manage sheet ---------------------------------------------------- */
/* `.h-mtool` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
.h-mtool:first-of-type { border-top: 0; }
/* A blocked row is greyed and says WHY, rather than being hidden. Hiding it
   makes the app look finished and leaves an organiser hunting. */
.h-mtool.is-off { opacity: .5; cursor: default; }
.h-mtool__main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* `.h-mtool__t` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
/* `.h-mtool__s` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
.h-mtool__go { flex: none; color: var(--muted); font-size: 17px; }

/* --- recruitment --------------------------------------------------------- */
/* `.h-recruit` MOVED TO components.css IN 08-17z. It was defined in both files with different values,
   so it rendered one way in the app and another on every page that does not load
   this file — including kit.html, the page that documents it. */
/* VERA'S RECRUITMENT FINDINGS, AND BOTH RULES ARE GONE RATHER THAN FIXED.
   `.h-recruit:first-of-type { border-top: 0 }` is why card 1 had three sides
   and cards 2 and 3 had four - "three cards, one a different shape", which is
   the "extra outline" Karl reported and which no colour value was ever going
   to fix. `.h-recruit .h-input` styled the permanently-open note box under
   every role. THE SCREEN IS REBUILT ON `.h-grp` AND NEITHER RULE HAS A CALLER.
   The `.h-recruit__*` family in components.css is now rendered ONLY by
   kit.html's gallery - reported, and decided in that pass rather than this. */

.h-room__body select.h-input, .h-sheet select.h-input { appearance: none; background-image: none; }
.h-room__body textarea.h-input, .h-sheet textarea.h-input { resize: vertical; min-height: 66px; }

@media (max-width: 380px) {
  .h-room__tiles { grid-template-columns: 1fr 1fr; }
}

/* ---------------------------------------------------------------------------
   EMAIL BLAST
   The recipient count is the loudest thing on the screen, because "who am I
   about to email" is the question the whole sheet exists to answer.
   ------------------------------------------------------------------------ */
.h-blast__count {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px;
  background: var(--panel2); border: 1px solid var(--line2); border-radius: var(--r-md);
  padding: 10px 12px; margin-bottom: 12px;
}
.h-blast__n { font-size: 15px; font-weight: 800; font-family: var(--font-head); color: var(--green); }
.h-blast__skip {
  font-size: 10.5px; font-weight: 800; color: var(--warn); border: 1px solid var(--warn);
  border-radius: var(--r-pill); padding: 1px 8px;
}
.h-blast__note { flex: 1 1 100%; font-size: 11.5px; color: var(--muted); overflow-wrap: anywhere; }
/* The "All" chip is not a control — it is the state of having picked nothing,
   said out loud. Styling it like a button would invite a tap that does nothing. */
.h-chip.is-all { background: var(--green-dim); border-color: var(--green); color: var(--green); cursor: default; }
.h-blast__row { border-top: 1px solid var(--line); padding: 9px 2px; }
.h-blast__row:first-of-type { border-top: 0; }
.h-blast__subj { display: block; font-size: 13px; font-weight: 700; overflow-wrap: anywhere; }
.h-blast__meta { display: block; font-size: 11px; color: var(--muted); margin-top: 2px; overflow-wrap: anywhere; }
.h-blast__st { font-weight: 800; text-transform: uppercase; font-size: 9.5px; letter-spacing: .04em; }
.h-blast__st.is-queued { color: var(--warn); }
.h-blast__st.is-sent { color: var(--green); }
.h-blast__st.is-failed, .h-blast__st.is-cancelled { color: var(--danger); }

/* ---------------------------------------------------------------------------
   SCHEDULE BUILDER
   ------------------------------------------------------------------------ */
.h-sb__prog { display: flex; gap: 5px; justify-content: center; margin: 0 0 14px; }
.h-sb__dot { width: 26px; height: 4px; border-radius: 2px; background: var(--line2); }
.h-sb__dot.is-done { background: var(--green); }
.h-sb__add { display: flex; gap: 8px; align-items: center; margin-top: 8px; }
.h-sb__add .h-input { flex: 1; min-width: 0; }
/* COMPOSITED (08-18j), and the token reference removed with it.

   This read `var(--warn-dim, rgba(255,184,77,.12))`. THERE IS NO `--warn-dim`.
   `--green-dim` and `--purple-dim` are both defined in tokens.css; the warn one
   never was, so the "fallback" was the only value this rule has ever used and
   the var() was decoration that read like a token. A theme could never have
   changed it, which is exactly what a reader would assume it could.
   (tests/tokens.test.mjs now refuses an undefined token reference outright.) */
.h-sb__notice {
  font-size: 12px; color: var(--warn);
  background: linear-gradient(rgba(var(--warn-wash-rgb),.12), rgba(var(--warn-wash-rgb),.12)), var(--panel);
  border: 1px solid var(--warn); border-radius: var(--r-md); padding: 8px 10px; margin-bottom: 10px;
}
.h-sb__count { font-size: 13.5px; font-weight: 800; margin-bottom: 10px; }
.h-sb__undo {
  display: block; width: 100%; margin-bottom: 10px; padding: 8px; cursor: pointer;
  background: none; border: 1px dashed var(--green); border-radius: var(--r-md);
  color: var(--green); font: inherit; font-size: 12px; font-weight: 700;
}
/* The review list scrolls INSIDE itself. Thirty rows inside a bottom sheet
   would push Create off the bottom of the phone. */
.h-sb__rows { max-height: 46vh; overflow-y: auto; overflow-x: hidden; margin: 0 -2px; padding: 0 2px; }
.h-sb__row {
  position: relative; background: var(--panel2); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 9px 34px 9px 10px; margin-bottom: 7px;
}
.h-sb__row.has-warn { border-left: 3px solid var(--warn); }
.h-sb__rmain { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: 6px; margin-bottom: 6px; }
.h-input--sm { padding: 6px 8px; font-size: 16px /* SYS-07: was 12px; under 16 the field zooms iOS */; }
.h-sb__warns { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
.h-sb__next { display: block; font-size: 10.5px; color: var(--muted); margin-top: 4px; }
.h-sb__del {
  position: absolute; top: 7px; right: 7px; width: 22px; height: 22px;
  background: none; border: 0; color: var(--muted); font-size: 17px; line-height: 1;
  cursor: pointer; border-radius: var(--r-sm);
}
.h-sb__del:hover { color: var(--danger); background: var(--panel); }
@media (max-width: 380px) {
  .h-sb__rmain { grid-template-columns: 1fr 1fr; }
  .h-sb__rmain > :first-child { grid-column: 1 / -1; }
}

/* The two Find tiles that are real modes light up when they are the one you
   are looking at. The third (Sessions) is not a mode yet and never lights. */
/* ===========================================================================
   `FND-01` - "BROWSE LOCAL GAMES IS INCONSISTENT WITH THE OTHER THREE", AND THE
   CAUSE IS A RULE THAT OUTLIVED THE GEOMETRY IT WAS WRITTEN FOR.

   MEASURED, 390px, dark, the Find screen exactly as it opens:
        Find Sessions        icon box 148 x 22   background transparent
        Browse Local Games   icon box 148 x 22   background rgb(7,247,8)
        Find a Pickup Group  icon box 148 x 22   background transparent
        Fill a Roster        icon box 148 x 22   background transparent
   A 148px SOLID GREEN BAR ACROSS ONE CARD OF FOUR, ON OPEN, EVERY TIME.

   KEY TWO THINGS HAD TO BE TRUE AND BOTH WERE. `schedule.js:71` defaults
   `findMode` to `games`, so this tile is `is-on` before the member touches
   anything - it is not a state they got into, it is the state they arrive in.
   And the rule below painted `background: var(--green)` on `.h-tile__ic`, which
   in THIS grid is `width: auto; height: auto; display: block` - so the fill is
   not a 32px chip, it is a band the full width of the card.
   MIRROR THE CHIP RULE WAS RIGHT WHEN IT WAS WRITTEN, and the comment 20 rules
   below is the one that broke it: "Naked icon, no chip. The chip was 32px of
   background doing the job of a colour, and four of them read as four buttons
   all shouting equally." The chip was removed from the BASE and left standing
   in the ON state, where it stopped being a chip and became a bar.
   ARROW THE FIX IS TO STOP FILLING IT. `is-on` is already marked by the tile's
   own border and tint; the icon keeps the green INK it has in every other tile,
   so the four cards finally have one shape. Karl's complaint is about the odd
   one out, and the odd one out was a rule nobody re-read after the redesign.
   ========================================================================= */
.h-tiles--find .h-tile.is-on { border-color: var(--green); background: var(--green-dim); }
.h-tiles--find .h-tile.is-on .h-tile__ic { background: none; }
/* A group's initials sit where a game's role icon does. */
.h-find__i { font-weight: 800; font-size: 14px; font-family: var(--font-head); }

/* ---------------------------------------------------------------------------
   THE GAME SHEET
   ------------------------------------------------------------------------ */
.h-gs__cancelled {
  display: flex; flex-direction: column; gap: 3px;
  /* COMPOSITED (08-18j). A see-through wash that carries its own ink has to
     name the surface it sits on, or it inherits whatever is behind it and the
     ratio changes with placement. Seventh instance of this shape. */
  background: linear-gradient(var(--wash-cancelled), var(--wash-cancelled)), var(--panel);
  border: 1px solid var(--danger);
  border-radius: var(--r-md); padding: 10px 12px; margin-bottom: 12px;
  font-size: 13px; color: var(--ink);
}
.h-gs__cancelled span { font-size: 12px; color: var(--muted); }

/* (`.h-gs__stars` / `.h-gs__star*` / `.h-gs__score` / `.h-gs__side` and the `.h-es*` stat grid RETIRED 2026-10-04: Stats & Three Stars is `statsws.css`.) */
/* MST-3: the organizer's Stat corrections cards. */
.h-gs__corr { display: flex; flex-direction: column; gap: 6px; padding: 12px; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel2); margin-bottom: 8px; }
.h-gs__corr-h { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 10px; }
.h-gs__corr-h small { color: var(--muted); font-size: 12px; }
.h-gs__corr-st { margin-left: auto; }
.h-gs__corr-f { font-size: 13px; font-variant-numeric: tabular-nums; }
.h-gs__corr-n { font-size: 13px; color: var(--muted); }
.h-gs__corr-a { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; }
.h-gs__card {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 13px; margin-bottom: 12px;
}
.h-gs__group { font-size: 11px; font-weight: 800; color: var(--green); text-transform: uppercase; letter-spacing: .06em; }
.h-gs__when { font-size: 15px; font-weight: 800; font-family: var(--font-head); margin-top: 3px; overflow-wrap: anywhere; }
.h-gs__where { font-size: 12.5px; color: var(--muted); margin-top: 2px; overflow-wrap: anywhere; }
.h-gs__chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
/* TWO numbers. "12 on the roster" and "7 have said they are coming" are both
   true, and only the second tells you whether you have a game. */
.h-gs__cap { font-size: 12.5px; color: var(--muted); margin-top: 10px; }
.h-gs__cap b { color: var(--green); font-size: 15px; font-family: var(--font-head); }
.h-gs__of { display: block; font-size: 11px; color: var(--faint); margin-top: 1px; }
.h-gs__bar { height: 4px; border-radius: 2px; background: var(--panel2); margin-top: 7px; overflow: hidden; }
.h-gs__bar i { display: block; height: 100%; background: var(--green); }
.h-gs__jersey { width: 13px; height: 13px; border-radius: 3px; flex: none; border: 1px solid var(--line2); display: inline-block; }
.h-gs__sub { font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--faint); font-weight: 800; margin: 10px 2px 5px; }
.h-mrow.is-you { border-left: 3px solid var(--green); padding-left: 9px; }
.h-gs__paid { flex: none; color: var(--green); font-weight: 800; font-size: 14px; }
.h-gs__paid.is-part { color: var(--warn); }

/* The attendance pill — the one control most members ever touch. */
.h-att {
  flex: none; border-radius: var(--r-pill); padding: 5px 11px; font: inherit;
  font-size: 11.5px; font-weight: 800; cursor: pointer; white-space: nowrap;
  border: 1px solid var(--line2); background: var(--panel2); color: var(--muted);
}
/* THE WASH GOES ON --panel, NOT ON THE ROW. These two sit inside `.h-mrow`,
   which on `.is-you` carries a wash of its own, so the tints stacked and the
   composited pass measured **4.13** (In) and **3.98** (Out) in light where the
   same chip on a panel measures about 4.9. Same remedy as the booking warning
   (08-18a) and the avatar disc (08-18b): pin the tint to an opaque surface and
   the chip is the same colour wherever it lands.

   `is-no` also mixed its wash from a hardcoded PINK — `rgba(255,92,138,.12)` —
   which is neither of this theme's danger colours and could never flip with the
   theme. It uses `--danger-rgb` now, so it is the colour it claims to be. */
.h-att.is-yes {
  border-color: var(--green); color: var(--green);
  background: linear-gradient(var(--green-dim), var(--green-dim)), var(--panel);
}
.h-att.is-no {
  border-color: var(--danger); color: var(--danger);
  background:
    linear-gradient(rgba(var(--danger-rgb), .12), rgba(var(--danger-rgb), .12)),
    var(--panel);
}
.h-att[disabled] { cursor: default; opacity: .7; }

/* --- teams --------------------------------------------------------------- */
.h-gt__cols { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 7px; }
.h-gt__col { min-width: 0; background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-md); padding: 7px; }
.h-gt__hd {
  display: flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 800;
  margin-bottom: 7px; overflow-wrap: anywhere;
}
.h-gt__hd span { margin-left: auto; color: var(--muted); flex: none; }
.h-gt__empty { font-size: 10.5px; color: var(--faint); text-align: center; padding: 10px 0; }
.h-gt__chip {
  display: flex; align-items: center; gap: 5px; background: var(--panel);
  border: 1px solid var(--line2); border-radius: var(--r-sm); padding: 5px 6px;
  margin-bottom: 5px; cursor: pointer; min-width: 0;
}
.h-gt__chip:hover { border-color: var(--green); }
.h-gt__chip.is-locked { border-color: var(--warn); }
.h-gt__pos { flex: none; font-size: 9px; font-weight: 800; color: var(--muted); }
.h-gt__n { flex: 1; min-width: 0; font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-gt__lock { flex: none; background: none; border: 0; color: var(--muted); font-size: 10px; cursor: pointer; padding: 0 2px; }
.h-gt__chip.is-locked .h-gt__lock { color: var(--warn); }

/* --- staffing a game ------------------------------------------------------
   One card per shift, because a shift is a THING with people on it — a flat
   list of names under one heading cannot say which two of the five are on
   scorekeeping and which three are on the gate. */
.h-wo__card {
  background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 11px 12px; margin-bottom: 10px;
}
.h-wo__hd { display: flex; align-items: center; gap: 8px; }
.h-wo__t { font-weight: 800; font-size: 13px; min-width: 0; overflow-wrap: anywhere; }
/* OPEN IS A STATE, NOT A WARNING. An unstaffed shift is the normal way to
   advertise one — the Staff Hub shows it to anyone who could claim it — so it
   reads as a quiet tag rather than as something gone wrong. */
.h-wo__open {
  flex: none; margin-left: auto; font-size: 9.5px; font-weight: 800;
  letter-spacing: .07em; text-transform: uppercase; color: var(--green);
  border: 1px solid var(--green); border-radius: var(--r-pill); padding: 2px 7px;
}
.h-wo__card .h-allrow { margin-top: 9px; flex-wrap: wrap; gap: 6px; }
.h-wo__card .h-allrow .h-input { flex: 1 1 120px; min-width: 0; }
/* The pay box holds "$25" and no more, so it does not take an equal third of a
   row it does not need. */
.h-wo__card .h-allrow .h-wo__pay { flex: 0 1 88px; }
.h-wo__card .h-lr__hint { margin: 8px 0 0; }

.h-stand--wide th, .h-stand--wide td { padding: 8px 4px; }
.h-stand--wide td.is-total { color: var(--green); font-weight: 800; }
.h-stand--wide th:not(:nth-child(2)), .h-stand--wide td:not(:nth-child(2)) { text-align: right; width: 34px; }
.h-stand--wide th:first-child, .h-stand--wide td:first-child { text-align: left; width: 24px; }

/* The win-loss-tie record, tucked under the name rather than given three more
   columns — at 320px a six-column table is already at its limit. */
.h-stand__rec { display: block; font-size: 10px; color: var(--faint); font-weight: 600; }

/* ---------------------------------------------------------------------------
   REVIEWS
   ------------------------------------------------------------------------ */
.h-rv__hero { display: flex; align-items: center; gap: 14px; margin-bottom: 12px; }
.h-rv__ring { position: relative; width: 84px; height: 84px; flex: none; }
.h-rv__ring svg { width: 100%; height: 100%; }
.h-rv__ringbg { fill: none; stroke: var(--line2); stroke-width: 8; }
.h-rv__ringfg {
  fill: none; stroke: var(--green); stroke-width: 8; stroke-linecap: round;
  transition: stroke-dashoffset var(--t-med);
}
.h-rv__ringc {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; line-height: 1;
}
.h-rv__ringc b { font-size: 21px; font-weight: 800; font-family: var(--font-head); }
.h-rv__ringc i { font-size: 9px; color: var(--muted); font-style: normal; margin-top: 2px; }
.h-rv__heroc { flex: 1; min-width: 0; }
.h-rv__stars { color: var(--green); font-size: 15px; letter-spacing: 1px; }
/* THE TRACK TOKEN, NOT A BORDER TOKEN. `--line2` measured 1.37:1 in dark, at
   which point a five-star scale has no visible denominator — and in the review
   FORM these are the targets you click. See --track in tokens.css. (08-18d) */
.h-rv__star { color: var(--track); }
.h-rv__star.is-full { color: var(--green); }
.h-rv__count { font-size: 12px; color: var(--muted); margin-top: 3px; }
.h-rv__rec { display: flex; align-items: center; gap: 6px; margin-top: 6px; flex-wrap: wrap; }
.h-rv__recl { font-size: 10px; text-transform: uppercase; letter-spacing: .06em; color: var(--faint); font-weight: 800; }
.h-rv__recc {
  font-size: 11px; font-weight: 800; background: var(--green-dim); color: var(--green);
  border-radius: var(--r-pill); padding: 2px 9px;
}
.h-rv__bars { margin-bottom: 12px; }
.h-rv__bar { display: grid; grid-template-columns: 1fr 3fr auto; gap: 8px; align-items: center; margin-bottom: 6px; }
.h-rv__barl { font-size: 11.5px; color: var(--muted); overflow-wrap: anywhere; }
.h-rv__bart { height: 6px; border-radius: 3px; background: var(--panel2); overflow: hidden; }
.h-rv__bart i { display: block; height: 100%; background: var(--green); }
.h-rv__barv { font-size: 11.5px; font-weight: 800; }

.h-rv__sort { display: flex; align-items: center; gap: 6px; margin: 12px 0 8px; }
.h-rv__sortl { font-size: 11px; color: var(--faint); font-weight: 700; }
.h-rv__sopt {
  background: none; border: 1px solid var(--line2); color: var(--muted);
  border-radius: var(--r-pill); padding: 4px 11px; font: inherit; font-size: 11.5px;
  font-weight: 700; cursor: pointer;
}
.h-rv__sopt.is-on { background: var(--green); border-color: var(--green); color: var(--on-green); }

.h-rv__card {
  background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 10px 12px; margin-bottom: 8px;
}
.h-rv__chd { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.h-rv__who { font-size: 13px; font-weight: 700; overflow-wrap: anywhere; }
.h-rv__when { font-size: 11px; color: var(--faint); flex: none; }
.h-rv__cstats { display: flex; flex-wrap: wrap; gap: 10px; margin: 6px 0; }
.h-rv__cstat { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.h-rv__cstat i { font-size: 10px; color: var(--faint); font-style: normal; }
.h-rv__cstat .h-rv__stars { font-size: 12px; }
.h-rv__note { font-size: 12.5px; line-height: 1.45; margin: 6px 0 0; white-space: pre-wrap; overflow-wrap: anywhere; }

/* --- the write form ------------------------------------------------------ */
.h-wr__intro { font-size: 12px; color: var(--muted); margin: 0 0 12px; line-height: 1.45; }
.h-wr__f { padding: 9px 0; border-top: 1px solid var(--line); }
.h-wr__f:first-of-type { border-top: 0; }
.h-wr__l { display: block; font-size: 13.5px; font-weight: 700; }
.h-wr__h { display: block; font-size: 11.5px; color: var(--muted); margin-top: 1px; }
.h-wr__row { display: flex; align-items: center; gap: 3px; margin-top: 6px; flex-wrap: wrap; }
.h-wr__s {
  background: none; border: 0; padding: 2px 3px; cursor: pointer;
  font-size: 24px; line-height: 1; color: var(--line2);
}
.h-wr__s.is-on { color: var(--green); }
.h-wr__s:hover { color: var(--green); }
.h-wr__clr {
  margin-left: 6px; background: none; border: 0; color: var(--muted);
  font: inherit; font-size: 11px; text-decoration: underline; cursor: pointer;
}
.h-wr__del {
  display: block; width: 100%; margin-top: 14px; padding: 9px; cursor: pointer;
  background: none; border: 1px solid var(--danger); border-radius: var(--r-md);
  color: var(--danger); font: inherit; font-size: 12.5px; font-weight: 700;
}

/* --- the About tab's rating block ---------------------------------------- */
.h-room__rate { display: flex; align-items: center; gap: 12px; margin-bottom: 6px; }
.h-room__rateN { font-size: 27px; font-weight: 800; font-family: var(--font-head); color: var(--green); }
.h-room__rateS { flex: 1; min-width: 0; }
.h-room__stars { color: var(--green); font-size: 14px; letter-spacing: 1px; display: block; }
.h-room__rateC { font-size: 11.5px; color: var(--muted); overflow-wrap: anywhere; }
.h-room__link { background: none; border: 0; color: var(--green); font: inherit; font-size: 11.5px; text-decoration: underline; cursor: pointer; }

/* `S2-02` ① — KARL: *"the More menu text and underline sit too tight to the
   buttons below"*. Measured headless at 390px: 1.00px between the label's box
   (whose last 2px ARE the underline) and the first row. Now 8.00px.
   📌 ON `[data-more-root]`, WHICH IS MARKUP `hub.js` AUTHORS, so this cannot
   reach another sheet: every other sheet's head is followed by its own body and
   never by this hook. It also survives the sub-menu, where the first child is
   the Back control rather than `.h-more` — the gap belongs under the HEAD, not
   above whichever element happens to come first. */
.h-sheet__head + [data-more-root] { margin-top: var(--sp-2); }

/* ---------------------------------------------------------------------------
   THE MORE MENU
   It was rendering as a wrapped row of grey pills because .h-wrow had no CSS
   at all — a <button> is inline-block by default, so fourteen of them flowed
   like words in a paragraph. These are rows.
   ------------------------------------------------------------------------ */
/* A GROUP NEEDS ROOM TO READ AS A GROUP. 4px between one card and the next
   section's label put five headings and fourteen rows into one undifferentiated
   column — the "disorganised" half of what this sheet looked like. */
/* `SYS-38` — THE CARD PAINT SLOTS REACH THIS LIST TOO, AND THE SURFACE HAD TO
   MOVE FOR THEM TO BE VISIBLE AT ALL.

   `SYS-04` wired `--card-edge` / `--card-tex` to `.h-grp` only, so street and
   pond painted their identity on the settings card and on nothing else. This is
   the app's only other row-stack card — bordered, radiused, clipping, children
   separated by a hairline — which I established by sweeping every stylesheet
   rather than by naming the one Karl happened to screenshot. The other three
   containers of that shape are excluded on their own merits: `.h-hero` is a
   gradient panel not a row stack, `.h-rb__msg` has no rows, and `.st-card` is
   PINNED DARK in both themes on purpose because it leaves the app as an image.

   ⛔ AND COPYING THE THREE DECLARATIONS ALONE WOULD HAVE BEEN A NO-OP THAT
   LOOKED LIKE A FIX. `.h-more` had no background of its own and its rows were
   opaque `--panel2` edge to edge, so an INSET shadow painted underneath them
   and nothing showed. Measured before and after, counting lit pixels in a
   street render: 0 green with the declarations alone, 22,208 once the surface
   moved to the container — against `.h-grp`'s 22,910. The surface belongs on
   the card here exactly as it already does on `.h-grp`; the rows keep their
   hover and their `is-soon` state and nothing moves. */
.h-more {
  border: 1px solid var(--line); border-radius: var(--r-md);
  overflow: hidden; margin-bottom: 18px;
  background: var(--panel2);
  /* AFTER the shorthand above, which resets `background-image` to none. */
  box-shadow: var(--card-edge);
  background-image: var(--card-tex);
  background-size: 9px 9px;
}
.h-more:last-child { margin-bottom: 4px; }
.h-more__row {
  display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
  /* `SYS-38`: TRANSPARENT, because the card above now carries the surface. The
     row painted its own `--panel2` edge to edge and that is what hid the card's
     inset edge. Same colour on screen, one layer further back. */
  background: none; border: 0; border-top: 1px solid var(--line);
  padding: 11px 12px; font: inherit; color: var(--ink); cursor: pointer;
  transition: background-color var(--t-fast);
}
.h-more__row:first-child { border-top: 0; }
.h-more__row:hover:not(.is-soon) { background: var(--panel); }
/* Shown, not hidden — hiding an unbuilt destination makes the app look finished
   and leaves people hunting for it. But it is shown QUIETLY: a not-yet row is
   reference material, not an offer, so it loses the coloured icon tile and sits
   at the end of its group rather than at the top competing with things that
   work.

   NOT `opacity`, which multiplies through to the text and drags it under AA —
   the same mistake the booking cards made. Each part is dimmed on its own,
   by choosing a dimmer colour. */
.h-more__row.is-soon { cursor: default; background: var(--panel2); }
.h-more__row.is-soon .h-more__t { color: var(--muted); font-weight: 600; }
.h-more__row.is-soon .h-more__s { color: var(--faint); }
.h-more__ic {
  width: 32px; height: 32px; border-radius: var(--r-sm); flex: none;
  display: grid; place-items: center; background: var(--green-dim); color: var(--green);
}
.h-more__ic svg { width: 17px; height: 17px; }
.h-more__row.is-soon .h-more__ic {
  background: transparent; color: var(--faint); border: 1px solid var(--line);
}
.h-more__main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* Explicitly block and left-aligned, so no button rule can centre it again. */
.h-more__t {
  display: block; text-align: left;
  font-weight: 700; font-size: 13.5px; overflow-wrap: anywhere;
}
.h-more__s {
  display: block; text-align: left;
  font-size: 11.5px; color: var(--muted); margin-top: 2px; line-height: 1.35;
  overflow-wrap: anywhere;
}
.h-more__go { flex: none; color: var(--muted); font-size: 17px; }

/* APPROVED GLOBAL MENU: one right-side drawer with clear scan groups. */
.h-panel--right{width:min(92%,420px);background:radial-gradient(circle at 88% 0,rgba(var(--purple-rgb),.11),transparent 28%),var(--panel)}
.h-panel--right .h-panel__head{min-height:64px;padding:14px 52px 12px 18px;position:relative}
.h-panel--right .h-panel__title{font-family:var(--head-font);font-size:22px;font-weight:var(--head-weight);letter-spacing:var(--head-track);line-height:1;text-transform:var(--head-case)}
/* V3.96 GS-03: the name under the title, same font, fit-to-width (ui.js shrinks it to 15px, then it truncates). */
.h-panel__title{min-width:0}
.h-panel__sub{display:block;margin-top:4px;font-size:22px;line-height:1.05;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.h-panel--right .h-panel__x{position:absolute;top:12px;right:14px;width:36px;height:36px;border:0;background:transparent;border-radius:50%;font-size:22px}
.h-panel--right .h-panel__body{padding:12px 14px calc(24px + env(safe-area-inset-bottom))}
.h-menu-member{display:grid;grid-template-columns:44px minmax(0,1fr) auto;align-items:center;gap:11px;width:100%;margin:0 0 18px;padding:12px;border:1px solid var(--line2);border-radius:var(--r-lg);background:linear-gradient(135deg,var(--panel2),var(--panel));color:var(--ink);font:inherit;text-align:left;cursor:pointer}
.h-menu-member__avatar{width:44px;height:44px;display:grid;place-items:center;border:2px solid var(--green);border-radius:50%;background:var(--elev);font-family:var(--head-font);font-weight:900}
.h-menu-member__avatar.has-face{background:none}
.h-menu-member__copy{min-width:0}.h-menu-member__copy b,.h-menu-member__copy small{display:block}.h-menu-member__copy b{font-size:14px}.h-menu-member__copy small{margin-top:2px;color:var(--muted);font-size:11px}
.h-menu-section{margin:0 0 19px}.h-menu-section>h2{margin:0 3px 7px;color:var(--green);font-family:var(--head-font);font-size:11px;font-weight:var(--head-weight);letter-spacing:.11em;text-transform:var(--head-case)}
.h-menu-section .h-more{margin:0}.h-menu-section .h-more__row{padding:12px}.h-menu-section .h-more__t{font-family:var(--head-font);font-size:14px;font-weight:var(--head-weight);letter-spacing:var(--head-track);text-transform:var(--head-case)}
.h-menu-footer{padding:2px 2px 8px}.h-menu-logout{display:inline-flex;align-items:center;gap:8px;padding:9px 10px;border:0;background:transparent;color:var(--muted);font:inherit;font-size:12px;font-weight:800;cursor:pointer}.h-menu-logout .h-ic,.h-menu-logout svg{width:17px;height:17px}

/* =============================================================================
   🧭 THE LAUNCH PAD WITH INDEX LIST (KARL_DECISIONS B46; Brodeur's accepted
   Member Menus design, 2026-10-10). Drawn by `H365UI.pad` for the Menu and the
   Group, Program and Game Manage drawers. Real tokens only: Impact headings,
   the green action, `--panel*` surfaces, `--r-*` radii.
   ========================================================================== */
/* a drawer drawn as the pad: its rows never push it wider than the panel */
.h-pad{min-width:0}
/* the green main action (and the quiet quick action) */
.h-pad__qa{position:relative}
.h-pad__main{margin:10px 0 0}
.h-pad__go{display:grid;grid-template-columns:auto minmax(0,1fr);column-gap:10px;align-items:center;width:100%;min-height:58px;padding:9px 12px;border:1px solid var(--action);border-radius:var(--r-xl);background:var(--action);color:var(--on-action);font:inherit;text-align:left;cursor:pointer;transition:filter var(--t-fast)}
.h-pad__go:hover{filter:brightness(1.06)}.h-pad__go:active{filter:brightness(.94)}
.h-pad__go:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.h-pad__gic{grid-row:span 2;width:38px;height:38px;border-radius:var(--r-md);display:grid;place-items:center;background:rgba(0,0,0,.12)}
.h-pad__gic svg,.h-pad__gic .h-ic{width:21px;height:21px}
.h-pad__gt{align-self:end;font-family:var(--head-font);font-weight:var(--head-weight);font-size:17px;letter-spacing:.02em;text-transform:var(--head-case);line-height:1.1}
.h-pad__gs{align-self:start;font-size:11.5px;font-weight:600;line-height:1.3}
.h-pad__go.is-solo .h-pad__gt{grid-row:span 2;align-self:center}
.h-pad__qwin{overflow:hidden;border-radius:var(--r-xl)}
.h-pad__qtrack{display:flex;transition:transform .26s cubic-bezier(.4,0,.2,1);touch-action:pan-y}
.h-pad__qtrack>.h-pad__go{flex:0 0 100%;min-width:0}
.h-pad__dots{display:flex;justify-content:center;margin:2px 0 -6px}
.h-pad__dot{width:24px;height:20px;padding:0;border:0;background:transparent;display:grid;place-items:center;cursor:pointer}
.h-pad__dot i{display:block;width:6px;height:6px;border-radius:50%;background:var(--line2)}
.h-pad__dot[aria-pressed="true"] i{background:var(--green)}
.h-pad__dot:focus-visible{outline:2px solid var(--green);outline-offset:-2px;border-radius:var(--r-sm)}
/* section tiles: two across, an odd last tile full width (Karl's rule) */
.h-pad__tiles{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:12px 0 4px}
.h-pad__tile{position:relative;display:grid;grid-template-columns:auto minmax(0,1fr);column-gap:10px;align-items:center;min-height:64px;padding:9px 10px;border:1px solid var(--line2);border-radius:var(--r-xl);background:linear-gradient(145deg,var(--panel2),var(--panel));color:var(--ink);font:inherit;text-align:left;cursor:pointer;transition:border-color var(--t-fast),background-color var(--t-fast)}
.h-pad__tile:last-child:nth-child(odd){grid-column:1/-1}
.h-pad__tile:hover{border-color:var(--muted)}
.h-pad__tile:focus-visible{outline:2px solid var(--green);outline-offset:2px}
.h-pad__tile[aria-pressed="true"]{border-color:var(--green);box-shadow:inset 0 0 0 1px var(--green)}
.h-pad__tic{grid-row:span 2;width:38px;height:38px;border-radius:var(--r-md);display:grid;place-items:center;background:linear-gradient(var(--green-dim),var(--green-dim)),var(--panel2);color:var(--green)}
.h-pad__tic svg,.h-pad__tic .h-ic{width:21px;height:21px}
.h-pad__tt{align-self:end;min-width:0;font-family:var(--head-font);font-weight:var(--head-weight);font-size:15px;letter-spacing:.02em;text-transform:var(--head-case);line-height:1.1;overflow-wrap:anywhere}
.h-pad__ts{align-self:start;color:var(--muted);font-size:11px}
.h-pad__tb{position:absolute;top:8px;right:8px}
/* the Index list: a big heading with a green rule and a count, then plain lines */
.h-ixl{margin:0 0 6px}
.h-ixl__h{display:flex;align-items:baseline;gap:10px;margin:20px 0 4px;font-family:var(--head-font);font-weight:var(--head-weight);font-size:26px;letter-spacing:.02em;text-transform:var(--head-case);line-height:1.05;scroll-margin-top:6px}
.h-ixl__h::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--green),transparent);opacity:.55}
.h-ixl__h small{order:3;font-family:var(--font-body,inherit);font-size:11px;font-weight:600;letter-spacing:.04em;color:var(--muted)}
.h-ixl__blurb{margin:-2px 0 4px;color:var(--muted);font-size:12px}
.h-ix{display:flex;align-items:center;gap:12px;width:100%;min-height:50px;padding:6px 4px;border:0;border-bottom:1px solid var(--line);background:transparent;color:var(--ink);font:inherit;text-align:left;cursor:pointer;transition:background-color var(--t-fast)}
.h-ix:hover:not(:disabled),.h-ix:active:not(:disabled){background:var(--green-dim)}
.h-ix:hover:not(:disabled) .h-ix__t{color:var(--green)}
.h-ix:focus-visible{outline:2px solid var(--green);outline-offset:-2px;border-radius:var(--r-sm)}
.h-ix__ic{flex:none;display:grid;place-items:center;color:var(--green)}
.h-ix__ic svg,.h-ix__ic .h-ic{width:20px;height:20px}
.h-ix__main{flex:1;min-width:0;display:flex;flex-direction:column}
.h-ix__t{display:block;text-align:left;font-size:15.5px;font-weight:700;line-height:1.25;overflow-wrap:anywhere}
.h-ix__s{display:block;text-align:left;margin-top:1px;color:var(--muted);font-size:12px;line-height:1.35;overflow-wrap:anywhere}
.h-ix__go{flex:none;display:grid;place-items:center;color:var(--muted)}
.h-ix__go svg,.h-ix__go .h-ic{width:16px;height:16px}
.h-ix__badge{flex:none;min-width:20px;height:20px;padding:0 6px;border-radius:var(--r-pill);display:grid;place-items:center;background:var(--danger);color:var(--bg);font-size:11px;font-weight:800}
.h-ix.is-soon{cursor:default}.h-ix.is-soon .h-ix__t{color:var(--muted);font-weight:600}.h-ix.is-soon .h-ix__s{color:var(--faint)}.h-ix.is-soon .h-ix__ic{color:var(--faint)}
/* destructive rows: red, apart at the bottom; they still open their confirmation */
.h-pad__danger{margin-top:18px;padding-top:4px;border-top:1px solid var(--line2)}
.h-ix.is-danger .h-ix__ic,.h-ix.is-danger .h-ix__t{color:var(--danger)}
.h-ix.is-danger:hover .h-ix__t{color:var(--danger)}
/* the member card at the top of the Menu: plan and family chips */
.h-menu-chips{display:flex;flex-wrap:wrap;gap:5px;margin-top:4px}
.h-menu-chip{padding:2px 8px;border:1px solid var(--line2);border-radius:var(--r-pill);color:var(--muted);font-size:9.5px;font-weight:800;letter-spacing:.07em;text-transform:uppercase}
.h-menu-chip.is-pro{border-color:var(--purple);color:var(--ink)}
.h-menu-chip.is-family{border-color:var(--green);color:var(--green)}
/* a Manage drawer's own lines */
.h-pad__for{margin:2px 4px 6px;color:var(--muted);font-size:11.5px}
.h-pad__lead{margin:0 4px 6px;color:var(--muted);font-size:13px}
@media (prefers-reduced-motion: reduce){.h-pad__qtrack,.h-pad__tile,.h-ix,.h-pad__go{transition:none}}

/* My reviews — the tabs reuse .h-seg, the cards reuse .h-rv__card. */
.h-my .h-seg { margin-bottom: 12px; }

/* ---------------------------------------------------------------------------
   TWO LAYOUT RULES, so these stop being fixed one at a time.

   1. ANY button or label that contains an icon lines its icon up with its text
      and puts a real gap between them. Karl flagged the Filters button; the
      same defect was latent on every control built the same way.
   2. A LABEL and its DESCRIPTION are separate lines. Both were inline spans in
      the setup cards, so they rendered as "ParentThings needing attention".
   ------------------------------------------------------------------------ */
/* `.h-more__t` IS NOT IN THIS LIST ANY MORE, and that was the whole bug in the
   More sheet. This rule exists to line an ICON up with its LABEL inside a
   BUTTON, so it centres its contents. A More row's title is a stacked heading
   with a left-aligned sub-line underneath it and no icon in it at all — given
   `justify-content: center` it stretched to the row width and centred itself,
   so every title floated in the middle above a left-aligned description. It
   read as broken because it was. */
/* THE CONTROL-LAYOUT RULE MOVED TO components.css IN 08-17w. It belongs with
   the components it lays out: this file is only loaded by index.html and
   staff.html, so while it lived here the login, claim, sign-in-link, email
   verify and signup-wizard pages — and kit.html, the page that documents what
   a component looks like — got a `.h-btn` with no flex centring and no `gap`.
   `.h-btn--block` was defined in BOTH files as a result, `display: block` in
   one and `display: flex` in the other, so the same class laid out two
   different ways depending on which page a member was on.
   The chip and switch selectors went with it; `.h-seg__b` did not exist in
   either file and was dropped. */
/* An icon inside a control is optically centred and never squashed. */
.h-btn .h-ic, .h-chip .h-ic, .h-room__switch .h-ic {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  line-height: 0;
}
.h-btn .h-ic svg, .h-chip .h-ic svg { display: block; }
/* A label and its sub-line always stack. */
.h-opt__n, .h-opt__s, .h-radio__t, .h-radio__s { display: block; }
.h-opt__s, .h-radio__s { margin-top: 2px; line-height: 1.35; }

/* --- the referee radio pair ---------------------------------------------- */
.h-radio { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; }
.h-radio__o {
  display: flex; align-items: flex-start; gap: 10px; width: 100%; text-align: left;
  background: var(--panel2); border: 1.5px solid var(--line2); border-radius: var(--r-md);
  padding: 11px 12px; font: inherit; color: var(--ink); cursor: pointer;
}
.h-radio__o.is-on { border-color: var(--green); background: var(--green-dim); }
.h-radio__dot {
  width: 18px; height: 18px; border-radius: 50%; flex: none; margin-top: 1px;
  border: 2px solid var(--line2); background: transparent;
}
.h-radio__o.is-on .h-radio__dot { border-color: var(--green); box-shadow: inset 0 0 0 3.5px var(--green); }
.h-radio__t { font-weight: 700; font-size: 13.5px; }
.h-radio__s { font-size: 11.5px; color: var(--muted); font-weight: 500; }

/* Setup help text can report success or failure, not just explain. */
.h-help.is-bad { color: var(--danger); }
.h-help.is-good { color: var(--green); }
.pill__x { background: none; border: 0; color: inherit; cursor: pointer; margin-left: 6px; font-size: 13px; padding: 0 2px; }

/* The About tab's rating, as a hero rather than another paragraph. */
/* `S2-02` ③④ — KARL: *"on a room space, rating sits a bit too tight to the
   rating section below and the green line actually touches the button"*.
   BOTH HALVES ARE ONE FACT. `base.css` paints `.h-sec-label`'s rule as a
   background at `0 100%` — the last 2px of the label's own box — and gives the
   label `margin: 0`. Measured headless: "Rating" bottom to hero top was 0.00px,
   so the rule was not NEAR the block below it, it was ON it.
   ⛔ ON THE SIBLING PAIR, NOT ON `.h-sec-label`. The label is emitted by 23
   files and a bottom margin there is the app-wide row, not this one. */
.h-sec-label + .h-room__hero { margin-top: var(--sp-2); }
.h-room__hero {
  display: flex; align-items: center; gap: 15px; margin-bottom: 10px;
  background: var(--panel); border: 1px solid var(--line2); border-radius: var(--r-lg);
  padding: 14px;
}
.h-room__heroc { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; align-items: flex-start; }
.h-room__pending { font-size: 11px; color: var(--faint); overflow-wrap: anywhere; }

/* ==========================================================================
   SKILL RATINGS — the roster pill and the player-record sheet
   ========================================================================== */

/* A member's rating in THIS group, on the roster row. Two pills for a two-way
   member; `flex: none` so a long name shrinks before the number does. */
.h-mrow__rates { display: flex; gap: 4px; flex: none; }
.h-rpill {
  display: inline-flex; align-items: baseline; gap: 3px;
  background: var(--panel2); border: 1px solid var(--line2);
  border-radius: var(--r-pill); padding: 3px 8px; line-height: 1;
}
.h-rpill b { font-size: 12.5px; font-weight: 800; color: var(--ink); }
.h-rpill i { font-style: normal; font-size: 9.5px; font-weight: 800; color: var(--faint); letter-spacing: .06em; }
/* A number built from half the attributes is a guess, and it says so rather
   than sitting next to somebody's name looking measured. */
.h-rpill.is-partial { border-style: dashed; }
.h-rpill.is-partial b { color: var(--muted); }

.h-sk { padding: 10px 0; border-bottom: 1px solid var(--line); }
.h-sk .h-skill { margin-bottom: 4px; }
.h-sk:last-of-type { border-bottom: 0; }
.h-sk__h { display: flex; align-items: center; gap: 8px; min-width: 0; }
.h-sk__l { font-size: 13px; font-weight: 700; flex: 1; min-width: 0; }
.h-sk__tag {
  flex: none; font-size: 9.5px; font-weight: 800; letter-spacing: .04em;
  text-transform: uppercase; border-radius: var(--r-pill); padding: 2px 7px;
  border: 1px solid var(--line2); color: var(--faint);
}
/* Three states, three looks. An organiser has to be able to tell at a glance
   which numbers are theirs and which are the member's own, because that is
   the difference between editing an assessment and overriding a person. */
.h-sk__tag.is-inherit { color: var(--muted); border-style: dashed; }
.h-sk__tag.is-set { color: var(--green); border-color: var(--green); }
.h-sk__tag.is-none { opacity: .7; }
.h-sk__range { width: 100%; margin: 7px 0 3px; accent-color: var(--green); }
.h-sk__range[disabled] { opacity: .55; }
.h-sk__f { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.h-sk__hint { flex: 1; min-width: 0; font-size: 11px; color: var(--faint); }
.h-sk__clear {
  flex: none; background: none; border: 0; padding: 0; font: inherit; font-size: 11px;
  font-weight: 700; color: var(--muted); text-decoration: underline; cursor: pointer;
}
.h-sk__clear:hover { color: var(--green); }
.h-sk__ov {
  margin-left: 6px; font-size: 12px; font-weight: 800; color: var(--green);
  font-variant-numeric: tabular-nums;
}
.h-sk__part { margin-left: 6px; font-size: 10px; font-weight: 600; color: var(--faint); text-transform: none; }
/* Walk v54 (Karl): their own rating (the baseline) above the sliders, and Calibrate. */
.h-skbase { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin: 2px 0 6px;
  padding: 8px 10px; border: 1px dashed var(--line2); border-radius: var(--r-md); }
.h-skbase__k { font-size: 12px; font-weight: 700; color: var(--muted); }
.h-skbase__v { font-size: 13px; font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }
.h-skbase__cal { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; margin: 0 0 10px; }
.h-skbase__cal .h-lr__hint { margin: 0; }
.h-skcaltip { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 600; color: var(--green); }
.h-skcaltip .h-ic { width: 13px; height: 13px; flex: none; }

/* The row that opens the ratings sheet. */
.h-frow__sub { display: block; font-size: 11px; font-weight: 600; color: var(--faint); margin-top: 2px; }
/* `GAME-09` - A NESTED SWITCH READS AS A CHILD OR IT READS AS A SECOND
   UNRELATED QUESTION. The indent and the rule down the left are the whole
   signal that "and they skip the spares wait" belongs to the switch above it.
   `[hidden]` still wins because this sets no `display`. */
.h-frow__nest { padding-left: 14px; border-left: 2px solid var(--line2); margin-left: 4px; }
.h-frow__go { flex: none; color: var(--faint); font-size: 17px; line-height: 1; }

/* ==========================================================================
   MONEY — the treasurer's three tabs, and every member's own balance
   ========================================================================== */

.h-mtot { display: flex; gap: 8px; margin-bottom: 12px; }
.h-mtot__c {
  flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 11px 10px;
}
/* Money IN and money OUT are tinted differently on purpose. A group that rents
   a goalie has two numbers that must never be read as one, and the live app
   presents both in the same list. */
.h-mtot__c.is-in  { border-color: color-mix(in srgb, var(--green) 45%, var(--line)); }
.h-mtot__c.is-out { border-color: color-mix(in srgb, var(--warn-solid) 45%, var(--line)); }
.h-mtot__v { font-size: 16px; font-weight: 800; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.h-mtot__c.is-in .h-mtot__v  { color: var(--green); }
.h-mtot__c.is-out .h-mtot__v { color: var(--warn-solid); }
.h-mtot__l { font-size: 10.5px; color: var(--muted); font-weight: 600; line-height: 1.25; }

.h-seg__n {
  display: inline-block; min-width: 16px; padding: 0 4px; margin-left: 4px;
  border-radius: var(--r-pill); background: var(--panel2); color: var(--muted);
  font-size: 10px; font-weight: 800;
}

.h-mperson { display: block; padding: 0; }
.h-mperson__h {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: none; border: 0; padding: 10px 0; font: inherit; color: var(--ink);
  text-align: left; cursor: pointer;
}
.h-mperson__c { flex: none; color: var(--faint); font-size: 16px; transition: transform .15s; }
.h-mperson.is-open .h-mperson__c { transform: rotate(90deg); }
.h-mperson__b { padding: 0 0 10px; }
.h-mamt { flex: none; font-size: 14px; font-weight: 800; font-variant-numeric: tabular-nums; }
.h-mamt.is-in  { color: var(--green); }
.h-mamt.is-out { color: var(--warn-solid); }

.h-mline {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 0 8px 10px; border-left: 2px solid var(--line2);
}
.h-mline.is-settled { opacity: .55; }
.h-mline__m { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.h-mline__t { font-size: 12.5px; font-weight: 700; }
.h-mline__s { font-size: 10.5px; color: var(--faint); overflow-wrap: anywhere; }
.h-mline__a { flex: none; font-size: 12.5px; font-weight: 800; font-variant-numeric: tabular-nums; }

/* A member's own balance, as a statement rather than a table row. */
.h-mme {
  display: flex; flex-direction: column; gap: 3px; padding: 14px;
  background: var(--panel); border: 1px solid var(--line2); border-radius: var(--r-lg);
  margin-bottom: 10px;
}
.h-mme__l { font-size: 11.5px; color: var(--muted); font-weight: 700; }
.h-mme__v { font-size: 21px; font-weight: 800; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.h-mme.is-owing { border-color: var(--warn-solid); }
.h-mme.is-owing .h-mme__v { color: var(--warn-solid); }
.h-mme.is-out .h-mme__v { color: var(--green); }

.h-mfacts { display: flex; gap: 8px; margin-bottom: 12px; }
.h-mfacts span {
  flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px;
  background: var(--panel2); border-radius: var(--r-md); padding: 9px 10px;
  font-size: 10.5px; color: var(--muted); font-weight: 600;
}
.h-mfacts b { font-size: 14px; color: var(--ink); font-variant-numeric: tabular-nums; }

.h-mlog { display: flex; align-items: center; gap: 9px; padding: 7px 0; border-bottom: 1px solid var(--line); }
.h-mlog:last-of-type { border-bottom: 0; }
.h-mlog__a { flex: none; font-size: 12.5px; font-weight: 800; font-variant-numeric: tabular-nums; }
.h-mlog__m { flex: 1; min-width: 0; font-size: 10.5px; color: var(--faint); overflow-wrap: anywhere; }
/* A reversal stays visible and struck through. A ledger you can quietly remove
   rows from is not a ledger. */
.h-mlog.is-rev { opacity: .6; }
.h-mlog.is-rev .h-mlog__a { text-decoration: line-through; }
.h-mlog__x {
  flex: none; background: none; border: 0; padding: 0; font: inherit; font-size: 10.5px;
  font-weight: 700; color: var(--muted); text-decoration: underline; cursor: pointer;
}
.h-mlog__x:hover { color: var(--danger); }

/* --- season passes -------------------------------------------------------
   A pass row is a ledger line with a status on it, so it reuses `.h-mline`
   rather than inventing a second row shape for the same idea. What it adds is
   the actions drawer underneath. */
.h-mpass__sell { margin-top: 14px; }
.h-mpass__acts {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 10px 0 12px; border-bottom: 1px solid var(--line);
}
.h-mpass__acts .h-lr__hint { flex: 1 1 100%; margin: 2px 0 0; }
/* A CANCELLED PASS STAYS ON THE SCREEN, dimmed, the same way a reversed
   payment does. It is a decision that was made, not a row that stopped
   existing, and a treasurer needs to see that it was made. */
.h-mpass.is-settled .h-mline__a { text-decoration: line-through; }

.h-lr__gap { color: var(--warn-solid); }
/* `.h-mback` RETIRED ON 2026-09-17, Meryl, `Q-02`. Seven buttons in money.js
   and waivers.js wore it; they now wear the shared `.h-back` in components.css,
   which is ONE body for what used to be six. */

/* ==========================================================================
   WAIVERS — the member's list, the text, and the organiser's roster
   ========================================================================== */

.h-wrowi {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: none; border: 0; border-bottom: 1px solid var(--line);
  padding: 11px 0; font: inherit; color: var(--ink); text-align: left; cursor: pointer;
}
.h-wrowi:last-of-type { border-bottom: 0; }
.h-wrowi__m { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.h-wrowi__t { font-size: 13.5px; font-weight: 700; overflow-wrap: anywhere; }
.h-wrowi__s { font-size: 11px; color: var(--faint); overflow-wrap: anywhere; }
.h-wrowi__go { flex: none; color: var(--faint); font-size: 17px; line-height: 1; }
/* A waiver whose text changed under a signature. Not an error — the person did
   sign — so it is amber rather than red. */
.h-wrowi.is-stale { border-left: 3px solid var(--warn-solid); padding-left: 9px; }
/* LR-09 second walk: the person My Waivers was opened for — first, and marked. */
.h-wrowi.is-focus { border-left: 3px solid var(--green); padding-left: 9px; background: color-mix(in srgb, var(--green) 8%, transparent); }

.h-wv__h { display: flex; flex-direction: column; gap: 2px; margin-bottom: 12px; }
.h-wv__t { font-size: 17px; font-weight: 800; overflow-wrap: anywhere; }
.h-wv__v { font-size: 11.5px; color: var(--muted); }
.h-wv__stale {
  margin: 0 0 12px; padding: 10px 12px; border-radius: var(--r-md);
  background: var(--panel2); border: 1px solid var(--warn-solid);
  font-size: 12px; color: var(--ink);
}

/* The waiver ITSELF, as readable text. The live app renders a PDF into a
   canvas with a lazy-loaded PDF.js — unreadable on a phone, unsearchable, and
   impossible to diff when the wording changes. */
.h-wv__body {
  max-height: 46vh; overflow-y: auto; -webkit-overflow-scrolling: touch;
  background: var(--panel); border: 1px solid var(--line2); border-radius: var(--r-lg);
  padding: 14px; margin-bottom: 14px;
}
.h-wv__body p { margin: 0 0 11px; font-size: 13px; line-height: 1.55; overflow-wrap: anywhere; }
.h-wv__body p:last-child { margin-bottom: 0; }

/* The typed signature. Cursive on purpose — it reads as a mark rather than as
   another form field, which is the one thing the drawn-canvas version got
   right. */
.h-wv__sig {
  font-family: Georgia, 'Times New Roman', serif; font-style: italic;
  font-size: 19px; letter-spacing: .01em;
}
.h-wv__consent { align-items: flex-start; }
.h-wv__consent span { font-size: 12.5px; line-height: 1.45; }
.h-wv__edit { font-size: 16px /* SYS-07: was 12.5px; under 16 the field zooms iOS */; line-height: 1.5; min-height: 220px; }

/* The organiser's roster. One dot per person, three states. */
.h-wtrack { border-left-width: 3px; }
.h-wtrack__dot { flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--line2); }
.h-wtrack.is-signed { border-left-color: var(--green); }
.h-wtrack.is-signed .h-wtrack__dot { background: var(--green); }
.h-wtrack.is-stale { border-left-color: var(--warn-solid); }
.h-wtrack.is-stale .h-wtrack__dot { background: var(--warn-solid); }
.h-wtrack.is-pending { border-left-color: var(--danger); }
.h-wtrack.is-pending .h-wtrack__dot { background: var(--danger); }
/* A roster entry with no account CANNOT sign. Drawn as absent rather than as
   outstanding, so nobody chases a name that will never clear. */
.h-wtrack.is-no-account { opacity: .55; }
.h-wtrack.is-no-account .h-wtrack__dot { background: transparent; border: 1px dashed var(--line2); }

.h-tag--draft     { color: var(--muted); }
.h-tag--published { color: var(--green); border-color: var(--green); }
.h-tag--archived  { color: var(--faint); opacity: .8; }

/* === WAIVERS: sections, the initials tag, and the signature pad =============
   Added V1.1 (08-07) with the client's draw pad + review gate. All on the
   shared tokens; nothing hard-codes a colour that has to be re-derived per
   theme. */

/* (.h-wv__body is declared once, further up — this was a verbatim duplicate) */
.h-wv__intro { margin: 0 0 14px; font-size: 13px; line-height: 1.55; color: var(--muted); }
.h-wv__sec { margin: 0 0 16px; }
.h-wv__sec:last-child { margin-bottom: 0; }
.h-wv__sech {
  margin: 0 0 6px; font-size: 12px; font-weight: 700; letter-spacing: .02em;
  text-transform: uppercase; color: var(--muted);
}
/* A clause that needs initials is marked before you reach it, not after you
   fail to submit. */
.h-wv__sec.is-init {
  border-left: 2px solid var(--green); padding-left: 12px;
}

.h-wv__init {
  display: inline-block; margin-top: 8px; min-width: 108px; min-height: 44px;
  padding: 8px 14px; border-radius: var(--r-sm); cursor: pointer;
  border: 1px dashed var(--green); background: transparent;
  color: var(--green); font: 600 13px/1.2 inherit; letter-spacing: .04em;
}
.h-wv__init.is-on {
  border-style: solid; background: var(--green); color: var(--on-green);
  font-family: 'Snell Roundhand', 'Brush Script MT', 'Segoe Script', cursive;
  font-size: 20px; font-style: italic; letter-spacing: 0;
}
.h-wv__init.is-ghost {
  border-style: dotted; color: var(--faint); cursor: default; min-height: 0; padding: 4px 10px;
  font-size: 11px;
}

.h-wv__tabs { display: flex; gap: 6px; margin: 4px 0 10px; }
.h-wv__tab {
  flex: 1; min-height: 44px; padding: 10px 12px; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: transparent;
  color: var(--muted); font: 600 13px/1.2 inherit;
}
.h-wv__tab.is-on { border-color: var(--green); color: var(--green); }

.h-wv__pane[hidden] { display: none; }
.h-wv__canvas {
  display: block; width: 100%; height: 180px; margin-bottom: 8px;
  background: #fff; /* raw-colour: exported as-is onto a certificate */ /* a signature is ink on white in BOTH themes:
                                       the PNG is exported as-is and ends up on a
                                       certificate, where a dark card would print
                                       as a black rectangle */
  border: 1px solid var(--line); border-radius: var(--r-sm);
  touch-action: none;               /* without this a drag scrolls the sheet
                                       instead of drawing, on every phone */
  cursor: crosshair;
}
.h-wv__typed {
  min-height: 96px; display: flex; align-items: center; justify-content: center;
  padding: 12px; margin-bottom: 8px;
  background: #fff; color: #111; /* raw-colour: must match the signature PNG this previews */ border: 1px solid var(--line); border-radius: var(--r-sm);
  font-family: 'Snell Roundhand', 'Brush Script MT', 'Segoe Script', cursive;
  font-style: italic; font-size: 34px; line-height: 1.2; overflow-wrap: anywhere;
}

@media (prefers-reduced-motion: reduce) {
  .h-wv__init, .h-wv__tab { transition: none; }
}

/* === MILESTONES (V1.3) =====================================================
   A ladder is one card, not ten. See the note at the top of milestones.js. */

.h-ms__list { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }

/* SECTIONS (Goalie / Player / For everyone / Your own goals). Ordered by the
   member's own athlete record; a heading, never a control — the milestones.js
   header carries the reasoning and Karl's ruling.

   ⚠️ `.h-sec-label` SETS `margin: 0` DESPITE THE COMMENT ABOVE IT IN base.css
   PROMISING "generous above, tight below", so that rhythm has to be written
   here — and the 12px on `.h-ms__list` works AGAINST it: unqualified it pushes
   each list away from its own heading and leaves the next heading glued to the
   card above. Both halves are set rather than one, because fixing only the gap
   that looks wrong is how a heading ends up reading as a caption of the
   section BEFORE it.

   The first section keeps the old 12px so a one-section screen and a sectioned
   screen start at the same place under the tabs — and that is written as an
   ADJACENT-SIBLING rule, not `:first-of-type`. `:first-of-type` matches on the
   ELEMENT NAME, and the first `div` in this body is the tab strip; it would
   have matched nothing here and every section would have carried 20px. */
.h-ms__sec { margin-top: 12px; }
.h-ms__sec + .h-ms__sec { margin-top: 20px; }
.h-ms__sec .h-ms__list { margin-top: 6px; }

.h-ms__card {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--panel2);
}
.h-ms__card.is-done { border-color: var(--green); }

.h-ms__ic { flex: 0 0 auto; width: 26px; height: 26px; color: var(--muted); }
.h-ms__card.is-done .h-ms__ic { color: var(--green); }

.h-ms__t { font-weight: 700; font-size: 14px; display: flex; align-items: baseline; gap: 8px; }
.h-ms__tier {
  font-size: 11px; font-weight: 600; color: var(--muted);
  border: 1px solid var(--line); border-radius: var(--r-pill); padding: 1px 7px;
}
.h-ms__s { margin-top: 2px; font-size: 11.5px; color: var(--muted); }

.h-ms__bar {
  margin-top: 8px; height: 6px; border-radius: var(--r-pill);
  background: var(--line); overflow: hidden;
}
.h-ms__bar > span {
  display: block; height: 100%; border-radius: var(--r-pill);
  background: var(--green);
  /* A bar that animates on every repaint reads as the number changing when it
     has not. Only a real change moves it, and reduced-motion stops it dead. */
  transition: width .35s ease;
}
@media (prefers-reduced-motion: reduce) { .h-ms__bar > span { transition: none; } }

/* +1 / +10 stacked on a phone, side by side with room. 44px each, because
   these are tapped with gloves on at a rink. */
.h-ms__acts { display: flex; flex-direction: column; gap: 6px; flex: 0 0 auto; }
.h-ms__acts .h-btn { min-height: 44px; min-width: 56px; }
/* Track / Hide. A ROW, not a column, and quieter than the counters beside it:
   these change what the LIST shows, where +1 and +10 change the thing itself. */
.h-ms__flags { display: flex; gap: 6px; flex: 0 0 auto; flex-wrap: wrap; }
.h-ms__flags .h-btn { min-height: 36px; font-size: 11.5px; opacity: .85; }

.h-ms__form { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }

/* === MESSAGES — THE LEAN MESSENGER (V1.4) ==================================
   PORTED, NOT REDESIGNED. The geometry, the two-phase resize, the grip handle
   and the deliberately-different accent all come from the FileMaker original
   (`System::Chat CSS` + the resize block in `System::Chat Engine JS`). Karl
   built that window and asked for it back as-is; the numbers below are his.

   THE POINT OF THE THING: it is a DOCK, not a sheet. Fixed to the right edge,
   full height, and — critically — there is NO SCRIM. The page behind stays
   live and clickable, which is why you can read a game sheet and talk about it
   at the same time. Adding a backdrop here would quietly destroy the feature.

   The accent is #3b82f6, which is neither BreakAway Green nor Power Play
   Purple ON PURPOSE. The messenger is supposed to read as a separate surface
   sitting on top of the app, and the colour is what sells that.

   ONE HOME since 2026-09-25: the Hub's inline Messages section is gone, and
   this dock is the Messenger everywhere. It begins below the top nav.
   ========================================================================= */

.h-dock {
  /* THE DOCK REDIRECTS THE COMPONENT NAMES INTO THE THEME FAMILY — the same
     move `.h-chrome` makes (`--panel: var(--chrome-panel)`), for the same
     reason. The VALUES and the contrast reasoning that justifies each of them
     now live in `tokens.css` as `--dock-*`, so a new style can supply them;
     the `--hc-*` names and all 95 uses below are untouched.

     THIS IS A REDIRECT AND NOT A MERGE, AND THAT DISTINCTION IS LOad-BEARING.
     The messenger HAD TWO HOMES until 2026-09-25: this dock, and the Hub's
     inline Messages section (now removed), which declared no `--hc-*` and so
     falls through to the page-token fallbacks written as the second argument of
     every `--hc-*` reference below (53 of them) — it BLENDS into the Hub on
     purpose, because it is a section of the page rather than a panel floating
     over it. (The fallback form is described in words rather than written out,
     because `tests/tokens.test.mjs` reads comments too and flagged the example
     this paragraph first carried — the same trap `stats.css` documents four
     lines above its own workaround, and the eighth time this tree has counted
     prose as code.) Declaring this
     family at `:root` would have handed the inline section the dock's blue-grey
     surfaces and silently restyled the Hub. Vera, 2026-09-04. */
  --hc-accent:        var(--dock-accent);
  --hc-accent-strong: var(--dock-accent-strong);
  --hc-accent-text:   var(--dock-accent-text);
  --hc-accent-ink:    var(--dock-accent-ink);
  --hc-surface:       var(--dock-surface);
  --hc-surface-2:     var(--dock-surface-2);
  --hc-raised:        var(--dock-raised);
  --hc-text:          var(--dock-ink);
  --hc-muted:         var(--dock-muted);
  --hc-border:        var(--dock-line);
  --hc-dock-w:     400px;   /* CONTENT width  — what the panel actually is */
  --hc-slide:      0px;     /* how far it is pushed off the right edge */
  --hc-top:        0px;     /* the app bar's bottom edge; chat.js measures it */
  --hc-ease:       cubic-bezier(.22,.61,.36,1);

  /* BELOW THE NAV. `--hc-top` is the app bar's measured bottom edge, set by
     chat.js on open and on resize; 0 where a page has no bar. */
  position: fixed; top: var(--hc-top); right: 0; bottom: 0;
  width: var(--hc-dock-w);
  transform: translateX(var(--hc-slide, 0px));
  z-index: 9000;
  display: flex;
  color: var(--hc-text);
  /* THE CLIP IS WHAT MAKES IT SLIDE FROM UNDER THE NAV rather than over it:
     the panel travels down inside this box, and nothing above the box's top
     edge — the nav — is ever painted over. */
  overflow: hidden;
}
/* OPEN slides the contents down; CLOSE slides them back up, then chat.js
   hides the dock. Both on the children, inside the clip above. */
.h-dock:not([hidden]) > * { animation: h-dock-in .24s var(--hc-ease) both; }
.h-dock.is-closing > * { animation: h-dock-out .2s var(--hc-ease) both; }
/* 🧱 A QUESTION ASKED FROM INSIDE THE DOCK MUST BE SEEN (B62 pre-walk,
   2026-10-04, Nolan). The dock is fixed at z-index 9000; H365UI's scrim,
   sheet and toast sit at 50 / 51 / 60 inside .h-app (components.css). On a
   phone the dock covers the screen, so Remove someone, Leave, Delete a
   message and Block asked a question nobody could see, and nothing happened.
   While the dock is open, an OPEN sheet, its scrim and the toast go above it.
   Nothing changes while the dock is closed. */
body:has(> .h-dock:not([hidden])) .h-scrim.is-open { z-index: 9001; }
body:has(> .h-dock:not([hidden])) .h-sheet.is-open { z-index: 9002; }
body:has(> .h-dock:not([hidden])) .h-toast { z-index: 9003; }
/* THE `[data-theme="light"] .h-dock` BLOCK THAT STOOD HERE IS GONE. Its seven
   values are now the light half of the `--dock-*` family in `tokens.css`, and
   the redirect above picks them up. Second theme-scoped selector removed today
   for the same reason as the first: such a selector matches whenever any
   ANCESTOR is light, while the tokens beside it resolve from the NEAREST theme
   scope, and nesting the two makes them disagree. Same defect
   `--warn-ink-on-wash` exists to fix. */

.h-dock[hidden] { display: none; }
.h-dock [hidden] { display: none; }
.h-dock[data-mode="full"] { width: 100%; }

/* Transitions are enabled only AFTER the first paint (so opening plays the
   slide-in keyframe instead of animating from width:0), and turned OFF again
   mid-drag so the panel tracks the pointer with no lag. */
.h-dock.is-ready    { transition: width .2s var(--hc-ease), transform .2s var(--hc-ease); }
.h-dock.is-resizing { transition: none; }

@keyframes h-dock-in  { from { transform: translateY(-100%); } to { transform: none; } }
@keyframes h-dock-out { from { transform: none; } to { transform: translateY(-100%); } }
@keyframes h-dock-fade-in  { from { opacity: 0; } to { opacity: 1; } }
@keyframes h-dock-fade-out { from { opacity: 1; } to { opacity: 0; } }

/* REDUCED MOTION: no travel, a short fade — the state change still reads.
   `data-motion="off"` (the app's own switch) already stops every animation in
   components.css, and chat.js hides at once rather than waiting on one. */
@media (prefers-reduced-motion: reduce) {
  .h-dock:not([hidden]) > * { animation: h-dock-fade-in .12s linear both; }
  .h-dock.is-closing > * { animation: h-dock-fade-out .12s linear both; }
}

/* NARROW: THE MESSENGER OWNS THE WIDTH. Karl, 2026-09-25 — on a phone it
   takes the full content width beneath the nav and shows one screen at a
   time (the dock is one pane by construction; see `.h-ch--dock`). No grab
   handle and no Maximize: there is nothing to resize against. The rail's
   width is left in state untouched, so a tablet turned sideways gets the
   member's own width back. 700px is the breakpoint the messenger has always
   used for its phone layout. */
@media (max-width: 700px) {
  .h-dock, .h-dock[data-mode="full"] { width: 100%; max-width: none; transform: none; }
  .h-dock__grab { display: none; }
  .h-dock [data-ch-max] { display: none; }
  .h-dock__panel { border-left: 0; }
}

/* ---- the grab handle ----------------------------------------------------
   An 18px strip down the left edge with a centred grip pill that brightens
   and grows on hover or drag. `touch-action: none` is what makes the drag
   work on a phone — without it the browser claims the gesture for scrolling. */
.h-dock__grab {
  position: relative;
  width: 18px; flex: 0 0 18px;
  cursor: ew-resize;
  background: transparent;
  touch-action: none;
}
.h-dock__grab::before {
  content: '';
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 5px; height: 33%;
  min-height: 48px; max-height: 130px;
  border-radius: var(--r-pill);
  background: var(--hc-border);
  box-shadow: var(--sh-hairline);
  transition: background .16s var(--hc-ease), width .16s var(--hc-ease), height .16s var(--hc-ease);
}
.h-dock__grab:hover::before,
.h-dock__grab.is-dragging::before { background: var(--hc-accent); width: 6px; height: 38%; }
.h-dock[data-mode="full"] .h-dock__grab { display: none; }

.h-dock__panel {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
  background: var(--hc-surface);
  border-left: 1px solid var(--hc-border);
  box-shadow: var(--sh-dock);
}

/* ---- header ------------------------------------------------------------- */
.h-dock__hd {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; min-height: 56px;
  border-bottom: 1px solid var(--hc-border);
}
.h-dock__title {
  flex: 1 1 auto; min-width: 0; font-weight: 800; font-size: 15.5px;
  /* A long group name truncates rather than shoving the actions off the end —
     which is what made this bar read as cramped. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.h-dock__acts { flex: 0 0 auto; display: flex; align-items: center; gap: 4px; }

/* Back sits at the LEFT EDGE, where a back control belongs, and is part of the
   one header rather than a second bar underneath it. */
.h-dock__back {
  flex: 0 0 auto; width: 32px; height: 32px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%; background: transparent;
  color: var(--hc-text); cursor: pointer;
}
.h-dock__back:hover { background: var(--hc-raised); }
.h-dock__back .h-ic { width: 20px; height: 20px; }

.h-dock__btn {
  height: 32px; min-width: 32px; padding: 0 10px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--hc-border); border-radius: var(--r-pill);
  background: var(--hc-raised); color: var(--hc-text);
  font-size: 12.5px; font-weight: 600; cursor: pointer;
}
/* Icon buttons are round and borderless — five bordered pills in a row is what
   made the bar look packed. */
.h-dock__btn--icon {
  width: 32px; padding: 0; border-color: transparent; background: transparent;
  color: var(--hc-muted);
}
.h-dock__btn--icon:hover { background: var(--hc-raised); color: var(--hc-text); }
.h-dock__btn--icon .h-ic { width: 18px; height: 18px; }
/* The expand/restore mark is a CHARACTER, not an SVG, so it scales with
   font-size — bigger glyph inside the same 32px button. */
.h-dock__glyph { font-size: 21px; line-height: 1; font-weight: 400; }
.h-dock__btn:hover { border-color: var(--hc-accent); }
.h-dock__btn--accent {
  background: var(--hc-accent-strong); border-color: var(--hc-accent-strong);
  color: var(--hc-accent-ink);
}
.h-dock__body { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }

/* ---- the empty state ----------------------------------------------------
   THIS is what was missing padding. Centred, generous, and it ends in an
   action — an empty state that does not tell you how to leave it is a
   dead end wearing a polite sentence. */
.h-ch__empty {
  flex: 1 1 auto;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 6px;
  padding: 40px 24px; text-align: center; color: var(--hc-muted, var(--muted));
}
.h-ch__empty-t { font-size: 15px; font-weight: 700; color: var(--hc-text, var(--ink)); }
.h-ch__empty-s { font-size: 13px; max-width: 280px; line-height: 1.5; }
.h-ch__empty-cta { margin-top: 12px; }
/* IN THE MESSENGER the empty inbox's "Start a message" is ITS New button, so
   it wears the Messenger's blue rather than the app's green. */
.h-dock .h-ch__empty-cta {
  background: var(--hc-accent-strong); border-color: var(--hc-accent-strong);
  color: var(--hc-accent-ink);
}

/* ---- THE INBOX TOOLS ----------------------------------------------------
   Search that is always there, the filter beside it, New at the end — one
   row, the approved layout. The search shell glows as ONE control on focus;
   the input inside it draws no outline of its own (the detached green ring is
   what the design rules out). 16px text: the zoom floor. */
.h-ch__tools {
  flex: 0 0 auto; display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; border-bottom: 1px solid var(--hc-border, var(--line));
}
.h-ch__ibfield {
  position: relative; flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: 8px; height: 42px; padding: 0 12px;
  border: 1px solid var(--hc-border); border-radius: var(--r-md);
  background: var(--hc-surface-2); color: var(--hc-muted); cursor: text;
  transition: border-color .15s var(--hc-ease), box-shadow .15s var(--hc-ease);
}
.h-ch__ibfield .h-ic { flex: 0 0 auto; width: 17px; height: 17px; }
.h-ch__ibfield .h-input {
  flex: 1 1 auto; min-width: 0; height: 100%; padding: 0;
  border: 0; background: transparent; box-shadow: none; color: var(--hc-text);
  font-size: 16px;
}
.h-ch__ibfield .h-input:focus, .h-ch__ibfield .h-input:focus-visible { outline: none; box-shadow: none; }
.h-ch__ibfield:focus-within {
  border-color: var(--hc-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--hc-accent) 28%, transparent);
}
.h-ch__newbtn {
  flex: 0 0 auto; height: 42px; min-width: 42px; padding: 0 12px;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  border: 1px solid var(--hc-accent-strong); border-radius: var(--r-md);
  background: var(--hc-accent-strong); color: var(--hc-accent-ink);
  font-size: 13px; font-weight: 700; white-space: nowrap; cursor: pointer;
}
.h-ch__newbtn .h-ic { width: 17px; height: 17px; }

/* THE FILTER LISTBOX: a compact trigger that says what is showing, and a
   short list with the current option checked. The list floats over the rows
   below rather than pushing them down. */
.h-ch__filter { position: relative; flex: 0 0 auto; }
.h-ch__filterbtn {
  height: 42px; padding: 0 10px 0 12px; max-width: 150px;
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--hc-border); border-radius: var(--r-md);
  background: var(--hc-surface-2); color: var(--hc-text);
  font-size: 13px; font-weight: 600; white-space: nowrap; cursor: pointer;
}
.h-ch__filterl { overflow: hidden; text-overflow: ellipsis; }
.h-ch__filterbtn .h-ic { flex: 0 0 auto; width: 16px; height: 16px; color: var(--hc-muted); }
.h-ch__filter.is-open .h-ch__filterbtn { border-color: var(--hc-accent); }
.h-ch__filterlist {
  position: absolute; z-index: 5; top: calc(100% + 6px); right: 0; min-width: 180px;
  display: flex; flex-direction: column; padding: 4px;
  border: 1px solid var(--hc-border); border-radius: var(--r-md);
  background: var(--hc-raised); box-shadow: var(--sh-dock);
}
.h-ch__filteropt {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 40px; padding: 0 10px; border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--hc-text); font-size: 14px; text-align: left;
  cursor: pointer;
}
.h-ch__filteropt:hover, .h-ch__filteropt:focus-visible { background: var(--hc-surface-2); }
.h-ch__filteropt .h-ic { width: 16px; height: 16px; color: var(--hc-accent-text); visibility: hidden; }
.h-ch__filteropt.is-on { font-weight: 700; }
.h-ch__filteropt.is-on .h-ic { visibility: visible; }

/* THE SMALLEST PHONES: New drops its word and keeps its name (aria-label),
   so the row never wraps at the 320px floor. */
@media (max-width: 380px) {
  .h-ch__newl { display: none; }
  .h-ch__newbtn { padding: 0; width: 42px; }
  .h-ch__filterbtn { max-width: 118px; }
}

/* ---- the New view ------------------------------------------------------- */
.h-ch__search { flex: 0 0 auto; padding: 10px 14px; border-bottom: 1px solid var(--hc-border, var(--line)); }
.h-ch__search .h-input { width: 100%; }
.h-ch__people { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 6px; }
.h-ch__person {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 10px; min-height: 44px; cursor: pointer;
  background: transparent; border: 0; border-radius: var(--r-md); color: inherit;
}
.h-ch__person:hover { background: var(--hc-raised, var(--panel2)); }
.h-ch__person-n { font-weight: 700; font-size: 13.5px; }

/* ---- New view: Direct / Group ------------------------------------------- */
.h-ch__seg {
  flex: 0 0 auto; display: flex; gap: 4px; margin: 10px 12px 0;
  padding: 3px; border-radius: var(--r-pill); background: var(--hc-raised, var(--panel2));
}
.h-ch__segb {
  flex: 1 1 0; min-height: 34px; padding: 0 12px;
  border: 0; border-radius: var(--r-pill); background: transparent; color: var(--muted);
  font-size: 13px; font-weight: 700; cursor: pointer;
}
.h-ch__segb.is-on {
  background: var(--hc-accent-strong); color: var(--hc-accent-ink);
}

.h-ch__build { flex: 0 0 auto; padding: 10px 12px 0; }
.h-ch__build .h-input { width: 100%; }
.h-ch__picked { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.h-chipsel {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 6px 4px 10px; border-radius: var(--r-pill);
  background: var(--hc-raised, var(--panel2));
  border: 1px solid var(--hc-border, var(--line));
  font-size: 12.5px; font-weight: 600;
}
.h-chipsel__x {
  width: 18px; height: 18px; padding: 0; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%; cursor: pointer;
  background: var(--hc-border, var(--line)); color: inherit; font-size: 10px;
}
.h-chipsel__x:hover { background: var(--hc-accent-strong); color: var(--hc-accent-ink); }
.h-ch__create { width: 100%; margin-top: 10px; }
.h-ch__create:disabled { opacity: .55; cursor: default; }
.h-ch__person.is-picked { background: var(--hc-raised, var(--panel2)); }
.h-ch__tick {
  margin-left: auto; width: 20px; text-align: center;
  color: var(--hc-accent-text); font-weight: 800;
}

/* ---- communities: the drill-down ---------------------------------------- */
.h-ch__commhead {
  flex: 0 0 auto; display: flex; align-items: center; gap: 8px;
  padding: 10px 14px; border-bottom: 1px solid var(--hc-border, var(--line));
}
.h-ch__commname { font-size: 15px; font-weight: 700; }
/* CHAT'S VISIBILITY POLICY FOR THE SHARED BACK CONTROL, `Q-02`, 2026-09-17.

   🔴 THE OLD `.h-ch__back` WAS `display: none` BY DEFAULT and three rules
   turned it on -- `.is-always`, `.h-ch--dock` and the `.h-ch--inline` media
   block. Retiring that rule without carrying the policy would have made chat's
   back button VISIBLE IN EVERY MODE, which is a behaviour change nobody asked
   for, and left three selectors pointing at a class the markup no longer has.
   Caught by checking what still referenced the class after the base rule went.

   IT LIVES HERE AND NOT ON `.h-back--icon` BECAUSE IT IS CHAT'S LAYOUT RULE,
   NOT THE CONTROL'S. A shared control that hides itself by default would be a
   trap for the second caller. */
.h-ch__hd .h-back--icon, .h-ch__commhead .h-back--icon { display: none; }
/* The back control inside a list, where there is no header bar to carry it. */
.h-back--icon.is-always { display: inline-flex; margin-left: 0; }
.h-ch__chev {
  flex: 0 0 auto; margin-left: 4px; color: var(--muted);
  font-size: 18px; line-height: 1;
}
/* A channel avatar is a glyph, not initials: # for the open room, ! for the
   one only organisers post to. */
.h-ch__av.is-announce {
  background: var(--warn-solid); border-color: var(--warn-solid);
  /* --on-warn, not --bg. The pair exists precisely so the ink on this fill is
     the measured one; --bg happens to be near-black in dark (fine) and #E8E8E8
     in light, where it measured 4.43:1 — a fail on a 17px glyph. 5.42 now. */
  color: var(--on-warn); font-size: 17px;
}

/* A hint that has turned into a validation error. Same element, so the layout
   does not jump when a field goes from explaining itself to complaining. */
.h-lr__hint.is-bad { color: var(--danger); font-weight: 600; }
/* B17 (T09-B): a soft amber signal (the waiver editor's short-wording line): the house --warn, never a refusal's red. */
.h-lr__hint.is-warn { color: var(--warn); font-weight: 600; }

/* ---- the organiser's roster tools ---------------------------------------
   Two buttons on a roster row: move them across the line, or take them off.
   Not a menu — there are only ever two things to do to somebody, and a menu
   with two items is a tap before the tap you wanted.
   ------------------------------------------------------------------------ */
.h-rtools { display: flex; gap: 6px; flex: none; margin-left: 6px; }
.h-rtool {
  padding: 4px 9px; border-radius: var(--r-sm, 8px);
  border: 1px solid var(--line2); background: var(--panel2);
  font: inherit; font-size: 11px; font-weight: 700; color: var(--ink);
  cursor: pointer; white-space: nowrap;
}
.h-rtool:hover { border-color: var(--green); }
/* Remove is the one that is not undoable from the member's side. */
.h-rtool--off { color: var(--danger); }
.h-rtool--off:hover { border-color: var(--danger); }
/* On a phone the two buttons drop under the name rather than squeezing it to
   three characters. .h-mrow is a flex row, so this is a wrap, not a reflow. */
@media (max-width: 430px) {
  .h-mrow { flex-wrap: wrap; }
  .h-rtools { margin-left: 46px; margin-top: 6px; width: 100%; }
}

/* The always-sent list on the email settings screen. Karl: "there are also
   some emails that can never be blocked i.e registration emails etc." Shown
   rather than omitted — a screen of off switches reads as "I turned everything
   off", and the member who then gets an invoice thinks the app ignored them. */
.h-always {
  margin: 4px 0 8px; padding-left: 18px;
  font-size: 12.5px; color: var(--muted); line-height: 1.7;
}

/* ---- game invites --------------------------------------------------------
   Karl, 08-11: "There is a difference between enabling 'friends can join' and
   sending a private invite to a specific friend." An invite is a QUESTION, so
   it is a card with two answers rather than a row you tap into.

   `h-ginv`, NOT `h-inv` — that prefix is already INVOICES (.h-inv__acts,
   .h-inv__head, .h-inv__right). Two modules sharing a BEM block is two sets of
   rules landing on each other's markup, and tools/css-tokens.mjs caught the
   collision as a duplicated `display` on one selector.
   ------------------------------------------------------------------------ */
.h-ginv {
  padding: 12px 13px; margin-bottom: 9px;
  background: var(--panel); border: 1px solid var(--line);
  border-left: 3px solid var(--brand-purple, var(--green));
  border-radius: var(--r-lg, 14px);
}
.h-ginv__who { font-size: 12px; font-weight: 800; color: var(--brand-purple, var(--green));
              text-transform: uppercase; letter-spacing: .02em; }
.h-ginv__game { font-size: 14.5px; font-weight: 700; margin-top: 3px; overflow-wrap: anywhere; }
.h-ginv__when { font-size: 12px; color: var(--muted); margin-top: 2px; overflow-wrap: anywhere; }
/* WHAT YES WILL DO, before they press it. An organiser's invite puts you on
   the roster and anybody else's puts you on the waitlist; being told after is
   being told too late. */
.h-ginv__note { margin: 8px 0 10px; font-size: 12px; color: var(--muted); }
.h-ginv__acts { display: flex; gap: 8px; }
.h-ginv__acts .h-btn:last-child { margin-left: auto; }
/* RE-02 (Karl): a yes / no pair sits together on the right. */
.h-ginv__acts--pair { justify-content: flex-end; }
.h-ginv__acts--pair .h-btn:last-child { margin-left: 0; }

/* ---- message requests ----------------------------------------------------
   Karl, 08-11: "dMs do not need friendship but handle these like Facebook
   does." A member with no connection to you can send one message, and it lands
   here rather than in the inbox.
   ------------------------------------------------------------------------ */
/* The ROW above the inbox. Deliberately not styled as one of the list rows —
   it is a pending decision, not a conversation, and the purple says "this is a
   different kind of thing" the way the old Find menu did. */
.h-ch__req {
  display: flex; align-items: center; gap: 11px; width: 100%;
  padding: 11px 13px; margin-bottom: 9px;
  background: var(--purple-dim, var(--panel2));
  border: 1px solid var(--brand-purple, var(--line2));
  border-radius: var(--r-lg, 14px);
  font: inherit; color: var(--ink); text-align: left; cursor: pointer;
}
.h-ch__req:hover { border-color: var(--brand-purple, var(--green)); }
.h-ch__av.is-req {
  background: var(--brand-purple, var(--panel2));
  border-color: var(--brand-purple, var(--line2));
  color: var(--on-brand-purple);
}
.h-ch__av.is-req .h-ic { width: 18px; height: 18px; }
/* The count, not a dot. "3 people are waiting on you" is a different sentence
   from "something is new", and this row is about the first one. */
.h-ch__reqn {
  flex: none; min-width: 21px; padding: 1px 7px; border-radius: var(--r-pill);
  background: var(--brand-purple, var(--green)); color: var(--on-brand-purple);
  font-size: 11.5px; font-weight: 800; text-align: center;
}

/* One card per request, inside the sheet. */
.h-rq {
  padding: 12px 0; border-bottom: 1px solid var(--line);
}
.h-rq:last-of-type { border-bottom: 0; }
.h-rq__who { font-size: 14px; font-weight: 700; margin-bottom: 4px; display: flex; align-items: center; gap: 8px; }
.h-rq__face, .h-ch__mface { flex: none; line-height: 0; }
/* THE MESSAGE IS SHOWN. Deciding whether you want to talk to somebody without
   being allowed to read what they said is a coin toss, not a decision. */
.h-rq__msg {
  font-size: 13px; color: var(--muted); margin-bottom: 10px;
  overflow-wrap: anywhere;
}
/* Delete and Block sit left, Accept right — the affirmative last, which is the
   order .h-sheet__actions already uses so the whole app agrees. */
.h-rq__acts { display: flex; gap: 8px; }
.h-rq__acts .h-btn:last-child { margin-left: auto; }
.h-rq__block { color: var(--danger); border-color: var(--danger); }

/* ---- the support agent queue -------------------------------------------- */
.h-ch__claim {
  margin-left: 6px; padding: 1px 7px; border-radius: var(--r-pill);
  border: 1px solid var(--line); font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .03em; color: var(--muted);
  vertical-align: 1px;
}
/* Unclaimed is the one an agent is scanning for, so it is the one that carries
   colour. Claimed-by-somebody-else is deliberately quiet. */
/* --warn is tuned to sit ON the page background, not to be read as small bold
   TEXT on a panel: in light it measures 3.84:1 there, which axe caught.
   --warn-solid is the pair meant for exactly this and clears AA in both
   themes (5.4:1 light, 10.7:1 dark). */
.h-ch__claim.is-open { border-color: var(--warn-solid); color: var(--warn-solid); }
.h-ch__claim.is-mine { border-color: var(--hc-accent-text); color: var(--hc-accent-text); }

/* ---- the members view --------------------------------------------------- */
.h-ch__mhead {
  flex: 0 0 auto; padding: 12px 14px;
  border-bottom: 1px solid var(--hc-border, var(--line));
}
.h-ch__mtitle { font-size: 15px; font-weight: 800; }
.h-ch__msub { margin-top: 2px; font-size: 12px; color: var(--muted); }
.h-ch__macts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.h-ch__mname { width: 100%; margin-top: 10px; }
.h-ch__danger { color: var(--danger); border-color: var(--danger); }
.h-ch__member {
  display: flex; align-items: center; gap: 8px;
  padding: 10px; min-height: 44px; border-radius: var(--r-md);
}
.h-ch__member:hover { background: var(--hc-raised, var(--panel2)); }
.h-ch__you { font-weight: 500; color: var(--muted); font-size: 12px; }
.h-ch__rolebadge {
  margin-left: 6px; padding: 1px 7px; border-radius: var(--r-pill);
  border: 1px solid var(--hc-accent-text); color: var(--hc-accent-text);
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
}
.h-ch__rowx {
  flex: 0 0 auto; margin-left: auto; width: 26px; height: 26px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--hc-border, var(--line)); border-radius: 50%;
  background: transparent; color: var(--muted); font-size: 11px; cursor: pointer;
}
.h-ch__rowx:hover { border-color: var(--danger); color: var(--danger); }

/* ---- shared list / thread ----------------------------------------------
   The dock stacks them: one screen at a time. */
.h-ch { display: flex; gap: 0; min-height: 0; }
/* NOTHING TO LIST: one centred panel across the whole surface, rather than an
   empty state squeezed into the sidebar column with a placeholder beside it. */
.h-ch.is-bare { flex: 1 1 auto; flex-direction: column; }
.h-ch.is-bare .h-ch__empty { flex: 1 1 auto; }
/* NO FIXED HEIGHT HERE. This used to say `height: 62vh` and the newer rule
   below replaced it with flex sizing WITHOUT removing this line — so the pane
   kept resolving to 62vh (558px of a 900px window) no matter what the flex
   chain offered it. That is the dead space under the Hub messenger. */
.h-ch--dock { flex: 1 1 auto; flex-direction: column; }
.h-ch--dock .h-ch__side { flex: 1 1 auto; border-right: 0; padding: 0; }
.h-ch--dock.is-open .h-ch__side { display: none; }
.h-ch--dock .h-ch__pane { padding: 0 12px 12px; min-height: 0; }
/* ↑ `min-height: 0` (Karl, 2026-10-04, "the composer is gone; the screen ends
   at the last message"): a flex column item's automatic minimum is its
   content, so a LONG thread grew the pane past the dock's clipped bottom, the
   message list never scrolled, and the composer sat below the screen. Short
   threads fitted, which is why it hid. With 0 the list scrolls and the
   composer stays on screen. */
.h-ch--dock:not(.is-open) .h-ch__pane { display: none; }
.h-ch--dock .h-ch__hd .h-back--icon { display: inline-flex; }

.h-ch__side { min-width: 0; overflow-y: auto; }
.h-ch__pane { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; padding-left: 12px; }
.h-ch__pane--empty { align-items: center; justify-content: center; }

/* THE ROW, to the live app's measurements: 12px/14px padding, a 12px gap, and
   a REAL DIVIDER under each one. The previous version had rounded floating
   rows with no separators, which is why the list read as a loose pile rather
   than a message list. */
.h-ch__row {
  display: flex; gap: 12px; align-items: center; width: 100%; text-align: left;
  padding: 12px 14px; min-height: 56px; cursor: pointer;
  background: transparent; border: 0; border-radius: 0; color: inherit;
  border-bottom: 1px solid var(--hc-border, var(--line));
  transition: background .12s;
}
.h-ch__row:last-child { border-bottom: 0; }
.h-ch__row:hover { background: var(--hc-surface-2, var(--panel2)); }
.h-ch__row.is-on { background: var(--hc-surface-2, var(--panel2)); }
.h-ch__t {
  display: block; font-weight: 600; font-size: 14.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Initials in a circle, as the live app draws them. A ROOM is filled, a
   PERSON outlined, so a group is distinguishable without reading the name. */
.h-ch__av {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--hc-raised, var(--panel2)); color: var(--hc-muted, var(--muted));
  font-size: 13px; font-weight: 700; letter-spacing: .02em;
  border: 1px solid var(--hc-border, var(--line));
}
/* A REAL FACE IN THE CHAT AVATAR. Karl's ChatInbox_Avatars playbook adds
   `.h365chat-avatar.has-ident` for exactly this — "transparent circle, SVG
   fills" — because the tinted disc and its letters are the placeholder the
   avatar replaces, not a frame around it. */
.h-ch__av.has-ident { background: transparent; padding: 0; }
.h-co__av.has-ident { background: transparent; padding: 0; }
.h-co__av.has-ident .h-av { width: 100%; height: 100%; }
.h-ch__av.has-ident .h-av { width: 100%; height: 100%; }

.h-ch__av.is-room {
  background: var(--hc-accent-strong, var(--green));
  border-color: var(--hc-accent-strong, var(--green));
  color: var(--hc-accent-ink, var(--on-green));
}
/* ===========================================================================
   `MORE-04` - THE RINGS THAT IDENTIFY NOTHING. Nora's diagnosis, and it is one
   word: support resolved to `var(--green)` through its fallback and coach WAS
   `var(--green)`. THE FEATURE WAS FULLY BUILT AND COMPLETELY INERT - the JS has
   emitted `is-support` and `is-coach` since before she arrived, and two
   identical rings cannot discriminate between two things.
   ARROW Support takes `--info`. Both go to 2px, because the base `.h-ch__av`
   ring is 1px and at that weight it reads as the disc's edge, not as a mark.
   WARNING THE `--hc-accent-text` FALLBACK IS DROPPED ON SUPPORT DELIBERATELY.
   It let a themed space repaint this ring, which is how it became green in the
   first place - a mark whose colour a caller can change is not a mark.
   STOP COACH IS STILL GREEN AND THAT IS THE HALF I COULD NOT LAND. Nora's
   ruling is coach = the schedule's own coach pink `#ff6ec7`
   (`functions/lib/spaces.js`, `SCHEDULE_SOURCES`), with a real argument:
   `--purple` already means H365 Training, and re-using it here re-introduces
   the exact collision that was deliberately removed from the calendar, on the
   one surface whose only job is to discriminate. THAT PINK IS NOT A TOKEN AND
   `css-raw-colour` correctly forbids a raw hex here. Minting a palette entry is
   `tokens.css`, which is Vera's, and a new colour needs measuring in both
   themes and all four styles.
   OK THE REPORTED DEFECT IS FIXED EITHER WAY: the two rings now differ. The
   pink is an improvement on top of that, and it is one line once the token
   exists.
   ========================================================================= */
.h-ch__av.is-support { border-width: 2px; border-color: var(--info); color: var(--info); }
.h-ch__av.is-coach { border-width: 2px; border-color: var(--green); color: var(--green); }
/* A PRIVATE MULTI-FRIEND GROUP MESSAGE: purple, so it never reads as a pickup
   group's room (blue fill), Support (info) or a coach (green). */
.h-ch__av.is-gm {
  border-width: 2px; border-color: var(--purple);
  background: var(--hc-raised, var(--panel2)); color: var(--hc-text, var(--ink));
}
/* WHICH OF A GROUP'S TWO ROOMS: `#` Global chat, `!` Announcements — a
   character, not a colour, on the corner of the group's own emblem. */
.h-ch__chanmark {
  position: absolute; right: -4px; bottom: -3px;
  width: 18px; height: 18px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--hc-raised); color: var(--hc-text);
  border: 1px solid var(--hc-border); font-size: 11px; font-weight: 800; line-height: 1;
}
/* A SPACE IS A ROUNDED SQUARE, NEVER A CIRCLE (Character + Space C3; Fable
   Q-27 item 1 / ID-07): people are round, groups and programs are squares, so a
   row says what it is before its name is read. The room avatar takes the
   Space radius when it shows the Space's own emblem. */
.h-ch__av.is-room.has-ident { border-radius: 26.2%; border-color: transparent; }
.h-ch__av.has-ident .h-gav { width: 100%; height: 100%; border-radius: 26.2%; }
/* A DOOR INTO THE MESSENGER, from a game Space's Chat tab or a group board.
   Karl, 2026-09-26: Space chat shares the Messenger's colours now that the
   Messenger is the primary one — the same conversation should not be green in
   one place and blue in the other. Filled for the main room, outlined (with
   `.h-btn--ghost`) for Announcements. Tokens from `--dock-*`, which live at
   the root so a page outside the dock can use them. */
/* A SPACE'S ROOM, ON THE SPACE (Karl, 2026-09-26). */
.h-sroom { margin-top: 12px; }
.h-sroom__head { margin: 0 2px 10px; }
.h-sroom__head small {
  display: block; color: var(--green); font-size: 12px; font-weight: 700; letter-spacing: .02em;
}
.h-sroom__head h3 { margin: 2px 0 0; font-family: var(--font-display); font-weight: 400; font-size: 20px; line-height: 1; text-transform: uppercase; letter-spacing: .025em; }
.h-sroom__slot {
  /* NO BOX (Karl, 2026-09-26): "the black background alone is perfect for
     the chat bubbles to appear on." The room is the page, not a card on it. */
  display: flex; flex-direction: column; min-height: 300px; overflow: hidden;
}
/* THE CHAT ROOM IS A MESSENGER ITEM: the same redirects `.h-dock` makes, so
   its surfaces, lines and accent are the Messenger's, not the Space's. */
.h-sroom--msgr {
  --hc-accent:        var(--dock-accent);
  --hc-accent-strong: var(--dock-accent-strong);
  --hc-accent-text:   var(--dock-accent-text);
  --hc-accent-ink:    var(--dock-accent-ink);
  --hc-surface:       var(--dock-surface);
  --hc-surface-2:     var(--dock-surface-2);
  --hc-raised:        var(--dock-raised);
  --hc-text:          var(--dock-ink);
  --hc-muted:         var(--dock-muted);
  --hc-border:        var(--dock-line);
  color: var(--hc-text);
}
.h-sroom--msgr .h-sroom__head small { color: var(--dock-accent-text); }
/* ONE THREAD, BOUNDED: it scrolls inside the Space rather than making the
   Space a mile long, and the composer stays under it. */
.h-ch--embed { flex: 1 1 auto; flex-direction: column; min-height: 0; }
.h-ch--embed .h-ch__pane { flex: 1 1 auto; min-height: 0; padding: 0 12px 12px; }
.h-ch--embed .h-ch__msgs { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
/* A short thread sits at the BOTTOM, by the composer, the way a messenger
   reads — the spacer takes the slack above it. */
.h-ch--embed .h-ch__msgs::before { content: ''; flex: 1 1 auto; }
.h-ch__empty--thread { flex: 1 1 auto; }
/* No bottom padding under a room: it runs to the screen's edge. */
.h-detail__body:has(.h-sroom__slot) { padding-bottom: 12px; }
.h-btn.h-msgr-entry {
  background: var(--dock-accent-strong); border-color: var(--dock-accent-strong);
  color: var(--dock-accent-ink);
}
.h-btn.h-btn--ghost.h-msgr-entry {
  background: transparent; border-color: var(--dock-accent-strong); color: var(--dock-accent-text);
}
/* THE MESSENGER'S OWN ACTIONS ARE BLUE. Karl, 2026-09-25: the Messenger accent
   is the established #3b82f6, "not purple/indigo and not BreakAway Green" — so
   inside the dock, the requests row (purple) and Send (green) take it. Scoped
   to the dock: Space chat keeps its Space's own theme. */
.h-dock .h-ch__req { background: color-mix(in srgb, var(--hc-accent) 12%, var(--hc-surface)); border-color: var(--hc-accent-strong); }
.h-dock .h-ch__req:hover { border-color: var(--hc-accent); }
.h-dock .h-ch__av.is-req, .h-dock .h-ch__reqn {
  background: var(--hc-accent-strong); border-color: var(--hc-accent-strong); color: var(--hc-accent-ink);
}
/* SEND: round, one icon, the room's accent — Messenger blue in the dock and
   a Space's Chat, the Space's own accent in its Announcements. 44px: the
   touch floor. */
.h-ch__send {
  flex: none; width: 44px; height: 44px; padding: 0; border: 0; border-radius: 50%;
  display: inline-grid; place-items: center; cursor: pointer;
  background: var(--hc-accent-strong, var(--green)); color: var(--hc-accent-ink, var(--on-green));
}
.h-ch__send .h-ic { width: 20px; height: 20px; }
.h-ch__send:disabled { opacity: .5; cursor: default; }
.h-ch__chanmark.is-announce { background: var(--hc-accent-strong); color: var(--hc-accent-ink); border-color: var(--hc-accent-strong); }
/* THE MESSAGES BADGE IN THE TOP NAV wears the Messenger's blue, not the
   app's green: it counts messages, and the Messenger is the blue surface. */
.h-topicon__badge[data-chat-badge] { background: var(--dock-accent-strong); color: var(--dock-accent-ink); }
.h-ch__row.is-unread .h-ch__t { font-weight: 800; }
.h-ch__p {
  display: block; margin-top: 2px; font-size: 11.5px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* --faint measures 4.1:1 on the page background, which is what this sits on
   in the Hub's inline Messages section. --muted is the quietest tier that
   passes everywhere. */
.h-ch__mute { margin-left: 6px; font-size: 10px; font-weight: 600; color: var(--muted); }
.h-ch__meta {
  flex: 0 0 auto; font-size: 11px; color: var(--muted); text-align: right;
  align-self: flex-start; padding-top: 2px;
}
.h-ch__dot {
  display: block; margin: 4px 0 0 auto; width: 8px; height: 8px;
  border-radius: 50%; background: var(--hc-accent, var(--green));
}
/* THE UNREAD COUNT, as a corner badge on the avatar. It used to sit stacked
   under the timestamp, which read as two unrelated things glued together —
   Karl's call, and it is where every other messenger puts it. */
.h-ch__avwrap { position: relative; flex: 0 0 auto; display: inline-flex; }
.h-ch__avn {
  position: absolute; top: -3px; right: -4px;
  min-width: 19px; height: 19px; padding: 0 5px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  background: var(--hc-accent-strong, var(--green));
  color: var(--hc-accent-ink, var(--on-green));
  font-size: 10.5px; font-weight: 800; line-height: 1;
  /* A ring in the row's own colour so the badge reads as sitting ON the
     avatar rather than merging into it. */
  box-shadow: 0 0 0 2px var(--hc-surface, var(--panel));
}
.h-ch__row:hover .h-ch__avn, .h-ch__row.is-on .h-ch__avn {
  box-shadow: 0 0 0 2px var(--hc-surface-2, var(--panel2));
}

.h-ch__hd { display: flex; align-items: center; gap: 8px; padding-bottom: 10px; border-bottom: 1px solid var(--line); }
/* On a phone the thread IS the screen, so back is always there; beside a list
   on a desktop it is redundant and hides. */
/* `.h-ch__back` RETIRED ON 2026-09-17, Meryl, `Q-02`. It is now
   `.h-back--icon` -- a MODIFIER on the shared control, not a class of its own,
   because a conversation header beside an avatar and a name genuinely has no
   room for words. One body, one position, one modifier for the case that
   differs, exactly as `.h-seg` / `.h-seg--pill` already works here.
   ⚠️ ITS `display: none` DEFAULT DID NOT COME WITH IT -- see `.h-ch__back`'s
   old `is-always` companion at the responsive rule above; that behaviour now
   belongs to whatever shows the header, and chat.js passes `is-always`
   explicitly on the one that was always visible. */
.h-ch__hd .h-ch__av { width: 32px; height: 32px; font-size: 11.5px; }
/* The mute control was sitting hard against the divider under it. */
.h-ch__hd .h-btn { margin-bottom: 2px; }
.h-ch__hdt { flex: 1 1 auto; font-weight: 700; font-size: 14px; }
/* (the .h-ch__back rule lives above with the rest of its declarations — a bare
   `display: none` here was a leftover that restated it and nothing else) */
.h-ch__closed {
  margin: 8px 0 0; padding: 8px 10px; border-radius: var(--r-sm);
  background: var(--panel2); color: var(--muted); font-size: 11.5px;
}

/* WHY A NAME YOU DO NOT RECOGNISE COULD MESSAGE YOU. Deliberately the SAME
   declarations as .h-ch__closed rather than a new look: both are the room
   explaining itself in a sentence, and the muted-on-panel2 pair is already the
   one this file's contrast pass measures. A new colour here would be a new
   thing to measure, for a line that is not more important than the one under
   it. */
.h-ch__known {
  margin: 8px 0 0; padding: 8px 10px; border-radius: var(--r-sm);
  background: var(--panel2); color: var(--muted); font-size: 11.5px;
}

/* 0046. The same shape as .h-ch__closed, but it is a WARNING rather than an
   explanation — an admin is one tap from emailing the whole roster — so it
   carries the accent edge instead of sitting in the muted grey that the eye
   learns to skip. */
/* 🚸 CC-09: a coach talking to a minor. A warning, so the warn edge, and it
   stays on screen above the messages rather than scrolling away with them. */
.h-ch__minor {
  margin: 8px 0 0; padding: 8px 10px; border-radius: var(--r-sm);
  border-left: 3px solid var(--warn-solid);
  background: var(--panel2); color: var(--ink); font-size: 12px;
}
.h-ch__minor strong { color: var(--warn); }

.h-ch__announce {
  margin: 8px 0 0; padding: 8px 10px; border-radius: var(--r-sm);
  border-left: 3px solid var(--brand-purple);
  background: var(--panel2); color: var(--ink); font-size: 11.5px;
}

.h-ch__msgs { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 10px 2px; }
.h-ch__more { display: block; margin: 0 auto 10px; }

/* SHRINK TO THE BUBBLE. The row was a fixed 78% wide whatever the message
   said, so the "..." control — pinned to the row's edge — floated far away
   from a short bubble. `fit-content` makes the row the width of what is in
   it, so the control sits against the message. */
.h-ch__m {
  max-width: 78%; width: fit-content; margin-bottom: 10px;
}
.h-ch__m.is-mine { margin-left: auto; text-align: right; }
/* A face beside the name on somebody else's message. Inline with the name
   rather than in a gutter column: the bubbles are already narrow on a phone,
   and a 22px avatar in the name line costs no width at all. */
.h-ch__who { display: flex; align-items: center; gap: 5px;
             font-size: 10.5px; color: var(--muted); margin-bottom: 2px; }
/* ID-31 (2026-10-04): the name line is a button now (it opens the Player Card),
   dressed exactly as the label it was. */
button.h-ch__who { background: none; border: 0; padding: 0; font: inherit; font-size: 10.5px;
                   color: var(--muted); cursor: pointer; text-align: left; }
.h-ch__mav { flex: none; display: block; }
/* And in the new-message picker. Sized to the row's text rather than to a
   72px tile — this is a search result, not a profile card. */
.h-ch__pav { flex: none; display: block; margin-right: 9px; }
.h-ch__mav .h-av { border: 1px solid var(--line); }
/* V5.18 (B64 PC-06): the Basic disc's letters sized for the 22px face. */
.h-ch__mav .h-av--init { font-size: 9px; letter-spacing: 0; }
.h-ch__b {
  display: inline-block; padding: 8px 12px; border-radius: var(--r-lg);
  background: var(--hc-raised, var(--panel2)); font-size: 13.5px; line-height: 1.45;
  overflow-wrap: anywhere; text-align: left;
}
/* Your own bubbles carry the messenger accent, not the app accent — same
   reason the chrome does. */
.h-ch__m.is-mine .h-ch__b {
  background: var(--hc-accent-strong, var(--green));
  color: var(--hc-accent-ink, var(--on-green));
}
/* --faint measures 4.4:1 on the light panel — just under AA, and axe caught
   it. --muted is 6.1:1 and still reads as the quietest tier. */
.h-ch__m.is-gone .h-ch__b { font-style: italic; color: var(--muted); }
.h-ch__ts { display: block; margin-top: 2px; font-size: 10px; color: var(--muted); }
/* "Read" carries a little more weight than a timestamp, because it is the one
   thing in the meta line somebody actually looks for. */
.h-ch__seen { font-weight: 700; color: var(--hc-accent-text, var(--green)); }
.h-ch__reacts { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-top: 3px; position: relative; }
.h-ch__m.is-mine .h-ch__reacts { justify-content: flex-end; }
.h-ch__react {
  padding: 1px 7px; min-height: 22px; border-radius: var(--r-pill);
  border: 1px solid var(--line); background: transparent; color: inherit;
  font-size: 11px; cursor: pointer;
}
.h-ch__react.is-mine { border-color: var(--hc-accent-strong); background: var(--hc-raised, var(--panel2)); }
.h-ch__addreact {
  width: 22px; height: 22px; padding: 0; line-height: 1;
  border: 1px dashed var(--line); border-radius: 50%;
  background: transparent; color: var(--muted); font-size: 13px; cursor: pointer;
  opacity: 0; transition: opacity .12s var(--hc-ease, ease);
}
/* Reveal on hover, and ALWAYS on touch — a control that only exists on hover
   does not exist on a phone. */
.h-ch__m:hover .h-ch__addreact, .h-ch__addreact:focus-visible { opacity: 1; }
@media (hover: none) { .h-ch__addreact { opacity: 1; } }
.h-ch__picker {
  position: absolute; bottom: calc(100% + 4px); left: 0; z-index: 3;
  display: flex; gap: 2px; padding: 4px;
  border-radius: var(--r-pill); border: 1px solid var(--hc-border, var(--line));
  background: var(--hc-raised, var(--panel2));
  box-shadow: var(--sh-popover);
}
.h-ch__m.is-mine .h-ch__picker { left: auto; right: 0; }
.h-ch__pick {
  width: 30px; height: 30px; padding: 0; font-size: 15px; line-height: 1;
  border: 0; border-radius: 50%; background: transparent; cursor: pointer;
}
.h-ch__pick:hover { background: var(--hc-border, var(--line)); }
.h-ch__mutebtn.is-on { border-color: var(--hc-accent-text); color: var(--hc-accent-text); }

/* ---- reply, edit, and the per-message menu ------------------------------ */
.h-ch__m { position: relative; }

/* The quote above a reply. Without it a reply is a sentence answering nothing. */
.h-ch__quote {
  display: block; margin-bottom: 3px; padding: 5px 9px;
  border-left: 3px solid var(--hc-accent-strong, var(--green));
  border-radius: 0 8px 8px 0;
  background: var(--hc-raised, var(--panel2));
  font-size: 11.5px; line-height: 1.35; text-align: left;
}
.h-ch__quote-a { display: block; font-weight: 700; color: var(--hc-accent-text, var(--green)); }
.h-ch__quote-b {
  display: block; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* THE MESSAGE MENU CONTROL.
   Three problems with the first version, all reported: it was a horizontal
   ellipsis (wide, so it overlapped the bubble), --muted on a dark panel (too
   faint to find), and 24px (too small to aim at). Now: a VERTICAL ellipsis in
   a 26px well, sitting fully OUTSIDE the bubble in its own gutter, in the
   panel's text colour on a raised chip so it reads against any background. */
.h-ch__menubtn {
  position: absolute; top: 2px;
  width: 26px; height: 26px; padding: 0; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid transparent; border-radius: 50%;
  background: transparent;
  color: var(--hc-text, var(--ink));
  font-size: 19px; font-weight: 700; cursor: pointer;
  opacity: 0; transition: opacity .12s ease, background .12s ease;
}
/* Clear of the bubble entirely — 30px out, so nothing overlaps the text. */
.h-ch__m .h-ch__menubtn { right: -30px; }
.h-ch__m.is-mine .h-ch__menubtn { right: auto; left: -30px; }
.h-ch__m:hover .h-ch__menubtn, .h-ch__menubtn:focus-visible {
  opacity: 1;
  background: var(--hc-raised, var(--panel2));
  border-color: var(--hc-border, var(--line));
}
/* No hover on touch, so it is always there — and always visible, not a ghost
   that only appears once you have already guessed where it is. */
@media (hover: none) {
  .h-ch__menubtn {
    opacity: 1;
    background: var(--hc-raised, var(--panel2));
    border-color: var(--hc-border, var(--line));
  }
}
/* The gutter the control lives in: without this the row is edge-to-edge and a
   control 30px outside it would be clipped by the scroller. */
.h-ch__msgs { padding-left: 34px; padding-right: 34px; }

/* ===========================================================================
   `MSG-01` — THE MESSAGE MENU OPENED OFF THE EDGE, AND BOTH ARMS WERE WRONG.

   Karl: the Reply / Edit / Delete menu "opens off the right edge", and "this
   is a problem on lean also". ⚠️ ONE CLASS, ONE RENDERER, BOTH SURFACES:
   `chat.js:msgHtml` is the only emitter of `.h-ch__menu`, `bodyHtml` is its
   only caller and `surface()` returns EITHER the Hub's Messages room OR the
   dock's `[data-role="ch"]`. So this rule is the component both messengers
   share, which is where the register said the fix belongs — and it lands on
   both at once rather than on my half of the item.

   THE ARITHMETIC, BECAUSE THIS IS GEOMETRY AND NOT A JUDGEMENT CALL.
   `.h-ch__msgs` carries 34px of gutter each side, so on a viewport W the
   content box is C = W - 68. A bubble is `width: fit-content`, and the menu is
   positioned against the BUBBLE (`.h-ch__m` is the relative box), not against
   the container. With `min-width: 132px`:

     · OUTGOING was `left: 0`, expanding RIGHTWARD from a bubble whose right
       edge is already at C. It overflows whenever the bubble is narrower than
       132px, and clears the viewport entirely below ~98px. "ok". "on my way".
       That is Karl's screenshot.
     · INCOMING was `right: 0`, expanding LEFTWARD from a bubble whose left
       edge is at 0. ⚠️ THE SAME DEFECT MIRRORED, off the LEFT edge, on exactly
       the same widths. Nobody had reported it because a short incoming message
       is rarer in a two-person test and the 34px gutter hides the first bite
       of it. Fixing only the reported arm would have left the item half open.

   SO THE TWO ARMS ARE SWAPPED: each menu is anchored to the side of its bubble
   that has the whole screen beyond it.

     · incoming  → `left: 0`,  expands right, right edge at 132 ≤ C
     · outgoing  → `right: 0`, expands left,  left edge at C - 132 ≥ 0

   Both hold for every C ≥ 132, and the narrowest viewport this project tests
   is 320 (`tools/overflow-check.mjs:45`), where C = 252. **120px of headroom,
   and overflow is now structurally impossible rather than detected.**

   ⚖️ AND THAT IS WHY THERE IS NO JAVASCRIPT HERE, WHICH THE REGISTER ASKED FOR
   ("standard edge-collision handling"). Measure-and-flip has to read layout
   after paint, so it is wrong for one frame, wrong again when a webfont
   settles, and needs re-running on resize, rotate and every repaint — and
   `repaint()` runs on a poll every few seconds. A rule that CANNOT overflow at
   any width beats a rule that notices it has. `tests/msgmenu.test.mjs` asserts
   the arithmetic, so raising `min-width` past the headroom turns red. */
.h-ch__menu {
  position: absolute; top: 22px; left: 0; right: auto; z-index: 4;
  display: flex; flex-direction: column; min-width: 132px; padding: 4px;
  border: 1px solid var(--hc-border, var(--line)); border-radius: var(--r-md);
  background: var(--hc-raised, var(--panel2));
  box-shadow: var(--sh-menu);
}
.h-ch__m.is-mine .h-ch__menu { left: auto; right: 0; }
.h-ch__mi {
  padding: 8px 10px; min-height: 36px; text-align: left;
  border: 0; border-radius: var(--r-sm); background: transparent; color: inherit;
  font-size: 13px; cursor: pointer;
}
.h-ch__mi:hover { background: var(--hc-border, var(--line)); }
.h-ch__mi--danger { color: var(--danger); }

/* Editing happens IN the bubble — no sheet stacked over the messenger. */
.h-ch__m.is-editing { max-width: 100%; }
.h-ch__editta { width: 100%; resize: none; }
.h-ch__editacts { display: flex; justify-content: flex-end; gap: 6px; margin-top: 6px; }

.h-ch__replybar {
  position: relative; display: block; padding: 7px 30px 7px 10px;
  margin-top: 8px;
  border-left: 3px solid var(--hc-accent-strong, var(--green));
  border-radius: 0 8px 8px 0;
  background: var(--hc-raised, var(--panel2)); font-size: 11.5px;
}
.h-ch__replybar-t { display: block; font-weight: 700; color: var(--hc-accent-text, var(--green)); }
.h-ch__replybar-b {
  display: block; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.h-ch__replybar-x {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  width: 22px; height: 22px; padding: 0;
  border: 0; border-radius: 50%; background: transparent;
  color: var(--muted); font-size: 11px; cursor: pointer;
}
.h-ch__replybar-x:hover { background: var(--hc-border, var(--line)); }

.h-ch__compose { display: flex; gap: 8px; align-items: flex-end; padding-top: 8px; border-top: 1px solid var(--line); }
/* NO SCROLLBAR UNTIL THERE IS SOMETHING TO SCROLL. The box auto-grows, so a
   permanent `overflow: auto` drew a track beside a single line of text.
   `overflow-y: hidden` is the resting state; the grow handler turns scrolling
   on only once the text passes the maximum height. Overlay scrollbars keep it
   out of the way even then. */
.h-ch__ta {
  flex: 1 1 auto; resize: none; max-height: 40vh; min-height: 40px;
  overflow-y: hidden; scrollbar-width: thin;
}
.h-ch__ta.is-scrolling { overflow-y: auto; }
.h-ch__compose .h-btn { min-height: 44px; }

/* ===========================================================================
   PRIVATE COACHING — the directory, the booking form, and both sides of the
   sessions list. Built against the live app's own measurements where they
   were already right (see assets/js/coach.js).
   ========================================================================= */

/* `.h-empty` HAD NO RULE AT ALL. chat.js has been painting `<div
   class="h-empty">Loading…</div>` in four places since V1.0 and it rendered as
   bare unstyled text hard against the left edge. The same silent-absence
   family as the undefined colour tokens: nothing throws, it just looks like
   nobody finished. */
.h-empty {
  padding: 28px 20px;
  text-align: center;
  color: var(--muted);
  font-size: 14px;
}
.h-empty__t { margin: 0 0 6px; font-weight: 700; color: var(--ink); font-size: 15px; }
.h-empty__b { margin: 0 0 14px; font-size: 13px; line-height: 1.5; }

.h-co { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }

.h-co__tabs {
  display: flex; gap: 4px; padding: 10px 14px 0;
  border-bottom: 1px solid var(--line);
  overflow-x: auto; scrollbar-width: none;
}
.h-co__tabs::-webkit-scrollbar { display: none; }
/* One line each: a coach has three tabs (Booking requests), and a label
   broken over two lines reads as six. */
.h-co__tab {
  appearance: none; background: none; border: 0;
  border-bottom: 2px solid transparent;
  padding: 8px 8px 10px; font: inherit; font-size: 14px; font-weight: 600;
  color: var(--muted); cursor: pointer;
  white-space: nowrap; flex: 0 0 auto;
}
@media (max-width: 380px) { .h-co__tab { font-size: 13px; } }
.h-co__tab.is-on { color: var(--ink); border-bottom-color: var(--green); }

.h-co__body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 14px; }

/* --- the directory ------------------------------------------------------- */
.h-co__searchrow { margin-bottom: 12px; }
.h-co__search { width: 100%; border-radius: var(--r-pill); padding: 10px 16px; }

.h-co__grid { display: flex; flex-direction: column; gap: 8px; }

.h-co__card {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 12px; text-align: left; cursor: pointer;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
  color: inherit; font: inherit;
  transition: border-color .15s, transform .15s;
}
.h-co__card:hover { border-color: var(--green); transform: translateY(-1px); }

.h-co__av {
  flex: 0 0 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--green-dim); color: var(--green);
  font-size: 15px; font-weight: 700; letter-spacing: .02em;
}
.h-co__av.is-lg { flex-basis: 52px; height: 52px; font-size: 18px; }

.h-co__cardbody { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.h-co__name { font-size: 15px; font-weight: 700; color: var(--ink); }
.h-co__where { font-size: 12px; color: var(--faint); }
.h-co__note {
  font-size: 12px; color: var(--muted); line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* THE RATE IS ON THE CARD, not two taps away behind a profile. The live
   directory shows one hardcoded "starting at $60" for everybody, so every card
   looks the same price and none of them is. */
.h-co__rate { flex: 0 0 auto; font-size: 15px; font-weight: 700; color: var(--ink); }
.h-co__rate small { font-size: 11px; font-weight: 600; color: var(--faint); }

/* --- booking ------------------------------------------------------------- */
.h-co__book { display: flex; flex-direction: column; gap: 16px; }

.h-co__strip {
  display: flex; align-items: center; gap: 12px; padding: 12px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
}

.h-co__tip {
  margin: 0; padding: 10px 12px; font-size: 12.5px; line-height: 1.5;
  color: var(--muted); background: var(--elev); border-radius: var(--r-md);
}

.h-co__sect { display: flex; flex-direction: column; gap: 8px; }
.h-co__secth {
  margin: 0; font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--faint);
}
.h-co__secth small { font-size: 10px; font-weight: 500; text-transform: none; letter-spacing: 0; }
.h-co__secth.is-urgent { color: var(--warn); }

.h-co__sesslist { display: flex; flex-direction: column; gap: 6px; }
.h-co__sess {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; background: var(--elev); border-radius: var(--r-md);
}
.h-co__sessgrow { display: flex; flex-direction: column; gap: 1px; flex: 1 1 auto; min-width: 0; }
.h-co__sessday { font-size: 13px; font-weight: 600; color: var(--ink); }
.h-co__sesstime { font-size: 12px; color: var(--faint); }
.h-co__sessamt { font-size: 13px; font-weight: 600; color: var(--ink); }
.h-co__sessx {
  flex: 0 0 26px; height: 26px; border-radius: 50%;
  background: none; border: 0; cursor: pointer;
  color: var(--muted); font-size: 13px; line-height: 1;
}
.h-co__sessx:hover { color: var(--danger); background: var(--panel2); }

.h-co__none, .h-co__help, .h-co__fine {
  margin: 0; font-size: 12px; color: var(--faint); line-height: 1.5;
}
.h-co__fine { font-style: italic; }

.h-co__addrow { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end; }
.h-co__field { display: flex; flex-direction: column; gap: 4px; flex: 1 1 120px; min-width: 0; }
.h-co__field > span {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--faint);
}
/* iOS ZOOMS ANY INPUT UNDER 16px ON FOCUS, which throws the whole booking form
   off-screen mid-tap. The live app hard-sets 16px on its time inputs for
   exactly this and says so. */
.h-co__addrow input, .h-co__addrow select { font-size: 16px; }

.h-co__parts { display: flex; flex-direction: column; gap: 6px; }
.h-co__part {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 8px 8px 12px; background: var(--elev);
  border: 1px solid var(--line); border-radius: var(--r-md);
}
.h-co__partname {
  flex: 1 1 auto; min-width: 0; font-size: 13px; font-weight: 700; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.h-co__parttag {
  flex: 0 0 auto; font-size: 10px; font-weight: 800; text-transform: uppercase;
  letter-spacing: .04em; padding: 2px 8px; border-radius: var(--r-pill);
  background: var(--bg); border: 1px solid var(--line); color: var(--muted);
}
.h-co__partx {
  flex: 0 0 24px; height: 24px; background: none; border: 0; cursor: pointer;
  color: var(--muted); font-size: 12px;
}
.h-co__partx:hover { color: var(--danger); }
.h-co__addpeople { display: flex; flex-wrap: wrap; gap: 6px; }

.h-co__ta { resize: vertical; min-height: 70px; }

.h-co__pay {
  padding: 14px; border-radius: var(--r-md);
  background: var(--green-dim); border: 1px solid rgba(var(--green-rgb), .3);
}
/* --muted, NOT --faint. This panel sits on the accent tint, which in light is
   a lavender wash rather than the page grey, and --faint lands at 4.23:1 on it
   — under AA by a hair, which is exactly the kind of miss that only an audit
   finds. Everything inside a tinted panel gets the darker ink. */
.h-co__payh {
  margin: 0 0 8px; font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted);
}
.h-co__payrow {
  display: flex; justify-content: space-between; gap: 10px;
  padding: 4px 0; font-size: 13px; color: var(--muted);
  border-bottom: 1px dashed var(--line);
}
.h-co__payrow small { color: var(--muted); }
.h-co__pay .h-co__fine, .h-co__pay .h-co__help { color: var(--muted); }
.h-co__paytotal {
  display: flex; justify-content: space-between; gap: 10px;
  margin-top: 8px; font-size: 16px; font-weight: 800; color: var(--ink);
}

.h-co__warn {
  margin: 0; padding: 10px 12px; border-radius: var(--r-md); font-size: 12.5px; line-height: 1.5;
  background: rgba(var(--warn-wash-rgb), .12); border: 1px solid var(--warn); color: var(--ink);
}
/* THE SEND WARNING IS STYLED AS A DANGER, ON PURPOSE — the live app's choice
   and the right one. Somebody who reads a soft grey note walks away believing
   the ice is booked. */
/* THE WASH IS LAID OVER --panel, NOT OVER WHATEVER HAPPENS TO BE BEHIND IT.

   A translucent tint is not a colour until you know what is under it. This card
   sits directly on the page, so in light the ink measured **4.09:1** against
   the wash-over-#E8E8E8 — a fail — while the identical card on a white panel
   measures 4.94 and passes. That is not a property anybody can see by reading
   this rule, and it is exactly what the composited browser pass in
   tools/_contrast-dom.mjs was built to catch. It caught this on its first run.

   Painting the tint as a gradient layer ON TOP of an opaque `--panel` makes the
   result the same wherever the card is put: 5.84 in dark, 4.94 in light. */
.h-co__warn.is-hard {
  background:
    linear-gradient(rgba(var(--danger-wash-rgb), .1), rgba(var(--danger-wash-rgb), .1)),
    var(--panel);
  border-color: var(--danger); color: var(--danger);
}
.h-co__warn.is-hard strong { font-weight: 800; }
.h-co__cap { margin: 0; font-size: 12.5px; color: var(--warn); line-height: 1.5; }
.h-co__gap p { margin: 0; }
.h-co__gapacts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }

.h-co__acts { display: flex; gap: 8px; }
.h-co__acts .h-btn { flex: 1 1 auto; }

/* --- my sessions --------------------------------------------------------- */
.h-co__bk {
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--panel); margin-bottom: 8px; overflow: hidden;
}
/* A pending request is DASHED and a cancelled one is dimmed — the live app's
   own signal, and it survives a greyscale screenshot, which colour alone does
   not. */
.h-co__bk.is-pending { border-style: dashed; border-color: var(--warn); }
/* OPACITY IS THE WRONG TOOL FOR "THIS IS OVER". Dimming the whole card
   multiplies through to the text inside it and drags it under AA — axe caught
   these at 3.36:1 the first time this surface was audited. The card recedes
   through its BACKGROUND and its border instead, and every word in it stays at
   full contrast. Somebody re-reading why they were declined is exactly the
   person who needs to be able to read it. */
.h-co__bk.is-declined, .h-co__bk.is-cancelled {
  background: var(--bg);
  border-color: var(--line);
  border-style: dashed;
}
.h-co__bk.is-confirmed { border-color: rgba(var(--green-rgb), .45); }

.h-co__bkhead {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 12px; background: none; border: 0; cursor: pointer;
  color: inherit; font: inherit; text-align: left;
}
.h-co__bkday { display: block; font-size: 14px; font-weight: 700; color: var(--ink); }
.h-co__bktime { display: block; font-size: 12px; color: var(--faint); }
/* Book a Coach pass: who asked (the coach's side) or which coach (the member's). */
.h-co__bkwho { display: block; margin-top: 2px; font-size: 12.5px; font-weight: 700; color: var(--ink); }
.h-co__pill {
  flex: 0 0 auto; font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; padding: 4px 9px; border-radius: var(--r-pill);
  background: var(--elev); color: var(--muted);
}
/* COMPOSITED (08-18j) — the confirmed sibling below already names an opaque
   token; this one was the only pill on the card still see-through. */
.h-co__bk.is-pending .h-co__pill {
  background: linear-gradient(rgba(var(--warn-wash-rgb),.18), rgba(var(--warn-wash-rgb),.18)), var(--panel);
  color: var(--warn);
}
.h-co__bk.is-confirmed .h-co__pill { background: var(--green-dim); color: var(--green); }
/* The danger tint at 15% is too pale to carry 10px bold text in light. The
   pill goes to plain ink on the elevated surface — the dashed border is
   already saying "finished", so the pill only has to say WHICH kind. */
.h-co__bk.is-declined .h-co__pill,
.h-co__bk.is-cancelled .h-co__pill {
  background: var(--elev);
  color: var(--muted);
  border: 1px solid var(--line2);
}

.h-co__bkbody {
  padding: 0 12px 12px; display: flex; flex-direction: column; gap: 10px;
  border-top: 1px solid var(--line);
}
.h-co__bkline { margin: 10px 0 0; font-size: 13px; color: var(--ink); line-height: 1.5; }
.h-co__bkline > span {
  display: block; font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--faint); margin-bottom: 2px;
}
.h-co__declined {
  padding: 10px 12px; border-radius: var(--r-md);
  background: rgba(var(--danger-wash-rgb), .08); border: 1px solid rgba(var(--danger-wash-rgb), .3);
}
.h-co__declined .h-co__bkline:first-child { margin-top: 0; }

.h-co__decform { display: flex; flex-direction: column; gap: 8px; }

@media (max-width: 560px) {
  .h-co__body { padding: 12px; }
  .h-co__field { flex-basis: 100%; }
  .h-co__addrow .h-btn { width: 100%; }
}

/* --- the Sessions rail (replaced the empty Seasons one) ------------------- */
.h-rail__item--sess { align-items: flex-start; }
.h-rail__sess { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.h-rail__sessn {
  font-size: 13px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.h-rail__sessw { font-size: 11px; color: var(--muted); }
/* A cancelled game STAYS IN THE LIST and says so. Dropping it is how somebody
   drives to a rink for a game that was called off. Struck through rather than
   dimmed, so the words keep their contrast. */
.h-rail__item--sess.is-off .h-rail__sessn { text-decoration: line-through; color: var(--muted); }
.h-rail__item--sess.is-off .h-rail__sessw { color: var(--danger); }

/* --- the booking calendar ------------------------------------------------- */
.h-co__cal { display: flex; flex-direction: column; gap: 10px; }

.h-co__strip-days {
  display: flex; gap: 6px; overflow-x: auto; padding-bottom: 4px;
  scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
}
.h-co__day {
  flex: 0 0 auto; scroll-snap-align: start;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 46px; padding: 7px 8px 6px; cursor: pointer;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
  color: var(--ink); font: inherit;
}
.h-co__day.is-on { border-color: var(--green); background: var(--green-dim); }
/* A DAY WITH NOTHING FREE IS SHOWN AND DISABLED, never hidden. Hiding it makes
   a coach look unavailable for a fortnight when really they are busy Tuesday. */
.h-co__day.is-empty { cursor: default; color: var(--faint); }
.h-co__dayw { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; }
.h-co__dayn { font-size: 15px; font-weight: 700; }
.h-co__daydot { width: 5px; height: 5px; border-radius: 50%; background: var(--green); }
.h-co__daydot.is-none { background: transparent; }

.h-co__legend {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: 11.5px; color: var(--muted);
}
.h-co__key { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.h-co__key.is-free { background: var(--green-dim); border: 1px solid var(--green); }
.h-co__key.is-mine { background: var(--purple-solid); }
.h-co__hint { margin-left: auto; }

.h-co__grid {
  position: relative; margin-left: 34px;
  border-left: 1px solid var(--line);
  /* The live grid's own scale — 50px an hour, 06:00 to 23:00 — so the shapes
     read the same as the app people already know. */
}
.h-co__hour {
  position: absolute; left: 0; right: 0; height: 0;
  border-top: 1px solid var(--line);
}
.h-co__hour span {
  position: absolute; left: -34px; top: -7px; width: 28px; text-align: right;
  font-size: 10px; color: var(--faint);
}

.h-co__free {
  position: absolute; left: 2px; right: 2px; z-index: 2;
  display: flex; align-items: flex-start; padding: 2px 6px; cursor: pointer;
  background: var(--green-dim); border: 1px solid var(--green); border-radius: var(--r-sm);
  /* THE LABEL IS INK, not the accent. The accent on its own 13%-tint is
     3.5:1 in the light theme — the tint and the text are the same hue, which
     is exactly the trap. The border and the fill carry the "available"
     meaning; the time has to be readable. */
  color: var(--ink); font: inherit; font-size: 11px; font-weight: 700;
  text-align: left;
}
.h-co__free:hover { background: rgba(var(--green-rgb), .22); }

/* PURPLE, NOT GREEN, and deliberately so: availability is green, and a green
   block on a green band is invisible. The live app hard-codes its selection to
   the secondary accent in both themes for exactly this reason. */
.h-co__sel {
  position: absolute; left: 8px; right: 8px; z-index: 3;
  display: flex; align-items: center; gap: 6px; padding: 2px 6px;
  background: var(--purple-solid); border: 2px solid var(--purple); border-radius: var(--r-sm);
  color: var(--on-purple); box-shadow: var(--sh-chip);
  overflow: hidden;
}
.h-co__selt { flex: 1 1 auto; min-width: 0; font-size: 11.5px; font-weight: 700;
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-co__selacts { flex: 0 0 auto; display: flex; gap: 3px; }
/* WHITE INK, AND A SCRIM DARK ENOUGH TO CARRY IT IN BOTH THEMES.

   This said `color: var(--on-purple)` on a scrim laid over the selection chip,
   which is GREEN. In dark that token is white and it looked right; in light it
   flips to #0A0A0A, so the − and + buttons rendered black on dark green at
   **3.69:1**. A token borrowed from the pair it does not belong to — the same
   shape as the rail count badge (08-17z) and the danger button (08-17w).

   White cannot work over a .25 scrim in DARK either (2.63 on #07F708), so the
   fix is not the ink alone: the scrim goes to .55, where white measures 6.39 in
   dark and 10.48 in light. One ink, one scrim, both themes. (08-18a) */
.h-co__selacts button {
  width: 20px; height: 20px; border-radius: 4px; cursor: pointer;
  /* TOKENISED ON THE SECOND ATTEMPT. The first one reverted: the wash lint in
     `tests/contrast.test.mjs` found washes by matching a LITERAL rgba(), so a
     var() made this rule invisible to it and its own exemption then read as
     stale — the suite went red for a rule that had not moved a pixel. Proto
     taught the lint to resolve a var() (2026-09-04) and it now measures this
     rule through the tokens. */
  background: var(--scrim-chip); border: 1px solid var(--hairline-on-scrim);
  color: var(--on-colour); font: inherit; font-size: 12px; line-height: 1;
  display: grid; place-items: center;
}
.h-co__selacts button:hover { background: var(--scrim-chip-hover); }

@media (max-width: 560px) {
  .h-co__hint { display: none; }
}

/* --- StaffHub: when I work ------------------------------------------------ */
.h-sh { display: flex; flex-direction: column; gap: 12px; min-height: 0; }
.h-sh__tabs { align-self: stretch; }
.h-sh__body { min-height: 0; }
.h-sh__lede { margin: 0 0 12px; font-size: 13px; color: var(--muted); line-height: 1.5; }
.h-sh__none { margin: 12px 0 0; font-size: 13px; color: var(--faint); }

.h-sh__week { display: flex; flex-direction: column; gap: 6px; }
.h-sh__day {
  padding: 10px 12px; border-radius: var(--r-md);
  background: var(--panel); border: 1px solid var(--line);
}
/* A day that is worked reads differently from one that is not, at a glance —
   the whole point of this screen is seeing your week, not reading it. */
.h-sh__day.is-on { border-color: rgba(var(--green-rgb), .45); }
.h-sh__dayh { display: flex; align-items: center; gap: 10px; }
.h-sh__dayn { font-size: 14px; font-weight: 700; flex: 1 1 auto; }
.h-sh__off { font-size: 12px; color: var(--faint); }
.h-sh__dayh .h-btn { flex: 0 0 auto; }

.h-sh__blocks { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.h-sh__block { display: flex; align-items: center; gap: 8px; }
/* 16px, because iOS zooms any input under it on focus and throws the layout
   off-screen mid-tap. */
.h-sh__block input { font-size: 16px; }
.h-sh__to { font-size: 12px; color: var(--faint); }
.h-sh__x {
  flex: 0 0 26px; height: 26px; border-radius: 50%; margin-left: auto;
  background: none; border: 0; cursor: pointer; color: var(--muted); font-size: 12px;
}
.h-sh__x:hover { color: var(--danger); background: var(--panel2); }

.h-sh__save {
  display: flex; align-items: center; gap: 10px; margin-top: 14px;
  padding-top: 12px; border-top: 1px solid var(--line);
}
.h-sh__dirty { flex: 1 1 auto; font-size: 12px; color: var(--muted); }

.h-sh__adjs { display: flex; flex-direction: column; gap: 6px; margin-top: 12px; }
.h-sh__adj {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; border-radius: var(--r-md);
  background: var(--elev); border: 1px solid var(--line);
}
.h-sh__adjd { display: block; font-size: 13px; font-weight: 700; }
.h-sh__adjw { display: block; font-size: 12px; color: var(--muted); }
.h-sh__adjtag {
  flex: 0 0 auto; font-size: 10px; font-weight: 800; text-transform: uppercase;
  letter-spacing: .04em; padding: 2px 8px; border-radius: var(--r-pill);
  background: var(--panel); border: 1px solid var(--line2); color: var(--muted);
}
/* Time off is the one that STOPS a booking, so it is the one that gets the
   colour. Extra hours only ever add. */
.h-sh__adj.is-time_off .h-sh__adjtag {
  /* COMPOSITED (08-18j). This tag lands inside `.h-sh__job`, and a done job
     row repaints itself `var(--bg)` — so the surface behind this wash really
     does change underneath it, which is the exact hazard the shape names. */
  background: linear-gradient(rgba(var(--warn-wash-rgb),.18), rgba(var(--warn-wash-rgb),.18)), var(--panel);
  color: var(--warn); border-color: var(--warn);
}

.h-sh__addadj {
  display: flex; flex-direction: column; gap: 10px; margin: 12px 0;
  padding: 12px; border-radius: var(--r-md);
  background: var(--panel); border: 1px solid var(--line);
}
.h-sh__f { display: flex; flex-direction: column; gap: 4px; }
.h-sh__f > span {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--faint);
}
.h-sh__f > span small { font-size: 10px; font-weight: 500; text-transform: none; letter-spacing: 0; }
.h-sh__f input { font-size: 16px; }
.h-sh__times { display: flex; gap: 10px; }
.h-sh__times .h-sh__f { flex: 1 1 0; min-width: 0; }
.h-sh__toggle { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.h-sh__toggle input { width: 16px; height: 16px; accent-color: var(--green); }
.h-sh__acts { display: flex; gap: 8px; }
.h-sh__acts .h-btn { flex: 1 1 auto; }

/* --- StaffHub: my work --------------------------------------------------- */
.h-sh__sech {
  margin: 18px 0 8px; font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--faint);
}
.h-sh__jobs { display: flex; flex-direction: column; gap: 6px; }
.h-sh__job {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 12px; border-radius: var(--r-md);
  background: var(--panel); border: 1px solid var(--line);
}
/* Finished work recedes through its BACKGROUND, never through opacity — that
   multiplies through to the text and drags it under AA. Same lesson as the
   booking cards. */
.h-sh__job.is-done { background: var(--bg); border-style: dashed; }
.h-sh__jobt { display: block; font-size: 14px; font-weight: 700; }
.h-sh__jobev { font-weight: 500; color: var(--muted); }
.h-sh__jobw { display: block; font-size: 12px; color: var(--muted); }
/* §9.1: a shift that changed after the coach confirmed it says so in words, in the warning colour, under its time. */
.h-sh__reconfirm { color: var(--warn); font-weight: 700; }
.h-sh__jobacts { display: flex; gap: 6px; flex: 0 0 auto; }
.h-sh__in {
  flex: 0 0 auto; font-size: 10px; font-weight: 800; text-transform: uppercase;
  letter-spacing: .04em; padding: 2px 8px; border-radius: var(--r-pill);
  background: var(--green-dim); color: var(--green); border: 1px solid var(--green);
}
.h-sh__doneTag {
  font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em;
  padding: 4px 9px; border-radius: var(--r-pill);
  background: var(--elev); color: var(--muted); border: 1px solid var(--line2);
}
/* A request waiting on you is the only thing on this screen that needs doing
   today, so it sits above everything and says how many. */
.h-sh__pending {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 12px; margin-bottom: 12px; border-radius: var(--r-md); font-size: 13px;
  background: rgba(var(--warn-wash-rgb), .12); border: 1px solid var(--warn); color: var(--ink);
}
.h-sh__pending .h-btn { margin-left: auto; }

@media (max-width: 560px) {
  .h-sh__jobacts { width: 100%; }
  .h-sh__jobacts .h-btn { flex: 1 1 auto; }
}

/* ===========================================================================
   STAFF ADMIN  (assets/js/staffadmin.js)

   Manager-only. Deliberately plainer than the member surfaces: this is a
   back-office screen and the thing that matters is that a rate and a listing
   toggle are unmistakable, not that the card has a gradient.

   NOTHING RECEDES BY OPACITY. Dimming a card with `opacity` drags its text
   under the AA contrast floor along with it, and this project has shipped that
   twice — booking cards on 08-08, and again in the staff hub. Where something
   needs to sit back, it sits back on its own background colour.
   ========================================================================= */
.h-sa { display: flex; flex-direction: column; gap: 14px; }

.h-sa__bar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.h-sa__srch { position: relative; flex: 1 1 200px; display: flex; align-items: center; }
.h-sa__srch .h-ic {
  position: absolute; left: 10px; width: 16px; height: 16px;
  color: var(--faint); pointer-events: none;
}
.h-sa__srch .h-input { padding-left: 32px; width: 100%; }

.h-sa__tabs { display: flex; gap: 8px; flex-wrap: wrap; }

.h-sa__list { display: flex; flex-direction: column; gap: 6px; }
.h-sa__row {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 12px 14px; text-align: left;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
  color: var(--ink); cursor: pointer;
}
.h-sa__row:hover { border-color: var(--line2); background: var(--panel2); }
/* Focus ring: the global `:focus-visible` in base.css already answers this.
   A private ring here would be a second answer to the same question. */
.h-sa__who { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.h-sa__nm { font-weight: 650; font-size: 15px; }
.h-sa__sub {
  font-size: 13px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.h-sa__tags { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.h-sa__count { margin: 2px 0 0; font-size: 12px; color: var(--muted); }

/* RINKS (0004's `area`, finally creatable — 2026-08-17). Three rules, because
   the row itself reuses `h-sa__row` / `__who` / `__nm` / `__sub` rather than
   growing a parallel set of names for the same three things. */
.h-sa__racts { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; flex: none; }
/* A CLOSED RINK IS STILL LISTED, and reads as switched off rather than missing
   — nothing is deleted, and a manager needs to find it again to re-open it. */
.h-sa__row.is-off { opacity: .62; }
.h-sa__row.is-off:hover { opacity: 1; }
/* The edit form replaces the row in place, so it stacks instead of sitting in
   one line. `cursor: pointer` from `.h-sa__row` would be a lie over a form. */
.h-sa__row--form { display: block; cursor: default; }
.h-sa__row--form:hover { background: var(--panel); border-color: var(--line); }

/* 🚦 PAGES AND FEATURES (the surface control, 2026-09-03). TWO RULES, and both
   are about a row that carries a SENTENCE rather than a stat line.

   ⚠️ `.h-sa__sub` IS DELIBERATELY ONE LINE WITH AN ELLIPSIS — right for a
   rink's "Kanata · 23 members · 4 posts", wrong for "SELF-LOCKING. The sign-in
   handler itself — closing it removes every route to proving you may reopen
   it." **A truncated reason is the same as no reason**, which is the exact
   thing the unsettable rows exist to avoid, so the why line wraps.

   AND THE ROW WRAPS TOO. Four state buttons plus a name do not fit a phone at
   one line; without this the switch runs off the edge of the screen it is the
   only way to reach. */
.h-sa__row--srf { flex-wrap: wrap; cursor: default; }
.h-sa__row--srf:hover { background: var(--panel); border-color: var(--line); }
.h-sa__why { white-space: normal; overflow: visible; text-overflow: clip; }

/* `.h-sa__back` RETIRED ON 2026-09-17, Meryl, `Q-02` -- and ITS SHAPE IS THE
   ONE THAT SURVIVED. Of the six looks this control had, this was already the
   right one: a chevron, the screen's own words, muted, quiet. `.h-back` in
   components.css is this rule under a shared name. */
.h-sa__h { margin: 0; font-size: 19px; }

.h-sa__card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 14px; display: flex; flex-direction: column; gap: 12px;
}
.h-sa__cardh {
  font-size: 12px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted);
}
.h-sa__f { display: flex; flex-direction: column; gap: 5px; font-size: 13px; }
.h-sa__f > span { color: var(--muted); }
.h-sa__f textarea { resize: vertical; min-height: 64px; font: inherit; }

.h-sa__sw, .h-sa__ck {
  display: flex; align-items: center; gap: 9px; font-size: 14px; cursor: pointer;
}
.h-sa__sw input, .h-sa__ck input { width: 17px; height: 17px; flex: 0 0 auto; accent-color: var(--green); }
.h-sa__row2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }

.h-sa__hint { margin: 0; font-size: 12px; color: var(--muted); line-height: 1.5; }
.h-sa__acts { display: flex; gap: 10px; flex-wrap: wrap; }

/* The "what this screen does not do" footer. It recedes on BACKGROUND, never
   on opacity — see the header note. */
.h-sa__note {
  background: var(--bg); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 12px 14px;
  font-size: 12px; color: var(--muted); line-height: 1.55;
}
.h-sa__note p { margin: 0 0 8px; }
.h-sa__note p:last-child { margin-bottom: 0; }
.h-sa__note strong { color: var(--ink); }

@media (max-width: 560px) {
  .h-sa__row2 { grid-template-columns: 1fr; }
  .h-sa__acts .h-btn { flex: 1 1 auto; }
  .h-sa__tags { justify-content: flex-start; }
}

/* ===========================================================================
   INVOICES  (assets/js/invoices.js)

   THE STATUS CHIP HAS TO CARRY MEANING WITHOUT COLOUR. `.h-tag--bad` and
   `.h-tag--warn` differ by hue, and roughly one man in twelve cannot tell one
   from the other — so the WORD is the signal ("Overdue" / "Part paid") and the
   colour only reinforces it. Nothing on this screen is colour-only.

   Nothing recedes by opacity: see the note on the staff-admin block above.
   ========================================================================= */
/* `.h-tag` was written for a game card: it carries `margin-top: 8px` and
   `cursor: pointer` because there it is a tappable chip under a heading. In a
   right-aligned status column it is neither, and inheriting both pushes the
   chip out of line and makes a label look clickable. Reset where it is used as
   a plain status badge, rather than forking the class. */
.h-inv__right .h-tag, .h-inv__head .h-tag, .h-sa__tags .h-tag {
  margin-top: 0; cursor: default;
}

.h-tag--ok     { border-color: var(--green); color: var(--green); }
.h-tag--bad    { border-color: var(--danger); color: var(--danger); }
.h-tag--muted  { border-color: var(--line2); color: var(--muted); }

.h-inv { display: flex; flex-direction: column; gap: 14px; }

/* WHAT YOU OWE, FIRST AND BIG — the only question anybody opens this for. */
.h-inv__sum {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 14px 16px;
}
.h-inv__owe { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.h-inv__oweL { font-size: 13px; color: var(--muted); }
.h-inv__oweN { font-size: 26px; font-weight: 750; font-family: var(--font-head); }
.h-inv__cred { margin-top: 6px; font-size: 13px; color: var(--green); }

.h-inv__tabs { display: flex; gap: 8px; flex-wrap: wrap; }
.h-inv__mem { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); cursor: pointer; }
.h-inv__mem input { width: 16px; height: 16px; accent-color: var(--green); }

.h-inv__list { display: flex; flex-direction: column; gap: 6px; }
.h-inv__row {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 12px 14px; text-align: left;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
  color: var(--ink); cursor: pointer;
}
.h-inv__row:hover { border-color: var(--line2); background: var(--panel2); }
.h-inv__main { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1 1 auto; }
.h-inv__t { font-weight: 650; font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-inv__meta { font-size: 12px; color: var(--muted); }
.h-inv__right { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex: 0 0 auto; }
.h-inv__amt { font-weight: 700; font-size: 15px; font-variant-numeric: tabular-nums; }

.h-inv__back {
  display: inline-flex; align-items: center; gap: 4px; align-self: flex-start;
  background: none; border: 0; padding: 4px 0; color: var(--muted); font-size: 13px; cursor: pointer;
}
.h-inv__back:hover { color: var(--ink); }
.h-inv__back .h-ic { width: 14px; height: 14px; }

.h-inv__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.h-inv__h { margin: 0; font-size: 19px; }
.h-inv__desc { margin: 0; font-size: 14px; color: var(--muted); }
/* INV-02 — THE DESCRIPTION IS CLAMPED HERE, NOT CUT IN THE CLIENT. It is
   `space.description` on a registration invoice, which is an organiser's free
   text and has no length anybody agreed to. `content.css`'s `.h-card__s` made
   this call already and the reason is the same one: how many lines fit is a
   question about THIS screen's width, and only this screen can answer it. A
   character count in JS is a guess that is wrong on every other viewport. */
.h-inv__desc.is-clamped {
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
.h-inv__descmore {
  background: none; border: 0; padding: 2px 0; margin: 0;
  font: inherit; font-size: 13px; color: var(--muted); cursor: pointer;
}
.h-inv__descmore:hover { color: var(--green); }

.h-inv__card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 14px; display: flex; flex-direction: column; gap: 12px;
}
.h-inv__lines, .h-inv__tot { display: flex; flex-direction: column; gap: 6px; }
.h-inv__tot { border-top: 1px solid var(--line); padding-top: 10px; }
.h-inv__li {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  font-size: 14px;
}
/* TABULAR FIGURES so a column of money lines up. Proportional digits make
   $9.00 and $11.00 sit at different widths and the column reads as ragged. */
.h-inv__li > span:last-child { font-variant-numeric: tabular-nums; white-space: nowrap; }
.h-inv__li.is-strong { font-weight: 700; }
.h-inv__bal {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  border-top: 1px solid var(--line); padding-top: 10px;
  font-size: 16px; font-weight: 750;
}
.h-inv__bal > span:last-child { font-variant-numeric: tabular-nums; }

.h-inv__note {
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 12px 14px; font-size: 13px; line-height: 1.55;
}
.h-inv__note strong { display: block; margin-bottom: 4px; }
.h-inv__note p { margin: 0; color: var(--muted); }
/* LR-06: How to pay — one line per way, the address and reference selectable. */
/* LR-06 (walk v54): the heading of the block — bigger, an icon, a rule under it. */
.h-inv__how .h-inv__howh { display: flex; align-items: center; gap: 8px; margin: 0 0 12px; padding-bottom: 10px;
  border-bottom: 1px solid var(--line); color: var(--ink); font-size: 16px; font-weight: 800; letter-spacing: .01em; }
.h-inv__how .h-inv__howh .h-ic { width: 18px; height: 18px; color: var(--green); }
.h-inv__how p { margin: 0 0 8px; color: var(--ink); line-height: 1.5; }
.h-inv__how p:last-child { margin-bottom: 0; }
.h-inv__how .h-inv__k { display: block; color: var(--green); font-size: 12px; letter-spacing: .04em; text-transform: uppercase; }
/* LR-06 (Karl): an inline Copy details link inside the sentence. */
.h-inv__link { display: inline; padding: 0; border: 0; background: none; color: var(--green); font: inherit; font-weight: 700;
  text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.h-inv__how .h-inv__paybtn { display: inline-flex; width: auto; margin: 0 0 12px; }
/* Karl (walk v45): a thin line between the card button and By Interac e-Transfer. */
.h-inv__how .h-inv__paybtn + p { padding-top: 12px; border-top: 1px solid var(--line); }
.h-inv__sel { user-select: all; -webkit-user-select: all; }
.h-inv__et { margin: 4px 0 8px; padding: 10px 12px; border: 1px dashed var(--line2); border-radius: var(--r-sm);
  background: var(--panel2); color: var(--ink); font: 13px/1.5 var(--font-body); white-space: pre-wrap; }
.h-inv__etcopy { display: inline-flex; align-items: center; gap: 6px; }
.h-inv__etcopy .h-ic { width: 16px; height: 16px; }

.h-inv__acts { display: flex; gap: 10px; flex-wrap: wrap; }

/* --- the staff end of an invoice -----------------------------------------
   Boxed and labelled, because these two controls do something no other
   control on this screen does: they write to somebody ELSE'S money. A member
   never sees this block at all — the server decides — but the person who does
   see it is looking at a screen that is otherwise entirely read-only, and an
   unmarked button there reads as "view", not "record a payment". */
.h-inv__staff {
  background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 12px 14px; margin-top: 14px;
  display: flex; flex-direction: column; gap: 9px;
}
.h-inv__staffH {
  font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase;
  font-weight: 800; color: var(--muted);
}
.h-inv__f { display: flex; flex-direction: column; gap: 4px; }
.h-inv__f > span { font-size: 11.5px; color: var(--muted); font-weight: 700; }
/* CANCEL SITS APART FROM THE PAY FORM. Two buttons in a row, one of which
   destroys the invoice, is a mis-tap waiting — it is armed as well, but the
   spacing should say so before the arming has to. */
.h-inv__cancel { margin-top: 4px; }
.h-inv__cancel:hover { border-color: var(--danger); color: var(--danger); }
.h-inv__hint { margin: 0; font-size: 11px; color: var(--faint); }
/* ISSUE SITS AT THE TOP OF THE STAFF BLOCK AND APART FROM THE PAY FORM, the
   mirror of the note on Cancel above. Issuing turns a draft into a bill;
   recording a payment assumes a bill already exists. Two controls that belong
   to different moments should not read as one row of choices. */
.h-inv__issue { align-self: flex-start; margin-bottom: 4px; }

.h-inv__hist {
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-md); padding: 12px 14px;
  display: flex; flex-direction: column; gap: 6px;
}
.h-inv__histH {
  font-size: 12px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted);
}

/* UNDO SITS INSIDE THE HISTORY ROW, small and quiet. It is a staff act on a
   ledger a member may also be reading, so it must not compete with the amount
   beside it — the amount is the fact, this is the correction. `--muted` rather
   than `--danger` until hover for the same reason the Cancel button waits:
   nothing here is destroyed, a reversing row is added, and colouring it as a
   deletion would misdescribe what it does. 32px of hit height keeps it a real
   target next to a number, which is the failure mode of every small inline
   control in this app. */
.h-inv__undo {
  margin-left: 8px; padding: 4px 8px; min-height: 32px;
  font: inherit; font-size: 12px; font-weight: 600;
  color: var(--muted); background: transparent;
  border: 1px solid var(--line); border-radius: var(--r-sm); cursor: pointer;
}
.h-inv__undo:hover { border-color: var(--danger); color: var(--danger); }
.h-inv__undo[disabled] { opacity: .5; cursor: default; }
/* A payment that WAS a reversal is labelled rather than styled away — the row
   stays, because a ledger you can visually lose a row from is not a ledger. */
.h-inv__undone { font-style: normal; font-size: 11px; color: var(--faint); }

@media (max-width: 560px) {
  .h-inv__acts .h-btn { flex: 1 1 auto; }
  .h-inv__oweN { font-size: 22px; }
}

/* === PARTNERS ==============================================================
   The directory, one partner, and the apply form. Added 08-09 with
   assets/js/partners.js.

   TWO THINGS WORTH KNOWING BEFORE EDITING THIS BLOCK:

   1. `.h-pt__logo` IS THE ONLY PLACE IN THE APP A THIRD PARTY PICKS A COLOUR.
      A partner's brand colour arrives from the database as an inline
      `background`, so nothing here may set one — a rule with the same
      specificity would win on some rows and lose on others depending on load
      order, and the result is a directory where a third of the logos are the
      partner's colour and the rest are not. The tokens below are the FALLBACK
      only, and they live on the element, not on a competing rule.

   2. THE PERK BLOCK IS DELIBERATELY LOUD. It is the reason somebody opens a
      partner at all, and the live overlay buries it under the description.
      Green border, own panel, above the buttons.
   ========================================================================== */
.h-pt { display: flex; flex-direction: column; gap: 14px; }

.h-pt__lede { margin: 0; color: var(--muted); font-size: 13.5px; line-height: 1.55; }

/* --- search -------------------------------------------------------------- */

.h-pt__chips { display: flex; flex-wrap: wrap; gap: 6px; }

/* --- the list ------------------------------------------------------------ */


/* CATEGORY FEATURED — the partner bought the top of their category (0400).
   Power Play Purple, because it is the brand's premium colour and this is the
   premium placement; the same left-accent shape `.h-room__next` uses, so a
   member reads it as "this one is picked out" rather than as a different kind
   of thing.
   ⚠️ DELIBERATELY RESTRAINED. Featured is SOFT — everyone else is still in this
   category at standard visibility — and the placements spec draws the line at
   "tasteful, not ad-overload". An accent and a tag, not a different card. */

/* WHAT A PARTNER PUTS THEIR NAME ON (0400). Deliberately quieter than the perk
   block above it: the perk is what the MEMBER gets and is the reason they tap,
   this is recognition the PARTNER bought. Ordering the two the other way round
   would be the ad-overload the placements spec warns off. */
/* ⚠️ THE TEXT IS `--ink`, NOT `--purple`, AND THAT IS NOT A STYLE CHOICE.
   Purple-on-purple-dim measures 3.74:1 in light and 2.77:1 in dark — both under
   the 4.5 bar — which `tests/contrast.test.mjs` caught before this shipped. The
   green tag next door gets away with the same shape because green-dim is a
   different wash; copying its pattern by eye is exactly how an unreadable badge
   ships. The purple stays as the BORDER, which carries no text. */
.h-tag--feat {
  border-color: var(--purple); color: var(--ink); background: var(--purple-dim);
}


/* `.h-tag` carries `margin-top: 8px` for its use inside a game card; inside a
   flex meta row that gap is already handled by the row itself. */
.h-tag--ok { border-color: var(--green); color: var(--green); background: var(--green-dim); }

/* --- the "run a business?" call ------------------------------------------ */

/* --- the review queue (staff only) ---------------------------------------
   The way in is a plain row rather than a button in the CTA above it: this is
   a staff tool sitting under a member surface, and it should read as a
   different kind of thing from "Get in touch". */
.h-pt__review {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; margin-top: 10px; padding: 11px 14px;
  background: none; border: 1px solid var(--line); border-radius: var(--r-md);
  font: inherit; font-size: 13px; font-weight: 700; color: var(--ink);
  cursor: pointer; text-align: left;
}
.h-pt__review:hover { border-color: var(--green); }
.h-pt__count { flex: none; font-size: 11.5px; font-weight: 700; color: var(--muted); }

/* ONE APPLICATION, WHOLE. Everything the business sent is on the card,
   because the decision and the thing being decided on should not be a click
   apart. */
.h-pt__app {
  background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 12px 14px; margin-bottom: 10px;
}
.h-pt__appH { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.h-pt__appH strong { font-size: 13.5px; min-width: 0; overflow-wrap: anywhere; }
.h-pt__appH .h-tag { margin-left: auto; }
.h-pt__appMeta {
  margin: 5px 0 0; font-size: 12px; color: var(--muted); overflow-wrap: anywhere;
}
/* The pitch itself, set apart from the contact line so it reads as something
   somebody wrote rather than another field. */
.h-pt__appMsg {
  margin: 9px 0 0; padding: 9px 11px; font-size: 12.5px;
  background: var(--panel); border-radius: var(--r-sm); border: 1px solid var(--line);
  overflow-wrap: anywhere; white-space: pre-wrap;
}
.h-pt__appActs { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px; }

/* --- partner records (staff) ---------------------------------------------
   A row per partner WHATEVER its status, which is the whole reason this list
   exists apart from the directory: a draft and a published partner read the
   same by name, and only one of them is on members' screens. */
.h-pt__new { margin: 4px 0 14px; }
.h-pt__rec {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: none; border: 0; border-bottom: 1px solid var(--line);
  padding: 11px 0; font: inherit; color: var(--ink); text-align: left; cursor: pointer;
}
.h-pt__rec:last-of-type { border-bottom: 0; }
.h-pt__rec:hover .h-pt__recName { color: var(--green); }
.h-pt__recMain { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.h-pt__recName { font-size: 13.5px; font-weight: 700; overflow-wrap: anywhere; }
.h-pt__recSub { font-size: 11.5px; color: var(--muted); overflow-wrap: anywhere; }
.h-pt__rec .h-tag { flex: none; }
/* WHAT A PARTNER HAS HAD. Two numbers per row, because taps and PEOPLE answer
   different questions — thirty taps from one person is not thirty people. */
.h-pt__rep {
  margin: 14px 0 4px; padding: 12px 13px; border-radius: var(--r-md);
  background: var(--panel2); border: 1px solid var(--line);
}
.h-pt__repH { font-size: 12.5px; font-weight: 800; color: var(--muted); margin-bottom: 8px; }
.h-pt__repRow {
  display: flex; align-items: baseline; gap: 10px; padding: 5px 0;
  font-size: 13px; border-top: 1px solid var(--line);
}
.h-pt__repRow:first-of-type { border-top: 0; }
.h-pt__repRow span { flex: 1 1 auto; min-width: 0; }
.h-pt__repRow b { font-weight: 800; font-variant-numeric: tabular-nums; }
.h-pt__repRow em { font-style: normal; font-size: 11.5px; color: var(--muted); min-width: 72px; text-align: right; }
.h-pt__repRow.is-total { border-top: 1px solid var(--line2); font-weight: 700; }

.h-pt__recActs { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 16px; }

/* --- one partner --------------------------------------------------------- */
.h-pt__back {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  padding: 0; border: 0; background: none; color: var(--muted);
  font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
}
.h-pt__back:hover { color: var(--ink); }
.h-pt__back .h-ic { width: 15px; height: 15px; }

.h-pt__h { margin: 0; font-size: 18px; font-weight: 800; overflow-wrap: anywhere; }

.h-pt__perkH {
  font-size: 10.5px; font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--green); margin-bottom: 5px;
}

.h-pt__hint { margin: 8px 0 0; font-size: 12px; color: var(--muted); }


/* --- the apply form ------------------------------------------------------ */
.h-pt__f { display: flex; flex-direction: column; gap: 5px; font-size: 12.5px; }
.h-pt__f > span { font-weight: 700; color: var(--muted); }
.h-pt__f em { font-style: normal; font-size: 10.5px; color: var(--faint); font-weight: 700; }
/* A CHECKBOX ROW IS THE ONE FIELD THAT IS NOT A COLUMN — the box and its label
   belong on ONE line, and `.h-pt__f`'s `flex-direction: column` puts the box on
   its own row with the words underneath it. `programs.css` hit exactly this and
   its comment says so; the sizing here matches `.pg-fld--check` so the two
   forms agree about how big a checkbox is. 0400. */
.h-pt__f--check { flex-direction: row; align-items: center; gap: 8px; }
.h-pt__f--check input[type="checkbox"] { width: 22px; height: 22px; flex: none; margin: 0; }
.h-pt__f--check > span { font-weight: 700; color: var(--ink); }




/* --- the standing note on a scope whose audience is not there yet --------- */
/* THE FRIENDS-WARNING NOTE STYLE AND ITS TWO MODIFIERS WERE DELETED WITH
   `HUB-02`. hub.js was the only emitter and it no longer emits them, so
   leaving the rules would be an orphan selector — the exact thing
   `client-contracts` exists to catch, pointed the other way. If the warning
   ever comes back it comes back with its own rule and its own reason.
   ⚠️ THE CLASS NAME IS DELIBERATELY NOT WRITTEN OUT HERE: `feed-friends`
   asserts hub.css does not contain it, and that witness cannot tell a rule
   from a comment about a rule. Spelling it to be helpful would turn the
   ratchet red and teach the next seat to weaken it. */

/* --- why you are on a waitlist of a half-empty game ---------------------- */
.h-rsvp__note {
  margin: 0; padding: 9px 11px; border-radius: var(--r-md);
  background: var(--panel2); border: 1px solid var(--line2);
  color: var(--muted); font-size: 12.5px; line-height: 1.5;
}

/* --- why a list row says Waitlist ---------------------------------------- */
.h-scard__why,
.h-agenda__why {
  display: block; margin-top: 3px;
  font-size: 11.5px; line-height: 1.45; color: var(--muted);
}
/* A superseded version. Not archived — the organiser did not withdraw it, a
   newer one took over — so it reads as muted rather than as a warning. */
.h-tag--outdated { color: var(--muted); border-color: var(--line2); }

/* === YOUR FAMILY ==========================================================
   Karl, 2026-08-14: family "feels like an after thought, a feature that is
   hidden inside the more menu... its just crammed in. But the Family feature is
   one of the most used things on hockey365... 60% of our clientel right now are
   people with families."

   This replaces the household SHEET's styles entirely. It is a screen now, in
   the Locker Room — a card per member carrying what is still missing on them,
   and a wizard for adding somebody. See assets/js/family.js.
   ======================================================================== */
.h-fam {
  display: flex; flex-direction: column; gap: 10px;
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

/* --- the one line that says whether there is anything to do --------------- */
.h-fam__top {
  padding: 13px 14px; border-radius: var(--r-md);
  background: var(--panel2); border: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 3px;
}
.h-fam__topn { font-size: 15px; font-weight: 700; }
.h-fam__topn b { font-weight: 850; }
.h-fam__topgap { font-size: 12.5px; font-weight: 750; color: var(--warn); }
.h-fam__topok  { font-size: 12.5px; font-weight: 750; color: var(--green); }
.h-fam__me { font-size: 11.5px; color: var(--muted); }

.h-fam__empty {
  padding: 16px 14px; border-radius: var(--r-md);
  background: var(--panel); border: 1px dashed var(--line2);
}
.h-fam__empty p { margin: 0 0 6px; font-size: 13px; line-height: 1.55; color: var(--muted); }
.h-fam__empty p:last-child { margin-bottom: 0; }
.h-fam__empty b { color: var(--ink); font-size: 14px; }

/* --- a member ------------------------------------------------------------- */
.h-fam__card {
  padding: 13px 14px; border-radius: var(--r-md);
  background: var(--panel); border: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 10px;
}
/* A LEFT EDGE, not a red card. Something still to fill in is a to-do, not an
   error — a member who is 90% set up should not look broken. */
.h-fam__card.has-gap { border-left: 3px solid var(--warn); }
.h-fam__card--adult { background: var(--panel2); }
/* HR-01: the Family members heading wears the members' amber edge as its rule. */
.h-sec-label--amber { --head-rule: var(--warn); }

/* SOMEBODY WHO CAME OF AGE. Not an error edge and not a to-do edge: nothing is
   wrong and nothing is owed — the relationship changed. The green edge is the
   same one this app uses for "this is theirs now" elsewhere, and the card keeps
   its normal weight so a grown child does not read as a problem in a list of
   children. */
.h-fam__card.is-grown { border-left: 3px solid var(--green); }

/* ARRIVED HERE FROM A NOTIFICATION. `H365Family.focus` adds this after
   scrolling, so the row a Needs Attention card named is the row the eye lands
   on. It also takes real focus — the card carries tabindex="-1" — so this is
   the visible half of something that already happened for the keyboard. */
.h-fam__card.is-focused { box-shadow: 0 0 0 2px var(--green); }
.h-fam__card:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }

.h-fam__cardh { display: flex; align-items: center; gap: 11px; }
.h-fam__av {
  flex: none; width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--green-dim); color: var(--green);
  font-size: 16px; font-weight: 800;
}
.h-fam__who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.h-fam__name { font-size: 15px; font-weight: 750; overflow-wrap: anywhere; }
.h-fam__meta { font-size: 11.5px; color: var(--muted); }

/* --- what is still missing on them ---------------------------------------- */
.h-fam__todo { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 6px; }
.h-fam__todo li {
  display: flex; flex-direction: column; gap: 1px;
  padding: 7px 10px; border-radius: var(--r-sm);
  background: var(--panel2); border: 1px solid var(--line);
}
.h-fam__todo li b { font-size: 12.5px; font-weight: 750; }
.h-fam__todo li span { font-size: 11.5px; color: var(--muted); line-height: 1.45; }
.h-fam__set { margin: 0; font-size: 12px; font-weight: 700; color: var(--green); }
/* Karl's walk (10-02): each thing left is a row you tap to fill in now. */
.h-fam__todo--tap li { padding: 0; background: none; border: 0; }
.h-fam__todob { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 9px 12px; border-radius: var(--r-sm); background: var(--panel2); border: 1px solid var(--line); color: var(--ink); cursor: pointer; font: inherit; }
.h-fam__todob:hover, .h-fam__todob:focus-visible { border-color: var(--green); }
.h-fam__todot { display: flex; flex-direction: column; gap: 1px; flex: 1 1 auto; min-width: 0; }
.h-fam__todot b { font-size: 13px; font-weight: 750; }
.h-fam__todot span { font-size: 11.5px; color: var(--muted); line-height: 1.45; }
.h-fam__todo .h-fam__todogo { flex: none; font-size: 20px; line-height: 1; color: var(--green); }
.h-fam__todob.is-static { cursor: default; }
.h-fam__todob.is-done { border-color: color-mix(in srgb, var(--green) 55%, transparent); }
.h-fam__todo .h-fam__todob.is-done .h-fam__todogo { font-size: 12px; font-weight: 700; }
.h-fam__todo .h-fam__todock { flex: none; width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; background: var(--green); color: var(--on-green); font-size: 13px; font-weight: 800; }
.h-fam__emguse, .h-cb__emguse { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.h-fam__now { font-size: 12px; font-weight: 700; color: var(--green); align-self: center; }

.h-fam__acts { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

.h-fam__warn {
  margin: 0; padding: 9px 11px; border-radius: var(--r-md);
  background: var(--panel2); border: 1px solid var(--warn);
  color: var(--ink); font-size: 12px; line-height: 1.5;
}

/* --- somebody asking YOU into their household ----------------------------- */
.h-fam__ask {
  padding: 12px 13px; border-radius: var(--r-md);
  background: var(--panel2); border: 1px solid var(--green);
}
.h-fam__ask p { margin: 0 0 10px; font-size: 12.5px; line-height: 1.55; }

/* --- invitations sent and unanswered -------------------------------------- */
.h-fam__sent {
  padding: 12px 13px; border-radius: var(--r-md);
  background: var(--panel); border: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 8px;
}
.h-fam__sh { font-size: 12.5px; font-weight: 800; color: var(--muted); }
.h-fam__srow { display: flex; align-items: center; gap: 10px; justify-content: space-between; font-size: 12.5px; }
.h-fam__srow em { font-style: normal; color: var(--muted); display: block; font-size: 11.5px; }
.h-fam__sacts { display: flex; gap: 6px; flex: none; margin-left: auto; }
/* Phone width (pre-walk 10-03): the state line was squeezed to a word per line beside two buttons. */
.h-fam__srow { flex-wrap: wrap; }
.h-fam__srow > span:first-child { flex: 1 1 200px; min-width: 0; }

/* WHO CAN SEE *YOUR* ACCOUNT — the adult's own guardians, and the one block on
   this screen pointing the other way (Meryl, 2026-08-23, Karl's 08-22 ruling).

   TOKENS ONLY, so both themes inherit and neither needs an override: `--panel2`
   on `--line`, `--ink` for the name, `--muted` for the hint. That is the rule
   `.pg-mini.danger` broke yesterday by reaching for a hard-coded pair, and the
   reason `contrast` measures composited colour rather than declared colour. */
.h-fam__mine {
  margin-top: 2px; padding: 13px 14px; border-radius: var(--r-md);
  background: var(--panel2); border: 1px solid var(--line);
}
.h-fam__mineh { font-size: 13px; font-weight: 800; margin-bottom: 4px; }
.h-fam__minelist { list-style: none; margin: 8px 0 0; padding: 0; display: flex;
  flex-direction: column; gap: 6px; }
/* THE NAME AND THE CONTROL ON ONE ROW, the control hard against the right so a
   column of them reads as a list rather than as ragged pairs. `gap` rather than
   a margin, so a long name wraps without pushing the button off the edge. */
.h-fam__minerow {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 10px; border-radius: var(--r-sm);
  background: var(--panel); border: 1px solid var(--line2);
}
.h-fam__minen { font-size: 13.5px; font-weight: 700; min-width: 0; overflow-wrap: anywhere; }

.h-fam__add { display: flex; flex-direction: column; gap: 8px; margin-top: 2px; }
.h-fam__foot { margin: 2px 0 14px; font-size: 11.5px; color: var(--muted); line-height: 1.5; }

/* --- the add-a-member wizard ---------------------------------------------- */
.h-fam__wz {
  padding: 14px; border-radius: var(--r-md);
  background: var(--panel); border: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 12px;
}
.h-fam__wzbar { display: flex; gap: 5px; }
.h-fam__seg { flex: 1; height: 3px; border-radius: 2px; background: var(--line2); }
.h-fam__seg.is-done { background: var(--green); }
.h-fam__seg.is-now  { background: var(--green); }
.h-fam__wzh { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.h-fam__wzt { font-size: 16px; font-weight: 800; }
.h-fam__wzs { font-size: 11.5px; color: var(--muted); flex: none; }
.h-fam__wzb { display: flex; flex-direction: column; gap: 12px; }
/* THE SKIP SITS BETWEEN THEM, so the thumb does not find it on the way to
   Continue. Karl asked for steps somebody can skip; a skip that is easy to hit
   by accident is a step that silently does not happen. */
.h-fam__wzacts { display: flex; gap: 8px; align-items: stretch; }
/* The primary gets the room; Leave and Skip take only what their word needs, so
   three controls fit one line on a 390px phone without wrapping. */
.h-fam__wzacts .h-btn { flex: 0 0 auto; white-space: nowrap; }
.h-fam__wzacts [data-w-next], .h-fam__wzacts [data-w-close] { flex: 1 1 auto; }

.h-fam__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.h-fam__f { display: flex; flex-direction: column; gap: 4px; }
.h-fam__fl { font-size: 11.5px; color: var(--muted); font-weight: 700; }
.h-fam__hint { margin: 0; font-size: 11.5px; color: var(--muted); line-height: 1.5; }
/* B29 (Karl, walk v45): a child's profile — what is left, beside its Finish
   setting up button, under "You're viewing"; and the permission checkboxes. */
/* FM-02 (Karl): the viewing bar — two columns, two rows. */
.h-lr__vbar { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.h-lr__vcol { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; min-width: 0; }
.h-lr__vcol--r { align-items: flex-end; text-align: right; }
.h-lr__perm { display: flex; flex-direction: column; gap: 4px; padding: 10px 0; border-bottom: 1px solid var(--line); }
.h-lr__perm:last-child { border-bottom: 0; }
.h-lr__perm input { width: 18px; height: 18px; vertical-align: -3px; accent-color: var(--green); }
.h-fam__err { margin: 0; font-size: 12px; font-weight: 700; color: var(--danger); min-height: 1em; }
.h-fam__done { margin: 0; font-size: 15px; font-weight: 750; color: var(--green); }

.h-fam__pills { display: flex; flex-wrap: wrap; gap: 8px; }
.h-fam__pill {
  padding: 9px 13px; border-radius: var(--r-pill); cursor: pointer;
  background: var(--panel2); border: 1px solid var(--line);
  color: var(--ink); font: inherit; font-size: 13px; font-weight: 700;
}
.h-fam__pill.is-on { background: var(--green-dim); border-color: var(--green); color: var(--green); }

.h-fam__check { display: flex; gap: 10px; align-items: flex-start; font-size: 12.5px; line-height: 1.5; }
.h-fam__check input { margin-top: 3px; flex: none; width: 18px; height: 18px; }
.h-fam__check b { font-size: 13px; }

/* === THE AVATAR ===========================================================
   Parts and renderer ported from Karl's FileMaker Avatar Studio build. This is
   only the framing: the SVG carries its own colours through CSS variables the
   renderer writes onto the <svg> element, so nothing here may set a fill.
   ======================================================================== */
.h-av {
  flex: none; display: grid; place-items: center; overflow: hidden;
  border-radius: 50%; line-height: 1;
}
/* THE TINT IS LAID ON --panel, NOT ON WHATEVER ROW THIS DISC LANDS IN.

   `--green-dim` is a 13% wash, so its result depends on what is underneath —
   and one of the places this disc goes is `.h-lr__emblem.is-on`, which is
   ITSELF painted `--green-dim`. Two washes stacked: the composited pass
   measured the initials at **4.25:1** in light where the same disc on a panel
   measures 4.98. A tint inside a tint is not something a stylesheet reader can
   see; only the rendered page knows.

   Pinning the wash to an opaque `--panel` makes the disc the same colour
   wherever it is dropped — 4.98 light, 9.65 dark — and the selected row still
   reads as selected, because that is carried by its border. (08-18b) */
.h-av--init {
  background: linear-gradient(var(--green-dim), var(--green-dim)), var(--panel);
  color: var(--green);
  font-weight: 800; font-size: 15px;
}
/* B65 third pass (Karl): a Basic disc in the member's colour set — the same dim-disc, bright-letters look as the house green. */
.h-av--init.h-av--tint {
  background: linear-gradient(color-mix(in srgb, var(--init-c, var(--green)) 16%, transparent), color-mix(in srgb, var(--init-c, var(--green)) 16%, transparent)), var(--panel);
  color: var(--init-c, var(--green));
}
/* A CHOSEN BADGE COLOUR OVERRIDES THE TINT, so the letters need a colour that
   works on anything. White on a member-chosen background is the one pairing we
   can promise without knowing what they picked. */
.h-av--badge { color: var(--on-colour); }
/* A RING, BECAUSE AN AVATAR CAN BE ANY COLOUR. A goalie's default mask is
   white, and a white head crop on a light panel is a blank disc — the member
   looks like they have no avatar at all when they have just built one. */
.h-av--char { background: var(--panel2); border: 1px solid var(--line); }
.h-av--char svg { width: 100%; height: 100%; display: block; }
/* CHARACTER + SPACE (2026-10-05): a saved Character (circle) and Space design (rounded square), drawn by
   assets/js/identityrender.js from catalogue art. Lettering is two glyph IMAGES (Karl ruling 5); a colour set
   only rings the face (ruling 6). Space squares never clip to a circle (Fable Q-27 item 1). */
.h-av--id { position: relative; overflow: visible; background: none; isolation: isolate; container-type: size; }
/* The art is clipped to the circle by an inner layer, so a portrait's seal can overhang the edge. */
.h-av--id > .h-id__clip { position: absolute; inset: 0; display: grid; place-items: center; overflow: hidden; border-radius: 50%; background: var(--panel2); isolation: isolate; }
.h-av--id.has-ring > .h-id__clip { box-shadow: inset 0 0 0 2px var(--id-ring, var(--green)); }
.h-id__clip > .h-id__bg, .h-gav--id > .h-id__bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -1; }
/* The Basic disc (Karl, B65 final): drawn live in the member's colour set — the house disc's dim wash. */
.h-id__plain { display: block; background: linear-gradient(color-mix(in srgb, var(--init-c, var(--green)) 16%, transparent), color-mix(in srgb, var(--init-c, var(--green)) 16%, transparent)), var(--panel); }
.h-id__clip > .h-id__plain, .h-gav--id > .h-id__plain { position: absolute; inset: 0; z-index: -1; }
.h-ids__disc > .h-id__plain { width: 100%; height: 100%; }
.h-id__clip > .h-id__por { position: absolute; transform: translate(-50%, -50%); object-fit: contain; z-index: 0; max-width: none; }
.h-id__ini { position: relative; display: flex; align-items: center; justify-content: center; pointer-events: none; }
.h-id__ini img { display: block; flex: none; max-width: none; }
.h-id__seal { position: absolute; right: -6%; bottom: -6%; width: 38%; height: 38%; line-height: 0; border-radius: 50%; box-shadow: 0 0 0 1.5px var(--panel); z-index: 1; }
.h-gav--id { position: relative; display: grid; place-items: center; overflow: hidden; border-radius: 26.2%; background: var(--panel2); isolation: isolate; container-type: size; }
.h-gav--id > .h-id__ul { position: absolute; left: 29%; right: 29%; top: 72%; height: 2.2%; min-height: 1.5px;
  background: linear-gradient(90deg, var(--ul1, var(--green)) 0 50%, var(--ul2, var(--purple)) 50% 100%); border-radius: 2px; }

/* --- choosing which emblem you wear --------------------------------------
   Three options, each drawn AS ITSELF rather than described — somebody
   choosing how they appear should be looking at how they appear. */
.h-lr__color { padding: 2px; height: 38px; cursor: pointer; }

/* === THE AVATAR STUDIO ====================================================
   The editor. Karl's FileMaker version has animations, a floating buddy, a
   locker-room scene and a trading card; this is pickers, colours, live preview
   and save. Nothing here mentions the rest — a placeholder for a feature is
   worse than its absence.
   ======================================================================== */

/* CAPPED BY HEIGHT, NOT WIDTH. The figure is 400x600, so sizing on width alone
   made it 345px tall on a phone and pushed every picker below the fold — a
   studio where you cannot see the preview and the control at the same time is
   not a studio. */
/* THE ROOM IS THE STAGE NOW. Karl's locker-room background lives on
   `.h365-avatar-preview-full` and has to be able to clip its own scroll, so the
   padding that used to give the celebrate-jump headroom moved inside the figure
   instead — the SVG has 28px of empty canvas above the head at this viewBox. */

/* FIGURE OR CARD. Karl's studio shows the figure, the head crop and the card
   side by side; on a 390px phone that is three things competing for 300px, and
   the card IS the figure in a frame — showing both says nothing extra. */

/* THE FIVE MOVES. A toggle row — pressing the one that is running stops it,
   because every animation loops for ever and somebody who wants it to stop
   should not have to guess which other button does that. */
/* The two walk arrows take only the width of a glyph, so five controls fit one
   row on a 390px phone. Their words live in aria-label. */




/* THE HOCKEY365 TAB'S ORG-SCOPED SEARCH. The box only renders when Discover
   can scope itself (see hub.js `discoverCanScope`), so these rules style a
   control that is either present and working or absent — never a dead one. */
/* ---- STAGE 2B: THE HOCKEY365 TAB (approved preview, 2026-09-26) ---------- */
/* ---- STAGE 2E: DISCOVER (approved preview, 2026-09-26) ------------------- */
.h-dc__head, .h-dc__card, .h-dc__sechead { margin-bottom: 14px; }
.h-dc__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 4px; }
.h-dc__head small, .h-dc__card > small, .h-dc__sechead small {
  display: block; color: var(--green); font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
}
.h-dc__head h2, .h-dc__card > h3, .h-dc__sechead h3 {
  margin: 3px 0 0; font-family: var(--font-display); font-weight: 400;
  text-transform: uppercase; letter-spacing: .025em; line-height: 1;
}
.h-dc__head h2 { font-size: 28px; }
.h-dc__card > h3, .h-dc__sechead h3 { font-size: 19px; }
.h-dc__city {
  flex: none; display: inline-flex; align-items: center; gap: 5px; min-height: 32px; padding: 0 11px;
  border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--panel2);
  color: var(--ink); font-size: 12px; font-weight: 700;
}
.h-dc__city .h-ic { width: 14px; height: 14px; color: var(--green); }
.h-dc__card {
  padding: 16px; border: 1px solid var(--line); border-radius: var(--r-lg);
  background: radial-gradient(circle at 92% 8%, color-mix(in srgb, var(--green) 9%, transparent), transparent 40%), var(--panel);
}
.h-dc__card > .h-sub { margin: 6px 0 12px; }
.h-dc__sechead { margin-top: 20px; }
/* The doors: three even cards, the preview's "Go straight there" grid. */
.h-dc__tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.h-dc__tiles .h-qact {
  min-width: 0; min-height: 104px; align-items: flex-start; text-align: left;
  border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel); padding: 12px;
}
@media (max-width: 380px) { .h-dc__tiles { grid-template-columns: 1fr; } .h-dc__tiles .h-qact { min-height: 0; } }
.h-h365 { display: flex; flex-direction: column; gap: 16px; padding: 4px 0 24px; }
.h-h365 [data-h365-home] { display: flex; flex-direction: column; gap: 22px; }
.h-h365 small {
  display: block; color: var(--green); font-size: 11px; font-weight: 800;
  letter-spacing: .1em; text-transform: uppercase;
}
.h-h365 h2, .h-h365 h3 {
  margin: 3px 0 0; font-family: var(--font-display); font-weight: 400;
  text-transform: uppercase; letter-spacing: .025em; line-height: 1;
}
.h-h365 h2 { font-size: 28px; }
.h-h365 h3 { font-size: 19px; }
.h-h365__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* THE H MARK STANDS ON ITS OWN (Karl, 2026-09-26): no button tile behind it,
   and a little larger. */
.h-h365__mark { flex: none; display: grid; place-items: center; color: var(--green); }
.h-h365__mark .h-ic { width: 40px; height: 40px; }
.h-h365__feature {
  width: 100%; min-height: 190px; display: flex; flex-direction: column; justify-content: flex-end;
  gap: 6px; padding: 18px; text-align: left; cursor: pointer; color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r-xl);
  background:
    radial-gradient(circle at 85% 15%, color-mix(in srgb, var(--green) 16%, transparent), transparent 45%),
    linear-gradient(160deg, var(--elev), var(--panel));
}
.h-h365__feature h3 { font-size: 24px; }
.h-h365__feature p { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.45; max-width: 46ch; }
.h-h365__cta {
  align-self: flex-start; margin-top: 6px; display: inline-flex; align-items: center; gap: 4px;
  min-height: 38px; padding: 0 14px; border-radius: var(--r-md);
  background: var(--green); color: var(--on-green); font-size: 13px; font-weight: 800;
}
.h-h365__cta .h-ic { width: 16px; height: 16px; }
.h-h365__card {
  padding: 16px; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel);
}
.h-h365__card p { margin: 6px 0 12px; color: var(--muted); font-size: 13px; }
/* The scoped search sits inside its card: no second margin under the box. */
.h-h365__search .h-h365__find { margin: 0; }
.h-h365__sec > header {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; margin: 0 2px 10px;
}
.h-h365__all {
  min-height: 32px; padding: 0 12px; border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--panel2); color: var(--ink); font-size: 12px; font-weight: 700; cursor: pointer;
}
.h-h365__next, .h-h365__news, .h-h365__trivia {
  width: 100%; display: flex; align-items: center; gap: 12px; padding: 12px 14px;
  border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel);
  color: var(--ink); text-align: left; cursor: pointer;
}
.h-h365__news + .h-h365__trivia, [data-h365-news] + .h-h365__trivia { margin-top: 10px; }
.h-h365__next > .h-ic, .h-h365__news > .h-ic, .h-h365__trivia > .h-ic {
  flex: none; width: 18px; height: 18px; color: var(--muted);
}
.h-h365__trivia { border-color: color-mix(in srgb, var(--purple) 55%, var(--line)); }
.h-h365__trivia > .h-ic { color: var(--purple); width: 22px; height: 22px; }
.h-h365__date {
  flex: none; width: 54px; padding: 6px 0; display: flex; flex-direction: column; align-items: center;
  border-radius: var(--r-md); background: var(--panel2); border: 1px solid var(--line);
}
.h-h365__date small { font-size: 10px; }
.h-h365__date strong { font-family: var(--font-display); font-weight: 400; font-size: 24px; line-height: 1; }
.h-h365__date em { font-style: normal; font-size: 10px; color: var(--muted); font-weight: 700; }
.h-h365__nt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.h-h365__nt strong { font-size: 15px; font-weight: 800; }
.h-h365__nt em {
  font-style: normal; color: var(--muted); font-size: 13px;
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.h-h365__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.h-h365__qc {
  min-width: 0; min-height: 96px; display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
  padding: 12px; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel);
  color: var(--ink); text-align: left; cursor: pointer;
}
.h-h365__qc.is-soon { opacity: .6; cursor: default; }
.h-h365__qi {
  width: 36px; height: 36px; flex: none; display: grid; place-items: center;
  border-radius: var(--r-md); background: color-mix(in srgb, var(--green) 12%, var(--panel2)); color: var(--green);
}
.h-h365__qi .h-ic { width: 19px; height: 19px; }
.h-h365__qt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.h-h365__qt strong { font-size: 14px; font-weight: 800; }
.h-h365__qt small { color: var(--muted); font-size: 12px; font-weight: 500; letter-spacing: 0; text-transform: none; }
@media (min-width: 900px) { .h-h365__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.h-h365__find { margin: 0 0 12px; }
.h-h365__q { width: 100%; }
.h-h365__results { display: flex; flex-direction: column; gap: 8px; }

/* THE PART PICKER, AS CARDS — you choose a hairstyle by looking at it.
   Ported from the live studio (`H365 Avatar Build/avatar-studio-css.txt`,
   `.h365-avatar-part-card`): a tight-cropped SVG of the part above its label.
   The pill `.h-as__opt` above stays for the rows that are genuinely words
   ("Out" / "In net"), so both shapes live side by side on purpose. */
/* Skin has no shape to show, so it shows its colour — live does the same. */
/* The selected card is marked by its FRAME, not by recolouring the art —
   tinting the thumbnail would misrepresent the part you are choosing. */

/* THE RING, NOT A TICK. A checkmark drawn on a swatch has to be readable on
   both white and near-black, and it is not. */


/* === REPORTED POSTS =======================================================
   The staff queue. `post_report` was written from the day the feed shipped
   and read by nothing; this is the screen that was missing. */
.h-rep { display: flex; flex-direction: column; gap: 10px; }
.h-rep__row {
  padding: 12px 13px; border-radius: var(--r-md);
  background: var(--panel); border: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 7px;
}
.h-rep__hd { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.h-rep__n { font-size: 13.5px; font-weight: 750; overflow-wrap: anywhere; }
.h-rep__hd .h-tag { margin-top: 0; cursor: default; }
/* The reported words themselves, quoted rather than styled as the app's own
   voice — a moderator is reading somebody else's text, not ours. */
.h-rep__body {
  margin: 0; padding: 9px 11px; border-radius: var(--r-md);
  background: var(--bg); border: 1px solid var(--line2);
  font-size: 13px; line-height: 1.55; overflow-wrap: anywhere; white-space: pre-wrap;
}
.h-rep__why { margin: 0; font-size: 12px; color: var(--muted); overflow-wrap: anywhere; }
.h-rep__gone { margin: 0; font-size: 12px; color: var(--faint); }
.h-rep__acts { display: flex; gap: 8px; flex-wrap: wrap; }

/* ---------------------------------------------------------------------------
   POST A GAME — one row per role

   Karl, 08-11, on the first version: "the way the skaters numbes and pricing
   is displaying is not clean... its just all over the place." It was: the
   count floated to the far right on its own line, the three money chips
   wrapped underneath it, and the amount box came in as a fourth chip in the
   same flow, so no two things lined up.

   Now it is a fixed shape: NAME + COUNT on one line, then a segmented money
   control with the amount to its right. Reading order, left to right, twice.

   `.h-need`, not `.h-ask` — that block is Discover's ask bar and reusing the
   name would have inherited its layout here. Two different questions.
   ------------------------------------------------------------------------ */
.h-need { padding: 11px 0; border-bottom: 1px solid var(--line2); }
.h-need:last-of-type { border-bottom: 0; }
/* `S2-108` - `flex-wrap: wrap` IS THE FALLBACK, NOT THE LAYOUT. The name
   wrapper shrinks first (`min-width: 0`), so on every phone measured the row
   stays one line; only if the stepper genuinely cannot fit does it drop under
   the name, right-aligned (its `margin-left: auto`), instead of losing its +. */
.h-need__top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.h-need__n { font-weight: 600; color: var(--ink); }

/* ===========================================================================
   `FND-07` ② — THE MODE TIP AND ITS WRAPPER. Sol specified the tip; the
   wrapper is mine because it is the seam and because it carries Karl's pick.

   🔴 THESE TWO CLASSES HAVE BEEN EMITTED BY `schedule.js:1080-1083` SINCE 00:05
   WITH NO RULE ANYWHERE. The tip has therefore been rendering at 16px `--ink`
   — full-strength body copy where a hint is meant — and `client-contracts` has
   been RED the whole time at 226/2, naming both classes. That suite is globbed
   into `test-all.mjs`, so it sits in the DEPLOY GATE: this was not cosmetic
   debt, it was a hold on shipping, and that is what moved it ahead of the rest
   of `FND-07`.

   ⓘ WHY THE WRAPPER EXISTS AT ALL, which is the part a value cannot express:
   KARL ASKED FOR THE TIP "NEXT TO" THE NAME AND THEN PICKED "UNDERNEATH" ONCE
   BOTH WERE ON SCREEN, because underneath is the one that holds its shape. So
   the name and the tip STACK, and the pair together is what takes the row's
   flexible space — `flex: 1 1 auto` moves OFF `.h-need__n` and onto the wrapper
   that now occupies its place in `.h-need__top`. Leaving it on the name would
   have been a declaration with nothing to act on: `__n` is no longer a child of
   a flex container.

   🔑 `min-width: 0` IS THE LOAD-BEARING LINE AND IT IS THE SAME MECHANISM AS
   `SYS-20`: a flex item defaults to `min-width: auto` and refuses to shrink
   below its content, so a long tip would push the row wider than the sheet
   instead of wrapping. That is exactly how the date field and the harness
   container both went wrong this week.

   The tip's size is `.h-help`'s own 11.5px — Sol's point, and it is right: the
   design system already has a size for "hint under a field", and inventing a
   second one is how a scale stops being a scale. `--faint` rather than
   `--muted` because it sits under ink at full strength and must read as
   subordinate to it. */
.h-need__nwrap { flex: 1 1 auto; min-width: 0; }
.h-need__nwrap .h-need__n { display: block; }
.h-need__tip {
  display: block;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--faint);
  margin-top: 1px;
}
/* Narrow on purpose: it holds 0-60, and a full-width box invites a sentence.

   THE HEIGHT IS TAKEN FROM ITS OWN ROW, NOT TYPED. Same mechanism as the
   amount box below and for the same stated reason — a box should take its
   height from the row rather than set its own — but the row it is IN is
   `.h-need__step`, whose 44px nudgers arrived after the money-row figure was
   worked out. `align-self` overrides that flex line's `align-items: center`
   for this one child and nothing else; the nudgers keep setting the height and
   this box cannot fall out of step with them if either number ever moves.
   MEASURED, all three at 390px: nudger 44, box 44, edges flush. Sol's literal
   9px measured 38 against a 44px nudger, six short and floating between them,
   and 13px measured 46, two proud — the number was right for the row he could
   see and there is now a nearer one to match. */
.h-need__c { flex: 0 0 84px; width: 84px; height: 44px; text-align: center; padding: 0 6px; margin-left: auto; }

/* `GAME-05` - MINUS AND PLUS EITHER SIDE OF THE COUNT. The row is filled in on
   a phone in a rink and the answer is usually 1 or 2, so a number keyboard is
   the wrong instrument for the commonest value.
   44px HIGH AND 36 WIDE: the height is the tap target, the width is what keeps
   the three roles the same shape on a 320px screen. `flex: 0 0` on all three
   children so a longer role name can never squeeze the controls. */
.h-need__vis { margin-top: 10px; padding-top: 2px; }
.h-need__vl { font-size: 11px; font-weight: 700; color: var(--faint); margin-bottom: 5px; }

/* `GAME-11` - THE FLOOR LINE. Karl asked for the floors applied LOUDLY, so it
   is not another grey tip: it borrows `--ink` and a heavier weight so the one
   line that states a RULE reads differently from the lines that state a
   consequence. Shown only while the visitor segment is on Rent. */
.h-need__floor { color: var(--ink); font-weight: 600; }

/* The money line. `grid` rather than flex so the segment always gets the room
   it needs and the amount is always the same width — with flex, a three-word
   label made the amount box shrink to nothing on a narrow phone. */
.h-need__money { display: flex; gap: 8px; align-items: stretch; margin-top: 9px; }
.h-need__money .h-seg--money { margin: 0; min-width: 0; flex: 1 1 auto; }
.h-need__money .h-seg--money button { font-size: 12px; padding: 6px 4px; white-space: nowrap; }
/* `S2-12` - THE ONE IN-FLOW OVERFLOW ANYWHERE ON THE CREATE SHEET, AND IT IS
   A THRESHOLD RATHER THAN A PHONE.

   Karl reported this sheet as needing a sideways swipe. It does not, at his
   width or any other - `tools/game18-sheet-overflow.mjs` (Iris) walked five
   doors at four widths and found no page swipe on any. What it DID find, and
   correctly reported as a stress reading rather than as his bug, is this row:
   at 320px the three mode buttons stand past the track that holds them.

   The labels are `Free` / `They pay` / `You pay them`. Karl ruled that wording
   FINE on `FND-07` and it is NOT touched. At 12px Public Sans 700 with `6px 4px`
   they need 34.14 + 59.22 + 84.56 = 177.92px on one line plus 12px of gaps, so
   they stop fitting the top-level row below a viewport of about 324px - and the
   `GAME-11` visitor row nested inside `.h-frow__nest`, which is the SAME three
   labels in a track 20px narrower, stops fitting below about 344px.

   THE BREAKPOINT IS THE SECOND OF THOSE NUMBERS, NOT THE FIRST, AND THE
   DIFFERENCE IS WHY THIS IS 360 AND NOT 340. The first version of this repair
   was scoped to `max-width: 340px` on the top-level measurement alone, and it
   left the nested row clipping at every width from 341 to 343 and wrapping at
   320. `tools/moneyrow-fit.mjs` is what caught that - the nested row had never
   been measured by anything, at any width, because it is `hidden` until the
   `List it on Find` switch is pressed and no harness had ever pressed it.

   THREE PROPERTIES, AND EACH ONE IS DOING WORK:
     `white-space: normal` - the BACKSTOP. A label may wrap; it may never be cut
        off. Whatever the wording becomes, this row cannot clip again.
     `padding: 6px 2px` - the twelve pixels that keep the PRIMARY row on ONE
        line at 320px rather than merely un-clipped. The nested row cannot be
        saved this way and is not: at 320 its track is 166px against 177.92px of
        labels, and there is nothing left to give it, so it wraps.
     `flex: 1 1 auto` - without it `flex: 1 1 0%` splits the track into equal
        thirds, and an equal third is NARROWER than the longest label at every
        width up to 385px, so `white-space: normal` alone would make the row
        wrap on Karl's own phone while it had 66px of room.

   AND IT IS SCOPED SO NOTHING ABOVE 360px MOVES. Measured at 361 / 375 / 390 /
   414: byte-identical button widths before and after. */
@media (max-width: 360px) {
  .h-need__money .h-seg--money button { flex: 1 1 auto; padding: 6px 2px; white-space: normal; }
}
/* Appears only when a mode needs one — see the data-money handler.

   ZERO VERTICAL PADDING IS HOW THE HEIGHT IS FIXED, NOT A SMALLER FONT.
   `base.css:65` is the standing rule: a focused field under 16px zooms mobile
   Safari, it is measured across 27 classes, and `SYS-07` is the floor. The
   11px came out of padding, so it goes back into padding. `stretch` on the
   grid then hands this box the row's height, which the pill sets. */
.h-need__amt { width: 84px; text-align: center; padding: 0 6px; }
/* HOW IT HIDES DOES NOT MATTER, AND SOL'S BLOCK SAID IT DID. His spec asked
   for `display: block; visibility: hidden` here so the box would keep
   occupying its column. I WROTE THAT RULE, MEASURED IT, AND IT NEVER RAN:
   `base.css:47` is `[hidden] { display: none !important }`, house-wide, so
   nothing at this specificity can put the box back in flow. The rule sat there
   claiming a behaviour it did not have.
   IT IS NOT NEEDED EITHER, WHICH IS THE OTHER HALF. The column is held by the
   TRACK — `1fr 84px` above — and a track does not need an element in it to
   exist. Measured at 320, 390 and 430: the pill is 196 / 266 / 296 wide in BOTH
   modes with the box at `display: none`. So the box hides the way everything
   in this app hides, and the fix for item 3 is the one declaration above. */
.h-need__from { margin-top: 10px; }

/* ---------------------------------------------------------------------------
   FIND — REBUILT FOR A PHONE, 2026-08-11

   Karl, on the shipped version: "the top buttons take up so much room, then
   there is only a small space at the bottom of a phone for the Open game
   list... this leaves about room for 1 game card to be visible before
   scrolling", and — the actual bug — with a short list there was nothing to
   scroll, so that sliver was all there was.

   THREE CHANGES, and the first is the one that matters.

   1. THE WHOLE SURFACE SCROLLS. The chrome moved out of `.h-sch__top` (which
      is flex: 0 0 auto and never shrinks) into the scroller. Only the role
      segment stays pinned. See findHtml().

   2. THE TILES GOT SMALLER, to the live app's proportions rather than mine.
      `Shared Find Overlay CSS.txt`: min-height 92px, 14px padding, a 24px
      naked icon at the TOP with the text pushed to the BOTTOM by
      space-between, title 14/700, sub 11 muted. Mine had a 32px filled icon
      chip stacked above 13px text with no min-height and it came out taller
      than the live one for less information.

   3. THE SECTION LABEL. Karl: "the label is very plain". The live app's
      `.h365-fnd-group-label` is 11px, uppercase, 0.08em tracking, muted — a
      quiet heading rather than a sentence. Copied, with our count kept on the
      right because a game list that says how short it is beats one that
      does not.
   ------------------------------------------------------------------------ */

/* The one pinned strip. Nothing above it: the title scrolls with everything
   else, which is 60px of a phone screen bought back. */
.h-sch__top--find { padding: 10px 16px 6px; }
/* `FND-04` - THE HEADING'S OWN PINNED ROW, above the filter segment. Tighter
   padding than `--find` because it sits directly on top of it and two full
   paddings between a title and its own filter reads as two sections. */
.h-sch__top--findh { padding: 12px 16px 0; }
.h-sch__top--findh .h-find__h { margin: 0; }
.h-sch__body--find { padding-top: 4px; }
.h-find__h { font-size: 20px; margin: 2px 0 2px; }
.h-find__h,.h-tiles--find .h-tile__name,.h-wsec--find .h-wsec__t{font-family:var(--head-font);font-weight:var(--head-weight);letter-spacing:var(--head-track);text-transform:var(--head-case)}

/* Live proportions. `space-between` with a min-height is what puts the icon at
   the top and the words at the bottom — without it the tiles are ragged when
   one caption wraps to two lines and its neighbour does not. */
.h-tiles--find { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 6px; }
.h-tiles--find .h-tile {
  min-height: 88px; padding: 12px; border-radius: var(--r-lg);
  display: flex; flex-direction: column; justify-content: space-between;
}
/* Naked icon, no chip. The chip was 32px of background doing the job of a
   colour, and four of them read as four buttons all shouting equally. */
.h-tiles--find .h-tile__ic {
  width: auto; height: auto; background: none; margin-bottom: 6px; color: var(--green);
  display: block;
}
.h-tiles--find .h-tile__ic svg { width: 22px; height: 22px; }
.h-tiles--find .h-tile__name { font-size: 14px; line-height: 1.2; }
.h-tiles--find .h-tile__sub { font-size: 11px; line-height: 1.25; margin-top: 2px; }

/* THE HERO — the one tile that does the opposite job.

   Karl asked for it in the fourth grid slot, in a different colour, "since its
   a button that serves a slightly different purpose (finding people to join ME
   rather than finding something for ME to join)". The live menu's first tile
   is `is-hero` and filled for exactly that reason.

   PURPLE rather than green: green already means "this filter is on" two rows
   below, and one colour meaning two things is how a screen stops reading at a
   glance. --purple is the brand's Power Play Purple, and the live app's own
   recruit banner uses its equivalent (--h365-comm). */
.h-tiles--find .h-tile--hero {
  background: var(--purple-solid); border-color: var(--purple); color: var(--on-purple);
}
.h-tiles--find .h-tile--hero .h-tile__ic,
.h-tiles--find .h-tile--hero .h-tile__name { color: var(--on-purple); }
.h-tiles--find .h-tile--hero .h-tile__sub { color: var(--on-purple); opacity: .74; }
.h-tiles--find .h-tile--hero:active { transform: scale(.977); }

/* The quiet heading, from the live app. */
.h-wsec--find {
  display: flex; align-items: baseline; justify-content: space-between;
  margin: 14px 2px 8px;
}
.h-wsec--find .h-wsec__t {
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--faint);
  font-weight: 700;
}
.h-wsec--find .h-wsec__link { font-size: 11px; color: var(--green); font-weight: 700; }

/* ---------------------------------------------------------------------------
   FRIENDS — the rows in the sheet behind the top-bar icon.

   `friend_connection` finally has a writer (functions/lib/friends.js), so the
   icon that has said "arrives with Phase 1" since the shell shipped opens
   something now.
   ------------------------------------------------------------------------ */
/* Premium Friends utility drawer. */
.h-frlayer { position:absolute; inset:0; z-index:54; pointer-events:none; }
.h-frlayer__scrim { position:absolute; inset:0; width:100%; border:0; background:var(--scrim-modal); opacity:0; pointer-events:none; transition:opacity var(--t-fast); }
.h-frdrawer { position:absolute; top:58px; right:0; bottom:0; width:min(100%,420px); display:flex; flex-direction:column; overflow:hidden; border-left:1px solid var(--line2); background:var(--panel); color:var(--ink); box-shadow:-22px 0 60px var(--scrim-modal); outline:0; transform:translateX(100%); transition:transform var(--t-med); }
.h-frlayer.is-open { pointer-events:auto; }
.h-frlayer.is-open .h-frlayer__scrim { opacity:1; pointer-events:auto; }
.h-frlayer.is-open .h-frdrawer { transform:none; }
.h-frdrawer>header { display:flex; align-items:center; justify-content:space-between; flex:none; padding:15px 16px; border-bottom:1px solid var(--line2); background:var(--panel2); }
.h-frdrawer>header small { display:block; color:var(--green); font-size:10px; font-weight:900; letter-spacing:.14em; }
.h-frdrawer>header h2 { margin:3px 0 0; font:400 27px/1 var(--font-display); letter-spacing:.03em; text-transform:uppercase; }
.h-frdrawer__close { display:grid; place-items:center; width:38px; height:38px; padding:0; border:1px solid var(--line2); border-radius:var(--r-md); background:var(--elev); color:var(--ink); font-size:24px; line-height:1; }
.h-frdrawer__body { flex:1; min-height:0; overflow-y:auto; padding:12px 13px 22px; }
.h-frtabs { margin-bottom:11px; }
.h-frtabs button span { display:inline-grid; place-items:center; min-width:18px; height:18px; margin-left:5px; border-radius:var(--r-pill); background:var(--purple-solid); color:var(--on-purple); font-size:10px; }
.h-frdrawer [data-fr-find] { margin-top:11px; padding:0 10px; border:1px solid var(--line2); border-radius:var(--r-lg); background:var(--bg); }
.h-frdrawer [data-fr-find]:focus-within { border-color:var(--purple); box-shadow:0 0 16px rgba(var(--purple-rgb),.2); }
.h-frdrawer [data-fr-q],.h-frdrawer [data-fr-q]:focus { width:100%; height:44px; padding:0; border:0!important; outline:0!important; background:transparent; color:var(--ink); font-size:16px; box-shadow:none!important; }
.h-frsummary { display:grid; grid-template-columns:repeat(3,1fr); gap:7px; margin:11px 0 14px; }
.h-frsummary div { padding:10px; border:1px solid var(--line); border-radius:var(--r-md); background:var(--panel2); }
.h-frsummary b,.h-frsummary span { display:block; }
.h-frsummary b { color:var(--active-purple-ink); font-size:18px; }
.h-frsummary span { margin-top:2px; color:var(--muted); font-size:10px; }
.h-frdrawer .h-sec-label { margin:14px 4px 4px; color:var(--purple); }
.h-frdrawer .h-fr { min-height:56px; padding:9px 3px; }
.h-frdrawer .h-fr__main.h-fr__person { min-width:0; padding:0; border:0; background:transparent; color:var(--ink); font:inherit; text-align:left; }
.h-frdrawer .h-fr__person small { display:block; margin-top:2px; color:var(--muted); font-size:10px; }
.h-frdrawer .h-fr__acts .h-btn { min-height:32px; padding:0 9px; border-radius:var(--r-sm); font-size:10px; }
.h-frempty { padding:34px 15px; text-align:center; }
.h-frempty strong,.h-frempty span { display:block; }
.h-frempty span { margin-top:5px; color:var(--muted); font-size:12px; }
.h-frdrawer__headacts { display:flex; align-items:center; gap:7px; }
.h-frdrawer__add { min-height:38px; padding:0 11px; border:1px solid var(--green); border-radius:var(--r-md); background:var(--active-green-bg); color:var(--active-green-ink); font-weight:900; white-space:nowrap; }
.h-fradd { position:absolute; z-index:2; inset:0; display:flex; flex-direction:column; background:var(--panel); transform:translateX(100%); transition:transform var(--t-med); }
.h-fradd[hidden] { display:none!important; }
.h-fradd.is-open { transform:none; }
.h-fradd>header { display:flex; align-items:center; justify-content:space-between; flex:none; padding:15px 16px; border-bottom:1px solid var(--line2); background:var(--panel2); }
.h-fradd>header small { display:block; color:var(--green); font-size:10px; font-weight:900; letter-spacing:.14em; }
.h-fradd>header h3 { margin:3px 0 0; font:400 25px/1 var(--font-display); text-transform:uppercase; }
.h-fradd__body { flex:1; min-height:0; overflow-y:auto; padding:12px 13px 22px; }
@media(max-width:390px){.h-frdrawer{width:100%}}
@media(prefers-reduced-motion:reduce){.h-frlayer__scrim,.h-frdrawer,.h-fradd{transition:none}}

.h-fr {
  display: flex; align-items: center; gap: 11px;
  padding: 9px 0; border-bottom: 1px solid var(--line2);
}
.h-fr:last-of-type { border-bottom: 0; }
.h-fr__i {
  width: 34px; height: 34px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--green-dim); color: var(--green);
  font-weight: 800; font-size: 12px; font-family: var(--font-head);
}
.h-fr__main { flex: 1 1 auto; min-width: 0; }
.h-fr__n { display: block; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The actions never wrap under the name — a row whose buttons move depending
   on the length of somebody's surname is a row you misclick. */
.h-fr__acts { flex: none; display: flex; align-items: center; gap: 6px; }

/* ---------------------------------------------------------------------------
   NOTIFICATIONS (0044) — the sheet behind the bell.

   A ROW IS A BUTTON when it has somewhere to go and a plain div when it does
   not. Styling a dead row to look tappable is the same lie as the bell itself
   was, one size down — so `.h-nt--flat` drops the affordances rather than
   leaving a button that does nothing.
   ------------------------------------------------------------------------ */
.h-nt {
  display: flex; align-items: flex-start; gap: 10px; width: 100%;
  padding: 11px 0; border-bottom: 1px solid var(--line2);
  background: none; border-left: 0; border-right: 0; border-top: 0;
  color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.h-nt:last-of-type { border-bottom: 0; }
.h-nt--flat { cursor: default; }
.h-nt__main { flex: 1 1 auto; min-width: 0; }
.h-nt__t { display: block; font-weight: 600; }
/* The child's name leads, because a parent cannot act on "Added to Tuesday
   Skate" until they know which of their kids it is about. */
.h-nt__who { color: var(--green); font-weight: 800; margin-right: 6px; }

/* ===== 0638 "FROM HOCKEY365" (Karl, approved 2026-10-01) =====
   The bell's two tabs, the message rows, and the message card the pop-up,
   the bell and the staff preview all draw. Three kinds, three colours:
   What's new green, Promotion purple, Notice amber. */
.h-nttabs { display: flex; gap: 6px; margin: 0 0 10px; padding: 3px; border: 1px solid var(--line); border-radius: var(--r-pill); }
.h-nttab { flex: 1 1 0; display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 34px; padding: 6px 10px;
  border: 0; border-radius: var(--r-pill); background: none; color: var(--muted); font: inherit; font-size: 13px; font-weight: 700; cursor: pointer; }
.h-nttab.is-on { background: var(--panel2); color: var(--ink); }
.h-nttab__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--purple); flex: none; }
.h-nt--h365 .h-nt__icon { color: var(--green); }
.h-nt--promo .h-nt__icon { color: var(--purple); }
.h-nt--notice .h-nt__icon { color: var(--warn); }
.h-nt__k { display: block; font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.h-nt--new.is-new .h-nt__t, .h-nt--promo.is-new .h-nt__t, .h-nt--notice.is-new .h-nt__t { font-weight: 800; }

.h-upd { display: flex; flex-direction: column; gap: 8px; }
.h-upd__art { position: relative; display: grid; place-items: center; height: 120px; border-radius: var(--r-md); overflow: hidden; color: #fff; }
.h-upd__art .h-ic { width: 46px; height: 46px; filter: drop-shadow(0 2px 6px rgba(0,0,0,.45)); }
.h-upd__art--spotlight { background: radial-gradient(circle at 50% 30%, rgba(7,247,8,.55), rgba(7,247,8,0) 60%), #0b1410; }
.h-upd__art--confetti { background:
  radial-gradient(circle at 15% 30%, #ffb84d 0 4px, transparent 5px), radial-gradient(circle at 80% 25%, #7e51ff 0 5px, transparent 6px),
  radial-gradient(circle at 30% 75%, #07f708 0 4px, transparent 5px), radial-gradient(circle at 65% 70%, #ff7b84 0 5px, transparent 6px),
  radial-gradient(circle at 50% 40%, rgba(126,81,255,.6), transparent 65%), #160f2b; }
.h-upd__art--ice { background: linear-gradient(160deg, #dbeefa 0%, #9cc7e6 55%, #4f86b3 100%); color: #10304d; }
.h-upd__art--ice .h-ic { filter: none; }
.h-upd__art--trophy { background: radial-gradient(circle at 50% 35%, rgba(255,200,80,.75), rgba(255,200,80,0) 62%), #2a1d07; }
.h-upd__art--whistle { background: repeating-linear-gradient(135deg, #1a1a1a 0 14px, #2a2a2a 14px 28px); color: #ffb84d; }
.h-upd__art--alert { background: radial-gradient(circle at 50% 35%, rgba(255,184,77,.6), rgba(255,184,77,0) 62%), #2b1a08; }
.h-upd__k { display: flex; align-items: center; gap: 8px; font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--green); }
.h-upd--promo .h-upd__k { color: var(--purple); }
.h-upd--notice .h-upd__k { color: var(--warn); }
.h-upd__ended { padding: 2px 8px; border: 1px solid var(--line2); border-radius: var(--r-pill); color: var(--muted); letter-spacing: .04em; }
.h-upd__t { margin: 0; font-family: var(--font-display); font-weight: 400; font-size: 24px; line-height: 1.1; letter-spacing: .02em; color: var(--ink); }
.h-nt__b {
  display: block; margin-top: 2px; font-size: 13px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis;
}
/* Never wraps under the text: a timestamp that moves with the length of a
   game's name makes the list read as ragged. */
.h-nt__at { flex: none; font-size: 12px; color: var(--muted); padding-top: 1px; }
/* UNREAD IS A BAR, NOT A BOLD FONT. Bold is how the title is already
   distinguished from the body, and using it twice means neither reads. */
.h-nt.is-new { border-left: 3px solid var(--green); padding-left: 9px; }
.h-nt__more { padding: 12px 0 2px; text-align: center; }
.h-nt__done {
  padding: 12px 0 3px; color: var(--muted); font-size: 11px;
  font-weight: 700; text-align: center;
}

/* THE NOTIFICATION CENTRE is a global top-bar utility, not a contextual
   action sheet. It stays visually attached to the bell, preserves the page
   beneath it, and owns a list/detail navigation state. */
.h-ntlayer {
  position: absolute; inset: 0; z-index: 52; pointer-events: none;
}
.h-ntlayer__scrim {
  position: absolute; inset: 0; width: 100%; border: 0;
  background: var(--scrim-modal); opacity: 0; pointer-events: none;
  transition: opacity var(--t-fast);
}
.h-ntcentre {
  position: absolute; top: 58px; right: 8px; max-height: calc(100% - 68px);
  display: flex; flex-direction: column; width: min(calc(100% - 16px), 390px);
  overflow: hidden; border: 1px solid var(--line2); border-radius: var(--r-xl);
  background: var(--panel); color: var(--ink); box-shadow: 0 22px 58px var(--scrim-modal);
  opacity: 0; transform: translateY(-7px) scale(.985);
  transition: opacity var(--t-fast), transform var(--t-fast); outline: 0;
}
.h-ntlayer.is-open { pointer-events: auto; }
.h-ntlayer.is-open .h-ntlayer__scrim { opacity: 1; pointer-events: auto; }
.h-ntlayer.is-open .h-ntcentre { opacity: 1; transform: none; }
.h-ntcentre > header {
  display: grid; grid-template-columns: 38px minmax(0,1fr) 38px;
  align-items: center; gap: 6px; flex: none; padding: 12px;
  border-bottom: 1px solid var(--line2); background: var(--panel2);
}
.h-ntcentre > header > div { min-width: 0; text-align: center; }
.h-ntcentre > header small {
  display: block; color: var(--green); font-size: 10px; font-weight: 900;
  letter-spacing: .14em;
}
.h-ntcentre > header h2 {
  margin: 3px 0 0; overflow: hidden; color: var(--ink);
  font: 400 25px/1 var(--font-display); letter-spacing: .03em;
  text-overflow: ellipsis; text-transform: uppercase; white-space: nowrap;
}
.h-ntcentre__back,.h-ntcentre__close {
  display: grid; place-items: center; width: 36px; height: 36px; padding: 0;
  border: 1px solid var(--line2); border-radius: var(--r-md);
  background: var(--elev); color: var(--ink); cursor: pointer;
}
.h-ntcentre__back[hidden] { display: grid !important; visibility: hidden; }
.h-ntcentre__back .h-ic { width: 17px; height: 17px; }
.h-ntcentre__close { font-size: 23px; line-height: 1; }
.h-ntcentre__body { flex: 1; min-height: 0; overflow-y: auto; padding: 10px 12px 18px; }
.h-ntcentre .h-sec-label { margin: 8px 4px 3px; color: var(--purple); }
.h-ntcentre .h-nt {
  display: grid; grid-template-columns: 38px minmax(0,1fr) auto;
  align-items: center; gap: 10px; padding: 11px 5px;
}
.h-ntcentre .h-nt.is-new { padding-left: 9px; }
.h-nt__icon {
  display: grid; place-items: center; width: 36px; height: 36px;
  border-radius: var(--r-md); background: var(--elev); color: var(--green);
}
.h-nt__icon .h-ic { width: 18px; height: 18px; }
.h-ntcentre .h-nt__b {
  display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical;
  -webkit-line-clamp: 2; line-height: 1.35; white-space: normal;
}
.h-ntcentre .h-nt__at { align-self: start; padding-top: 3px; }
.h-ntdetail { min-height: 100%; }
.h-ntdetail__hero {
  display: flex; align-items: center; gap: 12px; padding: 15px;
  border: 1px solid var(--line2); border-radius: var(--r-lg);
  background: linear-gradient(145deg, var(--panel2), var(--panel));
}
.h-ntdetail__icon {
  display: grid; place-items: center; width: 46px; height: 46px; flex: none;
  border-radius: var(--r-md); background: var(--active-green-bg); color: var(--active-green-ink);
}
.h-ntdetail__icon .h-ic { width: 22px; height: 22px; }
.h-ntdetail__hero > span:last-child { min-width: 0; }
.h-ntdetail__hero small,.h-ntdetail__hero strong { display: block; }
.h-ntdetail__hero small {
  color: var(--green); font-size: 10px; font-weight: 900; letter-spacing: .1em;
  text-transform: uppercase;
}
.h-ntdetail__hero strong { margin-top: 4px; font-size: 15px; line-height: 1.25; }
.h-ntdetail__copy { padding: 17px 4px 5px; }
.h-ntdetail__about {
  display: inline-flex; margin-bottom: 10px; padding: 5px 8px;
  border: 1px solid var(--purple); border-radius: var(--r-pill);
  background: var(--active-purple-bg); color: var(--active-purple-ink);
  font-size: 11px; font-weight: 800;
}
.h-ntdetail__copy p {
  margin: 0; color: var(--on-colour); font-size: 14px; line-height: 1.6;
  white-space: pre-wrap;
}
.h-ntdetail__time {
  display: flex; align-items: center; gap: 7px; margin-top: 15px;
  color: var(--muted); font-size: 11px;
}
.h-ntdetail__time .h-ic { width: 14px; height: 14px; color: var(--purple); }
.h-ntdetail__go {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  width: 100%; min-height: 44px; margin-top: 18px; border: 0;
  border-radius: var(--r-md); background: var(--green); color: var(--on-green);
  font: 900 12px var(--font-body); cursor: pointer;
}
.h-ntdetail__go .h-ic { width: 15px; height: 15px; }

/* QUICK DISCOVER shares the top-bar utility geometry with Notifications but
   keeps its own compact search/results contract. */
.h-qdisc-layer { position: absolute; inset: 0; z-index: 53; pointer-events: none; }
.h-qdisc-layer__scrim {
  position: absolute; inset: 0; width: 100%; border: 0;
  background: var(--scrim-modal); opacity: 0; pointer-events: none;
  transition: opacity var(--t-fast);
}
.h-qdisc {
  position: absolute; top: 58px; right: 8px; width: min(calc(100% - 16px), 390px);
  max-height: calc(100% - 68px); overflow-y: auto;
  border: 1px solid var(--line2); border-radius: var(--r-xl);
  background: var(--panel); color: var(--ink); box-shadow: 0 22px 58px var(--scrim-modal);
  opacity: 0; transform: translateY(-7px) scale(.985);
  transition: opacity var(--t-fast), transform var(--t-fast); outline: 0;
}
.h-qdisc-layer.is-open { pointer-events: auto; }
.h-qdisc-layer.is-open .h-qdisc-layer__scrim { opacity: 1; pointer-events: auto; }
.h-qdisc-layer.is-open .h-qdisc { opacity: 1; transform: none; }
.h-qdisc > header {
  position: sticky; z-index: 2; top: 0; display: grid;
  grid-template-columns: 38px minmax(0,1fr) 38px; align-items: center; gap: 6px;
  padding: 12px; border-bottom: 1px solid var(--line2); background: var(--panel2);
}
.h-qdisc > header > div { min-width: 0; text-align: center; }
.h-qdisc > header small {
  display: block; color: var(--purple); font-size: 10px; font-weight: 900;
  letter-spacing: .14em;
}
.h-qdisc > header h2 {
  margin: 3px 0 0; overflow: hidden; font: 400 25px/1 var(--font-display);
  letter-spacing: .03em; text-overflow: ellipsis; text-transform: uppercase;
  white-space: nowrap;
}
.h-qdisc__close {
  display: grid; place-items: center; width: 36px; height: 36px; padding: 0;
  border: 1px solid var(--line2); border-radius: var(--r-md);
  background: var(--elev); color: var(--ink); font-size: 23px; line-height: 1;
}
.h-qdisc__form {
  display: grid; grid-template-columns: 20px minmax(0,1fr) auto;
  align-items: center; gap: 7px; margin: 12px; padding: 5px 5px 5px 10px;
  border: 1px solid var(--purple); border-radius: var(--r-lg); background: var(--bg);
}
.h-qdisc__form:focus-within { box-shadow: 0 0 18px rgba(var(--purple-rgb),.22); }
.h-qdisc__form > .h-ic { width: 17px; height: 17px; color: var(--purple); }
.h-qdisc__form input,.h-qdisc__form input:focus {
  min-width: 0; height: 38px; padding: 0; border: 0 !important; outline: 0 !important;
  background: transparent; color: var(--ink); font-size: 16px; box-shadow: none !important;
}
.h-qdisc__form button {
  min-height: 36px; padding: 0 12px; border: 0; border-radius: var(--r-md);
  background: var(--purple-solid); color: var(--on-purple); font-weight: 900;
}
.h-qdisc__results { padding: 0 12px; }
.h-qdisc__result {
  display: grid; grid-template-columns: 36px minmax(0,1fr) 16px;
  align-items: center; gap: 10px; width: 100%; padding: 10px 4px;
  border: 0; border-bottom: 1px solid var(--line); background: transparent;
  color: var(--ink); font: inherit; text-align: left; text-decoration: none;
}
.h-qdisc__icon {
  display: grid; place-items: center; width: 36px; height: 36px;
  border-radius: var(--r-md); background: var(--active-purple-bg); color: var(--active-purple-ink);
}
.h-qdisc__icon .h-ic { width: 18px; height: 18px; }
.h-qdisc__copy { min-width: 0; }
.h-qdisc__copy strong,.h-qdisc__copy small { display: block; }
.h-qdisc__copy strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-qdisc__copy small {
  display: -webkit-box; margin-top: 3px; overflow: hidden; color: var(--muted);
  font-size: 11px; line-height: 1.35; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
}
.h-qdisc__arrow { width: 15px; height: 15px; color: var(--muted); }
.h-qdisc__loading,.h-qdisc__empty {
  padding: 20px 8px; color: var(--muted); font-size: 12px; line-height: 1.45; text-align: center;
}
.h-qdisc__empty small { display: block; margin-top: 4px; }
.h-qdisc__more {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  width: calc(100% - 24px); min-height: 40px; margin: 10px 12px 13px; padding: 0 10px;
  border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--elev);
  color: var(--active-purple-ink); font-weight: 900; white-space: nowrap;
}
.h-qdisc__more .h-ic { width: 14px; height: 14px; flex: none; }
@media (prefers-reduced-motion: reduce) {
  .h-ntlayer__scrim,.h-ntcentre,.h-qdisc-layer__scrim,.h-qdisc { transition: none; }
}

/* HELP is a compact global utility attached to the persistent top bar. */
.h-help-layer { position:absolute; inset:0; z-index:55; pointer-events:none; }
.h-help-layer__scrim { position:absolute; inset:0; width:100%; border:0; background:var(--scrim-modal); opacity:0; pointer-events:none; transition:opacity var(--t-fast); }
.h-helpwin { position:absolute; top:58px; right:8px; width:min(calc(100% - 16px),390px); max-height:calc(100% - 68px); display:flex; flex-direction:column; overflow:hidden; border:1px solid var(--line2); border-radius:var(--r-xl); background:var(--panel); color:var(--ink); box-shadow:0 22px 58px var(--scrim-modal); opacity:0; transform:translateY(-7px) scale(.985); transition:opacity var(--t-fast),transform var(--t-fast); outline:0; }
.h-help-layer.is-open { pointer-events:auto; }
.h-help-layer.is-open .h-help-layer__scrim { opacity:1; pointer-events:auto; }
.h-help-layer.is-open .h-helpwin { opacity:1; transform:none; }
.h-helpwin>header { display:grid; grid-template-columns:38px minmax(0,1fr) 38px; align-items:center; gap:6px; flex:none; padding:12px; border-bottom:1px solid var(--line2); background:var(--panel2); }
.h-helpwin>header>div { min-width:0; text-align:center; }
.h-helpwin>header small { display:block; color:var(--green); font-size:10px; font-weight:900; letter-spacing:.14em; }
.h-helpwin>header h2 { margin:3px 0 0; font:400 25px/1 var(--font-display); letter-spacing:.03em; text-transform:uppercase; }
.h-helpwin__back,.h-helpwin__close { display:grid; place-items:center; width:36px; height:36px; padding:0; border:1px solid var(--line2); border-radius:var(--r-md); background:var(--elev); color:var(--ink); }
.h-helpwin__back[hidden] { display:grid!important; visibility:hidden; }
.h-helpwin__back .h-ic { width:17px; height:17px; }
.h-helpwin__close { font-size:23px; line-height:1; }
.h-helpwin__body { min-height:0; overflow-y:auto; padding:14px; }
.h-helpwin__intro small { color:var(--purple); font-size:10px; font-weight:900; letter-spacing:.12em; }
.h-helpwin__intro h3 { margin:5px 0 4px; font:400 25px/1 var(--font-display); text-transform:uppercase; }
.h-helpwin__intro p { margin:0; color:var(--muted); font-size:12px; line-height:1.45; }
.h-helpwin__srch { margin-top:13px; }
.h-helpwin__guides { min-height:88px; margin-top:10px; border:1px dashed var(--line2); border-radius:var(--r-lg); background:var(--bg); }
/* GD-05: results are a plain list (the Guides result rows), no dashed box; the last row has no rule under it. */
.h-helpwin__guides.is-list { min-height:0; border:0; border-radius:0; background:transparent; }
.h-helpwin__guides.is-list .h-gd__res:last-child { border-bottom:0; }
.h-helpwin__empty { display:grid; place-items:center; min-height:88px; padding:14px; color:var(--muted); font-size:11px; line-height:1.45; text-align:center; }
.h-helpwin__more { margin-top:15px; }
.h-helpwin__more>small { display:block; margin:0 3px 5px; color:var(--green); font-size:10px; font-weight:900; letter-spacing:.12em; }
.h-helpwin__more>button { display:grid; grid-template-columns:38px minmax(0,1fr) 16px; align-items:center; gap:10px; width:100%; padding:11px 5px; border:0; border-bottom:1px solid var(--line); background:transparent; color:var(--ink); text-align:left; }
.h-helpwin__more>button>.h-ic:first-child { width:36px; height:36px; padding:9px; border-radius:var(--r-md); background:var(--active-green-bg); color:var(--green); }
.h-helpwin__more>button>.h-ic:last-child { width:15px; height:15px; color:var(--muted); }
.h-helpwin__more strong,.h-helpwin__more em { display:block; }
.h-helpwin__more em { margin-top:3px; color:var(--muted); font-size:10px; font-style:normal; }
.h-helpwin__form { display:grid; gap:12px; margin-top:15px; }
.h-helpwin__form label>span { display:block; margin-bottom:5px; color:var(--muted); font-size:11px; font-weight:800; }
.h-helpwin__form input,.h-helpwin__form textarea { box-sizing:border-box; width:100%; padding:11px; border:1px solid var(--line2); border-radius:var(--r-md); background:var(--bg); color:var(--ink); font:16px var(--font-body); }
.h-helpwin__form input:focus,.h-helpwin__form textarea:focus { outline:0; border-color:var(--purple); box-shadow:0 0 16px rgba(var(--purple-rgb),.18); }
.h-helpwin__form p { margin:0; color:var(--muted); font-size:11px; line-height:1.45; }
@media(prefers-reduced-motion:reduce){.h-help-layer__scrim,.h-helpwin{transition:none}}

/* ---------------------------------------------------------------------------
   THE STAFF HUB PAGE (08-13) — staff.html

   Karl: "staff hub should be its own layout... not a popup overlay... that
   being said, i do like the idea of the quick view pop up existing, and then
   having a link to a much deeper staff hub."

   ONE CLEAN SCROLL OF ALWAYS-OPEN CARDS, which is not a style choice — Phase 1
   of the live overhaul retired the collapsing accordion for exactly this, and
   its own test step reads "the page reads as one clean scroll of cards". No
   accordion here, inherited rather than invented.
   ------------------------------------------------------------------------ */
/* THE STAFF PAGE COULD NOT SCROLL, and Karl found it by opening it.
   `.h-app` is `height:100dvh; overflow:hidden` — a full-height column whose
   SCROLLER is `.h-app__screen`. staff.html is its own document and puts `.h-sp`
   straight into that column with neither `flex:1 1 auto; min-height:0` nor an
   overflow, so everything below the fold was unreachable. The page had all its
   content and no way to see it. */
.h-sp {
  max-width: 720px; margin: 0 auto; padding: 18px 16px 64px; width: 100%;
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
}
.h-sp__hi { font-family: var(--font-head); font-size: 22px; margin: 4px 0 2px; }
.h-sp__sub { color: var(--muted); font-size: 13px; margin: 0 0 18px; }

.h-sp__card {
  background: var(--panel); border: 1px solid var(--line2);
  border-radius: var(--r-md); padding: 14px 16px; margin: 0 0 14px;
}
.h-sp__cardhead {
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); font-weight: 800; margin-bottom: 10px;
}
.h-sp__calm { color: var(--muted); font-size: 13px; margin: 6px 0; }

/* NEEDS ATTENTION. Every row goes somewhere — a panel that tells you something
   needs doing and gives you nowhere to go is a worry with no handle on it. */
.h-sp__att-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: none; border: 0; border-bottom: 1px solid var(--line2);
  color: inherit; font: inherit; text-align: left; padding: 10px 0; cursor: pointer;
}
.h-sp__att-row:last-of-type { border-bottom: 0; }
.h-sp__att-dot {
  width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--muted);
}
.h-sp__att-dot.is-high { background: var(--green); box-shadow: 0 0 8px var(--green); }
.h-sp__att-main { flex: 1 1 auto; min-width: 0; }
.h-sp__att-l { display: block; font-weight: 600; }
.h-sp__att-s { display: block; font-size: 12.5px; color: var(--muted); margin-top: 1px; }
.h-sp__chev { flex: none; color: var(--muted); font-size: 18px; }

/* TWO TILES, and the row is absent rather than empty when there is nothing in
   it — Phase 6: "it never shows a confusing $0 shell early in a month." */
.h-sp__tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 0 0 14px; }
.h-sp__tile {
  background: var(--panel); border: 1px solid var(--line2);
  border-radius: var(--r-md); padding: 14px 16px;
}
.h-sp__tv { display: block; font-family: var(--font-head); font-size: 24px; color: var(--green); }

/* 🚪 THE STAFF-FACING PAYOUTS DOOR. It reads as a door rather than a tile
   because it goes somewhere — same anatomy as `.h-sp__att-row` (label, sub,
   chevron) but an anchor, so it gets a middle-click, a bookmark and Back.

   ⚠️ IT SITS OUTSIDE `.h-sp__tiles` AND THAT IS DELIBERATE. The tile row is
   absent when a month has no sessions; a coach with a quiet month is exactly
   the person who wants to look at what they were paid before it, so this must
   not vanish with the numbers. */
.h-sp__payouts {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: var(--panel); border: 1px solid var(--line2);
  border-radius: var(--r-md); padding: 14px 16px; margin: 0 0 14px;
  color: inherit; text-decoration: none;
}
.h-sp__payouts:hover { border-color: var(--green); }
.h-sp__payl { font-family: var(--font-head); font-size: 15px; }
.h-sp__pays { color: var(--muted); font-size: 12.5px; margin-left: auto; text-align: right; }
.h-sp__tl { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; }
.h-sp__tnote { grid-column: 1 / -1; margin: 0; font-size: 12px; color: var(--muted); }

.h-sp__hero { border-color: var(--green); background: var(--green-dim); }
.h-sp__hero-t { font-weight: 700; font-size: 16px; }
.h-sp__hero-w { color: var(--ink); font-size: 13px; margin-top: 2px; }
.h-sp__hero-p { color: var(--muted); font-size: 12.5px; margin-top: 1px; }

.h-sp__row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 0; border-bottom: 1px solid var(--line2);
}
.h-sp__row:last-of-type { border-bottom: 0; }
/* A BUTTON AS OF 08-13h — the shift title opens the shift. Reset to the text
   it was: left it alone and every assignment row grew a grey system chrome
   box around its name. `display:flex` keeps the two lines stacked exactly as
   the span did. */
.h-sp__row-main {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.h-sp__row-main:disabled { cursor: default; }
.h-sp__row-t { display: block; font-weight: 600; }
.h-sp__row-s { display: block; font-size: 12.5px; color: var(--muted); margin-top: 1px; }
/* Never wraps under the name: a figure that moves with the length of a venue
   is a figure you misread. */
.h-sp__row-pay { flex: none; font-weight: 700; }

.h-sp__soon { border-style: dashed; }

/* THE LINK OUT OF THE QUICK VIEW, in the sheet rather than on the page. */
.h-sh__deep {
  display: block; margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--line2);
  color: var(--green); font-weight: 600; font-size: 13px; text-decoration: none;
}

@media (max-width: 420px) {
  /* One tile per row rather than two squeezed ones — a dollar figure that
     wraps mid-number is worse than a taller card. */
  .h-sp__tiles { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------------------
   WHO HAS USED THIS ACCOUNT

   `profile_switch_log` has been written since 0001 and had no reader until
   2026-08-15. Three states, and they are not the same fact:
     right now   a session still exists AND still has this profile on screen
     finished    somebody pressed switch-back
     left open   neither — a closed tab, not a presence
   Only the first is coloured, because only the first is happening.
   ------------------------------------------------------------------------ */
.h-swlog { list-style: none; margin: 8px 0 0; padding: 0; }
.h-swlog li {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 10px;
  padding: 9px 0; border-top: 1px solid var(--line);
}
.h-swlog__who  { font-weight: 700; font-size: 13.5px; }
.h-swlog__when { font-size: 11.5px; color: var(--muted); text-align: right; }
.h-swlog__when.is-live { color: var(--green); font-weight: 700; }
.h-swlog__at   { grid-column: 1 / -1; font-size: 11.5px; color: var(--muted); }

/* ---------------------------------------------------------------------------
   SCHEDULES YOU HAVE BUILT

   One row per run of the builder. `schedule_series` has existed since 0009 and
   had no reader until 2026-08-16, so this is the first time an organiser can
   see what they made as a THING rather than as loose games on a calendar.
   ------------------------------------------------------------------------ */
.h-srs {
  padding: 11px 0; border-bottom: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 6px; align-items: flex-start;
}
.h-srs:last-child { border-bottom: 0; }
.h-srs__h { display: flex; width: 100%; gap: 10px; align-items: baseline; }
.h-srs__n { font-weight: 700; font-size: 14px; flex: 1; min-width: 0; }
.h-srs__d { font-size: 11.5px; color: var(--muted); flex: none; }
.h-srs__m { font-size: 12px; color: var(--muted); }
/* Nothing left to call off is a STATE, not a disabled button — a greyed control
   invites a tap that will never do anything. */
.h-srs__done { font-size: 11.5px; color: var(--muted); font-style: italic; }

/* ---------------------------------------------------------------------------
   GUARDIANSHIP — THE BACK-OFFICE PANEL

   Karl's 08-22 ruling gave managers the power to add and remove a guardian;
   the screen that uses it arrived 08-24, and these are the only rules it needed
   that did not already exist on the staff-admin surface. Everything else reuses
   `.h-sa__*`, deliberately: a second visual language for one panel is how a
   back office starts looking like four different products.

   TOKENS ONLY, no literal colours — the contrast pass reads computed values and
   a hard-coded hex is a value nobody can retune when a theme changes.
   ------------------------------------------------------------------------ */
.h-gd__row {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 10px; padding: 9px 10px; border-radius: var(--r-sm);
  background: var(--panel); border: 1px solid var(--line2);
}
/* The reason field takes the whole width UNDER the row it belongs to, rather
   than squeezing in beside the button. A one-line "why" box at the end of a
   flex row is the width of a word, and this text goes on a permanent record. */
.h-gd__reason {
  flex-basis: 100%; display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px;
  padding-top: 8px; border-top: 1px solid var(--line2);
}
.h-gd__reason .h-sa__f { flex: 1 1 220px; min-width: 0; }

/* A BADGE, NOT A BUTTON. `.h-chip` is a control everywhere else on this
   surface — it has `cursor: pointer` and lives in a tablist. These two carry a
   FACT about a row, so they lose the pointer and the tap affordance; a chip
   that looks tappable and is not is a smaller version of the same lie as a
   disabled control with no explanation. */
/* 🏛 `S2-07` KEEPS THIS ONE A PILL, AND THE PARAGRAPH ABOVE IS THE ARGUMENT
   FOR IT, NOT A NEW ONE: this variant already declares `cursor: default`
   because it is a FACT about a row and not a control. Karl asked for the
   FILTER chips to take the buttons' corner. A thing you can press now has the
   button's shape; a label keeps the label's. Shape carries the same meaning
   the cursor already does, in a file that had already made that call. */
.h-chip--sm { padding: 3px 9px; font-size: 11.5px; cursor: default; border-radius: var(--r-pill); }

/* "No guardian" on a minor is the one row in this list that needs finding at a
   glance — that member cannot sign in until it is fixed. `--danger-solid` with
   `--on-danger`, NOT `--danger`, for the reason tokens.css records against
   `.h-btn--danger`: white on `--danger` measures 2.78:1 and fails outright,
   while this pair is 5.46:1 and holds in both themes. */
.h-chip--danger {
  background: var(--danger-solid); border-color: var(--danger-solid);
  color: var(--on-danger);
}

/* ---------------------------------------------------------------------------
   THE HUB'S MOUNT POINTS — ONE CLASS THAT MEANT TWO DIFFERENT THINGS, NEITHER
   OF THEM WRITTEN DOWN.

   Found 2026-08-24 by the widened `client-contracts` check. `h-hub__slot` had
   NO rule at all, and `hub.js` emitted it in two shapes:

     Messages / Discover  <div class="h-hub__slot" style="flex:1 1 auto;
                              min-height:0;display:flex">   ← a full-height mount
     h365 / lockerroom /  <div class="h-hub__slot">          ← a plain block
     profile

   Same class, opposite layout contracts, and the difference living in an INLINE
   STYLE ATTRIBUTE on two of the five. An inline style is the one place a
   stylesheet cannot reach: it is invisible to the theme, to the contrast pass,
   and to every check that reads `assets/css`. Two of the five slots were being
   laid out somewhere no tool in this repo looks.

   SO THE TWO CONTRACTS GET TWO NAMES AND BOTH LIVE HERE. `--fill` carries
   exactly what the inline style carried — measured before and after, identical
   computed `display` / `flex-grow` / `min-height` — and the plain slot keeps
   the `display: block` it already had by default, said out loud so the class is
   no longer a promise with nothing behind it.
   ------------------------------------------------------------------------ */
.h-hub__slot { display: block; }
.h-hub__slot--fill { display: flex; flex: 1 1 auto; min-height: 0; }

/* SHORT VIEWPORTS — Find and Schedule's own header gives height back too.
   It is a fixed 68.75px on top of the shell's 122px of chrome, so on a 390px
   screen the two together are nearly half the viewport. Same height-keyed
   breakpoint as `components.css`; see the long note there for why it is keyed
   on height rather than on `orientation`. */
@media (max-height: 500px) {
  .h-sch__top { padding: 6px 16px 2px; }
  .h-sch__body { padding: 4px 16px 22px; }
}

/* ---- V3.94 · B03 · Manage lives in the tab bar: right-aligned, the owner
   ring's amber, outlined not filled, and its word is never folded away. ---- */
.h-mgbtn {
  display: inline-flex; align-items: center; gap: 6px; min-height: 34px; padding: 6px 12px;
  border: 1.5px solid var(--warn); border-radius: var(--r-pill);
  background: linear-gradient(rgba(var(--warn-rgb), .08), rgba(var(--warn-rgb), .08)), var(--panel2); color: var(--warn);
  font: inherit; font-size: 12px; font-weight: 800; cursor: pointer; flex: none; white-space: nowrap;
}
.h-mgbtn .h-ic { width: 15px; height: 15px; }
/* A not-built-yet stub panel (Membership & Pro). */
.h-stub { display: flex; flex-direction: column; gap: 12px; align-items: flex-start; }
.h-stub__lead { margin: 0; font-size: 17px; font-weight: 700; line-height: 1.35; }
.h-stub .h-btn { margin-top: 6px; }

/* Fill your roster in the Menu (Karl, 2026-09-29): an explainer, three
   multi-select role tiles, and a Continue that stays on screen. */
.h-rfill { display: flex; flex-direction: column; gap: 14px; }
.h-rfill__hero {
  padding: 16px; border-radius: var(--r-lg); border: 1px solid var(--line2);
  background: linear-gradient(160deg, var(--green-dim), transparent 60%), var(--panel2);
}
.h-rfill__kicker { margin: 0; color: var(--green); font-size: 11px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; }
.h-rfill__title { margin: 4px 0 6px; font-family: var(--font-display); font-weight: 400; font-size: 24px; line-height: 1.1; letter-spacing: .02em; text-transform: uppercase; }
.h-rfill__lead { margin: 0; font-size: 13.5px; line-height: 1.45; color: var(--ink); }
.h-rfill__steps { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 10px; }
.h-rfill__step { display: flex; gap: 10px; align-items: flex-start; }
.h-rfill__step b { display: block; font-size: 13.5px; }
.h-rfill__step small { display: block; font-size: 12px; color: var(--muted); }
.h-rfill__n {
  flex: none; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  border: 1.5px solid var(--green); color: var(--green); font-weight: 900; font-size: 13px;
}
.h-rfill__pickhd { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.h-rfill__pickhd b { font-size: 15px; }
.h-rfill__pickhd small { color: var(--green); font-size: 12.5px; font-weight: 700; }
.h-rfill__roles { display: grid; gap: 8px; }
.h-rfill__role {
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 64px; padding: 10px 12px;
  border: 1.5px solid var(--line2); border-radius: var(--r-lg); background: var(--panel2);
  color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.h-rfill__role.is-on { border-color: var(--green); background: linear-gradient(var(--green-dim), var(--green-dim)), var(--panel2); }
.h-rfill__ric { flex: none; width: 42px; height: 42px; border-radius: 12px; display: grid; place-items: center; background: var(--panel); }
.h-rfill__ric .h-ic { width: 24px; height: 24px; }
.h-rfill__rt { flex: 1; min-width: 0; }
.h-rfill__rt b { display: block; font-size: 15px; }
.h-rfill__rt small { display: block; font-size: 12px; color: var(--muted); }
.h-rfill__tick {
  flex: none; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  border: 1.5px solid var(--line2); color: transparent; font-weight: 900;
}
.h-rfill__role.is-on .h-rfill__tick { border-color: var(--green); background: var(--green); color: var(--on-green); }
/* WZ-08: the game-or-group choice is ONE pick, so it reads its state from
   `aria-pressed` rather than a toggled class. */
.h-rfill__kind[aria-pressed="true"] { border-color: var(--green); background: linear-gradient(var(--green-dim), var(--green-dim)), var(--panel2); }
.h-rfill__kind[aria-pressed="true"] .h-rfill__tick { border-color: var(--green); background: var(--green); color: var(--on-green); }
.h-rfill__bar { padding: 10px 0 4px; }   /* not sticky: it floated over the page (2026-09-29) */

/* GA-02: the sentence under a section label that says what the rows below control. */
/* B26: Settings' section tabs sit above the chapter they show. */
.h-set__tabs { margin: 0 0 14px; }
.h-grp__lead { margin: -2px 2px 8px; font-size: 12.5px; line-height: 1.4; color: var(--muted); }
/* GA-03: Leave group sits apart at the foot of the Info tab. */
.h-room__leave { margin-top: 22px; padding-top: 14px; border-top: 1px solid var(--line); }
.h-btn--dangerline { color: var(--danger); border-color: var(--danger); }
/* Household rule (Karl, walk v45): You & Family's Leave household, set apart like Leave group. */
.h-fam__leave { margin-top: 26px; padding-top: 14px; border-top: 1px solid var(--line); justify-content: flex-start; }
.h-fam__leave .h-btn { flex: 0 0 auto; width: auto; }
/* RO-02: the Roster heading's cog-only Manage roster button. */
.h-mgbtn--cog { width: 38px; height: 38px; min-height: 38px; padding: 0; justify-content: center; }
.h-mgbtn--cog .h-ic { width: 18px; height: 18px; }
/* RO-02 (walk v37): the roster icon, with a small amber cog badge on its corner. */
.h-mgbtn--roster { position: relative; }
.h-mgbtn--roster > .h-ic { width: 19px; height: 19px; }
/* RO-02 second walk (Karl): the disc sits TIGHT around the cog, so it no
   longer covers the people icon. */
.h-mgbtn__badge {
  position: absolute; right: 4px; bottom: 4px; width: 12px; height: 12px; border-radius: 50%;
  display: grid; place-items: center; background: var(--panel); color: var(--warn);
}
.h-mgbtn__badge .h-ic { width: 11px !important; height: 11px !important; }
.h-mgbtn__lb { display: inline; }   /* the word is never folded, unlike a tab's label */
.h-mgbtn:hover { background: rgba(var(--warn-rgb), .16); }
.h-mgbtn:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }
.h-room__tabs .h-mgbtn { margin-left: auto; }
/* Preview v2 (Karl, approved): Manage in a Space's tab bar is the slim amber
   cog + word — no chip, the tab bar's own type. */
.h-room__tabs .h-mgbtn { min-height: 0; padding: 7px 6px; gap: 5px; border: 0; background: none;
  font-size: 12.5px; font-weight: 700; color: var(--warn); }
.h-room__tabs .h-mgbtn:hover { background: none; color: var(--warn-solid); }
.h-room__tabs .h-mgbtn .h-ic { width: 17px; height: 17px; }

/* 🔀 Preview v2: a Program's title is the switcher. The whole name + role line
   is the button; the chevron is a hint with no background. */
.h-swt { flex: 1; min-width: 0; display: flex; flex-direction: column; padding: 0; border: 0; background: none;
  color: inherit; font: inherit; text-align: left; cursor: pointer; border-radius: 8px; }
.h-swt:focus-visible { outline: 2px solid var(--green); outline-offset: 3px; }
.h-swt__line { display: flex; align-items: center; gap: 4px; min-width: 0; }
.h-swt__line .h-room__n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-swt__chev { flex: none; width: 16px; height: 16px; color: var(--ink); opacity: .85; transition: transform .18s; }
.h-swt[aria-expanded="true"] .h-swt__chev { transform: rotate(180deg); }
.h-swdrop { padding: 12px; margin: 0 0 10px; border: 1px solid var(--line2); border-radius: var(--r-lg); background: var(--panel); }
.h-swdrop__k { display: block; margin: 0 2px 8px; font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.h-swdrop__cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.h-swcard { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; min-width: 0; padding: 10px;
  border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel2); color: var(--ink); font: inherit; text-align: left; cursor: pointer; }
.h-swcard .h-gav { border-radius: 10px; overflow: hidden; }
.h-swcard b { font-size: 12.5px; line-height: 1.25; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.h-swcard span { font-size: 10.5px; color: var(--muted); line-height: 1.3; }
.h-swdrop__hint { margin: 0; font-size: 13px; color: var(--muted); }
.h-swdrop__all { display: flex; align-items: center; justify-content: space-between; width: 100%; margin-top: 10px; padding: 10px 4px 2px;
  border: 0; border-top: 1px solid var(--line); background: none; color: var(--ink); font: inherit; font-size: 13.5px; font-weight: 700; cursor: pointer; }
.h-swdrop__all .h-ic { width: 16px; height: 16px; color: var(--muted); }
.h-room__tabs--mg { justify-content: flex-end; }
/* The Game Space's bar is a grid of equal tabs; Manage takes its own last column. */
.gs-tabs:has(.h-mgbtn) { grid-template-columns: repeat(var(--gs-tabs), minmax(0, 1fr)) auto; }
.gs-tabs .h-mgbtn { align-self: center; margin: 0 2px 0 4px; padding: 6px 10px; }
/* Walk v45 (Karl, phones): Manage + cog squished the tab bar and pushed the
   Switch chevron out of view. On a phone it is the amber cog alone; the
   button keeps its aria-label, so it still says "Manage …". */
@media (max-width: 520px) {
  .h-mgbtn:not(.h-mgbtn--cog) { width: 34px; min-height: 34px; height: 34px; padding: 0; gap: 0; justify-content: center; }
  .h-mgbtn:not(.h-mgbtn--cog) .h-mgbtn__lb { display: none; }
  .h-mgbtn:not(.h-mgbtn--cog) .h-ic { width: 17px; height: 17px; }
  .gs-tabs .h-mgbtn:not(.h-mgbtn--cog) { padding: 0; }
}
/* The app's own top-right buttons, copied into a Space's head. */
.h-detail__icons { gap: 10px; }
@media (max-width: 380px) { .h-detail__icons { gap: 7px; } .h-detail__icons .h-topicon svg { width: 19px; height: 19px; } }
.h-mdrawer__danger { margin-top: 18px; padding-top: 10px; border-top: 1px solid var(--line2); }

/* ---- V3.86 · the create-game wizard ---------------------------------------- */
.h-wiz { display: flex; flex-direction: column; gap: 12px; }
.h-wiz > section { display: flex; flex-direction: column; gap: 10px; }
.h-wiz > section[hidden], .h-wiz [data-wflow-body] > section[hidden] { display: none; }
.h-wiz [data-wflow-body] { display: contents; }
.h-wiz [data-wflow-body] > section { display: flex; flex-direction: column; gap: 10px; }
.h-wiz__prog { display: flex; flex-direction: column; gap: 6px; }
.h-wiz__bars { display: flex; gap: 5px; }
.h-wiz__bars i { flex: 1; height: 4px; border-radius: var(--r-pill); background: var(--line2); }
.h-wiz__bars i.is-on { background: var(--green); }
.h-wiz__lbl { font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.h-wiz__intro small { display: block; font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--purple); }
.h-wiz__intro h3 { margin: 4px 0 0; font-family: var(--font-head); font-size: 22px; line-height: 1.1; text-wrap: balance; }
.h-wiz__intro p { margin: 6px 0 0; font-size: 13px; line-height: 1.45; color: var(--muted); }
.h-wiz__intents { display: grid; gap: 8px; }
.h-wiz__intent, .h-wiz__fork {
  display: grid; grid-template-columns: 40px minmax(0, 1fr) 16px; align-items: center; gap: 10px;
  width: 100%; padding: 12px; text-align: left; font: inherit; color: var(--ink); cursor: pointer;
  border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel2);
}
.h-wiz__intent:hover, .h-wiz__fork:hover { border-color: var(--purple); }
.h-wiz__iic { width: 40px; height: 40px; display: grid; place-items: center; border-radius: var(--r-sm); background: var(--panel); color: var(--ink); }
.h-wiz__iic .h-ic { width: 20px; height: 20px; }
.h-wiz__itext strong, .h-wiz__itext small, .h-wiz__itext span { display: block; }
.h-wiz__itext strong { font-size: 14px; }
.h-wiz__itext small { font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--purple); }
.h-wiz__itext span, .h-wiz__intent .h-wiz__itext small { margin-top: 3px; font-size: 12px; line-height: 1.4; color: var(--muted); letter-spacing: 0; text-transform: none; font-weight: 400; }
.h-wiz__card { display: flex; flex-direction: column; gap: 8px; padding: 12px; border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel2); }
.h-wiz__card[hidden] { display: none; }
.h-wiz__row { display: flex; align-items: center; gap: 10px; }
.h-wiz__row[hidden] { display: none; }
.h-wiz__rn { font-weight: 800; font-size: 14px; }
.h-wiz__rl { font-size: 13px; color: var(--muted); }
.h-wiz__open { margin-left: auto; font-size: 12px; font-weight: 800; color: var(--muted); font-variant-numeric: tabular-nums; }
.h-wiz__say { margin: 0; font-size: 13px; line-height: 1.45; color: var(--ink); }
.h-wiz__say:empty { display: none; }
.h-wiz__live p { margin: 0; font-size: 13px; line-height: 1.45; }
.h-wiz__seg { width: 100%; }
.h-wiz [data-wseg="deliver"] button.is-on[data-wv="quiet"] { background: var(--purple-solid); color: var(--on-purple); }
.h-wiz__ctx { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel2); }
.h-wiz__ctx .h-ic { width: 18px; height: 18px; color: var(--purple); flex: none; }
.h-wiz__ctx strong, .h-wiz__ctx small { display: block; }
.h-wiz__ctx small { font-size: 12px; color: var(--muted); }
.h-wiz__sum small, .h-wiz__rev small { font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--purple); }
.h-wiz__sum strong, .h-wiz__rev strong { font-size: 14px; }
.h-wiz__sum span, .h-wiz__rev span { font-size: 13px; color: var(--muted); }
.h-wiz__rev { gap: 3px; }
.h-wiz [data-wrev] { display: flex; flex-direction: column; gap: 8px; }
.h-wiz__sumacts { display: flex; gap: 8px; flex-wrap: wrap; }
/* 🧊 PY-10 v41 (Karl's screenshot): the bar was `bottom: 0` inside a sheet
   padded at the bottom, so it floated above the edge with the form scrolling
   behind it. It now sits FLUSH (the sheet's padding cancelled), in the heavy
   sheet glass while more is below, solid at the floor (`ui.js footFloor`). */
.h-wiz__foot {
  /* Walk v45 (Karl): a wizard's Back / Continue sit at the END of the step,
     in the flow — never pinned, never on a bar (the global wizard protocol). */
  position: static; display: flex; gap: 10px; margin: 18px 0 4px; padding: 0;
  background: none; border: 0; box-shadow: none;
}
/* Continue while the step is incomplete: plainly NOT READY, still tappable so
   a tap can point at what is missing. */
.h-wiz__foot .h-btn.is-waiting { opacity: .5; }
/* `.is-attn` (the field a failed Continue is about) lives in components.css: sheets use it too. */
/* SP-02 v42: the Staff PIN view inside the Menu panel. */
.h-mpin { display: flex; flex-direction: column; gap: 10px; }
/* GA-05 v45: the group code chip (Roster, and under Join by code). */
.h-gcode {
  display: flex; align-items: center; gap: 10px; width: 100%; margin: 0 0 12px; padding: 10px 14px;
  background: var(--panel2); border: 1px dashed var(--line2); border-radius: var(--r-md);
  color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.h-gcode__l { font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.h-gcode__c { flex: 1; font-family: var(--font-head); font-size: 17px; letter-spacing: .08em; }
.h-gcode__i { width: 18px; height: 18px; color: var(--green); }
/* GA-05 second walk: the chip as a row with its own buttons (New code, Copy). */
.h-gcode--row { cursor: default; }
.h-gcode__btn { flex: none; display: grid; place-items: center; width: 34px; height: 34px; padding: 0; border: 1px solid var(--line2);
  border-radius: 50%; background: var(--panel); cursor: pointer; }
.h-gcode__btn:hover { border-color: var(--green); }
/* PY-10 v42: Roster & fees' three tabs. */
.h-rf__tabs { margin: 0 0 14px; }
/* PY-10 Roster & fees: the game's own limits, one row per role. */
.h-rf { display: block; }
.h-rf__limit { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 0; }
.h-rf__lt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* "Spots: 3" as text when Fill whatever opens is chosen. */
.h-need__fixed { font-family: var(--font-head); font-weight: 800; font-size: 16px; color: var(--ink); min-width: 28px; text-align: center; }
.h-wiz__foot .h-btn--ghost { flex: 1; }
.h-wiz__foot .h-btn:not(.h-btn--ghost) { flex: 1.6; }
.h-wiz__foot .h-btn[hidden] { display: none; }

/* ---- V3.90 · counts and money line up; no spinners ------------------------ */
.h-need__c, .h-need__amt { -moz-appearance: textfield; appearance: textfield; }
.h-need__c::-webkit-outer-spin-button, .h-need__c::-webkit-inner-spin-button,
.h-need__amt::-webkit-outer-spin-button, .h-need__amt::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.h-need__amt { flex: 0 0 84px; height: auto; align-self: stretch; }
.h-need__c[hidden] { display: none; }
.h-wiz__card.h-need { padding: 12px; border-bottom: 1px solid var(--line2); }
/* WZ-03 / WZ-05 (Karl, 2026-09-29): the question sits beside its box, and the
   box says what it counts. */
.h-wiz__card .h-need__countrow { display: flex; align-items: center; gap: 12px; margin-top: 8px; cursor: default; }
.h-need__cq { flex: 1 1 auto; min-width: 0; font-size: 14px; font-weight: 700; color: var(--ink); }
.h-need__cq .h-need__tip { display: block; margin-top: 2px; font-weight: 500; }
.h-need__cbox { flex: none; display: inline-flex; align-items: center; gap: 6px; }
.h-wiz__card .h-need__cbox .h-need__c { margin-left: 0; flex: 0 0 64px; width: 64px; }
.h-need__unit { font-size: 12px; font-weight: 700; color: var(--muted); }
/* WZ-03: the $ lives inside the money box again. */
.h-need__amtwrap { position: relative; flex: 0 0 96px; display: flex; align-self: stretch; }
.h-need__amtwrap .h-need__amt { flex: 1 1 auto; width: 100%; padding-left: 20px; text-align: left; }
.h-need__cur { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); font-weight: 800; color: var(--muted); pointer-events: none; }
/* WZ-06: They pay / You pay them with no amount yet — amber until filled. */
.h-need__amtwrap .h-need__amt:placeholder-shown { border-color: var(--warn); box-shadow: 0 0 0 1px var(--warn) inset; }
.h-need__amtwrap:has(.h-need__amt:placeholder-shown) .h-need__cur { color: var(--warn); }
.h-wiz__pubseg { margin-top: 10px; }

/* ---- V3.90 · who are you looking for (multi-select) ----------------------- */
.h-wiz__chips { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.h-wiz__chip {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 14px 8px; border: 1px solid var(--line2); border-radius: var(--r-md);
  background: var(--panel2); color: var(--ink); font: inherit; font-weight: 800; font-size: 13px; cursor: pointer;
}
.h-wiz__chip .h-ic { width: 24px; height: 24px; }
.h-wiz__chip.is-on { border-color: var(--green); box-shadow: 0 0 0 1px var(--green) inset; }
.h-wiz__tick { display: none; position: absolute; top: 6px; right: 8px; font-size: 12px; color: var(--green); }
.h-wiz__chip.is-on .h-wiz__tick, .h-wiz__friend.is-on .h-wiz__tick { display: block; }
.h-wiz__adds { display: flex; flex-wrap: wrap; gap: 8px; }
.h-wiz__add, .h-wiz__rm {
  border: 1px dashed var(--line2); border-radius: var(--r-pill); background: none; color: var(--ink);
  font: inherit; font-size: 12.5px; font-weight: 700; padding: 8px 14px; cursor: pointer;
}
.h-wiz__add[hidden] { display: none; }
.h-wiz__rm { align-self: flex-start; border-style: solid; color: var(--muted); padding: 6px 12px; font-weight: 600; }

/* ---- V3.90 · invite friends panel ------------------------------------------ */
.h-wiz--panel { gap: 12px; }
.h-wiz__friends { display: flex; flex-direction: column; }
.h-wiz__friend {
  position: relative; display: flex; align-items: center; gap: 10px; width: 100%; min-height: 48px;
  padding: 10px 34px 10px 6px; text-align: left; background: none; border: 0; border-bottom: 1px solid var(--line);
  color: var(--ink); font: inherit; cursor: pointer;
}
.h-wiz__friend small { color: var(--muted); font-size: 12px; margin-left: auto; }
.h-wiz__friend .h-wiz__tick { top: 50%; transform: translateY(-50%); right: 10px; font-size: 14px; }
.h-wiz__friend.is-on { background: var(--panel2); }

/* ---- V3.91 · the group roster manager ------------------------------------- */
.h-grm {
  /* Over the Space panel (`.h-detail`, 44) and the app's navigation, UNDER
     the sheet layer (50+) so the skill sheet, the roster intake and every
     confirmation open on top of it. */
  position: absolute; inset: 0; z-index: 46; overflow-y: auto; background: var(--bg); color: var(--ink);
  opacity: 0; transform: translateY(8px); transition: opacity var(--t-fast), transform var(--t-fast);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.h-grm.is-open { opacity: 1; transform: none; }
.h-grm__head {
  position: sticky; top: 0; z-index: 3; display: grid; grid-template-columns: 40px minmax(0, 1fr) auto;
  align-items: center; gap: 10px; padding: calc(12px + env(safe-area-inset-top, 0px)) 16px 12px;
  border-bottom: 1px solid var(--line); background: var(--bg);
}
.h-grm__back {
  width: 38px; height: 38px; display: grid; place-items: center; border: 1px solid var(--line2);
  border-radius: 50%; background: var(--panel2); color: var(--ink); cursor: pointer;
}
.h-grm__back .h-ic { width: 18px; height: 18px; }
.h-grm__titles { min-width: 0; }
.h-grm__titles small { display: block; color: var(--green); font-size: 11px; font-weight: 800; letter-spacing: .1em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.h-grm__titles h2 { margin: 2px 0 0; font-family: var(--font-head); font-size: 22px; line-height: 1.1; }
.h-grm__add {
  display: inline-flex; align-items: center; gap: 6px; min-height: 38px; padding: 0 12px;
  border: 1px solid var(--green); border-radius: var(--r-md); background: var(--panel2); color: var(--ink);
  font: inherit; font-size: 13px; font-weight: 800; cursor: pointer;
}
.h-grm__add .h-ic { width: 16px; height: 16px; }
/* RO-03: Share is a smaller button beside Add (it no longer takes a row). */
.h-grm__headbtns { display: flex; align-items: center; gap: 6px; }
.h-grm__add--share { border-color: var(--line2); padding: 0 10px; }
.h-grm__body { max-width: 720px; margin: 0 auto; padding: 14px 16px 40px; display: flex; flex-direction: column; gap: 12px; }
.h-grm__tiles, .h-rost__tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.h-rost__tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.h-grm__tiles > div, .h-rost__tiles > div { padding: 10px 8px; border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel2); }
.h-grm__tiles b, .h-rost__tiles b { display: block; font-family: var(--font-head); font-size: 22px; line-height: 1; font-variant-numeric: tabular-nums; }
.h-grm__tiles span, .h-rost__tiles span { display: block; margin-top: 4px; font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.h-grm__attn {
  width: 100%; display: grid; grid-template-columns: 38px minmax(0, 1fr) auto; align-items: center; gap: 10px;
  padding: 12px; border: 1px solid var(--purple); border-radius: var(--r-lg); background: var(--panel2);
  color: var(--ink); font: inherit; text-align: left; cursor: pointer;
  /* GA-04 v45 (Karl): room above and below, so it no longer touches the tiles. */
  margin: 12px 0;
}
.h-grm__attn > i { width: 36px; height: 36px; display: grid; place-items: center; border-radius: var(--r-md); border: 1px solid var(--purple); background: var(--panel); color: var(--ink); font-style: normal; }
.h-grm__attn > i .h-ic { width: 18px; height: 18px; }
.h-grm__attn strong, .h-grm__attn small { display: block; }
.h-grm__attn small { margin-top: 3px; font-size: 12px; color: var(--muted); }
.h-grm__attn > b { min-width: 26px; height: 26px; display: grid; place-items: center; border-radius: var(--r-pill); border: 1px solid var(--purple); background: var(--panel); color: var(--ink); font-size: 12px; }
.h-grm__code { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 12px; border: 1px solid var(--line2); border-radius: var(--r-lg); background: var(--panel2); }
.h-grm__code small, .h-grm__code strong { display: block; }
.h-grm__code small { font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.h-grm__code strong { margin-top: 3px; font-size: 14px; }
.h-grm__code button { display: inline-flex; align-items: center; gap: 6px; border: 0; background: none; color: var(--green); font: inherit; font-weight: 800; cursor: pointer; }
.h-grm__code .h-ic { width: 16px; height: 16px; }
.h-grm__fl small, .h-grm__lbl { display: block; margin: 0 0 6px 2px; font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.h-grm__seg { --n: 3; display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); gap: 6px; }
.h-grm__seg button {
  min-height: 40px; border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel2);
  color: var(--muted); font: inherit; font-size: 13px; font-weight: 800; cursor: pointer;
}
.h-grm__seg button.is-on { color: var(--ink); border-color: var(--line); background: var(--panel); }
.h-grm__seg.is-green button.is-on { border-color: var(--green); background: var(--green-dim); box-shadow: 0 0 14px rgba(var(--green-rgb), .14); }
.h-grm__seg.is-purple button.is-on { border-color: var(--purple); box-shadow: 0 0 14px rgba(var(--purple-rgb), .18); }
.h-grm__tools { display: flex; align-items: flex-end; justify-content: space-between; gap: 8px; }
.h-grm__tools > span small, .h-grm__tools > span b { display: block; }
.h-grm__tools > span small { font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--green); }
.h-grm__tools > span b { margin-top: 3px; font-size: 13px; }
.h-grm__btns { display: flex; gap: 6px; }
.h-grm__menuwrap { position: relative; }
.h-grm__btns button {
  display: inline-flex; align-items: center; gap: 6px; min-height: 38px; padding: 0 12px;
  border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel2); color: var(--ink);
  font: inherit; font-size: 13px; font-weight: 700; cursor: pointer; white-space: nowrap;
}
.h-grm__btns .h-ic { width: 15px; height: 15px; }
.h-grm__pop {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 5; min-width: 190px; padding: 6px;
  border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel); box-shadow: 0 12px 32px rgba(0, 0, 0, .35);
}
.h-grm__pop button {
  width: 100%; display: flex; justify-content: space-between; align-items: center; gap: 10px; min-height: 40px; padding: 0 10px;
  border: 0; border-radius: var(--r-sm); background: none; color: var(--ink); font: inherit; font-size: 14px; text-align: left; cursor: pointer;
}
.h-grm__pop button.is-current { background: var(--panel2); font-weight: 800; }
/* 📤 GA-04 v45: the Share menu (Copy code / Copy link / Share directly). The
   same popover, fixed to the viewport (spaces.js places it) with an icon per row. */
.h-sharepop { position: fixed; right: auto; z-index: 60; min-width: 220px; }
.h-sharepop button { justify-content: flex-start; }
.h-sharepop .h-ic { width: 18px; height: 18px; flex: none; color: var(--green); }
.h-sharepop__t { flex: 1; }
.h-sharepop__c { font-family: var(--font-head); font-size: 13px; letter-spacing: .08em; color: var(--muted); }
.h-sharepop button:hover, .h-sharepop button:focus-visible { background: var(--panel2); outline: none; }
.h-sharepop__head { display: flex; align-items: center; justify-content: space-between; padding: 4px 6px 6px 10px;
  font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.h-sharepop .h-sharepop__q { width: 24px; min-height: 24px; height: 24px; padding: 0; justify-content: center; border: 1px solid var(--line2);
  border-radius: 50%; font-size: 13px; font-weight: 800; color: var(--muted); }
.h-sharepop__help { margin: 0 4px 6px; padding: 8px 10px; border-radius: var(--r-sm); background: var(--panel2); max-width: 260px; }
.h-sharepop__help p { margin: 0 0 6px; font-size: 12.5px; line-height: 1.45; color: var(--ink); }
.h-sharepop__help p:last-child { margin-bottom: 0; }
.h-sharepop__help b { color: var(--green); }
.h-grm__attn.is-quiet { opacity: .85; }
/* Karl (walk v45): the switcher's pop-up list — up to 3 rows (avatar + name),
   then All my spaces. The share popover's look, fixed to the viewport. */
.h-swpop { position: fixed; right: auto; z-index: 60; min-width: 230px; max-width: calc(100vw - 16px); }
.h-swpop button { justify-content: flex-start; gap: 10px; }
.h-swpop__av { flex: none; border-radius: 8px; overflow: hidden; }
.h-swpop__n { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-swpop__all { border-top: 1px solid var(--line) !important; border-radius: 0 0 var(--r-sm) var(--r-sm) !important; margin-top: 4px; font-weight: 700; }
.h-swpop__all .h-ic { width: 16px; height: 16px; color: var(--muted); flex: none; }
.h-swpop__hint { margin: 6px 10px; font-size: 13px; color: var(--muted); }
.h-swpop__k { flex: none; width: 16px; height: 16px; color: var(--muted); }
.h-swpop button:hover, .h-swpop button:focus-visible { background: var(--panel2); outline: none; }
/* Karl (2026-10-01): a count on a Manage row (Applications waiting). */
/* BB-01 second walk: the quiet Fill your roster tip under Add a player. */
.h-addsec__tip { display: flex; gap: 10px; align-items: flex-start; margin: 18px 4px 0; padding-top: 14px; border-top: 1px solid var(--line);
  font-size: 13px; line-height: 1.5; color: var(--muted); }
.h-addsec__tip > .h-ic { width: 18px; height: 18px; flex: none; color: var(--green); margin-top: 1px; }
.h-addsec__link { padding: 0; border: 0; background: none; color: var(--green); font: inherit; font-weight: 700;
  text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.h-more__badge { flex: none; min-width: 20px; height: 20px; padding: 0 6px; border-radius: var(--r-pill); display: inline-grid; place-items: center; background: var(--danger-solid); color: var(--on-danger); font-size: 11px; font-weight: 800; }
.h-grm__list { border: 1px solid var(--line2); border-radius: var(--r-lg); background: var(--panel2); overflow: hidden; }
.h-grm__row {
  width: 100%; min-height: 60px; display: grid; grid-template-columns: 38px minmax(0, 1fr) auto; align-items: center; gap: 10px;
  padding: 10px 12px; border: 0; border-bottom: 1px solid var(--line); background: none; color: var(--ink);
  font: inherit; text-align: left; cursor: pointer;
}
.h-grm__row:last-child { border-bottom: 0; }
.h-grm__row[disabled] { cursor: default; }
.h-grm__row.is-retired, .h-grm__row.is-banned { opacity: .7; }
.h-grm__av {
  position: relative; width: 36px; height: 36px; display: grid; place-items: center; border: 2px solid var(--line2);
  border-radius: 50%; background: var(--panel); color: var(--ink); font-size: 12px; font-weight: 800;
}
.h-grm__av.is-big { width: 52px; height: 52px; font-size: 16px; }
/* C3 (2026-10-05): the face sits inside the ring (2px border), clipped round. */
.h-grm__av.has-face { background: none; }
.h-mrow__av.has-face { background: none; padding: 0; }
.h-mrow__av.has-face > .h-av { width: 100%; height: 100%; }
.h-grm__av.has-face > .h-av { width: 100%; height: 100%; }
/* Walk v45 (Karl): a member with an account wears a plain BLACK ring (may go
   when the avatar studio lands — coloured rings are for identifying only);
   no account = a plain black disc with a solid GREY ring; a member waiting to
   confirm keeps the normal face with a GREY DOTTED ring. */
.h-grm__av { border-color: var(--avatar-black); }
.h-grm__av.is-owner { border-color: var(--warn-solid); }
.h-grm__av.is-friend { border-color: var(--purple); }
.h-grm__av.is-ghost { border-style: solid; border-color: var(--avatar-ghost-ring); background: var(--avatar-black); color: var(--avatar-ghost-ink); }
/* RE-01 v45: a Hockey365 member added by email, waiting to confirm — the normal face with a grey dotted ring (Karl). */
.h-grm__av.is-pending { border-style: dotted; border-color: var(--avatar-ghost-ring); }
.h-grm__av i {
  position: absolute; right: -4px; bottom: -4px; width: 16px; height: 16px; display: grid; place-items: center;
  border-radius: 50%; border: 1px solid var(--warn-solid); background: var(--panel); color: var(--ink); font-style: normal; font-size: 9px; font-weight: 900;
}
.h-grm__rmain { min-width: 0; }
.h-grm__rmain strong, .h-grm__rmain small { display: block; }
.h-grm__rmain strong { font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.h-grm__rmain small { margin-top: 3px; font-size: 12.5px; line-height: 1.35; color: var(--muted); }
.h-grm__rmain small em { font-style: normal; color: var(--ink); }
.h-grm__rstat { display: flex; align-items: center; gap: 8px; color: var(--muted); }
.h-grm__rstat b { padding: 4px 9px; border-radius: var(--r-pill); font-size: 11px; font-weight: 800; border: 1px solid var(--line2); color: var(--ink); }
.h-grm__rstat b.is-regular { border-color: var(--green); }
.h-grm__rstat b.is-spare { border-color: var(--purple); }
.h-grm__sub { display: block; }   /* one back button only: the header's (Double Back Button, walk v37) */
.h-grm__sub > div { text-align: center; }
.h-grm__sub small { display: block; font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--purple); }
.h-grm__sub h3 { margin: 3px 0 0; font-family: var(--font-head); font-size: 20px; }
.h-grm__hero { display: flex; align-items: center; gap: 12px; padding: 14px; border: 1px solid var(--line2); border-radius: var(--r-lg); background: var(--panel2); }
.h-grm__hero strong, .h-grm__hero small { display: block; }
.h-grm__hero strong { font-size: 17px; }
.h-grm__hero small { margin-top: 4px; font-size: 13px; color: var(--muted); }
.h-grm__card { display: flex; flex-direction: column; gap: 8px; padding: 14px; border: 1px solid var(--line2); border-radius: var(--r-lg); background: var(--panel2); }
.h-grm__card > small { font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--green); }
.h-grm__card h4 { margin: 0 0 2px; font-size: 16px; }
.h-grm__jersey { max-width: 140px; }
.h-grm__note { margin: 0; font-size: 13px; line-height: 1.5; color: var(--muted); }
/* RO-09: the age-assumed flag on a placeholder's record. */
.h-grm__note--flag { color: var(--warn); font-weight: 700; }
.h-grm__skill { margin: 0; font-size: 15px; font-weight: 700; }
.h-grm__roles { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.h-grm__role {
  min-height: 44px; display: flex; justify-content: space-between; align-items: center; padding: 0 12px;
  border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel); color: var(--muted);
  font: inherit; font-size: 13px; font-weight: 800; cursor: pointer;
}
.h-grm__role i { width: 12px; height: 12px; border: 2px solid currentColor; border-radius: 50%; }
.h-grm__role.is-on { border-color: var(--purple); color: var(--ink); }
.h-grm__role.is-on i { background: var(--purple); border-color: var(--purple); }
.h-grm__acts { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.h-grm__acts button {
  min-height: 44px; border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel);
  color: var(--ink); font: inherit; font-size: 14px; font-weight: 800; cursor: pointer;
}
/* Walk v54: Adjust skill alone (no account) takes the whole row; Adjust is the green one. */
.h-grm__skacts { margin-top: 8px; }
.h-grm__skacts button:only-child { grid-column: 1 / -1; }
.h-grm__skacts button:first-child { border-color: var(--green); color: var(--green); }
.h-grm__acts button.is-danger { grid-column: 1 / -1; border-color: var(--danger); color: var(--danger); background: none; }
.h-grm__confirm { display: flex; flex-direction: column; gap: 8px; padding: 12px; border: 1px solid var(--danger); border-radius: var(--r-md); }
.h-grm__confirm span { font-size: 13px; line-height: 1.45; color: var(--muted); }
.h-grm__confirm div { display: flex; gap: 8px; }
.h-grm__confirm button {
  flex: 1; min-height: 42px; border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel);
  color: var(--ink); font: inherit; font-weight: 800; cursor: pointer;
}
.h-grm__confirm button.is-danger { border-color: var(--danger); color: var(--danger); }
.h-grm__app { display: flex; flex-direction: column; gap: 8px; padding: 14px; border: 1px solid var(--line2); border-radius: var(--r-lg); background: var(--panel2); }
.h-grm__app header { display: flex; align-items: center; gap: 10px; }
.h-grm__app header strong, .h-grm__app header small { display: block; }
.h-grm__app header small, .h-grm__app > small { font-size: 12.5px; color: var(--muted); }
.h-grm__app p { margin: 0; font-size: 14px; line-height: 1.5; }
.h-grm__app footer { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.h-grm__app footer button {
  min-height: 42px; border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel);
  color: var(--ink); font: inherit; font-size: 13px; font-weight: 800; cursor: pointer;
}
.h-grm__app footer button.is-primary { border-color: var(--purple); }
.h-grm__app footer button.is-danger { color: var(--danger); }

/* ---- V3.91 · the Roster tab, in the manager's language --------------------- */
.h-rost__head { display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
/* RO-02 second walk (Karl): the roster button sits centred between the tab
   bar's underline and the top of the tiles, not on the heading's baseline. */
.h-rost__head > .h-mgbtn--roster { align-self: center; }
/* Walk v57: the game's Roster and Info heads carry the same round button. */
.gs-rhead > .h-mgbtn--roster { align-self: center; flex: none; }
/* ===== Walk v59 (Karl): ONE PANEL HEADING, AND THE PANEL'S MANAGER BUTTONS.
   Every Space panel starts with `.h-phead`: a small label + title on the
   left, and on the right a column of TEXT buttons styled exactly like
   ⚙ Manage in the tab bar (amber icon + word, no chip) — the panel's own
   extension of the Manage menu, right under it. Top-aligned, so every panel
   starts at the same height; the first button's text sits level with the
   small label. On a collision the button words truncate first (flex-shrink
   100), always keeping the icon and three letters. */
.h-phead { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; margin: 0 0 12px; }
.h-phead__t { flex: 1 1 auto; min-width: 0; }
.h-phead__t small { display: block; font-size: 11px; line-height: 17px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--green); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.h-phead__t h3 { margin: 2px 0 0; font-family: var(--font-display); font-weight: 400; font-size: 24px; line-height: 1.05; letter-spacing: .03em; }
.h-phead__acts { flex: 0 100 auto; min-width: 66px; display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.h-tbtn { display: inline-flex; align-items: center; gap: 5px; min-width: 0; max-width: 100%; padding: 4px 6px; margin: -4px 0;
  border: 0; background: none; color: var(--warn); font: inherit; font-family: var(--font-body); font-size: 12.5px; font-weight: 700;
  line-height: 17px; letter-spacing: normal; text-transform: none; text-shadow: none; white-space: nowrap; cursor: pointer; }
.h-tbtn .h-ic { width: 17px; height: 17px; flex: none; }
.h-tbtn__lb { min-width: 4ch; overflow: hidden; text-overflow: ellipsis; }
.h-tbtn:hover { color: var(--warn-solid); }
.h-tbtn:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; border-radius: 6px; }
/* The Recruiting section label: the word left, its text button right, both
   sitting on the green line (the label's own row, nothing moves). */
.h-sec-act { display: flex; align-items: flex-end; justify-content: space-between; gap: 8px; }
.h-sec-act > span { min-width: 0; }
.h-sec-act > .h-tbtn { flex: 0 100 auto; margin: 0; padding: 0 6px; line-height: inherit; }
/* Walk v59 (Karl: panels start at inconsistent heights). A game Space is a
   flex column with a 12px gap, and the tab bar's own 12px bottom margin
   doubled it — game panels began 24px under the tabs, groups 12px. */
.gs > .h-room__tabs { margin-bottom: 0; }
.h-rost__head small { display: block; font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--green); }
.h-rost__head strong { display: block; margin-top: 2px; font-family: var(--font-head); font-size: 22px; }
.h-rost__count { margin: 0 2px 8px; font-size: 12.5px; color: var(--muted); }
@media (max-width: 420px) {
  .h-grm__tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .h-grm__add span:not(.h-ic) { display: none; }
  .h-grm__rstat b { display: none; }
}

/* 📰 Discover's Hockey news (Karl, 2026-09-29). */
.h-dc__news { display: grid; gap: 8px; margin-bottom: 18px; }
.h-dc__nrow {
  display: flex; flex-direction: column; gap: 2px; text-align: left; width: 100%;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--panel2); color: var(--ink); font: inherit; cursor: pointer;
}
.h-dc__nrow:active { transform: scale(.985); }
.h-dc__nt { font-size: 15px; font-weight: 700; line-height: 1.3; }
.h-dc__ns { font-size: 12px; color: var(--muted); }

/* 🧑‍🏫 Chat with a Coach (Karl, 2026-09-29). The tag rides in the row title,
   green like the coach ring; the picker rows are ordinary inbox rows with a
   Message button that stays on one line. */
.h-ch__kindtag {
  margin-left: 6px; padding: 1px 7px; border-radius: var(--r-pill);
  font-size: 10px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
  border: 1px solid var(--green); color: var(--green); vertical-align: 1px;
}
.h-ch__coachdoor {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  margin: 0 0 10px; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--panel2); color: var(--ink); font: inherit; cursor: pointer;
}
.h-ch__coachlead { margin: 0 0 12px; font-size: 14px; line-height: 1.45; color: var(--muted); }
.h-ch__coachrow { width: 100%; text-align: left; }
.h-ch__coachrow .h-btn { flex: none; pointer-events: none; }

/* RO-03 (walk v37): the group Overview's Share, for everybody, right-aligned. */
/* RO-03 second walk: Share on the hero photo, bottom right (`.h-sphoto` is relative). */
.h-room__heroshare { position: absolute; right: 12px; bottom: 12px; z-index: 1; }
/* GA-05 v45: the banner's code pill sits left of Share, in the same corner. */
.h-room__herobtns { position: absolute; right: 12px; bottom: 12px; z-index: 1; display: flex; gap: 6px; }
.h-codepill span:first-child { font-family: var(--font-head); letter-spacing: .08em; }

/* RO-05 (walk v37): an account holder's position and also-plays, shown but locked. */
.h-grm__seg.is-locked button { cursor: default; }
.h-grm__seg.is-locked button:not(.is-on) { opacity: .55; }

/* RR-04 (walk v37): the picked row that plays the other position says so. */
.gs-pk__row.is-mismatch small b { color: var(--warn); font-weight: 800; }
.gs-pk__mis { display: inline-block; width: 17px; height: 17px; margin-left: 5px; vertical-align: -2px; }
/* RR-04: a rounded amber triangle with the mark cut in the card's own ink. */
.gs-pk__mis svg { width: 100%; height: 100%; display: block; fill: var(--warn-solid); stroke: var(--warn-solid); stroke-width: 1.5; stroke-linejoin: round; }
.gs-pk__mis .gs-pk__misk { fill: none; stroke: var(--on-warn); stroke-width: 2.4; stroke-linecap: round; }

/* GA-02 (walk v37): the recruiting note's own label. */
.h-grp__notelbl { display: block; font-size: 11.5px; font-weight: 700; color: var(--muted); margin: 2px 0 2px; }

/* Book a Coach B3 (2026-10-01): the member said they sent an e-Transfer, and
   the admin list's prompt to check the ones waiting. */
.h-inv__etsent { margin: 10px 0 0; padding: 10px 12px; border-radius: var(--r-md);
  border: 1px solid var(--line); background: var(--panel); font-size: 13px; line-height: 1.5; }
.h-inv__etsent strong { color: var(--ink); }
/* BC-04 / BR-04 (Karl, 10-02): the e-Transfer icon beside Waiting approval,
   and Copy details + "Sent it? Let us know" in one row with room between. */
.h-inv__etsent { display: flex; align-items: flex-start; gap: 10px; }
.h-inv__etsent > .h-ic { flex: none; width: 22px; height: 22px; color: var(--warn); margin-top: 1px; }
.h-inv__etacts { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; margin-top: 10px; }
.h-inv__etacts .h-btn { display: inline-flex; align-items: center; gap: 7px; }
/* B16: a payment's Receipt (or a refund's / credit's confirmation) is a native disclosure; its summary is the green link. */
.h-inv__rcpt { display: block; margin-top: 6px; }
.h-inv__rcpt > summary { cursor: pointer; }
.h-inv__etacts .h-ic { width: 17px; height: 17px; }
.h-co__youth { display: grid; gap: 10px; justify-items: center; text-align: center; margin: 14px auto; max-width: 420px; padding: 20px 18px; border-radius: var(--r-lg); border: 1px solid var(--line); background: linear-gradient(rgba(var(--green-rgb), .06), rgba(var(--green-rgb), .06)), var(--panel); }
.h-co__youthic { display: grid; place-items: center; width: 52px; height: 52px; border-radius: 50%; background: linear-gradient(rgba(var(--green-rgb), .16), rgba(var(--green-rgb), .16)), var(--panel2); color: var(--green); }
.h-co__youthic .h-ic { width: 28px; height: 28px; }
.h-co__youth h3 { margin: 0; font-size: 17px; }
.h-co__youth p { margin: 0; color: var(--muted); font-size: 13.5px; }
.h-co__youth ul { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 9px; text-align: left; width: 100%; }
.h-co__youth li { display: flex; align-items: flex-start; gap: 10px; font-size: 13.5px; }
.h-co__youth li .h-ic { flex: none; width: 20px; height: 20px; color: var(--green); }
.h-co__etic { display: inline-flex; vertical-align: -3px; width: 16px; height: 16px; margin-right: 5px; color: var(--warn); }
.h-ainv__etwait { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 0 0 12px;
  padding: 10px 12px; border-radius: var(--r-md); border: 1px solid var(--warn);
  background: linear-gradient(rgba(var(--warn-wash-rgb), .12), rgba(var(--warn-wash-rgb), .12)), var(--panel);
  color: var(--ink); font-size: 13px; }
.h-ainv__etwait span { flex: 1 1 200px; }

/* ===========================================================================
   🏒 CENTRE ICE V11 (CI-2, 2026-10-01) — approved by Karl 2026-09-29; the
   reference is the V11 playground. Every post is its own card: the avatar
   sits in the HEADER ROW only, and the text, attachments, actions and
   comments use the full width below it. Teal marks Centre Ice itself; Join,
   Apply and Register stay green; type labels are green (games, sessions) or
   soft purple (programs, groups).
   ======================================================================== */
.h-ci__head { padding-bottom: 14px; }
.h-cp__av { overflow: hidden; }

.h-post__head .h-post__meta { display: flex; align-items: center; gap: 6px; min-width: 0; }
.h-post__head .h-post__name {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  display: block; font-size: 14.5px; font-weight: 800;
}
.h-post__via { margin-top: 1px; font-size: 12px; font-weight: 700; color: var(--muted); }
.h-post__via--open { color: var(--ci-teal); }
.h-post__via--staff { color: var(--active-purple-ink); }
.h-post__upd {
  margin: 8px 0 0; padding: 8px 10px; border-radius: var(--r-md);
  background: var(--panel2); font-size: 13px; line-height: 1.45;
}
.h-post__upd span { display: block; font-size: 10.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.h-post__bar .h-bar-btn { flex: none; padding: 0 8px; min-height: 36px; }
.h-post__bar .h-react { flex: none; }
.h-post__bar .h-bar-btn.is-on { color: var(--ci-teal); }
.h-bar-btn__em { font-size: 16px; line-height: 1; }
.h-post__bar .h-post__rsum { margin-left: auto; font-size: 12.5px; color: var(--muted); }
.h-feed .h-cmts { margin-top: 6px; padding-left: 10px; border-left: 2px solid var(--line); }
.h-feed .h-cmts--empty { padding-left: 0; border-left: 0; margin-top: 4px; }
/* The feed's thread, as V11 draws it: one line per comment, the name in bold
   and the words after it — no avatars, no bubbles. The opened post keeps the
   fuller thread with faces. */
.h-cmt--line { display: block; padding: 3px 0; font-size: 14px; line-height: 1.45; color: var(--ink); overflow-wrap: anywhere; }
.h-cmt__who {
  margin-right: 5px; padding: 0; border: 0; background: none;
  color: var(--ink); font: inherit; font-weight: 800; cursor: pointer;
}
.h-feed button.h-cmt__empty { color: var(--ci-teal); font-weight: 700; }
.h-post__moreatt {
  width: 100%; display: flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 38px; margin-top: 8px; border: 1px dashed var(--line2); border-radius: var(--r-md);
  background: none; color: var(--ink); font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
}
.h-post__moreatt .h-ic { width: 14px; height: 14px; color: var(--ci-teal); }

/* ---- Spotlight: the Space hero, three facts, the main action + Details ---- */
.h-cov { margin-top: 10px; border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; background: var(--panel); }
.h-cov__hero {
  position: relative; height: 150px;
  background: var(--hero) center 42% / cover no-repeat, var(--panel2);
}
.h-cov__hero::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,.05) 25%, rgba(0,0,0,.72)); /* raw-colour: the scrim over a photo is black in every theme */
}
.h-cov__cap { position: absolute; left: 12px; right: 12px; bottom: 10px; z-index: 1; color: var(--brand-neutral); }
.h-cov__kind {
  display: block; margin-bottom: 4px; font-size: 10.5px; font-weight: 800; letter-spacing: .14em;
  text-transform: uppercase; text-shadow: 0 1px 3px rgba(0,0,0,.75); /* raw-colour: text shadow on a photo */
}
.h-cov__kind.is-g, .h-crd__k.is-g { color: var(--green); }
.h-cov__kind.is-p, .h-crd__k.is-p { color: var(--ci-label-purple); }
.h-cov__cap strong {
  display: block; font-family: var(--font-head); font-weight: 400; font-size: 21px; line-height: 1.05;
  text-transform: uppercase; letter-spacing: .02em; overflow-wrap: anywhere;
}
.h-cov__cap small { display: block; margin-top: 3px; font-size: 12px; opacity: .9; }
.h-cov__stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: 1px solid var(--line); }
.h-cov__stats div { padding: 9px 10px; min-width: 0; }
.h-cov__stats div + div { border-left: 1px solid var(--line); }
.h-cov__stats small { display: block; font-size: 9.5px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.h-cov__stats b {
  display: block; margin-top: 2px; font-family: var(--font-head); font-weight: 400; font-size: 16px; line-height: 1.1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.h-cov__stats b.is-g { color: var(--green); }
.h-cov__joins { display: flex; gap: 8px; padding: 10px; }
.h-cov__go, .h-cov__dt, .h-cov__chip {
  flex: 1; min-height: 44px; border-radius: var(--r-sm); font: inherit; font-size: 13px; font-weight: 800;
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
}
.h-cov__go { border: 1px solid var(--green); background: var(--green); color: var(--on-green); }
.h-cov__go.is-quiet, .h-cov__dt { border: 1px solid var(--line2); background: transparent; color: var(--ink); }
.h-cov__chip { border: 1px solid var(--line); background: var(--panel2); color: var(--muted); cursor: default; }
.h-cov__chip.is-done { color: var(--green); }

/* ---- Card: smaller, still joinable ---- */
.h-crd {
  display: flex; align-items: center; gap: 10px; margin-top: 10px; padding: 8px;
  border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel);
}
.h-crd__open {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px;
  padding: 0; border: 0; background: none; color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.h-crd__th { width: 58px; height: 58px; flex: none; border-radius: var(--r-sm); background: var(--hero) center 42% / cover no-repeat, var(--panel2); }
.h-crd__ct { flex: 1; min-width: 0; }
.h-crd__k { display: block; font-size: 9.5px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; }
.h-crd__ct strong { display: block; margin-top: 1px; font-size: 14px; overflow-wrap: anywhere; }
.h-crd__ct small { display: block; font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-crd__go {
  flex: none; min-height: 40px; padding: 0 12px; border: 0; border-radius: var(--r-sm);
  background: var(--green); color: var(--on-green); font: inherit; font-size: 12.5px; font-weight: 800; cursor: pointer; white-space: nowrap;
}
.h-crd__go.is-quiet { border: 1px solid var(--line2); background: transparent; color: var(--ink); }
.h-crd__chip { flex: none; font-size: 12px; font-weight: 800; color: var(--muted); white-space: nowrap; }
.h-crd__chip.is-done { color: var(--green); }

/* ---- Link: a guide, a story or a place — never a website ---- */
.h-lnk {
  width: 100%; display: flex; align-items: center; gap: 10px; margin-top: 10px; padding: 9px 10px;
  border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel);
  color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.h-lnk.is-gone { cursor: default; opacity: .75; }
.h-lnk__ico, .h-ced__ico {
  width: 32px; height: 32px; flex: none; display: grid; place-items: center;
  border-radius: var(--r-sm); color: var(--ci-teal);
  /* The tint laid over an opaque panel, so the teal reads the same wherever
     the tile sits (the contrast pass composites it). */
  background: linear-gradient(rgba(var(--ci-teal-rgb), .12), rgba(var(--ci-teal-rgb), .12)), var(--panel);
}
.h-lnk__ico .h-ic, .h-ced__ico .h-ic { width: 17px; height: 17px; }
.h-lnk__t { flex: 1; min-width: 0; }
.h-lnk__t strong { display: block; font-size: 13.5px; }
.h-lnk__t small { display: block; font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-lnk__chev { width: 16px; height: 16px; color: var(--faint); flex: none; }

/* ---- The post box (the preview) ---- */
.h-ced { display: block; }
.h-sheet--ci .h-sheet__actions .h-btn:not(.h-btn--ghost) {
  background: var(--ci-teal); border-color: var(--ci-teal); color: var(--on-ci-teal);
}
.h-ced__lab {
  display: block; margin: 12px 0 6px; font-size: 10.5px; font-weight: 800; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted);
}
.h-ced__lab:first-child { margin-top: 0; }
/* CI-03 (Karl, 10-02): the Attach row is the fold control; its chevron shows
   while the picker is open and turns up to say "fold". */
.h-ced__labrow { display: flex; align-items: center; justify-content: space-between; width: 100%; margin: 12px 0 6px; padding: 0; background: none; border: 0; color: inherit; font: inherit; cursor: pointer; text-align: left; }
.h-ced__labrow .h-ced__lab { margin: 0; }
.h-ced__foldic { width: 16px; height: 16px; color: var(--muted); visibility: hidden; transition: transform .2s ease; }
.h-ced__labrow[aria-expanded="true"] .h-ced__foldic { visibility: visible; transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .h-ced__foldic { transition: none; } }
html[data-motion="off"] .h-ced__foldic { transition: none; }
.h-ced__aud { display: flex; gap: 4px; padding: 3px; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--bg); }
.h-ced__audb {
  flex: 1; min-height: 38px; border: 0; border-radius: var(--r-sm); background: none;
  color: var(--muted); font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
}
.h-ced__audb.is-on { background: var(--ci-teal); color: var(--on-ci-teal); }
.h-ced__ed { margin-top: 12px; padding: 10px 12px 12px; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel); }
.h-ced__ed:focus-within { border-color: rgba(var(--ci-teal-rgb), .5); }
.h-ced__tx.h-input {
  width: 100%; min-height: 78px; padding: 0; border: 0; background: transparent; resize: none;
  font-size: 16px; line-height: 1.5; box-shadow: none; overflow: hidden;
}
.h-ced__tx.h-input:focus { outline: none; box-shadow: none; }
.h-ced__card { margin-top: 10px; overflow: hidden; }
.h-ced__card + .h-ced__card { padding-top: 10px; border-top: 1px dashed var(--line); }
.h-ced__card .h-cov, .h-ced__card .h-crd, .h-ced__card .h-lnk { margin-top: 6px; }
.h-ced__card .h-cov button, .h-ced__card .h-crd button, .h-ced__card .h-lnk { pointer-events: none; }
.h-ced__tools { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.h-ced__tl { font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.h-ced__seg { display: inline-flex; gap: 2px; padding: 3px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--bg); }
.h-ced__seg button {
  min-height: 32px; padding: 0 12px; border: 0; border-radius: var(--r-sm); background: none;
  color: var(--muted); font: inherit; font-size: 12px; font-weight: 700; cursor: pointer;
  transition: background .2s ease, color .2s ease;
}
.h-ced__seg button.is-on { background: var(--ci-teal); color: var(--on-ci-teal); }
.h-ced__seg button:disabled { opacity: .4; cursor: not-allowed; }
.h-ced__seg button { display: inline-flex; align-items: center; gap: 5px; }
.h-ced__seg button .h-ic { width: 15px; height: 15px; flex: none; }
/* B45 (Karl): Spotlight that is not available here looks switched off, not broken. */
.h-ced__seg button.is-unavail { opacity: .55; }
.h-ced__seg button.is-unavail span:not(.h-ic) { text-decoration: line-through; text-decoration-thickness: 1.5px; }
/* B45 (Karl): the × is a badge on the attached card's corner. The wrapper's
   inset keeps it inside the card's clip. */
.h-ced__att { position: relative; padding: 6px 6px 0 0; }
.h-ced__x.is-badge { position: absolute; top: 0; right: 0; z-index: 1; width: 28px; height: 28px; box-shadow: 0 2px 6px rgba(0,0,0,.35); }
.h-ced__x.is-badge .h-ic { width: 12px; height: 12px; }
/* B45 (Karl): why Spotlight is off, in amber; a fix the poster can make is
   the whole line, with the manager cog and the fix in words. */
.h-ced__why { margin: 8px 0 0; font-size: 12px; line-height: 1.45; color: var(--warn); }
button.h-ced__why.is-fix {
  width: 100%; display: flex; align-items: center; gap: 10px; padding: 9px 10px; text-align: left;
  border: 1px solid rgba(var(--warn-rgb), .4); border-radius: var(--r-md);
  background: linear-gradient(rgba(var(--warn-rgb), .07), rgba(var(--warn-rgb), .07)), var(--panel);
  font: inherit; font-size: 12px; color: var(--warn); cursor: pointer;
}
.h-ced__why.is-fix span { flex: 1; min-width: 0; }
/* CM-08 (Karl): a listing waiting for the post. Teal, not amber: nothing is wrong, it just is not public yet. */
button.h-ced__why.is-fix.is-pend {
  border-color: rgba(var(--ci-teal-rgb), .4); color: var(--ci-teal);
  background: linear-gradient(rgba(var(--ci-teal-rgb), .07), rgba(var(--ci-teal-rgb), .07)), var(--panel);
}
.h-ced__why.is-fix b { flex: none; display: inline-flex; align-items: center; gap: 5px; font-weight: 800; white-space: nowrap; }
.h-ced__why.is-fix b .h-ic { width: 15px; height: 15px; }
.h-ced__promo {
  min-height: 32px; padding: 0 13px; border: 0; border-radius: var(--r-pill);
  background: var(--ci-teal); color: var(--on-ci-teal); font: inherit; font-size: 12px; font-weight: 800; cursor: pointer;
}
.h-ced__x {
  width: 36px; height: 36px; flex: none; display: grid; place-items: center; padding: 0;
  border: 1px solid var(--line2); border-radius: 50%; background: var(--panel2); color: var(--ink); cursor: pointer;
}
.h-ced__x .h-ic { width: 14px; height: 14px; }
.h-ced__note { margin: 6px 0 0; font-size: 12px; color: var(--muted); line-height: 1.45; }
.h-ced__opt {
  width: 100%; display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 9px 10px;
  border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--bg);
  color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.h-ced__opt > .h-ic { width: 16px; height: 16px; color: var(--faint); flex: none; }
.h-ced__opt.is-added { opacity: .55; cursor: default; }
.h-ced__ot { flex: 1; min-width: 0; }
.h-ced__ot strong { display: block; font-size: 13.5px; }
.h-ced__ot small { display: block; font-size: 11.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-ced__added { margin-left: auto; font-style: normal; font-size: 11.5px; font-weight: 800; color: var(--ci-teal); }
.h-ced__rows { display: flex; flex-direction: column; gap: 6px; }
/* ===== THE SLIM SEARCH (Karl, 2026-10-01) ==================================
   The regular search (`.h-ask__bar`) is too big for a sheet, so this is its
   slim sibling: a rounded-square bar with a slim filter button. At rest it
   looks exactly as before; on focus it behaves like the regular search — the
   FIELD draws nothing (no outline inside an outline) and the whole BAR lights
   with the green ring, the icon turning green with it. Reusable anywhere a
   compact search is needed. */
.h-slims {
  display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 6px 0 12px;
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--bg); color: var(--muted);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.h-slims__ic { width: 16px; height: 16px; flex: none; transition: color .15s ease; }
.h-slims__in {
  flex: 1; min-width: 0; border: 0; background: none; color: var(--ink);
  font: inherit; font-size: 16px; font-weight: 600; outline: none;
}
.h-slims__in:focus, .h-slims__in:focus-visible { outline: none; box-shadow: none; }
.h-slims__in::placeholder { color: var(--muted); }
.h-slims:focus-within { border-color: var(--green); box-shadow: 0 0 0 3px rgba(var(--green-rgb), .30); }
.h-slims:focus-within .h-slims__ic { color: var(--green); }
.h-slims__filter {
  flex: none; display: inline-flex; align-items: center; gap: 4px; min-height: 34px; padding: 0 8px 0 10px;
  border: 1px solid var(--line2); border-radius: var(--r-sm); background: var(--panel2);
  color: var(--ink); font: inherit; font-size: 12.5px; font-weight: 700; cursor: pointer;
}
.h-slims__filter .h-ic { width: 14px; height: 14px; color: var(--green); }
/* In Centre Ice the filter's chevron keeps Centre Ice teal. */
.h-ced .h-slims__filter .h-ic { color: var(--ci-teal); }
@media (prefers-reduced-motion: reduce) { .h-slims, .h-slims__ic { transition: none; } }
.h-ced__scopemenu { margin-top: 6px; padding: 5px; border: 1px solid var(--line2); border-radius: var(--r-md); background: var(--panel2); box-shadow: var(--sh-2); }
.h-ced__scopemenu button {
  width: 100%; display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 10px;
  border: 0; border-radius: var(--r-sm); background: none; color: var(--ink); font: inherit; font-size: 14px; text-align: left; cursor: pointer;
}
.h-ced__scopemenu button span { flex: 1; }
.h-ced__scopemenu button.is-on { background: rgba(var(--ci-teal-rgb), .1); }
.h-ced__ck { width: 18px; flex: none; display: grid; place-items: center; font-style: normal; color: var(--ci-teal); }
.h-ced__ck .h-ic { width: 15px; height: 15px; }
.h-ced__scopemenu small { width: 24px; flex: none; text-align: right; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.h-ced__pick > * + * { margin-top: 8px; }
.h-ced__mk { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.h-ced__mk span { font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.h-ced__mk button {
  display: inline-flex; align-items: center; gap: 5px; min-height: 38px; padding: 0 12px;
  border: 1px dashed rgba(var(--ci-teal-rgb), .45); border-radius: var(--r-sm); background: transparent;
  color: var(--ink); font: inherit; font-size: 12.5px; font-weight: 700; cursor: pointer;
}
.h-ced__mk button .h-ic { width: 14px; height: 14px; color: var(--ci-teal); }

/* Motion: a card slides in (0.30s), a Spotlight / Card switch cross-fades
   (0.28s), a removed card fades and collapses (0.24s). None of it under
   Reduced Motion. */
@keyframes h-ced-in { from { opacity: 0; transform: translateY(10px) scale(.97); } to { opacity: 1; transform: none; } }
@keyframes h-ced-swap { from { opacity: .2; transform: scale(.985); } to { opacity: 1; transform: none; } }
.h-ced__card.is-in { animation: h-ced-in .3s cubic-bezier(.2,.7,.2,1); }
.h-ced__card.is-swap .h-cov, .h-ced__card.is-swap .h-crd { animation: h-ced-swap .28s ease; }
.h-ced__card.is-out { opacity: 0; margin-top: 0; transition: height .24s cubic-bezier(.4,0,.2,1), opacity .18s ease, margin .24s ease; }
@media (prefers-reduced-motion: reduce) {
  .h-ced__card.is-in, .h-ced__card.is-swap .h-cov, .h-ced__card.is-swap .h-crd { animation: none; }
  .h-ced__card.is-out { transition: none; }
}
html[data-motion="off"] .h-ced__card.is-in,
html[data-motion="off"] .h-ced__card.is-swap .h-cov,
html[data-motion="off"] .h-ced__card.is-swap .h-crd { animation: none; }

.h-face__ini { display: grid; place-items: center; width: 100%; height: 100%; }
.h-face__sq { border-radius: var(--r-sm); }

/* ===========================================================================
   🏒 CENTRE ICE CI-3 (2026-10-01): @ mentions, the smart tip, List on Find.
   ======================================================================== */
/* A mention in a post: teal words that open the person or the thing. */
.h-men {
  display: inline; padding: 0; border: 0; background: none;
  color: var(--ci-teal); font: inherit; font-weight: 700; cursor: pointer;
}
/* The post box: the words drawn under a transparent box, so a mention can be
   teal while the caret and selection stay the browser's own. Both layers set
   the same font, size and wrapping or the paint drifts from the caret. */
.h-ced__edtx { position: relative; }
.h-ced__hl, .h-ced__edtx .h-ced__tx.h-input {
  font-family: inherit; font-size: 16px; font-weight: 500; line-height: 1.5; letter-spacing: normal;
  white-space: pre-wrap; overflow-wrap: anywhere; word-break: normal;
}
.h-ced__hl { position: absolute; inset: 0; pointer-events: none; color: var(--ink); overflow: hidden; }
.h-ced__edtx .h-ced__tx.h-input { position: relative; color: transparent; caret-color: var(--ink); }
.h-ced__edtx .h-ced__tx.h-input::placeholder { color: var(--faint); }
.h-ced__men { color: var(--ci-teal); font-weight: 700; }
/* The @ list, under the words. */
.h-ced__mlist {
  margin-top: 6px; padding: 6px; border: 1px solid var(--line2); border-radius: var(--r-md);
  background: var(--panel2); box-shadow: var(--sh-2);
}
.h-ced__mlist button {
  width: 100%; display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 6px;
  border: 0; border-radius: var(--r-sm); background: none; color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.h-ced__mlist button:hover, .h-ced__mlist button:focus-visible { background: rgba(var(--ci-teal-rgb), .08); }
.h-ced__mh { display: block; padding: 6px 6px 4px; font-size: 10px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.h-ced__mav {
  width: 30px; height: 30px; flex: none; display: grid; place-items: center; border-radius: 50%;
  background: var(--panel); color: var(--ink); font-size: 12px; font-weight: 800;
}
/* The one smart tip: a quiet row, at most two actions, and its ×. */
.h-ced__tip {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 8px; padding: 7px 8px 7px 10px;
  border: 1px solid rgba(var(--ci-teal-rgb), .3); border-radius: var(--r-md);
  background: linear-gradient(rgba(var(--ci-teal-rgb), .06), rgba(var(--ci-teal-rgb), .06)), var(--panel);
  color: var(--ci-teal); font-size: 12.5px;
}
.h-ced__tip > .h-ic { width: 16px; height: 16px; flex: none; }
.h-ced__say { font-weight: 700; color: var(--ink); margin-right: 2px; }
.h-ced__tip button {
  min-height: 34px; padding: 0 10px; border: 1px solid var(--line2); border-radius: var(--r-sm);
  background: var(--panel2); color: var(--ink); font: inherit; font-size: 12px; font-weight: 700; cursor: pointer;
}
.h-ced__tip .h-ced__tipx { margin-left: auto; width: 34px; padding: 0; display: grid; place-items: center; border: 0; background: none; color: var(--muted); }
.h-ced__tipx .h-ic { width: 13px; height: 13px; }
/* The Search Vocabulary screen's Smart tips tab (staff). */
.h-vtips { margin-top: 22px; }
.h-vtip { margin-top: 12px; padding: 12px; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel); }
.h-vtip__top { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.h-vtip__top small { margin-left: auto; color: var(--muted); font-size: 12px; }
.h-vtip__acts { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; }

/* ===== @ IN COMMENTS (Karl, 2026-10-01) — the same teal layer as the post
   box, on the one-line comment box that grows as you type. */
.h-cmt__edtx { position: relative; flex: 1; min-width: 0; }
.h-cmt__hl, .h-cmt__edtx .h-cmt__in.h-input {
  font-family: inherit; font-size: 16px; font-weight: 500; line-height: 1.4; letter-spacing: normal;
  white-space: pre-wrap; overflow-wrap: anywhere; word-break: normal;
  padding: 8px 12px; border-width: 1px; border-style: solid; box-sizing: border-box;
}
.h-cmt__hl { position: absolute; inset: 0; pointer-events: none; color: var(--ink); overflow: hidden; border-color: transparent; }
.h-cmt__edtx .h-cmt__in.h-input {
  position: relative; width: 100%; min-height: 38px; resize: none; overflow: hidden;
  color: transparent; caret-color: var(--ink); background: transparent;
}
.h-cmt__edtx .h-cmt__in.h-input::placeholder { color: var(--faint); }
.h-cmt__edtx { background: var(--panel2); border-radius: var(--r-md); }
.h-cmt__hl .h-ced__men { color: var(--ci-teal); font-weight: 700; }
.h-cmt__mbox:empty { display: none; }

/* ===== THE OPENED POST ON A PHONE (Karl, CM-02) — on a phone the page scrolls
   as one, so a post view pinned inside the feed could open below the screen.
   It fills the screen instead, with its own close bar, ready to comment. */
@media (max-width: 760px) {
  .h-ci .h-postx { position: fixed; inset: 0; z-index: 70; padding-top: env(safe-area-inset-top, 0px); }
  /* Pre-walk 10-02: a game, group or event opened FROM the opened post slid in
     underneath it (the page is z 44), so the tap seemed to do nothing. The post
     steps aside while that page is open and is there again on Back. */
  body:has(.h-detail.is-open) .h-ci .h-postx { visibility: hidden; }
}

/* ===== BOOK A COACH (Karl, BC-01, 2026-10-01) ============================= */
/* The name, then the rate on its own line. */
.h-co__stripwho { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* The day is its own scroll panel, opened on the earliest free time. */
.h-co__gridscroll {
  max-height: 340px; overflow-y: auto; overscroll-behavior: contain;
  padding: 8px 0; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel);
}
.h-co__selacts button:disabled { opacity: .4; cursor: default; }
/* What comes next, once a time is chosen. */
.h-co__next {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 8px; padding: 10px 12px;
  border: 1px solid var(--green); border-radius: var(--r-md);
  background: linear-gradient(rgba(var(--green-rgb), .06), rgba(var(--green-rgb), .06)), var(--panel);
  font-size: 13px; color: var(--ink);
}
.h-co__next span { flex: 1 1 200px; }
/* More room between the last hour of the day and "Who is this for?" (BC-01). */
.h-co__sect--who { margin-top: 14px; }

/* ===== BOOK A COACH · DIRECTION D (Karl approved 2026-10-01) ================
   The member's flow (coachbook.js). Colours are the agreed key: open = green
   tint, picking = solid purple with bars, your request = purple dashed, your
   session = solid green, anybody else's = a plain grey "Booked"; amber and red
   only while a block is being dragged into trouble. */
.h-cb { display: flex; flex-direction: column; gap: 10px; }
/* DOUBLE SCROLL BOX, OPTION C (Karl, 2026-10-02), trial on the Times step:
   one scroller per screen. The sheet's body stops scrolling, the calendar
   takes the height that is left, the day strip stays above and the count
   bar below. A screen too short for it still scrolls the body (fallback). */
.h-co__body:has(.h-cb.is-fill) { display: flex; flex-direction: column; }
.h-co__body [data-cb-host]:has(> .h-cb.is-fill) { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.h-cb.is-fill { flex: 1 1 auto; min-height: 0; }
.h-cb.is-fill > * { flex: none; }
.h-cb.is-fill > .h-cb__gw { flex: 1 1 auto; height: auto; min-height: 220px; }
.h-cb.is-fill > .h-cb__dock { position: static; padding-bottom: 0; }
.h-cb__steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.h-cb__steps span { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--faint); border-top: 3px solid var(--line); padding-top: 5px; }
.h-cb__steps span.is-on { color: var(--ink); border-color: var(--green); }
.h-cb__steps span.is-did { color: var(--green); border-color: rgba(var(--green-rgb), .45); }
.h-cb__coach { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel); }
.h-cb__av { width: 36px; height: 36px; border-radius: 50%; overflow: hidden; flex: none; display: grid; place-items: center; background: linear-gradient(var(--green-dim), var(--green-dim)), var(--panel); color: var(--green); font-weight: 900; }
.h-cb__cn { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.h-cb__cn b { font-size: 14px; }
.h-cb__cn small { color: var(--muted); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.h-cb__lnk { background: none; border: 0; color: var(--green); font-weight: 800; font-size: 12.5px; padding: 6px 2px; cursor: pointer; white-space: nowrap; }
/* ☰ "Prefer a list?" (Karl, 10-03): a small green link under the day strip; the list is a helper, the calendar stays first. */
.h-cb__view { margin: -2px 0 0; display: flex; justify-content: flex-end; }
.h-cb__viewsw { display: inline-flex; align-items: center; gap: 5px; padding: 2px 0; border: 0; background: none; color: var(--green); font: inherit; font-size: 12.5px; font-weight: 700; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.h-cb__viewsw .h-ic { width: 14px; height: 14px; }
/* BL-01 (Karl's B57 walk): the legend and "Prefer a list?" share one row. The
   switch's slot is a size container: as the legend leaves it less room, the
   words drop ("Prefer a" first, then "list?") and the icon alone becomes a
   small outlined button. The legend keeps its full width. */
.h-cb__keyrow { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; min-width: 0; }
/* The legend never shrinks or clips; if even the icon cannot sit beside it
   (the smallest phones), the switch drops to its own line, right-aligned. */
.h-cb__keyrow .h-cb__legend { flex: 0 0 auto; gap: 8px; }
.h-cb__keysw { flex: 1 1 32px; min-width: 32px; container-type: inline-size; display: flex; justify-content: flex-end; }
/* Companion item (2026-10-04): the switch's home is the DATE ROW, on the right
   of the selected date. On a phone the single-day header is a flex row whose
   label gives way first; on a wide screen it closes the date-range bar. */
.h-cb__daterow { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* V5.16: mirrors the label's 12px inset so the switch does not sit on the grid's edge; at the
   `.h-cb__gh .h-cb__ghone` weight, or `.h-cb__gh div { padding: 6px 0 }` wins. */
.h-cb__gh .h-cb__daterow { padding-right: 12px; }
.h-cb__dlabel { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-cb__navd .h-cb__keysw { flex: 0 0 128px; } /* V5.17: a size container cannot size to its content, so `auto` collapsed it to the icon */
/* V5.17: `.h-cb__navd button` dresses the bar's arrows (34px boxes); the switch keeps its own look. */
.h-cb__navd .h-cb__listsw { width: auto; height: auto; border-color: transparent; background: none; color: var(--green); }
.h-cb__listsw { display: inline-flex; align-items: center; gap: 5px; padding: 3px 0; border: 1px solid transparent; border-radius: 8px; background: none; color: var(--green); font: inherit; font-size: 12px; font-weight: 700; white-space: nowrap; cursor: pointer; }
.h-cb__listsw .h-ic { width: 15px; height: 15px; flex: none; }
/* V5.18 (B64 PC-08): the words are one group; the 5px gap is only icon to words. */
.h-cb__lsww { display: inline-flex; white-space: nowrap; }
.h-cb__listsw:hover .h-cb__lsw2, .h-cb__listsw:hover .h-cb__lsw1 { text-decoration: underline; text-underline-offset: 2px; }
@container (max-width: 112px) { .h-cb__lsw1 { display: none; } .h-cb__lsw2 { text-transform: capitalize; } }
@container (max-width: 54px) {
  .h-cb__lsw2 { display: none; }
  .h-cb__listsw { padding: 4px 6px; border-color: rgba(var(--green-rgb), .55); background: rgba(var(--green-rgb), .10); }
}
.h-cb__lhead { margin: 0; font-size: 12.5px; color: var(--muted); }
.h-cb__lhead b { color: var(--ink); }
.h-cb__list { display: grid; gap: 10px; }
.h-cb__lgrp .h-cb__lbl { margin: 0 0 6px; }
.h-cb__lrows { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px; }
.h-cb__lrow { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; padding: 9px 12px; border-radius: var(--r-md); border: 1px solid var(--line); background: var(--panel2); color: var(--ink); font: inherit; text-align: left; cursor: pointer; }
.h-cb__lrow span { font-size: 13.5px; font-weight: 800; }
.h-cb__lrow small { font-size: 11.5px; color: var(--muted); }
.h-cb__lrow:hover, .h-cb__lrow:focus-visible { border-color: var(--green); }
.h-cb__lrow.is-on { border-color: var(--green); background: var(--green-dim); }
.h-cb__strip { display: flex; gap: 6px; overflow-x: auto; scrollbar-width: none; padding-bottom: 2px; }
.h-cb__strip::-webkit-scrollbar { display: none; }
.h-cb__strip button { flex: 0 0 46px; position: relative; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel); color: var(--ink); padding: 6px 0 5px; text-align: center; font: inherit; font-weight: 800; font-size: 15px; line-height: 1.1; cursor: pointer; }
.h-cb__strip button small { display: block; font-size: 9.5px; color: var(--muted); text-transform: uppercase; }
.h-cb__strip button i { display: block; width: 5px; height: 5px; border-radius: 50%; background: var(--green); margin: 4px auto 0; }
.h-cb__strip button i.is-no { background: transparent; }
.h-cb__strip button.is-on { border-color: var(--green); background: var(--green-dim); }
.h-cb__strip button.is-none { color: var(--faint); }
.h-cb__strip button.is-has::after { content: ""; position: absolute; left: 10px; right: 10px; bottom: -1px; height: 3px; border-radius: 2px; background: var(--purple); }
.h-cb__mo { flex: none; align-self: center; font: 400 13px var(--font-display); letter-spacing: .06em; color: var(--faint); writing-mode: vertical-rl; transform: rotate(180deg); }
.h-cb__legend { display: flex; flex-wrap: nowrap; gap: 10px; font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; }
.h-cb__legend span { display: inline-flex; align-items: center; gap: 5px; }
.h-cb__legend i { width: 14px; height: 10px; border-radius: 3px; display: inline-block; }
.h-cb__legend .k-open { background: rgba(var(--green-rgb), .18); border: 1px solid rgba(var(--green-rgb), .5); }
.h-cb__legend .k-pick { background: var(--purple); }
.h-cb__legend .k-sent { border: 2px dashed var(--purple); }
.h-cb__legend .k-mine { background: var(--green); }
.h-cb__legend .k-taken { background: var(--panel2); border: 1px solid var(--line2); }
.h-cb__navd { display: flex; align-items: center; gap: 8px; }
.h-cb__navd b { flex: 1; font-size: 13px; }
.h-cb__navd button { width: 34px; height: 34px; border-radius: var(--r-sm); border: 1px solid var(--line); background: var(--panel2); color: var(--ink); cursor: pointer; }
.h-cb__gw { height: min(52vh, 520px); min-height: 280px; overflow-y: auto; overflow-x: hidden; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel); position: relative; overscroll-behavior: contain; scrollbar-width: thin; }
.h-cb__gh { display: grid; position: sticky; top: 0; z-index: 5; background: var(--panel); border-bottom: 1px solid var(--line); }
.h-cb__gh div { text-align: center; font-size: 11px; font-weight: 800; padding: 6px 0; }
.h-cb__gh div small { display: block; color: var(--muted); font-size: 10px; }
.h-cb__gh .h-cb__ghone { text-align: left; padding-left: 12px; }
.h-cb__gg { display: grid; position: relative; }
.h-cb__gut { position: relative; }
.h-cb__gut span { position: absolute; left: 6px; font-size: 10px; color: var(--faint); transform: translateY(-6px); }
.h-cb__gc { position: relative; border-left: 1px solid var(--line); touch-action: pan-y; }
.h-cb__hl { position: absolute; left: 0; right: 0; border-top: 1px solid rgba(255,255,255,.05); }
.h-cb__hl.is-half { border-top-style: dashed; border-color: rgba(255,255,255,.03); }
.h-cb__b { position: absolute; left: 4px; right: 6px; border-radius: 9px; padding: 4px 8px; font-size: 12px; font-weight: 800; line-height: 1.25; overflow: hidden; }
.h-cb__b small { display: block; font-weight: 600; font-size: 11px; opacity: .9; }
.h-cb__b.is-open { background: linear-gradient(rgba(var(--green-rgb), .10), rgba(var(--green-rgb), .10)), var(--panel); border: 1px solid rgba(var(--green-rgb), .42); color: var(--green); pointer-events: none; }
.h-cb__b.is-open span { font-size: 10.5px; }
.h-cb__b.is-taken { background: var(--panel2); border: 1px solid var(--line2); color: var(--faint); pointer-events: none; font-size: 11px; }
.h-cb__b.is-sent { background: linear-gradient(rgba(var(--purple-rgb), .12), rgba(var(--purple-rgb), .12)), var(--panel); border: 2px dashed var(--purple); color: var(--ink); pointer-events: none; }
.h-cb__b.is-mine { background: var(--green); color: var(--on-green); border: 1px solid var(--green); pointer-events: none; }
.h-cb__b.is-pick { background: var(--purple); color: #fff; /* raw-colour: white on the purple block, both themes */ border: 1px solid rgba(255,255,255,.35); box-shadow: 0 6px 18px rgba(var(--purple-rgb), .4); cursor: grab; touch-action: pan-y; z-index: 3; user-select: none; -webkit-user-select: none; }
.h-cb__b.is-pick.is-sel { box-shadow: 0 0 0 3px rgba(255,255,255,.85), 0 8px 22px rgba(var(--purple-rgb), .55); }
.h-cb__b.is-pick.is-lift { transform: scale(1.02); cursor: grabbing; z-index: 6; }
.h-cb__b.is-pick.is-near { background: linear-gradient(rgba(255,184,77,.25), rgba(255,184,77,.25)), var(--panel); /* raw-colour: the drag's amber warning wash */ border: 2px solid var(--warn); color: var(--ink); box-shadow: none; }
.h-cb__b.is-pick.is-bad { background: linear-gradient(rgba(255,107,107,.22), rgba(255,107,107,.22)), var(--panel); /* raw-colour: the drag's red clash wash */ border: 2px solid var(--danger); color: var(--ink); box-shadow: none; }
.h-cb__hdl { position: absolute; left: 0; right: 0; height: 14px; touch-action: none; cursor: ns-resize; z-index: 2; }
.h-cb__hdl.is-t { top: -6px; } .h-cb__hdl.is-b { bottom: -6px; }
.h-cb__hdl::after { content: ""; position: absolute; left: 50%; top: 5px; width: 28px; height: 4px; margin-left: -14px; border-radius: 2px; background: #fff; /* raw-colour: the grip on the purple block */ opacity: .9; }
/* Karl's fix §1.3: the small ✕ in the selected block's corner. */
.h-cb__bx { position: absolute; top: 3px; right: 3px; width: 22px; height: 22px; border-radius: 7px; border: 1px solid var(--line2); background: var(--panel2); color: var(--ink); font-size: 11px; display: grid; place-items: center; cursor: pointer; z-index: 4; }
.h-cb__tip { position: absolute; left: 6px; right: 6px; z-index: 7; padding: 3px 8px; border-radius: 7px; background: var(--panel2); border: 1px solid var(--line2); color: var(--ink); font-size: 11px; font-weight: 700; pointer-events: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.h-cb__dock { position: sticky; bottom: 0; z-index: 8; display: grid; gap: 8px; padding: 8px 0 4px; }
.h-cb__selbar { display: flex; align-items: center; gap: 6px; padding: 7px 8px 7px 12px; border-radius: var(--r-lg); background: var(--panel2); border: 1px solid rgba(var(--purple-rgb), .55); }
.h-cb__selt { position: relative; flex: 1; min-width: 0; background: none; border: 0; text-align: left; padding: 0 18px 0 0; color: var(--ink); font: inherit; cursor: pointer; }
.h-cb__selt b { display: block; font-size: 13px; }
.h-cb__pen { position: absolute; top: 0; right: 2px; width: 13px; height: 13px; color: var(--muted); }
.h-cb__bt { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding-right: 24px; }
.h-cb__locs:empty { display: none; }
.h-cb__flip { transform: rotate(180deg); } .h-cb__selt small { color: var(--muted); font-size: 11px; font-weight: 700; }
.h-cb__ib { width: 34px; height: 34px; border-radius: var(--r-sm); border: 1px solid rgba(var(--purple-rgb), .45); background: linear-gradient(rgba(var(--purple-rgb), .14), rgba(var(--purple-rgb), .14)), var(--panel2); color: var(--ink); font-weight: 900; font-size: 14px; display: grid; place-items: center; flex: none; cursor: pointer; }
.h-cb__ib:disabled { opacity: .35; cursor: default; }
.h-cb__undo { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: var(--r-md); background: var(--panel2); border: 1px solid var(--line2); font-size: 13px; }
.h-cb__undo span { flex: 1; } .h-cb__undo button { background: none; border: 0; color: var(--green); font-weight: 900; cursor: pointer; }
.h-cb__cbar { display: flex; align-items: center; gap: 10px; padding: 8px 8px 8px 14px; border-radius: var(--r-lg); background: var(--glass-nav-tint, var(--panel2)); border: 1px solid var(--line2); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
.h-cb__ct { flex: 1; min-width: 0; font-size: 12px; color: var(--muted); line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.h-cb__ct b { display: block; color: var(--ink); font-size: 13.5px; }
.h-cb__next { white-space: nowrap; }
/* Karl's fix §1.4: a menu row is an icon, a bold label, and its words UNDER it. */
.h-cb__panel { padding: 12px 14px 14px; border-radius: var(--r-lg); background: var(--panel2); border: 1px solid var(--line2); box-shadow: 0 -8px 24px rgba(0,0,0,.35); }
.h-cb__panel.is-inline { box-shadow: none; margin-top: 10px; }
.h-cb__panel h4 { margin: 0 0 6px; font: 400 18px var(--font-display); letter-spacing: .03em; text-transform: uppercase; }
.h-cb__panel h4 small { display: block; font: 600 12px var(--font-body, inherit); letter-spacing: 0; text-transform: none; color: var(--muted); margin-top: 2px; }
.h-cb__mrow { display: flex; align-items: flex-start; gap: 12px; width: 100%; padding: 12px 2px; border: 0; border-bottom: 1px solid var(--line); background: none; color: var(--ink); text-align: left; font: inherit; cursor: pointer; }
.h-cb__mrow .h-ic { flex: none; width: 20px; height: 20px; margin-top: 1px; color: var(--muted); }
.h-cb__mrow > span:last-child { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.h-cb__mrow b { font-size: 15px; } .h-cb__mrow small { font-size: 12.5px; color: var(--muted); font-weight: 600; }
.h-cb__mrow.is-red, .h-cb__mrow.is-red .h-ic { color: var(--danger); }
.h-cb__lbl { display: block; font-size: 12px; font-weight: 700; color: var(--muted); margin: 10px 0 5px; }
.h-cb__fit { font-size: 12.5px; margin: 8px 0 0; color: var(--green); }
.h-cb__fit.is-near { color: var(--warn); } .h-cb__fit.is-bad { color: var(--danger); }
.h-cb__acts { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; align-items: center; margin-top: 12px; }
.h-cb__acts--end { margin-top: 22px; }
.h-cb__why { flex: 1 1 100%; text-align: right; font-size: 12px; color: var(--warn); }
.h-cb__chips { display: flex; flex-wrap: wrap; gap: 7px; }
/* BD-05 (Karl, 10-02): Who is this session for? as person tiles: avatar,
   first name, one quiet line. Selected = green edge and a corner check. */
.h-cb__whos { display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: 8px; }
.h-cb__who { position: relative; display: flex; align-items: center; gap: 10px; min-width: 0; padding: 9px 28px 9px 10px; border-radius: var(--r-md); border: 1px solid var(--line); background: var(--panel2); color: var(--ink); font: inherit; text-align: left; cursor: pointer; }
.h-cb__who.is-on { border-color: var(--green); background: linear-gradient(rgba(var(--green-rgb), .12), rgba(var(--green-rgb), .12)), var(--panel2); }
.h-cb__wav { flex: none; display: grid; place-items: center; width: 34px; height: 34px; border-radius: 50%; overflow: hidden; background: var(--panel); font-weight: 800; }
.h-cb__wn { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.h-cb__wn b { font-size: 14.5px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.h-cb__wn small { margin-top: 2px; font-size: 11.5px; font-weight: 600; color: var(--muted); }
.h-cb__wn small.is-u18 { color: var(--warn); }
.h-cb__wck { position: absolute; top: 7px; right: 9px; display: none; color: var(--green); font-style: normal; font-weight: 900; }
.h-cb__who.is-on .h-cb__wck { display: block; }
.h-cb__who.is-add { border-style: dashed; }
.h-cb__who.is-add .h-cb__wav { background: none; border: 1px dashed var(--green); color: var(--green); font-size: 18px; }
.h-cb__who.is-add b { color: var(--green); }
.h-cb__chip { display: inline-flex; align-items: center; gap: 7px; padding: 9px 12px; border-radius: var(--r-md); border: 1px solid var(--line); background: var(--panel2); color: var(--ink); font: inherit; font-weight: 700; font-size: 13.5px; cursor: pointer; }
.h-cb__chip small { color: var(--muted); font-weight: 600; }
.h-cb__chip.is-on { border-color: var(--green); background: var(--green-dim); }
.h-cb__chip.is-on::before { content: "\2713"; color: var(--green); font-weight: 900; }
.h-cb__chip.is-add { border-style: dashed; color: var(--green); }
.h-cb__rplan div { display: flex; justify-content: space-between; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--line); font-size: 13.5px; }
.h-cb__rplan b { font-size: 12px; color: var(--muted); } .h-cb__rplan b.is-ok { color: var(--green); }
.h-cb__step { display: flex; flex-direction: column; gap: 4px; }
.h-cb__h { margin: 16px 2px 8px; font: 400 14px var(--font-display); letter-spacing: .12em; text-transform: uppercase; display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.h-cb__h small { font: 600 12px var(--font-body, inherit); letter-spacing: 0; text-transform: none; color: var(--muted); }
.h-cb__plist { display: grid; gap: 7px; margin-top: 10px; }
.h-cb__prow { display: flex; align-items: center; gap: 10px; padding: 9px 11px; border-radius: var(--r-md); border: 1px solid var(--line); background: var(--panel); }
.h-cb__pn { flex: 1; min-width: 0; display: flex; flex-direction: column; } .h-cb__pn b { font-size: 13.5px; } .h-cb__pn small { color: var(--muted); font-size: 12px; }
.h-cb__rm { width: 30px; height: 30px; border-radius: var(--r-sm); border: 1px solid var(--line); background: var(--panel2); color: var(--muted); flex: none; cursor: pointer; }
.h-cb__help { font-size: 12px; color: var(--muted); margin: 6px 2px 0; }
.h-cb__help.is-ok { color: var(--green); }
.h-cb__amber { margin-top: 12px; padding: 12px 13px; border-radius: var(--r-lg); border: 1px solid rgba(255,184,77,.55); background: rgba(255,184,77,.08); font-size: 13px; line-height: 1.45; }
.h-cb__amber h4 { margin: 8px 0 4px; font: 400 13px var(--font-display); letter-spacing: .1em; text-transform: uppercase; color: var(--warn); }
.h-cb__tick { display: flex; align-items: center; gap: 9px; width: 100%; padding: 8px 0; background: none; border: 0; color: var(--ink); font: inherit; font-weight: 700; font-size: 13.5px; text-align: left; cursor: pointer; }
.h-cb__tick i { width: 20px; height: 20px; border-radius: 6px; border: 2px solid var(--warn); display: grid; place-items: center; flex: none; font-style: normal; font-size: 12px; color: var(--on-green); }
.h-cb__tick.is-on i { background: var(--warn); }
.h-cb__tick small { color: var(--muted); font-weight: 600; }
.h-cb__tick:disabled { opacity: .85; cursor: default; }
.h-cb__sug { margin-top: 6px; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel); overflow: hidden; }
.h-cb__sug button { display: flex; align-items: center; gap: 9px; width: 100%; text-align: left; padding: 10px 12px; background: none; border: 0; border-bottom: 1px solid var(--line); color: var(--ink); font: inherit; font-size: 13.5px; cursor: pointer; }
.h-cb__sug button:last-child { border-bottom: 0; }
.h-cb__sug button small { color: var(--muted); margin-left: auto; }
.h-cb__sug .is-dym { background: rgba(var(--purple-rgb), .10); }
.h-cb__picked { display: flex; align-items: center; gap: 9px; margin-top: 6px; padding: 9px 12px; border-radius: var(--r-md); border: 1px solid rgba(var(--green-rgb), .45); background: var(--green-dim); font-size: 13.5px; }
.h-cb__picked > span:nth-of-type(2) { color: var(--green); margin-left: auto; font-weight: 800; font-size: 12px; }
.h-cb__card { border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel); padding: 12px 13px; margin-bottom: 9px; }
.h-cb__ab summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 10px; }
.h-cb__ab summary::-webkit-details-marker { display: none; }
.h-cb__ab summary > span:first-child { display: flex; flex-direction: column; } .h-cb__ab summary b { font-size: 14.5px; } .h-cb__ab summary small { color: var(--muted); font-size: 12px; }
.h-cb__go2 { margin-left: auto; color: var(--green); font-weight: 800; font-size: 12.5px; }
.h-cb__banner { margin: 10px 0; padding: 9px 11px; border-radius: var(--r-sm); background: var(--green-dim); border: 1px solid rgba(var(--green-rgb), .3); font-size: 12.5px; }
.h-cb__ta { width: 100%; min-height: 96px; resize: vertical; line-height: 1.45; }
.h-cb__row2 { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.h-cb__sw { display: inline-flex; align-items: center; gap: 8px; margin-top: 10px; font: inherit; font-size: 12.5px; color: var(--ink); background: none; border: 0; padding: 0; cursor: pointer; }
.h-cb__sw i { width: 34px; height: 20px; border-radius: 10px; background: var(--line2); position: relative; flex: none; }
.h-cb__sw i::after { content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%; background: var(--muted); transition: left .15s; }
.h-cb__sw.is-on i { background: rgba(var(--green-rgb), .35); } .h-cb__sw.is-on i::after { left: 16px; background: var(--green); }
.h-cb__sum { border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel); padding: 2px 12px; margin-bottom: 10px; }
.h-cb__r { display: flex; justify-content: space-between; gap: 10px; width: 100%; padding: 9px 0; border: 0; border-bottom: 1px solid var(--line); background: none; color: var(--ink); font: inherit; font-size: 13.5px; text-align: left; }
.h-cb__r:last-child { border-bottom: 0; }
.h-cb__r span { color: var(--muted); } .h-cb__r b { text-align: right; }
button.h-cb__r { cursor: pointer; }
.h-cb__r.is-tot { font-size: 15px; }
.h-cb__note { font-size: 12.5px; color: var(--muted); line-height: 1.5; margin: 6px 2px; }
.h-cb__warn { padding: 10px 12px; border-radius: var(--r-md); border: 1px solid rgba(255,184,77,.5); background: rgba(255,184,77,.08); font-size: 12.5px; margin: 10px 0; }
.h-cb__done { display: grid; justify-items: center; text-align: center; padding: 30px 10px 10px; }
.h-cb__ck { width: 78px; height: 78px; border-radius: 50%; background: linear-gradient(rgba(var(--purple-rgb), .16), rgba(var(--purple-rgb), .16)), var(--panel); border: 2px dashed var(--purple); display: grid; place-items: center; color: var(--ink); font-size: 34px; font-weight: 900; }
.h-cb__done h3 { margin: 14px 0 4px; font: 400 26px var(--font-display); letter-spacing: .03em; text-transform: uppercase; }
.h-cb__done p { margin: 0; color: var(--muted); max-width: 320px; }
@media (prefers-reduced-motion: reduce) { .h-cb__b.is-pick.is-lift { transform: none; } .h-cb__sw i::after { transition: none; } }

/* ===== BOOK A COACH · BOOKING REQUESTS (Direction D phase 2, coachdesk.js) ==
   The coach's queue: one card per request, ticks for the sessions that work. */
.h-cd { display: flex; flex-direction: column; gap: 10px; }
.h-cd__tabs { display: flex; gap: 4px; padding: 3px; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel); }
.h-cd__tabs button { flex: 1; padding: 8px 0; border: 0; border-radius: var(--r-sm); background: none; color: var(--muted); font: inherit; font-weight: 800; font-size: 12.5px; cursor: pointer; }
.h-cd__tabs button.is-on { background: var(--panel2); color: var(--ink); }
.h-cd__tabs em { font-style: normal; margin-left: 4px; padding: 1px 6px; border-radius: 8px; background: var(--purple); color: #fff; /* raw-colour: count on the purple badge */ font-size: 10.5px; }
.h-cd__req { border: 1px solid rgba(var(--purple-rgb), .5); border-radius: var(--r-lg); background: linear-gradient(rgba(var(--purple-rgb), .06), rgba(var(--purple-rgb), .06)), var(--panel); padding: 12px 13px; }
.h-cd__req.is-flash { box-shadow: 0 0 0 3px var(--purple); }
.h-cd__req h4 { margin: 0; font-size: 15px; }
.h-cd__sub { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.h-cd__tag { display: inline-block; margin-top: 6px; padding: 3px 8px; border-radius: 7px; background: linear-gradient(rgba(255,184,77,.13), rgba(255,184,77,.13)), var(--panel); /* raw-colour: the Under 18 amber wash */ color: var(--ink); font-size: 11px; font-weight: 800; }
.h-cd__ss { display: flex; align-items: center; gap: 10px; width: 100%; padding: 9px 0; border: 0; border-top: 1px solid var(--line); background: none; color: var(--ink); font: inherit; font-size: 13.5px; text-align: left; cursor: pointer; }
.h-cd__ss i { width: 20px; height: 20px; border-radius: 6px; border: 2px solid var(--green); display: grid; place-items: center; font-style: normal; font-size: 12px; color: var(--on-green); flex: none; }
.h-cd__ss.is-on i { background: var(--green); }
.h-cd__ss small { margin-left: auto; color: var(--muted); }
.h-cd__about { margin-top: 6px; border-top: 1px solid var(--line); padding-top: 6px; }
.h-cd__about summary { cursor: pointer; font-size: 12.5px; font-weight: 800; color: var(--purple); }
.h-cd__about p { white-space: pre-wrap; font-size: 12.5px; margin: 6px 0; }
.h-cd__held { display: flex; flex-direction: column; gap: 4px; padding: 10px 12px; border: 2px dashed var(--purple); border-radius: var(--r-lg); background: var(--panel); margin-bottom: 8px; font-size: 13px; }
.h-cd__held small { color: var(--muted); }
.h-cd__slots { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; }
.h-cd__slots button { padding: 10px 8px; border-radius: var(--r-md); border: 1px solid rgba(var(--green-rgb), .4); background: linear-gradient(rgba(var(--green-rgb), .07), rgba(var(--green-rgb), .07)), var(--panel2); color: var(--ink); font: inherit; font-size: 12.5px; text-align: left; cursor: pointer; display: flex; flex-direction: column; }
.h-cd__slots button small { color: var(--muted); }
/* Walk B49 (Karl, 10-02): Decline and offer times as one flow, with an amber
   accent on its button; Get help from Hockey365 as a quiet link. */
/* BK11 (phase 3): the Hockey365 activity block (member About step, coach card). */
.h-cb__act { display: grid; gap: 8px; }
.h-cb__acth { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.h-cb__acth small { color: var(--muted); font-size: 11.5px; }
.h-cb__act ul, .h-cd__actl { margin: 0; padding-left: 18px; display: grid; gap: 4px; font-size: 13px; color: var(--ink); }
.h-cd__dec { background: var(--panel2); color: var(--warn); border: 1px solid var(--warn); }
.h-cd__help { display: block; margin: 8px 0 0 auto; padding: 4px 0; background: none; border: 0; color: var(--muted); font: inherit; font-size: 12px; font-weight: 700; text-decoration: underline; cursor: pointer; }
.h-cd__ofs { display: grid; gap: 7px; padding: 10px 0; border-top: 1px solid var(--line); }
.h-cd__ofs > b { font-size: 13.5px; }
.h-cd__ofl { display: flex; flex-wrap: wrap; gap: 6px; }
.h-cd__of { display: inline-flex; align-items: center; gap: 6px; padding: 5px 6px 5px 10px; border-radius: var(--r-pill); border: 1px solid var(--green); background: var(--panel2); font-size: 12.5px; font-weight: 700; }
.h-cd__of small { color: var(--muted); font-weight: 600; }
.h-cd__of button { background: none; border: 0; color: var(--muted); font: inherit; cursor: pointer; padding: 0 4px; }
.h-cd__ofb { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.h-cd__ofb button { padding: 7px 10px; border-radius: var(--r-md); border: 1px dashed var(--green); background: none; color: var(--green); font: inherit; font-size: 12.5px; font-weight: 700; cursor: pointer; }
.h-cd__ofb small { color: var(--muted); font-size: 11.5px; }
.h-cd__type { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr) auto; gap: 6px; align-items: center; }
.h-co__sugs { margin: 8px 0 4px; }
.h-co__opt { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 0; border-top: 1px solid var(--line); }
.h-co__opt span { font-weight: 700; font-size: 13px; min-width: 0; }
.h-cd__slots button.is-on { border-color: var(--purple); background: var(--purple); color: #fff; /* raw-colour: white on the picked purple slot */ }
.h-cd__slots button.is-on small { color: #fff; /* raw-colour: on purple */ }
.h-cd__search { width: 100%; }
.h-cd__wk { margin: 14px 2px 4px; font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--faint); }
.h-cd__li { display: flex; align-items: center; gap: 10px; padding: 10px 2px; border-bottom: 1px solid var(--line); }
.h-cd__li > span:first-child { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.h-cd__li b { font-size: 13.5px; } .h-cd__li small { color: var(--muted); font-size: 12px; }
.h-cd__pill { padding: 3px 9px; border-radius: 8px; font-size: 11px; font-weight: 800; white-space: nowrap; background: var(--panel2); border: 1px solid var(--line2); color: var(--ink); }
.h-cd__pill.is-g { border-color: rgba(var(--green-rgb), .5); } .h-cd__pill.is-a { border-color: var(--warn); } .h-cd__pill.is-p { border-color: rgba(var(--purple-rgb), .6); }
.h-cd__calreq { pointer-events: auto; text-align: left; font: inherit; font-size: 12px; font-weight: 800; cursor: pointer; }
/* My sessions (coach.js): a partial accept to confirm, a suggested time. */
.h-co__grp + .h-co__grp { margin-top: 14px; }
.h-co__grp > .h-co__secth { margin-bottom: 8px; }
.h-co__held, .h-co__sug { border-radius: var(--r-lg); padding: 12px 13px; margin-bottom: 10px; background: var(--panel); font-size: 13px; }
.h-co__held { border: 2px dashed var(--purple); }
.h-co__sug { border: 1px solid rgba(var(--green-rgb), .45); }
.h-co__held b, .h-co__sug b { display: block; font-size: 14px; }
.h-co__held p, .h-co__sug p { margin: 6px 0; }
.h-co__heldno span { font-weight: 800; color: var(--muted); margin-right: 6px; }
.h-co__heldby { color: var(--muted); font-size: 12.5px; }

/* ⬇ Karl, 2026-10-02: the jump arrow on the booking calendar screens.
   Second pass: always green at half strength (glass, blurred), centred. The
   down arrow goes away at the bottom, and an up arrow shows at the TOP of the
   box instead (coach.js shows exactly one of the two). */
.h-co__jumpwrap { position: sticky; height: 0; z-index: 12; pointer-events: none; }
.h-co__jumpwrap--end { bottom: 0; }
.h-co__jumpwrap--top { top: 0; }
/* GLASS ON PURPOSE (Karl, 10-02): half-strength green over whatever the calendar scrolls under it. The ink is
   the dark on-green; over the dark panel the mix still clears 3:1 for an icon, and it is never text. */
.h-co__jump { position: absolute; left: 50%; transform: translateX(-50%); pointer-events: auto; width: 42px; height: 42px; border-radius: 50%; display: grid; place-items: center; padding: 0; cursor: pointer; color: var(--on-green); background: color-mix(in srgb, var(--green) 50%, transparent); border: 1px solid color-mix(in srgb, var(--green) 70%, transparent); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); box-shadow: 0 4px 14px rgba(0, 0, 0, .25); transition: background .2s; }
.h-co__jumpwrap--end .h-co__jump { bottom: 12px; }
.h-co__jumpwrap--top .h-co__jump { top: 10px; }
.h-co__jump svg { width: 22px; height: 22px; }
.h-co__jump:hover, .h-co__jump:focus-visible { background: color-mix(in srgb, var(--green) 80%, transparent); }
@media (prefers-reduced-motion: reduce) { .h-co__jump { transition: none; } }

/* BE-05: the decline panel's per-session ticks sit inside each block. */
.h-cd__ofs > .h-cd__dsel { border-top: 0; padding: 0 0 2px; }

/* CM-06: the post being asked about, quoted in the Remove from Find dialog. */
.h-ced__gone { margin: 6px 0; padding: 8px 10px; border-radius: var(--r-md); background: var(--panel2); }

/* Notifications: the slim search, once the list passes ten. */
.h-nt__search { margin: 4px 0 10px; }

/* Karl's walk: a child's emergency contact typed on the Review step. */
.h-cb__emg { display: grid; gap: 6px; margin-top: 8px; }
.h-cb__emg .h-btn { justify-self: start; }
.h-cb__emg .h-cb__emguse { margin-bottom: 0; }
.h-cb__warn.is-done { border-color: color-mix(in srgb, var(--green) 55%, transparent); background: color-mix(in srgb, var(--green) 7%, var(--panel)); }
.h-cb__ok { margin: 6px 0 0; font-size: 12.5px; font-weight: 700; color: var(--green); }

/* Karl's walk RY-06 (2026-10-03): Report asks why. Plain tick boxes (never pills). */
.h-repask { display: flex; flex-direction: column; gap: 10px; margin-top: 4px; }
.h-repask__opt { display: flex; align-items: center; gap: 10px; font-size: 14px; }
.h-repask__opt input { width: 18px; height: 18px; accent-color: var(--green); }
.h-repask__more { display: flex; flex-direction: column; gap: 6px; font-size: 13px; color: var(--muted); }
.h-repask__more textarea { font: inherit; color: var(--ink); background: transparent; border: 1px solid var(--line); border-radius: 10px; padding: 10px; resize: vertical; }

/* Relay Campaign 2 (2026-10-03): the travel fee on a waiting request, with
   Change / Remove as text links; Can't make it and File report on a booked
   session's row drop to their own line so the row never scrolls sideways. */
.h-cd__fee { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin-top: 8px; padding: 8px 10px; border-radius: var(--r-md); border: 1px solid var(--line2); background: var(--panel2); font-size: 12.5px; }
.h-cd__fee b { font-size: 13px; }
.h-cd__fee span { color: var(--muted); flex: 1 1 auto; min-width: 0; }
.h-cd__lnk { padding: 2px 0; background: none; border: 0; color: var(--purple); font: inherit; font-size: 12.5px; font-weight: 800; text-decoration: underline; cursor: pointer; }
.h-cd__li.is-acts { flex-wrap: wrap; }
.h-cd__liacts { flex-basis: 100%; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }

/* ---------------------------------------------------------------------------
   GET THE APP (Relay Campaign 3, Karl walk PU-11): one row above the top bar,
   only in a browser. Chrome-dark like the bar under it, green accent.
   ------------------------------------------------------------------------ */
.h-getapp { display: flex; align-items: center; gap: 10px; padding: 7px 12px 7px 14px;
  background: var(--chrome-appbar-top); color: var(--chrome-ink, #f0f0f0);
  border-bottom: 1px solid rgba(7, 247, 8, .28); font-size: 12.5px; line-height: 1.35; }
.h-getapp__ic { flex: none; color: var(--srcGreen); display: grid; place-items: center; }
.h-getapp__tx { flex: 1; min-width: 0; }
.h-getapp__btn { flex: none; background: var(--srcGreen); color: #04120a; border: 0; border-radius: 999px;
  padding: 6px 13px; font-weight: 800; font-size: 12px; cursor: pointer; }
.h-getapp__x { flex: none; background: none; border: 0; color: var(--muted); font-size: 20px; line-height: 1;
  padding: 0 2px; cursor: pointer; }
.h-getapp-sheet { display: grid; gap: 8px; }
.h-getapp-steps { list-style: none; margin: 4px 0 10px; padding: 0; display: grid; gap: 10px; }
.h-getapp-steps__li { display: flex; gap: 10px; align-items: flex-start; line-height: 1.45; }
.h-getapp-steps__n { flex: none; width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center;
  background: var(--green); color: var(--on-green); font-weight: 800; font-size: 12px; }

/* === CHARACTER BUILDER + SPACE DESIGNER (identitystudio.js V2.0, B65 2026-10-05) ==========
   Kestrel's Character Builder Sidebar Workflow v1 + Space Studio v8 at phone width, with
   Karl's B65 rulings: the page is a FULL-HEIGHT column so Reset / Review always sit on the
   bottom edge (F1: glass while choices scroll under them, solid at the end); the tabs are a
   fixed grid that always fits (a tab bar never scrolls sideways); the colour set is a dot
   in the preview's top-left corner (F2); the kits page, the Review page and the Space art
   page are full-screen layers with the same pinned pair. */
.h-ids-layer { background: var(--bg); display: flex; flex-direction: column; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
/* No slide on these layers: a transform would make the fixed button bar follow the page instead of the screen. They fade. */
.h-ids-layer, .h-ids-layer.is-open { transform: none; }
/* B65 second walk (Karl): room under the content for the FIXED button bar, so the last choice is never hidden behind it. */
.h-ids-layer > .tb-page__body { flex: 1 0 auto; width: 100%; display: flex; flex-direction: column; padding: 0 0 calc(88px + env(safe-area-inset-bottom, 0px)); }
.h-ids { gap: 12px; }
.h-ids__hero { position: relative; min-height: 220px; display: grid; place-items: center; overflow: hidden; border-bottom: 1px solid var(--line); background: var(--panel); }
.h-ids__hero::after { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(6, 9, 10, .05), rgba(6, 9, 10, .4)); pointer-events: none; }
.h-ids__face { position: relative; z-index: 1; width: 132px; height: 132px; filter: drop-shadow(0 10px 22px rgba(0, 0, 0, .55)); }
.h-ids__label { position: absolute; left: 14px; bottom: 10px; z-index: 1; margin: 0; max-width: calc(100% - 28px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--ink); }
.h-ids__tl { position: absolute; top: 10px; left: 10px; z-index: 2; display: flex; align-items: center; gap: 6px; }
.h-ids__dot { flex: none; width: 40px; height: 40px; display: grid; place-items: center; padding: 0; border-radius: 50%; border: 1px solid var(--line2); background: var(--panel); cursor: pointer; }
.h-ids__dot span, .h-ids__swdot { display: block; width: 26px; height: 26px; border-radius: 50%; background: conic-gradient(var(--c1, var(--green)) 0 50%, var(--c2, var(--purple)) 50% 100%); box-shadow: inset 0 0 0 2px rgba(0, 0, 0, .25); }
.h-ids__mode { position: absolute; top: 10px; right: 10px; z-index: 2; display: flex; gap: 4px; padding: 4px; border-radius: var(--r-pill); border: 1px solid var(--line2); background: var(--panel); }
.h-ids__mode button { padding: 7px 12px; border-radius: var(--r-pill); border: 1px solid transparent; background: none; color: var(--ink); font: inherit; font-size: 12px; font-weight: 800; cursor: pointer; }
.h-ids__mode button.is-on { background: var(--green); border-color: var(--green); color: var(--on-green, #06090a); }
.h-ids__hero.is-space { min-height: 170px; grid-template-columns: minmax(0, 1fr); place-items: end stretch; }
.h-ids__spcard { position: relative; z-index: 1; min-width: 0; display: flex; align-items: center; gap: 12px; margin: 58px 14px 14px; padding: 10px; border-radius: var(--r-lg); border: 1px solid var(--line2); background: rgba(14, 20, 23, .86); }
.h-ids__spcard > .h-ids__sq { width: 64px; height: 64px; flex: none; }
.h-ids__spt { flex: 1; min-width: 0; }
.h-ids__spt b { display: block; font-size: 17px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-ids__spt small { color: var(--muted); font-size: 12.5px; }
.h-ids__role { flex: none; align-self: flex-start; padding: 3px 8px; border-radius: var(--r-pill); border: 1px solid var(--line2); font-style: normal; font-size: 10.5px; font-weight: 900; letter-spacing: .06em; text-transform: uppercase; }
.h-ids__note { margin: 0 16px; padding: 10px 12px; border-radius: var(--r-md); border: 1px solid var(--warn); background: var(--panel); color: var(--ink); font-size: 13px; line-height: 1.4; }
.h-ids__kitp { display: inline-flex; align-items: center; gap: 6px; max-width: 132px; height: 40px; padding: 0 12px; border-radius: var(--r-pill); border: 1px solid var(--line2); background: var(--panel); color: var(--ink); font: inherit; font-size: 12.5px; font-weight: 800; cursor: pointer; }
.h-ids__kitp > span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-ids__kitp .h-ic { width: 16px; height: 16px; flex: none; color: var(--purple); }
.h-ids__kitp.is-undo { position: absolute; right: 10px; bottom: 8px; z-index: 2; height: 32px; color: var(--purple); }
.h-ids__hero.is-space .h-ids__kitp.is-undo { top: 10px; bottom: auto; }
.h-ids__lnk { padding: 2px 0; border: 0; background: none; color: var(--purple); font: inherit; font-size: 13px; font-weight: 800; text-decoration: underline; cursor: pointer; }
.h-ids__mut { color: var(--muted); font-size: 13px; }
.h-ids__tabs { position: sticky; top: calc(64px + env(safe-area-inset-top, 0px)); z-index: 2; display: grid; grid-template-columns: repeat(var(--n, 4), minmax(0, 1fr)); gap: 3px; margin: 0 16px; padding: 4px; border-radius: var(--r-lg); border: 1px solid var(--line); background: var(--panel); }
.h-ids__tabs button { min-width: 0; padding: 9px 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border-radius: var(--r-md); border: 1px solid transparent; background: none; color: var(--muted); font: inherit; font-size: 12px; font-weight: 800; letter-spacing: -.01em; cursor: pointer; }
.h-ids__tabs button.is-on { border-color: var(--green); color: var(--ink); background: var(--panel2); }
.h-ids__panel { padding: 0 16px; display: flex; flex-direction: column; gap: 14px; }
.h-ids__sec > header { display: flex; align-items: center; gap: 8px; }
.h-ids__sec > header h3 { flex: 1; min-width: 0; }
.h-ids__step { flex: none; width: 24px; height: 24px; display: grid; place-items: center; border-radius: 8px; border: 1px solid var(--purple); color: var(--ink); font-size: 12px; font-weight: 900; }
.h-ids__sec h3 { margin: 0; font-size: 18px; }
.h-ids__sec > header > span:last-child:not(.h-ids__step) { color: var(--muted); font-size: 12px; font-weight: 700; }
.h-ids__lead { margin: 4px 0 10px; color: var(--muted); font-size: 13px; line-height: 1.4; }
.h-ids__name { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px; margin: 8px 0 0; font-size: 16px; }
.h-ids__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.h-ids__grid.is-big { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.h-ids__grid.is-wide { grid-template-columns: 1fr; }
@media (min-width: 720px) { .h-ids__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } .h-ids__grid.is-big { grid-template-columns: repeat(3, minmax(0, 1fr)); } .h-ids__grid.is-wide { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.h-ids__tile { min-width: 0; display: flex; flex-direction: column; gap: 4px; padding: 7px; text-align: left; border-radius: var(--r-lg); border: 1.5px solid var(--line); background: var(--panel); color: var(--ink); font: inherit; cursor: pointer; }
.h-ids__tile.is-on { border-color: var(--green); box-shadow: 0 0 0 1px var(--green); }
.h-ids__tile.is-preview .h-ids__art > :not(.h-ids__chip) { opacity: .82; }
.h-ids__art { position: relative; display: grid; place-items: center; aspect-ratio: 1; border-radius: var(--r-md); background: var(--panel2); overflow: hidden; }
.h-ids__tile.is-wide .h-ids__art, .h-ids__art.is-wide { aspect-ratio: 16 / 7; }
.h-ids__art > .h-av, .h-ids__art > .h-ids__disc { width: 80%; height: 80%; }
.h-ids__disc { display: block; border-radius: 50%; overflow: hidden; }
.h-ids__disc img { display: block; width: 100%; height: 100%; object-fit: cover; }
.h-ids__wide { display: block; width: 100%; height: 100%; }
.h-ids__sq { display: block; width: 80%; aspect-ratio: 1; }
.h-ids__sq > .h-gav { width: 100%; height: 100%; }
.h-ids__grid.is-big .h-ids__sq { width: 88%; }
.h-ids__n { font-size: 13px; font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-ids__tile small { color: var(--muted); font-size: 11px; line-height: 1.3; }
.h-ids__chip { position: absolute; top: 5px; right: 5px; padding: 2px 6px; border-radius: var(--r-pill); border: 1px solid var(--line2); background: var(--panel); color: var(--ink); font-size: 9px; font-weight: 900; letter-spacing: .06em; }
.h-ids__chip.is-lock { border-color: var(--purple); }
.h-ids__chip.is-yours { border-color: var(--green); }
/* NEW for 14 days after release (catalogue source, 2026-10-05): top-left, the chip's opposite corner. */
.h-ids__new { position: absolute; top: 5px; left: 5px; padding: 2px 6px; border-radius: var(--r-pill); background: var(--green); color: var(--on-green); font-size: 9px; font-style: normal; font-weight: 900; letter-spacing: .06em; pointer-events: none; }
.h-ids__fam { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-top: 8px; }
.h-ids__famb { min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 8px 6px; border-radius: var(--r-lg); border: 1.5px solid var(--line); background: var(--panel); color: var(--ink); font: inherit; cursor: pointer; text-align: center; }
.h-ids__famb.is-on { border-color: var(--green); }
.h-ids__famb small { color: var(--muted); font-size: 10.5px; line-height: 1.3; }
.h-ids__swatches { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.h-ids__sw { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 10px 6px; border-radius: var(--r-lg); border: 1.5px solid var(--line); background: var(--panel); color: var(--ink); font: inherit; font-size: 12.5px; cursor: pointer; }
.h-ids__sw.is-on { border-color: var(--green); }
.h-ids__sw span { width: 40px; height: 40px; border-radius: 50%; box-shadow: inset 0 0 0 4px var(--c1, var(--green)), inset 0 0 0 8px var(--c2, var(--purple)); background: var(--panel2); }
/* F1: the pair sits on the bottom edge on every tab — pushed down by the full-height column, held there while the page scrolls. */
/* B65 second walk (Karl: "still floating"): a FIXED bar on the screen's bottom edge, never part of the page flow
   (sticky followed the content on a phone). No bar behind the buttons — they turn to glass while choices scroll under. */
/* Karl (B65 third pass, phone screenshot): lower — the pair sits in the home-indicator band, not above it. */
.h-ids__pin { position: fixed; left: 0; right: 0; bottom: 0; z-index: 5; display: flex; gap: 10px; margin: 0;
  padding: 10px max(16px, calc((100% - 868px) / 2)) max(8px, calc(env(safe-area-inset-bottom, 0px) - 14px)); pointer-events: none; }
.h-ids__pin > .h-btn { pointer-events: auto; }
.h-ids__pin .h-btn--ghost { flex: 1; }
.h-ids__pin .h-btn:not(.h-btn--ghost) { flex: 1.6; }
.h-ids__lockerb { justify-self: end; padding: 7px 10px; border-radius: var(--r-pill); border: 1px solid var(--line2); background: var(--panel); color: var(--ink); font: inherit; font-size: 12px; font-weight: 800; cursor: pointer; }
/* Kits page (G1, Kestrel's kit page without prices). */
.h-ids__kitpick { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.h-ids__kitb { min-width: 0; display: flex; align-items: center; gap: 10px; padding: 8px; text-align: left; border-radius: var(--r-lg); border: 1.5px solid var(--line); background: var(--panel); color: var(--ink); font: inherit; cursor: pointer; }
.h-ids__kitb.is-on { border-color: var(--green); }
.h-ids__kitb > span:last-child { min-width: 0; }
.h-ids__kitb b { display: block; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-ids__kitb small { color: var(--muted); font-size: 11px; }
.h-ids__kitface { position: relative; flex: none; width: 44px; height: 44px; display: grid; place-items: center; }
.h-ids__kitshow { position: relative; display: flex; flex-direction: column; gap: 10px; min-height: 230px; justify-content: flex-end; padding: 16px; border-radius: var(--r-lg); border: 1px solid var(--line2); overflow: hidden; background-color: var(--panel); }
.h-ids__kfaces { display: flex; gap: 14px; justify-content: center; }
.h-ids__kf { width: 104px; height: 104px; filter: drop-shadow(0 10px 20px rgba(0, 0, 0, .55)); }
.h-ids__kf > .h-av, .h-ids__kf > .h-gav { width: 100%; height: 100%; }
.h-ids__kcopy { padding: 10px 12px; border-radius: var(--r-md); background: rgba(6, 9, 10, .72); }
.h-ids__kcopy small { color: var(--green); font-size: 10.5px; font-weight: 900; letter-spacing: .1em; text-transform: uppercase; }
.h-ids__kcopy h3 { margin: 2px 0 2px; font-size: 19px; }
.h-ids__kcopy p { margin: 0; color: var(--ink2, var(--ink)); font-size: 12.5px; }
.h-ids__pieces { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 8px; }
.h-ids__piece { min-width: 0; display: flex; align-items: center; gap: 10px; padding: 8px; border-radius: var(--r-lg); border: 1px solid var(--line); background: var(--panel); }
.h-ids__piece > .h-ids__art { flex: none; width: 52px; }
.h-ids__piece > .h-ids__art.is-wide { width: 72px; }
.h-ids__piece > span:last-child { min-width: 0; }
.h-ids__piece b { display: block; font-size: 12.5px; }
.h-ids__piece small { display: block; color: var(--muted); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-ids__kcard { padding: 12px; border-radius: var(--r-lg); border: 1px dashed var(--line2); }
.h-ids__kcard p { margin: 0 0 8px; color: var(--muted); font-size: 13px; }
/* Review page (G2, Kestrel's full-screen review). */
.h-ids__rcard { margin: 12px 16px 0; border-radius: var(--r-xl, 18px); border: 1px solid var(--line2); overflow: hidden; background: var(--panel); }
.h-ids__rhero { height: 150px; background-color: var(--panel2); }
.h-ids__rrow { display: flex; align-items: center; gap: 14px; padding: 0 14px 14px; margin-top: -40px; position: relative; }
.h-ids__rface { flex: none; width: 88px; height: 88px; filter: drop-shadow(0 8px 18px rgba(0, 0, 0, .5)); }
.h-ids__rface > .h-av, .h-ids__rface > .h-gav { width: 100%; height: 100%; }
.h-ids__rwho { min-width: 0; padding-top: 40px; }
.h-ids__rwho b { display: block; font-size: 17px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.h-ids__rwho small { color: var(--muted); font-size: 12.5px; }
.h-ids__sum { margin: 0; display: grid; gap: 0; padding: 4px 14px; border-radius: var(--r-lg); border: 1px solid var(--line); background: var(--panel); }
.h-ids__sum div { display: flex; justify-content: space-between; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--line); }
.h-ids__sum div:last-child { border-bottom: 0; }
.h-ids__sum dt { color: var(--muted); font-size: 13px; }
.h-ids__sum dd { margin: 0; font-size: 13.5px; font-weight: 800; text-align: right; }
.h-ids__rcardrow { display: flex; gap: 14px; align-items: flex-start; margin-top: 8px; }
.h-ids__rcardpic { flex: none; }
.h-ids__rcardtx { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.h-ids__rcardtx b { font-size: 15px; }
.h-ids__rcardtx small { color: var(--muted); font-size: 12.5px; line-height: 1.4; }
.h-ids__note--top { margin-top: 12px; font-weight: 700; }
/* My Locker (personal only, tabs like the Builder) and Space art. */
.h-ids__tile.is-static { cursor: default; }
.h-ids__lgrp { margin: 6px 0 2px; font-size: 13px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
.h-ids__word { font-size: 10.5px; letter-spacing: .05em; }
.h-ids__pad { padding: 14px 16px 0; margin: 0; }
.h-ids__lkits { padding-top: 0; }
.h-ids-locker .h-ids__panel, .h-ids-art .h-ids__panel { padding-bottom: 24px; }
.h-ids-sub { z-index: 47; }
/* The Basic disc chosen on purpose (B65 second walk) at preview / tile / card size: its letters scale with the slot
   (the house disc's 15px is for list rows). */
.h-ids__face, .h-ids__art, .h-ids__rface, .h-ids__kf, .h-ids__kitface { container-type: inline-size; }
.h-ids__face > .h-av--init, .h-ids__rface > .h-av--init, .h-ids__kf > .h-av--init, .h-ids__kitface > .h-av--init { font-size: 36cqw; }
.h-ids__art > .h-av--init { font-size: 28cqw; }
.h-ids-kits .h-ids__panel, .h-ids-review .h-ids__panel { padding-top: 12px; }
.h-ids__kf.is-sq, .h-ids__rface.is-sq { border-radius: 26.2%; }

/* ---------------------------------------------------------------------------
   THE MEMBER APP BAR'S WORDMARK (Karl, 2026-10-08)
   ① It sits at the LEFT, just right of the avatar circle, at every width — not centred between the avatar and the
     top icons. The brand takes the free space and starts at its left edge, so the icons stay pinned right. Full size
     (the 15 px drawing is 126 px wide) wherever it fits; on the narrowest phones, where the five top icons leave less
     room, it scales down with its proportions instead of running under them. Bars that start with a back button keep
     their own layout.
   ② It is TWO-TONE: "Hockey" pure white (`--on-colour`, #fff), "365" the brand green. The "365" glyphs carry
     `.h-wm-num` in brand.js; everywhere else they keep painting with currentColor.
   ⚠️ DELIBERATELY HERE, NOT IN tokens.css / components.css: those files are byte-pinned as the News display
     (`tools/news-display-pin.mjs`), and a change there blanks the Tools News Preview Editor until Tools re-vendors.
     This loads after components.css, so it wins the `.h-chrome .h-wordmark` colour at equal specificity.
   ------------------------------------------------------------------------ */
.h-avatar-btn + .h-appbar__brand { flex: 1 1 auto; min-width: 0; justify-content: flex-start; margin: 0 10px; }
.h-avatar-btn + .h-appbar__brand .h-wordmark { height: auto; width: min(128px, 100%); }   /* the letters at their 15 px height, plus the drawing's 2-unit margin */
.h-avatar-btn + .h-appbar__brand .h-wordmark svg { width: 100%; height: auto; }
.h-chrome .h-wordmark { color: var(--on-colour); }
.h-chrome .h-wordmark .h-wm-num { fill: var(--green); }

/* ---------------------------------------------------------------------------
   CONV-B, 2026-10-08 — THE CONTEXTUAL STAFF ACTIONS IN THE SHARED STAFF
   LANGUAGE (Karl's accepted Staff Administration design: hub, session door,
   invoice, member record, Space organizer tools). Rows are the global
   `.h-grp` + `.h-mtool`; these lines only add what those do not have.
   ------------------------------------------------------------------------ */
/* THE STAFF HUB'S TABS FIT, NEVER SCROLL SIDEWAYS (Karl's rule): equal cells
   in a grid; five tabs wrap to two rows on the narrowest phones. */
.h-sh__tabs[data-n] { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 4px; }
.h-sh__tabs[data-n="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.h-sh__tabs[data-n="5"] { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.h-sh__tabs[data-n] button { padding: 8px 4px; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 400px) {
  .h-sh__tabs[data-n="5"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* A section label inside the quick view, with its icon beside the words. */
.h-sh__sec { display: flex; align-items: center; gap: 7px; }
.h-sh__sec .h-ic { width: 15px; height: 15px; color: var(--green); }
/* One of my payouts: what it is, and its status in plain words. */
.h-sh__pay {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: var(--r-md);
  background: var(--panel); border: 1px solid var(--line);
}
.h-sh__pay .h-tag { flex: none; }
.h-sh__payacts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.h-sh__payacts .h-ic { width: 14px; height: 14px; }

/* FULLER TOOLS — a destination row from the server's registry, beside a record
   (`H365UI.toolsDoors`). Where it opens is said in words, every time; H365 Tools
   is the purple surface in the design. */
.h-tdoors { margin-top: 14px; }
.h-tdoors > .h-sec-label { display: flex; align-items: center; gap: 7px; }
.h-tdoors > .h-sec-label .h-ic { width: 16px; height: 16px; color: var(--green); }
.h-tdoor .h-mtool__ic .h-ic { width: 18px; height: 18px; }
.h-tdoor__where { display: inline-flex; align-items: center; gap: 4px; margin-top: 4px;
  font-size: 11.5px; font-weight: 700; color: var(--muted); }
.h-tdoor__where .h-ic { width: 13px; height: 13px; }
/* §B27 (2026-10-10): the small cross-deployment marker on a Tools-owned row (the Fuller tools rows here and Staff
   Administration's doors) — Tools' own compact chip, so the row reads as an ordinary staff entry. The words "Opens in
   H365 Tools" stay for screen readers (.h-sr). */
.h-xapp { display: inline-block; padding: 1px 6px; border-radius: 999px; border: 1px solid currentColor;
  font-size: 10px; font-weight: 800; letter-spacing: .05em; line-height: 1.4; }
/* ↩️ §B27 item 6 (2026-10-10): Back to H365 Tools on a member record Tools opened — a small pill in the app bar's empty
   centre (the persona pill's place; below it when both show), in the Tools purple. Covers no control; ✕ hides it. */
.h-toolsret { position: fixed; left: 50%; transform: translateX(-50%); top: calc(8px + env(safe-area-inset-top, 0px));
  z-index: 2147483646; display: flex; align-items: center; gap: 2px; max-width: 60vw; padding: 2px 2px 2px 4px;
  border-radius: 999px; background: linear-gradient(rgba(var(--purple-rgb), .16), rgba(var(--purple-rgb), .16)), var(--panel); color: var(--active-purple-ink);
  border: 1px solid currentColor; box-shadow: 0 1px 6px rgba(0,0,0,.35); }
.h-toolsret--low { top: calc(44px + env(safe-area-inset-top, 0px)); }
.h-toolsret__go { display: inline-flex; align-items: center; gap: 5px; min-height: 32px; padding: 0 8px;
  color: inherit; font-size: 12px; font-weight: 700; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.h-toolsret__go .h-ic { width: 14px; height: 14px; flex: none; }
.h-toolsret__x { flex: none; width: 32px; height: 32px; border: 0; border-radius: 999px; background: none; color: inherit;
  font-size: 18px; line-height: 1; cursor: pointer; }

/* THE STAFF END OF AN INVOICE — "What you can do on this invoice": the heading
   with its icon, and the guided sheets' warning line (what the act does and
   what cannot be undone, said before the button). */
.h-inv__staffH { display: flex; align-items: center; gap: 6px; }
.h-inv__staffH .h-ic { width: 14px; height: 14px; color: var(--green); }
.h-inv__staff .h-grp { margin: 0; }
.h-inv__sheet { display: flex; flex-direction: column; gap: 10px; }
.h-inv__sheet .h-inv__f .h-ic { width: 13px; height: 13px; vertical-align: -2px; }
.h-inv__warn { margin: 0; padding: 10px 12px; border-radius: var(--r-md);
  border: 1px solid var(--warn); background: var(--panel2); color: var(--ink); font-size: 13px; line-height: 1.4; }

/* UP NEXT ON THE FULL STAFF HUB carries Check in, in the same window as the quick view. */
.h-sp__heroacts { margin-top: 10px; }

/* PT-SAFE U2 · N-E-33 (2026-10-08). A LOCKED KIOSK DOOR IS THE WHOLE SCREEN.
   `programs.js` marks the document `data-kiosk="1"` only while a locked door is
   open. The app bar (its ? Help, Chat with support, Messages, Menu) and the
   bottom nav are not drawn, and at desktop/tablet-landscape width the door stops
   being a centred sheet with the staff session's app around it. */
html[data-kiosk="1"] .h-appbar,
html[data-kiosk="1"] .h-bnav,
html[data-kiosk="1"] .h-help-layer { display: none; }
html[data-kiosk="1"] .h-app .pg-panel { inset: 0; width: auto; transform: none; border: 0; border-radius: 0; box-shadow: none; }

/* PT-SAFE N-E-31 (2026-10-08): a staff record the viewer may read but not change is one disabled fieldset — no frame of its own. */
.h-sa__fs { border: 0; margin: 0; padding: 0; min-width: 0; }
