/* Kundvyn — konceptet "Editorial".
 *
 * Grundmallen som varje ny restaurang ärver. En restaurang som aldrig rört
 * utseendefliken ska se färdig ut, så allt här står på egna ben utan
 * uppladdade bilder och utan valda färger.
 *
 * Idén är en tryckt meny, inte en matleverans-app: cremefärgat papper, tunna
 * linjer i stället för kort och skuggor, Georgia i rättnamnen och en punktlinje
 * fram till priset. Färg används sparsamt — terrakotta för nummer, pris och
 * aktion, olivgrönt för de mörka ytorna (kassaraden). Ingenting i menylistan är
 * en knapp att titta på: hela raden är klickbar och all interaktion sker i det
 * nedre arket.
 *
 * --primar och --accent sätts per restaurang i sidans <head> och faller
 * tillbaka på husets olivgröna och terrakotta.
 *
 * Byggd mobilt först. En pizzabeställning görs på en telefon, ofta stående,
 * ofta med en tumme. Först vid 900px delas menyn i två spalter, som en tryckt
 * menys spaltsättning.
 */

:root {
  /* --- paletten ------------------------------------------------------- */
  --oliv: #2e4b3f;
  --oliv-mork: #223a30;
  --terrakotta: #9d441b;
  --creme: #f5f1e8;
  --creme-djup: #ece6d8;
  --grafit: #252525;
  /* Papperets ton, men i rollen text-på-mörkt: kassaraden, kartlänken,
     rullbeskedet över kartan. Egen token därför att de två rollerna drar åt
     olika håll så fort papperet byts — bakgrunden ska följa paletten, den här
     ska fortsätta vara den ljusa av de två. Se app/paletter.py. */
  --pa-mork: var(--creme);

  /* Accenten lyft mot vitt, för de ställen där den ligger på ett uppladdat
     foto i stället för på papperet. Kulörerna till de fyra ljusa pappren är
     alla mörka — de är valda för att läsas *mot* creme — och en mörk ton på
     ett foto står i samma ljushet som fotot självt. Blandningen behåller
     tonen men flyttar ljusheten upp till namnets, så etiketten fortfarande
     bryter av mot det vita utan att försvinna. Sotpapperet skriver över den
     nedan: dess kulörer är redan ljusa och skulle bli nästan vita här.

     oklab och inte srgb: steget mot vitt ska kännas lika stort oavsett vilken
     ton restaurangen har, och accentfärgen är fri för dem som satte sina egna
     färger före paletterna. För de sju kurerade kulörerna skiljer de två
     rymderna någon enstaka nivå — valet gäller de andra.

     Att blandningen ligger i en token och inte i regeln nere vid heron är
     därför att villkoret är papperets och inte hjältebildens. */
  --accent-ljus: color-mix(in oklab, var(--accent) 45%, #fff);

  /* --- ytor ----------------------------------------------------------- */
  --papper: var(--creme);
  --text: var(--grafit);
  --dampad: #5c6b62;
  --svag: #777;
  /* Salvia bär ingredienserna på menyraden. Den ligger nära papperet i ton och
     lämnar därför rättnamnet ensamt kvar som det ögat fastnar på — men inte
     närmare än 4.5:1. Den ljusare salvian låg på 2.7:1, och på en meny där
     varje rätt bär sitt innehåll i den texten är det inte en nyans utan en
     halv meny som inte går att läsa. */
  --salvia: #5f6d5a;

  /* Delarlinjen är hela konceptets byggsten. Tonad i olivgrönt, aldrig ren
     svart: en varm sida med kallsvarta linjer ser smutsig ut. */
  --linje: rgba(46, 75, 63, .15);
  --linje-stark: rgba(46, 75, 63, .28);
  --punktlinje: rgba(0, 0, 0, .25);
  /* Den svaga tvätten under en hovrad flagga eller ett favoritkort. Egen token
     därför att svart med fem procents täckning inte syns alls på ett mörkt
     papper — en hovring som inte gör någonting är inte en nyans fel. */
  --tonad: rgba(0, 0, 0, .05);
  --kant: var(--linje);

  /* Status lånar ur paletten i stället för att dra in gröna och röda toner
     utifrån. Ett kvitto ska höra ihop med resten av sidan. */
  --gron: var(--oliv);
  --rod: #9a3218;
  /* Berget i styrkemärket. Ren dekoration bredvid en text som säger samma
     sak, så den behöver inte klara textkontrasten — men den ska läsa som
     sten och inte som ännu en av sidans gråtoner. */
  --berg-sten: #6d6455;
  --rod-bakgrund: #f4e6e0;
  --sand: #efe6d2;
  --sand-text: #7a5a22;

  /* --- form ----------------------------------------------------------- */
  --radie-s: 4px;
  --radie: 8px;
  --radie-ark: 16px;

  /* --- rörelse -------------------------------------------------------- */
  --mjuk: cubic-bezier(.22, .9, .28, 1);
  --studs: cubic-bezier(.34, 1.56, .64, 1);

  /* --- spalten -------------------------------------------------------- */
  /* En spalt för hela sidan. Toppbaren, kategorierna, menyn och foten hämtar
     sin bredd härifrån, så ingenting kan glida i sidled i förhållande till
     något annat. */
  --spalt: 60rem;
  --sidmarginal: clamp(1.15rem, 4vw, 2.5rem);
  --innerspalt: calc(var(--spalt) - 2 * var(--sidmarginal));

  /* --- typografi ------------------------------------------------------ */
  /* Georgia i rubriker och rättnamn, Arial i metadata. Båda finns på varje
     maskin: ingen nedladdning, inget som saknas offline, och en kund på 3G
     slipper vänta på ett typsnitt för att kunna läsa menyn. */
  --rubrikfont: Georgia, "Times New Roman", Times, serif;
  --brodfont: Arial, Helvetica, "Helvetica Neue", sans-serif;
}

/* --------------------------------------------------------------- papprena */

/* Restaurangens valda papper. Klassen står på <body> och kommer ur
   ``tenants.theme``; nycklarna och namnen bor i ``app/paletter.py``, som också
   bär papperets hexvärde åt webbmanifestet. Glider de två isär faller
   ``tests.test_palett``.

   :root ovanför ÄR cremen. Den står kvar som den är — dels för att en
   restaurang som aldrig valt något ska se ut precis som förut, dels för att
   den är svaret på ett okänt värde i kolumnen.

   Två av tokenarna måste upprepas i varje block trots att de ser ut att räknas
   ut av sig själva: ``--papper`` och ``--kant`` är alias (``var(--creme)`` och
   ``var(--linje)``), och ett alias löses ut där det *deklareras*. Deklarerat i
   :root skulle det peka på cremens värden och ärvas nedåt som en färdig färg,
   oavsett vad body säger. Därför står de med igen.

   Alla toner nedan är räknade mot 4.5:1 för brödtext. Se app/paletter.py. */

body.tema-kalk {
  --creme: #f4f5f2;
  --creme-djup: #e7e9e4;
  --papper: var(--creme);
  --pa-mork: var(--creme);
  --dampad: #586059;
  --svag: #636763;
  --salvia: #5a635a;
  --linje: rgba(40, 52, 45, .14);
  --linje-stark: rgba(40, 52, 45, .26);
  --kant: var(--linje);
}

body.tema-sand {
  --creme: #f3ebda;
  --creme-djup: #eae0cb;
  --papper: var(--creme);
  --pa-mork: var(--creme);
  --dampad: #645c48;
  --svag: #6a624f;
  --salvia: #606449;
  --linje: rgba(92, 72, 42, .16);
  --linje-stark: rgba(92, 72, 42, .3);
  --kant: var(--linje);
}

body.tema-linne {
  --creme: #eeece6;
  --creme-djup: #e1ded5;
  --papper: var(--creme);
  --pa-mork: var(--creme);
  --dampad: #5d5c55;
  --svag: #62615a;
  --salvia: #5c6156;
  --linje: rgba(60, 58, 50, .15);
  --linje-stark: rgba(60, 58, 50, .28);
  --kant: var(--linje);
}

/* Sot är det enda mörka papperet, och det vänder figur och botten. Blocket är
   därför längre än de andra tre: varenda ton som bara stod i :root hade ärvts
   ner som en färg räknad mot creme, och en grafitgrå brödtext på nästan svart
   är inte en nyans fel utan oläslig.

   Det som skiljer mest står först. --primar är kassaraden och den fyllda
   knappen, och på ett ljust papper kommer den ur restaurangens egen färg via
   :root i sidans <head>. Här kan den inte göra det: en mörk yta mot ett mörkt
   papper är ingen yta. Sotpapperet äger den i stället, och den är ljus. Att
   deklarationen står på body och inte på :root är precis det som gör det
   möjligt — allt som läser var(--primar) ligger inuti body.

   --pa-mork följer med om: den är texten *på* den ytan och blir därför mörk.
   Tokenens namn beskriver rollen den har på fyra av fem papper; rollen — den
   av de två som inte är ytan — är densamma på alla fem. Se app/paletter.py.

   Restaurangens egen mörka ton försvinner inte, den slutar bara måla
   kassaraden. Den står kvar i tenants.primary_color och är det dekalen trycks
   med och appikonen målas med. Kulören bär accenten ensam här. */
body.tema-sot {
  --creme: #191714;
  --creme-djup: #221f1a;
  --papper: var(--creme);
  --primar: #e8e2d6;
  --pa-mork: #16130f;

  --text: #ece6da;
  --dampad: #a89d8c;
  --svag: #9a9081;
  --salvia: #a3a08c;

  /* Linjerna vänder också: ljust på mörkt, och fortfarande tonade — en
     kallvit linje på ett varmt sotpapper ser ut som en repa. */
  --linje: rgba(236, 230, 218, .14);
  --linje-stark: rgba(236, 230, 218, .26);
  --kant: var(--linje);
  --punktlinje: rgba(236, 230, 218, .28);
  --tonad: rgba(236, 230, 218, .07);

  /* Statustonerna lånar ur paletten som på de ljusa pappren, men de går inte
     att spegla: en mörk oliv och en mörk tegelröd syns inte mot sot. De är
     ljusa toner av samma två färger. Röd och accenten glöd ligger nära
     varandra i ton — det är skälet till att lackrött inte finns som kulör här,
     ett felmeddelande ska inte kunna läsas som vilken accenttext som helst. */
  --gron: #7cc79b;
  --rod: #f08b7e;
  --rod-bakgrund: #2e1a16;
  --sand: #2b2418;
  --sand-text: #e0bf74;
  --berg-sten: #9a8f7c;

  /* Glöd, mässing och krom är valda för att läsas mot nästan svart och är
     därför redan ljusa. Att lyfta dem mot vitt en gång till hade tagit bort
     kulören och lämnat en gråvit etikett. */
  --accent-ljus: var(--accent);

  /* Berättar för webbläsaren att sidan är mörk, och det är inte kosmetika:
     det som ritas av systemet och inte av oss — rullistan i en <select>,
     kryssrutor, rullister, autofyll — målas annars på en ljus platta medan
     texten i den ärver sotpapperets ljusa --text. Klockslagen i kassans
     tidväljare stod ljusgrå på nästan vitt och gick att läsa först under
     hovringen. Ingen färgregel i det här blocket når in i den listan; det gör
     bara den här raden. */
  color-scheme: dark;
}

* { box-sizing: border-box; }

/* Varje klass med egen display slår ut webbläsarens regel för hidden. En gång
   här i stället för en undantagsregel per komponent. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: var(--brodfont);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--text);
  background: var(--creme);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* --------------------------------------------------------------- spalten */

/* Allt som ska ligga i samma lodräta linje får den härifrån. Bakgrunder får
   gärna gå kant till kant; innehållet gör det aldrig. */
.spalt,
.menyn,
.kassa,
.orderstatus,
.textsida,
.offlinesida {
  width: min(var(--spalt), 100%);
  margin-inline: auto;
  padding-inline: var(--sidmarginal);
}

/* Läsande sidor har en smalare spalt än menyn — men samma mittlinje, så
   toppbaren och foten står kvar där de stod. */
.kassa,
.orderstatus,
.textsida { --spalt: 42rem; }
.offlinesida { --spalt: 32rem; }

/* --------------------------------------------------------------- typografi */

/* Vikt 400 rakt igenom. Georgia i halvfet blir tung och tappar den satta
   känslan; storleken och luften får bära hierarkin i stället. */
h1, h2, h3 {
  margin: 0;
  font-family: var(--rubrikfont);
  font-weight: 400;
  line-height: 1.2;
}
h1 { font-size: clamp(2rem, 1.6rem + 1.1vw, 2.375rem); }
h2 { font-size: 1.35rem; }
h3 { font-size: 1.1rem; }
a { color: inherit; }
img { max-width: 100%; }

.dampad { color: var(--dampad); font-size: .875rem; line-height: 1.55; }
/* Står inuti versala etiketter men läses som vanlig text — spärren och
   versalerna ärvs bort här, annars blir "( V A L F R I T T )". */
.valfritt {
  color: var(--svag); font-weight: 400; font-size: .85em;
  text-transform: none; letter-spacing: normal;
}
.hjalptext {
  display: block;
  font-size: .8125rem; line-height: 1.55; color: var(--dampad); font-weight: 400;
  text-transform: none; letter-spacing: normal;
  margin: .4rem 0 0;
}

/* Etiketten över en sektion: versaler, gles spärr, terrakotta. Samma
   komponent i heron, över menykategorierna och i kassan. */
.etikett {
  margin: 0;
  font-size: .6875rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
}

/* -------------------------------------------------------------------- topp */

.topp {
  position: sticky;
  top: 0;
  z-index: 20;
  /* Papperet med genomskinlighet, inte en fast creme: raden ligger kvar över
     sidan när man rullar, och en hårdkodad ton hade legat som en ljusare list
     tvärs över ett sandfärgat papper. color-mix därför att ett alfavärde inte
     går att skriva in i en färg som kommer ur en variabel. */
  background: color-mix(in srgb, var(--creme) 92%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid var(--linje);
}
.toppinnehall {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: .7rem;
}
.marke {
  /* Skjuter allt annat till höger. Utan den lade space-between ut de tre
     barnen jämnt över hela baren, och öppettidslänken hamnade mitt i raden
     så fort språkväljaren kom till. */
  margin-right: auto;
  display: flex;
  align-items: center;
  gap: .6rem;
  font-family: var(--rubrikfont);
  font-size: 1.0625rem;
  text-decoration: none;
  color: var(--text);
}
.marke img { width: 30px; height: 30px; border-radius: 50%; object-fit: cover; }

/* Diskret textlänk i toppens högra hörn — inget piller, ingen fylld yta. */
.topplank {
  font-size: .8125rem;
  color: var(--dampad);
  text-decoration: none;
  border-bottom: 1px solid var(--linje-stark);
  padding-bottom: 1px;
  transition: color .2s, border-color .2s;
}
.topplank:hover { color: var(--accent); border-color: var(--accent); }

/* Språkväljaren: flaggorna i rad, det valda språket framhävt. Ingen
   rullgardin — två språk ska vara ett tryck, och listan tål ett tredje utan
   att byta form. Flaggan är en liten bild och koden står bredvid: en flagga
   ensam är en gissningslek för den som inte känner igen den. */
.sprakval {
  display: flex;
  align-items: center;
  gap: .25rem;
}
.sprakflagga {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .25rem .4rem;
  border-radius: 6px;
  text-decoration: none;
  color: var(--dampad);
  font-size: .6875rem;
  letter-spacing: .04em;
  line-height: 1;
  /* Halvgenomskinlig i viloläge: det valda språket ska vara det ögat fastnar
     på, inte de man kan byta till. */
  opacity: .55;
  transition: opacity .2s, background .2s;
}
.sprakflagga svg {
  width: 18px;
  height: 12px;
  border-radius: 2px;
  display: block;
  /* Ramen håller isär flaggan och papperet där de har samma ton: en vit kant
     mot cremen, en svart mot sotet. Ur paletten och inte ren svart, just
     därför att den behöver byta håll med papperet. */
  box-shadow: 0 0 0 1px var(--linje-stark);
}
.sprakflagga b { font-weight: 600; }
a.sprakflagga:hover { opacity: 1; background: var(--tonad); }
.sprakflagga.aktiv {
  opacity: 1;
  color: var(--text);
  background: var(--tonad);
}

/* -------------------------------------------------------------------- hero */

/* Grundläget: ljus hero, på samma papper som resten av sidan. Ingen mörk yta,
   ingen toning — uppbyggnaden är tagline → namn → underrubrik → statusrad,
   och det är typografin som gör jobbet. Det här är vad varje ny restaurang
   har, och det ska stå för sig självt utan att se ut att sakna något. */
/* Vänsterställd, som ett titelblad. Centrerad text gav ett annat intryck —
   inbjudningskort snarare än meny — och lämnade dessutom rubriken utan en
   vänsterkant att dela med raderna under. */
.hero {
  padding-block: clamp(2.5rem, 6vw, 4rem) clamp(1.5rem, 3vw, 2.25rem);
  background: var(--creme);
  text-align: left;
}
.heroinnehall { display: flex; flex-direction: column; align-items: stretch; }

/* Fotoläget. Har restaurangen laddat upp en bild tar den hela heroytan och
   texten ligger ovanpå — tidigare var bilden en smal remsa ovanför rubriken,
   men en restaurang som fotograferat sin lokal ska få visa den, inte få den
   beskuren till ett band.

   Toningen är det som gör texten läsbar: två bakgrundslager, där det första
   ligger överst. Svart 60 % i botten och genomskinligt upptill, och innehållet
   skjutet nedåt med ``justify-content`` så all text står i den mörka delen.
   Ett foto som är ljust i botten finns inte — det är där toningen är som
   tätast. */
.hero.harfoto {
  background-image:
    linear-gradient(to top, rgba(0, 0, 0, .6), rgba(0, 0, 0, .15) 55%, rgba(0, 0, 0, 0)),
    var(--herofoto);
  background-size: cover;
  background-position: center;
  min-height: clamp(15rem, 38vw, 22rem);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  color: #fff;
  /* Plats nedtill för loggaplattan, som dras upp i heron underifrån. */
  padding-block: clamp(3rem, 8vw, 5rem) clamp(2.25rem, 4vw, 3rem);
}
/* En sista säkring för texten. Toningen räcker i praktiken, men ett foto med
   en vit vägg längst ned finns — och då är skuggan skillnaden mellan läsbart
   och nästan läsbart. */
.hero.harfoto .heroinnehall { text-shadow: 0 1px 14px rgba(0, 0, 0, .55); }
.hero.harfoto .heroledtext,
.hero.harfoto .lagesrad { color: rgba(255, 255, 255, .82); }
/* Öppet och stängt måste synas som just öppet och stängt även här. Oliv och
   rött är gjorda för creme och försvinner mot ett mörkt foto, så fotoläget
   har ljusare syskon i samma toner. */
.hero.harfoto .lagesbricka.oppen { color: #b6d3c1; }
.hero.harfoto .lagesbricka.stangd { color: #f0a992; }
.hero.harfoto .lagesbricka + .lagesbricka::before { color: rgba(255, 255, 255, .45); }
/* Etiketten över namnet — orten, eller "Beställ online" — hade blivit kvar i
   accenten rakt av och var det enda i heron som inte fått ett fotoläge. Den
   drabbas dessutom hårdare än allt annat av att stå högst i innehållet:
   toningen är tätast i botten, så namnet under den ligger i det mörkaste och
   etiketten i det tunnaste. Den ljusa accenten och en egen, tätare skugga än
   blockets diffusa fjortonpunktare — versaler i tretton pixlar behöver en rand
   nära bokstaven, inte ett moln runt den. Kvar är att den bryter av mot det
   vita namnet, vilket är hela poängen med den. */
.hero.harfoto .heroetikett {
  color: var(--accent-ljus);
  /* Tre lager och inte ett: en enda skugga blir en tunn kant som fotot äter
     upp, medan tre som ligger i varandra mörknar samma pixlar tre gånger och
     ger en rand som håller. Tätt och inte diffust: en bred skugga blir en
     mörk fläck bakom bokstäverna på ett ljust foto, medan en rand på två
     pixlar syns som en kant där den behövs och inte alls där fotot redan är
     mörkt. Mätt mot det värsta fotot som finns — en vit vägg — går etiketten
     från 3.5:1 till över 8:1 mellan ljusaste och mörkaste pixel.
     Avsnitt [3] i e2e/identitet.mjs mäter det på riktiga pixlar. */
  text-shadow:
    0 0 2px rgba(0, 0, 0, .95),
    0 0 2px rgba(0, 0, 0, .9),
    0 1px 3px rgba(0, 0, 0, .85);
}

/* Loggan på neutral platta. Alltid samma platta, oavsett vad som ligger
   bakom: mot ett foto behöver loggan en egen yta för att synas, och mot creme
   ger plattan den samma inramning som på fotot i stället för två olika
   utseenden att hålla i huvudet.

   Loggan färgas aldrig om — inget filter, ingen maskning. Det är
   restaurangens märke och ska vara dess egna färger. ``contain`` beskär den
   heller inte: en avlång logga blir liten men hel, inte kringklippt. */
.loggarad {
  position: relative;
  z-index: 1;
  display: flex;
  /* Halva plattan hänger nedanför heron. Marginalen tas i flödet, så
     kategorimenyn under skjuts ned av sig själv och kan aldrig hamna över. */
  margin-top: -2rem;
  margin-bottom: .35rem;
}
.loggaplatta {
  display: grid;
  place-items: center;
  width: 4rem;
  height: 4rem;
  border-radius: 50%;
  /* Vitt också på ett mörkt papper, med flit. Plattan är ett föremål och inte
     en yta: loggor ritas för vit botten, och en logga med svart text på ett
     sotfärgat mynt hade försvunnit. */
  background: #fff;
  border: 1px solid var(--linje);
  box-shadow: 0 2px 12px rgba(0, 0, 0, .1);
}
.loggaplatta img {
  width: 72%;
  height: 72%;
  object-fit: contain;
}

.heroetikett {
  margin: 0 0 .85rem;
  font-family: var(--rubrikfont);
  font-style: italic;
  font-size: .8125rem;
  letter-spacing: .0625rem;
  text-transform: uppercase;
  color: var(--accent);
}
/* Namnet är sidans enda stora sak och får bära hela överdelen själv. */
.hero h1 {
  margin: 0;
  font-size: clamp(2rem, 6vw, 2.375rem);
  line-height: 1.1;
}
.heroledtext {
  margin: .7rem 0 0;
  font-family: var(--rubrikfont);
  font-style: italic;
  font-size: 1rem;
  color: var(--dampad);
}

/* Statusraden: en mening satt med mittpunkter, inte en rad brickor. Bara
   öppetläget är understruket — det är den enda uppgiften kunden söker efter,
   och stryks allt under blir understrykningen ingen markering alls. */
.lagesrad {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .35rem .5rem;
  margin: 1.35rem 0 0;
  padding: 0;
  list-style: none;
  font-size: .8125rem;
  color: var(--dampad);
}
/* Mittpunkten hör till mellanrummet och inte till orden: den sätts av raden
   mellan syskonen, så en bortvald bricka aldrig lämnar en punkt efter sig. */
.lagesbricka + .lagesbricka::before {
  content: "·";
  margin-right: .5rem;
  color: var(--linje-stark);
}
.lagesbricka.lage {
  border-bottom: 1px solid currentColor;
  padding-bottom: .15rem;
}
/* --gron och inte --oliv: på de ljusa pappren är de samma färg (se --gron
   ovan), men sotpapperet skriver om --gron till en ljus ton och lämnar --oliv
   orörd. Grannen .stangd bär redan --rod, som sot skriver om — den här raden
   låg kvar på --oliv och "Öppet" stod osynlig mörkgrön på nästan svart utan
   hero-bild. */
.lagesbricka.oppen { color: var(--gron); }
.lagesbricka.stangd { color: var(--rod); }

/* ------------------------------------------------------------------- notis */

.notis {
  max-width: var(--innerspalt);
  margin: 1.25rem auto;
  padding: .85rem 1.1rem;
  border: 1px solid var(--linje-stark);
  background: transparent;
  color: var(--dampad);
  font-size: .875rem;
}
.notis.stangdnotis { border-color: var(--sand-text); color: var(--sand-text); background: var(--sand); }

/* ----------------------------------------------------------- husets favorit */

/* En enda framhävd rätt, direkt under heron. Inramad i restaurangens
   accentfärg och inte fylld med den: en fylld färgruta hade blivit en annons
   mitt på ett papper, och accentfärgen är restaurangens egen — den kan vara
   vad som helst, och en ram fungerar i alla toner medan en fylld yta kräver
   att texten på den råkar ha kontrast.

   Modulen finns bara i markupen när en favorit är satt. Ingen tom variant
   behöver därför formges. */
/* Lika mycket luft under som över. Utan den nedre marginalen låg kortets ram
   kant i kant med kategorimenyns överlinje — två streck ovanpå varandra, och
   rutan såg ut att sitta fast i listan i stället för att vara en egen sak. */
.favorit { margin-block: clamp(1.5rem, 3vw, 2.25rem); }
.favoritkort {
  display: flex;
  align-items: center;
  gap: 1rem;
  width: 100%;
  padding: .9rem 1.1rem;
  text-align: left;
  background: transparent;
  border: 1px solid var(--accent);
  border-radius: var(--radie);
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition: background .2s, transform .2s var(--mjuk);
}
.favoritkort:hover { background: var(--tonad); }
.favoritkort:active { transform: scale(.995); }
.favoritbild {
  flex: none;
  width: 4.25rem;
  height: 4.25rem;
  border-radius: var(--radie-s);
  background-size: cover;
  background-position: center;
}
.favorittext { display: flex; flex-direction: column; gap: .2rem; min-width: 0; }
.favoritetikett {
  font-size: .6875rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
}
.favoritnamn { font-family: var(--rubrikfont); font-size: 1.0625rem; }
/* Restaurangens egen mening om rätten. Kursiv som resten av de talade
   texterna på sidan — ledtexten i heron, ingresserna — så den läses som
   någon som säger något och inte som ännu en uppgift. */
.favoritnotis {
  font-family: var(--rubrikfont);
  font-style: italic;
  font-size: .875rem;
  color: var(--dampad);
}
.favoritpris { margin-top: .15rem; font-size: .9375rem; }
.favoritkort .chevron { margin-left: auto; }

/* Raden favoriten och kampanjen delar. Marginalen flyttas hit från .favorit,
   annars hade två block i samma rad lagt sin luft var för sig och den ena
   halvan börjat en centimeter längre ned än den andra. */
.framrad { margin-block: clamp(1.5rem, 3vw, 2.25rem); }
.framrad > * { margin-block: 0; }

/* Kampanjen. Fylld platta och inte en ram som favoriten: de två står bredvid
   varandra, och två identiska rutor med olika innehåll läses som en lista där
   det ska stå två olika sorters erbjudanden. Accentfärgen är restaurangens
   egen, så plattan följer med när någon byter den. */
.kampanjbanner {
  display: flex;
  flex-direction: column;
  gap: .2rem;
  padding: .9rem 1.1rem;
  border: 1px solid var(--accent);
  border-radius: var(--radie);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
/* Rubriken och styckena bär med sig webbläsarens egna marginaler, och i en
   flexkolumn faller de inte ihop utan läggs till radavståndet. Utan det här
   står raderna tre centimeter isär medan favoriten bredvid är tätt satt. */
.kampanjbanner > * { margin: 0; }
.kampanjetikett {
  font-size: .6875rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
}
.kampanjnamn { font-family: var(--rubrikfont); font-size: 1.0625rem; font-weight: normal; }
.kampanjformaan { font-size: .9375rem; }
.kampanjvillkor { font-size: .875rem; color: var(--dampad); }
/* Länken sist och tryckt mot underkanten: står kampanjen bredvid favoriten är
   korten olika höga, och en länk som flyter mitt i luften ser ut att höra till
   nästa sak på sidan. */
.kampanjlank {
  margin-top: auto;
  padding-top: .35rem;
  font-size: .875rem;
  color: var(--accent);
  text-decoration: none;
}
.kampanjlank:hover { text-decoration: underline; }

/* -------------------------------------------------------------------- meny */

.kategorimeny {
  position: sticky;
  top: 3.1rem;
  z-index: 15;
  /* Samma skäl som .topp: papperet, inte cremen. */
  background: color-mix(in srgb, var(--creme) 94%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  border-block: 1px solid var(--linje);
}
.kategorirad {
  display: flex;
  gap: 1.5rem;
  padding-block: .7rem;
  overflow-x: auto;
  scrollbar-width: none;
}
.kategorirad::-webkit-scrollbar { display: none; }
.kategorimeny a {
  flex: none;
  font-size: .6875rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  color: var(--dampad);
  transition: color .2s;
}
.kategorimeny a:hover { color: var(--accent); }

.menyn { padding-block: clamp(2rem, 5vw, 3.25rem) 7rem; }
.kategori { margin-bottom: clamp(2.25rem, 5vw, 3.5rem); scroll-margin-top: 7rem; }

/* Kategorietiketten: 11px versaler i terrakotta, med en linje under som håller
   ihop sektionen. Inget band, ingen toning — samma återhållsamhet som resten. */
.kategori > h2 {
  font-family: var(--brodfont);
  font-size: .6875rem;
  font-weight: 400;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
  padding-bottom: .7rem;
  border-bottom: 1px solid var(--linje-stark);
}
.kategoritext { margin: .8rem 0 0; max-width: 38rem; color: var(--dampad); font-size: .875rem; }

.rattlista { list-style: none; margin: 0; padding: 0; }

/* --- menyraden, kärnkomponenten i hela konceptet ---------------------- */

/* Hela raden är klickbar. Att det ändå är ett <button>-element är för
   tangentbord och skärmläsare: den syns aldrig som en knapp, men den går att
   nå med tab och läses upp som något man kan trycka på. */
.menyrad {
  display: flex;
  flex-direction: column;
  gap: .2rem;
  width: 100%;
  padding: 14px 0;
  border: 0;
  border-bottom: 1px solid var(--linje);
  background: transparent;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  transition: opacity .2s var(--mjuk);
}
.rattlista li:last-child .menyrad { border-bottom: 0; }
.menyrad:hover .rattnamn { color: var(--accent); }
.menyrad:active { opacity: .6; }

.radtopp { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; }

/* Fast bredd, så namnen står på linje oavsett om numret är 7 eller 142. */
.rattnummer {
  flex: none;
  width: 16px;
  font-size: .8125rem;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.rattnamn {
  font-family: var(--rubrikfont);
  font-size: 1.0625rem;
  color: var(--text);
  transition: color .2s;
}
/* Punktlinjen fram till priset. Sitter något ovanför baslinjen, annars läser
   ögat den som understrykning av rättnamnet. */
.punktlinje {
  flex: 1;
  min-width: 1.5rem;
  border-bottom: 1px dotted var(--punktlinje);
  margin-bottom: 5px;
}
.rattpris {
  flex: none;
  font-size: .9375rem;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.chevron { flex: none; color: var(--accent); font-size: 1.1rem; line-height: 1; opacity: .75; }

/* Ingredienserna hör till raden, inte under den: i en tryckt meny står de
   mellan rättnamnet och priset, satta mindre och i salvia. På en telefon finns
   inte bredden — ``order`` viker ned dem på egen rad utan att markupen ändras,
   och punktlinjen får då tillbaka hela mellanrummet. */
.rattmeta {
  flex: 1 1 100%;
  order: 9;
  font-size: .8125rem;
  line-height: 1.5;
  color: var(--salvia);
}
.rattlista.numrerad .rattmeta,
.rattlista.numrerad .dealmarke { padding-left: 24px; }

/* Frågan gäller raden, inte fönstret: på skrivbord står menyn i två spalter,
   och en rad är då smalare än på en telefon i liggande läge. Ett @media hade
   satt ingredienserna inline just där det är trängst och tryckt ned priset på
   egen rad. */
.ratt { container-type: inline-size; }

@container (min-width: 30rem) {
  /* Egen spalt som håller sig nära priset, inte text som rinner ut direkt
     efter namnet: punktlinjen behåller ``flex: 1`` och skjuter ingredienserna
     högerut, precis som en tryckt meny sätter dem. Därför slutar linjen vid
     ingredienserna på de rader som har några — de leder resten av vägen. */
  .rattmeta { flex: 0 1 40%; order: 0; min-width: 0; }
  .rattlista.numrerad .rattmeta { padding-left: 0; }
}

/* Allergener stannar alltid på egen rad: de läses av den som söker dem, och
   ska aldrig konkurrera med ingredienserna om samma utrymme. */
.allergener {
  flex: 1 1 100%;
  order: 10;
  text-transform: uppercase;
  letter-spacing: .08em;
  font-size: .6875rem;
  color: var(--svag);
}
.rattlista.numrerad .allergener { padding-left: 24px; }

/* ── Styrkemärket ─────────────────────────────────────────────────────────
 *
 * Två skinn på en och samma siffra. Vilket som ritas bestäms av restaurangen
 * (``tenant_settings.spice_scale``); menyn lagrar sin styrka likadant oavsett.
 *
 * Märket står på egen rad ovanför allergenerna. Bägge är sådant en gäst
 * *söker efter* — de ska inte behöva samsas med ingredienserna om bredden.
 *
 * Ikonerna är ritade i CSS och inte som bilder eller tecken: en bild till är
 * en hämtning till på varje meny, och ett tecken ritas olika i varje
 * teckensnitt — vulkanemojin är en tecknad figur på en telefon och en grå
 * kontur på nästa. Formerna nedan ser likadana ut överallt och skalar med
 * texten. */
.styrka {
  flex: 1 1 100%;
  order: 9;
  display: flex;
  align-items: center;
  gap: .25rem;
  margin-top: .15rem;
  text-transform: uppercase;
  letter-spacing: .08em;
  font-size: .6875rem;
  /* Samma röda som resten av statusfärgerna. 5.9:1 mot papperet — märket är
     det enda i menyn en gäst kan må dåligt av att läsa fel. */
  color: var(--rod);
}
.rattlista.numrerad .styrka { padding-left: 24px; }
.styrka .styrkatext { margin-left: .15rem; }

.styrka i {
  flex: none;
  display: block;
  /* Formen är en mask och färgen ligger i bakgrunden. Det är hela knepet:
     märket kan då fyllas underifrån med en gradient utan att formen behöver
     ritas om, och samma tre tomma ``<i>`` duger åt båda skinnen — mallen och
     ``shop.js`` slipper var sin kopia av en SVG. */
  -webkit-mask-repeat: no-repeat;  mask-repeat: no-repeat;
  -webkit-mask-position: center;   mask-position: center;
  -webkit-mask-size: contain;      mask-size: contain;
}

/* Vesuvio: *ett* berg i tre lägen, inte tre likadana ikoner på rad. Glöden
   stiger i konen och berget gör något nytt vid varje steg — krönet ryker,
   halva berget glöder, hela berget får utbrott. Det är hela poängen med
   skalan: den som räknar frukter bredvid varandra har redan gjort det alla
   andra gjort.

   Att det är tre silhuetter och inte en enda som fylls olika högt är ett
   medvetet val. En trapets är ett berg; det är röken och utbrottet som gör
   den till en vulkan, och de går bara att teckna om formen får ändra sig.
   Storleken följer texten men är rejält tilltagen — under ungefär 14 px
   slutar vilken silhuett som helst att gå att tyda, och då är märket bara en
   fläck. */
.skala-vesuvio i:nth-child(2),
.skala-vesuvio i:nth-child(3) { display: none; }
.skala-vesuvio i { width: 1.45em; height: 1.45em; }

/* Rykande: berget ligger kallt och bara röken över krönet lyser. Brytpunkten
   64 % ligger strax ovanför konens topp (y=9 av 24), så inget av själva
   berget färgas. */
.skala-vesuvio[data-niva="1"] i {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%3E%3Cpath%20fill%3D%27%23000%27%20d%3D%27M7%209%20L9.6%209%20L12%2010.1%20L14.4%209%20L17%209%20C18.9%2013.3%2021%2018.1%2022.3%2021.1%20C22.5%2021.6%2022.2%2022%2021.6%2022%20L2.4%2022%20C1.8%2022%201.5%2021.6%201.7%2021.1%20C3%2018.1%205.1%2013.3%207%209%20Z%20M12.6%208.4%20C11.4%207.4%2011.2%206.4%2011.9%205.4%20C12.7%204.3%2012.6%203.4%2011.6%202.6%20C13.6%202.9%2014.4%204.1%2013.8%205.6%20C13.3%206.7%2013.4%207.6%2014.2%208.4%20Z%27%2F%3E%3C%2Fsvg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%3E%3Cpath%20fill%3D%27%23000%27%20d%3D%27M7%209%20L9.6%209%20L12%2010.1%20L14.4%209%20L17%209%20C18.9%2013.3%2021%2018.1%2022.3%2021.1%20C22.5%2021.6%2022.2%2022%2021.6%2022%20L2.4%2022%20C1.8%2022%201.5%2021.6%201.7%2021.1%20C3%2018.1%205.1%2013.3%207%209%20Z%20M12.6%208.4%20C11.4%207.4%2011.2%206.4%2011.9%205.4%20C12.7%204.3%2012.6%203.4%2011.6%202.6%20C13.6%202.9%2014.4%204.1%2013.8%205.6%20C13.3%206.7%2013.4%207.6%2014.2%208.4%20Z%27%2F%3E%3C%2Fsvg%3E");
  background: linear-gradient(to top, var(--berg-sten) 0 64%, var(--rod) 64%);
}
/* Glödande: glöden har stigit in i konens övre tredjedel, och en gnista följer
   med röken upp. */
.skala-vesuvio[data-niva="2"] i {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%3E%3Cpath%20fill%3D%27%23000%27%20d%3D%27M7%209%20L9.6%209%20L12%2010.1%20L14.4%209%20L17%209%20C18.9%2013.3%2021%2018.1%2022.3%2021.1%20C22.5%2021.6%2022.2%2022%2021.6%2022%20L2.4%2022%20C1.8%2022%201.5%2021.6%201.7%2021.1%20C3%2018.1%205.1%2013.3%207%209%20Z%20M12%203.4%20L13.3%206.6%20L12%205.8%20L10.7%206.6%20Z%20M12.6%208.4%20C11.4%207.4%2011.2%206.4%2011.9%205.4%20C12.7%204.3%2012.6%203.4%2011.6%202.6%20C13.6%202.9%2014.4%204.1%2013.8%205.6%20C13.3%206.7%2013.4%207.6%2014.2%208.4%20Z%27%2F%3E%3C%2Fsvg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%3E%3Cpath%20fill%3D%27%23000%27%20d%3D%27M7%209%20L9.6%209%20L12%2010.1%20L14.4%209%20L17%209%20C18.9%2013.3%2021%2018.1%2022.3%2021.1%20C22.5%2021.6%2022.2%2022%2021.6%2022%20L2.4%2022%20C1.8%2022%201.5%2021.6%201.7%2021.1%20C3%2018.1%205.1%2013.3%207%209%20Z%20M12%203.4%20L13.3%206.6%20L12%205.8%20L10.7%206.6%20Z%20M12.6%208.4%20C11.4%207.4%2011.2%206.4%2011.9%205.4%20C12.7%204.3%2012.6%203.4%2011.6%202.6%20C13.6%202.9%2014.4%204.1%2013.8%205.6%20C13.3%206.7%2013.4%207.6%2014.2%208.4%20Z%27%2F%3E%3C%2Fsvg%3E");
  background: linear-gradient(to top, var(--berg-sten) 0 46%, var(--rod) 46%);
}
/* Utbrott: hela berget är rött och kastar ut sitt innehåll. */
.skala-vesuvio[data-niva="3"] i {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%3E%3Cpath%20fill%3D%27%23000%27%20d%3D%27M7%209%20L9.6%209%20L12%2010.1%20L14.4%209%20L17%209%20C18.9%2013.3%2021%2018.1%2022.3%2021.1%20C22.5%2021.6%2022.2%2022%2021.6%2022%20L2.4%2022%20C1.8%2022%201.5%2021.6%201.7%2021.1%20C3%2018.1%205.1%2013.3%207%209%20Z%20M12%201.4%20L13.7%206%20L12%204.9%20L10.3%206%20Z%20M6.4%203.9%20L8.3%206.7%20L6.6%206.2%20L4.9%207.4%20Z%20M17.6%203.9%20L19.1%207.4%20L17.4%206.2%20L15.7%206.7%20Z%27%2F%3E%3C%2Fsvg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%3E%3Cpath%20fill%3D%27%23000%27%20d%3D%27M7%209%20L9.6%209%20L12%2010.1%20L14.4%209%20L17%209%20C18.9%2013.3%2021%2018.1%2022.3%2021.1%20C22.5%2021.6%2022.2%2022%2021.6%2022%20L2.4%2022%20C1.8%2022%201.5%2021.6%201.7%2021.1%20C3%2018.1%205.1%2013.3%207%209%20Z%20M12%201.4%20L13.7%206%20L12%204.9%20L10.3%206%20Z%20M6.4%203.9%20L8.3%206.7%20L6.6%206.2%20L4.9%207.4%20Z%20M17.6%203.9%20L19.1%207.4%20L17.4%206.2%20L15.7%206.7%20Z%27%2F%3E%3C%2Fsvg%3E");
  background: var(--rod);
}

/* Peperoncino: det gästen på ett thaiställe redan kan läsa utan förklaring.
   Ofyllda frukter står kvar som kontur, så att skalans längd syns även på en
   etta — "1 av 3" ska gå att se och inte bara läsa. Konturen är samma silhuett
   tecknad med stroke i stället för fyllning; frukten är en och samma form i
   båda lägena, och det är bara fyllningen som skiljer. */
.skala-peperoncino i {
  width: .72em;
  height: 1.45em;
  background: var(--rod);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%277%201.2%2010%2022%27%3E%3Cpath%20fill%3D%27none%27%20stroke%3D%27%23000%27%20stroke-width%3D%271.6%27%20stroke-linejoin%3D%27round%27%20d%3D%27M13%206.4%20C12.8%204.2%2011.4%202.8%209.4%202.4%20C8.4%202.2%208.1%203.4%209%203.8%20C10.2%204.3%2011%205.3%2011.2%206.6%20Z%20M9%207.8%20C9%206.4%2015.4%206.4%2015.8%208.6%20C17%2014%2015.2%2018.6%2011.2%2021.8%20C10.6%2022.3%209.8%2021.8%2010%2021%20C11.4%2016.2%2011%2011.6%209.2%208.4%20Z%27%2F%3E%3C%2Fsvg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%277%201.2%2010%2022%27%3E%3Cpath%20fill%3D%27none%27%20stroke%3D%27%23000%27%20stroke-width%3D%271.6%27%20stroke-linejoin%3D%27round%27%20d%3D%27M13%206.4%20C12.8%204.2%2011.4%202.8%209.4%202.4%20C8.4%202.2%208.1%203.4%209%203.8%20C10.2%204.3%2011%205.3%2011.2%206.6%20Z%20M9%207.8%20C9%206.4%2015.4%206.4%2015.8%208.6%20C17%2014%2015.2%2018.6%2011.2%2021.8%20C10.6%2022.3%209.8%2021.8%2010%2021%20C11.4%2016.2%2011%2011.6%209.2%208.4%20Z%27%2F%3E%3C%2Fsvg%3E");
}
.skala-peperoncino[data-niva="1"] i:nth-child(1),
.skala-peperoncino[data-niva="2"] i:nth-child(-n+2),
.skala-peperoncino[data-niva="3"] i {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%277%201.2%2010%2022%27%3E%3Cpath%20fill%3D%27%23000%27%20d%3D%27M13%206.4%20C12.8%204.2%2011.4%202.8%209.4%202.4%20C8.4%202.2%208.1%203.4%209%203.8%20C10.2%204.3%2011%205.3%2011.2%206.6%20Z%20M9%207.8%20C9%206.4%2015.4%206.4%2015.8%208.6%20C17%2014%2015.2%2018.6%2011.2%2021.8%20C10.6%2022.3%209.8%2021.8%2010%2021%20C11.4%2016.2%2011%2011.6%209.2%208.4%20Z%27%2F%3E%3C%2Fsvg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%277%201.2%2010%2022%27%3E%3Cpath%20fill%3D%27%23000%27%20d%3D%27M13%206.4%20C12.8%204.2%2011.4%202.8%209.4%202.4%20C8.4%202.2%208.1%203.4%209%203.8%20C10.2%204.3%2011%205.3%2011.2%206.6%20Z%20M9%207.8%20C9%206.4%2015.4%206.4%2015.8%208.6%20C17%2014%2015.2%2018.6%2011.2%2021.8%20C10.6%2022.3%209.8%2021.8%2010%2021%20C11.4%2016.2%2011%2011.6%209.2%208.4%20Z%27%2F%3E%3C%2Fsvg%3E");
}

/* I rättarket står märket ensamt under beskrivningen och får ta plats. */
.arkstyrka { margin: .1rem 0 .6rem; }

/* Aktiv deal på raden: ordinarie pris överstruket, dealpriset i terrakotta,
   och en rad som säger vad som ingår och när det gäller. */
.dealpris { color: var(--accent); }
.ordinariepris { color: var(--svag); font-size: .8125rem; margin-right: .35rem; }
.dealmarke {
  font-size: .75rem;
  letter-spacing: .04em;
  color: var(--accent);
}

/* Kampanjmärke på själva menyraden: en liten pill i accentfärg som säger att
   den pågående kampanjen biter på just den rätten. Bordad och inte fylld, så
   kontrasten är accent-på-papper (samma som .dealmarke klarar) oavsett vilken
   kulör restaurangen satt. Står mellan namnet och punktlinjen. */
.kampanjmarke {
  display: inline-block;
  margin-left: .4rem;
  padding: 0 .4rem;
  border: 1px solid var(--accent);
  border-radius: 999px;
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .02em;
  line-height: 1.5;
  color: var(--accent);
  white-space: nowrap;
  vertical-align: middle;
}

/* ------------------------------------------------- skylten till plattformarna */

/* Raden med Foodora, Wolt och Uber Eats. Står på menyn och i kassan, båda
   gångerna som en .panel — samma linje över och samma versaletikett som
   rubrikerna omkring — och båda gångerna under restaurangens egna val.

   Knapparna är avsiktligt de tystaste på hela sidan: papperets ton, en tunn
   kant och tjänstens namn i text. Ingen främmande varumärkesfärg, ingen fylld
   knapp. Det som ska sticka ut i en kassa är kassans egen knapp, och den här
   raden är en upplysning om var maten *också* finns — inte ett erbjudande som
   konkurrerar med det gästen redan står i. */

.menyn .leveransskylt {
  /* På menyn är skylten första .panel:en och tappar annars linjen över sig
     (.panel:first-of-type). Den behövs där: utan den flyter raden ihop med
     sista kategorin. */
  border-top: 1px solid var(--linje-stark);
  padding-top: 1.75rem;
  margin-bottom: 3rem;
}
.skylttext {
  margin: 0 0 1rem;
  max-width: 48ch;
  font-size: .875rem;
  color: var(--dampad);
}
.skyltknappar { display: flex; flex-wrap: wrap; gap: .6rem; margin: 0; }
.skyltknapp {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  background: var(--papper);
  color: var(--oliv);
  border: 1px solid var(--linje-stark);
  border-radius: 999px;
  padding: .5rem 1rem;
  /* 44 px är minsta träffyta för en tumme. Texten är liten med flit — knappen
     ska vara den tystaste på sidan — men liten text får inte ge en liten
     knapp: bredvid varandra på en telefon är det här just där en felträff
     kostar mest. Höjden sätts därför i knappen och inte av teckengraden. */
  min-height: 44px;
  font-size: .8125rem;
  letter-spacing: .02em;
  text-decoration: none;
  transition: background .2s var(--mjuk), color .2s var(--mjuk), border-color .2s var(--mjuk);
}
.skyltknapp svg { width: 1em; height: 1em; flex: none; }
.skyltknapp:hover, .skyltknapp:focus-visible {
  background: var(--oliv);
  color: var(--pa-mork);
  border-color: var(--oliv);
}
.skyltknapp:focus-visible { outline: 2px solid var(--oliv); outline-offset: 2px; }

/* --------------------------------------------- öppettider och platsen */

/* De två sista blocken på sidan hör ihop: när huset är öppet och var huset
   ligger. Var för sig fyller ingen av dem en hel spalt — tabellen är smal av
   naturen och kartan är ett liggande fotografi — så staplade lämnade de var
   sitt tomrum bredvid sig. På bred skärm ställs de i stället i samma rad. Se
   .underrad längst ned, i brytpunkten menyn redan delar sig vid. */

.oppettider { margin-bottom: 3rem; scroll-margin-top: 7rem; }
.oppettabell { width: 100%; border-collapse: collapse; font-size: .875rem; margin-top: 1rem; }
.oppettabell caption {
  text-align: left;
  font-size: .6875rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
  padding-bottom: .7rem;
  border-bottom: 1px solid var(--linje-stark);
}
.oppettabell th { text-align: left; font-weight: 400; padding: .5rem 0; border-bottom: 1px solid var(--linje); }
.oppettabell td { text-align: right; color: var(--dampad); padding: .5rem 0; border-bottom: 1px solid var(--linje); }
.oppettabell tr:last-child th, .oppettabell tr:last-child td { border-bottom: 0; }
.schemapar { display: grid; gap: 2rem; }

/* --------------------------------------------------------------- platsen */

/* Kartan är en illustration i tidningen, inte ett verktyg: en still bild med
   en nål i, satt i samma spalt som menyn och med samma tunna linjer omkring.
   Allt som liknar en kontroll — zoomknappar, kompass — är bortvalt i JS. */

.plats { margin-bottom: 3.5rem; scroll-margin-top: 7rem; }
.plats h2 {
  font-size: .6875rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 .7rem;
  padding-bottom: .7rem;
  border-bottom: 1px solid var(--linje-stark);
}
.plats address { font-style: normal; line-height: 1.7; }
.platstelefon { margin: .35rem 0 0; }
.platstelefon a { color: var(--dampad); }
.platstelefon a:hover { color: var(--accent); }

/* Bildtexten till utkörningsringen. En bildtext och inte ett meddelande: den
   berättar vad kunden ser, den varnar inte. Därför dämpad text i samma storlek
   som resten av småtexten — kassan är stället där gränsen får säga ifrån.

   Ringen framför meningen är samma cirkel som på kartan, i miniatyr: streckad
   kant i accentfärgen och en aning fyllning. Den knyter texten till kartan utan
   att behöva skriva "den streckade cirkeln" i ord, och överlever att kartan
   inte laddar — då står den kvar som en prick, inte som en trasig referens. */
.platsradie {
  margin: .9rem 0 0;
  font-size: .8125rem;
  line-height: 1.6;
  color: var(--dampad);
}
.platsradie::before {
  content: "";
  display: inline-block;
  width: .7rem;
  height: .7rem;
  margin-right: .45rem;
  vertical-align: -.05rem;
  border: 1px dashed var(--accent);
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}

.kartruta {
  position: relative;
  margin-top: 1.25rem;
  /* Bredare än hög, som en bild i ett reportage. Låg nog att den inte tar
     över sidan på en telefon, hög nog att kvarteret får plats. */
  aspect-ratio: 16 / 9;
  max-height: 22rem;
  border-radius: var(--radie);
  overflow: hidden;
  border: 1px solid var(--linje);
  /* Samma creme som kartans egen botten, så en ruta som ännu inte ritats
     ser ut som en tom yta och inte som ett hål i sidan. */
  background: var(--creme-djup);
}
/* Specificiteten är avsiktlig: maplibre-gl.css sätter .maplibregl-map till
   position: relative och laddas efter shop.css. Utan den extra specificiteten
   blev rutan noll pixlar hög och kartan osynlig. */
.kartruta > .karta { position: absolute; inset: 0; }

/* Vägbeskrivningen: en knapp i nedre vänstra hörnet. Den låg som en yta över
   hela kartan så länge kartan var en stillbild, men en karta som går att dra
   kan inte ha en länk ovanpå sig — varje drag hade blivit ett klick, och
   kunden hamnat i Google Maps när hen ville flytta bilden två kvarter. */
.kartlank {
  position: absolute;
  left: .8rem;
  bottom: .8rem;
  /* Över kartans canvas, under upphovsrättsnotisen som måste gå att trycka
     på — det är villkoret för att få använda OpenStreetMap-datan. */
  z-index: 2;
  background: var(--papper);
  color: var(--oliv);
  border: 1px solid var(--linje-stark);
  border-radius: 999px;
  padding: .4rem .9rem;
  font-size: .8125rem;
  letter-spacing: .02em;
  text-decoration: none;
  box-shadow: 0 2px 10px -4px rgba(37, 37, 37, .35);
  transition: background .2s var(--mjuk), color .2s var(--mjuk);
}
.kartlank:hover, .kartlank:focus-visible {
  background: var(--oliv);
  color: var(--pa-mork);
  border-color: var(--oliv);
}
.kartlank:focus-visible { outline: 2px solid var(--oliv); outline-offset: 2px; }

/* Zoomknapparna. MapLibres standard är vita rutor med hårda skuggor; de här är
   samma papper, kant och rundning som resten av sidan, så att kartan ser ut att
   höra hemma i menyn och inte i en inbäddad widget. */
.kartruta .maplibregl-ctrl-group {
  background: var(--papper);
  border: 1px solid var(--linje-stark);
  border-radius: var(--radie);
  box-shadow: 0 2px 10px -4px rgba(37, 37, 37, .35);
  overflow: hidden;
}
.kartruta .maplibregl-ctrl-group button + button { border-top: 1px solid var(--linje); }
.kartruta .maplibregl-ctrl-group button { width: 30px; height: 30px; }
.kartruta .maplibregl-ctrl-group button:hover { background: var(--creme-djup); }
.kartruta .maplibregl-ctrl-group button:focus-visible {
  outline: 2px solid var(--oliv);
  outline-offset: -2px;
  box-shadow: none;
}

/* Beskedet som visas när någon skrollar över kartan utan Ctrl, eller drar med
   ett finger på telefonen. MapLibres eget är svart med stor vit text; det här
   är husets mörka ton och en ordinär textstorlek — en upplysning, inte en
   varning. Den är ändå bara synlig i ett par sekunder. */
.kartruta .maplibregl-cooperative-gesture-screen {
  background: rgba(37, 45, 41, .55);
  color: var(--pa-mork);
  font-size: .9375rem;
  letter-spacing: .01em;
  padding: 1.5rem;
  text-align: center;
}

/* Nålen. Skuggan sitter på svg:n och inte på en pseudo-elementkopia, så den
   följer bladformen i stället för att bli en rektangel under den. */
.kartnal { filter: drop-shadow(0 3px 5px rgba(37, 37, 37, .35)); display: block; }

/* Upphovsrättsnotisen ligger överst i sitt hörn: den måste gå att trycka på,
   annars använder vi OpenStreetMaps data utan att uppfylla villkoret. */
.kartruta .maplibregl-ctrl-bottom-right { z-index: 3; }
.kartruta .maplibregl-ctrl-attrib {
  background: color-mix(in srgb, var(--creme) 80%, transparent);
  font-size: .625rem;
}
.kartruta .maplibregl-ctrl-attrib a { color: var(--dampad); }

/* Kartan kunde inte laddas — filen saknas eller webbläsaren har ingen WebGL.
   Då ska ytan se avsiktlig ut: adressen står redan ovanför, och det här blir
   en dämpad platta med länken kvar i hörnet. */
.kartruta.kartafel .karta { display: none; }

@media (min-width: 48rem) {
  /* På bredare skärmar står texten bredvid kartan i stället för över den —
     samma uppslag som öppettiderna, och adressen hamnar i ögonhöjd med nålen. */
  .plats {
    display: grid;
    grid-template-columns: minmax(12rem, 1fr) 2fr;
    gap: 2rem;
    align-items: start;
  }
  .plats h2 { grid-column: 1 / -1; }
  .kartruta { margin-top: 0; }
}

/* --------------------------------------------------------- nedre arket */

/* Bottom sheet. Det är här allt som liknar en kontroll finns — knappar,
   stepper, kryssrutor — så att menylistan kan förbli en menylista. */
.rattark {
  width: min(30rem, 100vw);
  max-height: 88vh;
  padding: 0;
  border: 0;
  border-radius: var(--radie-ark) var(--radie-ark) 0 0;
  background: var(--creme);
  color: var(--text);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 0 -8px 40px -12px rgba(37, 37, 37, .35);
}
/* display: flex ovanför slår ut webbläsarens egen regel om att en stängd
   dialog inte syns, och då låg en tom ruta kvar längst ned på menyn. */
.rattark:not([open]) { display: none; }
.rattark::backdrop { background: rgba(34, 58, 48, .45); }
.rattark[open] { margin: auto auto 0; animation: arkupp .3s var(--mjuk); }
@keyframes arkupp {
  from { transform: translateY(16px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

.arktopp { display: flex; justify-content: flex-end; padding: .6rem .6rem 0; }
.arktopp button {
  width: 2rem; height: 2rem;
  border: 1px solid var(--linje-stark);
  border-radius: 50%;
  background: transparent;
  font-size: 1.05rem; line-height: 1; cursor: pointer;
  transition: background-color .2s, border-color .2s;
}
.arktopp button:hover { background: var(--creme-djup); border-color: var(--dampad); }

.arkinnehall { padding: 0 1.35rem 1.35rem; overflow-y: auto; }
.arkbild {
  display: block;
  width: 100%;
  height: clamp(8rem, 34vw, 11rem);
  object-fit: cover;
  border-radius: var(--radie);
  margin-bottom: 1rem;
}
.arkinnehall h2 { margin-bottom: .3rem; font-size: 1.45rem; }
.arkinnehall > .dampad { margin: 0 0 .3rem; }
.arkdeal {
  margin: .8rem 0 0;
  padding: .6rem .8rem;
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: .8125rem;
}

.tillvalsgrupp { margin: 1.35rem 0 0; padding: 0; border: 0; }
.tillvalsgrupp legend {
  padding: 0 0 .5rem;
  font-size: .6875rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--dampad);
}
.kryss { display: flex; align-items: baseline; gap: .6rem; padding: .5rem 0; font-size: .9375rem; }
.kryss + .kryss { border-top: 1px solid var(--linje); }
.kryss input { margin: 0; flex: none; accent-color: var(--primar); }
.kryss .pristillagg { margin-left: auto; color: var(--svag); font-size: .8125rem; white-space: nowrap; }

/* Raden med räknare i stället för kryssruta — en grupp där samma sås får tas
   flera gånger. ``center`` och inte ``baseline`` som syskonet ovanför: knappar
   har ingen textbaslinje att ställa sig på, och raden hade lagt sig snett.
   Namnet får krympa så att pris och räknare aldrig pressas ut ur raden.

   Ordningen är namn → räknare → pris, och priset står alltså sist. Förr sköt
   ``.kryss .pristillagg`` beloppet till mitten med sitt ``margin-left: auto``,
   granne med minusknappen — samma fel som innehållsraden hade, och ögat läste
   "+15 kr" som priset för att *avstå*. Autot flyttade till räknaren, som nu är
   det som skjuts åt höger. */
.kryss.raknarrad { align-items: center; }
.kryss.raknarrad > span:first-child { min-width: 0; }
/* Reserverad bredd, inte innehållets, och innehållet högerställt. Minus och
   talet göms tills raden bär något, och utan de här två raderna hade plusset
   glidit fram och tillbaka mellan såserna varje gång ett val ändrades. Måttet
   är gruppens fulla bredd: två knappar på 26 px, ett tal på 1,3 rem och de två
   gluggarna på .35 rem emellan. */
.kryss.raknarrad .antalsvaljare {
  flex: none;
  margin-left: auto;
  justify-content: flex-end;
  width: calc(26px + 26px + 1.3rem + .7rem);
}
/* Priset i egen kolumn med reserverad minimibredd, högerställt: "Ingår" och
   "+15 kr" är olika långa och räknarna ska ändå stå i lod. ``min-width`` och
   inte ``width`` — ett ovanligt dyrt tillval ska knuffa sin egen rad, inte
   klippas av. Autot bor på räknaren ovanför och får inte stå kvar här. */
.kryss.raknarrad .pristillagg {
  margin-left: 0;
  min-width: 3.75rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Rättens innehåll: hopfällt, och tyst nog att inte konkurrera med de frågor
   som måste besvaras. ``details`` och inte en egen knapp — webbläsaren sköter
   öppet/stängt, tangentbordet och uppläsaren utan en rad skript. */
.innehallsruta {
  margin: 1.35rem 0 0;
  padding: .55rem .8rem;
  border: 1px solid var(--linje);
  border-radius: var(--radie);
  /* Kolumnbredderna bor här och inte i reglerna nedan, för rubrikraden och
     knapparna måste stå i samma lod och det är ett villkor som gäller hela
     rutan. Minus är bredare än ett minustecken behöver vara: bredden är
     rubrikens, och en 44 pixlar bred knapp är dessutom en tryckyta en tumme
     hittar. Plus rymmer "+30 kr" — det dyraste extrapriset seeden delar ut —
     med marginal, och tabular-nums nedan ser till att beloppen står i lod
     även när de är olika breda. */
  --utanbredd: 2.75rem;
  --extrabredd: 4.5rem;
  --knappglugg: .35rem;
}
.innehallsruta > summary {
  cursor: pointer;
  font-size: .6875rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--dampad);
}
.innehallsruta > summary::marker { color: var(--svag); }

/* Rubrikraden över knapparna, i samma språk som INNEHÅLL-rubriken själv. Den
   ersatte hjälpmeningen som stod här: en förklaring bredvid knappen slår en
   mening man läser en gång högst upp, och den kostar ingen extra höjd. Att
   "Utan" står omärkt med pris är själva beskedet — att avstå är alltid
   gratis, och att ta betalt för det hade lästs som en straffavgift. */
.innehallsrubrik,
.innehallsrad .innehallsknappar {
  display: flex;
  flex: none;
  gap: var(--knappglugg);
  /* Fast totalbredd, inte innehållets. Raden utan extrapris har inget plus,
     och en grupp som krympte till sitt innehåll hade låtit det ensamma minuset
     glida ut i plusets kolumn — precis vad tomatsåsen gjorde förr. Nu är
     platsen reserverad och varje minus står i lod. */
  width: calc(var(--utanbredd) + var(--extrabredd) + var(--knappglugg));
  margin-left: auto;
}
.innehallsrubrik {
  margin-top: .5rem;
  font-size: .6875rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--dampad);
}
.innehallsrubrik > span { text-align: center; }
.innehallsrubrik > span:first-child { width: var(--utanbredd); }
.innehallsrubrik > span:last-child { width: var(--extrabredd); }

.innehallsrad { align-items: center; }
.innehallsrad > span:first-child { min-width: 0; }
.innehallsrad .innehallsknappar button {
  width: var(--utanbredd);
  height: 30px;
  flex: none;
  padding: 0;
  border: 1px solid var(--linje);
  border-radius: 999px;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: .875rem;
  line-height: 1;
  cursor: pointer;
}
.innehallsrad .innehallsknappar button:hover {
  border-color: var(--dampad);
  background: var(--creme-djup);
}
/* Plusknappen bär sitt pris som etikett och är därför ett piller och ingen
   ruta. Fast bredd och tabular-nums: "+5 kr" och "+20 kr" ska inte flytta på
   kolumnen mellan två rader. */
.innehallsrad .innehallsknappar .extraknapp {
  width: var(--extrabredd);
  font-size: .8125rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* Den bortvalda råvaran stryks över: raden ska gå att läsa som rättens
   innehåll uppifrån och ner, och en överstruken rad säger vad som saknas
   snabbare än en knapp man måste titta två gånger på. */
.innehallsrad.bortvald > span:first-child {
  text-decoration: line-through;
  color: var(--svag);
}
.innehallsrad.dubblad > span:first-child { font-weight: 600; }
/* Det valda läget fylls, precis som pillret i vagnen. Ett tryckt läge som
   bara byter ram går inte att se på en telefon i solsken. */
.innehallsrad .innehallsknappar button[aria-pressed="true"] {
  border-color: var(--primar);
  background: var(--primar);
  color: var(--pa-mork);
}

/* Dryckesfrågan. Två knappar som väger lika tungt och en tredje som väger
   mindre — nej tack är ett riktigt svar och ska gå att ge, men den som redan
   bestämt sig för en läsk ska hitta läsken först. Ingenting är förvalt: se
   app/dryck.py.

   Rutan är ramad som innehållsavsnittet ovanför och står näst sist i arket.
   Den är en fråga och inte en lista, och en fråga tål att ta plats — men bara
   efter allt som handlar om rätten gästen faktiskt öppnade. */
.dryckfraga {
  margin: 1.35rem 0 0;
  padding: .8rem;
  border: 1px solid var(--linje);
  border-radius: var(--radie);
}
.dryckrubrik { margin: 0 0 .7rem; font-size: .9375rem; }
.dryckval { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
.dryckknapp {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .3rem;
  padding: .8rem .6rem;
  border: 1px solid var(--linje-stark);
  border-radius: var(--radie);
  /* Knapparna ligger på papperets djupare ton och inte på papperet självt:
     rutan runt dem har ingen egen bakgrund, och två knappar som delar färg
     med underlaget ser ut som text tills man råkar trycka på dem. */
  background: var(--creme-djup);
  color: var(--text);
  font: inherit;
  text-align: center;
  cursor: pointer;
  transition: border-color .2s, background-color .2s;
}
.dryckknapp img {
  width: 54px; height: 54px;
  object-fit: cover;
  border-radius: 50%;
}
.dryckknappnamn { font-size: .9375rem; }
.dryckpris { color: var(--dampad); font-size: .8125rem; font-variant-numeric: tabular-nums; }
.dryckknapp:hover { border-color: var(--dampad); }
/* Det valda läget fylls, precis som råvarornas knappar och pillret i foten.
   En ram som byter färg går inte att se på en telefon i solsken. */
.dryckknapp[aria-pressed="true"] {
  border-color: var(--primar);
  background: var(--primar);
  color: var(--pa-mork);
}
.dryckknapp[aria-pressed="true"] .dryckpris { color: var(--pa-mork); }
/* Nej tack: hela bredden, men i textvikt. Den är lika lätt att träffa som de
   andra två och lika lätt att låta bli att läsa. */
.drycknej {
  display: block;
  width: 100%;
  margin-top: .6rem;
  padding: .5rem;
  border: 0;
  background: transparent;
  color: var(--dampad);
  font: inherit;
  font-size: .8125rem;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.drycknej:hover { color: var(--text); }
.drycknej[aria-pressed="true"] {
  color: var(--text);
  text-decoration: none;
  font-weight: 600;
}

/* Beskedet när gruppens tak är nått. Rött och inte dämpat: det är ett svar på
   ett tryck som inte gick igenom, och det måste gå att koppla ihop med trycket.
   Färgerna är fasta i ``:root`` och inte pappersberoende, så de 6,1:1 provet
   mäter gäller alla fyra teman. Rutan står sist i gruppen — nära nog, och en
   ruta som flyttar sig till den kryssruta man råkade träffa är svårare att
   läsa än en som alltid står på samma ställe.

   Rött och rödbakgrunden stod länge bara i ``:root`` och var därför desamma på
   varje papper. Sotpapperet sätter om båda — en tegelröd text på nästan svart
   är inte läsbar — så siffran gäller per papper och mäts där. */
.takbesked {
  margin: .55rem 0 0;
  padding: .5rem .7rem;
  border: 1px solid var(--rod);
  background: var(--rod-bakgrund);
  color: var(--rod);
  font-size: .8125rem;
}

/* "På eller bredvid" under det val kunden kryssat i. Indraget knyter raden
   till såsen ovanför — utan det ser de två radioknapparna ut som ännu ett par
   tillval i gruppen. Skiljelinjen mellan krysser flyttas hit i stället:
   .kryss + .kryss träffar inte längre paret som fått ett block emellan. */
.placeringsval {
  display: flex;
  gap: 1.25rem;
  padding: 0 0 .55rem 1.9rem;
}
/* Dämpad men läsbar: ``--svag`` ger 4,0:1 mot arkets botten, och en fråga
   kunden ska svara på får inte vara den enda texten i dialogen som inte klarar
   kontrastkravet. */
.placeringsval .kryss { padding: 0; font-size: .875rem; color: var(--dampad); }
.placeringsval .kryss + .kryss { border-top: 0; }
.placeringsval + .kryss { border-top: 1px solid var(--linje); }

/* Block och inte flexkolumn: etiketten innehåller ett inline-"(valfritt)" som
   ska stå kvar på rubrikraden, inte bli ett eget flexbarn på egen rad. */
.noteringsfalt {
  display: block;
  margin-top: 1.35rem;
  font-size: .6875rem; letter-spacing: .16em; text-transform: uppercase; color: var(--dampad);
}
.noteringsfalt input { margin-top: .4rem; }

/* Halv & halv: hopfälld som innehållsrutan, så arket är kort för den som vill
   ha en hel pizza. Öppnad ger den en höjdbegränsad lista med egen scroll —
   aldrig hela menyn utfälld så att arket drar iväg flera skärmar. Varje rad
   bär rättens namn och, indraget under, dess innehåll som minnesstöd. */
.halvval {
  margin-top: 1.35rem;
  padding: .55rem .8rem;
  border: 1px solid var(--linje);
  border-radius: var(--radie);
}
.halvval > summary {
  cursor: pointer;
  font-size: .6875rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--dampad);
}
.halvval > summary::marker { color: var(--svag); }
.halvrubrik {
  margin: .7rem 0 .4rem;
  font-size: .6875rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--dampad);
}
.halvlista {
  max-height: 14rem;
  overflow-y: auto;
  border: 1px solid var(--linje);
  border-radius: var(--radie);
}
.halvrad {
  display: flex; align-items: flex-start; gap: .6rem;
  padding: .55rem .7rem;
  cursor: pointer;
}
.halvrad + .halvrad { border-top: 1px solid var(--linje); }
.halvrad input { margin-top: .15rem; flex: none; }
.halvtext { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.halvnamn { font-weight: 600; }
.halvingred { font-size: .8125rem; color: var(--dampad); }
.halvrad:hover { background: var(--creme); }
.halvrad:has(input:checked) { box-shadow: inset 0 0 0 2px var(--primar); }

.arkfot {
  display: flex;
  gap: .75rem;
  align-items: center;
  padding: .9rem 1.35rem;
  border-top: 1px solid var(--linje);
  background: var(--creme);
}
.antalsvaljare { display: flex; align-items: center; gap: .35rem; }
.antalsvaljare button {
  width: 30px; height: 30px;
  border: 1px solid var(--linje-stark);
  border-radius: 50%;
  background: transparent;
  font-size: 1rem; line-height: 1; cursor: pointer;
  transition: border-color .2s, background-color .2s;
}
.antalsvaljare button:hover { border-color: var(--dampad); background: var(--creme-djup); }
.antalsvaljare output { min-width: 1.75rem; text-align: center; font-variant-numeric: tabular-nums; }

/* Pillret. Den enda fyllda knappen i hela kundvyn, tillsammans med
   kassaraden — därför läser man den som *handlingen*. */
.pill {
  flex: 1;
  padding: .8rem 1.2rem;
  border: 0;
  border-radius: 30px;
  background: var(--primar);
  /* Inte hårdkodat vitt: på ett mörkt papper är --primar en ljus yta, och
     --pa-mork är den token som betyder texten på den. Samma par som
     kassaraden bär, och det paret är mätt i tests.test_palett. */
  color: var(--pa-mork);
  font: inherit;
  font-size: .9375rem;
  cursor: pointer;
  transition: filter .2s, transform .18s var(--mjuk);
}
.pill:hover { filter: brightness(1.08); }
.pill:active { transform: scale(.985); }
.pill[disabled] { opacity: .4; pointer-events: none; }

/* ------------------------------------------------------ sticky kassarad */

/* Alltid synlig så länge vagnen inte är tom. Vänster halva öppnar vagnen,
   höger går till kassan — och summan står alltid framme, eftersom ett dolt
   pris fram till sista steget är det som får folk att hoppa av. */
.kassarad {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 40;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 12px 20px;
  /* Bandet går kant till kant, men texten ställer sig på samma lodräta linje
     som menyn ovanför — annars står summan ute i marginalen på skrivbord. */
  padding-inline: max(20px, calc((100% - var(--spalt)) / 2 + var(--sidmarginal)));
  padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  background: var(--primar);
  color: var(--pa-mork);
  animation: radupp .3s var(--mjuk);
}
@keyframes radupp {
  from { transform: translateY(100%); }
  to   { transform: none; }
}
.kassarad[hidden] { display: none; }
.kassaoversikt {
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: .9375rem;
  padding: 0;
  cursor: pointer;
  text-align: left;
}
.kassaoversikt:hover { text-decoration: underline; }
.kassalank {
  font-size: .9375rem;
  text-decoration: none;
  white-space: nowrap;
  /* Ligger på kassaradens mörka yta: papperets ton i rollen text-på-mörkt,
     halvt uttonad så att den blir en antydan till understrykning som tar
     färg vid hover. Se --pa-mork i :root. */
  border-bottom: 1px solid color-mix(in srgb, var(--pa-mork) 50%, transparent);
  padding-bottom: 2px;
  transition: border-color .2s;
}
.kassalank:hover { border-color: var(--pa-mork); }
.kassarad .avstangd { opacity: .5; pointer-events: none; }

@keyframes radpuls {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.06); }
  100% { transform: scale(1); }
}
.kassaoversikt.pulsar { animation: radpuls .45s var(--studs); }

/* ---------------------------------------------------------------- vagnen */

.vagn {
  position: fixed;
  right: 0; bottom: 0;
  z-index: 45;
  width: min(26rem, 100vw);
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  background: var(--creme);
  border-radius: var(--radie-ark) var(--radie-ark) 0 0;
  box-shadow: 0 -8px 40px -12px rgba(37, 37, 37, .35);
  animation: arkupp .3s var(--mjuk);
}
.vagn[hidden] { display: none; }
.vagn header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.1rem 1.35rem .6rem;
}
.vagn header h2 { font-size: 1.25rem; }
.vagn header button {
  width: 2rem; height: 2rem; border: 1px solid var(--linje-stark); border-radius: 50%;
  background: transparent; font-size: 1.05rem; cursor: pointer;
  transition: background-color .2s, border-color .2s;
}
.vagn header button:hover { background: var(--creme-djup); border-color: var(--dampad); }
.vagn footer { padding: .9rem 1.35rem 1.35rem; border-top: 1px solid var(--linje); }

.skugga {
  position: fixed; inset: 0; z-index: 42;
  background: rgba(34, 58, 48, .42);
  animation: tona .25s ease;
}
@keyframes tona { from { opacity: 0; } to { opacity: 1; } }
.skugga[hidden] { display: none; }

.vagnrader { list-style: none; margin: 0; padding: 0 1.35rem; overflow-y: auto; }
.vagnrad, .orderrader li {
  display: flex;
  align-items: baseline;
  gap: .75rem;
  padding: .7rem 0;
  border-bottom: 1px solid var(--linje);
}
.vagnrad:last-child, .orderrader li:last-child { border-bottom: 0; }

/* Den nyss tillagda raden. Kvitteringen på trycket. */
@keyframes radin {
  0%   { transform: translateY(8px); opacity: 0; }
  100% { transform: none; opacity: 1; }
}
.vagnrad.ny { animation: radin .35s var(--mjuk); }
.antal { color: var(--accent); flex: none; font-variant-numeric: tabular-nums; }
.radnamn { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .1rem; font-family: var(--rubrikfont); }
.radnamn .dampad { font-family: var(--brodfont); }
.radpris { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Radens knappar under namnet och inte i en egen kolumn. En stepper till
   vänster hade tagit tredjedelen av bredden i en vagn på en telefon, och det
   som ska stå längst fram på raden är vad kunden beställt — inte reglagen för
   att ändra det.

   Antalet står bara här. Ett "2×" framför namnet *och* en tvåa i steppern är
   samma siffra på två ställen, och den dagen de säger olika saker är det ingen
   som vet vilken som gäller. */
.radverktyg {
  display: flex;
  align-items: center;
  gap: .85rem;
  margin-top: .4rem;
  font-family: var(--brodfont);
}
.antalsvaljare.liten button { width: 26px; height: 26px; font-size: .875rem; }
.antalsvaljare.liten output { min-width: 1.3rem; font-size: .875rem; }
/* Utskriven och inte ett kryss i kanten. Ett × betyder "stäng" lika ofta som
   "ta bort", och på en rad man just tryckt minus på ska det inte råda något
   tvivel om vilken av dem knappen gör. */
.taBort {
  flex: none;
  padding: 0;
  border: 0; background: transparent;
  color: var(--svag);
  font: inherit; font-size: .8125rem;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
  transition: color .2s;
}
.taBort:hover { color: var(--rod); }

.tomvagn { padding: 1.75rem 1.35rem; text-align: center; color: var(--dampad); }
.summarad {
  display: flex; justify-content: space-between; margin-bottom: .9rem;
  font-family: var(--rubrikfont); font-size: 1.1rem;
}

/* --------------------------------------------------------------- knappar */

/* Utanför menyn finns riktiga knappar — kassan är ett formulär, inte en
   meny. De håller sig ändå till linjer och pillerform. */
.knapp {
  display: inline-block;
  padding: .8rem 1.3rem;
  border: 1px solid var(--linje-stark);
  border-radius: 30px;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: .9375rem;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .2s, border-color .2s, filter .2s, transform .18s var(--mjuk);
}
.knapp:hover { border-color: var(--dampad); }
.knapp:active { transform: scale(.985); }
.knapp.primar { background: var(--primar); border-color: var(--primar); color: var(--pa-mork); }
.knapp.primar:hover { filter: brightness(1.08); }
.knapp.bred { display: block; width: 100%; }
.knapp.fara { color: var(--rod); border-color: color-mix(in srgb, var(--rod) 30%, transparent); }
.knapp.fara:hover { background: var(--rod-bakgrund); border-color: var(--rod); }
.knapp[disabled], .knapp.avstangd { opacity: .4; pointer-events: none; }

/* Ett nej ska vara lika lätt att hitta som ett ja, men inte lika högljutt. */
.knapp.tyst { border-color: transparent; color: var(--dampad); }
.knapp.tyst:hover { background: var(--creme-djup); border-color: transparent; }

/* Att tömma vagnen. Mindre och tystare än knappen ovanför den — den som ska
   vidare ska aldrig kunna råka trycka bort hela sin beställning i stället. */
.tommaknapp { margin-top: .65rem; padding: .55rem 1.1rem; font-size: .8125rem; }
/* Egen regel därför att ``.knapp.bred`` sätter display: block, vilket slår
   webbläsarens egen [hidden]-regel — utan den här stod knappen kvar och
   erbjöd sig att tömma en vagn som redan var tom. */
.tommaknapp[hidden] { display: none; }

/* -------------------------------------------------------- bekräftelserutan */

/* Frågan innan något inte går att ångra. Liten, mitt på skärmen och med två
   svar — inget tredje sätt att stänga den som betyder något annat. */
.bekraftruta {
  width: min(22rem, calc(100vw - 2rem));
  padding: 1.5rem;
  border: 0;
  border-radius: var(--radie);
  background: var(--creme);
  color: var(--text);
  box-shadow: 0 20px 50px -20px rgba(37, 37, 37, .45);
}
.bekraftruta:not([open]) { display: none; }
.bekraftruta::backdrop { background: rgba(34, 58, 48, .45); }
.bekraftruta h2 { margin: 0 0 .5rem; font-size: 1.15rem; }
.bekraftruta p { margin: 0 0 1.25rem; font-size: .9375rem; color: var(--dampad); }
.bekraftknappar { display: flex; gap: .6rem; justify-content: flex-end; }
.bekraftknappar .knapp { padding: .65rem 1.1rem; font-size: .875rem; }

/* ---------------------------------------------------------------- kassan */

.kassa, .orderstatus, .textsida { padding-block: clamp(1.5rem, 4vw, 2.5rem) 5rem; }
.tillbaka {
  display: inline-block; margin-bottom: 1.25rem;
  font-size: .8125rem; text-decoration: none; color: var(--dampad);
  transition: color .2s;
}
.tillbaka:hover { color: var(--accent); }
.kassa h1, .orderstatus h1 { margin-bottom: 1.5rem; }

/* Panelerna är sektioner avdelade med en linje, inte kort. */
.panel {
  margin: 0;
  padding: 1.5rem 0;
  border-top: 1px solid var(--linje);
}
.panel:first-of-type { border-top: 0; padding-top: 0; }
.panel h2 {
  margin-bottom: 1rem;
  font-family: var(--brodfont);
  font-size: .6875rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
}
.panel .vagnrader { padding: 0; }

.fel {
  padding: .85rem 1.1rem;
  border: 1px solid var(--rod);
  background: var(--rod-bakgrund);
  color: var(--rod);
  font-size: .875rem;
}
.fel[hidden] { display: none; }
/* Samma ruta i en mildare ton, för det som inte är kundens fel och redan är
   åtgärdat: en rad som försvunnit ur menyn och därför plockats ur vagnen. Rött
   hade sagt "du gjorde fel" om något kunden inte kan göra något åt, och sanden
   är samma ton som stängtnotisen på menyn — ett besked, inte ett stopp. */
.fel.mjuk { border-color: var(--sand-text); background: var(--sand); color: var(--sand-text); }

.kassaformular label {
  display: flex;
  flex-direction: column;
  gap: .4rem;
  margin-bottom: 1rem;
  font-size: .6875rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--dampad);
}
.kassaformular label:last-child { margin-bottom: 0; }
.kassaformular .kryss {
  flex-direction: row; align-items: flex-start; flex-wrap: wrap;
  font-size: .9375rem; letter-spacing: 0; text-transform: none; color: var(--text);
}
.kassaformular .kryss .hjalptext { flex-basis: 100%; margin-left: 1.6rem; }

input[type="text"], input[type="tel"], input[type="email"],
input[type="time"], input[type="date"], input[type="number"], select, textarea {
  width: 100%;
  padding: .7rem .85rem;
  border: 1px solid var(--linje-stark);
  border-radius: var(--radie-s);
  background: transparent;
  font: inherit;
  font-size: 1rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
  transition: border-color .2s;
}
input:hover, select:hover, textarea:hover { border-color: var(--dampad); }
input:focus-visible, select:focus-visible, textarea:focus-visible, button:focus-visible, a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.faltpar { display: grid; grid-template-columns: 1fr 1fr; gap: .75rem; }

/* Valen står bredvid varandra och ska väga exakt lika. Kolumnerna kommer från
   grid-auto-columns och inte från ett fast 1fr 1fr: står bara det ena valet
   kvar — hämtning avstängd, eller utkörning som inte når adressen — blir det
   en enda kolumn i full bredd i stället för en halvbred ruta med tomrum
   bredvid. minmax(0, 1fr) och inte 1fr, annars kan ett långt ord i den ena
   rutan göra den bredare än den andra. */
.valrad {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: .7rem;
}
.valknapp {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: .2rem;
  padding: .9rem;
  border: 1px solid var(--linje-stark);
  cursor: pointer;
  font-family: var(--rubrikfont);
  font-size: 1rem;
  transition: border-color .2s, background-color .2s;
}
/* Nollar marginalen från .kassaformular label, som lägger en rem under varje
   fält. Det är rätt för fält som staplas under varandra, men de här två står i
   en egen rad: marginalen hamnade bara under den första — :last-child tar bort
   den för den andra — och gjorde den 16 px lägre än sin granne. Skriven med
   .valrad framför just för att väga tyngre än .kassaformular label. */
.valrad .valknapp { margin: 0; }
.valknapp:hover { border-color: var(--dampad); }
.valknapp span {
  font-family: var(--brodfont); font-size: .8125rem; color: var(--svag);
  /* Raden tar plats även när den är tom. Utan minimihöjden hoppar rubriken i
     den ruta som saknar undertext uppåt, och de två slutar stå i linje så
     snart restaurangen inte har någon minsta ordersumma. */
  min-height: 1lh;
}
.valknapp input { position: absolute; opacity: 0; pointer-events: none; }
.valknapp:has(input:checked) { border-color: var(--primar); box-shadow: inset 0 0 0 1px var(--primar); }
/* Utkörning som inte går till kundens adress. Knappen står kvar men blir matt
   och slutar svara på musen — att ta bort den helt hade sett ut som att
   restaurangen inte kör ut alls, och skälet står ändå i rutan under. */
.valknapp.avstangd {
  opacity: .45;
  cursor: not-allowed;
  border-style: dashed;
}
.valknapp.avstangd:hover { border-color: var(--linje-stark); }

/* Tidväljaren. Står under de två valrutorna och fälls ut först när "vid en viss
   tid" är valt — en <select> som alltid syns läses som något man måste fylla i,
   och de allra flesta ska kunna gå förbi hela rutan. */
.tidfalt { display: block; margin-top: .9rem; }
.tidfalt select { width: 100%; margin-top: .4rem; }
.tidfalt .hjalptext { display: block; margin-top: .4rem; }

/* Beskedet om utkörningsområdet. Terrakotta och en linje i kanten: det är ett
   svar på något kunden just skrev, inte en fotnot. */
.leveransbesked[data-leveransbesked] {
  margin-top: .8rem;
  padding: .6rem .8rem;
  border-left: 2px solid var(--accent);
  background: var(--creme-djup);
  color: var(--text);
}

.summering { margin: 1.25rem 0 0; padding-top: 1rem; border-top: 1px solid var(--linje); }
.summering div { display: flex; justify-content: space-between; padding: .25rem 0; }
/* Måste stå efter regeln ovan: den sätter display på samma element som JS
   döljer med hidden-attributet, och en klassregel vinner över webbläsarens
   egen [hidden] { display: none }. */
.summering div[hidden] { display: none; }
.summering dt, .summering dd { margin: 0; }
.summering dd { font-variant-numeric: tabular-nums; }
.summering .rabattrad { color: var(--accent); }
.summering .totalrad {
  margin-top: .6rem; padding-top: .7rem;
  border-top: 1px solid var(--linje-stark);
  font-family: var(--rubrikfont);
  font-size: 1.2rem;
}
/* Behållaren för kassans momsrader. Måste bryta arvet från ``.summering div``,
   som gör varje div till en flexrad — annars hade raderna inuti lagts bredvid
   varandra i stället för under. Kvittot behöver ingen behållare: där renderas
   raderna direkt i listan av servern. */
.summering .momsrader { display: block; padding: 0; }

/* Momsen redovisas under totalen, dämpad. Den är en upplysning om vad som
   redan ingår i beloppet ovanför och inte ett belopp att lägga ihop med det —
   samma vikt som totalen hade fått den att läsas som en post till. */
.summering .momsrad {
  padding: .1rem 0;
  color: var(--dampad);
  font-size: .8125rem;
}
/* Luft mellan totalen och specifikationen. Väljs på grannskapet i stället för
   :first-of-type, som hade matchat sidans första summeringsrad — alla rader är
   div:ar, och "första av sin typ" ser inte klassen. */
.summering .totalrad + .momsrad,
.summering .totalrad + .momsrader .momsrad:first-child { margin-top: .5rem; }
.summering .momssumma { font-weight: 600; }
.summering[hidden] { display: none; }
/* Medan servern räknar om. Beloppen står kvar och går att läsa — de gällde
   vagnen som den såg ut för en sekund sedan — men tonen säger att de är på väg
   att bytas. En snurra i stället hade tagit bort siffrorna helt för ett svar
   som oftast är framme innan ögat hunnit dit. */
.summering.raknar { opacity: .5; }
.summering { transition: opacity .15s ease; }

/* ----------------------------------------------------------- stämpelkort */

/* Kortet ska kännas som ett kort, inte som en siffra. Stämplarna faller in
   en och en när uppslaget kommer tillbaka — det är den lilla belöningen som
   gör att någon bryr sig om att fylla det. */
.stampelkort {
  margin: 0 0 1rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--linje-stark);
  color: var(--text);
  font-size: .875rem;
}
.stampelkort[hidden] { display: none; }
.stampelkort p { margin: 0; }
.kortpost + .kortpost { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--linje); }
.kortrad { display: flex; justify-content: space-between; gap: .75rem; align-items: baseline; }
.kortrad strong { font-family: var(--rubrikfont); font-size: 1rem; font-weight: 400; }
.kortkvar { font-size: .8125rem; color: var(--svag); white-space: nowrap; }

.stamplar { display: flex; flex-wrap: wrap; gap: .38rem; margin-top: .7rem; }
.stampel {
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
  border: 1px solid var(--dampad);
  background: transparent;
  transform: scale(.72);
  opacity: .45;
  transition: transform .38s var(--studs), opacity .38s var(--mjuk),
              background-color .38s var(--mjuk), border-color .38s var(--mjuk);
}
.stampel.fylld {
  background: var(--accent);
  border-color: var(--accent);
  transform: scale(1);
  opacity: 1;
}

/* Kvittensen på orderbekräftelsen: två sorters fyllda stämplar. De kunden hade
   sedan tidigare i husets primärfärg, och de den här beställningen gav i
   accentfärgen med en ring runt. Färgen ensam hade inte räckt — en av tolv män
   ser skillnaden på oliv och terrakotta sämre än vi tror, och då är det ringen
   som bär informationen. Samma sak i text på aria-label i mallen. */
.stamplar.kvittens .stampel.fylld {
  background: var(--primar);
  border-color: var(--primar);
}
.stamplar.kvittens .stampel.fylld.ny {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--papper), 0 0 0 3px var(--accent);
}

.nyastamplar {
  margin: .55rem 0 0;
  color: var(--accent);
  font-size: .8125rem;
  font-weight: 500;
}

.kortfullt {
  margin-top: .7rem;
  padding: .5rem .8rem;
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: .875rem;
}

/* Inlösningsrutan i kassan. Terrakottakant och creme botten, samma språk som
   ``.kortfullt`` — det är samma nyhet, ett steg längre fram: där stod att
   kortet var fullt, här går det att göra något åt det. Rutan är avsiktligt
   det mest framträdande i formuläret utan att vara en knapp; kunden ska se
   den, men ingenting händer förrän hon kryssar själv. */
.inlosenruta {
  margin: 0 0 1rem;
  padding: .9rem 1.1rem;
  border: 1px solid var(--accent);
  background: var(--creme);
}
.inlosenruta[hidden] { display: none; }
.inlosenpost + .inlosenpost { margin-top: .9rem; padding-top: .9rem; border-top: 1px solid var(--linje); }

/* Bannern för en stamkundsförmån som ännu inte tagits ut. Släktskapet med
   ``.inlosenruta`` är avsiktligt — båda säger "du får något av oss" — men tonen
   ligger ett snäpp lägre: inlösen kräver ett kryss av kunden, det här är en
   upplysning hon får låta bli. Därför tonad botten och en dämpad kant i stället
   för inlösenrutans hela accentkant.

   Försvinner helt så snart något kvalificerande ligger i vagnen. Avdraget står
   då i summeringen, och två sätt att säga samma sak hade fått kunden att undra
   om hon fått rabatten en eller två gånger. */
.formansbanner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .55rem .9rem;
  margin: 0 0 1rem;
  padding: .85rem 1.05rem;
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  border-radius: var(--radie);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}
.formansbanner[hidden] { display: none; }
/* Egen marginalnollställning: stycket bär webbläsarens egna marginaler, och i
   en flexrad faller de inte ihop utan skjuter ut kanterna. Samma sak som
   ``.kampanjbanner > *`` löser på kundsidans framrad. */
.formanstext {
  flex: 1 1 12rem;
  margin: 0;
  font-size: .9375rem;
  color: var(--text);
}
/* Emojin ärver radhöjden och skulle annars klistra sig mot första ordet. */
.formansikon { margin-right: .45rem; }
/* Knappen är liten med flit. Den ska gå att trycka på utan att konkurrera med
   "Till betalning" längst ned — förmånen är en trevlighet, inte nästa steg. */
.formansknapp { flex: none; padding: .5rem 1rem; font-size: .875rem; }
/* Länken när kunden ska välja själv. Ingen knapp: den leder till en annan sida
   och lägger ingenting i vagnen, och det ska synas på formen. */
.formanslank {
  flex: none;
  font-size: .875rem;
  color: var(--accent);
  text-decoration: none;
  white-space: nowrap;
}
.formanslank:hover { text-decoration: underline; }

/* Etikettreglerna i kassaformuläret är versala och spärrade — rätt för
   "MOBILNUMMER", fel för en mening. Samma undantag som ``.kassaformular .kryss``
   gör för samtyckesrutan. */
/* Två klasser med flit: ``.kassaformular label`` väger tyngre än en ensam
   klass, och rubriken hade fortsatt komma ut som "DU HAR EN PIZZA PÅ HUSET". */
.inlosenruta .inlosenkryss {
  display: flex; flex-direction: row; align-items: flex-start;
  gap: .65rem; margin-bottom: 0;
  font-size: .9375rem; letter-spacing: 0; text-transform: none;
  color: var(--text);
}
.inlosenkryss input {
  margin: .2rem 0 0;
  flex: none;
  width: 1.1rem; height: 1.1rem;
  accent-color: var(--accent);
}
.inlosenkryss strong {
  display: block;
  font-family: var(--rubrikfont);
  font-size: 1.0625rem; font-weight: 400;
  color: var(--accent);
}
.inlosenkryss .hjalptext { margin-top: .15rem; }

.inlosenval {
  display: block;
  margin: .75rem 0 0;
  font-size: .6875rem; letter-spacing: .16em; text-transform: uppercase; color: var(--dampad);
}
.inlosenval select { margin-top: .4rem; }

.inlosenfel { margin: 0 0 .7rem; font-size: .875rem; color: var(--accent); }

/* Kodrutan under ett ikryssat kort. Inte en ruta i rutan: en tunn linje räcker
   för att skilja steget från valet ovanför, och inlösenrutan har redan sin
   accentkant. Siffrorna står i tabellsiffror och med luft emellan, så att sex
   siffror ur ett mejl går att jämföra med ögat. */
.kodruta {
  display: grid;
  gap: .6rem;
  margin-top: .85rem;
  padding-top: .85rem;
  border-top: 1px solid var(--linje);
}
.kodruta[hidden] { display: none; }
.kodruta > p { margin: 0; }
.kodruta .inlosenfel { margin: 0; }
.kodbesked { font-size: .875rem; color: var(--text); }
.kodrad { display: flex; flex-wrap: wrap; align-items: flex-end; gap: .5rem; }
.inlosenruta .kodfalt {
  display: grid;
  gap: .35rem;
  flex: 1 1 9rem;
  margin: 0;
  font-size: .6875rem; letter-spacing: .16em; text-transform: uppercase; color: var(--dampad);
}
.kodfalt input {
  font-size: 1.25rem;
  letter-spacing: .3em;
  font-variant-numeric: tabular-nums;
}
.kodknapp { justify-self: start; padding: .6rem 1.1rem; font-size: .875rem; }
/* Länkformen med flit: en ny kod är undantaget, och den ska inte stå bredvid
   Bekräfta och se lika viktig ut. */
.kodny {
  justify-self: start;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: .875rem;
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
}
.kodny[disabled] { opacity: .5; cursor: default; }
.kodklar { margin: .75rem 0 0; font-size: .875rem; color: var(--text); }
.kodklar::before { content: "✓ "; color: var(--accent); font-weight: 600; }

/* Vid e-postfältet när restaurangen har ett lojalitetsprogram. Kravet står i
   fetstil först i hjälptexten — det är det kunden behöver veta innan hon
   bestämmer sig för att hoppa över fältet. */
.epostkrav { display: block; font-weight: 600; color: var(--text); }

/* ------------------------------------------------------------- betalning */

.betalmetoder { display: flex; gap: .5rem; margin: 0 0 .75rem; flex-wrap: wrap; }
.metod {
  padding: .3rem .75rem;
  border: 1px solid var(--linje-stark);
  font-size: .8125rem;
}
.metod-swish { border-color: #6a4bb0; color: #4b2a86; }

.integritetstext { font-size: .8125rem; line-height: 1.6; color: var(--dampad); margin: 1.25rem 0; }

/* ---------------------------------------------------------- orderstatus */

.statuskort {
  padding: 2.25rem 0;
  text-align: center;
  border-block: 1px solid var(--linje-stark);
}
.ordernummer { font-size: .6875rem; letter-spacing: .18em; text-transform: uppercase; color: var(--accent); }
.statuskort h1 { margin: .6rem 0 .4rem; }
.statuskort .vantetid { color: var(--dampad); font-size: .875rem; }
/* Den valda tiden är sidans viktigaste uppgift för den som bokat: accentfärg
   och samma storlek som statustexten, inte en dämpad småtext bland de andra. */
.hamtningstid { margin: .4rem 0 0; color: var(--accent); font-size: 1.0625rem; }
.betalstatus { margin: 1.25rem 0 0; }

.bricka {
  display: inline-block;
  padding: .3rem .8rem;
  border: 1px solid var(--linje-stark);
  font-size: .8125rem;
}
.bricka.gron { border-color: var(--gron); color: var(--gron); }
.bricka.rod { border-color: var(--rod); color: var(--rod); }

.orderrader { list-style: none; margin: 0; padding: 0; }
.spara-lank { margin-top: 1.75rem; text-align: center; font-size: .8125rem; color: var(--dampad); }

/* ------------------------------------------------------------- textsida */

.textsida h2 { margin: 2rem 0 .5rem; }
.textsida p { margin: 0; }
/* Integritetstexten varvar rubrik och stycke, och där är noll rätt. Om oss är
   brödtext i flera stycken efter varandra och behöver luft emellan — annars
   sitter meningarna ihop till ett block ingen orkar läsa. */
.textsida p + p { margin-top: .85rem; }
/* Adressen är en adress och inte en kursiv notis. Webbläsarens förval för
   <address> är italic, vilket i Georgia läser som en avvikelse i texten. */
.textsida address { font-style: normal; margin-top: .25rem; }
/* Länken vidare, sist på sidan: till menyn från Hitta hit, till Hitta hit
   från Om oss. Luft ovanför så den inte läses som en del av sista stycket. */
.sidlank { margin-top: 2rem; }

/* ------------------------------------------------- offline och hemskärm */

/* Sitter överst på sidan och trycker ned innehållet i stället för att lägga
   sig över det — ett meddelande som täcker en knapp är värre än inget. */
.natbanner {
  margin: 0;
  padding: .7rem 1rem;
  background: var(--sand);
  color: var(--sand-text);
  font-size: .8125rem;
  text-align: center;
}
.natbanner[hidden] { display: none; }

.hemskarm {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  /* Samma sidmarginal som resten av sidan har via sin container. */
  max-width: min(var(--innerspalt), 100% - 2rem);
  margin: 1.75rem auto;
  padding: 1.25rem;
  border: 1px solid var(--linje-stark);
}
/* min-width tvingar knapparna ned på egen rad på en telefon i stället för att
   klämma texten till tre ord per rad. */
.hemskarmtext { display: flex; flex-direction: column; gap: .15rem; flex: 1; min-width: 15rem; font-family: var(--rubrikfont); }
.hemskarmtext span { font-family: var(--brodfont); font-size: .8125rem; color: var(--dampad); }
.hemskarmknappar { display: flex; gap: .5rem; align-items: center; }
.hemskarmknappar .knapp { padding: .6rem 1rem; font-size: .875rem; }

.offlinesida { padding-block: 4rem 5rem; text-align: center; }
.offlinesida h1 { margin-bottom: .75rem; }
.offlinesida .ledtext { color: var(--dampad); font-size: .9375rem; }
.offlinesida .notis { text-align: left; margin: 1.75rem 0; }
.offlinesida .knapp { min-width: 12rem; }

/* ------------------------------------------------------------------- fot */

.fot {
  padding-block: 2.5rem 3.5rem;
  font-size: .8125rem;
  color: var(--dampad);
  border-top: 1px solid var(--linje);
}
.fot p { margin: .25rem 0; }
.fot .fotnamn { font-family: var(--rubrikfont); font-size: 1.0625rem; color: var(--text); }
.fot a { transition: color .2s; }
.fot a:hover { color: var(--accent); }
/* Restaurangens egen rad är det enda i foten som är skrivet till gästen och
   får därför textens färg — resten är uppgifter man letar efter, inte läser. */
.fot .fotinfo { color: var(--text); }
/* Firman och organisationsnumret ett snäpp mindre: de ska gå att hitta, inte
   att märka. Samma grad som raden om oss, men utan luften ovanför. */
.fot .fotforetag { font-size: .75rem; }
/* Skiljetecknet mellan telefon och e-post. Egen klass och inte ett tecken i
   texten: den som lyssnar på sidan ska höra två uppgifter, inte en prick. */
.fot .prick { margin-inline: .35rem; }

/* Restaurangens kanaler. "Diskreta" är gjort med färg och storlek och inte med
   genomskinlighet: ikonerna ärver fotens --dampad, som är mätt mot papperet på
   samma 4.5:1 som texten runt omkring, och en opacity hade tagit dem under den
   gränsen utan att någon sett det i en mätning.
   Märkena ritas i currentColor (app/sociala.py), så hela färgbytet sker här. */
.fot .fotsocialt {
  display: flex;
  flex-wrap: wrap;
  gap: .15rem;
  margin-top: .7rem !important;
  margin-inline: -.55rem;
}
.socialikon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Ikonen är 20 px, träffytan 44. Skillnaden är vaddering och inte storlek:
     en tumme på en telefon träffar inte tjugo pixlar, och fyra länkar tätt
     intill varandra är just där en felträff kostar mest. */
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  color: var(--dampad);
  transition: color .2s, background-color .2s;
}
.socialikon svg { width: 1.25rem; height: 1.25rem; }
.socialikon:hover, .socialikon:focus-visible { color: var(--accent); background: var(--linje); }

/* Samma märken på "Om oss" och "Hitta hit", men med namnet utskrivet: sidorna
   har plats, och en ensam ikon mitt i en textsida är en gåta. */
.socialrubrik { margin-top: 2rem; }
.socialrad { display: flex; flex-wrap: wrap; gap: .5rem 1.5rem; }
.sociallank {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  min-height: 2.75rem;
  color: var(--text);
  transition: color .2s;
}
.sociallank svg { width: 1.25rem; height: 1.25rem; flex: none; color: var(--dampad); transition: color .2s; }
.sociallank:hover, .sociallank:focus-visible { color: var(--accent); }
.sociallank:hover svg, .sociallank:focus-visible svg { color: var(--accent); }
/* Raden om oss ligger ett snäpp under resten av foten: mindre grad, luft
   ovanför, och understruken länk så att den går att träffa utan att den
   behöver en färg som drar blicken. */
.drivsav {
  margin-top: 1rem !important;
  font-size: .75rem;
}
.drivsav a { text-decoration: underline; }
/* Bandet under spalterna. På telefonen är det bara två stycken i rad — där
   finns ingen bredd att skilja dem åt med, och ett hårstreck till hade delat
   en fot som redan är kort. Luft i stället, så att det finstilta inte klistrar
   sig i sista länken. Se @media 900px för raden. */
.fot .fotband { margin-top: 1rem; }

/* ---------------------------------------------------------- stor skärm */

/* Spaltsättningen. Två spalter per kategorisektion — inte över menyn i klump:
   en kategori med tre efterrätter ska inte tvingas fylla två spalter och se
   trasig ut. Läsordningen går uppifrån och ned i vänsterspalten och fortsätter
   i högerspalten, precis som i en tryckt meny. */
@media (min-width: 900px) {
  .kategori {
    column-count: 2;
    column-gap: 3.5rem;
  }
  /* Rubriken och ingressen hör till hela sektionen, inte till vänsterspalten. */
  .kategori > h2,
  .kategori > .kategoritext { column-span: all; }
  .kategori > h2 { margin-bottom: 1rem; }
  /* Ingen rad får klippas mitt itu vid spaltbrytet. */
  .ratt { break-inside: avoid-column; }
  /* Sista raden i listan har ingen linje under sig på mobil. I två spalter
     hamnar den mitt på sidan och behöver den. */
  .rattlista li:last-child .menyrad { border-bottom: 1px solid var(--linje); }

  .rattark { border-radius: var(--radie-ark); }
  .rattark[open] { margin: auto; }
  .vagn { bottom: 4.5rem; right: 1.5rem; border-radius: var(--radie-ark); }

  /* Kategoriraden ryms inte alltid på en rad: en meny med många kategorier
     (Royal India har 14) är bredare än spalten. På mobilen scrollar raden i
     sidled med fingret, men på desktop finns ingen sådan gest och ingen synlig
     scrollbar — overflow-x klipper då en kategori mitt itu och gömmer resten
     utan att något avslöjar det. På stor skärm låter vi raden radbryta i
     stället: alla kategorier syns, inget klipps. */
  .kategorirad {
    flex-wrap: wrap;
    overflow-x: visible;
    row-gap: .5rem;
  }
  /* Den radbrutna raden kan bli två–tre rader hög; ankarhoppen måste klara
     hela den stickytornet (toppbar + kategorimeny) så en rubrik inte landar
     bakom menyn. */
  .kategori { scroll-margin-top: 9.5rem; }

  /* Favoriten och kampanjen sida vid sida, i menyns ränna. Samma regel som
     .underrad längre ner, av samma skäl — och med samma undantag: den som är
     ensam tar hela bredden i stället för att lämna ett hål bredvid sig. */
  .framrad {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 3.5rem;
    /* Sträckta och inte toppställda: de två korten är olika höga av innehåll,
       men bär var sin ram, och två ramar som slutar på olika höjd bredvid
       varandra ser ut som ett fel i sidan snarare än som olika mycket text. */
    align-items: stretch;
  }
  .framrad > :only-child { grid-column: 1 / -1; }
  /* Favoritkortet fyller sin cell så att ramarna blir lika höga. */
  .framrad .favorit { display: flex; }
  .framrad .favoritkort { align-items: flex-start; }

  /* Öppettiderna och platsen sida vid sida, i samma ränna som menyns spalter.
     Ingen ny stil — bara rätt bredd på två block som var för sig lämnade en
     halv spalt tom. */
  .underrad {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 3.5rem;
    /* Blocken är olika höga och ska hänga i överkant. Rubrikerna står då på
       samma linje, vilket är det enda de behöver ha gemensamt. */
    align-items: start;
    margin-bottom: 3.5rem;
  }
  /* Bottenmarginalen flyttas upp till raden. Två spalter som slutar på olika
     höjd ska ändå lämna lika mycket luft ned mot foten. */
  .underrad > * { margin-bottom: 0; }
  /* En restaurang utan karta — eller utan öppettider — har bara ett block här,
     och då tar det hela bredden. Annars vore tomrummet bara flyttat. */
  .underrad > :only-child { grid-column: 1 / -1; }

  /* Platsen har en egen tvåspalt från 48rem, med adressen bredvid kartan. Den
     ryms inte i en halv spalt: kartan hade blivit en frimärksbild. Här står
     adressen ovanför i stället. */
  .underrad .plats { display: block; }
  .underrad .kartruta { margin-top: 1.25rem; }
  /* Tabellens caption bär redan sin egen luft, precis som platsens rubrik.
     Marginalen ovanför tabellen hade skjutit ned vänsterspalten en rad. */
  .underrad .oppettabell { margin-top: 0; }

  /* Två scheman bredvid varandra bara när öppettiderna har hela bredden — i en
     halv spalt blir de två tabeller på 200 px med tider som viker sig. */
  .underrad > .oppettider:only-child .schemapar { grid-template-columns: 1fr 1fr; }

  /* Foten fördelas över bredden i stället för att stå som en hög remsa till
     vänster. Flex och inte grid, med flit: kontaktspalten ritas inte alls när
     restaurangen varken har telefon, e-post eller kanaler, och en grid med tre
     namngivna spalter hade då lämnat ett hål till höger. Med flex-basis 0 delar
     de spalter som *finns* upp bredden mellan sig. */
  .fot .fotrad {
    display: flex;
    flex-wrap: wrap;
    gap: 3.5rem;
    /* Toppställda: spalterna är olika höga av innehåll, och det enda de
       behöver ha gemensamt är var de börjar. Samma val som .underrad. */
    align-items: start;
  }
  /* Växtfaktorerna, inte lika delar: adressraden är den längsta texten i foten
     och de tre länkorden de kortaste. Lika spalter hade brutit adressen i två
     rader medan sista spalten stod halvtom. */
  .fot .fotplats { flex: 1.6 1 0; }
  .fot .fotnara { flex: 1.2 1 0; }
  .fot .fotlankar { flex: 1 1 0; }
  /* Minsta bredd noll: utan den vägrar en flexrad krympa under sitt innehåll,
     och en lång e-postadress hade skjutit foten bredare än sidan. */
  .fot .fotgrupp { min-width: 0; }

  /* Telefon och e-post på var sin rad i spalten. På telefonen ryms de bredvid
     varandra med en prick emellan, men i en tredjedels bredd bryts raden mellan
     dem och pricken blir hängande sist på den första — ett skiljetecken utan
     något att skilja. Punkten är redan aria-hidden och bär ingen betydelse att
     ta bort. */
  .fot .fotkontakt {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .15rem;
  }
  .fot .fotkontakt .prick { display: none; }

  /* Det finstilta som en egen rad under spalterna, med hårstrecket som skiljer
     juridiken från uppgifterna. space-between och inte två spalter: raderna är
     olika långa och ska hänga i var sin kant. */
  .fot .fotband {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: .25rem 2rem;
    margin-top: 2.75rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--linje);
  }
  /* Luften ovanför raden om oss bars av marginalen när den stod sist i en
     stapel. Här bär bandet den, och marginalen hade skjutit raden ur linje med
     firman bredvid. */
  .fot .fotband .drivsav { margin-top: 0 !important; }
}

@media (max-width: 420px) {
  .faltpar { grid-template-columns: 1fr; }
  /* Staplade, men fortfarande lika höga: grid-auto-rows: 1fr ger alla rader
     samma höjd som den högsta. Utan den blir rutan med längre text — eller den
     som visar leveransavgiften — högre än sin granne så snart de inte längre
     ligger i samma rad och kan sträcka sig mot varandra. */
  .valrad { grid-auto-flow: row; grid-auto-rows: 1fr; }
}

/* Rörelsen är dekor. Den som bett systemet om lugn ska få en sida som står
   still, inte en som studsar lite mindre. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition: none !important;
    animation: none !important;
    scroll-behavior: auto !important;
  }
  .stampel { transform: scale(1); }
}
