/* ===========================================================================
   /boom — a third front page, in a register taken from
   sanity.io. Built 17 Sep 2026.

   What is borrowed is the TECHNIQUE, never the content. Measured off their page
   at 1280px, and the whole lesson is in the weight column:

     role        size  weight  tracking   line-height
     h1          112     400   -0.04em    1.00
     h2 major     72     400   -0.04em    1.00
     h2 section   48     400   -0.035em   1.075
     h3 card      38     400   -0.03em    1.10
     subhead      32     425   -0.01em    1.10
     button       24     400   -0.01em    1.10
     body         16     400   normal     1.50
     mono label   13     400   normal     1.30, uppercase

   NOTHING IS BOLD. The hierarchy is size and tracking alone, and the tracking
   tightens as the size grows. A 112px line at weight 400 reads as confidence;
   the same line at 700 reads as shouting. That is the single most useful thing
   on their page and it costs nothing to take.

   Four more: the subhead is 32px, not 18, so the second line of the page is
   still a statement; buttons carry 24px text, because a small button under a
   huge headline looks timid; one hot accent on a near-black ground; and social
   proof arrives immediately, full-bleed, unexplained.

   The accent carried no white text while the ground was dark; on 17 Sep 2026
   the ground went to the Sensa Design System's white and the accent to its ink,
   so the filled button is now ink with white text, the system's Dark button,
   which is also the only one they use.

   Their display face is Waldenburg and it is licensed. Archivo stands in: a
   grotesk with the same tight apertures at display size. Open Sans was tried on
   17 Sep 2026 and Martin preferred Archivo. The mono was IBM Plex Mono, which is
   theirs; since 17 Sep 2026 it is Azeret Mono, which is ours and arrives with the
   lifted head. Archivo is loaded at 400 and 500; the two subheads take 500.

   From 17 Sep 2026 this is a SKIN as well as a page. The token block and the
   component rules are scoped to html.boom, stamped from localStorage by the same
   bootstrap that stamps html.sd, so the whole site can be seen in this register.
   The .boom-* classes below belong to the front page alone: its hero, its accent
   band and its command line are structure, and a stylesheet cannot invent those
   on /about.

   Two selectors on the token block for the same reason the skin needs them:
   :root[data-theme="light"] is 0,2,0 and html.boom alone is only 0,1,1, and both
   sit on <html>.
   =========================================================================== */

html.boom,
html.boom[data-theme]{
  /* Sensa Design System colours, 17 Sep 2026. Martin: "bakgrunnsfargen kan
     heller ikke være svart, dessverre. bruk sensa design farger på boom." The
     near-black ground was sanity.io's, and the last of their marks. These are
     the same values as html.sd in sensa-design.css, read off the system's own
     cards: brand core ink, the neutral ramp, the opacity foreground ramp, the
     action blue as a fill and focus ring only, and the hero wash. */
  --paper:#ffffff;
  --surface:#ffffff;
  --surface-1:#fafafa;
  --surface-2:#f1f1f1;
  --wash:#f2f9fc;
  --action:#008dff;
  --ink:#05050c;
  --ink-2:rgba(5,5,12,.72);
  /* .62 fra 2 Okt 2026: flaten staar bak hele siden, og .56 ga 4,0:1 mot dens blaaeste tone (--fluid-2). */
  --ink-3:rgba(5,5,12,.62);
  /* Svar fra skjemaet (7 Okt 2026, Martin, bilde av «Meldingen kunne ikke sendes»): uten disse arvet BOOM site.css sine
     moerke verdier naar systemet er moerkt og siden lys, og feilen ble lys laks paa lys flate. Maalt mot flaten. */
  --good:#0f5a30;
  --bad:#8a271e;
  /* No accent hue: the action blue is 3.36 on white and cannot carry text, so
     emphasis is the ink itself, which is also the system's declared Dark button. */
  --accent:#05050c;
  --on-accent:#ffffff;
  --on-media:#ffffff;       /* tekst paa video, som alltid ligger paa en moerk toning */
  --on-media-skygge:rgb(5 5 12 / .55);  /* skyggen under en hvit pil rett paa filmen (Labs, 17 Okt 2026) */
  --rule:#dddddd;
  /* kanten paa skjemafelt (WCAG 1.4.11, docs/wcag-2026-10-07.md funn 7): minst 3:1 mot flaten, som --rule ikke er */
  --felt:#86868f;
  --rule-soft:#eaeaea;
  /* THE FOCUS RING WAS THE DARK THEME'S, on a white page, and had been since this
     block was written: BOOM declared neither token, so both fell through to :root,
     where the halo is #0b1418. Every focused control on every BOOM page drew a 4px
     near-black ring. contrast.py never saw it, because the BOOM pass only runs the
     pairs whose tokens BOOM defines, which is the "a check that names things stops
     covering them" trap in a fourth place. Found 20 Sep 2026 when the header ask
     bar put a focused field on screen on every open. Values are the Sensa Design
     System's own pair, the same one the profil skin uses, because this palette is
     that palette. */
  /* The RING is four per cent darker than --action, and only the ring. #008dff is
     the design system's action colour and stays exactly that as a fill; measured
     against the tile it sits on, #f1f1f1, it reaches 2.97 where a focus indicator
     needs 3.00, and a row highlighted in the ask panel is on that tile. #0087f5 is
     3.21 there, 3.63 on white and 5.60 on the ink, and is indistinguishable from
     the action blue beside it. */
  --focus:#0087f5;
  --focus-halo:#bde4ff;
  --header-bg:rgba(255,255,255,.92);
  /* Den levende flaten, 26 Sep 2026: bakgrunnen oeverst paa hver side blander guidens tre
     hovedfarger og tre bakgrunnsfarger (Sensa visual profil guide v1, side 16 og 17).
     ai.js leser dem herfra, saa ingen fargeverdi staar i skriptet. */
  --fluid-paper:#f2f9fc;
  --fluid-1:#bde4ff;
  --fluid-2:#8bcbff;
  --fluid-3:#c2ffff;
  --fluid-4:#9aebb8;
  --fluid-5:#d4f9dc;
  /* Streken under toppen er guidens blaa hovedfarge, ikke den graa, 26 Sep 2026: "jeg vil
     at streken ikke skal vaere graa-farge ... passer [ikke] noe godt med de andre fargene." */
  --fluid-lift:0 10px 32px -14px rgba(5,5,12,.24);
  /* Avrundingen, tre trinn etter stoerrelse (14 Okt 2026, Martin: «skal alle ha samme avrunding? ... mac/apple har
     det», «A, kjør»). Store flater (kort, ark, filmkort) er --r-ark, det som svever over siden (toppoeya, nedtrekk,
     kontaktpanelet, svaret i toppen) er --r-panel, og det som staar inne i et panel er --r-inne: panelet minus de 8 px
     luften rundt, saa hjoernene foelger hverandre. Knapper og felt er piller (999px). Ingen andre tall paa flater. */
  --r-ark:clamp(20px,2.6vw,36px);
  --r-panel:20px;
  --r-inne:12px;
  /* Linsen, 28 Sep 2026: flatens farger, litt sterkere. Draapen i det levende merket (ai.js) speiler dem. */
  --linse-0:#bde4ff;
  --linse-1:#5fb8ff;
  --linse-2:#c2ffff;
  --linse-3:#7fe0a8;
  --linse-4:#e6fbff;
  --linse-5:#8bcbff;
  /* Introens markeringsboks, 29 Sep 2026: logoens svarte, hvit tekst. */
  --boks:#05050c;
  --on-boks:#ffffff;
  /* Kino-introens fem systemer (1 Okt 2026), fra tools/lab/intro-skisser/kino.html: foering, sensorer,
     produksjon, fiskehelse, Excel. Fargen viser bare at de er hver sine; den koder ingenting. */
  --kino-0:#e2870b;
  --kino-1:#0993d3;
  --kino-2:#6b4fe0;
  --kino-3:#0ea56f;
  --kino-4:#dc3468;
  /* Den runde pillen er Sensas blaa med svart tekst (7 Okt 2026, designerens sak 4, Martin: «4 sensa-blå»);
     laks fra 29 Sep 2026 til da. Hvit tekst paa blaaen klarer ikke 4,5, svart er 6,0:1. Boksen rundt ordet
     i introen (9 Okt) og i overskriftene (10 Okt 2026) er ogsaa blaa; laksen (#ff6f4f) er tatt av. */
  --knapp-1:#008dff;
  --knapp-t:#05050c;
  --sans:"Archivo",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --mono:"Azeret Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  --pad:clamp(20px,5vw,72px);

  /* The system's hero wash, sky-blue and cyan fading to white, sits on the page
     itself rather than on the hero box: main is capped at 1280px, and a wash
     that stopped at the container edge on a wide screen would read as a panel.
     On <html> it is full-bleed at any width and gone by 900px down. */
  background:
    radial-gradient(120% 90% at 12% 0%,#cfeafd 0%,rgba(207,234,253,0) 62%),
    radial-gradient(90% 80% at 88% 8%,#d8f7fb 0%,rgba(216,247,251,0) 58%),
    linear-gradient(180deg,var(--wash) 0%,var(--paper) 82%);
  background-repeat:no-repeat;background-size:100% 900px;background-color:var(--paper);
  color:var(--ink);
  font-family:var(--sans);font-size:16px;line-height:1.5;
}
/* site.css paints body and .ai-page with --paper, and the site-wide skin below
   restates it as `.boom .ai-page` at 0,2,0, which would cover the wash on <html>.
   The second selector here is 0,2,2 and wins; the page colour still comes from
   html's background-color, so nothing shows through that should not. Found by
   listing every rule body matches with a background set: the first attempt,
   `html.boom body` at 0,1,2, lost to the skin's own rule. */
/* ===========================================================================
   BOOM I MØRK VISNING, 22 Sep 2026, på Martins "legg til dark mode mulighet på
   BOOM". Den var lys uansett hva temabryteren sa, fordi tokenblokken over står
   på både `html.boom` og `html.boom[data-theme]` og derfor treffer alle verdier.

   DETTE ER ET `[data-theme="dark"]`-BLOKK, OG CLAUDE.md SIER AT ET SLIKT IKKE
   SKAL FINNES. Regelen gjelder site.css, og grunnen der er at mørk ER standarden
   og bor i bar `:root`, så et dark-blokk ville vært dødt. På BOOM er det motsatt:
   lys er standarden, og da er dette den eneste måten. site.css er urørt, og
   gaten i contrast.py som ser etter et dark-blokk leser bare den filen.

   SPESIFISITET, ikke filrekkefølge: `html.boom[data-theme]` er 0,2,1. Et enkelt
   `html.boom[data-theme="dark"]` er også 0,2,1, og da avgjør rekkefølgen, som er
   fella dette prosjektet har gått i et titalls ganger. Den andre selektoren her
   er `:root.boom[data-theme="dark"]`, 0,3,0, og den avgjør saken uansett hvor i
   filen blokken står.

   Verdiene er nettstedets egen mørke palett fra site.css, som er målt og i bruk,
   ikke en ny palett funnet opp her. Det som snus er hva `--accent` betyr: i lys
   er den blekket selv, altså designsystemets Dark-knapp, så i mørk er den
   papiret, altså den samme knappen som Light. Bare det som faktisk endrer seg
   står her; resten arver fra blokken over.
   =========================================================================== */

html.boom[data-theme="dark"],
:root.boom[data-theme="dark"]{
  /* SENSA-LOGOENS SVARTE, 26 Sep 2026: "dark mode kan bruke sensa logo svartfargen", samme
     oenske som 24 Sep ("ikke den skitne blaa som vi har naa"), som ble angret med resten av
     profilen 25 Sep. Verdiene er de fra f376c0b: #05050c er guidens fontfarge og logoens
     blekk, flatene er noeytrale trinn over den uten blaastikk, og teksten er guidens #f2f9fc. */
  --paper:#05050c;
  --surface:#0e0e17;
  --surface-1:#0a0a12;
  --surface-2:#1a1a24;
  --wash:#0b1622;
  --ink:#f2f9fc;
  --ink-2:rgba(242,249,252,.74);
  --ink-3:rgba(242,249,252,.6);
  --good:#5ec489;
  --bad:#e8837a;
  /* Blekket er lyst nå, så den fylte knappen er lys med mørk skrift. Det er den
     samme logikken som i lys visning, speilvendt, ikke et nytt valg. */
  --accent:#f2f9fc;
  --on-accent:#05050c;
  --on-media:#ffffff;
  --on-media-skygge:rgb(5 5 12 / .55);
  --rule:#3b3b47;
  --felt:#6b6b78;
  --rule-soft:#262631;
  /* Aksjonsblåen er en fyll og en fokusring, aldri tekst. På mørk grunn er
     #008dff for svak til å bære en ring, så ringen er den mørke palettens egen
     #8bcbff, som er målt mot denne grunnen. */
  --focus:#8bcbff;
  --focus-halo:#10202e;
  --header-bg:rgba(5,5,12,.9);
  /* De samme seks i dype toner paa logoens svarte, saa lys tekst staar paa dem. */
  --fluid-paper:#05050c;
  --fluid-1:#0e2335;
  --fluid-2:#15385a;
  --fluid-3:#0b2a31;
  --fluid-4:#0f2f20;
  --fluid-5:#0a1a14;
  --fluid-lift:0 10px 32px -14px rgba(0,0,0,.6);
  --boks:#f2f9fc;
  --on-boks:#05050c;
  --kino-0:#ffb04a;
  --kino-1:#3ccbff;
  --kino-2:#a08cff;
  --kino-3:#45f0aa;
  --kino-4:#ff7196;
  --knapp-1:#008dff;
  --knapp-t:#05050c;
  background:var(--paper);
  color:var(--ink);
}

/* TOPPEN FOELGER SIDEN I MOERK MODUS (8 Okt 2026, Martin: «denne bør vel ha dark mode egenskaper også? toppmenyen
   lyser veldig opp»). Den hvite toppen fra 2 Okt (variant 5 paa /tools/valg/?p=topp) er tatt av: oeya staar i moerk
   `--surface`, og logoen inverteres som overalt ellers. */

/* ORDMERKET ER EN RASTERFIL MED MØRKT BLEKK, og den ble usynlig i mørk visning.
   site.css har allerede svaret, `--art-filter`, som er `brightness(0) invert(1)`
   i mørk og `none` i lys, men BOOM slo den av med `.boom .ai-brand img{filter:none}`
   fordi BOOM er en lys side. Den regelen er riktig i lys og feil i mørk, og gate-
   merket hadde ingen invertering i det hele tatt: dets egen `filter` med to
   drop-shadow ERSTATTER en arvet filter i stedet for å legge seg til.

   Valgt på kilden i stedet for på klassen: `img[src$="logo.webp"]` treffer
   ordmerket i toppen, i bunnen og på merkeflisen i omtalen, og en ny plassering
   av det samme bildet får det gratis. 0,3,1 slår `.boom .ai-brand img` på 0,2,1.
   Rekkefølgen i filterkjeden er ikke valgfri: hvitt først, glorien etterpå. */
html.boom[data-theme="dark"] img[src$="logo.webp"]{filter:brightness(0) invert(1)}
html.boom[data-theme="dark"] .boom-gate-mark{
  filter:brightness(0) invert(1)
         drop-shadow(0 0 18px var(--paper)) drop-shadow(0 0 44px var(--paper));
}

html.boom body,html.boom body.ai-page{background:transparent}
.boom main{max-width:1280px;margin:0 auto;padding-inline:var(--pad)}

/* The chrome is ours, restated on this ground so the page holds together. */
.boom .ai-hdr{background:var(--header-bg);border-bottom:1px solid var(--rule)}
.boom .ai-hdr::after{background:var(--rule)}
/* The nav was --ink-2 at 14px, which measured 11.6 and still read as washed out next
   to a solid black button. Martin, 18 Sep 2026: "de popper ikke og ser egentlig veldig
   claude generert." Muted small grey navigation IS the tell. Full ink at 15px, and the
   hover is an underline rather than a colour change, because there is no darker step
   left to move to. */
.boom .ai-nav > a,.boom .ai-dd > button,.boom .ai-nav .ai-dd-t{
  color:var(--ink);font-size:15px;font-weight:500;text-decoration:none;
  white-space:nowrap; /* «Om oss» brakk i to linjer paa 960 px med «Bruksområder» (2 Okt 2026) */
}
.boom .ai-nav > a:hover,.boom .ai-dd > button:hover,.boom .ai-nav .ai-dd-t:hover{
  text-decoration:underline;text-underline-offset:5px;text-decoration-thickness:1.5px;
}
/* PILEN VED «PRODUKTER» (APG Disclosure Navigation, apg-gjennomgang nr. 13, 7 Okt 2026): pilen som stod paa ordet,
   er naa en egen knapp, 24 px bred, med vinkelen fra .ai-dd > button::after i site.css. Ordet er lenken alene. */
.boom .ai-dd > .ai-dd-t::after{display:none}
.boom .ai-dd > .ai-dd-pil{width:24px;min-height:24px;justify-content:center;margin-left:-3px;padding:0;color:inherit}
.boom .ai-dd > .ai-dd-pil:hover{text-decoration:none}
.boom .ai-dd:has(> .ai-dd-pil){display:inline-flex;align-items:center}
/* NEDTREKKET ER MENY A, 24 Sep 2026, valgt av tre paa /old/meny/ etter Martins "the drop down
   menu fonts, sizing, color and everything is not looking good or slick". Maalt foer: navnene var
   19px i vekt 400 under en toppmeny paa 15/500, saa menyen var stoerre og svakere enn ordet den
   henger fra; kategorien var 12,5px i --ink-3; hover var en tynn strek; aapningen 4px og 140 ms
   begge veier; og et hull paa 10px mellom ordet og panelet kunne miste pekeren. Naa:
   - navnet i toppmenyens egen stoerrelse og vekt, kategorien 14px i --ink-2
   - de seks ikonene fra /produkter, med de samme bevegelsene paa hover
   - én flate som glir til raden under pekeren (ai.js), ikke streken under navnet
   - panelet aapner fra ordet med en myk kurve, radene kommer 18 ms etter hverandre, og det
     lukker raskere enn det aapner
   - en usynlig bro over hullet, og en svak skygge fordi panelet svever over siden
   - avrundet 16 (samme dag: "drop down er firkantet, mens mye annet er avrundet"), i familie
     med det som svever eller kan trykkes paa i samme topp
   Alt henger paa .boom .ai-hdr: 0,3,0 slaar baade site.css og objektgruppa lenger ned, og /ai,
   som er frosset, har ikke .boom. */
.boom .ai-hdr .ai-dd-p{
  top:calc(100% + 12px);left:-22px;padding:8px;border-radius:var(--r-panel);
  background:var(--surface);border:1px solid var(--rule-soft);
  box-shadow:0 1px 2px var(--shadow),0 20px 40px -24px var(--shadow);
  transform-origin:22px 0;transform:translateY(-6px) scale(.97);
  transition:opacity .12s ease,transform .12s ease,visibility 0s linear .12s;
}
.boom .ai-hdr .ai-dd-p::before{content:"";position:absolute;left:0;right:0;top:-14px;height:14px}
.boom .ai-hdr .ai-dd:hover .ai-dd-p,.boom .ai-hdr .ai-dd-p:focus-within,
.boom .ai-hdr .ai-dd > button[aria-expanded="true"] + .ai-dd-p{
  opacity:1;visibility:visible;transform:none;
  transition:opacity .16s ease,transform .28s cubic-bezier(.16,1,.3,1),visibility 0s;
}
/* Raden er et rutenett: ikonet over to linjer, navnet og kategorien ved siden av. Selskap har
   ingen ikoner, og da er det én kolonne. */
.boom .ai-hdr .ai-dd-p a:not(.boom-kart-a){
  position:relative;z-index:1;display:grid;grid-template-columns:22px minmax(0,1fr);
  column-gap:14px;align-items:start;padding:12px 14px;border-radius:var(--r-inne);color:var(--ink);
}
/* Selskap har ikoner fra 24 Sep 2026; en rad uten ikon faar én kolonne. */
.boom .ai-hdr .ai-dd-p a:not(.boom-kart-a):not(:has(.ai-dd-ic)){grid-template-columns:minmax(0,1fr)}
.boom .ai-hdr .ai-dd-ic{grid-row:1 / span 2;width:22px;height:22px;color:var(--ink)}
.boom .ai-hdr .ai-dd-p a:hover .ai-dd-ic,.boom .ai-hdr .ai-dd-p a:focus-visible .ai-dd-ic{color:var(--action)}
.boom .ai-hdr .ai-dd-n{
  font-family:inherit;font-size:15px;font-weight:500;letter-spacing:-.005em;line-height:1.3;
  color:var(--ink);width:auto;
}
.boom .ai-hdr .ai-dd-n::after{display:none}
.boom .ai-hdr .ai-dd-p a span:not(.ai-dd-n),.boom .ai-hdr .ai-dd-p a:hover span:not(.ai-dd-n){
  font-size:14px;line-height:1.4;color:var(--ink-2);margin-top:3px;
}
.boom .ai-hdr .ai-dd-p:not(.ai-dd-grid){min-width:280px}
/* TREET, 15 Okt 2026 (Martin: «c Treet er den jeg likte best», tools/valg/?p=produktmeny): Sensa Unity oeverst som
   plattformen, og en tynn strek grener ut til de fire som bygger paa den. Stammen gaar fra ikonet til Sensa Unity, og
   hver gren ender ved navnet; den siste svinger inn. Video til handling staar paa Labs-siden, ikke i menyen (16 Okt
   2026). Radenes ::before er streken, saa noden for siden du er paa er en bakgrunn i grenene. Rekkefoelgen
   inn (--i) staar her, fordi radene ligger i to nivaaer. */
.boom .ai-hdr .ai-dd-p.ai-dd-tre{min-width:330px}
.boom .ai-hdr #dd-prod .ai-dd-rot::after{content:"";position:absolute;left:25px;top:40px;bottom:-1px;border-left:1px solid var(--ink-3)}
.boom .ai-hdr #dd-prod .ai-dd-gren{position:relative;margin-left:36px}
.boom .ai-hdr #dd-prod .ai-dd-gren > *{position:relative}
.boom .ai-hdr #dd-prod .ai-dd-gren > *::before{content:"";position:absolute;left:-11px;top:-1px;bottom:-1px;width:0;height:auto;
  border-left:1px solid var(--ink-3);border-radius:0;background:none}
.boom .ai-hdr #dd-prod .ai-dd-gren > *::after{content:"";position:absolute;left:-11px;top:21px;width:11px;border-top:1px solid var(--ink-3)}
.boom .ai-hdr #dd-prod .ai-dd-gren > :last-child::before{bottom:auto;height:23px;width:11px;border-bottom:1px solid var(--ink-3);border-bottom-left-radius:8px}
.boom .ai-hdr #dd-prod .ai-dd-gren > :last-child::after{display:none}
.boom .ai-hdr #dd-prod .ai-dd-gren > :nth-child(1){--i:1}
.boom .ai-hdr #dd-prod .ai-dd-gren > :nth-child(2){--i:2}
.boom .ai-hdr #dd-prod .ai-dd-gren > :nth-child(3){--i:3}
.boom .ai-hdr #dd-prod .ai-dd-gren > :nth-child(4){--i:4}
/* Siden du er paa, 17 Okt 2026 (Martin: «the nodes are not big enough and not on the end of the line», «capture the
   current product ... with a line or something around them»): grenen ender i kanten av raden, noden staar paa enden,
   midt paa kanten, og raden har en strek rundt seg. Grenens ::after baerer noden; paa den siste er streken svingen. */
html.boom[data-meny=node] .ai-hdr #dd-prod .ai-dd-gren > a[aria-current]::after{display:block;top:17px;width:16px;height:9px;border:0;
  background:linear-gradient(var(--ink-3),var(--ink-3)) 0 4px / 11px 1px no-repeat,
    radial-gradient(circle,var(--ink) 4px,transparent 4.5px) 100% 0 / 9px 9px no-repeat}
html.boom[data-meny=node] .ai-hdr #dd-prod .ai-dd-gren > a[aria-current]:last-child::after{
  background:radial-gradient(circle,var(--ink) 4px,transparent 4.5px) 100% 0 / 9px 9px no-repeat}
.boom .ai-hdr .ai-dd-foot{grid-column:1 / -1;margin:6px 6px 2px;padding:12px 8px 6px;border-top:1px solid var(--rule-soft);font-size:15px}
/* For IT under streken (1 Okt 2026) er en vanlig rad, med samme ikon, navn og linje som de seks.
   translate gjoer raden til et eget lag, saa den maa ligge over flaten (2 Okt 2026). */
.boom .ai-hdr .ai-dd-foot:has(> a){position:relative;z-index:1;margin:6px 0 0;padding:6px 0 0}
/* Filmer staar ved siden av For IT, 2 Okt 2026: to rader under streken, i samme spalter som de seks. */
.boom .ai-hdr .ai-dd-foot:has(> a + a){display:grid;grid-template-columns:1fr 1fr;gap:2px}
/* Flaten. Uten skript ligger den paa raden selv; med skript er det ett element som glir. */
.ai-dd-hl{display:none}
.boom .ai-hdr .ai-dd-p:not(.has-hl) a:not(.boom-kart-a):hover{background:var(--surface-2)}
.boom .ai-hdr .ai-dd-hl{
  display:block;position:absolute;z-index:0;left:0;top:0;border-radius:var(--r-inne);background:var(--surface-2);
  opacity:0;pointer-events:none;
  transition:transform .24s cubic-bezier(.16,1,.3,1),width .24s cubic-bezier(.16,1,.3,1),
             height .24s cubic-bezier(.16,1,.3,1),opacity .14s ease;
}
/* Radene kommer inn etter hverandre. */
.boom .ai-hdr .ai-dd-p a:not(.boom-kart-a),.boom .ai-hdr .ai-dd-foot{opacity:0;translate:0 4px;transition:opacity .1s ease,translate .1s ease}
.boom .ai-hdr .ai-dd-p a:nth-child(2){--i:1}
.boom .ai-hdr .ai-dd-p a:nth-child(3){--i:2}
.boom .ai-hdr .ai-dd-p a:nth-child(4){--i:3}
.boom .ai-hdr .ai-dd-p a:nth-child(5){--i:4}
.boom .ai-hdr .ai-dd-p a:nth-child(6){--i:5}
.boom .ai-hdr .ai-dd-foot{--i:6}
.boom .ai-hdr .ai-dd:hover .ai-dd-p a:not(.boom-kart-a),.boom .ai-hdr .ai-dd-p:focus-within a:not(.boom-kart-a),
.boom .ai-hdr .ai-dd > button[aria-expanded="true"] + .ai-dd-p :is(a,.ai-dd-foot),
.boom .ai-hdr .ai-dd:hover .ai-dd-foot,.boom .ai-hdr .ai-dd-p:focus-within .ai-dd-foot{
  opacity:1;translate:0 0;
  transition:opacity .22s ease calc(var(--i,0) * 18ms + 40ms),translate .32s cubic-bezier(.16,1,.3,1) calc(var(--i,0) * 18ms + 40ms);
}
/* Ikonene lever paa hover, de samme bevegelsene som kortene paa /produkter. */
.boom .ai-hdr .ai-dd-p a:hover .i-unity .k1{translate:0 -2.6px}
.boom .ai-hdr .ai-dd-p a:hover .i-unity .k3{translate:0 2.6px}
.boom .ai-hdr .ai-dd-p a:hover .i-ai .d1{animation:ai-think .9s ease-in-out infinite}
.boom .ai-hdr .ai-dd-p a:hover .i-ai .d2{animation:ai-think .9s ease-in-out .15s infinite}
.boom .ai-hdr .ai-dd-p a:hover .i-ai .d3{animation:ai-think .9s ease-in-out .3s infinite}
.boom .ai-hdr .ai-dd-p a:hover .i-opt .a1,.boom .ai-hdr .ai-dd-p a:hover .i-opt .a2{opacity:0}
.boom .ai-hdr .ai-dd-p a:hover .i-opt .n1{opacity:0;translate:0 6.5px}
.boom .ai-hdr .ai-dd-p a:hover .i-opt .n2{opacity:0;translate:0 -6.5px}
.boom .ai-hdr .ai-dd-p a:hover .i-opt .k3{fill:currentColor}
.boom .ai-hdr .ai-dd-p a:hover .i-log .w1{animation:log-write .42s ease .05s both}
.boom .ai-hdr .ai-dd-p a:hover .i-log .w2{animation:log-write .42s ease .3s both}
.boom .ai-hdr .ai-dd-p a:hover .i-log .w3{animation:log-write .42s ease .55s both}
.boom .ai-hdr .ai-dd-p a:hover .i-pellet .needle{rotate:74deg}
.boom .ai-hdr .ai-dd-p a:hover .i-pellet .tick{opacity:1;transition-delay:.35s}
.boom .ai-hdr .ai-dd-p a:hover .i-labs .b1{animation:labs-drop .46s cubic-bezier(.34,1.5,.5,1) .04s both}
.boom .ai-hdr .ai-dd-p a:hover .i-labs .b2{animation:labs-drop .46s cubic-bezier(.34,1.5,.5,1) .18s both}
.boom .ai-hdr .ai-dd-p a:hover .i-labs .b3{animation:labs-drop .46s cubic-bezier(.34,1.5,.5,1) .32s both}
/* Selskap: de to bakerste personene glir ut til sidene med et lite sprett og den fremste loefter seg (17 Okt 2026,
   Martin: «kjør c»), avislinjene skrives, samtaleboblene spretter. */
.boom .ai-dd-ic :is(.p1,.p2,.p3){transition:translate .5s cubic-bezier(.34,1.56,.64,1)}
.boom .ai-hdr .ai-dd-p a:hover .i-team .p1{translate:0 -.6px}
.boom .ai-hdr .ai-dd-p a:hover .i-team .p2{translate:-1.1px 0}
.boom .ai-hdr .ai-dd-p a:hover .i-team .p3{translate:1.1px 0}
.boom .ai-hdr .ai-dd-p a:hover .i-news .w1{animation:log-write .42s ease .05s both}
.boom .ai-hdr .ai-dd-p a:hover .i-news .w2{animation:log-write .42s ease .22s both}
.boom .ai-hdr .ai-dd-p a:hover .i-news .w3{animation:log-write .42s ease .4s both}
/* Samtalen ved Kontakt (17 Okt 2026, Martin: «kjør b»): paa hover spretter spoersmaalet og saa svaret, hver fra
   spissen paa halen sin. Brevduen foer det staar i beslutningsloggen. */
.boom .i-samtale :is(.s1,.s2){transform-box:view-box}
.boom .i-samtale .s1{transform-origin:4.4px 15.8px}
.boom .i-samtale .s2{transform-origin:19.4px 21px}
@keyframes samtale-sprett{0%,100%{scale:1}40%{scale:1.12}70%{scale:.97}}
.boom .ai-hdr .ai-dd-p a:hover .i-samtale .s1{animation:samtale-sprett .45s ease-out both}
.boom .ai-hdr .ai-dd-p a:hover .i-samtale .s2{animation:samtale-sprett .45s ease-out .28s both}
.boom .ai-hdr .ai-dd-p a:hover .i-it path{animation:ai-think .9s ease-in-out infinite}
.boom .ai-dd-ic.i-film :is(.f1,.f3,.pl){transition:translate .34s cubic-bezier(.22,.61,.36,1),fill .2s ease}
.boom .ai-hdr .ai-dd-p a:hover .i-film .f1{translate:-1.2px 0}
.boom .ai-hdr .ai-dd-p a:hover .i-film .f3{translate:1.2px 0}
.boom .ai-hdr .ai-dd-p a:hover .i-film .pl{fill:currentColor;transition-delay:.12s}
@media (prefers-reduced-motion:reduce){
  .boom .ai-hdr .ai-dd-p,.boom .ai-hdr .ai-dd-p a,.boom .ai-hdr .ai-dd-foot,.boom .ai-hdr .ai-dd-hl{transition:none !important;transform:none;translate:none}
  .boom .ai-hdr .ai-dd-p a:hover .boom-i *{animation:none !important;translate:none}
}
.boom .ai-try{background:var(--accent);color:var(--on-accent);border-radius:999px;font-weight:400}
/* «BOOK EN DEMO» I TOPPEN, 24 Sep 2026: "det maa ogsaa alltid vaere kort vei til ta kontakt -
   saa den maa kanskje staa i topp margen." Samme hoeyde som spoerrefeltet ved siden av (38),
   ikke sidens store knapp paa 51, fordi toppen er én linje og to hoeyder i den ser tilfeldig ut.
   PLASSEN: knappen trenger ~150px, og toppen hadde 5px til overs ved 760. Maalt med knappen:
   63px for bredt ved 960, 137 ved 860, 205 ved 770. Derfor, bare i BOOM (/ai er frosset og har
   sine egne 760 i site.css):
   - under 1080 gaar spraakene ut av toppen; de staar i bunnmargen og i telefonmenyen fra foer
   - under 900, ikke 760, blir toppen en telefontopp, og knappen blir staaende i den
   - under 600 er det ikke plass til logo, felt, knapp og meny, og knappen staar i menyen */
.boom .ai-hdr .ai-try-hdr{
  display:inline-flex;align-items:center;height:38px;padding:0 18px;
  font-size:14.5px;line-height:1;white-space:nowrap;flex:none;
}
.boom .ai-hdr .ai-try-hdr.is-away{display:none}
@media (max-width:1080px){.boom .ai-hdr .ai-langs{display:none}}
/* Maanen staar i telefonmenyen naar menyknappen vises (8 Okt 2026, Martin: «b»), saa feltet faar plassen. Samme
   grenser som menyknappen: 900 px, norsk til 969 og spansk til 1023 (lenger ned i fila). */
@media (max-width:900px){.boom .ai-hdr .ai-theme{display:none}}
@media (min-width:901px) and (max-width:969px){html.boom[lang=nb]:not(.sd) .ai-hdr .ai-theme{display:none}}
@media (min-width:901px) and (max-width:1023px){html.boom[lang=es]:not(.sd) .ai-hdr .ai-theme{display:none}}
@media (min-width:761px) and (max-width:900px){
  .boom .ai-nav{display:none}
  .boom .ai-hdr{gap:10px}
  .boom .ai-burger{display:grid}
  .boom .ai-menu:not([hidden]){display:block}
  .boom .ai-ask{position:static;order:2;flex:1 1 auto;min-width:0;display:flex;justify-content:flex-end;--ask-w:100%}
  .boom .ai-tools{order:3}
  .boom .ai-ask-t{max-width:240px;padding-left:12px;gap:8px}
  .boom .ai-ask-p{top:calc(100% + 8px);left:var(--gutter);right:var(--gutter);width:auto;transform:none}
  .boom .ai-ask.is-open .ai-ask-t{visibility:visible;border-color:var(--ink-3)}
}
@media (max-width:900px){
  .boom .ai-hdr .ai-try-hdr{order:2}
  /* logoen skyver resten til hoeyre, saa det samme virker med og uten feltet (engelsk) */
  .boom .ai-hdr .ai-brand{margin-right:auto}
  .boom .ai-hdr .ai-tools{margin-left:0}
}
@media (max-width:600px){.boom .ai-hdr .ai-try-hdr{display:none}}
/* Og i telefonmenyen staar den OEVERST. Nederst laa den 1275px ned paa en 812px hoey
   telefon, altsaa bak fjorten lenker og en rulling; det er ikke kort vei. */
.boom .ai-menu-cta{order:-1;margin:4px 0 22px}
.boom .ai-brand img{filter:none}
/* The two inactive languages were --ink-3, 6.6 on this ground, and next to the dark
   NO they read as disabled rather than as choices. --ink-2 is 11.6 and still clearly
   secondary to the current one. */
.boom .ai-langs span,.boom .ai-langs a{color:var(--ink-3);font-size:14px}
.boom .ai-langs [aria-current]{color:var(--ink);font-weight:600}
/* TEMABRYTEREN ER TILBAKE, 22 Sep 2026. Den var skjult her fordi BOOM ikke hadde
   moerk visning, og da var en bryter som ikke gjorde noe verre enn ingen bryter.
   Med moerk visning paa plass er den kontrollen. Martin: "hvor er dark og light
   mode toogle knappen?" Den staar fortsatt skjult paa profil-skinnet, som er lyst
   uansett. */
/* IKONET VISER HVA KNAPPEN GJOER, ikke hva du ser paa, og i dette registeret er
   standarden motsatt av resten av nettstedet: BOOM er lys uten stempel, saa den
   skal vise en maane. site.css knytter maanen til [data-theme="light"], som er
   riktig der moerk er standarden og feil her. Spesifisitet, ikke filrekkefoelge:
   `[data-theme="light"] .ai-theme .ai-moon` er 0,3,0 og disse er 0,3,1 og 0,4,1. */
/* INGEN RAMME I RO. Martin, 22 Sep 2026: "matcher dark & light knappen generelt
   de andre geometriske formene paa siden? jeg vil ikke at den skal staa ut som
   noe som tar for mye oppmerksomhet."

   Maalt paa forsiden finnes den runde haarstrek-kontrollen fra foer, i tre
   stoerrelser: Shorts-knappene paa 44 med --rule, de sosiale ikonene i bunnen
   paa 34 med --rule-soft, og denne paa 32. Saa formen er ikke fremmed. Men i
   TOPPEN er den det eneste innrammede objektet: logoen, de fire menyordene og
   de tre spraakene er alle bare skrift. En ensom sirkel i en rad med ord er en
   prikk oeyet gaar til.

   Derfor: ingen ramme i ro, saa den leser som naboene sine, og ringen kommer
   naar du peker paa den eller tabber til den. Flaten er uendret paa 34px, saa
   trykkmaalet er det samme; det er bare streken som er borte. 34 og ikke 32,
   fordi bunnens ikoner alt er 34 og to stoerrelser for samme ting er to for
   mange. */
