/* Marikollen Deli — V2: horisontal fortelling.
   Mobil først: kapitlene stables vertikalt og fungerer uten JS.
   v2.js setter .is-rail på .j-viewport på brede skjermer uten
   prefers-reduced-motion — først da blir sporet en sideveis reise
   (kinetic-site-framework, references/horizontal-rail.md). */

/* Alle Gaglio-vekter (inkl. Medium, brukt til de mindre titlene under)
   lastes sentralt av tokens.css — ingen egne font-imports her lenger.
   --font-mega/--font-nav trenger heller ingen lokal v2-body-overstyring
   nå: begge er Gaglio (Bold/SemiBold) globalt, samme «kun 1 font i
   header»-idé denne blokka opprinnelig fantes for å oppnå. */
.v2-body {
  background: var(--ink-deep);
  color: var(--on-dark);
}

/* Vekt 400 overalt der Gaglio-Bold brukes — se blokka over. Menylabelen
   bor i ::before/::after (anchoren selv er transparent), så vekten må
   settes på pseudoene, ikke på a-en. */
.v2-body .j-mega,
.v2-body .j-title,
.v2-body .j-product-body h3,
.v2-body .j-news-item h3,
.v2-body .site-nav a::before,
.v2-body .site-nav a::after { font-weight: 400; }

/* De mindre titlene ett hakk lettere enn megaen: Gaglio Medium.
   Megaen og pusterom-ordene beholder Bold via --font-mega. */
.v2-body .j-title,
.v2-body .j-product-body h3,
.v2-body .j-news-item h3 { font-family: "Gaglio-Medium", var(--font-mega); }
.v2-body .j-title .script { font-family: "Gaglio-Medium", var(--font-mega); }

/* Header flyter transparent over reisen hele veien */
.v2-body .site-header {
  position: fixed;
  left: 0; right: 0;
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-bottom-color: transparent;
}
.v2-body .site-nav a::before { color: var(--on-dark); }
.v2-body .account-link,
.v2-body .logout-link { color: var(--on-dark); }
.v2-body .cart-btn { border-color: var(--line-dark); background: transparent; color: var(--on-dark); }
.v2-body .brand-patch img { filter: drop-shadow(0 18px 34px rgba(0, 0, 0, 0.45)); }
.v2-body .site-footer { margin-top: 0; }

/* ---------- Sporet ---------- */

.j-viewport { position: relative; }

/* Global fargefade (v2.js/om.js tintJourney): mørkt lag, kun opacity
   animeres — background-color-animasjon re-rastrerer hele flaten hver
   scroll-frame og var det som gjorde reisen hakkete. */
.j-tint {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--ink-deep);
  opacity: 0;
  pointer-events: none;
  will-change: opacity;
}

.j-track { display: flex; flex-direction: column; }

.j-panel {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  gap: clamp(24px, 4vw, 72px);
  padding: clamp(90px, 14vh, 140px) var(--gutter);
  overflow: hidden;
  /* Eksplisitt bakgrunn, ikke bare arvet gjennomsiktighet: .j-track får
     transform fra GSAP (den horisontale scroll-x-en), og det lager en
     ny stacking-context. Blend-mode-barn (.j-map) blander seg da mot
     HVA SOM ER MALT INNENFOR den konteksten, ikke sidens body-bakgrunn
     — uten en reell malt flate her ville de blandet seg mot ingenting
     (så det svarte i kartet ble stående synlig i stedet for å bli
     usynlig). Samme farge som body, så ingen visuell endring ellers. */
  background: var(--ink-deep);
}

/* Rail-modus: ett spor, max-content, ingen klipp av panelbredder */
.j-viewport.is-rail { height: 100svh; overflow: hidden; }
.j-viewport.is-rail .j-track {
  flex-direction: row;
  width: max-content;
  height: 100svh;
  will-change: transform;
  /* Luft mellom seksjonene: den dypgrønne bunnen skimtes i mellomrommene,
     så hvert kapittel leses som et eget kort man flyter forbi — ikke én
     sammenhengende vegg. Doblet fra clamp(60px,8vw,170px) — mer flyt,
     mer pust mellom kapitlene. Sporet måles med funksjonelle verdier, så
     den økte bredden fanges av invalidateOnRefresh (pin-distansen i
     v2.js regner overflow() på nytt, ikke en fastlåst tallverdi). */
  gap: clamp(120px, 16vw, 340px);
}
.j-viewport.is-rail .j-panel {
  height: 100svh;
  min-height: 0;
  flex: none;
}
.j-viewport.is-rail .j-cover,
.j-viewport.is-rail .j-finale,
.j-viewport.is-rail .j-poster { width: 100vw; }
.j-viewport.is-rail .j-chapter { width: max-content; max-width: 92vw; padding-right: clamp(70px, 9vw, 160px); }

/* ---------- Omslag og finale ---------- */

.j-cover, .j-finale { justify-content: center; text-align: center; }

/* Omslagstittelen venstrejusteres og starter inne i det grønne feltet
   (bildets 20 %-marg til venstre), så teksten krysser bildekanten og
   overlapper det grønne litt i stedet for å ligge sentrert på bildet. */
.j-cover { justify-content: flex-start; text-align: left; }
.j-cover-inner { padding-left: clamp(12px, 6vw, 120px); }

/* ---------- Sluttplakat: egen mørkegrønn panel, ikke over bildet ----------
   Patrick (3D) + alt footer-innholdet samlet på én rolig flate — speiler
   omslagets asymmetri (tekst venstre, figur høyre), men uten foto-lag
   og uten dimmer-overlay: bakgrunnen ER fargen, ingen bilde å dempe. */
