/* ==========================================================================
   Minnesboken -- the client's printed anniversary book, turnable on the
   history page. StPageFlip (MIT, vendored in assets/vendor/page-flip/) owns
   the geometry of #bok and its .bok-sida children; everything here styles the
   ground the book stands on, never the flipping mechanics.

   Two rules from the playbook shape the markup, not just the CSS:
     * the heading lives OUTSIDE the pinned scene. A heading inside a sticky
       100svh block collides with the content at some viewport height, and
       every fix for one height breaks another.
     * the scene pins UNDER the sticky header (--topp-h), never at top: 0,
       which hides the book's top edge behind the bar in scrolled screenshots.
   ========================================================================== */

/* The whole page is one dark room with one thing in it. No block padding: the
   scene sets its own height in JS, and any padding here would show as a gap
   before the wordmark or after the last page that reads as a broken section. */
.bok-band {
  position: relative;
  background: var(--valnot);
  color: var(--papper);
  padding: 0;
}

/* --- the portal ----------------------------------------------------------
   Its own screen above the book, not an overlay on it. Dennis, 2026-08-11:
   mark, words, then a button. A button rather than a scroll hint because it is
   a door: pressing it is the moment the visitor decides to go in, and the whole
   sequence below hangs off that decision.

   The button used to carry the reader down to the book. Since 2026-08-17 it
   does the opposite -- the portal steps out of the flow and the book falls into
   the frame where the reader already is -- so nothing here may assume there is
   a journey; see the "ingen återvändo" rule below. */

.bok-portal {
  min-height: calc(100svh - var(--topp-h, 5.75rem) - 1px);
  display: grid;
  align-content: center;
  justify-items: center;
  text-align: center;
  gap: clamp(1.1rem, 3svh, 2rem);
  padding: clamp(2rem, 6svh, 4rem) var(--s-5);
}

/* The lockup, in the print's own proportions: the aspect ratio and both
   children's boxes come out of bygg_bok.py, so the portal cannot drift away
   from the cover it is quoting. */
.bok-lasa {
  position: relative;
  display: block;
  width: min(28rem, 74vw);
  color: var(--papper);
}

.bok-lasa__mark,
.bok-lasa__hjarta { position: absolute; display: block; }

.bok-lasa__mark {
  background: currentColor;
  -webkit-mask: url("bok/omslag-ordmarke.png") no-repeat center / contain;
          mask: url("bok/omslag-ordmarke.png") no-repeat center / contain;
}

.bok-lasa__hjarta {
  background: url("bok/omslag-hjarta.png") no-repeat center / contain;
}

.bok-marke {
  display: block;
  color: var(--papper);
}

/* The mark is their own ink, lifted off the cover photograph and kept as pure
   coverage -- so it can be any colour by being a mask over currentColor. That
   is what lets the SAME shape read as cream in the dark portal and as print
   once it has landed on the paper. */
.bok-marke__inre {
  display: block;
  width: 100%;
  height: 100%;
  background: currentColor;
  -webkit-mask: url("bok/omslag-ordmarke.png") no-repeat center / contain;
          mask: url("bok/omslag-ordmarke.png") no-repeat center / contain;
  transform-origin: 50% 100%;
}

.bok-portal__rubrik {
  margin: 0;
  max-width: 20ch;
  font-family: var(--f-display);
  font-size: var(--t-2xl);
  font-weight: 300;
  line-height: 1.08;
  letter-spacing: var(--spar-display);
  text-transform: uppercase;
  text-wrap: balance;
  color: var(--papper);
}

.bok-portal .knapp-rad { margin: 0; }

/* --- efter Stig in finns ingen återvändo ---------------------------------
   Dennis 2026-08-17: "när man klickat på stig in så ska det inte finnas ett
   återvändo för att återvända till hur sidan började, så behöver man refresha
   sidan." Portalen tas därför UR FLÖDET av bok.js (klassen sätts på roten), och
   det gör två jobb i samma drag: dörren är stängd bakom läsaren, och scenen
   flyttar upp och lägger sig i den pinnade ramen av sig själv -- alltså behöver
   ingen scrollas ned för att komma in. Boken kommer till läsaren i stället.

   GÖMD, INTE BORTTAGEN, och det är inte en detalj: portalen bär sidans `h1`, och
   bandets aria-labelledby pekar på den. `display:none` här hade gjort landmärket
   namnlöst och sidan rubriklös -- ett fel ingen skärmbild kan visa. Knappen och
   ordmärket tas däremot ur helt: en osynlig knapp man kan tabba till är en fälla,
   inte en genväg. */
