/* ─── Reset & base ─────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --clr-green:   #1ea860;
  --clr-green-2: #16c79a;
  --clr-yellow:  #f0a818;
  --clr-red:     #e6493f;
  --clr-dark:    #15212e;
  --clr-mid:     #647686;
  --clr-light:   #eef2f4;
  --clr-white:   #ffffff;
  --clr-bg:      #f6f8f9;
  --clr-border:  #e3e9ec;
  --radius-sm:   10px;
  --radius:      14px;
  --radius-lg:   22px;
  --radius-pill: 999px;
  /* Layered, softer shadows for depth */
  --shadow:      0 1px 2px rgba(16,40,34,.04), 0 4px 16px rgba(16,40,34,.06);
  --shadow-lg:   0 4px 12px rgba(16,40,34,.08), 0 18px 48px rgba(16,40,34,.12);
  --shadow-green:0 6px 20px rgba(30,168,96,.30);
  --grad-green:  linear-gradient(135deg, #27ae60 0%, #16c79a 100%);
  --grad-hero:   radial-gradient(1200px 420px at 12% -8%, #d9f7e8 0%, rgba(217,247,232,0) 60%),
                 radial-gradient(900px 380px at 100% 0%, #d6f1ff 0%, rgba(214,241,255,0) 55%),
                 linear-gradient(180deg, #f3fbf7 0%, #ffffff 70%);
  --transition:  .2s cubic-bezier(.4,0,.2,1);
  --ease:        cubic-bezier(.4,0,.2,1);
  --font:        'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;

  /* Status-tint pairs (bg/fg) — hardcoded per-mode instead of a single var
     because the fg needs a real contrast flip, not just a hue shift. Used by
     score badges, ingredient alerts, allergen notices, pending/contribute
     banners, etc. so those don't need one-off dark overrides scattered
     across the file. */
  --tint-green-bg: #d5f5e3; --tint-green-fg: #1a7a42;
  --tint-yellow-bg:#fef9e7; --tint-yellow-fg: #9a6a00;
  --tint-red-bg:   #fdecea; --tint-red-fg:    #922b21;
  --tint-blue-bg:  #eaf3fb; --tint-blue-fg:   #1c5680;

  /* Intentionally-always-dark navy surface (site footer, trust strip) —
     constant across both themes, unlike --clr-dark which flips to a light
     text color in dark mode. */
  --clr-navy: #15212e;
}

/* ─── Dark mode ────────────────────────────────────────────────────────────
   Every component below is themed by re-pointing these custom properties —
   --clr-dark/--clr-mid (text) and --clr-white/--clr-bg/--clr-light (surfaces)
   swap roles, so cards/buttons/forms/nav/modal/toast/tab-bar etc. all follow
   without per-component overrides. Only genuinely mode-specific things (the
   hero gradient wash, status-tint pairs, shimmer) get their own block below. */
@media (prefers-color-scheme: dark) {
  :root {
    --clr-dark:    #eaf0f3;
    --clr-mid:     #93a4b3;
    --clr-light:   #212b36;
    --clr-white:   #1a222c;
    --clr-bg:      #0f151d;
    --clr-border:  #2a3542;
    --shadow:      0 1px 2px rgba(0,0,0,.3), 0 4px 16px rgba(0,0,0,.35);
    --shadow-lg:   0 4px 12px rgba(0,0,0,.35), 0 18px 48px rgba(0,0,0,.45);
    --grad-hero:   linear-gradient(180deg, #131c17 0%, #0f151d 70%);

    --tint-green-bg: #16301f;  --tint-green-fg: #6fe3a3;
    --tint-yellow-bg:#3a2f0d;  --tint-yellow-fg: #f0c96a;
    --tint-red-bg:   #3a1614;  --tint-red-fg:    #f29a92;
    --tint-blue-bg:  #142a3a;  --tint-blue-fg:   #8cc5ef;
  }

  .score--unknown .score-ring__fill { stroke: #3d4a58; }
  .score--unknown .score-ring__number { color: var(--clr-mid); }
  .subscore.score--unknown .subscore__fill { background: #3d4a58; }

  .skeleton { background: linear-gradient(90deg, #212b36 25%, #2a3542 50%, #212b36 75%); background-size: 200% 100%; }

  .upload-zone:hover, .upload-zone.drag-over { background: #142a20; }

  /* #ddd (unselected star) is a light "dim" gray on a white card; on a dark
     card the same value reads as bright/lit, which flips the semantics. */
  .star-input span { color: #3d4a58; }

  /* .btn--ghost/.tab-bar used a hardcoded rgba(255,255,255,..) glass
     background instead of a var — in dark mode --clr-dark/--clr-mid (their
     text colour) flip to near-white, so text was landing on a near-white
     translucent surface. (.nav no longer needs an entry here — it's now a
     constant navy background regardless of theme, same idea as --clr-navy.) */
  .btn--ghost { background: rgba(255,255,255,.06); }
  .btn--ghost:hover { background: rgba(255,255,255,.1); border-color: #384454; }
  .tab-bar  { background: rgba(26,34,44,.92); }
}

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

body {
  font-family: var(--font);
  background: var(--clr-bg);
  color: var(--clr-dark);
  min-height: 100dvh;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: 'cv02','cv03','cv04','cv11';
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
}

a { color: var(--clr-green); text-decoration: none; }
a:hover { text-decoration: underline; }

img { max-width: 100%; display: block; }

/* ─── Layout ───────────────────────────────────────────────────────────────── */
.container {
  width: 100%;
  max-width: 680px;
  margin: 0 auto;
  padding: 0 1rem 4rem;
}

/* ─── Top navigation ───────────────────────────────────────────────────────── */
/* Dark navy bar (matches .site-footer's --clr-navy) — deliberately constant
   across both color themes rather than following --clr-white/--clr-dark, so
   it always reads as its own distinct "chrome" band, and the green pill
   buttons below always have a guaranteed-dark surface to sit on. */
.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(21,33,46,.94);
  -webkit-backdrop-filter: saturate(160%) blur(10px);
  backdrop-filter: saturate(160%) blur(10px);
  border-bottom: 1px solid rgba(255,255,255,.08);
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: 680px;
  margin: 0 auto;
  padding: .75rem 1rem;
  gap: .5rem;
}

.nav__logo {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: 1.25rem;
  font-weight: 800;
  color: #fff;
  letter-spacing: -.03em;
  flex-shrink: 0;
  text-decoration: none;
}
.nav__logo svg { flex-shrink: 0; }
.nav__logo:hover { text-decoration: none; }

.nav__actions { display: flex; align-items: center; gap: .5rem; flex-shrink: 0; }

.nav__user-menu { align-items: center; gap: .5rem; }
#nav-username { font-size: .85rem; font-weight: 600; color: #fff; }

/* ─── Nav pill buttons (Search/Categories/Ingredients/Developers/Login/etc.) ──
   Bigger, solid brand-green pills on the navy nav bar — replaced the earlier
   translucent "ghost" style, which depended on a light background to read and
   broke in dark mode (see .btn--ghost, still used elsewhere for buttons that
   sit on the page body rather than the nav). */
.nav__pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  background: var(--grad-green);
  color: #fff;
  border: none;
  border-radius: var(--radius-pill);
  padding: .6rem 1.3rem;
  font-size: .88rem;
  font-weight: 700;
  letter-spacing: -.01em;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0,0,0,.25);
  transition: transform var(--transition), box-shadow var(--transition), filter var(--transition);
  -webkit-tap-highlight-color: transparent;
}
.nav__pill:hover { filter: brightness(1.08); box-shadow: 0 4px 14px rgba(0,0,0,.3); text-decoration: none; }
.nav__pill:active { transform: scale(.97); }

/* Hamburger toggle — hidden on wide screens (nav fits on one row); shown only
   under the mobile breakpoint below, where .nav__actions becomes a dropdown. */
.nav__toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 34px;
  height: 34px;
  padding: 0;
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  flex-shrink: 0;
}
.nav__toggle:active { background: rgba(255,255,255,.12); }
.nav__toggle span {
  display: block;
  width: 20px;
  height: 2px;
  margin: 0 auto;
  background: #fff;
  border-radius: 2px;
  transition: transform var(--transition), opacity var(--transition);
}
.nav__toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* Language toggle — only ever appears on the navy nav bar, so (like
   .nav/.nav__logo) it's styled as a constant light-on-navy control instead
   of following the --clr-light/--clr-dark theme vars. */
.lang-toggle {
  display: flex;
  background: rgba(255,255,255,.12);
  border-radius: 20px;
  padding: 2px;
  gap: 2px;
}
.lang-toggle button {
  border: none;
  background: transparent;
  padding: .25rem .6rem;
  border-radius: 18px;
  font-size: .75rem;
  font-weight: 600;
  cursor: pointer;
  color: rgba(255,255,255,.75);
  transition: var(--transition);
}
.lang-toggle button.active {
  background: #fff;
  color: var(--clr-navy);
  box-shadow: 0 1px 3px rgba(0,0,0,.1);
}

/* ─── Buttons ──────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  border: none;
  border-radius: var(--radius-pill);
  padding: .6rem 1.4rem;
  font-size: .9rem;
  font-weight: 600;
  letter-spacing: -.01em;
  cursor: pointer;
  transition: transform var(--transition), box-shadow var(--transition), background var(--transition), border-color var(--transition);
  white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
}
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn:active:not(:disabled) { transform: scale(.97); }

.btn--primary   { background: var(--clr-dark);  color: var(--clr-white); }
.btn--primary:hover  { background: #0d1620; }
.btn--green     { background: var(--grad-green); color: var(--clr-white); box-shadow: 0 2px 8px rgba(30,168,96,.28); }
.btn--green:hover  { box-shadow: var(--shadow-green); transform: translateY(-1px); }
.btn--ghost     { background: rgba(255,255,255,.6); color: var(--clr-dark); border: 1.5px solid var(--clr-border); }
.btn--ghost:hover  { background: var(--clr-white); border-color: #cfd9dd; }
.btn--danger    { background: var(--clr-red);   color: var(--clr-white); }
.btn--sm        { padding: .42rem 1rem; font-size: .8rem; }
.btn--full      { width: 100%; }

/* ─── Cards ────────────────────────────────────────────────────────────────── */
.card {
  background: var(--clr-white);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.card__body { padding: 1.25rem; }

/* Product view's card: centred, capped narrower than the viewport on phones
   too (matches .container's side margins). */
.product-card { margin: 0 1rem; max-width: 680px; margin-left: auto; margin-right: auto; }

/* ─── Scanner view ─────────────────────────────────────────────────────────── */
#view-scanner { padding-top: 1.5rem; }

.scanner__title {
  text-align: center;
  font-size: 1.4rem;
  font-weight: 700;
  margin-bottom: .4rem;
}
.scanner__subtitle {
  text-align: center;
  color: var(--clr-mid);
  font-size: .9rem;
  margin-bottom: 1.5rem;
}

.scanner__viewport {
  position: relative;
  background: #000;
  border-radius: var(--radius-lg);
  overflow: hidden;
  aspect-ratio: 1 / 1;
  max-height: 360px;
}

.scanner__viewport video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Crosshair overlay */
.scanner__overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.scanner__frame {
  width: 65%;
  aspect-ratio: 2 / 1;
  border: 3px solid rgba(255,255,255,.8);
  border-radius: 8px;
  box-shadow: 0 0 0 9999px rgba(0,0,0,.45);
  position: relative;
}
.scanner__frame::before,
.scanner__frame::after {
  content: '';
  position: absolute;
  left: 0; right: 0;
  height: 2px;
  background: var(--clr-green);
  animation: scan-line 2s ease-in-out infinite;
}
@keyframes scan-line {
  0%,100% { top: 10%; }
  50% { top: 90%; }
}

.scanner__manual {
  margin-top: 1.25rem;
  display: flex;
  gap: .5rem;
}
.scanner__manual input {
  flex: 1;
  border: 1.5px solid var(--clr-border);
  border-radius: 30px;
  padding: .6rem 1rem;
  font-size: .95rem;
  outline: none;
  transition: border-color var(--transition);
}
.scanner__manual input:focus { border-color: var(--clr-green); }

/* Validation message for manual barcode entry (6-14 digits). */
.manual-error {
  margin: .5rem 0 0;
  text-align: center;
  font-size: .85rem;
  font-weight: 600;
  color: var(--clr-red);
}

.scanner__status {
  text-align: center;
  padding: .75rem;
  color: var(--clr-mid);
  font-size: .85rem;
  min-height: 2.5rem;
}

/* ─── Score ring ───────────────────────────────────────────────────────────── */
.score-ring-wrap {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 1.25rem;
  border-bottom: 1px solid var(--clr-border);
}

.score-ring {
  position: relative;
  flex-shrink: 0;
  width: 88px;
  height: 88px;
}
.score-ring svg { transform: rotate(-90deg); }
.score-ring__bg   { fill: none; stroke: var(--clr-light); stroke-width: 8; }
.score-ring__fill { fill: none; stroke-width: 8; stroke-linecap: round; transition: stroke-dashoffset .6s ease, stroke .4s; }
.score--green  .score-ring__fill { stroke: var(--clr-green); }
.score--yellow .score-ring__fill { stroke: var(--clr-yellow); }
.score--red    .score-ring__fill { stroke: var(--clr-red); }
/* Not yet analysed — deliberately neutral, never reads as a verdict */
.score--unknown .score-ring__fill { stroke: #cbd2d9; }
.score--unknown .score-ring__number { color: #9aa5b1; }

.score-ring__number {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3rem;
  font-weight: 800;
  color: var(--clr-dark);
}

.score-meta__label {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--clr-mid);
  margin-bottom: .4rem;
}
.score-meta__badge {
  display: inline-block;
  padding: .35rem 1rem;
  border-radius: 20px;
  font-size: .8rem;
  font-weight: 700;
  margin-bottom: .7rem;
}
.score--green  .score-meta__badge { background: var(--tint-green-bg);  color: var(--tint-green-fg); }
.score--yellow .score-meta__badge { background: var(--tint-yellow-bg); color: var(--tint-yellow-fg); }
.score--red    .score-meta__badge { background: var(--tint-red-bg);    color: var(--tint-red-fg); }
.score--unknown .score-meta__badge { background: var(--clr-light); color: var(--clr-mid); }

.score-meta__name  { font-size: 1.05rem; font-weight: 700; line-height: 1.4; margin-bottom: .3rem; }
.score-meta__bc    { font-size: .78rem; color: var(--clr-mid); margin-top: .2rem; }
.score-meta__desc  { font-size: .72rem; color: var(--clr-mid); margin-top: .5rem; line-height: 1.4; max-width: 220px; }

.pending-banner {
  background: var(--tint-yellow-bg);
  color: var(--tint-yellow-fg);
  padding: .6rem 1.25rem;
  font-size: .82rem;
  display: flex;
  align-items: center;
  gap: .5rem;
}

/* Product image */
.product__image {
  width: 100%;
  max-height: 220px;
  object-fit: contain;
  background: var(--clr-light);
}

/* ─── Ingredients list ──────────────────────────────────────────────────────── */
.section-title {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--clr-mid);
  padding: 1rem 1.25rem .5rem;
  font-weight: 600;
}

.ingredient-item {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  padding: .75rem 1.25rem;
  border-bottom: 1px solid var(--clr-border);
  transition: background var(--transition);
  color: inherit;
  text-decoration: none;
}
.ingredient-item:last-child { border-bottom: none; }
.ingredient-item:hover { background: var(--clr-bg); }
a.ingredient-item:hover .ingredient-item__name { text-decoration: underline; }

.ingredient-item__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
  margin-top: .35rem;
}
.hazard-none   .ingredient-item__dot { background: var(--clr-green); }
.hazard-low    .ingredient-item__dot { background: var(--clr-green); }
.hazard-medium .ingredient-item__dot { background: var(--clr-yellow); }
.hazard-high   .ingredient-item__dot { background: var(--clr-red); }

.ingredient-item__name { font-weight: 600; font-size: .9rem; }
.ingredient-item__meta { font-size: .78rem; color: var(--clr-mid); margin-top: .15rem; }

.ingredient-item__alert {
  margin-top: .4rem;
  background: var(--tint-red-bg);
  border-left: 3px solid var(--clr-red);
  padding: .4rem .6rem;
  border-radius: 0 6px 6px 0;
  font-size: .8rem;
  color: var(--tint-red-fg);
}
.ingredient-item__alert.medium {
  background: var(--tint-yellow-bg);
  border-color: var(--clr-yellow);
  color: var(--tint-yellow-fg);
}

/* ─── Category chips (product page → category.php interlink) ────────────────── */
.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  padding: .25rem 1.25rem 1rem;
}
.chip {
  display: inline-block;
  background: var(--clr-bg);
  border: 1px solid var(--clr-border);
  border-radius: 999px;
  padding: .3rem .8rem;
  font-size: .78rem;
  font-weight: 600;
  color: var(--clr-dark);
  text-decoration: none;
  transition: background var(--transition);
}
.chip:hover { background: var(--clr-light); }

/* ─── Reviews ───────────────────────────────────────────────────────────────── */
.review-summary {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .75rem 1.25rem;
  border-bottom: 1px solid var(--clr-border);
}
.review-summary__stars { color: #f1c40f; font-size: 1.1rem; letter-spacing: .05em; }
.review-summary__count { font-size: .85rem; color: var(--clr-mid); }

.review-card {
  padding: .9rem 1.25rem;
  border-bottom: 1px solid var(--clr-border);
}
.review-card:last-child { border-bottom: none; }
.review-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: .3rem;
}
.review-card__user { font-weight: 600; font-size: .85rem; }
.review-card__date { font-size: .75rem; color: var(--clr-mid); }
.review-card__stars { color: #f1c40f; font-size: .85rem; margin-bottom: .3rem; }
.review-card__text { font-size: .88rem; line-height: 1.5; color: var(--clr-dark); }

/* ─── Star rating input ─────────────────────────────────────────────────────── */
.star-input { display: flex; gap: .25rem; margin-bottom: .75rem; }
.star-input span {
  font-size: 2rem;
  cursor: pointer;
  color: #ddd;
  transition: color .1s;
  line-height: 1;
}
.star-input span.active,
.star-input span:hover,
.star-input span:hover ~ span { color: #f1c40f; }
/* Reverse hover trick */
.star-input { flex-direction: row-reverse; justify-content: flex-end; }
.star-input span:hover,
.star-input span:hover ~ span { color: #f1c40f; }

/* ─── Submit form ───────────────────────────────────────────────────────────── */
.form-group { margin-bottom: 1rem; }
.form-group label { display: block; font-size: .85rem; font-weight: 600; margin-bottom: .35rem; color: var(--clr-dark); }
.form-group input[type="text"],
.form-group textarea {
  width: 100%;
  border: 1.5px solid var(--clr-border);
  border-radius: var(--radius);
  padding: .65rem .9rem;
  font-size: .95rem;
  font-family: var(--font);
  outline: none;
  transition: border-color var(--transition);
  background: var(--clr-white);
}
.form-group input:focus,
.form-group textarea:focus { border-color: var(--clr-green); }
.form-group textarea { resize: vertical; min-height: 80px; }

.upload-zone {
  border: 2px dashed var(--clr-border);
  border-radius: var(--radius);
  padding: 1.5rem;
  text-align: center;
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.upload-zone:hover,
.upload-zone.drag-over { border-color: var(--clr-green); background: #f0faf5; }
.upload-zone input { display: none; }
.upload-zone__icon { font-size: 2rem; margin-bottom: .4rem; }
.upload-zone__text { font-size: .85rem; color: var(--clr-mid); }
.upload-zone__preview { margin-top: .75rem; max-height: 140px; object-fit: cover; border-radius: 8px; }

/* ─── Modal (auth) ─────────────────────────────────────────────────────────── */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.5);
  z-index: 200;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 1rem;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition);
}
.modal-backdrop.open { opacity: 1; pointer-events: auto; }

.modal {
  background: var(--clr-white);
  border-radius: var(--radius-lg) var(--radius-lg) var(--radius) var(--radius);
  width: 100%;
  max-width: 440px;
  padding: 1.75rem 1.5rem 1.5rem;
  transform: translateY(30px);
  transition: transform var(--transition);
  max-height: 90dvh;
  overflow-y: auto;
}
.modal-backdrop.open .modal { transform: translateY(0); }

.modal__title { font-size: 1.25rem; font-weight: 700; margin-bottom: 1.25rem; }
.modal__switch { font-size: .85rem; text-align: center; margin-top: 1rem; color: var(--clr-mid); }
.modal__switch a { color: var(--clr-green); cursor: pointer; }
.modal__close {
  position: absolute;
  top: 1rem; right: 1rem;
  background: var(--clr-light);
  border: none;
  border-radius: 50%;
  width: 32px; height: 32px;
  font-size: 1.1rem;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}

/* ─── Toast notifications ───────────────────────────────────────────────────── */
#toast-container {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 300;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  align-items: center;
  pointer-events: none;
}
.toast {
  background: var(--clr-dark);
  color: var(--clr-white);
  padding: .65rem 1.25rem;
  border-radius: 30px;
  font-size: .88rem;
  font-weight: 500;
  box-shadow: var(--shadow-lg);
  animation: toast-in .25s ease;
  pointer-events: none;
  white-space: nowrap;
}
.toast--error { background: var(--clr-red); }
.toast--success { background: var(--clr-green); }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } }

/* ─── Install prompt ────────────────────────────────────────────────────────── */
.install-banner {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  background: var(--clr-white);
  border-top: 1px solid var(--clr-border);
  padding: 1rem 1.25rem;
  display: flex;
  align-items: center;
  gap: 1rem;
  z-index: 150;
  box-shadow: 0 -4px 16px rgba(0,0,0,.1);
  transform: translateY(0);
  transition: transform var(--transition);
}
.install-banner.hidden { transform: translateY(100%); }
.install-banner__icon { font-size: 2rem; flex-shrink: 0; }
.install-banner__text h3 { font-size: .95rem; margin-bottom: .1rem; }
.install-banner__text p  { font-size: .8rem; color: var(--clr-mid); }
.install-banner__actions { display: flex; gap: .5rem; flex-shrink: 0; margin-left: auto; }

/* ─── Skeleton loader ───────────────────────────────────────────────────────── */
.skeleton {
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: shimmer 1.4s infinite;
  border-radius: 6px;
}
@keyframes shimmer { to { background-position: -200% 0; } }

/* ─── View management ───────────────────────────────────────────────────────── */
.view { display: none; }
.view.active { display: block; }

/* ─── Utilities ─────────────────────────────────────────────────────────────── */
.text-center { text-align: center; }
.mt-1  { margin-top: .5rem; }
.mt-2  { margin-top: 1rem; }
.mt-3  { margin-top: 1.5rem; }
.mb-1  { margin-bottom: .5rem; }
.mb-2  { margin-bottom: 1rem; }
.gap-1 { gap: .5rem; }
.flex  { display: flex; }
.flex-col { flex-direction: column; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.text-muted { color: var(--clr-mid); }
.text-sm { font-size: .85rem; }
.font-bold { font-weight: 700; }
.w-full { width: 100%; }

/* ─── Responsive ────────────────────────────────────────────────────────────── */
@media (min-width: 480px) {
  .scanner__viewport { max-height: 420px; }
}

/* Desktop/tablet: previously every view (scanner/product/submit) and the nav
   bar stayed capped at a 680px phone-width column no matter the viewport, so
   a desktop visitor just saw that column stranded in the middle of the page.
   Widen the nav to match the landing page's wider desktop measure (see
   landing.css), and give the app views themselves a bit more room — kept
   narrower than the landing page's 1080px since these are single-column
   scanner/product/form content, not a multi-card layout, and a card that
   wide would stretch line lengths past a comfortable reading measure. */
@media (min-width: 900px) {
  .nav__inner { max-width: 1080px; }
  .container  { max-width: 760px; }
  .product-card { max-width: 760px; }
}

/* Nav: below this width, "Search · Ingredients · EN/BG · Login/Profile ·
   Logout" no longer fits one row without overflowing/squashing — collapse it
   into a hamburger-triggered dropdown instead. */
@media (max-width: 640px) {
  .nav__toggle { display: flex; }

  .nav__actions {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: .5rem;
    background: rgba(21,33,46,.98);
    padding: .75rem 1rem 1rem;
    border-bottom: 1px solid rgba(255,255,255,.08);
    box-shadow: var(--shadow-lg);
  }
  .nav__actions.nav__actions--open { display: flex; }

  .nav__actions .btn, .nav__actions .nav__pill { width: 100%; }
  .nav__actions .lang-toggle { align-self: center; }
  .nav__actions #user-menu {
    flex-direction: column;
    align-items: stretch !important;
    gap: .5rem !important;
  }
  .nav__actions #user-menu .btn,
  .nav__actions #user-menu button { width: 100%; }
  #nav-username { text-align: center; padding: .25rem 0; }
}

/* ─── Bottom tab bar (mobile) ────────────────────────────────────────────────
   Core app actions (scan/search/categories/ingredients/profile) reachable
   with one thumb, instead of buried behind the hamburger. Desktop keeps the
   top nav row only — the tab bar would just duplicate it with no ergonomic
   benefit on a pointer-driven layout. */
.tab-bar {
  display: none;
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 120;
  background: rgba(255,255,255,.92);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  border-top: 1px solid var(--clr-border);
  box-shadow: 0 -2px 12px rgba(16,40,34,.06);
  padding-bottom: env(safe-area-inset-bottom, 0);
}
.tab-bar__item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .15rem;
  padding: .45rem .25rem calc(.4rem + env(safe-area-inset-bottom, 0));
  color: var(--clr-mid);
  text-decoration: none;
  font-size: .68rem;
  font-weight: 600;
  -webkit-tap-highlight-color: transparent;
}
.tab-bar__item:hover { text-decoration: none; color: var(--clr-mid); }
.tab-bar__icon { font-size: 1.25rem; line-height: 1; }
.tab-bar__item.is-active { color: var(--clr-green); }

@media (max-width: 640px) {
  .tab-bar { display: flex; }
  /* Keep page content (and other fixed bars) clear of the tab bar. */
  body { padding-bottom: calc(60px + env(safe-area-inset-bottom, 0)); }
  #toast-container { bottom: calc(60px + 1rem + env(safe-area-inset-bottom, 0)); }
  .install-banner { bottom: calc(60px + env(safe-area-inset-bottom, 0)); }
  .install-banner.hidden { transform: translateY(150%); }
}

/* ─── Score class for admin pages ───────────────────────────────────────────── */
.score--green  { color: var(--clr-green); }
.score--yellow { color: var(--clr-yellow); }
.score--red    { color: var(--clr-red); }
/* Nothing linked yet — greyed out, matching the "not analysed" public state. */
.score--unknown { color: #9aa5b1; }

/* ─── Secondary scores (Nutrition + Mirella) ────────────────────────────────── */
.subscores {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--clr-border);
  border-bottom: 1px solid var(--clr-border);
}
.subscore {
  background: var(--clr-white);
  padding: .9rem 1rem 1rem;
  text-align: center;
}
.subscore__num {
  font-size: 1.5rem;
  font-weight: 800;
  line-height: 1;
  margin-bottom: .4rem;
}
.subscore__bar {
  height: 6px;
  border-radius: 4px;
  background: var(--clr-light);
  overflow: hidden;
  margin-bottom: .5rem;
}
.subscore__fill {
  height: 100%;
  width: 0;
  border-radius: 4px;
  transition: width .6s ease, background .4s;
}
.subscore__title {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--clr-mid);
  font-weight: 600;
}
.subscore__label {
  font-size: .82rem;
  font-weight: 700;
  margin-top: .15rem;
}
.subscore__desc {
  font-size: .75rem;
  color: var(--clr-mid);
  margin-top: .5rem;
  line-height: 1.4;
  font-weight: 500;
}
/* Colour states for the number + bar fill + label */
.subscore.score--green  .subscore__num,
.subscore.score--green  .subscore__label { color: var(--clr-green); }
.subscore.score--green  .subscore__fill  { background: var(--clr-green); }
.subscore.score--yellow .subscore__num,
.subscore.score--yellow .subscore__label { color: #c98a00; }
.subscore.score--yellow .subscore__fill  { background: var(--clr-yellow); }
.subscore.score--red    .subscore__num,
.subscore.score--red    .subscore__label { color: var(--clr-red); }
.subscore.score--red    .subscore__fill  { background: var(--clr-red); }
.subscore.score--unknown .subscore__num,
.subscore.score--unknown .subscore__label { color: #9aa5b1; }
.subscore.score--unknown .subscore__fill  { background: #cbd2d9; }

/* ─── Hidden utility ────────────────────────────────────────────────────────── */
.hidden { display: none !important; }

/* ─── Inline icons (Lucide, via icon()/svgIcon() helpers) ────────────────────
   stroke/fill="currentColor" means these inherit whatever color rule already
   applies to their container — no per-icon or per-theme overrides needed. */
.icon {
  display: inline-block;
  vertical-align: -0.15em;
  flex-shrink: 0;
}

/* ─── Allergen notice ────────────────────────────────────────────────────────
   Deliberately NOT styled like .ingredient-item__alert (the red/amber health
   warning). An allergen is not a health hazard — almonds are nutritious and also
   dangerous to a nut-allergic person. Blue = "information you may need", not
   "this is bad for you". The two can appear together on one ingredient. */
.ingredient-item__allergen {
  margin-top: .3rem;
  padding: .3rem .55rem;
  border-radius: 6px;
  background: var(--tint-blue-bg);
  color: var(--tint-blue-fg);
  font-size: .76rem;
  font-weight: 600;
  display: inline-block;
}

/* ─── Contribute CTA (product has no ingredients-label photo) ──────────────── */
.contribute-cta {
  background: var(--tint-yellow-bg);
  border-radius: var(--radius);
  padding: .9rem 1rem;
  margin: 0 0 1rem;
  text-align: center;
}
.contribute-cta p {
  margin: 0 0 .6rem;
  font-size: .85rem;
  color: var(--tint-yellow-fg);
}

/* ─── Footer logo (smaller variant of .nav__logo) ───────────────────────────── */
.site-footer__logo { font-size: 1.1rem; }

/* ─── View containers: scanner/product views share the same top padding ────── */
.container--pad-top { padding-top: 1.25rem; }

/* ─── Scanner viewport internals ─────────────────────────────────────────────
   The <video> itself needs no rule here — .scanner__viewport video already
   covers width/height/object-fit/display. */
.scanner__container { width: 100%; height: 100%; }

/* ─── Camera access denied state ─────────────────────────────────────────────*/
.camera-denied { text-align: center; padding: 1.75rem 1rem 1rem; }
.camera-denied__icon { font-size: 3rem; margin-bottom: .75rem; line-height: 1; }
.camera-denied__text { color: var(--clr-mid); margin-bottom: 1.25rem; font-size: .92rem; }
.camera-denied__retry { margin-bottom: .75rem; }
.camera-denied__hint { font-size: .77rem; color: var(--clr-mid); }

/* ─── Allergen warning banner (danger variant of .pending-banner) ───────────── */
.pending-banner--danger { background: var(--tint-red-bg); color: var(--tint-red-fg); }

/* ─── Review form / report section shared block spacing ─────────────────────── */
#review-form, #report-section { padding: 1.25rem; border-top: 1px solid var(--clr-border); }
.form-group--tight { margin-bottom: .5rem; }

/* ─── Report-an-inconsistency toggle + form ─────────────────────────────────── */
.report-toggle {
  display: flex;
  align-items: center;
  gap: .5rem;
  cursor: pointer;
  color: var(--clr-mid);
  font-size: .84rem;
  user-select: none;
}
.report-toggle__icon { font-size: 1rem; }
#report-chevron { margin-left: auto; }
#report-form-wrap { margin-top: .9rem; }
.report-form__title { margin: 0 0 .6rem; font-size: .9rem; }
#report-message {
  width: 100%;
  border: 1.5px solid var(--clr-border);
  border-radius: var(--radius-sm);
  padding: .65rem .8rem;
  font-size: .88rem;
  font-family: inherit;
  resize: vertical;
}
.report-photo-group { margin-top: .6rem; }
.report-photo-group label { display: block; margin-bottom: .35rem; }
#btn-submit-report { margin-top: .6rem; }

/* ─── Generic vertical spacer (end-of-view breathing room) ──────────────────── */
.spacer-2 { height: 2rem; }

/* ─── Submit new product view ────────────────────────────────────────────────── */
.submit-back-btn { margin: .75rem 0; }
.submit-title { margin-bottom: .4rem; }
#submit-intro { margin-bottom: 1.25rem; }
.submit-barcode-line { font-size: .85rem; margin-bottom: 1.25rem; }
.code-chip { background: var(--clr-light); padding: .2rem .5rem; border-radius: 4px; }
#submit-status { text-align: center; min-height: 1.5rem; }

/* ─── Focus visibility (WCAG 2.4.7) ──────────────────────────────────────────
   Earlier rules set `outline: none` and lean on a border-colour change alone,
   which is easy to miss — and anything that is not an input got no focus
   indicator at all, so keyboard users could not tell where they were. Declared
   last so it wins the cascade. :focus-visible means pointer users never see it. */
:focus-visible {
  outline: 3px solid var(--clr-green);
  outline-offset: 2px;
}
.scanner__manual input:focus-visible,
.form-group input:focus-visible,
.form-group textarea:focus-visible {
  outline: 3px solid var(--clr-green);
  outline-offset: 1px;
}
/* The upload zone is a role="button" div — give its focus ring room to breathe. */
.upload-zone:focus-visible {
  outline: 3px solid var(--clr-green);
  outline-offset: 4px;
  border-style: solid;
}
