/* ============================================================
   Huskis — styles
   Font: Atkinson Hyperlegible Next. Dempet skifer/grønn-palett. Responsivt.
   ------------------------------------------------------------
   DESIGNSYSTEM (gjenbruk — ikke hardkod):
   • Kontroll-tokens: --control-h/--control-radius/--control-bg gjelder ALLE
     knapper i knapperadene (＋-knapper, søppelkasser, filter, ☰) → identisk
     høyde/radius/flate i samme rad.
   • Fargede knapper: .btn-solid + .btn-green/.btn-accent/.btn-red/.btn-yellow —
     ÉN felles stil (gradient, hvit skrift, lys-opp ved hover) for alle fargede
     knapper. Aldri egne ad hoc-gradienter.
   • Lysretning: alle flate-gradienter er LODDRETTE med lyseste ende ØVERST —
     samme lys ovenfra som de nedoverforskjøvne skyggene forutsetter.
   • Delte klasser: .panel-head/.panel-title/.panel-actions (menyoverskrift +
     knapperad), .btn-add (grønn ＋), .trashcan (hvit søppelkasse),
     .corner-controls/.corner-btn (toppkontrollgruppen: varsler, kalender, søk, drakt, konto),
     .crumb-btn (navigasjonsknappen), delte sletteknapp-, placeholder- og
     håndtak-regler.
   • Flate-mønster: halvgjennomsiktig hvit (--control-bg) som hviletilstand,
     helt ugjennomsiktig (#fff) ved hover.
   • Luft-regler: hvert element har samme luft på alle kanter (én padding-
     verdi), og luft UTENFOR/MELLOM elementer er alltid ≥ luften INNI dem.
   ============================================================ */

/* WEBFONTEN — selvhostet fra assets/fonts/, ikke hentet fra Google Fonts.
   Appen har dermed ingen tredjepartsvert i det hele tatt: `style-src` og
   `font-src` er begge `'self'` (docs/sikkerhetsheadere.md), fonten laster like
   godt om Google er nede eller blokkert, og ingen brukeradresse lekker ut.
   Filene er de samme to woff2-utsnittene Google leverte — ett variabelt snitt
   (wght 400–700) per unicode-utsnitt — så typografien er uendret. Utsnittene
   og sjekksummene er dokumentert i docs/sikkerhetsheadere.md, og
   tests/security-headers.test.js regner dem ut på nytt.
   `font-display: swap`: teksten vises med reservefonten med én gang og byttes
   når fila er inne — en font som ikke er lastet skal aldri gi tom skjerm. */
