Designer Brief · v1.0

Field Mobile App

This brief is private. Enter your details and the access password to continue. If you don't have one, ask for it directly.

Field · Built with clubs

Field Mobile — Designer Brief

Everything you need to design Field's mobile app in 4 weeks. Read this section once. Refer back to the rest as needed.

The vibe

Whoop × Strava, for racquet sports

Field is to athletic identity what Whoop is to recovery and Strava is to running. Calm, confident, data-dense. Closer to a sterile clinic than a playground. No mascots. No cartoon trophies. Numbers feel personal, not corporate.

What this is

The complete design brief for Field's native iOS/Android app — a sports platform for clubs across Portugal (expanding into Spain) that combines bookings, competitions, video, and athletic identity. You're designing the player-facing app. Not the club admin backoffice.

Engagement

ScopeP0 screen list — ~66 unique screens (see Section 6)
Duration4 weeks, fixed-price
DeliverableHi-fi Figma file with components, variants, dev mode handoff
ReviewsDaily async Loom + 2 live syncs per week (Mon + Thu)
Tech stackReact Native 0.83 + Expo SDK 55 + NativeWind + Expo Router + Firebase
iOS baselineiPhone 16 Pro — 402 × 874 logical pt (primary Figma frame). Validate small-screen edge at iPhone SE 375 × 667.
Android baseline360 × 800 dp standard. Validate up to 440 dp. Visual mirror of iOS — same components, OS-appropriate affordances (back gesture, system fonts fallback).

How to read this brief

  1. Section 2 (Vision) sets the emotional north star. Read once. Refer when stuck on tone.
  2. Section 3 (Personas) tells you who you're designing for. Reference per screen.
  3. Section 4 (Decisions) answers every "should we…" question. Don't ask, look here first.
  4. Sections 5–7 are the structural map: IA, screen list, flows.
  5. Section 8 (Screen Specs) is your daily reference — one page per P0 screen.
  6. Section 9 (Visual System) is the design foundation — tokens, type, components.
  7. Section 10 (Content) is the copy — every CTA, label, error message in English. Use this verbatim.
Rule of thumb: If you're inventing something that isn't in this brief, stop. Either it's already specified (look harder), or it's a decision that needs to be made (ask, get an answer within 24h, document it in Section 4).

Vision Brief

The emotional north star, what we're building toward, and what success feels like.

What Field is becoming

Field started as a booking tool for racquet sports clubs. It's becoming a sports platform — the place where players live their athletic life, not where they reserve a court for 90 minutes. Three product pillars carry the transformation:

  • Competition — Americanos, mixes, ladders, box leagues, brackets. Real format variety with a Glicko-based rating that actually means something.
  • Video — Clutch cameras at every Field club. Every match recorded. Highlights auto-cut in hours, shareable in one tap.
  • Identity — Athletic profiles, stats, rankings, achievements, rivalries. The player's level isn't a tag in a booking — it's their story.

Bookings remain the practical floor, but they don't define the product. A player who opens Field doesn't think "I need to reserve a court." They think "what's happening tonight, who's playing, what's my level looking like."

The vibe

Whoop × Strava, for racquet sports

Dark by default. Data-forward. Numbers feel personal, not corporate. The interface is calm and confident — closer to a sterile clinic than a playground. Whoop's genius: "your strain score is 14.2" isn't a spreadsheet, it's an identity statement. Strava's genius: seeing your friends' activity creates motivation and FOMO. Field combines both — your number, your friends' progress, the social pull that gets you back on court.

The five design principles

1. Identity over activity

The hero of every surface is you, not what's available. Home opens on "here's who you are this week" — your μ, your streak, your last match. Not a feed of bookings. Other booking apps open on "Find a match" because they're booking apps. Field opens on identity because Field is an athletic identity app.

2. Dark is the default, not an option

Dark isn't a setting toggle in v1. Dark is Field's identity. Light surfaces appear where they serve a purpose — discovery, booking flows, social feeds, account management. Dark dominates where it matters most — the Home identity hero, competition live screens, video, stats deep-dives, achievements. The mode follows the purpose of the surface, not the OS setting.

3. Data as personality

Numbers are not metrics. They're statements about who the player is. The Glicko μ rating, the 7-day streak, the win rate, the rally win %, the level delta — each one carries narrative weight. Oswald handles big athletic display readouts; Barlow tabular-nums handles inline numerics. A score row should feel like a verdict, not a spreadsheet cell.

4. Social proof as gravity

Friends' activity, kudos, leaderboards, "who's playing tonight at your club" — these create the motivational loop that drives retention. Strava's kudos loop is their #1 retention primitive. Field's equivalent is the feed of friend matches, competition wins, and badge unlocks. Make it visible. Make it tap-able.

5. Motion is meaningful, not decorative

Every animation answers a question. A bar fills → spots are filling up. A number ticks → this value just changed. A dot pulses → this estimate is still firming up. No bounce-into-place icons. No "delight" micro-animations on every tap. Motion is signal, not garnish.

The cold-start moment

The two seconds after a player taps the Field icon are the most important seconds in the product. The OS splash hands off → Field boot loader (dark, branded) → Home loads. On Home, the dark identity card is the first thing the eye lands on. It contains their sport label, their μ, their streak.

Get this moment right and Field feels like a sports app. Get it wrong and Field feels like a booking website with a dark theme. Everything else in the design system serves this moment.

What success looks like

A player opens Field at 18:47 on a Wednesday.

They see their μ — 3.8. They see their streak — 🔥 2-win. They see tonight's Americano at their club — 12/16 spots, starts in 13 minutes, three friends already in. They tap into the recap of their last match — Clutch highlight plays, 6-4 win against Pedro and João.

They tap Join. Pay €5 with MB WAY. Done in 30 seconds.

They put the phone down and go grab their racquet. That feeling — "this is my sports life" — is the design target.

Equally important: a player shows Field to a friend at the club. The friend says "this looks sick" — not "ok where do I book a court."

Native affordances Field should embrace

  • Haptics — Subtle taps on score entry, payment success, kudos, tab switching. Apple's selection and impact.light equivalents. Used as confirmation, never as decoration.
  • Push notifications — Designed surfaces, not raw text. Match reminders, results pending, waitlist spots, friend activity. Each one is a designed mini-screen with deep-link routing.
  • Native video — Clutch playback is native, not a web embed. Autoplay muted on load, tap to unmute, pinch to fullscreen. 16:9 aspect, scrubber, frame-stepping.
  • System share sheet — Highlight clips and match results share via OS share sheet (WhatsApp, Stories, Messages). One tap.
  • Biometric auth — Face ID / Touch ID / fingerprint to re-auth for payment confirmation.
Reference test: Every screen passes three checks. The Slicker test — would a user of any other racquet-booking app say "this is slicker than mine" within 3 seconds? The Strava test — does this feel like an athlete's app, not a booking app? The Whoop test — does this surface tell me something about me, or just show me data? If any test fails, the screen needs work.

What Field is NOT

Hard boundaries to keep the work focused:
  • Not a generic booking marketplace — no nested tabs that each try to do four jobs, no profile sprawl, no maze of nav depth.
  • Not Duolingo — no mascots, no cartoon trophies, no rainbow palette, no streak guilt-trips.
  • Not a fitness tracker — no clinical biometric chart porn, no heart rate dashboards, no "recovery scores."
  • Not a betting app — no shouty CTAs, no glowing buttons, no urgency animations everywhere.
  • Not a banking app — wallet exists but doesn't dominate; money is plumbing, not the point.
  • Not Strava replica — no GPS maps, no elevation charts, no kudos as the only social mechanic.

The one-line summary

Field is the operating system for sports clubs. The mobile app is how athletes carry that with them. Design it so they feel like athletes, not customers.

Personas + Jobs

Three players. Five jobs each. Reference per screen.

Tiago — Casual Player
~60% of base
Plays padel 1–2× a week with the same group of friends. Doesn't care obsessively about ranking. In it for the fun, the social, the drink after.
Age
28–42
Frequency
4–8 / mo
Level
2.5–4.0
Spend
€40–80 / mo
  1. Book a court Friday night with my regular group, in under 30 seconds.
  2. Find an open match this weekend when one of my friends bails.
  3. Split the court cost so I don't have to chase three people for €8.
  4. See who from my club is playing tonight — maybe join their match.
  5. Share tonight's match with the WhatsApp group in one tap.
Design implication: Booking, joining open matches, and split-pay must be ≤3 taps each. WhatsApp share is a primary CTA, not an afterthought. Identity stats matter less — show them, don't push them.
Ana — Competitive Climber
~25% of base
Plays 3–5× a week. Lives for tournaments, ladders, and her Glicko rating. Watches her last match's highlights the same night. Has rivals she tracks.
Age
22–38
Frequency
12–20 / mo
Level
3.8–5.5
Spend
€150–300 / mo
  1. Sign up for the next Americano at my level, fast, before it fills.
  2. Check my μ trend and where I rank vs. people I beat last week.
  3. Watch my last match's Clutch highlights — share the best clip on Instagram.
  4. See my head-to-head record against my rival before our next match.
  5. Challenge someone above me on the ladder with one tap.
Design implication: Home identity hero is built for her. μ, streak, last match, friends' feed — these are the surfaces she opens the app for. Competition flows must surface skill-level and seat-availability immediately. Video is a daily reflex, not a feature.
Pedro — Field Pass Tourist
~15% of base
Travels for work across Lisbon, Porto, Madrid, Barcelona. Plays at multiple clubs. Subscribes to Field Pass for the booking window edge. Transactional and time-poor.
Age
32–50
Frequency
6–12 / mo
Level
3.0–4.5
Spend
€100–200 / mo
  1. Find a good club in a city I'm visiting this week and book a slot tonight.
  2. Use my Field Pass advance window to grab the 19:00 slot before non-members.
  3. Pay across multiple clubs without re-entering my card details every time.
  4. Find an open match in a city where I don't know anyone.
  5. See my cashback balance and credits across all the clubs I've played at.
Design implication: Club discovery (location-based, multi-city) must work cleanly. Field Pass benefits must be visible inside the booking flow ("you're seeing this 3 days early because of Field Pass"). Wallet and cross-club payments are core, not buried in Settings.

Who Field is not designed for (v1)

  • Pure spectators — Field is for people who play, not people who only watch. Spectator features (live scoreboards as a destination, public match watching) are post-v1.
  • Children < 16 unsupervised — Junior academy use cases route through a parent account with child profile switcher. No standalone kids' UX.
  • Casual gym-goers — Field is racquet sports + football. Not yoga, not gym, not running. Stay focused.

Decisions Locked

Every product decision answered. Designer doesn't ask, designer looks here.

How to use this section: Before starting any screen, scan the decisions. Anything not listed here is either still open (flag it) or already specified in another section. Re-opening a locked decision requires explicit approval.
01
Launch platforms
iOS + Android, simultaneous launch
Designer ships both platforms in one engagement. Primary frame is iOS (iPhone 16 Pro, 402×874 pt). Android designed as a visual mirror with OS-appropriate affordances: back gesture, Material 3 system fonts as fallback, Android share sheet pattern. Component library must handle both safe-area inset systems.
⚠ Implication: adds ~20–25% design time vs. iOS-only. Factored into the 80-screen scope decision below.
02
Languages at launch
EN only
Single-language content sheet. All UI copy, push notifications, error messages, empty states, and marketing copy in English. PT-PT / ES translations deferred to post-launch i18n pass. Designer assumes EN for all design comps and prototypes.
⚠ Implication: existing PT user base will see English UI on launch. Consider in-app explainer or onboarding moment that signals "we're going international, translations coming soon."
03
Login + sign-up methods
Email + Apple + Google + Magic Link
Four auth pathways. Sign-up screen (A2) hosts all four as primary surface. Login screen (A3) mirrors. Magic Link is the passwordless fallback (email-only flow). Forgot Password (A4) and Email Verification (A5) standard. Biometric re-auth (Face ID / Touch ID / fingerprint) for sensitive actions like payment confirmation.
04
Field Pass paywall placement
3 contextual entries
Field Pass surfaces in exactly three places:
1. Home smart nudge — appears after the user completes 2+ bookings. Dismissible.
2. Greyed booking slot explainer (PB15) — modal shown when user taps a slot outside their window. Explains the +3 day benefit with upsell.
3. Account → Field Pass entry — permanent Account tab section, soft self-serve.
No paywall during onboarding. No interstitial mid-booking-flow. No homepage takeover. Subtle, non-pushy.
05
Onboarding length
5 steps
Sequence: O1 Sports (multi-select padel / tennis / football) → O2 Level (per-sport slider or 4-question quiz) → O3 Location + follow clubs (geolocation → nearby list) → O4 Notifications rationale (skippable, fires native prompt) → O5 Done (confetti, deep-link to Home). Target completion under 90 seconds. No Field Pass sell during onboarding.
06
Dark / light mode strategy
Per-surface, no toggle in v1
Dark dominates: Home identity hero, all competition LIVE screens, Watch video, stats deep-dives, achievements, onboarding step O4. Light dominates: discovery (Compete listing, Book listing), booking flows, social feeds, Account admin, settings. No user-facing toggle in v1. Mode follows surface purpose, not OS setting. Both modes must be designed for every component — even if a component only appears on one mode in v1, the dark/light variant must exist for v2.
07
Design scope (screen count)
~80 screens (full P0 + key P1)
Full P0 list (~66 screens) plus pulled-forward key P1 surfaces: Watch tab (W1–W4 highlights + library + match player), Social feed expanded (H5–H8), Friends / find friends (M13, M14), Achievements + head-to-head (M6, M7, M8). Skip: Wrapped (G5), padel-specific stats (W9), clip editor (W5) — these stay v1.1.
08
AutoActions in mobile design scope
No — admin-side only
AutoActions is configured by club managers in the backoffice. The system dispatches WhatsApp / email / internal alerts. The mobile app design has no AutoActions configuration UI. Player-facing residue is minimal and already covered: push notification templates (part of standard notification design), deep-link landing screens (standard P0 flows), and the Notification Center H9 (already in P0).
09
Player Intelligence module in mobile design
Yes — already in the Account tab
Player Intelligence surfaces are the existing Account-tab P0/P1 screens: M2 Full Stats (8 insight tiles), M3 Rankings (per-club + global), M4 Competition History, M5 Match History, M8 Head-to-Head Rivalry. No additional screens needed beyond the Account-tab inventory in Section 6. Strategy and PRDs inform the content of these screens, not new ones.
10
Device baseline
iPhone 16 Pro (402 × 874) + Android 360 × 800 dp
Primary Figma frame: iPhone 16 Pro logical 402 × 874 pt with current safe-area insets. Small-screen edge validated at iPhone SE 375 × 667. Android baseline 360 × 800 dp standard, validated up to 440 dp. Devs test on real devices, not Figma frames — design system must be responsive across this range, not pixel-fixed.
11
Color palette
Mint #2DD4A0 + true black
Primary mint #2DD4A0 with full 9-step tonal scale. Secondary pure black #000000 with full greyscale. Surfaces white + grey-100. Coral #F97316 reserved for slot-fill urgency on progress bars approaching capacity. Mint reads as confident sports-tech — Whoop / Robinhood territory, not generic SaaS. Document tones in Figma variables. Full tokens in Section 9.
12
Typography
Oswald (display) + Barlow (body)
Headlines and display numerics: Oswald 400/500/600/700 — condensed editorial grotesque, athletic-magazine feel. Body, labels, captions, inline numerics: Barlow 400/500/600/700 — humanist sans with slight slab character, highly readable. Both free on Google Fonts. Numerics in Barlow use font-feature-settings: 'tnum' for tabular alignment. Full type scale in Section 9.

Decisions still open (flag if blocking)

Nothing structural. If something comes up during design that isn't covered here or in Section 8, flag it — answers within 24 hours. Document the resolution back into this section.

Information Architecture

Four tabs. One job each. Strict depth rules.

The tab bar

Screen content
Home
🎾
Play
🎬
Watch
👤
Account
TabOne-sentence purposeDefault modeDeep-link root
HomeYour athletic identity, today's plan, recent match, social pulse.Light (with dark identity hero)field://home
PlayFind a match, find a partner, book a court, join academy.Light (discovery) · Dark (live competition)field://play
WatchFull match videos, auto-highlights feed, your clip library.Dark (video-first)field://watch
AccountProfile, stats deep-dives, wallet, Field Pass, memberships, settings.Lightfield://account
Why 4 tabs, not 5 or 3. Strava runs 5 (Home / Maps / Record / Groups / You). Most racquet-booking apps run 3 (Play / Community / Profile). Field splits the difference. Four keeps thumb reach comfortable while giving Watch the real estate it needs as Field's video differentiator. Academy doesn't earn a tab — it's a segmented filter in Play and a section in Account.

