/* =============================================================================
   FODMAP-listan

   Three themes (nordic / orchard / pulse), each with a light and a dark palette.
   Everything downstream of the palette is written against the same token names,
   so a theme is nothing but a block of custom properties.

   `data-mode` on <html> is always resolved to "light" or "dark" by app.js — the
   "auto" preference is turned into one of the two before paint. That keeps this
   file free of prefers-color-scheme duplication.
   ========================================================================== */

/* --- Palettes ------------------------------------------------------------ */

/* Nordic — calm and clinical: desaturated sage, cool greys, lots of air. */
[data-theme='nordic'] {
  --font-head: 'Sora', system-ui, sans-serif;
  --font-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --radius: 14px;
  --radius-sm: 9px;
  --head-weight: 600;
  --head-tracking: -0.02em;
}
[data-theme='nordic'][data-mode='light'] {
  --bg: #f4f6f4;
  --bg-tint: #ecefec;
  --surface: #ffffff;
  --surface-2: #f7f9f7;
  --ink: #16201c;
  --ink-2: #47544e;
  --muted: #6a7873;
  --line: #dfe5e1;
  --line-strong: #c8d2cc;
  --accent: #2f6f5a;
  --accent-ink: #ffffff;
  --green: #2d7758;
  --green-bg: #e4f0ea;
  --yellow: #8f620b;
  --yellow-bg: #f6eddb;
  --red: #a8443a;
  --red-bg: #f6e5e3;
  --shadow: 0 1px 2px rgba(22, 32, 28, .05), 0 8px 24px -12px rgba(22, 32, 28, .18);
  --shadow-lift: 0 2px 4px rgba(22, 32, 28, .06), 0 18px 40px -18px rgba(22, 32, 28, .28);
}
[data-theme='nordic'][data-mode='dark'] {
  --bg: #0e1412;
  --bg-tint: #131a17;
  --surface: #161d1a;
  --surface-2: #1c2521;
  --ink: #e6ece9;
  --ink-2: #b3c0ba;
  --muted: #8b9a93;
  --line: #263029;
  --line-strong: #35423a;
  --accent: #6fbfa0;
  --accent-ink: #08110d;
  --green: #63c496;
  --green-bg: #163024;
  --yellow: #e0ae55;
  --yellow-bg: #33280f;
  --red: #e88377;
  --red-bg: #391f1c;
  --shadow: 0 1px 2px rgba(0, 0, 0, .5), 0 8px 24px -12px rgba(0, 0, 0, .7);
  --shadow-lift: 0 2px 4px rgba(0, 0, 0, .55), 0 18px 40px -18px rgba(0, 0, 0, .85);
}

/* Orchard — warm and editorial: cream paper, ink brown, terracotta. */
[data-theme='orchard'] {
  --font-head: 'Fraunces', Georgia, 'Times New Roman', serif;
  --font-body: 'Archivo', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --radius: 10px;
  --radius-sm: 6px;
  --head-weight: 600;
  --head-tracking: -0.005em;
}
[data-theme='orchard'][data-mode='light'] {
  --bg: #f8f2e7;
  --bg-tint: #f2ead9;
  --surface: #fffdf8;
  --surface-2: #faf4e9;
  --ink: #2a2118;
  --ink-2: #5d4e3c;
  --muted: #7b7160;
  --line: #e7dcc8;
  --line-strong: #d5c5a8;
  --accent: #8a4a2b;
  --accent-ink: #fffdf8;
  --green: #4a7233;
  --green-bg: #e8eeda;
  --yellow: #8c5f0e;
  --yellow-bg: #f6e9cd;
  --red: #a33a29;
  --red-bg: #f5e0da;
  --shadow: 0 1px 2px rgba(58, 42, 24, .07), 0 8px 24px -12px rgba(58, 42, 24, .2);
  --shadow-lift: 0 2px 4px rgba(58, 42, 24, .08), 0 18px 40px -18px rgba(58, 42, 24, .32);
}
[data-theme='orchard'][data-mode='dark'] {
  --bg: #17120e;
  --bg-tint: #1d1712;
  --surface: #221b15;
  --surface-2: #2a221a;
  --ink: #f1e7d8;
  --ink-2: #c9b89f;
  --muted: #9d8c76;
  --line: #33291f;
  --line-strong: #453728;
  --accent: #e0894f;
  --accent-ink: #17120e;
  --green: #8fbd63;
  --green-bg: #22301a;
  --yellow: #e5b352;
  --yellow-bg: #33280f;
  --red: #e2775f;
  --red-bg: #3a201a;
  --shadow: 0 1px 2px rgba(0, 0, 0, .5), 0 8px 24px -12px rgba(0, 0, 0, .7);
  --shadow-lift: 0 2px 4px rgba(0, 0, 0, .55), 0 18px 40px -18px rgba(0, 0, 0, .85);
}