@font-face {
  font-family: 'Atkinson Hyperlegible Next';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('assets/fonts/atkinson-hyperlegible-next-v7-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Atkinson Hyperlegible Next';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('assets/fonts/atkinson-hyperlegible-next-v7-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --font: 'Atkinson Hyperlegible Next', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

  /* Sier fra til nettleseren hvilken drakt siden er i, slik at alt VI ikke
     tegner selv følger med: <select>-nedtrekket, dato- og klokkeslettvelgerne i
     tidsplanen, rullefeltene og tekstmarkøren. Uten den blir en mørk app
     ledsaget av lyse systempopover-er — det ene stedet drakten ellers ville
     lekket. Settes her og snus i den mørke blokken. */
  color-scheme: light;

  --bg: #667788;
  --bg-grad-a: #667788;
  --bg-grad-b: #667788;

  --ink: #37343f;
  --ink-soft: #5f5a6b;
  --line: #e3e7e3;

  /* KONTRAST-KONTRAKT (WCAG AA). Verdiene under er ikke smaksvalg — de er målt,
     og `tests/a11y-contrast.test.js` håndhever dem. Endrer du en farge her, kjør
     den testen: den leser tokenene ut av denne fila og regner ratioene på nytt.

     HVA SOM LIGGER OPPÅ FLATEN avgjør hvilken farge den kan ha — det er hele
     grunnen til at det finnes både en grønn og en blågrønn her:

       • GRØNT (--primary) bærer bare SVARTE IKONER, aldri tekst. Det er ＋-
         knappene. Kravet er 3:1 for et grafisk objekt, og en LYS grønn er best
         for et svart ikon (6.96:1 mot den lyse enden). En grønn mørk nok til
         hvit tekst presset ikonkontrasten ned mot gulvet.
       • BLÅGRØNT (--accent) bærer HVIT tekst og hvite glyfer: Lagre, Inviter,
         bryterne, hake-fyllet, statuschipene. Fargen er kontoikonets egen
         (#85adad), mørknet til den bærer hvit tekst (4.84:1). Grønt og blågrønt
         skiller altså to ROLLER, ikke to smaksvalg.
       • RØDT (--danger) bærer hvit tekst.
       • GULT kan ikke bære hvit tekst i det hele tatt (en gul som gir 4.5:1 mot
         hvit er ikke lenger gul, den er oliven). .btn-yellow bruker derfor MØRK
         tekst — se .btn-yellow i knappeseksjonen.
       • Kontrast er symmetrisk, så de samme rød-/blågrønnverdiene er samtidig
         lovlige som TEKSTfarge på hvit (--danger brukes begge veier).
       • --focus er mørk, ikke brand-farget: en grønn ring forsvant mot både
         board-bakgrunnen og de grønne palettfargene (1,2:1). Denne gir ≥ 3:1
         mot alle flater i appen — hvit, board-bakgrunn, alle seks palettfarger
         og alle knappefargene. */
  --surface: #ffffff;
  /* Grønn: KUN flate under svarte ikoner (＋-knappene). Aldri hvit tekst. */
  --primary: #668866;       /* svart ikon: 4.75:1 */
  --primary-light: #7fa77f; /* svart ikon: 6.96:1 */
  --primary-dark: #4d664d;
  --primary-soft: rgba(102, 136, 102, 0.14);
  --primary-soft-hover: rgba(102, 136, 102, 0.24);
  /* Blågrønn: flate under HVIT tekst/glyfer. Kontoikonets farge, mørknet. */
  --accent: #487a7a;        /* hvit tekst: 4.84:1 */
  --accent-dark: #386262;   /* hvit tekst: 6.60:1 */
  --danger: #c0384d;        /* hvit tekst PÅ den: 5.37:1 — og som tekst på hvit: 5.37:1 */
  --danger-dark: #a82b40;   /* hvit tekst: 6.81:1 */
  /* Advarsel (noe pågår / venter), ikke fare. Frikoblet fra den gule
     knappegradienten: gradienten skal være GUL (den bærer mørk tekst), mens
     --warn brukes som tekst og som statusprikk på lys flate og derfor må klare
     4.5:1 mot hvit på egen hånd. */
  --warn: #7d5f10;          /* på hvit: 5.97:1 */
  /* Samme par som --primary-soft*, men i faresonen (sveip-for-å-slette-kontoen). */
  --danger-soft: rgba(192, 56, 77, 0.16);
  --danger-soft-hover: rgba(192, 56, 77, 0.30);

  /* Fokusring. Mørk (ikke brand-grønn) fordi den må lese mot ALLE flater appen
     har; --focus-on-dark er søsteren for de få mørke flatene (toast,
     oppdateringsbanner) der en mørk ring ville forsvunnet. */
  --focus: #10131a;
  --focus-on-dark: #ffffff;
  --focus-w: 3px;

  /* Fargede knapper (.btn-solid): én gradient per farge, gjenbrukt overalt.
     LYSRETNINGEN ER FELLES: alle flate-gradienter er LODDRETTE med den lyseste
     enden ØVERST. Skyggene i appen (--shadow-*) er forskjøvet nedover, altså
     lys skrått ovenfra; en gradient som lysner nedover ville lyssatt flaten
     motsatt av sin egen skygge. Loddrett gir dessuten hele fargespranget over
     knappens korteste akse, så gradienten leses like tydelig på en bred knapp
     som på en kvadratisk. */
  --grad-green: linear-gradient(180deg, var(--primary-light), var(--primary));
  --grad-accent: linear-gradient(180deg, var(--accent), var(--accent-dark));
  --grad-red: linear-gradient(180deg, var(--danger), var(--danger-dark));
  --grad-yellow: linear-gradient(180deg, #e8bb50, #d9a52c);
  /* Startgruppene i «Kommende hendelser» er INGEN advarsel, og skal derfor ikke
     låne varselfargene. To egne flater, lyse nok til at den svarte ikonstreken
     klarer 3:1 mot begge endene (som resten av kontraktsfargene er de like i
     begge drakter — se docs/kommende-hendelser.md). */
  --grad-purple: linear-gradient(180deg, #cda9cd, #ad85ad);
  --grad-blue: linear-gradient(180deg, #a9a9cd, #8585ad);
  /* Lenger ute enn en måned er ingen grad av hast, og da er flaten heller ingen
     farge: den nøytrale skifergrå sier «parkert». Den deles av de to ytterste
     gruppene i «Kommende hendelser» — én for frister, én for starter — som står
     i hver sin seksjon med hvert sitt ikon. Samme krav som de andre
     kontraktsflatene: lys nok til at den svarte ikonstreken klarer 3:1 mot
     begge endene, og lik i begge drakter. */
  --grad-slate: linear-gradient(180deg, #b9bec6, #949aa4);

  /* DEN SIKRE SONEN. Fire tall som sier hvor mye av viewportet som er dekket
     av systemets egne flater — statusfelt/hakk øverst, gestelinje nederst,
     hjørneavrunding og hakk i landskap på sidene. Alt som er `position: fixed`
     mot en viewport-kant skal legge disse PÅ sin egen avstand, slik at
     ingenting havner under systemflatene.

     `env(safe-area-inset-*)` er 0 i en vanlig nettleser (det finnes ingen
     inset-er å rapportere), så reglene som bruker dem er en no-op der. De får
     verdier først i et native skall, og bare når siden ber om å få tegne under
     systemfeltene (`viewport-fit=cover` i index.html).

     Fanget i egne tokens, ikke skrevet som env() der de brukes: da finnes
     sonen ETT sted, og en test kan sette dem for å bevise at de faste
     elementene faktisk flytter seg (tests/safe-area.test.js). */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);

  /* Slippfoten nederst (søppelkasse/arkiv): luften rundt kassene, og høyden
     board-et må holde av for dem når de er synlige. Kassene dobler høyden
     under et drag (se `.trashcan.drag-trash`); reservasjonen følger HVILE-
     høyden — draget vokser nedenfra og over foten, ikke inn i board-et. */
  --dock-pad: 10px;
  --dock-gap: 10px;
  --dock-h: calc(var(--control-h) + 2 * var(--dock-pad));

  /* Sidepolstring i toppmenyen — viewport-relativ. Kontoknappen (fast i
     viewportets hjørne) bruker samme token, så den flukter med toppmenyens
     høyre kant. */
  --toolbar-pad: clamp(12px, 3vw, 40px);
  /* ÉN luft-verdi for HELE headeren, i begge retninger: mellom panelets rader
     (hovedbryteren og fanens knapperad), mellom kontrollene på en rad, og
     mellom hjørneknappene — som bryter til flere rader og derfor bruker den
     samme verdien vannrett og loddrett. Ett tall, ingen kompenserende
     unntak: er avstanden mellom to knapper 10 px, er avstanden ned til raden
     under det også. `syncTopChrome()` LESER radgapet ut av panelet i stedet for
     å kjenne tallet, så høydeutregningen følger med av seg selv. */
  --topbar-gap: 10px;
  /* Panelets egen polstring over og under innholdet. Hjørnegruppen ligger
     UTENFOR panelets flyt og må flukte med den samme linjen, så begge leser
     tallet herfra. */
  --topbar-pad-y: 12px;
  /* Bredden toppkontrollgruppen tar, inkludert luften til innholdet ved siden
     av. Brukt to steder som MÅ holde takt: `.toolbar`s margin (én linje) og
     `.breadcrumb`s padding (stablet mobiloppsett) — se «Toppmenyen» over
     `.topbar`. Verdien her er kun en startverdi for de tre knappene som finnes
     i dag; `syncTopChrome()` i app.js MÅLER gruppen og skriver den faktiske
     bredden, slik at en ny knapp ikke krever en ny utregning her. */
  --corner-btns-w: calc(var(--control-h) * 3 + var(--topbar-gap) * 3);
  /* Høyden hovedbryteren (`.topbar-row-tabs`) legger beslag på øverst i
     panelet, medregnet radgapet under den. MÅLES i syncTopChrome; verdien her
     er reserven fram til den første målingen. */
  --main-tabs-h: 0px;
  /* BEVEGELSEN i appens brytere: knotten i konto-modalens av/på-brytere og den
     glidende flaten i de segmenterte bryterne (`.seg`) skal lese som den samme
     mekanikken, så varighet og kurve står ett sted. */
  --switch-motion: 0.16s ease;
  /* Ett tall for ALT luft-mellomrom i listevisningen: board-ets venstre/høyre/
     bunn-padding, kolonne-gap OG kort-til-kort-avstand — samme verdi overalt gir
     identisk luft rundt og mellom listekortene. Bunn-padding-effekten kommer fra
     siste korts EGEN bunn-margin (se .app-main), ikke fra en egen padding-bottom.
     Padding-top regnes ut i JS (se syncHeaderHeight) — nøyaktig meny-høyde +
     denne verdien, lest fra en reelt oppløst egenskap (column-gap), ikke fra
     denne variabelen direkte (clamp()/vw løses ikke ut ved lesing av en
     custom property). */
  --board-gap: clamp(12px, 4vw, 40px);

  /* Minste berøringsflate på en ikonknapp. Knappen TEGNES mindre (34–36 px, så
     listevisningen holder seg kompakt); dette er feltet som tar imot fingeren.
     Se «Berøringsflate på ikonknappene» lenger nede. */
  --touch: 44px;
  /* Synk-pillens høyde + luften under den. Den er `position: fixed` og ligger
     over alt som ikke er en modal, så flater som fyller viewportet må kunne
     holde av plassen den tar (.note-editor-body). */
  --sync-pill-h: 52px;

  /* Kontroll-tokens: alle knapper/kontroller i knapperadene deler disse. */
  --control-h: 49px;
  --control-radius: 14px;
  --control-bg: rgba(255, 255, 255, 0.75);

  /* Typografi-skala: ÉN kilde for de gjentakende tekststørrelsene, så «juster
     alt X %» er én endring. --fs-base er brødteksten (element/input/kort-tekst).
     Enkelte ikonspesifikke/en-gangs størrelser (brand, ikon-boks) står fortsatt
     som px der de er nært knyttet til en piksel-geometri. */
  --fs-xs: 15px;   /* etiketter, meta, panel-titler */
  --fs-sm: 17px;   /* små knapper, hint */
  --fs-md: 18px;   /* navn, sekundær tekst */
  --fs-base: 19px; /* brødtekst: element/kort/input */
  --fs-lg: 20px;   /* titler (kort/rader) */
  --fs-xl: 24px;   /* modal-overskrifter */

  --radius: 18px;
  --radius-sm: 12px;
  --shadow-sm: 0 2px 6px rgba(35, 45, 55, 0.12);
  --shadow-md: 0 8px 20px rgba(35, 45, 55, 0.18);
  --shadow-lg: 0 18px 42px rgba(25, 35, 45, 0.34);

  /* DRA-SLØRET: hvor mye av sin egen farge en LØFTET flate beholder. Ett tall
     for hele appen — flaten, korthodet og platene under det som dras leser det
     samme (se «ALT SOM DRAS ER HALVGJENNOMSIKTIG» lenger ned). */
  --dnd-veil: 58%;

  /* Skygge bak hvit skrift så den er lesbar også på lyse kort-/mappefarger. */
  --text-shadow: 0 1px 2px rgba(0, 0, 0, 0.42);

  /* RADENES POLSTRING, ETT STED FOR HVER FAMILIE. Appen har to slag klikkbare
     rader, og de var tidligere skrevet om igjen med litt ulike tall i hver
     meny (8/9 her, 7/9 der) — små nok forskjeller til at ingen enkeltmeny så
     gal ut, store nok til at to menyer ved siden av hverandre ikke leste likt.
     Tallet bor derfor her, og bruksstedene peker på det:

       • MENYRAD (`--menu-row-pad-*`) — en rad i en popover: objektmenyen og
         ansvarlig-velgeren, som deler `.switcher-panel`-skallet. Trangere enn
         listeraden, fordi panelet selv er smalt og har sin egen 8 px kant.
       • LISTERAD (`--list-row-pad-*`) — en rad i en rullende modalkropp:
         hendelser, varsler og søketreff. Romsligere, fordi den står på hele
         modalens bredde og skal kunne bære to linjer tekst.

     Endrer du et tall, endrer du det for hele familien. Det er poenget. */
  --menu-row-pad-y: 8px;
  --menu-row-pad-x: 9px;
  --list-row-pad-y: 9px;
  --list-row-pad-x: 12px;

  /* Samme linjetykkelse som ikonsettets strek (se icons.js/index.html), for
     CSS-tegnede streker (f.eks. sveipefeltets pil) som skal matche ikonene.
     Ikonstreken er nå 1 px i ALLE størrelser (non-scaling-stroke, se «ÉN
     PIKSEL STREK» ved .icon lenger ned), så dette tallet er den samme
     konstanten — ikke lenger et anslag på hvor tykk en skalert strek blir. */
  --icon-stroke: 1px;

  /* ========== DRAKT-TOKENS (lys) ==========
     Alt under er verdier som SNUR i mørk drakt. De sto tidligere hardkodet
     rundt om i fila (#fff, rgba(0,0,0,…), rgba(255,255,255,…)); her er de
     samlet, slik at den mørke drakten er ÉN blokk med overstyringer og ikke en
     kopi av stilarket. Verdiene er nøyaktig de samme som før — lys drakt ser
     ut som den alltid har gjort. Autoritativt: docs/mork-drakt.md.

     Tokenene er delt i to familier etter HVA de ligger på, fordi de snur på
     hver sin måte:

       • FLATE-familien (--surface*, --line, --wash*, --overlay, --glass-bg …)
         ligger på appens egne lyse flater (modaler, toppmeny, kort utenfor
         paletten). I mørk drakt blir flatene mørke og blekket lyst.
       • PÅ-FARGE-familien (--plate*, --tint*, --hairline, --on-color-soft)
         ligger OPPÅ en palettfarge (et listekort, et områdekort). Der er det
         ikke flaten som snur — palettfargen gjør jobben selv (app.js speiler
         L-en) — men lagene oppå: de halvgjennomsiktige HVITE platene blir
         halvgjennomsiktig SVARTE, og de svarte hårstrekene blir hvite. */

  /* Flater. --surface er modal-/panelflaten, -2 er den svakt tonede foten/
     seksjonsflaten, -3 er tekstfeltenes flate, -alt er den arvede låsens
     varselflate. --control-bg-hover er den ugjennomsiktige hviletilstanden
     --control-bg går til ved hover (flate-mønsteret). */
  --surface-2: #faf9fe;
  --surface-3: #fbfbfd;
  --surface-alt: #fff7ed;
  --control-bg-hover: #ffffff;
  /* Toppmenyens glassflate (backdrop-blur over board-et). */
  --glass-bg: rgba(255, 255, 255, 0.72);
  /* Toastens/oppdateringsbannerets mørke glassflate — mørk i BEGGE drakter
     (den bærer hvit tekst), bare et hakk dypere i den mørke. */
  --glass-dark: rgba(45, 38, 70, 0.62);
  /* Modal-/demo-mørkleggingen bak dialoger. */
  --overlay: rgba(45, 38, 70, 0.42);
  /* Svak toning PÅ en lys flate: hover på ikonknapper, kbd-brikker,
     hint-chipen på hvitt. --wash-2 er den samme, et hakk sterkere (spor). */
  --wash: rgba(0, 0, 0, 0.07);
  --wash-2: rgba(0, 0, 0, 0.1);
  /* Av-sporet i bryterne (på/av-pillene). */
  --track: #c4ccd2;
  /* Antall-sirkelen i søppelkasse-knappene. */
  --count-bg: #e6ece6;
  /* «Mapper delt med meg» er en VIRTUELL beholder uten palettfarge — en
     nøytral, lys kortflate (se .free-groups-card). Den er det ene kortet i
     appen som ikke får fargen sin fra paletten, og trenger derfor sitt eget
     sett. */
  --free-bg: #eef0f6;
  --free-head: #dfe3ee;
  --free-accent: #9aa3b8;

  /* Tekstfarger som må bytte side når flaten gjør det. --danger/--warn/
     --primary-dark er FLATE-/signalfarger (knappegradienter, prikker,
     stiplede kanter) og skal IKKE lysne i mørk drakt — derfor egne
     -ink-tokens for de stedene den samme fargen brukes som TEKST. */
  --danger-ink: #c0384d;    /* på hvit: 5.37:1 */
  --primary-ink: #4d664d;   /* = --primary-dark; på hvit: 7.09:1 */
  --note-ink: #9a6b15;      /* tidsnotatet; på hvit: 4.63:1 */

  /* Ikonsettet (icons.js + de innlimte SVG-ene i index.html) har fargene som
     PRESENTASJONSATTRIBUTTER — `stroke="#111"`, `fill="#ffffff"`,
     `fill="#c0c4c9"`. En CSS-regel slår et slikt attributt, så attributt-
     selektorene lenger nede maler dem om til disse tokenene i stedet: strek og
     «papir» snur med drakten, uten at én eneste SVG må endres. Fargede
     knapper (.btn-solid) pinner dem tilbake for sitt eget subtre — se der. */
  --icon-ink: #111111;
  --icon-paper: #ffffff;
  --icon-grey: #c0c4c9;

  /* ---- På-farge-familien: lag OPPÅ en palettfarge ---- */
  /* Listepunkt-platene i et kort. Hvite og halvgjennomsiktige i lys drakt,
     svarte og halvgjennomsiktige i mørk — begge veier er «samme flate, litt
     løftet fra kortet». */
  --plate: rgba(255, 255, 255, 0.55);
  --plate-hover: rgba(255, 255, 255, 0.85);
  --plate-done: rgba(255, 255, 255, 0.3);
  --plate-done-hover: rgba(255, 255, 255, 0.48);
  /* Knappeflatene som ligger rett på kortfargen (.card-cog/.cat-cog/
     .done-restore) — svak hvit flate + ring, lyser opp ved hover. */
  --tint: rgba(255, 255, 255, 0.2);
  --tint-hover: rgba(255, 255, 255, 0.34);
  /* Menyknappen mens dens egen popover står åpen: ett hakk over hover, så
     knappen ikke ser «kald» ut under menyen sin. */
  --tint-open: rgba(255, 255, 255, 0.42);
  --tint-ring: rgba(255, 255, 255, 0.35);
  /* Hårstrekene PÅ kortflaten (kategoriskiller, «Utført»-linja) og den dempede
     etiketten ved siden av dem. Disse MÅ snu: en svart strek på et mørkt kort
     er usynlig. */
  --hairline: rgba(0, 0, 0, 0.15);
  --on-color-soft: rgba(0, 0, 0, 0.42);
  /* Meta-chipene under navnet. */
  --chip-bg: rgba(255, 255, 255, 0.78);
  /* Tekst-border for mappetitler/listepunkter (.item-text) — se .item-text for
     hvorfor: teksten er `--ink`, ikke fast hvit, og trenger derfor ingen kant i
     lys drakt (av). Mørk drakt slår den på, se der. */
  --item-text-shadow: none;
  --item-text-stroke: 0 transparent;
  /* Placeholder-flaten under et drag («hullet» objektet skal falle i). Den
     ligger på board-bakgrunnen ELLER inne i et kort, og må være synlig begge
     steder: en mørkning på en mørk board-bakgrunn er ingenting (1,03:1). */
  --scrim: rgba(0, 0, 0, 0.12);
  /* FLATEN den semantiske fargen males som når objektet holdes over
     søppelkassen: et slipp der sletter. Den er UGJENNOMSIKTIG med vilje: den erstatter palettfargen i alle
     lagene av det løftede objektet i stedet for å vaskes over dem, og
     gjennomsikten kommer fra `--dnd-veil` som før. En vask alene lot kortets
     egen farge bestemme sluttfargen — og på et KOMPAKT løft malte korthodet
     sin egen palettfarge rett over vasken, så et grønt kort leste grønt. */
  --drag-danger-face: #b8394c;
  --drag-danger-ink: #ffffff;
  /* Samme lag, men for ARKIVET: et slipp der arkiverer, og arkivering er ingen
     fare — fargen er derfor arkivikonets egen manilagule, ikke rødt. Litt
     sterkere alfa enn rødvasken fordi tonen er lysere og ellers ville forsvunnet
     i kortfargene. `--archive-soft` er søsteren under knappen selv, som
     `--danger-soft` er det for kassen. */
  --archive-soft: rgba(201, 160, 106, 0.22);
  /* Arkivets tilsvarende flate. Gul bærer ikke hvit tekst (se
     kontrast-kontrakten), så blekket er det mørke. */
  --drag-archive-face: #d9a441;
  --drag-archive-ink: #2a2118;
  /* Avkryssingsboksens kant ved hover. Egen fra --primary fordi hvilekanten
     (--card-accent) regnes ut fra kortfargen og treffer 3:1 — en hover som
     bytter til en fast farge må klare det samme, ellers blir kontrollen
     UTYDELIGERE i det øyeblikket man sikter på den. */
  --check-hover: #668866;
}

/* ============================================================
   MØRK DRAKT
   ------------------------------------------------------------
   `data-theme` settes av theme.js FØR første maling (se den fila og
   docs/mork-drakt.md). Denne :root-blokken overstyrer KUN tokens — ingen nye
   regler, ingen duplisert geometri. Ser du deg nødt til å skrive en
   `[data-theme="dark"]`-regel med noe annet enn en custom property i her,
   mangler det sannsynligvis et token i :root over.

   ÉN GRUPPE TOKENS ER UNNTAKET, og bor derfor IKKE i denne blokken: platene og
   flatene som ligger oppå en palettfarge (listepunkt, korthode, kortflate,
   kategorifordypning, aksentstripen) skal bære et preg av NETTOPP DEN
   PALETTFARGEN, som først finnes inline per kort. De kan derfor ikke være en
   flat :root-verdi, og bor i stedet i en egen `.card`-scopet blokk rett under
   denne — se kommentaren der.

   Kontrastene er målt, ikke valgt på øyemål, og `tests/a11y-contrast.test.js`
   regner dem ut på nytt fra begge blokkene — nøyaktig som den gjør for :root.

   PALETTFARGENE STÅR IKKE HER. Kort-/mappe-/områdefargene lages i JS
   (app.js → colorForIndex): samme tone og samme metning, med L-settet speilet
   fra [60,75,90] til [42,32,22]. Se kommentaren der for hvorfor speilingen er
   komprimert og ikke en ren 100−L.
   ============================================================ */
:root[data-theme="dark"] {
  color-scheme: dark;

  /* Board-bakgrunnen. Samme tone som den lyse (skifer, h≈210), langt nede i
     L. Holdes i takt med THEME_COLOR i theme.js. */
  --bg: #141922;
  --bg-grad-a: #141922;
  --bg-grad-b: #141922;

  --ink: #e8e6ef;           /* på --surface: 12.76:1 */
  --ink-soft: #a8a5b4;      /* på --surface: 6.54:1 */
  --line: #333a46;

  --surface: #1e232c;
  --surface-2: #191e27;
  --surface-3: #171c25;
  --surface-alt: #2a2418;
  /* Kontrollflatene på board-et er nå et svakt LØFT, ikke en hvit plate: den
     mørke drakten bygger dybde med lys, ikke med skygge. */
  --control-bg: rgba(255, 255, 255, 0.1);
  --control-bg-hover: rgba(255, 255, 255, 0.18);
  --glass-bg: rgba(255, 255, 255, 0.06);
  --glass-dark: rgba(10, 12, 18, 0.72);
  --overlay: rgba(4, 6, 10, 0.62);
  --wash: rgba(255, 255, 255, 0.1);
  --wash-2: rgba(255, 255, 255, 0.14);
  --track: #3c434e;
  --count-bg: rgba(255, 255, 255, 0.14);
  --free-bg: #262c37;
  --free-head: #202631;
  --free-accent: #59616f;

  /* FOKUSRINGEN SNUR. Den mørke ringen (#10131a) er valgt for å lese mot alle
     LYSE flater; mot board-bakgrunnen i mørk drakt gir den 1.0:1. Hvit gir
     ≥ 4.0:1 mot alle 36 mørke palettfarger og ≥ 13:1 mot flatene.
     Ringen ligger alltid UTENFOR kanten på de fargede knappene
     (outline-offset ≥ 0), altså på flaten bak dem — ikke på selve knappen. */
  --focus: #ffffff;
  --focus-on-dark: #ffffff;

  /* Signalfargene beholder flate-rollen sin (knappegradientene og de stiplede
     kantene er uendret), men får lyse søsken der de brukes som TEKST. */
  --danger-ink: #f08fa0;    /* på --surface: 6.86:1 */
  --primary-ink: #8fbf8f;   /* på --surface: 7.52:1 */
  --note-ink: #e2bd63;      /* på --surface: 8.78:1 */
  /* --warn er statusprikken. Den mørke gulfargen (#7d5f10) er laget for hvit
     bakgrunn og faller til 1.4:1 mot den mørke statuspillen. */
  --warn: #e0b64a;          /* mot statuspillen: 6.6:1 */

  /* Ikonsettet: lys strek, mørkt «papir». Da leses de samme SVG-ene som en
     strektegning på mørk flate i stedet for som hvite blaff. */
  --icon-ink: #e9e7ef;
  --icon-paper: #262c36;
  --icon-grey: #767d88;

  /* Hårstrekene og de små kontrollflatene (tannhjul-knappene, menyknappen) er
     et svakt LØFT — dempet, ikke en sterk hvit flate, så de leser som en rolig
     detalj og ikke som en egen lyskilde. `--plate`/`--plate-hover`/
     `--plate-done`/`--plate-done-hover`/`--chip-bg` STÅR IKKE HER: de er
     «på-palettfarge»-tokens som må blandes med KORTETS EGEN farge (samme
     grunn som `--card-accent` er JS-satt, ikke et CSS-token), og bor derfor på
     `.card` lenger ned. */
  --tint: rgba(255, 255, 255, 0.08);
  --tint-hover: rgba(255, 255, 255, 0.14);
  --tint-open: rgba(255, 255, 255, 0.18);
  --tint-ring: rgba(255, 255, 255, 0.15);
  --hairline: rgba(255, 255, 255, 0.12);
  --on-color-soft: rgba(255, 255, 255, 0.62);
  /* Tynnere enn den lyse drakts 1px: kortflatene bærer nå selv et svakt preg av
     palettfargen (se `.card` lenger ned), og teksten trenger bare robusthet mot
     DET — ikke en kraftig kontur som på en fullt farget flate. */
  --item-text-shadow: var(--text-shadow);
  --item-text-stroke: 0.5px #000;
  /* Placeholderen LØFTER i stedet for å mørkne — se kommentaren ved :root.
     Mot board-bakgrunnen: 1,45:1, altså bedre enn den lyse drakts egne 1,22:1.
     Innover-skyggen blir stående svart i begge drakter; det er den som gir
     «hull», og et hull er mørkt uansett drakt. */
  --scrim: rgba(255, 255, 255, 0.13);
  /* Den mørke drakten LØFTER: flatene er de LYSE tonene, og blekket det mørke
     — motsatt av lys drakt, som alle andre løftede flater her. */
  --drag-danger-face: #ee8397;
  --drag-danger-ink: #2a1418;
  --archive-soft: rgba(230, 200, 150, 0.20);
  --drag-archive-face: #e6c896;
  --drag-archive-ink: #2a2118;
  /* --primary mot den mørke platen (nå en color-mix() mot palettfargen, se
     `.card` lenger ned) klarer så vidt 3:1 i verste hjørne — men med langt
     mindre margin (min 3,13:1) enn dette dedikerte tokenet gir (min 5,94:1),
     og en hover-kant skal ikke bli utydeligere enn hvilekanten i det øyeblikket
     man sikter på den. tests/a11y-contrast.test.js regner marginen ut på nytt. */
  --check-hover: #8fbf8f;
  /* Skygger bærer ikke dybde på en mørk flate slik de gjør på en lys — de må
     være dypere for i det hele tatt å synes. */
  --shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 8px 20px rgba(0, 0, 0, 0.5);
  --shadow-lg: 0 18px 42px rgba(0, 0, 0, 0.66);
}

/* ------------------------------------------------------------
   MØRK DRAKT — kortsubtreet
   --------------------------------------------------------------
   De platene/flatene som ligger OPPÅ en palettfarge (listepunkt, korthode,
   kategorifordypning, meta-chip …) kan ikke overstyres med en flat verdi i
   :root[data-theme="dark"] over: de skal bære et svakt preg av NETTOPP DET
   KORTET sin farge, og hvert kort får sin egen `--card-bg` inline fra
   `paintCardColor()` i app.js. Det er samme grunn til at palettfargene selv
   «ikke står her» (se kommentaren ved :root[data-theme="dark"]) — bare én
   lagdeling dypere. Denne blokken er derfor det ENE stedet i fila der en
   `[data-theme="dark"]`-regel treffer noe annet enn :root: den er scopet til
   `.card` og blander tokenene med `color-mix()` av `--card-bg`/`--card-accent`
   (satt inline av app.js) og en nøytral reserve-hex. En nettleser uten
   `color-mix` beholder reserve-hexen (den står FØR color-mix-deklarasjonen på
   samme token) — en fullgod, bare uten fargepreg, nøytral skifer-utgave.

   To ting å passe på ved endring her:

   1. INGEN regel her må lage en containing block for dra-og-slipp. dnd-kit
      løfter objektet inn i TOP LAYER og posisjonerer det selv (`position`,
      `top`/`left`, se dnd-kit-blokken lenger nede). Et tidligere forsøk satte
      `position: relative` på `.card` for å tegne en aksentstripe med
      `::before`, og det gjorde `.card` til containing block for sine absolutt
      posisjonerte etterkommere OG overstyrte det løftede objektets egen
      posisjonering (denne blokkens selektor er sterkere) — det løftede
      objektet la seg langt nedenfor fingeren. Stripen males
      derfor med en BAKGRUNNSGRADIENT: bakgrunn påvirker verken containing
      block, layout-boks eller `getBoundingClientRect()`, i motsetning til
      `position`/`transform`/`filter`/`perspective`/`contain`/`will-change`,
      som derfor ikke har noe i denne blokken å gjøre.
      `tests/dnd-viewport-clamp.test.js` måler pekerforankringen i mørk drakt
      på alle fem nivåer; `tests/dark-mode.test.js` slår fast at `.card` er
      `static`.
   2. INGEN regel her må overdøve en TILSTAND fra resten av fila. Selektorene
      er `(0,3,0)` og slår dermed `.card:hover`, `.dnd-surface .card[data-dnd-dragging]`
      og `.nav-board .card.active`. Flate-egenskaper som EIES av en tilstand
      (box-shadow) settes derfor ikke direkte her, men via tokens, slik at
      hvile/hover/dra fortsatt velges av reglene lenger nede i fila. Der en
      flate likevel settes direkte, står tilstanden eksplisitt utenfor
      (`:not(.active)`, `:not([data-dnd-dragging])`).

   Kontraster og tonale trinn (min–maks over alle 36 mørke palettfarger) er
   dokumentert i docs/mork-drakt.md og håndhevet av tests/a11y-contrast.test.js. */
/* PÅ-PALETTFARGE-FAMILIEN BOR DER `--card-bg` BOR. Verdiene er blandinger av
   flatens EGEN farge, så de må defineres på hver node som setter `--card-bg` —
   ikke bare på `.card`. Idébeholderen (nøytral) og idékategorien (palettfarget,
   se `.idea-cat`) er de to andre. Nøstingen går opp av seg selv: en
   idékategori inne i idébeholderen redefinerer dem fra sin egen `--card-bg`. */
:root[data-theme="dark"] .card,
:root[data-theme="dark"] .ideas-card,
:root[data-theme="dark"] .idea-cat {
  /* Listepunkt-platene, den utførte platen og meta-chipen: 10 % av kortets
     egen farge blandet inn i en nøytral skifer-reserve. */
  --plate: #262c35;
  --plate: color-mix(in srgb, var(--card-bg) 10%, #262c35);
  --plate-hover: #303742;
  --plate-hover: color-mix(in srgb, var(--card-bg) 10%, #303742);
  --plate-done: #222831;
  --plate-done: color-mix(in srgb, var(--card-bg) 10%, #222831);
  --plate-done-hover: #292f39;
  --plate-done-hover: color-mix(in srgb, var(--card-bg) 10%, #292f39);
  --chip-bg: #171c24;
  --chip-bg: color-mix(in srgb, var(--card-bg) 10%, #171c24);

  /* Kortflaten og korthodet: 13 % — et hakk mer enn resten (10 %) — for
     tydeligere adskillelse mellom nabokort. Platene og kategorifordypningen er
     innholdsflater, ikke identitetsflaten, og holder seg på den mer
     tilbakeholdne blandingen. Korthodet ligger fortsatt et tydelig trinn over
     flaten, kategorifordypningen (under) et trinn under den. */
  --card-face: #1e242d;
  --card-face: color-mix(in srgb, var(--card-bg) 13%, #1e242d);
  --card-head-face: #2c333c;
  --card-head-face: color-mix(in srgb, var(--card-bg) 13%, #2c333c);
  --cat-face: #171c24;
  --cat-face: color-mix(in srgb, var(--card-bg) 10%, #171c24);

  /* Aksentstripen ER `--card-accent` — samme verdi som avkryssingskanten, ikke
     en egen, lysere utgave. Pikselidentisk med lys drakts EGEN aksentformel
     (en mørkning av den LYSE palettfargen) er ikke trygt: mot de mørke platene
     ville den blitt nesten usynlig for enkelte fargetoner. `--card-accent`
     (allerede lysnet av paintCardColor for å holde 3:1 mot platen) er den
     nærmeste sikre tilnærmingen — samme verdi appen ellers bruker som
     «aksentfargen» til nettopp dette kortet i mørk drakt. Mot korthodet er den
     under 3:1 i verste hjørne, men det er en dekorativ stripe uten tekst på
     seg (samme presedens som --scrim over: paritet med intensjonen, ikke et
     nytt gulv). `--card-accent` SELV er urørt av dette —
     den bærer 3:1-kontrakten rundt avkryssingsboksen og skal ikke flyttes. */
  --card-stripe: var(--card-accent);
}

:root[data-theme="dark"] .card {
  /* Kortets egne skygger: kortet skal løftes fra board-bakgrunnen av tone og
     kontur, ikke av en tung boks-skygge. Kun tokenene endres her — `.card`,
     `.card:hover` og `.dnd-surface .card[data-dnd-dragging]` lenger ned i fila velger
     fortsatt hvilken som gjelder, så et løftet kort beholder draktens fulle
     `--shadow-lg`. Modaler og paneler er urørt: disse tokenene gjelder kun
     kort-subtreet. */
  --shadow-sm: 0 1px 4px rgba(0, 0, 0, 0.32);
  --shadow-md: 0 6px 16px rgba(0, 0, 0, 0.38);

  /* Selve flaten + stripen: en bakgrunnsgradient med HARDT stopp på 4 px
     (samme posisjon på begge fargestoppene, altså ingen overgangsfrynse).
     Kortets `overflow: hidden` + `border-radius` runder stripens hjørner. */
  background-color: var(--card-face);
  background-image: linear-gradient(90deg, var(--card-stripe) 0 4px, transparent 4px);
}
/* Konturen gjør kortkanten tydelig mot board-bakgrunnen uten en tung
   boks-skygge. `outline` (ikke `border`) tar ikke plass i layout-boksen —
   kortets geometri, og dermed DnD-målingene, er upåvirket.
   `:not(.active)` holder fingrene av navigasjonsmodalens aktive kort, som
   bruker nettopp `outline` til å vise hvor man står. */
:root[data-theme="dark"] .card:not(.active) {
  outline: 1px solid rgba(255, 255, 255, 0.09);
  outline-offset: -1px;
}
/* Hodet har sin egen flate og må derfor male stripen videre selv — ellers
   ville den startet under hodet. Innrykket holder tittelen klar av stripen. */
:root[data-theme="dark"] .card-head {
  padding-left: 14px;
  background-color: var(--card-head-face);
  background-image: linear-gradient(90deg, var(--card-stripe) 0 4px, transparent 4px);
}
/* Titlene er hvite med tekst-skygge + full kontur i lys drakt (se
   .card-title/.cat-title lenger ned) — på de nå tonalt varierte mørke
   kortflatene leser i stedet ekte blekk (--ink) bedre, med en tynnere kontur
   (0,5 px, samme begrunnelse som --item-text-stroke over) som robusthet mot
   fargepreget, ikke som kontur. */
:root[data-theme="dark"] .card-title,
:root[data-theme="dark"] .cat-title {
  color: var(--ink);
  text-shadow: var(--text-shadow);
  -webkit-text-stroke: 0.5px #000;
}
:root[data-theme="dark"] .collapse-count {
  color: var(--ink-soft);
  text-shadow: var(--text-shadow);
}
/* Listepunktene: platene er tokenstyrt over, så her trengs bare den svake
   kanten som skiller platen fra kortflaten. `:not([data-dnd-dragging])` fordi
   det løftede listepunktet eier sin egen `--shadow-lg` (se invariant 2 over) —
   dnd-kits krok, ikke en klasse.

   Avkryssingsboksens fyll følger med vilje IKKE hover-platen: kanten rundt
   boksen er `--card-accent`, og kontrakten er 3:1 mot fyllet den ligger på.
   Fulgte fyllet med opp til `--plate-hover`, ville kontrollen blitt
   utydeligere i samme øyeblikk man siktet på den. */
:root[data-theme="dark"] .item:not([data-dnd-dragging]) {
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.04);
}
/* Kategorifordypningen: fortsatt mørkere enn kortflaten, med innover-skyggen
   som gir «hylle» beholdt fra hvile-regelen. */
:root[data-theme="dark"] .cat-items {
  background: var(--cat-face);
  box-shadow: inset 0 2px 7px rgba(0, 0, 0, 0.3),
              inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}

/* IKONFARGENE, styrt av tokens i stedet for av SVG-ens egne attributter.
   Attributtselektorene treffer nøyaktig de tre verdiene ikonsettet faktisk
   bruker — en CSS-regel slår et presentasjonsattributt, så `stroke="#111"` i
   markupen blir stående som dokumentasjon av motivet mens fargen kommer
   herfra. I lys drakt er tokenene identiske med attributtene, så ingenting
   endrer seg; i mørk snur de.

   `fill="none"`/`stroke="none"` røres ikke (de er geometri, ikke farge), og
   `currentColor`-glyfene (haken, dør-ut, ✕) følger som før `color` på
   forelderen. */
[stroke="#111"] { stroke: var(--icon-ink); }
[fill="#111"] { fill: var(--icon-ink); }
[fill="#ffffff"] { fill: var(--icon-paper); }
[fill="#c0c4c9"] { fill: var(--icon-grey); }
/* UNNTAKET: de massive fargeknappene. Gradientene deres er de samme i begge
   drakter (kontraktsfarger — se kontrast-kontrakten over), så et ikon på dem
   skal bli stående SVART uansett drakt: det er nettopp derfor grønnfargen får
   være lys. Custom properties arver, så å pinne dem her dekker hele subtreet
   uten en eneste ekstra selektor. */
.btn-solid {
  --icon-ink: #111111;
  --icon-paper: #ffffff;
  --icon-grey: #c0c4c9;
  /* Og av samme grunn blekket: .btn-solid.btn-yellow setter `color: var(--ink)`
     fordi en gul flate ikke kan bære hvit tekst (se kontrast-kontrakten). Uten
     denne pinningen ville --ink lyst opp i mørk drakt og gjort nettopp det
     ulovlige. Gradienten er den samme i begge drakter, så det er blekket som
     skal stå stille. */
  --ink: #37343f;
}

* { box-sizing: border-box; }

/* hidden-attributtet skal alltid vinne over display-regler (f.eks. .trashcan
   sin inline-flex) — søppelkassene o.l. skjules med `hidden` i JS. */
[hidden] { display: none !important; }

/* SIKKERHETSNETT FOR TASTATURFOKUS. Alt som kan få fokus tegner den samme
   ringen — også kontroller ingen har skrevet en egen regel for. Uten denne
   arver de nettleserens innebygde ring, som verken vi eller
   tests/a11y-contrast.test.js har noe med å gjøre (Chrome maler den i en
   plattformavhengig farge, gullaktig på Android). Regelen står HØYT i fila med
   vilje: alle de spesifikke reglene lenger nede overstyrer den der geometrien
   krever en annen offset — eller ingen ring i det hele tatt, som på selve
   dialogflatene. */
:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }

/* Usynlig for øyet, men FULLT til stede i tilgjengelighetstreet. Brukes av
   opplesningsområdet (#a11y-live). Verken `display:none`, `visibility:hidden`
   eller `hidden` duger: alle tre tar elementet ut av treet, og da leser ingen
   skjermleser innholdet. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

html, body {
  margin: 0;
  padding: 0;
  min-height: 100%;
}

/* Toppmenyen er FAST og dekker de øverste pikslene av siden. Nettleseren vet
   ikke det: for den er alt fra y=0 synlig, så en rulling som «tar noe fram»
   kan legge det rett under panelet — fokus-rullingen når et navnefelt åpnes,
   og rullingen skjermtastaturet utløser når det krymper viewportet.
   `scroll-padding-top` sier hvor det egentlig synlige området begynner, og
   ligger på selve rulleboksen (siden). Det er hele grunnen til at den ikke
   kan stå som `scroll-margin` på feltet: kortene har `overflow: hidden`, og en
   scroll-margin inne i et slikt kort når aldri ut til sidens rulling.
   Verdien er board-ets egen klaring (--board-pad-top, se syncHeaderHeight). */
html { scroll-padding-top: var(--board-pad-top, 160px); }

body {
  font-family: var(--font);
  color: var(--ink);
  background: var(--bg);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
}

/* ---------------- Ikoner (SVG, se icons.js/index.html) ----------------
   Fargelagt ikonsett: strekene er SVARTE (stroke="#111", hardkodet i SVG-ene,
   ikke lenger currentColor) og flatene fylles med hvit + egne motivfarger der
   motivet tilsier det — kun et fåtall ikoner (globus, logo, kontoikon/kamera/
   hånd-opp) beholder appens kortfarger med vilje (fargekart i icons.js /
   docs/design-system.md). Størrelse arves fortsatt fra font-size på forelder.
   Unntak som beholder currentColor: knappe-glyfene (.btn-glyph, hvite på
   massiv fargeknapp) og avkryssings-haken (.item-check .icon), begge rene
   glyfer på massive fargeknapper. */
.icon {
  display: block;
  flex: 0 0 auto;
  width: 1em;
  height: 1em;
}

/* ÉN PIKSEL STREK, UANSETT HVOR STORT IKONET VISES.
   Ikonene tegnes i et 24×24-rutenett og vises i alt fra 15 px (en chip i
   hendelseslista) til 60 px (tom-tilstandene) og 52 px (merket på
   innloggingsskjermen). Uten dette skalerte streken med tegningen: samme
   `stroke-width` ble en hårstrek i det minste ikonet og nesten 3 px i det
   største, så settet så ut som to ulike sett.

   `vector-effect: non-scaling-stroke` tar stroke-width UT av 24-rutenettet og
   måler den i skjermpiksler i stedet. Da betyr `stroke-width="1"` i markup
   nøyaktig 1 px i alle størrelser, og det er derfor hvert eneste ikon (og
   logoen) står med `stroke-width="1"` — ingen størrelsesavhengige tall, og
   ingen kompensasjon for <g transform="scale(…)">, som streken ikke lenger
   ser.

   Egenskapen ARVES IKKE, så den må stå på formene selv, ikke på <svg> eller
   en <g> — derav etterkommer-selektoren. `favicon.svg` bærer den samme regelen
   i sin egen <style>, fordi den også lastes frittstående (<link rel="icon">)
   der dette stilarket ikke gjelder. Autoritativt: docs/design-system.md →
   «Ikoner». */
.icon *,
.brand-logo * {
  vector-effect: non-scaling-stroke;
}

/* Pinner --icon-paper (og --icon-grey, ubrukt av kalenderen selv, men med for
   å matche .btn-solid/.event-icon-mønsteret) til den LYSE verdien i BEGGE
   drakter — samme grep som .btn-solid/.event-icon (docs/mork-drakt.md →
   «Ikonene snur uten at en eneste SVG endres»), men her fordi MOTIVET selv er
   fargekontrakten: et ikon som forestiller papir (kalenderen) skal ikke bli
   en mørk klatt i mørk drakt — papir er hvitt uansett hvor mørkt rommet er.
   --icon-ink pinnes IKKE her: i lys drakt er den allerede #111111 (samme
   sluttresultat), men i mørk drakt overstyres den rett under til hvit, slik
   at streken smelter sammen med det pinnede hvite papiret i stedet for å stå
   som en mørk kant på det — kanten på selve platen mot den mørke bakgrunnen
   er kontrasten som definerer formen der, ikke en indre strek. Custom
   properties arver, så pinningen dekker hele ikonet fra denne ene klassen på
   <svg>-elementet selv, ingen ekstra selektor per barn. */
.icon-pin-light {
  --icon-paper: #ffffff;
  --icon-grey: #c0c4c9;
}
:root[data-theme="dark"] .icon-pin-light {
  --icon-ink: #ffffff;
}

/* ---------------- Berøringsflate på ikonknappene ----------------
   Ikonknappene TEGNES små (34–36 px) fordi listevisningen skal være kompakt —
   men en finger trenger 44 px (WCAG 2.5.5, og både Apple og Material sier det
   samme). De to kravene er ikke i konflikt: knappen ser ut nøyaktig som før,
   mens et gjennomsiktig `::after` strekker det KLIKKBARE feltet ut til 44×44.

   Utvidelsen er nøyaktig halve luften til naboen (4 px av en 8 px gap), så to
   nabo-mål MØTES uten å overlappe. Det er hele poenget med å regne på det: et
   overlapp ville gjort at et trykk i sonen mellom «innstillinger» og «slett»
   traff den ene vilkårlig — og av de to er den ene destruktiv. Derfor er
   kontrollradene (.item, .card-head, .cat-head) satt til `gap: 8px`: det er
   tallet som gjør 44 mulig uten overlapp.

   Legger du til en ny ikonknapp: ta den med i lista under, og sørg for at den
   har minst 8 px luft til naboen. tests/a11y-runtime.test.js måler den
   FAKTISKE flaten på alt som er synlig, så en glemt knapp feiler der.

   Objektmenyknappen (`.obj-menu-btn`) bærer klassene `.item-cog`/`.card-cog`/
   `.cat-cog` etter hvilken flate den står på, og er dermed allerede dekket.

   Unntak, med vilje:
   • `.pass-toggle` ligger INNI tekstfeltet. En utvidet flate der ville stjålet
     klikk fra selve feltet, som er et større og viktigere mål.
   • `.meta-chip` og `.item-text` er stablet med 3 px mellom seg inne i raden;
     de kan ikke vokse uten å overlappe hverandre. Begge er over AA-gulvet på
     24 px, og er tekstmål, ikke ikonknapper.
   • `.share-badge` er en DEKORATIV <span aria-hidden> på alle nivåer — den tar
     ikke imot klikk, og en treffflate på den ville bare lagt et usynlig teppe
     over raden bak. */
/* NOTAT-EDITORENS KNAPPER hører til den samme lista. De tegnes små fordi
   verktøylinjen skal romme seksten verktøy uten å rulle (og symbolpanelet
   femti tegn), men en finger trenger fortsatt 44 px. Luften mellom dem er
   nøyaktig det utvidelsen krever: `.note-tools` har `gap: 6px` (38 + 6 = 44)
   og `.note-symbol-panel` `gap: 4px` (40 + 4 = 44), så nabo-flatene MØTES uten
   å dekke hverandre. Tilbakeknappen krymper til bare pilen på telefon og er
   den viktigste knappen i bildet — den kan ikke være 35 px. */
.item-check, .item-cog, .card-cog,
.cat-cog, .done-restore, .done-delete, .cat-add-btn,
.note-tool, .note-symbol, .note-back,
.icon-btn:not(.pass-toggle) {
  position: relative;
}
.item-check::after, .item-cog::after,
.card-cog::after, .cat-cog::after,
.done-restore::after, .done-delete::after, .cat-add-btn::after,
.note-tool::after, .note-symbol::after, .note-back::after,
.icon-btn:not(.pass-toggle)::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--touch);
  height: var(--touch);
  transform: translate(-50%, -50%);
  /* Usynlig, men tar imot pekeren. Ligger UNDER knappens eget innhold i
     malingsrekkefølgen, så ikonet aldri dekkes. */
  z-index: 0;
}

/* ---------------- Paneler (modaler) ----------------
   Felles anatomi: en overskriftslinje (.panel-head med .panel-title) og en
   knapperad (.panel-actions) der alle kontroller deler høyde/radius. */
.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 24px;
}
.panel-title {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.panel-title .icon { font-size: var(--fs-sm); }
/* Overskrifter med objektnavn («Alle mapper i 🌐 [navn]»): etiketten brytes
   ikke; det er navnet som kappes med ellipsis når plassen er trang. */
.panel-title { min-width: 0; }
.panel-title-text { flex: 0 0 auto; white-space: nowrap; }
.panel-title-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.panel-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

/* ---------------- Toppmenyen (breadcrumb + listefunksjoner) ----------------
   Ett fast panel øverst (alle skjermstørrelser): breadcrumben (område ›
   mappe, bare navnene) og listefunksjonene («＋ Liste», søppelkasse, filter).
   De står på SAMME linje der bredden rekker — listefunksjonene rett til høyre
   for nav-knappen, ikke skjøvet ut til kanten. Panelet blir da én
   kontrollhøyde høyt, og det er høyde som er mangelvaren i landskap. Under
   560 px (telefon i portrett) legges listefunksjonene på raden under, slik at
   breadcrumb-navnene ikke kappes bort til ingenting. Toppkontrollene (kalender,
   søk, drakt, konto) er ÉN fast gruppe i viewportets hjørne
   (`.corner-controls`) og overlapper panelet visuelt øverst til høyre — plassen
   til dem holdes av en margin PÅ ENDEN av hver panelrad (`--corner-btns-w`,
   målt i JS), slik at panelets egen padding (og dermed fluktingen med
   kontoknappen) er uendret. */
.topbar {
  position: fixed;          /* uavhengig av scrolling (robust mot iOS-backdrop-bug) */
  top: 0;
  left: 0;
  right: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: var(--topbar-gap);
  /* Flaten når helt ut i kantene, men INNHOLDET holdes innenfor den sikre
     sonen: statusfeltet øverst og et eventuelt hakk i sidene legges på
     paddingen. Panelet blir dermed høyere, og `syncTopChrome()` måler den
     faktiske høyden — board-ets klaring følger med av seg selv.
     `--corner-btns-overflow` (også målt) er høyden hjørnegruppen har utover
     PANELETS EGNE RADER: hver panelrad holder av den horisontale klaringen
     (--corner-btns-w), så én gruppe-rad kan ligge ved siden av hver av dem.
     Har gruppen flere rader enn det, skyves HELE panelet ned like mye. Den er
     0 i begge dagens oppsett — én gruppe-rad mot én panelrad på bred skjerm,
     to mot to på smal. */
  padding: calc(var(--topbar-pad-y) + var(--safe-top) + var(--corner-btns-overflow, 0px))
           calc(var(--toolbar-pad) + var(--safe-right))
           var(--topbar-pad-y) calc(var(--toolbar-pad) + var(--safe-left));
  background: var(--glass-bg);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
  /* Panelet er en KOLONNE: hovedfanene (Lister | Notater) på den første raden,
     den aktive fanens egne kontroller på den neste (docs/notater-plan.md).
     Hver rad holder selv av plassen hjørnegruppen tar (--corner-btns-w). */
  flex-direction: column;
  align-items: stretch;
}

/* Én rad i panelet — den aktive fanens breadcrumb + knapper. Samme luft som
   mellom radene og mellom hjørneknappene (`--topbar-gap`): headeren har ÉN
   avstand, ikke én per retning. */
.topbar-row {
  display: flex;
  align-items: center;
  gap: var(--topbar-gap);
}

/* Breadcrumb: ÉN knapp med de to navnenivåene, skilt med › — bare navn, ingen
   ikoner (heller ikke delt-ikonet). Den KRYMPER (navnene kappes med ellipsis)
   når linjen blir trang, men VOKSER ikke: da ville den skjøvet
   listefunksjonene bort fra nav-knappen og ut til kanten. */
.breadcrumb {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  flex: 0 1 auto;
}
.crumb-btn {
  appearance: none;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  height: var(--control-h);
  padding: 0 13px;
  border-radius: var(--control-radius);
  background: var(--control-bg);
  color: var(--ink);
  font-family: inherit;
  font-weight: 600;
  font-size: var(--fs-lg);
  box-shadow: var(--shadow-sm);
  transition: background 0.18s, box-shadow 0.18s, transform 0.12s;
}
.crumb-btn:hover { background: var(--control-bg-hover); box-shadow: var(--shadow-md); }
.crumb-btn:active { transform: translateY(1px); }
.crumb-btn:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }
.crumb-btn .icon { font-size: var(--fs-base); }
.crumb-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.crumb-sep {
  flex: 0 0 auto;
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--ink-soft);
}
/* Mål når man drar en liste opp på 📁-breadcrumben (flytt til annen mappe):
   knappen lyser opp; slipp åpner flytte-velgeren. */
.crumb-btn.drop-target {
  background: var(--primary-soft);
  outline: 2.5px dashed var(--primary);
  outline-offset: 2px;
  box-shadow: 0 4px 12px rgba(82, 114, 82, 0.45);
}

/* ---------------- Fargede knapper (.btn-solid) ----------------
   ÉN felles stil for alle fargede knapper: gradient-flate (loddrett, lyseste
   ende øverst — se lysretningen ved --grad-*), hvit skrift m/ tekst-skygge, og
   samme hover-feedback overalt — flaten lysner litt og skyggen løftes
   (tydelig, men ikke dramatisk fargeendring). */
.btn-solid {
  color: #fff;
  text-shadow: var(--text-shadow);
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.18s, transform 0.12s, filter 0.18s;
}
.btn-solid:hover { box-shadow: var(--shadow-md); filter: brightness(1.09) saturate(1.05); }
.btn-solid:active { transform: translateY(1px); filter: brightness(0.98); }
.btn-solid:disabled { opacity: 0.45; cursor: not-allowed; box-shadow: none; filter: none; }
/* Grønn = flate under SVARTE IKONER (＋-knappene). Den skal ALDRI bære tekst:
   en grønn mørk nok til hvit tekst gjør det svarte ikonet utydelig, og det er
   ikonet som er hele knappen her. Runtime-testen sjekker at ingen synlig
   .btn-green har synlig tekst. */
.btn-green { background: var(--grad-green); }
/* Blågrønn = flate under HVIT TEKST (Lagre, Inviter, Godta, Neste, Logg inn …).
   Samme rolle .btn-green hadde for tekstknapper før — se kontrastkontrakten. */
.btn-accent { background: var(--grad-accent); }
.btn-red { background: var(--grad-red); }
/* Gult er unntaket fra «hvit skrift på .btn-solid»: en gul flate som gir 4.5:1
   mot hvit tekst er ikke gul lenger, den er oliven. Knappen beholder derfor
   gulfargen og bytter TEKSTEN til nesten-svart (6.75:1 / 5.43:1 mot de to
   gradient-endene). Tekst-skyggen må vekk med det samme — den er laget for å
   løfte hvit skrift fra en lys flate og ville bare gjøre den mørke uskarp.
   Ikonene på gule knapper er allerede svarte (#111), så de matcher nå teksten. */
.btn-yellow { background: var(--grad-yellow); }
.btn-solid.btn-yellow { color: var(--ink); text-shadow: none; }

/* ---------------- «＋»-knapper (felles: mappe/liste/område/element) ----------------
   Størrelse/form for knappene i knapperadene; fargen på FLATEN kommer fra
   .btn-solid .btn-green. .icon-only = kvadratisk, med kun ICONS.plus (se
   index.html) — ingen tekst-glyf lenger, så streken matcher resten av
   ikonsettet (1 px, runde ender, svart #111 — også på de fargede knappene). */
.btn-add {
  flex: 0 0 auto;
  appearance: none;
  border: none;
  cursor: pointer;
  height: var(--control-h);
  padding: 0 15px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  border-radius: var(--control-radius);
  font-family: inherit;
  font-weight: 600;
  font-size: var(--fs-base);
  line-height: 1;
  white-space: nowrap;
}
.btn-add.icon-only { width: var(--control-h); padding: 0; font-size: 23px; }
.btn-add .icon { font-size: var(--fs-base); }
/* icon-only-knappene (element ＋ / kategori) er kvadratiske og bærer store,
   tydelige ikoner: begge settes til samme størrelse (34px) så ＋-en er like
   stor som kategori-ikonet — kategori-ikonet trenger størrelsen for å lese
   detaljene (klammer/prikker/linjer), og ＋-en matcher det visuelt. */
.btn-add.icon-only .icon { font-size: 34px; }


/* ---------------- Toppkontrollene (hjørnegruppen) ----------------
   ÉN fast gruppe i øvre høyre hjørne av VIEWPORTET, utenfor toppmenyens flyt —
   z-index over det faste panelet (30) men under modaler (200). Knappene ligger
   i DOM-rekkefølge og plasseres av flex; ingen av dem kjenner naboens bredde,
   så en ny knapp (varsler) legges til ved å sette den FØRST i
   gruppen — ingen `right:`-kjede å regne om.

   Er det ikke plass til alle på én rad, brytes gruppen til flere rader mot
   høyre kant (`flex-wrap`); knappene krymper aldri. Plassen gruppen tar av
   toppmenyens linjer MÅLES i JS (`--corner-btns-w` = gruppens BREDESTE rad,
   syncTopChrome i app.js), og board-ets klaring regnes fra den laveste av
   toppmenyen og gruppen. */
.corner-controls {
  position: fixed;
  /* Samme sikre sone som toppmenyen gruppen flukter med — den ligger utenfor
     panelets flyt og må derfor legge på inset-ene selv. PLUSS høyden på
     hovedbryteren (`--main-tabs-h`, målt i syncTopChrome): den raden er
     panelets øverste og skal ligge alene, sentrert i hele bredden, så gruppen
     begynner først under den. */
  top: calc(var(--topbar-pad-y) + var(--safe-top) + var(--main-tabs-h, 0px));
  right: calc(var(--toolbar-pad) + var(--safe-right));
  z-index: 35;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--topbar-gap);
  /* Bredden gruppen har å bryte innenfor: viewportet minus den sikre sonen og
     panelets sidepolstring i begge ender. */
  max-width: calc(100vw - var(--safe-left) - var(--safe-right) - var(--toolbar-pad) * 2);
}

/* Telefon i portrett (samme grense som resten av appen): gruppen deles i TO
   rader — drakt og konto øverst, de tre innholdsknappene (varsler, kalender,
   søk) under. Gruppen er dermed to rader uansett om den har fire eller fem
   knapper, og board-ets klaring står stille når en ny kommer til. Panelet er
   også to rader så smalt, så den andre gruppe-raden legger seg ved siden av
   listefunksjonene i stedet for å skyve panelet nedover — se
   `--corner-btns-overflow` ved `.topbar`.

   DELINGEN GJØRES AV `wrap-reverse`, ikke av `order`. DOM-rekkefølgen er
   fortsatt den brede (varsler → kalender → søk → drakt → konto): flex fyller
   den første linjen med de tre første, den andre med drakt og konto — og
   `wrap-reverse` legger den SISTE linjen øverst. Da havner drakt og konto i
   hjørnet, innholdsknappene på raden under, og regelen «en ny knapp legges
   FØRST i gruppen» holder fortsatt uten en eneste ny utregning. Et usynlig
   bruddelement ville kostet en ekstra flex-linje — altså høyde. */
@media (max-width: 560px) {
  .corner-controls {
    max-width: calc(var(--control-h) * 3 + var(--topbar-gap) * 2);
    flex-wrap: wrap-reverse;
  }
}

/* Felles flate for hjørneknappene (varsler, kalender, søk, drakt, konto): flate-mønsteret —
   halvgjennomsiktig hvit → hvit ved hover, samme høyde/radius som resten av
   kontrollene. Innloggingsskjermens draktknapp bruker den samme klassen inline
   i språkraden. */
.corner-btn {
  flex: 0 0 auto;
  appearance: none;
  border: none;
  cursor: pointer;
  position: relative;      /* .menu-badge forankres i knappen */
  width: var(--control-h);
  height: var(--control-h);
  display: grid;
  place-items: center;
  border-radius: var(--control-radius);
  background: var(--control-bg);
  color: var(--ink-soft);
  box-shadow: var(--shadow-sm);
  transition: background 0.18s, box-shadow 0.18s, color 0.18s, transform 0.12s;
}
.corner-btn:hover { background: var(--control-bg-hover); color: var(--ink); box-shadow: var(--shadow-md); }
.corner-btn:active { transform: translateY(1px); }
.corner-btn > .icon { font-size: 23px; }

/* ---------------- Main ---------------- */
.app-main {
  /* Topp settes i JS (--board-pad-top, se syncHeaderHeight): eksakt toppmeny-
     høyde + --board-gap, så avstanden ned til første kort matcher gapet
     overalt ellers. Bunn er --safe-bottom — siste korts EGEN bunn-margin (også
     --board-gap, se .card) ER bunn-luften, og en egen bunn-padding ville lagt
     gap på gap; det eneste som legges til her er den delen av viewportet
     gestelinjen dekker (0 i en nettleser). Sidene får det samme for et hakk i
     landskap: --board-gap er fortsatt luften, inset-en er strimmelen som ikke
     kan brukes. */
  padding: var(--board-pad-top, 160px) calc(var(--board-gap) + var(--safe-right))
           calc(var(--safe-bottom) + var(--dock-reserve, 0px))
           calc(var(--board-gap) + var(--safe-left));
}
/* Er slippfoten synlig, holder board-et av høyden dens nederst — ellers ville
   den lagt seg over det siste kortet. Polstringen ligger på BUNNEN, så den
   flytter ingenting som allerede står: et drag som folder ut en tom kasse gjør
   siden litt lengre, ikke innholdet forskjøvet. */
/* `:not(.note-editing)`: notat-editoren er et fullskjermsbilde OVER foten, så
   der er den ikke synlig og skal ikke holdes klar av — verken av board-et
   under eller av synk-pillen, som ellers ville svevd midt oppi notatteksten. */
body:not(.note-editing):has(.drop-dock:not([hidden]) .item-trash:not([hidden])) { --dock-reserve: var(--dock-h); }

/* Listefunksjonene i toppmenyen (er også .panel-actions): rett til høyre for
   nav-knappen, og krymper aldri — det er breadcrumben som gir fra seg plass.
   Marginen er plassen drakt- OG kontoknappen trenger i hjørnet: den ligger i
   ENDEN av linjen (ikke mellom knappene), og teller med når flex regner ut
   hvor mye breadcrumben må krympe. Panelets padding er dermed uendret, og
   kontoknappen flukter fortsatt med kanten (se tests/safe-area.test.js). */
.toolbar {
  flex: 0 0 auto;
  /* Headerens ene luft-verdi, ikke `.panel-actions`' egen: knapperaden her er
     en header-kontrollgruppe og skal ha den samme avstanden som resten. */
  gap: var(--topbar-gap);
  margin-right: var(--corner-btns-w);
}

/* ---------------- Generelle knapper (modaler o.l.) ----------------
   .btn = base (form/typografi), .btn-ghost = hvit, .btn-small = mindre
   variant. Fargen (grønn/rød/gul) kommer alltid fra .btn-solid + fargeklasse. */
.btn {
  appearance: none;
  cursor: pointer;
  font-family: inherit;
  font-weight: 600;
  font-size: var(--fs-base);
  line-height: 1;
  border: none;
  border-radius: var(--control-radius);
  padding: 15px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  white-space: nowrap;
  transition: transform 0.12s, box-shadow 0.18s, background 0.18s, filter 0.18s;
}

.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; box-shadow: none; }
.btn:disabled:hover { box-shadow: none; }

.btn-ghost {
  background: var(--surface);
  color: var(--ink-soft);
  box-shadow: var(--shadow-sm);
}
.btn-ghost:hover { color: var(--ink); box-shadow: var(--shadow-md); }

.btn-small {
  padding: 9px;
  font-size: var(--fs-sm);
  border-radius: 11px;
}

/* ---------------- Søppelkasse-knapper (felles for alle fire nivåer) ----------------
   Hvit, avrundet beholder (halvgjennomsiktig → hvit ved hover) med søppelkasse-
   ikon + antall i grå sirkel. Vises kun når søppelkassen har innhold. Kort trykk
   åpner modalen; klikk-og-hold utvider selve knappen til et sveipefelt
   (se .swipe-field). */
.trashcan {
  position: relative;
  flex: 0 0 auto;
  appearance: none;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: var(--control-h);
  padding: 0 15px;
  border-radius: var(--control-radius);
  background: var(--control-bg);
  color: var(--ink);
  font-family: inherit;
  box-shadow: var(--shadow-sm);
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  touch-action: none;          /* hold/sveip uten at siden scroller */
  transition: background 0.18s, box-shadow 0.18s;
}
.trashcan:hover { background: var(--control-bg-hover); box-shadow: var(--shadow-md); }

.trashcan-icon { font-size: var(--fs-base); line-height: 1; display: inline-flex; }
.trashcan-count {
  position: relative;
  display: inline-grid;
  place-items: center;
  min-width: 26px;
  height: 26px;
  padding: 0 7px;
  border-radius: 999px;
  background: var(--count-bg);
  color: var(--ink-soft);
  font-size: 16px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* Sveipefelt: fixed felt som «vokser ut av» søppelkasse-knappen ved
   klikk-og-hold — JS starter det med knappens eksakte posisjon/størrelse/
   radius (og skjuler knappen imens), så det ser ut som knappen selv utvider
   seg. JS setter posisjon/bredde/padding inline og roterer ikonet (0→180°)
   ut fra sveipet; --p (0→1) driver den visuelle fyllingen. */
.swipe-field {
  position: fixed;
  z-index: 250;
  display: flex;
  align-items: center;
  gap: 10px;
  border-radius: var(--control-radius);
  background: var(--surface);
  box-shadow: var(--shadow-md);
  overflow: hidden;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;                 /* pekeren fanges av knappen (setPointerCapture) */
  -webkit-user-select: none;
  user-select: none;
  transition: opacity 0.14s ease, width 0.18s cubic-bezier(.2, .75, .3, 1), box-shadow 0.18s;
}
.swipe-field.open { opacity: 1; box-shadow: var(--shadow-lg); }
/* Grønn fylling som følger sveipet (venstre → høyre). */
.swipe-field::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--primary-soft), var(--primary-soft-hover));
  transform: scaleX(var(--p, 0));
  transform-origin: left center;
  pointer-events: none;
}
/* Ikonet har en ROMSLIG, kvadratisk viewBox sentrert på selve kassen
   (-9.5 -9.5 43 43, se icons.js): kassen står dermed alltid i sentrum av
   boksen, og boksen har plass til lokket i ALLE kombinasjoner av rotasjon
   (0–180°) og lokk-sving — ingenting klippes noensinne. Boksen er større enn
   den synlige kassen (kassen ≈ 40 % av boksen); font-size er skalert opp
   tilsvarende slik at kassen visuelt matcher knappens ikon (19px). Holdes i
   takt med SWIPE_ICON_BOX i app.js. */
.swipe-icon {
  position: relative;
  font-size: 34px;
  line-height: 1;
  flex: 0 0 auto;
  transition: transform 0.1s ease;      /* jevn rotasjon; kollaps roterer tilbake */
  transform-origin: 50% 50%;
}
/* Lokket (topp-strek + hank) svinger opp rundt venstre hengsel (4.5,7.5 i
   viewBox-en -9.5 -9.5 43 43 → 32.56 %/39.53 %) gjennom hele sveipet og går
   ALDRI tilbake til lukket — kassekropp + ribbene er urørt og roterer kun med
   hele ikonet (via .swipe-icon sin transform). Drevet av setProgress(p) i
   app.js sin sveip-for-å-tømme-motor. */
.swipe-icon-lid {
  transform-box: view-box;
  transform-origin: 32.56% 39.53%;
  transition: transform 0.12s ease;
}
.swipe-icon.shake { animation: swipe-shake 0.5s ease; }
@keyframes swipe-shake {
  0%, 100% { transform: rotate(180deg) translateX(0); }
  20% { transform: rotate(180deg) translateX(-4px); }
  40% { transform: rotate(180deg) translateX(4px); }
  60% { transform: rotate(180deg) translateX(-3px); }
  80% { transform: rotate(180deg) translateX(3px); }
}
.swipe-label {
  position: relative;
  flex: 0 0 auto;
  font-weight: 700;
  font-size: var(--fs-md);
  color: var(--ink-soft);
}
/* Pil som fyller resten av feltet: en voksende horisontal strek (::before) +
   et fast pilhode (::after, rotert hjørne). Streken tilpasser seg feltbredden
   via flex; symmetrisk padding (satt i JS) gir lik luft til høyre. */
.swipe-arrow {
  position: relative;
  flex: 1 1 auto;
  min-width: 24px;
  display: flex;
  align-items: center;
  /* Pila er tegnet med CSS-kanter, altså en STREK på sveipefeltets flate —
     --primary-ink og ikke --primary-dark, så den snur med drakten som annet
     blekk på en panelflate. */
  color: var(--primary-ink);
}
.swipe-arrow::before {
  content: '';
  flex: 1 1 auto;
  height: var(--icon-stroke);
  background: currentColor;
  border-radius: 2px;
}
.swipe-arrow::after {
  content: '';
  flex: 0 0 auto;
  width: 11px;
  height: 11px;
  border-top: var(--icon-stroke) solid currentColor;
  border-right: var(--icon-stroke) solid currentColor;
  border-top-right-radius: 2px;
  transform: rotate(45deg);
  margin-left: -13.5px;   /* pilspissen (etter 45°-rotasjon) stikker ut halve
    diagonalen (5.5 + 11/√2 ≈ 13.3px) forbi boksens venstrekant — dette
    trekker streken helt frem til selve tuppen i stedet for å stoppe der
    firkanten begynner */
}

/* Element-søppelkassen: midtstilt nederst i listekortet (samme knapp som de andre). */
.item-trash {
  display: flex;
  justify-content: center;
  padding: 0 10px;
}

/* ---------------- Slippfoten (søppelkasse + arkiv) ----------------
   Hovedsidens og notatfanens kasser står i en FAST fot nederst i viewportet,
   ikke i topplinjas knapperad. En kasse som deler rad med ＋-knappen er ~48 px
   bred og ligger inntil noe annet man kan treffe; her har den hele bredden for
   seg selv, langt fra alt annet. Det er den samme løsningen som område-kassen
   i nav-modalens fot (`.nav-foot`), og de to deler derfor reglene under.

   Foten er BORTE når den er tom: kassene er skjult når de ikke har innhold, og
   et drag folder dem ut (`data-drag-revealed`). Uten `:has()`-regelen ville en
   tom fot ligget som en stripe over board-et hele tiden. */
.drop-dock {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  /* Over board-et og de faste toppkontrollene (35), under modaler (200) og
     toaster (300) — foten er en del av flaten, ikke et lag over den. */
  z-index: 40;
  display: flex;
  align-items: flex-end;
  gap: var(--dock-gap);
  padding: var(--dock-pad) calc(var(--dock-pad) + var(--safe-right))
           calc(var(--dock-pad) + var(--safe-bottom)) calc(var(--dock-pad) + var(--safe-left));
  /* Innholdet som ruller forbi under foten skal ikke lese gjennom kassene.
     Toning, ikke en massiv stripe: foten er et mål, ikke et panel. */
  background: linear-gradient(to top, var(--bg) 55%, transparent);
  pointer-events: none;                /* selve stripa fanger ingen klikk … */
}
.drop-dock > * { pointer-events: auto; }   /* … men kassene i den gjør det */
/* Kassene i en fot (både `.drop-dock` og modalenes `.nav-foot`) deler bredden
   likt: er det to av dem — arkivet og søppelkassen — tar de en halvdel hver,
   med luft rundt og mellom. Er bare den ene synlig, får den hele bredden. */
.drop-dock .item-trash { flex: 1 1 0; padding: 0; }
/* En tom fot skal ikke ligge som en stripe over board-et. */
.drop-dock:not(:has(.item-trash:not([hidden]))) { display: none; }

/* ---------------- Board (kolonner) ----------------
   Kolonnene er EKTE containere (`.board-col`), ikke CSS multi-column. Grunnen er
   fyllrekkefølgen: multi-column balanserer (n lister → n kolonner med én hver),
   mens vi vil fylle kolonne 1 helt før kolonne 2 oppstår. Fordelingen gjøres i JS
   (`relayoutBoard`), som også gir DnD stabile kolonner: en placeholder lagt i én
   kolonne kan ikke lenger dytte kort over i en annen og dermed endre svaret på
   «hvilken liste er objektet i?» midt i et drag (flimringen). Se
   `docs/board-layout.md` og `docs/drag-and-drop.md`. */
.board {
  display: flex;
  align-items: flex-start;
  gap: var(--board-gap); /* column-gap leses av JS som den oppløste --board-gap */
  /* CSS-sidens svar på «er board-et i énkolonne-modus?». Settes til 1 kun i
     mobil-media-regelen under. Kolonnene fordeles av `relayoutBoard` i JS, og
     `tests/dnd-layout-modes.test.js` leser dette flagget for å vise at de to
     er enige om modus. */
  --board-single-column: 0;
  /* Bunn-luft etter siste kort: satt i JS (fixBoardBottomGap), IKKE en fast
     verdi her — se den funksjonen. */
  padding-bottom: 0;
}
/* Én kolonne: kortene stables med sin egen margin-bottom (--board-gap), også
   etter det siste — det ER bunn-luften under board-et. `flex: 1 1 0` gir alle
   kolonnene lik bredde uansett innhold (også de tomme), så et kort har samme
   bredde — og dermed samme høyde — uansett hvilken kolonne det havner i. Det er
   forutsetningen for at JS kan måle høydene ÉN gang og så fordele. */
.board-col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.board.empty {
  min-height: 40vh;
  display: grid;
  place-items: center;
}

.empty-state {
  text-align: center;
  color: rgba(255, 255, 255, 0.92);
  max-width: 440px;
}
.empty-state .big { font-size: 60px; margin-bottom: 6px; }
.empty-state .big .icon { margin: 0 auto; }
.empty-state p { margin: 6px 0; font-weight: 500; font-size: var(--fs-base); }
/* Inline «knapp-hint» i tom-tilstanden: viser ＋ + nivå-ikonet (som knappen),
   siden knappene ikke lenger har tekst-etikett («＋ Mappe»/«＋ Liste»). */
.hint-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 8px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.16);
  font-weight: 700;
  vertical-align: middle;
}
.hint-chip .icon { font-size: 1em; }

/* ---------------- Card ---------------- */
.card {
  /* Reserve inntil app.js setter palettfargen inline (colorForIndex). */
  --card-bg: var(--surface);
  --card-head: var(--surface-2);
  --card-accent: var(--line);

  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  page-break-inside: avoid;
  display: flex;
  flex-direction: column;
  width: 100%;
  margin: 0 0 var(--board-gap);
  border-radius: var(--radius);
  background: var(--card-bg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition: box-shadow 0.18s, transform 0.12s;
}

.card:hover { box-shadow: var(--shadow-md); }

.card-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px;
  background: var(--card-head);
  cursor: pointer;             /* klikk = kollaps/utvid (pekende hånd som område/mappe) */
}

/* Alt under headeren: kollapser som en rullgardin (samme mønster som .cat-items).
   Luften som lå på .card (10px gap + padding-bottom) bor nå her, så et kollapset
   kort blir nøyaktig header-høyt — kortets overflow:hidden + border-radius runder
   da alle fire hjørnene, også nederst på headeren. Ingen fast overflow: den settes
   kun inline mens kollapsen animerer (ellers ville et løftet element bli klippet). */
.card-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 10px 0;
}