.j-poster {
  background: var(--ink-deep);
  justify-content: flex-start;
  text-align: left;
}
.j-poster-inner {
  position: relative;
  z-index: 2;
  padding-left: clamp(12px, 6vw, 120px);
  max-width: 620px;
}
.j-poster-tagline {
  font-size: clamp(1rem, 2.6vh, 1.2rem);
  color: var(--on-dark);
  max-width: 46ch;
}
.j-poster-cols {
  display: flex;
  gap: clamp(40px, 6vw, 90px);
  margin: clamp(12px, 3vh, 28px) 0 0;
}
.j-poster-title {
  margin: 0 0 clamp(8px, 2vh, 20px);
  font-family: var(--font-mega);
  font-weight: 700;
  font-size: clamp(2rem, min(5.4vw, 9vh), 4.6rem);
  line-height: 1.02;
  color: var(--on-dark);
}
.j-poster-title .script {
  font-family: var(--font-quote-italic); /* Swarsh Daisy — kursiven bakt inn i fonten, ikke font-style */
  font-weight: 400;
  text-transform: none;
  letter-spacing: -0.01em;
}
.j-poster-cols .j-caption-kicker { margin-bottom: 10px; }
.j-poster-cols .j-text { margin: 0 0 6px; }
.j-poster-bottom {
  margin: clamp(12px, 3.5vh, 34px) 0 0;
  font-size: 0.8rem;
  color: var(--on-dark-soft);
}
.j-finale-phone {
  display: inline-block;
  margin-top: 4px;
  color: var(--on-dark);
  text-decoration: none;
  font-family: var(--font-nav);
  font-size: 1.05rem;
  border-bottom: 1px solid var(--line-dark);
  width: fit-content;
}
.j-finale-phone:hover { border-color: var(--on-dark); }

.j-layer {
  position: absolute;
  inset: -6%;
  z-index: 0;
}
.j-layer img { width: 100%; height: 100%; object-fit: cover; display: block; will-change: transform; }

/* Hovedbildet (omslaget) har 20 % statisk margin på venstre side —
   bakgrunnsfargen (--ink-deep) vises der. Høyre side har IKKE en
   tilsvarende margin: bildet strekker seg 20 % forbi panelets høyre
   kant i stedet (right: -20%), skjult av .j-panel sin overflow:hidden
   til den eksisterende scroll-drevne xPercent-panoreringen på <img>
   (satt lenger ned i denne fila, i .j-media img/.j-layer img-selektoren)
   avdekker mer av det etter hvert som man scroller.
   Kun omslaget, ikke finalen — .j-layer deles av begge, derfor
   scopet til .j-cover. */
.j-cover .j-layer { top: -6%; bottom: -6%; left: 20%; right: -20%; }
.j-cover::after, .j-finale::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  /* Dempet fra 0.66 — bildet skal synes tydeligere gjennom */
  background: rgba(1, 42, 32, 0.38);
}
.j-cover-inner, .j-finale-inner { position: relative; z-index: 2; }
/* Tittel og cue ligger over 3D-skinka (z 2) der de overlapper — teksten
   vinner alltid, uansett oppløsning. Skinka kan skli BAK teksten, men
   aldri over den. */
.j-cover .j-cover-inner { z-index: 3; }
.j-cover .j-cue { z-index: 3; }

.j-kicker {
  /* Mer luft mot den store tittelen under, og full kremfarge + svak
     skygge: den gamle (60 % opasitet, 0.78rem) forsvant nesten helt der
     den krysser over fotoet på omslaget. */
  margin: 0 0 clamp(20px, 3.2vh, 38px);
  font-family: var(--font-nav);
  font-size: clamp(0.85rem, 1vw, 1rem);
  font-weight: 400; /* SemiBold har vekten bakt inn — 700 ga syntetisk fet */
  letter-spacing: 0.2em;
  text-transform: none;
  color: var(--on-dark);
  text-shadow: 0 1px 14px rgba(1, 26, 19, 0.55);
}

.j-mega {
  margin: 0;
  font-family: var(--font-mega);
  font-weight: 700;
  /* 8vw, ikke 10: Gaglio Bold er bredere enn PT Serif, og «på Marikollen
     Torg» skal stå på én linje — brytes den, klipper .row-ens
     overflow:hidden (reveal-animasjonen) den ekstra linja. */
  font-size: clamp(2.6rem, min(8vw, 15vh), 8rem);
  line-height: 1.02;
  color: var(--on-dark);
  text-wrap: balance;
}
.j-mega .row { display: block; overflow: hidden; }
.j-mega .row > span { display: inline-block; }
/* To sett titteltekst (se v2/index.html sin kommentar ved h1-ene): kun
   ETT er noensinne synlig. Desktop-settet er default siden JS-en som
   animerer det (initJourney() i v2.js) bare kjører over 900px. */
.j-mega-mobile { display: none; }
.j-mega .row-shift { margin-left: clamp(0px, 12vw, 220px); }
.j-mega .accent { color: var(--red); font-family: var(--font-quote-italic); } /* Swarsh Daisy — kursiven bakt inn i fonten */
/* «Kun én font i header»: aksentordene følger også Gaglio Bold — ingen
   Fraunces-kursiv lenger. font-style normal, for Gaglio Bold-fila har
   ikke noe kursiv-snitt og italic ville blitt syntetisk skråstilt. */
.j-mega .script { font-family: var(--font-mega); font-style: normal; font-weight: 400; }
.j-mega-small { font-size: clamp(2.4rem, min(7vw, 13vh), 6.5rem); }

/* Åpningstider-lappen på omslaget — en papirlapp festet med tape, litt
   skjev, nede til høyre. Faller på plass etter tittelen (keyframes under). */