/* Pulse — sharp and app-like: near-black, electric indigo, saturated signals. */
[data-theme='pulse'] {
  --font-head: 'Space Grotesk', system-ui, sans-serif;
  --font-body: 'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --radius: 18px;
  --radius-sm: 11px;
  --head-weight: 700;
  --head-tracking: -0.03em;
}
[data-theme='pulse'][data-mode='light'] {
  --bg: #ffffff;
  --bg-tint: #f2f4f8;
  --surface: #f7f8fb;
  --surface-2: #eef1f6;
  --ink: #0b0d12;
  --ink-2: #3d4757;
  --muted: #667182;
  --line: #e3e7ee;
  --line-strong: #cdd4e0;
  --accent: #4636e8;
  --accent-ink: #ffffff;
  --green: #067a4c;
  --green-bg: #dcf5e9;
  --yellow: #92590a;
  --yellow-bg: #fdefd2;
  --red: #c22a3d;
  --red-bg: #fde3e7;
  --shadow: 0 1px 2px rgba(11, 13, 18, .06), 0 10px 28px -14px rgba(11, 13, 18, .3);
  --shadow-lift: 0 2px 6px rgba(11, 13, 18, .08), 0 22px 46px -20px rgba(11, 13, 18, .4);
}
[data-theme='pulse'][data-mode='dark'] {
  --bg: #08090c;
  --bg-tint: #0e1015;
  --surface: #12141a;
  --surface-2: #191c24;
  --ink: #f2f4f8;
  --ink-2: #c3cad6;
  --muted: #8d97a8;
  --line: #1f232c;
  --line-strong: #2e3441;
  --accent: #8b7bff;
  --accent-ink: #08090c;
  --green: #2ed99a;
  --green-bg: #06291f;
  --yellow: #fbbf24;
  --yellow-bg: #302108;
  --red: #fb7185;
  --red-bg: #33121c;
  --shadow: 0 1px 2px rgba(0, 0, 0, .6), 0 10px 28px -14px rgba(0, 0, 0, .8);
  --shadow-lift: 0 2px 6px rgba(0, 0, 0, .65), 0 22px 46px -20px rgba(0, 0, 0, .9);
}

/* --- Reset & base -------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  padding-bottom: env(safe-area-inset-bottom);
  /* Installed to a home screen the page owns the whole display, so in landscape
     it has to keep clear of the notch itself. Zero in an ordinary tab. */
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}

h1, h2, h3 {
  font-family: var(--font-head);
  font-weight: var(--head-weight);
  letter-spacing: var(--head-tracking);
  margin: 0;
}

button, input { font: inherit; color: inherit; }
button { cursor: pointer; }

/* Any author rule that sets `display` outranks the UA's `[hidden]` rule, so
   elements toggled via the hidden property (the empty state, the clear button)
   would stay on screen. Restate it here with enough weight to always win. */
[hidden] { display: none !important; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--accent);
  color: var(--accent-ink);
  padding: .6rem 1rem;
  border-radius: 0 0 var(--radius-sm) 0;
  text-decoration: none;
}
.skip:focus { left: 0; }

/* --- Top bar ------------------------------------------------------------- */

/* On a phone the filter block runs to five or six wrapped rows — pinning all of
   it would eat 40% of the viewport. So only brand + search are pinned there, and
   the filters scroll away. From tablet up the whole bar is short enough to pin. */
.topbar {
  z-index: 30;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--line);
  padding: .55rem clamp(.85rem, 3vw, 2rem) .5rem;
}