/* Tittel + meta-rad stables i en kolonne som tar resten av bredden. */
.card-title-wrap {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

/* Tittel + kollaps-teller på samme linje: tittelen tar sin egen bredde (klikk-
   flaten følger teksten), telleren «(N)» sitter rett til høyre. Telleren vises
   kun når lista/kategorien er kollapset (hidden fjernes i JS).
   `baseline` (ikke `center`): telleren har mindre skrift enn tittelen, og skal
   stå på SAMME skriftlinje — derfor må verken tittelen eller telleren sette
   `align-self` her (det ville koblet ut baseline-justeringen og lagt dem
   topp-justert, slik at «(N)» leste som hevet skrift). */
.title-line {
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
}
.collapse-count {
  flex: 0 0 auto;
  color: #fff;
  text-shadow: var(--text-shadow);
  font-weight: 600;
  font-size: var(--fs-base);
  opacity: 0.85;
}

.card-title {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 600;
  line-height: 1.2;
  color: #fff;                 /* hvit skrift m/ skygge for lesbarhet på kortfargen */
  text-shadow: var(--text-shadow);
  /* Tynn svart tekst-border for lesbarhet på de lyseste kortfargene (CSS har
     ingen egen border-egenskap for tekst). `paint-order` er påkrevd: uten den
     sentreres streken på glyfkanten og spiser innover, så bokstavene blir
     tynnere og små navn mister klarhet. Med `stroke fill` males fyllet oppå
     streken, slik at bare den ytre halvdelen synes og glyfen beholder full
     tykkelse. Faller tilbake til sentrert strek i eldre nettlesere. */
  -webkit-text-stroke: 1px #000;
  paint-order: stroke fill;
  /* IKKE tekst-cursor: et klikk på tittelen kollapser kortet (som resten av
     hodet), det redigerer ikke navnet — se «Navnet omdøpes IKKE lenger ved
     klikk» i buildUniverse()/buildCard(). `inherit` henter derfor pekehånden
     fra `.card-head` i stedet, så tittelen ikke signaliserer en handling den
     ikke har. */
  cursor: inherit;
  padding: 4px;
  border-radius: 8px;
  word-break: break-word;
}
/* Tittel-hover (redigerbarhets-signal): bakgrunnen bak tittelen mørkner når
   man hoverer den, så det er tydelig at et klikk starter navneredigering.
   KUN kategori og listepunkt — de er de eneste der klikk på navnet faktisk
   redigerer det. `.card-title` (område/liste) er tatt ut: der kollapser
   klikket kortet i stedet, se over. */
.cat-title:hover,
.item-text:hover { background: rgba(0, 0, 0, 0.12); }

/* ---------------- Items ---------------- */
.items-container {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0 10px;
  min-height: 14px;
}

.item {
  display: flex;
  align-items: center;
  /* 8, ikke 6: to nabo-berøringsflater strekker seg 4 px hver — se
     «Berøringsflate på ikonknappene». */
  gap: 8px;
  padding: 6px;
  border-radius: 10px;
  background: var(--plate);
  transition: background 0.15s, box-shadow 0.15s;
}
.item:hover { background: var(--plate-hover); }

/* Avkryssingsboks: rund-firkantet boks; grønt hake-fyll når gjort.
   Haken (SVG) ligger alltid der, men er usynlig til elementet er gjort. */
/* Avkryssingsboksen: KNAPPEN er 36×36 (og berøringsflaten 44, som de andre),
   mens den synlige boksen er de samme 26 px som før — den er flyttet til
   `::before`. Uten det skillet måtte enten boksen blitt like stor som knappen
   (en 36 px rute ved siden av 19 px tekst tar over hele raden), eller
   berøringsflaten blitt liggende igjen på 26. */
.item-check {
  flex: 0 0 auto;
  align-self: center;
  appearance: none;
  cursor: pointer;
  width: 36px;
  height: 36px;
  padding: 0;
  display: grid;
  place-items: center;
  border: none;
  background: transparent;
  color: #fff;
  transition: transform 0.1s;
}
.item-check::before {           /* den synlige boksen: 26×26, sentrert i knappen */
  content: '';
  position: absolute;
  inset: 5px;
  border: 2px solid var(--card-accent);
  border-radius: 8px;
  background: var(--plate);
  transition: background 0.15s, border-color 0.15s;
}
/* Haken males OVER boksen: begge er posisjonert, så tre-rekkefølgen avgjør —
   uten `position` her ville den absolutt posisjonerte ::before ligget øverst. */
.item-check .icon {
  position: relative;
  z-index: 1;
  width: 1em; height: 1em; font-size: 16px; opacity: 0; transition: opacity 0.12s;
}
.item-check:hover::before { border-color: var(--check-hover); }
.item-check:active { transform: scale(0.9); }
/* Ringen skal hugge den SYNLIGE boksen, ikke den større knappen. */
.item-check:focus-visible { outline: none; }
.item-check:focus-visible::before { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }
/* Haken er HVIT, så fyllet må være blågrønt og ikke grønt: den lyse grønnen
   ＋-knappene har, ville gitt 2.7:1 under en hvit glyf. */
.item.done .item-check::before {
  background: var(--grad-accent);
  border-color: transparent;
}
.item.done .item-check .icon { opacity: 1; }

/* Innstillingsknapp (tannhjul) på elementer: dempet i hvile, tydelig ved
   hover/fokus — samme plass som den gamle ansvarsknappen (venstre for ✕). */
.item-cog {
  flex: 0 0 auto;
  align-self: center;
  appearance: none;
  cursor: pointer;
  width: 36px;
  height: 36px;
  padding: 0;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
  opacity: 0.6;
  transition: transform 0.1s, color 0.15s, opacity 0.15s;
}
.item-cog .icon { width: 1em; height: 1em; font-size: 21px; }
.item:hover .item-cog,
.item:focus-within .item-cog { opacity: 1; }
.item-cog:hover { color: var(--primary); }
.item-cog:active { transform: scale(0.9); }
.item-cog:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }
.item-cog:disabled { cursor: default; opacity: 0.3; }
.item.done .item-cog { opacity: 0.5; }

/* Farget sirkel med initialer (ansvarssirkel). Bakgrunnsfargen settes inline
   fra paletten (personens plass i delegruppen). */
.resp-avatar {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: #fff;
  font-weight: 700;
  font-size: var(--fs-sm);
  text-transform: uppercase;
  text-shadow: var(--text-shadow);
  background: #8496a6;
}

/* Tekst + meta-rad stables i en kolonne som tar resten av bredden. */
.item-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.item-text {
  font-size: var(--fs-base);
  font-weight: 500;
  color: var(--ink);
  /* Usynlig i lys drakt (av), samme kant som .card-title/.cat-title i mørk —
     se tokenene ved :root for begrunnelsen. */
  text-shadow: var(--item-text-shadow);
  -webkit-text-stroke: var(--item-text-stroke);
  paint-order: stroke fill;
  cursor: text;
  padding: 2px 4px;
  border-radius: 6px;
  word-break: break-word;
  min-height: 26px;
  align-self: flex-start;      /* klikkflaten (redigering) følger teksten, ikke hele radbredden — som .card-title/.cat-title */
}
/* Mapperad: SAMME rad som et listepunkt (.item-text), men klikk her navigerer
   til mappen i stedet for å redigere navnet — se buildGroupRow(). Fjern derfor
   tekst-cursoren og hover-bakgrunnen `.item-text` ellers har: `inherit` henter
   pekehånden fra raden (`.nav-board .card:not(.is-locked) .item`), så navnet
   ikke ser redigerbart ut. */
.group-row .item-text { cursor: inherit; }
.group-row .item-text:hover { background: none; }
/* Gjort element: lavere bakgrunns-opacity + gjennomstreket, dempet tekst.
   Avkryssede dras ikke (de ligger i «Utført») — raden får `data-dnd-ignore`. */
.item.done { background: var(--plate-done); }
.item.done:hover { background: var(--plate-done-hover); }
.item.done .item-text { text-decoration: line-through; opacity: 0.5; }

/* «Utført»-seksjonen: egen liste under de aktive, skilt med en subtil linje. */
.items-done-wrap { display: flex; flex-direction: column; gap: 8px; }
.done-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 10px;
}
.done-divider span {
  flex: 0 0 auto;
  font-size: var(--fs-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--on-color-soft);
}
.done-divider::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: var(--hairline);
}
/* «Gjenopprett alle utførte» (⟲) og «Slett alle utførte» (🗑) står på
   «Utført»-linja, begge etter skillelinja: linja er divider-ens ::after og
   ligger derfor sist i flex-rekkefølgen; `order` på knappene (som står før
   pseudo-elementet i DOM-en) flytter dem forbi den — ⟲ først, 🗑 helt til
   høyre for den (oppgaven ber om 🗑 til høyre for ⟲). Containerens `gap: 10px`
   gir avstanden mellom de to knappene. 🗑 står i samme 36px-kolonne som
   listepunktenes menyknapp: begge containere har 10px sidepolstring, og
   `margin-right: 6px` legger til .item-ens egen polstring, så ikonene står
   nøyaktig over hverandre. Selve knappeflaten er den delte hvite
   flate-knappen — se `.cat-cog, .done-restore, .done-delete` lenger nede. */
.done-restore { order: 1; }
.done-delete { order: 2; margin-right: 6px; }
.items-done {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0 10px;
}

/* ---------------- Kategorier (nivå-1-rad som grupperer elementer) ----------------
   «Hylle i veggen»-metafor: overskriften (håndtak + tittel/meta + menyknapp)
   står på VEGGEN (listeflaten), og elementene ligger i en
   FORDYPNING rett under — `.cat-items` er en litt mørkere flate med innover-
   skygge, som en hylle som går inn i veggen, og elementene blir som «bøker» i
   hylla. Overskriften ligger tett oppå hylla (4px), så den leser som hyllas
   etikett. `.cat-head`s 6px sidepolstring stiller håndtak/knapper i SAMME
   kolonner som elementenes og kort-hodets; knappene bruker den hvite kort-hode-
   knappestilen (.card-cog) så de er synlige mot listeflaten. */
.category { list-style: none; display: flex; flex-direction: column; gap: 4px; }
/* Subtile skillelinjer rundt en kategoris hylle, mot nabo-radene på nivå 1:
   - UNDER kategorien (::after), mot det påfølgende elementet/kategorien — men
     ikke når kategorien er siste rad (da er det ingenting å skille fra).
   - OVER kategorien (::before) NÅR raden over er et element (`.item + .category`);
     to kategorier på rad får ingen linje mellom seg utover ::after-en fra den
     øverste.
   Kant-til-kant: negativ sidemargin (-10px) kansellerer .items-container sin
   sidepolstring. Lik avstand (16px) over og under hver linje, satt opp mot de
   omkringliggende flex-gapene (.category-gap 4px øverst/nederst i kategorien,
   .items-container-gap 8px mellom nivå-1-rader):
   - ::after: 12px margin-top + 4px gap = 16px over; 8px margin-bottom + 8px gap
     = 16px under.
   - ::before: 8px margin-top + 8px gap = 16px over; 12px margin-bottom + 4px gap
     = 16px under. */
.category:not(:last-child)::after,
.item + .category::before {
  content: '';
  display: block;
  height: 1px;
  background: var(--hairline);
}
.category:not(:last-child)::after { margin: 12px -10px 8px; }
.item + .category::before { margin: 8px -10px 12px; }

/* Forhåndsvisning av skillelinjene under DnD (se applyDragSeparators i app.js).
   Mens et listepunkt eller en kategori dras, tar JS over linjene i containerne
   draget berører: reglene over kjenner hverken placeholderen (den kommende
   plassen) eller det løftede objektet (som er ute av flyten), så de slås av her,
   og hver rad som skal ha en linje OVER seg får `.sep-above`.
   Samme geometri som i hvile, men uttrykt fra den NEDRE raden: 25px margin-top
   (8 + 1 + 8 rundt linja + 8px containergap som allerede finnes = 33px total luft,
   linja midt i med 16px på hver side), og selve linja males absolutt 16px over
   raden — kant-til-kant (-10px) som ellers. Absolutt posisjonering (ikke en
   flex-linje) fordi den skal virke likt på listepunkter, kategorier OG
   placeholderen, uten å endre radenes DOM-naboskap. */
.items-container.seps-managed > .category:not(.sep-below)::after,
.items-container.seps-managed > .category:not(.sep-above)::before { content: none; }
/* Kun radene som faktisk har en linje posisjoneres (aldri det løftede objektet —
   det er `position: absolute` og skal bli det). */
.items-container.seps-managed > .sep-above { position: relative; margin-top: 25px; }
.items-container.seps-managed > .sep-above::before {
  content: '';
  position: absolute;
  left: -10px;
  right: -10px;
  top: -17px;
  height: 1px;
  margin: 0;                          /* nullstill hvile-regelens marger på .category::before */
  background: var(--hairline);    /* samme linje som i hvile */
}
/* Samme linje, men malt fra raden OVER. Brukes når raden UNDER linja er forfar
   til det løftede objektet (et listepunkt dratt ut av en kategori): en `position:
   relative` der ville gjort raden til containing block for det absolutt
   posisjonerte dra-elementet, som da havner på feil sted og klippes bort av
   kortets `overflow: hidden`. Geometrien er speilvendt og identisk. */
.items-container.seps-managed > .sep-below { position: relative; margin-bottom: 25px; }
.items-container.seps-managed > .sep-below::after {
  content: '';
  position: absolute;
  left: -10px;
  right: -10px;
  bottom: -17px;
  height: 1px;
  margin: 0;                          /* nullstill hvile-regelens marger på .category::after */
  background: var(--hairline);
  display: block;
}
.cat-head { display: flex; align-items: center; gap: 8px; padding: 0 6px; }
/* Kategori-ikon: skjult i hvile, vist til venstre for tittelen KUN mens
   kategorien dras (se `.dnd-surface .category[data-dnd-dragging]`). Svarte streker
   (ICONS.category) mot den hvite dra-flaten. */
.cat-drag-icon { display: none; flex: 0 0 auto; align-items: center; }
.cat-drag-icon .icon { width: 1em; height: 1em; font-size: 23px; }
.cat-title-wrap {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.cat-title {
  margin: 0;                   /* <h3> — nullstill nettleserens standardmarg (blåste opp headeren) */
  font-size: var(--fs-md);
  font-weight: 700;
  line-height: 1.2;
  color: #fff;                 /* hvit m/ skygge — lesbar på enhver listefarge, som kort-tittelen */
  text-shadow: var(--text-shadow);
  /* Samme tekst-border som .card-title, se der for begrunnelse. */
  -webkit-text-stroke: 1px #000;
  paint-order: stroke fill;
  cursor: text;
  padding: 3px 5px;
  border-radius: 7px;
  word-break: break-word;
  letter-spacing: 0.01em;
}

/* Den hvite flate-knappen på LISTEFLATEN: kategoriens tannhjul + oppløs-knapp og
   ⟲/🗑-knappene på «Utført»-linja. Samme uttrykk som .card-cog (svakt hvit flate +
   ring, lysner ved hover) — synlige mot den fargede listeflaten og på linje med
   kort-hodets og listepunktenes knapper. Ikonene har svart strek i seg selv
   (ICONS-settets regel), så `color` styrer ikke dem. Ett felles sett regler så
   knappene ikke kan gli fra hverandre. */
.cat-cog, .done-restore, .done-delete {
  flex: 0 0 auto;
  align-self: center;
  appearance: none;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border-radius: 9px;
  color: #fff;
  background: var(--tint);
  box-shadow: inset 0 0 0 1px var(--tint-ring);
  transition: background 0.15s, transform 0.1s;
}
.cat-cog .icon, .done-restore .icon, .done-delete .icon { width: 1em; height: 1em; font-size: 21px; }
.cat-cog:hover, .done-restore:hover, .done-delete:hover { background: var(--tint-hover); }
.cat-cog:active, .done-restore:active, .done-delete:active { transform: scale(0.92); }
.cat-cog:focus-visible, .done-restore:focus-visible, .done-delete:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }
.cat-cog:disabled, .done-restore:disabled, .done-delete:disabled { cursor: default; opacity: 0.4; }

.cat-items {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  /* Fordypning («hylle»): lik luft på alle kanter rundt «bøkene» (fordypningen
     + innover-skyggen er nesting-signalet — intet ekstra venstre-innrykk). */
  padding: 9px;
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.1);   /* litt mørkere enn veggen (listeflaten) */
  box-shadow: inset 0 2px 7px rgba(0, 0, 0, 0.17),   /* innover-skygge = fordypning */
              inset 0 0 0 1px rgba(0, 0, 0, 0.05);
}

/* Kollapset kategori: hylla har høyde 0, men lå fortsatt som en flex-rad MELLOM
   to av `.category`s 4px-gap (over OG under seg) — så luften under overskriften
   ble 4px større enn luften over (tydeligst rundt knappene og mot skillelinjene).
   Den negative margen spiser det ene gapet, så en kollapset kategori er nøyaktig
   sin overskriftslinje med lik luft (16px) til skillelinja over og under — samme
   geometri som en kollapset liste, der headeren er hele kortet.
   Ikke under draging: `.dnd-surface .category[data-dnd-dragging]` har allerede gap:0,
   så der ville margen gjort det løftede objektet 4px lavere enn klonen som
   holder plassen. */
.category.collapsed:not([data-dnd-dragging]) > .cat-items { margin-top: -4px; }

/* Grønn ＋-knapp (nytt listepunkt direkte i kategorien). Ligger som siste rad
   INNI hylle-fordypningen (.cat-items), flyttet dit sist i buildCategory() —
   alltid rett under det siste listepunktet, samme gap som mellom listepunktene.
   Kollapses sammen med resten av hylla (.cat-items height:0) automatisk. */
.cat-add { display: flex; justify-content: center; }
.cat-add-btn.btn-add.icon-only {
  width: 34px;
  height: 34px;
}
.cat-add-btn.btn-add.icon-only .icon { font-size: 26px; }

/* ---------------- Add item ----------------
   To midtstilte knapper nederst i lista: grønn ＋ (nytt listepunkt) og gul
   (ny kategori). Ingen navnefelt — objektet opprettes tomt og navngis på
   plassen sin (samme mønster som ＋-knappen inne i en kategori, .cat-add). */
.add-item-row {
  display: flex;
  justify-content: center;
  gap: 8px;
  padding: 0 10px;
}

/* ---------------- Trykk-og-hold-sone (draging) ----------------
   Dra-håndtakene er fjernet; draging inviteres ved å trykke og holde på et
   objekts navn-/tittelsone (dnd-kits `handleSelector`, se board-oppsettene i
   app.js). Mens holdet registreres får det objektet som skal løftes et lite
   «press» (scale) som tilbakemelding — fjernes idet draget starter (da tar
   `[data-dnd-dragging]` over) eller holdet avbrytes. */
.drag-hold { transform: scale(0.98); transition: transform 0.12s ease; }
@media (prefers-reduced-motion: reduce) {
  .drag-hold { transform: none; transition: none; }
}

/* Åpen hånd (grab) på element-/kategori-dra-sonene så det er tydelig at
   klikk-og-hold (eller klikk-og-dra på desktop) løfter objektet. Områder,
   mapper og lister bruker i stedet pekende hånd (cursor: pointer) — der er et
   klikk den primære handlingen. Kun på det som faktisk KAN dras: ikke låste kort,
   ikke avkryssede elementer. Tittelen på et listepunkt (.item-text) og en
   kategori (.cat-title) beholder tekst-cursoren — der redigerer klikket
   navnet. Mapperadens .item-text arver i stedet denne pekehånden (se
   `.group-row .item-text` over): der navigerer klikket, som resten av raden.
   Knappene har sin egen cursor (mer spesifikke regler vinner). */
.card:not(.is-locked) .item:not(.done),
.card:not(.is-locked) .cat-head { cursor: grab; }

/* ---------------- Ikon-knapper ---------------- */
.icon-btn {
  appearance: none;
  border: none;
  background: transparent;
  cursor: pointer;
  color: var(--ink-soft);
  font-size: var(--fs-base);
  line-height: 1;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border-radius: 9px;
  flex: 0 0 auto;
  align-self: center;
  transition: background 0.15s, color 0.15s, transform 0.1s;
}
.icon-btn:hover { background: var(--wash); color: var(--ink); }

/* Objektmenyknappen — ÉN knapp per objekt, helt til høyre. Den arver flate og
   størrelse fra kontrollen den erstattet på hvert nivå (`.card-cog` på
   korthoder, `.item-cog` på rader, `.cat-cog` på kategorioverskrifter), så
   ingen ny knappestil er innført. `aria-expanded` markeres mens menyen står
   åpen, slik at knappen ikke ser «kald» ut under sin egen popover. */
.obj-menu-btn[aria-expanded='true'] { background: var(--tint-open); opacity: 1; }
.item-cog.obj-menu-btn[aria-expanded='true'] { background: var(--wash); }

/* Synlig tastaturfokus på kontrollene (samme brand-ring som aktivt kort). */
.btn-add:focus-visible,
.trashcan:focus-visible,
.corner-btn:focus-visible,
.icon-btn:focus-visible {
  outline: var(--focus-w) solid var(--focus);
  outline-offset: 2px;
}

/* ---------------- Inline editing ---------------- */
.edit-input {
  font-family: inherit;
  font-weight: inherit;
  font-size: inherit;
  color: var(--ink);
  border: none;
  outline: 2px solid var(--card-accent);
  background: var(--surface);
  border-radius: 6px;
  padding: 2px 6px;
  width: 100%;
}
/* Navneredigereren åpnes ALLTID fokusert (editText fokuserer den selv), så uten
   en egen regel var den eneste markeringen kortets egen aksentkant — den samme
   kanten feltet har i hvile. Nå bærer den den delte fokusringen, som ethvert
   annet fokusert element. */
.edit-input:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 1px; }

/* FLERLINJET redigering (listepunkter og idéer): feltet er et <textarea> som
   vokser med teksten, slik at hele punktet kan LESES mens det redigeres — det
   enlinjes feltet rullet resten ut av syne. Høyden settes av editText
   (scrollHeight), så feltet må verken rulle eller kunne dras i:
   `overflow: hidden` fjerner rullefeltet, `resize: none` håndtaket.
   Skriftstørrelsen og linjehøyden settes av `editText` fra elementet som
   byttes ut — de arves ikke fra raden, og et felt med en annen linjehøyde enn
   teksten hadde ville brutt på et annet ord og hoppet i høyden. */
.edit-input-multi {
  display: block;
  resize: none;
  overflow: hidden;
  min-height: 0;
}

/* Dialogflaten selv får fokus når en modal åpnes (se fokusfellen i app.js), slik
   at skjermleseren leser dialogens navn før innholdet. Den er ikke en kontroll
   man betjener, så den skal ikke BÆRE en fokusring — en ramme rundt hele
   modalen leser som en feil. Første Tab lander på en ekte kontroll, og DEN får
   ringen. Gjelder kun beholderne; alt inni beholder sin egen markering. */
.modal:focus, .modal:focus-visible,
.switcher-panel:focus, .switcher-panel:focus-visible { outline: none; }
/* ---------------- Dra-og-slipp: ny-liste-placeholderen ----------------
   Det LØFTEDE objektet og hullet det kom fra males av dnd-kit-reglene lenger
   nede i fila (`[data-dnd-dragging]` / `[data-dnd-placeholder]`). Her ligger
   bare den ene placeholderen som er VÅR: kort-sloten ekstrahering til en ny
   liste legger inn blant kortene (`makeNewListPlaceholder` i app.js).

   Svakt mørknet flate og en subtil INNOVER-skygge — inntrykket av et «hull»
   som skal fylles (ingen kant). Samme uttrykk som dnd-kits klone får. */
.card-placeholder {
  background: var(--scrim);
  box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.22);
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  width: 100%;
  margin: 0 0 var(--board-gap);
  border-radius: var(--radius);
}
/* «Ny liste»-placeholderen (kategori-/listepunkt-ekstrahering): en flat stripe
   som SVEVER i gapet mellom to kort.

   Den var en kort-formet slot med et ＋ i — 72+ px som skjøv kortene fra
   hverandre. Det gjorde hvert modusbytte til et layout-hopp: dro man videre ned
   i lista under, forsvant stripa, kortet smatt oppover, og raden havnet under
   sonen som nettopp flyttet seg.

   Derfor tar den ingen plass i flyten (`height: 0`, ingen marg): gapet mellom
   kortene er `--board-gap` med og uten den. Stripa males av `::before`, løftet
   opp så den ligger MIDT i det gapet. Ingen ＋: den er et sted, ikke en knapp,
   og på 10 px er det ikke plass til et ikon som betyr noe. */
.new-list-placeholder {
  height: 0;
  margin: 0;
  position: relative;
  background: none;
  box-shadow: none;
  overflow: visible;
}
.new-list-placeholder::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  /* Midt i gapet over: halve gapet pluss halve stripa. */
  top: calc((var(--board-gap) + 10px) / -2);
  height: 10px;
  border-radius: 5px;
  background: var(--scrim);
  box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.22),
              inset 0 0 0 2px rgba(255, 255, 255, 0.55);
}
body.is-dragging { cursor: grabbing; user-select: none; -webkit-user-select: none; }
body.is-dragging * { cursor: grabbing !important; }

/* Litt luft rundt kortene under draging så de ikke oppleves «låst» */
.card, .item { -webkit-user-select: none; user-select: none; }
.item-text, .card-title, .edit-input { -webkit-user-select: text; user-select: text; }
/* … MEN ALDRI MENS ET DRAG PÅGÅR. `body.is-dragging` slår av markering på
   body, og arv alene ville holdt — men de tre reglene over setter
   `user-select: text` PÅ etterkommere, og en eksplisitt verdi på et barn slår
   arven. Uten denne overstyringen markerer selve dra-gesten teksten den drar
   over (pekeren beveger seg med knappen nede), og et drag som endte over en
   tittel etterlot den blå. Regelen gjelder BARE under et aktivt drag, så
   vanlig markering ellers er urørt. `dnd-selection.test.js` er nettet. */
body.is-dragging,
body.is-dragging * {
  -webkit-user-select: none !important;
  user-select: none !important;
}

/* ---------------- Slette-animasjon («pakk sammen og fly i søpla») ----------------
   En klone av det slettede kortet/elementet krymper til en sirkel og svever
   inn i tilhørende søppelkasse-knapp (se flyToTrash i app.js). */
.fly-ghost {
  position: fixed;
  z-index: 260;
  margin: 0;
  overflow: hidden;
  pointer-events: none;
  will-change: left, top, width, height, opacity;
}

/* ---------------- Modaler (meny + søppelkasse) ---------------- */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  /* Mørkleggingen dekker hele skjermen, panelet holder seg innenfor den sikre
     sonen: 20 px luft PLUSS det systemflatene dekker. */
  padding: calc(20px + var(--safe-top)) calc(20px + var(--safe-right))
           calc(20px + var(--safe-bottom)) calc(20px + var(--safe-left));
  background: var(--overlay);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  animation: fade-in 0.15s ease;
}
.modal-overlay[hidden] { display: none; }

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop-in { from { opacity: 0; transform: translateY(8px) scale(0.98); } to { opacity: 1; transform: none; } }

.modal {
  width: min(560px, 100%);
  /* `100%` er overlayets INNHOLDSboks — altså høyden minus den sikre sonen.
     Uten den kunne 82vh (som måles mot hele viewportet) vokse forbi
     paddingen og legge overskriften under statusfeltet. */
  max-height: min(82vh, 100%);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-radius: 20px;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  animation: pop-in 0.18s cubic-bezier(.2, .75, .3, 1);
}

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 20px;
  border-bottom: 1px solid var(--line);
}
.modal-head h2 {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
  margin: 0;
  font-size: var(--fs-xl);
  font-weight: 700;
}
.modal-head h2 .icon { flex: 0 0 auto; }