.boom .ai-theme{width:34px;height:34px;border-color:transparent;color:var(--ink-3);transition:color .3s ease,border-color .3s ease}
.boom .ai-theme:hover{color:var(--ink);border-color:var(--rule)}
.boom .ai-theme .ai-sun{display:none}
.boom .ai-theme .ai-moon{display:block}
html.boom[data-theme="dark"] .ai-theme .ai-sun{display:block}
html.boom[data-theme="dark"] .ai-theme .ai-moon{display:none}
.boom .ai-tools{border-left:0}
.boom .ai-menu{background:var(--paper)}
/* Ingen strek over bunnmargen, 1 Okt 2026 (Martin: «en stygg "graa" strek ... kanskje bare droppe
   streken helt?»). Luften over foten skiller den fra siden. */
.boom .ai-foot{border-top:0;background:none}
.boom .ai-foot-c,.boom .ai-lang span,.boom .ai-lang a,.boom .ai-foot-intro,.boom .ai-foot-pv{color:var(--ink-3)}
.boom .ai-foot-intro:hover,.boom .ai-foot-pv:hover{color:var(--ink)}
/* Spraakene viser at de kan trykkes, 1 Okt 2026 (Martin: «naar man hover over norsk, engelsk eller
   spansk kommer det ikke en hover indikasjon»). Lenken faar samme strek som de andre i foten og samme
   blekk i toppen; spraaket du staar paa og ES, som ikke finnes, kan ikke trykkes og forblir rolige.
   Pekeren paa ES sier det samme: ingen haand. */
.boom .ai-lang a:is(:hover,:focus-visible){color:var(--ink);text-decoration:underline;text-underline-offset:3px}
.boom .ai-langs a{transition:color .3s ease}
.boom .ai-langs a:is(:hover,:focus-visible){color:var(--ink);text-decoration:underline;text-underline-offset:4px}
.boom :is(.ai-lang,.ai-langs) .off{cursor:not-allowed}
/* ES is INERT: /es does not exist. The rule above paints every span in the
   cluster alike, so without this the dead language looked exactly like the live
   EN link beside it, which is a trap: a visitor clicks and nothing happens. One
   class heavier, and the same --rule step site.css already gives it. The HEADER
   still shows ES at --ink-2 beside EN, because Martin raised both there on
   purpose 18 Sep 2026; that inconsistency is his call, not mine to reverse. */
.boom .ai-lang .off{color:var(--rule)}
.boom .ai-social a{color:var(--ink-2)}

/* The hero. One line at 112px, weight 400, tracking -0.04em, leading 1.00.
   These carry an extra class because the site-wide skin below sets `.boom main h1`
   at 0,1,2, which outranks a bare `.boom-hero h1` at 0,1,1 and would quietly
   render the front page's headline at the 72 step. */
.boom-hero{padding:clamp(56px,9vw,132px) 0 clamp(40px,6vw,80px)}
/* HEROEN FYLLER SKJERMEN, 23 Sep 2026: "forsiden paa toppen justeres slik at 'kjenner du
   deg igjen' ikke kommer foer man har scrollet litt ... man maa scrolle for at kjenner du
   deg igjen kommer frem." Heroen er minst én vindushoeyde, regnet fra under toppmenyen,
   saa neste seksjon starter under folden. svh og ikke vh, saa en telefons adressefelt
   ikke skyver den over. Hvor mye "litt" er, proeves fram: dette er ett tall. */
.boom .boom-hero{min-height:calc(100svh - 63px)}
/* LUFTEN LIGGER OVER, IKKE UNDER, 24 Sep 2026: "det er for mye luft paa forsiden naa den
   aapnes". Paa en hoey skjerm fylte heroen vinduet og innholdet sto oeverst, saa hele
   tomrommet havnet under knappene. ai.js maaler den ledige hoeyden i hviletilstand og
   legger 40 % av den over overskriften (--hero-lift), saa innholdet staar litt over
   midten. Ikke flex-sentrering: chatsvaret aapner seg inne i heroen, og da ville
   overskriften hoppe opp hver gang noen spoer. Uten ledig plass, som paa en laptop, er
   loeftet 0 og ingenting endres. */
.boom .boom-hero{padding-top:calc(clamp(56px,9vw,132px) + var(--hero-lift,0px))}
.boom .boom-hero h1{
  font-size:clamp(44px,8.8vw,112px);font-weight:400;
  letter-spacing:-0.04em;line-height:1;margin:0;max-width:14ch;
}
.boom .boom-sub{
  font-size:clamp(20px,2.5vw,32px);font-weight:500;
  letter-spacing:-0.01em;line-height:1.1;color:var(--ink);
  /* 46ch is about 830px at this size, which is the measure their subhead runs
     to. At 30ch it broke into three lines under a two-line headline and the
     hero read bottom-heavy: the subhead has to be a statement, not a column. */
  margin:clamp(22px,3vw,34px) 0 0;max-width:46ch;
}
.boom-cta{display:flex;flex-wrap:wrap;gap:12px;margin-top:clamp(26px,3.4vw,40px)}
/* UNDERTITTELEN I HEROEN, 28 Sep 2026: "veldig bold, brave and hairy" gjelder ordene, ikke
   skriften. Foerste versjon sto i Archivo 700 og ble forkastet samme dag: "fonten er veldig
   daarlig og konkurrerer voldsomt med overskriften". Naa er den sidens vanlige vekt, en
   tredjedel av overskriftens stoerrelse og i ink-2, saa overskriften er alene om aa vaere
   stor. Tre varianter bak ?under=. 14 Okt 2026: 64ch og balance, saa «din.» ikke staar alene
   paa neste linje (Martin: «det ser ikke bra ut»). */
.boom .boom-hero-sub{
  font-size:clamp(19px,2vw,26px);font-weight:400;
  letter-spacing:-0.005em;line-height:1.3;color:var(--ink-2);
  margin:clamp(18px,2.2vw,28px) 0 0;max-width:64ch;text-wrap:balance;
}
/* Etiketten over feltet (6 Okt 2026, Martin: «A på skillet»): saa chatten ikke leses som Unity AI. Luften over
   skiller den fra undertittelen; feltet staar rett under den. */
.boom .boom-hero-ln{display:block;margin:56px 0 12px;font-size:13px;line-height:1.3;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink-2)}
.boom .boom-hero-ln + .ai-box{margin-top:0}
/* KUNNSKAPSGRAFEN ER AV FORSIDEN, 23 Sep 2026: "kartet ser veldig rart ut naa.
   det kan ikke vaere saann. vurder aa fjerne det." To versjoner ble proevd. Med
   produktene store gjentok den de seks kortene rett under; med de fire delte
   ordene store leste den som fire tilfeldige ord med smaatekst rundt. Kartet
   bor paa produktsidene, der ett produkt er emnet og tegningen er navigasjon.
   Overskriften staar alene igjen, med luften til kortene den hadde. */
.boom .boom-prod-top{margin-bottom:clamp(30px,3.6vw,46px)}
.boom .boom-prod-top .boom-h2{margin:0}
/* Linjen til /shorts under kortene, 24 Sep 2026: ord og pil som de andre lenkene videre. */
.boom .boom-prod-go{margin:clamp(26px,3vw,38px) 0 0}
/* I heroen staar paret under brikkeraden og maa ha mer luft enn 40px: over det
   ligger en midtstilt rad med aatte smaa piller, og uten en tydelig pause leser
   de to knappene som en niende og tiende brikke. */
.boom .boom-hero-cta{margin-top:clamp(34px,4.4vw,54px)}
.boom .boom-btn{
  display:inline-block;font-size:clamp(17px,1.9vw,24px);font-weight:400;
  letter-spacing:-0.01em;line-height:1.1;text-decoration:none;
  padding:11px 32px;border-radius:999px;border:1px solid transparent;
}
/* Both carry .boom, or the skin's link rule (0,1,2) outranks them at 0,1,0 and
   paints the white pill's text white. Found 17 Sep 2026 by measuring, not by
   looking: the pill LOOKED like a pill, it just had no words on it. */
.boom .boom-btn-a{background:var(--accent);color:var(--on-accent)}
.boom .boom-btn-b{background:none;color:var(--ink);border-color:var(--ink)}
.boom-btn:hover{text-decoration:underline;text-underline-offset:4px}

.boom .boom-label{
  font-family:var(--mono);font-size:13px;line-height:1.3;text-transform:uppercase;
  color:var(--ink-3);margin:0 0 clamp(14px,1.8vw,20px);
}

.boom-sec{padding:clamp(56px,8vw,112px) 0 0}
.boom .boom-h2{
  font-size:clamp(30px,4.4vw,48px);font-weight:400;
  letter-spacing:-0.035em;line-height:1.075;margin:0;max-width:22ch;
}
.boom .boom-h2-big{
  font-size:clamp(36px,6vw,72px);font-weight:400;
  letter-spacing:-0.04em;line-height:1;margin:0;max-width:16ch;
}
/* The coverage cards were 1332px of a 5389px page and stood as six exits right
   before the closing ask; they are on /omtale now and the front keeps one line.
   A section holding a single sentence must not carry a full section's top
   padding, or it reads as an empty band, and the closing section below keeps
   its own opening distance regardless. */
.boom .boom-note{padding-top:clamp(40px,5vw,72px)}
.boom .boom-note .ai-seemore{margin:0;font-size:17px}

.boom-end{padding-bottom:clamp(72px,9vw,128px)}
.boom-end .boom-sub{font-size:clamp(18px,2vw,24px)}

/* KJENNER DU DEG IGJEN? The four pairs are lifted from /usecases at build time,
   so the words are the approved ones and cannot drift; only the register is
   BOOM's. Rows with a hairline between them rather than cards, because a pair is
   one thought in two halves and a box round each half would cut it in two.

   The LEFT column is the pain and the right is the answer, and the weight says
   so: --ink-3 against --ink. Not bold on the right, though. /ai sets it 600 and
   that is one device too many here, where the arrow, the colour step and the
   column order already say which side is which.

   THE ARROW IS THE FIRST TIME THE ACCENT APPEARS IN THE FRONT PAGE'S CONTENT,
   measured on 21 Sep 2026 when the UX-laws read found it at zero uses. It is
   carried over from the same component on /usecases rather than invented here,
   it marks a direction and not a category, so it is not the hue coding the house
   rules forbid, and at 3.36 on white it clears the bar for a graphical mark. */
/* The table carries the page's own colour, for the one reason every grid on this
   page carries it: it stops the context network being drawn through the words.
   It is invisible as a shape, because it IS the page colour; a band is a
   different colour. Without it the right column sat on bare mesh, which is the
   fault that cost the working day its ground two rounds ago. */
/* THE GROUND DISSOLVES INSTEAD OF ENDING. Martin, 21 Sep 2026: "nå ser vi
   rektangelboksen ligge over node-nettverket. det ser ikke spesielt flott eller
   elegant ut." The fill was doing its job, which is keeping the mesh out of the
   words, and failing at the same time: the network is dense here and stopped
   dead along a straight edge, so what a reader saw was a rectangular ABSENCE of
   drawing. The card grids get away with the same fill because they are cards
   with hairlines and a gap, so the rectangle is explained; a ruled table is not.

   So the fill is a masked pseudo-element that is solid across the text and gone
   before the edge. The mesh then emerges gradually and there is no line to see.
   Two things it must keep: the mask goes on the PSEUDO and never on the element,
   or it fades the text with the ground (the Shorts pool lesson), and the cells
   are capped so no line ever runs into the falloff. */
