diff --git a/.claude/settings.local.json b/.claude/settings.local.json
index 238a961..70d29e5 100644
--- a/.claude/settings.local.json
+++ b/.claude/settings.local.json
@@ -379,7 +379,9 @@
"Bash(grep -n \"class RoundCreate\\\\|class RoundOut\\\\|played_at\\\\|start_hole: int$\\\\|started_at\" /opt/teecup/app/routers/rounds.py)",
"Bash(python3 -c \"import ast; ast.parse\\(open\\('/opt/teecup/app/routers/rounds.py'\\).read\\(\\)\\)\")",
"Bash(python3 test_round_edit_delete.py)",
- "Bash(python3 test_round_starthole_time_nearby.py)"
+ "Bash(python3 test_round_starthole_time_nearby.py)",
+ "Bash(python3 test_round_strokes_received.py)",
+ "Bash(grep -n \"nearby-endepunkt\\\\|nærmest deg\\\\|Nærmest\\\\|/health\\\\`/\\\\`/dashboard\\\\`/\\\\`/my-rounds/new\\\\`\" /opt/teecup/ARCHITECTURE_DECISIONS.md)"
],
"additionalDirectories": [
"/opt/teeoff/deploy",
diff --git a/ARCHITECTURE_DECISIONS.md b/ARCHITECTURE_DECISIONS.md
index fa3ed7d..16eb5f8 100644
--- a/ARCHITECTURE_DECISIONS.md
+++ b/ARCHITECTURE_DECISIONS.md
@@ -2157,6 +2157,430 @@ migrasjon, `docker compose up -d --build teecup_api teecup_frontend`,
begge containere boot-et rent, `/health`/`/dashboard`/`/my-rounds/new`
→ 200, `teeoff.no` upåvirket.
+**Reell UX-bug funnet OG fikset, samme dag 2026-07-25, rapportert av
+bruker med skjermbilder av en konkurrerende golf-app (Golf Game Book)
+som referanse:** brukeren rapporterte at "All statistikk" ikke viste
+noe utover slag/putter under selve registreringen. **Bekreftet direkte
+mot ekte `teecup_db` (kun lesing) at dette IKKE var en datafeil** --
+brukerens faktiske runde hadde `stat_level='full'` lagret korrekt. Rot-
+årsaken var et REELT presentasjonsproblem: alle detaljfeltene (kølle,
+utslag, innspill, chip, bunker, straffeslag, putt-avstand, anywayslag)
+lå bak en "Score"/"Statistikk"-fane (V0-runden 2026-07-24s bevisste
+designvalg) som brukeren aldri oppdaget -- "aktivert full statistikk"
+ga i praksis ingen synlig endring uten et ekstra, ikke-annonsert
+tastetrykk. **Fikset ved å fjerne fane-løsningen helt:** alle feltene
+vises nå ALLTID samlet under slag/putter i én sammenhengende scroll når
+`statLevel==="full"` (samme prinsipp brukeren opprinnelig ba om FØR
+V0-rundens sveip/fane-vurdering) -- fjerner enhver tvetydighet om
+hvorvidt statistikken faktisk er slått på. `PanelTabs`-komponenten og
+`panelTab`-state fjernet som død kode.
+**Samtidig bygget: "Så langt i runden"-oversikt**, direkte etterspurt
+("jeg trenger et grensesnitt som viser scoren min så langt") med
+referansebildene som inspirasjon for FUNKSJONEN (ikke kopiert
+utseendemessig). Ny komponent `ScoreSoFar` i `round-detail.tsx`: en
+kompakt alltid-synlig linje ("Så langt: X hull · Y slag · +Z til par")
+rett under spillerfanene, pluss en "Vis full oversikt"-knapp (samme
+etablerte mønster som `session-scorecard.tsx` sin `HoleSummaryTable`
+for turnering-scoring) som åpner en tabell: hull, par, score, netto,
+løpende sum. **Ny backend-beregning for å muliggjøre netto-kolonnen:**
+`RoundHoleOut` fikk et nytt felt `strokes_received` (`list_holes` i
+`app/routers/rounds.py`) -- utledet fra deltakerens
+`course_handicap_snapshot` + hullenes `stroke_index` via den
+ALLEREDE eksisterende `allocate_strokes_by_index()` fra
+`handicap_engine.py` (samme allokeringsalgoritme som brukes overalt
+ellers i appen, ingen ny logikk) -- `None` for en deltaker uten
+beregnet HCP (f.eks. en gjest uten oppgitt handicap), aldri lagret,
+kun beregnet ved lesing.
+**Scratch-verifisert grundig** (isolert `teecup_app_scratch`-rolle +
+isolert scratch-MinIO + engangs API-container): 11 sjekker, inkl. et
+presist talleksempel (course rating 72.0/slope 113/HCP 10.0 → course
+handicap nøyaktig 10, bekreftet at de 10 laveste stroke-indeksene fikk
+nøyaktig 1 slag hver og de resterende 8 fikk 0, sum(strokes_received)
+== course_handicap), et registrert hull som ga korrekt netto (score 5 −
+1 mottatt slag = 4), og en gjest UTEN HCP som korrekt fikk
+`strokes_received: null` på alle 18 hull. `test_isolation.sql` 12/12
+(ingen skjemaendring). Ekte typesjekket produksjonsbuild kompilerte
+rent.
+**Rullet ut live 2026-07-25**, bruker bekreftet eksplisitt: ingen
+migrasjon, kun `teecup_api`+`teecup_frontend` redeployet.
+`/health`/`/dashboard` → 200, `teeoff.no` upåvirket.
+
+**Reell produksjonsregresjon rapportert AV BRUKEREN samme dag, rett
+etter utrulling over, funnet og fikset umiddelbart:** "Ingenting er
+klikkbart i den avanserte statistikken." Første antagelse (frontend-
+CSS/event-håndtering) ble IKKE bekreftet ved kodegjennomgang -- all
+onClick-kabling i `DirectionCross`/`Stepper`/`ChoiceRow`/`NumberPicker`
+var korrekt. Root cause funnet ved å faktisk GJENSKAPE brukerens
+klikk-sekvens mot en fersk, isolert scratch-container (samme mønster
+som resten av runden) i stedet for å gjette videre: `update_hole`
+(PATCH-endepunktet for hull-registrering) konstruerte fortsatt
+`RoundHoleOut(**dict(row))` UTEN det nye påkrevde
+`strokes_received`-feltet fra runden rett over -- en Pydantic
+`ValidationError` (500) på HVER ENESTE hull-lagring, ikke bare de
+"avanserte" feltene. Frontend sin `updateStat()` svelger `!res.ok`
+stille uten feilmelding, så symptomet fremsto nøyaktig som "ingenting
+skjer når jeg trykker" for ALLE felt (Slag/Putter inkludert) -- brukeren
+merket det trolig først på de avanserte feltene siden Slag/Putter fra
+TIDLIGERE runder allerede hadde lagrede verdier som så riktige ut ved
+åpning.
+**Fikset:** `update_hole` beregner nå `strokes_received` for akkurat det
+oppdaterte hullet (henter deltakerens `course_handicap_snapshot` +
+ALLE 18 sine `stroke_index` -- samme allokeringsalgoritme som
+`list_holes`, siden fordelingen avhenger av hele rundens
+stroke-indeks-rekkefølge, ikke bare ett hull) og sender den med i
+responsen.
+**Scratch-verifisert på nytt, presist mot akkurat denne regresjonen:**
+14 sjekker som gjenskaper brukerens EKSAKTE klikk-rekkefølge (Slag →
+kølle → Utslag-retning → Innspill-retning → Chip → første putt-bøtte →
+Anywayslag, pluss et klikk på et avansert felt FØR Slag i det hele tatt
+er satt, og en gjest uten HCP) -- alle 200 med riktig ekko, `GET` etterpå
+bekrefter faktisk lagring, gjest uten HCP gir korrekt `strokes_received:
+null` uten å krasje. `test_isolation.sql` uendret (ingen skjemaendring,
+ren Python-fiks). **Rullet ut live 2026-07-25**, bruker bekreftet
+eksplisitt: kun `teecup_api` redeployet, `/health`/`/dashboard` → 200,
+`teeoff.no` upåvirket.
+
+**Rediger/Fullfør/Slett tonet ned og flyttet til toppen + auto-scroll ved
+hull-bytte, LIVE samme dag (2026-07-25):** brukeren rapporterte at
+"Fullfør runde"/"Slett runde" lå som store, fremtredende knapper RETT
+under "Neste hull"-navigasjonen nederst i hull-panelet -- altfor lett å
+trykke feil ved et uhell mens man bare skulle bla mellom hull. Flyttet
+alle tre (Rediger/Fullfør/Slett) til en samlet rad ØVERST på siden,
+tonet ned til samme nøytrale "trigger"-stil (ikke lenger store,
+fargede knapper) -- brukeren må nå aktivt scrolle OPP forbi hele
+hull-registreringen for å nå dem. Samtidig rapportert, i samme runde:
+"Neste hull"/"Forrige" lastet nytt innhold, men brukeren ble stående
+scrollet nede der knappene er, med det nye hullets Slag-felt utenfor
+skjermen. Løst med `holePanelRef` + `scrollIntoView({block:"start"})`
+kalt fra `goPrev`/`goNext` OG fra hull-navigasjonens direkte hull-valg,
+med `scroll-mt-28` på panelet for å unngå at den sticky headeren dekker
+toppen. Ren frontend-endring, ingen backend/migrasjon. Ekte typesjekket
+build kjørt og bekreftet (alle 19 ruter), rullet ut, `teeoff.no`
+upåvirket.
+
+**"Så langt i runden" utvidet med netto/stableford-sum, putt-/kølle-
+statistikk-totaler og grafisk fairway-/innspill-fordeling, LIVE samme
+dag (2026-07-25):** brukeren etterspurte flere detaljer i
+rundeoversikten: netto- og stableford-sum, hvor man kan se totalt antall
+putter/chip/bunker/straffeslag/anywayslag for runden, grafisk fremstilt
+prosentvis fordeling av fairwaytreff og innspillstreff, og gjennomsnittlig
+score til par (to desimaler) splittet på fairwaytreff-vs-bom og
+innspill-treff-vs-bom.
+**Ingen backend-endring nødvendig** -- alt beregnes klientside fra data
+`GET .../holes` allerede returnerer (score/par/strokes_received/putts/
+chip_count/bunker_shot_count/penalty_strokes/tee_shot_result/
+approach_result/anyway_strokes). `ScoreSoFar`-komponenten
+(round-detail.tsx) utvidet med: en `StatPill`-rutenett (Slag/Til par/
+Netto/Stableford/Putt/Chip/Bunker/Straffeslag/Anywayslag -- hver vist
+kun hvis det faktisk finnes registrert data for akkurat det feltet), en
+ny Stableford-kolonne i hull-for-hull-tabellen (kun når netto er
+beregnbart), og to nye `DistributionBar`-seksjoner (Fairwaytreff/
+Innspill) -- generalisert N-kategori-variant av samme visuelle idé som
+`SegmentedBar` i tournament-leaderboard.tsx (ett fargesegmentert
+rektangel + prosent-legend), ikke noe chart-bibliotek lagt til.
+**Presisert i kode-kommentar, bevisst valg:** appen har ingen egen
+"spilleform"-innstilling for frittstående runder -- stableford beregnes
+derfor alltid ut fra netto score når det er mulig (krever registrert
+HCP, samme forutsetning som netto), uavhengig av om brukeren
+"egentlig" spiller slagspill eller stableford. Standard stableford-
+poengtabell brukt (netto par = 2 poeng, ett poeng mer/mindre per slag
+bedre/dårligere enn par, gulv på 0).
+Gjennomsnittlig score-til-par (fairway/innspill, treff-vs-bom) bruker
+BRUTTO score (ikke netto) relativt til par, formatert med fortegn og to
+desimaler (`formatSignedAvg`), matcher brukerens eksplisitte
+spesifikasjon. Fairwaytreff ekskluderer par-3-hull (samme regel som
+registrerings-skjemaet, som aldri viser Utslag-retning der).
+**Logikken verifisert manuelt mot et regnet eksempel** (4 hull, blandet
+par 3/4/5, ulike utslag-/innspillresultater) FØR utrulling -- stableford-
+sum, netto-sum og begge gjennomsnitts-splittene stemte med
+håndregning. Ekte typesjekket produksjonsbuild kjørt og bekreftet (alle
+19 ruter). **Rullet ut live 2026-07-25**, bruker bekreftet eksplisitt:
+ren frontend-endring, ingen migrasjon, `/health`/`/my-rounds` → 200,
+`teeoff.no` upåvirket.
+
+**Rundestatistikk-skjerm (dypdykk), inspirert av en konkurrent-video,
+BYGGET OG LIVE samme dag (2026-07-25):** brukeren lastet opp en 26
+sekunders skjermopptaksvideo av en KONKURRENT-apps statistikkskjerm og
+ba eksplisitt om et V0-prompt inspirert av innholdet, IKKE et plagiat.
+Video analysert bilde for bilde (ffmpeg kjørt i en engangs Docker-
+container, ikke installert på verten -- ryddet opp etterpå). Innhold
+identifisert: score-fordeling (par/bogey/dobbel bogey/verre),
+snitt-til-par per hulltype, fairwayfordeling + score-splitt, GIR-donut +
+per-hulltype + kryss med fairway + score-splitt, bom-retning på green
+som et kompass-diagram, putt-fordeling (1/2/3-putt) + snitt per hulltype
++ med/uten GIR, én-putt% etter puttlengde + lengdefordeling hit/miss,
+chip-fordeling, scrambling%/sand save%, bunker/straffeslag per runde +
+score-splitt.
+**Bevisste valg for å unngå plagiat, skrevet inn i selve V0-promptet:**
+egen visuell identitet (TeeCups presise grønn/oransje, ikke konkurrentens
+fargekoding), fritt valg av chart-type/layout/rekkefølge til V0 selv,
+INGEN kopiering av konkurrentens eksakte ordlyd/fargekoding/ikonografi.
+Puttlengde-bøttene i promptet er TeeCups EGNE seks bøtter
+(<1m/<2m/<3m/<5m/<8m/8m+, samme som ADR-033 allerede lagrer) -- bevisst
+ANDRE enn videoens fem bøtter (<1m/1-2/2-4/4-8/+), både fordi det unngår
+en direkte kopi og fordi det er det datamodellen faktisk allerede
+produserer. "Lengste drive" (krever GPS/avstandsmåling appen ikke har)
+utelatt fra promptet.
+**Zip 14 mottatt og integrert samme dag:** diffet mot live-treet FØR noe
+ble tatt inn (samme rutine som alltid) -- kun to reelt nye filer
+(`components/round-stats.tsx`, en ny `RoundStats`-skjerm bygget med
+kollapsbare `StatCard`-seksjoner, conic-gradient-donuter med sentertall,
+avviks-stolper fra en null-linje, og et kompass-rutenett for bom-retning
+-- en tydelig ANNEN visuell løsning enn konkurrentens skjermbilder, ikke
+en klone). Resten av eksporten var V0s vanlige uvitende reverts, inkl.
+sin egen `/rounds/[id]`-ruteversjon fra FØR `/my-rounds`-omdøpingen
+(se lenger opp, "Reell produksjonsbug...") -- korrekt hoppet over. Ny
+rute lagt til som `app/my-rounds/[id]/stats/page.tsx` (ikke
+`app/rounds/[id]/stats` som eksporten foreslo), samme
+kollisjon-unngåelse. `app/globals.css` sin nye `--chart-1..6`
+data-viz-fargeskala (god->dårlig-skala, brukt sammen med
+tekst-/tall-etiketter) slått sammen inn i alle tre temablokkene;
+V0s egne, mer omtrentlige `--primary`/`--ring`/`--brand-orange`-verdier
+i SAMME diff ble bevisst IKKE tatt inn -- beholdt de presise OKLCH-
+verdiene utregnet i ADR-016.
+**Datalag skrevet fullstendig om fra mock:** ny `computeStats()`-
+funksjon i `round-stats.tsx` regner ut alt fra rå `GET .../holes`-data
+(samme endepunkt round-detail.tsx allerede bruker -- ingen ny backend).
+Hver seksjon skjules helt når det ikke finnes nok data for den (samme
+"vis kun det som faktisk finnes"-prinsipp som `ScoreSoFar`). Ny enkel
+spillervelger (pill-rad) lagt til når runden har flere deltakere,
+default til eieren. `CompletedBanner` i round-detail.tsx fikk en "Se
+full rundestatistikk"-lenke (fantes i V0s egen, ellers reverterte fil --
+portert manuelt inn i vår live versjon i stedet for å ta hele filen).
+**Matematikken verifisert FØR utrulling, ikke bare "kompilerer":**
+`computeStats()`-logikken portert til et frittstående Node-script og
+kjørt mot et hånd-etterregnet 6-hulls syntetisk datasett (blandet par
+3/4/5, fairwaytreff/-bom, GIR-treff/-bom, bunkerslag) -- alle utledede
+tall (score-kategorier, snitt-til-par per hulltype, fairway-splitt,
+GIR%/kryss-fairway/score-splitt, bom-retning, putt-fordeling,
+scrambling%, sand save%) stemte med manuell utregning. Ekte typesjekket
+produksjonsbuild kjørt og bekreftet (`/my-rounds/[id]/stats` listet som
+ny rute).
+**Rullet ut live 2026-07-25**, ren frontend-endring, ingen migrasjon,
+`/health`/`/my-rounds` → 200, `teeoff.no` upåvirket.
+
+**Rundeliste-info + scorekort-redesign, BYGGET OG LIVE samme dag
+(2026-07-25):** brukeren delte en ny skjermopptaksvideo (video 2, 18
+frames analysert ved 1,5 fps) av to problemer: "Egne runder"-listen
+manglet ALL score-informasjon (kun tee/hull/dato/spillerantall/status),
+og selve scorekort-registreringen (rapportert "veldig dårlig
+designet") stablet fem ulike kontrolltyper (numpad, retningskors,
+steppere, pill-rutenett, pill-rad) uten hierarki, pluss at "Runde
+fullført"-siden gjentok NØYAKTIG samme tall tre ganger (CompletedBanner-
+differensial, "Så langt"-oppsummeringslinjen, og StatPill-rutenettet
+under). Bedt om å reflektere kort og eventuelt skrive V0-prompt(er).
+**Reflektert og handlet i samme runde** (ikke bare skrevet ned): pekte ut
+at score/til-par mangler helt fra listekortet som det klareste,
+konkrete hullet; anbefalte å samle alt utover Slag/Putter bak én
+kollapsbar "Flere detaljer"-seksjon som den viktigste enkeltfiksen for
+scorekort-rotet; og fikset duplikat-problemet PÅ "Runde fullført"-siden
+DIREKTE (ikke via V0) siden det bare er snakk om å SKJULE innhold, ikke
+designe noe nytt: `ScoreSoFar` skjules nå helt når runden er fullført
+(`{!completed && }`) -- CompletedBanner sin "Se full
+rundestatistikk"-lenke dekker akkurat det samme, langt grundigere.
+**Ny backend-beregning FØR V0-prompten** (slik at prompten kunne
+referere til ekte, tilgjengelig data): `_load_round_out`
+(`app/routers/rounds.py`) kjører nå en liten aggregatspørring mot
+`round_hole` for eierens egen deltaker-rad ved hver lasting --
+`owner_holes_played`/`owner_total_score`/`owner_score_to_par` (null
+til minst ett hull er registrert). Verifisert med 10 scratch-sjekker,
+inkl. at en gjests egen score IKKE lekker inn i eierens aggregat.
+**To V0-prompter skrevet** (round-card-redesign med prominent
+score-flis/hull-fremdrift-bar/differensial; scorekort-redesign med
+Slag+Putter+Avstand-første-putt alltid synlig og alt annet bak "Flere
+detaljer", pluss en bevisst ikke-bygget reservasjon av layout-plass for
+en fremtidig avstandsmåling-funksjon brukeren bekreftet er planlagt).
+**Zip 15 og 16 mottatt samme dag** (samme v0.app-prosjekt, kontinuerlig
+-- `round-card.tsx`/`own-rounds.tsx` byte-for-byte identiske i begge
+zip-ene; zip 16s `round-detail.tsx` var den nyeste med selve
+kollaps-redesignet, zip 15s tilsvarende fil manglet det og ble derfor
+forkastet til fordel for zip 16).
+`round-card.tsx`: ny `ScoreTile` -- prominent resultat+til-par-flis
+(fargekodet under/over par uten å stole på farge alene, tekst+tall
+alltid med) for fullførte/scorede runder, en hull-fremdrift-progressbar
+("6/18 hull spilt") for runder som fortsatt pågår, pluss en HCP-
+differensial-chip i metadata-raden når runden faktisk telte. Fullt
+`aria-label` på hele kortet for skjermlesere. `own-rounds.tsx` sitt
+datalag skrevet om fra mock til ekte fetch, kobler de nye `owner_*`-
+feltene fra backend + eierens `score_differential` (kun vist når
+`counts_for_handicap`).
+`round-detail.tsx`: ny kollapsbar "Flere detaljer"-seksjon (lukket som
+default, `ChevronDown`-rotasjon på toggle) som nå rommer kølle/utslag-
+retning/innspill-retning/chip-bunker-straffeslag/anywayslag -- Slag,
+Putter og Avstand første putt forblir alltid synlig over kollapsen,
+uendret rekkefølge fra den forrige runden. **Viktig integrasjonsdisiplin:**
+V0s eksport hadde reversert til en MYE eldre mock-baseline (manglet
+StatLevel-gating, Anywayslag, bøtte-basert puttlengde, kølle-bag fra
+profil, maxValue-capping, "Hullet er spilt"-avkrysningen som bevisst BLE
+FJERNET en tidligere runde, "Tid brukt" i CompletedBanner) -- kun selve
+kollaps-mekanismen og plasseringen av "Flere detaljer" ble hentet ut og
+lagt oppå den fullt oppdaterte, LIVE koden. Ingen av de tidligere
+byggede funksjonene gikk tapt. Lagt til en kort kode-kommentar (ikke
+noe bygget UI) som reserverer plass ved siden av hull-headeren til en
+fremtidig avstandsmåling-indikator.
+**Verifisert:** ekte typesjekket produksjonsbuild kjørt og bekreftet
+(alle 19 ruter). Ingen ny scratch-backend-runde nødvendig utover
+owner-score-testen over (ingen ny domenelogikk i selve rundeliste-/
+scorekort-visningen, kun lesing av allerede-testede felt).
+**Rullet ut live 2026-07-25**, ren frontend-endring + den lille
+backend-tilføyelsen over, ingen migrasjon, `/health`/`/my-rounds` →
+200, `teeoff.no` upåvirket.
+
+**Manglende scorekort på statistikk-siden, funnet og fikset SAMME dag
+(2026-07-25):** brukeren spurte rett etter forrige runde: "Hvor er
+scorekortet? (Gjerne også med statistikk?)" -- et ekte, uforutsett hull
+i forrige rundes endring. Da `ScoreSoFar` ("Så langt i runden") ble
+skjult for fullførte runder (for å fjerne dobbel informasjon, se over),
+forsvant OGSÅ det eneste stedet den rå hull-for-hull-tabellen (Hull/
+Par/Score/Netto/Sum) fantes -- ingen tilsvarende tabell ble noensinne
+lagt til på den nye `round-stats.tsx`-siden, som kun inneholdt UTLEDET/
+aggregert statistikk (donuter, kategori-stolper, avviks-visualiseringer),
+aldri de faktiske rå tallene per hull. Med andre ord: brukeren fikk
+riktignok fjernet duplikatet, men mistet samtidig tilgang til selve
+scorekortet -- en reell regresjon, ikke bare en presentasjonsdetalj.
+**Fikset ved å legge til en ny "Scorekort"-seksjon FØRST på
+`round-stats.tsx`** (før "Scorer"-kategoriseksjonen), åpen som default
+(i motsetning til resten av seksjonene som starter kollapsbare men
+åpne -- denne er det brukeren eksplisitt spurte etter, så den skal ikke
+kreve et ekstra trykk). Samme tabellmønster som `ScoreSoFar` sin
+tidligere tabell hadde (Hull/Par/Score/Netto/Stableford/Sum, Stableford-
+kolonnen vist kun når netto er beregnbart). To type-tilføyelser var
+nødvendig: `start_hole: number` lagt til `round-stats.tsx` sin
+`ApiRound`-type (manglet fra før, siden ingen tidligere seksjon på
+denne siden trengte rundens faktiske start-/rekkefølge) og
+`strokes_received: number | null` lagt til `ApiHole`-typen (feltet kom
+allerede fra backend -- lagt til i forrige runde for `list_holes` --
+men ble aldri lest av denne siden før nå). Ny `holeOrder`/
+`orderedHoles`-beregning i `RoundStats` gjenbruker EKSAKT samme
+sirkulære start_hole-formel som round-detail.tsx, slik at en 9-hulls
+runde som starter på hull 10 vises i riktig spillerekkefølge (10-18),
+ikke bare rå hullnummer 1-9.
+**Lærdom notert for fremtidige runder:** når et helt panel flyttes/
+skjules for å fjerne duplisert informasjon, må hver del av det gamle
+panelet spores til et nytt hjem FØR det fjernes -- ikke bare de delene
+som åpenbart var "statistikk". Denne runden ble oppdaget kun fordi
+brukeren faktisk lette etter scorekortet rett etterpå, ikke ved egen
+verifisering før utrulling.
+Ekte typesjekket produksjonsbuild kjørt og bekreftet. **Rullet ut live
+2026-07-25**, ren frontend-endring, ingen backend/migrasjon,
+`teeoff.no` upåvirket.
+
+**Scorekort-visning: ny presentasjonsregel + V0-prompt skrevet, IKKE
+bygget ennå (2026-07-25):** brukeren delte et referansebilde av et
+tradisjonelt fysisk golf-scorekort (horisontal layout, hull 1-9/10-18
+som KOLONNER, Slope/Par/Score/Net som rader, "Ut"/"Inn"-sum-kolonne
+YTTERST TIL HØYRE for hver ni-hulls-halvdel) og formulerte en generell
+presentasjonsregel: **listes hullene horisontalt (som kolonner), skal
+summeringen stå TIL HØYRE; listes hullene vertikalt (som rader), skal
+summeringen stå UNDER.** Den nylig byggede "Scorekort"-seksjonen på
+`round-stats.tsx` (se punktet rett over) lister hull VERTIKALT (én rad
+per hull) med en løpende sum-KOLONNE innimellom hver rad -- ikke i tråd
+med regelen (en vertikal liste burde hatt en avsluttende sumrad
+UNDERST, ikke en kolonne). Bedt om å tenke gjennom dette og skrive et
+V0-prompt for et "fabelaktig" scorekort inspirert av (ikke et plagiat
+av) referansebildet.
+**Bevisste avvik fra referansebildet for å unngå plagiat, skrevet inn i
+selve promptet:** egen visuell identitet (TeeCups grønn/oransje, ikke
+bildets rød-sirkel/blå-firkant-fargekoding for birdie/bogey), egen
+term ("Hcp" for hullets slag-fordelings-rangering -- IKKE "Slope", som
+i golf-terminologi betyr banens/tee-ens helhetlige vanskelighetsgrad,
+et helt annet tall enn det bildet faktisk viser per hull), en ekstra
+Stableford-rad (finnes ikke i referansen, men vi beregner det allerede
+andre steder), og INGEN kopiering av bildets spiller-header-komposisjon
+(navn/HCP/posisjon-boksen) -- kun selve tabell-strukturen er
+inspirasjonskilden.
+**Presist håndtert i promptet, IKKE triviell:** appen støtter allerede
+vilkårlig `start_hole` + `holes_planned` (9 ELLER 18, sirkulær
+rekkefølge, se "Manglende scorekort"-punktet over) -- en STIV
+fysisk "hull 1-9 er alltid Ut" ville vært feil for en 9-hulls runde som
+starter på hull 10. Promptet ber derfor om ÉN 9-kolonners blokk når
+`holes_planned=9`, TO blokker (første/andre halvdel AV SPILLEREKKEFØLGEN,
+ikke nødvendigvis fysisk hull 1-9/10-18) når `holes_planned=18` -- den
+faktiske hull-til-blokk-tildelingen løses av meg i datalaget ved
+integrering, som med alle tidligere V0-runder.
+**Venter på V0-eksport** før noe bygges. Når den kommer, erstatter den
+den eksisterende vertikale "Scorekort"-tabellen på `round-stats.tsx`
+(bygget rett over samme dag) -- ikke en ny, separat skjerm.
+**Notert som en generell prinsipp-lærdom, relevant utover akkurat dette
+scorekortet:** samme horisontal-til-høyre/vertikal-til-under-regel bør
+vurderes senere for turnering-scorekortet (`session-scorecard.tsx`,
+match-play) den dagen det scorekortet også skal pusses -- ikke i
+omfang nå, bare notert for konsistens.
+
+**Presisering av promptet samme dag, FØR noe ble sendt til V0:**
+brukeren spurte eksplisitt om et "if REALLY necessary"-unntak for
+horisontal scroll (opprinnelig formulering) faktisk fanget opp målet
+om ALDRI å måtte scrolle. Vurdert og svart nei -- reell breddekonflikt,
+ikke bare en formulering-detalj: 9 hull + 1 sum-kolonne (+ en
+label-kolonne) får ikke plass på en telefonskjerm med normal
+"lesbar uten briller"-tekststørrelse, og et unntak formulert som en
+myk fallback ville sannsynligvis latt V0 falle tilbake til scroll uansett,
+siden tilgjengelighetskravet rett under ga et påskudd. **Løst ved å
+gjøre "ingen scroll" til et HARDT krav i promptet, OG eksplisitt fortelle
+V0 hvordan det oppnås** (kompakte, fete, høykontrast-siffer i selve
+rutenettet -- samme konvensjon som et fysisk scorekort bruker, også
+synlig i brukerens eget referansebilde -- mens "lesbar uten
+briller"-kravet eksplisitt avgrenses til labels/knapper/løpetekst, ikke
+hvert enkelt rutenett-siffer). Smale forkortede rad-labels ("Hcp",
+"Par", "Score", "Netto") i en trang venstre-gutter i stedet for en bred
+tekstkolonne, for å frigjøre bredde til de 9 hull-kolonnene.
+
+**Zip 17 mottatt, horisontalt scorekort BYGGET OG LIVE samme dag
+(2026-07-25):** V0 leverte akkurat det det reviderte promptet ba om --
+en EKTE HTML `
` med `
` (fast `w-9`-label-kolonne, auto
+for hver hull-kolonne, `w-[11%]` sum-kolonne) og `table-fixed`, ingen
+scroll-container noe sted. Score-cellene bruker FORM (sirkel = under
+par, firkant = over par) + fylt/ufylt (fylt = 2+ slag av) i stedet for
+farge alene, pluss en egen liten symbolforklaring under rundesammendraget
+-- tilfredsstiller "aldri stole på farge alene" uten å kopiere
+referansebildets rød-sirkel/blå-firkant-konvensjon.
+**Egen, ny dedikert side** `/my-rounds/[id]/scorecard`
+(`components/round-scorecard.tsx`, ny `app/my-rounds/[id]/scorecard/
+page.tsx`) -- IKKE slått sammen inn i `round-stats.tsx`, siden V0
+designet komponenten med sin egen fulle side-chrome (sticky header,
+rundesammendrag-strip), ikke som et innebygd tabell-fragment. Dette gir
+en klar arbeidsdeling: `round-scorecard.tsx` = det rå scorekortet,
+`round-stats.tsx` = utledet/aggregert statistikk -- samme prinsipp som
+allerede etablert for `ScoreSoFar` vs. `round-stats.tsx` tidligere denne
+økten.
+**Bevisst forkastet fra V0s eksport:** V0s egen `strokesReceived()`-
+funksjon var en generisk `Math.floor(hcp/18) + (index <= hcp%18 ? 1 :
+0)`-modulo-formel -- byttet ut med backend sin ALLEREDE beregnede
+`strokes_received` per hull (samme `allocate_strokes_by_index()` som
+resten av appen bruker), for å unngå to parallelle, potensielt
+avvikende implementasjoner av HCP-slagfordeling i samme app. Samme
+sirkulære `start_hole`-rekkefølge som `round-detail.tsx`/
+`round-stats.tsx` bruker for Ut/Inn-blokkene. Ny spillervelger
+(pill-rad) lagt til for runder med flere deltakere, samme mønster som
+`round-stats.tsx`.
+**Opprydning i `round-stats.tsx`:** den midlertidige vertikale
+"Scorekort"-tabellen (bygget tidligere samme dag som en rask fiks for
+"Hvor er scorekortet?") er FJERNET og erstattet med en enkel, prominent
+"Se scorekort"-lenke til den nye siden, rett under rundesammendraget --
+`round-stats.tsx` er dermed nå rendyrket aggregert/utledet statistikk,
+det rå scorekortet finnes kun ett sted. `stablefordPoints()`-
+hjelpefunksjonen og `holeOrder`/`orderedHoles`-beregningen i
+`round-stats.tsx`, som kun eksisterte for den fjernede tabellen, fjernet
+som dødt kode.
+**V0 la selv til en to-knappers layout i `CompletedBanner`**
+(round-detail.tsx) -- "Se scorekort" (primær, fylt) ved siden av den
+eksisterende "Se full rundestatistikk" (sekundær, omrisset) -- tatt inn
+uendret bortsett fra å rette `/rounds/...`-hrefs til `/my-rounds/...`.
+**Samtidig, urelatert, rapportert av bruker midt i integreringen:**
+Anywayslag manglet helt fra `round-stats.tsx` sin "Chip, bunker og
+straffeslag"-seksjon (verken `anyway_strokes` i `ApiHole`-typen eller
+noe utledet total fantes). Lagt til `anyway_strokes` i typen, ny
+`anywayPerRound`-aggregat i `computeStats()`, ny generalisert
+`StatTileRow`-komponent (2 ELLER 3 fliser -- `StatTilePair` var fast to)
+brukt for Bunkerslag/Straffeslag/(Anywayslag når tilgjengelig).
+Seksjonen omdøpt fra "Chip, bunker og straffeslag" til "Annet" (bredere
+navn, bruker nevnte at et fritekst-notatfelt trolig havner der senere).
+**Verifisert:** ekte typesjekket produksjonsbuild kjørt og bekreftet,
+ny rute `/my-rounds/[id]/scorecard` listet. Ingen ny backend-endring
+(`anyway_strokes`/`strokes_received` fantes allerede i `RoundHoleOut`).
+**Rullet ut live 2026-07-25**, ren frontend-endring, ingen migrasjon,
+`teeoff.no` upåvirket.
+
**Motor-komponenten (punkt 1-11) er ✅ BYGGET OG TESTET 2026-07-22,**
som første, isolerte byggesteg (ren Python, ingen DB/API/frontend ennå —
matcher ADR-005s "test i isolasjon FØR resten"). Nye funksjoner i
diff --git a/CLAUDE.md b/CLAUDE.md
index d98c969..d75c7b9 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -2314,6 +2314,231 @@ Ferdig og verifisert:
avstand mot alle 174 teeoff-anlegg, geolokasjon i nettleseren, feiler
stille hvis avslått). 14 nye scratch-sjekker inkl. et ekte nearby-kall
mot teeoff. Full detalj i ADR-033.
+- **Reell UX-bug fikset + "Så langt i runden"-oversikt bygget, samme
+ dag (2026-07-25), klar for utrulling:** brukeren rapporterte at "All
+ statistikk" ikke viste noe utover slag/putter -- bekreftet (kun
+ lesing) mot ekte `teecup_db` at `stat_level='full'` FAKTISK var
+ lagret riktig, så feilen var presentasjonen: alle detaljfeltene lå
+ bak en "Score"/"Statistikk"-fane fra forrige V0-runde som brukeren
+ aldri oppdaget. Fikset ved å fjerne faneløsningen helt -- alt vises nå
+ alltid samlet. Samtidig bygget en ny "Så langt"-oversikt
+ (`ScoreSoFar`-komponent: kompakt linje + utvidbar full-oversikt-
+ tabell med netto per hull), med et nytt backend-felt
+ `strokes_received` (`allocate_strokes_by_index()`, ingen ny
+ algoritme). 11 nye scratch-sjekker (inkl. et presist tall-eksempel på
+ slagfordelingen), ren build. Full detalj i ADR-033.
+ **Rullet ut live 2026-07-25**, bruker bekreftet eksplisitt: kun
+ `teecup_api`+`teecup_frontend` redeployet, ingen migrasjon,
+ `/health`/`/dashboard` → 200, `teeoff.no` upåvirket.
+- **Reell produksjonsregresjon rapportert av bruker rett etter utrullingen
+ over, funnet og fikset umiddelbart samme dag (2026-07-25):**
+ "Ingenting er klikkbart i den avanserte statistikken." Root cause var
+ IKKE frontend (all onClick-kabling var korrekt) -- funnet ved å faktisk
+ gjenskape brukerens klikk-sekvens mot en fersk scratch-container:
+ `update_hole` (hull-PATCH) manglet fortsatt det nye påkrevde
+ `strokes_received`-feltet i responsen sin (lagt til i GET-endepunktet i
+ runden rett over, glemt i PATCH) -- ga en 500 (Pydantic-valideringsfeil)
+ på HVER hull-lagring, ikke bare de avanserte feltene. Frontend svelger
+ feilresponsen stille, så symptomet så ut som "ingenting skjer" for
+ ALT, ikke bare avansert statistikk (brukeren merket det trolig først
+ der siden Slag/Putter fra tidligere runder allerede hadde lagrede
+ verdier som så riktige ut). Fikset: `update_hole` beregner nå
+ `strokes_received` for hullet som oppdateres, samme algoritme som
+ `list_holes`. 14 scratch-sjekker som gjenskaper eksakt klikk-
+ rekkefølgen, alle bestått. **Rullet ut live 2026-07-25**, bruker
+ bekreftet eksplisitt: kun `teecup_api` redeployet, `/health`/
+ `/dashboard` → 200, `teeoff.no` upåvirket.
+- **Rediger/Fullfør/Slett tonet ned + flyttet til toppen, auto-scroll ved
+ hull-bytte, LIVE samme dag (2026-07-25):** brukeren rapporterte at
+ "Fullfør runde"/"Slett runde" var for lette å trykke på ved et uhell
+ (lå rett under "Neste hull"). Flyttet alle tre handlingene til en
+ nedtonet rad øverst -- må nå aktivt scrolles til. Samtidig: "Neste
+ hull"/"Forrige" scroller nå automatisk opp til toppen av hull-panelet
+ (også ved direkte hull-valg), så det nye hullets Slag-felt alltid er
+ synlig med en gang. Ren frontend-endring, ingen backend/migrasjon.
+ Rullet ut, `teeoff.no` upåvirket.
+- **"Så langt i runden" utvidet med netto/stableford-sum, putt-/kølle-
+ statistikk-totaler og grafisk fairway-/innspill-fordeling, LIVE samme
+ dag (2026-07-25):** etterspurt av bruker. Ny `StatPill`-rutenett
+ (Slag/Til par/Netto/Stableford/Putt/Chip/Bunker/Straffeslag/
+ Anywayslag), Stableford-kolonne i hull-tabellen, og to nye
+ `DistributionBar`-seksjoner (Fairwaytreff/Innspill, N-kategori-variant
+ av `SegmentedBar`-mønsteret fra tournament-leaderboard.tsx) +
+ gjennomsnittlig brutto score-til-par (to desimaler, fortegn) splittet
+ på treff-vs-bom for både fairway og innspill. Ingen backend-endring --
+ alt beregnes klientside fra data `GET .../holes` allerede returnerer.
+ Stableford beregnes alltid ut fra netto score når mulig (appen har
+ ingen egen "spilleform"-innstilling). Logikk verifisert manuelt mot et
+ regnet eksempel før utrulling. Ren frontend-endring, ingen migrasjon,
+ rullet ut, `teeoff.no` upåvirket.
+- **"Avstand første putt" flyttet rett under "Putter", LIVE samme dag
+ (2026-07-25):** lå tidligere lenger ned i "full"-statistikk-blokken
+ (etter kølle/retning/chip-gruppen) -- flyttet til å bli første felt i
+ den blokken, rett under Putter-NumberPickeren (som ligger utenfor
+ "full"-gaten). Ren omrokkering, ingen ny logikk. Ekte typesjekket
+ build, rullet ut, `teeoff.no` upåvirket.
+- **V0-prompt for en rikere rundestatistikk-skjerm skrevet, IKKE bygget
+ ennå (2026-07-25):** brukeren lastet opp en skjermopptaksvideo
+ (`screen-20260724-133013-1784892586987.mp4`, 26 sek, av en KONKURRENT-
+ apps statistikkskjerm) og ba om et V0-prompt inspirert av innholdet,
+ eksplisitt IKKE et plagiat. Video analysert bilde for bilde (ffmpeg i
+ en engangs Docker-container, ikke installert på verten). Innholdet
+ identifisert dekkes i stor grad av data vi ALLEREDE sporer
+ (fairwaytreff/innspill-retning/putts/chip/bunker/straffeslag/putt-
+ lengde-bøtte) -- ingen backend-endring skulle trengtes for de fleste
+ målene. Prompt skrevet til bruker i chatten (ikke lagret som egen
+ fil) -- beskriver mål/informasjonsarkitektur/tilgjengelighetskrav
+ abstrakt (donut med sentertall, gauge-stolper for avvik fra par,
+ retnings-diagram for bom-retning) UTEN å kopiere konkurrentens
+ eksakte fargevalg/layout/ordlyd, og ber eksplisitt om TeeCups egen
+ merkevareidentitet (grønn/oransje) + en egen visuell vri.
+ **Én bevisst forskjell fra videoen, valgt for å unngå plagiat OG fordi
+ det matcher vårt eget datamodell:** videoens puttlengde-bøtter
+ (<1m/1-2/2-4/4-8/+) er ANDRE enn TeeCups allerede lagrede seks bøtter
+ (<1m/<2m/<3m/<5m/<8m/8m+, ADR-033) -- promptet ber om TeeCups egne
+ bøtter, ikke videoens. "Lengste drive" (krever GPS/avstandsmåling vi
+ ikke har) bevisst utelatt fra promptet.
+ **Bygget og rullet ut live 2026-07-25, samme dag:** zip 14 mottatt.
+ Diffet mot live-treet FØR noe ble tatt inn (samme rutine som alltid) --
+ kun to reelt nye filer (`components/round-stats.tsx`,
+ `app/rounds/[id]/stats/page.tsx`), resten var V0s vanlige uvitende
+ reverts (bl.a. sin egen `/rounds/[id]`-ruteversjon fra FØR
+ `/my-rounds`-omdøpingen ADR-033 gjorde 2026-07-23 -- korrekt hoppet
+ over). Ruten lagt inn som `app/my-rounds/[id]/stats/page.tsx` i stedet
+ (samme kollisjon-unngåelse). `globals.css` sin nye `--chart-1..6`
+ data-viz-fargeskala slått sammen inn (V0 sine egne, mer omtrentlige
+ `--primary`/`--ring`/`--brand-orange`-verdier IKKE tatt inn -- beholdt
+ de presise OKLCH-verdiene fra ADR-016).
+ **Datalag skrevet fullstendig om fra mock:** henter `GET /rounds/{id}`
+ + `GET .../participants/{id}/holes` (samme endepunkter round-detail.tsx
+ allerede bruker) -- ingen ny backend. Ny `computeStats()`-funksjon
+ regner ut ALT fra rå hull-data ved lesing (score-kategorier,
+ snitt-til-par totalt/per hulltype, fairway-fordeling + score-splitt,
+ GIR totalt/per hulltype/kryss-fairway + score-splitt, bom-retning på
+ green, putt-fordeling 1/2/3-putt + snitt per hulltype + med/uten GIR,
+ én-putt% per TeeCups egne seks puttlengde-bøtter + lengdefordeling
+ hit/miss, chip-fordeling, scrambling%, sand save%, bunker/straffeslag
+ per runde + score-splitt). Hver seksjon skjules helt når det ikke
+ finnes nok data (samme "vis kun det som faktisk finnes"-prinsipp som
+ "Så langt i runden"). Ny enkel spillervelger (pill-rad) lagt til når
+ runden har flere deltakere -- default til eieren.
+ **"Se full rundestatistikk"-lenke** lagt inn i `CompletedBanner` i
+ round-detail.tsx (V0s egen versjon hadde denne, men i sin ellers
+ fullstendig reverterte fil -- portert manuelt inn i vår LIVE versjon
+ i stedet for å ta hele filen).
+ **Matematikken verifisert FØR utrulling:** `computeStats()`-logikken
+ portert til et frittstående Node-script og kjørt mot et
+ hånd-etterregnet 6-hulls syntetisk datasett (blandet par 3/4/5,
+ fairwaytreff/-bom, GIR-treff/-bom, bunkerslag) -- alle 15+ utledede
+ tall stemte eksakt med manuell utregning. Ekte typesjekket
+ produksjonsbuild kjørt og bekreftet (`/my-rounds/[id]/stats` listet
+ som ny rute).
+ **Rullet ut live 2026-07-25**, ren frontend-endring, ingen migrasjon,
+ `docker compose up -d --build teecup_frontend`, `/health`/`/my-rounds`
+ → 200, `teeoff.no` upåvirket.
+- **Rundeliste + scorekort-redesign, LIVE samme dag (2026-07-25):**
+ brukeren delte en ny skjermopptaksvideo av "Egne runder"-listen (som
+ manglet ALL score-informasjon) og av scorekort-registreringen (rapportert
+ som "veldig dårlig designet" -- for mange ulike knapp-typer stablet
+ oppå hverandre) + "Runde fullført"-siden (rapportert som "veldig mye
+ dobbel informasjon"). Reflektert over problemstillingen (kort, per
+ brukerens ønske) før to V0-prompter ble skrevet.
+ **Fikset direkte, uten V0:** "Runde fullført"-duplikatet -- `ScoreSoFar`
+ ("Så langt i runden") skjules nå helt når runden er fullført, siden
+ den nye rundestatistikk-siden dekker akkurat det samme, langt
+ grundigere. Ny backend-beregning i `_load_round_out`
+ (`app/routers/rounds.py`): `owner_holes_played`/`owner_total_score`/
+ `owner_score_to_par`, en enkel aggregatspørring mot `round_hole` for
+ eierens egen deltaker-rad -- verifisert med 10 scratch-sjekker
+ (inkl. at en gjests score IKKE påvirker eierens aggregat).
+ **Zip 15 og 16 mottatt** (samme v0.app-prosjekt, kontinuerlig --
+ `round-card.tsx`/`own-rounds.tsx` identiske i begge, zip 16s
+ `round-detail.tsx` var den nyeste med selve scorekort-redesignet; zip
+ 15 brukt kun for å bekrefte at zip 16 var det riktige, endelige
+ eksportet).
+ `round-card.tsx` fikk en ny `ScoreTile` -- prominent resultat+til-par
+ for fullførte runder, hull-fremdrift-bar ("6/18 hull spilt") for
+ runder som pågår, pluss en HCP-differensial-chip når runden telte.
+ Datalag i `own-rounds.tsx` skrevet om fra mock til ekte fetch, kobler
+ de nye `owner_*`-feltene fra backend + eierens `score_differential`
+ (kun vist når `counts_for_handicap`).
+ `round-detail.tsx` fikk en ny kollapsbar "Flere detaljer"-seksjon
+ (lukket som default) som nå rommer kølle/utslag-retning/innspill-
+ retning/chip-bunker-straffeslag/anywayslag -- Slag/Putter/Avstand
+ første putt forblir alltid synlig over. Datalag/statLevel-gating/
+ bucket-basert puttlengde/maxValue-capping (alt bygget tidligere denne
+ økten) bevisst IKKE revertert til V0s eldre mock-baseline, kun selve
+ kollaps-mekanismen og plasseringen ble hentet derfra. Lagt til en kort
+ kode-kommentar (ikke noe bygget UI ennå) som reserverer plass ved
+ siden av hull-headeren til en fremtidig avstandsmåling-indikator,
+ bekreftet av bruker at dette kommer senere.
+ Ekte typesjekket produksjonsbuild kjørt og bekreftet (alle 19 ruter).
+ **Rullet ut live 2026-07-25**, ren frontend-endring (+ den lille
+ backend-tilføyelsen over), ingen migrasjon, `/health`/`/my-rounds` →
+ 200, `teeoff.no` upåvirket.
+- **Reelt hull funnet og fikset SAMME dag, rapportert av bruker rett
+ etter forrige punkt ("Hvor er scorekortet?"):** da "Så langt i runden"
+ ble skjult for fullførte runder (se over), forsvant OGSÅ den eneste
+ plassen den rå hull-for-hull-tabellen (Hull/Par/Score/Netto/Sum) fantes
+ -- `round-stats.tsx` (den nye dedikerte statistikk-siden) hadde KUN
+ utledet/aggregert statistikk (donuter, stolper), ingen tabell med de
+ faktiske tallene per hull. Fikset ved å legge til en ny "Scorekort"-
+ seksjon FØRST på statistikk-siden (samme tabell-mønster som "Så
+ langt" hadde -- Hull/Par/Score/Netto/Stableford/Sum), åpen som
+ default. La til `start_hole` i `round-stats.tsx` sin `ApiRound`-type
+ og `strokes_received` i `ApiHole`-typen (sistnevnte kom allerede fra
+ backend, bare ikke lest av denne siden ennå) for å kunne vise hullene
+ i rundens FAKTISKE rekkefølge (samme sirkulære start_hole-logikk som
+ round-detail.tsx) i stedet for bare rå hullnummer 1-18. Ekte
+ typesjekket build kjørt og bekreftet. Rullet ut, ren frontend-endring,
+ ingen backend/migrasjon, `teeoff.no` upåvirket.
+- **Ny scorekort-presentasjonsregel + V0-prompt skrevet, IKKE bygget
+ ennå (2026-07-25):** brukeren delte et referansebilde av et
+ tradisjonelt horisontalt golf-scorekort og formulerte en generell
+ regel: hull listet HORISONTALT (som kolonner) → sum TIL HØYRE; hull
+ listet VERTIKALT (som rader) → sum UNDER. Dagens "Scorekort"-tabell
+ (bygget rett over samme dag) er vertikal med sum som løpende KOLONNE
+ -- ikke i tråd med regelen. V0-prompt skrevet (horisontalt scorekort,
+ hull 1-9/10-18 som kolonner, Ut/Inn-sum til høyre for hver halvdel,
+ Hcp/Par/Score/Netto/Stableford-rader, håndterer både 9- og 18-hulls
+ runder med vilkårlig start_hole), bevisst IKKE et plagiat av
+ referansebildet (egne farger, egen "Hcp"-term i stedet for bildets
+ "Slope", ingen kopiert spiller-header). Full detalj i
+ ARCHITECTURE_DECISIONS.md. **Presisert samme dag, før noe ble sendt:**
+ brukeren spurte om et mykt "scroll hvis nødvendig"-unntak fanget opp
+ målet om ALDRI å måtte scrolle -- svart nei (reell breddekonflikt med
+ "lesbar uten briller"-kravet, ikke bare ordlyd) og skrevet om til et
+ hardt "ingen scroll"-krav som eksplisitt forteller V0 HVORDAN det
+ oppnås (kompakte fete høykontrast-siffer i selve rutenettet, smale
+ forkortede rad-labels i en trang gutter -- "lesbar uten briller"
+ avgrenset til labels/knapper, ikke enkeltsifre). Full detalj i
+ ARCHITECTURE_DECISIONS.md.
+ **Zip 17 mottatt og BYGGET/LIVE samme dag:** en ekte HTML `
` med
+ `
` faste kolonnebredder -- ingen scroll-container i det hele
+ tatt, løst med kompakte celler i stedet. Score-cellene bruker FORM
+ (sirkel=under par, firkant=over par) + fylt/ufylt (2+ slag av) for å
+ aldri stole på farge alene, pluss en egen symbolforklaring. Egen,
+ NY dedikert side `/my-rounds/[id]/scorecard`
+ (`components/round-scorecard.tsx`) -- ikke slått sammen med
+ `round-stats.tsx`, siden V0 designet den med egen side-chrome (header,
+ rundesammendrag). Datalag skrevet om fra mock til ekte fetch; V0s egen
+ `strokesReceived()`-formel (generisk modulo) BEVISST forkastet til
+ fordel for backend sin allerede beregnede `strokes_received` (samme
+ `allocate_strokes_by_index()` som resten av appen -- unngår to ulike
+ HCP-slagfordelings-implementasjoner). Samme sirkulære
+ start_hole-rekkefølge som resten av rundeskjermene. Den gamle
+ vertikale "Scorekort"-tabellen i `round-stats.tsx` FJERNET (erstattet
+ med en lenke til den nye siden) -- `round-stats.tsx` er nå rendyrket
+ aggregert statistikk, det rå scorekortet bor kun ett sted. V0 la selv
+ til en "Se scorekort"-knapp i `CompletedBanner` (round-detail.tsx) ved
+ siden av den eksisterende "Se full rundestatistikk" -- tatt inn.
+ **Samtidig, rapportert av bruker:** Anywayslag manglet helt fra
+ rundestatistikk-siden sin "Chip, bunker og straffeslag"-seksjon --
+ lagt til som en tredje per-runde-flis, og seksjonen omdøpt til "Annet"
+ (bredere navn, siden et notatfelt trolig havner der senere også).
+ Ekte typesjekket build kjørt og bekreftet (ny rute
+ `/my-rounds/[id]/scorecard` listet). Rullet ut, ren frontend-endring,
+ ingen backend/migrasjon, `teeoff.no` upåvirket.
Neste steg:
1. **Pauset, venter på retning:** dashbordets tom-tilstand ved første
diff --git a/FEATURE_BACKLOG.md b/FEATURE_BACKLOG.md
index 18f4a43..57e7333 100644
--- a/FEATURE_BACKLOG.md
+++ b/FEATURE_BACKLOG.md
@@ -1366,7 +1366,7 @@ tom-skjermens endelige form kan bestemmes.
---
-## Frittstående rundeføring + detaljert statistikk (uten turnering/organisasjon) — ✅ BACKEND + FRONTEND LIVE (2026-07-23)
+## Frittstående rundeføring + detaljert statistikk (uten turnering/organisasjon) — ✅ BACKEND + FRONTEND LIVE, løpende oppfølging t.o.m. 2026-07-25 (se ADR-033 for full detalj per dag)
**Fremdrift 2026-07-22:** HCP-indeks-motor (43/43 tester), databaseskjema
(`020`+`021`, sistnevnte en fiks for manglende rating-snapshot-kolonner),
@@ -1455,6 +1455,12 @@ en ekstern golf-GPS-database?) eller UI — kun fanget som en kjent,
fremtidig ambisjon som statistikk-modellen (Beslutning B) og
banedata-modellen (Beslutning C) bør ha i bakhodet, siden begge kan
trenge en utvidelse den dagen dette faktisk designes.
+**Reconfirmed 2026-07-25** (scorekort-redesign-runden): brukeren
+gjentok at avstandsmåling "ligger i kortene". Fortsatt IKKE designet
+eller bygget -- eneste konkrete tiltak er en kode-KOMMENTAR i
+`round-detail.tsx` sin hull-header som reserverer visuell plass ved
+siden av GIR-merket, slik at en fremtidig avstand-indikator kan legges
+til uten en layout-endring. Ingen data, ingen funksjonalitet.
**Se ADR-033 i ARCHITECTURE_DECISIONS.md for den fulle, besluttede
arkitekturen** (eierskapsmønster, statistikk-datamodell, HCP-indeksmotor).
diff --git a/app/routers/rounds.py b/app/routers/rounds.py
index ff493b7..4ce1b26 100644
--- a/app/routers/rounds.py
+++ b/app/routers/rounds.py
@@ -427,6 +427,14 @@ class RoundOut(BaseModel):
started_at: str | None
completed_at: str | None
participants: list[RoundParticipantOut]
+ # Eierens egen fremdrift/score, utledet fra round_hole (aldri lagret) --
+ # brukt av rundelisten (round-card.tsx) som i dag manglet ethvert tall i
+ # det hele tatt (kun tee/hull/dato/spillerantall), rapportert av bruker
+ # 2026-07-25. `owner_score_to_par` er None helt til minst ett hull er
+ # registrert.
+ owner_holes_played: int
+ owner_total_score: int | None
+ owner_score_to_par: int | None
async def _load_round_out(conn, round_id: str) -> RoundOut:
@@ -448,6 +456,21 @@ async def _load_round_out(conn, round_id: str) -> RoundOut:
""",
round_id,
)
+ owner_id = next((r["id"] for r in participant_rows if r["is_owner"]), None)
+ owner_agg = await conn.fetchrow(
+ """
+ SELECT COUNT(*) FILTER (WHERE played) AS played_count,
+ COALESCE(SUM(score) FILTER (WHERE played), 0) AS total_score,
+ COALESCE(SUM(par) FILTER (WHERE played), 0) AS total_par
+ FROM round_hole WHERE round_participant_id = $1
+ """,
+ owner_id,
+ )
+ owner_holes_played = owner_agg["played_count"] if owner_agg else 0
+ owner_total_score = owner_agg["total_score"] if owner_holes_played > 0 else None
+ owner_score_to_par = (
+ owner_agg["total_score"] - owner_agg["total_par"] if owner_holes_played > 0 else None
+ )
return RoundOut(
id=round_row["id"],
course_source=round_row["course_source"],
@@ -459,6 +482,9 @@ async def _load_round_out(conn, round_id: str) -> RoundOut:
started_at=round_row["started_at"].isoformat() if round_row["started_at"] else None,
completed_at=round_row["completed_at"].isoformat() if round_row["completed_at"] else None,
participants=[RoundParticipantOut(**dict(r)) for r in participant_rows],
+ owner_holes_played=owner_holes_played,
+ owner_total_score=owner_total_score,
+ owner_score_to_par=owner_score_to_par,
)
@@ -886,6 +912,12 @@ class RoundHoleOut(BaseModel):
penalty_strokes: int | None
first_putt_distance_bucket: str | None
anyway_strokes: int | None
+ # Slag mottatt på dette hullet, utledet fra course_handicap_snapshot
+ # (samme allokeringsalgoritme som resten av appen) -- kun til visning
+ # av netto-score i en oversiktstabell, aldri lagret. None hvis
+ # deltakeren ikke har en beregnet course handicap (f.eks. gjest uten
+ # HCP).
+ strokes_received: int | None
@router.get(
@@ -899,11 +931,11 @@ async def list_holes(
) -> list[RoundHoleOut]:
async with plain_connection() as conn:
await _get_owned_round_or_404(conn, round_id, user.user_id)
- owner_check = await conn.fetchval(
- "SELECT 1 FROM round_participant WHERE id = $1 AND round_id = $2",
+ participant_row = await conn.fetchrow(
+ "SELECT course_handicap_snapshot FROM round_participant WHERE id = $1 AND round_id = $2",
participant_id, round_id,
)
- if owner_check is None:
+ if participant_row is None:
raise app_error(404, "NOT_FOUND", "Deltakeren finnes ikke på denne runden.")
rows = await conn.fetch(
"""
@@ -914,7 +946,21 @@ async def list_holes(
""",
participant_id,
)
- return [RoundHoleOut(**dict(r)) for r in rows]
+
+ strokes_received_by_hole: dict[int, int] | None = None
+ if participant_row["course_handicap_snapshot"] is not None:
+ allocation = allocate_strokes_by_index(
+ participant_row["course_handicap_snapshot"], [r["stroke_index"] for r in rows]
+ )
+ strokes_received_by_hole = {r["hole_number"]: a for r, a in zip(rows, allocation)}
+
+ return [
+ RoundHoleOut(
+ **dict(r),
+ strokes_received=strokes_received_by_hole[r["hole_number"]] if strokes_received_by_hole else None,
+ )
+ for r in rows
+ ]
class HoleUpdate(BaseModel):
@@ -944,11 +990,11 @@ async def update_hole(
) -> RoundHoleOut:
async with plain_connection() as conn:
await _get_owned_round_or_404(conn, round_id, user.user_id)
- owner_check = await conn.fetchval(
- "SELECT 1 FROM round_participant WHERE id = $1 AND round_id = $2",
+ participant_row = await conn.fetchrow(
+ "SELECT course_handicap_snapshot FROM round_participant WHERE id = $1 AND round_id = $2",
participant_id, round_id,
)
- if owner_check is None:
+ if participant_row is None:
raise app_error(404, "NOT_FOUND", "Deltakeren finnes ikke på denne runden.")
async with translate_db_errors():
@@ -972,7 +1018,24 @@ async def update_hole(
)
if row is None:
raise app_error(404, "NOT_FOUND", "Hullet finnes ikke på denne deltakeren.")
- return RoundHoleOut(**dict(row))
+
+ # strokes_received er utledet av HELE rundens stroke-indeks-rekkefølge
+ # (samme allokeringsalgoritme som list_holes/GET), ikke bare dette ene
+ # hullet -- må derfor hente alle 18 sin stroke_index for å plassere
+ # riktig antall mottatte slag på nøyaktig dette hullet.
+ strokes_received = None
+ if participant_row["course_handicap_snapshot"] is not None:
+ all_indexes = await conn.fetch(
+ "SELECT hole_number, stroke_index FROM round_hole WHERE round_participant_id = $1 ORDER BY hole_number",
+ participant_id,
+ )
+ allocation = allocate_strokes_by_index(
+ participant_row["course_handicap_snapshot"], [r["stroke_index"] for r in all_indexes]
+ )
+ by_hole = {r["hole_number"]: a for r, a in zip(all_indexes, allocation)}
+ strokes_received = by_hole[hole_number]
+
+ return RoundHoleOut(**dict(row), strokes_received=strokes_received)
# ---------------------------------------------------------------------------
diff --git a/frontend/app/globals.css b/frontend/app/globals.css
index 253cc7e..4716261 100644
--- a/frontend/app/globals.css
+++ b/frontend/app/globals.css
@@ -14,6 +14,7 @@
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
+ --color-chart-6: var(--chart-6);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
@@ -70,11 +71,14 @@
--ring: oklch(0.7512 0.1613 130.33);
--brand-orange: oklch(0.6792 0.2128 36.53);
--brand-orange-foreground: oklch(0.99 0 0);
- --chart-1: oklch(0.87 0 0);
- --chart-2: oklch(0.556 0 0);
- --chart-3: oklch(0.439 0 0);
- --chart-4: oklch(0.371 0 0);
- --chart-5: oklch(0.269 0 0);
+ /* Statistikk-fargeskala (rundestatistikk, ADR-033) -- brukt sammen med
+ tekst-/tall-etiketter, aldri farge alene som eneste signal. */
+ --chart-1: oklch(0.55 0.15 160);
+ --chart-2: oklch(0.72 0.17 140);
+ --chart-3: oklch(0.68 0.13 210);
+ --chart-4: oklch(0.79 0.15 85);
+ --chart-5: oklch(0.68 0.2 45);
+ --chart-6: oklch(0.57 0.22 25);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
@@ -108,11 +112,13 @@
--ring: oklch(0.7512 0.1613 130.33);
--brand-orange: oklch(0.6792 0.2128 36.53);
--brand-orange-foreground: oklch(0.16 0.02 40);
- --chart-1: oklch(0.87 0 0);
- --chart-2: oklch(0.556 0 0);
- --chart-3: oklch(0.439 0 0);
- --chart-4: oklch(0.371 0 0);
- --chart-5: oklch(0.269 0 0);
+ /* Statistikk-fargeskala, løftet for kontrast på mørk bakgrunn. */
+ --chart-1: oklch(0.7 0.16 160);
+ --chart-2: oklch(0.79 0.17 140);
+ --chart-3: oklch(0.75 0.13 210);
+ --chart-4: oklch(0.83 0.14 85);
+ --chart-5: oklch(0.73 0.19 45);
+ --chart-6: oklch(0.66 0.21 25);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
@@ -146,11 +152,12 @@
--ring: oklch(0.7512 0.1613 130.33);
--brand-orange: oklch(0.6792 0.2128 36.53);
--brand-orange-foreground: oklch(0.16 0.02 40);
- --chart-1: oklch(0.87 0 0);
- --chart-2: oklch(0.556 0 0);
- --chart-3: oklch(0.439 0 0);
- --chart-4: oklch(0.371 0 0);
- --chart-5: oklch(0.269 0 0);
+ --chart-1: oklch(0.7 0.16 160);
+ --chart-2: oklch(0.79 0.17 140);
+ --chart-3: oklch(0.75 0.13 210);
+ --chart-4: oklch(0.83 0.14 85);
+ --chart-5: oklch(0.73 0.19 45);
+ --chart-6: oklch(0.66 0.21 25);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
diff --git a/frontend/app/my-rounds/[id]/scorecard/page.tsx b/frontend/app/my-rounds/[id]/scorecard/page.tsx
new file mode 100644
index 0000000..5cb1fe4
--- /dev/null
+++ b/frontend/app/my-rounds/[id]/scorecard/page.tsx
@@ -0,0 +1,10 @@
+import { RoundScorecard } from "@/components/round-scorecard"
+
+export default async function RoundScorecardPage({
+ params,
+}: {
+ params: Promise<{ id: string }>
+}) {
+ const { id } = await params
+ return
+}
diff --git a/frontend/app/my-rounds/[id]/stats/page.tsx b/frontend/app/my-rounds/[id]/stats/page.tsx
new file mode 100644
index 0000000..b5573cd
--- /dev/null
+++ b/frontend/app/my-rounds/[id]/stats/page.tsx
@@ -0,0 +1,10 @@
+import { RoundStats } from "@/components/round-stats"
+
+export default async function RoundStatsPage({
+ params,
+}: {
+ params: Promise<{ id: string }>
+}) {
+ const { id } = await params
+ return
+}
diff --git a/frontend/components/own-rounds.tsx b/frontend/components/own-rounds.tsx
index 091e4db..3b2bc95 100644
--- a/frontend/components/own-rounds.tsx
+++ b/frontend/components/own-rounds.tsx
@@ -17,6 +17,8 @@ type ApiRoundParticipant = {
id: string
is_owner: boolean
guest_name: string | null
+ counts_for_handicap: boolean
+ score_differential: number | null
}
type ApiRound = {
@@ -27,9 +29,14 @@ type ApiRound = {
holes_planned: number
completed_at: string | null
participants: ApiRoundParticipant[]
+ owner_holes_played: number
+ owner_total_score: number | null
+ owner_score_to_par: number | null
}
function toRound(r: ApiRound): Round {
+ const owner = r.participants.find((p) => p.is_owner)
+ const differential = owner?.counts_for_handicap ? owner.score_differential : null
return {
id: r.id,
courseName: r.course_name_snapshot,
@@ -38,6 +45,10 @@ function toRound(r: ApiRound): Round {
holes: r.holes_planned === 9 ? 9 : 18,
date: r.played_at,
playerCount: r.participants.length,
+ holesPlayed: r.owner_holes_played,
+ totalScore: r.owner_total_score ?? undefined,
+ toPar: r.owner_score_to_par ?? undefined,
+ differential,
}
}
diff --git a/frontend/components/round-card.tsx b/frontend/components/round-card.tsx
index 8d624d3..e69f419 100644
--- a/frontend/components/round-card.tsx
+++ b/frontend/components/round-card.tsx
@@ -1,5 +1,5 @@
import Link from "next/link"
-import { CalendarDays, ChevronRight, Flag, MapPin, Users } from "lucide-react"
+import { CalendarDays, ChevronRight, Flag, Gauge, MapPin, Users } from "lucide-react"
import { cn } from "@/lib/utils"
export type RoundStatus = "active" | "completed"
@@ -12,6 +12,13 @@ export type Round = {
holes: 9 | 18
date: string
playerCount: number
+ // Progress for rounds still in play.
+ holesPlayed?: number
+ // Owner's score, present once at least one hole is recorded.
+ totalScore?: number
+ toPar?: number
+ // Handicap differential, only when a completed round counted (one decimal).
+ differential?: number | null
}
const STATUS_CONFIG: Record = {
@@ -39,6 +46,17 @@ function formatDate(value: string) {
return dateFormatter.format(parsed)
}
+// "+10", "-2" or "E" for level par. The sign carries the meaning (never color alone).
+function formatToPar(toPar: number) {
+ if (toPar === 0) return "E"
+ return toPar > 0 ? `+${toPar}` : `${toPar}`
+}
+
+function toParDescription(toPar: number) {
+ if (toPar === 0) return "på par"
+ return toPar > 0 ? `${toPar} over par` : `${Math.abs(toPar)} under par`
+}
+
function RoundStatusBadge({ status }: { status: RoundStatus }) {
const config = STATUS_CONFIG[status]
return (
@@ -54,13 +72,87 @@ function RoundStatusBadge({ status }: { status: RoundStatus }) {
)
}
+// Prominent right-side tile: final score for completed/scored rounds,
+// hole progress for rounds still in play.
+function ScoreTile({ round }: { round: Round }) {
+ const hasScore = typeof round.totalScore === "number" && typeof round.toPar === "number"
+
+ if (round.status === "active" || !hasScore) {
+ const played = round.holesPlayed ?? 0
+ const pct = round.holes > 0 ? Math.min(100, Math.round((played / round.holes) * 100)) : 0
+ return (
+
+
+
(null)
- // "score" (slag/putter) eller "stats" (kølle/retning/chip/bunker/
- // straffeslag/putt-avstand/anywayslag) -- kun relevant når
- // statLevel==="full", ellers vises "score"-innholdet direkte uten
- // faneraden (se PanelTabs-bruken lenger ned).
- const [panelTab, setPanelTab] = useState<"score" | "stats">("score")
const [showAddGuest, setShowAddGuest] = useState(false)
const [completing, setCompleting] = useState(false)
const [deleting, setDeleting] = useState(false)
const [showEditRound, setShowEditRound] = useState(false)
+ // "Flere detaljer" er kollapset som default (etterspurt av bruker
+ // 2026-07-25 -- scorekortet var "veldig dårlig designet", altfor mye
+ // stablet oppå hverandre for et enkelt slag-registrering) slik at en
+ // rask slag-/putt-registrering ikke krever noe scrolling i det hele tatt.
+ const [detailsOpen, setDetailsOpen] = useState(false)
+ // Hull-panelet gjenbrukes ved bytte av hull -- "Forrige"/"Neste hull" ligger
+ // NEDERST i panelet, så uten dette ville brukeren blitt stående scrollet
+ // helt ned (der knappene er) mens det NYE hullets Slag-felt (øverst i
+ // panelet) er utenfor skjermen (rapportert av bruker 2026-07-25).
+ const holePanelRef = useRef(null)
+ function scrollToHolePanel() {
+ holePanelRef.current?.scrollIntoView({ behavior: "smooth", block: "start" })
+ }
const loadRound = useCallback(async () => {
try {
@@ -357,12 +367,12 @@ export function RoundDetail({ roundId }: { roundId: string }) {
function goPrev() {
const i = holeOrder.indexOf(activeHole)
setCurrentHole(holeOrder[(i - 1 + holeOrder.length) % holeOrder.length])
- setPanelTab("score")
+ scrollToHolePanel()
}
function goNext() {
const i = holeOrder.indexOf(activeHole)
setCurrentHole(holeOrder[(i + 1) % holeOrder.length])
- setPanelTab("score")
+ scrollToHolePanel()
}
async function addGuest(name: string, gender: Gender, hcp: number | null, statLevel: StatLevel) {
@@ -525,18 +535,50 @@ export function RoundDetail({ roundId }: { roundId: string }) {
)}
-
- {showEditRound ? (
- setShowEditRound(false)} />
- ) : (
+ {/* Rediger/Fullfør/Slett samlet ØVERST, bevisst tonet ned (samme
+ nøytrale trigger-stil som hverandre) -- disse lå tidligere som
+ store, fremtredende knapper RETT under "Neste hull"-navigasjonen
+ nederst i hull-panelet, som gjorde det altfor lett å trykke feil
+ ved et uhell mens man bare skulle bla mellom hull (rapportert av
+ bruker 2026-07-25). Ved å flytte dem hit må man aktivt scrolle OPP
+ forbi hull-registreringen for å nå dem i det hele tatt. */}
+
@@ -545,6 +587,7 @@ export function RoundDetail({ roundId }: { roundId: string }) {
)}
@@ -566,6 +609,13 @@ export function RoundDetail({ roundId }: { roundId: string }) {
/>
)}
+ {/* Skjules når runden er fullført (2026-07-25, rapportert av bruker
+ som "veldig mye dobbel informasjon") -- CompletedBanner sin
+ "Se full rundestatistikk"-lenke dekker nå akkurat det samme,
+ langt grundigere. Fortsatt nyttig som live fremdriftsoversikt
+ mens runden pågår. */}
+ {!completed && }
+
{showAddGuest && !readOnly && setShowAddGuest(false)} />}
{/* Hole navigation */}
@@ -581,144 +631,184 @@ export function RoundDetail({ roundId }: { roundId: string }) {
isPlayed={holeIsPlayed}
onSelect={(n) => {
setCurrentHole(n)
- setPanelTab("score")
+ scrollToHolePanel()
}}
/>
{/* Current hole panel */}
{hole && (
-
+
+ {/* Høyre kolonne reserverer plass ved siden av hull-headeren
+ til en fremtidig avstandsmåling-indikator (ikke bygget
+ ennå, men avklart 2026-07-25 at det kommer) -- GIR-merket
+ ligger under den reserverte plassen slik at et senere
+ avstand-chip her ikke krever noen layout-endring. */}
Hull {hole.holeNumber} · Par {hole.par} · Hcp {hole.index}
-
- updateStat({ firstPuttBucket: v as PuttBucket })}
- readOnly={readOnly}
- />
+ {/* Slag/Putter og (ved statLevel="full") alle detaljene vises
+ ALLTID samlet under hverandre -- ikke bak en fane man må
+ oppdage og trykke på (funnet 2026-07-25: brukeren huket
+ av "All statistikk", men fikk aldri se noe utover
+ slag/putter siden det lå bak en fane). */}
+
- )}
+ )}
+
+ {activePlayer.statLevel === "full" && (
+ <>
+ {/* Rett under antall putter (etterspurt av bruker 2026-07-25) --
+ hører naturlig sammen med Putter-feltet rett over, ikke med
+ kølle/retning/chip-gruppen lenger ned. */}
+ updateStat({ firstPuttBucket: v as PuttBucket })}
+ readOnly={readOnly}
+ />
+
+ {/* Alt annet lever bak én kollapsbar seksjon, lukket som
+ default -- panelet forblir kort for det vanlige
+ slag-/putt-registreringstilfellet. */}
+
+ )
+}
+
+// Ett rektangel delt i fargede segmenter proporsjonalt med antall --
+// samme visuelle idé som SegmentedBar i tournament-leaderboard.tsx, men
+// generalisert til N kategorier (ikke bare to lag).
+function DistributionBar({ segments }: { segments: { label: string; count: number; colorClass: string }[] }) {
+ const total = segments.reduce((sum, s) => sum + s.count, 0)
+ if (total === 0) return null
+ return (
+
+ )
+}
+
+// --- Row of N stat tiles (2 eller 3 -- StatTilePair er en fast to-tiles-
+// variant, denne generaliserer for "Annet"-seksjonens tre per-runde-tall) ---
+
+function StatTileRow({ tiles }: { tiles: { label: string; value: string }[] }) {
+ return (
+
+ {s.totalStrokes || "–"}
+ {s.playedCount > 0 && (
+ {signed(s.totalToPar)} til par
+ )}
+
+
+
+ {/* Selve hull-for-hull-scorekortet flyttet til en egen, dedikert
+ horisontal side 2026-07-25 (erstatter en tidligere vertikal
+ tabell her på statistikk-siden -- se ARCHITECTURE_DECISIONS.md
+ ADR-033) -- denne siden forblir aggregert/utledet statistikk. */}
+
+ Se scorekort
+
+
+
+ {/* Spillervelger, kun når runden har flere deltakere */}
+ {round.participants.length > 1 && (
+
+ Andel én-putt etter lengde på første putt
+ {s.onePuttPctByBucket.map((b, i) => (
+
+ ))}
+
+
+
+
+
+
+
+ )}
+
+ {/* 7. Annet -- "catch all" for chip/bunker/straffeslag/anywayslag
+ (het tidligere "Chip, bunker og straffeslag", men Anywayslag
+ manglet helt fra oppsummeringen -- rettet + omdøpt til noe
+ bredere 2026-07-25, siden et fritekst-notatfelt trolig havner
+ her senere også). */}
+
+ {(s.scramblingPct !== null || s.sandSavePct !== null) && (
+