.modal-body {
  padding: 20px;
  overflow-y: auto;
}

/* Område-/mappe-/konto-modalene: seksjoner skilt med en linje i samme stil
   som modal-head sin border-bottom (samme farge/tykkelse, kant-til-kant).
   .menu-body arver modal-body sin side-padding (20px); negativ side-margin
   kansellerer den så linja når helt ut til modal-kanten, som modal-head sin. */
.menu-modal { width: min(480px, 100%); }
.menu-body {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
}
/* Konto-modalens bunnrad: «Logg ut» (gul) i venstre ende, «Slett konto» (rød) i
   høyre. Hver i sin ende — begge er lette å finne, ingen av dem ligger der
   fingeren treffer den andre. Wrap-er på smale skjermer. */
.menu-account-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}
/* Rene glyfer på massive fargeknapper (dør-ut på «Logg ut», søppelkasse på
   «Slett konto»): hvite streker (currentColor), litt større enn brødteksten. */
.btn-glyph { font-size: var(--fs-lg); line-height: 1; }
.menu-divider {
  border: none;
  border-bottom: 1px solid var(--line);
  margin: 5px -20px;
}
.menu-body .panel-head { min-height: 0; }
.menu-body .panel-actions { margin-top: 2px; }

/* ---------------- Konto-modalens trekkspill ----------------
   Tre skuffer — kontoopplysninger, tips, logg ut/slett konto — i stedet for én
   lang rull. Mekanikken er den samme som objektmenyens skuffer (animert høyde,
   kun ÉN åpen om gangen; `slideSub` i app.js), men formen er en annen: her er
   hver skuff en egen blokk med ramme, ikke nok en rad i en meny. Språkraden
   står utenfor og beholder sin `.menu-setting`-form. */
.menu-acc { display: flex; flex-direction: column; gap: 8px; }
.menu-acc-group {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  /* Skuffen animerer på høyde og skal klippes av gruppens avrundede hjørner. */
  overflow: hidden;
}
.menu-acc-head {
  appearance: none;
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 48px;
  padding: 11px 12px;
  background: var(--primary-soft);
  color: var(--ink);
  font-family: inherit;
  font-weight: 700;
  font-size: var(--fs-md);
  text-align: left;
  transition: background 0.15s;
}
.menu-acc-head:hover { background: var(--primary-soft-hover); }
.menu-acc-head:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: -3px; }
.menu-acc-icon { flex: 0 0 auto; display: flex; }
.menu-acc-icon .icon { width: 22px; height: 22px; }
.menu-acc-label { flex: 1 1 auto; min-width: 0; }
/* Vinkelen peker til høyre når skuffen er lukket og ned når den er åpen —
   samme utslag som i objektmenyen. */
.menu-acc-chev { flex: 0 0 auto; display: flex; color: var(--ink-soft); transition: transform 0.18s; }
.menu-acc-chev .icon { width: 20px; height: 20px; }
.menu-acc-head[aria-expanded='true'] .menu-acc-chev { transform: rotate(90deg); }
.menu-acc-sub {
  overflow: hidden;
  background: var(--surface);
  transition: height 0.18s ease;
}
.menu-acc-sub.is-closed { height: 0; }
.menu-acc-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
}
/* Skillelinjene mellom seksjonene i en skuff går kant-til-kant, som resten av
   delelinjene i modalene: den negative side-margen kansellerer nøyaktig
   `.menu-acc-body` sin polstring. Sideveis luft rundt dem kommer fra `gap`-en. */
.menu-acc-body .menu-divider { margin: 0 -12px; }
/* Innstillingsradene i en skuff får avstanden sin fra `gap`-en, ikke fra sin
   egen toppmarg (den gjelder når raden står fritt i `.menu-body`). */
.menu-acc-body .menu-setting { margin-top: 0; }
/* Skuffen skifter tilstand momentant for den som har bedt om mindre bevegelse —
   `slideSub` setter fortsatt høydene, de bare animeres ikke. */
@media (prefers-reduced-motion: reduce) {
  .menu-acc-sub, .menu-acc-chev { transition: none; }
}

/* Tastatursnarveier i konto-modalen: definisjonsliste i to kolonner, tastene
   som små `kbd`-brikker. Ligger her og ikke ved ikonene i board-et — se
   kommentaren i index.html. */
.key-list {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6px 12px;
  margin: 4px 0 0;
  align-items: baseline;
}
.key-list dt { white-space: nowrap; }
.key-list dd {
  margin: 0;
  font-size: var(--fs-xs);
  color: var(--ink-soft);
  font-weight: 500;
}
.key-list kbd {
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  background: var(--wash);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 1px 6px;
  white-space: nowrap;
}

/* ---------------- Navigasjonsmodalen (områder + mapper) ----------------
   Områder og mapper bruker NØYAKTIG samme oppsett som lister og listepunkter:
   `#nav-board` er et vanlig `.board` med `.card`/`.item`/`.category` inni, bare
   alltid i ÉN kolonne. Derfor arves hele kort-/rad-/kategori-designet (og hele
   dra-og-slipp-motoren) uten egne kopier — det som står her er kun forskjellene:
   énkolonne, litt mer plass i modalen, fast (viewport-)posisjonering under
   draging, og de nivå-spesifikke knappene/markørene. */
.nav-modal { width: min(560px, 100%); }
/* Overskriften er «[globus] Områder og [mappe] mapper» — la den brekke MELLOM
   de to leddene, aldri midt i et ord. */
.nav-modal .modal-head h2 { flex-wrap: wrap; }
.nav-modal .modal-head h2 span { white-space: nowrap; }
/* Område-søppelkassen står i modalens egen fot (se index.html) — sentrert som
   idé-modalens kontrollfelt (`.ideas-foot`), men uten dens stabling: her er
   det bare den ene kassen. `.ideas-foot` har alltid de to ＋-knappene og
   trenger derfor aldri skjules — nav-foten har KUN kassen, så er den tom
   (det vanlige), skal hele foten kollapse, ikke bare stå igjen som en tom
   stripe. `updateTrashBadge()` skjuler wrapperen, ikke foten selv (den vet
   ingenting om at wrapperen sitter i en fot) — derfor følger foten etter med
   `:has()`, samme mønster som `.update-banner`s skjulte notat lenger opp.

   `.item-trash` fyller hele fotens bredde (ingen ＋-knapp å dele rad med her,
   i motsetning til topplinjas liste-kasse) — i hvile holder wrapperens egen
   `justify-content: center` (se `.item-trash` lenger ned) knappen midtstilt
   likevel, og under en DnD gir den fulle bredden `.item-trash .trashcan.
   drag-trash` (samme regel som mappe-/listepunkt-kassene) noe å vokse inn i,
   så kassen blir like lett å treffe her som i et kort. */
.nav-foot .item-trash { flex: 1 1 auto; }
/* … og notatenes nav-modal har TO (arkiv + kasse) i den samme foten, så
   spørsmålet er ikke «er en av dem skjult» men «er alle det». */
.nav-foot:not(:has(.item-trash:not([hidden]))) { display: none; }
/* Kolonnene lages av `relayoutBoard` (samme maskineri som hovedsidens board),
   men nav-scopet setter `singleColumn` → alltid ÉN `.board-col`. */
.nav-board {
  /* Nav-scopet setter `singleColumn` og har alltid nøyaktig én kolonne, uansett
     vindusbredde — mobil-media-regelen gjelder derfor ikke her. */
  --board-single-column: 0;
}
/* Board-gapet er en vw-basert clamp for hovedsiden; i modalen vil vi ha en fast,
   litt tettere luft mellom områdekortene. Siste kort har ingen margin: modalens
   egen padding er bunn-luften der (hovedsidens board bruker i stedet siste korts
   margin, se fixBoardBottomGap). */
.nav-board .card { margin-bottom: 12px; }
.nav-board .board-col > .card:last-child { margin-bottom: 0; }
.nav-board.empty { min-height: 0; padding: 18px 0; }
.nav-board .empty-state { color: var(--ink-soft); }
.nav-board .empty-state .big { font-size: 46px; }
.nav-board .hint-chip { background: var(--wash); }

/* ---------------- dnd-kits dra-og-slipp ----------------
   ALLE nivåene — nav-modalens tre, hovedsidens to og idémodalens ett — kjører på
   dnd-kit gjennom Smett (se «NAV-SCOPET PÅ dnd-kit», «BOARD-SCOPETS KORTNIVÅ …»,
   «BOARD-SCOPETS RADNIVÅ …» og «IDÉ-SCOPET PÅ dnd-kit» i app.js).

   Reglene står på `.dnd-surface` — markørklassen HVER dra-rot bærer (`#board`,
   `#nav-board`, `#ideas-body`), altså nøyaktig de elementene `scope.root` peker
   på. De sto tidligere på `.board`, og da fantes de bare der et board fantes:
   idémodalen er ingen board, så den fikk hverken malt hull eller en
   ugjennomsiktig løftet kategori. Får appen en fjerde dra-flate, er
   markørklassen det ene den må ha.

   dnd-kit løfter selve objektet inn i TOP LAYER via
   `popover` og lar en KLONE holde plassen i layouten, så de to tilstandene har
   egne kroker:

     [data-dnd-dragging]     det løftede objektet
     [data-dnd-placeholder]  klonen som holder plassen

   Geometrien er dnd-kits og skrives med `!important` (`position`, `top`, `left`,
   `width`, `height`, `transform`, `translate`). Vår egen løfte-effekt må derfor
   uttrykkes i egenskaper dnd-kit IKKE skriver: `scale` som en EGEN egenskap,
   aldri via `transform`. Den står her.

   ALT SOM DRAS ER HALVGJENNOMSIKTIG. Det løftede objektet ligger oppå det man
   sikter mot, og det man sikter mot er hele svaret på hvor slippet lander:
   hullet, ny-liste-stripa, skillelinja, søppelkassen. Stripa er 10 px og
   ligger mellom to kort — akkurat der fingeren, og dermed objektet, er. Flaten
   beholder derfor sin EGEN farge (kortets palettfarge, radens plate) og bare
   slipper lys gjennom; `backdrop-filter` gir det et tynt slør, så teksten på
   objektet ikke leses rett mot mønsteret under.

   Dette er Huskis' politikk, ikke Smetts: Smett sier hvor et slipp lander, ikke
   hvordan det som dras ser ut. */
.dnd-surface .card[data-dnd-dragging] {
  scale: 1.02;
  box-shadow: var(--shadow-lg);
  background: color-mix(in srgb, var(--card-bg) var(--dnd-veil), transparent);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  cursor: grabbing;
}
.dnd-surface .item[data-dnd-dragging],
.dnd-surface .category[data-dnd-dragging] {
  scale: 1.03;
  box-shadow: var(--shadow-lg);
  background: color-mix(in srgb, var(--surface) var(--dnd-veil), transparent);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  list-style: none;
  cursor: grabbing;
}
/* … OG DET GJELDER HELE DEN MALTE FLATEN, ikke bare det ytterste laget. Et kort
   er flere flater oppå hverandre: kortfargen, korthodets eget hakk, og platene
   innholdet står på. Med bare den ytterste sluppet gjennom leser et løftet
   NOTATKORT som ugjennomsiktig — hodet og utdragsplaten dekker nesten hele det.
   Regelen står derfor på de indre lagene også, med det samme sløret.

   Ikke `opacity`: den ville tatt teksten med seg. Bakgrunnen alene slipper lys
   gjennom, innholdet står i full styrke (`dnd-drop-animation`, punkt 6). */
.dnd-surface [data-dnd-dragging] .card-head {
  background: color-mix(in srgb, var(--card-head) var(--dnd-veil), transparent);
}
/* Mørk drakt maler hodet og platene med SINE tokens (og hodet i tillegg med
   stripe-gradienten, som `background`-kortformen her rydder bort — nøyaktig som
   på kortflaten over). Platene er allerede halvgjennomsiktige i LYS drakt
   (`--plate` er hvitt med alfa), så de trenger bare sløret her. */
:root[data-theme="dark"] .dnd-surface [data-dnd-dragging] .card-head {
  background: color-mix(in srgb, var(--card-head-face) var(--dnd-veil), transparent);
}
:root[data-theme="dark"] .dnd-surface [data-dnd-dragging] .item,
:root[data-theme="dark"] .dnd-surface [data-dnd-dragging] .note-card-excerpt {
  background: color-mix(in srgb, var(--plate) var(--dnd-veil), transparent);
}
/* Kategorien dras som en kompakt rad: hylla er foldet sammen ved løft
   (`dndCollapseCategory`), og resten må matche et listepunkt — samme polstring
   og radius, ingen gap mot den sammenfoldede hylla, og klipping så den ikke
   stikker ut; uten dem leser det løftede objektet som en beholder med luft i.
   Måles i `dnd-drop-animation` («6 kategori»), på det som faktisk står malt. */
.dnd-surface .category[data-dnd-dragging] {
  gap: 0;
  padding: 6px;
  border-radius: 10px;
  overflow: hidden;
}
/* Skillelinjene hører til kategoriens plass på nivå 1 (mot nabo-radene) — de
   skal ikke males på det løftede objektet (ga ellers en «fantom-strek»). */
.dnd-surface .category[data-dnd-dragging]::before,
.dnd-surface .category[data-dnd-dragging]::after { content: none; }
/* ＋-knappen hører til kategoriens hvile-tilstand; hylla er alt foldet sammen
   ved løft (navCollapseCategory), og knappen skal ikke stikke ut av den. */
.dnd-surface .category[data-dnd-dragging] .cat-add { display: none; }
/* Menyknappen skjules HELT (ikke bare tonet ned) så overskriften leser som en
   kompakt rad, og tittelen males svart uten skygge: hvit-på-hvit var uleselig
   mot dra-flaten. Dra-ikonet er det som bærer «dette er løftet». */
.dnd-surface .category[data-dnd-dragging] .obj-menu-btn { display: none; }
.dnd-surface .category[data-dnd-dragging] .cat-title {
  color: var(--ink);
  text-shadow: none;
  -webkit-text-stroke: none;
}
.dnd-surface .category[data-dnd-dragging] .cat-drag-icon { display: inline-flex; }
/* Forhåndsvisnings-linja som skal males på HULLET settes på det LØFTEDE
   objektet, fordi klonen speiler klassene dens (se `addSep` i app.js). Objektet
   ligger i top layer og er ingen rad i lista: det skal hverken male linja eller
   ta imot marginen som gjør plass til den — dnd-kit setter `top`/`left` selv, og
   en `margin-top` på 25 px ville flyttet det løftede objektet vekk fra fingeren. */
.dnd-surface [data-dnd-dragging].sep-above,
.dnd-surface [data-dnd-dragging].sep-below { margin: 0 !important; }
.dnd-surface [data-dnd-dragging].sep-above::before,
.dnd-surface [data-dnd-dragging].sep-below::after { content: none; }

/* ---- DET LØFTEDE OBJEKTET ER KOMPAKT ----
   Alt som dras krymper i BEGGE retninger ved løft (`dndCompactLift` i app.js):
   objektet ligger oppå det man sikter mot, og alt det dekker er svar man
   trenger. Igjen står TITTELEN og ikonene til VENSTRE for den — typeikonet,
   delt-merket og avkryssingsboksen — for det er de som sier HVA man holder i.
   Alt til høyre for tittelen (menyknapp, kollaps-teller, «sist endret»,
   meta-chips) og hele kortkroppen foldes bort.

   Bredden er innholdets egen. `fit-content` har containerens bredde som tak, så
   en lang tittel brytes som før og objektet blir aldri BREDERE enn det var —
   bare smalere når det kan.

   Reglene står på klassen, ikke på `[data-dnd-dragging]`, og det er ikke en
   smakssak: dnd-kit forankrer det løftede objektets geometri (`--dnd-width`/
   `--dnd-height`/`--dnd-left`/`--dnd-top`) i KLONENS boks. Et hull som ble
   tvunget tilbake til full bredde ville dermed blåst objektet opp igjen —
   krympingen ville vært borte, og skiftet som sentrerte det på grepet med den.
   Klonen arver derfor klassen som alt annet, og hullet er like stort som det
   som lander i det.

   `overflow: visible` er nødvendig for slipp-etiketten («Slett»/«Arkiver»),
   som males OVER objektet — se `[data-drop-label]` under. Kortet klipper
   ellers alt utenfor sin egen boks, og da ville etiketten forsvunnet. Hodet
   overtar derfor kortets avrunding, siden det nå ER hele den synlige flaten. */
.dnd-compact {
  width: -moz-fit-content;
  width: fit-content;
  overflow: visible;
}
/* Alt til høyre for tittelen, og hele kortkroppen. */
.dnd-compact > .card-body,
.dnd-compact > .cat-items,
.dnd-compact .meta-row,
.dnd-compact .collapse-count,
.dnd-compact .note-card-meta,
.dnd-compact .obj-menu-btn,
.dnd-compact .idea-del-btn { display: none !important; }
.dnd-compact > .card-head,
.dnd-compact > .cat-head { border-radius: var(--radius); }
/* Kategorien er allerede foldet sammen ved løft (`dndCollapseCategory`); her
   nulles bare luften hylla ellers holder av. */
.dnd-compact.category { padding: 6px; }

/* Sikter man på søppelkassen, skifter det løftede objektet BAKGRUNNSFARGE til
   rødt: et slipp her sletter. Gjennomsikten og sløret er allerede signalet for
   «dette dras», så tilstanden kan ikke uttrykkes med mer gjennomsikt — da hadde
   de to lest likt.

   MÅLFARGEN ERSTATTER PALETTFARGEN; den vaskes ikke over den. Et kort er flere
   flater oppå hverandre — kortflaten, korthodets eget hakk, platene innholdet
   står på — og hver av dem males av sitt eget palett-token. En vask på det
   ytterste laget lot derfor de indre lagene stå i kortets egen farge, og på et
   KOMPAKT løft er det nettopp hodet som ER hele den synlige flaten: et grønt
   kort leste grønt over søppelkassen. Vi bytter derfor ut selve TOKENENE på
   det løftede objektet, så alle lagene arver den semantiske fargen med én
   gang. `--dnd-veil` og `backdrop-filter` står urørt over dem, så dragets egen
   gjennomsikt og slør er de samme som ellers — det er bare hvilken farge som
   slipper gjennom, som skifter.

   Blekket pinnes samtidig: rødt bærer hvit tekst, gult bærer mørk (se
   kontrast-kontrakten øverst). Uten pinningen fulgte tittelen kortets eget
   blekk, som er valgt for palettfargen og ikke for denne.

   `!important` er nødvendig, ikke pynt: `paintCardColor` setter `--card-bg` og
   `--card-head` som INLINE-stil på kortet, og en inline-stil slår enhver
   vanlig regel på det samme elementet. Uten den sto palettfargen igjen og hele
   overstyringen var en vakt som ikke voktet noe (MÅLT: et grønt kort leste
   fortsatt grønt over søppelkassen).

   HELE IKONTRIOEN PINNES, ikke bare streken — og den pinnes til den LYSE
   verdien i BEGGE drakter, som `.btn-solid` og `.icon-pin-light` gjør. Ikonene
   er fargelagte: papiret i et notat-, liste- eller kalenderikon males av
   `--icon-paper`, og den snur ellers med drakten (hvit i lys, nesten svart i
   mørk). Sto den igjen mens flaten skiftet til målfargen, ble et notat som ble
   dratt over arkivet et sort hull på det lyse tanet (MÅLT: `#262c36` på
   `#e6c896`). Men målfargen er den SAMME i begge drakter, akkurat som
   gradienten på en massiv knapp — så ikonet oppå den skal også stå stille:
   svart strek på hvitt papir, lyst som mørkt. Motivet er da det samme her som
   overalt ellers i appen, bare på en rød eller gul flate.

   `to-trash`/`to-archive` settes fra JS (`setDragTrashTarget` /
   `setDragArchiveTarget`). `dnd-drop-colour.test.js` måler den FAKTISKE malte
   fargen, ikke tokenet. */
.dnd-surface [data-dnd-dragging].to-trash {
  --card-bg: var(--drag-danger-face) !important;
  --card-head: var(--drag-danger-face) !important;
  --card-head-face: var(--drag-danger-face) !important;
  --card-accent: var(--drag-danger-face) !important;
  --surface: var(--drag-danger-face) !important;
  --plate: var(--drag-danger-face) !important;
  --ink: var(--drag-danger-ink) !important;
  --ink-soft: var(--drag-danger-ink) !important;
  --icon-ink: #111111 !important;
  --icon-paper: #ffffff !important;
  --icon-grey: #c0c4c9 !important;
}
/* Sikter man på ARKIVET, skifter objektet til arkivfargen på nøyaktig samme
   måte — samme lag, samme grunn, bare en annen betydning. */
/* NAVNET BÆRES AV KONTUREN, ikke av flaten under det. Målfargen er den samme
   i begge drakter, så teksten oppå skal også stå stille — og da er svaret det
   appen allerede bruker for hvit skrift på en vilkårlig kortfarge: hvitt blekk
   med skygge og full svart kontur (`.hvit-på-farge`, samme oppskrift som
   `.card-title`). Hvit rett på arkivets gule er 2,5:1, og det er nettopp det
   konturen kompenserer for — samme regnestykke som lys drakt gjør for hele
   palettens korttitler (docs/tilgjengelighet.md).

   Listepunktets tekst har konturen bare i mørk drakt til vanlig
   (`--item-text-stroke`); her får den den i begge, av den samme grunnen. */
/* Notatkortets tittel bærer BEGGE klassene (`card-title note-card-title`), så
   den er dekket av den første selektoren — den trenger ingen egen. */
.dnd-surface [data-dnd-dragging].to-trash .card-title,
.dnd-surface [data-dnd-dragging].to-trash .item-text,
.dnd-surface [data-dnd-dragging].to-trash .cat-title,
.dnd-surface [data-dnd-dragging].to-archive .card-title,
.dnd-surface [data-dnd-dragging].to-archive .item-text,
.dnd-surface [data-dnd-dragging].to-archive .cat-title {
  color: #fff;
  text-shadow: var(--text-shadow);
  -webkit-text-stroke: 1px #000;
  paint-order: stroke fill;
}
.dnd-surface [data-dnd-dragging].to-archive {
  --card-bg: var(--drag-archive-face) !important;
  --card-head: var(--drag-archive-face) !important;
  --card-head-face: var(--drag-archive-face) !important;
  --card-accent: var(--drag-archive-face) !important;
  --surface: var(--drag-archive-face) !important;
  --plate: var(--drag-archive-face) !important;
  --ink: var(--drag-archive-ink) !important;
  --ink-soft: var(--drag-archive-ink) !important;
  --icon-ink: #111111 !important;
  --icon-paper: #ffffff !important;
  --icon-grey: #c0c4c9 !important;
}
/* … OG DEN SIER HVA SOM SKJER. En fargeendring alene er et svakt signal — den
   forutsetter at man kjenner fargen fra før — så det løftede objektet får i
   tillegg en etikett («Slett» / «Arkiver») rett over seg. Den males på selve
   OBJEKTET, ikke på kassen: objektet ligger i top layer og kan ikke dekkes av
   noe, mens en etikett på kassen ville havnet under både fingeren og det man
   drar. Teksten kommer fra `data-drop-label` (i18n, satt av
   `setDragTrashTarget`/`setDragArchiveTarget`), så den finnes bare på det ene
   objektet som faktisk sikter — og bare så lenge det sikter.

   Flaten er TOASTENS: appens egen «etikett som svever over hva som helst», med
   den kontrasten den allerede er målt på. Fargen som skiller sletting fra
   arkivering bærer objektet selv. */
.dnd-surface [data-dnd-dragging][data-drop-label]::after {
  content: attr(data-drop-label);
  position: absolute;
  left: 50%;
  bottom: calc(100% + 10px);
  translate: -50% 0;
  padding: 5px 14px;
  border-radius: 999px;
  background: var(--glass-dark);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  backdrop-filter: blur(14px) saturate(1.3);
  border: 1px solid rgba(255, 255, 255, 0.16);
  color: #fff;
  font-size: var(--fs-sm);
  font-weight: 700;
  white-space: nowrap;
  box-shadow: var(--shadow-md);
  pointer-events: none;
}
/* Klonen speiler attributtene til det løftede objektet, og en etikett på hullet
   ville lovet en handling der ingenting skjer. `.sep-above`/`.sep-below` bruker
   de samme pseudo-elementene til skillelinjene sine, så unntaket er snevret inn
   til nøyaktig etiketten — og den finnes bare mens man sikter på en kasse, der
   hullet uansett ikke lover noe (`body.is-over-trash`). */
.dnd-surface [data-dnd-placeholder][data-drop-label]::after { content: none !important; }

/* Lista sikter på 📁-breadcrumben (flytt til en annen mappe). Den ENESTE
   dra-tilstanden som fortsatt tones ut i stedet for å skifte farge: en flytting
   har ingen egen farge i paletten slik slettingen har rødt, og signalet den
   deler med er breadcrumbens egen `.drop-target`-markering. */
.dnd-surface [data-dnd-dragging].to-group { opacity: 0.45; }

/* Klonen er «hullet» objektet kom fra: samme uttrykk som `.card-placeholder`
   lenger opp i fila — svakt mørknet flate med en subtil INNOVER-skygge. dnd-kit
   skjuler klonen som standard (`visibility: hidden`); vi viser boksen og skjuler
   INNHOLDET i stedet. */
.dnd-surface .card[data-dnd-placeholder],
.dnd-surface .item[data-dnd-placeholder],
.dnd-surface .category[data-dnd-placeholder] {
  visibility: visible;
  background: var(--scrim);
  box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.22);
  outline: none;
}
.dnd-surface .card[data-dnd-placeholder] { border-radius: var(--radius); }
.dnd-surface .item[data-dnd-placeholder],
.dnd-surface .category[data-dnd-placeholder] { border-radius: 10px; }
/* Klonen er tatt av det løftede objektet ETTER at skalaen er satt, så den
   bærer den som en INLINE-stil — og en inline-stil slår enhver klasseregel.
   Hullet i lista skal stå i sin egen størrelse, så her må det `!important`
   til; uten det er regelen en vakt som ikke vokter noe. */
.dnd-surface [data-dnd-placeholder] { scale: none !important; }
/* … og av samme grunn skiftet som sentrerte den KRYMPEDE boksen på grepet
   (`dndCompactLift`): det ligger allerede i målingen dnd-kit tok, så et hull
   som bar det en gang til ville stått forskjøvet i lista. */
.dnd-surface [data-dnd-placeholder] { translate: none !important; }
.dnd-surface [data-dnd-placeholder] > * { visibility: hidden; }
/* HULLET SOM IKKE LOVER NOE: verken maling eller plass.

   Et malt hull sier «her lander raden». Tre ganger sier det ikke det:
   i ekstraheringsmodus (ny-liste-stripa er plassen raden skal til), når pekeren
   står på en kasse (slippet sletter), og når klonen ligger igjen i en ANNEN
   liste enn den slippet gjelder. Da males den ikke — og LISTA STÅR HELLER IKKE
   ÅPEN: en rad uten en plassholder i lover en plassering som ikke finnes.

   Plassen tas av en negativ `margin-bottom` på klonen. Aldri `display: none`
   eller `height: 0`: klonens boks ER dra-objektets geometri, og dnd-kit speiler
   mål, plassering og viewport-klemme fra den (`display: none` krympet
   dra-objektet til 12×12 px; frosne mål slapp det 269 px utenfor skjermkanten).

   Beløpet kommer som en ARVET variabel fra containeren, ikke som en inline-stil
   på klonen: klonen er en kopi av raden som dras, og dnd-kit bygger den om fra
   originalens `style`-attributt — det samme attributtet vi maler rotasjonen i
   (se regelen over). En inline `margin-bottom` ble vasket bort med den.
   Containeren er VÅR node, og klonen arver. Se `syncHoleSpace` i app.js. */
body.is-hole-gone .dnd-surface [data-dnd-placeholder] { visibility: hidden; }
/* Marginene på et hull som ikke lover noe er VÅRE. `!important` av samme grunn
   som for det løftede objektet lenger opp: kategoriens skillemarger står i en
   regel med tre klasser (`.items-container.seps-managed > .sep-above`), og 25 px
   tom marg er nettopp den åpne raden komprimeringen skal fjerne. Linja i margen
   males uansett ikke — hullet er `visibility: hidden`. */
body.is-hole-gone [data-dnd-placeholder] {
  margin-top: 0 !important;
  margin-bottom: var(--hole-shrink, 0px) !important;
}
/* Pekeren på kassen: der SLETTER slippet, så ny-liste-stripa skal ikke love en
   ny liste. Stripa tar ingen plass, så her er det bare malingen. */
body.is-over-trash .new-list-placeholder { visibility: hidden; }
/* Kategoriens hvile-linjer hører til kategorien, ikke til hullet — MEN under et
   raddrag ER klonen «raden som kommer», og da er det den som skal bære linja
   (`applyDragSeparators` gir den `.sep-above`/`.sep-below` som enhver annen
   rad). Unntaket må derfor skrives på samme form som `seps-managed` bruker,
   ellers slår det — mer spesifikt — ut den forhåndsvisningen det ikke handler
   om. */
.dnd-surface .category[data-dnd-placeholder]:not(.sep-above)::before,
.dnd-surface .category[data-dnd-placeholder]:not(.sep-below)::after { content: none; }

/* Aktivt område / aktiv mappe: samme grønne brand-ring som resten av appen,
   trukket innover så den ikke kolliderer med nabokortet. */
/* AKTIV posisjon (området/mappen man står i) — en ring trukket INNOVER.
   Den var brand-grønn, men grønt på de seks kortfargene ligger på 1,5–2,3:1 og
   var altså ikke synlig der den skulle si hvor man er. Mørk ring gir 5,3–8:1 mot
   alle seks. Tilstanden bæres dessuten av `aria-current` (app.js), så den ikke
   bare finnes for øyet.
   Fokusringen bruker samme farge, men ligger UTENFOR kanten (se under) — de to
   ringene kan derfor stå samtidig uten å smelte sammen. */
.nav-board .card.active { outline: var(--focus-w) solid var(--focus); outline-offset: -2px; }
.nav-board .item.active { outline: var(--focus-w) solid var(--focus); outline-offset: -2px; }

/* Klikk er primærhandlingen på begge nivåer (gå til mappen / kollaps området),
   så pekende hånd — ikke den åpne hånden listepunkter/kategorier har. */
.nav-board .card:not(.is-locked) .item,
.nav-board .card:not(.is-locked) .cat-head { cursor: pointer; }

/* Tastatur: korthodet (område) og mapperaden er fokuserbare knapper — de er de
   eneste veiene inn til navigering uten peker, så de må vises tydelig. */
.nav-board .card-head:focus-visible,
.nav-board .item.group-row:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }

/* Type-ikon foran navnet: [globus] område, [mappe] mappe — samme ikoner som
   breadcrumben, så modalen og toppmenyen leser likt. Er objektet delt, ligger
   delt-merket MELLOM ikonet og navnet ([ikon][delt]Navn). */
.nav-board .kind-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  font-size: var(--fs-lg);
  line-height: 1;
}
/* Områdekortet skal ikke ha den lyse innerkanten delte lister har: på et kort
   der body-en er gjennomsiktig lyser ringen gjennom nederst og leser som en
   ramme rundt mappelista. Delt-merket ved navnet sier alt som trengs. */
.nav-board .card.is-shared { box-shadow: var(--shadow-sm); }
.nav-board .card.is-shared:hover { box-shadow: var(--shadow-md); }

/* Kollapset område: [mappe] + antall mapper i stedet for «(N)» — samme lille,
   subtile pill som antall-merket ellers i appen. */
.uni-count {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 6px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.16);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  align-self: center;
}
.uni-count .icon { font-size: var(--fs-xs); }

/* Søppel-radene (alle fire kassene): [prikk] [navn (+ metadata)] [Gjenopprett].
   Navnet er det ENESTE som skal kunne gi etter; prikken, metadataen og knappen
   har fast bredde. På en smal skjerm er summen av de faste større enn raden er
   bred, og navnet fikk resten — som var omtrent ingenting. `word-break:
   break-word` gjorde samtidig navnets min-content-bredde til ETT tegn, så flex
   hadde ingen nedre grense å stoppe på: navnet ble en loddrett bokstavsøyle,
   og resten av raden gikk likevel utenfor modalen (knappen havnet utenfor den
   synlige flaten, og modal-body-en fikk horisontal scroll).

   Løsningen er et GULV i stedet for en fast bredde: navneblokka har en
   flex-basis, og når den ikke får plass bryter flex linjen i stedet for å
   presse — knappen faller ned på egen linje (fortsatt høyrestilt), og
   metadataen legger seg under navnet. Bredere skjermer har plass til alt på én
   linje og ser ut som før. Ingen breakpoint: gulvet måles mot radens FAKTISKE
   bredde, som er modalens, ikke vindusbredden. */
.trash-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 12px;
  padding: 12px 4px;
  border-bottom: 1px solid var(--line);
}
.trash-row:last-child { border-bottom: none; }
/* Prikken bærer objektets palettfarge, og palettfargen er mørk i mørk drakt —
   omtrent like mørk som modalflaten. Kantstreken er derfor --wash og ikke en
   fast svart: den snur med drakten og gir prikken en synlig kant begge veier. */
.trash-dot { width: 21px; height: 21px; border-radius: 7px; flex: 0 0 auto; box-shadow: inset 0 0 0 1px var(--wash); }
/* Navn og metadata hører sammen: samme linje når det er plass, ellers legger
   metadataen seg UNDER navnet (innrykket forbi prikken, ikke ved siden av den). */
.trash-main {
  flex: 1 1 12rem;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px 10px;
}
/* `overflow-wrap: break-word`, ikke `word-break`/`anywhere`: et langt navn
   brekker MELLOM ord når det går, og et enkeltord uten mellomrom brekkes bare
   når det ellers ville stukket utenfor. */
.trash-name { flex: 1 1 11rem; min-width: 0; font-weight: 600; font-size: var(--fs-base); overflow-wrap: break-word; }
/* Metadataen står på én linje så lenge den får plass (flex bryter linjen før den
   krymper et element), men er ikke `nowrap`: da ville en uventet lang tekst
   stukket ut av raden i stedet for å brekke. */
.trash-meta { flex: 0 1 auto; min-width: 0; color: var(--ink-soft); font-size: var(--fs-sm); font-weight: 500; }
/* Knappen krymper aldri (berøringsflaten er uendret) og holder seg til høyre —
   også på linja den faller ned på. */
.trash-row > .btn { flex: 0 0 auto; margin-left: auto; }
.trash-empty-msg { text-align: center; color: var(--ink-soft); font-weight: 500; font-size: var(--fs-base); padding: 26px 0; margin: 0; }

.modal-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;                   /* se .modal-note */
  gap: 14px;
  padding: 20px;
  border-top: 1px solid var(--line);
  background: var(--surface-2);
}
/* Notatet tar hele linjen, knappen linjen under (høyrestilt): tøm-knappen
   navngir det den faktisk sletter («Slett listepunktene for godt»), og ved
   siden av notatet ville den presset teksten til en smal søyle — på mobil til
   én bokstav per linje. Stablet ser de fire søppelkassene dessuten like ut,
   uansett hvor langt navnet på nivået er. */
.modal-note { flex: 1 1 100%; margin: 0; font-size: 16px; color: var(--ink-soft); font-weight: 500; }
.modal-note ~ .btn { flex: 0 0 auto; margin-left: auto; }

/* Felles bekreftelses-modal: smal, melding + Avbryt/OK samlet til høyre. */
.confirm-modal { width: min(430px, 100%); }
.confirm-msg { margin: 0; font-size: var(--fs-base); line-height: 1.5; color: var(--ink); font-weight: 500; }
.confirm-foot { justify-content: flex-end; }