.boom .rec{
  margin-top:clamp(26px,3vw,38px);border-block:1px solid var(--rule);
  position:relative;isolation:isolate;
}
.boom .rec::before,.boom .rec-said::before{
  content:"";position:absolute;inset:0 -4vw 0 0;z-index:-1;background:var(--paper);
  -webkit-mask-image:linear-gradient(90deg,#000 0 86%,transparent 100%);
  mask-image:linear-gradient(90deg,#000 0 86%,transparent 100%);
}
/* SITATETS GRUNN ER IKKE TABELLENS, 23 Sep 2026: "denne har litt for lang
   seksjonsboks som fader ut i node-nettverket i bakgrunnen." Maalt paa 1440 var
   den delte regelen riktig for tabellen og feil her: tabellen fyller bredden sin
   med tekst, sitatet gjoer ikke. Den lengste linja slutter paa x 889 mens grunnen
   sto ubrutt hvit til 1178 og foerst da begynte aa tone ut - **289 piksler tom
   flate, naer 40 % av blokka** - og den hadde harde kanter oppe og nede fordi
   masken bare gikk paa én akse. Naa faller den av paa BEGGE akser og begynner
   der teksten faktisk slutter, saa formen er en pol uten en eneste rett kant.
   To gradienter med mask-composite, fordi én gradient bare kan tone ut én vei;
   svart i dem er et alfa-stopp og ikke en palettfarge. Fallet vertikalt ligger
   inne i blokkas egne 26px luft, saa det naar aldri en bokstav. */
.boom .rec-said::before{
  -webkit-mask-image:linear-gradient(90deg,#000 0 64%,transparent 88%),
                     linear-gradient(180deg,transparent 0,#000 11%,#000 89%,transparent 100%);
  mask-image:linear-gradient(90deg,#000 0 64%,transparent 88%),
             linear-gradient(180deg,transparent 0,#000 11%,#000 89%,transparent 100%);
  -webkit-mask-composite:source-in;
  mask-composite:intersect;
}
/* 30ch er 275px og ga tre og fire linjer per celle, som er grunnen til at
   radene var 140px hoeye og seksjonen leste som luft. 42ch er 385 og lander
   hver celle paa to linjer. */
.boom .rec-r p,.boom .rec-h p{max-width:42ch}
.boom .rec-h,.boom .rec-r{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(20px,4vw,64px);
}
.boom .rec-h{padding:clamp(14px,1.6vw,20px) 0}
/* KOLONNEOVERSKRIFTENE I SIDENS EGET UTTRYKK, 23 Sep 2026: "overskriften til hver
   kolonne ser rar ut og midtstreken gaar ikke helt opp. Font, font stoerrelse og hva de
   sier matcher ikke resten av forsiden sitt uttrykk." De var 14px i vekt 600, altsaa
   den eneste fete, smaa etiketten i en seksjon der alt annet er stort og i vekt 400.
   Naa er de trinnet over setningene, 24-32px i vekt 400 med stram sperring, og
   fargesteget er det samme som i radene: i dag dempet, med Sensa i fullt blekk.
   Midtstreken gaar gjennom overskriftsraden ogsaa. 0,3,1 fordi etikettregelen lenger
   ned i filen er 0,2,1 og ellers ville vunnet. */
.boom .rec .rec-h p{
  margin:0;font-family:var(--sans);font-weight:400;font-size:clamp(24px,2.4vw,32px);
  line-height:1.1;letter-spacing:-0.03em;
}
.boom .rec .rec-h p.rec-a{color:var(--ink-3)}
.boom .rec .rec-h p.rec-b{color:var(--ink)}
/* Strammere: fire rader paa 140px for to linjer tekst var mest luft. */
.boom .rec-r{padding:clamp(15px,1.5vw,21px) 0;border-top:1px solid var(--rule)}
.boom .rec-r p{margin:0;font-size:15.5px;line-height:1.5;letter-spacing:0}
/* The two columns' colour is settled further down, with the name layer. */
/* The quote is words on the page, not an object: no card, no bubble, no marks.
   The bubble on /ai belongs to the portrait beside it and there is no portrait
   here. A hairline on the left is enough to say somebody else is speaking. */
/* The block runs the FULL content width and the text is measured inside it, so
   the page colour behind it stops exactly where the table's does. Held to the
   text's own 660px instead, it would have left a vertical edge in the middle of
   the column where the network resumed, which is the rectangular cut-out fault
   again. Measured before the ground went on: 127 hairlines over the quote. */
.boom .rec-said{
  margin:clamp(26px,3vw,40px) 0 0;
  padding:clamp(18px,2vw,26px) 0 clamp(18px,2vw,26px) clamp(16px,1.8vw,24px);
  border-left:2px solid var(--rule);position:relative;isolation:isolate;
}
.boom .rec-said blockquote{
  margin:0;max-width:60ch;font-size:clamp(17px,1.5vw,21px);line-height:1.45;
  letter-spacing:-0.012em;color:var(--ink);
}
/* NAVNET OG ANSIKTET STAAR SAMMEN. Portrettet er ikke pynt: et sitat uten
   ansikt er en paastand, med ansikt er det et menneske som sa noe, og det er
   nettopp derfor blokka finnes. Rundt og 120px, fra 23 Sep 2026 ("juster bildet
   hennes slik at det blir minst dobbel saa stort"); det var 56. Kildebildet er
   480px, saa det staar skarpt ogsaa paa en skjerm med dobbel pikseltetthet. */
.boom .rec-said figcaption{
  display:flex;align-items:center;gap:20px;
  margin-top:22px;font-family:var(--sans);font-size:14px;color:var(--ink-2);
}
.boom .rec-said figcaption img{
  width:120px;height:120px;border-radius:50%;object-fit:cover;flex:none;
  /* height:auto er IKKE riktig her: bildet henter stoerrelsen fra reglene over
     mens markupen baerer et height-attributt, og uten en eksplisitt height ville
     attributtet vunnet og gjort sirkelen til en oval. Samme felle som .ai-face. */
}
.boom .rec-said figcaption span{font-weight:600;color:var(--ink);line-height:1.3}
.boom .rec-said figcaption small{
  display:block;font-size:13.5px;font-weight:400;color:var(--ink-3);margin-top:2px;
}
/* THE COLUMN DIVIDER DOES WHAT FOUR ARROWS WERE DOING, and does it once.
   Martin, 21 Sep 2026: "pilene kan sentreres eller gjoeres paa en helt annen
   maate. hva gjoer de beste design selskapene?" They do not draw them. Direction
   in a comparison is carried by the left-to-right order and by weight, so an
   arrow on every row is four repetitions of what the two column headings already
   said once, and a mark that repeats is the thing that reads as a template. This
   is the middot separator he had removed in September, wearing a chevron.

   What was missing was not a transition mark, it was the BOUNDARY: the two
   columns were two blocks of text in one field, and nothing said where today
   ended and Sensa began. One hairline down the middle says it for the whole
   table, and it is the same rule weight everything else on this page uses. */
.boom .rec-h,.boom .rec-r{position:relative}
.boom .rec-h::after,.boom .rec-r::after{
  content:"";position:absolute;left:50%;top:0;bottom:0;width:1px;
  background:var(--rule);
}
/* One column below 760, and then there is no boundary to draw: the header row
   names two columns that are no longer side by side, so it goes, and the pair
   is held together by the gap alone. */
@media (max-width:760px){
  .boom .rec-h{display:none}
  .boom .rec-r{grid-template-columns:1fr;gap:6px}
  .boom .rec-r::after{display:none}
}

/* SPERRINGEN STOPPER IKKE VED NULL. Measured against sanity.io at 1280 on
   22 Sep 2026, because the BOOM scale was taken from them in September and the
   question was what we had drifted from. The top four steps are IDENTICAL:
   112/400/-0.040/1.00, 72 the same, 48/-0.035/1.07, 38/-0.030/1.10. What we had
   lost is below that. Their tracking is a continuous function of size and it
   FLATTENS rather than stopping: -0.010em on everything from 32px down to 15,
   and only 0 at 13. Ours went to normal at 22 and below, so our small text was
   set at the face's own default while theirs is still drawn tighter.

   It goes on main and inherits, so every step that sets its own tracking is
   untouched and only the ones that had none pick it up. That is the whole fix:
   one declaration, and small text stops looking like a browser default. */
.boom main{letter-spacing:-0.01em}

/* ONE PAGE PER ANSWER, /svar/<slug>/. Built 21 Sep 2026: the answers existed
   only inside a JavaScript array on the front page, so no crawler and no model
   had ever seen one, and a visitor could send the site but not the answer.

   The question is the H1 and it takes the SECTION step, not the hero's 112px:
   a question is not a claim and this is not a front page. Everything else is the
   page's own furniture, so there is almost nothing here. */
.boom .svar{max-width:none}
.boom .svar h1{
  font-size:clamp(30px,4.4vw,48px);font-weight:400;letter-spacing:-0.035em;
  line-height:1.07;margin:clamp(10px,1.2vw,14px) 0 0;max-width:20ch;
}
.boom .svar p{max-width:64ch}
.boom .svar h1 + p{margin-top:clamp(18px,2.2vw,28px)}
.boom .svar h1 ~ p{font-size:clamp(17px,1.5vw,20px);line-height:1.5}
.boom .svar .boom-sub{font-size:clamp(17px,1.6vw,21px);color:var(--ink-2);max-width:56ch}
.boom .svar-go{margin-top:clamp(22px,2.6vw,32px)}
.boom .svar-ask{margin-top:clamp(30px,3.6vw,46px)}
.boom .svar-list{list-style:none;margin:14px 0 clamp(26px,3vw,38px);padding:0}
.boom .svar-list li{border-top:1px solid var(--rule)}
.boom .svar-list a{
  display:block;padding:14px 0;font-size:clamp(17px,1.5vw,20px);
  text-decoration:none;color:var(--ink);
}
.boom .svar-list a:hover{text-decoration:underline;text-underline-offset:4px}
.boom .svar h2{margin-top:clamp(30px,3.6vw,44px)}

/* The datakart demo at /datakart/, and its teaser on the front page. */
/* Én linje fra 24 Sep 2026: "jeg vet ikke om jeg liker linjeskift paa overskriften paa
   datakart, det ser saa sammentrykket ut." max-width:18ch brakk en setning paa 28 tegn i to
   uten grunn; naa brytes den bare der skjermen er for smal. */
.boom .kart h1{
  font-size:clamp(30px,4.4vw,48px);font-weight:400;letter-spacing:-0.035em;
  line-height:1.07;margin:0;max-width:none;
}
/* the row's own label carries the section spacing, so the pills sit under it */
.boom .kart-ask-h.kart-pick-h{margin:clamp(24px,3vw,36px) 0 9px;display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 22px}
/* ROLIGERE TOPP, 24 Sep 2026: "denne maa ordnes ogsaa. veldig busy side naa og veldig topp-tung."
   Valgteksten over brikkene ble en hel setning («Eksempel: et oppdrettsanlegg med fire merder.
   Velg systemene det har.») i overskriftsstoerrelse, 27px, og «Velg alle / Fjern alle» fulgte med
   i samme stoerrelse. Naa staar setningen paa ingress-trinnet (16-19px, ink-2) og de to handlingene
   i 15px. Panelets egne overskrifter er uroert: de ble store 22 Sep paa Martins "overskriftene maa
   staa litt mer ut". */
.boom .kart .kart-ask-h.kart-pick-h{font-size:clamp(16px,1.5vw,19px);color:var(--ink-2);letter-spacing:-0.01em;line-height:1.35}
.boom .kart .kart-pick-h .kart-all{font-size:15px}
/* GRAFEN STAAR MENS LISTEN RULLER, samme dag. Spoersmaalslisten var 1569px mot grafens 560,
   saa grafen sto oeverst til venstre med et tomrom under seg. Fra 900px klebes den under
   toppmenyen; under 900 staar spaltene over hverandre og ingenting klebes. */
@media (min-width:901px){
  .boom .kart-fig{position:sticky;top:88px}
}
/* EN LINJE MED SYSTEMER OVER HVERT SPOERSMAAL. Listen «A + B + C + D + E» gikk ofte over to linjer
   og var det meste av stoeyen i panelet; naa én linje som kuttes med ellipse, og hele listen staar
   i title (kart.js). Spoersmaalet selv er uendret. */
.boom .kart .kart-q-k{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.boom .kart-pick{display:flex;flex-wrap:wrap;gap:10px;margin:0}
/* The teaser on the front page: the same chips, then a count and one way in.
   No canvas, no list - the whole point is that it is a fifth the height of the
   demo it opens. */
/* TAKET ER REGNET UT, ikke valgt. De tolv brikkene er 1370px skrift pluss elleve
   mellomrom, altsaa 1480px innhold, saa halvparten er 740. Uten tak faller de 9 og 3
   i en 1152px spalte, som er "1 lang rad og 1 kort rad". Ved 820 tar foerste rad
   seks (739px) og andre rad de seks siste (731px). Radene er like lange fordi 820
   ligger mellom halvparten og halvparten pluss neste brikke, ikke fordi bruddet er
   skrevet inn noe sted: legges det til en trettende brikke, balanserer den seg selv. */
.boom .boom-kart-pick{max-width:var(--kart-w,820px)}
/* To spalter fra 900px: venstre er det man gjoer (velg, lenken videre), hoeyre er
   hva det gir (tallet). Tallet staar midt paa hoeyden av venstre spalte, saa det
   aldri ligger oppaa brikkene. Under 900px stables det under lenken. */
/* FELTET BAK DEMOEN, 24 Sep 2026: "dette er den eneste som ikke har en slags bakgrunn bak seg
   paa forsiden, hva foreslaar du til det?" Regelen er at der tekst staar oppaa nettverket,
   ligger et felt i sidens farge som toner ut paa alle sider, og demoen var den eneste uten.
   22 Sep ble den lukket paa .18 demping uten felt, fordi et tekstformet hull i et tett felt saa
   rart ut; dette er ikke et hull rundt teksten, men samme myke flate som de andre seksjonene
   har, en rektangel som toner ut paa begge akser (to gradienter, mask-composite). Toppen
   toner ut i seksjonens egen luft foer overskriften; masken sitter paa pseudo-elementet, ikke
   paa seksjonen, saa teksten ikke tones med. */
.boom #datakart{position:relative;isolation:isolate}
/* Balanserte linjer i utgangspunktet, saa «lukket.» ikke staar alene paa smal skjerm. */
.boom #datakart .boom-kart-l .boom-sub{text-wrap:balance}
.boom #datakart::before{
  content:"";position:absolute;z-index:-1;top:0;bottom:-56px;left:-5vw;right:-9vw;
  background:var(--paper);
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 6%,#000 84%,transparent 100%),
                     linear-gradient(180deg,transparent 0,#000 13%,#000 86%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 6%,#000 84%,transparent 100%),
             linear-gradient(180deg,transparent 0,#000 13%,#000 86%,transparent 100%);
  -webkit-mask-composite:source-in;
  mask-composite:intersect;
}
.boom .boom-kart-row{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(20px,3vw,32px);
  margin-top:clamp(14px,1.8vw,22px)}
.boom .boom-kart-l .boom-sub{margin:0}
/* TALLET STAAR INNTIL BRIKKENE, 23 Sep 2026: "naa virker tallet nesten ikke koblet til
   selve system-velgeren." Med en fleksibel venstre spalte ble det liggende langt ute
   til hoeyre. Begge spaltene er naa sin egen bredde og pakket fra venstre, saa tallet
   staar et fast mellomrom fra brikkene det teller, og en tynn strek skiller dem. */
@media (min-width:900px){
  /* align-items:start fra 24 Sep 2026: "naar jeg velger flere systemer saa flytter 'velg det
     anlegget har' overskriften seg - den og valgene maa staa i ro paa siden." Med center ble
     venstre spalte midtstilt mot hoeyre, og hoeyre endrer hoeyde med listen og eksempelet. */
  .boom .boom-kart-row{grid-template-columns:max-content minmax(240px,320px);justify-content:start;
    align-items:start;gap:clamp(36px,4.4vw,64px)}
  .boom .boom-kart-n{border-left:1px solid var(--rule);padding-left:clamp(28px,3.4vw,48px)}
}
.boom .boom-kart-k{list-style:none;margin:10px 0 0;padding:0;display:grid;gap:6px}
/* display:grid slaar UA-arkets [hidden], saa den maa skrives ut: samme felle som fire ganger foer. */
.boom .boom-kart-k[hidden]{display:none}
.boom .boom-kart-k li{font-size:16px;line-height:1.3;color:var(--ink-2);letter-spacing:-0.01em}
/* Eksempelet under tallet, 24 Sep 2026: ett av spoersmaalene i ord, saa "svar" betyr noe. */
.boom .boom-kart-ex{margin:14px 0 0;font-size:16px;line-height:1.4;color:var(--ink-2);letter-spacing:-0.01em;max-width:30ch}
.boom .boom-kart-ex[hidden]{display:none}
.boom .boom-kart-k b{font-family:var(--mono);font-weight:400;font-size:15px;color:var(--ink);
  display:inline-block;min-width:2.2ch}
.boom .boom-kart-n{margin:0}
.boom .boom-kart-pick{margin-top:clamp(18px,2.2vw,26px)}
/* Instruksjonen er én stille linje, ikke en andre overskrift (24 Sep 2026: "litt mye tekst"). */
.boom .boom-kart-sub{margin:0;font-size:clamp(16px,1.3vw,18px);line-height:1.45;color:var(--ink-2);letter-spacing:-.01em}
.boom .boom-kart-go{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 22px;
  margin:clamp(18px,2.2vw,26px) 0 0;
}
/* TALLET ER HELTEN. Det sto i 21px nederst i seksjonen mens det var det
   sterkeste i den, og det er dessuten det eneste tallet paa nettstedet som
   endrer seg mens du ser paa det. Samme trinn som verdikortenes figurer, og
   samme regel: sifferet er stort, ordene ved siden av er det ikke. */
.boom .boom-kart-n{display:flex;flex-direction:column;align-items:flex-start;gap:8px}
.boom .boom-kart-tall{
  font:400 clamp(56px,7.8vw,108px)/0.92 var(--sans);letter-spacing:-0.045em;
  color:var(--ink);
}
.boom .boom-kart-tall:empty{display:none}
.boom .boom-kart-ord{
  font-size:clamp(17px,1.5vw,20px);line-height:1.25;letter-spacing:-0.015em;
  color:var(--ink-2);max-width:26ch;
}
/* Et lite sprang naar tallet endrer seg. Det er ikke pynt: det ER informasjonen,
   nemlig at akkurat det krysset endret svaret. Bare transform og opacity, saa
   det koster ingen layout, og det er av under prefers-reduced-motion. */
@keyframes kart-tall{from{opacity:.45;transform:translateY(5px) scale(.94)}to{opacity:1;transform:none}}
.boom .boom-kart-tall.er-ny{animation:kart-tall .26s cubic-bezier(.2,.9,.3,1) both}
@media (prefers-reduced-motion:reduce){.boom .boom-kart-tall.er-ny{animation:none}}
/* the same rule-and-arrow the product cards draw, because it is the same promise */
/* EN LENKE, IKKE EN KNAPP, 23 Sep 2026: "denne knappen trenger ikke se ut som book
   demo knapp, hold den til strukturen eks. 'les mer -->'." Den var en svart pille
   fra 22 Sep, da den var det eneste man kunne trykke paa i seksjonen; naa er brikkene
   ogsaa trykkbare, og svarte piller er sidens handlinger (Book en demo). Den tar
   kortenes lenkeform: ord og pil, en 1,5px strek som tegner seg inn fra venstre og en
   pil som tar et skritt ut av linjen ved hover. Teksten staar. `:not(.boom-kart-a)` i
   den generelle lenkeregelen blir staaende, fordi denne regelen setter fargen selv. */
.boom .boom-kart-a{
  display:inline-flex;align-items:center;gap:8px;position:relative;padding-bottom:3px;
  font-size:16px;line-height:1.2;letter-spacing:-0.01em;text-decoration:none;
  color:var(--ink);background:none;
}
.boom .boom-kart-a::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1.5px;
  background:var(--ink);transform:scaleX(0);transform-origin:left center;
  transition:transform .28s cubic-bezier(.22,.61,.36,1);
}
.boom .boom-kart-a i{font-style:normal;display:inline-block;
  transition:transform .28s cubic-bezier(.22,.61,.36,1)}
.boom .boom-kart-a:hover::after,.boom .boom-kart-a:focus-visible::after{transform:scaleX(1)}
.boom .boom-kart-a:hover i,.boom .boom-kart-a:focus-visible i{transform:translateX(6px)}
@media (prefers-reduced-motion:reduce){.boom .boom-kart-a::after,.boom .boom-kart-a i{transition:none}}
/* Den gamle tekstlenkeregelen er borte. Den var 0,2,1 og slo den nye pilla paa
   0,2,0, saa knappen kom ut med blekk paa blekk: usynlig tekst. Og den bar en
   strek-som-tegner-seg-inn, som er riktig paa en tekstlenke og feil paa en fylt
   pille. **Naar en lenke blir en knapp, maa reglene som var skrevet for lenken
   ut, ikke bare overstyres.** Fant vinneren ved aa gaa gjennom document.styleSheets
   og beholde hver regel elementet matches, i stedet for aa gjette paa skinnet. */
/* Velg alle / Fjern alle sit RIGHT AFTER the label, not pushed to the far right.
   Ranged right they floated some six hundred pixels from the words they belong
   to, with nothing in between; next to the label the three read as one line
   about one thing. Separated by space alone, which is what the header's own
   utility cluster does, because a middot separator is banned here. They are
   underlined text and not pills: a pill is a choice and these are actions. */
.boom .kart-all{display:flex;gap:16px;font-weight:400}
.boom .kart-all button{
  border:0;background:none;padding:0;cursor:pointer;font:inherit;
  color:var(--ink-3);text-decoration:underline;text-underline-offset:3px;
}
.boom .kart-all button:hover:not(:disabled){color:var(--ink)}
/* and one that would change nothing says so, rather than being a control that
   looks live and does not respond */
.boom .kart-all button:disabled{opacity:.38;cursor:default;text-decoration:none}
/* BRIKKENE MAA HA EGEN GRUNN. Martin: "de systemene som ikke er valgt glir for
   mye inn i node-nettverket i bakgrunnen." De var gjennomsiktige med en
   haarstrek, saa veven gikk rett gjennom dem og et ukrysset system leste som en
   del av tegningen. --paper er sidens egen farge, altsaa ingen ny flate, bare
   noe som stopper nettet bak ordene: samme grep som kortrutenettene bruker. */
.boom .kart-chip{
  font:400 15px/1.2 var(--sans);letter-spacing:-0.01em;padding:11px 18px;
  border:1px solid var(--rule);border-radius:999px;background:var(--paper);
  color:var(--ink-2);cursor:pointer;
  transition:border-color .16s ease,color .16s ease,background-color .16s ease;
}
.boom .kart-chip:hover{border-color:var(--ink-3);color:var(--ink)}
/* VALGT ER EN FYLT NODE, IKKE EN FYLT BRIKKE, 23 Sep 2026: "de valgte systemene
   trenger ikke fylles med svart, da ligner de for mye paa action buttons." Svarte
   piller er sidens knapper ("Book en demo", "Se hva dere kan spoerre om"), saa sju
   av dem i en rad leste som sju handlinger. Fyllet ligger naa i PRIKKEN foran ordet,
   som er en node i grafen: tom naar systemet ikke er med, fylt naar det er koblet
   inn. Moenster 01 staar ("du er her er fylt"), fyllet har bare flyttet til merket. */
.boom .kart-chip{display:inline-flex;align-items:center;gap:9px}
.boom .kart-chip::before{
  content:"";flex:none;width:9px;height:9px;border-radius:50%;box-sizing:border-box;
  border:1.5px solid var(--ink-3);background:transparent;
  transition:background-color .16s ease,border-color .16s ease;
}
.boom .kart-chip.is-on{border-color:var(--ink);color:var(--ink)}
.boom .kart-chip.is-on::before{background:var(--ink);border-color:var(--ink)}
.boom .kart-row{
  display:grid;grid-template-columns:minmax(0,1.8fr) minmax(0,1fr);
  gap:clamp(20px,3vw,48px);align-items:start;margin-top:clamp(18px,2.2vw,28px);
}
/* The drawing is the object on this page, so it gets the room. The old cap was
   set when a button underneath had to clear the fold; that button is gone. */
/* The one gesture the drawing takes is a turn, so the cursor says grab and
   nothing else. touch-action pan-y lets a finger going DOWN the page scroll the
   page while a sideways drag turns the scene. */
.boom .kart-c{display:block;width:100%;height:min(62vh,560px);touch-action:pan-y;cursor:grab}
.boom .kart-c:active{cursor:grabbing}
.boom .kart .boom-sub{font-size:clamp(16px,1.5vw,19px);color:var(--ink-2);max-width:58ch}
/* The note stands alone now: the button it used to sit beside was a mode and
   is gone, so there is no row and nothing to align a first line against. */
.boom .kart-note{
  margin:clamp(12px,1.6vw,20px) 0 0;font-size:14.5px;
  color:var(--ink-3);max-width:40ch;
}
/* The note carries two paragraphs when a row says what its calculation is built
   from: the provenance first, then the method. The second is one step stronger,
   because it is the point being made and the first is the mechanism. */
.boom .kart-note span{display:block}
.boom .kart-why{margin-top:9px;color:var(--ink-2)}
/* The panel is words on the page, not a card: the drawing beside it is the
   object here and a box round the list would make two. */
/* THE HEADINGS CARRY THEIR OWN WEIGHT, in the register this whole design was
   taken from. Martin, 22 Sep 2026: "overskriftene maa staa litt mer ut, som i
   sanity siden." They were 14px at weight 600 in 72 % ink, which is SMALLER than
   the lead above them and heavier: the exact inversion of the one thing that
   page teaches, that hierarchy is size and tracking and nothing is bold. A step
   below the 48px h1 at weight 400 in full ink, tracking tightening as it grows,
   and they outrank the body by being bigger rather than by shouting. */
.boom .kart-ask-h{
  margin:0 0 11px;font-size:clamp(21px,2vw,27px);font-weight:400;
  letter-spacing:-0.02em;line-height:1.1;color:var(--ink);
}
/* The class a question belongs to. A GROUP LABEL, which is a different job from
   the section headings above and is allowed to be small and set in 600: that is
   the treatment Martin asked for on the chat panel's own categories
   ("kategorinavnene kan gjerne vaere uthevet"), and the two lists should not
   speak differently. It sits just above the group's first rule, so the rule
   reads as the group's top edge. Sentence case; ALL CAPS is banned outright. */
.boom .kart-cls{
  display:flex;align-items:center;gap:10px;width:100%;
  margin:clamp(18px,2vw,26px) 0 2px;padding:4px 0;
  border:0;background:none;cursor:pointer;text-align:left;
  font-family:inherit;font-size:14px;font-weight:600;color:var(--ink-2);
}
.boom .kart-cls:hover{color:var(--ink)}
/* the count is a digit, so it is the mono, and it sits with the chevron on the
   right where a fold's own controls belong */
.boom .kart-cls-c{margin-left:auto;font-family:var(--mono);font-weight:400;color:var(--ink-3)}
/* the site's own chevron, the one the header dropdowns draw: down when shut, up
   when open, so a fold here behaves like every other fold on the site */
.boom .kart-cls::after{
  content:"";width:5px;height:5px;flex:0 0 auto;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:translateY(-2px) rotate(45deg);transition:transform .16s ease;
}
.boom .kart-cls[aria-expanded="true"]::after{transform:translateY(1px) rotate(225deg)}
.boom .kart-grp.is-shut{display:none}
/* A question is pressable now: it traces where its answer would come from.
   Left-aligned and full width so it reads as a row and not as a button, with the
   press said by the mark on the left rather than by a box. */
.boom .kart-q{
  display:block;width:100%;text-align:left;padding:14px 0 14px 14px;
  border:0;border-top:1px solid var(--rule);background:none;cursor:pointer;
  margin-left:-14px;box-shadow:inset 2px 0 0 transparent;
  transition:box-shadow .16s ease;
}
.boom .kart-q:hover{box-shadow:inset 2px 0 0 var(--rule)}
.boom .kart-q.is-on{box-shadow:inset 2px 0 0 var(--ink)}
.boom .kart-q-k{display:block;font-size:13px;color:var(--ink-3);margin-bottom:3px}
.boom .kart-q-t{display:block;font-size:clamp(15px,1.3vw,17px);line-height:1.4;color:var(--ink)}
.boom .kart-ask-f{
  margin:clamp(14px,1.6vw,20px) 0 0;font-size:13.5px;line-height:1.5;
  color:var(--ink-3);max-width:44ch;
}
.boom .kart-ask .ai-send{margin-top:14px}
/* What a missing source would open, and which product supplies it. Words under
   a rule, never a card: it sits at the end of an honest list and a box round it
   would turn the whole list into the run-up to an advert. The question is the
   loud part, because the product is introduced by what it answers. */
.boom .kart-gap-h{margin-top:clamp(22px,2.6vw,32px);padding-top:16px;border-top:1px solid var(--rule)}
.boom .kart-gap{
  margin:0 0 14px;font-size:13.5px;line-height:1.5;
  color:var(--ink-3);max-width:44ch;
}
.boom .kart-gap a{font-weight:600;color:var(--ink)}
.boom .kart-gap-q{display:block;margin-top:5px;font-size:15px;color:var(--ink)}
@media (max-width:900px){
  /* minmax(0,1fr): uten den styrte den lengste etiketten (nowrap) bredden, og kartet og spoersmaalene gikk 96 px ut
     av telefonen etter koblingen (funksjonstest M05, 14 Okt 2026) */
  .boom .kart-row{grid-template-columns:minmax(0,1fr)}
}

/* Figures and products. A card here is a hairline and a lot of air, because the
   ground is already dark and a fill would only mute the type. */
.boom-figs,.boom-prods{
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:1px;
  margin-top:clamp(30px,4vw,52px);
  position:relative;isolation:isolate;
}
/* LINJENE TONER UT MOT HJOERNENE, 23 Sep 2026: "skulle den faded ut i alle hjoerner?"
   Uten rammen sluttet linjene mellom kortene braatt ute ved kanten. Linjefargen ligger
   naa bak kortene paa et eget lag, og det laget har en maske som er hel i midten og
   borte i hjoernene; kortene dekker alt unntatt den ene pikselen mellom dem, saa det er
   bare linjene som toner ut. Masken sitter paa laget, aldri paa rutenettet, ellers ville
   ogsaa teksten i kortene tonet ut. */
.boom-figs::before,.boom-prods::before{
  content:"";position:absolute;inset:0;z-index:-1;background:var(--rule);
  -webkit-mask-image:radial-gradient(closest-side,#000 55%,transparent 100%);
  mask-image:radial-gradient(closest-side,#000 55%,transparent 100%);
}
/* OG DET HVITE FELTET TONER UT, 23 Sep 2026: "hele det hvite feltet ogsaa." Kortene
   har sidens egen farge, og under dem ligger en grunn i samme farge som gaar 64px ut
   forbi rutenettet og toner ut over de 64 pikslene, sterkest i hjoernene der de to
   fallene moetes. Da har kortblokken ingen rett kant mot nettet i bakgrunnen: kanten
   til kortene forsvinner inn i grunnen, og grunnen gaar over i nettet. */
.boom-figs::after,.boom-prods::after{
  content:"";position:absolute;inset:-64px -64px;z-index:-2;background:var(--paper);
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 64px,#000 calc(100% - 64px),transparent 100%),
                     linear-gradient(180deg,transparent 0,#000 64px,#000 calc(100% - 64px),transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 64px,#000 calc(100% - 64px),transparent 100%),
             linear-gradient(180deg,transparent 0,#000 64px,#000 calc(100% - 64px),transparent 100%);
  -webkit-mask-composite:source-in;mask-composite:intersect;
}
/* Grunnen gaar 64px ut paa sidene, og paa smale vinduer er det mer enn margen, saa
   siden fikk 5px sidelengs rulling. Klippet sitter paa VINDUET og ikke paa seksjonene:
   paa seksjonene ble grunnen kuttet i en rett kant til hoeyre og venstre ("bare at du
   tar med fade paa sidene ogsaa", 23 Sep 2026). Det sitter paa <main>, som er like bred
   som vinduet, og IKKE paa <html>: der slo det av den klebrige toppmenyen (maalt, toppen
   fulgte ikke med lenger). clip og ikke hidden, fordi hidden lager en rullebeholder. */
.boom main{overflow-x:clip}
/* INGEN RAMME OPPE OG NEDE, 23 Sep 2026: "trenger seksjonen topp og bunnlinje?" Nei.
   Linjene MELLOM kortene skiller dem; en linje rundt hele rutenettet er en boks rundt
   seks bokser. Gjelder begge rutenettene, fordi de er den samme komponenten. */
@media (max-width:900px){.boom-figs,.boom-prods{grid-template-columns:1fr}}
/* Flex column so the call to action can be pushed to the bottom: the bodies run to
   two or three lines and the links were landing at three different heights across a
   row. Martin, 18 Sep 2026: "alle proev naa og les mer maa vaere paa linje." */
.boom-fig,.boom-prod{
  background:var(--paper);padding:clamp(24px,2.8vw,36px);min-width:0;
  text-decoration:none;color:inherit;display:flex;flex-direction:column;
}
.boom-prod:hover,.boom-fig:hover{background:var(--surface-1)}
/* 13.5px in the faintest ink measured 6.6 and Martin read it as generated filler:
   "teksten ser ai generert ut, lite lesbare, gjoer den ogsaa fet". 14px at 600 in
   --ink-2 measures 8.67. It stays clearly under the 38px product name, which is what
   keeps it a label rather than a second heading. */
.boom .boom-k{
  font-family:var(--sans);font-size:14px;font-weight:600;line-height:1.35;
  /* No positive tracking. It was here from the ALL CAPS mono era and survived
     the move to sentence case on 18 Sep 2026: letters are spread APART for caps
     and drawn together for lower case, so this was fighting the label's own
     form. It inherits the -0.01em floor now, like everything else small. */
  color:var(--ink-2);margin:0;
}
.boom .boom-n{
  font-family:var(--mono);font-size:clamp(40px,5vw,64px);font-weight:400;
  letter-spacing:-0.03em;line-height:1;color:var(--accent);
  margin:clamp(18px,2.2vw,26px) 0 0;font-variant-numeric:tabular-nums;
}
/* The unit was .32em of the figure, 20px against 64, in the faintest ink. Martin:
   "prosent og mnd skriften kan gjoeres stoerre og tydeligere." Now .42em, 27px,
   and one step up the ramp. It stays mono: a unit is not a word. */
.boom-n small{font-size:.42em;margin-left:0;word-spacing:-.3em;letter-spacing:0;color:var(--ink-2)}
.boom .boom-fig h3,.boom .boom-prod h3{
  font-size:clamp(22px,2.6vw,38px);font-weight:400;
  letter-spacing:-0.03em;line-height:1.1;margin:clamp(12px,1.4vw,16px) 0 0;
}
.boom .boom-b{font-size:16px;line-height:1.5;color:var(--ink-2);margin:14px 0 0}
.boom-go{display:inline-block;margin-top:20px;font-size:16px;color:var(--accent)}
.boom .ev{margin-top:22px;font-size:14px}
.boom .ev-1,.boom .ev-2{color:var(--accent)}
.boom .ev-3{color:var(--ink-3)}

/* /USECASES, 24 Sep 2026 (boom.py, usecases_page): "null design, null struktur. rotete." Bygget
   paa forsidens komponenter og ett rutenett, og ingenting er fett. Rekkefoelgen er oversikt foer
   detalj: kortene, sakene, de sju. En sak staar i to spalter, hva og hvor mye til venstre og
   hvordan til hoeyre som tre nummererte steg med haarstrek mellom, ikke tre overskrifter med
   strek under. De sju er en tabell i tre spalter sortert etter bevis. Fyllmerket (.ev) betyr bare
   hvor godt noe er dokumentert; tallets type staar som tekst (.uc-type). */
.boom .uc-top{padding-top:clamp(56px,8vw,112px)}
.boom .uc-top h1{margin:0}
.boom .uc-lede{margin:clamp(14px,1.6vw,20px) 0 0;max-width:46ch;font-size:clamp(19px,1.7vw,23px);
  line-height:1.35;letter-spacing:-0.015em;color:var(--ink-2)}
.boom .uc-funn .boom-h2,.boom .uc-sju .boom-h2{margin:0 0 clamp(24px,3vw,36px)}
.boom .uc-type{margin:auto 0 0;padding-top:18px;font-size:14px;line-height:1.35;color:var(--ink-3)}
.boom .uc-k{margin:0;font-size:14px;line-height:1.35;color:var(--ink-3)}
.boom .uc-case{
  display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);gap:clamp(32px,6vw,96px);
  align-items:start;margin-top:clamp(56px,8vw,112px);padding-top:clamp(40px,5vw,64px);
  border-top:1px solid var(--rule);
}
.boom .uc-h{margin:12px 0 0;font-size:clamp(28px,3vw,40px);font-weight:400;letter-spacing:-0.03em;
  line-height:1.1;max-width:18ch}
.boom .uc-n{margin:clamp(24px,3vw,36px) 0 0;font-family:var(--mono);font-size:clamp(48px,6vw,80px);
  font-weight:400;line-height:1;letter-spacing:-0.03em;color:var(--accent);font-variant-numeric:tabular-nums}
.boom .uc-n small{font-size:.4em;margin-left:0;word-spacing:-.3em;letter-spacing:0;color:var(--ink-2)}
.boom .uc-what{margin:10px 0 0;font-size:clamp(19px,1.7vw,23px);line-height:1.3;letter-spacing:-0.015em;color:var(--ink)}
.boom .uc-l{margin:12px 0 0;font-size:15px;line-height:1.5;color:var(--ink-2);max-width:38ch}
.boom .uc-meta{margin:20px 0 0;display:flex;flex-wrap:wrap;gap:6px 18px;align-items:center}
.boom .uc-meta .ev,.boom .uc-key .ev,.boom .uc-row-k .ev{margin:0;font-weight:400}
.boom .uc-meta .uc-type{margin:0;padding:0}
.boom .uc-steps{list-style:none;margin:0;padding:0}
.boom .uc-steps li{display:grid;grid-template-columns:44px minmax(0,1fr);gap:0 16px;padding:22px 0;
  border-top:1px solid var(--rule)}
.boom .uc-steps li:first-child{border-top:0;padding-top:4px}
.boom .uc-sn{font-family:var(--mono);font-size:13px;line-height:1.6;letter-spacing:0;color:var(--ink-3)}
.boom .uc-steps h3{margin:0;font-size:18px;font-weight:400;letter-spacing:-0.015em;line-height:1.3;color:var(--ink)}
.boom .uc-steps p{margin:8px 0 0;font-size:16px;line-height:1.55;color:var(--ink-2);max-width:60ch}
.boom .uc-sju{margin-top:clamp(24px,3vw,40px)}
.boom .uc-key{list-style:none;margin:0 0 clamp(24px,3vw,36px);padding:0;display:flex;flex-wrap:wrap;gap:12px 36px}
.boom .uc-key li{display:flex;flex-direction:column;gap:6px;max-width:32ch;font-size:14px;line-height:1.4;color:var(--ink-3)}
.boom .uc-rows{border-top:1px solid var(--rule)}
.boom .uc-row{
  display:grid;grid-template-columns:minmax(150px,1.1fr) minmax(0,3fr) minmax(170px,1fr);
  gap:clamp(18px,3vw,48px);padding:clamp(22px,2.6vw,32px) 0;border-bottom:1px solid var(--rule);align-items:start;
}
.boom .uc-row-k{display:flex;flex-direction:column;gap:8px}
.boom .uc-row-k .uc-k{font-size:15px;color:var(--ink)}
.boom .uc-row-b h3{margin:0;font-size:clamp(19px,1.8vw,24px);font-weight:400;letter-spacing:-0.02em;line-height:1.2}
.boom .uc-row-b p{margin:10px 0 0;font-size:16px;line-height:1.55;color:var(--ink-2);max-width:62ch}
.boom .uc-row-go{display:flex;flex-direction:column;align-items:flex-start;gap:10px;padding-top:3px}
@media (max-width:900px){
  .boom .uc-case{grid-template-columns:1fr}
  .boom .uc-row{grid-template-columns:1fr;gap:10px}
  .boom .uc-row-k{flex-direction:row;align-items:baseline;gap:14px}
  .boom .uc-steps li{grid-template-columns:30px minmax(0,1fr);gap:0 10px}
}

/* The chat, restated on this ground. */
/* The field is the hero's main object from 18 Sep 2026, not a control further down,
   so it is sized like one: 860px wide against the standfirst's 844, and 22px text,
   which is the step between body and the 32px standfirst. Martin asked how to make
   the landing feel impressive with the chat at the top, "plassering og storrelse av
   font". Placement was the move up; this is the size. It stays a pill and stays on
   --surface: the page has one ground and this is the one object lifted off it. */
.boom .ai-box{
  background:var(--surface);border:1px solid var(--rule);border-radius:999px;
  /* The gap was 26-38px under a 32px standfirst. With the standfirst gone the field
     sits under a 112px headline, so it needs the room a headline asks for. */
  max-width:860px;margin-top:clamp(30px,4.4vw,52px);
  padding:12px 12px 12px 28px;
}
.boom .ai-box:focus-within{border-color:var(--action)}
.boom .ai-box input{color:var(--ink);font-size:clamp(18px,1.9vw,22px)}
/* Tekstfeltet paa forsiden, 24 Sep 2026: samme skrift og luft som input-en det erstatter,
   uten haandtak, og hoeyden settes av ai.js (én til fem linjer). Naar teksten gaar over
   én linje blir pillen en avrundet boks og knappen staar nederst, som i Claude. */
.boom .ai-box textarea{
  flex:1;min-width:0;background:none;border:0;outline:none;resize:none;display:block;
  font:inherit;font-size:clamp(18px,1.9vw,22px);line-height:1.4;color:var(--ink);
  padding:11px 0;margin:0;overflow-y:hidden;
}
.boom .ai-box textarea::placeholder{color:var(--ink-3)}
.boom .ai-box textarea:focus-visible{outline:none;box-shadow:none}
.boom .ai-box.is-multi{border-radius:28px;align-items:flex-end}
.boom .ai-box button[type=submit]{width:48px;height:48px}
.boom .ai-ph{font-size:clamp(18px,1.9vw,22px);left:28px}
.boom .ai-box input::placeholder{color:var(--ink-3)}
.boom .ai-box button[type=submit]{background:var(--accent);color:var(--on-accent)}
/* Centred on the field, not ranged left. Martin, 18 Sep 2026: "jeg liker ogsaa slik
   de var organisert tidligere, midtstilt paa chatten". 860px matches the field, so
   the row centres on it rather than on some wider box. */
.boom .ai-chips{justify-content:center;max-width:860px}
.boom .ai-chip{
  background:none;border:1px solid var(--rule);color:var(--ink-2);
  border-radius:999px;font-size:14px;
}
.boom .ai-chip:hover{border-color:var(--accent);color:var(--ink)}
/* «Flere spørsmål», 3 Okt 2026: tre forslag framme, resten bak en rund knapp i forslagenes egen form med en V som snur
   seg naar raden er aapen (Martin: «v»; plusset kunne leses som «legg til»). Ordet staar ved pekeren (data-tip). */
.boom .ai-chips .ai-chip[hidden]{display:none}
.boom .ai-chips .ai-flere{display:inline-grid;place-items:center;box-sizing:border-box;padding:0;width:calc(1lh + 20px);height:calc(1lh + 20px);color:var(--ink)}
.boom .ai-flere svg{width:14px;height:14px;overflow:visible;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;transition:transform .45s cubic-bezier(.3,.7,.2,1)}
.boom .ai-flere[aria-expanded=true] svg{transform:rotate(180deg)}
@media (prefers-reduced-motion:reduce){.boom .ai-flere svg{transition:none}}
/* Forslagene er ord, ikke piller (3 Okt 2026, Martin: «blir det for mange pille-former på forsiden nå», og «gå for tekst»;
   skille og strek ble proevd). Feltet og knappene beholder pillen; streken kommer ved hover. ai.js setter data-forslag
   utenom Visuell profil (.sd), som er frosset. */
html.boom[data-forslag] .ai-chips{gap:2px 4px}
html.boom[data-forslag] .ai-chips .ai-chip{background:none;border-color:transparent;border-radius:0;padding:6px 10px;font-size:15px;color:var(--ink-2);
  text-decoration:underline;text-decoration-color:transparent;text-decoration-thickness:1px;text-underline-offset:6px;
  transition:color .16s ease,text-decoration-color .16s ease}
html.boom[data-forslag] .ai-chips .ai-chip:is(:hover,:focus-visible),
html.boom[data-forslag] .ai-chips .ai-chip.is-on{background:none;border-color:transparent;color:var(--ink);text-decoration-color:currentColor}
/* Resten av setningen staar graa i feltet mens du skriver (skygge() i ai.js, 3 Okt 2026). Speilet er likt satt som
   feltet; teksten du har skrevet er usynlig i det, og bare resten kan trykkes paa. */
html.boom .ai-skygge{position:absolute;margin:0;border-style:solid;border-color:transparent;background:none;color:transparent;
  white-space:pre-wrap;overflow-wrap:break-word;overflow:hidden;text-overflow:ellipsis;pointer-events:none;z-index:2}
html.boom .ai-skygge[hidden]{display:none}
html.boom .ai-skygge-r{color:var(--ink-3);pointer-events:auto;cursor:text}
html.boom[data-forslag] .ai-chips .ai-flere{width:auto;height:auto;padding:6px 10px;align-self:stretch}
/* VALGT FORSLAG ER EN LYS FYLL, IKKE EN SVART PILLE, 23 Sep 2026: "markerte
   setninger/spoerringer kan ikke vaere helt lik som book en demo." Prikken fra
   systembrikkene ble proevd her og tatt ut samme dag: "liker ikke helt den prikk-ideen
   til chatten, det fungerer med system-valg." Et forslag er en setning, ikke et system
   man kobler inn, saa noden betyr ingenting her. Valgt er naa en lys flate med
   blekkkant og fullt blekk: fortsatt et fyll, som moenster 01 krever, men ikke sidens
   svarte knapp. */
.boom .ai-chip.is-on,.boom .ai-chip.is-on:hover{
  background:var(--surface-2);color:var(--ink);border-color:var(--ink);font-weight:400;
}
/* SVARET STAAR PAA LINJE MED FELTET, 23 Sep 2026: "flytt chat svar mer til venstre."
   Det var midtstilt i heroen med 820px bredde, og startet derfor 166px til hoeyre for
   feltet det svarer fra. Naa har det feltets bredde og feltets venstre kant, og teksten
   starter der den skrevne teksten i feltet starter: 28px inn, som feltets polstring. */
/* SVARET ER ET ARK (5 Okt 2026, Martin valgte A: «ett svar som ett ark»). Streken over spoersmaalet er borte; svaret
   staar i et ark i --surface med myk skygge, som oeya og den aapne raden paa /resultater, og spoersmaalet er linja
   oeverst i arket. Ett svar om gangen; luft uten ark og historikk med tidligere spoersmaal er proevd og forkastet. */
.boom .ai-answer{border-top:0;max-width:860px;margin-left:0;margin-right:0;
  background:var(--surface);border-radius:var(--r-ark);box-shadow:var(--fluid-lift);
  padding:clamp(22px,2.6vw,30px) 28px clamp(16px,1.8vw,22px)}
.boom .ai-q{color:var(--ink-3);font-family:var(--mono);font-size:13px;text-transform:uppercase}
.boom .ai-a p{color:var(--ink);font-size:clamp(17px,1.8vw,22px);line-height:1.4;letter-spacing:-0.01em}
/* Den levende chatten (5 Okt 2026): ventelinja pulserer stille, og merket om KI staar lite og graatt under svaret. */
html.boom .ai-a p.ai-vent,html.boom .ai-ask-b p.ai-vent{color:var(--ink-3);animation:ai-vent 1.6s ease-in-out infinite}
@keyframes ai-vent{50%{opacity:.45}}
/* UNDER SVARET (6 Okt 2026, pakke B): KI-merket, «Bygger på», Kopier og Lagre er tatt av. Ett neste steg, blaa pille
   som handlingen ellers paa siden, men mindre fordi den staar i arket; under den linja «Hvorfor stole på dette
   svaret?» i graatt 15 px med en V som snur seg, og sidene som lenker med tynn strek naar den er aapen. */
html.boom :is(.ai-more,.ai-ask-m){display:flex;flex-direction:column;align-items:flex-start;gap:12px;margin-top:18px}
html.boom[data-knapp=rund] :is(.ai-more,.ai-ask-m) .ai-demo{height:42px;padding:0 18px 0 22px;font-size:15px;gap:10px}
/* de store knappene i heroen (u-stor) gjelder ikke knappen i svaret */
html.boom.u-stor[data-knapp=rund] :is(#chat,#start) .ai-more .boom-btn.ai-demo{height:42px;padding:0 18px 0 22px;font-size:15px;gap:10px;letter-spacing:0}
html.boom .ai-tillit{font-size:15px;line-height:1.45;color:var(--ink-3)}
html.boom .ai-tillit summary{display:inline-flex;align-items:center;gap:8px;cursor:pointer;list-style:none}
html.boom .ai-tillit summary::-webkit-details-marker{display:none}
html.boom .ai-tillit summary svg{width:12px;height:12px;fill:none;stroke:currentColor;stroke-width:1.5;transition:transform .2s ease}
html.boom .ai-tillit[open] summary svg{transform:rotate(180deg)}
html.boom .ai-tillit summary:hover,html.boom .ai-tillit[open] summary{color:var(--ink-2)}
html.boom .ai-tillit p{margin:6px 0 0;font-size:15px;letter-spacing:0;color:var(--ink-3)}
html.boom .ai-tillit a{color:inherit;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px}
html.boom .ai-tillit a:hover{color:var(--ink)}
/* Krysset som lukker svaret i toppchatten (nr. 9): oeverst til hoeyre i arket, graatt, flaten bare ved hover. */
html.boom .ai-ask-a{position:relative}
html.boom .ai-ask-lukk{position:absolute;top:8px;right:8px;display:grid;place-items:center;width:34px;height:34px;padding:0;
  border:0;border-radius:999px;background:none;color:var(--ink-3);cursor:pointer;transition:color .16s ease,background-color .16s ease}
html.boom .ai-ask-lukk svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round}
html.boom .ai-ask-lukk:is(:hover,:focus-visible){color:var(--ink);background:var(--surface-2)}
html.boom .ai-ask-a .ai-ask-q{padding-right:40px}
@media (prefers-reduced-motion:reduce){html.boom p.ai-vent{animation:none}}
.boom .ai-more a{color:var(--accent)}
/* SPØR OM DITT EGET ANLEGG (5 Okt 2026, idé 3, ANLEGG i ai.js): tre steg i svaret. Hvert steg er et lite nummer og
   spoersmaalet i graatt, og valgene er ord med noden foran, tom eller fylt, som systemene i verktoeyet paa Unity AI
   (Martin 23 Sep 2026: prikken «fungerer med system-valg»). Ingen piller og ingen bokser; valgt er fylt node og blekk. */
html.boom .ai-anlegg{display:grid;gap:18px}
html.boom .ai-steg[hidden]{display:none}
html.boom .ai-anlegg p.ai-steg-l{margin:0 0 6px;font-size:15px;line-height:1.4;letter-spacing:0;color:var(--ink-3)}
html.boom .ai-steg-n{font-family:var(--mono);font-size:13px;margin-right:10px}
html.boom .ai-steg-r{display:flex;flex-wrap:wrap;gap:2px 4px;margin-left:-10px}
html.boom .ai-steg-v{display:inline-flex;align-items:center;gap:9px;font:400 15px/1.3 var(--sans);letter-spacing:-0.01em;
  padding:6px 10px;border:0;background:none;color:var(--ink-2);cursor:pointer;
  text-decoration:underline;text-decoration-color:transparent;text-decoration-thickness:1px;text-underline-offset:6px;
  transition:color .16s ease,text-decoration-color .16s ease}
html.boom .ai-steg-v::before{content:"";flex:none;width:9px;height:9px;border-radius:50%;box-sizing:border-box;
  border:1.5px solid var(--ink-3);background:transparent;transition:background-color .16s ease,border-color .16s ease}
html.boom .ai-steg-v:is(:hover,:focus-visible){color:var(--ink);text-decoration-color:currentColor}
html.boom .ai-steg-v.is-on{color:var(--ink)}
html.boom .ai-steg-v.is-on::before{background:var(--ink);border-color:var(--ink)}
html.boom .ai-steg-go,html.boom .ai-steg-endre{font:400 15px/1.3 var(--sans);letter-spacing:0;border:0;background:none;padding:0;
  cursor:pointer;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:4px}
html.boom .ai-steg-go{margin-top:14px;color:var(--ink);text-decoration-color:transparent}
html.boom .ai-steg-go:is(:hover,:focus-visible){text-decoration-color:currentColor}
html.boom .ai-steg-go i{font-style:normal;margin-left:6px}
html.boom .ai-steg-endre{color:var(--ink-3);vertical-align:baseline}
html.boom .ai-steg-endre:hover{color:var(--ink)}
html.boom .ai-anlegg-vi{color:var(--ink-2)}
/* /resultater: én linje under kortet, og stegene i et eget ark under den, som kortet over (ultimat.css .u-rs-l). */
html.boom .ai-anlegg-rs{margin-top:clamp(20px,2.4vw,32px)}
html.boom .ai-anlegg-apne{display:inline-flex;align-items:center;gap:10px;font:400 17px/1.4 var(--sans);letter-spacing:-0.01em;
  color:var(--ink);background:none;border:0;padding:6px 0;cursor:pointer;
  text-decoration:underline;text-decoration-color:transparent;text-decoration-thickness:1px;text-underline-offset:6px;
  transition:text-decoration-color .16s ease}
html.boom .ai-anlegg-apne:is(:hover,:focus-visible){text-decoration-color:currentColor}
html.boom .ai-anlegg-apne svg{width:14px;height:14px;flex:none;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;
  stroke-linejoin:round;transition:transform .45s cubic-bezier(.3,.7,.2,1)}
html.boom .ai-anlegg-apne[aria-expanded=true] svg{transform:rotate(180deg)}
html.boom .ai-anlegg-svar{margin-top:12px;background:var(--surface);border-radius:var(--r-ark);box-shadow:var(--fluid-lift);
  padding:clamp(22px,3vw,44px) clamp(20px,3vw,48px)}
html.boom .ai-anlegg-svar[hidden]{display:none}
html.boom .ai-anlegg-svar .ai-a p + p{margin-top:12px}
@media (prefers-reduced-motion:reduce){html.boom .ai-anlegg-apne svg{transition:none}}

/* The switch between the three front pages sits on this ground too. */
.boom .ai-switch{background:var(--surface);border-color:var(--rule)}
.boom .ai-switch button{color:var(--ink-2)}
.boom .ai-switch button[aria-pressed="true"]{background:var(--accent);color:var(--on-accent)}

/* ---------------------------------------------------------------------------
   The rest of the site in this register, 17 Sep 2026. Everything below is the
   SKIN: it applies wherever html.boom is stamped, and it changes no markup.
   The rule throughout is the one taken from their page: hierarchy by size and
   tracking, never by weight, and the tracking tightens as the size grows.
   --------------------------------------------------------------------------- */

.boom body,.boom .ai-page{background:var(--paper);color:var(--ink-2)}
.boom main{color:var(--ink-2)}

/* The type scale, on every page. h1 takes the 112 step like the front page (3 Oct 2026, Martin: «A på alle
   undersider»): at 72 the title was weaker than the section headings under it. Before, the 112 was the front
   page's alone. The answer pages keep their own smaller h1 (.svar h1), because their title is a question. */
.boom main h1,.boom .pp-hero h1{
  font-size:clamp(44px,8.8vw,112px);font-weight:400;letter-spacing:-0.04em;line-height:1;
  /* et langt ord som ikke faar plass deles heller enn aa gaa ut av spalten */
  -webkit-hyphens:auto;hyphens:auto;hyphenate-limit-chars:14 6 6;
}
/* En tittel som er ett langt ord staar paa én linje (3 Okt 2026, Martin: «den kan gjøres mindre så alt kommer på en
   linje»): «Personvernerklæring» er 7,9 em bred, saa 100 px faar plass i spalten paa 840 og 8,6vw paa telefon. */
.boom main h1.ett-ord{font-size:clamp(30px,8.6vw,100px);-webkit-hyphens:manual;hyphens:manual;max-width:none}
.boom main h2,.boom .pp-h,.boom .ai-sec-h h2,.boom .ai-scale-h{
  font-size:clamp(28px,4.2vw,48px);font-weight:400;letter-spacing:-0.035em;
  line-height:1.075;max-width:26ch;
}
.boom main h3{font-size:clamp(21px,2.6vw,38px);font-weight:400;letter-spacing:-0.03em;line-height:1.1}
.boom main h4,.boom .pp-do h3,.boom .layer h3,.boom .day-i h3,.boom .rows .row h4{
  font-size:20px;font-weight:400;letter-spacing:-0.02em;line-height:1.2;
}
/* The 32px statement belongs to a SHORT standfirst, which is the only place
   their page uses it. A 329-character intro paragraph at 32px is a wall, so a
   long lead takes a step above body instead. The selector has to reach 0,3,2 to
   beat `.ai-doc main .narrow .lead` in the bridge, which is 0,2,2. */
.boom .pp-lead{
  font-size:clamp(20px,2.6vw,32px);font-weight:500;letter-spacing:-0.01em;
  line-height:1.1;color:var(--ink);
}
.boom main .ai-lede,.boom.boom main .narrow .lead,.boom.boom main .hero .lead,.boom main .lead{
  font-size:20px;font-weight:400;letter-spacing:-0.01em;line-height:1.4;
  color:var(--ink-2);
}
.boom .pp-intro,.boom main p,.boom .card p,.boom .layer p,.boom .layer ul,.boom .vcase p,
.boom .person p,.boom .prop p,.boom .after p,.boom .start p,.boom .faq details p,.boom .rec-r p{
  font-size:16px;line-height:1.5;color:var(--ink-2);
}
.boom main h1,.boom main h2,.boom main h3,.boom main h4{color:var(--ink)}

/* Mono, thirteen pixels, uppercase, for anything that labels rather than says. */
/* These render WORDS, so they are Open Sans and not in caps. They were 13px mono
   uppercase, which is the site's own typography rule broken in ten places at once,
   and Martin named the effect on 18 Sep 2026: "her kan du finne en annen font for
   settefiskanlegg - RAS, per nå skriker det claude code generert." The labels stay,
   because a sector or a category is information the heading does not carry; it is
   the FACE that was wrong. Mono is still correct one step away, on .boom-n small,
   because a unit is a unit. */
.boom .ai-case-k,.boom .nw-who,.boom .pr-tag,.boom .ai-kicker,.boom .rec-h p,.boom .day-t,
.boom .ai-menu-k,.boom .status,.boom .fig-s,.boom .ev,.boom .ai-q{
  font-family:var(--sans);font-size:14px;font-weight:600;line-height:1.35;
  letter-spacing:0.005em;text-transform:none;
}
.boom .ai-kicker{color:var(--ink-3);font-weight:400}

/* Objects are a hairline and a lot of air. The ground is already dark; a fill
   would only mute the type. */
.boom .ai-case,.boom .ai-prod,.boom .nw-card,.boom .ai-bubble,.boom .card,.boom .person-card,
.boom .sh-screen,.boom .ai-box,.boom .ai-chip,.boom .ai-dd-p,.boom .sh-nav,.boom .demo{
  background:var(--surface);border:1px solid var(--rule);box-shadow:none;
}
.boom .ai-case,.boom .ai-prod,.boom .nw-card,.boom .ai-bubble,.boom .demo{border-radius:2px}
.boom .ai-case:hover,.boom .ai-prod:hover,.boom .nw-card:hover{background:var(--surface-2)}
.boom .card{border-top:1px solid var(--rule);border-inline:0;border-bottom:0;background:none}
.boom .ai-bubble::before{background:var(--surface);border-color:var(--rule)}
.boom .nw-mark{background:var(--surface-2)}
.boom .person img,.boom .ai-face{border:1px solid var(--rule);border-radius:2px}
/* TEAMET PAA /about SOM MOSAIKK, 3 Okt 2026 (Martin: «bare i ytterkantene på de ytterste bildene ... tar inspo fra
   omtale siden»). Samme grep som omtalekortene: de seks personene er én flate med smale fuger, bare de ytre
   hjoernene er runde, bildet trekker seg sakte naermere ved hover, og teksten fylles graatt fra der pekeren
   kommer inn (ai.js gir .p-t --mx, --my og --mr). Seks personer fyller siste rad i 3, 2 og 1 spalte. */
html.boom .team{gap:4px;border-radius:var(--r-ark);overflow:hidden;isolation:isolate}
html.boom .person{background:var(--surface)}
html.boom .p-bilde{display:block;overflow:hidden}
html.boom .person .p-bilde img{display:block;border:0;border-radius:0;transition:transform 1.1s cubic-bezier(.2,.7,.2,1)}
html.boom .person:is(:hover,:focus-within) .p-bilde img{transform:scale(1.05)}
/* Trond Ove staar lavere i sitt bilde enn de andre, saa kortet hans bruker et eget utsnitt fra tools/ai/ansikter.py
   (KORT), der hodet naar toppen som Mortens (16 Okt 2026, Martin: «ta trond ove sitt bilde mer opp»). Ingen zoom i CSS:
   den gjorde det lille bildet uskarpt. */
html.boom .p-t{
  position:relative;z-index:1;flex:1;display:flex;flex-direction:column;overflow:hidden;background:var(--surface);
  padding:clamp(22px,2.2vw,32px) clamp(22px,2.2vw,32px) clamp(26px,2.6vw,38px);
}
html.boom .p-t::before{
  content:"";position:absolute;z-index:-1;left:var(--mx,50%);top:var(--my,0);
  width:calc(var(--mr,600px) * 2);height:calc(var(--mr,600px) * 2);margin:calc(var(--mr,600px) * -1) 0 0 calc(var(--mr,600px) * -1);
  border-radius:50%;background:var(--surface-2);transform:scale(0);transition:transform .55s cubic-bezier(.3,.7,.2,1);
}
html.boom .person:is(:hover,:focus-within) .p-t::before{transform:scale(1)}
html.boom .p-t h4{margin-top:0}
@media (prefers-reduced-motion:reduce){
  html.boom .person .p-bilde img,html.boom .p-t::before{transition:none}
  html.boom .person:is(:hover,:focus-within) .p-bilde img{transform:none}
}
/* The architecture drawing was drawn in this register, so the skin restates
   only weights and label faces. The base rules sit at 0,3,0; these are 0,4,0. */
.boom .arch-st{background:var(--paper);border:1px dashed var(--rule);border-radius:2px}
.boom .arch-core{background:var(--accent);border-color:var(--accent);border-style:solid}
.boom .arch .arch-st .arch-k{font-family:var(--mono);font-size:13px;text-transform:uppercase;color:var(--ink-3)}
.boom .arch-k span{letter-spacing:0}
.boom .arch .arch-st .arch-h{font-size:24px;font-weight:400;letter-spacing:-0.03em;line-height:1.1;color:var(--ink)}
.boom .arch .arch-core .arch-h{font-size:32px;color:var(--on-accent)}
.boom .arch .arch-core .arch-k,.boom .arch .arch-core .arch-k span,.boom .arch-tag{color:var(--on-accent)}
.boom .arch-ls{font-size:16px}
.boom .arch-ls li{border-color:var(--rule);color:var(--ink)}
.boom .arch-ls small{color:var(--ink-3);font-size:13px}
.boom .arch-caps b{font-weight:400;font-size:20px;letter-spacing:-0.02em}
.boom .arch-caps span{font-size:14px}
.boom .arch-f,.boom .arch-ln small,.boom .arch-tag{font-family:var(--mono);font-size:12px;text-transform:uppercase;line-height:1.3}
.boom .arch-f{color:var(--ink-3)}
.boom .arch-tag b{font-weight:400;font-size:11px}
.boom .uoneway{border-color:var(--rule)}
.boom .uoneway b{font-weight:400;font-size:20px;letter-spacing:-0.02em}

/* Figures in the mono, in the accent, because a number is the loudest thing on
   a page in this register and the accent is what it has. */
.boom .ai-num,.boom .fig-v{
  font-family:var(--mono);font-size:clamp(38px,5vw,64px);font-weight:400;
  letter-spacing:-0.03em;line-height:1;color:var(--accent);
}
.boom .ai-num small,.boom .fig-u{font-size:.32em;color:var(--ink-3);letter-spacing:0}
.boom .fig-l{font-size:16px;color:var(--ink-2)}
.boom .ev-1,.boom .ev-2,.boom .status.s-3,.boom .status.s-2{color:var(--accent)}
.boom .ev-3,.boom .status.s-1{color:var(--ink-3)}
.boom .status-key .k-3{background:var(--accent)}
.boom .status-key .k-2{border-color:var(--accent)}
.boom .status-key .k-1{border-color:var(--ink-3)}
/* BEVISMERKET ER BILDET I DE SJU RADENE, 24 Sep 2026 (convert.py, zigzag): "tegningen ser helt
   forferdelig ut", etter to smaa grafer. Seksjonen handler om hvor godt hver beslutning er
   dokumentert, saa raden viser det: samme fyllskala som forklaringen over (fylt, tykk ring,
   tynn ring i ink-3), stor nok til aa baere raden, med omraadet i Archivo ved siden av og
   merkets navn under. Omraadet er under seksjonsoverskriften i stoerrelse. Paa telefon staar
   merket over teksten, som en etikett for raden. */
.boom .ai-doc .vcase-m{display:flex;align-items:center;justify-content:center;gap:clamp(18px,2.2vw,30px)}
.boom .ai-doc .vm-dot{flex:none;width:clamp(52px,5.4vw,76px);aspect-ratio:1;border-radius:50%;
  box-sizing:border-box;border:1.5px solid var(--ink-3)}
.boom .ai-doc .vcase-m.s-3 .vm-dot{background:var(--accent);border-color:var(--accent)}
.boom .ai-doc .vcase-m.s-2 .vm-dot{border:clamp(9px,.95vw,13px) solid var(--accent)}
.boom .ai-doc .vm-w{display:flex;flex-direction:column;gap:6px;min-width:0}
.boom .ai-doc .vm-who{font:400 clamp(28px,3.1vw,42px)/1.02 var(--sans);letter-spacing:-0.035em;color:var(--ink)}
.boom .ai-doc .vm-ev{font-size:15px;line-height:1.3;color:var(--ink-2);letter-spacing:-0.005em}
.boom .ai-doc .vcase-go{display:flex;flex-wrap:wrap;gap:8px 22px;margin:18px 0 0}
@media (max-width:860px){
  .boom .ai-doc .vcase-m{order:-1;justify-content:flex-start}
}
.boom .status-key{font-family:var(--sans);font-size:14px;color:var(--ink-2);text-transform:none}

/* Buttons: pill, 24px on the front page, a step down in a card or a row. */
.boom .ai-try,.boom .btn{
  background:var(--accent);color:var(--on-accent);border-radius:999px;
  font-weight:400;font-size:17px;padding:11px 26px;border:1px solid transparent;
}
.boom .ai-try:hover,.boom .btn:hover{text-decoration:underline;text-underline-offset:4px}
.boom .ai-try-q{background:none;border-color:var(--rule);color:var(--ink)}
.boom .ai-try-q:hover{border-color:var(--accent);color:var(--ink)}
.boom .pr-more,.boom .nw-go,.boom .ai-more a,.boom .ai-seemore a,.boom .link-center a{
  color:var(--accent);
}
.boom .pr-tag{background:none;border:1px solid var(--rule);color:var(--ink-3);border-radius:2px}
.boom .pr-tag.pr-live{border-color:var(--accent);color:var(--accent)}

/* Rules and separators. */
.boom .rec-h,.boom .rec-r,.boom .layer,.boom .rows .row,.boom .pp-do,.boom .start li,
.boom .prop,.boom .after .st,.boom .day-i,.boom .faq details,.boom .cases-list,.boom .rec{
  border-color:var(--rule);
}
/* A NAME ON EVERY CELL, which is what Augury's version of this table has and
   ours did not. Read off their page 21 Sep 2026: each cell is two words and then
   one line, so the eye scans four names down a column and reads a sentence only
   when a name lands. Ours was eight sentences of eight words with no way in. The
   approved lines are untouched; the name is a layer ABOVE them, and the pairs do
   most of the work by themselves: To fasiter against En fasit, For sent against
   Samme dag. The line drops to --ink-3 on both sides, because once there is a
   name to scan the sentence is the thing you read second.

   These sit here, after the skin's own .rec colours, and not up in the front
   page's block: both are 0,2,0 and this one is later, so file order decides. The
   arrow rule that used to be on this line went with the arrows. */
/* SETNINGEN ER ALT, 23 Sep 2026: "minimalt med tekst, men den teksten som staar der
   er kraftfull og veldig lett aa forstaa." Navnelaget er ute og hver celle er én kort
   setning, saa setningen tar navnets plass og stoerrelse. Venstre er problemet i
   ink-3, hoeyre er svaret i fullt blekk: et ekte steg mellom spaltene, og det eneste
   skillet raden trenger. 0,3,2 fordi `.boom main p` er 0,2,1. */
.boom .rec-r p.rec-a,.boom .rec-r p.rec-b{
  font-size:clamp(19px,1.7vw,23px);line-height:1.25;letter-spacing:-0.02em;max-width:34ch;
  text-wrap:balance;
}
.boom .rec-r p.rec-a{color:var(--ink-3)}
.boom .rec-r p.rec-b{color:var(--ink)}
.boom .start li::before{color:var(--accent);font-family:var(--mono)}
.boom address,.boom .muted,.boom .person .role,.boom .rows .row h4 small{color:var(--ink-3)}
/* :not(.boom-btn) is load-bearing. Each :not(.class) counts as a class, so this
   selector is 0,3,2 and outranked `.boom .boom-btn-b` at 0,2,0: the white pill
   got white text and the orange one white text at 3.21, which the accent must
   never carry. Same trap as .ai-menu-in > a on /ai, same fix: a link rule that
   covers a whole region excludes the buttons in it by class. */
.boom main a:not(.ai-try):not(.btn):not(.boom-btn):not(.boom-kart-a){color:var(--ink)}
/* The hover rule has to exclude the same things as the rule above it. It lost
   :not(.boom-btn) and, at 0,5,2, painted "Book en demo" ink on its own ink fill on
   hover, so the words disappeared (Martin, 23 Sep 2026). Two rules that must name
   the same exclusions sit on adjacent lines so the next edit sees both. */
.boom main a:not(.ai-try):not(.btn):not(.boom-btn):not(.boom-kart-a):hover{color:var(--accent)}
/* LENKEN I ET KLIPP ER HVIT, 24 Sep 2026. Regelen over gjorde "Se Pellet Monitor" blekk-
   svart paa videoens moerke toning, paa forsiden og paa /shorts, og den ble ikke sett for
   Martin viste et skjermbilde av noe annet. Tyngre enn begge reglene over (0,5,3). */
.boom main .sh-over a:not(.ai-try):not(.btn):not(.boom-btn):not(.boom-kart-a),
.boom main .sh-over a:not(.ai-try):not(.btn):not(.boom-btn):not(.boom-kart-a):hover{color:var(--on-media)}

/* Forms. */
.boom form.contact input,.boom form.contact textarea{
  background:var(--surface);border:1px solid var(--felt);color:var(--ink);border-radius:2px;
}
.boom form.contact input::placeholder,.boom form.contact textarea::placeholder{color:var(--ink-3)}
.boom form.contact label{color:var(--ink-3)}

/* No light mode is on offer here: the register is a dark ground and one hot
   accent, so the theme switch is hidden rather than left doing nothing. */

/* Sensa Shorts on BOOM. The section is LIFTED from /ai, where it is centred:
   a tall 9:16 player hugging a left gutter left a void, so /ai centred heading
   and player both. BOOM is left-aligned throughout and its answer to the void
   is the other column: kicker, heading and standfirst on the left, the phone
   on the right, the same two-column move as the hero. No band, no blurred
   backdrop, no shadow bath: one white ground, a hairline frame at the 24 radius
   the buttons use, and the controls as the round hairline buttons they are.
   Martin, 17 Sep 2026: "shorts må tilpasses boom-designet, det ser rått ut nå." */
.boom .ai-shorts{
  /* One column, and the player centred on the PAGE. Martin, 18 Sep 2026:
     "videospilleren maa midtstilles paa hjemmesiden". It was two columns with the
     player in the right one, which is what he had questioned the day before; the
     heading keeps its place at the top left and the player sits under it, centred. */

  /* NO ground at all, 19 Sep 2026: "ta vekk hele bakgrunnen, bare la videoen staa
     alene." Three versions died to get here and the direction was one way the whole
     time: a card, then a card with no border, then a pool that faded out, then
     nothing. Each step removed something and each step read better, which is the
     answer to what the section needed: **it was never a ground, it was the absence
     of everything else.** The clip is the only object, and on a page that is one
     background everywhere else this section finally obeys the same rule.

     What that settles: the empty width question is gone with the box, the shielding
     question is gone because the video was always opaque and the ground never did
     that job, and the section takes the same top margin as every .boom-sec so its
     rhythm matches the card grids instead of its edges matching them. */
  margin:clamp(56px,8vw,112px) 0 0;
  padding:0;
  background:none;border:0;border-radius:0;
}
/* Centred, heading and player both, 18 Sep 2026: "midtstill sensa shorts over
   videoen naa". This is the one section on the page that is not left-aligned, and
   it is the same exception /ai makes for the same reason: a tall 9:16 player is
   centred, and a heading ranged left against a centred player reads as a mistake.
   One alignment per section; here the alignment is centre. */
.boom .ai-shorts-in{max-width:none;margin:0;padding:0;text-align:center}
.boom .ai-shorts-h{max-width:none;margin:0}
.boom .ai-shorts-h .boom-label{margin-bottom:clamp(14px,1.8vw,20px)}
.boom .ai-shorts-h h2{margin:0 auto;max-width:14ch}
/* PAA SIN EGEN SIDE ER SPILLEREN SISTE TING FOER BUNNMARGEN, 24 Sep 2026: "ikke la videoen
   ligge paa bunnmargen". Paa forsiden kom neste seksjon etter; her maa seksjonen selv
   holde avstanden, samme trinn som over den. */
.boom main > .ai-shorts:last-child{padding-bottom:clamp(56px,8vw,112px)}
.boom .ai-shorts-h .ai-lede{
  font-size:clamp(20px,2.2vw,28px);font-weight:400;letter-spacing:-0.015em;
  line-height:1.2;color:var(--ink-2);margin:clamp(14px,1.6vw,22px) auto 0;max-width:24ch;
}
/* A RAIL ON THE RIGHT, 21 Sep 2026: "denne paa sensa short kan vaere paa
   hoeyresiden av videospilleren." This reverses the column of 19 Sep, and the
   reason it can is that the thing the column was fixing has since gone. Back then
   three round buttons stood in 708px of empty PANEL beside a 427px player,
   attached to nothing; Martin then had the panel removed entirely two days later
   ("ta vekk hele bakgrunnen, bare la videoen staa alene"), so there is no empty
   ground for them to float in any more. Against the player's own edge they read as
   the player's controls, which is the arrangement every vertical player uses and
   the one the /ai design never stopped using.

   A CENTRED PLAYER WITH SOMETHING BESIDE IT NEEDS THE SPACER BACK, and this is the
   part that is easy to forget: the rail sits in the same flex row, so centring the
   row centres the PAIR and leaves the player half a rail off centre, measured at
   31px in September. `.sh-stage::before` is an empty box of one rail width on the
   other side; unlike absolute positioning it is part of the layout and cannot
   overflow. And --sh-chrome has to reserve BOTH of them again, or the player is
   sized against a viewport that is 136px wider than the room it actually has. */
.boom .sh-stage{
  --sh-hmax:min(760px,calc(100vh - 240px));
  --sh-chrome:calc((2 * var(--gutter)) + 136px);
  margin:clamp(26px,3.4vw,44px) 0 0;padding:0;max-width:none;
  flex-direction:row;justify-content:center;align-items:center;
  gap:clamp(12px,1.6vw,22px);
}
.boom .sh-stage::before{display:block}
/* No hairline on the screen. The panel behind it is a real step now, and a clip is
   a picture with its own edge; a border round it was a second frame at the SAME
   24px radius and the SAME --rule as the panel, which is what read as unfinished.
   The radii are deliberately apart now, 32 outside and 20 inside. */
.boom .sh-screen{
  width:min(var(--sh-w),100%);height:auto;aspect-ratio:9/16;
  border-radius:20px;box-shadow:none;border:0;background:var(--paper);
}
.boom .sh-rail{flex-direction:column;gap:clamp(10px,1.1vw,14px)}
/* UNDER THE PLAYER ON A PHONE, and it is the picture that decides. Beside it at
   375px the rail and its balancing spacer cost 136px of a 375px viewport, which
   takes the player from 310 wide to 237: a quarter of the picture for three
   buttons, on the one screen where the picture is already smallest. Below the
   breakpoint the component already uses, the stage is a column again, the spacer
   goes, and the chrome stops reserving the two rails. */
@media (max-width:620px){
  .boom .sh-stage{
    --sh-chrome:calc(2 * var(--gutter));
    flex-direction:column;justify-content:flex-start;
    gap:clamp(14px,1.8vw,20px);
  }
  .boom .sh-stage::before{display:none}
  .boom .sh-rail{flex-direction:row}
}
.boom .sh-nav{width:44px;height:44px;background:var(--paper);border-color:var(--rule);color:var(--ink)}
.boom .sh-nav:hover{background:var(--ink);color:var(--paper);border-color:var(--ink)}
.boom .sh-nav[disabled]:hover{background:var(--paper);color:var(--ink);border-color:var(--rule)}
.boom .sh-mute[aria-pressed="true"]{background:var(--ink);color:var(--paper);border-color:var(--ink)}
/* The end card is the last FRAME of the film, not a blank sheet. It was --surface
   white inside a white screen on a near-white panel: three whites stacked, which is
   why that one frame read as a hole in the section. It takes --accent and
   --on-accent, the pair contrast.py already measures, and size does the receding
   between the two lines rather than an opacity, the same way the band label was
   fixed. The filled pill inverts, or an ink button on ink ground disappears. */
.boom .sh-end{background:var(--accent)}
.boom .sh-end .sh-t{color:var(--on-accent)}
.boom .sh-end .sh-d{color:var(--on-accent);font-size:14px}
.boom .sh-end .ai-try{background:var(--on-accent);color:var(--accent);border-color:var(--on-accent)}

/* Icons on the product cards, 18 Sep 2026: "det gir det en ny edge og mer lesbart".
   The same six the product pages already use, so nothing new was drawn. One weight,
   one size, the card's own ink, sitting above the label: they identify the product
   at a glance and they do not compete with the 38px name under them. The value
   cards get NONE, deliberately: a figure is already the thing your eye lands on. */
.boom-prod .boom-i{
  display:block;width:26px;height:26px;color:var(--ink);
  margin:0 0 clamp(14px,1.6vw,18px);
}
.boom-prod:hover .boom-i{color:var(--action)}

/* The card's call to action on hover. Martin, 18 Sep 2026: "maa ha en slags animasjon
   naar man hover over, utheving eller en slags shading, gjoer det som er mest unikt og
   fett." A tint behind the card is what every template does, so the movement is in the
   TYPE instead, which is this page's whole argument: a rule draws in from the left
   under the words, and the arrow steps out of the line it was sitting in. Both are
   driven from the CARD, so the whole card is the target and not just the four words.
   scaleX from a left origin costs no layout; a width transition would reflow. */
.boom .boom-go{
  display:inline-flex;align-items:center;gap:8px;position:relative;
  /* margin-top:auto pins it to the bottom; the padding is the MINIMUM gap, for a
     card whose body already fills the height. Martin: "knappene og teksten maa ha
     litt mer luft, naa staar de helt oppi hverandre." */
  padding-bottom:3px;margin-top:auto;padding-top:clamp(18px,2.2vw,28px);
  align-self:flex-start;
}
.boom .boom-go::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1.5px;
  background:var(--ink);transform:scaleX(0);transform-origin:left center;
  transition:transform .28s cubic-bezier(.22,.61,.36,1);
}
.boom .boom-go i{
  font-style:normal;display:inline-block;
  transition:transform .28s cubic-bezier(.22,.61,.36,1);
}
.boom-prod:hover .boom-go::after,.boom-prod:focus-visible .boom-go::after,
.boom-fig:hover .boom-go::after,.boom-fig:focus-visible .boom-go::after{transform:scaleX(1)}
.boom-prod:hover .boom-go i,.boom-prod:focus-visible .boom-go i,
.boom-fig:hover .boom-go i,.boom-fig:focus-visible .boom-go i{transform:translateX(6px)}
@media (prefers-reduced-motion:reduce){
  .boom .boom-go::after,.boom .boom-go i{transition:none}
}

/* The figure comes forward when you point at its card, 18 Sep 2026: "tallene popper
   litt frem". It grows from its own left baseline, so the label above and the heading
   below do not move; a scale that pushed layout would shift the whole row. */
.boom .boom-n{
  transition:transform .3s cubic-bezier(.22,.61,.36,1);
  transform-origin:left bottom;
}
.boom-fig:hover .boom-n{transform:scale(1.055) translateY(-2px)}

/* The six product icons, 18 Sep 2026. Each does what its product does, and the
   shapes are INLINE on the card rather than <use>d, which is what makes this
   possible at all: a <use> clones into a shadow tree where document keyframes do
   not resolve, so "blank sheet, then one line at a time" could not be written.
   The shapes come from tools/lab/icons.py either way, so there is still one source.
   Every animation runs only while hovered, and none of them runs under
   prefers-reduced-motion. */
.boom-i .k1,.boom-i .k2,.boom-i .k3{transition:translate .34s cubic-bezier(.22,.61,.36,1)}

/* Unity: the three layers open from the top down. */
.boom-prod:hover .i-unity .k1,.boom-prod:focus-visible .i-unity .k1{translate:0 -2.6px}
.boom-prod:hover .i-unity .k3,.boom-prod:focus-visible .i-unity .k3{translate:0 2.6px}

/* Unity AI: the dots think, then the source line draws in under the bubble. The
   bubble is not the point; what is ours is that the answer arrives with a source. */
/* A bubble and three dots, solid at rest. Hovering makes them think in sequence. */
.boom-prod:hover .i-ai .d1{animation:ai-think .9s ease-in-out infinite}
.boom-prod:hover .i-ai .d2{animation:ai-think .9s ease-in-out .15s infinite}
.boom-prod:hover .i-ai .d3{animation:ai-think .9s ease-in-out .3s infinite}
@keyframes ai-think{0%,100%{opacity:.3}45%{opacity:1}}

/* Optimizer: the alternatives fade AND their end nodes slide into the chosen one,
   so it reads as collapsing to an answer rather than merely dimming. */
.i-opt .a1,.i-opt .a2,.i-opt .n1,.i-opt .n2{transition:opacity .34s ease,translate .38s cubic-bezier(.22,.61,.36,1)}
.i-opt .k3{transition:fill .34s ease}
.boom-prod:hover .i-opt .a1,.boom-prod:hover .i-opt .a2{opacity:0}
.boom-prod:hover .i-opt .n1{opacity:0;translate:0 6.5px}
.boom-prod:hover .i-opt .n2{opacity:0;translate:0 -6.5px}
.boom-prod:hover .i-opt .k3{fill:currentColor}

/* Aqualog: the sheet blanks and the three lines are written back in, one at a time,
   ending exactly where they started. Martin, 18 Sep 2026: "denne må starte med blankt
   ark, så kommer en og en linje inn på arket." A transition cannot do that; only an
   animation can start from a state the element is not in. */
.boom-prod:hover .i-log .w1{animation:log-write .42s ease .05s both}
.boom-prod:hover .i-log .w2{animation:log-write .42s ease .3s both}
.boom-prod:hover .i-log .w3{animation:log-write .42s ease .55s both}
@keyframes log-write{
  from{opacity:0;clip-path:inset(0 100% 0 0)}
  to{opacity:1;clip-path:inset(0 0 0 0)}
}

/* Pellet Monitor: the needle swings from target into over-feeding. transform-box is
   view-box and the origin is the pivot itself, so the needle turns about its own base
   rather than about the middle of the icon. */
.i-pellet .needle{
  transition:rotate .55s cubic-bezier(.34,1.25,.5,1);
  transform-box:view-box;transform-origin:12px 16.6px;
}
.i-pellet .tick{opacity:.3;transition:opacity .3s ease}
.boom-prod:hover .i-pellet .needle{rotate:74deg}
.boom-prod:hover .i-pellet .tick{opacity:1;transition-delay:.35s}

/* Labs: the slab is the data you already have and trust; the three blocks are what
   you build on it, and on hover ALL THREE drop in sequence. One block landing was too
   quiet to read as anything: "denne animasjonen er for svak." The overshoot in the
   easing is what makes them land rather than arrive. */
.boom-prod:hover .i-labs .b1{animation:labs-drop .46s cubic-bezier(.34,1.5,.5,1) .04s both}
.boom-prod:hover .i-labs .b2{animation:labs-drop .46s cubic-bezier(.34,1.5,.5,1) .18s both}
.boom-prod:hover .i-labs .b3{animation:labs-drop .46s cubic-bezier(.34,1.5,.5,1) .32s both}
@keyframes labs-drop{from{translate:0 -13px;opacity:0}to{translate:0 0;opacity:1}}

@media (prefers-reduced-motion:reduce){
  .boom .boom-n{transition:none}
  .boom-fig:hover .boom-n{transform:none}
  .boom-i *,.boom-prod:hover .boom-i *{animation:none !important;transition:none;translate:none}
  .boom-prod:hover .i-ai .k2,.boom-prod:hover .i-ai .k3{opacity:1}
  }

/* ===========================================================================
   The context network, 18 Sep 2026. A mass of nodes that spreads down the page
   as you scroll and withdraws as you scroll back. Geometry in tools/ai/boom.py.

   NODES ARE THE PICTURE, LINES ONLY CONNECT THEM. Martin, on the build before
   this one: "ser dette mer ut som spindelvev enn nettverks noder?" It did, and
   the cause was the ratio: edges at .14 against nodes at .45 that were two to
   three units wide, so the lines carried the drawing and the dots vanished. In
   all three references he sent, the dots dominate and the lines are hairlines
   between them. So the edges came DOWN to .09 and the nodes UP to .62, with
   roughly double the radius and more spread by degree, which is what makes a
   junction look like a junction.

   THREE LAYERS, and the middle one is what stops it reading flat:
     .boom-net-d  a second, sparser mesh drawn BLURRED behind the first. The
                  blur is one filter on the group, not one per element. Two of
                  his references use exactly this, a soft mesh behind a sharp
                  one, and it is the difference between a diagram and a cloud
                  with depth.
     .boom-net-e  the edges, hairlines.
     .boom-net-n  the nodes, drawn last so a line always stops at a dot.

   Unreached is ABSENT, not faint: opacity starts at zero. A fabric over the
   whole viewport takes attention even at .03, and the page is a page before it
   is a picture.

   The bright flash is gone: arriving from zero is already a visible change.
   What is left is a fade in, a small settle on the nodes so an arrival lands
   rather than blinks on, and a plain fade out coming back. The layer's overall
   presence is set from ai.js against scroll progress, full on the landing
   screen and easing to a floor once content is being read; the measurements
   behind that are in the script. Nothing here drifts.

   Every colour is alpha on --ink, never a grey token: a fixed grey that reads on
   the white page vanishes on the hero wash, while alpha composites against
   whatever it crosses.
   =========================================================================== */
.boom-net{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.boom-net svg{display:block;width:100%;height:100%}
.boom main,.boom .ai-foot{position:relative;z-index:1}

/* Depth, three planes. Each blur is ONE filter on a group; per-element blur on
   hundreds of shapes is the same picture at many times the cost.

   The FAR plane is finer and fainter than the focal one, so it recedes. The NEAR
   plane is the one that was missing, and it is what Martin meant by "fortsatt
   mangler den dybde": large soft dots lying IN FRONT of the sharp mesh, carrying
   no edges. It is the only cue that puts the viewer inside the cloud rather than
   in front of it, and one blurred layer behind a sharp one is a binary, which
   reads flat however well it is tuned. */
/* PERSPECTIVE. Three planes at the same scale are one flat picture with fuzz on
   it, which is why two rounds of blur tuning did not read as depth. A nearer
   plane has to be LARGER and a farther one SMALLER, about a common vanishing
   point, so they nest instead of sitting concentric. transform-box:view-box so
   the origin is a point in the drawing's own 1600x1000 coordinates and not in
   each group's own bounding box, which would put every plane on a different
   centre and shear the stack apart.

   PARALLAX is the other half, and it is the strongest depth cue a scrolling page
   has: --par is set per group from ai.js against scroll progress, and the near
   plane travels about seven times as far as the far one. This is not the idle
   drift the rest of this block forbids; it moves only when the reader moves,
   like everything else here, and prefers-reduced-motion pins it to zero.

   The SELECTOR on this block had gone missing, eaten by the same slice that took
   a comment's closing token on 19 Sep 2026, so the browser read two orphaned
   declarations, threw the whole thing away as a parse error and fell back to
   each group's own centre. The planes were scaling about three different points
   and shearing apart, which is the one thing this rule exists to prevent. Found
   by counting braces, not by looking: a stylesheet that still parses is not the
   same as a stylesheet that is right. */
.boom-net-d,.boom-net-e,.boom-net-n,.boom-net-c{
  transform-box:view-box;transform-origin:860px 470px;
}
.boom-net-d{filter:blur(1.5px);transform:translateY(var(--par,0px)) scale(.86)}
/* The route shares the focal plane's parallax exactly, or it would drift out of
   register with the mesh it is a path THROUGH as the page scrolls. */
/* The ONLY circles on the page with no edge at all are these twenty-six, and at
   5px of blur they still read as dots, which is exactly the "noder i loese lufta"
   Martin circled and sent back. Bigger and far softer: a large smudge with no
   edge is depth, a small soft dot is a node someone forgot to connect. */
.boom-net-c{filter:blur(9px);transform:translateY(var(--par,0px)) scale(1.3)}
.boom-net-c line{
  stroke:var(--ink);stroke-opacity:0;stroke-width:2.2;vector-effect:non-scaling-stroke;
  transition:stroke-opacity .8s ease;
}
.boom-net-c line.is-on{stroke-opacity:calc(.05 + .04 * var(--pulse,0))}
.boom-net-c line.is-off{stroke-opacity:0}
.boom-net-c line.is-on.is-set{transition:none}
.boom-net-c circle{fill:var(--ink);fill-opacity:0}
.boom-net-c circle.is-on{animation:net-near .9s ease forwards}
.boom-net-c circle.is-off{animation:net-near-out .4s ease both}
@keyframes net-near{from{fill-opacity:0}to{fill-opacity:.07}}
@keyframes net-near-out{from{fill-opacity:.07}to{fill-opacity:0}}
.boom-net-d line{
  stroke:var(--ink);stroke-opacity:0;stroke-width:1.4;vector-effect:non-scaling-stroke;
  transition:stroke-opacity .8s ease;
}
/* The far plane's dots sit at .10 and its edges sat at .04, a ratio of 2.5, so
   fifteen of them read as unconnected on the landing screen. Raised to match. */
.boom-net-d line.is-on{stroke-opacity:calc(.065 + .04 * var(--pulse,0))}
.boom-net-d line.is-off{stroke-opacity:0}
.boom-net-d circle{fill:var(--ink);fill-opacity:0}
.boom-net-d circle.is-on{animation:net-back-n .9s ease forwards}
.boom-net-d circle.is-off{animation:net-back-n-out .4s ease both}
@keyframes net-back-n{from{fill-opacity:0}to{fill-opacity:.10}}
@keyframes net-back-n-out{from{fill-opacity:.10}to{fill-opacity:0}}

/* Edges. Non-scaling stroke because the viewBox is 1600 wide and slice scales it
   from about .5 on a narrow window to 1.2 on a wide one; the mass should keep
   its line weight while its spacing changes. */
.boom-net-e line{
  stroke:var(--ink);stroke-opacity:0;stroke-width:1;vector-effect:non-scaling-stroke;
  transition:stroke-opacity .7s ease;
}
/* A TRANSITION, not an animation, and the reason is a trap worth keeping: an
   animation that has finished with fill-mode:forwards FREEZES the value it
   computed, so a var() inside its last keyframe stops tracking. The edge weight
   has to follow --pulse for the whole page, so it cannot live in a keyframe. The
   beat can, because it never finishes. */
/* Pushed to PARITY at the bottom, not merely raised. A 1px stroke and a disc of
   about three pixels do not read alike at the same alpha: the disc has nine times
   the area, so an edge that merely matches on paper still leaves the node looking
   unattached. At the foot of the page the edges now land at .176 effective against
   the nodes' .166, and only there; at the top they stay at .17 against .52,
   because that is the ratio Martin approved when he asked for nodes to be the
   picture. Reported three times before the numbers went this far. */
.boom-net-e line.is-on{stroke-opacity:calc((.17 + .38 * var(--pulse,0)) * var(--e,1))}
.boom-net-e line.is-off{stroke-opacity:0}

/* OCCLUSION, and it is the depth cue that was missing entirely. Blur, scale and
   parallax separate the three planes from each other, but inside a plane every
   line ran straight through every dot, and nothing that overlaps nothing reads as
   flat however well the rest is tuned. The node carries a stroke in the PAGE
   colour with paint-order:stroke, so the halo is painted under the fill and the
   edges stop short of the dot instead of crossing it. No extra elements: a second
   circle per node would have been three hundred more shapes for the same picture.

   --z is the node's own depth, written by the builder: nearer nodes come out
   bigger (in the radius) and darker (here). Within a plane everything used to be
   the same weight, which is the flattest a drawing can be. */
.boom-net-n circle{
  /* How fast the heart runs, and how strongly it beats at this node. --live is the
     scroll progress with the node's own distance from the core subtracted, so the
     ring grows outward as the page goes down instead of everything rising at once.
     min/max rather than clamp: clamp wants three values of one type and these are
     bare numbers coming out of custom properties. */
  /* Four beats live inside one cycle, so the period is the SEQUENCE, not the
     interval between beats: those run 2.92s to 4.03s. See @keyframes net-beat. */
  --period:13.9s;
  /* THE RING GROWS IN REACH, not only in strength, and the two are separate
     factors because they are separate ideas. Martin, 19 Sep 2026: "pulseringen,
     skal den oeke i omfang etterhvert som man scroller nedover - symboliserer at
     mer kommer til live?" It should, and the build before this one could not: the
     beat pool was 120 nodes that all sat inside the opening lobe, so the gate
     below could only make the same small disc louder. --near is a real distance
     now, normalised against NET_BEAT_REACH, so a front can move along it.

       --reach   where the wave front has got to. At rest it stands at the lobe's
                 own rim, .19, which is the picture he approved; by the foot of
                 the page it has passed the whole reach. The /.20 is the softness
                 of the front, so it is a wave and not a cut line.
       second    how hard the whole thing beats, which rises with the scroll too.
       third     a wave dissipates as it travels, so the outermost beat gently.
                 It is also what keeps motion off the closing words, which sit on
                 bare page at the far end.

       pulse 0, near 0    -> .53   the heart is going when you land, as before
       pulse 0, near .19  -> 0     and nothing outside the lobe is
       pulse .5, near .5  -> .52   the front has travelled half the reach
       pulse 1, near .9   -> .69   the whole reach alive, softest at the rim     */
  --reach:max(0, min(1, (var(--pulse,0) * .94 + .19 - var(--near,0)) / .20));
  --live:calc(var(--reach) * (.56 + .44 * var(--pulse,0)) * (1 - .34 * var(--near,0)));
  /* --base is the weight this node settles at, so the pulse can breathe around it
     rather than around a constant. Without it a live node inside the opening lobe
     was pulled from .82 down to the .52 the swathe uses, and thirty-four of them
     sat visibly duller than their neighbours on the landing screen. */
  --base:.52;
  fill:var(--ink);fill-opacity:0;transform:scale(0);
  transform-box:fill-box;transform-origin:center;
  /* NO HALO ANY MORE. It was 2.6px of page colour under every dot with
     paint-order:stroke, so an edge stopped short of the node instead of running
     through it, and that occlusion is the strongest depth cue a flat drawing
     has. The edges are TRIMMED to the rim now, which does the same job properly
     and at the source, so the ring was paying for itself twice. And it was
     expensive: the stroke does not scale, so at an 800px window a median dot is
     1.9px and the ring took 1.3 of it, 68 %. Martin, 20 Sep 2026: "trenger vi aa
     ha en slags hvit ring rundt nodene? hva er hensikten her?" With the trimming
     in place, no. Put back by restoring these two lines if a line is ever seen
     touching a dot it does not belong to. */
}
.boom-net-n circle.is-on{animation:net-node .8s cubic-bezier(.34,1.3,.5,1) .06s forwards}
.boom-net-n circle.is-off{animation:net-node-out .4s ease both}
@keyframes net-node{
  0%{fill-opacity:0;transform:scale(0)}
  34%{fill-opacity:calc(.6 * var(--z,1));transform:scale(1.26)}
  100%{fill-opacity:calc(.52 * var(--z,1));transform:scale(1)}
}
@keyframes net-node-out{
  from{fill-opacity:calc(.52 * var(--z,1));transform:scale(1)}
  to{fill-opacity:0;transform:scale(0)}
}

/* A PULSE deep inside the mass, 18 Sep 2026: "det kan gjerne oppleves som litt
   levende. at det er en slags puls eller aktivitet som skjer dypt inni, som
   kommer mer til live naar man scroller nedover." This is the one exception to the
   rule that nothing in this layer drifts, and it is bounded so it stays one: it
   rides on the nodes within NET_BEAT_REACH of the core's own centroid and no
   further, which keeps it off the closing words at the far end of the swathe, and
   prefers-reduced-motion switches it off outright.

   Three sentences here used to describe the FIRST build of this beat and were
   wrong for a day, which is worth a line of its own. It does NOT ride on the
   junctions with the most connections, it rides on the ones nearest the origin.
   The nodes do NOT each carry their own period: that was the version that failed,
   because independent periods drift apart and a travelling wave becomes flicker.
   And the landing screen is NOT still: Martin asked for something alive inside the
   starting point, and setting the amplitude to zero there was my own misreading of
   an older note of his. A comment that describes a build two versions back is
   worse than no comment.

   It animates fill-opacity, the same property the arrival animation ends on, so
   it is declared SECOND and delayed past the arrival: a later animation wins the
   property while it runs, and starting it immediately would have replaced the
   arrival with a pulse. */
/* PULSEN ER AV, 27 Sep 2026: "fjern pulsen i grafen". Nodene kommer som alle andre og
   staar stille. For aa faa den tilbake: legg
   `net-beat var(--period) linear calc(1s + var(--d,0s)) infinite` til her, og
   `animation:net-beat var(--period) linear var(--d,0s) infinite` i .is-set-regelen under. */
.boom-net-n circle.boom-live.is-on{
  animation:net-node .8s cubic-bezier(.34,1.3,.5,1) .06s forwards;
}
/* A BEAT, not a breath. It rises fast, falls back, and then holds still for most
   of the cycle, which is what separates a heartbeat from a node fading in and out.
   The builder gives each node a delay proportional to its distance from the core's
   centroid, so one cycle is a ring expanding outward rather than sixty-four points
   flickering; and --near, that distance normalised, gates how far the ring reaches.

   --live is the amplitude for THIS node: the scroll progress minus how far out it
   sits, so the core is already beating when you land and the ring reaches the rim
   only once the reader is well down. That is the growth he asked for, "blir
   stoerre og faar mer liv", rather than the whole thing simply getting louder.

   IT BEATS IN SIZE AS WELL AS IN WEIGHT, and that is what made it visible at all.
   Opacity alone was measurable and invisible: the layer dims to .32 by the bottom
   of the page, so a .36 swing on a three-pixel dot arrived as about a tenth of a
   step of grey. Martin: "jeg ser ingen puls eller slag." Scale is not touched by
   the layer's opacity, so a node swelling 62 % reads at any presence.

   Multiplied, not added: an additive swing is the same size whatever the node
   settles at, so the lobe at .82 clipped against full black while the swathe at
   .52 barely moved. A factor cannot overshoot. */
/* NO TWO BEATS ARE THE SAME, 19 Sep 2026. Martin: "burde selve start pulseringen
   variere for hver gang den pulserer, ikke foelge et fast moenster?" It should,
   and it did not: one beat on a 3.1s loop is a metronome, and three cycles is all
   an eye needs to lock onto a loop and stop reading it as something living.

   What CANNOT do it, and why, because both were tried before: a CSS animation
   repeats identically by definition, so per-cycle randomness is not available
   without driving 210 nodes from JavaScript every frame; and giving each node its
   own period, which is the obvious fix, is the FIRST build of this beat and it
   failed, because the phases drift apart within a minute and a travelling wave
   degrades into flicker. The origin and the order are the whole thing.

   So the cycle is longer and holds FOUR beats of different strength at uneven
   spacing: 1.00, .58, .86 and .42, at 3.34s, 2.92s, 4.03s and 3.61s apart. Every
   node still runs the same sequence with the same distance delay, so the ring
   surges together and travels outward exactly as before; what changes is that a
   surge is now hard, soft, middling, faint, and the gaps between them are not
   equal either. Unequal SPACING matters as much as unequal strength: four beats
   on the quarter would still read as a metronome with the volume moving.

   The timings inside each beat are the ones already approved, converted to the
   new period rather than re-tuned: the rise is 0.217s, the dip lands at 0.806s
   and it is back at rest by 1.705s. And the sequence is not the only variation
   in play, because --live is a function of scroll position, so while the reader
   is moving no two beats have the same amplitude anyway. The fixed pattern only
   exists for someone who stops and watches the same spot for fourteen seconds. */
@keyframes net-beat{
  0%,12.27%,24%,36.27%,45%,57.27%,74%,86.27%,100%{
    fill-opacity:calc(var(--z,1) * var(--base,.52));
    transform:scale(1);
  }
  /* 1: full */
  1.56%{
    fill-opacity:calc(var(--z,1) * var(--base,.52) * (1 + .5 * var(--live)));
    transform:scale(calc(1 + .8 * var(--live)));
  }
  5.8%{
    fill-opacity:calc(var(--z,1) * var(--base,.52) * (1 - .3 * var(--live)));
    transform:scale(calc(1 - .12 * var(--live)));
  }
  /* 2: soft */
  25.56%{
    fill-opacity:calc(var(--z,1) * var(--base,.52) * (1 + .29 * var(--live)));
    transform:scale(calc(1 + .464 * var(--live)));
  }
  29.8%{
    fill-opacity:calc(var(--z,1) * var(--base,.52) * (1 - .174 * var(--live)));
    transform:scale(calc(1 - .07 * var(--live)));
  }
  /* 3: middling */
  46.56%{
    fill-opacity:calc(var(--z,1) * var(--base,.52) * (1 + .43 * var(--live)));
    transform:scale(calc(1 + .688 * var(--live)));
  }
  50.8%{
    fill-opacity:calc(var(--z,1) * var(--base,.52) * (1 - .258 * var(--live)));
    transform:scale(calc(1 - .103 * var(--live)));
  }
  /* 4: faint */
  75.56%{
    fill-opacity:calc(var(--z,1) * var(--base,.52) * (1 + .21 * var(--live)));
    transform:scale(calc(1 + .336 * var(--live)));
  }
  79.8%{
    fill-opacity:calc(var(--z,1) * var(--base,.52) * (1 - .126 * var(--live)));
    transform:scale(calc(1 - .05 * var(--live)));
  }
}

/* The opening sphere carries a step more weight than the mass behind it: it is
   the whole of what a visitor sees on arrival and has to read on its own.
   Overriding animation-name alone keeps the timing from the rule above. No
   is-off variant on purpose: threshold 0 can never be above the current
   progress, so the sphere never retracts, and the rule would be dead CSS.

   The .is-set pairing matters more than it looks: the sphere is PLACED rather
   than animated on the first paint, so without its own placed weight it would
   land at the mass's own and the point would be lost on exactly the screen it
   was made for. */
/* The lobe's nodes sit at .82 and its edges sat at .24, so forty-two nodes in
   the core had a strongest neighbour more than twice fainter than themselves and
   read as unconnected. Matched to the weight they actually carry. */
/* The ball's edges are boom-seed too, and this rule outranks the one above, so
   --e has to be here or the depth ramp never reaches them: they sat at a flat
   .42 while the canvas ran .05 to .35 by depth, and the ball read round on one
   side of the handover and flat on the other. */
.boom-net-e line.boom-seed.is-on{stroke-opacity:calc((.34 + .38 * var(--pulse,0)) * var(--e,1))}
/* THE LANDING SCREEN IS NOT PAINTED BLACK. --base .82 over white composites
   to rgb(50,50,56), which is near enough to ink, and since everything that
   arrives at scroll 0 carries this class it was the colour of the whole first
   screen. Martin, 20 Sep 2026: "er fargen litt for svart?" It was. .62 makes
   rgb(100,100,105), a clear step above the .52 the rest of the mass settles
   at, so the opening cluster still reads first without being ink. */
/* THE HERO'S OWN AIR. ai.js marks whatever falls inside the headline's glyphs,
   the chips and the chat control while the reader is still at the top, and takes
   the mark off once the hero has scrolled away. It is opacity and not display,
   so nothing reflows and the drawing closes behind the words rather than popping
   into place. Element opacity multiplies with the fill-opacity the arrival
   animation ends on, so the two do not fight. */
/* NO BLUE BOX INSIDE THE FIELD. The site-wide `input:focus-visible` rule paints a
   2px outline at a 2px offset plus a 4px halo, and on a pill that holds a bare
   input those land as a hard rectangle INSIDE the round shape, corners and all.
   Martin, 21 Sep 2026: "denne blaa firkanten ... ser helt forferdelig ut - fjern
   den med en gang." The focus does not disappear, it MOVES to the pill, which is
   what a reader thinks of as the control: the same border-and-halo the header's
   own ask bar already uses. Keyboard focus is as visible as it was and follows
   the shape it belongs to. */
.boom .ai-box input:focus-visible{outline:none;box-shadow:none}
.boom .ai-box:focus-within{border-color:var(--action);box-shadow:0 0 0 3px var(--focus-halo)}
.boom-net .boom-shy{opacity:0;transition:opacity .34s ease}
.boom-net-quiet .boom-shy{transition:none}
.boom-net-n circle.boom-seed{--base:.50}
.boom-net-n circle.boom-seed.is-on{animation-name:net-node-seed}
.boom-net-n circle.boom-seed.is-on.is-set{fill-opacity:.50;transform:scale(1.06)}
@keyframes net-node-seed{
  0%{fill-opacity:0;transform:scale(0)}
  34%{fill-opacity:.56;transform:scale(1.3)}
  100%{fill-opacity:.50;transform:scale(1.06)}
}


/* Reloading halfway down, or jumping to an anchor, must not set off a hundred
   arrivals at once, so whatever the front has already passed is placed at its
   settled weight. The script marks that batch. */
.boom-net-e line.is-on.is-set{transition:none}
.boom-net-n circle.is-on.is-set{animation:none;fill-opacity:calc(.52 * var(--z,1));transform:scale(1)}
/* A placed node still pulses. .is-set exists to skip the ARRIVAL, not the life:
   most of the live junctions sit in the dense core, which is placed rather than
   animated on the first paint, so without this the pulse would be switched off
   exactly where it was meant to be. One class heavier than the rule above. */
.boom-net-n circle.boom-live.is-on.is-set{
  animation:none;fill-opacity:calc(.52 * var(--z,1));
  transform:scale(1);
}
.boom-net-d line.is-on.is-set{transition:none}
.boom-net-c circle.is-on.is-set{animation:none;fill-opacity:.07}
.boom-net-d circle.is-on.is-set{animation:none;fill-opacity:.10}

/* The route's rules sit LAST in this section on purpose. They are 0,4,1, and so
   are the placed-batch rule and the beat's own rule above; at equal specificity
   the cascade falls back to file order, and six waypoints were still beating
   because those rules came after. Order is the tie-breaker, so the thing that
   must win goes last. */
/* THE ROUTE IS A MARK ON THE MESH, not a line drawn over it. Martin, 18 Sep 2026:
   "kan ikke ruten foelge en allerede etablert node og strek? saa kan den bli bold
   eller merket paa en maate?" It was an overlay until then, a second line at the
   same coordinates in its own group, and that is exactly why it read as a path
   laid ACROSS the mesh rather than one chosen through it. Now the edges the route
   uses are the same elements the mass is made of; they simply go bold.

   The route's edges sit in .boom-net-e, which is under the node group, so the
   dots it passes through sit ON the line. That is the right way round: the route
   runs through the nodes, it does not cross them.

   It is a real shortest path, Dijkstra over the graph that is actually drawn,
   computed in tools/ai/boom.py: 25 hops from the top right to the bottom left,
   6 % longer than the straight line no one can walk. ai.js carries a second
   pointer over data-r so it lights late and unlights on the way back up. */
/* Turned up a step, 18 Sep 2026: "naa kan du lage den litt mer synlig." The
   ceiling is fixed and worth writing down: the route lives inside a layer that
   sits at .32 by the foot of the page, so no matter what it is given here it can
   never exceed .32 effective. Opacity now reaches exactly 1 at the bottom, which
   is that ceiling, and the rest of the visibility has to come from somewhere
   opacity cannot be taken from. Width does it: 2.8 against the mesh's 1 is nearly
   three times the ink per unit length. The nodes it passes through grow with it,
   so the waypoints read as waypoints. */
/* Written heavy on purpose, and the three things it has to outrank are the whole
   reason. `.boom-seed.is-on` is 0,3,1 and paints the lobe's edges at .42+; the
   placed-batch rule `.is-on.is-set` is 0,3,1 and pins the node transform to
   scale(1); and the beat is an ANIMATION, which beats any static declaration
   whatever its selector, so the waypoints have to switch it off rather than try
   to outweigh it. A route node is a decision, not a heartbeat. At 0,4,1 this wins
   the first two on specificity rather than on file order, which is the lesson
   from every other specificity trap in this file. */
.boom .boom-net-e line.is-on.is-route{
  stroke-opacity:calc(.72 + .28 * var(--pulse,0));stroke-width:2.8;
  transition:stroke-opacity .45s ease,stroke-width .45s ease;
}
.boom .boom-net-n circle.is-on.is-route{
  animation:none;
  fill-opacity:calc(.82 + .18 * var(--pulse,0));
  transform:scale(1.35);
  transition:fill-opacity .45s ease .1s,transform .45s cubic-bezier(.34,1.3,.5,1) .1s;
}

@media (prefers-reduced-motion:reduce){
  .boom-net-d,.boom-net-e,.boom-net-n,.boom-net-c{--par:0px}
  .boom-net-n circle.boom-live.is-on,.boom-net-n circle.boom-live.is-on.is-set{
    animation:none;fill-opacity:calc(var(--base,.52) * var(--z,1));transform:scale(1);
  }
  .boom-net-e line.is-on{transition:none}
  .boom-net-n circle.is-on{animation:none;fill-opacity:calc(.52 * var(--z,1));transform:scale(1)}
  .boom-net-n circle.boom-seed.is-on{fill-opacity:.50;transform:scale(1.06)}
  .boom-net-d line.is-on{transition:none}
  .boom-net-d circle.is-on{animation:none;fill-opacity:.10}
  .boom-net-c circle.is-on{animation:none;fill-opacity:.07}
  /* A retreat under reduced motion is not a fade, it is simply gone. This list
     had a trailing comma and no declaration block at all, left behind by the
     same slice that took the vanishing-point selector above, so the whole rule
     was discarded and these elements kept animating out. */
  .boom-net-e line.is-off,.boom-net-n circle.is-off,
  .boom-net-d line.is-off,.boom-net-d circle.is-off,
  .boom-net-c circle.is-off{
    animation:none;transition:none;fill-opacity:0;stroke-opacity:0;
  }
}

/* ===========================================================================
   THE INTRO GATE, 19 Sep 2026. Martin: "kan vi ha en salgs gate som alle maa
   trykke seg inn paa foer de kommer til forsiden? ... en animasjon hvor det
   foeles og ser ut som at man flyr inn i kjernen paa nodenettverket ... saa
   lander man paa forsiden og animasjonen slutter med at nodenettverket fester
   seg opp til hoeyre." Reference: ascension.pegassi.be.

   IT DRAWS NOTHING OF ITS OWN. The camera is a transform on the page's own
   network layer, so the thing you fly into and the thing that settles top right
   are the same elements; nothing has to be lined up at the end because nothing
   was ever copied. The veil hides the page by VISIBILITY, not opacity, so the
   content behind it leaves the tab order while staying in the DOM for a crawler
   and a screen reader.

   It is the page's own white ground, not a black screen. The reference is black
   and copying that would be borrowing somebody's mark again, which is the whole
   sanity.io lesson; and Martin ruled a black ground off this page in September.
   ======================================================================== */
html.is-gated{overflow:hidden}
html.is-gated .ai-foot,html.is-gated .ai-menu,html.is-gated .ai-switch{visibility:hidden}
/* main takes BOTH, and the opacity is the one that does the work. visibility is
   inherited, so any descendant that sets its own visibility:visible walks
   straight through it, and the chat's typing hint does exactly that: every
   character is a span that flips visibility with no transition. One letter of
   the placeholder was floating on the gate because of it. An opacity group
   cannot be overridden from inside, so the two together are hidden AND out of
   the tab order. */
html.is-gated main{visibility:hidden;opacity:0}
html.is-flying{overflow:hidden}
/* THE WORDMARK IS THE GATE'S OWN, CENTRED, AND THE HEADER IS GONE. Martin, 19
   Sep 2026: "sensa logo eller en overskrift burde vel vaere over eller under
   eller et sted som gir sikkerhet paa at man er paa riktig sted?" The header's
   logo WAS on screen, tucked in the top left of an otherwise empty bar, and he
   is right that it does not do the job: a mark in the corner of a bar with
   nothing else in it reads as leftover furniture, not as "you are at Sensa".

   So the gate composes itself the way a gate should, top to bottom: who this is,
   the object, what to do. It is the wordmark and NOT the headline, because the
   headline is the first thing on the page one second later and a claim that
   lands twice in three seconds lands weakly; the gate's job is to identify, and
   the page's job is to claim.

   Keeping the header's own logo would have meant it did not MOVE when the page
   arrived. That argument dies against the flash: the handover happens under full
   white at 880 ms, so nothing is seen to move at all.

   The six header rules this replaces were eaten by a line-range slice earlier
   the same day and Martin saw the full navigation sitting on the gate. The rule
   in this file says to LIST what is between two markers before cutting; I
   checked only that the range held what I meant to remove, never what else was
   in it. After any range cut, diff the SELECTOR list, not just the line count. */
html.is-gated .ai-hdr{visibility:hidden}
/* THE WORDMARK IS THE FIRST THING ON THE SCREEN, so it is sized like it.
   Martin, 21 Sep 2026: "sensa logo paa forsiden maa vaere litt stoerre og poppe
   lit mer, gjoer den eksklusiv." Three things, and not one of them is a box or a
   drop shadow in a colour, because both of those are what a template does:

   SIZE. Unchanged. It was taken up 45 % on 21 Sep 2026 and put straight back the
   same day: "sensa logoen ble litt for stor. ta den tilbake til utgangspunktet."
   The other two below are what "poppe mer" turned out to mean, and they cost the
   mark nothing in size.

   SEPARATION. The halo is the page's own colour, so it is invisible against the
   page and only exists where the mesh would otherwise run through the letters.
   It is the same paint-order:stroke trick the nodes and the cursor label use,
   at a larger radius. A coloured shadow would read as cheap; this reads as
   nothing at all, which is the point.

   ARRIVAL. It rises a little and fades in, once, over nine tenths of a second.
   Something that is simply there was placed; something that arrives was made.
   The animation must be switched OFF again on is-flying, or its filled end state
   freezes the computed opacity and the fade-out never runs. That is the
   fill-mode trap this project has hit before, and the one-line answer to it. */
.boom-gate-mark{
  position:absolute;left:50%;top:clamp(40px,9vh,104px);
  width:clamp(104px,11vw,148px);height:auto;
  transform:translateX(-50%);pointer-events:none;
  filter:drop-shadow(0 0 18px var(--paper)) drop-shadow(0 0 44px var(--paper));
  animation:gate-mark .9s cubic-bezier(.2,.86,.28,1) both;
}
@keyframes gate-mark{
  from{opacity:0;transform:translateX(-50%) translateY(16px) scale(.96)}
  to{opacity:1;transform:translateX(-50%) translateY(0) scale(1)}
}
/* THE GATE'S OWN OBJECT is a CANVAS, and that was forced by what it has to do:
   rotate slowly, carry hundreds more nodes, and remember which of them a hand
   has touched. Re-projecting a sphere in SVG is one attribute write per node and
   two per edge every frame, about three thousand of them at sixty frames a
   second; a canvas redraws the whole thing in one pass, is crisp because it
   redraws at devicePixelRatio and at the camera's own scale rather than
   magnifying a bitmap, and gives every node somewhere to keep its own state,
   which is what "holder seg uthevet" needs.

   While the gate is up the page's mass is not the object, so it is not drawn.
   The binary and the pointer ripple went onto the canvas with the sphere, which
   is why three blocks of rules left this file in the same change. */
.boom-gate-orb{position:absolute;inset:0;width:100%;height:100%}
/* THE GATE'S OWN OBJECT is a CANVAS, and that was forced by what it has to do:
   rotate slowly, carry hundreds more nodes, and remember which of them a hand
   has touched. Re-projecting a sphere in SVG is one attribute write per node and
   two per edge every frame, about three thousand of them at sixty frames a
   second; a canvas redraws the whole thing in one pass, is crisp because it
   redraws at devicePixelRatio and at the camera's own scale rather than
   magnifying a bitmap, and gives every node somewhere to keep its own state,
   which is what "holder seg uthevet" needs.

   While the gate is up the page's mass is not the object, so it is not drawn.
   The binary and the pointer ripple went onto the canvas with the sphere, which
   is why three blocks of rules left this file in the same change. */
.boom-gate-orb{position:absolute;inset:0;width:100%;height:100%}
html.is-gated #boomNet{display:none}

/* ABOVE EVERYTHING, including the header at 70. It was at 40, so from the cut
   onward the header punched straight through the white and appeared a moment
   before the iris reached it, which is exactly the seam the iris exists to
   remove. An overlay that covers the page has to cover all of it. */
.boom-gate{position:fixed;inset:0;z-index:90}

/* THE CAMERA IS THE SVG'S OWN viewBox, not a CSS transform on the layer, and
   that is the answer to "det maa vaere hoey opploesning og crisp". A transform
   scales what the browser has already drawn, so a deep push is a magnification
   of a raster and it softens exactly when the viewer is closest to it. Moving
   the viewBox re-renders the vectors every frame at the window's own resolution:
   the dots stay round and the hairlines stay hairlines however deep it goes.
   ai.js writes four numbers per frame, which is cheaper than the style recalc
   the transform was causing anyway.

   It removed two bugs rather than fixing them. There is no clipping problem any
   more, because the viewBox IS the window and it is cut to the viewport's own
   aspect, so nothing is cropped on a narrow screen and the layer's own overflow
   never enters into it.

   The transform survives for the LANDING alone, where the move is six per cent
   and a raster scale is invisible. */
/* THE PAGE COMES OUT OF THE NODE. The iris alone is a hole in paper: what shows
   through it does not move, so it reads as a cut-out rather than as arriving.
   The content scales down to rest about the SAME point the hole opens from, so
   the two are one movement. This is not the settle that was removed a round ago
   and then argued back: that one scaled about the middle of the screen, which is
   a second movement in a different place. Origin is set per element, because
   transform-origin is relative to each box and main does not start where the
   viewport does. The overlay is NOT in here, or the hole would travel with it.

   Scroll stays locked for the 760 ms this takes, or a scaled page would put a
   bar on the side of the window for the length of it. */
html.is-opening{overflow:hidden}
html.is-opening #boomNet{
  transform-origin:var(--ex,50%) var(--ey,50%);
  transform:scale(var(--os,1));
}
html.is-opening main{
  transform-origin:var(--mx,50%) var(--my,50%);
  transform:scale(var(--os,1));
}
/* The retreat itself. Set at nine, committed, then transitioned to one: the
   class is added on the frame after so the browser has a value to move FROM.
   Ease-out, because a camera that is pulling back settles rather than stops. */
html.is-pulling #boomNet,html.is-pulling main{
  transition:transform 1.15s cubic-bezier(.17,.74,.26,1);
}

/* THE PULSE IS IN THE NODES. THE OBJECT ITSELF DOES NOT MOVE. The first build
   scaled the whole svg on the beat, a third of a per cent at a time, and Martin
   named it exactly: "klumpen som hopper er helt forferdelig. den maa pulsere i
   nodene. dette foeles og ser ut som venstrehaandsarbeid." He is right twice
   over. A blob that bounces is the cheapest effect there is; and the drawing
   ALREADY has a heartbeat that travels outward through its nodes, so the scale
   was a second rhythm competing with a better one that was running underneath
   it the whole time. His reference does the same thing: the object on that page
   is still, and all the life is inside it.

   What the gate changes is only the REACH of the beat that already exists. On
   the page the ring is meant to stay deep inside the mass, so at scroll 0 it
   covers --near .19 and the lobe runs to .317; on the gate that lobe IS the
   whole picture, blown up four times, and a cluster whose outer third is dead
   looks broken rather than restrained. Here it carries the full lobe, at full
   amplitude in the middle and dying out at the rim, with the same per-node delay
   as ever, so one cycle is a ring crossing the cluster in about half a second.
   121 of its 180 nodes take part. */
/* The flash covers the one cut in the whole sequence: at its peak the camera
   stops pushing in and is placed at the page's own position to settle out of.
   Without it you would see the direction reverse, which is the tell that turns
   a flight into a zoom that changed its mind. */
/* The canvas is simply hidden once the tunnel has run out. Nothing fades it and
   nothing opens a hole in it: the page is already drawing back from the node
   underneath while the wall thins, so by the time it goes there is nothing on
   it left to see. */

/* "Utforsk" follows the pointer, 19 Sep 2026: "jeg oensker ogsaa at musepekeren
   skal ha en Utforsk eller noe som foelger etter naar man drar musepekeren over
   node-nettverket." It appears only over the cluster, so it says that THIS
   object is the thing to touch rather than acting as a custom cursor for the
   whole screen, and the real cursor is left alone: hiding it on something that
   is also a button is a good way to lose people. translate3d so the follow is
   composited and never touches layout. */
.boom-gate-tip{
  position:fixed;left:0;top:0;z-index:2;pointer-events:none;white-space:nowrap;
  margin:0;font:500 13px/1 var(--sans);color:var(--ink-2);letter-spacing:.06em;
  /* It now sits ON the sphere rather than beside the cursor, so it needs the
     same trick the nodes use: a halo in the page colour so a hairline mesh does
     not run through the word. text-shadow is paint-order:stroke by another
     name. The offset margin is gone because ai.js places it on its orbit. */
  text-shadow:0 0 7px var(--paper),0 0 4px var(--paper),0 0 2px var(--paper);
  /* No transition on the position. It is placed every frame by ai.js, and a
     transition on top of that is a second lag fighting the first. */
  transform:translate3d(var(--px,-300px),var(--py,-300px),0);
  opacity:0;transition:opacity .3s ease;
}
html.is-near-net .boom-gate-tip{opacity:1}
html.is-flying .boom-gate-tip{opacity:0;transition-duration:.14s}
/* NODEN ER PEKEREN, MED FIRE REGLER SOM GJELDER OVERALT, 24 Sep 2026. Den startet som
   "Utforsk" over produktkortene og ble pekeren paa hele siden ("kan vi ha den hele
   tiden?"). Saa: "ringen gjoer noe tekst mer utydelig for leseren - og hvorfor har vi
   forskjellige moenstre ... vi burde ha regler som gjaldt for alle tilfeller. lesbarhet og
   innovasjon er viktig. man skal ogsaa forstaa at musepeker-noden har kommet over noe som
   kan trykkes paa." Den frostede platen ble lagt over teksten og gjorde den uskarp, og tre
   former (prikk, ring, plate med ord) var tre regler. Naa er det fire, og ingen unntak:
   1. Prikken er alltid pekeren.
   2. Ingenting ligger over teksten. Rammen av Sensa-merkets to halvdeler rundt det som kan
      trykkes paa er fjernet, 28 Sep 2026: "fjern alle valg-klammer som er fra sensa logoen.
      de skal vekk." Det som kan trykkes paa, sier det selv med sin egen hover.
   3. Ordet vises bare der elementet ikke selv sier hva som skjer, altsaa paa kort der hele
      kortet er lenken ("Utforsk", "Les" paa omtalekortene som gaar ut). Det svinger rundt
      prikken, aldri oppaa, med en glorie i sidens farge, slik introens "Utforsk".
   4. I tekstfelt kommer skrivemarkoeren tilbake.
   Prikken er hvit i differanseblanding, saa de er moerke paa lys bunn og lyse paa
   en svart knapp eller en video. Systempekeren er skjult med !important, bevisst: hele
   poenget er aa overstyre cursor-regler av ulik tyngde. Bare med mus (ai.js). */
.boom.has-tip,.boom.has-tip *{cursor:none !important}
.boom.has-tip input,.boom.has-tip textarea,.boom.has-tip [contenteditable="true"]{cursor:text !important}
.boom .boom-tip-w{
  position:fixed;left:0;top:0;z-index:200;pointer-events:none;white-space:nowrap;margin:0;
  font:500 13px/1 var(--sans);color:var(--ink);letter-spacing:.06em;
  text-shadow:0 0 7px var(--paper),0 0 4px var(--paper),0 0 2px var(--paper);
  /* Ordet svinger rundt ringen, 24 Sep 2026: "den skal kunne rotere 360 rundt hele sirkelen -
     ordet henger litt igjen - helt likt som paa intro-siden." ai.js plasserer midten av ordet
     paa en bane rundt ringen (--wx, --wy); ingen overgang paa posisjonen. */
  transform:translate3d(var(--wx,-300px),var(--wy,-300px),0) translate(-50%,-50%);
  opacity:0;transition:opacity .18s ease;
}
.boom .boom-tip-w.is-on{opacity:1}
/* Prikken er pekeren, 10px, alltid. */
.boom .boom-dot{
  position:fixed;left:0;top:0;z-index:201;pointer-events:none;
  width:10px;height:10px;margin:-5px 0 0 -5px;border-radius:50%;
  background:var(--on-media);mix-blend-mode:difference;
  transform:translate3d(var(--px,-300px),var(--py,-300px),0);opacity:0;transition:opacity .15s ease;
}
.boom .boom-dot.is-on{opacity:1}

.boom-gate-go{
  position:absolute;inset:0;width:100%;height:100%;
  display:flex;align-items:flex-end;justify-content:center;
  padding:0 24px 11vh;background:none;border:0;cursor:pointer;
  font:500 15px/1.5 var(--sans);color:var(--ink-2);letter-spacing:.01em;
  transition:opacity .22s ease;
}
.boom-gate-go span{position:relative;padding-bottom:6px}
.boom-gate-go span::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1.5px;background:currentColor;
  transform:scaleX(0);transform-origin:left;transition:transform .34s cubic-bezier(.16,.84,.3,1);
}
/* THE UNDERLINE BELONGS TO THE GLOBE, NOT TO THE SCREEN. Martin, 21 Sep 2026:
   "jeg vil at skriften under globen skal faa en strek under seg naar musepekeren
   hover over globen. saa gaar streken vekk naar musepeker er utenfor globen."
   It was :hover, and this button is position:absolute with inset:0, so it covers
   the whole viewport and the rule was true wherever the pointer sat: the line was
   always drawn and said nothing. `is-near-net` is the state the "Utforsk" label
   already runs on, the pointer inside the sphere's own reach, so the two now say
   the same thing at the same moment.

   AND THE UNDERLINE CAME OFF :focus-visible, which is the part that is easy to
   get wrong. The button takes focus on arrival so Enter enters, and the browser
   treats that programmatic focus as keyboard-ish, so the rule matched from the
   first frame and the line was drawn before the pointer had gone anywhere near
   the globe. The keyboard has not lost anything: the focus OUTLINE below is the
   indicator, which is what a focus indicator is for. The underline now means one
   thing only, and a signal that is always on means nothing. */
html.is-near-net .boom-gate-go span::after{transform:scaleX(1)}
.boom-gate-go:focus-visible{outline:2px solid var(--focus);outline-offset:-6px}
html.is-flying .boom-gate-go{opacity:0;pointer-events:none}
/* The wordmark goes with the button. It identifies the gate; once the camera is
   inside the graph there is no gate left to identify, and a logo floating over
   the tunnel is the one thing in the sequence that is not part of the scene. */
.boom-gate-mark{transition:opacity .24s ease}
html.is-flying .boom-gate-mark{animation:none;opacity:0}

/* Never gate a reader who asked for less motion. ai.js removes the element
   outright so this is a second lock, not the mechanism. */
@media (prefers-reduced-motion:reduce){
  .boom-gate{display:none}
  html.is-gated main,html.is-gated .ai-hdr,
  html.is-gated .ai-foot,html.is-gated .ai-menu{visibility:visible}
  html.is-gated{overflow:auto}
}

/* KINO, INTROEN PAA / OG /en (1 Okt 2026). Martin 30 Sep og 1 Okt: kino blir introen, én gang per
   besoek og bak «Se introen» i bunnen. Filmen er tools/lab/intro-skisser/kino.html flyttet inn i
   siden, uten iframe og uten ny sidelasting: den spiller i et dekkende lag over porten, og naar kula
   i filmen ligger oppaa portens kule, toner laget ut paa 0,28 s og porten dykker inn gjennom logoens
   merke. Fargene er sidens tokens; de fem systemene er --kino-0..4. Alt er avgrenset til #kino, saa
   ingen regel her naar siden. Under redusert bevegelse finnes laget ikke (det tas bort foer det vises). */
html:not(.is-kino) #kino{display:none}
/* merket er et .merke-host-span fra det levende merket, og html.boom .merke-host.boom-gate-mark gir det
   display:block, saa regelen maa vaere sterkere; ellers sto den gamle logoen i de 0,28 s mellom filmen
   og dykket (1 Okt 2026, Martin: «gammel logo kommer til syne over kontekstgrafen, det maa vekk») */
html.is-kino .boom-gate-mark,html.boom.is-kino .merke-host.boom-gate-mark,html.is-kino .boom-gate-tip{display:none}
html.is-kino .boom-gate-go{opacity:0}
#kino{position:fixed;inset:0;z-index:95;background:var(--fluid-paper);color:var(--ink);font-family:var(--sans);
  -webkit-font-smoothing:antialiased;overflow:hidden}
/* overleveringen er et kutt: porten under er det samme bildet, saa laget gaar bort i én ramme (hand() i ai.js) */
#kino.k-ut{visibility:hidden;pointer-events:none}
#kino canvas{position:absolute;inset:0;width:100%;height:100%;display:block;transition:opacity .28s}
#kino .k-fl{z-index:0}
#kino .k-cv{z-index:1}
#kino .k-logo{position:absolute;z-index:4;left:50%;top:calc(45vh - clamp(44px,5.4vw,80px)/2);height:clamp(44px,5.4vw,80px);
  transform:translateX(-50%);color:var(--ink);opacity:0;display:block;transition:opacity .9s}
#kino .k-logo svg{height:100%;width:auto;display:block}
#kino .k-logo.k-on{opacity:1}
#kino .k-logo svg>g:first-child path{transform-box:fill-box;transform-origin:center;transition:transform .8s cubic-bezier(.75,0,.25,1.25),opacity .35s}
/* halvdelene flyr inn paa .8 s, ikke 1 s (14 Okt 2026, introen strammet) */
#kino .k-logo svg>g:first-child path:first-child{transform:translate(-260px,-160px) scale(.7);opacity:0}
#kino .k-logo svg>g:first-child path:last-child{transform:translate(260px,160px) scale(.7);opacity:0}
#kino .k-logo.k-on svg>g:first-child path{transform:none;opacity:1}
#kino .k-skip{position:absolute;z-index:4;right:clamp(18px,2.6vw,44px);top:clamp(18px,2.4vw,34px);font-size:15px;color:var(--ink-2);
  text-decoration:none;padding:4px 0;margin:0;background:none;border:0;font:inherit;font-size:15px;cursor:pointer;
  opacity:0;transition:opacity .3s,color .2s}
#kino .k-skip.k-on{opacity:1}
/* Tydeligere «Hopp over» (break-it funn 13, 3 Okt 2026, Martin: introen staar, «Hopp over» blir tydeligere): stoerre,
   i full tekstfarge, med den tynne streken rundt som «Se produktene», og den er der med en gang, uten toning inn.
   Filmen er urort. */
#kino .k-skip{font-size:17px;color:var(--ink);padding:10px 20px;border:1px solid var(--ink-3);border-radius:999px}
#kino .k-skip.k-on{transition:color .2s}
#kino .k-skip:hover{border-color:var(--ink)}
/* «Hopp over» (1 Okt 2026): filmen og porten toner ut paa 0,6 s mens siden toner inn under, saa slipper
   porten (ai.js). Nettverket bak siden staar fast fra foerste bilde, saa ingenting popper inn etterpaa. */
html.k-hopp #kino,html.k-hopp .boom-gate{opacity:0;transition:opacity .6s ease;pointer-events:none}
html.k-hopp.is-gated main,html.k-hopp.is-gated .ai-hdr,html.k-hopp.is-gated .ai-foot{visibility:visible;opacity:1;transition:opacity .6s ease}
html.k-hopp.is-gated #boomNet{display:block}
/* Logoen hjem (2 Okt 2026, Martin: «lik animasjonen til "Hopp over"»): fra en annen side toner siden over
   i forsiden paa de samme 0,6 s. Overgangen meldes paa bare ved klikket (ai.js) og av forsiden som ser
   flagget (template.html), saa ingen andre lenker faar den. Uten overgang mellom sider toner forsiden inn. */
::view-transition-group(root),::view-transition-old(root),::view-transition-new(root){animation-duration:.6s;animation-timing-function:ease}
/* Spraakbyttet i telefonmenyen (8 Okt 2026): bare ordene skifter, saa overgangen er kort */
html.meny-bytt::view-transition-group(root),html.meny-bytt::view-transition-old(root),html.meny-bytt::view-transition-new(root){animation-duration:.25s}
html.hjem-inn body{animation:hjem-inn .6s ease}
@keyframes hjem-inn{from{opacity:0}}
#kino .k-skip:hover{color:var(--ink)}
/* strek under ordene ved hover, som spraakvalget (1 Okt 2026, Martin: «maa ha en strek indikasjon») */
#kino .k-skip span{text-decoration:underline;text-decoration-color:transparent;text-underline-offset:4px;text-decoration-thickness:1px;transition:text-decoration-color .2s}
#kino .k-skip:is(:hover,:focus-visible) span{text-decoration-color:currentColor}
/* Ingen blaa ring og ingen glorie (16 Okt 2026, Martin: «det er fortsatt en slags glorie og blå kant rundt denne»):
   fokus vises som hover, med streken i full tekstfarge og ordene understreket. Den felles regelen i site.css
   tegnet ogsaa `--focus-halo` som skygge, og den tok ikke `k-auto` bort. */
#kino .k-skip:focus-visible{outline:none;box-shadow:none;border-color:var(--ink);opacity:1}
#kino .k-skip.k-auto:focus-visible:not(:hover){border-color:var(--ink-3)}
#kino .k-skip.k-auto:focus-visible:not(:hover) span{text-decoration-color:transparent}
#kino .k-say{position:absolute;z-index:3;left:50%;transform:translateX(-50%);width:min(92vw,1100px);margin:0;text-align:center;
  pointer-events:none;letter-spacing:-.022em;line-height:1.1}
#kino .k-say em,#kino .k-tag em{font-family:"Instrument Serif",serif;font-style:italic;font-weight:400;letter-spacing:-.01em;font-size:1.14em;padding-right:.06em}
#kino .k-say em{line-height:.9}
#kino .k-tag{position:absolute;z-index:4;left:0;top:0;overflow:hidden;padding:.12em .2em .28em 0;margin:-.12em 0 0;pointer-events:none;
  white-space:nowrap;font-weight:500;letter-spacing:-.022em;line-height:1;opacity:0}
#kino .k-tag.k-on{opacity:1}
#kino .k-tag>span{display:inline-block;transform:translateX(-102%)}
#kino .k-tag .k-bl{display:inline-block;width:0;height:0;vertical-align:baseline}
/* boksen er en markeringstusj: tegnes fra venstre over ordene naar det siste ordet har landet.
   Samme laks og samme hoeyde som boksen paa forsiden (1 Okt 2026, Martin: «noen steder overlapper
   merking av tekst boksene hverandre» og «skulle merking ha hatt samme farge som merking paa
   forsiden?»): 86 % av skrifthoeyden og uten luft over og under, saa to bokser paa linjer rett
   under hverandre aldri moetes. Boksen staar nederst i flaten, 12 til 100 %, fordi Archivo sine
   bokstaver gaar fra 14 % (k, ô) til 97 % (y, g); midt i flaten, 6 til 92 %, stakk y og komma ut
   under (1 Okt 2026, Martin: «markering dekker ikke hele skriften, y-en kommer utenfor, ogsaa komma»).
   Saa sto toppen i kanten av k og ô («staar helt i kanten paa topp bokstav»): naa har boksen 0,05 em
   luft under og 95 % av hoeyden. Det gir 0,1 em over k, 0,05 em over ringen i å og 0,08 em under y.
   Den store setningen fikk linjeavstand 1,06 (foer 1,02), saa boksen paa linje to ikke roerer g-en over. */
html.boks #kino .k-bx{white-space:nowrap;border-radius:.06em;padding:0 .16em .05em;margin:0 .02em;
  -webkit-box-decoration-break:clone;box-decoration-break:clone;
  background:linear-gradient(var(--u-merk,var(--boks)),var(--u-merk,var(--boks))) no-repeat 0 100%/0% 95%;
  transition:background-size var(--d,.5s) cubic-bezier(.3,.05,.6,.95),opacity .5s}
/* .k-say.k-on, ikke .k-on: svaret staar i kortet #kino-reply, som faar .k-on foer teksten bygges, saa
   boksen matchet fra foerste bilde og ble aldri tegnet (1 Okt 2026, Martin: «markering i svaret er der
   naar teksten kommer frem»). Sloganet ved logoen staar i .k-tag og trenger sin egen (Martin: «mangler
   markering i starten» og «sensa faar anlegget til aa snakke mangler ogsaa markering») */
html.boks #kino .k-say.k-on .k-bx,html.boks #kino .k-tag.k-on .k-bx{background-size:100% 95%}
html.boks #kino .k-off .k-bx{opacity:0;transition:opacity .5s;transition-delay:0s!important}
html.boks #kino .k-bx .k-w{transition:opacity .45s ease,transform .8s cubic-bezier(.16,1.12,.3,1),filter .6s ease,color .2s ease}
html.boks #kino .k-say.k-on .k-bx .k-w,html.boks #kino .k-tag.k-on .k-bx .k-w{color:var(--u-merk-t,var(--on-boks))}
/* Boksen i introen er Sensas blaa med svart tekst, som pillen (9 Okt 2026, Martin: «ordne kino-intro markering fra
   laks-farge til sensa-blå»). Overskriftene paa sidene beholder laksen. */
html.boks #kino{--u-merk:var(--knapp-1);--u-merk-t:var(--knapp-t)}
/* 1200 px, ikke 1100: den spanske setningen er 1140 px i full stoerrelse og brøt til to linjer over systemnavnene
   (3 Okt 2026, Martin: «her ser du feilen»); norsk og engelsk staar paa én linje som foer */
#kino .k-s1{top:10vh;font-size:clamp(30px,4vw,64px);font-weight:500;width:min(92vw,1200px)}
#kino .k-s1.k-low{top:22vh}
#kino .k-big{top:50%;transform:translate(-50%,-50%);font-size:clamp(42px,6.6vw,108px);font-weight:500;line-height:1.06;--sl:1.4}
#kino .k-w{display:inline-block;opacity:0;transform:translateY(.06em) scale(var(--sl,1.22));filter:blur(10px);white-space:pre;
  transition:opacity .45s ease,transform .8s cubic-bezier(.16,1.12,.3,1),filter .6s ease}
