# Slides

Presentasjoner bygget med native web components, uten navigasjons-/
tilstandslogikk i JS - all navigasjon, visning og utskrift løses med CSS
og vanlige anker-lenker. Se `.github/instructions/slides.instructions.md`
for de fulle prosjekt-instruksjonene (harde krav, arkitektur,
komponentbruk).

## Hvordan presentasjonene fungerer, i vanlig språk

Denne seksjonen er ment å kunne leses av hvem som helst - også uten
programmerings-bakgrunn - for å forstå hva som faktisk skjer, f.eks. hvis
du designer en presentasjon og vil forstå rammene du designer innenfor.

**Én fil per slide, ikke én fil for hele presentasjonen.** En presentasjon
("deck") er en mappe, f.eks. `slides/mitt-foredrag/`, med én HTML-fil per
slide (`slide-1.html`, `slide-2.html`, ...). Tenk på hver fil som et fast
16:9-"artboard" i et design-verktøy: alltid samme proporsjon, skalert opp
eller ned til å fylle skjermen/vinduet uten å bli beskåret eller strukket.
Å bla i presentasjonen er derfor bokstavelig talt å besøke en ny side -
ikke annerledes enn å klikke seg gjennom flere vanlige nettsider.

**Å bla videre = å klikke en usynlig lenke til neste fil.** Det finnes
bevisst ingen synlige piler eller sidetall. I stedet ligger det en
usynlig, klikkbar sone langs venstre kant (forrige) og høyre kant (neste)
av hvert artboard - akkurat som de usynlige "hotspot"-sonene man tegner i
et interaktivt prototype-verktøy. Klikk (eller Tab + Enter på tastaturet)
i en av disse sonene navigerer nettleseren til `forrige-slide.html` eller
`neste-slide.html` - helt vanlig lenkenavigasjon, ingen JS involvert.
Nettleserens frem/tilbake-knapper fungerer derfor helt av seg selv.

**Myke overganger mellom slides er valgfritt, og kun CSS.** Siden hvert
bytte er en ekte sidenavigasjon, kan nettleserens innebygde
"view transitions"-mekanisme brukes til å myke opp byttet (en kryssfade,
en glidning, en zoom, eller en delt elementovergang for tittelen) - helt
uten JavaScript. Dette er av og på per
presentasjon (se "Myke overganger mellom slides" lenger ned) - uten å slå
det på ser byttet ut som en vanlig, øyeblikkelig sidenavigasjon.

**Komponentene er gjenbrukbare "slide-typer" med utfyllingsfelter.**
`<lm-slide-tittel>`, `<lm-slide-agenda>`, `<lm-slide-punktliste>` osv. er
ferdige layout-oppskrifter - omtrent som komponenter/instanser i et
design-verktøy. Hver har noen faste "utfyllingsfelter" (kalt *slots* i
koden) du legger innhold i, f.eks. en tittel-plass og en
innholds-plass - selve komponenten bestemmer bare *hvordan* det du legger
inn blir plassert/style, ikke *hva* du skriver.

**Tema velges én gang per fil, ikke per slide.** Et lite attributt øverst
i hver fil (`data-tema="mork"` for eksplisitt mørkt tema, eller ingenting
for å la standardtemaet følge systemets light/dark-preferanse automatisk)
bestemmer farger/aksent for den slide-en - mer som å velge en overordnet
stilprofil for et dokument enn en per-element-innstilling. Det finnes
ingen bryter for å endre tema mens man ser på presentasjonen -
forfatteren bestemmer eventuelle overstyringer på forhånd, og bør sette
samme verdi i alle filene i en deck for et konsistent uttrykk.

**Notater er skjult tekst, ikke en egen fane.** Et lite avsnitt merket
"notater" kan legges inni hver slide - dette vises aldri i selve
presentasjonen (det er teknisk sett ikke koblet til noe synlig sted i
layouten i det hele tatt), men kan leses av en egen telefonvisning (se
under).