/* ---------------- Slett konto (advarsel + sveip for å bekrefte) ----------------
   Samme formspråk som søppelkassenes sveipefelt (.swipe-field): ikon til
   venstre, etikett, pil som fyller resten, og en fylling som følger sveipet —
   men i faresonens farger, og som et fast felt i modalen (ingen knapp å vokse
   ut av). Bekreftelsen ER gesten: modalen har ingen OK-knapp, for slettingen
   kan ikke angres. Tastatur når det samme med piltastene (role="slider"). */
.delete-account-body { display: flex; flex-direction: column; gap: 14px; }
.danger-list {
  margin: 0;
  padding-left: 22px;
  display: flex;
  flex-direction: column;
  gap: 7px;
  font-size: var(--fs-md);
  line-height: 1.45;
  color: var(--ink-soft);
  font-weight: 500;
}
.delete-account-hint {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--danger-ink);
}
.confirm-swipe {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  height: var(--control-h);
  padding: 0 14px;
  border-radius: var(--control-radius);
  background: var(--surface);
  box-shadow: inset 0 0 0 1.5px var(--danger-soft-hover), var(--shadow-sm);
  overflow: hidden;
  white-space: nowrap;
  cursor: grab;
  touch-action: none;                   /* sveipet er vårt, ikke sidens scroll */
  -webkit-user-select: none;
  user-select: none;
}
.confirm-swipe:active { cursor: grabbing; }
.confirm-swipe:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }
.confirm-swipe::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--danger-soft), var(--danger-soft-hover));
  transform: scaleX(var(--p, 0));
  transform-origin: left center;
  pointer-events: none;
}
.confirm-swipe .swipe-label { color: var(--danger-ink); }
.confirm-swipe .swipe-arrow { color: var(--danger-ink); }

body.modal-open { overflow: hidden; }

/* ---------------- Popover-skall (ansvarlig-velger + tids-popover) ----------------
   Felles skall: popover på desktop, sentrert modal på mobil (media-queryen
   lenger ned). Samme klikk-utenfor-lukker-mønster som de andre modalene
   (ev.target === overlay). */
.switcher-overlay {
  position: fixed;
  inset: 0;
  z-index: 210;
  background: transparent;
}
.switcher-panel {
  position: fixed;
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: max-content; /* kun så bred som det lengste navnet krever — ingen kunstig minstebredde */
  max-width: min(320px, calc(100vw - 20px - var(--safe-left) - var(--safe-right)));
  max-height: min(70vh, 480px);
  overflow-y: auto;
  padding: 10px;
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}
/* Ansvarlig-velgeren: nøytralt hvitt panel (arver .switcher-panel) med rader
   som viser farget initial-sirkel + fullt navn. Ingen fulle fargede rader som
   bytterne — her er selve avataren det fargede elementet. */
.resp-panel { gap: 3px; }
.resp-row {
  appearance: none;
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
  width: 100%;
  padding: var(--menu-row-pad-y) var(--menu-row-pad-x);
  border-radius: var(--control-radius);
  background: transparent;
  color: var(--ink);
  font-family: inherit;
  font-weight: 600;
  font-size: var(--fs-md);
  text-align: left;
  transition: background 0.15s;
}
.resp-row:hover { background: var(--primary-soft); }
.resp-row.active { background: var(--primary-soft); }
.resp-row:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: -2px; }
.resp-row-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.resp-avatar-none {
  background: var(--control-bg);
  color: var(--ink-soft);
  text-shadow: none;
}
.resp-avatar-none .icon { width: 1em; height: 1em; font-size: 21px; }
.resp-row-clear { color: var(--ink-soft); }

/* ---------------- Synk-varsel ----------------
   Synken går fortløpende i bakgrunnen (ingen egen knapp lenger). Når en
   endring kommer fra en annen enhet vises et lite, forbigående varsel.
   Flaten er halvgjennomsiktig med backdrop-blur, så innholdet under skinner
   gjennom uten at teksten blir utydelig (mørk flate + hvit tekst). */
.toast {
  position: fixed;
  /* Midt i det BRUKBARE feltet, ikke midt på skjermen: et hakk i siden
     (landskap) flytter senteret et halvt inset-avvik, ellers ville en bred
     toast lagt seg delvis under hakket. Er begge sidene 0 — enhver nettleser —
     er dette nøyaktig `50%`. Sentreringen MÅ bli værende som `left` +
     `translate(-50%)`: sveip-for-å-lukke legger draget inn i den samme
     transformen (`calc(-50% + Npx)`, se attachToastSwipe i app.js). */
  left: calc(50% + (var(--safe-left) - var(--safe-right)) / 2);
  /* Over gestelinjen — og over SLIPPFOTEN når den er framme: den lever nederst
     i viewportet, og en toast som la seg oppå søppelkassen ville dekket nettopp
     det man nettopp brukte. `--dock-reserve` er 0 når foten er borte. */
  bottom: calc(24px + var(--safe-bottom) + var(--dock-reserve, 0px));
  transform: translate(-50%, 16px);
  z-index: 300;
  display: flex;
  align-items: center;
  gap: 14px;
  /* `left: 50%` gjør at en auto-bredde bare kan vokse ut til høyre kant — en
     toast som brekker teksten ville presset seg ned i en halvbred søyle på
     mobil. `max-content` lar den bruke hele max-width først, og brekke etter
     det. */
  width: max-content;
  /* Siste leddet er det brukbare feltet minus 12 px på hver side: bredden kan
     ikke vokse ut over hakket selv om 90vw ville tillatt det. */
  max-width: min(90vw, 480px, calc(100vw - 24px - var(--safe-left) - var(--safe-right)));
  padding: 11px 13px 11px 20px;
  border-radius: 999px;
  background: var(--glass-dark);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  backdrop-filter: blur(14px) saturate(1.3);
  border: 1px solid rgba(255, 255, 255, 0.16);
  color: #fff;
  font-size: var(--fs-md);
  font-weight: 600;
  box-shadow: var(--shadow-md);
  opacity: 0;
  pointer-events: none;              /* ikke-interaktiv i hvile … */
  /* Sveip-til-lukk: vertikal drag skal fortsatt rulle siden nativt, og
     teksten skal ikke markeres når man tar tak i toasten. */
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
  transition: opacity 0.25s ease, transform 0.25s ease;
}
/* … men interaktiv når den vises: hele flaten kan dras til høyre for å lukke. */
.toast.show { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
/* Mens fingeren/musen drar: ingen transisjon (JS setter transform per bevegelse).
   Varsel-toastene deler gesten, og dermed disse to tilstandene. */
.toast.toast-dragging,
.notif-toast.toast-dragging { transition: none; cursor: grabbing; }
/* Utkast til høyre etter et fullført sveip (JS rydder inline-stilene etterpå). */
.toast.toast-swipe-out,
.notif-toast.toast-swipe-out { transition: opacity 0.18s ease, transform 0.18s ease; }
/* Beskjeden brekker over flere linjer i stedet for å kappes med ellipsis: den
   sier hva som skjedde med brukerens innhold, og en toast som stopper på
   «Lagt i søppelkassen: «Ukens gjø…» har mistet nettopp det den skulle si.
   Ellipsen kappet alt over ~28 tegn på mobil, altså de fleste beskjedene.
   Linjetaket er ikke pynt: navnet i beskjeden er brukerens egen tekst og kan
   være vilkårlig langt, og en toast uten tak ville vokst opp over
   lagringsstatusen (som ligger UNDER den i z-orden) og skjult både feilen og
   «Prøv igjen». Fire linjer rommer alle appens egne beskjeder og tips; blir
   det for langt, er det navnet som kappes — poenget står først. */
.toast-msg {
  min-width: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
}
/* Kontekstuelt tips (docs/introduksjon.md): en hel setning, ikke en kvittering
   på tre ord — og den får litt mer bredde å brekke innenfor. Alt annet (flate,
   sveip-til-lukk, plassering) er som en vanlig toast: et tips skal aldri kreve
   mer oppmerksomhet enn en beskjed. */
.toast.toast-tip {
  max-width: min(92vw, 540px, calc(100vw - 24px - var(--safe-left) - var(--safe-right)));
}
/* Angre-knappen (hele toasten er interaktiv mens den vises). */
.toast-action {
  flex: 0 0 auto;
  appearance: none;
  border: none;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  font-family: inherit;
  font-weight: 700;
  font-size: 16px;
  padding: 7px 14px;
  border-radius: 999px;
  transition: background 0.15s;
}
.toast-action:hover { background: rgba(255, 255, 255, 0.3); }
.toast-action:focus-visible { outline: var(--focus-w) solid var(--focus-on-dark); outline-offset: 2px; }

/* ---------------- Varsel-toastene (docs/varsler.md) ----------------
   Et nytt varsel skal SES, ikke bare telles: en liten toast springer ut fra
   bjelleknappen og står i tre sekunder. Den er bevisst et annet format enn den
   midtstilte `.toast` — den hører til KNAPPEN, ikke til noe brukeren nettopp
   gjorde — og et annet format enn varselraden: navn + én kort setning.

   FLATEN ER VARSELTYPENS EGEN FARGE, halvgjennomsiktig med backdrop-blur, så
   toasten sier hva den gjelder før man har lest et ord. Fargen er den MØRKESTE
   enden av den samme gradienten ikonet står på: en toast er en liten flate der
   gradienten ikke leses uansett, og det mørke stoppet er det som bærer
   tekstfargen sin med margin også når det halvgjennomsiktige laget legger seg
   over en hvit bakgrunn (verst tenkelige tilfelle). Tekstfargen pinnes per
   tone, som på chipene: hvitt på rødt og blågrønt, mørkt på gult og lilla —
   en gul flate som bærer hvit tekst er ikke gul lenger.
   `tests/a11y-contrast.test.js` regner begge ytterpunktene ut på nytt. */
.notif-toasts {
  position: fixed;
  /* `top`/`right` settes i JS fra bjelleknappens faktiske plass — gruppen
     brytes til flere rader på smale skjermer. */
  top: 0;
  right: 0;
  z-index: 305;                      /* over den vanlige toasten (300) */
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  pointer-events: none;              /* stabelen selv tar ikke imot klikk … */
  max-width: min(340px, calc(100vw - 24px - var(--safe-left) - var(--safe-right)));
}
.notif-toast {
  pointer-events: auto;              /* … men hver toast gjør det */
  appearance: none;
  cursor: pointer;
  font-family: inherit;
  text-align: left;
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: 100%;
  padding: 9px 14px 9px 10px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: var(--shadow-md);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  backdrop-filter: blur(14px) saturate(1.3);
  color: var(--toast-ink);
  /* Sveip til høyre lukker, som den vanlige toasten. */
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
  /* «Springer ut fra knappen»: origo øverst til høyre, altså der bjellen står. */
  transform-origin: top right;
  animation: notif-toast-in 0.22s cubic-bezier(0.2, 1.2, 0.4, 1);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
@keyframes notif-toast-in {
  from { opacity: 0; transform: translate(6px, -10px) scale(0.72); }
  to   { opacity: 1; transform: none; }
}
/* Timeren løper ut: en myk uttoning PÅ PLASS (sveipet kaster derimot ut). */
.notif-toast.is-leaving { opacity: 0; transform: translateY(-6px) scale(0.96); }
/* Ringen ligger UTENFOR pillen (offset), altså på board-flaten — ikke på
   toastens egen farge. Den hvite er derfor riktig for alle fire tonene, som på
   de andre mørke flatene appen har. */
.notif-toast:focus-visible { outline: var(--focus-w) solid var(--focus-on-dark); outline-offset: 2px; }
.notif-toast-text {
  min-width: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  /* Toasten er en kvittering i forbifarten, ikke en tekst å lese: to linjer,
     så et langt objektnavn ikke kan vokse den ut over halve skjermen. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
.notif-toast-name { font-weight: 800; }
/* Skilletegnet hører til formen, ikke til setningen — derfor i CSS og ikke i
   ordboken (det er likt på begge språk). */
.notif-toast-msg::before { content: ' · '; }
/* Tonene: flaten er typens egen farge, teksten pinnet til det flaten bærer. */
.notif-toast.is-over { background: rgba(168, 43, 64, 0.85); --toast-ink: #ffffff; }
.notif-toast.is-soon { background: rgba(217, 165, 44, 0.85); --toast-ink: #111111; }
.notif-toast.is-started { background: rgba(56, 98, 98, 0.85); --toast-ink: #ffffff; }
.notif-toast.is-startsoon { background: rgba(173, 133, 173, 0.85); --toast-ink: #111111; }
/* De to lyse flatene bærer heller ingen lys kant. */
.notif-toast.is-soon, .notif-toast.is-startsoon { border-color: rgba(0, 0, 0, 0.16); }

/* ---------------- Lagringsstatus (diskret, vedvarende) ----------------
   Motstykket til toasten: der toasten er et FORBIGÅENDE varsel om noe som
   nettopp skjedde, er dette en TILSTAND som blir stående så lenge den gjelder.
   Derfor er den også plassert utenfor toastens/bannerets midtstilte «varsel-
   sone» — nede i venstre hjørne, fast, uten å røre toppmenyens høyde.

   Formspråket er flate-mønsteret (halvgjennomsiktig hvit + blur), ikke toastens
   mørke flate: statusen er bakgrunnsinformasjon, ikke en melding som krever
   oppmerksomhet. Prikken følger TRAFIKKLYSET (grønn = lagret, gul = lagrer,
   rød = noe gikk galt, grå = frakoblet, altså «lyset er av»), og teksten sier
   det samme i klartekst.

   Pillen er `pointer-events: none` slik at den aldri kommer i veien for board-et
   under; kun «Prøv igjen»-knappen tar imot klikk. */
.sync-status {
  position: fixed;
  left: calc(12px + var(--safe-left));
  bottom: calc(16px + var(--safe-bottom) + var(--dock-reserve, 0px));
  z-index: 290;                      /* under toasten (300) og banneret (410) */
  display: inline-flex;
  align-items: center;
  gap: 9px;
  /* Statustekstene er hele setninger, og hele setningen må få plass: en
     avkortet «Frakoblet – endringene lagre…» skjuler nettopp det som
     beroliger. Derfor nesten full bredde på små skjermer, og ombrekking (med
     mykere hjørner) i stedet for ellipse hvis den likevel ikke rekker. */
  max-width: calc(100vw - 24px - var(--safe-left) - var(--safe-right));
  padding: 7px 13px;
  border-radius: 999px;
  background: var(--control-bg);
  -webkit-backdrop-filter: blur(12px) saturate(1.2);
  backdrop-filter: blur(12px) saturate(1.2);
  border: 1px solid var(--line);
  color: var(--ink-soft);
  font-size: var(--fs-xs);
  font-weight: 600;
  box-shadow: var(--shadow-sm);
  pointer-events: none;              /* klikk skal gå gjennom til board-et … */
  transition: opacity 0.25s ease, background 0.25s ease, transform 0.25s ease;
}
.sync-status-text { min-width: 0; }
/* Brekker teksten, blir pillen for høy for 999px — samme grep som bannerets. */
@media (max-width: 460px) { .sync-status { border-radius: 18px; } }
/* På smale skjermer spenner toasten og oppdateringsbanneret over hele bunnen og
   ville lagt seg oppå statusen (og over «Prøv igjen»). Da løftes statusen over
   dem — samme `:has()`-grep som banneret bruker mot toasten, og av samme grunn:
   hvem som havnet først i <body> avhenger av rekkefølgen de dukket opp i.
   Løftene er avstemt mot MAKSHØYDENE på en 390 px skjerm: toasten er kappet
   til fire linjer (≈108 px, se `.toast-msg`) og banneret er ≈149 px med
   forklaringslinjen synlig. Uten linjetaket på toasten kunne et langt navn
   skjøvet den opp over statusen. Står banneret OG en toast, ligger banneret
   allerede løftet over toasten — statusen må derfor klare summen. */
@media (max-width: 560px) {
  body:has(.toast.show) .sync-status { transform: translateY(-128px); }
  body:has(.update-banner.show) .sync-status { transform: translateY(-165px); }
  body:has(.toast.show):has(.update-banner.show) .sync-status { transform: translateY(-293px); }
}
/* TRAFIKKLYSET. Grønnfargen er --primary-dark, ikke --primary: pilleflaten er
   halvgjennomsiktig hvit over board-bakgrunnen, og den lyse --primary havner
   under 3:1 mot den. Grått (--ink-soft) betyr «lyset er av» — vi når ikke
   serveren, så vi vet ikke. Fargene håndheves av tests/a11y-contrast.test.js. */
.sync-status-dot {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--primary-ink);    /* lagret */
}
.sync-status[data-state="saving"] .sync-status-dot { background: var(--warn); }
.sync-status[data-state="offline"] .sync-status-dot { background: var(--ink-soft); }
.sync-status[data-state="rejected"] .sync-status-dot { background: var(--danger-ink); }
.sync-status[data-state="rejected"] { color: var(--ink); border-color: var(--danger-soft-hover); }
/* «Lagret» er en kvittering, ikke en tilstand å stirre på: ett sekund etter at
   den kom, fader pillen HELT ut. En status som alltid står der er visuell støy
   — og for den som ikke vet hva den er, en gåte. Kvitteringen skal rekke å bli
   sett, ikke bli stående og bli lest. Den fader inn igjen ved neste aktivitet.
   Dette gjelder KUN «Lagret»: `is-quiet` settes bare i den tilstanden (se
   syncStatus.paint), så «Lagrer …», «Frakoblet» og en avvisning blir stående
   til de er over — et uløst problem skal aldri kunne forveksles med
   «ingenting vist». */
.sync-status.is-quiet { opacity: 0; }
/* … men «Prøv igjen» må kunne trykkes. */
.sync-status-action {
  flex: 0 0 auto;
  pointer-events: auto;
  appearance: none;
  border: none;
  cursor: pointer;
  background: var(--danger-soft);
  color: var(--ink);
  font-family: inherit;
  font-weight: 700;
  font-size: var(--fs-xs);
  padding: 5px 11px;
  border-radius: 999px;
  transition: background 0.15s;
}
.sync-status-action:hover { background: var(--danger-soft-hover); }
.sync-status-action:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }

/* ---------------- Oppdateringsbanner (ny klientversjon) ----------------
   Samme glassflate og pilleform som toasten, men VEDVARENDE: det står til
   siden lastes på nytt. Ikke-modalt (fanger ikke fokus, dekker ingenting man
   trenger), og ligger over toasten så de to ikke overlapper når begge vises.
   Vises av update-check.js. */
.update-banner {
  position: fixed;
  /* Sentreres med left/right + `margin: auto` (ikke `left: 50%`): en fast
     plassert boks med `left: 50%` får bare halve viewporten som tilgjengelig
     bredde, og teksten brekker da til én ordkolonne på mobil. */
  left: calc(12px + var(--safe-left));
  right: calc(12px + var(--safe-right));
  bottom: calc(24px + var(--safe-bottom) + var(--dock-reserve, 0px));
  margin: 0 auto;
  width: fit-content;
  transform: translateY(16px);
  /* Over toasten (300) OG innloggingsskjermen (400): en fane som har stått
     åpen på innloggingssiden skal også kunne oppdateres. */
  z-index: 410;
  display: flex;
  align-items: center;
  gap: 14px;
  max-width: min(92vw, 640px);
  padding: 11px 13px 11px 20px;
  border-radius: 999px;
  background: var(--glass-dark);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  backdrop-filter: blur(14px) saturate(1.3);
  border: 1px solid rgba(255, 255, 255, 0.16);
  color: #fff;
  font-size: var(--fs-md);
  font-weight: 600;
  box-shadow: var(--shadow-md);
  opacity: 0;
  transition: opacity 0.25s ease, transform 0.25s ease;
}
/* Med to tekstlinjer (venter på trygg tilstand) blir pillen for høy — myk
   avrunding i stedet, som modalene. */
.update-banner:has(.update-banner-note:not([hidden])) { border-radius: 22px; }
.update-banner.show { opacity: 1; transform: translateY(0); }
/* Står toasten samtidig, løftes banneret over den. Beskjedene er hele setninger
   som brekker over flere linjer på smale skjermer — løftet er avstemt mot
   toastens makshøyde (fire linjer, ≈108 px, se `.toast-msg`). `:has()` i stedet
   for en søsken-selektor: hvem av de to som ble lagt i <body> først avhenger av
   rekkefølgen de dukket opp i. */
body:has(.toast.show) .update-banner.show { transform: translateY(-128px); }
.update-banner-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* Vises kun når en reload IKKE er trygg ennå (usynkede endringer, drag, modal …). */
.update-banner-note { font-size: var(--fs-sm); font-weight: 500; opacity: 0.82; }
.update-banner-btn {
  flex: 0 0 auto;
  appearance: none;
  border: none;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  font-family: inherit;
  font-weight: 700;
  font-size: 16px;
  padding: 7px 14px;
  border-radius: 999px;
  transition: background 0.15s;
}
.update-banner-btn:hover { background: rgba(255, 255, 255, 0.3); }
.update-banner-btn:focus-visible { outline: var(--focus-w) solid var(--focus-on-dark); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .update-banner { transition: none; }
}

/* ---------------- Demonstrasjonen for nye brukere ----------------
   Autoritativt: docs/introduksjon.md.

   Laget ligger over appen og lagringsstatusen (290), men under toasten (300) og
   oppdateringsbanneret (410) — de to skal kunne nå fram også midt i demoen.

   Kortet er en TOOLTIP, ikke en modal. Det er hele poenget: brukeren skal se
   appen i sin helhet mens hen bruker den, så det finnes verken mørklegging,
   uskarphet eller ring rundt kontrollen — bare en pilspiss som peker på den.
   Selve avgrensningen (hva som KAN trykkes på nå) håndheves i JS, ikke av et
   lag som ligger i veien; CSS-en her demper bare det som ikke er i bruk, slik
   at det ser avskrudd ut i tillegg til å være det.

   Velkomsten er unntaket: `.tour.narrated` er midtstilt, med både mørklegging
   og uskarphet på flaten bak. Der er det ingenting å peke på ennå. */
.tour {
  position: fixed;
  inset: 0;
  z-index: 295;
  pointer-events: none;  /* laget selv er aldri i veien — kun kortet tar imot */
}
.tour .tour-card { pointer-events: auto; }
.tour.narrated {
  pointer-events: auto;  /* velkomsten er modal: flaten svelger bomtrykk */
  background: var(--overlay);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

/* Det som ikke er i bruk i dette steget dempes. `.tour-live` står på kontrollen
   steget FAKTISK handler om, og `:not(.tour-live)` er hele forskjellen: en rad
   som er levende (den skal dras) har fortsatt en menyknapp og en avmerkingsboks
   som IKKE er i bruk, og de skal bli stående dempet inni den.
   Blokkeringen ligger i JS (demoGate) — dette er affordansen, ikke vakten. */
body.tour-demo .obj-menu-btn:not(.tour-live),
body.tour-demo .item-check:not(.tour-live),
body.tour-demo .share-badge:not(.tour-live),
body.tour-demo .done-restore:not(.tour-live),
body.tour-demo .done-delete:not(.tour-live),
body.tour-demo .trashcan:not(.tour-live),
body.tour-demo .add-item-btn:not(.tour-live),
body.tour-demo .add-cat-btn:not(.tour-live),
body.tour-demo .cat-add-btn:not(.tour-live),
body.tour-demo #add-card-btn:not(.tour-live),
body.tour-demo .nav-add-uni button:not(.tour-live),
body.tour-demo .corner-btn:not(.tour-live),
body.tour-demo #nav-crumb:not(.tour-live),
body.tour-demo #nav-modal-close:not(.tour-live),
body.tour-demo #trash-close:not(.tour-live),
body.tour-demo #trash-empty:not(.tour-live),
body.tour-demo .trash-row button:not(.tour-live) { opacity: 0.35; }

/* Pilspissen: et kvadrat rotert 45°, lagt inntil kortkanten. Kortet males etter
   den i DOM-en, så den halvdelen som stikker inn under kortet blir borte og
   bare spissen står igjen. Den ligger UTENFOR kortet fordi kortet ruller
   innvendig når plassen er trang (overflow ville klippet en pil inni det). */
.tour-arrow {
  position: fixed;
  width: 14px;
  height: 14px;
  background: var(--surface);
  /* Konturen er det som gjør spissen synlig: uten den forsvinner et hvitt
     kvadrat mot alt som er lyst — den hvite modalen bak, en lys side. Bare de
     to YTRE kantene vises (kortet dekker den halvdelen som peker innover), så
     linjen leses som en spiss, ikke som en firkant. */
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
  transform: rotate(45deg);
}
.tour-card {
  position: fixed;
  /* Bredden må trekke fra den sikre sonen i tillegg til luften: kortet
     plasseres av JS INNENFOR sonen (se placeTour), så et kort som bare tok
     hensyn til viewport-bredden ville stukket ut over motsatt kant. */
  width: min(400px, calc(100vw - 24px - var(--safe-left) - var(--safe-right)));
  /* Høyden settes i JS når hele kortet ikke får plass (lav skjerm, eller for
     lite luft ved siden av målet — se placeTour). Kortet er en flex-kolonne
     nettopp for det tilfellet: det er TEKSTEN (`.tour-body`) som ruller, mens
     framdriftsstolpen og knapperaden blir stående. Ruller hele kortet, kan
     «Kom i gang» ligge under skjermkanten på et kort brukeren tror hen har
     lest ferdig. */
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 18px;
  border-radius: 20px;
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  animation: pop-in 0.18s cubic-bezier(.2, .75, .3, 1);
}
.tour-card:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 3px; }
/* Rulleflaten når kortet er kappet. `min-height: 0` er det som gjør at den
   faktisk krymper: en flex-item nekter ellers å bli mindre enn innholdet sitt,
   og kortet ville vokst ut av maxHeight igjen. */
.tour-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}
/* Er det mer tekst under kanten, tones de nederste linjene ut. Uten den ser et
   kappet kort FERDIG ut — teksten slutter gjerne etter et helt punkt, og en ny
   bruker har ingen grunn til å tro at det finnes mer (mobilens rullefelt er
   usynlig til man drar). Masken ligger på RULLEBOKSEN, ikke på innholdet, så
   avtoningen blir stående ved kanten mens teksten glir forbi under den.
   `.has-more` settes av `markTourOverflow()` i app.js og forsvinner når man er
   nede — da skal siste linje være helt skarp. */
.tour-card.has-more .tour-body {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 34px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 34px), transparent);
}

/* Framdriftsstolpe i stedet for «Steg n av m»: mindre tekst å lese, og like
   presist om hvor langt igjen det er. */
.tour-progress {
  flex: 0 0 auto;           /* krymper ikke når kortet er kappet */
  height: 5px;
  margin: 0 30px 12px 0;
  border-radius: 999px;
  background: var(--wash-2);
  overflow: hidden;
}
.tour-progress-fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--accent);
  transition: width 0.25s ease;
}
.tour-title { margin: 0 0 8px; padding-right: 30px; font-size: var(--fs-lg); font-weight: 700; }
/* Én linje under teksten: det som gjenstår akkurat nå («skriv navnet»), eller
   det ene forbeholdet velkomsten har (demoen rører ikke innholdet ditt). */
.tour-note {
  margin: 10px 0 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink-soft);
}
.tour-text { font-size: var(--fs-md); line-height: 1.45; }
/* Ikoner MIDT i en setning. `.icon` er `display: block` globalt — riktig i
   knapper og rader, men her ville hvert ikon brutt setningen i to. */
.tour-text p .icon { display: inline-block; vertical-align: -0.15em; }
.tour-text p { margin: 0 0 8px; }
.tour-text p:last-child { margin-bottom: 0; }
/* Punktlisten i velkomsten: ikon + tekst på samme linje, uten kulepunkt. */
.tour-list { margin: 8px 0; padding: 0; list-style: none; }
.tour-list li {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 0 0 6px;
}
.tour-list li:last-child { margin-bottom: 0; }
.tour-list .icon { flex: 0 0 auto; margin-top: 2px; }
/* .hint-chip er laget for fargede flater (lys, gjennomsiktig hvit); på det hvite
   kortet trengs den mørke varianten — samme unntak som i nav-modalen. */
.tour-text .hint-chip { background: var(--wash); }
.tour-actions {
  flex: 0 0 auto;           /* blir stående når teksten over ruller */
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 16px;
}
/* Tom knapperad tar ikke plass: de fleste stegene har verken «Tilbake» eller
   en knapp som driver dem videre — det er handlingen i appen som gjør det. */
.tour-actions:empty, .tour-actions.is-empty { display: none; }
.tour-nav { display: flex; align-items: center; gap: 8px; }
/* To klasser, ikke én: `.icon-btn:not(.pass-toggle)` setter `position:
   relative` med samme spesifisitet som en enkelt klasse ville hatt, og vant —
   så ✕-en havnet i flyten nederst i kortet i stedet for i hjørnet. */
.tour-card .tour-close { position: absolute; top: 10px; right: 10px; }
@media (prefers-reduced-motion: reduce) {
  .tour-progress-fill { transition: none; }
}

/* ---------------- Merkevare-logo (innloggingsskjerm) ---------------- */
/* (app-innhold skjules av `body.no-auth`-regelen i FASE 2-seksjonen under.) */
.lock-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 34px;
  font-weight: 700;
  color: #f4f6f7;
}
.lock-brand .brand-mark {
  display: inline-grid;
  place-items: center;
  width: 52px;
  height: 52px;
}
/* Logo: tre stablede lister (samme motiv som favicon.svg). Svarte streker;
   kortene fylles med palettfarge 3/2/1 (bakerst→fremst), slik at det fremste
   kortet dekker strekene på kortene bak → stablet «papirbunke»-effekt. */
.lock-brand .brand-logo {
  width: 100%;
  height: 100%;
}

/* ---------------- Smalt: stablet toppmeny, én kolonne, modal-popovere ----------------
   Samme toppmeny som desktop, men stablet i to rader; board-et endres til én
   kolonne, og popover-skallet blir en sentrert modal. De TO grensene er ulike
   og skal være det — se under. */

/* TOPPMENYEN STABLES FØR board-et gir opp den andre kolonnen (620 vs. 560).
   De to grensene svarer på hver sin ting, og den ene fulgte den andre bare så
   lenge tallene tilfeldigvis stemte:

     • Board-ets grense (560) speiler hva `relayoutBoard` regner ut i JS. Den
       må IKKE flyttes uten at utregningen flyttes med — flagget her er kun
       CSS-sidens kopi av det samme svaret.
     • Toppmenyens grense er ren plass på ÉN linje, og den avhenger av hvor
       bred hjørnegruppen er. Gruppen har seks knapper (`docs/menus.md`), og
       med den reserven (`--corner-btns-w`) tar breadcrumben, listefunksjonene
       og gruppen mer enn 560 px til sammen: breadcrumben krympet til null og
       listefunksjonene la seg OPPÅ den. En knapp til flytter grensen igjen —
       tallet er en konsekvens av gruppens bredde, ikke et designvalg.

   Under grensen legges listefunksjonene på raden under. Panelet blir én
   kontrollhøyde høyere — det er byttet mot at navnene ikke kappes bort.
   Telefonen i LANDSKAP er bredere enn dette og beholder derfor
   én-linjes-panelet.
   Klaringen holdes av BEGGE radene: er hjørnegruppen også to rader (under
   560 px), ligger den ene gruppe-raden ved siden av breadcrumben og den andre
   ved siden av listefunksjonene — og da slipper panelet å skyves ned for
   gruppens andre rad (se `--corner-btns-overflow`, syncTopChrome). */
@media (max-width: 620px) {
  /* Panelet er alltid en kolonne (fanene øverst) — her stables i tillegg den
     AKTIVE fanens egen rad, så breadcrumb-navnene ikke kappes bort. */
  .topbar-row { flex-direction: column; align-items: stretch; }
  .breadcrumb { padding-right: var(--corner-btns-w); }
  .toolbar { margin-right: var(--corner-btns-w); flex-wrap: wrap; }

  /* Litt tettere breadcrumb så navnene får plass ved siden av hjørnegruppen. */
  .crumb-btn { font-size: var(--fs-md); padding: 0 10px; gap: 6px; }
}

@media (max-width: 560px) {
  /* Kolonneantallet regnes ut i JS (`relayoutBoard`) og er uansett 1 så smalt —
     her settes bare CSS-sidens flagg for den samme modusen. */
  .board { --board-single-column: 1; }

  /* Nav-modalens overskrift er lang (to nivåer med hvert sitt ikon) — mindre
     skrift så den får plass på én linje ved siden av lukkeknappen. */
  .nav-modal .modal-head h2 { font-size: var(--fs-md); gap: 6px; }

  /* Ansvarlig-velgeren/tids-popoveren: sentrert modal med intern scroll i
     stedet for en popover ved siden av knappen — mobilskjermen har ikke
     plass til det. */
  .switcher-overlay {
    display: grid;
    place-items: center;
    padding: calc(20px + var(--safe-top)) calc(20px + var(--safe-right))
             calc(20px + var(--safe-bottom)) calc(20px + var(--safe-left));
    background: var(--overlay);
  }
  .switcher-panel {
    position: static;
    width: 100%;
    max-width: 420px;
    max-height: min(70vh, 480px, 100%);   /* som .modal: 100% er den sikre sonen */
  }
}

/* ============================================================
   FASE 2 — brukerkontoer og deling
   Auth-skjerm (e-post/passord), del-modal, plasserings-modal,
   invitasjons-innboks, delt/låst-merker. Gjenbruker tokens og
   flate-mønstre fra designsystemet over.
   ============================================================ */

/* Skjul app-innhold før innlogging. Hele
   toppkontrollgruppen (kalender, søk, drakt, konto) går med — innloggingsskjermens egen
   draktknapp (#auth-theme-toggle-btn) dekker draktvalget der.

   REGELEN GJELDER FRA FØRSTE MALING: klassen står på `<body>` i index.html,
   ikke bare fra `initAccounts()`. Stilarket lastes i <head> og er dermed på
   plass før noe males, mens app.js er over 1 MB — settes klassen først derfra,
   rekker toppmenyen og hjørnekontrollene å synes bak innloggingsmuren så lenge
   app.js er underveis. `cloudStart()` er det ENESTE som fjerner den. */
body.no-auth .topbar,
body.no-auth .app-main,
body.no-auth .corner-controls { display: none; }

/* ---------------- Auth-skjerm ---------------- */
.auth-screen {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: flex;
  padding: calc(24px + var(--safe-top)) calc(24px + var(--safe-right))
           calc(24px + var(--safe-bottom)) calc(24px + var(--safe-left));
  overflow-y: auto;
  background: linear-gradient(180deg, var(--bg-grad-a), var(--bg-grad-b));
}
.auth-screen[hidden] { display: none; }

.auth-box {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 18px;
  width: 100%;
  max-width: 440px;
  /* Sentreringen ligger HER, ikke som `align-items: center` på skjermen: en
     flex-item som er høyere enn containeren blir da klippet på TOPPEN, og
     overflow mot start-kanten kan ikke rulles fram — logoen og overskriften
     ville blitt liggende under statusfeltet på registreringsskjemaet når
     tastaturet krymper viewportet. Auto-marginer sentrerer likt, men gir aldri
     fra seg mer plass enn det som finnes. */
  margin: auto;
}
.auth-box .lock-brand { justify-content: center; }

.auth-form, .auth-sent {
  display: flex;
  flex-direction: column;
  gap: 13px;
  background: var(--surface);
  border-radius: 20px;
  padding: 22px;
  box-shadow: var(--shadow-lg);
}
.auth-sent[hidden] { display: none; }
.auth-title {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  margin: 0 0 2px;
  font-size: 26px;
  font-weight: 700;
  color: var(--ink);
  text-align: center;
}
.auth-title .icon { color: var(--primary); }
.auth-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink-soft);
}
/* Fornavn + etternavn side om side (kun ved registrering). */
.auth-name-row { display: flex; gap: 10px; }
.auth-name-row .auth-field { flex: 1 1 0; min-width: 0; }
/* Felles tekstfelt-klasse (auth-input + inviter-input): solid kant, myk
   bakgrunn, grønn fokus-ring. Nye felt trenger bare `.field`. */