#kino .k-on .k-w{opacity:1;transform:none;filter:blur(0)}
#kino .k-off .k-w{opacity:0;transform:scale(.9) translateY(-.2em);filter:blur(10px);transition:opacity .5s,transform .6s,filter .5s;transition-delay:0s!important}
/* Slutten foer tunnelen (1 Okt 2026, Martin): halvdelene gaar fra hverandre mens merket snurrer og krymper til
   ingenting rundt sin egen midte (15,5 % av logoens bredde). «Sensa» er alt rullet inn. */
#kino .k-logo.k-snurr svg{overflow:visible;transform-origin:15.5% 50%;transform:rotate(540deg) scale(0);transition:transform .9s cubic-bezier(.55,0,.8,.3)}
#kino .k-logo.k-snurr svg>g:first-child path{transition:transform .5s cubic-bezier(.3,0,.3,1)}
#kino .k-logo.k-snurr svg>g:first-child path:first-child{transform:translate(-90px,-90px)}
#kino .k-logo.k-snurr svg>g:first-child path:last-child{transform:translate(90px,90px)}
#kino .k-chat{position:absolute;z-index:3;left:50%;top:10vh;transform:translateX(-50%);width:min(90vw,760px)}
#kino .k-ask{border-radius:999px;display:flex;align-items:center;gap:14px;padding:12px 12px 12px 28px;background:var(--surface);
  border:1px solid var(--rule);opacity:0;transform:translateY(-14px) scale(.97);transition:opacity .7s,transform 1s cubic-bezier(.16,.84,.24,1)}