html.bok-inne .bok-portal {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
  min-height: 0;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

html.bok-inne .bok-portal .knapp-rad,
html.bok-inne .bok-portal .bok-lasa { display: none; }

/* --- what falls onto the bare cover -------------------------------------- */

.bok-pafall {
  position: absolute;
  inset: 0;
  z-index: 30;
  pointer-events: none;
}

/* Once the board carries its own printing again, the two floating marks have
   nothing left to do. display:none rather than opacity, so nothing of them can
   survive a page turn as a ghost. */
.bok-tryckt .bok-pafall { display: none; }

/* Both marks are placed by bok.js in the exact rectangle they were lifted
   from, and both rest at transform:none. The flight is therefore allowed to be
   approximate while the landing cannot be. */
.bok-pafall .bok-marke,
.bok-pafall img {
  position: absolute;
  width: auto;
  opacity: 0;
}

.bok-pafall img { display: block; }

/* --- the invitation ------------------------------------------------------ */

/* The invitation is not centred on the page -- it is centred in the BAND the
   print leaves empty, between the wordmark above and the #We are schnitzel
   badge below. --lucka-topp and --lucka-botten are written onto this element by
   sida_ovriga.py out of bok.json, and bok.js turns them into pixels by
   publishing the page height as --sida-h.

   Measured before this existed, with the block centred on the page instead: it
   stood 20 px into the wordmark at 1440x900, 28 at 1280x800, and on a phone it
   was a 154 px block inside a 100 px band -- over the wordmark at the top AND
   over the badge at the bottom. Centring on the page cannot work, because the
   band is neither centred nor a fixed height.

   HORIZONTALLY it is a child of .bok-ram and one PAGE wide, not one frame wide.
   The book's box is two pages, and at the last spread the back board is the
   left-hand one -- so left:0 with the page's own width is the board, and the
   half-page shift that centres that board (--skjut, a transition on .bok-ram)
   carries the words with it instead of leaving them behind. In portrait the
   ram is a single page and the same two numbers still describe it. */
.bok-slut {
  --band: calc((var(--lucka-botten, .62) - var(--lucka-topp, .40)) * var(--sida-h, 0px));
  --band-mitt: calc(((var(--lucka-topp, .40) + var(--lucka-botten, .62)) / 2 - .5)
                    * var(--sida-h, 0px));
  position: absolute;
  left: 0;
  width: var(--sida-b, 100%);
  top: calc(50% + var(--band-mitt));
  height: var(--band);
  transform: translateY(-50%);
  z-index: 32;
  display: grid;
  align-content: center;
  justify-items: center;
  text-align: center;
  padding-inline: var(--s-5);
  pointer-events: none;
}

/* BOKA BORD IS A BUTTON. Dennis, 2026-08-14: "jag vill fortfarande att CTA:n
   är en knapp."

   It was briefly set as a printed line -- ink, wide tracking, the board's own
   red-white-red rule underneath -- on the reading that "insmält i baksidan"
   covered the button too. It did not: what he wanted gone was the fade, not
   the affordance. The site's red block is the same button as the one in the
   header and on every other page, and a reader who has just turned twenty
   pages should not have to work out that a line of type is the way out.

   The block is the only part of this band that does not scale with the type,
   so on a small page it takes a fixed 44 px of a band that can be under 90.
   That is deliberate: matt_bok.mjs measures it as a tap target and WCAG 2.5.8
   is the floor. What gives way instead is the heading, which is allowed to run
   the full width of the page -- see [data-slut="smal"] above. */
.bok-slut .knapp { pointer-events: auto; }

/* The band cannot hold two lines of the designed size AND a 44 px button on a
   small page -- and the button is the part that must not give way, since
   matt_bok.mjs measures it as a tap target. So the LINE gives way instead:
   bok.js measures what the block needs, and where it does not fit the heading
   is allowed to run to the full width of the page, which turns two lines into
   one. A wide page never enters this state and reads exactly as designed. */
.bok-scen[data-slut="smal"] .bok-slut__rad { max-width: none; }

/* .knapp-rad is a <p> and carries the stylesheet's paragraph margin-top: 16 px
   that no band can scale, and the single largest reason the block stood 21 px
   into the wordmark on a phone. The air between line and button is
   .bok-slut__rad's own margin, which does follow the band. */
.bok-slut .knapp-rad { margin: 0; }

/* Both the type and the air below it are capped by the band, never by the
   viewport: the band is what the print left, and 26 % of a 390 px page is 100 px
   whatever the screen is called. The designed sizes are the ceiling, so nothing
   grows -- on a desktop page the caps never bind and this reads exactly as it
   did before. */
.bok-slut__rad {
  margin: 0 0 min(var(--s-5), calc(var(--band) * .11));
  max-width: 18ch;
  font-family: var(--f-display);
  font-size: min(var(--t-xl), calc(var(--band) * .19));
  /* 500, not 300. The board's own type -- the address line under the badge --
     is a condensed grotesque set bold and tracked wide, and a hairline 300
     next to it reads as a caption laid over the page rather than as something
     printed on it. */
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: var(--spar-display);
  text-transform: uppercase;
  text-wrap: balance;
  /* Ink, not gold, and the back cover is the reason. It was --guld-ljus while
     the board was near-black; on the cream board it went to 2,6:1, which is
     the site's own long-standing measurement for gold on cream and the reason
     gold is never small type here. The words sit on the restaurant's paper
     now, so they are the colour their paper takes. */
  color: var(--valnot);
}

/* THE INVITATION DOES NOT ARRIVE. IT IS PRINTED THERE.

   Dennis, 2026-08-14: "bli en del av vår historia och den där CTA:n den
   fadeas in, jag vill att den liksom ska vara insmält i baksidan så som
   moldau loggan är samt all annan information". The wordmark, the badge and
   the address do not fade up when you reach the last page -- they are on the
   paper. These two words were the only thing on that board behaving like a
   web page, and a 0,45 s fade with a 20 px rise is exactly what gives that
   away.

   The state it hangs on changed with it, and twice. First from the scroll's
   act to the book's page index, because the act said "slut" 780 ms before the
   turn onto the last page had finished -- so the words popped up over a page
   still turning, which is what the fade was covering for. Then from the index
   to `data-inbjudan`, which bok.js writes out of three facts at once: the
   engine is still, the last board is the one showing, and the scroll is still
   asking for the end. The index alone was not enough in the other direction
   -- it only changes when a turn LANDS, so on the way back it still said
   "last page" for the whole fold. Nothing here is timed; the words are on the
   board that is facing the reader, and gone the moment it is not. */
.bok-scen[data-akt] .bok-slut__rad,
.bok-scen[data-akt] .bok-slut .knapp-rad {
  opacity: 0;
  visibility: hidden;
}

.bok-scen[data-akt][data-inbjudan="pa"] .bok-slut__rad,
.bok-scen[data-akt][data-inbjudan="pa"] .bok-slut .knapp-rad {
  opacity: 1;
  visibility: visible;
}

/* --- the pinned scene ---------------------------------------------------- */

.bok-scen { position: relative; }

.bok-pinne {
  position: sticky;
  /* Same minus-one-pixel reasoning as .menytopp-band: --topp-h is rounded DOWN
     on purpose, so the gap under the header can be up to a pixel smaller than
     this calculation assumes. */
  top: calc(var(--topp-h, 5.75rem) + 1px);
  height: calc(100svh - var(--topp-h, 5.75rem) - 1px);
  display: grid;
  align-items: center;
  justify-items: center;
  /* clip, not hidden: a hard-covered page lifts out of the flat plane while it
     turns, and without a clip that lift becomes horizontal page scroll. */
  overflow: clip;
  /* No padding, and the meter overlays rather than taking a row: Dennis asked
     for edge to edge, and a frame that keeps a gap for its own furniture can
     never give the book the whole screen. */
  padding: 0;
}

/* A square album on a portrait phone is letterbox by arithmetic: a square
   page on a 375 px screen can only be 375 px tall inside a 629 px frame, and
   no width the book is allowed to take changes that. The dark space is
   therefore not a bug to remove but a room to light -- a single soft pool
   makes it read as a table the book lies on rather than as emptiness. It costs
   nothing and it helps the wide screens too. */
.bok-pinne::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(60% 55% at 50% 46%,
              rgba(201, 162, 39, .13), rgba(201, 162, 39, 0) 70%);
  pointer-events: none;
}