.field {
  font-family: inherit;
  font-size: var(--fs-base);
  font-weight: 500;
  color: var(--ink);
  padding: 12px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  transition: border-color 0.15s, box-shadow 0.15s;
}
/* Feltet fikk før KUN en grønn kantfarge + en 14 %-transparent glød; på en lys
   flate var det knapt synlig, og fokus skal aldri være noe man må lete etter.
   Nå samme mørke ring som resten av appen, med den grønne kanten beholdt som
   sekundært signal. */
.field:focus-visible {
  outline: var(--focus-w) solid var(--focus);
  outline-offset: 2px;
  border-color: var(--primary);
}
/* Passordfelt med «vis passordet»-knapp: øyet ligger INNI feltet (høyre kant),
   feltet får plass til det. Samme .icon-btn som ellers, litt dempet i hvile. */
.pass-wrap {
  position: relative;
  display: flex;
  flex: 1;
  min-width: 0;
}
.pass-wrap .field {
  flex: 1;
  min-width: 0;
  padding-right: 46px;
}
.pass-toggle {
  position: absolute;
  top: 50%;
  right: 4px;
  transform: translateY(-50%);
  width: 34px;
  height: 34px;
  opacity: 0.65;
}
.pass-toggle:hover, .pass-toggle:focus-visible { opacity: 1; background: transparent; }
.pass-toggle .icon { width: 22px; height: 22px; }
.auth-msg {
  margin: 0;
  min-height: 22px;
  font-size: var(--fs-sm);
  font-weight: 600;
  text-align: center;
  color: var(--danger-ink);
}
.auth-msg.ok { color: var(--primary-ink); }
.auth-msg:empty { min-height: 0; }

.auth-links {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  margin-top: 2px;
}
.auth-link {
  appearance: none;
  border: none;
  background: none;
  cursor: pointer;
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--primary-ink);
  padding: 2px 4px;
}
.auth-link:hover { text-decoration: underline; }

.auth-sent { align-items: center; text-align: center; gap: 14px; }
.auth-sent-icon { font-size: 55px; color: var(--primary); }
.auth-sent-icon .icon { margin: 0 auto; }
.auth-sent-msg { margin: 0; font-weight: 600; font-size: var(--fs-base); color: var(--ink); line-height: 1.5; }
.auth-sent-msg strong { color: var(--primary-ink); }

/* ---------------- Konto-modal: profil + badge ---------------- */
/* «Bilde»-seksjonen i kontoopplysnings-skuffen: samme etikett-over-innhold som
   navn/e-post/passord (`.account-form`), med avatar + identitet på raden under. */
.account-photo-row {
  display: flex;
  align-items: center;
  gap: 14px;   /* kamera-merket henger 2px utenfor sirkelen — hold det klar av teksten */
  padding: 2px 0;
}
.account-ident { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.account-photo-actions { display: flex; flex-wrap: wrap; gap: 6px; }
/* Endre navn / e-post: etikett over felt + Lagre-knapp på samme rad. */
.account-edit {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.account-form {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.account-form-label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink-soft);
}
.account-form-row { display: flex; gap: 8px; }
.account-form-row .field { flex: 1; min-width: 0; }
.account-msg {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--primary-ink);
}
.account-msg.error { color: var(--danger-ink); }
/* Avatar-sirkler (konto + delings-medlemmer): felles form (rund, sentrert hvit
   initial på gradient); størrelse/farge varierer per bruk. */
.account-avatar, .member-avatar {
  flex: 0 0 auto;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-weight: 700;
  color: #fff;
  text-transform: uppercase;
  /* Hvite initialer → blågrønn flate. Grønnfargen er ikonflate og bærer ikke
     tekst; blågrønt er dessuten kontoikonets egen farge. */
  background: var(--grad-accent);
}
/* Profilbilde: fyller sirkelen i stedet for initialene (samme form overalt). */
.account-avatar img, .member-avatar img, .resp-avatar img {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}
/* Konto-avataren er SELV knappen som endrer bildet (kamera-merke nederst). */
.account-avatar {
  position: relative;
  width: 56px;
  height: 56px;
  font-size: var(--fs-lg);
  appearance: none;
  border: none;
  padding: 0;
  cursor: pointer;
  transition: filter 0.15s, transform 0.1s;
}
.account-avatar:hover { filter: brightness(1.09); }
.account-avatar:active { transform: scale(0.96); }
.account-avatar:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }
.avatar-cam {
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  display: grid;
  place-items: center;
}
.avatar-cam .icon { width: 16px; height: 16px; }
.account-email { font-weight: 600; font-size: var(--fs-md); color: var(--ink); word-break: break-all; }

.menu-badge {
  position: absolute;
  top: -6px; right: -6px;
  min-width: 22px; height: 22px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--danger);
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  line-height: 22px;
  text-align: center;
  box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
.menu-badge[hidden] { display: none; }

/* ---------------- Meny-innstilling (e-postvarsel) ---------------- */
.menu-setting {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  margin-top: 8px;
  border-radius: var(--radius-sm);
  background: var(--primary-soft);
}
.menu-setting[hidden] { display: none; }
.menu-setting-label {
  flex: 1; min-width: 0;
  display: flex; align-items: center; gap: 9px;
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink);
}
.menu-setting-label .icon { width: 22px; height: 22px; flex: 0 0 auto; color: var(--ink-soft); }
.toggle-switch {
  touch-action: pan-y;       /* sidelengs er dragets, loddrett er scrollens */
  flex: 0 0 auto;
  width: 50px; height: 28px;
  border: none; border-radius: 999px;
  background: var(--track);
  padding: 3px;
  cursor: pointer;
  transition: background var(--switch-motion);
}
.toggle-switch .toggle-knob {
  display: block;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,0.28);
  transition: transform var(--switch-motion);
}
.toggle-switch[aria-checked="true"] { background: var(--accent); }
/* Knottens plassering er en BRØK av vandringen, ikke to faste stillinger: da
   kan den samme egenskapen bære både hvilestillingen (0 eller 1, fra
   `aria-checked`) og et pågående drag (`--knob-drag`, hva som helst imellom).
   Vandringen er sporets bredde minus knotten og polstringen: 50 − 22 − 2×3. */
.toggle-switch .toggle-knob { transform: translateX(calc(var(--knob-drag, var(--knob-p, 0)) * 22px)); }
.toggle-switch[aria-checked="true"] { --knob-p: 1; }
.toggle-switch.is-tog-drag .toggle-knob { transition: none; }
.toggle-switch:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }

/* ---------------- Språkvelger ----------------
   Samme kontroll to steder: i konto-modalen (en `.menu-setting`-rad som de
   andre innstillingene) og nederst på innloggingsskjermen, som er det eneste
   stedet valget kan tas før man har en konto. En <select> og ikke to knapper:
   den er tastatur- og skjermlestertilgjengelig uten en linje ekstra kode, og
   den vokser når det kommer et tredje språk. */
/* Ikonet settes av app.js (ICONS.language), så det må ligge i en beholder som
   allerede finnes i markupen. `display:flex` fjerner baseline-gapet en inline
   <span> ellers ville lagt under svg-en. */
.menu-setting-icon { display: flex; flex: 0 0 auto; }
.lang-select {
  flex: 0 0 auto;
  width: auto;
  padding: 8px 10px;
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
}
/* Raden bærer språkparet (etikett + velger) og draktknappen på
   innloggingsskjermen. Den brytes heller enn å presse dem sammen — men aldri
   INNE i språkparet: en etikett som blir stående igjen på linja over
   velgeren sin hører ikke sammen med noe. Derfor er paret sin egen flex-boks
   (`.auth-lang-pair`); draktknappen trenger ingen, siden ikonet ALENE er
   navnet (samme `.corner-btn`-flate som i toppkontrollgruppen). */
.auth-lang {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin-top: 4px;
}
.auth-lang-pair { display: inline-flex; align-items: center; gap: 10px; }
/* Etiketten ligger UTENFOR det hvite kortet, rett på skiferflaten — samme sted
   som ordmerket. `--ink-soft` er en tekstfarge for hvit bakgrunn og gir 1,4:1
   her; hvit gir 4,6:1 og klarer AA for vanlig tekst (docs/tilgjengelighet.md). */
.auth-lang-label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: #ffffff;
}

/* ---------------- Bilderedigering (profilbilde) ----------------
   Scenen er nøyaktig det kvadratiske utsnittet som lagres; sirkelmasken viser
   hva appen faktisk tegner. Alt utenfor sirkelen dempes (men lagres), så det
   er tydelig både HVA som blir bildet og HVORDAN det vil se ut. */
.avatar-modal { width: min(420px, 100%); }
.avatar-body { display: flex; flex-direction: column; gap: 14px; }
.avatar-hint {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--ink-soft);
  text-align: center;
}
.avatar-stage {
  position: relative;
  width: 100%;
  max-width: 320px;
  aspect-ratio: 1 / 1;
  margin: 0 auto;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: #2d2646;
  box-shadow: var(--shadow-sm);
  cursor: grab;
  touch-action: none;   /* dra/knip er våre gester, ikke sidens scroll */
}
.avatar-stage.is-panning { cursor: grabbing; }
.avatar-canvas { display: block; width: 100%; height: 100%; }
.avatar-mask {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  box-shadow: 0 0 0 9999px rgba(45, 38, 70, 0.55), inset 0 0 0 2px rgba(255, 255, 255, 0.85);
}
.avatar-controls { display: flex; flex-direction: column; gap: 10px; }
.avatar-slider { display: flex; align-items: center; gap: 10px; }
.avatar-slider-label {
  flex: 0 0 auto;
  width: 84px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink-soft);
}
/* Glidebrytere: appens grønne håndtak på et nøytralt spor (ingen native look). */
.avatar-slider input[type="range"] {
  flex: 1;
  min-width: 0;
  appearance: none;
  -webkit-appearance: none;
  height: 26px;
  background: transparent;
  cursor: pointer;
}
.avatar-slider input[type="range"]::-webkit-slider-runnable-track {
  height: 6px; border-radius: 999px; background: var(--line);
}
.avatar-slider input[type="range"]::-moz-range-track {
  height: 6px; border-radius: 999px; background: var(--line);
}
.avatar-slider input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 22px; height: 22px;
  margin-top: -8px;
  border: none; border-radius: 50%;
  /* Håndtaket måles mot det lyse sporet (--line): lys grønn ga 2.17:1, blågrønn 4.37:1. */
  background: var(--grad-accent);
  box-shadow: var(--shadow-sm);
}
.avatar-slider input[type="range"]::-moz-range-thumb {
  width: 22px; height: 22px;
  border: none; border-radius: 50%;
  background: var(--accent);
  box-shadow: var(--shadow-sm);
}
.avatar-slider input[type="range"]:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }
/* «Roter 90°» gjenbruker den sirkulære pila (ICONS.restoreArrow), speilvendt så
   den peker MED klokka — samme vei som knappen faktisk roterer. */
.avatar-rot90 .icon { transform: scaleX(-1); }
.avatar-foot { justify-content: flex-end; }
/* Lave vinduer (mobil i landskap o.l.): mindre scene så alt får plass uten scroll. */
@media (max-height: 720px) { .avatar-stage { max-width: 236px; } }

/* ---------------- Invitasjons-innboks ---------------- */
.menu-invites[hidden] { display: none; }
.invite-list { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }
.invite-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 11px;
  border-radius: var(--radius-sm);
  background: var(--primary-soft);
}
.invite-info { flex: 1 1 140px; min-width: 0; }
.invite-name { font-weight: 700; font-size: var(--fs-md); color: var(--ink); }
.invite-from { display: block; font-size: 16px; color: var(--ink-soft); font-weight: 500; }
.invite-type-tag {
  font-size: 14px; font-weight: 700; text-transform: uppercase;
  color: var(--primary-ink); letter-spacing: 0.03em;
}
.invite-actions { display: flex; gap: 6px; }

/* ---------------- Enheter og økter (konto-modalen) ----------------
   To lister med samme form: en rad per nettleserkontekst, med navnet øverst,
   verten under og «sist sett» sist. Formspråket er innboksens (`.invite-row`)
   — en myk flate, tekst til venstre, handlingen til høyre — fordi det er den
   samme slags rad: noe som gjelder kontoen, med én knapp ved siden av.
   Se docs/accounts.md. */
.device-group { display: flex; flex-direction: column; gap: 6px; }
.device-lead { margin: 0; font-size: var(--fs-xs); color: var(--ink-soft); font-weight: 500; }
.device-list { list-style: none; margin: 2px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.device-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 11px;
  border-radius: var(--radius-sm);
  background: var(--primary-soft);
}
/* «Denne enheten» får den samme aksentflaten som andre «du er her»-markører,
   så raden kjennes igjen før teksten er lest. */
.device-row.is-current { background: var(--primary-soft-hover); }
.device-text { flex: 1 1 160px; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; }
.device-name { font-weight: 700; font-size: var(--fs-md); color: var(--ink); }
/* Merkelappen står ved navnet, ikke som en egen rad: den er en egenskap ved
   enheten, ikke en opplysning til. */
.device-here {
  font-size: 14px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.03em; color: var(--primary-ink);
}
.device-origin { flex: 1 0 100%; font-size: 16px; color: var(--ink-soft); font-weight: 500; word-break: break-word; }
.device-seen { flex: 1 0 100%; font-size: var(--fs-xs); color: var(--ink-soft); font-weight: 500; }
.device-action { flex: 0 0 auto; }
.device-empty { font-size: var(--fs-sm); color: var(--ink-soft); font-weight: 500; }
.device-others { align-self: flex-start; margin-top: 2px; }
.device-others[hidden] { display: none; }
.device-error { margin: 0; font-size: var(--fs-xs); color: var(--danger-ink); font-weight: 600; }
.device-error[hidden] { display: none; }
/* Inngangen fra varselpanelet: «Vis enheter» under linjen som teller dem.
   `.notif-channel` er ikke en flex-beholder, så knappen gjøres til en blokk med
   automatisk høyremarg — ellers ville den strukket seg over hele bredden. */
.notif-channel-devices { display: block; margin: 8px auto 0 0; }

/* ---------------- Del-modal ---------------- */
/* Tilbakeknappen (vises når del-modalen ble åpnet fra område-/mappe-
   modalen) står før tittelen; tittelen tar resten av bredden. Overskriften
   er vanlig tekstflyt (ikke flex): nivå-ikonet ligger INLINE i direkte
   tilknytning til navnet (.share-title-obj), og bryter sammen med det. */
.share-back { flex: 0 0 auto; }
.share-modal .modal-head h2 {
  flex: 1 1 auto;
  display: block;
}
.share-title-obj { display: inline; }
.share-title-obj .icon {
  display: inline-block;
  vertical-align: -0.13em;
  margin-right: 6px;
}
/* MODALEN ER FIRE SEKSJONER, IKKE ÉN RAMSE: slippe noen inn, hvem som er
   inne, låsen, og de to endelige knappene. De ble tidligere lagt rett etter
   hverandre med det samme lille gapet (10 px) som skiller to felt INNE i en
   seksjon, og da var det ingenting som sa hvor den ene sluttet og den neste
   begynte — verst på mobil, der alt står under hverandre og skjermen er full.

   Grensen er ÉN luft-verdi (`--share-sec-gap`) på hver side av en hårfin
   linje, den samme linjen som modalhodet bruker. Luften INNE i en seksjon er
   det halve, så nivåene leses på avstanden alene og streken bare bekrefter
   dem. På mobil er verdien større: der er seksjonene høye, og luften er det
   eneste som holder dem fra hverandre når alt ligger i én kolonne.

   Første SYNLIGE seksjon har ingen linje over seg — hodets egen ligger der
   allerede. Invitasjonsseksjonen er den eneste som kan skjules i sin helhet
   (den som ikke kan invitere, har ingenting der), og den er alltid først, så
   ett unntak for `[hidden] + *` dekker det. En seksjon uten innhold i det hele
   tatt (ingen «Forlat», ingen «Slett») faller ut på samme vis. */
.share-body {
  --share-sec-gap: 18px;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.share-sec {
  display: flex;
  flex-direction: column;
  gap: calc(var(--share-sec-gap) / 2);
  margin-top: var(--share-sec-gap);
  padding-top: var(--share-sec-gap);
  border-top: 1px solid var(--line);
}
.share-body > .share-sec:first-child,
.share-body > [hidden] + .share-sec {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}
.share-actions:empty { display: none; }
.share-invite-form { display: flex; gap: 8px; }
.share-invite-form .field { flex: 1; min-width: 0; }
/* Invitasjonspolicy-avmerking (under e-postfeltet): la andre invitere folk.
   Interaktiv kun for autoriserte; ellers lesbar status via .share-policy-note.
   Ingen egen marg: seksjonen har ÉN luft-verdi, og en marg oppå den ville lagt
   et fjerde tall inn i en rytme som er bygget av to. */
.share-policy-row { margin: 0; }
.share-policy-label { display: flex; align-items: center; gap: 8px; cursor: pointer;
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
.share-policy-label input[type="checkbox"] { flex: none; }
.share-policy-note { margin: 4px 0 0; font-size: var(--fs-xs); color: var(--ink-soft); font-weight: 500; }
.share-noinvite { margin: 8px 0 2px; }
/* Rollevelgeren ved siden av e-postfeltet (medlem vs. medeier). Vises kun for
   den som faktisk kan invitere til eierskap. */
.share-role-select { flex: none; width: auto; padding-right: 26px; }
/* Medlemslisten har sin EGEN inndeling inni seksjonen (Eier, Medlemmer,
   Ventende invitasjoner), og radene bærer allerede hver sin hårstrek. Den
   arver derfor ikke seksjonsgapet — det ville lagt luft mellom radene og
   løsnet streken fra raden under den. I stedet får hver bolk-overskrift som
   har noe over seg sin egen pause: mindre enn mellom to seksjoner, mer enn
   mellom to rader, så nivåene står i rekkefølge. */
.share-members { display: flex; flex-direction: column; gap: 0; }
.share-members > * + .share-section-title { margin-top: calc(var(--share-sec-gap) / 2); }
/* Forklaringen under navnet når en bruker ikke kan fjernes her (arvet fra
   området) eller er siste eier. */
.member-hint { display: block; font-size: var(--fs-xs); color: var(--ink-soft); font-weight: 500; font-style: italic; }
/* «Forlat» og «Slett for alle» står sammen nederst: begge kan være aktuelle
   samtidig (en medeier kan både forlate og slette). */
.share-actions {
  display: flex;
  /* Seksjonsskallet stabler; de to knappene står ved SIDEN av hverandre og
     brekker bare når linjen ikke rekker. */
  flex-direction: row;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.share-leave .icon { vertical-align: -0.15em; margin-right: 2px; }
/* `line-height: 1` er ikke pynt: overskriften er det FØRSTE blekket under en
   seksjonslinje, og med vanlig linjehøyde la halve linjeavstanden seg oppå
   seksjonens polstring. Luften over linja ble da 18 px og under 25 (MÅLT), på
   en linje som skal ha like mye på hver side. Boksen klemmes derfor rundt
   teksten, og polstringen er den eneste luften som teller. */
.share-section-title { font-size: var(--fs-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-soft); margin: 0 0 4px; line-height: 1; }
/* Raden har navn + inntil to rollehandlinger. Blir det for trangt (mobil), skal
   knappene falle ned på egen linje — ikke presse navnet ned til én bokstav per
   linje. Derfor: navnet får lov å ta plassen den trenger (flex-basis), knappene
   krymper aldri, og raden brytes. */
.member-row {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap;
  /* Ingen sidepolstring: raden har ingen egen flate å polstre, og de 4 px den
     hadde skjøv avataren inn fra bolk-overskriften og knappene inn fra
     «Inviter» rett over. Modalens egen polstring er venstrekanten for alt i
     kroppen. */
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.member-row > button { flex: none; }
.member-row > button:nth-of-type(1) { margin-left: auto; }
/* Siste rad i en bolk har ingen strek å polstre ned mot, og polstringen ville
   i stedet lagt seg oppå seksjonens egen luft (10 + 18 = 28 px mot 18 over
   linja). Den faller derfor bort, så seksjonsgapet er hele avstanden. */
.member-row:last-child { border-bottom: none; padding-bottom: 0; }
/* Medlems-avatar: felles form fra .account-avatar, .member-avatar over; her kun
   størrelse + grå standard-gradient (eier får den grønne igjen). */
.member-avatar {
  width: 39px; height: 39px; flex: none;
  font-size: var(--fs-sm);
  background: linear-gradient(180deg, #8496a6, #5f6f7d);
}
.member-avatar.owner { background: var(--grad-accent); }
.member-info { flex: 1 1 9em; min-width: 0; }
.member-name { font-weight: 600; font-size: var(--fs-md); color: var(--ink); word-break: break-word; }
/* Tett linjehøyde: rollen er den SISTE tekstlinjen i medlemsbolken, og med
   vanlig linjeavstand la halve avstanden seg som usynlig luft oppå
   seksjonsgapet under den. Navnet og rollen er dessuten ett par, ikke to
   avsnitt. */
.member-role { display: block; font-size: var(--fs-xs); color: var(--ink-soft); font-weight: 500; line-height: 1.25; }
.member-pending .member-name { color: var(--ink-soft); font-style: italic; }
.share-msg { margin: 0; font-size: var(--fs-sm); font-weight: 600; min-height: 20px; color: var(--danger-ink); }
.share-msg.ok { color: var(--primary-ink); }
.share-lock-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px; border-radius: var(--radius-sm); background: var(--surface-2);
}
.share-lock-title { display: flex; align-items: center; gap: 6px; }
.share-lock-icon { display: inline-flex; font-size: 18px; color: var(--ink); }
.share-lock-label { font-weight: 600; font-size: var(--fs-md); color: var(--ink); }
.share-lock-hint { display: block; font-size: var(--fs-xs); font-weight: 500; color: var(--ink-soft); margin-top: 2px; }
/* Arvet lås (objektet er låst fordi en forelder er låst): tydeliggjør at dette
   er en informasjons-/unntakstilstand, ikke en vanlig av/på-lås. */
.share-lock-row.is-inherited { background: var(--surface-alt); }
.share-lock-anc-icon { display: inline-flex; vertical-align: -3px; font-size: 15px; color: var(--ink); }
.share-lock-anc-icon svg { width: 15px; height: 15px; }
/* Arvet medlem (tilgang via området): svakere, og uten «Fjern» her. */
.member-row.is-inherited { opacity: 0.85; }
.member-row.is-inherited .member-avatar { background: linear-gradient(180deg, #b0bcc7, #8a97a3); }

/* Telefon i portrett (samme grense som board-ets én-kolonne-grense). To ting
   må gi etter når bredden forsvinner:

   1. Seksjonene får MER luft, ikke mindre. Alt ligger i én kolonne her, og en
      skjerm full av kontroller uten pauser er nøyaktig det som leste som
      «crowded». Luften er det eneste som skiller dem når bredden ikke gjør det.
   2. Invitasjonsraden brekker. Tre felt på én linje ga 130 px til e-postfeltet
      og 110 til rollevelgeren — «E-post å» og «Som m» (MÅLT på 390 px). Feltet
      tar derfor hele linjen, og rollevelgeren deler den neste med knappen: det
      er den ene raden der man skriver, og den skal kunne leses mens man gjør
      det. */
@media (max-width: 560px) {
  .share-body { --share-sec-gap: 22px; }
  .share-invite-form { flex-wrap: wrap; }
  .share-invite-form > .field:not(.share-role-select) { flex: 1 0 100%; }
  .share-role-select { flex: 1 1 auto; width: auto; min-width: 0; }
}

/* ---------------- Plasserings-modal ---------------- */
#place-body { display: flex; flex-direction: column; gap: 8px; }
.place-hint { margin: 0 0 4px; font-size: var(--fs-sm); color: var(--ink-soft); font-weight: 500; }
.place-option {
  appearance: none; cursor: pointer; text-align: left;
  font-family: inherit; font-size: var(--fs-base); font-weight: 600; color: var(--ink);
  padding: 14px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  transition: border-color 0.15s, background 0.15s;
}
.place-option:hover { border-color: var(--primary); background: var(--primary-soft); }

/* ---------------- Søkemodal ----------------
   Feltet står i ro og RESULTATLISTEN ruller: skriver man videre etter å ha
   rullet nedover, skal søkefeltet fortsatt være der. `.modal-body`s egen
   rulling slås derfor av her, og flyttes inn på lista.
   Panelet har en minstehøyde så det ikke hopper i størrelse for hvert
   tastetrykk mens treffene kommer og går. */
.search-modal { min-height: min(340px, 100%); }
.search-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.search-note { margin: 0; font-size: var(--fs-sm); color: var(--ink-soft); font-weight: 500; }
.search-results {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* En tom liste skal ikke legge igjen et gap over tom-tilstanden. */
.search-results:empty { display: none; }
.search-result {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: var(--list-row-pad-y) var(--list-row-pad-x);
  border: 1.5px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.search-result:hover { background: var(--wash); }
/* Den aktive raden bæres av TRE signaler, ikke bare farge: kant, flate og en
   pilspiss i enden (docs/tilgjengelighet.md — farge er aldri alene). */
.search-result.is-active {
  border-color: var(--primary);
  background: var(--primary-soft);
}
.search-result-icon { flex: 0 0 auto; display: inline-flex; font-size: var(--fs-lg); line-height: 1; }
.search-result-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.search-result-name {
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--ink);
  overflow-wrap: anywhere;
}
/* Typen i klartekst + kontekststien — dempet, så navnet dominerer raden. */
.search-result-meta {
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}
.search-result-cue {
  flex: 0 0 auto;
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--ink-soft);
  visibility: hidden;
}
.search-result.is-active .search-result-cue { visibility: visible; }

/* ---------------- «Kommende hendelser» ----------------
   Samme modalskall som søket, med den samme delingen: hodet står i ro og
   INNHOLDET ruller. To seksjoner (frister, starter), hver med opptil tre
   grupper — overskrift med statusikon, og radene under.

   ARBEIDSDELINGEN MELLOM IKONENE: gruppens overskrift bærer STATUS (farget
   plate), raden bærer OBJEKTTYPEN (liste/kategori/listepunkt, uten flate).
   Fargen er dermed aldri gjentatt nedover en hel gruppe, og den er aldri
   eneste bærer: overskriften står i klartekst, og radens navn sier typen
   (docs/tilgjengelighet.md).

   PINNINGEN FØLGER PLATEN, ikke modalen. Gruppens statusikon står på en
   kontraktsgradient som er den samme i begge drakter, så det pinner
   `--icon-ink`/`--icon-paper` for seg selv, akkurat som `.btn-solid` gjør.
   Typeikonet i raden har ingen plate — det står rett på modalflaten, og den
   SNUR med drakten, så streken må snu med den. Et av typeikonene (kategori) er
   bare streker, uten «papir» å bli sett på: pinnet mørk ble det nesten
   usynlig på en mørk rad. */
/* TIDSHORISONTEN står fast under tittelen: den er en innstilling for listen,
   ikke en del av den, og skal være der også når man har rullet langt ned.
   Panelet ligger derfor UTENFOR `.events-body` (som er den eneste flaten som
   ruller) og bærer den samme skillelinjen som modalhodet. */
.events-horizon-panel {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
}
.events-horizon-title {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--ink);
}
/* Bryteren med tre posisjoner ER appens segmenterte bryter (`.seg`, se
   «SEGMENTERT BRYTER» lenger ned): ett spor, tre like brede segmenter, og ÉN
   grønn flate som glir mellom dem. Formen, fargen og dra-gesten kommer derfra
   og står ikke her — en bryter med sin egen markeringsfarge og uten gesten
   leste som den samme kontrollen i ustand.

   Det eneste bruksstedet legger til er bredden: `.seg` er `inline-grid` og
   sentrerer seg selv, mens denne skal fylle panelet sitt som før — en sentrert
   pille under en venstrestilt overskrift står ikke på noen linje. Panelet står
   i selektoren fordi `.seg` kommer SENERE i fila og ellers vinner på likt. */
.events-horizon-panel .events-horizon { align-self: stretch; }
/* … og HVORDAN etiketten gir etter når sporet krymper. Segmentene holder seg
   like brede uansett (`min-width: 0` på `.seg-btn`), men da må teksten vike
   for noe. Her er etiketten ren tekst i en modal med plass NEDOVER, så den
   BREKKER i stedet for å bli kappet — «1 måned» over to linjer er lesbart,
   «1 må…» er det ikke. Den glidende flaten er `top`/`bottom`-forankret og
   strekker seg med høyden, så markeringen følger med.

   Polstringen er knappere enn hovedbryterens 14 px, og det er regnet, ikke
   smak: den lengste etiketten er «1 måned» på 65 px (engelsk «1 month», 63).
   På 320 px — den smaleste telefonen som fortsatt er i bruk — er sporet 78 px,
   og 6 px på hver side lar de 65 stå på ÉN linje. Under det brekker den, som
   den gamle bryteren gjorde allerede fra 320 (den hadde 10 px og bare 55 px
   igjen til teksten). */
.events-horizon-panel .events-horizon .seg-btn {
  white-space: normal;
  padding-inline: 6px;
}

/* Luften bærer inndelingen. Gapet er det samme i begge ledd (30 px), så
   avstanden mellom to SEKSJONER er den samme som mellom to grupper og mellom
   en seksjonsoverskrift og gruppene under den — mens luften inne i en gruppe
   (8 px mellom radene) er en helt annen størrelsesorden. Da leses grupperingen
   uten en eneste strek; en skillelinje i tillegg ble bare støy. */
/* ---------------- Idémodalen (docs/ideer.md) ----------------
   Kroppen er ETT kort uten hode, så radene, kategoriene, skillelinjene og
   dra-og-slipp-motoren er nøyaktig listas. Kortet skal likevel ikke LESE som
   et kort inne i en modal: flaten er modalens egen, uten skygge og uten
   palettfarge, så idéene ligger rett på arket. */
.ideas-modal { min-height: min(320px, 100%); }
.ideas-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
/* Idébeholderen er IKKE en `.card` (se index.html), men radene inni er listas,
   og de leser de tre kortvariablene: `--card-bg` gir platene sin tone i mørk
   drakt, `--card-accent` er kanten navnefeltet får. De settes derfor her, som
   `.card` gjør for seg.

   NØYTRAL flate, ingen palettfarge: idébeholderen er ikke en av kortene i
   board-ets rekke, og en posisjonsfarge ville lovet en tilhørighet som ikke
   finnes. Flaten må likevel være en TONE, ikke modalens egen hvite — radenes
   plate er halvgjennomsiktig hvit, og på hvitt forsvinner den. */
.ideas-card {
  --card-bg: var(--surface-2);
  --card-head: var(--surface-2);
  --card-accent: var(--line);

  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 10px 0;
  border-radius: var(--radius);
  background: var(--card-bg);
}

/* Tom-tilstand: ren CSS, slik at den ikke kan komme i utakt med listen —
   heller ikke midt i et drag, der dnd-kits klone gjør listen «ikke tom». */
.ideas-empty { display: none; margin: 0; font-size: var(--fs-sm); color: var(--ink-soft); font-weight: 500; }
.items-container:empty + .ideas-empty { display: block; }
/* … og da er kortet en ren tekstboks, med LIK luft hele veien rundt. Kortets
   egen polstring er 10 px opp/ned og 0 til sidene (radene bærer sitt eget
   innrykk), så teksten sto 34 px fra toppen — kortets 10 + den tomme
   beholderens minstehøyde 14 + hyllegapet 10 — og klint mot venstrekanten.
   Er beholderen tom, er det heller ingenting å slippe i den: den legges flat,
   og polstringen settes i ÉN verdi. Under et drag er beholderen ikke tom
   (dnd-kits klone ligger i den), så slippmålet er urørt der det finnes noe å
   slippe. */
.ideas-card:has(> .items-container:empty) { padding: 16px; }
.ideas-card > .items-container:empty { display: none; }

/* KATEGORIENE ER MODALENS ENESTE FARGEDE FLATER, og de får fargen sin av
   POSISJONEN — samme regel som lister og områder: den øverste er alltid den
   første palettfargen, også etter en omrokkering (`reindexIdeaCatColors` deler
   ut på nytt). Fargen lagres derfor ikke og synkes ikke; den utledes.

   Den fargede flaten er samtidig svaret på hvorfor en idékategori er et BLOKK
   og ikke bare en overskrift over en hylle: idébeholderen har ingen kort-hoder
   å dele lista inn med, så bolken må bære grensen sin selv. */
.idea-cat {
  padding: 8px;
  border-radius: 12px;
  background: var(--card-bg);
}
/* Mørk drakt maler kortflater som en DEMPET blanding av palettfargen (se
   `--card-face`), aldri som den rå tonen — ellers ville de tre lyshetssettene
   lyst opp mot en mørk bakgrunn. Kategoriblokken er en kortflate og får hele
   pakken: den dempede flaten, aksentstripen som bærer selve fargen, og
   konturen som skiller blokken fra flaten under. Uten de to siste er blokkene
   i mørk drakt nesten umulige å skille fra hverandre — tonetrinnet alene er
   for lite. Nøyaktig det samme svaret som `.card` får.

   MEN BARE I HVILE. Regelen er like spesifikk som de delte dra-reglene og står
   etter dem i fila, så uten unntaket her ville den slått dem begge: hullet ble
   et lite kategorikort med aksentstripe i stedet for et hull (og et hull skal
   se likt ut uansett hva som skal lande i det), og det løftede objektet mistet
   den halvgjennomsiktige løfteflaten og den kompakte polstringen klonen måles
   mot. Begge tilstandene eies av dra-blokken; hvileflaten er vår. */
:root[data-theme="dark"] .idea-cat:not([data-dnd-placeholder]):not([data-dnd-dragging]) {
  background-color: var(--card-face);
  background-image: linear-gradient(90deg, var(--card-stripe) 0 4px, transparent 4px);
  padding-left: 12px;                 /* hold innholdet klar av stripen */
  outline: 1px solid rgba(255, 255, 255, 0.09);
  outline-offset: -1px;
}
/* Hvile-hårstrekene rundt en kategori skiller hylla fra nabo-radene NÅR alle
   ligger på den samme flaten. Her har kategorien sin egen farge, og da er
   streken bare støy. Dra-forhåndsvisningen (`seps-managed`, lenger opp) er
   urørt: DER er streken svaret på hvor raden lander. */
.idea-cat:not(:last-child)::after,
.item + .idea-cat::before { content: none; }

/* Slett-knappen på en idé er den ENESTE knappen raden har. Den arver
   `.item-cog` sin plass og berøringsflate; det eneste som skiller den er at
   hover er rød (handlingen er destruktiv), ikke grønn. */
.idea-del-btn:hover { color: var(--danger); }

/* KONTROLLFELTET (se index.html): knappene og kassen stablet og midtstilte,
   utenfor det rullende feltet. `.modal-foot` står som ellers — bare aksen
   snus, for her er det ikke et notat og en knapp, men to rader av samme slag. */
.ideas-foot {
  flex-direction: column;
  justify-content: center;
  gap: 10px;
  padding: 14px 20px;
}

.events-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 30px;
}
.events-empty { margin: 0; font-size: var(--fs-sm); color: var(--ink-soft); font-weight: 500; }
.events-section { display: flex; flex-direction: column; gap: 30px; }
.events-section-head {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-md);
  font-weight: 700;
  color: var(--ink);
}
/* Feltets eget ikon foran overskriften — det SAMME motivet chipene i board-et
   bruker for den samme tiden (kalender for start, kalender med utropstegn for
   frist). Ingen plate: seksjonen er ikke en status, den sier hvilket FELT dette
   er, og uten plate følger streken drakten som radenes typeikon gjør. */
.events-section-icon {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
}
.events-section-icon .icon { width: 1em; height: 1em; font-size: 20px; }
.events-group { display: flex; flex-direction: column; gap: 8px; }
.events-group-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink-soft);
}
.events-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.event-row {
  width: 100%;
  appearance: none;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: var(--list-row-pad-y) var(--list-row-pad-x);
  border: 1.5px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  transition: background 0.15s, border-color 0.15s;
}
.event-row:hover { background: var(--wash); }
.event-row:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }
/* Typeikonet: samme boks-størrelse som gruppens statusikon, men uten flate —
   det er en opplysning om hva raden ER, ikke en status. */