.j-hours-note {
  position: absolute;
  z-index: 4;
  right: clamp(24px, 5vw, 96px);
  bottom: clamp(56px, 9vh, 110px);
  padding: clamp(16px, 1.6vw, 24px) clamp(20px, 2vw, 30px) clamp(14px, 1.4vw, 20px);
  background: var(--paper);
  color: var(--ink);
  border-radius: 3px;
  box-shadow: var(--shadow-deep), 0 2px 6px rgba(1, 26, 19, 0.25);
  transform: rotate(4deg);
  text-align: left;
  animation: jHoursPin 0.9s var(--ease-out) 1.4s both;
}
/* Tape-stripen øverst */
.j-hours-note::before {
  content: "";
  position: absolute;
  top: -12px;
  left: 50%;
  width: 74px;
  height: 24px;
  transform: translateX(-50%) rotate(-5deg);
  background: rgba(246, 238, 222, 0.72);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}
.j-hours-note p { margin: 0; }
.j-hours-kicker {
  font-family: var(--font-quote-italic); /* Swarsh Daisy — kursiven bakt inn i fonten */
  font-size: clamp(1.3rem, 1.6vw, 1.7rem);
  line-height: 1;
  color: var(--red);
}
.j-hours-time {
  margin-top: 6px !important;
  font-family: var(--font-mega);
  font-weight: 400;
  font-size: clamp(1.25rem, 1.8vw, 1.9rem);
  line-height: 1.05;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.j-hours-place {
  margin-top: 8px !important;
  font-family: var(--font-nav);
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  color: var(--ink-soft);
}
@keyframes jHoursPin {
  from { opacity: 0; transform: translateY(-26px) rotate(-6deg) scale(1.06); }
  to   { opacity: 1; transform: rotate(4deg); }
}
@media (max-width: 900px) {
  .j-hours-note { right: var(--gutter, 22px); bottom: auto; top: calc(var(--header-h, 86px) + 18px); transform: rotate(4deg) scale(0.88); transform-origin: top right; animation: none; }
}
@media (prefers-reduced-motion: reduce) {
  .j-hours-note { animation: none; }
}

/* 3D-skinka (skinke3d.js) — høyre halvdel av omslaget, over overlayen
   (z 1) men under tittel/floats-laget der de møtes. pointer-events: none
   så den aldri stjeler scroll eller klikk. */
.j-ham {
  position: absolute;
  z-index: 2;
  right: 2%;
  top: 54%;
  transform: translateY(-42%);
  width: clamp(300px, 32vw, 580px);
  aspect-ratio: 1;
  pointer-events: none;
  filter: drop-shadow(0 40px 60px rgba(1, 20, 14, 0.55));
}
.j-ham canvas { width: 100%; height: 100%; display: block; }
@media (max-width: 900px) { .j-ham { display: none; } }

/* Osten i «Fra bunnen, hver morgen» — samme WebGL-oppførsel som skinka
   (webgl3d.js), skalert ned og plassert oppe til høyre i
   håndverk-panelet, over kollasjen uten å dekke teksten. */
.j-cheese {
  position: absolute;
  z-index: 2;
  right: 4%;
  top: 8%;
  width: clamp(220px, 22vw, 380px);
  aspect-ratio: 1;
  pointer-events: none;
  filter: drop-shadow(0 30px 46px rgba(0, 0, 0, 0.5));
}
.j-cheese canvas { width: 100%; height: 100%; display: block; }
@media (max-width: 900px) { .j-cheese { display: none; } }

/* Patrick på sluttplakaten — stor og til høyre, som om han stroller inn
   fra siden: bare beskåret til hode-til-bein (webgl3d.js sin opts.crop/
   lookY zoomer kameraet nærmere enn den vanlige «alltid helt innenfor
   rammen»-garantien, med vilje — se kommentaren ved mountModel("jPatrick"...)
   i webgl3d.js). Boksen henger litt UTENFOR panelets høyre/nedre kant
   (right/bottom negative) så beina og en bit av skulderen naturlig
   forsvinner ut av synsfeltet i stedet for å klippes midt i ansiktet.
   z 1 mot finale-inner sin z 2, over bakgrunnsbilde+dimmer i .j-finale
   (den panelet deler z-indeksrommet med, men Patrick kommer senere i
   DOM og vinner ved lik z-index). v2.js legger på en scroll-drevet
   xPercent+opacity-inngang («stroller inn») når panelet ruller i syne;
   ansiktsrotasjonen mot kamera styres uavhengig av webgl3d.js sin
   scrollFace, drevet av den globale scroll-fremdriften. */
.j-patrick {
  position: absolute;
  z-index: 1;
  right: -6%;
  /* Topp-forankret, IKKE sentrert: hodet skal ligge fast ~40px under
     headeren (webgl3d.js sin lookY/crop beskjærer 3D-rammingen slik at
     selve hodetoppen lander nær kant-0 av canvasen — se
     mountModel("jPatrick"...)), uansett hvor lang figuren blir nedover
     (beina får lov til å bleede forbi panelets bunnkant, se .j-poster). */
  top: calc(var(--header-h, 108px) + 40px);
  width: clamp(650px, 78vw, 1475px);
  aspect-ratio: 3 / 4;
  pointer-events: none;
  filter: drop-shadow(0 50px 70px rgba(0, 0, 0, 0.5));
}
.j-patrick canvas { width: 100%; height: 100%; display: block; }
@media (max-width: 900px) { .j-patrick { display: none; } }

.j-cue {
  position: absolute;
  bottom: clamp(28px, 6vh, 64px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  font-size: var(--type-small);
  letter-spacing: 0.2em;
  text-transform: none;
  color: var(--on-dark-soft);
  white-space: nowrap;
}
.j-cue span { display: block; width: 46px; height: 1px; background: var(--on-dark-soft); }

/* ---------- Kapitler ---------- */

.j-chapter { flex-wrap: wrap; align-content: center; }

.j-num {
  position: absolute;
  top: clamp(80px, 12vh, 120px);
  left: var(--gutter);
  font-family: var(--font-quote-italic); /* Swarsh Daisy — kursiven bakt inn i fonten */
  font-size: clamp(3rem, 7vw, 6rem);
  color: rgba(246, 238, 222, 0.14);
  pointer-events: none;
}

.j-title {
  margin: 0 0 18px;
  font-family: var(--font-mega);
  font-weight: 700;
  font-size: clamp(2rem, min(4.6vw, 8.5vh), 4.4rem);
  line-height: 1.06;
  color: var(--on-dark);
}
.j-title .script { font-family: var(--font-mega); font-style: normal; font-weight: 400; color: var(--green-bright); }

.j-body { max-width: 44ch; min-width: 0; }
/* 2pt (~2.67px) over sidens 16px-standard — brødteksten under titlene
   skal lese litt tyngre enn resten av siten. */
.j-text { margin: 0 0 14px; font-size: 1.17rem; line-height: 1.7; color: var(--on-dark-soft); }
.j-text-soft { opacity: 0.75; }
.j-sign { margin: 22px 0 0; font-family: var(--font-quote-italic); font-size: 1.3rem; } /* Swarsh Daisy — kursiven bakt inn i fonten */
.j-sign em { font-style: normal; font-family: var(--font-ui); font-size: 0.78rem; letter-spacing: 0.14em; text-transform: none; color: var(--on-dark-soft); }

.j-media {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--ink);
  box-shadow: var(--shadow-deep);
  /* Se samme begrunnelse ved .j-collage: uten denne kan et
     .j-chapter-nowrap-kapittel aldri krympe bildet under sitt eget
     clamp()-tak for å få plass ved siden av teksten. */
  min-width: 0;
}
.j-media img { width: 100%; height: 100%; object-fit: cover; display: block; will-change: transform; }
.j-media-tall { width: min(88vw, 460px); aspect-ratio: 3 / 4; }

/* Flytende småbilder med egen dybde */
.j-float {
  position: absolute;
  margin: 0;
  overflow: hidden;
  border-radius: var(--radius);
  box-shadow: var(--shadow-deep);
  will-change: transform;
  z-index: 2;
}
.j-float img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Polaroid-variant: hvit ramme rundt bildet med tykkere bunn for
   tittel/pris. Rammen ER objektet, så overflow slippes fri (pusten på
   <img> klippes i stedet av .j-polaroid-media). aspect-ratio overstyres
   til auto — høyden følger bilde + tekst. */
.j-float.j-polaroid {
  overflow: visible;
  aspect-ratio: auto;
  background: var(--paper);
  border-radius: 5px;
  padding: clamp(8px, 0.8vw, 13px);
}
.j-polaroid-media {
  overflow: hidden;
  aspect-ratio: 3 / 4;
  border-radius: 2px;
}
.j-polaroid figcaption {
  padding: clamp(8px, 0.7vw, 12px) 2px 2px;
  font-family: var(--font-quote-italic); /* Swarsh Daisy — kursiven bakt inn i fonten */
  font-size: clamp(0.78rem, 0.95vw, 0.98rem);
  line-height: 1.3;
  color: var(--ink); /* var #2e2a22 (varm sort) utenfor systemet — grønnblekket er husets håndskriftfarge */
}
.j-polaroid-price {
  display: block;
  margin-top: 2px;
  font-family: var(--font-nav);
  font-style: normal;
  font-weight: 400;
  font-size: 0.92em;
  color: var(--red);
}
/* Litt lavere enn før (14 %): polaroid-rammen gjør figuren høyere, og
   den skal kysse tittelens underkant — ikke ligge oppå «på Marikollen». */
.j-float-a { width: clamp(110px, min(15vw, 26vh), 240px); aspect-ratio: 3 / 4; left: 6%; bottom: 7%; }
.j-float-b { width: clamp(170px, 19vw, 320px); aspect-ratio: 4 / 3; right: 7%; top: 16%; }
.j-float-c { width: clamp(150px, 16vw, 260px); aspect-ratio: 4 / 3; right: 4%; bottom: 10%; }
.j-float-d { width: clamp(150px, 17vw, 280px); aspect-ratio: 4 / 3; right: 6%; top: 14%; }

/* Italia-kartet i «Råvarer med opphav» — svart-hvitt konturkart uten
   alfakanal (flat svart bunn). mix-blend-mode: screen gjør den svarte
   bunnen usynlig mot panelets mørkegrønne bakgrunn og lar bare de hvite
   konturlinjene lyse svakt gjennom, som et vannmerke. z-index: -1 på et
   position:relative-barn av .j-panel (som selv er position:relative)
   legger den bak all statisk-posisjonert tekst/bilder i panelet, uansett
   DOM-rekkefølge — position:absolute ville ellers alltid malt OVER
   ikke-posisjonerte søsken. */
.j-map {
  position: absolute;
  z-index: -1;
  right: -6%;
  top: 50%;
  transform: translateY(-50%);
  width: clamp(1280px, 176vw, 2880px);
  aspect-ratio: 1024 / 1536;
  opacity: 0.34;
  mix-blend-mode: screen;
  pointer-events: none;
}
.j-map img { width: 100%; height: 100%; object-fit: contain; display: block; }
@media (max-width: 900px) { .j-map { display: none; } }

/* Kollasj i håndverk-kapittelet */
.j-chapter-dark { background: var(--ink); }
/* min-width: 0 på raden OG hvert bilde: flex-items sin standard
   min-width er "auto" (den egne spesifiserte/intrinsic bredden), som
   FORHINDRER krymping under clamp()-taket uansett flex-shrink — akkurat
   den kjente flexbox-fellen. Uten denne satt kunne ikke .j-chapter-nowrap
   (v2.js/CSS lenger ned) faktisk krympe kollasjen til å få plass ved
   siden av teksten; den overflowet i stedet panelets høyrekant. */
.j-collage { position: relative; display: flex; gap: clamp(16px, 2vw, 36px); align-items: center; min-width: 0; }
.j-collage-a { width: clamp(200px, 24vw, 400px); aspect-ratio: 3 / 4; min-width: 0; transform: rotate(-2deg); }
.j-collage-b { width: clamp(180px, 21vw, 350px); aspect-ratio: 3 / 4; min-width: 0; margin-top: clamp(30px, 6vh, 80px); transform: rotate(1.5deg); }
.j-collage-c { width: clamp(220px, 26vw, 430px); aspect-ratio: 4 / 5; min-width: 0; margin-top: calc(-1 * clamp(20px, 4vh, 60px)); }

/* ---------- Produkter ---------- */

.j-products { display: flex; gap: clamp(14px, 1.8vw, 28px); flex-wrap: wrap; }
.j-viewport.is-rail .j-products { flex-wrap: nowrap; }

/* .j-product er en bar layout-skall: bredden, og INGENTING annet — den
   eier scroll-parallaksen (yPercent + rotation, v2.js). Selve kortflaten
   (bakgrunn, avrunding, skygge) flyttet til .j-product-tilt inni, som
   eier hover-vippen (egen rotation via quickTo). To ting kan ikke skrive
   samme transform-kanal på samme element uten å slåss — derfor splittet,
   se v2.js sin kommentar ved siden av magnetic-hover-koden. */
.j-product {
  width: clamp(170px, min(21vw, 34vh), 290px);
  flex: none;
}
.j-product-tilt {
  background: var(--paper);
  color: var(--ink);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-deep);
  transition: box-shadow 0.3s ease;
  will-change: transform;
}
.j-product-img { aspect-ratio: 4 / 3; overflow: hidden; background: var(--cream-deep); }
.j-product-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.j-product-body { padding: 14px 16px 16px; }
.j-product-body h3 { margin: 0 0 4px; font-family: var(--font-mega); font-weight: 700; font-size: 1.15rem; line-height: 1.15; }
.j-product-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 10px; }
.j-product-price { font-weight: 700; }
.j-product .btn { padding: 8px 16px; font-size: 0.8rem; }