/* bok.js writes an explicit pixel width here. The cap has to live on a parent:
   the engine rewrites the book element's own inline styles every time it
   rebuilds, so a max-width set there does not survive.

   z-index, not just order: the pool above is painted by a pseudo-element, and
   the pages are positioned, so without a stacking position of its own the book
   would sit under its own light. */
.bok-ram { max-width: 100%; position: relative; z-index: 1; }

/* --- the two marks arrive ------------------------------------------------
   Dennis, 2026-08-11: the board is bare, the wordmark drops onto its own
   printed place, the flag comes down after it, and then the book opens.

   The curves are the start page's hero (hero-film.css, "THE MARK COMES DOWN
   AND LANDS"), because that weight is what he pointed at. Falling is a
   sequence, not an ease: accelerate under gravity, hit, get thrown back a
   shorter way, hit again, settle -- so the timing function changes direction
   at every contact. One cubic-bezier across the whole drop reads as rubber.

   Two elements, one transform each. An element has ONE transform, and the mark
   has to travel AND squash: put both on one element and the animation wins
   while it runs, then the element snaps to its base style the moment the
   animation is removed instead of continuing from where it left off.

   And the colour travels with it. The mark is a mask over currentColor, so the
   same shape can be cream in the dark portal and ink once it is on the paper --
   which is the whole point of lifting it off the photograph as coverage rather
   than as a picture. */