/* The top inset lives here rather than on .topbar because this is the element
   that pins to y=0 on phones — and under the status bar of an installed app,
   whatever sits at y=0 is what gets covered. On desktop, where .topbar is the
   sticky one instead, padding on this static child does the same job. */
.topbar-sticky {
  position: sticky;
  top: 0;
  z-index: 31;
  background: inherit;
  -webkit-backdrop-filter: inherit;
  backdrop-filter: inherit;
  margin-inline: calc(clamp(.85rem, 3vw, 2rem) * -1);
  padding: calc(.1rem + env(safe-area-inset-top)) clamp(.85rem, 3vw, 2rem) .1rem;
}

@media (min-width: 700px) {
  .topbar { position: sticky; top: 0; }
  .topbar-sticky { position: static; }
}

.topbar-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  max-width: 1240px;
  margin: 0 auto;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  text-decoration: none;
  color: inherit;
  font-family: var(--font-head);
  font-weight: var(--head-weight);
  letter-spacing: var(--head-tracking);
  font-size: 1.06rem;
}
.brand-mark { display: inline-flex; gap: 3px; }
.brand-mark .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: block;
}
.dot-g { background: var(--green); }
.dot-y { background: var(--yellow); }
.dot-r { background: var(--red); }
.brand-thin { color: var(--muted); font-weight: 400; }

/* "FODMAP-listan" needs 415px of header before it wraps to a second line, in
   the widest of the three themes and with the longer Swedish suffix. Below that
   the suffix goes and the wordmark stands alone, which fits from 300px down.
   The threshold moved up when the install button joined the row - before it,
   the brand survived to 375px. */
@media (max-width: 439px) {
  .brand-thin { display: none; }
}

.topbar-actions { display: flex; align-items: center; gap: .4rem; }

.seg {
  display: inline-flex;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 2px;
}
.seg-btn {
  border: 0;
  background: transparent;
  color: var(--muted);
  padding: .28rem .62rem;
  border-radius: 999px;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .02em;
  line-height: 1.4;
  transition: background .15s, color .15s;
}
.seg-btn.is-on {
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow);
}

.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: .95rem;
  transition: background .15s, color .15s, border-color .15s;
}
.icon-btn:hover { color: var(--ink); border-color: var(--line-strong); }

#modeBtn .icon-moon { display: none; }
[data-mode='dark'] #modeBtn .icon-sun { display: none; }
[data-mode='dark'] #modeBtn .icon-moon { display: inline; }

/* The install offer. Tinted with the accent so it reads as an invitation rather
   than a fourth grey control, but still a header button — no banner, no toast,
   nothing that covers the list. */
.install-btn {
  display: inline-flex;
  align-items: center;
  gap: .34rem;
  height: 34px;
  padding: 0 .7rem;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
  background: color-mix(in srgb, var(--accent) 10%, var(--surface-2));
  color: var(--accent);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .01em;
  white-space: nowrap;
  transition: background .15s, border-color .15s;
}
.install-btn:hover {
  background: color-mix(in srgb, var(--accent) 17%, var(--surface-2));
  border-color: var(--accent);
}
.install-glyph { font-size: .95rem; line-height: 1; }

/* Below 560px the header row is already carrying the brand, the language
   switch and two icon buttons — drop to the glyph alone rather than let the
   row wrap. aria-label carries the name either way. */
@media (max-width: 559px) {
  .install-btn { padding: 0; width: 34px; justify-content: center; }
  .install-text { display: none; }
}

/* Belt and braces: an installed window can still be showing a cached shell
   from before `appinstalled` was ever observed. */
@media (display-mode: standalone) {
  .install-btn { display: none !important; }
}

.install-steps {
  margin: 0;
  padding-left: 1.15rem;
  display: grid;
  gap: .4rem;
  font-size: .85rem;
  color: var(--ink-2);
}

/* --- Search -------------------------------------------------------------- */

.search-row {
  max-width: 1240px;
  margin: .55rem auto .5rem;
}

.search {
  position: relative;
  display: flex;
  align-items: center;
}
.search-icon {
  position: absolute;
  left: .95rem;
  font-size: 1.15rem;
  color: var(--muted);
  pointer-events: none;
  line-height: 1;
}
#q {
  width: 100%;
  padding: .72rem 5.2rem .72rem 2.65rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--shadow);
  transition: border-color .15s, box-shadow .15s;
  -webkit-appearance: none;
  appearance: none;
}
#q::-webkit-search-cancel-button { display: none; }
#q::placeholder { color: var(--muted); }
#q:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--shadow), 0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent);
}