Persistent top-nav (every tab)

  • Left: user avatar → tap routes to Account
  • Right: bell (notifications) + chat icon (messages), each with unread badge
  • Center: contextual to tab (tab-specific title or filter chips)

Second-level navigation inside a tab

Tabs do not have their own nested tab bars. Inside any tab, structure is one of four patterns:

  1. Scrolling sections — Home is one long scroll, never a sub-tab. Sections appear in priority order.
  2. Segmented controls at top — used only where scope genuinely changes. The Play tab uses a 3-segment control:
Compete
Book
Academy

Sticky during scroll. Selection remembered across sessions. Default for first-time users: Compete (pushes the pillar).

  1. Modal flows — used for wizards: booking flow, sign-up for competition, academy enrollment. Full-screen modal, dismissible, with explicit step counter.
  2. Bottom sheets — used for secondary actions: filters, share, edit, confirm. Slide up from bottom, dismissible by drag-down.

Depth rules (non-negotiable)

No screen has more than two levels of nested navigation. The maximum depth chain:

Home
Section
Detail

Anything deeper is a design smell. If a flow requires deeper nesting, the IA is wrong — restructure rather than add depth.

Why Compete and Book share a tab (the booking-marketplace mistake)

Most booking apps split booking and competitions into separate tabs. Result: users must decide what kind of thing they're doing before they even know what's available. That's cognitive overhead.

In reality, a user wants to play Friday at 7pm. Sometimes that's a booked court with friends. Sometimes it's an Americano at their club. Sometimes it's a public match someone else is hosting. The Play tab treats "I want to play" as one intent. The segmented control scopes from there.

One canonical path per screen

No duplicate entry points. Every screen has one canonical reachable path. The Booking Window explainer is only reachable from a greyed slot — not from a menu item. The Field Pass paywall has exactly three entries (see Section 4, Decision 04). Avoid the multi-entry pattern of "you can get there 5 different ways" — it makes documentation, analytics, and IA all messy.

State-based layouts over duplicate screens

Competition-detail-LIVE is one screen with state-switched layouts, not six separate screens. The wrapper is identical; only the central "Now" section changes by format (Americano grid vs. Ladder card vs. Bracket vs. Round-robin standings). This pattern repeats across the app — prefer one screen with mode switches over multiple near-duplicates.

Reference test (Strava): "Does this navigation feel like an athlete's app, or like a SaaS booking marketplace?" If it feels like the latter, the IA needs to compress.

Screen List

~80 screens grouped by surface. Each with mode, priority, and acceptance criteria.

80
Total in scope
66
P0 — must ship
14
Key P1 — in scope
14
Surfaces

How to read this list

  • ID — Stable identifier, used in commits, messages, dev handoff. Don't rename.
  • ModeDark · Light · Mixed (one surface, both modes used inside it).
  • StatusP0 ship in v1. P1 key P1 pulled forward into this engagement per Decision 07.
  • Done means — One-line acceptance criteria. Designer ticks when delivered.

6.1 Splash · Auth · Onboarding · Permissions

14 screens · all P0
First-time and returning user entry. Sets visual tone for entire app.
IDScreenModeStatusDone means
S1Native OS splashDarkP0Native iOS/Android launch image with Field logo on ink background.
S2Field boot loaderDarkP0300ms–2s branded loader bridging OS splash to first screen.
S3Update / migration gateDarkP0Forced-update screen with single CTA to App Store / Play Store.
A1Welcome carouselMixedP04 swipeable slides (Compete · Watch · Track · Play) + sticky [Create account] / [Log in] footer.
A2Sign upLightP0Email + password form + Apple + Google + Magic Link + Terms checkbox. All 4 auth paths visible.
A3Log inLightP0Same 4 paths as A2 + Forgot Password link + lockout warning after 5 attempts.
A4Forgot passwordLightP0Email input → success state ("Check your email"). Error states for unknown email.
A5Email verificationLightP0Soft gate: can browse, blocked from book/enroll until verified. Resend CTA + "verified" success.
O1Onboarding — sportsLightP0Multi-select padel/tennis/football. ~10s to complete. Skip disabled.
O2Onboarding — levelLightP0Per-sport level slider OR 4-question quiz fallback. Numeric output (Glicko μ).
O3Onboarding — location + followLightP0Geolocation rationale → permission → nearby clubs list → multi-select follow.
O4Onboarding — notificationsDarkP0Rationale screen with Continue (fires native prompt) + Not now. Skippable.
O5Onboarding — doneLightP0Confetti moment + deep-link to Home. ~3s before auto-dismiss.
PR1Permission rationale (6 variants)DarkP0One template, six copy variants (Location, Push, Camera, Photos, Contacts, Calendar). Denied-state variant included.

6.2 Home — Identity dashboard

12 screens · 6 P0 + 6 P1
The anchor surface. Identity hero card + today's plan + last match + friends feed + recommendations.
IDScreenModeStatusDone means
H1Home dashboardMixedP0Dark identity hero card on light page. Today strip + Last Match + Friends (3 items) + Recommended (3 cards). Pull-to-refresh.
H2Identity card expandedDarkP0Full identity story: μ + confidence + 30-day line chart + matches block + edges narrative + partners + rival.
H3Today detailLightP0Today + tomorrow's events listed chronologically with deep-link entries to each.
H4Recent match (with Clutch)DarkP0Full-bleed video player + score row + highlights carousel + Clutch stats + social block + share.
H5Social feed expandedLightP1Full scrollable feed. Filter chips (All/Friends/Clubs/Comps). Infinite scroll. 7 feed item types.
H6Post detailLightP1Single feed item full view with all kudos, comments, replies.
H7Kudos listLightP1List of users who kudoed a match/post. Tap user → public profile.
H8Weekly summaryLightP17-day rollup (μ, matches, W/L, hours, partners). Shareable as story.
H9Notification centerLightP0Grouped by day. Swipe-to-dismiss. Category tabs (All / Activity / System).
H10Notification deep-link routerMixedP0Invisible interstitial handling notification taps. Edge-case messaging for stale/invalid deep links.
H11Recommendations see-allLightP1Full algorithmic rec list. Each card has reason-chip ("same club", "your level", "nearby").
H12Streak detailDarkP1Gamified streak story — why streak matters, how to keep it.

6.3 Play — Compete

17 screens · 14 P0 + 3 P1
Competition discovery, registration, live screens, match results, ladder challenges, find-partner.
IDScreenModeStatusDone means
PC1Compete discoveryLightP0My competitions (LIVE first) + Upcoming + Find partner entry + For you (3 algorithmic).
PC2Competition detail — registration openLightP0Hero + status chip + info rows + participants + rules + eligibility + sticky [Sign Up] CTA.
PC3Competition detail — LIVEDarkP0One screen, 5 state variants (Americano/Ladder/Box/Bracket/Round-robin). Tabs: Now/Standings/Matches/Info.
PC4Competition detail — completedDarkP0Winner card + final standings + your result + share.
PC5Registration — solo vs duoLightP0Two big cards. Solo → algorithmic match. Duo → next step PC6.
PC6Registration — invite partnerLightP0Search by name/phone/email. Pending state until partner accepts.
PC7Registration — paymentLightP0Individual-pay or organizer-pays. Wallet/Card/MB WAY/Multibanco. Reuses PB8 payment component.
PC8Registration — confirmationLightP0Summary + Add to calendar + Invite friends + Share.
PC9Match result — simpleDarkP0Americano-style. Two totals. ≤10s input. Team A → Team B → Submit.
PC10Match result — set-by-setDarkP0Bracket-style. Three set inputs per team + super-tiebreak toggle.
PC11Result confirmation / disputeDarkP0Counterparty confirms. Dispute path: reason picker + free text → club admin.
PC12Ladder challengeDarkP0Pick opponent → suggest 3 date windows → optional note → send. Push to opponent with 3-button response.
PC13QR check-inLightP0Camera full-screen. Haptic on scan. Success card + manual-code fallback.
PC14Initial level assessmentLightP0Same as O2. Standalone entry from Compete tab for users skipping onboarding's level step.
PC15Find partner — boardLightP1Filter chips + list of partner-request cards + Message / Pair-up CTAs.
PC16Find partner — post requestLightP1Form: sport, level range, date window, clubs, note → Post.
PC17Competition recap modalDarkP1Post-event auto-modal: your finish + μ change + share CTA.

6.4 Play — Book (slot-first, match-first)

14 screens · all P0
Open Matches feed is the default surface. Hosting forks into Public vs Private. Club detail is secondary.
IDScreenModeStatusDone means
PB1Book home — Open matches + Host CTALightP0Top: [+ Host a match] CTA. My bookings strip if any. Open Matches Near You list (My level / All sub-segment).
PB2Open matches — full listLightP0Sticky filter row (Sport/Level/Time/Club/Distance) + sort toggle + infinite scroll.
PB3Open match detailLightP0Match info + level gate (qualifies/outside range) + players (3/4) + your share + [Join match] CTA.
PB4Join-match checkoutLightP0Summary + payment method + Field Pass line + [Pay €X] CTA. Single screen.
PB5Host a match — Public vs PrivateLightP0Two big cards. Fork happens at step 1, not deep in flow.
PB6Host — club + time + court + sportLightP0Merged 4-in-1 vertical-stack screen. Each block collapses to summary row when chosen. Embeds Booking Window.
PB7Host setup (Public/Private variant)LightP0State-variant. Public: level slider + auto-approve. Private: invite friends + per-seat split row.
PB8Host checkoutLightP0Pay organizer share or full court. Field Pass benefit line. Method picker.
PB9Booking confirmation (Public/Private)LightP0Success state with summary + invite/share CTAs + add to calendar.
PB10Club detail (secondary path)LightP0Club info + courts + open matches at this club + members + competitions hosted.
PB11My bookingsLightP0Tabs: Upcoming / Past / Cancelled. Sort newest first.
PB12Booking detail (Public/Private)LightP0Variant by visibility. Inline split-payment status row (4 circles paid/pending).
PB13Cancel + refund previewLightP0Confirm modal with refund amount + policy explanation + final CTA.
PB15Booking window explainerLightP0Modal triggered by tapping a "Member only" or "Beyond window" slot. Field Pass upsell. No mid-flow paywall route.

6.5 Play — Academy (key flows only)

6 of 10 screens · selected P1
Discovery + enrollment + ongoing-student surfaces. Coach approval, child profiles, and insurance fee defer to v1.1.
IDScreenModeStatusDone means
PA1Academy discoveryLightP1Play tab segment. Program cards by sport + level + age group.
PA2Program detailLightP1Hero + coach + schedule + price + spots + level fit + [Enroll] CTA.
PA3Enrollment — player details + child switcherLightP1Player or child selection + contact + medical disclaimer.
PA4Enrollment — schedule + planLightP1Schedule confirm + plan picker (monthly/quarterly/annual).
PA6My academy — overviewLightP1Active program + next session + attendance summary + plan status.
PA8Payments / planLightP1Plan terms + auto-renew toggle + change plan CTA + payment history.

6.6 Watch — Video + Highlights