/* ---------- Nyheter ---------- */

.j-news { margin-top: 8px; }
.j-news-item { padding: 14px 0; border-top: 1px solid var(--line-dark); max-width: 46ch; }
.j-news-item h3 { margin: 0 0 4px; font-family: var(--font-mega); font-weight: 700; font-size: 1.3rem; color: var(--on-dark); }
.j-news-date { font-size: 0.74rem; letter-spacing: 0.14em; text-transform: none; color: var(--green-bright); }
.j-news-item p { margin: 6px 0 0; font-size: 0.92rem; color: var(--on-dark-soft); }

.j-cta { margin-top: 26px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.j-poster-inner .j-cta { justify-content: flex-start; margin-top: clamp(12px, 3.2vh, 30px); }

/* ---------- Fremdrift ---------- */

.j-progress {
  position: fixed;
  left: var(--gutter);
  right: var(--gutter);
  bottom: 18px;
  height: 2px;
  background: rgba(246, 238, 222, 0.18);
  z-index: 30;
  display: none;
}
.j-viewport.is-rail .j-progress { display: block; }
.j-progress span {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--red);
  transform-origin: left center;
  transform: scaleX(0);
}

/* ---------- Pusterom: fullskjermbilde med ett ord ---------- */

.j-breather { padding: 0; }
.j-viewport.is-rail .j-breather { width: 100vw; }
.j-breather .j-layer { inset: -6% -10%; }
.j-breather::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: rgba(1, 42, 32, 0.28);
}
/* Mørkt scrim bak TEKSTEN — ikke bare den jevne grønntoningen over
   (::after): den hjelper generell lesbarhet, men gir ikke ekstra
   kontrast akkurat der ord faktisk ligger. Én gradient dekker BEGGE
   mulige tekstplasseringer (.j-word er alltid midtstilt; .j-caption
   ligger enten oppe (-tl) eller nede (-br), varierer per pusterom) —
   mørkere ved topp- og bunnkant, klart imellom. Samme styrke og
   utstrekning begge veier, så «marginen» til der bildet faktisk
   starter/slutter blir lik uansett hvilken kant teksten står ved. */