.clear-btn {
  position: absolute;
  right: 2.6rem;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--muted);
  font-size: .7rem;
}
.clear-btn:hover { color: var(--ink); }

.search-kbd {
  position: absolute;
  right: .9rem;
  font-family: var(--font-body);
  font-size: .72rem;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 0 .32rem;
  line-height: 1.35;
  background: var(--surface-2);
}
@media (hover: none) { .search-kbd { display: none; } #q { padding-right: 3rem; } .clear-btn { right: .8rem; } }

/* --- Filter chips -------------------------------------------------------- */

.filters {
  max-width: 1240px;
  margin: 0 auto;
  display: grid;
  gap: .4rem;
}

/* Wraps rather than scrolls sideways: a horizontal scroller hides options
   off-screen with no affordance, and every category should be visible at a
   glance. Category chips use the short labels from data.js to keep the wrapped
   block to two or three rows even on a phone. */
.chiprow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .38rem;
}

/* Naming the row is what makes a plain "Alla" chip unambiguous — spelling it out
   as "Alla statusar" pushes the level row past a phone's width and wraps it. */
.filter-label {
  flex: 0 0 auto;
  width: 4.6rem;
  color: var(--muted);
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  line-height: 1.2;
}

.chip {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .34rem .7rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
  font-size: .82rem;
  font-weight: 500;
  white-space: nowrap;
  transition: background .14s, color .14s, border-color .14s;
}
.chip:hover { border-color: var(--line-strong); }
.chip-glyph { font-size: .6rem; line-height: 1; }
.chip-count {
  font-size: .7rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  font-weight: 500;
}
.chip .cat-icon { font-size: .85rem; }

.chip.is-on {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg);
}
.chip.is-on .chip-count { color: color-mix(in srgb, var(--bg) 70%, transparent); }

.chip-level.lvl-green .chip-glyph { color: var(--green); }
.chip-level.lvl-yellow .chip-glyph { color: var(--yellow); }
.chip-level.lvl-red .chip-glyph { color: var(--red); }

.chip-level.lvl-green.is-on {
  background: var(--green-bg); border-color: var(--green); color: var(--green);
}
.chip-level.lvl-yellow.is-on {
  background: var(--yellow-bg); border-color: var(--yellow); color: var(--yellow);
}
.chip-level.lvl-red.is-on {
  background: var(--red-bg); border-color: var(--red); color: var(--red);
}
.chip-level.is-on .chip-glyph,
.chip-level.is-on .chip-count { color: inherit; }

/* Favourites are not a fourth level, so the chip is set apart by a hairline and
   takes the accent rather than a signal colour when on — the three-colour system
   has to keep meaning exactly one thing. */
.chip-sep {
  flex: 0 0 auto;
  width: 1px;
  height: 1.15rem;
  background: var(--line-strong);
  margin: 0 .2rem;
}
.chip-fav .chip-star { font-size: .78rem; line-height: 1; color: var(--accent); }
.chip-fav.is-on {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.chip-fav.is-on .chip-star { color: inherit; }
.chip-fav.is-on .chip-count { color: color-mix(in srgb, var(--accent-ink) 75%, transparent); }

/* --- Results ------------------------------------------------------------- */

main {
  max-width: 1240px;
  margin: 0 auto;
  padding: 0 clamp(.85rem, 3vw, 2rem) 3rem;
}

.resultbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin: 1rem 0 .75rem;
  color: var(--muted);
  font-size: .82rem;
  min-height: 1.4rem;
}

.linkbtn {
  border: 0;
  background: none;
  color: var(--accent);
  font-size: .82rem;
  font-weight: 600;
  padding: 0;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .6rem;
  grid-template-columns: repeat(auto-fill, minmax(258px, 1fr));
}
/* Cards carry a variable number of FODMAP tags, so let each stretch to its
   row's height rather than leaving ragged gaps.

   The hover lift lives here rather than on .card because the favourite star is a
   sibling of the card, not a child (buttons cannot nest) — moving the cell moves
   both. `:active` matches ancestors of whatever is being pressed, so pressing
   either the card or its star settles the cell back down. */