**Print/PDF bruker nettleserens egen utskriftsfunksjon** - men siden hver
slide nå er sin egen fil, gir "Skriv ut" på én fil kun ut den ene slide-en.
Se "Skrive ut / lagre som PDF" lenger ned for hva dette betyr i praksis
for en hel deck.

**Presenter view er én egen, delt telefon-skjerm for alle presentasjoner.**
Ett enkelt nettsted (`slides/foredragsholder.html`) er alt en foredragsholder
noensinne trenger å åpne på telefonen, uansett hvilken presentasjon som
holdes. PC-en (via `<lm-slide-nav>`) genererer en QR-kode som peker dit med
riktig kobling forhåndsutfylt. Blar man på telefonen, følger PC-skjermen
automatisk med (og omvendt). Se eget avsnitt lenger ned for hvordan dette
settes opp.

## Lage en ny presentasjon

1. Lag en ny mappe, f.eks. `slides/mitt-foredrag/`.
2. Lag én HTML-fil per slide (`slide-1.html`, `slide-2.html`, ...). Bruk
   `slides/eksempel/slide-1.html` som utgangspunkt for `<head>`-innholdet
   (stilark, delt Web App Manifest og komponent-imports for de slide-typene
   du faktisk bruker). Hver HTML-fil i decken skal lenke inn
   `../manifest.webmanifest` med
   `<link rel="manifest" href="../manifest.webmanifest">`. For hver
   komponent-`<script type="module">` du legger til, legg også til en
   tilsvarende `<link rel="preload" as="style">` for komponentens `.css`-fil
   rett før - se hvorfor i "Ytelse: unngå et kort, usynlig lasteopphold ved
   navigering" lenger ned.
3. Hver fil inneholder ett `<lm-slide>`-element med `forrige`/`neste`-
   attributter som peker på filnavnene til naboene (utelates helt på
   første/siste slide):

```html
<!-- slide-1.html -->
<link rel="manifest" href="../manifest.webmanifest">
<link rel="preload" href="../komponenter/slide/slide.css" as="style">
<script type="module" src="../komponenter/slide/slide.js"></script>
<link rel="preload" href="../komponenter/slide-tittel/slide-tittel.css" as="style">
<script type="module" src="../komponenter/slide-tittel/slide-tittel.js"></script>

<lm-slide id="slide-1" neste="slide-2.html">
    <lm-slide-tittel>
        <h1>Tittel</h1>
        <p slot="undertittel">Undertittel/forfatter</p>
    </lm-slide-tittel>
</lm-slide>
```

```html
<!-- slide-2.html -->
<lm-slide id="slide-2" forrige="slide-1.html" neste="slide-3.html">
    <lm-slide-punktliste>
        <h2 slot="tittel">Overskrift</h2>
        <ul>
            <li>Punkt 1</li>
        </ul>
    </lm-slide-punktliste>
</lm-slide>
```

4. **Valgfritt, men anbefalt:** legg til en `manifest.json` i mappen. Den
   brukes av `<lm-slide-nav>` sin filmstripe, Home/End-hopp og valgfritt
   sidetall, og kan enten være en enkel liste over slides eller et utvidet
   objekt med deck-metadata (se "Informasjonsside og PDF-eksport per deck"
   lenger ned). Uten manifest fungerer vanlig forrige/neste-navigasjon
   fortsatt fint - det er kun "hopp til en vilkårlig slide"-funksjonene som
   trenger den fulle rekkefølgen:

```json
[
    {"fil": "slide-1.html", "tittel": "Tittel"},
    {"fil": "slide-2.html", "tittel": "Overskrift"}
]
```

5. **Valgfritt, men anbefalt for en "ekte" presentasjon:** legg til en
   `index.html` (informasjonsside, `<lm-slide-info>`) og en `utskrift.html`
   (samle-alle-slides-for-PDF, `<lm-slide-utskrift>`) - se
   "Informasjonsside og PDF-eksport per deck" lenger ned. Legg deretter til
   en lenke til deckens `index.html` i `slides/index.html`. For minimale,
   tekniske demo-decks uten slik infoside kan `slides/index.html` fortsatt
   lenke direkte til `slide-1.html`.

