/* CHANGED 04.08 - see changes.txt */
/* ============================================================ FONTS */
@font-face{font-family:"Archivo Narrow";font-weight:500;font-style:normal;font-display:swap;
  src:url("fonts/archivonar.woff2") format("woff2")}
@font-face{font-family:"Archivo Narrow";font-weight:600;font-style:normal;font-display:swap;
  src:url("fonts/archivonar6.woff2") format("woff2")}
@font-face{font-family:"Archivo Narrow";font-weight:700;font-style:normal;font-display:swap;
  src:url("fonts/archivonar7.woff2") format("woff2")}

/* ============================================================ TOKENS
   Every colour is sampled from the restaurant itself: the cream of the enamel
   street plate, the ink of its frame, the signal red of TAKE-AWAY, and the
   light blue of the staff shirts. */
/* CHANGED 08.09 - see changes.txt */
/* GREEN REPLACES THE BLACK. Dennis 2026-08-12: "Dominanta färger: Mörkgrön istället
   för svart, vitt, beige". Scoped on his behalf to the black only -- the enamel plate
   and the tile field keep their cream and white, because both are transcriptions of
   real objects: the plate is the sign at the entrance and the tile is the wall behind
   the counter. There is no green plate on Blasieholmsgatan.

   THE GREEN IS SAMPLED, like every other colour here: the bentwood chairs in the
   dining room, warmed off their petrol toward green so it does not read as a second
   --shirt. The room's other greens were measured and rejected -- the bar's ceramic
   vase is olive, which reads trattoria on a house that sells fish, and the curtains
   are too pale to carry cream type.

   TWO VALUES, NOT ONE, and the split is the load-bearing part. --ink keeps its name
   and its job (type, frames, hairlines) and only changes value, so all 17 colour and
   20 border declarations follow without being touched. --green is the surface, one
   step lighter, so a frame drawn in --ink on a green field is still visible. Swapping
   --ink for --green everywhere instead would have flattened every plaque into its own
   border.

   RED IS NOT TYPE ON GREEN: 1.87:1, worse than the 2.68:1 that already forced
   .s-blue .eyebrow onto its own hue. Red stays a button surface here, with cream on
   the red and never red on the green. The gate measures this per surface. */
:root{
  --enamel:#E4E4D8;
  --enamel-hi:#F0EEE5;
  /* Was #16181A. Green-black: 12.47:1 on --enamel where the black measured 13.89,
     both AAA, and no longer a black. */
  --ink:#14251F;
  --ink-soft:#28403A;
  /* The dominant surface -- nav, footer, plaques, dark sections, the hero ground.
     Cream on it is 9.58:1 and white 12.28:1, both AAA. */
  --green:#1E3A34;
  /* One field lighter, for a green block that has to sit on green without a border.
     Cream on it is 6.91:1, which is AA for body and AAA for nothing -- so it carries
     no small print. */
  --green-soft:#2C5145;
  /* Lines and hover on green: 4.43:1, past WCAG 1.4.11's 3:1 for a UI boundary and
     past 3:1 for large type, which is all it is ever used for. */
  --green-line:#7FA396;
  --red:#B4231E;
  --red-deep:#8E1B17;
  --shirt:#A8BCCB;
  /* The shirt tone is one value, and direction A leans on light blue as paint
     rather than as an accent, so it needs a field, a line and a text-safe dark
     of the same hue. --shirt-deep on --shirt-pale measures 9.73:1. */
  --shirt-pale:#DDE7ED;
  --shirt-mid:#8FA9BB;
  --shirt-line:#7C97A9;
  --shirt-deep:#223845;
  --tile:#F9F7F2;
  --grout:#DFDCD2;
  /* The same wall, wet. Havsgrillen is the fish hall and a market hall is cold
     white and daylight, not warm cream, so the tile gets a second temperature
     rather than a second material. Both are the shirt hue, so this is not a
     ninth colour: --ice sits above --shirt-pale and --ice-grout between it and
     --shirt-mid. Body text #333F3A measures 10.13:1 on --ice — the gate prints
     the real ratio in every check, so these comments must not be a second,
     drifting copy of a number qa.mjs already owns. */
  --ice:#F2F7FA;
  --ice-grout:#D5E2EA;
  /* The counter's chalk signs are --ink and its rail is --shirt-line: the fish
     hall is built out of the palette that exists, not out of a slate grey and a
     stainless grey that would be two more names for colours we already have. */

  /* CHANGED 08.09: 34rem until the site went to one condensed typeface. A narrow face fits
     more characters into the same width, and measured in the new one a 34rem column held 87
     characters of body copy at --step-0 -- past the 80 this stylesheet keeps to, which is the
     line length where a reader starts losing their place on the return sweep. 30rem measures
     77. The leads (--step-1) were never the problem at either width; they come down with it
     because both use this one token, and 58 characters is a comfortable lead. */
  --measure:30rem;
  --gut:clamp(1.25rem,4vw,3.5rem);
  --bar-h:60px;

  --step--1:clamp(.78rem,.76rem + .12vw,.86rem);
  --step-0:clamp(.98rem,.95rem + .18vw,1.08rem);
  --step-1:clamp(1.15rem,1.08rem + .38vw,1.4rem);
  --step-2:clamp(1.5rem,1.32rem + .9vw,2.1rem);
  --step-3:clamp(2rem,1.6rem + 2vw,3.4rem);
  --step-4:clamp(2.6rem,1.8rem + 4vw,5.2rem);
}

/* ============================================================ RESET */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
/* Dennis 2026-08-03: "footern och botten ska vara densamma". body is enamel, so anything
   past the end of the body box -- overscroll, and the strip under the footer on a short
   page -- showed cream against a dark footer. The canvas takes the footer's ink; body keeps
   its own enamel, so nothing inside the page changes. */
html{background:var(--green);
  -webkit-text-size-adjust:100%;scroll-behavior:smooth;
  /* **The one place the sticky chrome is allowed for.** scroll-padding on the
     scrollport and scroll-margin on the target ADD UP, and having both is how a
     category heading ended up 433px down the page instead of 187 — measured, not
     guessed. So this is the whole allowance and nothing downstream repeats it.
     The two menu-page bars are 0px on every other page, which leaves the fixed
     bar's height there. */
  scroll-padding-top:calc(var(--bar-h) + var(--tabs-h,0px) + var(--rail-h,0px) + 1rem)}
/* No overflow-x:hidden. It would paper over layout bugs instead of surfacing
   them, and qa.mjs is what guards against horizontal scroll. */
/* CHANGED 08.09 - see changes.txt */
/* ONE TYPEFACE, EVERYWHERE. Client 2026-09-08: "kan vi göra brödtexterna överallt i samma
   font som alla rubriker ... så vi får en enhetlighet på sidan. Så samma typsnitt överallt
   på sidan." The site ran two widths of one superfamily -- Archivo Narrow for plaques, nav,
   headings, dish names and prices; Archivo for body, leads and form labels. Now it is Narrow
   for all of it, and this line is the only place that decides.

   500, not 400: Archivo Narrow is subset here at 500/600/700 and has no 400. Body copy at
   500 in a condensed face is a little heavier than the 400 it replaces, which reads closer to
   the plaques rather than fighting them -- which is the point of the change.

   AND --measure CAME DOWN WITH IT. A condensed face fits more characters into the same
   millimetre, so the 34rem column that held 66 characters in Archivo held 78 in Narrow --
   inside the 80 this stylesheet keeps to, but only just, and the guideline exists because a
   long line loses the reader's place on the return sweep. Measured and set to 30rem, which is
   the same 66 characters it was before. See the token.

   The three Archivo files are deleted rather than left unreferenced: 42 kB of woff2 that
   nothing asks for. The 30 redundant font-family declarations went with them -- every one
   named this same face, so they said nothing that this line does not. */
body{
  background:var(--enamel);color:var(--ink);
  font:500 var(--step-0)/1.65 "Archivo Narrow",system-ui,sans-serif;
}
/* height:auto matters: the markup carries real width/height attributes so the box
   is reserved before decode, and without this the intrinsic height is kept while
   the width shrinks, which stretches the photo. */
img,video,svg{display:block;max-width:100%;height:auto}
/* display:block above beats the UA rule for [hidden], so a hidden img or video
   would still paint. Restore it once, globally. */
[hidden]{display:none!important}
button,input,select,textarea{font:inherit;color:inherit}
a{color:inherit}
/* The focus ring, measured per surface. --shirt is 9.09:1 on ink but only
   1.53:1 on enamel, 1.83 on tile, 1.56 on the pale blue and 1.25 on the solid
   blue — effectively invisible on four of the five grounds the site uses.
   --shirt-deep is the mirror: 4.98 to 11.41 on all four light grounds, 1.46 on
   ink. One colour cannot serve both, so the light grounds get the default and
   the dark surfaces name themselves. */
:where(a,button,input,select,textarea,summary,[tabindex]):focus-visible{
  outline:2px solid var(--shirt-deep);outline-offset:3px;border-radius:1px;
}
:where(.s-ink,.hdr,.sheet,.cookie,footer) :where(a,button,input,select,textarea,summary,[tabindex]):focus-visible{
  outline-color:var(--shirt);
}
.vh{position:absolute!important;width:1px;height:1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap}

/* ============================================================ SURFACES
   Running bond subway tile, drawn rather than photographed so it stays crisp
   and weightless. Direction A is the tiled hall, so the bond is meant to be
   seen: the grout carries real contrast and the tile is the page's ground
   rather than a texture under one section. */
/* CHANGED 08.09 - see changes.txt */
/* BEVELLED, Dennis 2026-08-12: "Kakel = Gör 3D dimensionellt". The bond, the 88x44
   tile and the 2px grout are unchanged -- what is added is a 2px white edge along
   each tile's top and left and a 2px shade along its bottom and right, which is how
   a glazed subway tile actually catches light from a room lit from above. It is drawn
   in the same one SVG rather than as a second background layer, so the wall is still
   one paint and one HTTP-free data URI, and the geometry is generated rather than
   hand-typed: the face rects are computed from the grout's own coordinates, so a
   change to the bond cannot leave the bevel behind.

   PAINT ORDER IS LOAD BEARING: highlight, then shade, then grout last. The grout has
   to land on top or the bevel's 2px strips would sit over the joint and the tiles
   would read as one sheet with a pattern on it instead of as separate tiles.

   On a phone the pattern is halved to 96x48 by the query below, so the bevel scales
   to ~1.1px with it. Fainter, deliberately: at four tiles across, a full-strength
   bevel is louder than the wall. */
.s-tile{
  background-color:var(--tile);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='176' height='88'%3E%3Cg fill='%23FFFFFF'%3E%3Crect x='2' y='2' width='86' height='2'/%3E%3Crect x='2' y='2' width='2' height='42'/%3E%3Crect x='90' y='2' width='86' height='2'/%3E%3Crect x='90' y='2' width='2' height='42'/%3E%3Crect x='0' y='46' width='44' height='2'/%3E%3Crect x='0' y='46' width='2' height='42'/%3E%3Crect x='46' y='46' width='86' height='2'/%3E%3Crect x='46' y='46' width='2' height='42'/%3E%3Crect x='134' y='46' width='42' height='2'/%3E%3Crect x='134' y='46' width='2' height='42'/%3E%3C/g%3E%3Cg fill='%23EBE7DE'%3E%3Crect x='2' y='42' width='86' height='2'/%3E%3Crect x='86' y='2' width='2' height='42'/%3E%3Crect x='90' y='42' width='86' height='2'/%3E%3Crect x='174' y='2' width='2' height='42'/%3E%3Crect x='0' y='86' width='44' height='2'/%3E%3Crect x='42' y='46' width='2' height='42'/%3E%3Crect x='46' y='86' width='86' height='2'/%3E%3Crect x='130' y='46' width='2' height='42'/%3E%3Crect x='134' y='86' width='42' height='2'/%3E%3Crect x='174' y='46' width='2' height='42'/%3E%3C/g%3E%3Cg fill='%23DFDCD2'%3E%3Crect x='0' y='0' width='176' height='2'/%3E%3Crect x='0' y='44' width='176' height='2'/%3E%3Crect x='0' y='0' width='2' height='44'/%3E%3Crect x='88' y='0' width='2' height='44'/%3E%3Crect x='44' y='44' width='2' height='44'/%3E%3Crect x='132' y='44' width='2' height='44'/%3E%3C/g%3E%3C/svg%3E");
}
/* The fish hall's wall: the same bond, wet and cold. Havsgrillen used to be the
   page's one dark room, which is the opposite of what a market hall is, so the
   section takes the tile at a second temperature instead of a second material.
   It follows the hero, which is warm tile, and the two are told apart by the
   grout as much as by the ground — hence a grout that carries more contrast than
   the hero's, not less. The seam between them is the rail below. */
/* CHANGED 04.08 - see changes.txt */
.s-ice{
  background-color:var(--ice);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='176' height='88'%3E%3Cg fill='%23FFFFFF'%3E%3Crect x='2' y='2' width='86' height='2'/%3E%3Crect x='2' y='2' width='2' height='42'/%3E%3Crect x='90' y='2' width='86' height='2'/%3E%3Crect x='90' y='2' width='2' height='42'/%3E%3Crect x='0' y='46' width='44' height='2'/%3E%3Crect x='0' y='46' width='2' height='42'/%3E%3Crect x='46' y='46' width='86' height='2'/%3E%3Crect x='46' y='46' width='2' height='42'/%3E%3Crect x='134' y='46' width='42' height='2'/%3E%3Crect x='134' y='46' width='2' height='42'/%3E%3C/g%3E%3Cg fill='%23DFE9EF'%3E%3Crect x='2' y='42' width='86' height='2'/%3E%3Crect x='86' y='2' width='2' height='42'/%3E%3Crect x='90' y='42' width='86' height='2'/%3E%3Crect x='174' y='2' width='2' height='42'/%3E%3Crect x='0' y='86' width='44' height='2'/%3E%3Crect x='42' y='46' width='2' height='42'/%3E%3Crect x='46' y='86' width='86' height='2'/%3E%3Crect x='130' y='46' width='2' height='42'/%3E%3Crect x='134' y='86' width='42' height='2'/%3E%3Crect x='174' y='46' width='2' height='42'/%3E%3C/g%3E%3Cg fill='%23D5E2EA'%3E%3Crect x='0' y='0' width='176' height='2'/%3E%3Crect x='0' y='44' width='176' height='2'/%3E%3Crect x='0' y='0' width='2' height='44'/%3E%3Crect x='88' y='0' width='2' height='44'/%3E%3Crect x='44' y='44' width='2' height='44'/%3E%3Crect x='132' y='44' width='2' height='44'/%3E%3C/g%3E%3C/svg%3E");
  /* Two tiled sections meeting would read as one wall with a colour change in
     the middle of it. A stainless line is where the fish hall starts. */
  border-top:2px solid var(--shirt-line);
}
/* On a phone an 88px tile is four tiles across and stops reading as tile at all,
   so the bond is halved rather than scaled with the viewport. */
@media(max-width:640px){.s-tile,.s-ice{background-size:96px 48px}}
/* The start page's blue was swapped to white tile for one revision on 2026-08-03 and put
   back: "på stora sällskap så kan blocket fortfarande vara den där blåa färg, sen vill jag
   ha den färgen på vi ses vid disken eller vid dörren också." So #stora-teaser is .s-blue
   again and #komhit moved from .s-blue-solid to the SAME .s-blue -- one pale field shared by
   two blocks rather than two different blues stacked. .s-blue-solid still exists for the
   enquiry form on Stora sällskap, which is the page's one task and wants the stronger
   ground. A .stora-teaser-tile separator lived here for that one revision, to keep two tiled
   sections from reading as one wall; with the blue back there is nothing to separate.
   Kontakt and Om oss keep the white tile -- that part stood. */
.s-enamel{background:var(--enamel)}
/* A white surface and a --white token lived here for half an hour on 2026-08-04, while the menu
   page was tried on white against pale blue against this enamel. The enamel won, so both went:
   the menu page is .s-enamel top to bottom and the sticky rails already carry that background,
   which is why nothing has to be scoped to the surface here. If a white ground is ever wanted
   again, the rails have to come with it -- their background spans the text column only, so on a
   ground that is not enamel they read as a plate stopping mid-screen. */