.grid > li {
  display: flex;
  position: relative;
  transition: transform .13s ease;
}
.grid > li:hover { transform: translateY(-1px); }
.grid > li:active { transform: translateY(0); }

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: .3rem;
  width: 100%;
  text-align: left;
  padding: .78rem .85rem .8rem;
  background: var(--surface);
  /* The level badge top-right already carries the colour, so the card itself
     stays neutral — a coloured edge on every card made the grid noisy. */
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  transition: box-shadow .13s ease, border-color .13s;
}
.grid > li:hover .card {
  box-shadow: var(--shadow-lift);
  border-color: var(--line-strong);
}

.card.lvl-green  { --lvl: var(--green);  --lvl-bg: var(--green-bg); }
.card.lvl-yellow { --lvl: var(--yellow); --lvl-bg: var(--yellow-bg); }
.card.lvl-red    { --lvl: var(--red);    --lvl-bg: var(--red-bg); }

.card-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: .6rem;
  /* Keeps the level badge clear of the star sitting in the corner above it. */
  padding-right: 1.45rem;
}

/* Both are spans inside a span, so they need to be told to stack — otherwise the
   two names run together on the cards that reveal a search match. */
.card-name {
  display: block;
  font-family: var(--font-head);
  font-weight: var(--head-weight);
  letter-spacing: var(--head-tracking);
  font-size: 1.02rem;
  line-height: 1.25;
}
.card-alt {
  display: block;
  margin-top: .1rem;
  color: var(--muted);
  font-size: .8rem;
  line-height: 1.3;
}

.badge {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: .28rem;
  padding: .16rem .48rem;
  border-radius: 999px;
  background: var(--lvl-bg);
  color: var(--lvl);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  white-space: nowrap;
}
.badge i { font-style: normal; font-size: .55rem; }

.serving {
  display: flex;
  align-items: baseline;
  gap: .38rem;
  margin-top: .12rem;
  font-size: .82rem;
  color: var(--ink-2);
}
.serving-label {
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  flex: 0 0 auto;
}
.card.lvl-yellow .serving-value { color: var(--yellow); font-weight: 600; }

.card-foot {
  display: flex;
  align-items: center;
  gap: .3rem;
  flex-wrap: wrap;
  margin-top: auto;   /* pins the tag row to the bottom of a stretched card */
  padding-top: .28rem;
}

.tag {
  font-size: .68rem;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: .06rem .42rem;
  white-space: nowrap;
}
.tag-cat { border-color: transparent; background: var(--surface-2); }
.tag-untested { border-style: dashed; }

/* --- Favourite star ------------------------------------------------------ */

/* Accent, not gold: a yellow star next to a yellow level badge would read as
   part of the signal system. Off is a hollow glyph, on is a filled one, so the
   state does not rest on colour alone. */
.fav-btn {
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  line-height: 1;
  transition: color .14s, opacity .14s, background .14s, border-color .14s;
}
.fav-btn.is-fav { color: var(--accent); }
.fav-btn > span { display: block; }

.fav-btn-card {
  position: absolute;
  top: .34rem;
  right: .34rem;
  z-index: 1;
  width: 28px;
  height: 28px;
  font-size: 1.02rem;
  opacity: .5;
}
.fav-btn-card:hover { opacity: 1; color: var(--accent); background: var(--surface-2); }
.fav-btn-card.is-fav { opacity: 1; }
.fav-btn-card.is-fav:hover { background: color-mix(in srgb, var(--accent) 14%, transparent); }
/* Nothing reveals an unstarred card's star on a touch screen, so it has to hold
   its own weight there instead of waiting for a hover that never comes. */
@media (hover: none) { .fav-btn-card { opacity: .72; } }

.fav-btn-sheet {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  font-size: 1.05rem;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink-2);
}
.fav-btn-sheet:hover { border-color: var(--line-strong); color: var(--accent); }
.fav-btn-sheet.is-fav {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background: color-mix(in srgb, var(--accent) 10%, var(--surface-2));
}

/* Added by toggleFav and left in place; it is the class swap that plays it, so
   a re-rendered card never replays the pop on its own. */