7 screens · pulled forward to P1 per Decision 07
Clutch playback, vertical highlights feed, library, match player, share. Clip editor (W5) and padel-specific stats (W9) defer.
IDScreenModeStatusDone means
W1Watch home — your feedDarkP1Vertical feed of latest match highlights (yours + friends'). Tap → W4 viewer.
W2My libraryDarkP1All your videos chronologically. Filter by sport / club / date.
W3Match player (full match)DarkP1Full match with scrubber, frame-step, score-mark jumps. Pinch fullscreen.
W4Highlights viewer (vertical swipe)DarkP1TikTok-style vertical swipe per clip. Auto-advance to next clip.
W6Share sheetDarkP19:16 preview card with clip + score + avatar. iOS/Android share sheet trigger.
W7Club Clutch feedDarkP1Embedded in Club Detail (PB10). Latest highlights from this club.
W8Match stats screenDarkP1Clutch data native: rally win %, avg rally length, smash success, court coverage. Per-match.

6.7 Account — Profile / Identity

14 screens · 5 P0 + 9 P1
Account tab covers identity deep-dives, stats, achievements, friends. Child profiles defer to v1.1.
IDScreenModeStatusDone means
M1Account overviewLightP0Avatar + name + level chip + sections: Profile, Wallet, Field Pass, Memberships, Settings. Single scroll.
M2Full stats (Insights, 8 tiles)DarkP1Whoop-style insight tiles: win rate, streak, level trend, peak μ, hours, partners, edges, rival.
M3Rankings (per club + global)DarkP0Toggleable scope (your club / your sport / global). Position + delta + rivals near you.
M4Competition historyLightP0Chronological list of all competitions entered + final placement + μ change.
M5Match historyLightP1All matches: date, opponents, score, μ delta. Filter by sport / club / outcome.
M6Achievements gridLightP1Grid of earned + locked badges. Geometric abstract icons, no cartoon trophies.
M7Achievement detailDarkP1Single achievement story: criteria, when earned, who else has it, share CTA.
M8Head-to-head rivalryDarkP1Opponent profile + W-L record + last 5 matches + rivalry intensity score.
M9Public profile (other player)MixedP1Light page + dark stats card. Their μ, achievements, recent matches. Follow / challenge CTAs.
M10Edit profileLightP0Form: name, email, phone, avatar, level (locked if assessed), favourite sport, bio.
M12Followed clubsLightP0List of clubs you follow. Tap → PB10 club detail. Unfollow swipe action.
M13Friends / followersLightP1Tabs: Friends / Followers / Following. Tap user → M9 public profile.
M14Find friendsLightP1Contacts permission rationale + matched users + search + invite via WhatsApp.
M15My feed postsLightP1Your public activity timeline. Edit / delete actions per post.

6.8 Account — Wallet

5 screens · all P0
Cross-club wallet balance, credits, transactions, embedded in checkout.
IDScreenModeStatusDone means
MW1Wallet homeLightP0Total balance + per-club breakdown + recent transactions + top-up CTA.
MW2Transaction historyLightP0Chronological list. Filter by club, type (booking/refund/cashback), date range.
MW3Credit detailLightP0Single credit: source, amount, expiry, terms.
MW4Expiration warning modalLightP0Triggered when credits expire in <14 days. "Use it or lose it" CTA → discover.
MW5Wallet-in-checkoutLightP0Embedded component (not standalone screen). Apply wallet balance toggle + remaining-to-pay.

6.9 Account — Field Pass

5 screens · pulled forward P1
Field Pass paywall, plan selection, active benefits, manage, cashback history.
IDScreenModeStatusDone means
MF1PaywallDarkP1Hero benefit + 3 key features + price + [Start free month] CTA. No dark patterns.
MF2Plan selectDarkP1Monthly / Annual / cancel anytime. Trial info. Clear cancellation policy.
MF3Active benefits dashboardDarkP1Subscribed-state Home. Cashback YTD + booking window + status badge.
MF4ManageLightP1Pause, cancel, change plan, billing. Apple/Google subscription deep-link.
MF5Cashback historyLightP1List of cashback events. Total YTD + per-club breakdown.

6.10 Account — Memberships

4 screens · pulled forward P1
Club memberships (distinct from Field Pass — each membership is club-specific).
IDScreenModeStatusDone means
MM1Membership offer (inline)LightP1Component shown inside Club Detail (PB10). Member benefits + price + CTA.
MM2EnrollmentLightP1Member form + auto-renew + payment + terms.
MM3My memberships listLightP1All active memberships across clubs. Status, renewal date, manage CTA.
MM4Membership detailLightP1Single membership: benefits, terms, renewal, cancel, history.

6.11 Account — Payments

3 screens · all P0
Stored payment methods. SIBS card + MB WAY are the main rails for Portugal.
IDScreenModeStatusDone means
MP1Payment methods listLightP0Cards + MB WAY + Multibanco history. Set default. Swipe delete.
MP2Add card (SIBS)LightP0Card form (number, expiry, CVC) + SIBS validation + 3DS challenge.
MP3Add MB WAYLightP0Phone number form + MB WAY app verification flow.

6.12 Account — Settings / Legal

9 screens · all P0 (3 deferred to P1)
Account management, legal, help. Notification matrix and Privacy hub move to P1. App appearance is post-v1.
IDScreenModeStatusDone means
MS1Settings homeLightP0List of sections: Account, Notifications, Privacy, Language, Data, Help, Legal.
MS2Account (email/phone/password)LightP0Change email + phone + password. Each action requires re-auth.
MS5Language & regionLightP0Language picker (EN only at launch, structure for PT/ES). Region: timezone, currency.
MS7Data & storage + delete accountLightP0Cache mgmt + download my data + delete account (with confirmation friction).
MS8Help & supportLightP0FAQs + contact form + email support + version info.
MS9Terms of ServiceLightP0Full ToS rendered in-app. Scrollable. Last-updated date.
MS10Privacy PolicyLightP0Full Privacy Policy. Scrollable. Last-updated date.
MS11Cookie / tracking prefsLightP0Toggle analytics, ad tracking, third-party SDK. GDPR-compliant default off.
MS12LicensesLightP0Open-source library acknowledgments. Auto-generated list.

6.13 Split Payment

1 screen · P0
Consolidated to a single surface. Setup happens inline on PB7; status inline on PB12.
IDScreenModeStatusDone means
SP1Pay-my-shareLightP0Single screen shown to invited player from push/chat link. Cash-at-club toggle. Payment method picker.

6.14 Global — Messaging, Engagement, Errors

9 screens · 4 P0 + 5 P1
Cross-app surfaces: chat, recaps, share, error pages, offline banner, maintenance.
IDScreenModeStatusDone means
G1Conversation listLightP1Threads with users / groups. Unread badges. Search.
G2Chat screen (1:1 + group)LightP1Message bubbles + typing indicator + match invitations as inline cards.
G3New chat composerLightP1Recipient search + multi-select for group. First message field.
G4Competition recap (modal)DarkP1Post-event auto-trigger: your placement + clip + share.
G6Achievement share sheetDarkP19:16 story card + iOS/Android share trigger.
G7Offline banner (reused)MixedP0Persistent top banner: "Offline. Showing last seen data." Auto-dismisses on reconnect.
G8Empty state (template)MixedP0Centered line icon + copy + primary CTA. Used across the app (Section 9 component).
G9Generic errorMixedP0Friendly error + retry CTA + report-bug link. Never dead-end.
G11Server maintenanceLightP0Maintenance page with ETA + status page link. Cannot bypass.

Final tally

Splash/Auth/Onboarding 14 · Home 12 · Compete 17 · Book 14 · Academy 6 · Watch 7 · Profile 14 · Wallet 5 · Field Pass 5 · Memberships 4 · Payments 3 · Settings 9 · Split Payment 1 · Global 9 = 120 unique items in scope, ~80 of which are unique designed screens (remaining are state variants of single canonical screens, reusable components, and inline modals — PR1 alone is 6 variants of one template).

Designer's daily ritual: Open this section. Filter by surface. Pick the next P0. Open the matching screen spec (Section 8). Design it. Mark it shipped via Figma comment. Repeat.

User Flows

Thirteen critical journeys. Internalize these before designing any screen — they're how the screen list connects.

How to read these

  • Rectangles = screens, labelled with their ID from Section 6 (e.g., PB1, H4).
  • Diamonds = decision points or eligibility gates.
  • Rounded shapes = events, actions, or system triggers (push notifications, payment success, etc.).
  • Every flow ends at a stable terminal state — confirmation, a deep-linked destination, or a feed update.

Flow 1 — Onboarding (first-time user)

Screens: 14 (Splash + Auth + Onboarding) Target time: <90 seconds Drop-off risk: O2 (level), O3 (location prompt)
flowchart TD Start([App install / first launch]) --> S1[S1 OS Splash] S1 --> S2[S2 Field boot loader] S2 --> A1[A1 Welcome carousel] A1 --> Choice{New or existing?} Choice -->|New| A2[A2 Sign up] Choice -->|Existing| A3[A3 Log in] A2 --> A5[A5 Verify email — soft gate] A5 --> O1[O1 Pick sports — multi-select] O1 --> O2[O2 Set level — slider or quiz] O2 --> O3[O3 Location + follow clubs] O3 --> O4[O4 Notifications rationale] O4 --> NativePerm{Native push prompt} NativePerm -->|Allow| O5 NativePerm -->|Skip| O5 O5[O5 Done — confetti] --> H1[H1 Home dashboard] A3 --> H1

Flow 2 — Host a public match

Screens: 7 Target time: <2 minutes Critical moment: PB5 fork is step 1, not deep in flow
flowchart TD Start([Intent: I want to host]) --> PB1[PB1 Book home] PB1 --> HostCTA([Tap + Host a match]) HostCTA --> PB5{PB5 Public or Private?} PB5 -->|Public| PB6[PB6 Sport / Club / Time / Court — merged 4-in-1] PB5 -->|Private| PB6 PB6 --> PB7P[PB7 Host setup — level range + auto-approve + per-seat split] PB7P -->|Public variant| PB8[PB8 Host checkout] PB6 --> PB7V[PB7 Host setup — invite friends + per-seat split] PB7V -->|Private variant| PB8 PB8 --> PaymentH{Payment success?} PaymentH -->|Yes| PB9[PB9 Confirmation] PaymentH -->|No| PB8 PB9 -->|Public| Feed([Match visible in Open Matches feed]) PB9 -->|Private| Invites([Invited friends get push + chat DM]) Feed --> Joiners([Other players can join via PB3]) Invites --> SeatFill([Seats fill as friends pay via SP1])

Flow 3 — Join an open match

Screens: 4 Target time: <30 seconds Multi-entry: 3 valid entry points converge on PB3
flowchart TD EntryA([Home: 'Open matches near you' card]) --> PB3 EntryB([Push: 'New match at your club']) --> PB3 EntryC([Play / Book tab]) --> PB1[PB1 Book home] PB1 --> PB2[PB2 Open matches list — filters + sort] PB2 --> PB3[PB3 Open match detail] PB3 --> LevelGate{Level qualifies?} LevelGate -->|Yes, auto-approve| PB4[PB4 Join checkout] LevelGate -->|Outside range| Request([Sends request to host]) Request --> HostDecision{Host approves?} HostDecision -->|Yes| PB4 HostDecision -->|No| Decline([Push: 'Host declined — try another']) PB4 --> PaymentJ{Payment success?} PaymentJ -->|Yes| PB9V[PB9 Confirmation — 'You joined Ana's match'] PaymentJ -->|No| PB4 PB9V --> Chat([Auto-joined to match chat thread])

Flow 4 — Enter a competition (full lifecycle)

Screens: 11 Spans multiple sessions: registration → event day → result Critical: result entry never leaves PC3 — modal overlay
flowchart TD Start([Intent: I want to compete]) --> PC1[PC1 Compete discovery] PC1 --> PC2[PC2 Competition detail — registration open] PC2 --> Eligible{Eligibility — level, club, Field Pass?} Eligible -->|No| Locked([Reason shown — adjust or leave]) Eligible -->|Yes| PC5{PC5 Solo or Duo?} PC5 -->|Solo| PC7[PC7 Payment] PC5 -->|Duo| PC6[PC6 Invite partner] PC6 --> PartnerAccepts{Partner accepts?} PartnerAccepts -->|Yes| PC7 PartnerAccepts -->|Pending| Wait1([Awaiting partner — visible on PC2]) PC7 --> PC8[PC8 Confirmation + Add to calendar] PC8 --> Wait2([Wait for event day]) Wait2 --> PC13[PC13 QR check-in at venue] PC13 --> PC3[PC3 LIVE — Now / Standings / Matches / Info] PC3 --> Play([Play match]) Play --> Result{Result entry} Result -->|Simple| PC9[PC9 Match result simple] Result -->|Set-by-set| PC10[PC10 Match result set-by-set] PC9 --> PC11{PC11 Counterparty confirms?} PC10 --> PC11 PC11 -->|Confirms| Update([μ updates, standings refresh]) PC11 -->|Disputes| Admin([Routed to club admin]) Update --> MoreRounds{More rounds?} MoreRounds -->|Yes| PC3 MoreRounds -->|No| PC4[PC4 Completed — final standings] PC4 --> Share([Share result → G6])

Flow 5 — Watch last match

Screens: 5 Target time-to-video: <3 taps Hero moment: autoplay on H4 entry
flowchart TD EntryA([Push: 'Your highlights are ready']) --> H4 EntryB([Home — Last Match card]) --> H4 EntryC([Watch tab]) --> W1[W1 Watch home — your feed] W1 --> H4[H4 Recent match detail] H4 --> Video([Autoplay muted on load]) Video --> Interact{User intent} Interact -->|Tap| Unmute([Unmute — audio on]) Interact -->|Pinch| FullScreen([Full-screen player]) Interact -->|Scrub| ScoreJump([Tap score row to jump]) H4 --> HighlightsRow[Highlights carousel — 5–10 clips] HighlightsRow --> W4[W4 Highlights viewer — vertical swipe] H4 --> StatsRow[Clutch stats: rally %, smash %, coverage] StatsRow --> W8[W8 Full match stats] H4 --> SocialRow[Kudos / comments] H4 --> ShareCTA([Share highlight]) ShareCTA --> ShareSheet([OS share sheet: WhatsApp, Stories, Messages])

Flow 6 — Book a court

Screens: 4–5 (depending on split or not) Target time: <30 seconds for the default path Default path: Pick court → pay it all → done. Split is an optional branch.
flowchart TD Start([Intent: I want a court at 19:00]) --> PB1[PB1 Book home] PB1 --> CTA([Tap Book a court]) CTA --> PB6[PB6 Sport / Club / Time / Court — 4-in-1 picker] PB6 --> Review[Review: Court 3, Padel Club Porto, Fri 19:00–20:00, €32] Review --> PayChoice{How to pay?} PayChoice -->|Pay it all myself — default| PB8Full[PB8 Pay full €32] PayChoice -->|Split with friends| PB7[PB7 Add seats + per-seat split row] PB8Full --> PayCheck{Payment success?} PayCheck -->|Yes| PB9[PB9 Booking confirmation] PayCheck -->|No| PB8Full PB9 --> Done([Visible in PB11. Calendar reminder. Optionally invite friends later.]) PB7 --> PB8Split[PB8 Pay your share] PB8Split --> PaySplit{Payment success?} PaySplit -->|Yes| PB9S[PB9 Confirmation — invites sent] PaySplit -->|No| PB8Split PB9S --> SP1[SP1 Each invitee pays their share] SP1 --> SettleLoop([Status reflected live in PB12]) SettleLoop --> Done
Why this is simpler than Flow 2: Hosting a public match (Flow 2) publishes to the feed and uses level-range matching. Booking a court is just reserving a slot. Pay-all-myself is the default — split is optional, opt-in. The PB7 Private variant only appears if the user chooses to split.
IA note: This flow has a primary "Book a court" CTA on PB1. The PB1 layout supports it alongside the secondary "+ Host a match" entry — Book is the default action, Host is the publish-to-feed variant.

Flow 7 — Join an Academy program

Screens: 6 + ongoing-student return Variants: Single class · Clinic · Course Key fork: PA2 type drives PA3 / PA4 scope
flowchart TD Start([Intent: I want lessons]) --> Play[Play tab] Play --> AcademySeg([Switch to Academy segment]) AcademySeg --> PA1[PA1 Academy discovery] PA1 --> Filter([Filter: sport / level / age group / type]) Filter --> PA2[PA2 Program detail] PA2 --> Type{Program type?} Type -->|Single class — drop-in| PA3S[PA3 Enrollment — self or child + medical disclaimer] Type -->|Clinic — 2–4 sessions| PA3C[PA3 Enrollment — self or child + medical disclaimer] Type -->|Course — multi-week recurring| PA3O[PA3 Enrollment — self or child + medical disclaimer] PA3S --> PA4S[PA4 Confirm single session date + €X price] PA3C --> PA4C[PA4 Pick clinic days + €X total] PA3O --> PA4O[PA4 Pick weekly schedule + plan: monthly / quarterly / annual] PA4S --> Pay[PB8 component — pay one-time] PA4C --> Pay PA4O --> PayR[PB8 component — pay first month + auto-renew] Pay --> Confirm[Enrollment confirmation] PayR --> Confirm Confirm --> PA6[PA6 My Academy overview] PA6 --> Reminders([Auto-reminders: 24h + 2h before each session]) PA6 --> OngoingType{Program type?} OngoingType -->|Single class| Done([Done after the class]) OngoingType -->|Clinic| ClinicEnd([Done after final session]) OngoingType -->|Course| PA8[PA8 Payments / plan — recurring billing visible] PA8 --> Renewal{Auto-renew?} Renewal -->|On| NextCycle([Next monthly charge, no action needed]) Renewal -->|Off| EndsAt([Plan ends at current period — confirmation])
Designer note for the 3 variants: PA2, PA3, and PA4 are the same screens for all three types — but PA2's program metadata changes (single session vs. clinic dates vs. recurring schedule), PA4's plan picker changes (one-time vs. recurring), and PA6's overview changes (one event vs. ongoing). State variants, not separate screens. Reuse the same components with different content.

Flow 8 — Subscribe to Field Pass

Screens: 4 + IAP Entry points: 3 contextual (per Decision 04) Monetization-critical
flowchart TD Entry1([Home smart nudge — after 2+ bookings]) --> MF1 Entry2([PB15 explainer — tapped 'Beyond window' slot]) --> MF1 Entry3([Account → Field Pass row]) --> MF1 MF1[MF1 Paywall — dark, 3 key benefits, price] --> Sold{Interested?} Sold -->|Dismiss| Dropped([Logged for re-marketing — no aggressive retry]) Sold -->|Yes| MF2[MF2 Plan select — Monthly / Annual] MF2 --> Trial{Trial eligible?} Trial -->|Yes — first time| FreeMonth[Start free month CTA] Trial -->|No — trial used| PaidStart[Subscribe €X/month or €Y/year] FreeMonth --> StoreKit[Apple App Store / Google Play Billing] PaidStart --> StoreKit StoreKit --> Verify{Subscription confirmed?} Verify -->|Yes| Activate[Benefits applied: +3d window, cashback, no fees] Verify -->|Failed| MF2 Activate --> MF3[MF3 Active benefits dashboard] MF3 --> Push([Welcome push + email with onboarding tips])

Flow 9 — Cancel a booking + refund

Screens: 3 Refund variants: Full / Partial / None — driven by timing Universal edge case — every user hits this
flowchart TD Start([Need to cancel]) --> PB11[PB11 My bookings] PB11 --> PB12[PB12 Booking detail] PB12 --> CancelTap([Tap Cancel booking]) CancelTap --> PB13[PB13 Cancel + refund preview] PB13 --> Timing{Cancellation timing vs club policy} Timing -->|>24h before — free window| FullRefund[Full refund to wallet + payment method] Timing -->|2h–24h — partial| PartialRefund[Partial refund — % per club policy] Timing -->|<2h — no refund| NoRefund[No refund — booking still cancelled] FullRefund --> ConfirmStep{Final confirm?} PartialRefund --> ConfirmStep NoRefund --> ConfirmStep ConfirmStep -->|No| PB12 ConfirmStep -->|Yes| Process[Process refund + release seats] Process --> SplitCheck{Other paid co-payers?} SplitCheck -->|Yes| RefundAll([Refund each co-payer + push notify each]) SplitCheck -->|No| SoloRefund([Refund only you]) RefundAll --> Done([Booking cancelled. Refund in MW2 within 5 business days.]) SoloRefund --> Done

Flow 10 — Join a club membership

Screens: 4 Entry: Club Detail PB10 (only) Per-club, recurring billing
flowchart TD Start([Want member benefits at this club]) --> PB10[PB10 Club detail] PB10 --> MM1[MM1 Membership offer — inline component] MM1 --> SeeBenefits([Member booking window, discount %, exclusive access]) SeeBenefits --> Decide{Enroll?} Decide -->|Not now| PB10 Decide -->|Yes| MM2[MM2 Enrollment form — contact + emergency + auto-renew + terms] MM2 --> Pay[PB8 component — enrollment fee + first period] Pay --> PayCheck{Payment success?} PayCheck -->|Yes| Active[MM4 Membership active] PayCheck -->|No| MM2 Active --> Unlock([Member-only booking window unlocks immediately]) Unlock --> PB10v[PB10 now shows Member badge + discount in checkout] PB10v --> RenewalSet{Auto-renew on?} RenewalSet -->|Yes| AutoCharge([Charged at end of period. Push reminder T-7d.]) RenewalSet -->|No| ExpiryPush([Push at T-30d: 'Renew or lose member benefits'])

Flow 11 — Receive + respond to a ladder challenge

Screens: 2 + auto-booking Multi-actor async loop Persona: Ana — Competitive Climber
flowchart TD Trigger([Challenger uses PC12 to send challenge]) --> Push([Push: 'Tiago challenged you for Friday']) Push --> Entry{Tap notification?} Entry -->|Yes — direct| ChallengeView[Challenge detail — 3 proposed windows + note] Entry -->|Later — open app| H9[H9 Notification Center] H9 --> ChallengeView ChallengeView --> Decision{Pick response} Decision -->|Accept window A| AcceptA[Accept Friday 18:00] Decision -->|Accept window B| AcceptB[Accept Saturday 10:00] Decision -->|Accept window C| AcceptC[Accept Sunday 16:00] Decision -->|None work| Counter[Propose alternative window] Decision -->|Decline| DeclineFlow[Decline + optional reason] AcceptA --> AutoBook[Auto-create booking at chosen window] AcceptB --> AutoBook AcceptC --> AutoBook AutoBook --> SplitDefault[Default 50/50 split — both pay via SP1] SplitDefault --> Confirmed([PB12 booking detail visible to both players]) Counter --> CounterPush([Push to challenger: 'Pedro proposed different window']) CounterPush --> Loop{Challenger accepts counter?} Loop -->|Yes| AutoBook Loop -->|No| Expired([Challenge expires after 48h — both notified]) DeclineFlow --> NotifyChallenger([Challenger notified: declined + reason if shared])

Flow 12 — Find friends + invite to Field

Screens: 2–3 + permission rationale Growth flow Reward: Optional invitee-played-1-match credit
flowchart TD Start([Want to find people I know]) --> Entry{Entry point} Entry -->|Account → Find friends| M14 Entry -->|Empty social feed CTA| M14 Entry -->|Recommended user| M14 M14[M14 Find friends] --> Granted{Contacts permission?} Granted -->|Not yet| PR1[PR1 Permission rationale — Contacts variant] PR1 --> Native{Native dialog} Native -->|Allow| Match[Match contacts vs. Field users] Native -->|Deny| ManualOnly[Manual search only] Granted -->|Yes| Match Match --> Display[3 groups: On Field / Invited / Not on Field] Display --> Action{User action} Action -->|Tap user on Field| Follow[Follow / friend request → M13] Action -->|Tap user not on Field| WAInvite[Open WhatsApp share — pre-filled link] Action -->|Search manually| SearchRes[Search by name / username / phone] WAInvite --> Sent[Send WhatsApp invite] Sent --> Track([Logged + reward credited if invitee signs up + plays 1 match]) SearchRes --> Action Follow --> Connected([Friend appears in M13])

Flow 13 — Dispute a match result

Screens: 2 + admin queue (out of mobile scope) High-stakes edge case Default: Confirm (μ updates) · Dispute opens reason picker
flowchart TD Start([Opponent entered result you disagree with]) --> PC11[PC11 Result confirmation prompt] PC11 --> View[See: opponent's submitted score] View --> Choice{Action} Choice -->|Score is correct| Confirm[Confirm — μ updates instantly] Choice -->|Score is wrong| DisputeTap[Tap Dispute] DisputeTap --> Reason{Pick dispute reason} Reason -->|Wrong score| ScoreFix[Submit your correct score] Reason -->|Wrong opponent| OppFix[Flag wrong opponent assigned] Reason -->|Didn't play| NoShow[Flag no-show / forfeit] ScoreFix --> Queue[Routed to club admin queue — backoffice] OppFix --> Queue NoShow --> Queue Queue --> AdminReview([Admin sees both submissions + dispute reason]) AdminReview --> Verdict{Admin verdict} Verdict -->|Side A wins| ResolveA[Admin sets official result] Verdict -->|Side B wins| ResolveB[Admin sets official result] Verdict -->|Cannot resolve| Replay([Schedule replay or void match]) ResolveA --> Notify([Both players notified — μ updates / corrects]) ResolveB --> Notify Replay --> Notify Notify --> Resolved([Match status: Resolved in PC3 / M5])

What's not diagrammed here

These thirteen flows cover the highest-traffic and highest-stakes journeys. Smaller flows (top up wallet, edit profile, switch language, forgot password, leave a competition mid-event, switch child profile) live in Section 8 as part of each screen's spec — they're single screens or 2–3 step linear paths that don't need a diagram. If you need an end-to-end view of a less-common flow, ask and we'll add it to this section.

Designer's check before designing any screen: trace it back to one of these five flows. Which flow does it belong to? What screen comes before it? What screen comes after? If you can't place a screen in a flow, ask before designing — the screen may not need to exist.

Screen Specs

Per-screen design briefs. Two tiers: 15 anchor screens get full deep-dives. The rest get compact specs.

How to use this section

  • Anchor screens (15) set the visual tone. Read these carefully first. If you nail these, the rest follow naturally.
  • Compact specs cover the remaining ~65 screens grouped by surface. Reference daily as you design.
  • Every spec has Acceptance criteria — Figma frame is "done" only when these are met. Include in your handoff checklist.

Anchor screens — jump to

Anchor deep-dives

H1 Home dashboard P0
The anchor screen of the entire app. Answers "who am I as an athlete right now, and what's next?" in under 2 seconds of scroll. Dark identity hero card on a light page is Field's signature contrast.
Layout
┌──────────────────────────────┐ │ [Avatar] Good evening, 🔔💬│ 56pt top nav │ {firstName} │ ├──────────────────────────────┤ │ ████ IDENTITY CARD ███████ │ dark hero (16:9) │ ██ ██ │ μ 3.8 · 7-day dots │ ██ PADEL ██ │ +0.3 this week │ ██ 3.8 ●●● ██ │ 🔥 2-win streak │ ██ +0.3 this week ██ │ [See full story →] │ ██ ● ● ● ● ● ● ○ ██ │ │ ██ 3W 1L · 🔥 2 streak ██ │ │ █████████████████████████ │ ├──────────────────────────────┤ │ TODAY │ next 48h events │ ┌── upcoming card ────┐ │ competition / booking │ └────────────────────┘ │ ├──────────────────────────────┤ │ LAST MATCH 🎬 │ Clutch thumbnail │ ┌── video card ─────┐ │ score + W/L + μ delta │ └──────────────────┘ │ [Watch highlights →] ├──────────────────────────────┤ │ FRIENDS │ 3 feed items + see all ├──────────────────────────────┤ │ RECOMMENDED │ 3 horizontal cards └──────────────────────────────┘
Sections in order
  1. Top nav (56pt): avatar left, greeting center-left, bell + chat right with unread badges.
  2. Identity card (dark, full-bleed, 16:9 ratio): sport label, μ in Oswald 48pt, 3-dot confidence row, delta line ("+0.3 this week" green / "-0.1" amber), 7-day match dots (W/L/rest), week count, streak emoji + label, [See full story →] CTA. Multi-sport users get horizontal swipe between sport cards.
  3. Today strip: 1–3 upcoming items within 48h (competition + booking + academy auto-merged chronologically). Empty state: "Nothing on your plate. Find a match →".
  4. Last Match: Clutch thumbnail with play overlay, score row, μ delta, win indicator. Processing state if <3h ago: "Highlights coming in ~2h".
  5. Friends feed: 3 inline items, [See all →] to H5. Feed item types: friend won comp, friend earned badge, friend played a match with clip, friend joined club, friend challenged you.
  6. Recommended: 3 horizontal cards, each reason-chip tagged ("Same club", "Your level", "Nearby").
States
  • Cold (new user, no matches): Identity card shows "Build your identity — play your first match" + CTA.
  • Mid-cold (1–3 matches): "Early days — we're still learning your level" message; confidence σ shown as dot pulse.
  • Warm (4+ matches): Full hero as shown.
  • Loading: skeleton shimmer respecting card layouts.
  • Offline: Top banner "Offline. Showing last seen data." Feed hides Kudos actions.
  • Error per section: inline retry, never blocks whole screen.
Data
μ rating + 7-day match outcomes + week W/L + streak + delta + sport list · Today events (competitions, bookings, academy within 48h) · Last completed match with Clutch payload · Friend activity feed (3 latest items) · Algorithmic recommendations (3 reason-tagged). All fetched in parallel.
Interactions
  • Tap identity card → H2 expanded story.
  • Swipe left/right on identity card → next sport (multi-sport users only).
  • Tap Today item → relevant detail (PC2 / PB12 / PA6).
  • Tap Last Match card → H4 recent match detail.
  • Tap feed item → H6 post detail. Tap Kudos → toggle. Tap Comment → focused composer.
  • Tap Recommended card → PC2.
  • Pull-to-refresh → re-fetch all sections in parallel.
Done means
Dark identity hero renders correctly on light background with no z-index issues. All section cold/mid-cold/warm states visualised. Pull-to-refresh haptic + spinner. Skeleton loading state for each section. Offline banner reuses G7. All Oswald numerics tabular and aligned. Accessibility: WCAG AA contrast for identity hero white-on-ink, body grey on white.
H2 Identity card expanded ("See full story") P0
The Whoop "Monthly Performance Assessment" equivalent. Tells the story behind the hero μ number. Dark full-screen.
Sections
  1. Hero: sport + μ + confidence + delta. Sticky on scroll.
  2. Level history graph: 30-day μ line chart with Glicko σ confidence band shaded. Points = matches. Tap point → match info popover. Oswald 11pt axis labels.
  3. Peak μ this month: number + date achieved.
  4. Matches block: count, win rate, hours on court.
  5. Your edges (narrative): 1–2 sentences. "You're winning 73% on your own serve, losing 60% of tiebreaks. Tiebreak practice is your edge." AI-generated if data supports; else static per-sport default.
  6. Partners played with: 4 avatars + "more" link.
  7. Toughest rival block → tap to M8 head-to-head.
  8. Share your story button → G6 share sheet.
States
Loading (skeleton with shimmer over dark) · Cold (less than 4 matches: narrative replaced with "Play 4+ matches to unlock your edges") · No rival yet · Offline (cached snapshot).
Interactions
Scrollable. Graph: tap data point for popover. Partner avatar → public profile (M9). Rival → M8. Share → G6.
Done means
All states visualised. Graph renders with σ band. Narrative text gracefully handles cold state. Oswald on all numerics. Dark surface high-contrast typography passes WCAG AA.
H4 Recent match detail (Clutch native surface) P0
The critical Clutch surface #1. Watch the match + see stats + see social — all in one screen. Native video, not a web embed.
Sections
  1. Full-bleed video player (16:9). Autoplay muted on load. Tap to unmute. Pinch to fullscreen. Scrubber + play/pause + frame-step.
  2. Match meta: date, round, format, club, court.
  3. Score row: team A vs team B, set-by-set columns, final score, W/L badge.
  4. Highlights carousel: 5–10 auto-cut clips (10–20s each). Tap clip → W4 vertical viewer.
  5. Stats block: rally win %, avg rally length, smash success, court coverage. [See full stats →] to W8.
  6. Social block: 👏 kudos count, 💬 comments count. Top comment preview. [Give kudos] / [See all] CTAs.
  7. Share: [Share highlight] + [Share result] buttons.
States
  • Video processing: show score + "Video ready in ~45 min" placeholder where player would be.
  • Clutch not available (non-Clutch club): no video, stats hidden, show score + social only.
  • Offline: cached video plays if previously downloaded, else "Come back online to watch."
  • Disputed result: warning banner "Result pending confirmation" above score.
Interactions
Video: tap unmute, pinch fullscreen, tap score row to jump. Highlights: tap → W4. Stats: tap → W8. Kudos: tap to give. Comment: tap to focus composer. Share: native OS share sheet.
Done means
All 4 states (processed, processing, no Clutch, disputed) designed. Video autoplay state default. Highlights carousel scrubbing smooth. Share preview is 9:16 with clip + score + avatar. Oswald on score row, tabular-nums aligned.
PC2 Competition detail — registration open P0
The sign-up entry screen. Must convey availability, eligibility, and social proof fast enough to drive a [Sign Up] tap.
Sections
  1. Hero: club/format image, status chip ("Registration open — 12/16 spots", or "Almost full — 14/16").
  2. Info rows: format, date, club + court count, level range, price, duo/solo requirement, spots remaining.
  3. Description (from club): rich text.
  4. Participants: avatar chips (+N more). Social proof.
  5. Rules: expandable accordion.
  6. Eligibility check: inline pass/fail (level qualifies, club member status, Field Pass requirement).
  7. Sticky footer: [Sign Up — €5] primary CTA (disabled with reason if ineligible).
States
Spots filling (amber banner at 80%) · Full (CTA = "Waitlist", lower weight) · Past registration deadline (CTA = "Closed") · Already registered (CTA = "View your registration" → PC2 confirmation variant) · Ineligible (level mismatch, missing Field Pass) — inline explainer.
Interactions
Tap rules → expand. Tap participant avatar → M9 public profile. Tap [Sign Up] → PC5 wizard. Tap [Waitlist] → confirm modal. Share button → OS share sheet.
Done means
All 5 states designed. Eligibility logic visible with clear copy. Sticky footer survives scroll. Price visible always (free explicit). Participant chips align consistently.
PC3 Competition detail — LIVE (state-switched, 5 formats) P0
One screen, 5 layout variants by format. Wrapper identical; central "Now" section differs. Replaces the v2 mistake of 6 separate screens.
Wrapper (same across formats)
Top: comp name + status (LIVE chip). Sticky tab bar: Now / Standings / Matches / Info.
"Now" variants
  • Americano / Mexicano / KoC: current round courts grid. Each court card = team A vs team B + live score + [Enter Result] if participant.
  • Ladder: your position card + challengeable players (≤3 above you) + your ladder match history.
  • Box League: your box card + box standings table + pending matches to schedule.
  • Single Elimination Bracket: horizontal scroll bracket, pinch-zoom, your match highlighted.
  • Round Robin: standings table + cross-table grid + your remaining matches at top.
Other tabs
Standings: flat leaderboard, always available. Matches: all matches grouped by round. Info: rules, schedule, participants.
States + push signals
Round started (push) · Your court ready (push) · Result pending (banner) · Disputed match (warning) · Competition complete → routes to PC4.
Done means
All 5 "Now" variants designed. Tab persistence on scroll. Live indicator pulses. Result entry triggers PC9/PC10 as modal overlay — never leaves PC3.
PB1 Book home — slot-first feed P0
Answers "what can I play right now?" — NOT "which club has free courts?". The Open Matches feed pattern, Field-branded.
Sections
  1. [+ Host a match] — primary CTA, ink fill, at top.
  2. My Bookings strip (only if any upcoming) — most imminent booking with payment status.
  3. Open matches near you — sub-segment chip row (All / My level). Card list. Each card: time, sport, club, distance, level range, spots filled, avatars, share price, [Join →].
  4. [See all open matches →] → PB2.
States
Empty (no nearby matches): "No open matches in your radius right now. Be the first — host one." + [+ Host a match]. Loading: skeleton cards. Offline: cached last view with banner.
Interactions
[+ Host a match] → PB5. Sub-segment chip toggles My level filter. Card tap → PB3. [See all] → PB2. Pull-to-refresh.
Done means
Empty state designed with strong host CTA. My Bookings strip conditional. Card variant for level-qualifies vs outside-range visible. Sub-segment defaults to My level when level known.
PB3 Open match detail P0
The join decision screen. Must show eligibility, social proof (other players), and total cost transparency before tapping Join.
Sections
  1. Header: sport, date/time, club name, court, small map thumbnail. Share icon top right.
  2. Level range: 3.5–4.2 with your level inline (green check if qualifies / amber warning if outside).
  3. Players (3/4 with one empty seat): host row (with [host] tag, level, match count), then other players, then "1 spot left — that's you" placeholder.
  4. Your share: €8 (court total €32 ÷ 4). Inline explainer if your share differs from base (Field Pass discount).
  5. Cancellation note: "If you cancel, seat returns to the feed."
  6. Primary CTA: [Join match →] → PB4.
States
Qualifies (green check, instant join) · Outside range (amber, becomes request — needs host approval) · Match full (waitlist option) · Match cancelled (cannot join) · Past deadline · You're already in (CTA = "View booking" → PB12).
Done means
Level gate logic visible in 2 variants (qualifies, outside-range). Share calculation transparent (court total ÷ seats). Cancellation policy inline, no buried legalese. Sticky footer CTA.
PB6 Host setup — Sport + Club + Time + Court (4-in-1) P0
Replaces the old 5-step wizard. One scrollable screen with 4 collapsible blocks. Each block collapses to summary row once filled.
Sections
  1. Sport picker — pills (Padel default if user's primary). Auto-collapses on selection.
  2. Club picker — horizontal card row (Followed clubs first, then Nearby). Search expands modal. Auto-collapses on selection.
  3. Date + Time — embeds the Booking Window surface (see PB15 spec). Auto-collapses on selection.
  4. Court + Duration — cards per court for selected slot. Clutch badge per court. Duration toggle (60 / 90 / 120 min) where supported.
  5. Bottom-docked [Continue →] enabled when all 4 complete.
Behavior
Each block collapses to a single-line summary row once filled ("Padel ✓", "Padel Club Porto ✓", "Fri 21 · 18:30 ✓", "Court 3 · 90 min ✓"). Tap row to expand and change. Bottom validation: "You're booking Court 3 at Padel Club Porto, Friday 18:30, 90 min. Court total €32."
States
All blocks expanded (start) · Progressive collapse · All complete (CTA enabled) · No slots in window (block 3 shows greyed slots, links to PB15) · No courts available for slot.
Done means
Auto-collapse on selection works smoothly. Summary row legible. Booking Window component embedded correctly with date scroll + slot pill states. CTA disabled state has clear message ("Pick a court to continue").
PB7 Host setup — state-variant (Public vs Private) P0
Renders differently based on matchVisibility from PB5. Common wrapper. Different middle section.
Common
Summary of PB6 choices (compact, 2 lines). Self is always seat 1, labelled "Host". Seat count derives from sport (4 padel doubles / 2 singles / 14 football).
Public variant
WHO CAN JOIN: level range dual-thumb slider with your level marked inline. Auto-approve toggle (on by default). Verified-players-only toggle (off by default). SPLIT: court total ÷ seats = per-player share. You row only (other seats pay on join). Your method picker: [Pay via Field] / [Pay at club].
Private variant
INVITE FRIENDS: [+ Add friend] + [+ From chat]. Per-seat rows: seat 1 (you, host) + invited friends + empty [+ Add friend] placeholders. Each seat has 3 payment options: [Pay €X via Field] / [Pay at club] / [I'll cover (organizer)]. Inline note: "Invited friends get push + chat DM to pay their share."
Done means
Both variants share the wrapper visually. Split row inline (no SP1 modal). Friend chips display correctly. Level slider shows your level marker. Continue CTA visible at bottom in both variants.
PB15 Booking window explainer (modal) P0
Modal triggered when user taps a greyed slot ("Member only" or "Beyond window"). The Field Pass contextual paywall entry #2.
Triggering slots
  • "Member only" slot → modal explains member-only window; CTA: become a member (→ MM2) OR view membership offer.
  • "Beyond window" slot → modal explains base window; CTA: get +3 days with Field Pass (→ MF1).
Sections
Modal header with close button. Friendly explainer copy (no shame: "You can book courts up to N days ahead. Want a longer window?"). Visual: 3-tier comparison: Base · Member · Field Pass. Primary CTA + dismiss link.
Done means
Both trigger variants designed (member-only, beyond-window). Copy is informative not aggressive. 3-tier comparison visualised. Modal dismissible via swipe-down + close button + tap outside.
M1 Account overview P0
The Account tab hub. One scroll. Sections to identity, stats, wallet, Field Pass, memberships, settings.
Sections
  1. Identity strip: avatar (tap to edit), name, level chip per sport, member-since date.
  2. Profile section: rows for Stats (→ M2), Rankings (→ M3), Competition history (→ M4), Match history (→ M5), Achievements (→ M6), Friends (→ M13), Followed clubs (→ M12), Edit profile (→ M10).
  3. Money section: Wallet balance preview (→ MW1), Field Pass status (→ MF3 or MF1), Memberships (→ MM3), Payment methods (→ MP1).
  4. Settings section: rows for Account, Notifications, Privacy, Language, Help, Legal, Sign out.
Done means
Section grouping clear. Wallet balance preview live. Field Pass row shows "Active" badge when subscribed; soft upsell when not. Settings rows compact with chevron right.
M3 Rankings (per club + global) P0
Ana's surface. Where competitive climbers check where they stand. Toggleable scope.
Sections
  1. Scope picker: tabs or segmented (Your club / Your sport / Global).
  2. Your position card: dark hero. Position number (Oswald large), sport, delta this week, your name, μ.
  3. Leaderboard list: avatar + name + μ + position. Players near you highlighted (3 above, 3 below).
  4. Filter chips: All / Friends only / My club / My level ±0.5.
Interactions
Tap user row → M9 public profile. Scope toggle re-fetches. Pull-to-refresh updates rankings.
Done means
3 scope variants designed (club / sport / global). Position highlights (3 above + you + 3 below) clear. Dark surface contrast passes WCAG. Oswald on all positions.
MW1 Wallet home P0
Cross-club wallet balance + per-club breakdown + recent transactions + top-up. Pedro's surface (Field Pass Tourist).
Sections
  1. Total balance hero card: Oswald large €X.XX. Subtitle: "Across N clubs".
  2. Per-club breakdown: each club gets a row with logo, name, balance, expiry warning if <14 days.
  3. Recent transactions: 5 most recent. [See all] → MW2.
  4. [Top up wallet] CTA.
States
Zero balance (welcome state with explainer) · Expiring credits (amber warning at top) · Single club (collapsed per-club row).
Done means
Cross-club aggregation clear. Expiring credit warning prominent without being scary. Tap any row → MW3 credit detail. Top up flow opens drawer.
MF1 Field Pass paywall P1
The monetization moment. Dark. Confident. No dark patterns. Lands from PB15 / Home nudge / Account.
Sections
  1. Hero: short headline + supporting subhead. No urgency timers.
  2. 3 key benefits: +3 days booking window · Cashback on every booking · No booking fees. Each row: icon + benefit + 1-line explainer.
  3. Price block: Monthly OR Annual (annual highlighted with savings). Free trial CTA if eligible.
  4. Social proof: "Trusted by N players at M clubs" (only if numbers are meaningful — else skip).
  5. FAQ accordion: cancel anytime, how cashback works, when it activates.
  6. Primary CTA: [Start free month] or [Subscribe €X/month].
  7. Secondary: [Not now] dismiss link.
States
First-time view · Returning to paywall (different copy: "Still thinking?") · Trial already used (no free trial CTA) · Already subscribed (this screen should not appear — guard in routing).
Done means
No countdown timers. No "limited offer" badges. Clear pricing. Dismiss option respected. Apple/Google StoreKit subscription terms visible.
G8 Empty state template P0
Reused across the entire app. One template, many contexts. No dead ends — every empty state has a primary action.
Structure
Vertically centered. Single line icon (Phosphor 32px) → 1-line headline (H3 weight) → 1–2 line body (text.secondary) → primary CTA (brand.green) → optional secondary text link.
Voice rules
Headline names the absence ("No matches yet" / "No bookings on your plate"). Body explains how to fix it. CTA is an action verb ("Find a match" / "Book a court"). Never use sad emoji or pity language.
Variants designed
Light + dark backgrounds. Tablet width responsive. With illustration (none in v1, abstract icon only).
Used by
H1 cold state, H5 empty feed, PB1 no nearby matches, PC1 no comps, M4 no comp history, M5 no match history, M6 no achievements yet, MW1 zero balance, W1 no videos, G1 no conversations.
Done means
Single component definition. All 10+ usage contexts documented. Voice rules visible to designer. No dead ends — every variant has a CTA.

Compact specs (by surface)

Remaining ~65 screens. Each gets purpose, layout, key states, and reference back to Section 6 acceptance criteria.

Splash · Auth · Onboarding

S1Native OS splashP0
Native iOS LaunchScreen.storyboard / Android splash drawable. Ink background + Field logo centered.
States: single. Watch out: must use OS-native APIs (not animated) for first-frame compliance.
S2Field boot loaderP0
Branded bridge between OS splash and first screen. Lasts 300ms–2s. Dark, logo centered with subtle motion (slow fade or pulse, not bounce).
States: fast (<500ms — no animation), slow (1–2s — show loading dots). Don't: show progress bars (looks broken if it stalls).
S3Update / migration gateP0
Forced-update screen. Single CTA → App Store / Play Store. Cannot bypass.
States: update required · migration in progress (data being upgraded). Copy tone: calm, not alarming.
A1Welcome carouselP0
4 swipeable slides — Compete, Watch, Track, Play. Sticky footer with [Create account] + [Log in]. Slides 1–3 dark, slide 4 (Play) light.
States: per-slide (4). Interactions: swipe + dot indicators + tap footer CTAs anytime.
A2Sign upP0
Email + password form + Apple + Google + Magic Link entries. Terms checkbox required. Lockout after 5 failed attempts.
States: empty · validation errors · loading · success · existing-email error → A3 redirect. Done: all 4 auth paths visible as primary surface, not buried.
A3Log inP0
Mirrors A2 — same 4 paths + Forgot password link. Biometric prompt for returning users with stored credentials.
States: first-time · returning (offer biometric) · locked out (after 5 attempts, 15-min cooldown). Done: Face ID / Touch ID rationale on first biometric offer.
A4Forgot passwordP0
Email input → success state ("Check your email"). Unknown-email error stays generic ("If that email exists, we'll send a reset link") for security.
States: input · loading · success · error. Done: no email enumeration leakage in error states.
A5Email verificationP0
Soft gate: can browse Home/Play discovery but blocked from Book/Compete signup until verified. Resend CTA + persistent banner across app.
States: unverified (banner) · verifying · verified (success toast). Done: banner reuses G7 pattern.
O1Onboarding — sportsP0
Multi-select Padel / Tennis / Football. Big tap targets. ~10s to complete. Skip disabled.
States: empty (no selection — Continue disabled) · 1+ selected · all selected. Done: minimum 1 selection enforced.
O2Onboarding — levelP0
Per-sport: either "I know my level" slider (2.0–6.0) OR 4-question quiz fallback. Both produce a Glicko μ estimate with high σ (confidence).
States: slider mode · quiz mode · quiz-in-progress (question N of 4) · result. Done: both paths land on same data shape.
O3Onboarding — location + follow clubsP0
Location permission rationale → permission grant → nearby clubs list → multi-select follow.
States: permission ask · permission denied (fall back to manual search) · loading clubs · clubs list · 0 nearby clubs (offer manual). Done: denial path doesn't dead-end.
O4Onboarding — notificationsP0
Rationale screen (dark) — explains push categories before firing the native prompt. [Continue] fires native; [Not now] skips.
States: rationale · native prompt (system) · allowed · denied. Done: denied state proceeds to O5 (never blocks).
O5Onboarding — doneP0
Confetti moment + "You're in" headline + auto-dismiss to Home after 3s. Single CTA: [Take me to Home].
States: default. Done: confetti is restrained (not Duolingo). Auto-dismiss optional via tap.
PR1Permission rationale (6 variants)P0
One template, 6 copy variants — Location, Push, Camera, Photos, Contacts, Calendar. Each: line icon → H2 title → 2–3 line body → [Continue] + [Not now]. Denied-state variant: copy rewritten to "You turned this off" + [Open Settings].
States per variant: initial · denied → reopen. Done: all 6 variants designed (12 screens total with denied variants).

Home

H3Today detailP0
Today + tomorrow events expanded into full chronological list. Tap any → relevant detail screen.
States: empty (nothing today) · 1+ events · 10+ events (long list). Done: reuses Today strip card pattern from H1.
H5Social feed expandedP1
Full scrollable feed. Filter chips: All / Friends / My clubs / Competitions I'm in. Infinite scroll. 7 feed item types each with avatar, verb-first headline, detail, timestamp, inline kudos + comment row.
States: empty (no friend activity yet → CTA "Find friends") · loading · offline · end of feed. Done: Instagram-density skim, not compute-heavy.
H6Post detailP1
Single feed item full view — all kudos, comments, replies. Threaded comments. Tap user → M9.
States: 0 comments · <10 · 10+ (load more). Done: comment composer sticky at bottom.
H7Kudos listP1
List of users who gave kudos to a match/post. Tap user → M9 public profile.
States: <20 (simple list) · 20+ (paginate). Done: follow/follow-back CTAs inline.
H8Weekly summaryP1
7-day rollup: μ change, matches played, W/L, hours on court, partners. Shareable as 9:16 story.
States: insufficient data (<3 matches: skip summary) · standard. Done: share preview is on-brand and template-stable.
H9Notification centerP0
Grouped by day. Swipe-to-dismiss per item. Category tabs: All / Activity (matches, comps) / System (account, billing).
States: empty · unread (visual emphasis) · read · old (>30d auto-archive). Done: deep-link from notification → correct screen.
H10Notification deep-link routerP0
Invisible interstitial. Handles edge cases: stale deep link, deleted resource, user logged out, version mismatch.
States: routing · stale (friendly "this match no longer exists" → fallback Home) · auth needed · version gate. Done: never crashes; always lands somewhere coherent.
H11Recommendations see-allP1
Full algorithmic rec list. Reason chips per card: "Same club", "Your level", "Nearby", "Friends are in".
States: populated · loading · empty (no recs → CTA to broaden filters). Done: reason chip is the differentiator; never an opaque list.
H12Streak detailP1
Gamified streak story. Why streak matters, how to keep it, longest historic streak. Dark.
States: active streak · broken (encouragement, not shame) · never had one. Done: loss-streak gets cold messaging "🧊 Ready to break the streak" not "you suck."

Play — Compete

PC1Compete discoveryP0
Play tab Compete segment. My competitions horizontal carousel (LIVE first, red dot). Upcoming vertical scroll. Find a Partner entry. For You algorithmic.
States: no competitions joined · LIVE in progress · empty discovery nearby. Done: filters reachable via bottom sheet.
PC4Competition detail — completedP0
Winner card (avatars + trophy abstract icon). Final standings table. Your result: final position, μ change, W/L. Share + "Next one at this club" link.
States: you won · you placed · you didn't play. Done: abstract trophy (no cartoon).
PC5Registration — Solo vs DuoP0
Two big cards. Solo: auto-matched at R1 by algorithm. Duo: continue to PC6 partner invite.
States: default · duo unavailable for this format (hide). Done: equally weighted card visuals.
PC6Registration — invite partnerP0
Search by name / phone / email. Recently played partners as quick chips. Selected → [Send invite]. Pending state until accept.
States: empty search · results · selected · sent (pending) · partner accepted · partner declined. Done: pending state visible on PC2 for both parties.
PC7Registration — paymentP0
Individual-pay or organizer-pays toggle. Method picker (Wallet / Card / MB WAY / Multibanco). Reuses PB8 payment component.
States: standard · wallet has balance (default selected) · payment failure. Done: uses same component as PB8.
PC8Registration — confirmationP0
Summary + [Add to calendar] + [Invite friends] + [Share].
States: standard. Done: calendar permission rationale (PR1 variant) on first use.
PC9Match result — simpleP0
Americano-style. Two team totals. ≤10s input. Team A avatars + input + Team B avatars + [Submit]. Modal over PC3.
States: input · loading · success (returns to PC3). Done: haptic on submit. Oswald on score input.
PC10Match result — set-by-setP0
For brackets. Three set inputs per team. Super-tiebreak toggle. Modal over PC3.
States: input · super-tiebreak active · validation (invalid sets). Done: set validation visible (can't have 6-6 without TB).
PC11Result confirmation / disputeP0
Counterparty receives push + sees result on PC3 with [Confirm] / [Dispute]. Dispute: reason picker + free text → club admin.
States: pending confirmation · confirmed · disputed (admin queue) · auto-flagged (both parties entered different scores). Done: dispute reasons standardized (wrong score / wrong opponent / didn't play).
PC12Ladder challengeP0
Pick opponent → suggest 3 date windows → optional note → [Send]. Opponent gets push with 3 buttons: accept a window / propose different / decline.
States: compose · sent (pending) · accepted (auto-creates booking) · declined · counter-proposal. Done: challenge expiry visible (48h to respond).
PC13QR check-inP0
Camera full-screen. Haptic + success card on scan ("Checked in — Court 3, Round 1 starts in 4 min"). Manual code entry fallback.
States: camera permission · scanning · success · invalid QR · manual entry · already checked in. Done: permission rationale via PR1 before native camera ask.
PC14Initial level assessmentP0
Same as O2 but accessible standalone from Compete tab for users who skipped during onboarding. Slider or 4-question quiz.
States: identical to O2. Done: shared component with O2.
PC15Find partner — boardP1
Filter chips (sport / level / date / club). List of partner-request cards with avatar, name, level, availability, note. CTAs: [Message] / [Pair up for X].
States: empty (no requests in your filters) · populated · your own request highlighted. Done: level proximity highlighted (±0.3).
PC16Find partner — post requestP1
Form: sport, level range, date window, clubs (multi-select), free-text note → [Post].
States: compose · posted · expired (auto after 7d). Done: request visible to user under "Your posts" in M15.
PC17Competition recap modalP1
Auto-trigger after competition completes. Your placement + μ change + key moment clip + [Share my result].
States: single. Done: dismissible without sharing. Triggered once per competition.

Play — Book

PB2Open matches — full listP0
Sticky filter pill row (Sport · Level · Time · Club · Distance). Same card shape as PB1. Sort toggle top-right: Nearest / Soonest / Lowest level / Highest level.
States: populated · empty per filter combo (CTA: clear or host one yourself) · loading · offline. Done: filter chips reflect counts when applied ("Padel 12").
PB4Join-match checkoutP0
Summary row (date, club, share, total) + payment method (Wallet default if balance) + Field Pass line ("€0 fee — waived by Field Pass" OR "€0.50 fee. Waive with Field Pass →"). [Pay €X] CTA.
States: standard · wallet covers full · partial wallet + card · payment failure. Done: success → PB9 with "You joined Ana's match" variant.
PB5Host a match — Public vs PrivateP0
Two big cards. Public: anyone at your level can join. Private: only invited friends. Fork at step 1, not buried.
States: default. Done: equal visual weight on both cards.
PB8Host checkoutP0
Pay your share or full court (organizer-covers). Method picker. Field Pass benefit line.
States: per-share · full court · payment failure. Done: success → PB9 host variant.
PB9Booking confirmation (Public / Private)P0
Success state. Public variant: "You hosted a match — visible in feed". Private: "Invited 3 friends, awaiting payment". Joiner variant: "You joined Ana's match".
States: 3 variants (host public · host private · joiner) · partial-payment private. Done: [Add to calendar] + [Invite friends] + [Share] CTAs.
PB10Club detailP0
Hero photo + club info (sports, courts, indoor/outdoor, surface, amenities) + open matches at this club + memberships offered + Club Clutch feed (W7 embed) + competitions hosted.
States: followed · not followed · member · non-member. Done: follow toggle persistent.
PB11My bookingsP0
Tabs: Upcoming / Past / Cancelled. Newest first. Each row: date, club, status (paid / pending / cancelled).
States: empty per tab · populated. Done: empty state uses G8 template.
PB12Booking detail (Public / Private)P0
Booking summary + court + time + players + inline split-payment status (4 circles paid/pending) + actions (cancel, share, chat).
States: public · private · all paid · partial paid · all cancelled. Done: split status row inline, no separate modal.
PB13Cancel + refund previewP0
Confirm modal with refund amount + policy explanation + final CTA. Refund varies by timing vs cancellation window.
States: within free window · partial refund · no refund · already cancelled. Done: policy explainer not buried.

Play — Academy

PA1Academy discoveryP1
Play tab Academy segment. Program cards by sport + level + age group + schedule + price.
States: empty (no programs nearby) · populated · child mode (showing child-specific). Done: filter by age group / sport / level.
PA2Program detailP1
Hero + coach profile + schedule + price + spots remaining + level fit + [Enroll].
States: spots available · waitlist · closed. Done: coach details linked.
PA3Enrollment — player + child switcherP1
Self or child selection (if child profiles configured) + contact + medical disclaimer checkbox.
States: self · child · multiple children. Done: child switcher reuses M11 component.
PA4Enrollment — schedule + planP1
Schedule confirm + plan picker (monthly / quarterly / annual) + recurring billing terms.
States: schedule conflict (warning) · standard. Done: plan terms transparent.
PA6My academy — overviewP1
Active program card + next session + attendance summary + plan status + coach contact.
States: active · paused · ending. Done: session reminders set automatically.
PA8Academy payments / planP1
Plan terms + auto-renew toggle + change plan CTA + payment history + next charge date.
States: standard · payment failed (banner). Done: change plan triggers prorated billing modal.

Watch

W1Watch home — your feedP1
Vertical scrolling feed of latest match highlights (yours + friends'). Each card: thumbnail with play overlay, player names, match meta, kudos count.
States: empty (no matches recorded yet → CTA "Play at a Clutch club") · populated · loading. Done: dark, video-first density.
W2My libraryP1
All your videos chronologically. Filter by sport / club / date range. Grid view.
States: empty · populated · loading more. Done: grid responsive to screen width.
W3Match player (full match)P1
Full match playback with scrubber, frame-step, score-mark jumps (tap score row to jump to that point), pinch fullscreen.
States: loading · playing · paused · buffering · error. Done: score-mark jumps work as anchor navigation.
W4Highlights viewer (vertical swipe)P1
TikTok-style vertical swipe through clips. Auto-advance to next clip. Tap to pause. Swipe up for share. Swipe right for next.
States: playing · paused · end of feed. Done: autoplay muted on enter, unmute via tap.
W6Share sheetP1
9:16 preview card with clip + score + avatar + Field watermark. Triggers iOS/Android share sheet.
States: preview · rendering · ready. Done: consistent preview template across share contexts.
W7Club Clutch feedP1
Embedded inside Club Detail (PB10). Latest 5 highlights from this club. [See all] → club-filtered W1.
States: populated · empty (club not Clutch-equipped) · loading. Done: embed not full-screen.
W8Match stats screenP1
Full Clutch stats: rally win %, avg rally length, smash success, court coverage, longest rally. Per-match.
States: data available · partial data · no data (sport without Clutch). Done: Oswald tabular nums throughout.

Account — Profile

M2Full stats (Insights, 8 tiles)P1
Whoop-style 8-tile grid: win rate, streak, level trend, peak μ, hours, partners, edges, rival. Tap any tile → detail.
States: cold (less than 4 matches: tiles greyed with unlock criteria) · warm. Done: dark surface, tabular Oswald numerics.
M4Competition historyP0
Chronological list of all competitions entered + final placement + μ change.
States: empty (uses G8) · populated. Done: tap row → PC4 or PC2 depending on completion.
M5Match historyP1
All matches: date, opponents, score, μ delta. Filter by sport / club / outcome. Tap row → H4 if Clutch, else summary.
States: empty · populated · filter empty. Done: infinite scroll. Oswald numerics.
M6Achievements gridP1
Grid of earned + locked badges. Abstract geometric icons (no cartoon trophies). Earned: color. Locked: grey with hint.
States: none earned (cold) · some · many. Done: grid 3 columns on mobile.
M7Achievement detailP1
Single achievement story: criteria, when earned, who else has it (% of users), share CTA → G6.
States: earned · locked (preview). Done: dark, hero abstract icon.
M8Head-to-head rivalryP1
Opponent profile + W-L record + last 5 matches + rivalry intensity score + your average μ delta when playing them.
States: sufficient matches (≥3) · insufficient (CTA: "Play them again"). Done: dark surface, Oswald.
M9Public profile (other player)P1
Light page with dark stats card. Their μ, achievements, recent matches, follow / challenge CTAs.
States: follower · not following · self (route to M1) · blocked. Done: privacy respected (profile visibility setting).
M10Edit profileP0
Form: name, email, phone, avatar, level (locked if assessed), favourite sport, bio.
States: standard · validation errors · saving · saved. Done: email/phone change requires re-verification.
M12Followed clubsP0
List of clubs you follow. Tap → PB10 club detail. Swipe to unfollow.
States: empty (uses G8) · populated. Done: follow toggle reflects on PB10 instantly.
M13Friends / followersP1
Tabs: Friends (mutual) / Followers / Following. Tap user → M9.
States: empty per tab · populated. Done: unfollow + remove friend swipe actions.
M14Find friendsP1
Contacts permission rationale → matched users on Field → search → invite non-users via WhatsApp.
States: permission ask · permission denied (manual search only) · loading matches · matched · not matched. Done: non-Field contacts get [Invite] WhatsApp deep link.
M15My feed postsP1
Your public activity timeline. Edit / delete actions per post.
States: empty · populated. Done: reuses H6 post detail on tap.

Account — Wallet

MW2Transaction historyP0
Chronological list. Filter by club, type (booking / refund / cashback / topup), date range.
States: empty · populated. Done: infinite scroll. Filter chips persistent.
MW3Credit detailP0
Single credit: source (cashback / refund / topup / promo), amount, expiry, terms, usable-at clubs.
States: active · expired (greyed) · partially used. Done: expiry visible prominently.
MW4Expiration warning modalP0
Triggered when credits expire in <14 days. Modal with "Use it or lose it" framing + [Discover what to book] CTA → PB1.
States: single expiring credit · multiple. Done: max once per session.
MW5Wallet-in-checkout (embedded)P0
Embedded component (not standalone). Apply wallet balance toggle + remaining-to-pay computed live.
States: wallet covers full · wallet partial · wallet zero (toggle disabled). Done: reused across PB4, PB8, PC7.

Account — Field Pass

MF2Field Pass — plan selectP1
Monthly / Annual cards. Annual highlighted with savings tag. Trial info if eligible. Clear cancellation policy.
States: default · trial eligible · trial used. Done: Apple/Google IAP terms visible.
MF3Field Pass — active benefitsP1
Subscribed-state. Cashback YTD + booking window status + member-only privileges + status badge.
States: active monthly · active annual · paused · expiring soon · grace period after payment failure. Done: renewal date visible.
MF4Field Pass — manageP1
Pause, cancel, change plan, billing details. Apple / Google subscription deep-link.
States: standard · cancelling (in grace period). Done: cancellation reasons captured.
MF5Field Pass — cashback historyP1
Chronological list of cashback events. Total YTD + per-club breakdown.
States: empty (just subscribed) · populated. Done: "How cashback works" link inline.

Account — Memberships

MM1Membership offer (inline component)P1
Component shown inside Club Detail (PB10) for non-members. Member benefits + price + [Enroll] CTA.
States: not member · member (component hidden) · member of another club. Done: not a full screen.
MM2Membership enrollmentP1
Member form (name, contact, emergency contact) + auto-renew toggle + payment + terms acceptance.
States: standard · validation · payment failure. Done: terms acceptance required.
MM3My memberships listP1
All active memberships across clubs. Each row: club, status, renewal date, [Manage].
States: empty (uses G8) · 1 · multiple. Done: tap → MM4 detail.
MM4Membership detailP1
Single membership: benefits, terms, renewal, cancel, history of charges.
States: active · cancelling · expired. Done: benefits clearly listed.

Account — Payments

MP1Payment methods listP0
Cards + MB WAY history. Set default. Swipe delete (with confirm). Add new entry.
States: empty (CTA add) · 1 method (default auto) · multiple. Done: card last-4 visible, type icon (Visa / MC).
MP2Add card (SIBS)P0
Card form (number, expiry, CVC, cardholder name) + SIBS validation + 3DS challenge.
States: input · validating · 3DS · success · failed. Done: input via Apple/Google Pay autofill where available.
MP3Add MB WAYP0
Phone number form + MB WAY app verification flow (push to user's bank app for confirmation).
States: input · awaiting confirmation · success · timeout · failure. Done: 60s timeout with retry.

Account — Settings

MS1Settings homeP0
List of sections: Account · Notifications · Privacy · Language · Data · Help · Legal · Sign out.
States: default. Done: consistent row pattern with chevron right.
MS2Account settingsP0
Change email · change phone · change password. Each action requires re-auth (biometric or password).
States: read · editing · saving · re-auth required · success. Done: email/phone changes re-trigger A5 verification.
MS5Language & regionP0
Language picker (EN only at launch, structure for PT-PT / ES) + region (timezone, currency).
States: default · language selected (restart prompt). Done: change triggers app restart prompt.
MS7Data & storage + delete accountP0
Cache management (clear cache) + download my data (GDPR) + delete account (with confirmation friction).
States: standard · delete confirmation 1 (type "DELETE") · delete confirmation 2 (re-auth) · deleted. Done: delete is destructive; multiple confirmations.
MS8Help & supportP0
FAQs + contact form + email support + version info + diagnostic info copy.
States: default · submitting · sent. Done: version info copyable for support.
MS9Terms of ServiceP0
Full ToS rendered in-app. Scrollable. Last-updated date.
States: default. Done: markdown rendered legibly.
MS10Privacy PolicyP0
Full Privacy Policy. Scrollable. Last-updated date.
States: default. Done: matches MS9 pattern.
MS11Cookie / tracking prefsP0
Toggle analytics, ad tracking, third-party SDK. GDPR-compliant default off for non-essential.
States: default · saving. Done: toggle changes effective immediately.
MS12LicensesP0
Auto-generated list of open-source library acknowledgments.
States: default. Done: generated from package.json, not manually maintained.

Split Payment

SP1Pay-my-shareP0
Single screen shown to invited player tapping the pay-link from push/chat. Summary + payment method + cash-at-club toggle.
States: standard · cash-at-club selected · paid · payment failed · link expired · match cancelled. Done: cash toggle is inline, not separate modal.

Global

G1Conversation listP1
Threads with users / groups. Unread badges. Search across messages.
States: empty · populated · unread count > 99. Done: sort by recent activity.
G2Chat screen (1:1 + group)P1
Message bubbles + typing indicator + inline match invitation cards + pay-share reminders.
States: 1:1 · group · with pay-share embed · with match invite. Done: inline cards tappable.
G3New chat composerP1
Recipient search + multi-select for group + first message field.
States: selecting · ready to send. Done: create group requires ≥3 members.
G4Competition recap (modal)P1
Post-event auto-trigger. Your placement + clip + share. Dark modal.
States: single. Done: shows once per competition.
G6Achievement share sheetP1
9:16 story card with abstract badge icon + headline + Field watermark + OS share trigger.
States: preview · rendering · sharing. Done: reuses preview template logic from W6.
G7Offline banner (reused)P0
Persistent top banner: "Offline. Showing last seen data." Auto-dismisses on reconnect with success toast.
States: offline · reconnecting · reconnected (success toast). Done: banner respects light/dark of host screen.
G9Generic errorP0
Friendly error message + retry CTA + report-bug link. Never dead-end.
States: 4xx · 5xx · network · unknown. Done: retry preserves prior state.
G11Server maintenanceP0
Maintenance page with ETA + status page link. Cannot bypass.
States: active · ending (CTA to retry). Done: ETA from server header, not hardcoded.
What's missing on purpose: per-component specs (Card, Button, Chip, etc.) live in Section 9, not here. Per-screen API contracts live in the engineering dev-reference, which the designer doesn't need. Push notification templates live in Section 10 (Content Sheet). If you need anything not here, ask and we'll add to Section 8.

Visual System

Tokens, type, spacing, components. Rendered live.

This section is the design foundation. Tokens, type scale, spacing, components — all rendered live in the brief itself so you can verify visual decisions in real time. Match these exactly in your Figma file. The whole engagement depends on a consistent system.

Color tokens

Tonal system. Each color exposes a full 9-step scale (50 → 900). Components reference a token, never raw hex. Update Figma variables to these exact values.

Primary — Mint

Base: mint.400 · #2DD4A0. Used for primary CTAs, active states, identity highlights.

mint.50
#E8FBF3
mint.100
#C7F4DD
mint.200
#95E8C0
mint.300
#62D9A0
mint.400 ★
#2DD4A0
mint.500
#21B689
mint.600
#1A9573
mint.700
#15745B
mint.800
#105944
mint.900
#0A3D2E

Secondary — Ink (greyscale)

Base: ink · #000000. Used for dark surfaces, primary text on light, high-contrast UI.

ink ★
#000000
grey.900
#171717
grey.800
#262626
grey.700
#404040
grey.600
#525252
grey.500
#737373
grey.400
#A3A3A3
grey.300
#D4D4D4
grey.200
#E5E5E5
grey.100
#F5F5F5

Surfaces

mist
#F5F5F5
mist.card
#FFFFFF
mist.divider
#E5E5E5

Semantic + signal

coral.progress
#F97316
amber.warning
#F59E0B
red.live
#DC2626
green.win
#2DD4A0

Coral progression: Used on slot-fill bars as they approach capacity. Mint at start, coral as urgency rises. Tension drives joining behaviour.

Text

TokenHexUsage
text.primary.light#0A0A0APrimary text on light backgrounds
text.secondary.light#596173Secondary text on light
text.tertiary.light#8891A3Disabled / placeholder on light
text.primary.dark#FFFFFFPrimary text on dark backgrounds
text.secondary.dark#A1A1AASecondary text on dark
text.tertiary.dark#6B7280Disabled / placeholder on dark

Sport accents (used one per screen, never mix)

sport.padel
#2DB8A3
sport.tennis
#F28C28
sport.football
#DC2626
Single-accent rule: Each surface uses one accent. Home identity hero → brand.green. Competition LIVE → red (urgency). Watch player → no accent (the video carries color). Stats deep-dive → sport-specific. Don't combine three colors decoratively on one screen.

Typography

Typefaces

FamilyWeightsUse
Oswald400 · 500 · 600 · 700All headlines, screen titles, large display numerics (μ rating, big scores), section labels.
Barlow400 · 500 · 600 · 700Body text, labels, captions, micro, inline numerics (use tabular-nums feature). All UI text below H3.
Hard rule: Oswald for headlines and big athletic display numerics. Barlow for everything else. No third typeface. No serif fallback. The condensed character of Oswald + humanist sans of Barlow is the "High Performance Athletic" signature — don't dilute it.

Both fonts are free on Google Fonts. Load with this single line: <link href="https://fonts.googleapis.com/css2?family=Oswald:wght@400;500;600;700&family=Barlow:wght@400;500;600;700&display=swap" rel="stylesheet">

Type scale

RoleSize / line-heightWeightFamilyExample
Display56 / 60700OswaldIdentity hero μ "3.8" — big athletic readout
H132 / 38600OswaldScreen title
H224 / 30600OswaldSection title
H318 / 24600OswaldCard title
Section label (caps)13 / 18 · letter-spacing 0.08em600Oswald"COMPETE THIS WEEK", "OPEN MATCHES"
Body16 / 22400BarlowParagraph
Body bold16 / 22600BarlowEmphasized body
Label14 / 18500BarlowForm label, chip
Caption12 / 16500BarlowTimestamp, helper
Micro11 / 14500BarlowLegal, badge count
Stat (inline)varies500–700Barlow tabular-nums"12 matches", "+0.3 delta", "€32"
Stat (display)varies (28pt+)600–700OswaldBig hero numerics, identity card μ, win rate "67%"

Type scale rendered

3.8
Screen title (H1) — Oswald 32/38 600
Section title (H2) — Oswald 24/30 600
Card title (H3) — Oswald 18/24 600
SECTION LABEL — OSWALD CAPS 0.08EM
Body — Field is the operating system for sports clubs. The mobile app is how athletes carry that with them. Barlow 16/22 400.
Body bold — Emphasized phrase inline. Barlow 16/22 600.
LABEL — FORM FIELD · Barlow 14/18 500
Caption · 2 hours ago · Barlow 12/16 500
Micro · ©2026 Field · Barlow 11/14 500

Spacing & layout

Spacing scale (pt / dp)

Use only these values. Never invent a 7pt or 13pt margin.

4
8
12
16
20
24
32
40
56
80

Standard distances

ElementValue
Screen edge padding20 pt
Card internal padding16 pt
Section vertical spacing24 pt
Tab bar height56 pt + safe area
Top nav height56 pt + status bar
Tap target minimum44 × 44 pt

Radius, elevation, borders

ElementRadius
Pill / chip4 pt
Input field8 pt
Card12 pt
Hero card16 pt
Fully rounded (avatar, pill button)999 pt

Elevation on light: 0 1 2 rgba(0,0,0,0.06) for cards. Secondary cards use a 1px mist.divider border with no shadow.

Elevation on dark: No shadows. Use ink.soft lift to indicate elevation.

Iconography

Use Phosphor icon set, 1.5-stroke weight, rounded style. One weight across the entire app. Never mix Phosphor with another icon library.

SizeUse
16 ptInline with body text, label icons
20 ptButtons, list rows
24 pt (default)Tab bar, nav, primary actions
32 ptHero / empty state lead icon

Base components

Eight primitives. Build these as Figma components with variants. Everything else composes from these.

1. Button

4 variants × 4 states. Primary (mint fill, ink text), Secondary (grey-100 fill), Inverted (ink fill, white text), Outlined (white fill, ink stroke). All pill-rounded (999pt radius). States: default · pressed · disabled · loading.

2. Card

2 variants. Light: mist.card background, 1 px mist.divider border or subtle shadow, 12 pt radius. Dark: ink.soft background, no shadow, 12 pt radius.

Light card
mist.card · 12 pt radius · 1px divider
Dark card
ink.soft · 12 pt radius · no shadow

3. Chip / Pill

3 variants: neutral, status (semantic-colored), sport-tagged. Always 4 pt radius. Inter 12pt 500 weight.

Neutral Available Live Full Padel

4. Avatar chip

3 sizes: small (24pt), medium (32pt), large (48pt). 999 pt radius. Optional border (2pt brand.green for "host" / "active" indicator).

JD
JD
JD
JD

5. Progress bar

Slot-fill indicator. Uses brand.green for filled portion, mist.divider for empty. Optional amber tint as fill approaches 100% (urgency).

3/4 players
11/16 spots
2/8 spots — early

6. Stat block

Used in identity tiles, match cards, profile stats. Oswald tabular nums. Top label + big number + delta line.

μ Rating
3.8
+0.3 this week
Win rate
67%
Last 30 days
Matches
12
8 wins · 4 losses

7. Tab bar (bottom nav)

56 pt height + safe-area inset. Background: mist.card on light / ink.soft on dark. Icon 24 pt + label 11 pt Inter 500. Active: brand.green icon + label + 3 pt rounded pill beneath. Haptic selection on tab change.

Screen content
Home
🎾
Play
🎬
Watch
👤
Account

8. Form input

4 states: default, focused, error, disabled. 8 pt radius. 48 pt minimum height. Floating label or top-aligned label.

Email
Password
Phone (error)
Phone number must contain only digits.

Permission rationale screen template

One template, six copy variants (Location, Push, Camera, Photos, Contacts, Calendar). Always dark mode. Centered line icon, H2 title, 2–3 line body, primary [Continue], secondary [Not now]. Denied-state variant: body rewritten to "You turned this off. Open Settings to change it" + [Open Settings] deep link.

📍
Find clubs near you
Show clubs closest to you. We never track in the background.

Content Sheet

Every CTA, label, empty state, error, and push notification. English. Reference verbatim — designer doesn't invent copy.

Voice principles

Field's voice is confident, direct, and athletic. Closer to Whoop's clipped utility than Duolingo's chatty encouragement. Never apologizes for itself. Never shouts.

Do Verb-first CTAs in Title Case.
"Book a court", "Find a partner", "Watch highlights"
Don't Generic action words.
"Continue", "OK", "Submit", "Go"
Do Sentence case for body, periods at end.
"Your usual Friday slot is open."
Don't Exclamation points except confetti moments (O5, achievement unlocks).
"Your slot is open!"
Do Cold messaging for loss streaks — never shame.
"Ready to break the streak."
Don't Negative framing.
"You're on a losing streak", "You haven't won in 3 matches"
Do Plain language errors that name the fix.
"We couldn't process that payment. Try a different card."
Don't Technical error codes or apologies.
"Error 500. We're sorry for the inconvenience."
Do Numerals always.
"3 spots left", "12 matches", "€8 per player"
Don't Spelled-out numbers.
"three spots left", "twelve matches"

Formatting rules

  • CTAs: Title Case (capitalize Major Words). Max 3–4 words. Verb first.
  • Section labels (all caps): Use for "OPEN MATCHES", "TODAY", "LAST MATCH". Oswald 12–13pt with 0.08em letter-spacing.
  • Body: Sentence case. Periods at end of sentences.
  • Numbers: Numerals always. Currency symbol before number (€8 not 8€). Date format "Fri, Oct 24 · 18:30".
  • Emojis: Only as functional indicators (🔥 streak, ✓ check, ▶ play). Never decorative.
  • Names: First name + last initial in social contexts ("Ana M."). Full name in profile.

10.1 Splash · Auth · Onboarding

ScreenElementEnglish copyNotes
A1Carousel slide 1 titleReal competitions. Real rankings.Dark
A1Carousel slide 1 subtitleAmericanos, ladders, box leagues. With a rating that actually means something.
A1Carousel slide 2 titleEvery match recorded.Dark
A1Carousel slide 2 subtitleClutch cameras at every Field club. Highlights in hours. Shareable in one tap.
A1Carousel slide 3 titleYour level. Your story. Your rivals.Dark
A1Carousel slide 3 subtitleEvery match counted. Every trend visible. Every rival on your card.
A1Carousel slide 4 titleBook. Play. Repeat.Light
A1Carousel slide 4 subtitleCourts, partners, academies — one app.
A1Primary CTACreate account
A1Secondary CTALog in
A2Screen titleCreate your Field account
A2Email labelEmail
A2Email placeholderyou@example.com
A2Password labelPassword
A2Password helperAt least 8 characters with one number.
A2Terms checkboxI agree to Field's Terms of Service and Privacy Policy.Links inline
A2Primary CTACreate account
A2Divideror continue with
A2Apple buttonContinue with Apple
A2Google buttonContinue with Google
A2Magic link buttonEmail me a magic link
A2Error — email existsAn account already exists with this email. Log in instead.Inline CTA
A2Error — weak passwordPassword needs at least 8 characters and one number.
A3Screen titleWelcome back
A3Forgot password linkForgot password?
A3Primary CTALog in
A3Error — wrong credsEmail or password doesn't match. Try again.Generic for security
A3Error — locked outToo many attempts. Try again in 15 minutes.
A3Biometric promptUse Face ID to sign iniOS · "Touch ID" / "Fingerprint" variants
A4Screen titleReset your password
A4BodyEnter the email on your account. We'll send a reset link.
A4Primary CTASend reset link
A4Success messageIf that email exists, we sent a reset link. Check your inbox.Generic for security
A5Banner — unverifiedVerify your email to book courts and join competitions.Persistent banner
A5Banner CTAResend verification
A5Success toastEmail verified. You're all set.
O1Screen titleWhat do you play?
O1SubtitlePick all that apply.
O1Continue CTA disabledPick a sport to continue
O2Screen titleWhat's your level?
O2Slider mode subtitleDrag the slider to your level. Not sure?Link to quiz mode
O2Quiz mode triggerTake a quick quiz instead
O2Quiz question 1How long have you played?
O2Quiz question 2How often do you play in a typical month?
O2Quiz question 3Can you hit a topspin consistently?Sport-specific
O2Quiz question 4Have you played in a tournament before?
O3Screen titleFind clubs near you
O3Permission bodyShow clubs closest to you. We never track in the background.
O3Follow CTA per clubFollow
O3Continue CTAContinue with {N} clubsVariable count
O3Skip linkSkip for now
O4Screen titleStay in the loopDark
O4BodyMatch reminders, results, waitlist spots, friend activity.
O4Primary CTAContinueFires native prompt
O4SecondaryNot now
O5Screen titleYou're in.One of the only periods + confetti moments
O5SubtitleTime to play.
O5Primary CTATake me home
PR1Location titleFind clubs near you
PR1Location bodyShow clubs closest to you. We never track in the background.
PR1Push titleStay in the loop
PR1Push bodyMatch reminders, results, waitlist spots, friend activity.
PR1Camera titleScan to check in
PR1Camera bodyScan the court QR to check in. Or pick from your library.
PR1Photos titleAdd a photo
PR1Photos bodyPick a photo for your profile or a match highlight.
PR1Contacts titleFind friends on Field
PR1Contacts bodyFind teammates on Field. We only check names you share.
PR1Calendar titleAdd matches to your calendar
PR1Calendar bodyAdd matches and competitions to your calendar automatically.
PR1Continue CTA (all variants)Continue
PR1Skip CTANot now
PR1Denied state bodyYou turned this off. Open Settings to change it.
PR1Denied state CTAOpen Settings

10.2 Home

ScreenElementEnglish copyNotes
H1Top greeting (morning)Good morning, {firstName}5am–11am
H1Top greeting (afternoon)Good afternoon, {firstName}11am–6pm
H1Top greeting (evening)Good evening, {firstName}6pm–11pm
H1Top greeting (night)Up late, {firstName}11pm–5am
H1Identity card sport labelPADELAll caps, Oswald
H1Identity card delta (+)+{X.X} this weekMint color
H1Identity card delta (–){X.X} this weekAmber, no minus
H1Identity card week count{W}W {L}LOswald, tabular
H1Streak label (active)🔥 {N}-win streak
H1Streak label (cold)🧊 Ready to break the streakNever "you're losing"
H1Identity card CTASee full storyArrow icon
H1Identity cold state titleBuild your identityNew user, no matches
H1Identity cold state bodyPlay your first match to start tracking your level.
H1Identity cold state CTAFind a competition
H1Identity mid-cold noteEarly days — we're still learning your level.1–3 matches
H1Section label — TodayTODAYOswald caps 0.08em
H1Today see-all linkSee all
H1Today empty stateNothing on your plate. Find a match.Inline link "Find a match"
H1Today event card — countdown (hours)In {N} hours · {filled}/{total} spots
H1Today event card — countdown (tomorrow)Tomorrow {time} · {filled}/{total} spots
H1Section label — Last MatchLAST MATCH
H1Last Match CTA (with video)Watch highlights
H1Last Match CTA (processing)Highlights ready in ~2hGreyed state
H1Last Match — no Clutch clubPlayed at {clubName} — no video at this club yet.
H1Section label — FriendsFRIENDS
H1Friends empty stateNo friend activity yet. Find friends to fill your feed.CTA "Find friends"
H1Friends see-all linkSee all
H1Section label — RecommendedRECOMMENDED
H1Rec reason chip — same clubSame club
H1Rec reason chip — your levelYour level
H1Rec reason chip — nearbyNearby
H1Rec reason chip — friends inFriends are in
H1Offline bannerOffline. Showing last seen data.Top banner
H1Reconnected toastBack online.
H2Screen titleYour identityOr "Your story" — match brand voice
H2Section — peak μPeak this month
H2Section — your edgesYour edges
H2Edges fallback (insufficient data)Play more matches to unlock your edges.
H2Section — partnersTop partners
H2Section — rivalToughest rival
H2Share CTAShare your story
H4Match meta line{Day} · R{N} {format}e.g., "Wed · R3 Americano"
H4Win badgeWINOswald, mint background
H4Loss badgeLOSSOswald, grey background — no shame
H4Section — highlightsHIGHLIGHTS
H4Section — statsSTATS
H4Stats CTASee full stats
H4Section — socialSOCIAL
H4Kudos CTAGive kudos
H4Kudos given toastKudos sent.
H4Share highlight CTAShare highlight
H4Share result CTAShare result
H4Video processing stateVideo ready in ~{N} min
H4No Clutch stateNo video — this club doesn't have Clutch cameras yet.
H4Disputed result bannerResult pending confirmationAmber banner
H9Screen titleNotifications
H9Empty stateYou're all caught up.
H9Tab — allAll
H9Tab — activityActivity
H9Tab — systemSystem
H9Mark all readMark all readTop right action

10.3 Play — Compete

ScreenElementEnglish copyNotes
PC1Top greetingPlayTab title
PC1Segment — CompeteCompete
PC1Segment — BookBook
PC1Segment — AcademyAcademy
PC1Section — Live nowLIVE NOWRed dot
PC1Section — My competitionsMY COMPETITIONS
PC1Section — UpcomingUPCOMING
PC1Section — Find a partnerLooking for a duo?CTA below
PC1Find partner CTAFind players at your level
PC1Section — For youFOR YOU
PC1Empty — no comps nearbyNo competitions in your radius. Broaden the search or tell your club admin you want one.
PC1Empty CTABroaden search
PC2Status — openRegistration open · {filled}/{total} spots
PC2Status — closing soonClosing in {time}
PC2Status — fullFull · waitlist open
PC2Status — closedRegistration closed
PC2Info row — FormatFormat
PC2Info row — WhenWhen
PC2Info row — WhereWhere
PC2Info row — LevelLevel
PC2Info row — PricePrice
PC2Info row — PartnersPartners
PC2Section — AboutAbout
PC2Section — ParticipantsParticipants
PC2Eligibility passYou're eligible to joinGreen check
PC2Eligibility fail — levelThis is for level {min}–{max}. You're at {μ}.
PC2Eligibility fail — memberClub members only. Become a member to join.CTA inline
PC2Eligibility fail — Field PassField Pass holders only.CTA inline
PC2Primary CTA — sign upSign up · €{price}
PC2CTA — waitlistJoin waitlist
PC2CTA — already signed upYou're inGreyed
PC2Share CTAShare
PC3Status chip — LIVELIVE · ROUND {N}/{total}Red dot
PC3Tab — NowNow
PC3Tab — StandingsStandings
PC3Tab — MatchesMatches
PC3Tab — InfoInfo
PC3Enter result CTAEnter result
PC3Waiting stateWaiting for scoreGreyed
PC4Section — Final standingsFINAL STANDINGS
PC4Your result labelYour result
PC4Position labelFinished {place} of {total}e.g., "Finished 2nd of 16"
PC4μ delta line{±X.XX} μOswald
PC4Share CTAShare my result
PC4Next competition linkNext one at {clubName}
PC5Screen titleHow are you playing?
PC5Solo card titleSolo
PC5Solo card bodyWe match you with a partner at round 1.
PC5Duo card titleDuo
PC5Duo card bodyPick a partner. You play every round together.
PC6Screen titlePick your partner
PC6Search placeholderSearch by name, phone, or email
PC6Recent partners labelRecent partners
PC6Send invite CTASend invite
PC6Pending stateWaiting for {firstName} to accept
PC6Accepted state{firstName} acceptedMint check
PC6Declined state{firstName} can't make this one. Pick someone else.
PC7Screen titlePay your share
PC7Pay-mode — individualEach player pays their share
PC7Pay-mode — organizerI'm covering everyone
PC7Total labelYou pay
PC7Primary CTAPay €{amount}
PC8Success titleYou're in.
PC8Success subtitleSee you {dayOfWeek} at {time}.
PC8Add to calendar CTAAdd to calendar
PC8Invite friends CTAInvite friends
PC8Share CTAShare
PC9Screen titleEnter resultModal over PC3
PC9Submit CTASubmit result
PC10Super-tiebreak toggleSuper-tiebreak in set 3
PC11Confirm prompt titleConfirm result?
PC11Confirm body{opponent} submitted: {score}
PC11Confirm CTAConfirm
PC11Dispute CTADispute
PC11Dispute reason — wrong scoreWrong score
PC11Dispute reason — wrong opponentWrong opponent assigned
PC11Dispute reason — no-showDidn't play / no-show
PC11Dispute submittedSent to club admin. We'll let you know.
PC12Screen titleChallenge {firstName}
PC12Date windows labelPick 3 windows that work
PC12Note placeholderAdd a note (optional)
PC12Send CTASend challenge
PC12Expires noteExpires in 48 hours if no response.
PC13Screen instructionPoint the camera at the court QR
PC13Manual entry linkType the code instead
PC13Success titleChecked in
PC13Success subtitleCourt {N}. Round {R} starts in {time}.
PC13Error — invalid QRThat QR isn't valid for this competition. Try again or check in at the desk.
PC13Error — already checked inYou're already checked in.

10.4 Play — Book

ScreenElementEnglish copyNotes
PB1Primary CTABook a court
PB1Section — My bookingsMY BOOKINGSConditional
PB1Section — Open matchesOPEN MATCHES NEAR YOU
PB1Sub-segment — AllAll
PB1Sub-segment — My levelMy level
PB1Card — time todayToday {time}
PB1Card — time tomorrowTomorrow {time}
PB1Card — share price€{amount} per player
PB1Card — spots row{filled}/{total} players
PB1Empty stateNo open matches near you. Be the first — host one.
PB1Empty CTAHost a match
PB1See all CTASee all open matches
PB2Filter — SportSport
PB2Filter — LevelLevel
PB2Filter — TimeTime
PB2Filter — ClubClub
PB2Filter — DistanceDistance
PB2Sort — NearestNearest first
PB2Sort — SoonestSoonest first
PB2Sort — Level lowestLowest level first
PB2Sort — Level highestHighest level first
PB2Empty (filtered)Nothing matches these filters. Clear them or host one yourself.
PB2Clear filters CTAClear filters
PB3Eligibility — qualifiesYou qualify · Your level {μ} is in range.Mint check
PB3Eligibility — outside rangeYour level {μ} is outside the range. The host can still approve you.Amber
PB3Players sectionPLAYERS · {filled}/{total}
PB3Host tagHostMint outline pill
PB3Empty seat label1 spot left — that's you
PB3Share lineYour share
PB3Share breakdownCourt total €{total} ÷ {players}
PB3Cancellation noteIf you cancel, your seat returns to the feed.
PB3Primary CTA — qualifiesJoin match · €{amount}
PB3Primary CTA — needs approvalRequest to join
PB4Method labelPay with
PB4Field Pass line (waived)€0 booking fee — covered by Field PassMint check
PB4Field Pass line (offer)€0.50 booking fee. Waive it with Field Pass.Link
PB4Primary CTAPay €{amount}
PB4Error — declinedThat card was declined. Try a different method.
PB5Screen titleWho's this match for?
PB5Public card titlePublic
PB5Public card bodyAnyone at your level can join. Faster to fill.
PB5Private card titlePrivate
PB5Private card bodyOnly the friends you invite can join.
PB6Sport block labelSport
PB6Club block labelClub
PB6Date block labelDate & time
PB6Court block labelCourt & duration
PB6Followed clubs labelYour clubs
PB6Nearby clubs labelNearby
PB6Booking window banner (in window)You can book {N} days ahead.
PB6Booking window banner (Field Pass)Get +3 days with Field PassLink to MF1
PB6Slot — availableAvailableMint pill
PB6Slot — bookedBookedGrey
PB6Slot — member onlyMember onlyAmber pill, taps PB15
PB6Slot — beyond windowBeyond windowGrey, taps PB15
PB6Continue CTAContinueBottom-docked
PB6Summary lineCourt {N} at {club}, {day} {time}, {duration} min. Total €{amount}.
PB7Section — Who can join (public)WHO CAN JOIN
PB7Level range labelLevel range
PB7Your level noteYour level {μ} is inside this range
PB7Auto-approve toggleAuto-approve players in range
PB7Verified toggleVerified players only
PB7Section — Split (public)SPLIT
PB7Split summaryCourt total €{total} ÷ {seats} = €{share} each
PB7Section — Invite (private)INVITE FRIENDS
PB7Add friend CTAAdd friend
PB7From chat CTAFrom chat
PB7Seat row — pay via FieldPay €{share} via Field
PB7Seat row — pay at clubPay at the club
PB7Seat row — organizer coversI'll cover this seatPrivate only
PB7Invite noteInvited friends get a push and a chat with the pay link.
PB7Continue CTAContinue to payment
PB9Success title (public host)Match is live.
PB9Success body (public)Players can join from the feed.
PB9Success title (private host)Court locked.
PB9Success body (private){N} friends invited. We'll let you know as they pay.
PB9Success title (joiner)You joined {hostFirstName}'s match.
PB11Tab — UpcomingUpcoming
PB11Tab — PastPast
PB11Tab — CancelledCancelled
PB11Empty — UpcomingNo bookings on your plate. Book a court.
PB11Empty — PastNo past bookings yet.
PB11Empty — CancelledNothing cancelled.
PB12Section — Players & paymentPLAYERS & PAYMENT
PB12Seat status — paidPaidMint dot
PB12Seat status — at clubPay at clubGrey dot
PB12Seat status — pendingPendingAmber dot
PB12Open chat CTAOpen chat
PB12Cancel CTACancel bookingRed, bottom
PB13Screen titleCancel this booking?
PB13Refund — fullFull refund · €{amount} returns to your walletMint
PB13Refund — partialPartial refund · €{amount} returns to your walletAmber
PB13Refund — noneNo refund · Cancellation is too late per club policyGrey
PB13Confirm CTACancel booking
PB13Keep CTAKeep booking
PB15Title — member onlyThis slot is for members
PB15Body — member only{clubName} opens this time only to members. Become a member to book.
PB15CTA — become memberSee membership
PB15Title — beyond windowThat's beyond your booking window
PB15Body — beyond windowYou can book {N} days ahead. Field Pass adds 3 more.
PB15CTA — get Field PassGet Field Pass
PB15Dismiss linkPick another time

10.5 Play — Academy

ScreenElementEnglish copyNotes
PA1Section — Single classesSINGLE CLASSES
PA1Section — ClinicsCLINICS
PA1Section — CoursesCOURSES
PA1Empty stateNo academy programs nearby. Tell your club admin you're interested.
PA2Type — single classSingle classTag
PA2Type — clinicClinic · {N} sessions
PA2Type — courseCourse · {duration}
PA2Primary CTAEnroll
PA3Medical disclaimerI confirm I have no medical conditions that prevent me from playing.Checkbox
PA3Child switcherEnrolling for
PA3Add child linkAdd a child profile
PA4Plan — monthlyMonthly · €{amount}/mo
PA4Plan — quarterlyQuarterly · €{amount}/quarter (save {pct}%)
PA4Plan — annualAnnual · €{amount}/year (save {pct}%)
PA6Next session labelNext session
PA6Attendance labelAttendance
PA6Plan status — activeActive · Renews {date}
PA6Plan status — pausedPaused

10.6 Account — Profile, stats, friends

ScreenElementEnglish copyNotes
M1Section — ProfilePROFILE
M1Section — MoneyMONEY
M1Section — SettingsSETTINGS
M1Sign out CTASign out
M2Tile — μ ratingμ rating
M2Tile — win rateWin rate
M2Tile — matchesMatches
M2Tile — hoursHours on court
M2Tile — partnersTop partner
M2Tile — rivalToughest rival
M2Tile — streakBest streak
M2Tile — peakPeak μ
M3Scope — your clubYour club
M3Scope — your sportYour sport
M3Scope — globalGlobal
M4Empty stateNo competitions yet. Sign up for one.
M5Empty stateNo matches yet. Find one.
M6Empty stateNo achievements yet. Keep playing.
M8H2H titleYou vs {firstName} {lastInitial}.
M8Insufficient dataPlay {firstName} {lastInitial}. {N} more times to unlock this view.
M9Follow CTAFollow
M9Unfollow CTAFollowingState toggle
M9Challenge CTAChallenge
M10Section — DisplayHow you appear on Field
M10Field — bio placeholderA line about your game (optional)
M10Save toastSaved.
M13Tab — FriendsFriends
M13Tab — FollowersFollowers
M13Tab — FollowingFollowing
M14Section — On FieldON FIELD · {N}
M14Section — InvitedINVITED · {N}
M14Section — Not on FieldNOT ON FIELD · {N}
M14Invite via WhatsAppInvite via WhatsApp
M14Invite message templateI'm playing on Field — a sports app that's actually good. Join me: {inviteLink}Pre-filled

10.7 Account — Wallet, Field Pass, Payments

ScreenElementEnglish copyNotes
MW1Total labelTotal balance
MW1Subtitle — across N clubsAcross {N} clubs
MW1Section — Per clubPER CLUB
MW1Recent transactions sectionRECENT TRANSACTIONS
MW1Top up CTATop up wallet
MW1Zero stateYour wallet is empty. Credits land here from cashback, refunds, and top-ups.
MW3Source — CashbackCashback
MW3Source — RefundRefund
MW3Source — Top upTop up
MW3Source — PromoPromo
MW3Expiry — soonExpires {date}Amber if <14d
MW4Modal titleYou have credits expiring soon
MW4Modal body€{amount} expires {date}. Use it to book or join a match.
MW4Primary CTADiscover what to book
MW4Dismiss linkDismiss
MF1Paywall titleField Pass
MF1Paywall subtitlePlay more. Pay less. Book sooner.
MF1Benefit 1Book courts 3 days earlier
MF1Benefit 1 bodySkip the rush. Lock in prime time before anyone else.
MF1Benefit 2Get cashback on every booking
MF1Benefit 2 body{pct}% back to your Field wallet. Use anywhere.
MF1Benefit 3No booking fees
MF1Benefit 3 bodyOther players pay a small fee per booking. You don't.
MF1Trial CTAStart free month
MF1Paid CTASubscribe · €{amount}/mo
MF1Dismiss linkNot now
MF1Fine printCancel anytime. Trial converts to paid unless cancelled before the month ends.
MF3Status badgeActiveMint
MF3Cashback YTD labelCashback this year
MF3Window statusYou can book {N} days ahead.
MF3Renewal labelRenews {date}
MF4Pause CTAPause subscription
MF4Cancel CTACancel subscriptionRed
MF4Cancel modal titleMind sharing why?
MF4Cancel reason — too expensiveToo expensive
MF4Cancel reason — not usingNot using it enough
MF4Cancel reason — switchingFound something else
MF4Cancel reason — otherSomething else
MF4Cancel confirmYou'll keep Field Pass benefits until {date}, then it ends.
MP1Empty stateNo payment methods yet.
MP1Add method CTAAdd a payment method
MP1Default tagDefaultPill
MP1Set default CTASet as defaultSwipe action
MP1Delete CTADeleteSwipe action red
MP2Card number labelCard number
MP2Expiry labelExpiry
MP2CVC labelCVC
MP2Cardholder labelCardholder name
MP2Save CTASave card
MP23DS messageConfirming with your bank…
MP3Phone labelPhone number
MP3Awaiting confirmationOpen MB WAY on your phone to confirm.
MP3Timeout errorMB WAY didn't confirm in time. Try again.

10.8 Account — Settings & Legal

ScreenElementEnglish copyNotes
MS1Row — AccountAccount
MS1Row — NotificationsNotifications
MS1Row — PrivacyPrivacy
MS1Row — LanguageLanguage & region
MS1Row — DataData & storage
MS1Row — HelpHelp & support
MS1Row — LegalLegal
MS1Row — Sign outSign outRed
MS2Change email CTAChange email
MS2Change phone CTAChange phone
MS2Change password CTAChange password
MS2Re-auth promptConfirm it's you
MS5Language labelApp language
MS5Region labelRegion
MS5Restart noteThe app will restart to apply the new language.
MS7Clear cache CTAClear cache
MS7Download data CTADownload my data
MS7Delete account CTADelete accountRed
MS7Delete titleDelete your Field account?
MS7Delete bodyThis is permanent. You lose your stats, matches, wallet, and competition history. Wallet credits are not refunded.
MS7Delete confirmation inputType DELETE to confirm
MS7Delete final CTAPermanently delete account
MS8Contact labelEmail support
MS8Version labelApp version
MS11Section — AnalyticsAnalytics
MS11Analytics bodyAnonymous usage data helps us improve Field.
MS11Section — TrackingAd tracking
MS11Tracking bodyOff by default. We never sell your data.

10.9 Global — Errors, empty states, banners

ScreenElementEnglish copyNotes
G7Offline bannerOffline. Showing last seen data.
G7Reconnected toastBack online.
G8Generic empty template{Headline names absence}. {Body: 1 sentence path forward}.Pattern
G9Error — generic 4xxSomething didn't work. Try again.
G9Error — server 5xxField is having a moment. Try again in a sec.
G9Error — networkCan't reach Field. Check your connection.
G9Retry CTATry again
G9Report CTAReport this
G10Forbidden / lockedThis is private.
G10Forbidden bodyYou don't have access to this. If that's a mistake, tell us.
G11Maintenance titleField is getting a tune-up
G11Maintenance bodyBack at {time}. Status updates at status.field.app.

10.10 Push notification library

≤80 characters per body. Verb-first when possible. No exclamation points except confetti moments. Title is the trigger; body is the personal hook.

TriggerTitleBodyNotes
P01Match starts soonMatch in {N} hours{Day} {time} at {clubName}. Bring water.Deep-link → PB12
P02Highlights readyYour highlights are ready{Score} vs {opponentFirstName}. Watch the clips.→ H4
P03Open match nearbyNew open match near you{Sport} {day} {time} at {clubName}. {N} spots left.→ PB3
P04Result to confirmConfirm match result{opponentFirstName} entered {score}. Confirm or dispute.→ PC11
P05μ rating upYour level just moved{firstName}, your μ is now {newμ} ({+delta}). See the story.→ H2
P06Streak milestone{N}-win streakThree in a row, {firstName}. Keep it going.→ H12
P07Friend played{friendFirstName} just played{Score} at {clubName}. Give kudos.→ H6
P08Friend joined Field{friendFirstName} is on FieldWave hi or challenge them.→ M9
P09Friend won competition{friendFirstName} won {compName}Top of the {compType}. Send kudos.→ H6
P10Challenge received{firstName} challenged youPick a window or counter-propose.→ PC12 mirror
P11Challenge accepted{firstName} accepted{Day} {time} at {clubName}. Booking is live.→ PB12
P12Challenge declined{firstName} can't make itFind another opponent at your level.→ M3
P13Partner invitation{firstName} invited youDuo for {compName} on {day}. Accept?→ PC6
P14Partner accepted{firstName} is inYou're paired for {compName}. Pay your share.→ PC7
P15Pay your share{hostFirstName} invited you to play{Sport} {day} {time}. Your share: €{amount}.→ SP1
P16Pay reminder T-24hStill need your share{hostFirstName}'s match is tomorrow. €{amount} due.→ SP1
P17Booking confirmedCourt locked{Day} {time} at {clubName}. Court {N}.→ PB12
P18Booking cancelledBooking cancelled{Day} {time} at {clubName}. Refund: €{amount} to wallet.→ PB11
P19Waitlist spot openedYou got a waitlist spot{compName} on {day}. You're in.→ PC2
P20Competition starts{compName} starts soon{Time at clubName}. Check in with the court QR.→ PC13
P21Round readyYour court is readyCourt {N}. Head over.→ PC3
P22Competition done{compName} is overYou finished {place}. {±delta} μ.→ PC4
P23Wallet credit expires€{amount} expires in {N} daysUse it on a booking or competition.→ MW3
P24Field Pass trial endingFree month ends in 3 daysYou'll be charged €{amount} on {date}. Manage anytime.→ MF4
P25Smart booking nudgeYour usual {day} slot is open{Time at clubName}. Book it before it's gone.→ PB6 pre-filled
P26Kudos received{N} kudos on your last matchSee who.→ H7
P27Achievement unlockedNew badge: {achievementName}{1-line description}.→ M7
P28Disputed result resolvedResult resolved{compName}: official score is {score}. μ adjusted.→ M5
P29Academy session reminderClass in 2 hours{coachFirstName} at {clubName}. Court {N}.→ PA6
P30Membership renewing{clubName} membership renews soon€{amount} on {date}. Manage anytime.→ MM4
Variables convention: Curly-brace placeholders ({firstName}, {amount}, {clubName}) in this sheet are populated at runtime. Maintain them exactly as named — engineering wires them to the same keys. Don't rename or add new ones without coordinating.
What's deferred: Tooltips, onboarding educational overlays, marketing email templates, and SMS one-time-codes are not in this sheet — they're separate workstreams. If you need a copy moment that isn't here, write it in the brief voice and flag it for canonical adoption.
End of brief

Now go design.

You have the vision, the audience, the decisions, the structure, the screens, the flows, the specs, the visual system, and the copy. Everything you need to ship Field's mobile app is in this document. If you find a gap, that's a real gap — flag it and we'll close it together.

Field is built with clubs. Now it's built with you too.