.s-ink{background:var(--green);color:var(--enamel)}
.s-ink .lead{color:#C2CCC6}
/* Light blue as paint, not accent: the pale field carries a whole section, the
   solid one carries the enquiry so the form reads as the page's one task. */
.s-blue{background:var(--shirt-pale);color:var(--shirt-deep)}
.s-blue .lead{color:#2E4655}
.s-blue-solid{background:var(--shirt-mid);color:#0F1D26}
.s-blue-solid .lead{color:#152B38}
/* Red survives the pale field at 5.23:1 but only reaches 2.68:1 on the mid one,
   under AA for the small caps an eyebrow uses, so there it takes the ink-dark of
   its own hue instead. Measured, not guessed. */
.s-blue-solid .eyebrow{color:#0F1D26}

/* ============================================================ TYPE */
.sign{font-weight:700;
  text-transform:uppercase;letter-spacing:.06em;line-height:1.02}
.eyebrow{font-weight:700;
  text-transform:uppercase;letter-spacing:.2em;font-size:var(--step--1);color:var(--red)}
/* Signal red on ink is only 2.71:1, so the dark sections and the footer use the
   shirt blue for eyebrows instead. */
.s-ink .eyebrow,footer .eyebrow{color:var(--shirt)}
h1,h2,h3,h4{font-weight:700;
  text-transform:uppercase;letter-spacing:.03em;line-height:1.04;text-wrap:balance}
h2{font-size:var(--step-3)}
h3{font-size:var(--step-2)}
h4{font-size:var(--step-1);letter-spacing:.08em}
.lead{font-size:var(--step-1);line-height:1.55;max-width:var(--measure);color:#333F3A;
  text-wrap:pretty}
p{max-width:var(--measure);text-wrap:pretty}

/* ============================================================ LAYOUT */
.wrap{max-width:1320px;margin-inline:auto;padding-inline:var(--gut)}
/* No scroll-margin-top: html's scroll-padding-top above is the single allowance
   for the fixed bar, and this was a second copy of it — every section reached by a
   hash landed 60px lower than it needed to, on every page, since the bar stopped
   hiding itself. */
section{padding-block:clamp(3.5rem,9vw,8rem)}
.rule{height:1px;background:currentColor;opacity:.22;border:0}
.stack>*+*{margin-top:1.1rem}
.grid2{display:grid;gap:clamp(1.75rem,5vw,4.5rem);align-items:center}
@media(min-width:900px){.grid2{grid-template-columns:1fr 1fr}
  .grid2--wide{grid-template-columns:1.15fr .85fr}}

/* ============================================================ ENAMEL PLATE
   The cream street sign: outer ink frame, a breath of enamel, then an inner
   hairline. Screws at the top because the real ones are bolted to the wall. */
.plate{
  position:relative;display:block;text-decoration:none;
  background:var(--enamel);color:var(--ink);
  border:2px solid var(--ink);padding:1.6rem 1.35rem 1.35rem;
  box-shadow:0 10px 30px rgba(0,0,0,.34);
  transition:transform .22s ease,box-shadow .22s ease;
}
.plate::before{
  content:"";position:absolute;inset:4px;border:1px solid var(--ink);
  pointer-events:none;
}
.plate::after{ /* the two mounting screws */
  content:"";position:absolute;top:11px;left:13px;right:13px;height:5px;
  background:
    radial-gradient(circle at 2.5px 2.5px,#8A8778 0 2.5px,transparent 2.5px) left top/5px 5px no-repeat,
    radial-gradient(circle at 2.5px 2.5px,#8A8778 0 2.5px,transparent 2.5px) right top/5px 5px no-repeat;
  pointer-events:none;
}
a.plate:hover,a.plate:focus-visible{transform:translateY(-4px);
  box-shadow:0 18px 44px rgba(0,0,0,.44)}
@media(max-width:759px){.plate{padding:1.15rem 1rem .95rem}}

/* ============================================================ PLAQUE
   The black enamel plaque that hangs over the counter: inset double line,
   dot ornaments either side of the word. */
.plaque{
  display:inline-flex;align-items:center;gap:.7em;
  background:var(--green);color:var(--enamel);
  border:1px solid var(--ink);
  box-shadow:inset 0 0 0 3px var(--ink),inset 0 0 0 4px rgba(228,228,216,.9);
  padding:.52em 1.15em;border-radius:3px;
  font-weight:700;text-transform:uppercase;
  letter-spacing:.15em;font-size:var(--step--1);text-decoration:none;
  white-space:nowrap;      /* a wrapped plaque breaks the fixed bar height */
  transition:color .18s ease,box-shadow .18s ease;
}
.plaque::before,.plaque::after{content:"";width:5px;height:5px;border-radius:50%;
  background:currentColor;flex:none;opacity:.9}
/* A plaque that is also an outbound link: .arr puts an arrow in ::after, which
   until now inherited the dot's 5px round box and rendered the glyph inside a
   filled circle. The trailing ornament becomes the arrow instead of wearing it. */
.plaque.arr::after{width:auto;height:auto;border-radius:0;background:none;
  font-size:.9em;line-height:1;margin-left:.1em;opacity:1}
a.plaque:hover,a.plaque:focus-visible,.plaque[aria-current="true"],
.plaque[aria-current="page"]{color:var(--shirt);
  box-shadow:inset 0 0 0 3px var(--ink),inset 0 0 0 4px var(--shirt)}
.plaque--lg{font-size:clamp(.95rem,.85rem + .5vw,1.3rem);padding:.6em 1.5em}

/* A plaque hung from an iron bracket, as over the ice counter. */
.hang{display:flex;flex-direction:column;align-items:center;margin-bottom:2.5rem}
/* The hanging stem above each plaque is gone, Dennis 2026-07-29: the signs read
   as signs without a bracket drawn over them. */

/* ============================================================ HEADER */
/* The bar is there from the first pixel on every page, including the start page.
   It used to slide in once the hero was behind you, which worked while the hero
   carried three nav plates of its own; direction A's hero is one plate with two
   buttons, so hiding the bar would land a visitor with no navigation at all. */
.bar{
  position:fixed;inset:0 0 auto;z-index:60;height:var(--bar-h);
  background:rgba(20,37,31,.94);backdrop-filter:blur(10px);
  border-bottom:1px solid rgba(228,228,216,.16);
  transition:background-color .3s ease,border-bottom-color .3s ease;
}
#main{padding-top:var(--bar-h)}
/* CHANGED 08.09 - see changes.txt */
/* THE START PAGE HAS NO TOP PADDING, so the video runs the full height of the viewport and
   up under the header. Every other page keeps it: they start at their own first line and
   have no picture for a transparent bar to sit on, so a transparent bar there would float
   over body copy.
   This was tried once against the OLD hero and backed out the same afternoon, because the
   two-pane plate's top frame got clipped by the viewport and the slideshow's pause control
   ended up under the bar at every width below 1200px. Both were symptoms of the hero, not
   of the header: the sign is centred now and the pause control is in the bottom corner, so
   neither can happen. See changes.txt for the measurements that settled it. */
body[data-page="start"] #main{padding-top:0}

/* Dennis 2026-08-12: "Nav transparent först -> blir vår mörkgröna färg när man scrollar."
   app.js adds .is-stuck past one bar-height of scroll -- see HEADER GROUND there -- which is
   the exact moment the video's first pixel row goes behind the bar.

   IT IS A SCRIM RATHER THAN NOTHING, and the strength is measured rather than tasted. The
   bar's type is --enamel cream and what is behind it is the client's film: across the loop
   the top 60px band has a mean luminance running to 0.62, and single pixels reach pure
   white, where cream is 1.03:1. 65% green over that mean is 5.07:1 and 70% over pure white
   is 4.64:1, so 70% is the floor and it is what is used. The eight photographs the old hero
   ran measured the same way and gave the same answer, which is some comfort that the number
   is about cream-on-bright and not about this one film.

   IT IS A FLAT WASH RATHER THAN A GRADIENT, and that was a correction. The first build put
   the scrim on a ::after with a gradient that held full strength across the bar and faded
   out below it, which looked better and was worse in two ways. It is not measurable -- the
   gate reads composited background COLOURS, so a pseudo-element gradient is invisible to it
   and the bar reported cream-on-cream at 1:1. And the shape was doing no work: nothing is
   written in the 38px below the bar, so the fade was decoration on the one surface where the
   contrast floor is the whole point. A flat .72 is above the .70 floor, is a real background
   on the element itself, and is one mechanism instead of two.
   The lesson worth keeping: a scrim that fades THROUGH its own type is the version to avoid.
   Solid at the top edge and transparent at the bar's bottom leaves roughly half strength at
   the type's centre line, which measures 2.6:1 and fails. */
/* CHANGED 10.09 - see changes.txt */
/* GENUINELY TRANSPARENT NOW, and the way there was not a lower number -- it was taking the
   contrast floor off the bar and putting it on the three things that actually needed one.

   The first version of this was a flat 72% green wash. It passed, and it satisfied the
   instruction on paper, but 72% green over a film reads as a dark green bar you can just
   about see through. That is not what "nav transparent först" describes.

   WHAT THE FLOOR ACTUALLY WAS. Eight things sit in this bar and FIVE already carry their own
   ground: the five nav plaques are .plaque, which is green on cream by definition; Boka bord
   is red; and the selected language chip is filled cream. None of them ever needed the bar.
   The three that did are handled individually below -- Take away, the language group and the
   burger -- and once they are, the only thing left on bare film is the WORDMARK, which has
   no minimum at all: WCAG 1.4.3 exempts text that is part of a logo or brand name. Its
   legibility is a design judgement, not a compliance one, and it was checked by eye at six
   widths against the film's brightest frames.

   So the bar carries no background here. The blur stays, because it is the one thing that
   helps the wordmark without darkening the picture -- it softens the film's detail behind a
   cream mark rather than putting a layer over it. */
body[data-page="start"] .bar{
  background-color:transparent;backdrop-filter:blur(7px);
  border-bottom-color:transparent;
}
/* TAKE AWAY IS FILLED HERE, and it is the same move Meny on the hero needed for the same
   measured reason: cream 12px type with a cream 1px outline on a moving photograph is small
   text, so WCAG wants 4.5:1, and the film's nav band runs to a mean luminance of 0.62 where
   cream manages under 2:1. Filled, it carries its own ground and the film behind it stops
   mattering. Enamel on ink is 12.47:1.
   It reverts to the outline as soon as the bar turns green, because there it has a ground. */
body[data-page="start"] .bar:not(.is-stuck) .btn-ghost{
  background:var(--enamel);color:var(--ink);border-color:var(--ink)}
body[data-page="start"] .bar:not(.is-stuck) .btn-ghost:hover,
body[data-page="start"] .bar:not(.is-stuck) .btn-ghost:focus-visible{
  background:var(--enamel-hi)}
/* The language group and the burger get a ground of their own rather than a scrim over the
   whole bar. Both are UI components under WCAG 1.4.11, which asks 3:1 of their boundary --
   the group's 40% cream outline and the burger's three cream bars measure well under that on
   a bright frame. .62 green behind them clears it with room, and two 44px controls carrying
   their own ground is a fraction of the picture that a full-width wash costs.
   The inactive language button is deliberately at .55 opacity, so it is the one piece of type
   here that would still be weak on bare film -- this is what fixes it. */
body[data-page="start"] .bar:not(.is-stuck) .lang,
body[data-page="start"] .bar:not(.is-stuck) .burger{
  background:rgba(20,37,31,.62);border-color:rgba(228,228,216,.55)}
body[data-page="start"] .bar.is-stuck{
  background-color:rgba(20,37,31,.94);backdrop-filter:blur(10px);
  border-bottom-color:rgba(228,228,216,.16);
}
/* The colour change answers a scroll the guest made, so it is motion they asked for -- but
   it is still a 300ms cross-fade on a fixed element, and reduced motion means the state
   flips instead of easing. */
@media(prefers-reduced-motion:reduce){
  .bar{transition:none}
}
.bar-in{height:100%;display:flex;align-items:center;gap:clamp(.6rem,2vw,1.5rem)}
/* The wordmark is wide and short, so the link needs its own height to be a
   comfortable tap target rather than a 31px sliver. */
.bar-logo{color:var(--enamel);flex:none;display:inline-flex;align-items:center;
  min-height:44px}
.bar-logo svg,.bar-logo img{display:block;width:clamp(62px,7vw,84px);height:auto}
.bar-nav{display:none;margin-left:auto;align-items:center;gap:.4rem}
/* Threshold measured, not guessed. With five pages the bar's intrinsic width is
   1260px in Swedish and 1300px in English, so the old 1040px was 300px short and
   the language pair fell off the right edge. Dropping the plaque dots inside the
   bar and tightening the padding brings it to 1076/1116, and the query sits above
   the wider of the two languages with room after the wordmark. Both languages have
   to fit the same query — the switch does not reload the page.
   Re-measure with scratchpad/natural-bar.mjs if a page is ever added. */
@media(min-width:1180px){.bar-nav{display:flex}}
/* Five dotted plaques in a row at 13px is ornament reading as noise, and the dots
   cost about 145px of the width the row does not have. Plain in the bar; the
   dotted plaque stays what marks a section heading. */
.bar-nav .plaque{padding:.52em .85em;letter-spacing:.12em}
.bar-nav .plaque::before,.bar-nav .plaque::after{display:none}
.bar-tools{display:flex;align-items:center;gap:.5rem;margin-left:auto}
@media(min-width:1180px){.bar-tools{margin-left:0}}
/* Below the desktop breakpoint the bar keeps only the logo, Boka bord and the
   burger. Take away and the language switch live in the sheet, so repeating
   them here just overflowed the 60px bar. */
/* Below the threshold the two buttons and the language pair live in the sheet,
   so the bar is the wordmark and the burger. */
@media(max-width:1179px){.bar-tools>.plaque,.bar-tools>.btn-red,
  .bar-tools>.btn-ghost,.bar-tools>.lang{display:none}}
.lang{display:flex;flex:none;border:1px solid rgba(228,228,216,.4);border-radius:2px;
  overflow:hidden}
.lang button{background:none;border:0;cursor:pointer;color:var(--enamel);
  font-weight:700;font-size:.72rem;
  letter-spacing:.12em;padding:0 .9em;min-height:36px;opacity:.55}
.sheet .lang button{min-height:46px;padding-inline:1.35em;font-size:.85rem}
.lang button[aria-pressed="true"]{background:var(--enamel);color:var(--ink);opacity:1}
.btn-red{display:inline-flex;align-items:center;min-height:44px;background:var(--red);color:#fff;text-decoration:none;
  font-weight:700;text-transform:uppercase;
  letter-spacing:.13em;font-size:.78rem;padding:.68em 1.15em;border:0;cursor:pointer;
  white-space:nowrap;transition:background .18s ease}
.btn-red:hover,.btn-red:focus-visible{background:var(--red-deep)}
.btn-ghost{display:inline-flex;align-items:center;min-height:44px;text-decoration:none;border:1.5px solid currentColor;
  font-weight:700;text-transform:uppercase;
  letter-spacing:.13em;font-size:.78rem;padding:.66em 1.15em;background:none;cursor:pointer;
  transition:background .18s ease,color .18s ease}
.btn-ghost:hover,.btn-ghost:focus-visible{background:var(--green);color:var(--enamel)}
.s-ink .btn-ghost:hover,.s-ink .btn-ghost:focus-visible{background:var(--enamel);
  color:var(--ink)}
/* Take away became a button in the bar (Dennis 2026-07-29) and arrived invisible:
   .btn-ghost draws its border from currentColor, .bar sets no colour, so it
   inherited ink on an ink bar — 1.09:1. Enamel here, and the hover inverts the way
   it does on any other dark field. Measured: enamel on the bar 12.63:1. */
.bar .btn-ghost{color:var(--enamel)}
.bar .btn-ghost:hover,.bar .btn-ghost:focus-visible{background:var(--enamel);
  color:var(--ink)}
/* The bar is a single row that must not grow taller, so no label in it may wrap.
   "Take away" broke onto two lines at 1040px before this. */
.bar .btn-ghost,.sheet-foot .btn-ghost{white-space:nowrap}
.cookie .btn-ghost:hover,.cookie .btn-ghost:focus-visible{background:var(--enamel);
  color:var(--ink)}

.burger{display:grid;place-items:center;width:44px;height:44px;background:none;
  border:1px solid rgba(228,228,216,.4);cursor:pointer;color:var(--enamel);flex:none}
@media(min-width:1180px){.burger{display:none}}
.burger i{display:block;width:19px;height:1.5px;background:currentColor;
  box-shadow:0 -6px 0 currentColor,0 6px 0 currentColor}
.burger[aria-expanded="true"] i{box-shadow:none;transform:rotate(45deg)}
.burger[aria-expanded="true"] i::after{content:"";display:block;width:19px;height:1.5px;
  background:currentColor;transform:rotate(-90deg)}

/* The mobile sheet must fit the screen without scrolling, so it is a grid that
   distributes what space there is rather than a stacked list that can overflow. */
/* CHANGED 04.08 - see changes.txt */
.sheet{
  position:fixed;inset:0;z-index:70;background:var(--green);color:var(--enamel);
  display:none;grid-template-rows:auto 1fr auto;padding:1rem var(--gut) 1.25rem;
}
.sheet.is-on{display:grid}
.sheet-top{display:flex;align-items:center;justify-content:space-between;gap:1rem}
.sheet-nav{display:flex;flex-direction:column;justify-content:center;gap:.55rem;
  min-height:0}
.sheet-nav a{text-decoration:none;font-weight:700;
  text-transform:uppercase;letter-spacing:.08em;
  font-size:clamp(1.35rem,4.4vh,2.1rem);line-height:1.1;
  padding-block:.22em;border-bottom:1px solid rgba(228,228,216,.16)}
.sheet-nav a .n{color:var(--shirt);font-size:.5em;letter-spacing:.2em;margin-right:.7em;
  vertical-align:.28em}
.sheet-nav a[aria-current="page"]{color:var(--shirt)}
.sheet-foot{display:grid;gap:.6rem}
.sheet-foot .btn-red,.sheet-foot .btn-ghost{text-align:center;min-height:48px;
  display:grid;place-items:center}

/* ============================================================ HERO
   CHANGED 08.09 - see changes.txt
   The film, with four things on it: the wordmark, one line, two buttons and the week. The
   client asked for the sign to go transparent -- "jag tycker den ska vara transparant, du kan
   ha öpptettiderna längst ner centrerad ... Så kör vi bara Loggan, Resttaurang Bar Saluhall
   och knapparna under" -- so there is no card here at all. Fisk & skaldjur and the paragraph
   moved to #fisk-skaldjur.

   100svh, not 100vh: on iOS 100vh is the tallest the viewport ever gets, so browser chrome
   would cover the bottom of the hero -- and the week board is AT the bottom now, so that is
   the row that would go missing. It is the full svh rather than svh-minus-bar because the
   header is transparent over this section and the film runs up under it. */
.shero-sec{padding:0}
.shero{position:relative;display:grid;overflow:hidden;
  min-height:100svh;background:var(--green)}

/* The film, and the poster is what paints first. Under prefers-reduced-motion app.js never
   sets a source, so the poster IS the hero -- which is why it is a real frame of the film
   rather than a colour, and why object-fit is on the element and not on a wrapper. */
.shero-vid{position:absolute;inset:0;z-index:0;display:block;
  width:100%;height:100%;object-fit:cover}

/* THE SCRIM, AND EVERY STOP IN IT IS MEASURED. There is no opaque ground on this hero any
   more, so this gradient is what carries the wordmark and the line. Worst mean luminance
   across the whole 17.7s loop, per band, with what cream needs there:

     band            worst mean   cream needs      here
     nav      0-7%      0.622     4.5:1 -> 0.60    the header's own .72 wash, on top of this
     middle  38-62%     0.383     3.0:1 -> 0.30    0.38
     bottom  82-97%     0.510     4.5:1 -> 0.58    0.38 ramping to 0.74

   THE MIDDLE IS THE WEAKEST STOP ON PURPOSE. It is the part of the film a guest actually
   looks at; only LARGE type sits there, so WCAG's 3:1 applies rather than 4.5:1; and every
   small thing in that band -- both buttons -- carries its own ground instead. Making the
   middle strong enough for 4.5:1 would cost 0.50 and take the film with it.
   THE BOTTOM RAMP IS GONE FROM THIS LAYER, and that was a bug the gate caught rather than a
   simplification. It used to ramp to .76 by the hero's foot, which worked at 1440 -- where
   the foot group's top edge lands at 78% of the hero -- and failed at 320, where the same
   group starts at 58% because the viewport is short and the content is not. The gate measured
   4.08:1 for the line and 4.06:1 for the board there, both under the 4.5 they need.
   A ground positioned as a fraction of the VIEWPORT cannot serve content positioned by its
   own height. So the foot group carries its own gradient now -- see .shero-foot -- which
   travels with it, and this layer went back to being flat.

   WHAT THIS DOES NOT BUY, stated rather than hidden: single specular pixels in this film
   reach pure white in all three bands, and cream on white is 1.03:1 whatever the mean is. A
   highlight can pass behind a letter. That is the cost of type directly on moving film, it is
   the client's own call, and the two things where it would have mattered most were given
   their own grounds rather than left to this gradient. */
.shero-scrim{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(to bottom,
    rgba(20,37,31,.50) 0,
    rgba(20,37,31,.38) 26%,
    rgba(20,37,31,.38) 100%)}

/* TWO ROWS, not one centred group: the sign belongs in the middle of the picture and the week
   belongs at the bottom edge, which is what the client asked for in those words. 1fr on the
   middle row and auto on the board puts each where it was asked for without either being
   positioned absolutely against the other -- so a longer status sentence pushes the board up
   rather than off the screen.
   pointer-events is inherited from the panel this replaces: the layer is full-bleed over the
   film, so it would otherwise swallow clicks meant for the pause control. The layer declines
   them and the interactive children take them back. */
.shero-over{position:relative;z-index:2;display:grid;
  grid-template-rows:1fr auto;justify-items:center;align-items:center;
  padding:calc(var(--bar-h) + clamp(1rem,3vw,2rem)) var(--gut)
          calc(var(--cookie-h, 0px) + clamp(1rem,2.5vw,1.6rem));
  pointer-events:none}
.shero-sign,.shero-over .statwk{pointer-events:auto}
/* PUSHED DOWN, AND IT IS A CORRECTION RATHER THAN A PREFERENCE. The client 2026-09-08: "kan
   du dra ner loggan och knapparna lite, de känns inte riktigt centrerade, kanske 2-3 cm ner."
   They were right and the cause is structural: .shero-over is two rows, and align-items
   centres this group inside the FIRST row -- which runs from the top padding down to the foot
   group, not to the bottom of the hero. So the group was centred on the upper region and read
   high by a constant amount. Measured before this line existed: 89px too high at 1400 and at
   900, 88 at 800, 99 at 844, 106 at 568. About 2.4cm, which is what the client saw.

   So the offset lands it on the hero's TRUE centre rather than moving it an arbitrary
   distance. 10svh is that measurement expressed as a share of the viewport, capped at 92px so
   a 27-inch screen does not push it past centre.

   THE SHORT-VIEWPORT CASE IS CAPPED SEPARATELY because the content does not shrink as fast as
   the viewport does: at 320x568 there are only 48px between this group and the foot, so the
   full offset would drive one into the other. Under 700px tall it takes what room there is
   and no more. The gate asserts the clearance rather than trusting these two numbers. */
.shero-sign{text-align:center;max-width:min(46rem,92vw);
  translate:0 min(10svh,92px)}
@media(max-height:700px){.shero-sign{translate:0 min(5svh,40px)}}
/* The cream cut of the wordmark. It is an SVG so there is no upscale to fear; the cap is
   about the line under it, which should not be wider than the mark above it. */
.shero-logo{display:block;width:min(430px,74vw);height:auto;margin-inline:auto;
  max-height:12svh}
.shero-acts{display:flex;flex-wrap:wrap;gap:.7rem;justify-content:center;
  margin-top:min(clamp(1.4rem,3vw,2.1rem),3svh)}
.shero-acts .btn-red,.shero-acts .btn-cream{
  font-size:clamp(.8rem,.72rem + .3vw,.95rem);letter-spacing:.14em;
  padding:.95em 1.8em;min-height:52px}

/* BOTH BUTTONS ARE FILLED, and Meny stopped being a ghost for a measured reason: a cream
   1px outline with cream 14px type on a moving photograph is the one thing on this hero that
   could not be made to pass -- small text needs 4.5:1 and the middle band gives 3.8:1 at
   best. Filled, it carries its own ground and the film behind it stops mattering.
   Ink on enamel is 12.47:1. It is the same pair as .plate, so this is the site's own object
   rather than a new one. */
.btn-cream{display:inline-flex;align-items:center;justify-content:center;
  min-height:44px;padding:0 1.1em;text-decoration:none;
  background:var(--enamel);color:var(--ink);border:2px solid var(--ink);
  font-weight:700;text-transform:uppercase;
  letter-spacing:.12em;font-size:.78rem;transition:background .18s ease}
.btn-cream:hover,.btn-cream:focus-visible{background:var(--enamel-hi)}

/* THE WEEK, at the bottom and centred. CELLS RATHER THAN A CARD: it is a printed table and a
   table has cells, so a translucent fill in each is the board's own design rather than a
   panel smuggled back in after the client asked for transparent. It is also what makes the
   board legible without the scrim having to carry 11px type -- the fill composites on top of
   the gradient, so behind the day names the effective ground is 1-(1-.60)(1-.55) = .82 of
   green, which is 6.5:1 for cream even over the film's brightest pixel.
   The ink hairlines the board draws on cream would disappear here, so they become cream at a
   fifth -- enough to separate seven columns, not enough to read as a grid drawn on the film. */
/* THE BOTTOM GROUP: the street-plate line, then the week. The client 2026-09-08: "ta ner
   Restaurang - Bar - Saluhall över öppettiderna istället och gör så att texten är i en rad
   över den." The line and the board share a width so they read as one object, the line
   captioning the week rather than floating above it. */
/* THE FOOT CARRIES ITS OWN GROUND, and it is a gradient rather than a fill so it has no
   edge -- it reads as the film darkening toward the bottom, which is what a scrim is, and not
   as the card the client asked us to remove. Transparent at the top of the group, .58 by a
   third of the way down, so the line and the board both sit on it.
   IT TRAVELS WITH THE CONTENT, which is the whole point: composited with the flat .38 above
   it the effective ground is 1-(1-.38)(1-.58) = .74 wherever the group happens to land, on a
   1400px desktop or a 568px phone. The version this replaces was a fraction of the hero's
   height and was 4.06:1 at 320px for exactly that reason.
   It bleeds past the group's own box on both sides and below, so the gradient's dark end is
   the hero's own bottom edge rather than a line across it. */
.shero-foot{position:relative;width:100%;max-width:min(44rem,92vw);
  display:grid;justify-items:center}
.shero-foot::before{content:"";position:absolute;z-index:-1;pointer-events:none;
  left:50%;translate:-50% 0;width:100vw;
  top:calc(-1 * clamp(1.2rem,3vw,2.4rem));
  bottom:calc(-1 * (var(--cookie-h, 0px) + clamp(1.5rem,4vw,3rem)));
  background:linear-gradient(to bottom,
    rgba(20,37,31,0) 0,
    rgba(20,37,31,.58) 34%,
    rgba(20,37,31,.62) 100%)}

/* ONE LINE AT EVERY WIDTH, AND THE COEFFICIENT IS MEASURED. nowrap makes wrapping
   impossible; what keeps it from overflowing instead is the size, and the size comes from
   the string's own width-to-font-size ratio measured in this typeface: 15.93 for
   "Restaurang - bar - saluhall" and 17.57 for "Restaurant - bar - market hall".

   THE ENGLISH STRING IS THE ONE THAT SETS IT, and that is the part worth writing down. This
   is one element that setLang() swaps the text of, so a coefficient derived from the Swedish
   would fit until a visitor pressed EN and then overflow by ten per cent.

   AND THE RATIO IS NOT CONSTANT WITH SIZE, which cost a round trip. Measured at 100px the
   English string is 17.57x its font size; measured at the 16px the narrowest screen actually
   uses it is 18.46x -- about five per cent wider, because letter-spacing and glyph advances
   round up per character and that rounding is a larger share of a small em. A coefficient
   taken from the large sample overflowed 320px by 5px, clipped silently by the hero's own
   overflow:hidden. So the number below is derived from the SMALL case with margin on top:
   4.7vw while 92vw governs the width, capped at 38px once the 44rem board does.

   AND IT CHANGES WHICH CONTRAST RULE APPLIES, which is why the scrim's bottom ramp moved
   with it. Held on one line the type is ~38px on a desktop -- large text, so WCAG asks 3:1 --
   and ~16px at 320px, which is not large text and needs 4.5:1. The ramp reaches .62 by the
   top of this group for that reason. The gate reads the rendered size and picks the threshold
   from it rather than assuming one. */
.shero-line{display:block;white-space:nowrap;max-width:100%;
  font-weight:700;text-transform:uppercase;
  letter-spacing:.08em;line-height:1.1;color:var(--enamel);
  font-size:min(4.7vw,38px);
  margin-bottom:min(clamp(.5rem,1.4vw,.9rem),1.6svh)}
.statwk--film{width:100%;max-width:none}
.statwk--film .statwk-wrap{max-width:none}
.statwk--film .statwk-week{border-color:rgba(228,228,216,.22)}
.statwk--film .statwk-day{background:rgba(20,37,31,.55);border-color:rgba(228,228,216,.22)}
.statwk--film .statwk-d,.statwk--film .statwk-t{color:var(--enamel)}
.statwk--film .statwk-key{color:var(--enamel)}
.statwk--film .statwk-sub{color:rgba(228,228,216,.82)}
.statwk--film .statwk-line{justify-content:center}
.shero .statwk--film[data-state="open"] .statwk-day[data-today="1"]{background:var(--enamel)}
.shero .statwk--film[data-state="open"] .statwk-day[data-today="1"] .statwk-d,
.shero .statwk--film[data-state="open"] .statwk-day[data-today="1"] .statwk-t{color:var(--ink)}
.shero .statwk--film[data-state="closed"] .statwk-day[data-today="1"]{
  background:rgba(20,37,31,.78);box-shadow:inset 0 0 0 2px var(--enamel)}
/* THE THREE STATES HAVE TO BE OVERRIDDEN INDIVIDUALLY, and they were caught being wrong
   rather than assumed to be. The board's state rules are written for cream and they carry an
   attribute selector, so `.statwk[data-state="closed"] .statwk-key` outranks
   `.statwk--film .statwk-key` and won -- which put --ink-soft, a dark green, on a dark scrim.
   The film rules therefore carry a .shero prefix: at equal specificity the base rules would
   win on source order, because they are declared 100 lines further down the file. Raising
   specificity rather than moving the block, so neither can be reordered into breaking the
   other. The gate measured 1.1:1 here before this line existed.
   Measured against the composited ground under the status line: cream is 5.77:1, --ink-soft
   is 1.51:1, and the brand red the summer state uses is 1.13:1. Two of the three states were
   effectively invisible on the film, and only the one that happens to be showing today looked
   right, which is exactly how this kind of bug survives a screenshot.
   The summer state keeps its red SIGNAL rather than being flattened to cream: #F5CFCB is the
   brand red lightened until it reads on the film, 5.17:1, so "Sommarstängt" still arrives in
   red the way it does everywhere else on the site. */
.shero .statwk--film[data-state="closed"] .statwk-key{color:var(--enamel)}
.shero .statwk--film[data-state="shut"] .statwk-key{color:#F5CFCB}
.shero .statwk--film[data-state="shut"] .statwk-week{color:rgba(228,228,216,.6);
  border-color:rgba(228,228,216,.3)}
.shero .statwk--film[data-state="shut"] .statwk-day{border-left-color:rgba(228,228,216,.3)}

/* WCAG 2.2.2's pause. TOP right, below the header, and that is the opposite of two passes ago
   for a reason that inverted: the content used to be a card in the middle with free corners,
   so the control sat bottom right. The week board is at the bottom and centred now and on a
   phone it is nearly the full width, so the bottom right corner is the one place it cannot
   go. The top right is empty film at every width because the sign is centred.
   It clears the header by --bar-h rather than by a number, so it follows if the bar ever
   changes height. The gate hit-tests it at six widths -- which is how the version that ended
   up under the plate at 320px was caught. */
.vid-stop{position:absolute;right:.6rem;z-index:3;
  top:calc(var(--bar-h) + .6rem);
  min-width:44px;min-height:44px;display:inline-flex;align-items:center;
  justify-content:center;gap:.45em;padding:0 .8em;cursor:pointer;
  background:var(--shirt-line);color:var(--ink);border:1px solid var(--ink);
  font-weight:700;text-transform:uppercase;
  letter-spacing:.11em;font-size:var(--step--1);transition:background .18s ease}
.vid-stop:hover{background:var(--shirt)}
/* The glyph is drawn, not typed: a pause character out of a text font is one more thing that
   can resolve to an emoji on a phone, which is the bug the outbound arrow had.
   Two bars, then one triangle when paused. */
.vid-stop .g{display:block;width:11px;height:12px;flex:none;
  border-left:3px solid currentColor;border-right:3px solid currentColor}
.vid-stop[aria-pressed="true"] .g{width:0;height:0;border:6px solid transparent;
  border-left:10px solid currentColor;border-right:0}


/* The plate is the street sign at the size it has on the building: the wordmark,
   then the three type blocks the real one carries, hairline-separated. */
.plate--hero{padding:clamp(2.2rem,5vw,4rem) clamp(1.5rem,4vw,3.5rem) clamp(1.9rem,4vw,3rem)}
/* The wordmark drives the whole plate's scale, so it is a share of the plate
   rather than a fixed pixel width. */
.plate-logo{width:min(720px,86%);height:auto;margin-inline:auto}
.plate-hr{border:0;border-top:2px solid var(--ink);margin-block:clamp(.9rem,2vw,1.35rem)}
.plate-line{display:block;font-weight:700;
  text-transform:uppercase;text-align:center;letter-spacing:.08em;line-height:1.14;
  font-size:clamp(1.15rem,.85rem + 1.9vw,2.35rem)}
.plate-line--red{color:var(--red)}
.plate-note{display:block;font-weight:600;
  text-transform:uppercase;text-align:center;letter-spacing:.17em;
  font-size:var(--step--1);margin-top:.55rem}
/* The plate's one running paragraph, added 2026-08-12 on the client's ask for body copy on
   the sign itself. Every other line on the plate is display type transcribed from the real
   street sign; this one reads like a sentence, so it drops the plate's uppercase/tracking
   voice rather than force a paragraph through it. */
/* Both of these are <p>, and the global p{max-width:34rem} was capping them, so
   their centred content was centred inside 34rem sitting at the plate's left
   edge rather than inside the plate. On a 1120px plate that reads as a block
   pushed left. */
.plate-acts{max-width:none;display:flex;flex-wrap:wrap;gap:.6rem;justify-content:center;
  margin-top:clamp(1.1rem,2.5vw,1.6rem)}
.plate-foot{max-width:none;text-align:center;margin-top:1.1rem}

/* Framed photographs. Named for the hero they were born in; the hero has none
   any more, but Om oss, Stora sällskap and the about card all use them.
   No border, Dennis 2026-08-12 ("inga svarta ramar runt bilderna") -- the
   background stays as the letterbox colour behind an image while it loads. */
.hero-frame{position:relative;overflow:hidden;
  background:var(--green)}
.hero-frame img{width:100%;height:100%;object-fit:cover}
/* A <picture> is display:inline, so height:100% on the img inside it resolves against an
   auto height and the picture collapses to the intrinsic one. Art direction per breakpoint
   inside a framed photograph needs this or the frame's own height is ignored. */
.hero-frame picture{display:block;width:100%;height:100%}
.hero-cap{display:block;padding-top:.55rem;
  font-weight:600;text-transform:uppercase;letter-spacing:.14em;font-size:.7rem;
  color:#5C6164}
.s-blue .hero-cap,.s-blue-solid .hero-cap{color:var(--shirt-deep)}
/* Capped rather than fluid: the source frame is 1170px, so a wider slot would be
   an upscale. Centred so the column does not look half empty. */
.fig--spec{max-width:585px;margin-inline:auto;width:100%}

/* ------------------------------------------------------- STATUS BOARD
   The week, printed. Replaces a rounded pill with a glowing dot, which came from
   a different design system than the plate: nothing else on the sign has a round
   corner, and the pill's own outline measured rgba(20,37,31,.32) on enamel =
   1.99:1, under the 3:1 WCAG 1.4.11 asks of a control boundary. Every line here
   is full ink, 13.89:1, and no new colour is introduced.

     open    today's cell filled ink
     closed  today's cell framed, and the line says when it opens next
     shut    the whole week greyed to #5C6164 (4.89:1, AA) and struck through

   Measured: ink on enamel 13.89:1, enamel on ink 13.89:1, red on enamel 5.12:1. */
.statwk{margin-top:clamp(1.1rem,2.8vw,1.7rem)}
.statwk-wrap{position:relative;max-width:620px;margin-inline:auto}
.statwk-week{display:grid;grid-template-columns:repeat(7,1fr);list-style:none;
  border:2px solid var(--ink)}
.statwk-day{display:grid;gap:.2em;padding:.5em .15em .55em;text-align:center;
  border-left:1px solid var(--ink)}
.statwk-day:first-child{border-left:0}
.statwk-d{font-weight:700;
  text-transform:uppercase;letter-spacing:.1em;font-size:.64rem;line-height:1}
.statwk-t{font-weight:600;
  letter-spacing:.02em;font-size:.74rem;line-height:1}
/* inset box-shadow rather than a border, so framing today cannot shift the grid. */
.statwk[data-state="open"] .statwk-day[data-today="1"]{background:var(--green);color:var(--enamel)}
.statwk[data-state="closed"] .statwk-day[data-today="1"]{box-shadow:inset 0 0 0 2px var(--ink)}
.statwk[data-state="shut"] .statwk-week{color:#5C6164;border-color:#5C6164}
.statwk[data-state="shut"] .statwk-day{border-left-color:#5C6164}
.statwk[data-state="shut"] .statwk-wrap::after{content:"";position:absolute;
  left:0;right:0;top:50%;height:4px;margin-top:-2px;background:var(--red)}
.statwk-line{max-width:none;display:flex;flex-wrap:wrap;align-items:baseline;
  justify-content:center;gap:.3em .8em;margin-top:.8rem;text-align:center}
.statwk-key{font-weight:700;
  text-transform:uppercase;letter-spacing:.16em;font-size:var(--step-0);
  line-height:1.1;color:var(--ink)}
.statwk-sub{font-weight:600;
  text-transform:uppercase;letter-spacing:.16em;font-size:var(--step--1);
  line-height:1.1;color:#4A4E51}
.statwk[data-state="closed"] .statwk-key{color:var(--ink-soft)}
.statwk[data-state="shut"] .statwk-key{color:var(--red)}
/* Seven columns on a 390px screen leave about 50px each. The times may shrink,
   but the row must never wrap: a wrapped column stops reading as a table. */
/* CHANGED 04.08 - see changes.txt */
@media(max-width:520px){
  .statwk-d{font-size:.58rem;letter-spacing:.04em}
  .statwk-t{font-size:.66rem}
  .statwk-day{padding:.45em .08em .5em}
}


/* ================================================== FISK & SKALDJUR
   CHANGED 08.09 - see changes.txt
   The content that used to sit on the hero's sign, given a section of its own with
   photographs taped to the tile wall beside it. The client, through Marko 2026-09-08: "som
   på kvarnen 'en öl och en pratstund' där bilderna är 'klistrade' på kaklet".

   THE DEVICE IS KVARNEN'S, ADAPTED. What carries across from .bar-section there is the
   construction -- paper, tape, layered shadow, rotation -- and what does not is Kvarnen's own
   voice: its italic display captions and warm tan tape belong to that house. The chin here
   carries B.A.R.'s caption style, small caps tracked out the way .hero-cap is everywhere
   else, and the tape is a cool neutral because this wall is white tile rather than brown.

   TWO TILED SECTIONS MEET HERE, which this stylesheet has a rule about: a wall above a wall
   reads as one wall with a colour change in the middle of it. Havsgrillen follows directly and
   is also .s-tile, so this section takes a stainless line at its foot -- the same device
   .s-ice used to carry for exactly this, before the blue block came between them. */
.s-tile--wall{border-bottom:2px solid var(--shirt-line)}
/* The text column is the narrower one. Six prints need room to read as a wall rather than as
   thumbnails, and the paragraph is the only thing in the left column -- at 0.85fr it still
   holds a 62-character line, which is inside the 80 this stylesheet keeps everything to. */
.grid2--fisk{align-items:center;gap:clamp(2rem,5vw,4rem)}
@media(min-width:900px){.grid2--fisk{grid-template-columns:.85fr 1.15fr}}
/* The box on the tile. .plate brings the enamel ground, the ink frame, the inner hairline and
   the two mounting screws; what is set here is only what a block of copy needs that a link
   did not -- a measure, and left-aligned text, because .plate--hero centred everything and
   this is a paragraph rather than a sign's three lines.
   The screws stay. On the hero's full-height panel they had to be disabled because they read
   as two dots stranded in a field of cream; at this size the box is a sign again and a sign
   is bolted to the wall. */
.fisk-plate{text-align:left;padding:clamp(1.6rem,3vw,2.4rem)}
/* CHANGED 08.09: a step down from --step-1, client's word -- "gör texten i till dagspriser
   och hjärtat på bar lite mindre". At --step-1 the paragraph was the largest body text on the
   page and read as a second headline under the plaque; at --step-0 it is copy again and the
   plaque above it keeps the weight. max-width:none because the box's own padding is the
   measure here -- --measure would leave a ragged column inside a box narrower than it. */
.fisk-plate .lead{font-size:var(--step-0);max-width:none}
.fisk-plate .cta-row{margin-top:clamp(1.2rem,2.5vw,1.7rem)}
/* Havsgrillen's lead in the same box, client's word. It keeps its centring -- it is one
   sentence introducing the three steps below it, not a column of copy. */
.hg-lead.plate{padding:clamp(1.5rem,3vw,2.2rem) clamp(1.6rem,3.5vw,2.8rem)}
/* Same step down, same reason. This one is 46rem wide, so at --step-1 it measured 79
   characters a line -- the widest body text on the site; at --step-0 it is 62. */
.hg-lead.plate .lead{font-size:var(--step-0)}

/* THE WALL. A grid with rotation, NOT a stack. Marko 2026-09-08: "de ska inte vara
   överlappande dock, kanske lite bara". Kvarnen's three prints are absolutely positioned and
   layered three deep, which reads as a pile the moment there are six of them -- so these sit
   in a real grid and the only overlap is the second row riding up under the first by a few
   pixels. Rotation does the rest: at 1.5-3 degrees the corners come close enough to touch
   without anything covering anything.
   overflow is visible because the tape sits above each print's top edge and the rotation
   pushes corners past the cell.
   3 x 2 at full width, 2 x 3 in the middle, and 2 columns on a phone -- never one, because a
   single column of six prints is 2000px of scrolling for a block that is an aside. */
.tapewall{list-style:none;margin:0;padding:clamp(.6rem,1.5vw,1rem) 0 0;
  display:grid;grid-template-columns:repeat(2,1fr);
  gap:clamp(1.4rem,3vw,2.4rem) clamp(1rem,2.4vw,1.8rem);
  overflow:visible}
@media(min-width:1100px){.tapewall{grid-template-columns:repeat(3,1fr)}}
/* The second row rides up. Small, and only where there is a row above it to ride under. */
@media(min-width:1100px){.tapewall>:nth-child(n+4){margin-top:clamp(-1.4rem,-2vw,-.7rem)}}
@media(min-width:640px) and (max-width:1099px){.tapewall>:nth-child(n+3){margin-top:clamp(-1.2rem,-1.8vw,-.6rem)}}

/* The print itself: paper, a wide chin under the image, and a shadow that says it is lying on
   the tile rather than floating over it. The inset white line along the top is what makes
   paper read as paper -- a sheet catches light on its own top edge.
   No border-radius. There is not one anywhere on this site and a photo print does not have
   one either. */
.print{position:relative;margin:0;background:var(--enamel-hi);
  padding:10px 10px 34px;
  box-shadow:0 1px 0 rgba(255,255,255,.6) inset,
             0 14px 26px -10px rgba(20,37,31,.42),
             0 3px 8px -3px rgba(20,37,31,.3);
  transition:transform .4s cubic-bezier(.16,1,.3,1),box-shadow .4s ease}
/* Straighten and lift on hover. It answers a pointer, so it is motion the guest asked for --
   and it is the only way to see a print that a neighbour's corner is clipping.
   :focus-within so a keyboard visitor tabbing the section gets the same, and reduced motion
   gets the lift without the rotation change. */
@media(hover:hover){
  .print:hover{transform:rotate(0deg) translateY(-5px);z-index:4;
    box-shadow:0 1px 0 rgba(255,255,255,.6) inset,
               0 22px 40px -10px rgba(20,37,31,.5),
               0 6px 14px -4px rgba(20,37,31,.34)}
}
.print img{display:block;width:100%;aspect-ratio:4/5;object-fit:cover;
  background:var(--green)}
/* The vignette is what stops six bright plates on a white wall from flattening into one
   field. multiply so it darkens the photograph rather than greying it. */
.print::after{content:"";position:absolute;top:10px;left:10px;right:10px;
  aspect-ratio:4/5;pointer-events:none;mix-blend-mode:multiply;
  background:radial-gradient(circle at 50% 45%,transparent 58%,rgba(20,37,31,.2) 100%)}
.print figcaption{position:absolute;left:8px;right:8px;bottom:9px;text-align:center;
  font-weight:700;text-transform:uppercase;
  letter-spacing:.13em;font-size:.62rem;line-height:1.2;color:#4E5A55}

/* THE TAPE. A translucent strip with torn edges: the two pseudo-elements are a 45-degree
   repeating gradient clipped to 4px, which is what makes the ends look ripped rather than
   cut. Cool neutral rather than Kvarnen's tan, because the wall behind it is white tile.
   It is aria-hidden in the markup -- it is a drawn object, not content. */
.tape{position:absolute;z-index:2;pointer-events:none;
  width:clamp(46px,42%,74px);height:20px;
  background:rgba(223,220,210,.72);
  box-shadow:0 1px 2px rgba(20,37,31,.2),inset 0 0 0 1px rgba(255,255,255,.3)}
.tape::before,.tape::after{content:"";position:absolute;top:0;bottom:0;width:4px;
  background:linear-gradient(135deg,transparent 50%,rgba(223,220,210,.72) 50%) repeat-y;
  background-size:4px 6px}
.tape::before{left:-4px;transform:scaleX(-1)}
.tape::after{right:-4px}

/* Six rotations and six tape positions, all small and all different, because six identical
   angles is a pattern and a pattern is not a wall. The tape sits half off the top edge of
   its print, which is where a piece of tape holding something up actually is. */
.tw-1 .print{transform:rotate(-2.4deg)}
.tw-2 .print{transform:rotate(1.6deg)}
.tw-3 .print{transform:rotate(-1.2deg)}
.tw-4 .print{transform:rotate(2.2deg)}
.tw-5 .print{transform:rotate(-1.8deg)}
.tw-6 .print{transform:rotate(1.1deg)}
.tw-1 .tape{top:-9px;left:22%;transform:rotate(-6deg)}
.tw-2 .tape{top:-9px;right:20%;transform:rotate(5deg)}
.tw-3 .tape{top:-9px;left:50%;translate:-50% 0;transform:rotate(-3deg)}
.tw-4 .tape{top:-9px;left:18%;transform:rotate(4deg)}
.tw-5 .tape{top:-9px;right:24%;transform:rotate(-5deg)}
.tw-6 .tape{top:-9px;left:44%;transform:rotate(3deg)}
/* Under prefers-reduced-motion the prints keep their rotation -- it is a still arrangement,
   not an animation -- but nothing transitions and nothing lifts. */
@media(prefers-reduced-motion:reduce){
  .print{transition:none}
  .print:hover{transform:none}
}

/* ========================================================== HAVSGRILLEN
   The fish hall, and since 2026-08-03 a scroll sequence: the stage pins itself to the viewport
   while a tall track scrolls past behind it, and each step's opacity is driven by how far
   through that track the guest has come. Dennis's brief -- text left, picture right, fade
   through the steps, then carry on down the page.

   Rewritten rather than layered over the rules that were here for the film and the three chalk
   signs. Same lesson as the two passes before: new rules on top of old ones inherit whatever
   they forget to reset, so what is gone is gone from the file.

   The section is a light tile ground, not ink -- .s-ice until 2026-08-03, .s-tile since.
   Everything dark here is an object standing on a light wall,
   which is the point: a market hall is daylight and wet tile, and the weight comes from the
   objects rather than from the room.

   Measured, and these are the gate's own printed numbers rather than hand arithmetic. On --ice
   #F2F7FA: the lead 10.17:1. On --green #1E3A34: enamel 9.58:1, the step copy #C2CCC6 7.45:1. The
   cream numeral chip is the mirror of the sign it sits on, so it inherits 9.58:1.
   Restated 2026-09-08 with the green palette; the black's numbers were 10.13, 13.89 and 10.5. */
/* Centred copy wants balance rather than the global pretty: pretty only protects the last line,
   and what was wrong here was the rag above it -- three lines of very different lengths,
   centred, which reads as an accident. */
/* The lead's trailing air, and it was MEASURED AT ZERO: the lead sits in one .wrap and the step
   list in the next, neither carries a block margin, so the paragraph's last line ended exactly
   where step 1's 2px border began -- 1226px to 1226px at 1440, 900 and 390 alike. The gap has to
   be larger than .hgs-list's own gap between boxes (24-40px), otherwise the lead reads as part of
   box 1 rather than as the section's opening. Dennis 2026-08-04: "ge mer spacing mellan texten
   och blocket".
   The margin collapses out through .wrap (which has inline padding only), which is what puts the
   air between the two wraps rather than inside the first. */
.hg-lead{max-width:46rem;margin-inline:auto;text-align:center;
  margin-bottom:clamp(2.5rem,5vw,4rem)}
.hg-lead .lead{max-width:none;text-wrap:balance}

/* ---- THE THREE STEPS.
   Dennis 2026-08-12: put the three steps in a row instead of stacked ("lägg den vågrätt
   istället för lodrätt som den är nu") -- reversing the 2026-08-03 decision below this
   comment. Each step is now a single card, copy over its own photograph, three cards side
   by side from 900px up; below that they still stack, one per row, same as before.

   1080 is the measure this section has always been built around. */
.hgs-list{list-style:none;display:grid;gap:clamp(1.5rem,4vw,2.5rem)}
.hgs-step{display:grid;max-width:1080px;margin-inline:auto;width:100%;
  background:var(--enamel);border:2px solid var(--ink)}
.hgs-txt{display:grid;justify-items:start;align-content:center;row-gap:.6rem;
  padding:clamp(1.5rem,3vw,2.5rem)}
/* --step-2 rather than --step-3: inside a 430px column a 54px heading is three lines of it. */
.hgs-txt h3{font-size:var(--step-2);text-wrap:balance}
.hgs-txt p{max-width:34rem;color:#333F3A}
/* The numeral is the numbered tag on the ice: ink chip, cream figure, the plaque's double line
   inverted. Tracking is zero on purpose -- letter-spacing puts its space *after* the glyph, so a
   single digit in a centred box sits visibly left of centre with it on. */
.hg-num{display:inline-flex;align-items:center;justify-content:center;
  width:2.2rem;height:2.2rem;background:var(--green);color:var(--enamel);border-radius:2px;
  box-shadow:inset 0 0 0 2px var(--ink),inset 0 0 0 3px rgba(228,228,216,.9);
  font-weight:700;line-height:1;
  font-size:var(--step--1);letter-spacing:0}
/* The photograph bleeds to the box's edge: the box's own 2px border frames it, so the .hero-frame
   inside drops its border rather than drawing a second line 2px inside the first. */
.hgs-pic .hero-frame{aspect-ratio:4/3;border:0}
/* CHANGED 08.09 - see changes.txt */
/* THE PHOTOGRAPHS WERE 0px TALL ON EVERY DESKTOP, and this is the fix. The client spotted it
   -- "sedan ska 1 2 3 rutorna ha en bild under dem" -- and they were not asking for a new
   feature, they were reporting that three photographs in the markup rendered at no height
   above 900px. Measured before this change: 372x0, 372x0, 372x0 at 1440; 338x0, 338x29,
   338x0 at 1201; correct at 899 and below.

   THE CAUSE WAS AN INTENT THAT COULD NOT WORK. The rule this replaces gave the copy an `auto`
   row and the photograph a `1fr` row, so the picture would "take what is left" and three
   cards would line up. But a card's height comes from the tallest card's COPY -- the list
   stretches them to match -- so there is nothing left over to take. `1fr` resolved to 0 for
   the tallest card and to the difference for the others, which is where the stray 29px came
   from. The frame being position:absolute meant it contributed no intrinsic height of its
   own, so nothing pushed back.

   SO THE PHOTOGRAPH GETS A REAL HEIGHT: the 4:3 ratio it already uses below 900px, at every
   width. Alignment across the three then comes from SUBGRID rather than from arithmetic --
   the list owns two rows, each card spans both, so the copy row is as tall as the tallest
   copy and the picture row as tall as the tallest picture, and the three photographs start on
   the same line by construction.
   Without subgrid the cards keep their own heights and the photographs sit at slightly
   different tops. That is a cosmetic difference rather than a broken layout, which is why
   there is no @supports fallback: every browser this site targets has had subgrid since
   Safari 16. */
@media(min-width:900px){
  .hgs-list{grid-template-columns:repeat(3,1fr);grid-template-rows:auto auto}
  .hgs-step{grid-template-columns:1fr;grid-row:span 2;grid-template-rows:subgrid;
    max-width:none}
}

/* The teaser's picture is 3:2 -- restored 2026-08-04 with the block itself. A zigzag device lived
   here for a few hours: Havsgrillen as one block, a new saluhall block mirrored under it, and this
   teaser rebuilt to match. Dennis walked all three back ("ändra tillbaka och ta bort saluhalls
   blocket och gör om stora sällskaps blocket som det var förut"), so the device is gone with the
   only three blocks that used it. It is in git at 02c42fc if a two-column block is ever wanted:
   .zz/.zz--flip with justify-items:end on the unmirrored side, which is the one non-obvious part. */
.stora-shot .hero-frame{aspect-ratio:3/2}
/* The teaser's old right-column rules described a 3:2 frame in a grid2 and a centred plaque above
   it; both are gone with that structure. .stora-intro's own heading spacing stays -- the copy is
   unchanged, only its container is. */
/* The hand-off to the menu, centred under the three steps, and larger on Dennis's word
   2026-08-03. .btn-red is sized for the fixed bar -- .78rem on a 44px box -- which is right in a
   60px chrome and undersized as the one route a whole section hands over to. The 44px floor stays
   a floor; the real height now comes from the type and the padding. */
.hg-more{margin:clamp(2.5rem,6vw,4rem) auto 0;text-align:center}
.hg-more .btn-red{font-size:clamp(.9rem,.75rem + .45vw,1.1rem);letter-spacing:.15em;
  padding:1.1em 2.4em;min-height:60px}
/* The button is inline-flex, so the whitespace between the label span and the arrow span
   collapses to nothing and the arrow touches the last letter. Any button carrying a trailing
   arrow gets the gap, not just this one. */
.btn-arrow{gap:.45em}

/* ============================================================ STORA TEASER
   Dennis 2026-08-03: "text på vänster sida bilder på höger sida". The intro is a left
   column now instead of a centred introduction above a row of three, so its own
   centring is gone -- left-aligned text with `margin-inline:auto` still on the eyebrow
   would have pushed a short label into the middle of its own column.
   minmax(0,1fr) rather than 1fr wherever an image is in a grid item: the item mistakes
   the image's intrinsic width for its minimum and pushes the row wide. */
/* The teaser's own block padding, tighter than the site's default. Measured after
   the photographs were cropped to 3:2 and the block was still 941px on desktop:
   only 288px of that was the pictures, the rest was the section's own air plus a
   centred intro of four stacked rows. A teaser's job is to point at a page, so it
   is allowed to be shorter than a section that has to hold content. */
#stora-teaser{padding-block:clamp(2.25rem,5vw,4rem)}
.stora-intro h3{margin:.25rem 0 .45rem}
/* One photograph beside the teaser's copy, 2026-08-03, in place of the three-room cluster. 3:2 as
   shot -- .hero-frame's default here is 3/2 already via the .shot21 rule, but that rule is scoped
   to the cluster this replaced, so the ratio is stated rather than inherited from a selector that
   no longer matches. The file is 1200x800, so the frame takes nothing off it. */
/* Larger, on Dennis's word. grid2--wide gives the text the bigger share (1.15/0.85), which was
   right when the right column held three small frames and is wrong when it holds the photograph
   the block is showing. Equal columns and a tighter gap take it from 480 to about 584px.
   **584 is close to the ceiling and the ceiling is the file, not the layout.** party.webp is
   1200px wide, so 600 CSS px is exactly 2x and anything past that starts costing sharpness on a
   retina screen. Bigger than that needs the original from B.A.R., not a number here. */
/* CHANGED 04.08 - see changes.txt */
@media(min-width:900px){
  #stora-teaser .grid2--wide{grid-template-columns:minmax(0,1fr) minmax(0,1fr);
    gap:clamp(1.5rem,3vw,2.5rem)}
}
/* ---- 2+1. Three photographs in a column that is about 480px wide rather than across a
   1320px wrap: at a third of 480 a room is 150px and reads as texture, which is the
   same finding the six dish photographs produced at 184. So the widest frame takes the
   whole column and the other two share the row under it. One column below 600px, where
   two halves would be 165px each -- under the same threshold this rule exists to avoid.
   The aspect ratio opens up when it stacks for the reason the row below does: a tall
   photograph on a phone is most of the block's height on its own. */
/* TWO EQUAL FRAMES, Dennis 2026-08-04: "ta bort ... uppdukat och klart bilden och gör långbord i
   matsalen bilden och mingel i baren lika stora och det ska aligna med texten". The cluster was 2+1
   -- one wide frame across the top and two half-width ones under it -- which was right for three
   pictures and cannot be right for two: the survivors would have been one wide and one half as wide.
   One column, both frames the full width of the media column, so they are the same size by
   construction rather than by a matching pair of numbers. */
.shot21{display:grid;gap:clamp(.7rem,1.6vw,1.1rem);
  grid-template-columns:minmax(0,1fr);align-items:start}
.shot21 .hero-frame{aspect-ratio:3/2}
@media(max-width:599px){
  .shot21{grid-template-columns:minmax(0,1fr)}
  .shot21 .hero-frame{aspect-ratio:16/9}
}
/* .shot3 is the same row under a name that is not owned by one section, added
   2026-08-03 when the julbord page needed it. Naming it after the section it was
   born in would mean the next page either reuses a wrong name or copies the rule,
   and a copied rule is the one that stops matching after the first edit. */
.shot3{display:grid;gap:clamp(.8rem,2vw,1.15rem);
  margin-top:clamp(1.25rem,2.8vw,1.75rem)}
@media(min-width:800px){.shot3{grid-template-columns:repeat(3,minmax(0,1fr))}}
/* Dennis 2026-07-31: "blocket är alldeles för högt". Three 4:3 photographs side by
   side are the whole reason — at a third of a 1320px wrap each is about 300px tall
   and the row alone was over 300px before the intro and the button. 3:2 takes a
   third of that height off without shrinking anything the eye is actually looking
   for, because these are wide rooms photographed wide: the crop that goes is
   ceiling and floor. Stacked below 800px the same three become one column, which is
   where the aspect ratio matters most — three 4:3 photographs stacked on a phone
   was most of the block's height on its own.
   The images are still 1400px wide originals, so a 3:2 frame at a third of the wrap
   remains well past 2x. Nothing is upscaled and nothing is re-encoded. */
.shot3 .hero-frame{aspect-ratio:3/2}
@media(max-width:799px){.shot3 .hero-frame{aspect-ratio:16/9}}

/* ============================================================ PRINT DEVICES
   Dennis 2026-07-30: everything in the same style. So the two devices the printed
   menu uses beside the engravings are here too, read off the PDF rather than
   invented.

   The plate frame is the signature: a thick red outer line and a thin red inner
   line, with an **ogee corner** where the line turns in concave and then flares
   out convex. That is a cartouche corner, the same family as the enamel signs the
   whole site is built from, and it cannot be done with border-radius in either
   direction. So it is one SVG used as a 9-slice border-image: the corner box is
   40 of 120 units and stays fixed, and the edges are two straight parallel lines
   which stretch losslessly. Inline as a data URI rather than a file, because it is
   part of the design system and not content, and it saves a request.

   Text inside is the site's own --shirt-deep rather than the print's navy: same
   style means using the palette we have, not adding a ninth colour. It measures
   between 4.98 and 11.41 on every light ground here, see the token comments. */
.plat{
  border-style:solid;border-width:22px;
  border-image:url("data:image/svg+xml,<svg%20xmlns='http://www.w3.org/2000/svg'%20width='120'%20height='120'><g%20fill='none'%20stroke='%23C4271F'><path%20stroke-width='4.6'%20d='M%2060%203.5%20L%2022%203.5%20C%2016%203.5%2014%207.5%2014%2013.5%20C%2014%2017.5%2010%2019.5%203.5%2019.5%20L%203.5%2060%20M%2060%203.5%20L%2098%203.5%20C%20104%203.5%20106%207.5%20106%2013.5%20C%20106%2017.5%20110%2019.5%20116.5%2019.5%20L%20116.5%2060%20M%2060%20116.5%20L%2022%20116.5%20C%2016%20116.5%2014%20112.5%2014%20106.5%20C%2014%20102.5%2010%20100.5%203.5%20100.5%20L%203.5%2060%20M%2060%20116.5%20L%2098%20116.5%20C%20104%20116.5%20106%20112.5%20106%20106.5%20C%20106%20102.5%20110%20100.5%20116.5%20100.5%20L%20116.5%2060'/><path%20stroke-width='1.8'%20d='M%2060%2011.1%20L%2024%2011.1%20C%2019%2011.1%2021.1%2019%2021.1%2024%20L%2021.1%2060%20M%2060%2011.1%20L%2096%2011.1%20C%20101%2011.1%2098.9%2019%2098.9%2024%20L%2098.9%2060%20M%2060%20108.9%20L%2024%20108.9%20C%2019%20108.9%2021.1%20101%2021.1%2096%20L%2021.1%2060%20M%2060%20108.9%20L%2096%20108.9%20C%20101%20108.9%2098.9%20101%2098.9%2096%20L%2098.9%2060'/></g></svg>") 40 stretch;
  margin:clamp(1.25rem,3vw,2rem) auto 0;max-width:26rem;
  padding:.15rem clamp(.5rem,2vw,1.1rem) .9rem;text-align:center;color:var(--shirt-deep);
}
.plat-n{display:block;font-weight:700;
  text-transform:uppercase;letter-spacing:.04em;font-size:var(--step-0);line-height:1.15}
.plat-d{display:block;margin-top:.5rem;
  font-weight:600;text-transform:uppercase;letter-spacing:.05em;
  font-size:var(--step--1);line-height:1.45;color:#2E4655}
.plat-p{display:block;margin-top:.55rem;
  font-weight:700;text-transform:uppercase;letter-spacing:.06em;font-size:var(--step--1)}
/* The ornamental rule: a row of small red diamonds, repeated. In print it brackets
   a highlighted line, so here it closes the menu intro before the categories
   begin. background-repeat rather than a border-image because it only repeats in
   one direction and has no corners. */
.orn-rule{height:10px;margin:clamp(1rem,2.5vw,1.5rem) auto 0;max-width:26rem;
  background-image:url("data:image/svg+xml,<svg%20xmlns='http://www.w3.org/2000/svg'%20width='12'%20height='10'><path%20d='M6%201.2%2010.4%205%206%208.8%201.6%205Z'%20fill='none'%20stroke='%23C4271F'%20stroke-width='1.1'/></svg>");
  background-repeat:repeat-x;background-position:center}

/* ============================================================ ENGRAVINGS
   The printed menu's own ornaments, placed the way the print places them: a foot
   under a block with air above it, or a head above a heading. Decoration only,
   so they carry no alt text and no non-text contrast duty; the category heading
   beside them says what the block is.

   `.orn` is a <p>, which means the global p{max-width:34rem} makes it a narrow
   box at the left edge. margin-inline:auto centres the box in the 48rem reading
   column and the image centres inside the box. Learned the hard way in the
   closing band an hour before this was written.

   height:auto is not optional: these carry real width/height attributes so the
   space is reserved before the file lands, and the displayed width comes from an
   inline style, so without it the height attribute would stand while the width
   shrank. */
.orn{margin-inline:auto}
.orn--foot{margin-top:clamp(1.5rem,3.5vw,2.5rem)}
.orn--head{margin-bottom:clamp(.6rem,1.5vw,1rem)}
.orn-i{display:block;margin-inline:auto;height:auto;max-width:100%}
/* The hand is the one with a job rather than a position: in print it sits beside
   the oyster warning and points at it, so it shares that line here. */

/* ============================================================ KOM HIT
   The closing band. Tighter vertical rhythm than a content section, because it
   is the page landing rather than a sixth thing to read.

   Dennis 2026-08-03: one block holding two symmetrical offers -- come to the counter,
   or take it with you -- each a heading, a photograph and one button under the
   photograph. */
.komhit{text-align:center;padding-block:clamp(2.25rem,5vw,3.5rem)}
/* text-align:center is not enough here, and the same trap is already noted at
   .statwk further down: the global p{max-width:34rem} turns every paragraph into
   a narrow block sitting at the left edge, so centring the text centres it
   inside that block rather than on the page. The eyebrow and the button row are
   both <p>, so their boxes have to be centred too. */
.komhit .eyebrow,.komhit .cta-row{margin-inline:auto}
/* --step-2, not the global h2's --step-3. These are two card titles inside 30rem
   halves, and at 3.4rem "VI SES VID DÖRREN!" wrapped to two lines while its twin stayed
   on one -- which the subgrid then honoured by pushing BOTH photographs down past an
   empty line. Sized to the longer of the two labels rather than to the type scale. */
.komhit h2{font-size:var(--step-2);margin:.35rem 0 clamp(.9rem,2vw,1.25rem)}
.komhit .cta-row{justify-content:center;margin-top:clamp(.9rem,2vw,1.2rem)}

/* One block, one message, 2026-08-03: Dennis merged the two symmetrical halves. So .wrap is a
   plain centred column again rather than a two-column grid, and what was .komhit-half and its
   subgrid is gone -- with one heading there is nothing left to line up across a pair.
   The two photographs are the pair now. Equal columns, because they are equals: the menu on the
   table and the bag on the quay. They split at 620px, which is where two 4:3 frames still hold a
   readable size side by side; below that they stack, menu first, in the order the sentence names
   them. */
/* **balance, not the global pretty.** `.lead` is text-wrap:pretty site-wide, which only protects
   the last line from being a single word -- "med sig." is two, so it sailed through and sat alone
   under two full lines. Centred text wants balance: it evens every line instead of guarding one.
   The measure opens from 34rem to 40rem at the same time, because balance can only redistribute
   what the box allows and at 544px this sentence has no arrangement that is not lopsided.
   The gate measures the last line as a share of the longest, so a lone tail fails loudly rather
   than being something someone has to notice. */
.komhit-lead{margin-inline:auto;text-align:center;max-width:40rem;text-wrap:balance}
/* The two photographs are gone, 2026-08-03, so the buttons are the block. Larger than the site's
   default for the reason the Hela menyn button is: .btn-red and .btn-ghost are sized for the fixed
   bar -- .78rem on a 44px box -- which is right in a 60px chrome and undersized when they are the
   only thing in a section. The 44px floor stays a floor; the height comes from the type and the
   padding.
   .komhit-pair and its 4:3 frames went with the pictures rather than being left behind for a
   selector that matches nothing. */
.komhit-row{margin-top:clamp(1.5rem,3.5vw,2.25rem);gap:.8rem}
.komhit-row .btn-red,.komhit-row .btn-ghost{
  font-size:clamp(.9rem,.75rem + .45vw,1.1rem);letter-spacing:.15em;
  padding:1.1em 2.4em;min-height:60px}

/* ============================================================ MENU CALL
   The one object the brief asked to be unmissable: the enamel plate in full
   width, clickable, with the word the printed menu shouts in signal red. */
.menucall{display:grid;text-decoration:none;gap:clamp(1rem,3vw,2rem);
  align-items:center;padding:clamp(1.6rem,4vw,2.6rem) clamp(1.35rem,4vw,3rem)}
@media(min-width:820px){.menucall{grid-template-columns:minmax(0,1fr) auto}}
.menucall-key{display:block;font-weight:700;
  text-transform:uppercase;letter-spacing:.01em;line-height:.9;color:var(--red);
  font-size:clamp(3rem,1.5rem + 8vw,6.5rem)}
.menucall-sub{display:block;font-weight:700;
  text-transform:uppercase;letter-spacing:.11em;font-size:var(--step-1);margin-top:.4rem}
/* The plate's contents are spans inside a link, so each one has to be told to
   be a block: an inline eyebrow would sit on the same line as the word. */
.menucall .eyebrow{display:block;margin-bottom:.45rem}
.menucall-note{display:block;font-size:var(--step--1);color:#4A4E51;margin-top:.6rem;
  max-width:32rem;line-height:1.55;letter-spacing:normal;text-transform:none}
.menucall-go{display:inline-flex;align-items:center;justify-content:center;gap:.6rem;
  background:var(--green);color:var(--enamel);
  font-weight:700;text-transform:uppercase;
  letter-spacing:.13em;font-size:.86rem;padding:.95rem 1.6rem;min-height:48px;
  white-space:nowrap}
a.menucall:hover .menucall-go,a.menucall:focus-visible .menucall-go{background:var(--ink-soft)}

/* ====================================================== OM OSS, START PAGE
   Dennis 2026-08-03: "gör så bilden är lika stort som text blocket totalt, läs hela historien är
   liksom utanför blocket". Both halves of that are one cause: .grid2 centres its items, so a 3:2
   photograph sat in the middle of a column of copy that is twice its height, and the copy ran past
   it at both ends -- the button at the bottom read as having fallen out of the block.
   align-items:stretch makes the figure the height of the row, which is the height of the copy, and
   the frame is then placed with inset:0 rather than sized: a percentage height in a stretched cell
   is one more thing that can resolve against something indefinite, and this layout has produced
   that bug twice today already. The figure holds nothing but the frame here -- no figcaption -- so
   absolute placement takes nothing with it.
   **The crop is the cost.** team_entre.webp is 1440x960 landscape and the slot becomes about 480
   wide by 700 tall, so cover keeps roughly the middle half of the frame's width. The three people
   are centred and survive; the enamel sign behind them is what goes. object-position holds the
   crop a little high, where the faces are. If the whole sign matters more than the equal height,
   the answer is a portrait frame from B.A.R. rather than a number here. */
/* CHANGED 04.08 - see changes.txt */
@media(min-width:900px){
  #om-oss-kort .grid2{align-items:stretch}
  #om-oss-kort .hero-shot{position:relative;min-height:24rem}
  #om-oss-kort .hero-frame{position:absolute;inset:0;aspect-ratio:auto}
  #om-oss-kort .hero-frame img{object-position:50% 42%}
}

/* ============================================================ ROLES
   Who does what, as a dotted list rather than three cards: on the start page it
   is a caption to the photograph, not a team page. */
.roles{list-style:none;display:grid;gap:.35rem}
.roles li{display:flex;flex-wrap:wrap;gap:.35rem 1rem;justify-content:space-between;
  padding-block:.4rem;border-top:1px solid rgba(20,37,31,.16)}
.roles b{font-weight:700;text-transform:uppercase;
  letter-spacing:.1em;font-size:var(--step--1)}
.roles span{font-size:var(--step--1);color:#4E5A55}
.s-blue-solid .roles span,.s-blue .roles span{color:var(--shirt-deep)}

/* ============================================================ FIGURES */
figure{margin:0}
.fig{position:relative;overflow:hidden;background:var(--green)}
.fig img{width:100%;height:100%;object-fit:cover}
.fig figcaption{font-size:var(--step--1);color:#5E6164;padding-top:.7rem;line-height:1.5}
.s-ink .fig figcaption{color:#A9B7B1}
.fig--tall{aspect-ratio:4/5}
.fig--wide{aspect-ratio:3/2}
.fig--pano{aspect-ratio:2/1}
/* Three portraits across, one per room the copy names. minmax(0,1fr) rather than
   1fr: a bare 1fr lets an image's intrinsic width push the track wider than the
   column and the whole document sideways. */
/* Collage locked to the tile behind it. The bond is 88 wide by 44 high, offset
   half a tile per course, so the three frames take heights that are whole
   numbers of courses (10, 8, 7) and step down by exactly one course each — the
   same half-step the tiling does. Widths are 5, 3 and 4 of twelve so it reads as
   a composition rather than a row of thirds. Below 700px it stacks and the steps
   go away: a 44px offset on a single column is just a crooked gap. */
.collage{display:grid;gap:1.1rem;grid-template-columns:minmax(0,1fr);
  /* One tile course below the form's bottom edge, not a free-floating gap. */
  margin-top:44px;align-items:start}
.collage .hero-frame{height:auto;aspect-ratio:4/3}
/* Stora sällskap, restructured 2026-08-03: the form moved out of the right column and
   down the page, so the two rules that existed to line the text up with the form's
   heading are gone with it -- a .75fr/1.25fr split and a --form-pad offset both described
   a layout that no longer exists, and left in they would have squeezed the text beside
   two photographs and pushed it 2.4rem out of line with them.
   What is left is the default grid2--wide share, top-aligned: the text and the picture
   cluster beside it are peers and should start on the same line. */
/* CHANGED 04.08 - see changes.txt */
@media(min-width:900px){
  /* THE TWO FRAMES SPLIT THE COPY'S HEIGHT. Dennis 2026-08-04: "gör bilderna lite mindre så dom
     alignar botten linje". A fixed ratio cannot do that -- measured, the cluster overshot the copy by
     137px at 1440, by 54 at 1100 and fell 32px SHORT at 900, because the overshoot is a function of
     how the copy wraps and not of the pictures. So the pictures take the height they are given
     instead of asking for one, which is the mechanism .kontakt-side already documents.
     height:0 with min-height:100% and NOT height:100%: a grid row is as tall as its tallest item, so
     with height:100% the cluster would still contribute its natural height and the row would grow to
     it -- stretching the copy instead. Contributing zero makes the row the copy's height alone.
     The figure becomes a grid of 1fr + auto so the frame takes what is left after its caption; the
     caption is a sibling of the frame, so without that the two rows would overflow by its height. */
  #stora-sallskap .grid2{align-items:stretch}
  .shot21{height:0;min-height:100%;grid-template-rows:minmax(0,1fr) minmax(0,1fr)}
  .shot21 .hero-shot{height:100%;min-height:0;display:grid;grid-template-rows:minmax(0,1fr) auto}
  .shot21 .hero-frame{aspect-ratio:auto;height:auto;min-height:0}
}
/* The rooms sit a clear step below the block above them rather than one tile course, which
   is what the gap meant when the thing above it was the form's bottom edge. Two groups of
   photographs need to read as two groups. */
#stora-sallskap .collage{margin-top:clamp(2.5rem,6vw,4rem)}
/* The form is the page's one task and it is now the page's last thing, so it gets the
   separation a section would and the measure it had beside the text. */
.stora-form{margin-top:clamp(2.5rem,6vw,4.5rem)}

/* THREE EQUAL BOXES, Dennis 2026-08-04: "gör bild rutorna lika stora".
   This was a composition: spans of 5, 3 and 4 twelfths, fixed heights of 440, 352 and 308, and
   stagger margins of 0, 44 and 88 -- every one of those numbers a whole course of the running-bond
   tile, because the collage was locked to the tiled wall behind it. That wall is gone: this page
   went to flat grey-cream earlier today, so the alignment those numbers served has nothing left to
   align to and they were three arbitrary sizes standing in front of a plain ground.
   Equal thirds instead, and the stagger goes with the sizes -- three identical boxes stepped down
   by 44px each read as a mistake rather than as a composition, and the step cost 88px of height on
   a page that has been getting shorter all morning.
   3:2 rather than the 4:3 the mobile stack uses, which is the same call .shot3 carries: three 4:3
   photographs across a 1320px wrap stand about 319px tall and Dennis called exactly that row
   "alldeles för högt" on julbord. What the crop drops is ceiling and floor. */
/* CHANGED 04.08 - see changes.txt */
@media(min-width:700px){
  .collage{grid-template-columns:repeat(3,minmax(0,1fr));gap:1.4rem}
  .collage .hero-frame{aspect-ratio:3/2;height:auto}
}

/* .ticks (a bulleted list, red square markers) was Stora sällskap's only user and its bullet
   list was replaced by running copy 2026-08-12 -- removed with it rather than left as coverage
   for a marker no page uses. */

.frame{padding:6px;background:var(--enamel)}
.s-ink .frame{background:transparent}

/* ============================================================ LEGEND CARD
   The catch-method key written on the tile wall, set as an enamel card. */
.legend{background:var(--enamel);border:2px solid var(--ink);padding:1.15rem 1.35rem;
  max-width:22rem}
.legend h4{color:var(--red);margin-bottom:.75rem}
.legend dl{display:grid;grid-template-columns:auto 1fr;gap:.1rem .9rem;
  text-transform:uppercase;
  letter-spacing:.1em;font-size:var(--step--1)}
.legend dt{font-weight:700;color:var(--red)}
.legend dd{font-weight:500}
.legend dt,.legend dd{padding-block:.3rem;border-top:1px solid rgba(20,37,31,.16)}
.legend dt:first-of-type,.legend dl>dt:first-of-type+dd{border-top:0}

/* ============================================================ MENU
   Three menus behind three tabs. The tabs are the cream enamel plate; the
   selected one flips to the black plaque that hangs over the counter. */
/* Dennis 2026-07-31: the tabs sit directly above the sticky rail and follow the
   scroll on desktop and on mobile. Two sticky layers, not one wrapper: the rail
   lives *inside* each panel because every menu has its own categories, and the
   tabs sit outside the panels, so they cannot share a container without giving up
   the per-menu rail. Instead each pins itself and the rail's offset is the bar plus
   the tabs' own measured height.
   --tabs-h and --rail-h are written by app.js from a ResizeObserver rather than
   guessed in CSS: the row's height changes when the labels wrap, and the labels
   change with the language switch and with the viewport. A hardcoded offset here
   would put a 4px gap or a 4px overlap between the two bars on some width nobody
   tested. They default to 0px so every other page is unaffected.
   z-index 41 against the rail's 40, so the rail can never paint over the tabs. */
.menu-tabs{position:sticky;top:var(--bar-h);z-index:41;
  /* Air above the plates, none below. Dennis 2026-07-31, in two steps: first trim the
     row (8px top and bottom went, 177px -> 161px), then put the top half back because
     pinned against the bar the plates read as welded to it. Padding rather than a
     larger `top`, because a gap made with `top` is a gap the tabs' own background does
     not cover and the menu would scroll through it. So the air is inside the sticky
     box and the enamel fills it: separated from the bar above, still sitting directly
     on the rail below. 161px -> 171px, which is the price of the separation. */
  /* Air on both sides now, Dennis 2026-07-31: 10px above so the plates are not
     welded to the bar, 10px below so the rail can breathe under them. Both inside the
     sticky box with the enamel filling it, for the same reason as the top one — a gap
     made with `top` or a margin is a gap the background does not cover and the menu
     scrolls through it. Stack 161 -> 171 -> 181px; that is what two separations cost
     and it is a fifth of a phone screen, which is worth knowing rather than
     discovering. */
  background:var(--enamel);padding-block:.6rem;
  display:flex;flex-wrap:wrap;justify-content:center;gap:.5rem;
  /* Dennis 2026-07-31: "jäkligt mycket onödig spacing mellan meny knapparna och
     menyn". Three margins stacked up between the tabs and the first dish — this
     one, .menu-intro's bottom and .menu-nav's — so cutting one alone did nothing
     visible. Tabs to intro is the tightest relationship of the three: the tab you
     pressed and the menu it opened are one object. */
  margin-bottom:clamp(.55rem,1.2vw,.8rem)}
.menu-tab{
  display:inline-flex;align-items:center;justify-content:center;min-height:40px;
  background:var(--enamel);color:var(--ink);border:1px solid var(--ink);
  box-shadow:inset 0 0 0 3px var(--enamel),inset 0 0 0 4px var(--ink);
  padding:.6em 1.35em;border-radius:3px;cursor:pointer;
  font-weight:700;text-transform:uppercase;
  letter-spacing:.15em;font-size:var(--step--1);white-space:nowrap;
  transition:background .18s ease,color .18s ease,box-shadow .18s ease;
}
.menu-tab:hover{background:var(--enamel-hi)}
/* Three tabs on a narrow phone: share the row rather than leaving the third
   one orphaned on a line of its own. */
/* Four tabs share 341px at 390 wide, so about 85px each, and the label cannot
   wrap — .menu-tab is white-space:nowrap so the row keeps its height. At .72rem
   with .06em tracking DRYCKESMENY measured wider than its own plate and the text
   ran out through the borders. It looked like a design choice in a screenshot and
   the overflow gate could not see it: the *button* stayed inside the wrap, only its
   text did not, and the offender check measures element boxes.
   Sized to the longest label rather than to a guess, and qa.mjs now compares
   scrollWidth to clientWidth on every control so the next long word fails loudly. */
/* CHANGED 04.08 - see changes.txt */
@media(max-width:480px){
  .menu-tabs{gap:.3rem;flex-wrap:nowrap}
  .menu-tab{flex:1 1 0;min-width:0;padding:.6em .3em;font-size:.64rem;
    letter-spacing:.01em}
}
.menu-tab[aria-selected="true"]{background:var(--green);color:var(--enamel);
  box-shadow:inset 0 0 0 3px var(--ink),inset 0 0 0 4px rgba(228,228,216,.9)}
/* A tabpanel is not a page section. .menu-panel is a <section> element, so it was
   inheriting section{padding-block:clamp(3.5rem,9vw,8rem)} — 128px of page padding
   inside the panel, which is what stood between the tabs and the rail and made them
   141px apart while the wrapper section it lives in already carries the page's own
   padding. Measured before assuming: tabs ended at 849, panel started at 861,
   padding-top computed 128px, rail at 989. */
.menu-panel{padding-block:0}
.menu-panel[hidden]{display:none}
.menu-intro{max-width:48rem;margin:0 auto clamp(.6rem,1.5vw,.95rem);text-align:center}
.menu-lead{max-width:none;font-size:var(--step-0);color:#4C4F52}
.menu-nav{position:sticky;top:calc(var(--bar-h) + var(--tabs-h,0px));z-index:40;background:var(--enamel);
  border-block:1px solid rgba(20,37,31,.2);margin-bottom:clamp(1rem,2.2vw,1.5rem)}
/* Centred, but `safe` falls back to start alignment when the rail has to
   scroll, so the first category never ends up unreachable off the left edge. */
.menu-nav ul{display:flex;gap:.25rem;list-style:none;overflow-x:auto;
  scrollbar-width:none;padding:.35rem 0;
  justify-content:center;justify-content:safe center}
.menu-nav ul::-webkit-scrollbar{display:none}
.menu-nav a{white-space:nowrap;text-decoration:none;
  font-weight:700;text-transform:uppercase;
  letter-spacing:.11em;font-size:var(--step--1);padding:.42em .8em;
  border:1px solid transparent;border-radius:2px;transition:all .18s ease}
.menu-nav a:hover{border-color:rgba(20,37,31,.3)}
.menu-nav a[aria-current="true"]{background:var(--green);color:var(--enamel)}
/* The menu page's head takes julbord's shape, Dennis 2026-08-03, so it needs no rules of its
   own: .hang, .grid2--wide, .factplate and .shot3 are all devices that already existed. What this
   block held -- MENU PAGE HEAD, .mhead, .mounts and .mount, the enamel polaroid mounts and their
   reversed stacking order -- is gone rather than left for selectors that match nothing. It is at
   a6569f6 with the argument about why a white plastic frame is not this restaurant's form language,
   and with the hit-test the gate used to prove every engraving was on top rather than buried.
   The one thing carried forward: the row of three needs air under the two columns above it. */
.page-head .shot3{margin-top:clamp(2.5rem,6vw,4rem)}


/* One column, printed-menu width. A multi-column or grid menu would put two
   categories on screen at once and make the sticky category nav ambiguous. */
.menu-cols{max-width:48rem;margin-inline:auto}
/* A menu category is a <section>, so it has to opt out of the page-level
   section padding. Left in, each of the six categories carried 128px top and
   bottom, roughly 1500px of dead space through the menu.
   scroll-margin clears the fixed bar plus the sticky category rail. */
.cat{padding-block:0;margin-bottom:clamp(1.75rem,3.5vw,2.5rem)}
.cat>h3{color:var(--ink);padding-bottom:.35rem;border-bottom:2px solid var(--ink);
  margin-bottom:.7rem}
.cat-lead{font-size:var(--step--1);color:#4C4F52;margin-bottom:.8rem;max-width:none}
.grp{margin-bottom:1.1rem}
.grp-head{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;
  margin-bottom:.1rem}
.grp-head h4{color:var(--red)}
.grp-sub{font-size:var(--step--1);color:#5E6164;margin-bottom:.4rem}
.dish{display:flex;align-items:baseline;gap:.4ch;padding-block:.32rem;
  border-top:1px solid rgba(20,37,31,.13)}
.grp .dish:first-of-type{border-top:0}
.dish-t{flex:0 1 auto}
.dish-n{display:block;font-weight:600;
  text-transform:uppercase;letter-spacing:.05em;font-size:var(--step-0);line-height:1.25}
.dish-d{display:block;font-size:var(--step--1);color:#4E5A55;line-height:1.45;
  max-width:30rem}
.dish-dots{flex:1 1 2ch;min-width:1.5ch;align-self:baseline;
  border-bottom:1px dotted rgba(20,37,31,.45);transform:translateY(-.3em);height:0}
.dish-p{flex:none;font-weight:700;
  font-variant-numeric:tabular-nums;white-space:nowrap;font-size:var(--step-0)}
.dish--plain{border-top:1px solid rgba(20,37,31,.13);display:block;padding-block:.42rem}
.dish--plain .dish-d{max-width:none;color:#333F3A;font-size:var(--step-0)}
/* Sides and sauces are priced per group, so they read better as two columns.
   CSS columns, not grid: with grid the items flow left to right and rows of
   unequal height leave the hairlines misaligned. Columns flow top to bottom, so
   each column's rules line up. */
/* CHANGED 04.08 - see changes.txt */
@media(min-width:700px){
  .grp--list .dishes{columns:2;column-gap:clamp(1.5rem,4vw,3rem)}
  .grp--list .dish--plain{break-inside:avoid}
}
.grp--list .dish--plain:first-child{border-top:0}
.price-all{font-weight:700;
  font-variant-numeric:tabular-nums;font-size:var(--step-0);flex:none}
.menu-foot{max-width:48rem;margin:1.25rem auto 0;padding-top:1rem;
  border-top:1px solid rgba(20,37,31,.2);font-size:var(--step--1);color:#4E5A55}
.menu-foot li{list-style:none;padding-block:.1rem}
/* U+2197 followed by U+FE0E, the text presentation selector. Without FE0E, iOS
   Safari resolves the arrow through Apple Color Emoji and paints a blue emoji
   glyph. Headless Chrome on macOS picks a text font for the bare character, so
   every screenshot and every gate we have ever run showed the thin cream arrow
   that was intended -- the defect was only ever visible on a real phone.
   Dennis found it 2026-08-03. Social links dropped the arrow entirely; these
   remaining outbound links keep it, now in ink rather than emoji. */
.arr::after{content:"\2197\FE0E";display:inline-block;margin-left:.5em;font-weight:700}

/* ============================================================ AKVARIET */
.aq{display:grid;gap:clamp(2rem,5vw,4.5rem);align-items:center}
@media(min-width:900px){.aq{grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr)}}
.aq-vid{position:relative;justify-self:center;width:min(100%,340px);
  border:2px solid rgba(228,228,216,.55);padding:7px}
.aq-vid video{width:100%;aspect-ratio:9/16;object-fit:cover;background:#101D19}
.aq-vid figcaption{padding-top:.8rem;text-align:center;font-size:var(--step--1);
  color:#A9B7B1;letter-spacing:.06em}

/* ============================================================ FORM */
/* The panel's own inset, named so the column beside it can start on the same
   line as its heading instead of being nudged by a hand-picked number. */
:root{--form-pad:clamp(1.35rem,3.5vw,2.4rem)}
.form{background:var(--enamel);border:2px solid var(--ink);padding:var(--form-pad)}
/* The field grid counts the space it actually has, not the viewport's. The same
   partial sits in a wide column on stora-sallskap and a narrower one on the start
   page, and a viewport media query cannot tell those apart — it gave the narrow
   one three columns or the wide one two. */
.form{container-type:inline-size}
.form-grid{display:grid;gap:.65rem;grid-template-columns:minmax(0,1fr)}
.f-wide{grid-column:1/-1}
/* Thresholds are the container's CONTENT box, so the panel's ~76px of padding is
   already subtracted — 540 here is a ~640px panel. Measured, not guessed: at 620
   the 1180px layout fell back to two columns. */
/* Two columns, never three. The raggedness three columns had was not the count:
   it was auto-flowing an ODD number of short fields around full-width items, which
   leaves a visible hole wherever the packing breaks — company mode had three. With
   the event type and the message taking whole rows, the short fields come out even
   in both modes (private 6, company 4 + 4), so no cell is ever left over. The
   arithmetic does it; no :has(), no mode attribute, no JS.
   The one-column fallback on the line above must stay BEFORE the query; these
   three set grid-column on children and cannot collide with it either way. */
@container (min-width:430px){
  .form-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:.7rem}
}
.f-msg,.f-full{grid-column:1/-1}
/* Two real radios, drawn as enamel plates. Radios rather than buttons because the
   control is a choice between two states, not two actions: the browser gives us
   arrow keys, one tab stop and the announced group for free. */
/* A field row is 66px, so 40px of margin around the switch was a whole wasted row. */
.seg{border:0;padding:0;margin:.55rem 0 .9rem}
.seg legend{font-weight:700;
  text-transform:uppercase;letter-spacing:.13em;font-size:.7rem;padding:0;
  margin-bottom:.5rem}
.seg-row{display:flex;gap:.5rem}
/* The input covers the whole plate rather than being shrunk to a hidden pixel:
   then the thing you press IS the control, at full size, and the tap-target gate
   measures something real. A 1px input with a big label beside it passes for a
   sighted mouse user and fails everyone else. */
.seg-opt{flex:1 1 0;min-width:0;position:relative}
.seg-opt input{position:absolute;inset:0;width:100%;height:100%;margin:0;
  opacity:0;cursor:pointer;z-index:1}
.seg-opt span{display:flex;align-items:center;justify-content:center;
  min-height:44px;text-align:center;
  font-weight:700;text-transform:uppercase;
  letter-spacing:.11em;font-size:.78rem;padding:.5rem .5rem;
  border:2px solid var(--ink);background:transparent;color:var(--ink);
  transition:background .14s ease,color .14s ease}
.seg-opt input:checked+span{background:var(--green);color:var(--enamel)}
/* The site's global focus ring is --shirt, which measures 1.53:1 on enamel and is
   effectively invisible on this panel. --shirt-deep is 9.53:1. */
.seg-opt input:focus-visible+span{outline:2px solid var(--shirt-deep);outline-offset:2px}
@media(hover:hover){.seg-opt input:not(:checked)+span:hover{background:rgba(20,37,31,.08)}}
/* The company block is a second grid, so it needs the gap that the field rows get
   from their own container rather than sitting flush against the next one. */
.form-block{margin:0 0 .7rem}
/* The thank you replaces the form inside .form, so it inherits the enamel panel
   and its border and only needs its own rhythm. min-height keeps the panel from
   collapsing to a third of its height and yanking the page up under the reader. */
.thanks{display:grid;gap:.5rem;align-content:center;min-height:16rem;outline:0}
.thanks h3{margin:0}
.thanks .lead{margin:0}
.thanks .form-note{margin-top:.6rem}
/* ---- the engraved field, variant B "Inskriften", chosen by Dennis 2026-07-29
   The box stays, because a box is what tells you where to write. What goes is the
   label floating above it: engraved inside the field instead, so one field is one
   object rather than two, and the ~32px of label line plus gap above every input
   disappears.

   The label is absolutely placed and the INPUT fills the whole box. Done the other
   way round — label in flow, input shrunk to its text — the real tap target
   becomes ~26px and the box around it is dead. pointer-events stays off the label
   so every press lands on the control. */
.field{position:relative}
.field>label:not(.check){position:absolute;top:.42rem;left:.72rem;right:.72rem;
  z-index:1;pointer-events:none;
  font-weight:600;text-transform:uppercase;
  letter-spacing:.1em;font-size:.6rem;line-height:1.1;color:#4E5A55;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.req{color:var(--red);font-weight:700;margin-left:.1em}

/* #73746F measures 3.68:1 against the enamel outside the box and 4.51:1 against
   the fill inside it, so the edge delimits the control on both sides. The border
   this replaces was rgba(20,37,31,.4) = 2.44:1, under the 3:1 WCAG 1.4.11 asks of
   a control boundary — the boxes were visually heavy AND technically too weak. */
.field input:not([type=checkbox]),.field select,.field textarea{
  width:100%;background:#FBFAF6;border:1.5px solid #73746F;border-radius:0;
  margin:0;padding:1.5rem .7rem .4rem;min-height:54px;font-size:var(--step-0);
  color:var(--ink);
  transition:border-color .16s ease,box-shadow .16s ease,background .16s ease}
.field select{appearance:none;-webkit-appearance:none;padding-right:2rem;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='7'%3E%3Cpath d='M1 1l4.5 4.5L10 1' fill='none' stroke='%2316181A' stroke-width='1.6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right .7rem center;cursor:pointer}
.field textarea{min-height:5.4rem;resize:vertical;line-height:1.5}
@media(hover:hover){
  .field input:not([type=checkbox]):hover,.field select:hover,
  .field textarea:hover{border-color:var(--ink)}
}
/* CHANGED 04.08 - see changes.txt */
.field input:focus,.field select:focus,.field textarea:focus{
  outline:0;border-color:var(--ink);background:#fff;
  box-shadow:0 0 0 3px rgba(34,56,69,.32)}
.field[data-bad="1"] input,.field[data-bad="1"] select,
.field[data-bad="1"] textarea{border-color:var(--red);
  box-shadow:0 0 0 3px rgba(180,35,30,.15)}
/* The engraved label goes red with its field, so the one that needs attention says
   so twice rather than only at its edge. */
.field[data-bad="1"]>label:not(.check){color:var(--red-deep)}
.err{display:none;color:var(--red);font-size:var(--step--1);margin-top:.3rem;font-weight:500}
.field[data-bad="1"] .err{display:block}

/* ---- the two questions, on their own side of a rule ---- */
.form-ask{grid-column:1/-1;margin-top:.35rem;padding-top:.8rem;
  border-top:1.5px solid rgba(20,37,31,.55)}
.check{display:flex;gap:.7rem;align-items:flex-start;min-height:44px;
  padding-block:.45rem;font-size:var(--step--1);line-height:1.5;cursor:pointer;
  max-width:none}
/* Drawn, not native. These two were the only controls on the site still painted
   by the UA: accent-color tints a native checkbox but cannot square it, so they
   came out softly rounded in Safari and distinctly rounder on iOS, where the
   platform draws a heavier radius. Dennis found it on his phone 2026-08-03 --
   the site's whole control language is hard edges, and every sibling here is
   already border-radius:0. appearance:none is the only thing that stops the
   platform drawing its own shape, and once it is off the checkmark has to be
   ours too.
   Edge and fill are the same #73746F / #FBFAF6 as .field's boxes above, so the
   3.68:1 boundary contrast that comment measures covers these as well; the
   checked plate keeps the red accent-color used to give it, with a #fff tick
   matching .btn-red's own foreground. */
.check input{appearance:none;-webkit-appearance:none;
  width:1.35rem;height:1.35rem;flex:none;margin-top:.1rem;
  background:#FBFAF6;border:1.5px solid #73746F;border-radius:0;
  display:grid;place-content:center;cursor:pointer;
  transition:background .16s ease,border-color .16s ease}
.check input:checked{background:var(--red);border-color:var(--red)}
/* The tick is a clip-path polygon rather than a background SVG so it scales
   with the box and inherits nothing that can fail to load. */
.check input:checked::before{content:"";width:.72rem;height:.72rem;background:#fff;
  clip-path:polygon(13% 48%,0 61%,38% 96%,100% 22%,86% 11%,37% 70%)}
@media(hover:hover){.check input:not(:checked):hover{border-color:var(--ink)}}
.check span{max-width:27rem}
.form-part{margin:.5rem 0 .3rem 2.05rem;max-width:22rem}
.form-foot{margin-top:1.15rem;display:flex;flex-wrap:wrap;align-items:center;
  gap:.9rem 1.3rem}
.form .btn-red{min-height:48px;padding-inline:1.5em;display:inline-flex;
  align-items:center}
.form-note{font-size:var(--step--1);color:#4E5A55;margin-top:1rem}
.form-foot .form-note{margin:0}
.form-note a{color:#4E5A55}
.status{margin-top:1rem;font-size:var(--step-0);font-weight:500}
.status[data-kind="ok"]{color:#1F6B38}
.status[data-kind="bad"]{color:var(--red)}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* ---- tap targets, the 44px house standard ------------------------------------
   Measured at 390px, only counting a/button/input — selecting on style classes
   flags headings that reuse a plate style and turns the gate into a false-alarm
   machine. What was under: footer list links at 15px, the powered-by mark at 18,
   standalone plaque links at 36, menu tabs at 40, buttons at 38-39.
   Inline links inside a sentence are left alone: WCAG 2.5.8 exempts them, and
   padding them out would break the line they sit in. */
.foot-list a,.hours a{display:inline-flex;align-items:center;min-height:44px}
a.plaque{min-height:44px;display:inline-flex;align-items:center;justify-content:center}
.menu-tab{min-height:44px}
.powered{display:inline-flex;align-items:center;min-height:44px}
/* The last standalone controls under the standard: the menu category rail, the
   follow link in a feed card's footer, and the inline-styled button in the
   privacy text. Inline links inside a sentence are left as they are. */
.menu-nav a{display:inline-flex;align-items:center;min-height:44px}
.feed-foot a{display:inline-flex;align-items:center;min-height:44px}
button.lnk{min-height:44px;display:inline-flex;align-items:center}


/* ============================================================ FACT PLATE + JULBORD
   The Skaljulsbord, and the fact plate it introduced -- which the menu page now uses too, on
   Dennis's word 2026-08-03 ("gör den lik julbordssidan"). **Renamed from .julfacts on the same
   day**: a name owned by one page and used by two is either wrong on the second page or about to
   be copied, and a copied rule is the one that stops matching after the first edit. The same
   argument .shot21/.shot3 already carries.
   Two devices, both borrowed rather than invented: the facts sit on the enquiry form's own enamel
   plate, and the menu is the reading column the three menus use, so a julbord and a kvällsmeny are
   the same kind of document on this site.

   .hours is Kontakt's list, and its hairline is rgba(228,228,216,.14) -- cream at 14%,
   which is chosen for the ink ground and is simply not there on enamel. That one colour
   is restated and nothing else is: the day label and the value both inherit the page's
   ink, and .hours li:first-child already drops its own rule. */
.factplate{background:var(--enamel);border:2px solid var(--ink);padding:var(--form-pad)}
.factplate .hours li{border-top-color:rgba(20,37,31,.16)}
.factplate .cta-row{margin-top:clamp(1.1rem,2.5vw,1.5rem)}
.factplate-fine{font-size:var(--step--1);color:#4E5A55;margin-top:.9rem;max-width:none}
.factplate-fine a{color:#333F3A}
/* Sixty dish names in five courses, so the block needs the menu's rhythm rather than the
   page's: .cat already opts out of section padding, and the course heading takes the same
   ruled line a menu category does. The whole column is centred at the menus' own 48rem. */
.julmeny{margin-top:clamp(2rem,5vw,3rem)}
.julmeny>h2{text-align:center}
.julmeny .cat>h3{font-size:var(--step-1);letter-spacing:.08em}
/* Dennis 2026-08-12: smaller serving headings on julbord ("Första servering" etc). This is
   scoped to the two julbord panels by id -- #panel-julmeny/#panel-jul-veg are only ever built
   by render_julbord's panel() -- so the menu page's own .cat>h3 (still --step-2) is untouched. */
#panel-julmeny .cat>h3,#panel-jul-veg .cat>h3{font-size:var(--step-1)}
/* The vegetarian menu is a second document inside the first, so it gets air and a rule
   above it rather than only a heading -- without the separation its four courses read as
   a sixth and seventh serving of the shellfish table, which would be wrong about what a
   guest is being offered. */
.julmeny>h2:not(:first-child){margin-top:clamp(2.5rem,6vw,4rem);padding-top:clamp(1.25rem,3vw,2rem);
  border-top:2px solid var(--ink);text-align:left}
.julmeny .menu-foot{margin-top:clamp(1.5rem,3.5vw,2.25rem)}
/* .cat carries a bottom margin and no top one, which is right inside a menu where every
   category follows another category -- and wrong directly under a lead, where the first
   course heading ended up touching the sentence introducing it. The air belongs to the
   things that introduce a course list, not to the course list. */
.julmeny>.lead{margin-bottom:clamp(1.25rem,3vw,1.75rem)}
.julmeny>.orn-rule{margin-bottom:clamp(1.5rem,3.5vw,2.25rem)}

/* ============================================================ CONTACT */
.info{display:grid;gap:clamp(1.75rem,4vw,3rem)}
@media(min-width:700px){.info{grid-template-columns:repeat(auto-fit,minmax(13rem,1fr))}}
/* THREE ACROSS WAS TRIED AND REVERTED, 2026-08-03: the facts sit in the LEFT column of
   kontakt-cols, ~560px beside the 30rem map, so an 11rem min fits three tracks at 176px --
   and at 176px the VALUES wrap. "5 juli till 4 / augusti", "11:30 till / sent",
   "fakturor@restaurangbar. / se". A label-value table whose values break is worse than the
   dead space it was meant to remove, and no amount of column count fixes 560px holding
   three of them. Two across it is; the compaction came from the blocks themselves. */
/* The column headings are h2 since Kontakt became its own page and its plaque
   took the h1. Styled by position rather than by rank, so the outline can change
   again without the design following it. */
/* GROUND-AGNOSTIC from 2026-08-03, when Kontakt went from ink to white tile: these were
   written for the dark ground -- shirt-blue headings, enamel links, cream hairlines -- and on
   tile all three read as missing rather than as styling. currentColor mixes follow whatever
   the section sets, so the same rules serve both and there is no second copy to keep in
   sync. The .s-ink overrides below restore the blue heading where a dark ground still
   exists (Akvariet), because shirt blue on ink is the site's convention and ink on ink is
   not a colour. */
.info :is(h2,h3){font-size:var(--step-1);margin-bottom:.7rem;
  padding-bottom:.5rem;border-bottom:1px solid color-mix(in srgb,currentColor 30%,transparent)}
.info a{color:inherit;text-decoration:none;
  border-bottom:1px solid color-mix(in srgb,currentColor 45%,transparent)}
.info a:hover{border-bottom-color:currentColor}
.s-ink .info :is(h2,h3){color:var(--shirt)}
.s-ink .info a{color:var(--enamel)}
.s-ink .info a:hover{color:var(--shirt)}
/* The phone and mail rows use .hours so they read as the same label-value table as the
   opening hours -- but `fakturor@restaurangbar.se` is wider than a ~213px column has left
   after its label, and a .hours row is a flex line that would let it overflow. So this list
   alone may break the pair onto two lines. The phone rows still sit on one; only the mail
   rows ever wrap, which is the row being long rather than the layout giving up. */
.kontakt-reach li{flex-wrap:wrap;gap:.1rem 1rem}
.kontakt-reach a{word-break:break-word}
.hours{list-style:none;font-variant-numeric:tabular-nums}
.hours li{display:flex;justify-content:space-between;gap:1rem;padding-block:.3rem;
  border-top:1px solid color-mix(in srgb,currentColor 16%,transparent)}
.hours li:first-child{border-top:0}
.hours .d{font-weight:600;text-transform:uppercase;
  letter-spacing:.1em;font-size:var(--step--1)}
/* .people/.person were the three owner-name cards under the collage, removed 2026-08-12 on
   the client's word along with the names themselves. Dead selectors are worse than no
   selectors: they read as coverage. */

/* ============================================================ OM OSS KOLLAGE
   Dennis 2026-08-03: "text och bilder integrerat som ett kollage, försök göra något
   coolt!" Four objects on a twelve column grid, stepping in and out rather than sitting in
   two tidy columns: the text, the portrait beside and below it, the staff group offset back
   towards the middle, then who-does-what across the full width.

   NOTHING OVERLAPS RUNNING TEXT. A photograph over a paragraph is not a collage, it is a
   photograph on top of a paragraph, so the composition is made of unequal spans and
   offsets -- the same device the room collage on Stora sällskap uses. The one thing that
   does break a frame is the plaque, and it breaks the photograph's own edge, which is what
   a sign hung on a wall does.

   Twelve columns and not four: 5/7 and 4/8 splits are what make it read as composed, and
   they are not available in a three or four column grid. minmax(0,1fr) so an image's
   intrinsic width cannot push a track wider than its column. */
.omoss-kollage{display:grid;gap:clamp(1.75rem,4vw,3rem);
  grid-template-columns:minmax(0,1fr)}
@media(min-width:900px){
  .omoss-kollage{grid-template-columns:repeat(12,minmax(0,1fr));
    column-gap:clamp(1.5rem,3vw,2.5rem);row-gap:0}
  /* 6+6, not 7+4: the frame beside the text went from 4:5 to 3:2 on 2026-08-03, and a
     landscape in a 4-column slot is ~380x253 -- a stamp next to a tall block of type. Six
     columns puts it at ~570px, which is 1140 at 2x and inside what the source gives. */
  .omoss-txt{grid-column:1/7}
  /* Dennis 2026-08-03: "kan vi göra bilden lika hög som text blocket". So the frame stops
     having a ratio here and takes the row's height instead, which is the text beside it --
     align-self:stretch, and the figure becomes a grid so the CAPTION keeps its own auto row
     and the frame takes what is left. A frame told to fill the cell with the caption inside
     the same box pushes the picture up by the caption's height and the bottom edges stop
     agreeing, which is the whole point of this.
     minmax(0,1fr) and not 1fr: a 1fr row has an auto minimum, so the picture's own
     intrinsic height would set the floor and the row could not shrink to the text.
     Both edges now line up, so align-self:end is gone -- it was the offset that made the
     pair read as placed rather than as two columns, and equal heights replace it. */
  .omoss-portratt{grid-column:7/13;align-self:stretch;
    display:grid;grid-template-rows:minmax(0,1fr) auto}
  .omoss-portratt .hero-frame{aspect-ratio:auto;height:auto}
  /* .omoss-familjhang was here for one revision, holding the plaque after the staff
     photograph went; Dennis removed the plaque too, so it is gone with it.
     .omoss-folk (the owner-cards row) went the same way 2026-08-12. */
}
/* The frame carries a cream outline on this ink ground so it still reads as an object in
   the room rather than a hole in the section, now that .hero-frame has no border of its
   own to make that true on any ground automatically. */
.s-ink .omoss-kollage .hero-frame{outline:1px solid rgba(228,228,216,.14);outline-offset:4px}
/* The 3:2 fallback for this frame lives in the max-width:899px block at the end of this
   section, NOT here as a base rule. A media query adds no specificity, so an unscoped
   `.omoss-portratt .hero-frame{aspect-ratio:3/2}` here beats the override inside
   min-width:900px purely by coming later in the file -- the frame stayed 389px tall inside
   a 516px cell and the caption floated 99px below it. Same-specificity selectors are
   ordered by source position; scope both sides instead of relying on it. */
/* .omoss-familj and .omoss-skylt were here, removed 2026-08-03 with the staff photograph
   they styled -- a 5:3 frame capped at 600px because the source is only 1200x738, and the
   plaque hung on its corner. Dead selectors are worse than no selectors: they read as
   coverage. The photograph is still built as familj.webp; if it comes back, so do they. */
/* Three across in a 1320px wrap is right; three across inside a narrower cell is 166px
   per person, so the list only splits once it has the whole width. */
@media(max-width:899px){
  /* One column here, so there is no text block beside the picture to take a height from --
     and a stretched minmax(0,1fr) row inside an auto-height container has no height at all.
     So the frame keeps a ratio, and <picture> serves the 3:2 crop into it. */
  .omoss-portratt .hero-frame{aspect-ratio:3/2}
}


/* ================================================== THE STAFF RAIL
   CHANGED 08.09 - see changes.txt
   Fourteen portraits on Om oss, closing an item open since 12 August ("rullande bilder på
   personalen"). The photographs are one series -- same chair, same empty dining room, same
   black and white, the SALUHALL sign in the same place above every one -- so the layout shows
   several at once. That repetition IS the content; one-at-a-time would show fourteen
   photographs and hide the single idea they share.

   A RAIL RATHER THAN A CAROUSEL, and the reason is this page rather than a preference. It
   scrolls on drag, wheel and arrow key, snaps to each portrait, and the two buttons move it a
   screenful at a time, so it is operated like a carousel. What it does not do is move on its
   own: Om oss is six paragraphs of body copy, and a strip drifting at the edge of vision while
   someone reads makes a page harder to use rather than livelier. The site already has one
   thing that moves unasked -- the hero film, with its pause control -- and that is the right
   number. Adding the drift later means adding a pause with it. */
.folk{margin-top:clamp(3rem,7vw,5rem)}
/* Heading left, controls right, and they sit on the same baseline rather than being centred
   against each other: the eyebrow above the heading makes this block top-heavy, so centring
   would float the buttons above the heading's cap line. */
.folk-head{display:flex;flex-wrap:wrap;gap:1rem clamp(1rem,3vw,2rem);
  align-items:flex-end;justify-content:space-between;
  margin-bottom:clamp(1.1rem,2.5vw,1.6rem)}
.folk-nav{display:flex;gap:.5rem;margin:0;flex:none}
/* 44px both ways, square because there is no border-radius anywhere on this site. Ink on
   enamel: 12.47:1, and the border carries the same ink so the disabled state can drop the
   whole thing to a third without the glyph and the frame disagreeing. */
.folk-btn{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;
  background:transparent;color:var(--ink);border:2px solid var(--ink);
  font-size:1.1rem;line-height:1;cursor:pointer;
  transition:background .18s ease,color .18s ease,opacity .18s ease}
.folk-btn:hover:not(:disabled),.folk-btn:focus-visible:not(:disabled){
  background:var(--ink);color:var(--enamel)}
/* Disabled rather than hidden at the ends: a control that vanishes moves the one beside it,
   and a guest who has just clicked it then finds their pointer over the other one. */
.folk-btn:disabled{opacity:.3;cursor:default}

/* grid-auto-flow:column so the fourteen never wrap and the track width is one number.
   overscroll-behavior-x:contain stops a horizontal swipe at the rail's end from turning into
   a browser back-gesture, which on a touchpad is easy to trigger and hard to undo. */
.folk-rail{list-style:none;margin:0;padding:0 0 .6rem;
  display:grid;grid-auto-flow:column;
  /* CHANGED 09.09: up from clamp(160px,21vw,240px) on the client's word ("kan vi göra
     bilderna på personalen lite större?"). 240 -> 330 on a desktop is a third wider and a
     third taller. Measured, the 1320px wrap now shows three whole portraits and most of a
     fourth where it showed five and a bit -- still enough for the repetition the series is
     about to read, which is the thing that would break first if this went larger again. Two
     and a half would be a gallery of individuals rather than a series.
     THE CEILING IS THE SOURCE, not taste. 330 CSS px on a 2x screen asks for 660 real
     pixels, and the files are 700 wide, so this is still a true 2x with a little room. It is
     also why the files were RE-ENCODED from the original JPEGs rather than the number simply
     being raised: at 240 the old 600px encode was already at its limit, and pushing the
     display past it would have upscaled fourteen photographs of real people. If this ever
     wants to be larger again, re-encode first -- see the PERSONAL PORTRAITS note in
     prep_images.py. */
  grid-auto-columns:clamp(190px,24vw,330px);
  gap:clamp(.5rem,1.2vw,.85rem);
  overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory;
  /* The scrollbar is kept rather than hidden -- it is the only affordance a mouse user has
     before they touch a button -- but thinned and given the palette's own ink so it reads as
     part of the page instead of as chrome. */
  scrollbar-width:thin;scrollbar-color:rgba(20,37,31,.35) transparent}
.folk-rail:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
.folk-rail>li{scroll-snap-align:start}
/* 3:4, the source's own ratio, so there is no crop and no focal point to get wrong. The green
   ground is what shows while a lazy image is still in flight. */
.folk-rail img{display:block;width:100%;height:auto;aspect-ratio:3/4;object-fit:cover;
  background:var(--green)}

/* ============================================================ BAND
   A short section that is a statement and a pair of actions, nothing else:
   text left, actions right at wide, stacked below. */
.band{display:grid;gap:clamp(1.25rem,3vw,2.5rem);align-items:center}
@media(min-width:820px){.band{grid-template-columns:minmax(0,1fr) auto}}
.cta-row{display:flex;flex-wrap:wrap;gap:.6rem;align-items:center}

/* ============================================================ FEEDS
   Two cards with the same skeleton, so a live feed and a plain link do not read
   as two different kinds of thing: plaque, frame, footer row.

   Both frames are a fixed height on purpose. The Facebook page plugin renders at
   whatever height it is given and clips at whatever height its container has, so
   the two numbers have to be the same one; stretching the iframe to 100% cut the
   header mid-word and the post images in half. No red in this block either --
   two red buttons side by side was the loudest thing on the page. */
.feeds{display:grid;gap:clamp(1rem,2.5vw,1.75rem);grid-template-columns:minmax(0,1fr)}
@media(min-width:760px){.feeds{grid-template-columns:repeat(2,minmax(0,1fr))}}
.feed{display:grid;gap:.9rem;justify-items:start}
.feed-frame{width:100%;height:440px;overflow:hidden;
  border:2px solid var(--ink);background:var(--enamel);color:var(--ink);
  display:grid;place-items:center;padding:1.5rem}
.feed-note{font-size:var(--step--1);max-width:22rem;color:inherit}
/* The Instagram card: a photograph with the handle on a solid ink bar across the
   bottom. Not a scrim -- enamel type over the bright side of this photograph
   measured 1.51:1, and a gradient strong enough to fix that would have killed the
   picture. On ink it is 12.7:1 whatever the photograph does, and the type is on a
   plate, which is the language the rest of the site already speaks. */
/* Photo and bar are grid rows rather than an overlay, so the bar never covers the
   subject: the bag's printed wordmark is the reason this frame is here. The row
   split also gives the photo real vertical overflow, which is what lets
   object-position choose the crop. */
.feed-frame--photo{padding:0;display:grid;grid-template-rows:minmax(0,1fr) auto}
.feed-frame--photo img{width:100%;height:100%;object-fit:cover;object-position:50% 68%}
.feed-over{width:100%;background:var(--green);color:var(--enamel);
  padding:clamp(1rem,3vw,1.35rem);display:grid;gap:.85rem;justify-items:center;
  text-align:center}
.feed-over .feed-handle{color:var(--enamel)}
.feed-over .btn-ghost:hover,.feed-over .btn-ghost:focus-visible{
  background:var(--enamel);color:var(--ink)}
/* The plugin caps at 500px and is centred, so the blue block never spans a whole
   desktop column: it sits inside the enamel like a framed print. */
.feed-frame iframe{border:0;background:transparent;max-width:100%}
.feed.is-live .feed-frame{padding:0;background:#fff}
.feed-handle{font-weight:700;
  text-transform:uppercase;letter-spacing:.1em;font-size:var(--step--1)}
.feed-handle--lg{font-size:var(--step-1);letter-spacing:.06em}
.feed-foot{width:100%;display:flex;flex-wrap:wrap;gap:.5rem 1rem;
  justify-content:space-between;align-items:baseline;
  border-top:1px solid rgba(20,37,31,.2);padding-top:.6rem}
.feed-foot a{font-weight:700;
  text-transform:uppercase;letter-spacing:.14em;font-size:var(--step--1);
  text-decoration:none;border-bottom:1px solid currentColor}
/* The cards also appear inside .s-ink on the contact page, where the inherited
   light text colour would make the footer rule and the handle disappear. */
.s-ink .feed-handle{color:var(--enamel)}
.s-ink .feed-foot{border-top-color:rgba(228,228,216,.28)}
.s-ink .feed-foot a{color:var(--shirt)}
.embed .btn-red{margin-bottom:1.1rem}

/* ====================================== PROSE, for the policy page
   A document, not a marketing section: one readable column, section rules
   instead of oversized display headings. */
.prose{max-width:44rem;margin-inline:auto}
.prose h2{font-size:var(--step-2);margin:clamp(2rem,4vw,2.75rem) 0 .7rem;
  padding-bottom:.35rem;border-bottom:2px solid var(--ink)}
.prose h3{font-size:var(--step-1);letter-spacing:.08em;color:var(--red);
  margin:1.7rem 0 .45rem}
.prose p{max-width:none;margin-bottom:.9rem;color:#333F3A}
.prose a{text-decoration:underline;text-underline-offset:.18em}
/* Reads as a link but opens the cookie dialog rather than navigating, so it has
   to be a button. Inline text links stay line-height tall on purpose. */
.lnk{background:none;border:0;padding:0;font:inherit;color:inherit;cursor:pointer;
  text-decoration:underline;text-underline-offset:.18em}

/* ============================================================ FOOTER */
footer{background:var(--green);color:var(--enamel);padding-block:clamp(2.25rem,5vw,3.5rem) 1.75rem}
/* One row, not a box: the words and the field beside each other, with a single
   rule above carrying the separation the four borders used to. The field column
   is fixed rather than fluid so the button never wraps under the input on a
   desktop width. */
/* Recentred 2026-07-31 on Dennis's read: "undrar om det skulle funka bättre att
   den är centrerad och att epost blocket och prenumerera knappen är bredvid
   varandra på sin egen rad." He was right about why it looked off. Two columns
   put the words hard left and the field hard right across the full 1320px wrap,
   which reads as two unrelated things sharing a rule rather than one invitation —
   and the footer's four columns underneath already establish a left grid, so the
   band above it was competing with a stronger pattern. One centred column ends
   that argument: the eyebrow, the heading and the fine print stack in the middle,
   then the field and the button sit side by side on their own row underneath.
   The ground stays the footer's, deliberately. It is part of the footer. */
/* The rule moved under the block, Dennis 2026-07-31: he wants the line as the
   separation but the newsletter above it. So the newsletter is the first thing in
   the footer and the rule closes it off from the four columns below, rather than
   the newsletter sitting under a line with nothing above it. No padding-top: the
   footer's own padding-block already opens the space, and adding ours on top of it
   was what made the block sit low even before the rule moved. */
.news{padding-bottom:clamp(1.25rem,3vw,1.75rem);
  border-bottom:1px solid rgba(228,228,216,.32);
  margin-bottom:clamp(1.75rem,4vw,2.5rem);
  display:flex;flex-direction:column;align-items:center;
  gap:clamp(.9rem,2vw,1.35rem);text-align:center}
.news-say{display:flex;flex-direction:column;align-items:center}
.news h3{margin:.35rem 0 .4rem}
/* Let it spread, Dennis 2026-07-31. The 44ch cap broke ~100 characters of fine
   print into two short centred lines inside a footer 1320px wide, which read as
   cramped rather than as restrained. Uncapped it sits on one line on a desktop and
   wraps on its own further down, and `balance` keeps the two lines even when it
   does. The tracking is opened a touch as well: at this size, centred, one line, a
   little air between the letters is what makes it read as a caption under a sign
   rather than as a leftover sentence. */
.news-fine{color:#C2CCC6;font-size:var(--step--1);max-width:none;
  margin-inline:auto;letter-spacing:.04em;text-wrap:balance}
/* Side by side on their own row, and they stay side by side: nowrap plus a field
   that can shrink, so the button never drops under the input the way it did at
   the old fluid width. It only stacks below 30rem, where the row genuinely
   cannot hold both at 48px tall. */
.news-form{display:flex;flex-wrap:nowrap;gap:.7rem;justify-content:center;
  width:100%;max-width:32rem}
@media(max-width:30rem){.news-form{flex-wrap:wrap}}
.news-form input{flex:1 1 auto;min-width:0;min-height:48px;background:transparent;
  color:var(--enamel);border:1.5px solid rgba(228,228,216,.45);padding:.7em .85em;
  text-align:center}
.news-form .btn-red{min-height:48px}
.news-form input::placeholder{color:#8E9192}
.news-form input:focus{outline:0;border-color:var(--shirt);
  box-shadow:0 0 0 3px rgba(168,188,203,.28)}
/* Four columns now: the wordmark with the two channels under it, then contact,
   then the hours, then the exceptions. The site link list is gone with this pass,
   so the tallest column is the hours rather than a stack of 44px tap targets. */
.foot-grid{display:grid;gap:clamp(1.5rem,3.5vw,2.25rem)}
@media(min-width:680px){.foot-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(min-width:1000px){.foot-grid{grid-template-columns:1.3fr 1fr 1fr 1fr}}
.foot-logo{width:min(280px,70vw);color:var(--enamel);margin-bottom:1.1rem}
.foot-list{list-style:none;font-size:var(--step--1);line-height:1.9}
.foot-list a{text-decoration:none;border-bottom:1px solid rgba(168,188,203,.45)}
.foot-list a:hover{color:var(--shirt)}
.foot-soc{display:flex;flex-wrap:wrap;gap:.6rem;margin-top:1.1rem}
.foot-soc .btn-ghost{font-size:.72rem}
/* The generated hour rows: a <li> with a day span and a value. They are not links,
   so no 44px minimum applies and the column's height is set by its content. */
.hours--foot{list-style:none;font-size:var(--step--1);line-height:1.7}
.hours--foot li{display:flex;justify-content:space-between;gap:1rem;
  padding-block:.15rem;color:#C2CCC6}
.hours--foot .d{color:var(--enamel)}
/* ============================================================ DRIVS AV
   Its own section under the footer: the footer is the restaurant talking to its
   guests, this line is us. It also puts the cookie control and the policy last on
   every page, which is where a visitor goes looking for them.

   Centred, on Dennis's picture, but paid for in width rather than in height: the
   four stacked lines became three rows, because the wrap is 1320px wide and the
   small print needs maybe 900 of them. The credit keeps a line of its own; the
   copyright and the two legal controls share the next one; the registered company
   takes the last. The two lower rows wrap, so a phone gets short centred lines
   out of the same markup.

   The footer's own .foot-bot is gone, its company line moved down here, so all of
   the small print is one block. */
/* Was #101112, a shade darker than the footer above it: two dark bands with a seam
   between them read as two sections where this is the footer's own last line. Same ink now,
   on Dennis's word 2026-08-03. */
.drivsav{background:var(--green);color:#A9B7B1;
  padding-block:clamp(1rem,2.2vw,1.35rem)}
.drivsav .wrap{display:flex;flex-direction:column;align-items:center;
  text-align:center;gap:.1rem}
/* The shared row. gap is the space between items on one line and between the lines
   they wrap into, so a phone gets tighter rows without a second rule. */
.drivsav-row{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:.1rem 2.2rem}

/* ---------------------------------------------------------- THE HOUSE CREDIT
   Our mark, and two things about it that are standards rather than choices, so
   that it is the same on every site we build. See docs/spec.md section 6.

   Size: an 18px tall lockup beside an 11px uppercase label, .6rem apart. Copy
   this block, do not eyeball it.

   Placement: always alone on its own centred line. Dennis, 2026-07-30. It is our
   signature under someone else's website, not one item in a row of small print,
   so it never shares a line with the copyright or the legal links even when there
   is width going spare. */
.powered{display:inline-flex;align-items:center;gap:.6rem;text-decoration:none;
  color:#A9B7B1;font-size:.7rem;letter-spacing:.12em;text-transform:uppercase;
  font-weight:600;
  min-height:44px}
.powered img{height:18px;width:auto;display:block}
.powered:hover{color:var(--enamel)}

/* The copyright takes the same narrow uppercase as the credit beside it, so the
   row reads as one line of small print rather than two competing sizes. */
.drivsav-copy{max-width:none;font-weight:600;
  font-size:.7rem;letter-spacing:.12em;text-transform:uppercase;color:#A9B7B1}
/* Underlined text rather than the site's ghost plaques: at the very bottom of the
   page these are legal controls, not calls to action. Both keep the 44px from the
   tap target pass, which is also what sets the height of row one. */
.drivsav-link{display:inline-flex;align-items:center;min-height:44px;
  font-weight:600;font-size:.7rem;
  letter-spacing:.12em;text-transform:uppercase;color:#C2CCC6;
  background:none;border:0;padding:0;cursor:pointer;
  text-decoration:underline;text-underline-offset:.28em}
.drivsav-link:hover{color:var(--enamel)}
/* Row two. The label sits in front of the values instead of above them: it is
   there to name what the numbers are, and a line of its own cost 20px. */
.drivsav-lbl{font-weight:700;
  font-size:.62rem;letter-spacing:.2em;text-transform:uppercase;color:#A9B7B1}
.drivsav-legal{max-width:none;display:flex;flex-wrap:wrap;justify-content:center;
  align-items:center;gap:.1rem 1.6rem;font-size:.8rem;font-style:italic;
  color:#A9B7B1}
/* On a phone the row cannot hold the label and both values, and the natural break
   left "Företagsuppgifter Restaurang B.A.R. AB" on one line with the org number
   orphaned under it. Give the label its own line instead: same two lines, but the
   label names the pair below it rather than half of it. */
@media(max-width:640px){.drivsav-lbl{flex:0 0 100%}}

/* ============================================================ COOKIES */
.cookie{position:fixed;inset:auto 0 0;z-index:80;background:var(--green);
  color:var(--enamel);border-top:2px solid var(--red);padding:1.1rem var(--gut);
  display:none}
.cookie.is-on{display:block}
.cookie-in{display:flex;flex-wrap:wrap;gap:1rem;align-items:center;
  justify-content:space-between;max-width:1320px;margin-inline:auto}
.cookie p{font-size:var(--step--1);max-width:46rem;color:#C2CCC6}
.cookie-btns{display:flex;gap:.6rem;flex-wrap:wrap}
dialog{max-width:min(620px,92vw);border:2px solid var(--ink);background:var(--enamel);
  color:var(--ink);padding:clamp(1.35rem,3.5vw,2.25rem)}
dialog::backdrop{background:rgba(10,11,12,.66)}
dialog h3{margin-bottom:1rem}
dialog p{font-size:var(--step--1);margin-bottom:.85rem;max-width:none;color:#333F3A}

/* ============================================================ MOTION */
.rv{opacity:0;transform:translateY(18px);
  transition:opacity .7s ease,transform .7s cubic-bezier(.2,.7,.2,1)}
.rv.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important}
  html{scroll-behavior:auto}
  .rv{opacity:1;transform:none}
}
@media print{.bar,.sheet,.cookie{display:none!important}}

/* ---------------------------------------------------------- KONTAKT + KARTA
   Dennis 2026-07-31: the map goes on the right. Facts left, map right from 900px;
   stacked below that with the map last, because an address you can read beats a
   map you have to pinch.

   Dennis 2026-08-03: "Jag vill ha allt på en vertikal rad, bilden och google maps kan vara
   större". So the two ratios INVERTED. The facts were the 1fr and the media a fixed 30rem;
   now the facts are a fixed 20rem single column and the media takes everything left -- about
   870px at 1440 instead of 480, which is the photograph and the map nearly twice the size.

   THE FACTS BEING ONE COLUMN IS WHAT MAKES THAT POSSIBLE, not a separate wish. A
   label-value table needs its width: three of them across 560px broke their own values
   earlier today, and the only way to give the media 870px is to stop asking the facts to
   sit side by side at all. 20rem is 320px, which holds the longest pair here
   ("ONSDAG TILL FREDAG" against "11:30–01:00", which was "11:30 till sent" until the real
   closing time arrived 2026-08-05 and is two characters shorter) on one line with room over.

   The left stack ends before the right one does, and align-items:start is what lets it --
   the media column is the taller of the two now and that is the trade he asked for. */
.kontakt-cols{display:grid;gap:clamp(1.75rem,4vw,3rem)}
@media(min-width:900px){
  /* Dennis 2026-08-04: "balansera blocken lite mer, tycker att bilden och google maps tar upp
     för mycket plats". The text column was pinned at 20rem while the media column took
     everything left of it -- 320px against 840 -- so the page was two thirds photograph and
     map by area on a page whose content is an address and an opening time.
     Measured, and the second number is the one that mattered: widening the text column alone
     changed nothing about the height, because the text column was forced to a single vertical
     track (see below) and its 926px came from stacking four blocks, not from wrapping. Width
     and tracks together: text 320x926 -> 696x586, each picture 840x451 -> 464x281, the section
     1271 -> 930px. Media area falls from ~758k px2 to ~261k, about a third.
     The media column's height still derives from the text column's, which is the mechanism
     from 2026-08-03 -- so this is one number to move if the pictures should be larger again. */
  .kontakt-cols{grid-template-columns:minmax(0,1.2fr) minmax(0,.8fr);align-items:stretch}
  /* Dennis 2026-08-03: "balansera det så bilderna är samma höjd som texten". The two
     figures TAKE the row's height and split it, rather than each standing at a ratio and
     the column ending up whatever they add to -- it was 1214px against the facts' 791.
     Two equal 1fr rows, no aspect-ratio, and both pictures cover-fit their box, so the
     media column is exactly as tall as the facts at every width. Solving it by ratio
     instead means picking a width where 3:2 plus 4:3 happens to equal the text, and it
     stops being true the moment the copy rewraps.
     minmax(0,1fr) twice, not 1fr twice: a 1fr row keeps an auto minimum, so the pictures'
     own intrinsic heights would floor the column and it could not shrink to the text.

     height:0 with min-height:100% and NOT height:100%: a grid row is as tall as its
     tallest item, so with height:100% the media column still contributed its natural 1214px
     and the row grew to it -- which stretched the FACTS to 1144 and spread the three blocks
     apart. Exactly backwards from "more compact". Contributing zero height makes the row
     the facts' height alone, and min-height then fills it back.

     The split was 0.72 to 1.28 for one revision on 2026-08-03 -- "gör bilden på tjejen
     mindre och gör google maps större" -- and is back to half each on his next word: "gör
     blocken lika stora så hon och google maps ska vara lika stora". Either way the column's
     TOTAL height is unchanged, so the balance against the text survives; only the line
     between the two moves. That is the point of splitting a row instead of setting two
     ratios: the answer to "make one bigger" is one number here, not a resample. */
  .kontakt-side{height:0;min-height:100%;
    grid-template-rows:minmax(0,1fr) minmax(0,1fr)}
  .kontakt-side .hero-frame,.kontakt-side .map-frame{aspect-ratio:auto;height:100%}
  /* height:100% on the grid ITEMS, not just min-height:0. Without it .hero-shot stays auto,
     so height:100% on the frame inside it resolves against auto and falls back to the
     image's intrinsic ratio -- row one claimed 556px of a 767px pair and the map was left
     with 2. A definite chain from the row down to the frame is the whole mechanism. */
  .kontakt-side .hero-shot,.kontakt-side .mapbox{height:100%;min-height:0}
  /* The row is much wider than tall now, so the crop takes a band out of the middle of a
     portrait source -- and centred, that band cuts across her face. 38% puts the eyeline
     in the frame at every height the text can produce. */
  .kontakt-side .hero-frame img{object-position:50% 38%}
  /* COLUMNS RATHER THAN GRID TRACKS, and that is the whole answer to Dennis's "vill undvika
     empty space ... kolla på följ oss blocket det är massa tom rum" (2026-08-04).
     A two-track grid aligns rows, so every row is as tall as its tallest block and the shorter
     one leaves a hole underneath it. Measured with four blocks: Hitta hit 157 beside Telefon
     261, then Öppettider 277 beside Följ oss 87 -- 104px of nothing under the first and 190px
     under the last, which is exactly the emptiness he pointed at. And a fifth block made it
     worse, because five blocks in two tracks is three rows with half of one empty.
     Multi-column balances the two columns' heights by itself and flows top to bottom, so the
     blocks pack against each other and the number of them stops deciding the height. Same
     device as the footer's link list, and the same reason: `columns` flows down, grid flows
     across. break-inside:avoid so a table is never split between the columns, and the gap
     between blocks is a margin because a column gap is only horizontal.
     Below 900px this does not apply and the page is a single stack, untouched. */
  .kontakt-cols .info{display:block;columns:2;column-gap:clamp(1.75rem,4vw,3rem)}
  .kontakt-cols .info > *{break-inside:avoid;margin-bottom:clamp(1.75rem,4vw,3rem)}
  .kontakt-cols .info > *:last-child{margin-bottom:0}
}
/* Dennis 2026-08-03: the photograph goes above the map, so the right column is a stack of
   two objects rather than one. The gap is the figures' own, tighter than the two columns'
   -- a photograph and the map under it are one panel, not two sections. */
.kontakt-side{display:grid;gap:clamp(1rem,2.5vw,1.5rem);align-content:start}
/* The frame carries a cream outline on this ink ground so it still reads as an object in
   the room rather than a hole in the section, now that .hero-frame has no border of its
   own on any ground. */
.s-ink .kontakt-side .hero-frame{outline:1px solid rgba(228,228,216,.14);outline-offset:4px}
/* The 3:2 and the map's 4:3 apply BELOW 900px only, where the column is a stack under the
   facts and each figure stands at its own ratio. Above 900px the two split the facts'
   height and must have no ratio -- and these rules sit later in the file than that override
   at equal specificity, so left unscoped they simply won and the map was squeezed to 2px
   while the photograph kept its 3:2. Second time today; see the om-oss frame. */
/* CHANGED 04.08 - see changes.txt */
@media(max-width:899px){
  .kontakt-side .hero-frame{aspect-ratio:3/2}
  .kontakt-side .map-frame{aspect-ratio:4/3}
}
.find-near{margin-top:.7rem;color:color-mix(in srgb,currentColor 78%,transparent);
  font-size:var(--step--1);max-width:34ch}
/* The same framed object as every photograph on this site: ink border, and on the
   ink ground a cream hairline just inside it so the frame reads at all. 4:3 keeps
   the panel from becoming a letterbox on a laptop. */
.mapbox{position:relative;margin:0}
/* The border is a cream hairline, not the ink one .hero-frame uses. Kontakt is
   the ink section, so an ink border on an ink ground is an invisible frame — the
   blocked panel floated with its button in the middle of nothing until this was
   measured on screen rather than reasoned about. Same double-line device as the
   plaque, drawn in the only colour that reads here, plus a ground lifted off the
   section so the panel is an object even before the map lands. */
/* Blocked, this panel is a field with a note and a button on it, so it needs a ground of
   its own that is not the section's -- on ink that was a lifted dark, on tile it is the
   enamel every panel on the light grounds uses. Border and outline follow the same rule as
   the photograph beside it: the site's 2px ink frame on tile, the cream hairline on ink. */
/* CHANGED 04.08 - see changes.txt */
.map-frame{
  position:relative;overflow:hidden;
  border:2px solid var(--ink);background:var(--enamel);
}
/* CHANGED 04.08 - see changes.txt */
.s-ink .map-frame{
  border:1px solid rgba(228,228,216,.42);background:#202426;
  outline:1px solid rgba(228,228,216,.14);outline-offset:4px;
}
.map-frame iframe{display:block;width:100%;height:100%;border:0}
/* Blocked, the panel is a plain field with the note, the accept button and the
   plain Maps link. It reuses .feed-over so the blocked map and the blocked feed
   are visibly the same object, which is the honest signal: one decision covers
   both. */
/* .feed-over carries background:var(--green);color:var(--enamel) for the social cards, which
   sat on the ink ground. The blocked map now sits on white tile, so it takes the panel's own
   enamel and ink instead -- otherwise the frame is enamel with a black block filling it,
   which is what it looked like the first build after the ground changed. Scoped to .mapbox,
   so the cards keep theirs if the feed ever comes back on a dark section. */
.mapbox .feed-over{position:absolute;inset:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:.85rem;padding:clamp(1rem,3vw,2rem);
  text-align:center;background:transparent;color:var(--ink)}
.s-ink .mapbox .feed-over{background:var(--green);color:var(--enamel)}
.mapbox.is-live .feed-over{display:none}