## Style din egen presentasjon

Standard-stilen følger med komponentene, men du kan nå overstyre den i din
egen deck uten å forke noen `.css`-filer. Det finnes to mekanismer:

1. **`::part()`** for å treffe de viktigste, navngitte delene inni
   komponentenes shadow DOM.
2. **CSS custom properties** i `slides/styles.css` for delte avstand- og
   layout-verdier som ellers hadde vært hardkodet.

Et konkret eksempel: hvis du vil gjøre tittelslidene større og luftigere,
kan du legge dette i deckens eget `<style>`-element eller stilark.

**Før**
```html
<lm-slide-tittel>
    <h1>Mer minimalistisk</h1>
    <p slot="undertittel">Min egen deck</p>
</lm-slide-tittel>
```

**Etter**
```html
<style>
    :root {
        --slide-tittel-gap: 1rem;
        --slide-tittel-strek-bredde: 6rem;
    }

    lm-slide-tittel::part(tittel) {
        font-size: 2.6em;
        letter-spacing: 0.04em;
        text-transform: uppercase;
    }

    lm-slide-tittel::part(undertittel) {
        font-size: 0.75em;
    }
</style>

<lm-slide-tittel>
    <h1>Mer minimalistisk</h1>
    <p slot="undertittel">Min egen deck</p>
</lm-slide-tittel>
```

Det viktige her er at du ikke trenger å kjenne den interne shadow-DOM-en:
komponenten eksponerer bare de delene som er ment for styling, som
`::part(tittel)`, `::part(undertittel)`, `::part(innhold)`,
`::part(bildetekst)` og `::part(kilde)`. Se
`.github/instructions/slides.instructions.md` for full oversikt over hvilke
`part`-navn og `--slide-*`-variabler som finnes per komponent.

## Navigere i en presentasjon

- Klikk i venstre/høyre 12% av vinduet for å gå tilbake/frem, eller bruk
  Tab + Enter.
- Med `<lm-slide-nav>` lagt til (se under) fungerer i tillegg piltaster for
  forrige/neste, `Home`/`End` mot manifestet, valgfritt sidetall og en
  filmstripe med tekst-miniatyrer (slide-tall + tittel) av alle slides i
  manifestet - hovre helt nederst i vinduet for å vise den, og klikk en
  miniatyr for å hoppe direkte dit. Se
  `slides/komponenter/slide-nav/README.md` for full tasteoversikt og alle
  detaljer om filmstripe/presenter-synk.
- Nettleserens frem/tilbake-knapper fungerer normalt (hver slide er sin
  egen historikk-oppføring, som på hvilken som helst nettside).
- Selve slide-fremvisningen starter fortsatt i første slide-fil
  (`slide-1.html`); en eventuell deck-`index.html` er bare en infoside
  foran denne, ikke et eget JS-startpunkt.

Legg til `<lm-slide-nav>` for tastatur/filmstripe-navigasjon i hver fil:
```html
<script type="module" src="../komponenter/slide-nav/slide-nav.js"></script>
...
<lm-slide-nav manifest="manifest.json"></lm-slide-nav>
```
(valgfritt - se `slides/komponenter/slide-nav/README.md` for detaljer)

## Myke overganger mellom slides

Valgfritt, av/på per presentasjon - uten dette navigerer sidene øyeblikkelig
(som en vanlig lenke), akkurat som før. For å slå det på i en deck:

1. Legg til `<link rel="stylesheet" href="../overganger.css">` i hver fil.
2. For en eksplisitt variant: sett `data-slide-overganger="gli"`, `"zoom"`
   eller `"element"` på `<html>`-elementet i hver fil (samme verdi i hele
   decken). Vil du bare ha standard kryssfade, holder det å lenke inn
   stilarket; `data-slide-overganger="fade"` kan brukes som en tydelig,
   men valgfri markering i markupen.

```html
<html lang="no" data-slide-overganger="gli">
```