.j-breather::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
    to bottom,
    rgba(1, 8, 6, 0.5) 0%,
    transparent 22%,
    transparent 78%,
    rgba(1, 8, 6, 0.5) 100%
  );
  pointer-events: none;
}

.j-word {
  /* «Kun én font i header» gjelder også pusterom-ordene: Gaglio Bold,
     rett opp og ned — ingen Fraunces-kursiv. */
  position: relative;
  z-index: 2;
  margin: 0 auto;
  font-family: var(--font-mega);
  font-style: normal;
  font-weight: 400;
  font-size: clamp(2.8rem, 8vw, 7.5rem);
  color: var(--on-dark);
  text-shadow: 0 10px 60px rgba(1, 42, 32, 0.65);
  white-space: nowrap;
  will-change: transform;
}
/* Siste ord i pusterom-ordene — samme aksent-behandling som .j-mega .accent:
   serif, kursiv, rød, i stedet for Gaglio Bold rett opp og ned. */
.j-word .accent { color: var(--red); font-family: var(--font-quote-italic); } /* Swarsh Daisy — kursiven bakt inn i fonten */
/* Bokstavene i pusterom-ordene — inline-block så transform biter */
.j-letter { display: inline-block; will-change: transform; }
.j-letter-in { display: inline-block; will-change: transform; }
/* Wrapper rundt hvert ords bokstaver (om.js/v2.js sin splitLetters()):
   uten white-space: nowrap her får adjacent .j-letter-bokser (inline-
   block, ingen mellomrom mellom seg i markupen) en implisitt linjeskift-
   mulighet SEG IMELLOM — ord brekker da midt inni ved trang plass.
   nowrap her tillater fortsatt linjeskift MELLOM ord (mellomrommet
   utenfor denne wrapperen er et vanlig break-punkt), bare ikke inni. */