.event-row-icon {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
}
/* Litt skygge, så den lyse streken i mørk drakt løftes fra raden i stedet for
   å ligge flatt i den. `filter` og ikke `box-shadow`: boksen er gjennomsiktig,
   det er GLYFEN som skal kaste skyggen. Svart i begge drakter — den mørkner
   både en lys og en mørk flate. */
.event-row-icon .icon {
  width: 1em;
  height: 1em;
  font-size: 21px;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3));
}
.event-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.event-row-name {
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--ink);
  overflow-wrap: anywhere;
}
/* Kontekststien — dempet, så navnet dominerer raden. */
.event-row-meta {
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}
/* Høyre side: avstanden i tid over den konkrete datoen. */
.event-row-when {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.event-row-rel { font-size: var(--fs-xs); font-weight: 600; color: var(--ink-soft); }
.event-row-date { font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
/* Gruppens statusikon: en rund plate i gruppens farge. */
.event-icon {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--chip-bg);
  box-shadow: 0 1px 3px rgba(35, 45, 55, 0.16);
  /* Kontraktsfargene under glyfen er de samme i begge drakter, så glyfen skal
     stå stille også. Custom properties arver, så pinningen her dekker hele
     ikonet uten en eneste ekstra selektor — samme grep som `.btn-solid`. */
  --icon-ink: #111111;
  --icon-paper: #ffffff;
  --icon-grey: #c0c4c9;
}
.event-icon .icon { width: 1em; height: 1em; font-size: 15px; }
.event-icon.is-over { background: var(--grad-red); }
.event-icon.is-soon { background: var(--grad-yellow); }
.event-icon.is-later { background: var(--grad-green); }
.event-icon.is-started { background: var(--grad-accent); }
.event-icon.is-startsoon { background: var(--grad-purple); }
.event-icon.is-startlater { background: var(--grad-blue); }
.event-icon.is-far { background: var(--grad-slate); }
/* Telefon i portrett (samme grense som board-ets én-kolonne-grense): tiden
   flyttes ned på sin egen linje, på linje med teksten. Da får stien hele
   bredden i stedet for å brekke over fire linjer ved siden av en kolonne som
   likevel ikke kan krympe (tidspunktet skal aldri kappes). */
@media (max-width: 560px) {
  .event-row { align-items: flex-start; flex-wrap: wrap; }
  /* Basis 0, ikke `auto`: med innholdsbredden som basis ville navnet brutt ned
     under ikonet i stedet for å krympe ved siden av det. */
  .event-row-main { flex-basis: 0; }
  .event-row-when {
    width: 100%;
    padding-left: 36px;
    flex-direction: row;
    align-items: baseline;
    gap: 8px;
  }
}

/* ---------------- Varselmodalen ----------------
   Samme modalskall som «Kommende hendelser», og BEVISST de samme statusflatene:
   et varsel om en utløpt frist skal se ut som gruppen «Frist utløpt» gjør —
   `.event-icon` med sin tone gjenbrukes derfor rått, med pinningen og
   kontrastkontrakten den allerede har (docs/mork-drakt.md,
   docs/tilgjengelighet.md). Modalen selv pinner INGENTING.

   Raden er to knapper, ikke én: hele venstresiden navigerer til objektet, og
   den lille klokka til høyre folder ut «Utsett». En `<button>` inne i en annen
   er ulovlig, så de er søsken i en flex-linje. */
.notif-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  /* Luften mellom to døgnbunker. Som i «Kommende hendelser» er det avstanden
     som bærer inndelingen — ingen strek mellom bunkene. */
  gap: 26px;
}
/* To ikonknapper i modalhodet (tannhjul + lukk): `.modal-head` er
   space-between, så de må ligge i én boks for å holde sammen i enden. */
.modal-head-actions { flex: 0 0 auto; display: flex; align-items: center; gap: 2px; }
/* Hodet har TRE barn når innstillingene står framme (tilbake, overskrift,
   lukk). `space-between` ville da dyttet overskriften til midten — `auto`-
   margin holder tilbakeknappen og overskriften samlet i venstre ende. */
.notif-back-btn { flex: 0 0 auto; }
.notif-modal .modal-head h2 { margin-right: auto; }
/* Bjellen og tannhjulet ligger begge i overskriften og veksles med `hidden`;
   ikonet er da markup og ikke en streng i JS. */
.notif-title-icon { display: inline-flex; flex: 0 0 auto; }
.notif-title-icon[hidden] { display: none; }

.notif-empty { margin: 0; font-size: var(--fs-sm); color: var(--ink-soft); font-weight: 500; }
/* Én bunke per døgn, med datoen som overskrift over den. Datoen står da ÉN
   gang der den betyr noe, i stedet for som et tidsstempel på hver eneste rad,
   og bunkene skilles av luft (modalens `gap`) framfor av en strek. */
.notif-day { display: flex; flex-direction: column; gap: 8px; }
.notif-day-head {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--ink-soft);
}
.notif-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.notif-item { display: flex; flex-direction: column; gap: 6px; }
.notif-line { display: flex; align-items: center; gap: 6px; }
.notif-row {
  flex: 1 1 auto;
  min-width: 0;
  appearance: none;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  display: flex;
  /* Raden er tre linjer (sti, navn, melding) og meldingen kan brekke videre.
     Ikonet midtstilles mot hele blokken — toppstilt ville det stått på linje
     med den lille stien i stedet for med innholdet. */
  align-items: center;
  gap: 10px;
  padding: var(--list-row-pad-y) var(--list-row-pad-x);
  border: 1.5px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  transition: background 0.15s, border-color 0.15s;
}
.notif-row:hover { background: var(--wash); }
.notif-row:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }
/* Ulest bæres av mer enn farge: en prikk i enden av navnet OG en kant
   (docs/tilgjengelighet.md). Lest er den rolige tilstanden, ikke omvendt. */
.notif-row.is-unread { border-color: var(--primary); background: var(--primary-soft); }
/* Målet er slettet eller utenfor tilgangen min: raden står, men den fører
   ingen steder — og sier det i teksten sin, ikke bare med tonen. */
.notif-row.is-gone { cursor: default; opacity: 0.72; }
.notif-row.is-gone:hover { background: var(--surface-2); }
.notif-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
/* Kontekststien øverst i raden, og bevisst SVÆRT liten: den plasserer objektet
   uten å konkurrere med navnet, som er det man leter etter. */
.notif-path {
  font-size: 10px;
  line-height: 1.35;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--ink-soft);
  opacity: 0.85;
  overflow-wrap: anywhere;
}
.notif-name-row { display: flex; align-items: center; gap: 6px; min-width: 0; }
.notif-name {
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.notif-dot {
  flex: 0 0 auto;
  width: 8px; height: 8px;
  border-radius: 999px;
  background: var(--primary);
}
.notif-meta {
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}
.notif-snooze-btn {
  flex: 0 0 auto;
  align-self: center;
  appearance: none;
  cursor: pointer;
  width: var(--control-h);
  height: var(--control-h);
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--ink-soft);
  display: grid;
  place-items: center;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.notif-snooze-btn:hover { background: var(--wash); color: var(--ink); }
.notif-snooze-btn:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }
.notif-snooze-btn[aria-expanded="true"] { border-color: var(--primary); background: var(--primary-soft); color: var(--ink); }
.notif-snooze-btn .icon { width: 20px; height: 20px; }
/* ARMERT: et nytt varsel er alt bestilt. Knappen er da en TILSTAND, ikke bare
   en handling, og bærer aksentflaten med hvit glyf — den samme «på»-fargen
   bryterne bruker. Fargen er ikke eneste bærer: knappens navn sier det samme,
   og popoveren forteller når varselet kommer. */
.notif-snooze-btn.is-armed {
  border-color: transparent;
  background: var(--grad-accent);
  /* Klokkeglyfen tegnes med `currentColor` (ICONS.snooze), så fargen her er
     alt som trengs — ingen `--icon-*`-pinning i varselmodalen. */
  color: #fff;
}
.notif-snooze-btn.is-armed:hover { background: var(--grad-accent); }
/* Slett ÉN rad: samme boks som utsett-knappen, men uten flate i hvile — den
   er den stille av de to, og skal ikke konkurrere med selve raden. */
.notif-del-btn {
  flex: 0 0 auto;
  align-self: center;
  appearance: none;
  cursor: pointer;
  width: var(--control-h);
  height: var(--control-h);
  border: 1.5px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink-soft);
  display: grid;
  place-items: center;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.notif-del-btn:hover { background: var(--danger-soft); border-color: var(--danger); color: var(--danger-ink); }
.notif-del-btn:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }
.notif-del-btn .icon { width: 18px; height: 18px; }

/* Utsett-popoveren (arver `.switcher-panel`: popover på desktop, sentrert ark
   på mobil). Overskriften bærer «om», så valgene er rene varigheter. */
.notif-snooze-panel {
  gap: 8px;
  /* Panelet er så bredt innholdet krever (`.switcher-panel` er `max-content`):
     smalt mens det bare er fire varigheter, og bredt nok til dato + klokkeslett
     på én linje i det «Egendefinert»-skuffen åpnes — den er da det bredeste
     barnet. Minstebredden er bare et gulv for menyen alene, og trekker fra den
     sikre sonen slik `.switcher-panel`s maks-bredde gjør: en min-width VINNER
     over max-width, og uten leddet kunne panelet blitt liggende under et hakk
     på en smal skjerm. */
  min-width: min(184px, calc(100vw - 20px - var(--safe-left) - var(--safe-right)));
}
.notif-snooze-title {
  padding: 0 2px;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--ink-soft);
}
.notif-snooze-list { display: flex; flex-direction: column; gap: 2px; }
.notif-snooze-choice {
  appearance: none;
  border: none;
  cursor: pointer;
  width: 100%;
  padding: 8px 10px;
  border-radius: var(--control-radius);
  background: transparent;
  color: var(--ink);
  font-family: inherit;
  font-size: var(--fs-md);
  font-weight: 600;
  text-align: left;
  transition: background 0.15s;
}
.notif-snooze-choice:hover { background: var(--primary-soft); }
.notif-snooze-choice:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: -2px; }
/* «Egendefinert» skiller seg fra de faste varighetene: den åpner en skuff i
   stedet for å utsette med én gang. En hårstrek over sier det uten et ord. */
.notif-snooze-more { border-top: 1px solid var(--line); border-radius: 0 0 var(--control-radius) var(--control-radius); }
.notif-snooze-more[aria-expanded="true"] { background: var(--primary-soft); }
/* Er et nytt varsel alt bestilt, sier panelet NÅR — og tilbyr det ene som
   gir mening: å avbryte det. Ingen ny utsettelse oppå den forrige. */
.notif-snooze-note {
  margin: 0;
  padding: 0 2px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink);
}
.notif-snooze-panel > .btn { align-self: flex-start; }
/* Skuffen: dato + klokkeslett og én knapp som bekrefter. */
.notif-snooze-custom { display: flex; flex-direction: column; gap: 8px; padding: 2px 2px 0; }
.notif-snooze-custom[hidden] { display: none; }
.notif-snooze-custom .btn { align-self: flex-start; }

/* Preferansene (tannhjulet). De styrer om hendelsen GENERERES, ikke bare om
   den vises — hinten sier det, så ingen tror en avslått type kommer tilbake
   når den slås på igjen. */
.notif-settings { display: flex; flex-direction: column; gap: 4px; }
.notif-settings .menu-setting { margin-top: 4px; }

/* KANALEN — «Varsler på denne enheten» (docs/varsler.md). Den er et annet slag
   valg enn de fire typene over: typene sier hva som blir et varsel, kanalen om
   det også forlater appen. Derfor en tynn skillelinje og en forklarende linje
   under bryteren — den ene teksten som får stå i dette panelet, fordi den er
   det som forklarer tillatelsen FØR systemdialogen dukker opp. */
.notif-channel {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
}
.notif-channel .menu-setting { margin-top: 0; }
.notif-channel-note {
  margin: 4px 0 0;
  font-size: var(--fs-xs);
  line-height: 1.35;
  color: var(--ink-soft);
}
/* Nedtellingen i «Angre · 10» skal ikke få knappen til å hoppe i bredde. */
#notif-clear { font-variant-numeric: tabular-nums; }

@media (max-width: 560px) {
  /* Raden har ingen tidskolonne lenger — teksten har hele bredden, og
     `flex-basis: 0` holder navnet ved siden av ikonet i stedet for under det. */
  .notif-main { flex-basis: 0; }
}

/* ---------------- Kortvarig markering av et navigasjonsmål ----------------
   Settes av `navigateToObject()` på objektet man nettopp havnet ved (søk i
   dag, kommende hendelser og varsler senere) og fjernes igjen etter
   NAV_FLASH_MS. Ringen tegnes som en INNVENDIG box-shadow, ikke som en
   outline: kortene har `overflow: hidden` (en utvendig ring ville blitt
   klippet), og fokusringen — som ligger på det samme elementet i det samme
   øyeblikket — eier `outline`. */
@keyframes nav-flash {
  0%   { box-shadow: inset 0 0 0 0 transparent; }
  15%  { box-shadow: inset 0 0 0 3px var(--focus); }
  70%  { box-shadow: inset 0 0 0 3px var(--focus); }
  100% { box-shadow: inset 0 0 0 0 transparent; }
}
.nav-flash {
  box-shadow: inset 0 0 0 3px var(--focus);
  animation: nav-flash 1.6s ease-in-out;
}
@media (prefers-reduced-motion: reduce) {
  /* Ingen pulsering — ringen står stille til den fjernes. */
  .nav-flash { animation: none; }
}

/* ---------------- Delt / låst-merker ----------------
   Delt-merket og del-knappen har samme høyde som navnet ved siden av
   (chip-/korttittel-teksten) — relativt store og godt synlige. */
.share-badge {
  flex: 0 0 auto;
  font-size: var(--fs-lg);
  line-height: 1;
}
.share-badge[hidden] { display: none; }
/* Knappeflaten i et KORTHODE (`.card-cog`): egen svakt markert flate som
   lysner ved hover (samme idé som flate-mønsteret, på farget bakgrunn).
   Områdekort og listekort bruker den samme flaten til objektmenyknappen. */
.card-cog {
  flex: 0 0 auto;
  align-self: center;
  appearance: none;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border-radius: 9px;
  font-size: var(--fs-lg);
  color: #fff;
  background: var(--tint);
  box-shadow: inset 0 0 0 1px var(--tint-ring);
  transition: background 0.15s;
}
.card-cog:hover {
  color: #fff;
  background: var(--tint-hover);
}
.card-cog:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }
.card.is-locked .card-title { opacity: 0.9; }

/* ---------------- Indikator-chips (meta-raden under navn) ----------------
   Rad under liste-/elementnavnet med chips for innstillinger som ER satt:
   delt (kun lister), ansvarlig (initial-sirkel), start (kalender/klokke) og
   frist (kalender-med-utropstegn/klokke). Chipene er knapper — de åpner
   hurtig-redigering av akkurat den innstillingen. Fargestatus:
     start:  nøytral → grønn når starttiden er passert.
     frist:  nøytral → gul dagen før fristen → rød f.o.m. fristdatoen. */
.meta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  padding: 0 4px;
}
.meta-row[hidden] { display: none; }
.card-meta { padding-bottom: 2px; }

.meta-chip {
  appearance: none;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 26px;
  padding: 0 9px;
  border-radius: 999px;
  font-family: inherit;
  font-size: var(--fs-xs);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  background: var(--chip-bg);
  box-shadow: 0 1px 3px rgba(35, 45, 55, 0.16);
  transition: filter 0.15s, box-shadow 0.15s, transform 0.1s;
}
.meta-chip:hover { filter: brightness(1.04); box-shadow: 0 2px 5px rgba(35, 45, 55, 0.24); }
.meta-chip:active { transform: scale(0.95); }
.meta-chip:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 1px; }
.meta-chip:disabled { cursor: default; }
.meta-chip .icon { width: 1em; height: 1em; font-size: 15px; flex: 0 0 auto; }
/* Ansvarlig-chipen er kun sirkelen (navnet ligger i title/aria). */
.meta-chip.meta-resp { padding: 0 3px; background: transparent; box-shadow: none; }
.meta-chip .resp-avatar { width: 22px; height: 22px; font-size: 11px; }
/* STATUSFARGER — de samme seks flatene som gruppene i «Kommende hendelser»
   (docs/kommende-hendelser.md), og de samme seks bøttene: fristen går rød →
   gul → grønn, starten blågrønn → lilla → blå. At noe BEGYNNER er ingen
   advarsel, så startene låner ikke varselfargene.

   LYSE FLATER PINNER MØRKE MERKER. I mørk drakt snur ikonstreken til
   --icon-ink, og det er en forbedring på de MØRKE flatene (blågrønt 3,90 →
   3,95/5,54, rødt 3,52 → 4,38/5,56) — men en katastrofe på de lyse (gult
   10,48 → 1,47). Samme regel som for .btn-yellow: gult, grønt, lilla og blått
   bærer mørke merker, blågrønt og rødt beholder gevinsten av den lyse.
   «Papiret» pinnes SAMMEN med streken: kalender-/klokkeikonene har en hvit
   flate under strekene (fill="#ffffff"), og med bare streken pinnet ville mørk
   strek møtt mørkt papir og ikonet blitt en ulesbar klatt. Nøyaktig samme par
   som .btn-solid pinner. */
.meta-chip.is-over { background: var(--grad-red); color: #fff; text-shadow: var(--text-shadow); }
.meta-chip.is-started { background: var(--grad-accent); color: #fff; text-shadow: var(--text-shadow); }
.meta-chip.is-soon,
.meta-chip.is-later,
.meta-chip.is-startsoon,
.meta-chip.is-startlater {
  color: #fff;
  text-shadow: var(--text-shadow);
  --icon-ink: #111111;
  --icon-paper: #ffffff;
}
.meta-chip.is-soon { background: var(--grad-yellow); }
.meta-chip.is-later { background: var(--grad-green); }
.meta-chip.is-startsoon { background: var(--grad-purple); }
.meta-chip.is-startlater { background: var(--grad-blue); }
/* Fristen ligger etter forelderens (docs/scheduling.md). Meningen bæres av
   varseltrekanten og av chipens tekst (`title`/`aria-label`) — statusfargen
   under sier fortsatt hvor fristen står i tid. Kanten er ren forsterkning og
   arver chipens EGEN tekstfarge, så den aldri kan være svakere enn teksten som
   allerede står på den samme flaten. */
.meta-chip.is-conflict { border: 1.5px dashed currentColor; }

/* ---------------- Objektmenyen (én knapp per objekt) ----------------
   Popover ved menyknappen på desktop, sentrert ark på mobil — panelet arver
   `.switcher-panel` (samme skall som ansvarlig-velgeren og tids-popoveren), så
   posisjonering, maks-høyde og mobil-omleggingen finnes bare ÉN gang i appen.
   Radene er hele knapper med ikon + etikett (+ evt. et dempet hint), og
   undermenyene er et TREKKSPILL: kun én skuff åpen om gangen. */
.obj-menu-panel {
  gap: 0;
  padding: 8px;
  /* Minstebredden må trekke fra sonen på samme måte som `.switcher-panel`s
     maks-bredde: en min-width VINNER over max-width, så uten leddene her ville
     panelet blitt liggende under et hakk på en smal skjerm (delt skjerm, liten
     WebView) selv om maks-bredden er sone-bevisst. 0 i en nettleser. */
  min-width: min(268px, calc(100vw - 20px - var(--safe-left) - var(--safe-right)));
}
/* Overskrift: hvilket objekt menyen gjelder. På mobil dekker arket raden den
   kom fra, og uten navnet her ville man ikke se hva man holder på med. */
.obj-menu-head {
  display: flex;
  align-items: center;
  gap: 8px;
  /* Samme venstrekant som radene under, så navnet og etikettene
     står på én linje: X-en er radfamiliens token. */
  padding: 4px var(--menu-row-pad-x) 9px;
  margin-bottom: 5px;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--ink-soft);
}
.obj-menu-head-icon { flex: 0 0 auto; display: grid; place-items: center; font-size: 20px; }
.obj-menu-head-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink);
}
.obj-menu-list { display: flex; flex-direction: column; }
.obj-menu-row {
  appearance: none;
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
  width: 100%;
  /* 40 px høy rad: over AA-gulvet på 24 px, og radene ligger tett i tett, så
     de utvider seg ikke som ikonknappene gjør (ingen naboer å møte). */
  min-height: 40px;
  padding: var(--menu-row-pad-y) var(--menu-row-pad-x);
  border-radius: var(--control-radius);
  background: transparent;
  color: var(--ink);
  font-family: inherit;
  font-weight: 600;
  font-size: var(--fs-md);
  text-align: left;
  transition: background 0.15s;
}
.obj-menu-row:hover { background: var(--primary-soft); }
.obj-menu-row:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: -2px; }
.obj-menu-icon { flex: 0 0 auto; display: grid; place-items: center; font-size: 21px; }
.obj-menu-label { flex: 1 1 auto; min-width: 0; }
/* Hintet står under etiketten (lås-radens «Andre kan se, men ikke redigere»). */
.obj-menu-row .obj-menu-hint {
  flex: 1 0 100%;
  order: 3;
  /* Flukter med etiketten over: ikonets 21 px + radens 10 px gap. Regnet,
     ikke gjettet, så et nytt ikonmål ikke etterlater hintet i utakt. */
  padding-left: calc(21px + 10px);
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--ink-soft);
}
.obj-menu-row:has(.obj-menu-hint) { flex-wrap: wrap; }
/* Telleren (antall koblinger) står i ENDEN av raden, på samme linje som
   etiketten. Den er en opplysning om raden, ikke en handling, så den er en
   dempet pille uten egen flateforskjell — og fremfor alt lar den radhøyden
   være i fred, slik at hver menyrad har den samme polstringen. */
.obj-menu-count {
  flex: 0 0 auto;
  min-width: 22px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--wash);
  font-size: var(--fs-xs);
  font-weight: 700;
  /* Tett linjehøyde: pillen skal ikke være høyere enn etiketten ved siden av,
     ellers dytter den radhøyden ett hakk opp og «Koblinger» blir igjen den ene
     raden som ikke matcher naboene (MÅLT: 41 px mot 40). */
  line-height: 1.35;
  text-align: center;
  color: var(--ink-soft);
}
/* Sletting/oppløsing: rød etikett bak en skillelinje, alltid nederst. */
.obj-menu-sep { height: 1px; margin: 5px 4px; background: var(--line); }
.obj-menu-row.is-danger { color: var(--danger-ink); }
.obj-menu-row.is-danger:hover { background: var(--danger-soft); }

/* Trekkspillet: overskriftsraden får en vinkel til høyre som roterer 90° når
   skuffen er åpen; skuffen animerer på høyde (og klippes mens den beveger seg). */
.obj-menu-group { display: flex; flex-direction: column; }
/* Skillelinjer mellom skuffene (og mot de vanlige radene over/under): en fane
   som kan folde seg ut er en egen blokk, ikke nok en rad i rekka. Linjene
   ligger på selve gruppen — ikke som egne elementer — så nabo-faner deler én
   linje og ingen ekstra luft snik-legges inn mellom dem. */
.obj-menu-list > * + .obj-menu-group { border-top: 1px solid var(--line); }
/* Raden UNDER en skuff får linjen som eget strøk, ikke som `border-top`: radene
   er avrundet (`--control-radius`), så en kant på selve raden buer i endene og
   linjen ville sett annerledes ut enn de flate linjene ellers i menyen.
   SAMME STRØK MELLOM TO VANLIGE RADER. Linjene fulgte tidligere bare skuffene,
   og da fikk en meny linjer der det tilfeldigvis sto en skuff og ingen der det
   ikke gjorde det: på notatsiden rant «Deling og medlemmer», «Lås», «Koblinger»
   og «Arkiver» sammen til én blokk mens radene over dem sto hver for seg.
   Skillet er MELLOM valgene, ikke rundt skuffene, så hver rad som har en
   nabo over seg bærer det. `.obj-menu-sep` (over sletteraden) er fortsatt sin
   egen, tydeligere pause med luft rundt: den skiller det som fjerner noe fra
   alt annet, og skal ikke lese som nok en radgrense.
   Bare direkte barn av lista — radene INNE i en skuff («Flytt opp/ned»,
   ansvarlig-radene) er ett trinn ned og hører sammen. */
.obj-menu-group + .obj-menu-row,
.obj-menu-list > .obj-menu-row + .obj-menu-row { position: relative; }
.obj-menu-group + .obj-menu-row::before,
.obj-menu-list > .obj-menu-row + .obj-menu-row::before {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  background: var(--line);
}
.obj-menu-chev {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  font-size: 16px;
  color: var(--ink-soft);
  transition: transform 0.18s;
}
.obj-menu-toggle[aria-expanded='true'] { background: var(--primary-soft); }
.obj-menu-toggle[aria-expanded='true'] .obj-menu-chev { transform: rotate(90deg); }
.obj-menu-sub {
  overflow: hidden;
  transition: height 0.18s ease;
}
.obj-menu-sub.is-closed { height: 0; }
/* Innholdet i en skuff rykkes inn, så nivåene leses uten ekstra kanter. */
.obj-menu-sub > * { padding: 6px 0 8px 8px; }
.obj-menu-movebox { display: flex; flex-direction: column; }
.obj-menu-resp { display: flex; flex-direction: column; gap: 2px; }
.obj-menu-resp .uni-empty { margin: 4px 2px; font-size: var(--fs-sm); color: var(--ink-soft); }
/* Tids-editoren i en skuff: samme editor som tids-popoveren bruker. Den har
   ingen radpolstring av seg selv, så uten det ekstra innrykket her ville den
   startet lengre til venstre enn radene i de andre skuffene: 8 px fra
   `.obj-menu-sub > *` + 9 px fra `.obj-menu-row` = samme venstrekant. */
.obj-menu-sub > .time-editor { padding-left: calc(8px + var(--menu-row-pad-x)); }
.obj-menu-sub .time-editor { gap: 12px; }
.obj-menu-sub .time-lock { font-size: var(--fs-sm); }

/* ---------------- Slett ved å dra objektet i søppelkassen ----------------
   Kassen for nivået man drar på vises fram i det draget starter (`.drag-trash`)
   og lyser opp når man sikter på den (`.drop-target`), og det løftede objektet
   skifter til rød bakgrunn. Se app.js («SLETT VED Å DRA OBJEKTET I
   SØPPELKASSEN»).

   Markeringen er flate + skygge, ikke en kantlinje: 📁-breadcrumben beholder
   sin stiplede ring, men en søppelkasse har ingen.

   `.drag-trash` bærer ingen egen maling. Kassene i et kort viser seg fram ved å
   strekke seg over radbredden (rett under), og alle fire ved at de i det hele
   tatt DUKKER OPP — de er skjult når de er tomme. Siktemarkeringen er
   `.drop-target` lenger ned. */
/* Kassene som har en HEL rad for seg selv — listepunkt-kassen nederst i
   lista, mappe-kassen nederst i området, OG område-kassen i nav-modalens
   faste fot — strekker seg over hele radbredden mens draget står på.
   Grunnen er fingeren: knappen er ellers ~48 px bred, den forsvinner under
   tuppen, og på berøring finnes ingen peker som viser hvor man egentlig sikter.
   Bare BREDDEN endres. Høyden står — for kassene i et kort altså kortets boks,
   og ekstraher-terskelen (`cardBand` = kortets egen kant) rører seg ikke.
   Nav-modalens fot har ingen tilsvarende terskel å forstyrre.
   Topplinjas liste-kasse er ANNERLEDES: den deler rad med ＋-knappen og har
   ingen ledig bredde å ta av, så den forblir knapp-bred. */
.item-trash .trashcan.drag-trash {
  flex: 1 1 auto;
  justify-content: center;
}
/* … OG DOBBELT SÅ HØY, alle sammen. En kasse er det ene stedet i appen der et
   bom betyr at handlingen ikke skjer, og en finger som drar noe dekker selv
   målet sitt. Veksten er MOMENTAN (ingen overgang): dnd-kit måler sonen ÉN gang,
   idet draget starter, og en kasse som fortsatt vokste ville blitt målt for
   liten. Foten nederst på siden og modalenes fot er festet i bunnen, så kassene
   der vokser OPPOVER — bort fra kanten og inn mot fingeren. */
.trashcan.drag-trash { height: calc(var(--control-h) * 2); }
/* Kassen INNE I ET KORT vokser oppover UTEN å gjøre kortet høyere: den ekstra
   høyden tas av en negativ toppmarg, så knappen legger seg over ＋-raden i
   stedet for å skyve bunnen av kortet ned. Grunnen er dra-ankeret
   (`docs/drag-and-drop.md`): kasseraden som dukker opp og forsvinner er
   allerede en høydeendring ankeret må sette av, og en kasse som ga kortet enda
   en knapperad ville flyttet både ekstraher-terskelen og alt under kortet midt
   under fingeren. ＋-raden er ingen ting man sikter på under et drag, så
   overlappet koster ingenting. */
.card .item-trash .trashcan.drag-trash { margin-top: calc(var(--control-h) * -1); }
/* … og ＋-raden viker for den. Kassen ligger nå OPPÅ knappene, og de skinner
   gjennom den halvgjennomsiktige flaten — to knapper midt i et slippmål leser
   som noe man kan treffe. Plassen beholdes (`visibility`), så kortet står
   nøyaktig like høyt som før. */
.card:has(.item-trash .trashcan.drag-trash) .add-item-row { visibility: hidden; }
/* Den radbrede kassen vokser ikke i tillegg: 12 % av den stikker utenfor kortet,
   som klipper (`overflow: hidden`). Siktemarkeringen bæres av flaten, skyggen
   og rødvasken på det som dras. */
.item-trash .trashcan.drag-trash.drop-target { transform: none; }

/* En kasse som ble AVDEKKET av draget er per definisjon tom, og «0» der leser
   som et antall i stedet for et mål. Attributtet settes av armDragTrash — på
   knappen selv (topplinja) eller på wrapperen rundt den (kort/områdekort). */
.trashcan.drag-trash[data-drag-revealed] .trashcan-count,
[data-drag-revealed] .trashcan.drag-trash .trashcan-count { display: none; }
.trashcan.drag-trash.drop-target {
  background: var(--danger-soft);
  box-shadow: 0 4px 12px rgba(180, 60, 60, 0.35);
  transform: scale(1.12);
}
/* Arkivet er den samme knappen med en annen betydning, og markeres derfor på
   den samme måten i sin egen farge. Bare flaten og skyggen byttes; veksten og
   reduced-motion-unntaket over gjelder begge. */
.trashcan.archive-can.drag-trash.drop-target {
  background: var(--archive-soft);
  box-shadow: 0 4px 12px rgba(150, 115, 60, 0.35);
}
@media (prefers-reduced-motion: reduce) {
  .trashcan.drag-trash.drop-target { transform: none; }
}


/* ---------------- Tids-editoren (objektmenyen + tids-popoveren) ---------------- */
.time-editor { display: flex; flex-direction: column; gap: 14px; }
/* Feltpar (dato+klokkeslett) med egen overskrift over («Starttid»/«Tidsfrist»
   + tilhørende ikon) — kun i fullvisningen (menyens tidsplan-skuff);
   tids-popoveren har sin egen tittel (time-panel-title) og hopper over denne
   (se opts.only i JS). */
.time-group { display: flex; flex-direction: column; gap: 6px; }
.time-group-heading {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink-soft);
}
.time-group-heading .icon { font-size: 17px; flex: 0 0 auto; }
.time-row { display: flex; align-items: center; gap: 8px; }
.time-row .field { padding: 8px 10px; font-size: var(--fs-sm); }
/* Datofeltet er så bredt som «dd.mm.åååå» + kalenderikonet trenger — ikke
   bredere (var tidligere elastisk og langt bredere enn innholdet). Samme
   bredde på alle skjermstørrelser. Litt krymp tillatt (helt smale mobiler)
   fremfor å tvinge klokkeslettet ned på egen linje. */
.time-date { flex: 0 1 146px; min-width: 130px; }
/* Klokkeikonet står som eget element til venstre for klokkeslett-feltet
   (ikke lenger inni inputen) — unngår at det overlapper med teksten som
   skrives. Bredden på selve feltet er tilpasset det norske 24-timersformatet
   («tt:mm», uten fm/em-suffiks). */
.time-clock-icon { display: inline-flex; flex: 0 0 auto; color: var(--ink-soft); }
.time-clock-icon .icon { font-size: 15px; }
.time-clock-icon:has(+ .time-clock:disabled) { opacity: 0.55; }
/* min-width er bevisst lavere enn flex-basis: på de trangeste mobilene (den
   smale objektmenyen) må feltet fortsatt kunne krympe forbi «tt:mm»-bredden
   for at fjern-krysset (.time-clear) ikke skal klippes av `.obj-menu-sub`s
   overflow: hidden — se PR-diskusjon. */
.time-clock { flex: 0 1 104px; min-width: 72px; }
.time-clear {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border-radius: 8px;
}
.time-row .field:disabled { opacity: 0.55; }
/* Subtilt hint (utenfor listens tidsrom / styrt av listen). */
.time-note { margin: 0; font-size: var(--fs-xs); font-weight: 600; color: var(--note-ink); }
.time-note.is-muted { color: var(--ink-soft); font-weight: 500; }
.time-note[hidden] { display: none; }
.time-lock {
  display: flex;
  align-items: center;
  gap: 9px;
  cursor: pointer;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink);
}
.time-lock input { flex: none; }

/* ---------------- Toggle-switcher (egendefinerte checkboxes) ----------------
   Alle checkboxes i modaler rendres som en pille-formet av/på-bryter (ren CSS,
   inputen selv er kontrollen — appearance:none + ::before-håndtak; ingen ekstra
   DOM). Av = grå spor, på = blågrønn (--grad-accent, samme som .btn-accent):
   håndtaket er HVITT, og det trenger en flate som bærer hvitt. */
.time-lock input[type="checkbox"],
.share-policy-label input[type="checkbox"] {
  -webkit-appearance: none;
  appearance: none;
  position: relative;
  width: 42px;
  height: 25px;
  border-radius: 999px;
  background: var(--track);
  margin: 0;
  cursor: pointer;
  flex: none;
  transition: background-color 0.16s ease;
}
.time-lock input[type="checkbox"]::before,
.share-policy-label input[type="checkbox"]::before {
  content: '';
  position: absolute;
  top: 2.5px;
  left: 2.5px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(35, 45, 55, 0.35);
  transition: transform 0.16s ease;
}
.time-lock input[type="checkbox"]:checked,
.share-policy-label input[type="checkbox"]:checked {
  background: var(--grad-accent);
}
.time-lock input[type="checkbox"]:checked::before,
.share-policy-label input[type="checkbox"]:checked::before {
  transform: translateX(17px);
}
.time-lock input[type="checkbox"]:focus-visible,
.share-policy-label input[type="checkbox"]:focus-visible {
  outline: var(--focus-w) solid var(--focus);
  outline-offset: 2px;
}
.time-lock input[type="checkbox"]:disabled,
.share-policy-label input[type="checkbox"]:disabled {
  opacity: 0.5;
  cursor: default;
}
@media (max-width: 560px) {
  .time-row { gap: 6px; }
}

/* Tids-popoveren (samme skall som bytterne). */
.time-panel { min-width: min(320px, calc(100vw - 20px - var(--safe-left) - var(--safe-right))); gap: 10px; }
.time-panel-title {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: var(--fs-md);
  font-weight: 700;
  color: var(--ink);
}
.time-panel-title .icon { font-size: 19px; }