/* HÄNGER PÅ ENTRÉN, INTE PÅ AKTEN (Dennis 2026-08-17). Förut startade fallet så
   fort scrollen passerade aktgränsen, vilket band ihop två olika saker: var
   läsaren är, och att hen tryckt på dörren. Nu är entrén en händelse som bok.js
   utlöser vid klicket och stegar i två attributvärden -- "faller" medan boken
   själv faller ned i ramen, "landad" när den ligger still och trycket kan börja
   landa på den. Ett märke som faller mot en bok som fortfarande rör sig landar
   ju inte på sin ruta. */
.bok-scen[data-entre="landad"] .bok-pafall .bok-marke,
.bok-scen[data-entre="landad"] .bok-hjarta {
  animation: bok-marke-in 1150ms both;
}

@keyframes bok-marke-in {
  0% {
    transform: translateY(-64svh);
    opacity: 0;
    color: var(--papper);
    animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.35);   /* gravity */
  }
  6%  { opacity: 1; }
  46% {
    transform: translateY(0);                                     /* contact */
    color: var(--papper);
    animation-timing-function: cubic-bezier(0.1, 0.62, 0.5, 1);   /* thrown up */
  }
  62% {
    transform: translateY(-7%);
    animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.35);
  }
  76% {
    transform: translateY(0);
    animation-timing-function: cubic-bezier(0.1, 0.62, 0.5, 1);
  }
  86% { transform: translateY(-2.2%); animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.35); }
  94% { transform: translateY(0); }
  97% { transform: translateY(-0.6%); }
  /* Cream on the way down, print when it is down. It does not fade into place,
     it BECOMES the printing that was missing. */
  100% { transform: translateY(0); opacity: 1; color: #17130f; }
}

/* The squash belongs to the contacts, not to the whole drop, and its origin is
   the bottom centre -- which is what makes it read as weight landing rather
   than as a shrink. Same duration as the fall so the two cannot drift apart. */
.bok-scen[data-entre="landad"] .bok-pafall .bok-marke__inre {
  animation: bok-nedslag 1150ms both;
}

@keyframes bok-nedslag {
  0%, 38% { transform: scaleX(1) scaleY(1); }
  46%     { transform: scaleX(1.09) scaleY(0.88); }
  55%     { transform: scaleX(0.98) scaleY(1.035); }
  76%     { transform: scaleX(1.04) scaleY(0.96); }
  83%     { transform: scaleX(0.99) scaleY(1.015); }
  94%     { transform: scaleX(1.015) scaleY(0.985); }
  100%    { transform: none; }
}

/* The flag comes AFTER, and it does not fall -- it flies. A pennant on a pole
   has one heavy end and one loose one, so it swings into place rather than
   bouncing on it: the rotation settles a beat later than the travel does. */
.bok-scen[data-entre="landad"] .bok-flagga {
  animation: bok-flagga-in 900ms 620ms both;
}

@keyframes bok-flagga-in {
  0% {
    transform: translate(9%, -78svh) rotate(-19deg);
    opacity: 0;
    animation-timing-function: cubic-bezier(0.42, 0, 0.72, 0.5);
  }
  10% { opacity: 1; }
  62% {
    transform: translate(0, 0) rotate(6deg);
    animation-timing-function: cubic-bezier(0.25, 0.7, 0.35, 1);
  }
  82% { transform: translate(0, 0) rotate(-2.4deg); }
  93% { transform: translate(0, 0) rotate(0.9deg); }
  100% { transform: none; opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .bok-pafall .bok-marke,
  .bok-pafall .bok-marke__inre,
  .bok-pafall img { animation: none !important; opacity: 1; color: #17130f; }
}

/* A closed book is one page wide, but the engine's box is always two: the
   cover sits in the right-hand slot and the left half is empty, so a closed
   book hangs off to one side of the frame and reads as a layout fault. The
   same happens in reverse on the back board. Shifting the box by half a page
   puts the visible board in the middle of the frame -- and because the shift
   is a transition, the book SLIDES out to full width as it opens, which is
   what a book on a table actually does. bok.js writes --skjut and the state. */
/* --- boken faller ned i ramen --------------------------------------------
   Dennis 2026-08-17: "när man klickat stig in kan boken istället falla ner ifrån
   toppen och sedan ha animationerna den har." Entrén är alltså bokens egen
   ankomst, inte en resa läsaren gör.

   Fallet ligger på `translate` och INTE på `transform`, och det är hela skälet
   till att det får bo på samma element som glidningen: ett element har EN
   transform, så en animation här hade vunnit medan den kör och sedan slängt bort
   halvsidesskjutningen i det ögonblick den togs bort. `translate` är en egen
   egenskap som komponeras med transform -- boken kan alltså falla och samtidigt
   stå halvsidan åt sidan som en stängd bok ska.

   Kurvan är märkets: acceleration under gravitation, kontakt, ett kortare kast
   tillbaka, kontakt igen. En enda cubic-bezier över hela fallet läser som gummi.
   Ramen klipper (`overflow: clip` på .bok-pinne), så boken kommer in bakom
   ramens överkant och inte ovanifrån sidhuvudet.

   `[data-entre]` och inte `[data-entre="faller"]`: attributet stegas vidare till
   "landad" när boken ligger, och en animation som TAS BORT slänger sitt slutläge
   -- vilket här hade betytt att boken hoppar en bildruta just när märket ska
   börja falla mot den. Med `both` och en väljare som håller kvar ligger den kvar
   där fallet slutade. */
.bok-scen[data-entre] .bok-ram { animation: bok-boken-faller 780ms both; }

@keyframes bok-boken-faller {
  0%   { translate: 0 -118%; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.35); }
  50%  { translate: 0 0;     animation-timing-function: cubic-bezier(0.1, 0.62, 0.5, 1); }
  68%  { translate: 0 -5.5%; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.35); }
  83%  { translate: 0 0;     animation-timing-function: cubic-bezier(0.1, 0.62, 0.5, 1); }
  92%  { translate: 0 -1.6%; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.35); }
  100% { translate: 0 0; }
}