`"element"` bruker fortsatt en vanlig helside-kryssfade for resten av
sliden, men gir tittelen i `<lm-slide-tittel>` et eget
`view-transition-name` slik at tittelen kan flytte seg og endre størrelse
mykt mellom to påfølgende slides når begge har en tittel.

Se `slides/eksempel-overganger/` for fire komplette, minimale eksempel-decks
(én per variant) og `slides/overganger.css` for selve implementasjonen -
kun `@view-transition { navigation: auto; }`, noen
`::view-transition-old/new(root)`-regler og én navngitt elementovergang,
ingen JavaScript.

## Ytelse: unngå et kort, usynlig lasteopphold ved navigering

Hver `slide-*`-komponent henter sin egen `.css`-fil asynkront (`fetch()`,
se f.eks. `komponenter/slide/slide.js`) - helt vanlig i dette repoet, men
det betyr at nettleseren normalt først må laste ned og kjøre selve
`.js`-filen **før** den i det hele tatt starter nedlastingen av den
tilhørende `.css`-filen (skriptet er det som ber om den). `<lm-slide>` er
bevisst usynlig (`visibility: hidden`, se `slides/styles.css`) helt til
den er ferdig oppgradert, nettopp for at man aldri skal se rå, ustylet
tekst i dette vinduet - men selve vinduet (noen titalls millisekunder,
mer på en tregere tilkobling) er fortsatt reelt, og kan oppleves som en
kort, tom "pause" med kun bakgrunnsfargen synlig rett etter en navigering.

Løsningen er ett enkelt, standard `<link rel="preload" as="style">`-hint
per komponent, plassert rett før den tilhørende `<script>`-taggen - dette
lar nettleseren starte nedlastingen av `.css`-filen **parallelt** med
`.js`-filen (oppdaget direkte av HTML-parserens forhåndsskanner), i stedet
for at den ene må vente på den andre. Se steg 2 i "Lage en ny
presentasjon" over, eller hvilken som helst fil i `slides/eksempel/`/
`slides/eksempel-overganger/` for eksempler - mønsteret er alltid det
samme: én `<link rel="preload">` per `<script type="module">`, samme
filnavn, kun `.css` i stedet for `.js`.

Dette er en ren `<head>`-tilleggslinje (ingen JavaScript), og regnes
derfor ikke som et av de dokumenterte JS-unntakene i
`.github/instructions/slides.instructions.md` - det er valgfritt, men
anbefalt for alle nye slide-filer.

### Bilder i `<lm-slide-bilde>`

`<lm-slide-bilde>` eier ikke noe eget `<img>`-element; komponenten slotter
bare bildet som forfatteren selv skriver i HTML-en. Når du bruker
komponenten, anbefales det derfor å sette `decoding="async"` direkte på
ditt eget `<img>`:

```html
<lm-slide-bilde>
    <img src="skjermbilde.png" alt="Beskrivende alt-tekst" decoding="async">
</lm-slide-bilde>
```

Dette er en enkel, ubetinget nyttig anbefaling: nettleseren kan dekode
bildet asynkront i stedet for å blokkere hovedtråden unødvendig.

`loading="lazy"` anbefales **ikke** som generell regel for slike
slide-bilder. I denne arkitekturen er hver slide en egen, fullskjerms
HTML-side uten scrolling, og bildet er som regel selve hovedinnholdet
(ofte LCP-elementet) på den siden. Lazy-loading sin vanlige gevinst -
å utsette henting av innhold utenfor synsfeltet - gjelder derfor i
praksis lite eller ikke i det hele tatt her. `<lm-slide-nav>`s filmstripe
har ingen levende `<iframe>` i det hele tatt (kun tekst-miniatyrer, se
`slide-nav/README.md`) - lazy-loading av selve slide-innholdet er derfor
ikke relevant der; `<lm-slide-info>`s "Alle slides"-rutenett er stedet i
`slides/` som fortsatt bruker levende `<iframe loading="lazy">`.

## Offline: presentasjonen virker også uten nett etter første besøk