#kino .k-ask.k-on{opacity:1;transform:none}
/* linja under sloganet (fra Mortens intro, 14 Okt 2026) */
#kino .k-say.k-sub{top:calc(45vh + clamp(44px,5.4vw,80px)/2 + clamp(22px,2.6vw,40px));font-size:clamp(20px,2vw,30px);font-weight:400}
/* linja glir ut fra sin egen venstre kant som sloganet glir ut fra merket, med samme tid og kurve (eio, 1,15 s) */
#kino .k-sm{display:inline-block;overflow:hidden;vertical-align:top;padding:.1em .25em .25em 0;margin:-.1em -.25em -.25em 0}
#kino .k-sm>span{display:inline-block;transform:translateX(-102%);transition:transform 1.15s cubic-bezier(.65,0,.35,1)}
#kino .k-sm>span.k-on{transform:none}
#kino .k-q{flex:1;padding:11px 0;font:400 clamp(18px,1.9vw,22px)/1.4 var(--sans);color:var(--ink)}
#kino .k-q:empty::before{content:attr(data-tom);color:var(--ink-3)}
#kino .k-c{display:inline-block;width:2px;height:1.15em;vertical-align:-.2em;background:var(--ink);margin-left:1px;animation:kino-blink 1s steps(1) infinite}
@keyframes kino-blink{50%{opacity:0}}
#kino .k-go{flex:none;width:48px;height:48px;border-radius:50%;display:grid;place-items:center;background:var(--accent);transition:transform .25s}
#kino .k-go svg{width:18px;height:18px;stroke:var(--on-accent);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
#kino .k-go.k-hit{transform:scale(.88)}
#kino .k-reply{margin-top:12px;padding:24px 28px 20px;background:var(--surface);border:1px solid var(--rule);border-radius:28px;
  opacity:0;transform:translateY(-8px);transition:opacity .6s,transform .8s cubic-bezier(.16,.84,.24,1);--sl:1.1}