.j-letter-group { display: inline-block; white-space: nowrap; }

/* Liten tekstbolk i et hjørne av fullskjermbildene — forteller hva man
   ser. Hjørnet varierer per panel (-br, -tl, ...): det skal kjennes
   strødd utover, ikke systematisk. Under pusterom-ordet (z 2 begge, men
   ordet kommer senere i DOM) og over overlayen (z 1). */
.j-caption {
  position: absolute;
  z-index: 2;
  /* Smal spalte — teksten oppå fullskjermbildene skal lese som en
     kolonne, ikke en bred bolk som strekker seg utover bildet. */
  max-width: min(24ch, 34vw);
  color: var(--on-dark);
  text-shadow: 0 2px 24px rgba(1, 42, 32, 0.7);
}
.j-caption-br { right: clamp(20px, 4vw, 70px); bottom: clamp(24px, 6vh, 70px); text-align: right; }
/* Samme avstand til bildekanten som -br (clamp(24px,6vh,70px)) — bare
   forskjøvet forbi headeren, som -br ikke trenger å ta hensyn til.
   Sto tidligere som en egen, større konstant (16vh/160px) uten
   sammenheng med -br sin, så «oppe»-varianten av teksten hadde synlig
   mer luft til toppen enn «nede»-varianten hadde til bunnen. */
.j-caption-tl { left: clamp(20px, 4vw, 70px); top: calc(var(--header-h, 108px) + clamp(24px, 6vh, 70px)); }
.j-caption-kicker {
  display: block;
  margin-bottom: 6px;
  font-family: var(--font-nav);
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: none;
  color: var(--on-dark-soft);
}
.j-caption p { margin: 0; font-size: 0.95rem; line-height: 1.5; }

/* ---------- Musikk-knapp ---------- */