Når en presentasjon først er åpnet én gang i nettleseren, lagres de
relevante filene lokalt i bakgrunnen. Det betyr at den samme decken som
regel fortsatt kan åpnes igjen selv om du senere mister nettet på toget,
i et møterom eller på scenen - så lenge akkurat disse slidene allerede har
vært besøkt på denne enheten/nettleseren.

Teknisk skjer dette via en service worker som hører til `slides/`:
nettleseren bruker en lagret kopi umiddelbart hvis den finnes, og prøver
samtidig å hente en fersk versjon i bakgrunnen når nettverket er oppe.
For deg som lager/holder presentasjonen betyr det bare: åpne decken én
gang på forhånd på enheten du faktisk skal bruke, så er du langt mindre
sårbar for midlertidig nett-trøbbel.

Den samme generiske stale-while-revalidate-strategien fanger også opp den
delte `manifest.webmanifest`-filen og SVG-ikonet den peker på, så disse
installasjonsfilene blir cachet automatisk uten ekstra konfigurasjon.

## Installerbar på hjemskjerm / som app

Alle HTML-filene i en deck kan lenke til den delte
`slides/manifest.webmanifest` med:

```html
<link rel="manifest" href="../manifest.webmanifest">
```

Manifesten er bevisst generisk (`name`/`short_name` = "Presentasjon"),
fordi én delt fil ikke kan kjenne deck-tittelen statisk. Den bruker
`display: "fullscreen"` og den statiske, mørke bakgrunnstoken-verdien fra
`slides/styles.css` (`#111827` fra `--slide-bg`) som både
`theme_color`/`background_color`, siden Web App Manifest ikke kan
evaluere CSS-variabler eller `light-dark()` (og `--slide-accent` nå er
`currentColor`, altså ingen statisk fargeverdi å referere til her).

Ikonet er et håndskrevet SVG (`slides/manifest-ikon.svg`) med
`purpose: "any"`, som fungerer i moderne Chromium-baserte nettlesere uten
eget bildegenereringssteg.

**Kjent begrensning:** iOS/Safari sin "Legg til på Hjem-skjerm" krever et
ekte raster-`apple-touch-icon` (PNG). Denne runden løser derfor
installering via Web App Manifest der SVG støttes, men legger bevisst ikke
til noen Safari-spesifikk hjemskjerm-ikonløsning.

## Tema

Sett `data-tema="mork"` på `<html>`-elementet i hver fil i en deck for å
tvinge mørkt tema. Standardtemaet (ingen `data-tema`) følger automatisk
systemets light/dark-preferanse via `light-dark()` og `color-scheme:
light dark`. Temaet velges fortsatt av forfatteren i markupen - ikke av
en kjøretids-veksler - fordi et eksplisitt `data-tema` alltid overstyrer
systemvalget og bør settes likt i alle filene i én deck for et konsistent
uttrykk.

## Tilgjengelighet: høy kontrast og fokusindikatorer

Slides-oppsettet er auditert for steder der viktige indikatorer ellers kun
var avhengige av temafargen. Konkret betyr det:

- `@media (forced-colors: active)` brukes målrettet på knappelenker,
  utskriftsknappen, `<lm-slide>` sine fokussoner, filmstripens
  `aria-current`-kant og dialog/lukkeknapper i `<lm-slide-nav>`, slik at de
  bruker systemfarger som `Highlight`, `ButtonBorder` og `ButtonText` når
  Windows High Contrast er aktivt.
- `@media (prefers-contrast: more)` forsterker de samme indikatorene via
  delte custom properties i `slides/styles.css` (tykkere fokusring og
  tydeligere "gjeldende slide"-kant), i stedet for å redesigne resten av
  temaet.
- Agenda-punkt markert med `aria-current="step"` får en ekstra understrek i
  høy kontrast / mer kontrast-modus, så "der vi er nå" ikke bare er en
  fargeforskjell.

## Skrive ut / lagre som PDF