.fav-btn.is-popping > span { animation: star-pop .24s ease; }
@keyframes star-pop {
  40% { transform: scale(1.38); }
  100% { transform: scale(1); }
}

mark {
  background: color-mix(in srgb, var(--accent) 22%, transparent);
  color: inherit;
  border-radius: 3px;
  padding: 0 .08em;
}

.empty {
  display: grid;
  justify-items: center;
  gap: .2rem;
  padding: 3.5rem 1rem;
  color: var(--muted);
  text-align: center;
}
.empty-mark { font-size: 2rem; opacity: .5; }
.empty span { font-family: var(--font-head); font-size: 1.05rem; color: var(--ink-2); }
.empty small { font-size: .85rem; }

/* --- Footer -------------------------------------------------------------- */

.footer {
  max-width: 1240px;
  margin: 0 auto;
  padding: 1.5rem clamp(.85rem, 3vw, 2rem) 3rem;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: .78rem;
}
.legend {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem 1.1rem;
  margin: 0 0 .8rem;
}
.legend-item { display: inline-flex; align-items: center; gap: .38rem; }
.legend-item i { font-style: normal; font-size: .6rem; }
.legend-item.lvl-green i { color: var(--green); }
.legend-item.lvl-yellow i { color: var(--yellow); }
.legend-item.lvl-red i { color: var(--red); }
.disclaimer { margin: 0; max-width: 62ch; line-height: 1.55; }

.sources { margin-top: 1.1rem; }
.sources summary {
  cursor: pointer;
  color: var(--ink-2);
  font-weight: 600;
  width: fit-content;
  padding: .15rem 0;
}
.sources summary:hover { color: var(--ink); }
.sources-lead { max-width: 62ch; line-height: 1.55; margin: .6rem 0 .8rem; }
.sources-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .6rem;
  max-width: 62ch;
}
.sources-list li { display: grid; gap: .1rem; }
.sources-list a {
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
  width: fit-content;
}
.sources-list a:hover { text-decoration: underline; text-underline-offset: 3px; }
.source-note { line-height: 1.5; }

/* --- Overlays: theme panel + detail sheet -------------------------------- */

.scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--ink) 42%, transparent);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  animation: fade .16s ease;
}
@keyframes fade { from { opacity: 0; } }

.panel, .sheet {
  position: fixed;
  z-index: 50;
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lift);
}

.panel {
  top: 3.6rem;
  right: clamp(.85rem, 3vw, 2rem);
  width: min(380px, calc(100vw - 1.7rem));
  border-radius: var(--radius);
  padding: 1rem;
  animation: pop .16s ease;
}
@keyframes pop { from { opacity: 0; transform: translateY(-6px) scale(.985); } }

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: .2rem;
}
.panel-head h2 { font-size: 1rem; }
.panel-hint { margin: 0 0 .8rem; font-size: .8rem; color: var(--muted); }

.theme-choices { display: grid; gap: .45rem; }

.theme-card {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: 'sw name' 'sw fonts' 'desc desc';
  align-items: center;
  gap: .05rem .6rem;
  text-align: left;
  padding: .6rem .7rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  transition: border-color .14s, background .14s;
}
.theme-card:hover { border-color: var(--line-strong); }
.theme-card.is-on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--surface-2)); }

.swatches { grid-area: sw; display: grid; grid-template-columns: 1fr 1fr; gap: 2px; }
.swatches i { width: 13px; height: 13px; border-radius: 3px; display: block; }
.theme-name { grid-area: name; font-family: var(--font-head); font-weight: var(--head-weight); font-size: .92rem; }
.theme-fonts { grid-area: fonts; font-size: .72rem; color: var(--muted); }
.theme-desc { grid-area: desc; font-size: .76rem; color: var(--ink-2); margin-top: .32rem; line-height: 1.4; }