.j-music-toggle {
  position: fixed;
  z-index: 160; /* over grainet (150), under ingenting — cursoren har ingen z */
  right: clamp(18px, 3vw, 34px);
  bottom: clamp(18px, 3vw, 34px);
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1px solid var(--line-dark);
  background: rgba(1, 42, 32, 0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: var(--on-dark);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s, transform 0.2s;
}
.j-music-toggle:hover { background: rgba(1, 42, 32, 0.75); border-color: var(--on-dark-soft); }
.j-music-toggle svg { width: 22px; height: 22px; }
.j-music-icon-off { display: block; }
.j-music-icon-on { display: none; }
.j-music-toggle.is-playing .j-music-icon-off { display: none; }
.j-music-toggle.is-playing .j-music-icon-on { display: block; }
/* Rolig puls mens musikken spiller — signaliserer "aktiv" uten tekst */
.j-music-toggle.is-playing { animation: j-music-pulse 2.4s ease-in-out infinite; }
@keyframes j-music-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(246, 238, 222, 0.18); }
  50% { box-shadow: 0 0 0 8px rgba(246, 238, 222, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .j-music-toggle.is-playing { animation: none; }
}
@media (max-width: 900px) {
  .j-music-toggle { width: 44px; height: 44px; }
}

/* ---------- Ekstra medieformater ---------- */

.j-media-big { width: min(88vw, 540px); aspect-ratio: 3 / 4; }
/* .j-chapter-nowrap: .j-chapter sin flex-wrap: wrap gir WRAPPING
   forrang over krymping på én linje i flexbox — et barn som ikke får
   plass ved sin egen (u-krympede) bredde hopper ned på egen linje,
   uansett hvor mye det egentlig KUNNE krympet. For et vanlig
   .j-body + .j-media-par (to barn) er det alltid riktigere at de
   krymper sammen og blir stående side om side, enn at bildet detter
   under teksten — reprodusert på helt ordinære skrivebordsbredder
   (901–1600px, ikke bare smale vinduer) med .j-media-big. nowrap her
   tvinger fram den krympingen (flex-shrink sin default er allerede 1,
   den fikk aldri sjansen mens wrap vant først). Egen klasse i stedet
   for å fjerne wrap fra .j-chapter globalt — andre kapitler kan ha
   flere barn som faktisk trenger å brekke. */
.j-chapter-nowrap { flex-wrap: nowrap; }
.j-media-wide { width: min(88vw, 640px); aspect-ratio: 4 / 3; }

.j-float-e { width: clamp(150px, 16vw, 260px); aspect-ratio: 4 / 3; right: 5%; top: 12%; }
.j-float-f { width: clamp(140px, 14vw, 230px); aspect-ratio: 4 / 3; left: 3%; bottom: 9%; }

/* ---------- Animert filmgrain over hele reisen ----------
   Overstyrer den globale body::after fra site.css: den er multiply-blandet
   og forsvinner på mørk bunn. Her: eget stort kornlag som flyttes i sprang
   med steps() (gjenbruker @keyframes vista-grain fra site.css) — kornet
   «skifter rute» som i film i stedet for å gli. Ligger over alt innhold
   (z-index 150), under musepekeren (200). */

.v2-body::after {
  position: fixed;
  inset: auto;
  top: -100%;
  left: -100%;
  width: 300%;
  height: 300%;
  z-index: 150;
  /* screen i stedet for overlay: fractalNoise ligger rundt mellomgrå, og
     overlay med ~50 % grå er identitet — kornet ble usynlig. screen med
     hvite prikker lysner mørke flater tydelig (de grønne bakgrunnene) og
     nesten ikke de lyse, så cream-feltene og fotoenes høylys skånes. */
  mix-blend-mode: screen;
  opacity: 0.2; /* halvert fra 0.4 — «for synlig» */
  /* Terskel i stedet for rå støy: alfamatrisen (3·lum − 1.8) slipper bare
     gjennom de lyseste toppene av støyen som spredte, tydelige hvite
     prikker à la referansen — resten av flaten er helt gjennomsiktig. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.35' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 3 0 0 0 -1.8'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23g)'/%3E%3C/svg%3E");
  /* Rolig brus: 2.8s med 4 steg (~1,4 skift/s) — halvert tempo, sitring
     i stedet for flimmer */
  animation: vista-grain 2.8s steps(4) infinite;
}

@media (prefers-reduced-motion: reduce) {
  .v2-body::after { animation: none; opacity: 0.16; }
}

/* ============================================================
   LAV SKJERMHØYDE PÅ DESKTOP/LAPTOP (rail kjører, men vh er
   begrenset — typiske 1280×720/650/600-laptoper). Railen låser
   panelhøyden til 100svh; portrettbildene/kollasjen er dimensjonert
   etter BREDDE (vw/px-tak) med aspect-ratio, som på en vanlig
   ≥900px høy skjerm gir rikelig luft — men på en lav, bred skjerm
   blir de bildene HØYERE enn selve panelet og klippes av .j-panel
   sin overflow: hidden (bunnen/toppen av bildet forsvinner, eller
   teksten dyttes ut av synsfeltet). Fikset ved å styre disse etter
   HØYDE i stedet for bredde i dette vindusintervallet — samme
   aspect-ratio, bredden følger av seg selv og krymper naturlig
   sammen med teksten (flex-shrink, se .j-chapter-nowrap). */
@media (min-width: 901px) and (max-height: 760px) {
  .j-panel { padding-block: clamp(48px, 8vh, 90px); }
  .j-media-tall, .j-media-big {
    width: auto;
    height: min(62vh, 520px);
  }
  .j-media-wide {
    width: auto;
    height: min(54vh, 420px);
  }
  /* Kollasjen har TRE bilder på rad, ikke ett — trenger mer bredde per
     høydeenhet enn de enkeltstående portrettbildene over, ellers klipper
     .j-panel sin overflow: hidden raden i høyrekanten. */
  .j-collage-a, .j-collage-b, .j-collage-c {
    width: auto;
    height: min(34vh, 300px);
  }
  .j-body { max-width: 42ch; }
  .j-text { font-size: 1.05rem; line-height: 1.6; margin-bottom: 10px; }
  .j-title { font-size: clamp(1.9rem, 3.6vw, 3.4rem); margin-bottom: 12px; }
  .j-num { top: clamp(36px, 7vh, 80px); font-size: clamp(2.2rem, 5vw, 4rem); }
  .j-mega { font-size: clamp(2.4rem, 6.4vw, 6.4rem); }
  .j-kicker { margin-bottom: 10px; }
  .j-cue { bottom: clamp(18px, 4vh, 40px); }
}

/* ============================================================
   SMAL SKJERM — vertikal reise (mobil)
   Rail-en kjører aldri her (901px-gaten i v2.js/om.js); panelene
   stables av .j-track sin kolonne-standard. Denne blokka gjør
   stablingen til en KOMPONERT side i stedet for et uhell:
   - .j-float var absolutt posisjonert med DESKTOP-koordinater og la
     seg RETT OVER teksten på smale skjermer («bilder over tekst») —
     de legges nå i flyten som en vekslende scrapbook-kolonne, og
     beholder scroll-driften fra assets/vertical-journey.js.
   - Panelene slipper 100svh-kravet (tekst+bilder flyter naturlig);
     bare pusterommene (paneler med .j-layer-bakgrunn) beholder full
     høyde — de ER fullskjermsøyeblikkene.
   Gjelder både / og /om (begge laster denne fila). ============ */
@media (max-width: 900px) {
  .j-chapter {
    flex-direction: column;
    /* nowrap er AVGJØRENDE: basestilen har flex-wrap: wrap (for railens
       skyld), og kolonne + wrap gjør at barna sizes til max-content i
       tverretningen i stedet for å strekkes — tekstblokkene ble 872px
       brede i en 375px viewport og klipptes i begge kanter. */
    flex-wrap: nowrap;
    align-items: stretch;
    /* Luft mellom BILDE og TEKST innad i ett kapittel (økt fra 52px —
       tekst/tittel lå fortsatt for tett på bildene på mobil). Se
       .j-panel rett under for luften MELLOM kapitler. */
    gap: 88px;
  }
  /* Bare KAPITLENE slipper 100svh-kravet — pusterom/finale/hero (alle
     panler som ikke er .j-chapter) beholder basens fulle høyde. Uttrykt
     med :not() i stedet for :has(): :has() finnes først i iOS 15.4, og
     en selektor iOS ikke forstår droppes stille — pusterommene mistet
     fullskjermshøyden sin på eldre telefoner uten at noe feilet synlig. */
  .j-panel.j-chapter { min-height: auto; }
  /* Luften FØR/ETTER hvert panel ER avstanden mellom seksjonene på
     mobil (kapitlene stables uten egen height:100svh, se regelen over,
     så padding-block er hele mellomrommet). Økt fra clamp(128px, 24vh,
     220px) — modulene skal stå mye høyere/luftigere. */
  .j-panel { padding-block: clamp(170px, 32vh, 300px); }

  .j-float {
    position: static;
    width: min(64vw, 300px);
    /* aspect-ratio fra .j-float-a/b/… beholdes — bare plasseringen
       nulles. align-self veksler side, se under. */
  }
  /* Vekslende sider — samme side som de sto på i desktop-kollasjen
     (a/f venstre, resten høyre), så bildeutvalget beholder rytmen sin. */
  .j-float-a, .j-float-f { align-self: flex-start; }
  .j-float-b, .j-float-c, .j-float-d, .j-float-e { align-self: flex-end; }
  /* Focaccia-polaroiden på omslaget: 58vw/260px-taket var ment for de
     LILLE flyte-bildene i kapitlene, men polaroiden er selve heroens
     eneste bilde-element og skal ha mer nærvær — bredere tak, og en
     større ANDEL av skjermbredden. */
  .j-cover .j-float.j-polaroid { width: min(84vw, 380px); }

  /* ---------- Omslaget (heroen) ----------
     Kickeren («Marikollen Torg · Italiensk deli») og scroll-hinten
     («Scroll for å bli med inn») bort på mobil — begge var tekst i
     tillegg til en allerede stor tittel, og trengte plassen mer enn de
     ga verdi på en smal skjerm. Tittelen får synlig egen h1 (se
     .j-mega-desktop/.j-mega-mobile over) og flyttes godt ned i
     heroen — margin-top i stedet for endret flex-justering, så resten
     av oppsettet (polaroiden, bakgrunnsbildet) står urørt. */
  .j-kicker, .j-cue { display: none; }
  .j-mega-desktop { display: none; }
  .j-mega-mobile { display: block; }
  .j-cover-inner { margin-top: clamp(120px, 32vh, 260px); }

  /* Kapittelnumrene: mindre, opp i hjørnet, bak alt — de er tapet,
     ikke innhold, og skal aldri konkurrere med tekst om plassen. */
  .j-num { font-size: clamp(4rem, 22vw, 7rem); opacity: 0.5; z-index: 0; }

  .j-body { max-width: none; }

  /* Megatittelen: 3rem-gulvet i clamp-en er fortsatt for bredt for
     «Marikollen» på 375px — nettleseren nødbrøt MIDT I ordet, og den
     ekstra linja ble attpåtil klippet av .row sin overflow:hidden
     (reveal-mekanikken). Viewport-skalert med lavere gulv + eksplisitt
     forbud mot ordbrekk: heller mindre skrift enn delte ord. */
  .j-mega {
    font-size: clamp(2rem, 11vw, 3rem);
    overflow-wrap: normal;
    word-break: keep-all;
    hyphens: none;
  }

  /* Bildetekstene på fullskjermspartiene: 34vw-spalten (en tredjedels
     skjerm) ble en avklemt stripe langs kanten på telefon — slipp dem
     ut til nesten full bredde nederst, alltid venstrestilt (høyrestilt
     smalspalte leser som feiljustering når den fyller hele linja). */
  .j-caption {
    max-width: min(38ch, 86vw);
  }
  .j-caption-br { right: var(--gutter); left: var(--gutter); bottom: clamp(20px, 5vh, 48px); text-align: left; }
  .j-caption-tl { left: var(--gutter); right: var(--gutter); }

  /* Kollasjen: LIGGER horisontalt (én rad, ikke wrap) og FORSKYVES
     sidelengs av assets/vertical-journey.js mens man scroller forbi
     kapittelet vertikalt — samme «vertikal styrer horisontal»-idé som
     desktop-railen, bare lokalt for denne ene modulen i stedet for hele
     siden. Bredden per bilde er bevisst > 100vw/3 (de skal stikke ut
     over kantene) — det er poenget: uten overheng ville det ikke vært
     noe å avsløre når stripen beveger seg.

     Sto tidligere som en wrap-et scrapbook-klynge (tre 200px+-bilder
     presset av flex-shrink til frimerker, så flex:none+wrap i stedet)
     — helt forkastet nå til fordel for den etterspurte sidescroll-
     følelsen. .j-chapter (basisregelen) har allerede overflow:hidden,
     så overhenget kan aldri åpne horisontal scroll på SIDEN. */
  .j-collage {
    flex-wrap: nowrap;
    width: max-content;
    /* Startposisjon FØR animasjonen tar over (progress 0) — samme
       verdi som x: fra-tallet i vertical-journey.js, så det ikke blir
       et hopp idet ScrollTrigger kobler seg på ved scroll. */
    transform: translateX(14vw);
    will-change: transform;
  }
  .j-collage-a, .j-collage-b, .j-collage-c { flex: none; margin-top: 0; }
  .j-collage-a { width: 58vw; }
  .j-collage-b { width: 46vw; margin-top: 40px; }
  .j-collage-c { width: 66vw; margin-top: -10px; }
}

/* ---------- Lave skjermer (f.eks. 1280x720 og ned mot ~550 px høyde) ----------
   Panelene er låst til 100svh i rail-modus, så det som ikke får plass blir
   klippet. Toppluften regnes fra headerens faktiske høyde (--header-h, satt
   av site.js) i stedet for en fast clamp, og bunnluften krymper — det gir
   innholdet mest mulig av den lille høyden. */
@media (min-width: 901px) and (max-height: 760px) {
  .j-viewport.is-rail .j-panel {
    padding-top: calc(var(--header-h, 108px) + 10px);
    padding-bottom: clamp(18px, 4vh, 40px);
  }
  .j-text { font-size: 1.05rem; line-height: 1.6; }
}
@media (min-width: 901px) and (max-height: 620px) {
  .j-text { font-size: 0.98rem; line-height: 1.55; margin-bottom: 10px; }
  .j-poster-cols .j-text { margin-bottom: 2px; }
  /* Produktkortene: bredere og lavere, så pris + knapp får plass på én linje */
  .j-product { width: clamp(200px, min(21vw, 42vh), 290px); }
  .j-product-img { aspect-ratio: 16 / 9; }
  .j-product-body { padding: 10px 12px 12px; }
  .j-product-body h3 { font-size: 1rem; }
  .j-product-row { margin-top: 6px; }
  .j-cta { margin-top: 14px; }
}