Siden en presentasjon nå er mange separate filer, gir nettleserens vanlige
"Skriv ut" (`Ctrl/Cmd+P`) kun ut den ene filen du står på - `@media print`
sørger for at akkurat den slide-en fyller siden pent, uten synlig
klikksone-UI. Dette er en bevisst forenkling sammenlignet med den gamle
ettfils-modellen (der alle slides lå i samme dokument og kunne skrives ut
samlet i én operasjon).

For å eksportere en **hel** deck til PDF i én operasjon: bruk decken sin
`utskrift.html` (se "Informasjonsside og PDF-eksport per deck" under) -
den henter alle slide-filene og setter dem inn i én side, klar til
`Ctrl/Cmd+P` → "Lagre som PDF". Uten en `utskrift.html` (eldre/enkle
decks) er den manuelle fremgangsmåten fortsatt tilgjengelig: skriv ut hver
`slide-N.html`-fil for seg og slå sammen PDF-ene med et PDF-verktøy etter
eget valg (f.eks. `pdfunite`/Forhåndsvisning på macOS/et nettbasert
slå-sammen-verktøy).

## Informasjonsside og PDF-eksport per deck

To valgfrie, men anbefalte filer per "ekte" presentasjon (i tillegg til
selve `slide-N.html`-filene):