@media (prefers-reduced-motion: reduce) {
  .bok-scen[data-entre] .bok-ram { animation: none; }
}

.bok-ram { transition: transform .48s ease-in-out; }
.bok-scen[data-lage="stangd"] .bok-ram { transform: translateX(calc(var(--skjut, 0px) * -1)); }
.bok-scen[data-lage="slut"] .bok-ram { transform: translateX(var(--skjut, 0px)); }

@media (prefers-reduced-motion: reduce) {
  .bok-ram { transition: none; }
}

#bok { margin: 0 auto; }

.bok-sida {
  background: var(--papper);
  overflow: hidden;
}

.bok-sida img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The pages are photographs of print. Without this they inherit the global
     img rule's max-width and lose a pixel row at the fold on fractional page
     widths. */
  max-width: none;
}

/* The two hard covers carry the album's own board colour behind the artwork,
   so the half-millimetre of board that shows at the fold is never white. */
.bok-sida--parm { background: #1c1a18; }

/* ==========================================================================
   TELEFONEN: PANELEN OCH LÄSAREN
   Dennis 2026-08-12: häftet i skärmformat som täcker hela sidan, och när man
   trycker på det öppnas boken i sin egen vy där man sveper bladen.

   Varför en panel och inte sidan själv: sidorna är 1,078:1, mätta ur trycket,
   och en telefon är ~9:19,5. Ett skärmformat kan alltså aldrig VARA en sida --
   panelen bär pärmens foto, och sidorna bor i läsaren.

   html.bok-mobil sätts av bok.js under 52rem. Klassen står på roten och inte på
   sektionen, för läsaren låser dokumentets scroll och det är rotens sak.
   ========================================================================== */

/* SCENEN ÄR FORTFARANDE BORTA PÅ TELEFON -- den pinnade, scrolldrivna boken
   mätte 10,6 skärmhöjder för en sida på 375x347 och är ersatt av läsaren.
   PORTALEN ÄR DÄREMOT TILLBAKA, Dennis 2026-08-17: telefonen ska ha samma tre
   akter som skrivbordet. Akt 1 är alltså samma element och samma regler i båda
   lägena; det är bara akt 2 som skiljer sig, för en scrolldriven bok finns inte
   här. */
.bok-mobil .bok-scen { display: none; }

/* AKT 2 VÄNTAR BAKOM DÖRREN. Panelen visas först när html.bok-inne satts -- samma
   klass som skrivbordet använder, satt av samma knapp. Utan den här raden låg
   panelen och portalen på varandra som två helskärmar i rad, och sidan hade två
   ingångar där den ska ha en.

   [hidden] städas bort av bok.js när dörren öppnas; regeln nedan är det som gör
   att den ligger still i flödet fram till dess. */
.bok-mobil .bok-panel { display: none; }

.bok-mobil.bok-inne .bok-panel {
  display: grid;
  position: relative;
  /* Hela skärmen minus sidhuvudet. svh, inte vh, för att adressfältet på iOS
     annars äter 60 px av botten. */
  min-height: calc(100svh - var(--topp-h, 5.75rem));
  align-content: center;
  justify-items: center;
  text-align: center;
  gap: clamp(1.1rem, 3svh, 2rem);
  padding: clamp(2rem, 6svh, 4rem) var(--s-5);
  /* Klipper fallet, precis som .bok-pinne gör på skrivbordet: boken ska komma in
     bakom panelens överkant och inte uppifrån sidhuvudet. */
  overflow: clip;
}

/* BOKEN ÄR ETT FÖREMÅL PÅ MÖRK MARK, inte en helskärmsgrund bakom text.

   DEN GAMLA LÖSNINGEN VAR ETT RIKTIGT FEL, inte en smaksak: pärmfotot låg
   `object-fit: cover` över hela panelen med `object-position: 50% 38%`, och på
   375 px landade omslagets EGEN tryckta text ("ÄKTA WIENERSCHNITZEL / FRÅN WIEN
   TILL HORNSTULL") exakt där panelens rubrik stod. Två uppsättningar versaler i
   varandra, båda oläsliga, och slöjan var som tunnast just där. Ingen kontroll
   kunde se det -- kontrasten mättes mot en medelyta och den var grön.

   Bredden följer portalens ordmärke (28rem/74vw) så de två akterna står i samma
   spalt, och höjden faller ur pärmens egen kvot. */
.bok-panel__bok {
  display: block;
  /* STÖRRE, Dennis 2026-08-19: "kan vi även göra boken lite större så den tar
     upp lite mer yta". 62vw band bakom talet: panelen är 774 px hög på en
     390-skärm och pärmen bara 242 -- en fjärdedel av lådan, med tomrum kvar
     över och under. Ingen annan post i panelen växer med den (vinken och
     knappen har sina egna mått), så det finns höjd att ta av innan
     max-height:56svh ens blir den bindande gränsen. */
  width: min(26rem, 82vw);
  max-height: 56svh;
  filter: drop-shadow(0 18px 34px rgb(0 0 0 / .55));
}

.bok-panel__parm {
  display: block;
  width: 100%;
  height: auto;
  max-height: 56svh;
  object-fit: contain;
}

/* BOKEN FALLER IN, samma keyframes som ramen använder på skrivbordet -- inte en
   kopia av dem. Dennis 2026-08-17: "animationerna saknas på mobil, lägg tillbaka
   dem så det efterliknar desktop", och fallet är den rörelse han själv beskrev
   när entrén byggdes ("boken kan istället falla ner ifrån toppen").

   `[data-entre]` och inte `[data-entre="faller"]`, av exakt samma skäl som på
   skrivbordet: attributet stegas vidare till "landad", och en animation som TAS
   BORT slänger sitt slutläge -- boken hade hoppat en bildruta just när den ska
   ligga still.

   VAD SOM INTE FÖLJER MED: märket, hjärtat och flaggan som faller ned på pärmen
   på skrivbordet. De ligger i .bok-pafall inne i scenen och placeras av bok.js ur
   pixelrektanglar mätta mot skrivbordets ram, alltså finns de inte att flytta hit
   utan en egen uppmätning. Telefonens pärm är omslag-hel.webp, som bär dem
   TRYCKTA -- alltså samma slutbild som skrivbordets animation lämnar. */
.bok-panel[data-entre] .bok-panel__bok {
  animation: bok-boken-faller 780ms both;
}

@media (prefers-reduced-motion: reduce) {
  .bok-panel[data-entre] .bok-panel__bok { animation: none; }
}

.bok-panel__ord {
  display: grid;
  gap: var(--s-4);
  justify-items: center;
}

.bok-panel__rad {
  margin: 0;
  max-width: 26ch;
  font-family: var(--f-bok);
  font-size: var(--t-sm);
  line-height: 1.35;
  color: rgb(245 239 228 / .82);
}

/* --- läsaren ------------------------------------------------------------- */

/* Dokumentet får inte gå att scrolla bakom läsaren. overflow på ROTEN och inte
   på body: body har sin egen bakgrund och en overflow där lämnar iOS kvar en
   gummiscroll bakom vyn. Positionen sparas i JS och läggs tillbaka vid
   stängning, eftersom en låst rot i Safari kan nolla den. */
html.bok-last { overflow: hidden; }

/* --- the door is shut ----------------------------------------------------
   Set by bok.js on the scroll-driven path only, and only when the page loads
   at the top: the history page arrives as one screen with one button on it,
   and the scroll opens when the button is pressed. It is not in the served
   markup on purpose -- see the long note in bok.js. scrollbar-gutter keeps the
   page from jumping sideways by a scrollbar's width at the moment it opens. */
html.bok-vantar {
  overflow: hidden;
  scrollbar-gutter: stable;
}

/* --- boken öppnas och stängs, och scrollen får vänta -----------------------
   Dennis 2026-08-17: man ska inte kunna hetsa förbi ankomsten och stängningen.
   Sätts av bok.js kring de två gesterna och släpps av en klocka; se den långa
   noten där för varför det aldrig kan sitta kvar.

   scrollbar-gutter av samma skäl som dörren ovan, men det gör mer här: hållet
   armeras MITT PÅ en sida som redan har en rullningslist, så utan reserverad
   plats byter dokumentet bredd i det ögonblick greppet tas -- och en bredd som
   ändras väcker resize-lyssnaren, som river och bygger om boken mitt i sin egen
   öppning. */
html.bok-haller {
  overflow: hidden;
  scrollbar-gutter: stable;
}

.bok-lasare {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: grid;
  /* Två rader sedan toppraden lades ovanpå i stället för i flödet: uppslaget och
     vinken. Boken får hela höjden mellan dem. */
  grid-template-rows: 1fr auto;
  background: #0f0b07;
  overscroll-behavior: contain;
  /* Svepet ned. --ned skrivs av bok.js medan fingret drar, och nollas när det
     släpper. translate och inte transform: duken inuti äger sin egen transform,
     och två egenskaper som inte krockar är billigare än en som måste upprepas. */
  translate: 0 var(--ned, 0px);
  transition: translate 240ms cubic-bezier(0.2, 0.8, 0.3, 1);
}
/* Medan fingret ligger kvar följer vyn handen direkt, utan efterhäng. */
.bok-lasare--lagger { transition: none; }
.bok-lasare[hidden] { display: none; }

/* TOPPRADEN TAR INGEN PLATS LÄNGRE. Dennis 2026-08-17: "läsarvyn ska INTE läsa
   som en meny, jag ogillar krysset i toppen och räknaren 2 / 20". Raden är inte
   borttagen ur markupen -- den bär vyns tillgängliga namn och sin aria-live-region,
   se notisen i sida_ovriga.py -- men den är noll hög och ritar ingenting.

   `position: absolute` och inte `display: none`: en gömd rad tar med sig sin egen
   knapp ur tangentbordets ordning, och då hade en läsare utan finger bara haft
   Escape. Raden ligger alltså kvar ovanpå vyn, osynlig, tills något i den får
   fokus. */
.bok-lasare__topp {
  position: absolute;
  inset: 0 0 auto;
  z-index: 2;
  display: flex;
  align-items: flex-start;
  padding: var(--s-3) var(--s-4);
  pointer-events: none;
}

/* KNAPPEN TRÄDER FRAM NÄR DEN FÅR TANGENTBORDSFOKUS, och bara då. Ett kryss som
   ingen ser förrän man tabbar till det är inte en meny -- det är den enda vägen ut
   för den som inte kan svepa. :focus-visible och inte :focus: ett tryck någonstans
   i vyn ska aldrig kunna tända den. */
.bok-lasare__stang {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  border: 0;
  background: none;
  color: var(--guld-ljus);
  cursor: pointer;
}

.bok-lasare__stang:focus-visible {
  position: static;
  display: grid;
  place-items: center;
  /* 2,75rem, samma tappyta som knapparna. WCAG 2.5.8 kräver 24, sajten ger 44. */
  width: 2.75rem;
  height: 2.75rem;
  margin: 0;
  overflow: visible;
  clip-path: none;
  border: 1px solid rgb(232 200 106 / .3);
  background: rgb(15 11 7 / .92);
  font-size: 1.1rem;
  pointer-events: auto;
}
.bok-lasare__zoom {
  padding: 0.1rem 0.4rem;
  border: 1px solid var(--guld);
  color: var(--guld-ljus);
}
.bok-lasare__zoom[hidden] { display: none; }

.bok-lasare__scen {
  position: relative;
  display: grid;
  place-items: center;
  overflow: hidden;
  /* Motorn äger gesten i oskalat läge, så webbläsaren får inte tolka svepet som
     en scroll. I zoomat läge byter JS den här till "none" och panorerar själv. */
  touch-action: pan-y;
}

.bok-lasare__duk {
  /* Duken är sidans egen låda -- uppmätt 390x390 på en 390 px telefon, alltså
     exakt sidan och inte scenen. Det är vad inbjudan nedan hänger i: bandet på
     baksidan räknas ur SIDANS höjd, och en förälder som är högre än sidan hade
     lagt orden under bandet. (transform ovan gör redan duken till
     containing block för allt absolut inuti; raden står här för att det är ett
     krav och inte en bieffekt.) */
  position: relative;
  /* Zoomen är en transform på duken och inte en storleksändring på sidan:
     motorns lådor räknas om vid varje storleksändring, och en omräkning mitt i
     en vändning tappar bladet. */
  transform: scale(var(--zoom, 1)) translate(var(--pan-x, 0px), var(--pan-y, 0px));
  transform-origin: center center;
  transition: transform 220ms ease-out;
  will-change: transform;
}
.bok-lasare--drar .bok-lasare__duk { transition: none; }
.bok-lasare--zoom .bok-lasare__scen { touch-action: none; }
/* Inzoomad är dragningen panorering, inte bläddring -- så motorn ska inte se
   pekaren alls. Utan det slåss de två om samma gest och sidan vänds medan man
   drar för att läsa. */
.bok-lasare--zoom .bok-lasare__host { pointer-events: none; }

.bok-lasare__vink {
  margin: 0;
  padding: var(--s-3) var(--s-4) var(--s-5);
  text-align: center;
  font-size: var(--t-xs);
  line-height: 1.4;
  color: rgb(245 239 228 / .62);
  transition: opacity 300ms ease;
}
/* Två sätt att tystna, och det som kommer först gäller: första bläddringen, eller
   tre sekunder. Klockan behövs sedan krysset togs bort -- vinken bär numera den
   enda synliga vägen ut, och den som inte bläddrar direkt ska ändå ha hunnit läsa
   den innan den går. */
.bok-lasare--rord .bok-lasare__vink,
.bok-lasare--tyst .bok-lasare__vink { opacity: 0; }

/* INBJUDAN PÅ TELEFON, Dennis 2026-08-19: "på historien sidan så finns inte den
   där boka bord CTA:n och texten bli en del av vår historia saknas också".

   Den saknades av EN anledning, och det var inte en glömd rad: orden bor i
   .bok-ram inne i .bok-scen, och scenen är display:none på telefon. Akt 3 fanns
   alltså bara på skrivbordet och i kolumnen.

   VAR DEN LIGGER NU: på baksidan, i läsaren, i samma tomma band som på
   skrivbordet -- bok.js FLYTTAR elementet in i duken när läsaren byggs, precis
   som sidorna flyttas dit. Ett andra exemplar i markupen hade betytt två
   likadana Boka bord-knappar i dokumentet, varav en alltid gömd.

   Placeringen är ärvd, inte kopierad: .bok-slut ovan räknar bandet ur
   --sida-b/--sida-h, och bok.js publicerar telefonens sidmått i samma två
   variabler. Uppmätt band: 100 px på 390 px, 96 px på 375 px.

   SYNS BARA NÄR BAKSIDAN LIGGER FRAMME, och det är samma villkor som
   skrivbordets data-inbjudan: motorn står still OCH sista bladet är det som
   visas. Inget tonas fram -- orden är tryckta på pappret, inte pålagda av en
   webbsida.

   OCH INTE I ZOOMAT LÄGE. Dubbeltryck är till för att läsa trycket; då är
   inbjudan en knapp som ligger i vägen för panoreringen och kan hamna utanför
   ramen med pappret. */
.bok-lasare .bok-slut {
  opacity: 0;
  visibility: hidden;
}

.bok-lasare[data-inbjudan="pa"]:not(.bok-lasare--zoom) .bok-slut {
  opacity: 1;
  visibility: visible;
}

/* Samma eftergift som scenen gör, av samma skäl: bandet rymmer inte två rader av
   den ritade graden OCH en 44 px-knapp på den minsta sidan, och knappen är den
   som inte får ge sig (matt_bok.mjs mäter den som tappyta). Rubriken får då gå
   ut i sidans fulla bredd, vilket gör två rader till en. */
.bok-lasare[data-slut="smal"] .bok-slut__rad { max-width: none; }

/* --- still fallback ------------------------------------------------------
   No flipping engine at all: the pages become a plain column of images. This
   is the state a visitor with prefers-reduced-motion gets, and the state the
   page falls back to if the script never runs. It is a real reading
   experience, not a placeholder. */

.bok-stilla .bok-scen { height: auto !important; }

.bok-stilla .bok-pinne {
  position: static;
  height: auto;
  display: block;
  overflow: visible;
  padding-block: var(--s-6);
}

.bok-stilla .bok-svalg { transform: none; opacity: 1; }
.bok-stilla .bok-ram { width: auto !important; transform: none !important; }
/* Without motion the two marks stay where they belong, printed on the cover,
   and the invitation is simply the last thing on the page. */
.bok-stilla .bok-pafall { display: none; }
/* height and transform have to go with the absolute position: the band is a
   box cut out of a pinned page, and there is no pinned page here. Left in, a
   static block would keep the band's height and sit half its own height too
   high. */
.bok-stilla .bok-slut {
  position: static;
  width: auto;
  height: auto;
  transform: none;
  padding-block: var(--s-7);
}

.bok-stilla #bok {
  display: grid;
  gap: var(--s-5);
  width: min(46rem, 92%);
  margin-inline: auto;
}

/* On a phone the same column runs edge to edge. The 8 % the desktop column
   gives away is 30 px of a 375 px screen, and every one of them is print: the
   pages carry their own printed margins, so the paper still has air inside its
   own edge. Measured against the column's own default: the print is shrunk
   4,03x at full width against 4,38x at 92 %, so the type grows 9 % for nothing
   but a rule. Against the flipping book it is a wash -- that page was already
   375 px wide; what the column buys is the whole page visible at once, plain
   scrolling, and no engine to fall out of step with the scroll. */
.bok-kolumn #bok {
  width: 100%;
  gap: var(--s-4);
}

.bok-stilla .bok-sida {
  position: relative !important;
  width: auto !important;
  height: auto !important;
  transform: none !important;
  /* The book's own ratio, published on the section by sida_ovriga.py out of
     bok.json. A literal here was a second copy of a number that lives in the
     manifest, and when the book went square on 2026-08-14 this was the copy
     that did not get the message. */
  aspect-ratio: var(--bok-kvot, 1);
  box-shadow: 0 .75rem 2rem rgba(0, 0, 0, .38);
}