/* ---------------- Redusert bevegelse (tilgjengelighet) ----------------
   Respekterer OS-innstillingen «reduser bevegelse»: nøytraliser animasjoner/
   transisjoner. JS-drevne fly-/FLIP-/drop-animasjoner hoppes uansett over i
   app.js (prefersReducedMotion()); dette dekker de rene CSS-effektene
   (modal-sprett, mappe-puls, sveipefelt-morf, hover-løft osv.). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}


/* ---------------- Nav-modalen: de tre seksjonene ----------------
   «Mine områder», «Områder delt med meg» og «Mapper delt med meg» ligger
   i SAMME ene board-kolonne som områdekortene, som egne rader. DnD-motoren
   hopper over dem (`boardRows` filtrerer på `.card`), så de kan stå der uten å
   bli dra-mål. Skillelinjen over hver overskrift (unntatt den første) markerer
   seksjonsgrensen. */
.nav-section-head {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 10px;
  font-size: var(--fs-md); font-weight: 700; color: var(--ink);
}
.nav-section-head[data-section="1"],
.nav-section-head[data-section="2"] {
  margin-top: 18px; padding-top: 16px;
  border-top: 1px solid var(--line);
}
.nav-section-icons { display: inline-flex; align-items: center; gap: 2px; flex: none; }
.nav-section-icons .icon { width: 20px; height: 20px; }
.nav-section-empty {
  margin: 0 0 10px; padding: 0 2px;
  font-size: var(--fs-sm); font-weight: 500; color: var(--ink-soft);
}
.nav-add-uni { display: flex; justify-content: center; margin: 4px 0 2px; }
/* «Mapper delt med meg» er en VIRTUELL beholder — den har ingen egen farge,
   ingen del-/slett-knapp og ingen ＋-rad; bare mappene. */
.free-groups-card { --card-bg: var(--free-bg); --card-head: var(--free-head); --card-accent: var(--free-accent); }
/* Tittelen står på en LYS flate her (ikke en mettet kortfarge), så den hvite
   skriften med skygge ville blitt uleselig — bruk vanlig blekk uten skygge.
   Cursor/hover følger `.card-title`s vanlige `inherit` (pekehånden fra
   `.card-head` — hodet kollapser fortsatt ved klikk her også). */
.free-groups-card .card-title { color: var(--ink); text-shadow: none; -webkit-text-stroke: none; }

/* ============================================================
   NOTATER — hovedbryter, notatkort og editor
   ------------------------------------------------------------
   Autoritativt for produktet: docs/notater-plan.md. Alt her gjenbruker
   designsystemets tokens (`--control-h`, `--radius`, `--surface*`, `--ink*`,
   `--line`, `--shadow-*`) — ingen egne farger, ingen ad hoc-gradienter. Begge
   draktene faller derfor ut av tokenene, uten en eneste `[data-theme]`-regel
   her (docs/mork-drakt.md).
   ============================================================ */

/* Det SYNLIGE feltet, målt av `visualViewport` (trackVisualViewport i app.js).
   Mobiltastaturet krymper det uten å røre layoutviewporten, så `100dvh` blir
   stående like høy som før og editorens verktøylinje glir ut over toppkanten.
   Verdiene her er hvilen — de gjelder når tastaturet er nede, og når
   nettleseren ikke har `visualViewport` i det hele tatt. */
:root {
  --viewport-h: 100dvh;
  --viewport-top: 0px;
  --keyboard-inset: 0px;
}

/* SEGMENTERT BRYTER (`.seg`) — ÉN kontroll med to bruk: hovedbryteren
   Lister ↔ Notater øverst i headeren (`.main-tabs`), og søkets scopevelger
   Alt | Lister | Notater (`.search-scope`). Formen står HER, én gang;
   bruksstedene setter bare størrelse.

   MARKERINGEN ER ÉN FLATE SOM GLIR. Ikke en bakgrunn som tones inn på det
   aktive segmentet og ut på det forrige — da leser kontrollen som to knapper
   som blinker, ikke som én bryter med et hendel. Flaten er `::before` på
   beholderen, nøyaktig ett segment bred, og den flyttes med `transform` i
   samme egenskap og samme timing som knotten i konto-modalens brytere
   (`--switch-motion`).

   SEGMENTENE ER LIKE BREDE (`flex: 1 1 0`), og det er dét som gjør reisen til
   ren regning: flaten er `100% / --seg-n` bred og står `--seg-i * 100%` inn.
   De to tallene settes fra JS (`paintSeg`) — ingen måling, ingen hardkodet
   segmentbredde, og en tredje fane ville virket av seg selv. Semantikken
   (`role`/`aria-selected`/rullende `tabIndex`) settes det samme stedet.

   FLATEN ER DEN GRØNNE ＋-KNAPPENS (`--grad-green`). Den bærer derfor SVARTE
   ikoner og MØRKT blekk, ikke hvitt — nøyaktig kontrakten `.btn-solid` pinner
   (se kontrast-kontrakten øverst), og tokenene pinnes på samme måte her, så
   den mørke drakten ikke kan lyse dem opp på en flate som ikke skifter. */
.seg {
  touch-action: pan-y;       /* sidelengs er dragets, loddrett er scrollens */
  position: relative;
  /* GRID, ikke flex: `grid-auto-columns: 1fr` gir segmentene like brede spor OG
     lar beholderen bli så bred at det bredeste segmentet får plass i sitt eget
     spor. Med `flex: 1 1 0` blir beholderen bare summen av innholdet, og da
     klemmer `min-width: auto` det lengste segmentet ut av takt — målt: 51/71/86
     px i stedet for tre like. Like brede segmenter er hele forutsetningen for at
     markøren kan flyttes med ren brøkregning. */
  display: inline-grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  align-items: center;
  align-self: center;
  /* Ingen gap: segmentene ligger inntil hverandre, og det er den glidende
     flaten som skiller dem. Et gap ville dessuten gjort «ett segment» til noe
     annet enn `100% / n`. */
  gap: 0;
  padding: 3px;
  border-radius: 999px;
  background: var(--control-bg);
  box-shadow: var(--shadow-sm);
}
.seg::before {
  content: '';
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 3px;
  width: calc((100% - 6px) / var(--seg-n, 1));
  border-radius: 999px;
  background: var(--grad-green);
  box-shadow: var(--shadow-sm);
  /* `--seg-drag` er dragets BRØKDELS-indeks og overstyrer hvilestillingen
     mens fingeren er nede (`attachToggleDrag`). Hvilestillingen (`--seg-i`,
     et helt tall fra `paintSeg`) står urørt under, så et slipp bare fjerner
     overstyringen og lar den vanlige overgangen gli på plass. */
  transform: translateX(calc(var(--seg-drag, var(--seg-i, 0)) * 100%));
  transition: transform var(--switch-motion);
}
/* Under selve draget følger flaten fingeren direkte — en overgang ville lagt
   seg som et etterslep mellom fingeren og flaten. */
.seg.is-tog-drag::before { transition: none; }
.seg-btn {
  position: relative;        /* over den glidende flaten */
  /* LIKE BREDE ER EN INVARIANT, IKKE ET ØNSKE. Rutenett-elementer har
     `min-width: auto` og nekter å krympe under sitt eget innhold, så på en
     smal nok skjerm sluttet sporene å være like: da traff verken den glidende
     flaten (`100% / --seg-n`) eller dragets geometri (`togGeometry`, samme
     regnestykke) segmentene lenger, og etiketten rant ut av pillen (MÅLT på
     280 px: 68/93/60 px i en 200 px bred bryter, med markøren på 65). Med 0
     krymper sporene i takt og regnestykket holder hele veien ned. */
  min-width: 0;
  appearance: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  white-space: nowrap;
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: 1;
  padding: 6px 14px;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-soft);
  transition: color var(--switch-motion), opacity var(--switch-motion);
}
.seg-btn:not(.is-active) { opacity: 0.72; }
.seg-btn:not(.is-active):hover { opacity: 1; color: var(--ink); }
/* Det aktive segmentet står PÅ den grønne flaten. Ikonene pinnes som på
   `.btn-solid`: gradienten er den samme i begge drakter, så streken oppå skal
   stå stille.

   ETIKETTEN ER HVIT MED KONTUR, ikke mørk. Mørkt blekk på den lyse grønne ga
   en matt, lavkontrasts etikett akkurat der valget skal være tydeligst — og
   appen har allerede ett svar på «hvit skrift på en vilkårlig farget flate»:
   skygge pluss full svart kontur, det samme korttitlene bruker. Da leser det
   aktive segmentet som en markert flate og ikke som en litt annen gråtone, og
   det gjør det likt i begge drakter. */
.seg-btn.is-active {
  --icon-ink: #111111;
  --icon-paper: #ffffff;
  --icon-grey: #c0c4c9;
  color: #fff;
  text-shadow: var(--text-shadow);
  -webkit-text-stroke: 1px #000;
  paint-order: stroke fill;
  font-weight: 800;
}
.seg-btn:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .seg::before { transition: none; }
}

/* HOVEDBRYTEREN: Lister ↔ Notater, `.seg` i header-størrelse, på panelets egen
   øverste linje — sentrert i HELE headerens bredde, ikke skjøvet til side av
   hjørnegruppen. Gruppen skyves i stedet ned like mye som denne raden er høy
   (`--main-tabs-h`, målt i syncTopChrome), så bryteren ligger alene øverst.
   Kompakt med vilje: høyde er mangelvaren i landskap (se .topbar). */
/* Bryteren midtstilles både når raden er vannrett (bred skjerm) og når
   `.topbar-row` stables til en kolonne under 620 px. */
.topbar-row-tabs { justify-content: center; align-items: center; }
.main-tab { padding: 7px 14px; }
.main-tab > .icon { width: 20px; height: 20px; flex: none; }

/* NOTATKORTET er et LISTEKORT: samme `.card`-flate, samme korthode, samme
   palettfarge fra posisjonen (colorForIndex/paintCardColor), og innholdet på
   en `--plate` i kroppen. Ingen egne kontrastregler — det er nøyaktig de
   flatene tests/a11y-contrast.test.js allerede måler. Hele kortet er
   klikkflate (åpner editoren) og dra-sone. */
.note-card { cursor: pointer; }
.note-card:focus-visible {
  outline: var(--focus-w) solid var(--focus);
  outline-offset: 2px;
}
.note-card-head { align-items: flex-start; }
/* Ikonet står på FØRSTE tittellinje, slik det gjør på alle andre objekttyper —
   der er hodet `align-items: center` og tittelen én linje, så de to havner på
   samme skriftlinje av seg selv. Notatkortets hode er topp-justert fordi
   tittelen kan gå over flere linjer, og et rent `flex-start` la ikonet på
   TOPPEN av tittelblokka i stedet for midt på dens første linje. Ikonet får
   derfor høyden til den linjeboksen (tittelens skriftstørrelse × linjefall +
   dens egen polstring) og sentreres i den. Størrelsen er den samme som
   type-ikonene i nav-modalen (`.nav-board .kind-icon`), så et notat leser likt
   uansett hvor det står. */
.note-card-head > .note-card-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  font-size: var(--fs-lg);
  line-height: 1;
  height: calc(var(--fs-lg) * 1.2 + 8px);
}
.note-card-title {
  /* `.card-title` gir hvit skrift med skygge på korthodet; her bare linjefallet
     for en tittel som kan gå over flere linjer. */
  overflow-wrap: anywhere;
}
/* «Sist endret» øverst til HØYRE i hodet — samme chip som listenes meta-rad,
   men den er ren informasjon og skal ikke se ut som en knapp. */
.note-card-meta {
  flex: 0 0 auto;
  cursor: inherit;
  align-self: flex-start;
}
/* IKKE flex: `.card-body` er det, og en flex-item BLOKKIFISERES — da faller
   `-webkit-box` (og dermed linjeklippingen på utdraget) bort. */
/* SYMMETRISK LUFT: like mye over utdraget som under og på sidene. Uten
   toppolstringen lå utdragsplaten inntil hodet over, og kortet leste som to
   flater som var klistret sammen. Kroppen skjules helt når den er tom
   (`hidden` fra renderNoteCard) — en padding uten innhold ble ellers stående
   som en lav, tom stripe under hodet på et notat uten tekst. */
.note-card-body { display: block; padding: 10px; }
/* Utdraget står på listepunktets plate — den flaten brødtekst i `--ink` er
   målt mot i begge drakter, oppå kortets egen palettfarge. */
.note-card-excerpt {
  margin: 0;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--plate);
  font-size: var(--fs-sm);
  color: var(--ink);
}
/* LINJEKLIPPINGEN LIGGER PÅ EN INDRE NODE, ikke på platen selv: `overflow`
   klipper ved PADDING-boksen, så en linje utover klippet ville blitt stående
   synlig i platens egen bunnpolstring. Tre linjer holder kortene noenlunde
   like høye uten å kappe et utdrag som så vidt får plass. */
.note-card-excerpt-text {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}
.note-card-excerpt[hidden] { display: none; }

/* BOKHYLLEN i nav-modalen: områdekortet, uten deling og kategorier. Hodet er
   et trekkspill som områdenes, og tittelen står på kortfargen som deres. */
.note-project-card .card-body { padding-bottom: 6px; }
.notes-add-project { display: flex; justify-content: center; margin: 4px 0 2px; }
.note-book-icon { flex: none; }
/* «Frie notater»-raden er bokhyllens EGEN plass — den står først, og skiller
   seg fra notatbøkene med kursiv tittel og ingen tellepille når den er tom. */
.note-free-row .item-text { font-style: italic; }

/* ------------------------------------------------------------
   EDITOREN
   ------------------------------------------------------------
   Et eget fullskjermsbilde OVER hele appflaten — også over toppkontrollene,
   som er `z-index: 35`. Flaten festes til det SYNLIGE feltet (`--viewport-*`),
   ikke til layoutviewporten: med mobiltastaturet oppe er de to ikke det samme,
   og verktøylinjen skal bli stående synlig. Den sikre sonen legges på her,
   ikke på barna: baren skal ikke ligge under statusfeltet, og teksten ikke
   under gestelinjen. */
.note-editor {
  position: fixed;
  left: 0;
  right: 0;
  top: var(--viewport-top);
  height: var(--viewport-h);
  z-index: 60;
  display: flex;
  flex-direction: column;
  /* Bakgrunnen er board-flaten: selve ARKET under er papiret (se .note-sheet). */
  background: var(--bg);
}
/* Hjørnegruppen ville ellers ligget oppå verktøylinjen — idéer og drakt finnes
   i stedet i editorens egen linje (.note-editor-aside). */
body.note-editing .corner-controls { display: none; }
.note-editor-bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: calc(10px + var(--safe-top)) calc(10px + var(--safe-right))
           10px calc(10px + var(--safe-left));
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
.note-back { flex: 0 0 auto; }
/* VERKTØYENE BRYTES, DE RULLER ALDRI. Et verktøy man må lete etter er et
   verktøy man ikke bruker: får ikke knappene plass på én linje, legger de seg
   på flere. Gruppen er sentrert i plassen mellom tilbakeknappen og
   høyresiden. */
/* `gap: 6px` er ikke en smaksavgjørelse: knappene er 38 px og
   berøringsflaten 44, så 6 er nøyaktig luften som gjør 44 mulig uten at to
   nabo-flater overlapper — samme regnestykke som `gap: 8` i kontrollradene
   (docs/tilgjengelighet.md, «Berøringsflater»). Gjelder begge veier: linjene
   brytes, så radavstanden er den samme gapen. */
.note-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px;
  flex: 1 1 auto;
  min-width: 0;
}
.note-editor-aside {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 6px;
}
/* Idé- og draktknappen i editoren er hjørnegruppens knapper, i editorens egen
   linje. Samme flate, samme mål, samme ikon. */
.note-editor-btn { flex: 0 0 auto; }
.note-tool {
  appearance: none;
  cursor: pointer;
  flex: 0 0 auto;
  min-width: 38px;
  height: 38px;
  display: inline-grid;
  place-items: center;
  padding: 0 8px;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink-soft);
  font-family: inherit;
  font-size: var(--fs-sm);
  line-height: 1;
  transition: background 0.15s, color 0.15s;
}
.note-tool:hover { background: var(--control-bg); color: var(--ink); }
.note-tool.is-on { background: var(--control-bg-hover); color: var(--ink); box-shadow: var(--shadow-sm); }
.note-tool:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 1px; }
.note-tool .icon { width: 20px; height: 20px; }
.note-tool-text { font-weight: 700; }
/* Overskriftsknappene VISER de tre nivåene: H1 er størst, H3 minst — samme
   rangorden som dokumentets egne overskrifter (.note-doc h1–h3). Uten det er
   tre like store knapper bare tre etiketter. */
.note-tool-h1 { font-size: 1.15em; font-weight: 800; }
.note-tool-h2 { font-size: 1em; font-weight: 700; }
.note-tool-h3 { font-size: 0.86em; font-weight: 600; }
.note-tool-b { font-weight: 800; }
.note-tool-i { font-style: italic; }
.note-tool-u { text-decoration: underline; }
.note-tool-sep {
  flex: 0 0 auto;
  width: 1px;
  height: 22px;
  margin: 0 2px;
  background: var(--line);
}
.note-save-status {
  flex: 0 0 auto;
  font-size: var(--fs-xs);
  color: var(--ink-soft);
  min-width: 5.5em;
  text-align: right;
}
/* «Andre redigerer nå» (docs/notater-plan.md). Diskret med vilje: den skal
   fortelle at man ikke er alene, ikke ta oppmerksomhet fra det man skriver.
   Prikken bruker den samme grønnfargen som resten av appens «i orden», og
   pulsen slås av for den som har bedt om mindre bevegelse. */
/* `display` slår `[hidden]` fra nettleserens eget stilark, så den må settes
   tilbake eksplisitt — ellers står chipen synlig hele tiden og tar plass i en
   verktøylinje som allerede er trang. */
.note-live[hidden] { display: none; }
.note-live {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-xs);
  color: var(--ink-soft);
  white-space: nowrap;
}
.note-live-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--primary);
  animation: note-live-pulse 1.8s ease-in-out infinite;
}
@keyframes note-live-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}
@media (prefers-reduced-motion: reduce) {
  .note-live-dot { animation: none; }
}
/* På en smal skjerm er verktøylinjen allerede trang: da holder prikken, og
   teksten står igjen i hjelpeteksten for skjermleseren. */
@media (max-width: 560px) {
  .note-live span:not(.note-live-dot) {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
}

/* PANELENE (lenke og spesialtegn) FORANKRES UNDER KNAPPEN SIN. Posisjonen
   settes i JS (placeNotePanel), som også klemmer panelet innenfor det synlige
   feltet og snur det over knappen når det ikke er plass under. Her står bare
   flaten. */
.note-panel {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 2;
  width: max-content;
  max-width: min(520px, calc(100vw - 20px));
  padding: 10px;
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  border: 1px solid var(--line);
}
.note-link-panel { display: flex; flex-direction: column; gap: 8px; width: 320px; }
.note-panel-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.note-symbol-panel {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  width: 360px;
  max-height: 45vh;
  overflow-y: auto;
}
.note-symbol {
  appearance: none;
  cursor: pointer;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--control-bg);
  color: var(--ink);
  font-family: inherit;
  font-size: var(--fs-base);
}
.note-symbol:hover { background: var(--control-bg-hover); }
.note-symbol:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: 1px; }

/* BUNNEN HOLDER AV PLASS TIL SYNK-PILLEN. Den ligger `position: fixed` nederst
   til venstre med `z-index: 290`, altså OVER bildet (60), og den skal bli der:
   det er det eneste stedet «frakoblet» og «noe gikk galt» sier fra, og det er
   nettopp mens man skriver man trenger å vite det. Da er det teksten som må
   vike — akkurat som board-et holder av høyden til slippfoten. Uten dette lå
   de siste linjene i et langt notat under pillen. */
.note-editor-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 18px calc(18px + var(--safe-right)) calc(24px + var(--safe-bottom) + var(--sync-pill-h))
           calc(18px + var(--safe-left));
}
.note-sheet-wrap {
  width: 100%;
  max-width: 760px;
  margin: 0 auto;
}
/* TITTELEN LIGGER OVER ARKET, med notatikonet foran seg — den er notatets NAVN,
   ikke dokumentets første overskrift, og skal ikke kunne forveksles med en H1
   inne i teksten. Den står på board-flaten, ikke på papiret, så den bærer den
   samme hvite skriften med skygge som alt annet på den flaten
   (.card-title, .empty-state). */
.note-title-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 4px;
  margin: 0 0 10px;
}
.note-title-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  font-size: var(--fs-xl);
  line-height: 1;
}
.note-title-input {
  display: block;
  flex: 1 1 auto;
  min-width: 0;
  appearance: none;
  border: none;
  background: transparent;
  color: #fff;
  text-shadow: var(--text-shadow);
  font-family: inherit;
  font-size: var(--fs-xl);
  font-weight: 700;
  padding: 4px 2px;
}
.note-title-input::placeholder { color: rgba(255, 255, 255, 0.72); }
.note-title-input:focus { outline: none; }
.note-title-input:focus-visible {
  outline: var(--focus-w) solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
/* ARKET: et tydelig avgrenset kort som VOKSER med innholdet. Minstehøyden er
   en halv skjerm, så et tomt notat fortsatt ser ut som et ark. */
.note-sheet {
  padding: 20px 22px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}
.note-doc {
  /* Innrykket per overskriftsnivå. Ett trinn, litt mindre på telefon. */
  --note-indent: 22px;
  min-height: 42vh;
  font-size: var(--fs-base);
  color: var(--ink);
  line-height: 1.55;
  /* Linjeskift inne i en blokk bæres som et tegn i dokumentmodellen. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.note-doc:focus { outline: none; }
.note-doc h1 { font-size: 1.6em; font-weight: 800; margin: 0.7em 0 0.3em; }
.note-doc h2 { font-size: 1.35em; font-weight: 700; margin: 0.7em 0 0.3em; }
.note-doc h3 { font-size: 1.15em; font-weight: 700; margin: 0.7em 0 0.3em; }
.note-doc p { margin: 0 0 0.6em; }
.note-doc ul, .note-doc ol { margin: 0 0 0.6em; padding-left: 1.6em; }
.note-doc li { margin: 0 0 0.2em; }
.note-doc hr { border: none; border-top: 1px solid var(--line); margin: 1em 0; }
/* OVERSKRIFTSHIERARKIET SES SOM INNRYKK. En overskrift eier innholdet fram til
   neste overskrift på samme eller høyere nivå, og hvert nøstede nivå rykkes ett
   trinn inn. Nivået er en AVLEDET VISNING — `noteApplyIndent()` regner det ut
   av blokkrekkefølgen og skriver `data-lvl`; dokumentmodellen lagrer det ikke.
   Ingen trekkspill, trekanter eller nivåfarger: bare innrykket. */
.note-doc > [data-lvl="1"] { margin-left: var(--note-indent); }
.note-doc > [data-lvl="2"] { margin-left: calc(var(--note-indent) * 2); }
.note-doc > [data-lvl="3"] { margin-left: calc(var(--note-indent) * 3); }
/* Lenken er MERKET tekst med adressen i `data-url` — ikke et anker. Se
   docs/domains-and-urls.md og noteRunNode() i app.js. */
.note-doc .note-link {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
/* I et SKRIVEBESKYTTET notat er lenken et tabbstopp (app.js:
   applyNoteEditorAccess) — og da må den ha en synlig ring som alt annet man
   kan nå med tastaturet. Ringen ligger utenpå tekstlinjen, så den ikke skyver
   på avstanden mellom linjene. */
.note-doc .note-link:focus-visible {
  outline: var(--focus-w) solid var(--focus);
  outline-offset: 2px;
  border-radius: 3px;
}

/* Telefon i portrett: verktøyene får HELE bredden på sin egen rad under
   tilbakeknappen og høyresiden. De brytes uansett (aldri rull), men på en
   delt rad ville de brutt til fem korte linjer i stedet for to lange.
   Tilbakeknappen viser bare pilen — teksten ville spist plassen. Innrykket
   blir ett hakk mindre. */
@media (max-width: 560px) {
  .note-editor-bar { flex-wrap: wrap; }
  .note-tools { order: 3; flex: 1 1 100%; }
  .note-editor-aside { margin-left: auto; }
  .note-back > span { display: none; }
  .note-editor-body { padding-left: calc(12px + var(--safe-left)); padding-right: calc(12px + var(--safe-right)); }
  .note-sheet { padding: 14px 14px; }
  .note-doc { --note-indent: 14px; }
  .note-link-panel, .note-symbol-panel { width: auto; }
}


/* ============================================================
   SØKESCOPE, KOBLINGER OG NOTATENES KASSER
   Autoritativt: docs/sok-og-navigering.md og docs/notater-plan.md.
   ============================================================ */

/* Scopevelgeren i søket er `.seg` i sin minste bruk — formen står ved
   hovedbryteren i header-seksjonen, og her settes bare plasseringen. */
.search-scope { margin: 0 auto 2px; }

/* Utdraget fra notatteksten under et treff: sitatet som forklarer HVORFOR
   notatet står i lista. Det brytes over inntil to linjer og kappes så — raden
   skal fortsatt kunne skummes. */
.search-result-snippet {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: var(--fs-xs);
  color: var(--ink-soft);
  font-style: italic;
}

/* Koblingsmodalen: to lister med den samme raden — de eksisterende koblingene
   og velgeren. Raden er `[ikon] navn + sti` med en ✕ til høyre. */
.links-body { display: flex; flex-direction: column; gap: 8px; }
.links-heading {
  margin: 4px 0 0;
  font-size: var(--fs-xs);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
}
.links-list { display: flex; flex-direction: column; gap: 6px; }
.links-pick { max-height: 40vh; overflow-y: auto; }
.link-row {
  display: flex;
  align-items: center;
  gap: 6px;
  border-radius: var(--radius-sm);
  background: var(--plate);
}
.link-open {
  appearance: none;
  cursor: pointer;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: inherit;
  font-family: inherit;
  text-align: left;
}
.link-open:hover { background: var(--primary-soft); }
.link-open:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: -2px; }
.link-open[disabled] { cursor: default; opacity: 0.6; }
.link-icon { flex: none; display: inline-flex; }
.link-icon > .icon { width: 20px; height: 20px; }
.link-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* Navnet vises i sin helhet, aldri kappet med ellipsis — det er nettopp der
   brukeren kjenner igjen hva koblingen peker på (samme grunn som i
   søppelkasse-raden, docs/trash.md). */
.link-name { font-weight: 700; overflow-wrap: break-word; }
.link-meta { font-size: var(--fs-xs); color: var(--ink-soft); overflow-wrap: break-word; }
.link-row.is-gone .link-name { font-style: italic; color: var(--ink-soft); }
.link-remove { flex: none; margin-right: 4px; }

/* ------------------------------------------------------------
   NOTATHISTORIKKEN (docs/notater-plan.md, «Historikk»)

   Ingen nye former: modalen er `.modal`, radene er `.plate`-flater som
   koblingsraden, og den åpne raden er et trekkspill som objektmenyens
   undergrupper. Det ENESTE som er nytt her er forhåndsvisningen — et
   skrivebeskyttet ark som gjenbruker `.note-doc` fra editoren, med editorens
   minstehøyde slått av (et bilde skal ta plassen innholdet trenger, ikke en
   halv skjerm).
   ------------------------------------------------------------ */
.note-history-body-wrap { display: flex; flex-direction: column; gap: 8px; }
.note-history-list { display: flex; flex-direction: column; gap: 6px; }
.note-history-row {
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  overflow: hidden;
}
/* En BEHOLDT versjon er skjermet mot opprydningen, og skal kunne kjennes igjen
   i lista uten å åpnes. Markeringen er en kantstripe i aksentfargen — samme
   virkemiddel som andre «denne er spesiell»-rader, ikke en ny farge. */
.note-history-row.is-kept { box-shadow: inset 3px 0 0 0 var(--accent); }
.note-history-head {
  appearance: none;
  cursor: pointer;
  width: 100%;
  /* 44 px berøringsflate, som overalt ellers (docs/tilgjengelighet.md). */
  min-height: 44px;
  display: grid;
  grid-template-columns: 18px 1fr;
  align-items: start;
  gap: 4px 8px;
  padding: 9px 10px;
  border: none;
  background: transparent;
  color: inherit;
  font-family: inherit;
  font-size: var(--fs-base);
  text-align: left;
}
.note-history-head:hover { background: var(--wash); }
.note-history-head:focus-visible { outline: var(--focus-w) solid var(--focus); outline-offset: -2px; }
.note-history-chev {
  grid-row: 1 / span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 1px;
  transition: transform 0.15s;
}
.note-history-chev > .icon { width: 16px; height: 16px; }
.note-history-row.is-open .note-history-chev { transform: rotate(90deg); }
.note-history-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  min-width: 0;
}
.note-history-when { font-weight: 700; }
/* «Nå» er den ferskeste raden — den man kommer tilbake til hvis en
   gjenoppretting var feil. */
.note-history-now {
  font-size: var(--fs-xs);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--accent);
}
.note-history-kept { display: inline-flex; }
.note-history-kept > .icon { width: 15px; height: 15px; }
/* Tegntallet er der historikken faktisk brukes: raden som er MYE kortere enn
   den over er den man leter etter når noe har blitt borte. */
.note-history-size { font-size: var(--fs-xs); color: var(--ink-soft); margin-left: auto; }
.note-history-text {
  grid-column: 2;
  font-size: var(--fs-xs);
  color: var(--ink-soft);
  font-style: italic;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.note-history-body {
  padding: 0 10px 10px 36px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.note-history-doc-title { margin: 0; font-weight: 800; overflow-wrap: break-word; }
.note-history-doc {
  min-height: 0;
  max-height: 40vh;
  overflow-y: auto;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: var(--fs-sm);
}
.note-history-actions { display: flex; flex-wrap: wrap; gap: 8px; }
/* Knappene har appens vanlige flate; utvidelsen til 44 px ligger i luften
   rundt dem, ikke i tegningen (samme regel som editorens verktøy). */
.note-history-actions > .btn { min-height: 38px; }
.note-history-keep.is-on { font-weight: 800; color: var(--accent); }
.note-history-foot { justify-content: flex-end; }

/* ------------------------------------------------------------
   VERSJONSSAMMENLIGNING (docs/notater-plan.md, «Versjonssammenligning»)

   Ingen ny kontroll og ingen ny modal: bryteren mellom «Hele versjonen» og
   «Endringer» er appens egen segmenterte bryter (`.seg`), og diffen tegnes i
   det SAMME arket som forhåndsvisningen (`.note-doc`).

   TRE ROLLER, TRE TOKENS SOM ALLEREDE SNUR MED DRAKTEN: det som kom til er
   grønt (`--primary-ink` på `--primary-soft`), det som falt bort er rødt
   (`--danger-ink` på `--danger-soft`), og det som bare byttet formatering er
   notatgult (`--note-ink`) med en stiplet strek. En blokk som ble FLYTTET er
   ingen av delene — ingenting ble borte — og står derfor dempet, med en
   kantstripe i aksentfargen. Ingen nye fargeverdier: kontrastkontrakten i
   docs/design-system.md gjelder som den er.

   FARGEN ER ALDRI DEN ENESTE BÆREREN. Hver endret linje har en usynlig
   merkelapp foran seg som skjermleseren leser («Lagt til: …»), det som kom til
   ligger i `<ins>` og det som falt bort i `<del>`, og strek-under/gjennom
   skiller de to også uten farge (docs/tilgjengelighet.md).
   ------------------------------------------------------------ */
/* Bryteren tar 44 px, som alt annet man trykker på. `.seg` tegner selv de 3 px
   luft rundt segmentene, så flaten blir 50 px høy og segmentene nøyaktig 44. */
.note-history-views { align-self: flex-start; max-width: 100%; }
.note-history-views .seg-btn { min-height: 44px; padding: 6px 16px; }

.note-diff-summary {
  margin: 0;
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--ink-soft);
  overflow-wrap: break-word;
}
.note-diff-summary.is-none { font-weight: 600; font-style: italic; }
.note-diff-title-row {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  font-weight: 800;
  overflow-wrap: break-word;
}
.note-diff-title-label {
  font-size: var(--fs-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
}
/* Linjene som ikke er endret står med, men dempet: uten dem kunne man ikke se
   HVOR i notatet endringen skjedde. */
.note-diff-doc .note-diff-line { position: relative; }
.note-diff-doc .note-diff-line.is-same { color: var(--ink-soft); }
.note-diff-doc .note-diff-line.is-add,
.note-diff-doc .note-diff-line.is-del,
.note-diff-doc .note-diff-line.is-chg,
.note-diff-doc .note-diff-line.is-fmt,
.note-diff-doc .note-diff-line.is-move {
  border-radius: var(--radius-sm);
  padding-inline: 6px;
  margin-inline: -6px;
}
.note-diff-doc .note-diff-line.is-add { box-shadow: inset 3px 0 0 0 var(--primary); }
.note-diff-doc .note-diff-line.is-del { box-shadow: inset 3px 0 0 0 var(--danger); }
.note-diff-doc .note-diff-line.is-chg { box-shadow: inset 3px 0 0 0 var(--accent); }
.note-diff-doc .note-diff-line.is-fmt { box-shadow: inset 3px 0 0 0 var(--note-ink); }
.note-diff-doc .note-diff-line.is-move {
  box-shadow: inset 3px 0 0 0 var(--accent);
  color: var(--ink-soft);
  font-style: italic;
}
/* Listepunktene beholder sin egen kule/nummerering: en punktliste skal LESES
   som en liste også når bare ett av punktene er endret. */
.note-diff-doc .note-diff-list { margin: 0; padding-left: 1.4em; }

/* «avsnitt → overskrift 2»: en liten, rolig etikett — den forklarer linjen,
   den er ikke en del av teksten. */
.note-diff-kind {
  display: inline-block;
  margin-right: 6px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--wash);
  font-size: var(--fs-xs);
  font-weight: 700;
  font-style: normal;
  color: var(--ink-soft);
  vertical-align: middle;
}

.note-diff-ins,
.note-diff-del,
.note-diff-fmt { border-radius: 3px; padding: 0 2px; }
.note-diff-ins {
  background: var(--primary-soft);
  color: var(--primary-ink);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 2px;
}
.note-diff-del {
  background: var(--danger-soft);
  color: var(--danger-ink);
  text-decoration: line-through;
  text-decoration-thickness: 2px;
}
.note-diff-fmt {
  color: var(--note-ink);
  text-decoration: underline dotted;
  text-decoration-thickness: 2px;
  text-underline-offset: 2px;
}

/* På telefon er innrykket under raden dyrt: teksten skal ha bredden. */
@media (max-width: 560px) {
  .note-history-body { padding-left: 10px; }
  .note-history-doc { max-height: 34vh; }
  /* Bryteren tar hele bredden i stedet for å bli klemt sammen — og etiketten
     BRYTES i stedet for å bli klippet. `.seg-btn` er `nowrap` fordi de andre
     bryterne har korte ord; her er ordene lengre, og de er ulike på hvert
     språk. Et klippet segment er verre enn et som går over to linjer. */
  .note-history-views { align-self: stretch; display: grid; }
  .note-history-views .seg-btn {
    padding: 6px 8px;
    white-space: normal;
    line-height: 1.15;
    text-align: center;
  }
}

/* Koblingsraden i notatkortets kropp — chipen under utdraget. */
.note-card-links { display: flex; margin-top: 6px; }

/* Koblingschipen på et objekt: samme `.meta-chip` som tid og ansvarlig. Den
   står i en `.title-line` ved siden av navnet (og i notatkortets kropp), så den
   må aldri strekke seg: `flex: none` holder den på sin egen bredde uansett om
   forelderen er en rad eller en kolonne. */
.meta-chip.meta-link { gap: 4px; flex: 0 0 auto; align-self: center; }
/* Mapperaden har ingen `.title-line` — der står chipen i `.item-main`, som er
   en KOLONNE, og da er «på linje med toppen» det som ser riktig ut. */
.item-main > .meta-chip.meta-link { align-self: flex-start; margin-top: 2px; }
.meta-chip.meta-link > .icon { width: 15px; height: 15px; }

/* Bokhyllekortets to knapper står side om side, som ÉN rad nederst i kortet. */
.note-folder-cans { display: flex; justify-content: center; gap: 8px; }
.nav-foot { gap: 8px; }
