diff --git a/038_stableford_and_pickup.sql b/038_stableford_and_pickup.sql new file mode 100644 index 0000000..66e2b3f --- /dev/null +++ b/038_stableford_and_pickup.sql @@ -0,0 +1,29 @@ +-- ===================================================================== +-- TeeCup — Stableford som egen spilleform + "plukket opp"-tilstand, +-- migrasjon 038. FEATURE_BACKLOG.md sitt eget notat fra 2026-07-25: +-- frittstående runder hadde ingen faktisk Stableford-FORMAT (kun rå +-- slagtall), og ingen vei til å registrere at en spiller plukket opp +-- ballen fordi hullet uansett var klart 0 poeng. +-- +-- Stableford-POENGENE var allerede beregnet og vist flere steder (rund- +-- detail.tsx/round-scorecard.tsx/round-leaderboard.tsx sin stablefordPoints() +-- /total_points) -- denne migrasjonen dekker de to reelt manglende bitene: +-- (1) 'stableford' som et faktisk selvdeklarert play_format, side om side +-- med 'stroke'/'match' (samme individuelle, ikke-to-sidede kategori som +-- 'stroke' -- IKKE i _TWO_SIDED_FORMATS), (2) round_hole.picked_up. +-- +-- "Plukket opp" lagres IKKE som en NULL-score -- den skrives eksplisitt +-- som Net Double Bogey (par + 2 + mottatte slag), samme cap som +-- handicap_engine.py sin max_hole_score_for_handicap() ALLEREDE bruker +-- for enhver høy score (Rule 3.1b). Dette gir automatisk nøyaktig 0 +-- Stableford-poeng (samme formel som ellers) OG et korrekt AGS-bidrag +-- for faktisk-HCP (ADR-038) -- ingen ny motorlogikk trengs, kun et nytt +-- felt for VISNING ("Plukket opp" i stedet for et rått slagtall). +-- ===================================================================== +\set ON_ERROR_STOP on + +ALTER TABLE round_hole ADD COLUMN picked_up boolean NOT NULL DEFAULT false; + +ALTER TABLE round DROP CONSTRAINT round_play_format_check; +ALTER TABLE round ADD CONSTRAINT round_play_format_check + CHECK (play_format IN ('stroke', 'match', 'skins', 'fourball', 'foursome', 'greensome', 'scramble_2', 'scramble_4', 'stableford')); diff --git a/CLAUDE.md b/CLAUDE.md index f0f8bd2..25e154f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5304,6 +5304,141 @@ Ferdig og verifisert: ingen backend-kode rørt). Begge containere boot-et rent, `/health`/ `/dashboard` → 200, `teeoff.no` upåvirket. +- **Territorium-bar-språket fullført på de to siste "Matchstatus"-boksene, + BYGGET, BROWSERVERIFISERT OG LIVE (2026-07-29), samme dag -- brukeren ba + eksplisitt om "visuell konsistens ferdig helt ut" etter at jeg flagget + disse to som gjenstående:** `round-leaderboard.tsx` sin + `MatchStatusSection` (den innloggede rundens leaderboard-side) og + `watch-round.tsx` sin `MatchStatus` (den offentlige "Følger live"-siden + for en delt/synlig runde, ADR-036 fase 2) hadde begge fortsatt den gamle + flate boksen (kun stor tekst, ingen fargesone). Disse to har INGEN + navn å vise (deltakernavnene vises allerede andre steder på samme side) + -- lagt til KUN de to fargesonene + den sentrerte statuspillen (samme + `leadZoneFraction`+CSS-Grid-mønster som identitetsbanneret dagen før, + egen lokal kopi i hver fil), ikke selve `LeadZone`-identitetsboksen. + Begge filenes lokale `ApiFormatResult`-type manglet `match_lead` helt + (aldri lest her før, selv om backend alltid har eksponert det) -- lagt + til i begge. + **Verifisert i en isolert scratch-nettleserøkt** (fersk `teecup_scratch`- + database + isolert scratch-MinIO + engangs API-container, ekte `next + dev`, Chrome DevTools MCP, 390×844 mobil-viewport): bygget en ekte + OFFENTLIG (`visibility_mode:"public"`) match-runde fra bunnen via API, + bekreftet BEGGE sider (innlogget leaderboard OG anonym `/watch/{id}`) + viser identisk, korrekt fargesatt "1 UP (Side B)"-tilstand med riktig + dominant/lys sone -- OG en egen AS/0-hull-spilt-test (nøytral 50/50, + ingen farge). Begge bekreftet i BÅDE lys og mørk modus. Ingen + konsollfeil (kun en godartet, urelatert PWA-install-loggmelding). Ekte + typesjekket produksjonsbuild kjørt og bekreftet. + **Rullet ut live 2026-07-29**, ingen migrasjon (ren frontend), `docker + compose up -d --build teecup_frontend` (gjenskapte også `teecup_api` + som vanlig bivirkning, ingen backend-kode rørt). Begge containere + boot-et rent, `/health`/`/dashboard` → 200, `teeoff.no` upåvirket. + **Territorium-bar-språket er dermed konsistent på ALLE fem stedene en + matchstatus vises i appen** (tre fulle identitetsbannere + disse to + navnløse variantene) -- listevisningene (blind draw-reveal, offentlig + turnering-live) beholder bevisst sin egen, ulike kort-per-match-stil + (farget topplinje + statuschip), siden de viser MANGE matcher samtidig + og ikke er en fokusert enkelt-match-visning. + +- **Stableford som ekte spilleform + "plukket opp"-tilstand for frittstående + runder, BYGGET, GRUNDIG SCRATCH-/BROWSERVERIFISERT (inkl. TO reelle bugs + funnet OG fikset UNDER browserverifiseringen) OG LIVE (2026-07-29), samme + dag:** brukeren ba om å ta fatt på det siste, klart avgrensede hullet fra + ADR-038-gjennomgangen -- Stableford-POENGENE var allerede beregnet og vist + flere steder (round-detail.tsx/round-scorecard.tsx/round-leaderboard.tsx + sin `stablefordPoints()`/`total_points`, bygget 2026-07-25/26), men to + ting manglet reelt: (1) `'stableford'` fantes ikke som et faktisk + selvdeklarert `play_format` (kun "stroke"/"match" fantes som individuelle + format-etiketter), (2) ingen vei til å registrere at en spiller plukket + opp ballen fordi hullet uansett var klart 0 poeng. + **Design, ny migrasjon `038_stableford_and_pickup.sql`:** `round_hole. + picked_up boolean DEFAULT false`, `'stableford'` lagt til + `round_play_format_check`. "Plukket opp" lagres IKKE som en NULL-score -- + serveren skriver eksplisitt Net Double Bogey (par + 2 + mottatte slag, + `handicap_engine.py` sin allerede eksisterende og testede `max_hole_ + score_for_handicap()`, Rule 3.1b) som selve `score`-verdien når + `picked_up=true` sendes til `PATCH .../holes/{n}` -- dette gir automatisk + presis 0 Stableford-poeng (samme formel som ellers, ingen spesialkoding) + OG et korrekt AGS-bidrag for faktisk-HCP (ADR-038) helt uendret -- INGEN + ny motorlogikk trengs, kun ett nytt felt for VISNING ("PU"-merke i stedet + for det underliggende tallet, samme "form+farge, aldri farge alene"-språk + som resten av golfscore-visningen). `HoleUpdate` beregner strokes_received + for AKKURAT det aktuelle hullet FØR selve UPDATE-en (omstrukturert fra + tidligere "beregn etterpå"-rekkefølge) for å kunne skrive riktig NDB-verdi + i samme kall. Avvist tydelig (400 `VALIDATION_FAILED`) hvis deltakeren + ikke har noen beregnet course handicap ennå. + **To reelle bugs funnet OG fikset UNDER selve browserverifiseringen, ikke + antatt riktig fra kodegjennomgang alene** -- begge samme underliggende + mønster: eksisterende kode som spesialsjekket `play_format === "stroke"` + (for å bety "individuelt, ikke to-sidet format") måtte utvides til + eksplisitt å ekskludere `"stableford"` også, ellers falt det nye formatet + feilaktig gjennom til den TO-SIDEDE grenen: + 1. `new-round.tsx` sin `needsSidesSetup = playFormat !== "stroke" && + playFormat !== "skins"` -- et ekte skjermbilde viste "Du setter opp + sidene..."-teksten under Stableford-valget, til tross for at formatet + aldri bruker sider. Rettet ved å legge til `&& playFormat !== + "stableford"`. + 2. **Alvorligere:** `round-detail.tsx` sin `FormatResultPanel` (`if + (round.play_format === "stroke" || !result) return null`) -- et ekte + skjermbilde av en fersk Stableford-runde viste en fullstendig + meningsløs "Side A"/"Side B"-territorium-bar (samme komponent bygget + tidligere samme dag for ekte to-sidede formater) med "Ingen hull + spilt ennå", siden backend sin `_build_format_result()` returnerer en + harmløs tom `ready:true`-respons for ethvert format utenfor + `_TWO_SIDED_FORMATS`/`"skins"` (inkl. det nye "stableford"), som + frontend-sjekken ikke fanget opp. Rettet samme sted (lagt til + `round.play_format === "stableford"` i den samme betingelsen), pluss + den tilhørende `useEffect` som utløser selve HTTP-kallet (unødvendig + nettverkskall for Stableford, samme fiks som for "stroke"). + **Systematisk oppfølging etter de to funnene, IKKE bare disse to + stedene:** grep'et gjennom HELE frontend-kodebasen etter samme + `"stroke"`-spesialsjekk-mønster og fant tre til ekte hull i + `watch-round.tsx` (den offentlige "Følger live"-siden) -- leaderboard- + henting, `StrokeLeaderboard`-visning, og "ingen live-visning + tilgjengelig"-fallback-meldingen ville alle feilaktig behandlet en + offentlig Stableford-runde som enten to-sidet eller "ukjent format". + Alle tre rettet samme runde, FØR de kunne bli oppdaget i produksjon. + Backend-siden av samme klasse spesialsjekk (`app/routers/rounds.py`) + var allerede korrekt fra første forsøk (`_format_setup_status`, + `my_net_score_to_par`-gaten, `RoundCreate`/`RoundUpdate` sine + `Literal`-typer) -- kun frontend hadde det gjentatte hullet. + `EditRoundPanel` sin spilleform-brytar (rediger-runde-panelet) utvidet + fra to til tre valg (Slagspill/Stableford/Matchspill), samme mønster + som `new-round.tsx`. + **Scratch-verifisert grundig i to lag** (isolert `teecup_app_scratch`- + rolle + isolert scratch-MinIO + engangs API-container, alle 38 + migrasjoner kjørt friskt, samme mønster som hele prosjektet): et + hånd-utregnet scenario (course handicap 18, slope 113/rating lik par, + 1 slag mottatt per hull) bekreftet "plukket opp" på et par-4-hull med + 1 mottatt slag ga eksakt score 7 (4+2+1, identisk med håndregning), + leaderboardets `total_points` stemte eksakt (0 for plukket-opp-hullet + + 3 for et normalt netto-birdie-hull = 3), reversering (fjern plukket- + opp, sett ekte score, plukk opp igjen) fungerte, avvist tydelig for en + deltaker uten HCP (400), `_format_setup_status` bekreftet IKKE lenger + krasjer (KeyError) for stableford (`setup_complete:true` uten + sider), `RoundUpdate.play_format` PATCH til "stableford" i etterkant + bekreftet, runde fullført uten krasj. + **Deretter en FULL, ekte nettleser-gjennomgang** (Chrome DevTools MCP, + samme `localhost`-ikke-`127.0.0.1`-lærdom fra tidligere runder): hele + opprett-runde-flyten klikket gjennom i UI-et (Stableford-valg, riktig + beskrivelsestekst, INGEN sider-notis etter fiksen), "Plukket opp (0 + poeng)"-knappen i selve `ScoringWizard` bekreftet å auto-hoppe videre + akkurat som et vanlig slagtall, og "PU"-merket bekreftet konsekvent på + ALLE FIRE stedene det vises: scorekort-gridet på selve Score-fanen, + det post-runde `round-scorecard.tsx`-scorekortet (med korrekt "Poeng + 0"/netto 6), `round-leaderboard.tsx` (både i hull-stripen og i + Poeng-modus, total "3" korrekt), og "Så langt i runden"-tabellen. En + separat REGRESJONSSJEKK av et eksisterende `match`-format (to sider, + territorium-bar, "1 UP") bekreftet UENDRET oppførsel -- de to bug- + fiksene rørte kun stableford-grenen. Ingen konsollfeil i noen av + rundene. + **Rullet ut live 2026-07-29**, bruker bekreftet eksplisitt (plan vist + FØR migrasjonen, per CLAUDE.md sin ufravikelige regel): migrasjon 038 + kjørt mot ekte `teecup_db` (kolonne + utvidet CHECK-constraint + bekreftet, `test_isolation.sql` fortsatt 12/12), deretter `docker + compose up -d --build teecup_api teecup_frontend`. Begge containere + boot-et rent, `/health`/`/dashboard` → 200, `teeoff.no` upåvirket. + Neste steg: 0a. **Spillerliste-redesign — nå FAKTISK nettleser-bekreftet (2026-07-27, full 22-skjerms gjennomgang):** rendrer korrekt, ingen @@ -5319,11 +5454,17 @@ Neste steg: 2026-07-25 og siden BYGGET, SCRATCH-VERIFISERT OG RULLET UT LIVE samme dag (se status over). Venner fase 2 (rundevisibilitet) og fase 3 (ekte medspillere) er fortsatt ikke bygget. -3. **Frittstående rundeføring + detaljert statistikk — ADR-033 skrevet - 2026-07-22, IKKE bygget.** Brukeren avklarte 2026-07-22 at dette skal - bli appens HOVEDFOKUS (turneringsoppsett skal bli ekstremt enkelt - ETTER dette er på plass) — den største enkeltbeslutningen i prosjektet - siden ADR-001. Fire load-bærende delbeslutninger avklart eksplisitt +3. **Frittstående rundeføring + detaljert statistikk — ADR-033, skrevet + 2026-07-22 og siden BYGGET/ITERERT KONTINUERLIG hver dag fram til + 2026-07-29 (se hele status-loggen over -- dette punktet er nå appens + klart mest utviklede område, ikke lenger "ikke bygget").** Beholdt her + UENDRET som historisk kontekst for selve grunnbeslutningen fra + 2026-07-22 (hvorfor/hvordan ADR-033 ble designet) -- ikke som en + påstand om at arbeidet fortsatt gjenstår. Brukeren avklarte 2026-07-22 + at dette skulle bli appens HOVEDFOKUS (turneringsoppsett skulle bli + ekstremt enkelt ETTER dette var på plass) — den største enkeltbeslutningen + i prosjektet siden ADR-001, og det har stemt. Fire load-bærende + delbeslutninger avklart eksplisitt (AskUserQuestion): nytt parallelt eierskapsmønster keyet på `user_id` (gjenbruker det allerede beviste `plain_connection()`-mønsteret fra personlig profil/HCP-historikk/sekundær e-post — IKKE en skjult @@ -5510,9 +5651,11 @@ Neste steg: punkt (a), er nå OGSÅ tettet, se status 2026-07-28 over — punktet beholdes her kun for historikk): (a) ~~offline-kø (ADR-028) er kun koblet til turnering-scorekortet~~ — ferdig, browserverifisert og - live; (b) ingen Stableford-poengberegning for frittstående runder (kun - rå slag/differensial), inkl. en uløst "plukket opp ballen"-tilstand; - (c) ~~rundedeling/visibility (ADR-036 fase 2, public/private/friends) + live; (b) ~~ingen Stableford-poengberegning for frittstående runder + (kun rå slag/differensial), inkl. en uløst "plukket opp ballen"- + tilstand~~ — ferdig, scratch-/browserverifisert og live 2026-07-29, + se status over (`play_format='stableford'` + `round_hole.picked_up`, + migrasjon 038); (c) ~~rundedeling/visibility (ADR-036 fase 2, public/private/friends) fortsatt ikke bygget~~ — ferdig, browser-/scratch-verifisert og live 2026-07-28, se status over (ADR-036 er dermed HELT ferdig, alle tre faser); (d) ~~flere flighter i én frittstående runde fortsatt kun @@ -5521,8 +5664,7 @@ Neste steg: koblet til venneforespørsler, ikke til rundehendelser ennå~~ — ferdig, scratch-verifisert og live 2026-07-28, se status over (medspiller lagt til/venn ser synlig runde/tilkoblet runde fullført). - Eneste reelt gjenstående punkt i denne listen nå: (b), Stableford for - frittstående runder. + Alle fem punktene (a)-(e) i denne listen er dermed ferdig. 11. **Ferdig, kun for historikk:** ekte spillformer (match/skins/fourball/ foursome/greensome/scramble) for frittstående runder — backend (ADR-039 + minimums-spiller-håndhevelse) OG frontend (sideoppsett, diff --git a/FEATURE_BACKLOG.md b/FEATURE_BACKLOG.md index 69c7220..2572324 100644 --- a/FEATURE_BACKLOG.md +++ b/FEATURE_BACKLOG.md @@ -2931,17 +2931,19 @@ utslag/innspill + vurdering av sveip vs. scroll) er BEVISST IKKE bygget selv** — brukeren ba eksplisitt om at dette prompres til V0 for en egen vurdering, se egen V0-prompt utarbeidet samme dag (ikke kjørt av brukeren ennå ved denne loggens skriving). -**Fanget, IKKE bygget (brukerens egen kommentar mens punkt 7 ble -avklart):** "plukket opp"-mulighet for Stableford-format -- i Stableford -er det vanlig å plukke opp ballen uten å fullføre hullet når det er -klart 0 poeng uansett. Frittstående runder har i dag INGEN -Stableford-poengberegning i det hele tatt (kun rå slagtall for HCP- -differensial) -- dette er et helt eget, udesignet format-spørsmål, ikke -løst av at "spilt"-avkrysningen ble fjernet. Trenger egen designrunde -(scoring-format-valg per runde, poengberegning, og en "plukket opp"- -tilstand som sannsynligvis bør lagres som en cap på nettoscore, samme -prinsipp som WHS sin Net Double Bogey) den dagen Stableford faktisk -bygges. +**Fanget 2026-07-25, ✅ BYGGET OG LIVE 2026-07-29:** "plukket opp"- +mulighet for Stableford-format -- i Stableford er det vanlig å plukke +opp ballen uten å fullføre hullet når det er klart 0 poeng uansett. +Løst nøyaktig som antatt her: `'stableford'` lagt til som eget +`round.play_format` (migrasjon `038_stableford_and_pickup.sql`), og +"plukket opp" lagres som en cap på (netto) score -- Net Double Bogey, +samme prinsipp som WHS allerede bruker, via den eksisterende +`max_hole_score_for_handicap()` i `handicap_engine.py` (ingen ny +motorlogikk). Full detalj i CLAUDE.md-status 2026-07-29, inkl. to +reelle frontend-bugs funnet og fikset under browserverifisering +(`play_format === "stroke"`-spesialsjekker som ikke ekskluderte det +nye "stableford"-formatet, samme mønster funnet og rettet fem steder +på tvers av `new-round.tsx`/`round-detail.tsx`/`watch-round.tsx`). **Notat fra bruker, IKKE designet/bygget ennå (fanget 2026-07-22):** brukeren har tenkt å ha med (a) måling av lengde på slag, og (b) å kunne @@ -3199,31 +3201,41 @@ trolig avklares SAMMEN, ikke som tre uavhengige design-runder, for å unngå tre parallelle, litt ulike implementasjoner av i bunn og grunn samme idé. -**Åpne spørsmål, ingen besvart ennå:** +**Åpne spørsmål under — HISTORISK, alle AVKLART OG BYGGET samme dag via +ADR-039 (se oppdateringsnotatet øverst i denne seksjonen). Beholdt uendret +som referanse for hvordan spørsmålene opprinnelig ble stilt, med fasiten +lagt til rett under hvert punkt — ikke slettet, per CLAUDE.md sin regel +om å ikke fjerne historikk:** - Skal `round.play_format` utvides med `'skins'`/`'pair_team'` (ny migrasjon, ny CHECK-verdi), eller er dette en helt egen entitet parallelt med `round`? + → **Avklart:** utvidet til 8 verdier (migrasjon 031), samme `round`-tabell. - Match/par-lag: hvordan velges/lagres hvem som spiller mot/med hvem — ved oppsett (som blind draw for turneringer), eller fritt valgt av eieren i etterkant? + → **Avklart:** ny `round_side`-tabell (maks to per runde), eieren + tildeler deltakere til en side fritt i etterkant via UI (`SidesPanel`). - Skins: netto eller brutto, og hvordan behandles uavgjorte hull (rullerer premien, eller deles)? + → **Avklart:** begge akser konfigurerbare av oppsetteren + (`skins_scoring`/`skins_tie_handling`), ny `compute_skins()`-motor. - Skal scorekortets NYE presentasjoner (matchstatus, skins-tavle, side-score) bygges som varianter av eksisterende komponenter (`round-scorecard.tsx`/`round-detail.tsx`), eller gjenbruke turnering- sidens `session-scorecard.tsx`-språk direkte? + → **Avklart:** egne lokale varianter i `round-detail.tsx`/ + `round-scorecard.tsx` (samme visuelle SPRÅK som `session-scorecard.tsx`, + ikke delt kode — prosjektets etablerte "én fil, én kopi"-konvensjon). - Hvordan påvirker dette allerede byggede ADR-038 (faktisk HCP)? Match/ skins/par-lag-runder trenger sannsynligvis EGNE regler for om/hvordan de teller mot faktisk HCP (samme "matchspill telles vanligvis ikke"- resonnement som allerede finnes for `'match'`, men skins/par-lag er ikke vurdert i det hele tatt ennå). - -**Ingen kode skrevet** — dette er bevisst kun fanget/dokumentert nå, på -brukerens eksplisitte instruks. Trenger en egen, dedikert design-/ -ADR-runde (samme skala som ADR-033/036/037) før noe bygges, gitt at -punkt 2-4 hver krever nytt skjema, ny motorlogikk (for skins) eller -gjenbruk av eksisterende turnering-motor (for match/par-lag), og en -egen scorekort-presentasjon per format. + → **Avklart:** delt-ball-formater (foursome/greensome/scramble) teller + ALDRI (ingen individuell score å bygge en differensial fra — viste seg + automatisk av eksisterende `complete_round`-logikk, ingen kodeendring + krevdes). Skins teller NORMALT som slagspill. Match følger allerede + etablert `exclude_from_handicap`-mønster fra ADR-038. --- diff --git a/alternativ designinstruks.md b/alternativ designinstruks.md deleted file mode 100644 index fa5435b..0000000 --- a/alternativ designinstruks.md +++ /dev/null @@ -1,117 +0,0 @@ -# Alternativ designinstruks — PROMOTERT til DESIGN_SYSTEM.md (2026-07-29) - -**Status: AVSLUTTET/ARKIVERT.** Forsøket på dashbordet ble godkjent samme -dag ("det ser bra ut") — innholdet under er nå slått sammen inn i -`DESIGN_SYSTEM.md` (som fortsatt er DEN autoritative kilden, sammen med -CLAUDE.md sin ufravikelige tilgjengelighetsregel). Denne filen beholdes -kun som historisk referanse for selve forslaget slik det opprinnelig ble -formulert — les `DESIGN_SYSTEM.md` for gjeldende regelverk, ikke denne. - -## De nye instruksene (shadcn-basert, klar til bruk i prompter) - -### 1. Fargesystem og Design Tokens (Shadcn-basert) - -- **Bruk eksisterende CSS-variabler:** systemet bygger allerede på - semantiske variabler (`bg-background`, `text-foreground`, `bg-card`, - `border-border`, `text-muted-foreground`). Aldri hardkod - Tailwind-farger som `slate-500`/`gray-100` — det bryter den - eksisterende mørk/lys-tema-logikken. -- **Merkevarefarger:** Grønn (primær) — hovedhandling, valgt tilstand, - positivt (f.eks. HCP-nedgang). Oransje (sekundær/kontrast) — merkevarens - andre pol, brukes til oppmerksomhet/motsetninger (over par, - motstanderlag, "ventende"-indikator). **Oransje er IKKE en advarsel- - eller feilfarge.** -- **Feil/advarsler:** faktiske feil (sletting/fare) bruker `destructive` - (rød). - -### 2. Typografi og lesbarhet (designet for "uten lesebriller") - -- Standard brødtekst er `text-base` (16px). Ved denne størrelsen og med - god kontrast (f.eks. `text-foreground`) er `font-normal` helt - akseptabelt og foretrukket, for å unngå visuell støy. Mindre tekst - (`text-sm`) brukes kun til metadata, og bør da ofte gis `font-medium` - for å kompensere for størrelsen. -- `tabular-nums` konsekvent på all numerisk visning (HCP, score, datoer). -- Signerte tall (HCP-trend, score mot par) bruker ekte minustegn (−), - aldri bindestrek (-). - -### 3. Layout, avstander og "grid" - -- **8-punkts rutenett:** alle marger, avstander (`gap`) og padding følger - multipler av 8 (`p-2`, `p-4`, `p-6` osv.). -- **Trykkflater:** absolutt ufravikelig krav om minimum 44×44px for enhver - interaktiv flate. -- **Kort og beholder:** `rounded-2xl`, `border border-border`, `bg-card`, - svak skygge (`shadow-sm`) i lyst tema. Tomtilstander kan bruke - `border-dashed`. - -### 4. Interaksjon og navigasjon - -- Alle interaktive elementer må ha tydelige tilstander for `:hover` og - `:active` — umiddelbar, taktil bekreftelse på at trykket er registrert. -- Deaktivert tilstand: `opacity-50` og `pointer-events-none`. -- `lucide-react`. Viktige handlinger skal alltid ha en tekstlabel ved - siden av ikonet. Rene ikon-knapper tillates kun for universelt - forståtte symboler (tannhjul, lukkekryss, varselbjelle) og MÅ da ha en - beskrivende `aria-label`. - -### 5. Lyst og mørkt tema - -- Tema styres automatisk av shadcn-variablene (punkt 1) — ingen egen - logikk trengs per skjerm. -- Dybde i mørkt tema skapes automatisk av at `bg-card` er marginalt - lysere enn `bg-background`, adskilt med `border-border`. -- Kontrastnivå skal møte WCAG AA i begge oppsett (shadcn-variablene - håndterer dette ut av boksen). - -### 6. Skjemaer og inndata (mobil-først UX) - -- Tekst i ``/`