- **`index.html`** - en enkel informasjonsside (tittel, beskrivelse,
  antall slides, ressurslenker, en "Start presentasjon"-knapp og en "Last
  ned som PDF"-knapp), bygget med `<lm-slide-info manifest="manifest.json">`.
  `slides/index.html` lenker til denne i stedet for direkte til
  `slide-1.html`.
- **`utskrift.html`** - samler alle slide-filene til én side for
  `Ctrl/Cmd+P` → "Lagre som PDF" i én operasjon, bygget med
  `<lm-slide-utskrift manifest="manifest.json">` (se
  `slides/komponenter/slide-utskrift/README.md` for hvordan den henter
  og setter sammen filene).

Begge leser fra decken sin `manifest.json`, som nå kan skrives i to former:

```json
[
    {"fil": "slide-1.html", "tittel": "..."}
]
```

eller, for å også få en info-side, det utvidede formatet med deck-nivå
metadata:

```json
{
    "tittel": "Min presentasjon",
    "beskrivelse": "Kort om hva presentasjonen handler om.",
    "ressurser": [
        {"tittel": "Lesestoff/kilde", "url": "https://..."}
    ],
    "slides": [
        {"fil": "slide-1.html", "tittel": "..."}
    ]
}
```

`tittel`/`beskrivelse`/`ressurser` er alle valgfrie - kun `slides`-listen
kreves. Se `slides/eksempel/manifest.json`, `slides/eksempel/index.html` og
`slides/eksempel/utskrift.html` for et komplett, fungerende eksempel.

Merk at dette `manifest.json` fortsatt er deckens egen navigasjons-/metadata-
fil for `<lm-slide-nav>`, `<lm-slide-info>` og `<lm-slide-utskrift>` - den
er noe annet enn den delte Web App-manifesten `slides/manifest.webmanifest`.

## Presentasjonsnotater og presenter view

Skriv notater til en slide som et vanlig barn med `slot="notater"` inni
`<lm-slide>` - forblir usynlig i selve presentasjonen (se
`slides.instructions.md` for detaljer), men kan leses av presenter view.

For at foredragsholderen skal kunne bruke telefonen som presenter view
(nåværende/neste slide, notater, tidtaker) mens PC-en viser selve
presentasjonen, trengs en kjørende relay-server (se
`slides/presenter-server/README.md` for hvordan man kjører den). Legg til
`<lm-slide-nav relay="...">` i hver fil i decken:

```html
<lm-slide-nav relay="wss://din-relay-server" manifest="manifest.json"></lm-slide-nav>
```

Telefonen trenger **ikke** noe eget oppsett per presentasjon - den åpner
alltid den samme, delte `slides/foredragsholder.html`. Trykk `P` på PC-en
for å vise en øktkode + QR-kode som peker dit med kode og relay-adresse
forhåndsutfylt. Se `slides/komponenter/slide-nav/README.md` og
`slides/komponenter/foredragsholder-visning/README.md` for full detaljer.

### Teste presenter view lokalt

`slides/eksempel/` er allerede satt opp for lokal testing (peker på
`ws://localhost:8787`). Kjør disse tre stegene fra repo-roten, hver i sitt
eget terminalvindu:

1. **Start relay-serveren:**
   ```bash
   node slides/presenter-server/server.js
   ```
   (bruk `PORT=8877 node slides/presenter-server/server.js` for en annen
   port - husk å oppdatere `ws://localhost:8787`-referansene i
   presentasjonens `.html`-filer tilsvarende).
2. **Server nettstedet statisk** (så filene kan lastes i nettleseren):
   ```bash
   python3 -m http.server 8080
   ```
3. **Åpne "PC-siden"** i én fane:
   `http://localhost:8080/slides/eksempel/slide-1.html`. Trykk `P` - et
   overlay med øktkode + QR-kode vises.
4. **Åpne "telefon-siden"** i en annen fane/vindu (eller en faktisk telefon
   på samme nettverk - bytt da `localhost` til maskinens IP-adresse):
   `http://localhost:8080/slides/foredragsholder.html?kode=<koden fra steg 3>&relay=ws://localhost:8787`
   (eller skann QR-koden fra steg 3 direkte med telefonens kamera - da
   forhåndsutfylles begge feltene automatisk).
5. **Bekreft synkroniseringen:** naviger på PC-siden (piltaster/klikk) -
   telefon-siden skal vise riktig nåværende/neste slide + notater etter en
   liten forsinkelse (PC-en gjenoppretter presenter-tilkoblingen på hver
   nye side). Trykk "Forrige"/"Neste" på telefon-siden - PC-siden skal
   navigere tilsvarende. Tidtakeren på telefon-siden skal telle oppover.

For faktisk bruk (ikke bare lokal testing) må `ws://localhost:...` byttes
til en `wss://`-adresse mot en relay-instans du drifter et sted - se
"Kjøring i produksjon (Cloudflare Tunnel)" i
`slides/presenter-server/README.md` for en konkret, enkel driftsvei hvis du
har et domene på Cloudflare.

## Komponenter

Se README.md i hver mappe under `slides/komponenter/` for full
props-/slot-dokumentasjon: `slide` (chassis), `slide-tittel`,
`slide-agenda`, `slide-seksjon`, `slide-punktliste`, `slide-bilde`,
`slide-kode`, `slide-sitat`, `slide-prototype`, `slide-nav` (valgfri
tastatur-/filmstripe-navigasjon + presenter-synk), `foredragsholder-visning`
(telefonens presenter view - se `slides/foredragsholder.html`).

### Delte stiler for slide-innholdsmalene (`slide-felles.css`)

De syv slide-*innholds*malene (`slide-tittel`, `slide-seksjon`,
`slide-agenda`, `slide-punktliste`, `slide-sitat`, `slide-bilde`,
`slide-kode`) adopterer alle `slides/komponenter/slide-felles.css` (via
`slide-felles-stiler.js`) i **tillegg til** sin egen, lokale `.css` -
samme `adoptedStyleSheets`-mekanisme, bare med to ark i stedet for ett.
Arket inneholder kun det som er reelt identisk på tvers av flere maler:
grunnleggende `:host`-flex-oppsett, den sentrerte varianten (tittel/
seksjon/sitat/bilde), en generell `::slotted()`-typografireset, og
agenda/punktliste sitt delte overskrift-med-understrek-mønster.
`:host()`/`::slotted()`-selektorer i et delt, adoptert stilark løses mot
den shadow-roten arket faktisk er adoptert av - så `:host(lm-slide-x)`
her lekker ikke mellom komponentene selv om selve arket er felles.

**Regel**: legg en ny regel til `slide-felles.css` først når minst to
maler faktisk trenger nøyaktig samme oppførsel - alt annet (gap-verdier,
egne fargede detaljer, kodeblokk-boksen osv.) hører hjemme i malens egen,
lokale `.css`.