/* Each card previews its own palette regardless of the active theme. */
[data-pick-theme='nordic']  .swatches i:nth-child(1) { background: #2f6f5a; }
[data-pick-theme='nordic']  .swatches i:nth-child(2) { background: #2f7d5c; }
[data-pick-theme='nordic']  .swatches i:nth-child(3) { background: #9a6a0c; }
[data-pick-theme='nordic']  .swatches i:nth-child(4) { background: #a8443a; }
[data-pick-theme='orchard'] .swatches i:nth-child(1) { background: #8a4a2b; }
[data-pick-theme='orchard'] .swatches i:nth-child(2) { background: #4a7233; }
[data-pick-theme='orchard'] .swatches i:nth-child(3) { background: #c9860f; }
[data-pick-theme='orchard'] .swatches i:nth-child(4) { background: #a33a29; }
[data-pick-theme='pulse']   .swatches i:nth-child(1) { background: #4636e8; }
[data-pick-theme='pulse']   .swatches i:nth-child(2) { background: #067a4c; }
[data-pick-theme='pulse']   .swatches i:nth-child(3) { background: #d97706; }
[data-pick-theme='pulse']   .swatches i:nth-child(4) { background: #c22a3d; }

.panel-sub {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: .9rem;
  padding-top: .8rem;
  border-top: 1px solid var(--line);
  font-size: .85rem;
  color: var(--ink-2);
}

/* Detail sheet: centred dialog on desktop, bottom sheet on phones. */
.sheet {
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(520px, calc(100vw - 2rem));
  max-height: min(80vh, 640px);
  overflow-y: auto;
  border-radius: var(--radius);
  border-left: 4px solid var(--lvl);
  padding: 1.15rem 1.25rem 1.4rem;
  animation: pop .18s ease;
}
.sheet.lvl-green  { --lvl: var(--green);  --lvl-bg: var(--green-bg); }
.sheet.lvl-yellow { --lvl: var(--yellow); --lvl-bg: var(--yellow-bg); }
.sheet.lvl-red    { --lvl: var(--red);    --lvl-bg: var(--red-bg); }

.sheet-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: .8rem;
}
.sheet-actions { display: flex; gap: .4rem; flex: 0 0 auto; }
.sheet h2 { font-size: 1.4rem; line-height: 1.15; }
.sheet-sub { color: var(--muted); font-size: .92rem; margin: .15rem 0 0; }

.sheet-serving {
  margin: 1rem 0 0;
  padding: .75rem .85rem;
  border-radius: var(--radius-sm);
  background: var(--lvl-bg);
  color: var(--ink);
}
.sheet-serving .serving-label { display: block; margin-bottom: .12rem; color: var(--lvl); }
.sheet-serving strong { font-size: 1.08rem; font-family: var(--font-head); letter-spacing: var(--head-tracking); }

.sheet-note {
  margin: .8rem 0 0;
  font-size: .9rem;
  line-height: 1.55;
  color: var(--ink-2);
}

.sheet-meta {
  margin: 1rem 0 0;
  padding-top: .85rem;
  border-top: 1px solid var(--line);
  display: grid;
  gap: .5rem;
  font-size: .82rem;
}
.meta-row { display: flex; gap: .5rem; align-items: baseline; flex-wrap: wrap; }
.meta-key {
  flex: 0 0 auto;
  min-width: 8.5rem;
  color: var(--muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}

@media (max-width: 560px) {
  .sheet {
    top: auto;
    bottom: 0;
    left: 0;
    transform: none;
    width: 100%;
    max-height: 86vh;
    border-radius: var(--radius) var(--radius) 0 0;
    border-left: 0;
    border-top: 4px solid var(--lvl);
    padding-bottom: calc(1.4rem + env(safe-area-inset-bottom));
    animation: rise .2s ease;
  }
  @keyframes rise { from { transform: translateY(14px); opacity: 0; } }

  .panel {
    top: auto;
    bottom: 0;
    left: 0;
    right: 0;
    width: 100%;
    border-radius: var(--radius) var(--radius) 0 0;
    padding-bottom: calc(1rem + env(safe-area-inset-bottom));
    animation: rise .2s ease;
  }
  .grid { grid-template-columns: 1fr; }
  .resultbar { margin-top: .8rem; }

  /* Give the label its own line so the four level chips stay on one row
     instead of dropping "Röd" by itself. */
  .filter-label { width: 100%; margin-bottom: -.1rem; }

  /* The favourites chip wraps to its own line here, where a leading hairline
     would look like a stray mark rather than a divider. */
  .chip-sep { display: none; }
}