#kino .k-reply.k-on{opacity:1;transform:none}
#kino .k-reply .k-say{position:static;transform:none;width:auto;text-align:left;text-wrap:pretty;font-size:clamp(20px,1.85vw,28px);
  font-weight:400;line-height:1.3;letter-spacing:-.01em}
#kino .k-src{margin-top:18px;padding-top:14px;border-top:1px solid var(--rule);font-size:15px;line-height:1.5;color:var(--ink-2);
  display:flex;flex-wrap:wrap;gap:4px 24px;opacity:0;transform:translateY(6px);transition:opacity .8s,transform .9s cubic-bezier(.16,.84,.24,1)}
#kino .k-src.k-on{opacity:1;transform:none}
#kino .k-src .k-k{color:var(--ink-3)}
#kino .k-src b{font-weight:500;color:var(--ink)}
#kino .k-src .k-d{display:inline-block;width:9px;height:9px;border-radius:50%;background:var(--d);margin-right:8px;vertical-align:.05em}
/* Paa telefon staar kildene under hverandre til hoeyre for «Kilder», ikke brukket under ordet (7 Okt 2026, Martin:
   «flytt de to til venstre til under den til høyre»). */
@media (max-width:760px){#kino .k-src{display:grid;grid-template-columns:auto 1fr;gap:4px 20px}
  #kino .k-src > :not(.k-k){grid-column:2}
  #kino .k-src .k-k{grid-row:1 / span 3}}
@media (prefers-reduced-motion:reduce){#kino{display:none}}

/* SPØR SENSA in the header, 20 Sep 2026. Same family as the chat field on the
   front page: a pill on --surface inside a hairline, no shadow, and the ACTION
   blue for focus, because --accent here is the ink and a focus ring has to be a
   hue. The sub-lines and group labels take --ink-2 rather than --ink-3, for the
   reason the card labels took it on 18 Sep: at 6.6 on this white they read as
   disabled rather than as quiet. */
.boom .ai-ask-t,.boom .ai-ask-f{
  background:var(--surface);border:1px solid var(--rule);box-shadow:none;
}
.boom .ai-ask-t{color:var(--ink-2);font-size:14.5px}
.boom .ai-ask-t:hover{border-color:var(--ink);color:var(--ink)}
.boom .ai-ask-f:focus-within{border-color:var(--action);box-shadow:0 0 0 3px var(--focus-halo)}
/* 16 px, ikke 15: iPhone zoomer inn paa et felt med mindre skrift naar du trykker i det, og blir staaende zoomet, saa
   siden ble skjoevet mot hoeyre (7 Okt 2026, Martins skjermbilder fra simulatoren). */
html.boom .ai-ask-f textarea{font-size:16px}
.boom .ai-ask-r,.boom .ai-ask-b p,.boom .ai-ask-m a{color:var(--ink)}
.boom .ai-ask-rd,.boom .ai-ask-k,.boom .ai-ask-q,.boom .ai-ask-n,.boom .ai-ask-x{color:var(--ink-2)}
/* EN DEFINERT FORM, 29 Sep 2026: "la listen ha en finere og mer definert form paa drop-down."
   Skyen uten kant (20 Sep) er tatt ut i toppen. Lista og svaret er en flate som nedtrekket
   under «Produkter»: --surface, hairline, 16px og den samme svake skyggen. Flaten ligger paa
   selve rullefeltet, saa kanten staar stille mens forslagene ruller innenfor den. */
.boom .ai-ask-l,.boom .ai-ask-a{
  background:var(--surface);border:1px solid var(--rule-soft);border-radius:var(--r-panel);
  box-shadow:0 1px 2px var(--shadow),0 20px 40px -24px var(--shadow);
}
.boom .ai-ask-l{padding:6px}
.boom .ai-ask-sub,.boom .ai-ask-res{margin:0;padding:0}
.boom .ai-ask-a{margin-top:8px;padding:18px 20px;border-color:transparent}
.boom :is(.ai-ask-sub,.ai-ask-res,.ai-ask-a)::before,.boom .ai-ask-sub::after{content:none}

/* ET TALL DU KAN STOLE PAA, 23 Sep 2026: "kunne paalitelige tall / data vises som
   en slags graf? ... keep in mind; minimalistic maximalism and visualization."
   Fire ord og én stor tegning. Én maaling i midten, fem forbindelser som tegnes inn
   i rekkefoelge, og midten som vokser med graden sin mens de kommer. Grunnen bak er
   en rund pol i sidens farge som loeser seg opp, saa bakgrunnsnettet ikke floker seg
   inn i figuren, men uten en kant. Animasjonen FEILER AAPENT: skjult tilstand settes
   bare av ai.js (.tru-anim), saa uten skript eller med redusert bevegelse staar hele
   grafen der fra start. Generert av tools/ai/tillit.py. */
.boom .tru .boom-h2{margin:0}
/* Seksjonens utgang til /palitelig, under tegningen. */
.boom .tru-go{margin:clamp(14px,2vw,24px) 0 0}
/* /PALITELIG, 24 Sep 2026: "veldig lavmaelt og lett forstaaelig". Samme tegning, ferdig tegnet,
   og én linje per forbindelse: forbindelsen og noden til venstre, hva den betyr til hoeyre. */
.boom .pl-h{font-family:var(--sans);font-weight:400;font-size:clamp(44px,8.8vw,112px);line-height:1.02;letter-spacing:-.04em;margin:0;text-wrap:balance}
.boom .pl-ex{font-size:14px;color:var(--ink-3);margin:6px 0 0}
.boom .pl-rows{list-style:none;margin:clamp(18px,2.4vw,28px) 0 0;padding:0}
.boom .pl-rows li{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);gap:6px clamp(20px,3vw,48px);
  padding:clamp(16px,1.8vw,22px) 0;border-top:1px solid var(--rule);align-items:baseline}
.boom .pl-rows li:last-child{border-bottom:1px solid var(--rule)}
.boom .pl-k{margin:0;display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 10px}
.boom .pl-k span:not(.tru-m){font-size:15px;color:var(--ink-3)}
.boom .pl-k b{font-weight:400;font-size:clamp(20px,1.9vw,24px);letter-spacing:-.02em;color:var(--ink)}
.boom .pl-v{margin:0;font-size:clamp(16px,1.3vw,18px);line-height:1.5;color:var(--ink-2);max-width:56ch}
.boom .pl-p{font-size:clamp(17px,1.5vw,20px);line-height:1.5;color:var(--ink-2);max-width:60ch;margin:clamp(14px,1.6vw,20px) 0 0}
@media (max-width:720px){.boom .pl-rows li{grid-template-columns:1fr}}
.boom .tru .tru-sub{margin:clamp(10px,1.2vw,16px) 0 0;max-width:64ch;text-wrap:balance;
  font-size:clamp(19px,1.7vw,23px);line-height:1.3;letter-spacing:-0.015em;color:var(--ink-2)}
.boom .tru-fig{margin:clamp(14px,2.4vw,34px) 0 0;position:relative;isolation:isolate}
.boom .tru-fig::before{
  content:"";position:absolute;inset:-8% -6%;z-index:-1;background:var(--paper);
  -webkit-mask-image:radial-gradient(closest-side,#000 62%,transparent 100%);
  mask-image:radial-gradient(closest-side,#000 62%,transparent 100%);
}
.boom .tru-svg{display:block;width:100%;height:auto;overflow:visible}
.boom .tru-port{display:none}
@media (max-width:620px){
  .boom .tru-land{display:none}
  .boom .tru-port{display:block;max-width:420px;margin:0 auto}
}
.boom .tru-e line{stroke:var(--ink);stroke-opacity:.4;stroke-width:1.4}
.boom .tru-c circle{fill:var(--ink)}
.boom .tru-n circle{fill:var(--ink);fill-opacity:.78}
.boom .tru-t,.boom .tru-rel{paint-order:stroke;stroke:var(--paper);stroke-width:6;stroke-linejoin:round}
.boom .tru-t{font-family:var(--sans);font-size:19px;letter-spacing:-.01em;fill:var(--ink)}
.boom .tru-tc{font-size:24px;letter-spacing:-.02em}
.boom .tru-rel{font-family:var(--sans);font-size:14px;fill:var(--ink-3)}
.boom .tru-port .tru-t{font-size:17px}
.boom .tru-port .tru-tc{font-size:21px}
.boom .tru-port .tru-rel{font-size:13px}
/* Sifre og koder er Azeret Mono, ord er Open Sans. */
.boom .tru-m{font-family:var(--mono);font-size:.88em;letter-spacing:0}
.boom .tru-c,.boom .tru-n{transform-box:fill-box;transform-origin:center}

.boom .tru.tru-anim .tru-e line{stroke-dasharray:var(--len);stroke-dashoffset:var(--len)}
/* Nodene er der fra start, dempet: delene finnes allerede. Det som kommer er
   forbindelsene, og med dem blir nodene hele. */
.boom .tru.tru-anim .tru-rel{opacity:0}
.boom .tru.tru-anim .tru-n{opacity:.32}
.boom .tru.tru-anim .tru-c{transform:scale(.42)}
.boom .tru.tru-anim.is-in .tru-e line{
  stroke-dashoffset:0;
  transition:stroke-dashoffset .55s cubic-bezier(.3,.7,.3,1) calc(.3s + var(--i) * .34s);
}
.boom .tru.tru-anim.is-in .tru-n{
  opacity:1;transition:opacity .45s ease calc(.6s + var(--i) * .34s);
}
.boom .tru.tru-anim.is-in .tru-rel{opacity:1;transition:opacity .4s ease calc(.75s + var(--i) * .34s)}
.boom .tru.tru-anim.is-in .tru-c{transform:none;transition:transform 2.2s cubic-bezier(.4,0,.2,1) .35s}

/* SITATET SOM EGEN SEKSJON, 23 Sep 2026. Midtstilt, uten den vertikale streken:
   portrettet sier hvem som snakker. Sitatet et trinn stoerre enn broedtekst,
   fordi det er seksjonens eneste innhold, og portrettet over navnet i en kolonne.
   Grunnen bak er en rund pol i sidens farge i stedet for tabellens venstrestilte
   fall, fordi innholdet naa staar i midten. 0,3,0 og tyngre, saa reglene for
   sitatet inne i tabellseksjonen over ikke vinner. */
.boom .boom-said .rec-said{
  border-left:0;margin:0 auto;padding:clamp(20px,3vw,40px) 0;
  max-width:820px;text-align:center;
}
.boom .boom-said .rec-said::before{
  inset:-4% -12%;
  -webkit-mask-image:radial-gradient(closest-side,#000 64%,transparent 100%);
  mask-image:radial-gradient(closest-side,#000 64%,transparent 100%);
  -webkit-mask-composite:source-over;mask-composite:add;
}
.boom .boom-said .rec-said blockquote{
  margin:0 auto;max-width:42ch;font-size:clamp(21px,2vw,27px);line-height:1.38;
  letter-spacing:-0.02em;text-wrap:balance;
}
.boom .boom-said .rec-said figcaption{
  flex-direction:column;justify-content:center;gap:12px;margin-top:clamp(22px,2.4vw,30px);
}
/* Stoerre signatur, 23 Sep 2026: "tittel og selskap under birthe kan vaere stoerre.
   det kan bildet hennes ogsaa." Portrettet 160px, navnet 19px og tittelen 16px i
   ink-2, mot 120 / 14 / 13,5 i ink-3 foer. Bare i den midtstilte seksjonen. */
.boom .boom-said .rec-said figcaption{font-size:19px}
.boom .boom-said .rec-said figcaption img{width:160px;height:160px}
.boom .boom-said .rec-said figcaption span{font-size:19px;letter-spacing:-0.01em}
.boom .boom-said .rec-said figcaption small{font-size:16px;color:var(--ink-2);margin-top:4px}


/* GJENKJENNELSEN ER EN BRYTER, 23 Sep 2026. Fire former ble bygget og sammenlignet
   (stram, forvandling, bryter, kobling); Martin: "jeg likte bryter ... gjoer bryter
   knappen litt lengre, slik at bryteren maa 'reise' en lengre distanse for aa komme
   bort til 'Med Sensa'. Naar bryteren staar paa Slik det ofte er saa er det en pil
   eller guiding som peker det bort til 'med sensa'."
   Uten skript staar tabellen i to spalter som foer; ai.js setter .rec-bryter og bygger
   bryteren, saa den feiler aapent. Én spalte, alle fire linjene bytter paa samme sted.
   Knotten er en lys flate med blekkkant, samme valgt-tilstand som et chatforslag, og den
   GLIR: plassen mellom de to ordene er strekningen den reiser. Pila mellom dem dytter mot
   hoeyre bare saa lenge venstre side er valgt. */
.boom #gjenkjenn.rec-bryter .rec-h{display:grid;grid-template-columns:1fr;border:0;padding-bottom:clamp(16px,1.8vw,22px)}
/* display:grid staar her fordi tabellhodet ellers skjules under 760px, og da forsvant
   bryteren paa mobil og "Med Sensa" var umulig aa naa. */
.boom #gjenkjenn.rec-bryter .rec-h::after,
.boom #gjenkjenn.rec-bryter .rec-r::after{display:none}
.boom #gjenkjenn.rec-bryter .rec-r{grid-template-columns:1fr;padding:clamp(20px,2.2vw,28px) 0}
/* RADENE ER MINDRE ENN OVERSKRIFTEN, OG TONEN BAERER VEKTEN, 24 Sep 2026. Foerst stoerre
   tekst for aa fylle plassen til hoeyre (44px), saa: "de kan jo ikke vaere stoerre enn
   overskriften - her maa du heller benytte deg av font-kunst og triks for aa kapre
   oppmerksomhet og viktighet." Radene er hoeyst 32px mot overskriftens 48, og hver setning
   er graa med kjernen i fullt blekk (.rec-k, merket i boom.py). I svaret staar kjernen i
   blekk og 500, to trinn over resten; i problemet ett trinn, ink-2 over ink-3, saa
   problemene er stillere enn svarene. Naar raden ruller, bytter den moerke frasen plass. */
.boom #gjenkjenn.rec-bryter .rec-r p{max-width:none;font-size:clamp(22px,2.5vw,32px);
  line-height:1.2;letter-spacing:-0.02em}
.boom #gjenkjenn.rec-bryter .rec[data-vis="a"] .rec-r p.rec-b,
.boom #gjenkjenn.rec-bryter .rec[data-vis="b"] .rec-r p.rec-a{display:none}
.boom #gjenkjenn.rec-bryter .rec[data-vis="a"] .rec-r p.rec-a{color:var(--ink-3)}
.boom #gjenkjenn.rec-bryter .rec[data-vis="b"] .rec-r p.rec-b{color:var(--ink)}
@keyframes rec-inn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.boom #gjenkjenn.rec-bryter .rec-r p{animation:rec-inn .35s ease both}
.boom .rec-sw{
  position:relative;justify-self:start;display:grid;grid-template-columns:auto 1fr auto;
  align-items:center;width:min(620px,100%);padding:5px;border:1px solid var(--rule);
  border-radius:999px;background:var(--paper);
}
.boom .rec-sw-k{
  position:absolute;top:5px;bottom:5px;left:var(--x,5px);width:var(--w,0px);
  border-radius:999px;background:var(--surface-2);border:1px solid var(--ink);
  transition:left .5s cubic-bezier(.65,0,.35,1),width .5s cubic-bezier(.65,0,.35,1);
}
.boom .rec-sw button{
  position:relative;z-index:1;font:inherit;font-size:clamp(16px,1.5vw,20px);letter-spacing:-0.01em;
  padding:11px 22px;border-radius:999px;border:0;background:none;color:var(--ink-3);cursor:pointer;
  transition:color .3s ease;white-space:nowrap;
}
.boom .rec-sw button[aria-pressed="true"]{color:var(--ink)}
/* INGENTING MELLOM ORDENE, 24 Sep 2026. Pila og en strek som fyltes ble begge avvist
   ("pilen ser helt forferdelig ut", "nei, det ble ikke bra"), og to avviste loesninger
   paa samme sted betyr at stedet ikke trengte en. Rommet er en tom strekning knotten
   reiser over, og bevegelsen ligger i radene selv. */
.boom .rec-sw-k{z-index:1}
.boom .rec-sw button{z-index:2}
.boom .rec-sw-go{position:relative;z-index:0;justify-self:stretch;align-self:stretch;cursor:pointer}
/* Sporet er Sensa-merket som moetes (ai.js): de to halvdelene i blekk, fra hver sin ende til
   midten. Mens innholdet staar stille paa problemene, staar «Rull» mellom dem paa et felt i
   sidens farge, med en node som foelger rullingen ned en kort strek og gaar i loekke naar du
   staar stille. */
.boom .rec-sw-g{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
.boom .rec-half{fill:var(--ink)}
.boom .rec-rull{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:flex;align-items:center;gap:10px;
  padding:4px 12px;border-radius:999px;background:var(--paper);
  font-size:15px;line-height:1;color:var(--ink);pointer-events:none;transition:opacity .2s ease;
}
.boom .rec-rull i{position:relative;display:block;width:1.5px;height:22px;background:var(--ink-3);border-radius:1px}
.boom .rec-rull b{
  position:absolute;left:50%;top:0;width:7px;height:7px;margin:-1px 0 0 -3.5px;
  border-radius:50%;background:var(--ink);
}
.boom .rec-rull.is-idle b{animation:rec-rull 1.6s cubic-bezier(.45,0,.25,1) infinite}
@keyframes rec-rull{0%{transform:translateY(0);opacity:0}20%{opacity:1}75%{transform:translateY(15px);opacity:1}100%{transform:translateY(15px);opacity:0}}
@media (prefers-reduced-motion:reduce){.boom .rec-rull{display:none}}

/* RULLETEKST, 24 Sep 2026. To overganger ble bygget side om side, gjennomstreking og
   rulletekst; Martin: "vi gaar for rulletekst." Problemet ruller ut opp og svaret inn
   nedenfra, klippet av ruten, rad for rad mens du ruller: ai.js setter --o per rad.
   Begge setningene staar i samme rute (.rec-cell), saa raden har samme hoeyde foer og
   etter og ingenting hopper. */
.boom #gjenkjenn.rec-bryter.rec-v .rec .rec-r .rec-cell{display:grid}
.boom #gjenkjenn.rec-bryter.rec-v .rec .rec-r .rec-cell p{grid-area:1/1;display:block;animation:none}
.boom #gjenkjenn.rec-bryter.rec-v .rec .rec-r .rec-cell p.rec-a{color:var(--ink-3)}
.boom #gjenkjenn.rec-bryter.rec-v .rec .rec-r .rec-cell p.rec-b{color:var(--ink-3)}
.boom #gjenkjenn.rec-v .rec-cell p.rec-a .rec-k{color:var(--ink-2)}
.boom #gjenkjenn.rec-v .rec-cell p.rec-b .rec-k{color:var(--ink);font-weight:500;letter-spacing:-0.025em}
.boom #gjenkjenn.rec-v .rec-cell{overflow:hidden;padding:.08em 0;margin:-.08em 0}
.boom #gjenkjenn.rec-v .rec-cell p.rec-a{transform:translateY(calc(var(--o,0) * -115%))}
.boom #gjenkjenn.rec-v .rec-cell p.rec-b{transform:translateY(calc((1 - var(--o,0)) * 115%))}
.boom .rec[data-vis="b"] .rec-sw-go{pointer-events:none}
/* Rullestyrt: knotten flyttes av rullingen, ikke av en overgang, saa den skal ikke
   glide etter. Den klebrige blokken er innholdet; seksjonens hoeyde er banen. */
.boom #gjenkjenn.rec-scrub .rec-sw-k{transition:none}
.boom #gjenkjenn.rec-scrub .rec-pin{position:sticky}
@media (prefers-reduced-motion:reduce){
  .boom #gjenkjenn.rec-bryter .rec-r p{animation:none}
  .boom .rec-sw-k{transition:none}
}

/* Rullestyrt graf: verdiene settes fra ai.js per bilde, saa ingen overgang skal gli
   etter dem, og den klebrige blokken er innholdet mens seksjonens hoeyde er banen. */
.boom #tillit.tru-scrub .tru-e line,.boom #tillit.tru-scrub .tru-rel,
.boom #tillit.tru-scrub .tru-n,.boom #tillit.tru-scrub .tru-c{transition:none}
.boom #tillit.tru-scrub .tru-pin{position:sticky}

/* ===========================================================================
   DEN LEVENDE FLATEN, 26 Sep 2026: "jeg kunne tenkt meg en fluid bakgrunn, levende og
   x-faktor". Standard paa alle BOOM-sider samme dag; Visuell profil (.sd) har den ikke.
   ai.js legger et lerret rett FOER node-nettverket, like hoeyt som heroen og i hele
   bredden, saa kontekstgrafen staar paa flaten i heroen og siden er som foer under.
   Underkanten toner ut, saa overgangen til siden er en tone og ikke en kant.
   Grunnen er papiret, 29 Sep 2026: et lerret som ikke har tegnet ennaa (siden lastet i en
   skjult fane eller ramme) eller har mistet WebGL, viser da sidens farge og ikke svart,
   saa overskriften alltid staar paa sin egen grunn.
   =========================================================================== */
.boom-fluid{position:absolute;top:0;left:0;width:100%;z-index:0;pointer-events:none;display:block;background:var(--fluid-paper);
  -webkit-mask-image:linear-gradient(180deg,#000 0,#000 calc(100% - 220px),transparent 100%);
  mask-image:linear-gradient(180deg,#000 0,#000 calc(100% - 220px),transparent 100%)}
/* Flaten staar fast bak hele vinduet, saa den ikke toner ut: forsiden 27 Sep, alle sider 2 Okt 2026. */
.boom-fluid.is-hel{position:fixed;height:100vh;-webkit-mask-image:none;mask-image:none}
html.sd .boom-fluid{display:none}
/* TOPPEN ER EN OEY, 26 Sep 2026. Flaten gaar under toppmenyen ogsaa («la flaten gaa under
   toppmenyen ogsaa»), og skillet mot den er toppens egen flate, ikke en strek: graa, blaa og
   svart strek ble forkastet, og «kanskje toppmargen ikke skal ha samme bakgrunn» ga tre
   varianter (flate, glass, oy). Martin valgte oeya: toppen flyter i --surface, trukket inn
   fra kantene, loeftet med en myk skygge, og flaten renner rundt den. Lik hele veien ned;
   naar den gjemmer seg, tar den luften over seg med. */
html.boom:not(.sd) .ai-hdr{top:12px;margin:12px var(--gutter) 0;
  padding:10px 14px 10px 22px;border-radius:var(--r-panel);background:var(--surface);
  border-bottom-color:transparent;box-shadow:var(--fluid-lift);
  -webkit-backdrop-filter:none;backdrop-filter:none}
html.boom:not(.sd) .ai-hdr::after{background:transparent}
html.boom:not(.sd) .ai-hdr.is-away{transform:translateY(calc(-100% - 16px))}
/* OEYA KOMMER NAAR DU RULLER (6 Okt 2026, moetet nr. 2, Martin: «C på menyen»): oeverst staar menyen rett paa flaten,
   uten flate og skygge, fordi oeya ved innlasting saa ut som noe man vil lukke. `hdr-rullet` settes av ai.js. Aapent
   felt og aapen telefonmeny har alltid oeya. Midtstilt og bare logoen ble proevd i tools/valg/. */
html.boom:not(.sd) .ai-hdr{transition:background-color .35s ease,box-shadow .35s ease,transform .24s ease}
@media (prefers-reduced-motion:reduce){html.boom:not(.sd) .ai-hdr{transition:none}}
html.boom:not(.sd):not(.hdr-rullet) body:not(.ai-locked) .ai-hdr:not(.is-ask){background:transparent;box-shadow:none}

/* UTEN BAKGRUNNER, 27 Sep 2026, standard paa alle sider (seksjoner_ti.py og seksjoner.py setter
   bak-ingen). Bare feltene og kortfyllet; linjene i tabellen staar. */
html.bak-ingen #datakart::before,html.bak-ingen #gjenkjenn .rec::before,
html.bak-ingen #sitat .rec-said::before,html.bak-ingen #tillit .tru-fig::before,
html.bak-ingen #verdi .boom-figs::before,html.bak-ingen #verdi .boom-figs::after{display:none}
html.bak-ingen #verdi .boom-fig{background:transparent}
html.bak-ingen #verdi .boom-fig:hover{background:transparent}

/* Demoflaten fra ?forside=ny (27 Sep 2026) vises aldri: HTML-en i boom.py er bare kilden som
   seksjoner_ti.py og seksjoner.py leser kortene fra. Bryteren er tatt av 3 Okt 2026 (QA 2.8). */
#demo{display:none}

/* Noden som maaleinstrument, 28 Sep 2026 (ai.js). Laget ligger rett over nettverket og under
   innholdet, i full styrke, saa en node kan leses selv naar nettverket er dempet til 18 %. */
.boom .maal-lag{position:fixed;inset:0;z-index:0;pointer-events:none;opacity:0;transition:opacity .18s ease}
.boom .maal-lag.is-on{opacity:1}
.boom .maal-lag svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
.boom .maal-lag line{stroke:var(--ink);stroke-opacity:.42;stroke-width:1}
.boom .maal-lag .maal-nabo{fill:var(--ink);fill-opacity:.6}
.boom .maal-lag .maal-ring{fill:none;stroke:var(--ink);stroke-opacity:.8;stroke-width:1}
.boom .maal-tekst{
  position:absolute;left:0;top:0;transform:translate(var(--mx,-999px),var(--my,-999px));
  display:flex;flex-direction:column;gap:2px;white-space:nowrap;
}
.boom .maal-tekst b{font-weight:400;font-size:15px;line-height:1.2;color:var(--ink)}
.boom .maal-tekst span{font-family:var(--mono);font-size:12px;line-height:1.3;letter-spacing:.04em;
  text-transform:uppercase;color:var(--ink-3)}
@media (prefers-reduced-motion:reduce){.boom .maal-lag{transition:none}}

/* Kapsel, 2 Okt 2026 (Martin valgte «kapsel» paa /tools/valg/?p=banner): én linje med helt runde ender, som
   toppmenyen, i --surface med myk skygge i stedet for kant. Under 1100 px faar ikke teksten og knappene plass paa
   én linje, og kapselen brytes til to linjer med runde hjoerner. Visuell profil (.sd) beholder kortet. */
html.boom:not(.sd) .ai-cs{
  flex-direction:row;align-items:center;gap:28px;max-width:calc(100vw - 32px);
  padding:10px 10px 10px 28px;border:0;border-radius:999px;background:var(--surface);box-shadow:var(--fluid-lift);
}
html.boom:not(.sd) .ai-cs p{white-space:nowrap;font-size:16px}
/* Stoerre tekst i kapselen (2 Okt 2026, Martin: «gjør teksten litt større i kapselen»): 14,5 til 16 px, knappene 15 px. */
html.boom:not(.sd) .ai-cs-b button{font-size:15px}
@media (max-width:1100px){
  html.boom:not(.sd) .ai-cs{flex-direction:column;align-items:flex-start;gap:14px;border-radius:var(--r-panel);padding:18px 20px}
  html.boom:not(.sd) .ai-cs p{white-space:normal}
}

/* ===========================================================================
   TOPPMENYEN MED NODEN, 29 Sep 2026, laast 3 Okt 2026 (QA 2.8). Martin om bunsenstudio.com: «enkelt og
   greit. topp menyen har en liten fade på seg og er midtstilt. så med hover blir meny highligheted med en
   liten node til venstre». Ordene hviler i --ink-3 og blir --ink med en node paa 5px som glir inn til
   venstre. Hodet setter data-meny=node paa alle sider utenom Visuell profil (.sd).
   =========================================================================== */
/* Toppen er oeya igjen (Martin 30 Sep 2026: «ha de samme endringene som allerede er vedtatt, bare at
   selve pillen er slik den er nå»): fade-toppen er tatt ut, menyen, noden og knappene staar. */
/* Under 1100 px staar menyen i raden. Med «Bruksområder» (proevd 2 Okt 2026) ble raden for bred paa 901 til
   1099 px, og bryteren stakk ut av oeya; mindre luft og et smalere spoerrefelt gjoer at alt staar paa én linje. */
@media (min-width:901px) and (max-width:1099px){
  html.boom:not(.sd) .ai-hdr{gap:18px}
  html.boom .ai-ask{--ask-w:160px}
  /* Spansk (3 Okt 2026): «Pregunte a Sensa» er 114 px og fikk 100, og menyordene er lengre. To px mindre luft
     i raden og seks fra polstringen og mellomrommet i feltet gir ordet plass; raden har fortsatt 7 px igjen paa 901. */
  html.boom[lang=es]:not(.sd) .ai-hdr{gap:16px}
  html.boom[lang=es] .ai-ask{--ask-w:172px}
  html.boom[lang=es] .ai-ask-t{padding-left:12px;gap:8px}
  /* Naar feltet og demoen venter (forsiden foer heroen er forbi), staar menyordene ytterst til hoeyre, saa nedtrekkene
     henger fra hoeyre kant av ordet, speilet av left:-22px. Fra venstre gikk «Produkter» (500 px) og «Om oss» ut av
     skjermen, ogsaa lukket, og siden rullet 70 px sidelengs paa 1024 (8 Okt 2026). Med feltet framme er det plass. */
  html.boom:not(.sd) .ai-hdr:has(.ai-ask.is-away) .ai-dd-p{left:auto;right:-22px;transform-origin:calc(100% - 22px) 0}
}
/* Spansk faar ikke plass i raden under 1024 px etter at demoknappen ble «¿Por qué agendar una demo?» (230 px, 6 Okt
   2026): paa 901 manglet 98 px, maanen stod utenfor oeya og siden rullet 48 px sidelengs (8 Okt 2026). Spansk har
   derfor telefontoppen til 1023 px, samme regler som 761 til 900 px over. 1024 gir luft til et rullefelt paa 17 px. */
@media (min-width:901px) and (max-width:1023px){
  html.boom[lang=es]:not(.sd) .ai-nav{display:none}
  html.boom[lang=es]:not(.sd) .ai-hdr{gap:10px}
  html.boom[lang=es]:not(.sd) .ai-burger{display:grid}
  html.boom[lang=es]:not(.sd) .ai-menu:not([hidden]){display:block}
  html.boom[lang=es]:not(.sd) .ai-ask{position:static;order:2;flex:1 1 auto;min-width:0;display:flex;justify-content:flex-end;--ask-w:100%}
  html.boom[lang=es]:not(.sd) .ai-ask-t{max-width:240px;padding-left:12px;gap:8px}
  html.boom[lang=es]:not(.sd) .ai-ask-p{top:calc(100% + 8px);left:var(--gutter);right:var(--gutter);width:auto;transform:none}
  html.boom[lang=es]:not(.sd) .ai-ask.is-open .ai-ask-t{visibility:visible;border-color:var(--ink-3)}
  html.boom[lang=es]:not(.sd) .ai-hdr .ai-try-hdr{order:2}
  html.boom[lang=es]:not(.sd) .ai-hdr .ai-brand{margin-right:auto}
  html.boom[lang=es]:not(.sd) .ai-hdr .ai-tools{order:3;margin-left:0}
}
/* Norsk har det samme til 969 px (8 Okt 2026, Martin: «a»): paa undersidene, der feltet staar framme, stod maanen
   opptil 44 px utenfor oeya paa 901 til 951 px. Raden faar plass fra 952; 969 gir luft til et rullefelt paa 17 px.
   Engelsk faar plass paa 901 og har menyordene der. */
@media (min-width:901px) and (max-width:969px){
  html.boom[lang=nb]:not(.sd) .ai-nav{display:none}
  html.boom[lang=nb]:not(.sd) .ai-hdr{gap:10px}
  html.boom[lang=nb]:not(.sd) .ai-burger{display:grid}
  html.boom[lang=nb]:not(.sd) .ai-menu:not([hidden]){display:block}
  html.boom[lang=nb]:not(.sd) .ai-ask{position:static;order:2;flex:1 1 auto;min-width:0;display:flex;justify-content:flex-end;--ask-w:100%}
  html.boom[lang=nb]:not(.sd) .ai-ask-t{max-width:240px;padding-left:12px;gap:8px}
  html.boom[lang=nb]:not(.sd) .ai-ask-p{top:calc(100% + 8px);left:var(--gutter);right:var(--gutter);width:auto;transform:none}
  html.boom[lang=nb]:not(.sd) .ai-ask.is-open .ai-ask-t{visibility:visible;border-color:var(--ink-3)}
  html.boom[lang=nb]:not(.sd) .ai-hdr .ai-try-hdr{order:2}
  html.boom[lang=nb]:not(.sd) .ai-hdr .ai-brand{margin-right:auto}
  html.boom[lang=nb]:not(.sd) .ai-hdr .ai-tools{order:3;margin-left:0}
}
/* Spraakvalget kommer paa 1081 px, men paa spansk skjoev det maanen 16 px ut av oeya; der kommer det fra 1100 */
@media (min-width:1081px) and (max-width:1099px){html.boom[lang=es]:not(.sd) .ai-hdr .ai-langs{display:none}}
/* «Still et spørsmål» i feltet (7 Okt 2026, Martin: «sensa sensa» stod to ganger, ved logoen og i feltet). Feltet
   maaler selv om den lange teksten faar plass, og viser ellers det korte ordet («Spør», «Ask», «Pregunte»); knappens
   aria-label sier fortsatt hele. Grensene er tekstens bredde i em, fordi feltet har ulik skrift paa ulike bredder. Erstatter bruddpunktene fra 3 Okt 2026
   (break-it funn 11), som kuttet « Sensa» under 400 og 430 px. */
html.boom .ai-ask-t .ai-ask-v{flex:1 1 auto;min-width:0;container-type:inline-size;text-align:left}
html.boom .ai-ask-t .ai-ask-lang{display:block}
html.boom .ai-ask-t .ai-ask-kort{display:none}
@container (max-width:7.1em){
  html.boom:lang(nb) .ai-ask-t .ai-ask-lang{display:none}
  html.boom:lang(nb) .ai-ask-t .ai-ask-kort{display:block}
}
@container (max-width:6.55em){
  html.boom:lang(en) .ai-ask-t .ai-ask-lang{display:none}
  html.boom:lang(en) .ai-ask-t .ai-ask-kort{display:block}
}
@container (max-width:8.5em){
  html.boom:lang(es) .ai-ask-t .ai-ask-lang{display:none}
  html.boom:lang(es) .ai-ask-t .ai-ask-kort{display:block}
}
/* Paa 320 px faar ordet rundt 28 px: «Pregunte» ble «Pre…» og «Spør» «Sp…»; da staar bare pila i feltet. */
@container (max-width:4.1em){html.boom:lang(es) .ai-ask-t .ai-ask-kort{display:none}}
@container (max-width:2.15em){html.boom:lang(nb) .ai-ask-t .ai-ask-kort{display:none}}
/* Under 440 px gir raden feltet 18 px mer, saa «Still et spørsmål» faar plass paa 402 px, iPhone Pro (7 Okt 2026). */
@media (max-width:439px){
  html.boom:not(.sd) .ai-hdr{gap:6px;padding-left:18px}
  html.boom:not(.sd) .ai-tools{gap:6px}
  html.boom .ai-ask-t{padding-left:10px;gap:4px}
}
/* Paa 320 fikk feltet 64 px og «Spør» ble «S…», og «Pregunte» ble kuttet paa 360. Litt mindre luft i raden gir ordet
   plass: norsk og engelsk under 360 px, spansk under 400 px. */
@media (max-width:359px){
  html.boom:not(.sd) .ai-hdr{gap:6px;padding-left:16px}
  html.boom:not(.sd) .ai-tools{gap:6px}
  html.boom .ai-ask-t{padding-left:10px;gap:6px}
}
@media (max-width:399px){
  html.boom[lang=es]:not(.sd) .ai-hdr{gap:6px;padding-left:16px}
  html.boom[lang=es]:not(.sd) .ai-tools{gap:6px}
  html.boom[lang=es] .ai-ask-t{padding-left:10px;gap:4px}
}
/* KAPSEL I FULL BREDDE fra 1100 px (7 Okt 2026, Martin: «kan du dra ut hele menyen? nå er den midstilt liten
   pille»): oeya gaar fra marg til marg med helt runde ender. Logoen staar til venstre, feltet og menyordene i
   midten og demoen, spraak og moerk modus til hoeyre. Den smale kapselen (2 til 7 Okt) er i beslutningsloggen. */
@media (min-width:1100px){
  /* Tre grupper (7 Okt 2026, designerens sak 10, Martin: «10A»): logoen alene, så feltet og menyordene, så
     «Hvorfor booke en demo?», spraak og moerk modus. 14 px inne i en gruppe; luften mellom dem er det som er til
     overs i full bredde (auto-margen etter logoen og etter menyordene), saa spansk faar plass paa 1100 px. */
  /* Logoen og maanen staar paa sidens linjer (8 Okt 2026, Martin: «A, A, B»): oeya gaar fortsatt nesten fra kant til
     kant, men kantene er der innholdet starter og slutter, minus luften inne i oeya. --hdr-l er venstre linje i heroen
     og seksjonene (--pad inne i --maks); prosent i margen er av sidens bredde uten rullefeltet, som heroen. */
  html.boom:not(.sd) .ai-hdr{--hdr-l:calc(max(0px, (100% - var(--maks,1440px)) / 2) + var(--pad));--hdr-pr:15px;
    margin:12px calc(var(--hdr-l) - 24px) 0;border-radius:999px;gap:14px;padding:8px var(--hdr-pr) 8px 24px}
  html.boom:not(.sd) .ai-hdr .ai-brand{margin-right:auto}
  html.boom[data-meny=node] .ai-nav{order:2;margin:0 auto 0 0}
  html.boom[data-meny=node] .ai-ask{--ask-w:clamp(186px,16vw,230px)}
  html.boom[data-meny=node] .ai-hdr .ai-tools{order:4;margin-left:0}
  /* Paa forsiden venter feltet og «Book en demo» til heroen er forbi. I kapselen foldes de inn og ut i stedet
     for aa forsvinne, saa kapselen glir i bredden og ikke hopper (2 Okt 2026). Den negative margen tar luften
     foran dem; visibility gjoer at de ikke kan naas med tab mens de er foldet inn. */
  html.boom:not(.sd) .ai-hdr .ai-ask{max-width:var(--ask-w)}
  html.boom:not(.sd) .ai-hdr .ai-try-hdr{max-width:230px}
  /* «¿Por qué agendar una demo?» faar samme 230 px som norsk fra 6 Okt 2026 (pakke A); 160 px holdt for «Agende una demo» */
  html.boom:not(.sd) .ai-hdr :is(.ai-ask,.ai-try-hdr).is-away{
    display:flex;max-width:0;margin-left:-14px;padding-left:0;padding-right:0;border-width:0;opacity:0;overflow:hidden;
    visibility:hidden;pointer-events:none}
  html.boom:not(.sd) .ai-hdr .ai-ask.is-away{display:block}
  html.boom:not(.sd) .ai-hdr.is-glid :is(.ai-ask,.ai-try-hdr){
    transition:max-width .35s cubic-bezier(.65,0,.35,1),margin-left .35s cubic-bezier(.65,0,.35,1),
               padding .35s cubic-bezier(.65,0,.35,1),opacity .2s ease .12s,visibility 0s linear 0s}
  html.boom:not(.sd) .ai-hdr.is-glid :is(.ai-ask,.ai-try-hdr).is-away{
    transition:max-width .35s cubic-bezier(.65,0,.35,1),margin-left .35s cubic-bezier(.65,0,.35,1),
               padding .35s cubic-bezier(.65,0,.35,1),opacity .14s ease,visibility 0s linear .35s}
  html.boom[data-meny=node] .ai-hdr .ai-try-hdr{order:3}
  /* Feltet staar til venstre, saa panelet vokser mot hoeyre og ikke ut av skjermen, og
     feltet i panelet staar til venstre med det; ellers la det seg oppaa menyen (29 Sep 2026). */
  html.boom[data-meny=node] .ai-ask-p{left:-8px;right:auto}
  html.boom[data-meny=node] .ai-ask-f{margin-left:0}
}
/* MENYORDENE MIDT PAA SIDEN (7 Okt 2026, Martin: «sentrer menyordene midt på siden»). Toppen er et rutenett med fem
   kolonner: logoen, feltet, menyordene, demoen og spraak med moerk modus. Feltet og demoen deler det som er til overs
   likt, og den hoeyre kanten er bredere enn den venstre med forskjellen paa luften inne i oeya (24 px mot --hdr-pr);
   da staar menyordene midt paa siden, ogsaa naar feltet og demoen er foldet inn paa forsiden. Fra 1200 px, fordi
   norsk og spansk ikke faar plass paa 1100; der deler de luften som over. */
@media (min-width:1200px){
  html.boom[data-meny=node]:not(.sd) .ai-hdr{display:grid;--hdr-side:112px;--hdr-pr:14px;
    grid-template-columns:var(--hdr-side) minmax(0,1fr) auto minmax(0,1fr) calc(var(--hdr-side) + 24px - var(--hdr-pr));
    align-items:center;column-gap:14px}
  html.boom[data-meny=node]:not(.sd) .ai-hdr > *{grid-row:1}
  html.boom[data-meny=node]:not(.sd) .ai-hdr .ai-brand{grid-column:1;justify-self:start;margin:0}
  /* Feltet og demoen er like brede (7 Okt 2026, Martin: «gjør feltet og demoknappen like brede»); 230 px rommer
     «¿Por qué agendar una demo?». Menyordene har 18 px ekstra luft paa begge sider, saa prikken foran «Produkter»
     ikke staar inntil feltet (Martin: «avstand fra prikken til Produkter og chat er for kort»). */
  html.boom[data-meny=node]:not(.sd) .ai-hdr .ai-ask{grid-column:2;justify-self:end;--ask-w:230px}
  html.boom[data-meny=node]:not(.sd) .ai-hdr .ai-nav{grid-column:3;margin:0 18px}
  html.boom[data-meny=node]:not(.sd) .ai-hdr .ai-try-hdr{grid-column:4;justify-self:end;width:230px;justify-content:center}
  html.boom[data-meny=node]:not(.sd) .ai-hdr .ai-tools{grid-column:5;justify-self:end;margin:0}
  /* Foldet inn staar de ytterst mot menyordene og trenger ikke den negative margen */
  html.boom[data-meny=node]:not(.sd) .ai-hdr :is(.ai-ask,.ai-try-hdr).is-away{margin-left:0}
}
/* Ordene hviler svakere og blir klare ved hover (2 Okt 2026, Martin: «litt mer faded, og når man hover over
   blir de klar - samme med no, en, es og dark mode»). Siden du er paa og spraaket du leser staar klart. */
html.boom[data-meny=node] :is(.ai-nav > a,.ai-nav .ai-dd-t,.ai-dd > button){position:relative;color:var(--ink-3);text-decoration:none;transition:color .3s ease}
html.boom[data-meny=node] .ai-dd > .ai-dd-pil::before{display:none}
html.boom[data-meny=node] :is(.ai-nav > a,.ai-nav .ai-dd-t,.ai-dd > button)::before{content:"";position:absolute;left:-15px;top:50%;width:5px;height:5px;margin-top:-2.5px;
  border-radius:50%;background:var(--ink);opacity:0;transform:translateX(10px);
  transition:opacity .3s ease,transform .3s ease-in-out}
html.boom[data-meny=node] :is(.ai-nav > a,.ai-nav .ai-dd-t,.ai-dd > button):is(:hover,:focus-visible,[aria-current]),
html.boom[data-meny=node] .ai-dd:is(:hover,:focus-within) > :is(.ai-dd-t,button){color:var(--ink);text-decoration:none}
html.boom[data-meny=node] :is(.ai-nav > a,.ai-nav .ai-dd-t,.ai-dd > button):is(:hover,:focus-visible,[aria-current])::before,
html.boom[data-meny=node] .ai-dd:is(:hover,:focus-within) > :is(.ai-dd-t,button)::before{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){html.boom[data-meny=node] :is(.ai-nav > a,.ai-nav .ai-dd-t,.ai-dd > button),html.boom[data-meny=node] :is(.ai-nav > a,.ai-nav .ai-dd-t,.ai-dd > button)::before{transition:none}}
/* Siden du er paa i et nedtrekk (6 Okt 2026): ordet over faar noden (aria-current=true, satt i ai.js), og raden faar
   samme node foran, 10 px foran ikonet og paa hoeyde med navnet, som i toppen (8 Okt 2026, Martin: «a»). */
html.boom[data-meny=node] .ai-hdr .ai-dd-p a[aria-current]::before{content:"";position:absolute;left:-4.5px;top:17px;
  width:9px;height:9px;border-radius:50%;background:var(--ink)}
/* Og raden har en strek rundt seg (17 Okt 2026, se TREET), i alle nedtrekkene, saa du ser hvor du er. */
html.boom[data-meny=node] .ai-hdr .ai-dd-p a[aria-current]{box-shadow:inset 0 0 0 1px var(--ink-2)}
html.boom[data-meny=node] .ai-menu-in > a[aria-current]:not(.ai-menu-cta){position:relative}
html.boom[data-meny=node] .ai-menu-in > a[aria-current]:not(.ai-menu-cta)::before{content:"";position:absolute;left:-13px;top:21px;width:5px;height:5px;
  border-radius:50%;background:var(--ink)}

/* ===========================================================================
   DEN RUNDE LAKS PILLEN, laast 3 Okt 2026 (QA 2.8, Martin: «De valgte låses, og resten tas av»). Martin,
   29 Sep 2026: «En avrundet knapp som har en unik farge eller gradient som skiller seg ut. når man hover
   over så skjer det noe som indikerer at man er på knappen.» Store som paa sanity.io. Neste steg er
   noeytral, saa bare handlingen har farge, og banneret er noeytralt: avslaa og godta skal veie like mye.
   Forslagene som ble vist foer valget (hav, laks, glans, filet, fisk, nordlys, blaa, blekk og melk,
   stille, tusj, node, og hoverne lykt, vipp og kantlys) er tatt av; de ligger i 87f94eb.
   =========================================================================== */
html.boom[data-knapp=rund] .boom-cta{gap:12px 16px;align-items:center}
/* Store som paa sanity.io (Martin, 29 Sep 2026: «knappene må være mye større, like som sanity.io»):
   24px tekst og rundt 60px hoeyde paa en bred skjerm, litt mindre paa en smal. */
html.boom[data-knapp=rund] .boom-btn{position:relative;overflow:hidden;isolation:isolate;display:inline-flex;align-items:center;
  height:clamp(54px,2.6vw + 22px,62px);padding:0 clamp(26px,2.4vw,34px);
  font-size:clamp(19px,1.25vw + 6px,24px);letter-spacing:-.01em;line-height:1;text-decoration:none}
html.boom[data-knapp=rund] :is(.boom-btn,.ai-try-hdr,.ai-menu-cta,.ai-cs-b button){border-radius:999px;text-decoration:none}
html.boom[data-knapp=rund] :is(.boom-btn,.ai-try-hdr,.ai-menu-cta,.ai-cs-b button):is(:hover,:focus-visible){text-decoration:none}
html.boom[data-knapp=rund] :is(.boom-btn-a,.ai-try-hdr,.ai-menu-cta){border:0;
  transition:transform .25s ease,box-shadow .25s ease,background-position .5s ease,filter .25s ease}
html.boom[data-knapp=rund] :is(.boom-btn-a,.ai-try-hdr,.ai-menu-cta):is(:hover,:focus-visible){transform:translateY(-2px)}
html.boom[data-knapp=rund] :is(.boom-btn-a,.ai-try-hdr,.ai-menu-cta):active{transform:translateY(0) scale(.98)}
html.boom[data-knapp=rund] :is(.boom-btn-a,.ai-try-hdr,.ai-menu-cta):focus-visible{outline:2px solid var(--ink);outline-offset:3px}
/* Neste steg og banneret: noeytrale, som foer. */
html.boom[data-knapp=rund] :is(.boom-btn-b,.ai-cs-b button:not(.is-a)){background:transparent;color:var(--ink);border:1px solid color-mix(in srgb,var(--ink) 30%,transparent);transition:background-color .2s ease,border-color .2s ease}
html.boom[data-knapp=rund] :is(.boom-btn-b,.ai-cs-b button:not(.is-a)):is(:hover,:focus-visible){background:var(--surface-2);border-color:var(--ink-3)}
html.boom[data-knapp=rund] .ai-cs-b button.is-a{background:var(--boks);color:var(--on-boks);border-color:transparent}
html.boom[data-knapp=rund] .ai-cs-b button.is-a:is(:hover,:focus-visible){background:color-mix(in srgb,var(--boks) 84%,var(--paper))}

/* RUND MED PIL, 29 Sep 2026. Martin, etter laks, glans, filet og fisk: «velger ingen av de. lag noe
   likt som dette: når man hover over så blir den en annen farge», med et bilde av en lys graa
   pille, svart tekst og en tynn pil. Handlingen er pillen med pil; neste steg er de samme ordene
   og pila uten flate, og faar flaten ved hover. Ingen loeft, bare fargen skifter, og pila glir
   litt fram. 30 Sep 2026, Martin: «knappen kan være laks, og bli svart når man hover over - da er
   den eye-catching til å begynne med og samtidig indikerer at man hover over.» Graa i ro, og
   hover til laks eller hav, er tatt ut. Fargen er Sensas blaa med svart tekst fra 7 Okt 2026 (--knapp-1). */
html.boom[data-knapp=rund] .boom-btn{height:clamp(56px,2.4vw + 26px,64px);padding:0 28px 0 32px;
  font-size:clamp(17px,.9vw + 6px,20px);letter-spacing:-.005em;gap:14px}
html.boom[data-knapp=rund] :is(.boom-btn-a,.ai-try-hdr,.ai-menu-cta){background:var(--knapp-1);color:var(--knapp-t);
  transition:background-color .25s ease,color .25s ease}
html.boom[data-knapp=rund] :is(.boom-btn-a,.ai-try-hdr,.ai-menu-cta):is(:hover,:focus-visible){transform:none;box-shadow:none}
html.boom[data-knapp=rund] .boom-btn-b{background:transparent;border:0;color:var(--ink);transition:background-color .25s ease}
html.boom[data-knapp=rund] .boom-btn-b:is(:hover,:focus-visible){background:var(--surface-2)}
html.boom[data-knapp=rund] .boom-btn::after{content:"";flex:none;width:22px;height:14px;background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 14'%3E%3Cpath d='M1 7h19M14 1l6 6-6 6' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 14'%3E%3Cpath d='M1 7h19M14 1l6 6-6 6' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;transition:transform .25s ease}
html.boom[data-knapp=rund] .boom-btn:is(:hover,:focus-visible)::after{transform:translateX(4px)}
html.boom[data-knapp=rund] :is(.boom-btn-a,.ai-try-hdr,.ai-menu-cta):is(:hover,:focus-visible){background:var(--ink);color:var(--surface)}

/* FYLLET SOM FOELGER PEKEREN, 30 Sep 2026 (data-hover=fyll). Martin, med et bilde av blekk og melk: «går
   det an å lage disse knappene uten dråpe/magnet effekten? at de blir som piller, men påvirkes av hover over
   på forskjellige steder?» og samme dag «gjør fyll til standard på hele nettstedet». Svart fyller pillen som
   en sirkel fra der pekeren kommer inn, og trekker seg ut der den gaar; neste steg («Se produktene») faar det
   samme i graatt. ai.js gir knappen pekerens plass (--mx, --my, px) og avstanden til hjoernet lengst unna
   (--mr). Tastaturfokus regnes fra midten. */
html.boom[data-knapp=rund][data-hover] :is(.boom-btn,.ai-try-hdr,.ai-menu-cta){position:relative;overflow:hidden;isolation:isolate}
html.boom[data-knapp=rund][data-hover] :is(.boom-btn,.ai-try-hdr,.ai-menu-cta)::before{content:"";position:absolute;z-index:-1;pointer-events:none}
html.boom[data-knapp=rund][data-hover=fyll] :is(.boom-btn-a,.ai-try-hdr,.ai-menu-cta){transition:color .2s ease .18s}
html.boom[data-knapp=rund][data-hover=fyll] :is(.boom-btn-a,.ai-try-hdr,.ai-menu-cta):is(:hover,:focus-visible){background:var(--knapp-1);transition:color .2s ease .08s}
html.boom[data-knapp=rund][data-hover=fyll] .boom-btn-b:is(:hover,:focus-visible){background:transparent}
html.boom[data-knapp=rund][data-hover=fyll] :is(.boom-btn,.ai-try-hdr,.ai-menu-cta)::before{left:var(--mx,50%);top:var(--my,50%);width:calc(var(--mr,160px) * 2);height:calc(var(--mr,160px) * 2);
  margin:calc(var(--mr,160px) * -1) 0 0 calc(var(--mr,160px) * -1);border-radius:50%;background:var(--ink);
  transform:scale(0);transition:transform .5s cubic-bezier(.3,.7,.2,1)}
html.boom[data-knapp=rund][data-hover=fyll] .boom-btn-b::before{background:var(--surface-2)}
html.boom[data-knapp=rund][data-hover=fyll] :is(.boom-btn,.ai-try-hdr,.ai-menu-cta):is(:hover,:focus-visible)::before{transform:scale(1)}
/* Neste steg fylles i sin egen bakgrunn, og streken er en ring over fyllet (6 Okt 2026, Martin: «knappen "still et
   spørsmål" mister linjen sin på undersiden når man hover over», «fungerer fortsatt ikke» og «fortsatt er det et
   problem på andre sider»). Safari la fyllet over streken, foerst fra en ::before som vokser i eget lag, og saa fra
   bakgrunnen mens pila glir (pila faar et eget lag, og knappen klippet det med runde hjoerner). Naa klipper knappen
   ingenting, kanten er gjennomsiktig, og streken tegnes av ::before oeverst i knappen, saa ingenting kan legge seg
   over den. Sirkelen er samme fyll fra samme sted (--mx, --my, --mr fra ai.js), og radien vokser med --fyll-r. En
   kontur i stedet for kanten ble proevd samme dag; Safari la fyllet over den ogsaa. */
@property --fyll-r{syntax:'<length>';inherits:false;initial-value:-2px}
html.boom[data-knapp=rund][data-hover=fyll] .boom-btn.boom-btn-b,
html.boom[data-knapp=rund][data-hover=fyll] .boom-btn.boom-btn-b:is(:hover,:focus-visible){overflow:visible;border-color:transparent;
  background:radial-gradient(circle at var(--mx,50%) var(--my,50%),var(--surface-2) var(--fyll-r),transparent calc(var(--fyll-r) + 1px)) padding-box}
html.boom[data-knapp=rund][data-hover=fyll] .boom-btn.boom-btn-b{--fyll-r:-2px;transition:--fyll-r .5s cubic-bezier(.3,.7,.2,1)}
html.boom[data-knapp=rund][data-hover=fyll] .boom-btn.boom-btn-b:is(:hover,:focus-visible){--fyll-r:var(--mr,160px)}
html.boom[data-knapp=rund][data-hover=fyll] .boom-btn.boom-btn-b::before{inset:-1px;width:auto;height:auto;margin:0;z-index:1;
  border:1px solid color-mix(in srgb,var(--ink) 30%,transparent);border-radius:inherit;background:none;transform:none;
  transition:border-color .2s ease}
html.boom[data-knapp=rund][data-hover=fyll] .boom-btn.boom-btn-b:is(:hover,:focus-visible)::before{border-color:var(--ink-3)}
@media (prefers-reduced-motion:reduce){
  html.boom[data-knapp=rund][data-hover] :is(.boom-btn,.ai-try-hdr,.ai-menu-cta),html.boom[data-knapp=rund][data-hover] :is(.boom-btn,.ai-try-hdr,.ai-menu-cta)::before,
  html.boom[data-knapp=rund][data-hover=fyll] .boom-btn.boom-btn-b,html.boom[data-knapp=rund][data-hover=fyll] .boom-btn.boom-btn-b::before{transition:none}
}

@media (prefers-reduced-motion:reduce){
  html.boom[data-meny=node] :is(.boom-btn,.ai-try-hdr,.ai-chip,.ai-cs-b button),
  html.boom[data-meny=node] :is(.boom-btn,.ai-try-hdr,.ai-chip,.ai-cs-b button)::before,
  html.boom[data-meny=node] :is(.boom-btn,.ai-try-hdr,.ai-chip,.ai-cs-b button)::after,
  html.boom[data-meny=node] .ai-menu-cta,
  html.boom[data-meny=node] .ai-menu-cta::before,
  html.boom[data-meny=node] .ai-menu-cta::after{transition:none;animation:none}
  html.boom[data-knapp=rund] .boom-btn:is(:hover,:focus-visible)::after{transform:none}
}

/* DET LEVENDE MERKET, 28 Sep 2026 (ai.js). Vektorlogoen ligger over rasterbildet, som er
   usynlig og bare holder stoerrelsen og alt-teksten. Fargen er --ink, saa moerk visning
   trenger ingen invertering. Introens logo er stoerre enn foer (104 til 148px): Martin,
   28 Sep 2026, "logo maa vaere stoerre", med flyten inne i merket. Glorien er en flate bak logoen, ikke en filter paa den: `drop-shadow`
   gjoer hele logoen om til et bilde, og det ble uskarpt ved zoom ("det kan vi ikke ha"). */
html.boom .merke-host{position:relative;display:block;line-height:0;color:var(--ink)}
html.boom .merke-host > img{opacity:0}
html.boom .merke-host.boom-gate-mark > img{width:100%;height:auto;display:block}
html.boom .merke-svg{position:absolute;left:0;top:0;width:100%;height:100%;overflow:visible;fill:currentColor}
html.boom .merke-host.boom-gate-mark,
html.boom[data-theme="dark"] .merke-host.boom-gate-mark{
  position:absolute;width:clamp(168px,17vw,240px);filter:none;isolation:isolate;
}
html.boom .merke-host.boom-gate-mark::before{
  content:"";position:absolute;inset:-36px -48px;z-index:-1;pointer-events:none;
  background:radial-gradient(closest-side,var(--paper) 55%,transparent);
}

/* ===========================================================================
   DET VEDTATTE I UTKASTET, PAA FORSIDEN, 1 Okt 2026 (docs/overlevering-ultimat-til-boom.md).
   Martin: «oppdater boom til det vi har bestemt her nå slik at boom er oppdatert». Reglene kom
   fra ultimat.css og gjelder naa begge sidene: forsiden setter klassene i hodet (boom.py),
   utkastet /old/ultimat/ i sitt (FLAGG i ultimat.py), og ultimat.css har bare sitt eget igjen.
   Klassene er laast 3 Okt 2026 (QA 2.8, Martin: «De valgte låses, og resten tas av»); flaggene er tatt av.
     u-hode    overskriftene i heroens skrift (bare forsiden; utkastet har det alltid)
     boks      hovedordet i en boks som tegnes inn ved rulling; u-laks og u-ro gjoer den laks
     u-stor    store knapper i heroen og avslutningen, uten filmen (ikke klarert, LANSERING.md)
     u-rull    ordene i sitatet og avslutningen fylles i takt med rullingen
     u-ro      spoersmaalsstroemmen uten systemene
   =========================================================================== */

/* ---- overskriftene i heroens skrift: Archivo bred, 600, versaler ---------------------------- */
html.boom.u-hode:not(.sd) main :is(.boom-hero h1,.boom-h2,.boom-h2-big,.demo-h){
  font-weight:600;font-stretch:122%;text-transform:uppercase;letter-spacing:-.025em;max-width:none;text-wrap:balance;
}
html.boom.u-hode:not(.sd) .boom .boom-hero h1{font-size:clamp(40px,7.4vw,138px);line-height:.88}
html.boom.u-hode:not(.sd) main :is(.boom-h2,.demo-h){font-size:clamp(32px,3.9vw,56px);line-height:1.08}
html.boom.u-hode:not(.sd) main .boom-h2-big{font-size:clamp(36px,5.4vw,92px);line-height:.94}
@media (max-width:899px){html.boom.u-hode:not(.sd) main :is(.boom-h2,.demo-h){font-size:clamp(28px,8.7vw,56px)}}

/* ---- boksen: hovedordet i hver overskrift ------------------------------------------------------
   Tegnes fra venstre naar ordene passerer 70 % av skjermen paa vei opp, og viskes ut naar du ruller
   tilbake (.paa, ai.js). Begynner boksen en linje (.kant), staar den et tusjstroek ut til venstre,
   saa ordene inni staar i kanten av linja over. Uten skript og under redusert bevegelse staar den
   ferdig tegnet: det tomme utgangspunktet krever .u-tegn, som ai.js setter. Boksen er --u-merk, Sensas
   blaa fra «Book en demo» (u-laks, u-ro), og teksten i den knappens svarte i begge visninger. Laks til
   10 Okt 2026 (Martin: «gjør det samme på overskriftene», etter introen 9 Okt). */
html:is(.u-laks,.u-ro){--u-merk:var(--knapp-1);--u-merk-t:var(--knapp-t)}
html.boom.boks :is(.boom-sec .boom-h2,.boom-sec .boom-h2-big,.u-svar .b-h,.u-neste .b-h) em{
  font:inherit;font-style:normal;text-transform:inherit;letter-spacing:inherit;
  padding:.03em .16em .015em;margin:0;border-radius:.06em;
  -webkit-box-decoration-break:clone;box-decoration-break:clone;
  /* Like mye laks over versalene som under dem, og runde hjoerner oppe og nede (2 Okt 2026, Martin: «den må matche
     nede og opp»). Maalt i Archivo ved 122 % bredde: versalhoeyden er .686em, innholdsflaten gaar .88em over grunnlinja
     og .21em under. Med .03em over og .015em under staar boksen .225em over og under versalene, og fargen fyller
     hele boksen. Foer fikk toppen .12em ekstra og fargen sluttet .1em over bunnen, saa det var tre ganger saa mye
     over som under og bunnen var kantet. Ringen i Å naar .242em over versalene og ligger i kanten. */
  background:linear-gradient(var(--u-merk,var(--ink)),var(--u-merk,var(--ink))) no-repeat 0 0/100% 100%;
  color:var(--u-merk-t,var(--paper));
  transition:background-size .5s cubic-bezier(.3,.05,.6,.95) .25s,color .2s .45s;
}
html.boom.boks.u-tegn :is(.boom-sec .boom-h2,.boom-sec .boom-h2-big,.u-svar .b-h,.u-neste .b-h) em:not(.paa){
  background-size:0 100%;color:var(--ink);transition:background-size .5s cubic-bezier(.3,.05,.6,.95),color .2s;
}
/* Forskyvning, ikke negativ marg (2 Okt 2026, Martin: «markering er feil og ikke på linje»): Safari gir margen bare
   til foerste linjebit, saa en boks over to linjer stakk ut paa den ene og ikke den andre. left flytter alle bitene likt. */
html.boom.boks :is(.boom-sec .boom-h2,.boom-sec .boom-h2-big,.u-svar .b-h,.u-neste .b-h) em.kant{position:relative;left:-.16em}
/* paa forsiden holder de korte ordene i boksen sammen, saa boksen aldri deler seg over to linjer */
html.boom.boks .boom-sec :is(.boom-h2,.boom-h2-big) em{white-space:nowrap}
@media (prefers-reduced-motion:reduce){html.boom.boks em{transition:none!important}}
/* Paa sider uten boks staar ordet som foer, uten kursiv. */
html.boom:not(.boks) .boom-sec :is(.boom-h2,.boom-h2-big) em{font-style:inherit}
/* Den samme boksen i baandene paa undersidene: /it og produktsidene (6 Okt 2026, Martin: «her har vi kursiv, men paa
   "for it" har vi markering»; den sto bare i it.css, saa <em> paa produktsidene ble nettleserens kursiv). ai.js tegner
   den ved 70 % som over. */
/* .95 i linjehoeyde gir boksen (.225em over og under versalene) ikke plass, saa den la seg over linja over og under
   (Martin 3 Okt: «markering går over annen tekst»). 1.12 gir luft for boksen og ringen i Å. */
/* ogsaa overskriften oeverst paa /demo (16 Okt 2026, Martin: «a, gjør den best mulig visuell»): «Å bruke» staar i boksen */
/* og «Skaler.» i avslutningen paa forsiden (16 Okt 2026, Martin: «velg 04 H») */
html.boom.boks main .b-band:not(.u-topp) h2.b-h:has(em){line-height:1.12}
html.boom.boks :is(main .b-band:not(.u-topp) h2.b-h,main .u-topp h1.b-h,main #start h2.b-end) em{
  font:inherit;font-style:normal;text-transform:inherit;letter-spacing:inherit;
  padding:.03em .16em .015em;margin:0;border-radius:.06em;white-space:nowrap;
  -webkit-box-decoration-break:clone;box-decoration-break:clone;
  background:linear-gradient(var(--u-merk,var(--ink)),var(--u-merk,var(--ink))) no-repeat 0 0/100% 100%;
  color:var(--u-merk-t,var(--paper));
  transition:background-size .5s cubic-bezier(.3,.05,.6,.95) .25s,color .2s .45s;
}
html.boom.boks.u-tegn :is(main .b-band:not(.u-topp) h2.b-h,main .u-topp h1.b-h,main #start h2.b-end) em:not(.paa){
  background-size:0 100%;color:var(--ink);transition:background-size .5s cubic-bezier(.3,.05,.6,.95),color .2s;
}
html.boom.boks :is(main .b-band:not(.u-topp) h2.b-h,main .u-topp h1.b-h,main #start h2.b-end) em.kant{position:relative;left:-.16em}
/* En boks paa én linje trekkes ut med marg, ikke left (17 Okt 2026): left lot plassen staa igjen bak boksen, saa et
   punktum rett etter stod .16em fra den («Aprovéchelos.» paa /es, «valor.» paa /es/demo). En boks over to linjer
   (.bryt) beholder left, fordi Safari gir margen bare til foerste linjebit (se over). */
html.boom.boks :is(main .b-band:not(.u-topp) h2.b-h,main .u-topp h1.b-h,main #start h2.b-end) em.kant:not(.bryt){left:0;margin-left:-.16em}
/* bredere enn overskriften (ai.js), saa boksen deler seg i stedet for aa staa ut av skjermen */
html.boom.boks :is(.boom-sec :is(.boom-h2,.boom-h2-big),:is(main .b-band:not(.u-topp) h2.b-h,main .u-topp h1.b-h)) em.bryt{white-space:normal}
@media (prefers-reduced-motion:reduce){html.boom.boks main .b-band :is(h1,h2).b-h em{transition:none!important}}

/* ---- store knapper i heroen og avslutningen, maalt mot sanity.io (24 px tekst, 55 px hoey) -----
   Filmen bak «Book en demo» staar av til klippet er klarert; den bor i ultimat.css. */
html.boom.u-stor :is(#chat,#start) .boom-cta{gap:clamp(12px,1.4vw,20px)}
html.boom.u-stor :is(#chat,#start) .boom-btn{
  font-size:clamp(20px,2.3vw,34px);letter-spacing:-.02em;
  padding:clamp(20px,2vw,32px) clamp(34px,3.6vw,58px);
}
/* 56 px hoeye paa alle bredder, lavere enn spoerrefeltet (75 px), og like hoeye med og uten strek (8 Okt 2026,
   Martin: «a»; de vokste til 84 px paa 1440 og ble hoeyere enn chatten). */
html.boom.u-stor[data-knapp=rund] :is(#chat,#start) .boom-btn{box-sizing:border-box;height:56px;gap:14px;
  font-size:clamp(20px,1.6vw,22px);padding:0 clamp(26px,2.2vw,32px) 0 clamp(30px,2.6vw,36px)}
html.boom.u-stor[data-knapp=rund] :is(#chat,#start) .boom-btn::after{width:22px;height:14px}
/* Teksten i feltet starter der teksten i knappen starter (8 Okt 2026, Martin: «A, A, B»), saa etiketten, feltet og
   knappene har én ytre linje og teksten inni dem én indre. Samme venstre polstring som knappen over. */
html.boom.u-stor[data-knapp=rund] #chat .ai-box{padding-left:clamp(30px,2.6vw,36px)}
/* Ingen pil paa telefon (7 Okt 2026, Martin: «trenger vi de "pilene" på knappene? det gjør pillene enda lengre», og
   «A»: bort under 560 px, som foer paa PC). Polstringen blir lik paa begge sider naar pila er borte. */
@media (max-width:560px){
  html.boom[data-knapp=rund] .boom-btn::after{content:none}
  html.boom[data-knapp=rund] .boom-btn{padding-left:28px;padding-right:28px}
  html.boom.u-stor[data-knapp=rund] :is(#chat,#start) .boom-btn{padding-left:28px;padding-right:28px}
  html.boom.u-stor[data-knapp=rund] #chat .ai-box{padding-left:28px}
}
/* Pila betyr «til en annen side» (8 Okt 2026, Martin: «A»). Knapper som aapner kontaktpanelet (lenkene til
   /contact og pillen nederst til hoeyre) eller blir paa siden («Still et spørsmål», #chat), staar uten, med lik
   polstring paa begge sider. Det gjelder ogsaa alle <button>, som Send i kontaktskjemaet: en knapp sender eller
   aapner noe her, den gaar aldri til en annen side (8 Okt 2026, Martin: «send skal ikke ha pil heller»). */
html.boom[data-knapp=rund] :is(.boom-btn:is([href$="/contact"],[href^="#"]),button.boom-btn)::after{content:none}
html.boom[data-knapp=rund] .boom-btn:is([href$="/contact"],[href^="#"]){padding-left:30px;padding-right:30px}
html.boom.u-stor[data-knapp=rund] :is(#chat,#start) .boom-btn:is([href$="/contact"],[href^="#"]){padding-left:clamp(28px,2.4vw,34px);padding-right:clamp(28px,2.4vw,34px)}

/* ---- tekst som kommer fram ved rulling: ordene i Birthes sitat og i avslutningen staar svake og
   fylles ett og ett, begge veier (--o, ai.js). Uten skript og under redusert bevegelse staar alt fullt. */
html.boom.u-rull .u-w{opacity:var(--o,1);transition:opacity .18s linear}
@media (prefers-reduced-motion:reduce){html.boom.u-rull .u-w{opacity:1}}

/* ---- spoersmaalsstroemmen (#uStrom, ai.js; Martin 30 Sep og 1 Okt 2026) ------------------------
   Hvert kort er chatfeltet fra heroen. Fem kort, skrevet inn ovenfra og ned én gang og staaende etterpaa
   (ingen karusell, Martin 1 Okt 2026), og ai.js holder listens hoeyde, saa ingenting under hopper. Fra 8 Okt 2026
   (Martin: «en fin og smooth appear animasjon og så skrives spørsmålet») toner kortet inn i full bredde og glir litt
   opp, og saa skrives teksten; skallet som vokste fra pila (2 til 8 Okt) er tatt av. Teksten brekker
   linja foerst naar den er full. Kortet tar sidens egne farger ogsaa naar det staar paa et baand med egne
   tokens (utkastet): de hentes paa <html> som --u-c-* og settes tilbake. */
html.boom{
  --u-c-surface:var(--surface);--u-c-ink:var(--ink);--u-c-ink-2:var(--ink-2);--u-c-ink-3:var(--ink-3);
  --u-c-rule:var(--rule);--u-c-accent:var(--accent);--u-c-on-accent:var(--on-accent);
}
html.boom .u-strom{position:relative}
html.boom .u-s-l{display:flex;flex-direction:column;justify-content:flex-start}
html.boom .u-s-k{
  --surface:var(--u-c-surface);--ink:var(--u-c-ink);--ink-2:var(--u-c-ink-2);--ink-3:var(--u-c-ink-3);
  --rule:var(--u-c-rule);--accent:var(--u-c-accent);--on-accent:var(--u-c-on-accent);
  position:relative;isolation:isolate;flex:none;display:grid;gap:16px;margin-top:14px;padding:21px 13px 13px 27px;
  color:var(--ink);opacity:0;transform:translateY(14px);
  transition:opacity .6s ease,transform .8s cubic-bezier(.22,1,.36,1);
}
html.boom .u-s-k::before{content:"";position:absolute;inset:0;z-index:-1;border:1px solid var(--rule);border-radius:28px;background:var(--surface)}
/* Toner inn og glir litt opp, saa skrives spoersmaalet (8 Okt 2026, Martin); av skjuler kortet uten overgang */
html.boom .u-s-k.inn{opacity:1;transform:none}
html.boom .u-s-k.av{transition:none}
html.boom .u-s-k:first-child{margin-top:0}
html.boom .u-s-q{margin:0;padding-right:14px;font-size:clamp(18px,1.7vw,22px);line-height:1.4;color:var(--ink);min-height:1.4em}
html.boom .u-s-q.skriv::after{content:"";display:inline-block;width:2px;height:1.05em;margin:0 -4px 0 2px;vertical-align:-.15em;background:var(--ink);animation:u-mark .9s steps(1) infinite}
@keyframes u-mark{50%{opacity:0}}
html.boom .u-s-b{display:flex;align-items:flex-end;justify-content:space-between;gap:14px}
html.boom .u-s-sy{flex:1;min-width:0;display:flex;flex-wrap:wrap;gap:8px;margin:0;font-size:13px;color:var(--ink-2);transition:opacity .4s ease}
html.boom .u-s-sy span{display:inline-flex;align-items:center;gap:7px;padding:5px 12px;border:1px solid var(--rule);border-radius:999px}
html.boom .u-s-sy.av{opacity:0}
html.boom .u-go{flex:none;display:grid;place-items:center;width:44px;height:44px;border-radius:50%;background:var(--accent);transition:transform .25s}
html.boom .u-go svg{width:17px;height:17px;fill:none;stroke:var(--on-accent);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
html.boom .u-go.hit{transform:scale(.88)}
/* Uten pil i stroemmen (7 Okt 2026, Martin: «8A»): spennet har ingen bredde og ingen flate, kortet vokser fra en prikk */
html.boom .u-s-k .u-go{width:0;background:none}
/* ro: spoersmaalet og pila paa én linje, uten systemene (Martin 1 Okt 2026) */
html.boom.u-ro .u-s-sy{display:none}
html.boom.u-ro .u-s-k{grid-template-columns:1fr auto;align-items:center;padding-block:13px}
/* Paa forsiden staar stroemmen under heroen, i feltets bredde. */
html.boom #strom{padding-top:clamp(24px,3vw,40px)}
html.boom #strom .u-strom{max-width:860px}
@media (max-width:600px){
  html.boom .u-s-k{padding-inline:21px 11px}
  html.boom .u-s-sy{gap:4px 14px;font-size:12px}
  html.boom .u-s-sy span{padding:0;border:0}
}
@media (prefers-reduced-motion:reduce){
  html.boom .u-s-k,html.boom .u-go{transition:none}
  html.boom .u-s-q.skriv::after{animation:none}
}
/* Stroemmen staar bare der den er valgt (u-ro, satt i hodet); uten skript har forsiden sin gamle form. */
html.boom:not(.u-ro) #strom{display:none}
@media (prefers-reduced-motion:reduce){html.boom:not(.sd) .ai-hdr.is-glid :is(.ai-ask,.ai-try-hdr){transition:none !important}}

/* OMTALE SOM MOSAIKK, 2 Okt 2026 (Martin: «lag denne litt mer spennende ... hjoernene paa hver ytterst
   sak avrundet ... litt mer luft mellom tekst og bilder»). De seks kortene er én flate med smale fuger
   der den levende flaten skinner gjennom, og bare de ytre hjoernene er runde, med baandenes radius.
   Bildet trekker seg sakte naermere ved hover, og teksten fylles graatt fra der pekeren kommer inn,
   som «Se produktene» (ai.js gir .nw-t --mx, --my og --mr). Siste rad er alltid full (6 kort i 3, 2
   og 1 spalte), saa de runde hjoernene treffer riktig kort i alle bredder. */
html.boom .nw{gap:4px;border-radius:var(--r-ark);overflow:hidden;isolation:isolate}
html.boom .nw-card,html.boom .nw-card:hover{border:0;border-radius:0;background:var(--surface);transition:none}
/* Logoflisen: site.css leser manglende tema som moerkt og inverterte merket til hvitt paa lys flate. */
html.boom:not([data-theme="dark"]) .nw-mark img{filter:none}
html.boom .nw-card > img,html.boom .nw-mark{transition:transform 1.1s cubic-bezier(.2,.7,.2,1)}
html.boom .nw-card:is(:hover,:focus-visible) > :is(img,.nw-mark){transform:scale(1.05)}
html.boom .nw-t{
  position:relative;z-index:1;flex:1;overflow:hidden;background:var(--surface);
  padding:clamp(26px,2.6vw,38px) clamp(22px,2.2vw,32px) clamp(30px,3vw,44px);
}
html.boom .nw-t::before{
  content:"";position:absolute;z-index:-1;left:var(--mx,50%);top:var(--my,0);
  width:calc(var(--mr,600px) * 2);height:calc(var(--mr,600px) * 2);margin:calc(var(--mr,600px) * -1) 0 0 calc(var(--mr,600px) * -1);
  border-radius:50%;background:var(--surface-2);transform:scale(0);transition:transform .55s cubic-bezier(.3,.7,.2,1);
}
html.boom .nw-card:is(:hover,:focus-visible) .nw-t::before{transform:scale(1)}
html.boom .nw-t > *{margin-inline:0}
html.boom .nw-t .nw-who{margin-top:0;color:var(--ink-3)}
html.boom .nw-t h3{margin-top:clamp(12px,1.2vw,18px);font-size:clamp(21px,1.9vw,28px);line-height:1.12;text-wrap:balance}
html.boom .nw-t .nw-us{margin-top:clamp(12px,1.2vw,16px);font-size:15px;line-height:1.5;text-wrap:pretty}
@media (prefers-reduced-motion:reduce){
  html.boom .nw-card > img,html.boom .nw-mark,html.boom .nw-t::before{transition:none}
  html.boom .nw-card:is(:hover,:focus-visible) > :is(img,.nw-mark){transform:none}
}

/* KONTAKT PAA LINJE, 2 Okt 2026 (convert.py skjemaoppsett, site.js kontakt). Martin, med et bilde av
   /about#kontakt: «denne må ordnes slik at den er på linje og ser bra ut.» Overskrift og ingress staar
   over begge spaltene, saa «Hvem vil dere snakke med?» og «Fornavn» starter paa samme linje i samme
   skrift, og moetetidene staar under ansiktene: hvem, saa naar, saa hva. Feltene er avrundet som
   det andre som kan trykkes paa, og naar ingen fyll paa siden. */
html.boom .kt-hode{max-width:760px}
html.boom .kt-hode h2{margin:0}
html.boom .kt-hode .lead{margin:14px 0 0}
html.boom .contact-grid{margin-top:clamp(32px,3.6vw,48px)}
/* Skjemaet og bunnen paa én skjerm, 5 Okt 2026. Martin, helt nede paa /contact paa MacBook: «ser ikke
   overskrift». Overskriften over begge spaltene la 140 px oppaa skjemaet, og alt trengte 975 px av 834.
   Fra 821 px staar overskriften i venstre spalte over personene, skjemaet starter oeverst til hoeyre,
   og luften over og under seksjonen er mindre. Panelet (.ktp) er én spalte og beroeres ikke. */
@media (min-width:821px){
/* Martin samme dag, paa /about: «ser bunnen av bildene til hvert medlem over». Som avslutningen paa forsiden fyller
   seksjonen skjermen over bunnen (173 til 204 px), saa helt nede vises ingenting fra seksjonen over. */
html.boom main section:has(>.wrap>.kt-hode){padding-block:clamp(40px,4vw,64px) clamp(24px,2.2vw,32px);min-height:calc(100svh - 170px);display:flex;flex-direction:column;justify-content:center}
html.boom main section>.wrap:has(>.kt-hode){width:100%}
html.boom main .wrap:has(>.kt-hode+.contact-grid){display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);column-gap:clamp(28px,5vw,72px);align-items:start}
html.boom main .wrap>.kt-hode+.contact-grid{display:contents}
html.boom main .wrap>.kt-hode{grid-column:1;grid-row:1}
html.boom main .wrap>.kt-hode+.contact-grid>div:first-child{grid-column:1;grid-row:2;margin-top:clamp(20px,1.8vw,28px)}
html.boom main .wrap>.kt-hode+.contact-grid>form{grid-column:2;grid-row:1/3}
}
/* KONTAKTSKJEMAET HELT NEDE, tre forslag bak ?kontakt= (5 Okt 2026, Martin om oppsettet over: «tja, ikke super nice»,
   og alle fire: tomt paa LG, oppsettet, personene og luften). Valgsiden er tools/valg/kontakt.html. Felles: én avstand
   (--ktg) mellom alt, som vokser med skjermhoeyden, og meldingsfeltet vokser med den. Tas av naar Martin har valgt.
   a: overskriften stor over begge spaltene, som avslutningen paa forsiden; personene som i dag.
   b: overskriften stor i venstre spalte, personene i to kolonner med ansikt, omraade og navn; bunn mot bunn.
   c: som b, men personene er ord med et lite ansikt, og navnet kommer fram paa den som er valgt. */
@media (min-width:821px){
html.boom[data-kontakt] main .wrap:has(>.kt-hode+.contact-grid){--ktg:clamp(20px,3.4svh,56px)}
/* Paa hoeye skjermer vokser feltene, merkelappene og ansiktene litt, saa skjemaet ikke staar lite i en stor flate. */
html.boom[data-kontakt] main .wrap:has(>.kt-hode+.contact-grid) form.contact input{min-height:clamp(54px,5svh,72px)}
html.boom[data-kontakt] main .wrap:has(>.kt-hode+.contact-grid) :is(.kv-k,form.contact label,.kt-not,.kv-n,.kv-t){font-size:clamp(15px,1.26svh,18px)}
html.boom[data-kontakt] main .wrap:has(>.kt-hode+.contact-grid) .lead{font-size:clamp(19px,1.7svh,24px)}
html.boom[data-kontakt=a] main .wrap:has(>.kt-hode+.contact-grid){grid-template-rows:auto auto 1fr}
html.boom[data-kontakt=a] main .wrap:has(>.kt-hode+.contact-grid)>.kt-hode{display:contents}
html.boom[data-kontakt=a] main .wrap:has(>.kt-hode+.contact-grid)>.kt-hode h2{grid-column:1/-1;grid-row:1;font-size:clamp(44px,min(9vw,100svh - 780px),130px);line-height:.97;margin:0 0 var(--ktg)}
html.boom[data-kontakt=a] main .wrap:has(>.kt-hode+.contact-grid)>.kt-hode .lead{grid-column:1;grid-row:2;margin:0}
html.boom[data-kontakt=a] main .wrap:has(>.kt-hode+.contact-grid)>.contact-grid>div:first-child{grid-column:1;grid-row:3;margin-top:var(--ktg)}
html.boom[data-kontakt=a] main .wrap:has(>.kt-hode+.contact-grid)>.contact-grid>form{grid-column:2;grid-row:2/4}
html.boom[data-kontakt=a] main .wrap:has(>.kt-hode+.contact-grid) textarea{min-height:clamp(96px,100svh - 740px,340px)}
:is(html.boom[data-kontakt=b] main .wrap:has(>.kt-hode+.contact-grid),html.boom[data-kontakt=c] main .wrap:has(>.kt-hode+.contact-grid)){grid-template-rows:auto 1fr}
:is(html.boom[data-kontakt=b] main .wrap:has(>.kt-hode+.contact-grid),html.boom[data-kontakt=c] main .wrap:has(>.kt-hode+.contact-grid))>.kt-hode{max-width:none}
:is(html.boom[data-kontakt=b] main .wrap:has(>.kt-hode+.contact-grid),html.boom[data-kontakt=c] main .wrap:has(>.kt-hode+.contact-grid))>.kt-hode h2{font-size:clamp(48px,min(6.6vw,100svh - 690px),104px);line-height:.97;text-wrap:balance}
:is(html.boom[data-kontakt=b] main .wrap:has(>.kt-hode+.contact-grid),html.boom[data-kontakt=c] main .wrap:has(>.kt-hode+.contact-grid))>.kt-hode .lead{margin-top:var(--ktg)}
:is(html.boom[data-kontakt=b] main .wrap:has(>.kt-hode+.contact-grid),html.boom[data-kontakt=c] main .wrap:has(>.kt-hode+.contact-grid))>.contact-grid>div:first-child{align-self:end;margin-top:var(--ktg)}
:is(html.boom[data-kontakt=b] main .wrap:has(>.kt-hode+.contact-grid),html.boom[data-kontakt=c] main .wrap:has(>.kt-hode+.contact-grid)) textarea{min-height:clamp(120px,100svh - 690px,420px)}
:is(html.boom[data-kontakt=b] main .wrap:has(>.kt-hode+.contact-grid),html.boom[data-kontakt=c] main .wrap:has(>.kt-hode+.contact-grid)) .kv-r{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
html.boom[data-kontakt=b] main .wrap:has(>.kt-hode+.contact-grid) .kv-g{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 20px}
html.boom[data-kontakt=b] main .wrap:has(>.kt-hode+.contact-grid) .kv-p{display:grid;grid-template-columns:48px minmax(0,1fr);column-gap:12px;align-content:center;margin:-6px;padding:6px}
html.boom[data-kontakt=b] main .wrap:has(>.kt-hode+.contact-grid) .kv-p img{width:48px;height:48px;margin:0;grid-row:1/3}
html.boom[data-kontakt=b] main .wrap:has(>.kt-hode+.contact-grid) .kv-t,html.boom[data-kontakt=b] main .wrap:has(>.kt-hode+.contact-grid) .kv-n{grid-column:2;margin:0}
html.boom[data-kontakt=c] main .wrap:has(>.kt-hode+.contact-grid) .kv-g{display:flex;flex-wrap:wrap;gap:6px 20px}
html.boom[data-kontakt=c] main .wrap:has(>.kt-hode+.contact-grid) .kv-p{flex-direction:row;align-items:center;gap:10px;margin:-6px;padding:6px 10px 6px 6px;border-radius:999px}
html.boom[data-kontakt=c] main .wrap:has(>.kt-hode+.contact-grid) .kv-p img{width:36px;height:36px;margin:0;outline-offset:2px}
html.boom[data-kontakt=c] main .wrap:has(>.kt-hode+.contact-grid) .kv-t{font-size:15px;font-weight:400;color:var(--ink)}
html.boom[data-kontakt=c] main .wrap:has(>.kt-hode+.contact-grid) .kv-p:not([aria-pressed=true]) .kv-n{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
html.boom[data-kontakt=c] main .wrap:has(>.kt-hode+.contact-grid) .kv-p[aria-pressed=true] .kv-n{margin:0;color:var(--ink-2)}
}
html.boom .kv{margin-top:0}
html.boom .kv-k,html.boom form.contact label{font-size:15px;line-height:1.4;color:var(--ink-2);margin:0 0 8px}
html.boom .kv-k{margin-bottom:18px}
html.boom form.contact{gap:18px}
html.boom form.contact input,html.boom form.contact textarea{
  border-radius:var(--r-inne);background:var(--surface);border:1px solid var(--felt);color:var(--ink);
  transition:border-color .15s ease,box-shadow .15s ease;
}
html.boom form.contact input:focus,html.boom form.contact textarea:focus{
  outline:none;border-color:var(--ink);box-shadow:0 0 0 1px var(--ink);
}
/* et felt med feil faar dobbel kant og meldingen under seg (WCAG 3.3.1, funn 8); fargen alene sier ingenting */
html.boom form.contact [aria-invalid="true"]{border-color:var(--ink);box-shadow:0 0 0 1px var(--ink)}
html.boom form.contact textarea{min-height:160px}
/* EN STOR SEND-KNAPP (6 Okt 2026, pakke A, Martin: «b»): hele bredden i skjemaet og panelet, midtstilt. Statusen staar
   under. Tekstforslagene over meldingen (.ktf) er tatt ut av site.js samme dag. */
html.boom form.contact .actions{flex-direction:column;align-items:stretch}
html.boom form.contact .kt-send{width:100%;justify-content:center}
html.boom button.boom-btn{font-family:inherit}
html.boom .mb{margin-top:clamp(32px,3.4vw,44px)}
html.boom .mb-k{font-size:15px}
html.boom .mb-s{font-size:15px}
html.boom .kt-not{font-size:15px;line-height:1.5;color:var(--ink-2);margin:0}
html.boom form.contact .status{font-size:15px}
/* KONTAKTPANELET, 2 Okt 2026 (site.js). Martin: «uten å gå ut fra dette viewet eller åpne andre
   faner.» Lenker til /contact aapner skjemaet i en flytende oey til hoeyre, i familie med toppmenyen:
   --surface, avrundet, myk skygge. Fra 1500 px flytter siden seg til venstre saa ingenting ligger
   under panelet (smalere fikk toppmenyen ikke plass); smalere ligger panelet over hoeyre del. Det er ikke modalt: siden kan rulles og markeres. */
html.boom .ktp[hidden],html.boom .ktp-pille[hidden]{display:none}
html.boom.samtykke-aapen .ktp-pille{display:none}
/* Pillen dekker aldri innhold (break-it funn 12, 3 Okt 2026): den er borte mens telefonmenyen er aapen, og siden faar
   luft nederst like hoey som pillen (--pille-h settes av site.js naar pillen vises). */
html.boom body.ai-locked .ktp-pille{display:none}
/* Pillen er en .boom-btn fra 6 Okt 2026 (pakke A), og knappens display er sterkere enn de tre linjene over */
html.boom[data-knapp][data-hover] .boom-btn.ktp-pille:is([hidden],html.samtykke-aapen *,body.ai-locked *,html:is(.is-kino,.is-gated,.is-flying,.is-dive,.is-land,.is-opening,.is-pulling) *){display:none}
html.boom.har-pille body{padding-bottom:var(--pille-h,72px)}
html.boom .ktp{
  position:fixed;top:12px;right:12px;bottom:12px;z-index:90;width:min(500px,calc(100vw - 24px));
  overflow-y:auto;overscroll-behavior:contain;padding:12px clamp(20px,2.6vw,32px) 32px;
  background:var(--surface);border:1px solid var(--rule-soft);border-radius:var(--r-panel);
  box-shadow:0 1px 2px var(--shadow),0 24px 60px -24px var(--shadow);
}
html.boom .ktp.ktp-inn-ny{animation:ktp-inn .32s cubic-bezier(.2,.8,.2,1) both}
@keyframes ktp-inn{from{opacity:0;transform:translateX(24px)}to{opacity:1;transform:none}}
html.boom .ktp-topp{position:sticky;top:-12px;z-index:1;display:flex;justify-content:flex-end;margin:0 -8px 4px;padding:8px 0;background:var(--surface)}
html.boom .ktp-lukk{
  appearance:none;background:none;border:1px solid var(--rule);border-radius:999px;padding:8px 16px;
  font:inherit;font-size:15px;color:var(--ink);cursor:pointer;
}
html.boom .ktp-lukk:hover{border-color:var(--ink)}
html.boom .ktp-lukk:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
/* Arket har uttrykket fra bunnen av /contact (8 Okt 2026, Martin: «Smalt, men samme uttrykk»): overskriften og linja i
   samme stoerrelse som der, mer luft, og arket er bare saa hoeyt som innholdet, uten tomrommet under Send. */
@media (min-width:561px){html.boom .ktp{bottom:auto;max-height:calc(100dvh - 24px);padding-bottom:36px}}
html.boom .ktp .kt-hode h2{font-size:clamp(34px,3.2vw,43px);line-height:1.05;font-weight:400;letter-spacing:-.035em;margin:4px 0 0}
html.boom .ktp .kt-hode h2:focus{outline:none}
html.boom .ktp .kt-hode .lead{font-size:19px;line-height:1.45;color:var(--ink-2)}
html.boom .ktp .contact-grid{grid-template-columns:1fr;gap:32px;margin-top:36px}
html.boom .ktp .kv-g{gap:18px 12px}
html.boom .ktp .kv-p img{width:60px;height:60px}
html.boom .ktp .mb{margin-top:28px}
html.boom .ktp form.contact .row{grid-template-columns:1fr 1fr}
/* «Legg til firma eller en melding» (8 Okt 2026, Martin: «det skal virke riktig å bare skrive navn og jobbepost og så
   trykk send»): en stille linje med V-en fra «Flere spørsmål», ikke en knapp, saa Navn, Jobb-e-post og Send er hele
   skjemaet til noen vil skrive mer. Aapen viser den Firma og Melding under seg. */
html.boom form.contact .kt-mer>summary{display:inline-flex;align-items:center;gap:8px;min-height:24px;padding:2px 0;
  list-style:none;cursor:pointer;color:var(--ink-2);font-size:15px}
html.boom form.contact .kt-mer>summary::-webkit-details-marker{display:none}
html.boom form.contact .kt-mer>summary:hover{color:var(--ink)}
html.boom form.contact .kt-mer>summary:focus-visible{outline:2px solid var(--focus);outline-offset:3px;border-radius:2px}
html.boom form.contact .kt-mer>summary svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:1.5;
  stroke-linecap:round;stroke-linejoin:round;transition:transform .45s cubic-bezier(.3,.7,.2,1)}
html.boom form.contact .kt-mer[open]>summary svg{transform:rotate(180deg)}
html.boom form.contact .kt-mer-inn{display:grid;gap:16px;margin-top:16px}
html.boom form.contact .kt-mer-inn textarea{min-height:120px}
@media (prefers-reduced-motion:reduce){html.boom form.contact .kt-mer>summary svg{transition:none}}
/* Siden flytter seg for panelet bare naar toppen faar sitt oppsett fra 1200 px ved siden av det: 1200 + 524 = 1724 px
   (12 Okt 2026, Martin: «"om oss" forsvinner bak blå knapp»). Grensen var 1500 fra 2 Okt, foer feltet og demoen
   fikk 230 px hver; da ble siden 976 px bred mens toppen fortsatt tegnet rutenettet for 1200 px. Smalere ligger
   panelet over siden. */
@media (min-width:1724px){html.boom.ktp-aapen body{margin-right:524px}}
@media (max-width:560px){
  html.boom .ktp{top:0;right:0;bottom:0;width:100vw;border-radius:0;border:0}
  html.boom .ktp form.contact .row{grid-template-columns:1fr}
}
/* PILLEN ER «BOOK EN DEMO» (6 Okt 2026, pakke A, nr. 10): handlingen, blaa med fyll som knappene ellers (boom-btn
   boom-btn-a fra site.js), men mindre enn sidens store knapp og fast nede til hoeyre. Reglene under gjelder ellers. */
html.boom .ktp-pille{
  position:fixed;right:16px;bottom:16px;z-index:89;appearance:none;cursor:pointer;
  padding:12px 20px;border-radius:999px;border:1px solid var(--rule-soft);background:var(--surface);
  font:inherit;font-size:15px;color:var(--ink);box-shadow:0 1px 2px var(--shadow),0 16px 40px -20px var(--shadow);
}
html.boom[data-knapp][data-hover] .boom-btn.ktp-pille{position:fixed;height:52px;padding:0 26px;font-size:17px;gap:12px;
  transition:transform .3s ease,opacity .3s ease,color .2s ease .18s}
html.boom[data-knapp][data-hover] .boom-btn.ktp-pille:is(:hover,:focus-visible){transition:transform .3s ease,opacity .3s ease,color .2s ease .08s}
@media (max-width:560px){html.boom[data-knapp][data-hover] .boom-btn.ktp-pille{height:48px;font-size:16px;padding:0 22px}}
html.boom .ktp-pille-n{font-family:var(--mono)}
/* Pillen glir bort mens du ruller nedover, og kommer tilbake naar du ruller opp eller stopper (3 Okt 2026, Martin: «velg b»).
   Ikke naar den har fokus. site.js setter klassen. */
html.boom .ktp-pille{transition:transform .3s ease,opacity .3s ease}
html.boom .ktp-pille:is(.ktp-pille-bort,.ktp-pille-vik):not(:focus-visible){transform:translateY(calc(100% + 24px));opacity:0;pointer-events:none}
@media (prefers-reduced-motion:reduce){html.boom .ktp-pille,html.boom[data-knapp][data-hover] .boom-btn.ktp-pille,html.boom[data-knapp][data-hover] .boom-btn.ktp-pille:is(:hover,:focus-visible){transition:none}}
html.boom .ktp-pille:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
/* Send til sjefen (5 Okt 2026, idé 2): én linje under meldingen, ord og pil, til siden som kan sendes videre (/for-oss). */
html.boom .ktp-side{margin:0;font-size:15px;line-height:1.4}
html.boom .ktp-side[hidden]{display:none}
html.boom .ktp-side a{display:inline-flex;align-items:center;gap:10px;color:var(--ink);text-decoration:none}
html.boom .ktp-side a i{font-style:normal;transition:transform .3s}
html.boom .ktp-side a:hover i{transform:translateX(5px)}
@media (prefers-reduced-motion:reduce){html.boom .ktp-side a i{transition:none}}
@media (prefers-reduced-motion:reduce){
  html.boom .ktp.ktp-inn-ny{animation:none}
  html.boom form.contact input,html.boom form.contact textarea{transition:none}
}

/* OEYA VOKSER, chatfeltet i toppmenyen (standard 3 Okt 2026, Martin: «velg a»; forslaget kom samme dag, Martin: «hva er en kulere og unik
   måte å skalere den på? jeg er veldig åpen for nytt»). Naar feltet aapnes, toner menyordene, verktoeyene og
   knappen ut, og panelet legger seg over hele oeya med logoen staaende. Oeya vokser nedover med en fjaer
   (clip-path fra oeyas hoeyde), forslagene og svaret staar inne i den samme flaten, og teksten faar hele bredden.
   Fra 7 Okt 2026 ogsaa under 1100 px (Martin: «skulle heller hele toppmenyen blitt til en chatboks?», og «A»): der
   toner logoen ogsaa ut, saa feltet faar hele oeya og «Sensa» ikke staar to ganger. Svaret staar inne i oeya, ikke i en
   egen boks over heroen. */
@media all{
  html.boom .ai-hdr > :not(.ai-brand):not(.ai-ask){transition:opacity .22s ease,filter .22s ease}
  html.boom .ai-hdr.is-ask > :not(.ai-brand):not(.ai-ask){opacity:0;filter:blur(3px);pointer-events:none}
  html.boom .ai-hdr.is-ask > .ai-ask{position:static}
  html.boom .ai-hdr.is-ask > .ai-brand{position:relative;z-index:42}
  html.boom[data-meny] .ai-hdr .ai-ask-p{
    top:0;left:0;right:0;width:auto;padding:8px;
    background:var(--surface);border-radius:var(--r-panel);box-shadow:var(--fluid-lift);
    animation:oy-inn .6s cubic-bezier(.2,.8,.2,1) both;
    animation-timing-function:linear(0,.009,.035 2.1%,.141 4.4%,.723 12.9%,.938 16.7%,1.017 19.4%,1.067,1.099 24.3%,1.108 26%,1.1,1.077 30.6%,1.019 35.7%,.998 39%,.99 41.9%,.991 47.6%,1.001 57%,1)}
  html.boom[data-meny] .ai-hdr .ai-ask-f{
    width:100%;max-width:none;margin:0;min-height:39px;padding:0 0 0 120px;
    background:none;border:0;border-radius:0;box-shadow:none}
  html.boom[data-meny] .ai-hdr .ai-ask-f textarea{font-size:16px}
  html.boom .ai-hdr .ai-ask-l,
  html.boom .ai-hdr .ai-ask-a{
    margin:6px 0 0;background:none;border:0;border-top:1px solid var(--rule-soft);border-radius:0;box-shadow:none}
  html.boom .ai-hdr .ai-ask-a{padding:18px 16px 12px;border-top:0}
}
/* Under 1100 px (se over): logoen toner ogsaa ut, og feltet starter ved kanten av oeya. */
@media (max-width:1099px){
  html.boom .ai-hdr > .ai-brand{transition:opacity .22s ease,filter .22s ease}
  html.boom .ai-hdr.is-ask > .ai-brand{opacity:0;filter:blur(3px);pointer-events:none}
  html.boom[data-meny] .ai-hdr .ai-ask-f{padding-left:14px}
  html.boom[data-meny] .ai-hdr .ai-ask-p{max-height:calc(100dvh - 24px);overflow-y:auto}
}
@keyframes oy-inn{
  from{clip-path:inset(0 0 calc(100% - 55px) 0 round 28px)}
  to{clip-path:inset(0 0 0 0 round 28px)}
}
@media (prefers-reduced-motion:reduce){
  html.boom .ai-hdr .ai-ask-p{animation:none!important}
  html.boom .ai-hdr > *{transition:none!important;filter:none!important}
}

/* ===========================================================================
   TELEFONMENYEN, 8 Okt 2026, tredje runde. Foerste runde (Martin: «beauty-fie») blandet 16 og 30 px; andre runde
   («uklart og for store fonts») la Resultater og Filmer under «Om oss». Naa (Martin: «om oss inneholder ikke
   resultater», «filmer ser ut som er under om oss», «husk at de fleste holder med 1 hånd, ofte høyre, så tommel må
   rekke»): samme inndeling som toppmenyen paa PC, to spalter der hele ruta er lenken (44 px, tommelen treffer hvor
   som helst i den), listen staar nederst naar den faar plass, og demoen og et kryss staar fast i bunnen.
   Raden du trykker paa, faar en flate mens du holder; understrek bare der det finnes en peker. Spraak og visning er
   brytere der valget er fylt med blekket. Undertekstene staar i markupen for soeket, men vises ikke.
   =========================================================================== */
html.boom .ai-menu{overflow:hidden;padding-bottom:0}
html.boom .ai-menu-in{display:flex;flex-direction:column;height:100%;outline:0}
/* Spoersmaalsfeltet i toppen viker mens menyen er aapen: toppen er bare logoen og krysset */
html.boom body:has(#aiMenu:not([hidden])) #aiAsk{visibility:hidden}
html.boom .ai-menu-liste{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow-y:auto;
  margin:0 -12px;padding:16px 0 8px;
  -webkit-mask-image:linear-gradient(to bottom,transparent,#000 16px,#000 calc(100% - 12px),transparent);
  mask-image:linear-gradient(to bottom,transparent,#000 16px,#000 calc(100% - 12px),transparent)}
html.boom .ai-menu-liste > :first-child{margin-top:auto}
html.boom .ai-menu-g{display:grid;grid-template-columns:1fr 1fr;column-gap:8px;margin:0 0 18px}
html.boom .ai-menu-g > .ai-menu-k{grid-column:1/-1}
html.boom .ai-menu-in .ai-menu-k{margin:0;padding:0 12px 4px;font-size:14px;font-weight:400;letter-spacing:0;
  text-transform:none;color:var(--ink-3)}
html.boom .ai-menu-g > a{display:flex;align-items:center;min-height:44px;margin:0;padding:0 12px;border:0;border-radius:var(--r-inne);
  font-family:var(--sans);font-size:17px;line-height:1.3;letter-spacing:0;color:var(--ink);text-decoration:none;
  -webkit-tap-highlight-color:transparent}
html.boom .ai-menu-g > a > span{display:none}
html.boom .ai-menu-g > a:active{background:var(--surface-2)}
html.boom .ai-menu-g > a:focus-visible{outline:2px solid var(--ink);outline-offset:-2px}
@media (hover:hover){html.boom .ai-menu-g > a:hover{background:var(--surface-2)}}
/* Siden du er paa: noden foran ordet, som i toppen og nedtrekket, og ordet i halvfet. Den staar inne i ruta,
   saa rullingen ikke klipper den (8 Okt 2026, Martin: «a») */
html.boom .ai-menu-g > a[aria-current]{font-weight:600}
html.boom .ai-menu-g > a[aria-current]{position:relative}
html.boom[data-meny=node] .ai-menu-g > a[aria-current]::before{content:"";position:absolute;left:1px;top:50%;width:6px;height:6px;
  margin-top:-3px;border-radius:50%;background:var(--ink)}
html.boom .ai-menu-rad{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0 0 8px;padding:0 12px}
html.boom .ai-menu-rad .ai-menu-k{padding:0}
html.boom .ai-menu-rad .ai-menu-lang{display:inline-flex;flex-direction:row;gap:2px;padding:3px;border-radius:999px;
  background:var(--surface-2);font-size:15px}
html.boom .ai-menu-rad .ai-menu-lang > *{display:flex;align-items:center;min-height:38px;padding:0 14px;margin:0;border:0;
  border-radius:999px;background:none;font:inherit;line-height:1;color:var(--ink-2);text-decoration:none}
html.boom .ai-menu-rad .ai-menu-lang :is([aria-current],[aria-pressed="true"]){background:var(--ink);color:var(--surface);font-weight:400;cursor:default}
html.boom .ai-menu-rad .ai-menu-lang > :focus-visible{outline:2px solid var(--ink);outline-offset:2px}
@media (hover:hover){html.boom .ai-menu-rad .ai-menu-lang > :is(a,[aria-pressed="false"]):hover{color:var(--ink)}}
/* Bunnen: demoen og krysset der hoeyre tommel naar, over hjemstreken */
html.boom .ai-menu-bunn{flex:none;display:flex;align-items:center;gap:10px;padding:12px 0 max(16px,env(safe-area-inset-bottom))}
html.boom .ai-menu-bunn > .ai-menu-cta{flex:1 1 auto;margin:0;min-height:52px;padding:0 20px;
  display:flex;align-items:center;justify-content:center;font-size:16px}
html.boom .ai-menu-lukk{position:relative;flex:none;width:52px;height:52px;border:0;border-radius:50%;padding:0;
  background:var(--surface-2);cursor:pointer;-webkit-tap-highlight-color:transparent}
html.boom .ai-menu-lukk::before,html.boom .ai-menu-lukk::after{content:"";position:absolute;left:50%;top:50%;width:18px;
  height:2px;margin:-1px 0 0 -9px;border-radius:1px;background:var(--ink);transform:rotate(45deg)}
html.boom .ai-menu-lukk::after{transform:rotate(-45deg)}
html.boom .ai-menu-lukk:focus-visible{outline:2px solid var(--ink);outline-offset:2px}

/* MENYKNAPPEN (8 Okt 2026, Martin: «bare tre streker»): tre streker uten ring, og de blir et kryss naar menyen er
   aapen; den midterste toner ut. Ringen var en svak graa strek som saa ut som en feil, og krysset nederst har ingen.
   site.css har to streker for Visuell profil (/ai), som er frosset. */
html.boom .ai-burger{border:0;gap:4px}
/* 2 px streker med 6 px mellom toppene, saa de faller paa hele piksler; med 1,5 px saa den midterste tykkere ut */
html.boom .ai-burger span{width:18px;height:2px}
html.boom .ai-burger[aria-expanded="true"] span:first-child{transform:translateY(6px) rotate(45deg)}
html.boom .ai-burger[aria-expanded="true"] span:nth-child(2){opacity:0}
html.boom .ai-burger[aria-expanded="true"] span:last-child{transform:translateY(-6px) rotate(-45deg)}

/* ?ytelse, 14 Okt 2026: maalingen nede til venstre for testere (sensaYtelse i ai.js). Bare med parameteren. */
html.boom .ytelse-maal{position:fixed;left:12px;bottom:12px;z-index:2147483000;max-width:min(560px,calc(100vw - 24px));
  padding:10px 12px;border-radius:10px;background:var(--surface);color:var(--ink);box-shadow:var(--fluid-lift);
  font:13px/1.45 "Azeret Mono",ui-monospace,monospace;white-space:pre-wrap;pointer-events:none}
