:root {
  --primary: #34d399; /* pastel green */
  --primary-hover: #059669;
  --bg-color: #ffffff;
  --surface-color: #f8fafc;
  --surface-hover: #f1f5f9;
  --text-main: #1e293b;
  --text-muted: #64748b;
  --border-color: #e2e8f0;
  --accent: #60a5fa; /* pastel blue */
  --radius: 12px;
  --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  --header-bg: rgba(255, 255, 255, 0.9);
  --card-bg: #ffffff;
  --breakdown-bg: #f8fafc;
  --input-bg: #ffffff;
  --table-header-bg: rgba(0, 0, 0, 0.02);
  --font-display: 'Space Grotesk', 'Inter', system-ui, -apple-system, sans-serif;
}

:root[data-theme="dark"] {
  --bg-color: #0f172a; /* Sleek slate-900 */
  --surface-color: #1e293b; /* slate-800 */
  --surface-hover: #334155; /* slate-700 */
  --text-main: #f8fafc; /* slate-50 */
  --text-muted: #94a3b8; /* slate-400 */
  --border-color: #334155; /* slate-700 */
  --accent: #60a5fa; /* pastel blue */
  --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.5), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
  --header-bg: rgba(15, 23, 42, 0.9);
  --card-bg: #1e293b;
  --breakdown-bg: #0f172a;
  --input-bg: #1e293b;
  --table-header-bg: rgba(255, 255, 255, 0.05);
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
}

html {
  /* Stop iOS Safari from inflating text when a phone is rotated to landscape */
  -webkit-text-size-adjust: 100%;
}

body {
  background-color: var(--bg-color);
  color: var(--text-main);
  line-height: 1.6;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  transition: background-color 0.3s ease, color 0.3s ease;
}

img,
video,
iframe {
  max-width: 100%;
}

header {
  background-color: var(--header-bg);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border-color);
  position: sticky;
  top: 0;
  z-index: 100;
  padding: 1rem 2rem;
  padding-left: max(2rem, env(safe-area-inset-left));
  padding-right: max(2rem, env(safe-area-inset-right));
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  transition: background-color 0.3s ease, border-color 0.3s ease;
}

.logo {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--primary);
  text-decoration: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}

.logo svg {
  flex-shrink: 0;
}

/* Hamburger — hidden until the nav collapses at the --bp-nav breakpoint */
.nav-toggle {
  display: none;
  background: transparent;
  border: 1px solid var(--border-color);
  color: var(--text-main);
  border-radius: 10px;
  width: 42px;
  height: 42px;
  cursor: pointer;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.nav-toggle.open {
  border-color: var(--primary);
  color: var(--primary);
}

nav ul {
  list-style: none;
  display: flex;
  gap: 2rem;
}

nav a {
  color: var(--text-muted);
  text-decoration: none;
  font-weight: 500;
  transition: color 0.2s;
}

nav a:hover, nav a.active {
  color: var(--text-main);
}

main {
  flex: 1;
  max-width: 1200px;
  margin: 0 auto;
  padding: 3rem 2rem;
  padding-left: max(2rem, env(safe-area-inset-left));
  padding-right: max(2rem, env(safe-area-inset-right));
  width: 100%;
}

.hero {
  padding: clamp(1.5rem, 7vw, 4rem) 0;
}

.hero.hero-split {
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: center;
  text-align: left;
}

.hero h1 {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.01em;
  font-size: clamp(2rem, 6vw, 3.25rem);
  line-height: 1.12;
  margin-bottom: 1.5rem;
  color: var(--text-main);
}

.hero p {
  font-size: clamp(1rem, 3.6vw, 1.25rem);
  color: var(--text-muted);
  max-width: 600px;
  margin: 0 0 2.5rem;
}

.hero-actions {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 2rem;
}

/* ── Homepage hero gauge card ─────────────────────────────────────────────── */
/* Issue #22: this is an <a> (links to the sample recipe's calculator page) --
   neutralize link defaults and add the same hover lift as .card so it reads
   as clickable. */
.hero-gauge-card {
  background: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  padding: 1.75rem 1.5rem 1.5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-decoration: none;
  color: inherit;
  transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s;
}

.hero-gauge-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow);
  border-color: var(--primary);
}

.hero-gauge-caption {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-bottom: 0.75rem;
}

.hero-gauge-caption strong {
  color: var(--text-main);
}

#hero-gauge {
  width: 220px;
  height: 140px;
}

.hero-gauge-readout {
  text-align: center;
  margin-top: -0.4rem;
}

.hero-gauge-score {
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  font-size: 2.6rem;
  font-weight: 700;
  line-height: 1;
}

.hero-gauge-unit {
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: 0.3rem;
}

.hero-gauge-tier {
  display: inline-block;
  margin-top: 0.6rem;
  font-size: 0.8rem;
  font-weight: 700;
}

@media (max-width: 860px) {
  .hero.hero-split {
    grid-template-columns: 1fr;
    text-align: center;
  }
  .hero .hero-actions {
    justify-content: center;
  }
  .hero p {
    margin: 0 auto 2.5rem;
  }
}

/* ── Shared page-level typography ─────────────────────────────────────────── */
.page-title {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.01em;
  font-size: clamp(1.85rem, 6.5vw, 2.5rem);
  line-height: 1.15;
  margin-bottom: 1rem;
}

.page-subtitle {
  color: var(--text-muted);
  font-size: clamp(0.98rem, 3.4vw, 1.1rem);
}

/* Used to be a green-to-blue gradient clip on every secondary page title --
   replaced with a solid brand color so the gradient-hero look (the one AI
   "eco SaaS" cliche we were most often getting compared to) isn't repeated
   on every page. */
.gradient-title {
  color: var(--primary-hover);
}

/* Long-form content cards: roomy on desktop, tight on a phone */
.section-card {
  padding: clamp(1.25rem, 4.5vw, 3rem);
}

/* Wide content (reference tables) scrolls inside its own box rather than
   pushing the page sideways. */
.table-scroll {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.btn {
  display: inline-block;
  background-color: var(--primary);
  color: white;
  padding: 0.75rem 1.5rem;
  border-radius: var(--radius);
  text-decoration: none;
  font-weight: 600;
  transition: all 0.2s;
  border: none;
  cursor: pointer;
  font-size: 1rem;
}

.btn:hover {
  background-color: var(--primary-hover);
  transform: translateY(-2px);
  box-shadow: var(--shadow);
}

.btn:disabled,
.btn-outline:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

.btn-outline {
  background-color: transparent;
  border: 1px solid var(--border-color);
  color: var(--text-main);
}

.btn-outline:hover {
  background-color: var(--surface-color);
  border-color: var(--text-muted);
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 2rem;
  margin-top: 2rem;
}

.card {
  background-color: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  overflow: hidden;
  transition: transform 0.3s, box-shadow 0.3s, background-color 0.3s ease, border-color 0.3s ease;
  display: flex;
  flex-direction: column;
}

.card:hover {
  border-color: var(--primary);
}

.card-img {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

.meal-label {
  position: absolute;
  top: 1rem;
  right: 1rem;
  background-color: var(--primary);
  color: white;
  padding: 0.25rem 0.75rem;
  border-radius: 99px;
  font-size: 0.75rem;
  font-weight: 600;
  box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}

.card-content {
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  flex: 1;
}

.card-title {
  font-size: 1.25rem;
  margin-bottom: 0.5rem;
}

.card-desc {
  color: var(--text-muted);
  font-size: 0.9rem;
  margin-bottom: 1.5rem;
  flex: 1;
}

.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.tag {
  background-color: rgba(59, 130, 246, 0.1);
  color: var(--accent);
  padding: 0.25rem 0.75rem;
  border-radius: 99px;
  font-size: 0.75rem;
  font-weight: 600;
}

/* Tabs */
.tabs {
  display: flex;
  gap: 1rem;
  margin-bottom: 2rem;
  border-bottom: 1px solid var(--border-color);
  padding-bottom: 1rem;
  overflow-x: auto;
}

.tab-btn {
  background: transparent;
  border: 1px solid var(--border-color);
  color: var(--text-muted);
  padding: 0.5rem 1rem;
  border-radius: 99px;
  cursor: pointer;
  font-weight: 500;
  transition: all 0.2s;
  white-space: nowrap;
}

.tab-btn:hover {
  background-color: var(--surface-color);
  color: var(--text-main);
}

.tab-btn.active {
  background-color: var(--primary);
  color: white;
  border-color: var(--primary);
}

.unit-toggle {
  display: inline-flex;
  flex-shrink: 0;
  border: 1px solid var(--border-color);
  border-radius: 99px;
  padding: 0.2rem;
  gap: 0.2rem;
}

.unit-toggle-btn {
  background: transparent;
  border: none;
  color: var(--text-muted);
  padding: 0.35rem 0.9rem;
  border-radius: 99px;
  cursor: pointer;
  font-weight: 600;
  font-size: 0.8rem;
  white-space: nowrap;
  transition: all 0.2s;
}

.unit-toggle-btn:hover {
  color: var(--text-main);
}

.unit-toggle-btn.active {
  background-color: var(--primary);
  color: white;
}

/* Calculator Grid */
.calculator-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3rem;
  background-color: var(--surface-color);
  border-radius: var(--radius);
  padding: 2.5rem;
  border: 1px solid var(--border-color);
}

.recipe-info img {
  width: 100%;
  height: 250px;
  object-fit: cover;
  border-radius: var(--radius);
  margin-bottom: 1.5rem;
}

/* Metrics Accordion */
.metrics-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.metric-item {
  background-color: var(--card-bg);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  overflow: hidden;
  transition: background-color 0.3s ease, border-color 0.3s ease;
}

.metric-header {
  padding: 1.25rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  cursor: pointer;
  transition: background-color 0.2s;
}

.metric-header:hover {
  background-color: var(--surface-hover);
}

.metric-title {
  font-weight: 600;
  font-size: 1.1rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.metric-value {
  font-weight: 700;
  color: var(--accent);
  font-size: 1.1rem;
}

.metric-breakdown {
  display: none;
  padding: 1.25rem;
  border-top: 1px solid var(--border-color);
  background-color: var(--breakdown-bg);
  transition: background-color 0.3s ease, border-color 0.3s ease;
}

.metric-item.open .metric-breakdown {
  display: block;
}

.metric-item.open .metric-header {
  background-color: rgba(59, 130, 246, 0.1);
  border-bottom-color: transparent;
}

.breakdown-row {
  display: flex;
  justify-content: space-between;
  padding: 0.5rem 0;
  border-bottom: 1px dashed var(--border-color);
  font-size: 0.9rem;
}

.breakdown-row:last-child {
  border-bottom: none;
}

.verdict-box {
  padding: 1.5rem;
  background-color: rgba(59, 130, 246, 0.1);
  border-left: 4px solid var(--accent);
}

/* Form Styles */
.form-control {
  width: 100%;
  background-color: var(--input-bg);
  border: 1px solid var(--border-color);
  color: var(--text-main);
  padding: 0.75rem 1rem;
  border-radius: var(--radius);
  font-size: 1rem;
  transition: border-color 0.2s, background-color 0.3s ease, color 0.3s ease;
}

.form-control:focus {
  outline: none;
  border-color: var(--primary);
  background-color: var(--input-bg);
  box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.2);
}

footer {
  text-align: center;
  padding: 2rem;
  border-top: 1px solid var(--border-color);
  color: var(--text-muted);
  font-size: 0.875rem;
}

.loading {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 200px;
  font-size: 1.25rem;
  color: var(--text-muted);
}

.spinner {
  width: 40px;
  height: 40px;
  border: 3px solid rgba(16, 185, 129, 0.3);
  border-radius: 50%;
  border-top-color: var(--primary);
  animation: spin 1s ease-in-out infinite;
  margin-bottom: 1rem;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.scan-spinner {
  display: inline-block;
  width: 16px;
  height: 16px;
  border: 2px solid rgba(16, 185, 129, 0.3);
  border-radius: 50%;
  border-top-color: var(--primary);
  animation: spin 1s ease-in-out infinite;
  flex-shrink: 0;
}

/* Results Layout */
.results-layout-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2rem;
  margin-bottom: 2rem;
}

@media (max-width: 768px) {
  .results-layout-grid {
    grid-template-columns: 1fr;
  }
}

/* Speedometer / Gauge - Even More Compact */
.gauge-container {
  position: relative;
  width: 200px;
  height: 100px;
  margin: 0 auto;
  overflow: hidden;
}

.gauge-base {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  background: conic-gradient(
    from 270deg,
    #10b981 0deg,      /* Green */
    #f59e0b 90deg,     /* Yellow/Orange */
    #ef4444 180deg     /* Red */
  );
  mask: radial-gradient(circle, transparent 60%, black 61%);
  -webkit-mask: radial-gradient(circle, transparent 60%, black 61%);
}

.gauge-needle {
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 3px;
  height: 80px;
  background: var(--text-main);
  transform-origin: bottom center;
  transform: translateX(-50%) rotate(-90deg);
  transition: transform 1.5s cubic-bezier(0.4, 0, 0.2, 1);
  border-radius: 4px;
  z-index: 2;
}

.gauge-needle::after {
  content: '';
  position: absolute;
  bottom: -4px;
  left: 50%;
  transform: translateX(-50%);
  width: 8px;
  height: 8px;
  background: var(--text-main);
  border-radius: 50%;
}

/* Nested Breakdown Styles */
.breakdown-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.75rem 0.5rem;
  border-bottom: 1px solid var(--border-color);
  cursor: pointer;
  transition: background 0.2s;
  border-radius: 6px;
  gap: 0.5rem;
}

.breakdown-row:hover {
  background-color: var(--surface-hover);
}

.breakdown-row-active {
  background-color: var(--surface-color);
}

.nested-breakdown {
  display: none;
  background-color: var(--surface-color);
  padding: 0.75rem 1rem;
  border-radius: 0 0 8px 8px;
  margin-top: -1px;
  border: 1px solid var(--border-color);
  border-top: none;
}

.nested-item {
  display: flex;
  justify-content: space-between;
  font-size: 0.85rem;
  padding: 0.25rem 0;
  color: var(--text-muted);
}

/* Mobile rules live in the RESPONSIVE section at the end of this file. */

/* Ingredient List with Impact */
.ingredient-list-impact {
  list-style: none;
}

.ingredient-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.75rem 0;
  border-bottom: 1px dashed var(--border-color);
  gap: 1rem;
}

.ingredient-item:last-child {
  border-bottom: none;
}

.ingredient-info {
  display: flex;
  flex: 1;
  align-items: center;
}

.ingredient-name {
  font-weight: 600;
}

.ingredient-qty {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--accent);
  white-space: nowrap;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}


.error-message, .warning-message {
  padding: 1rem;
  border-radius: var(--radius);
  margin-bottom: 1.5rem;
  display: none;
  font-weight: 500;
  font-size: 0.95rem;
  border: 1px solid transparent;
}

.error-message {
  background-color: #fef2f2;
  color: #991b1b;
  border-color: #fecaca;
}

/* Recovery actions shown under a failed URL fetch. Inherits the surrounding
   message's colour so it reads correctly in whichever palette wraps it. */
.error-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 0.85rem;
}

.error-actions a,
.error-actions button {
  font: inherit;
  font-weight: 600;
  color: inherit;
  background: transparent;
  border: 1px solid currentColor;
  border-radius: var(--radius);
  padding: 0.45rem 0.9rem;
  cursor: pointer;
  text-decoration: none;
  opacity: 0.9;
}

.error-actions a:hover,
.error-actions button:hover {
  opacity: 1;
  background: rgba(0, 0, 0, 0.06);
}

.warning-message {
  background-color: #fffbeb;
  color: #92400e;
  border-color: #fde68a;
}

/* Sticky Summary Bar */
.sticky-summary {
  position: sticky;
  /* nav.js publishes the header's measured height, which changes with the
     breakpoint and once the auth widget loads. 73px is the desktop fallback. */
  top: var(--header-h, 73px);
  z-index: 90;
  background-color: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  margin-bottom: 1.5rem;
  padding: 0.75rem 1.5rem;
  box-shadow: var(--shadow);
  display: flex;
  align-items: center;
  transition: all 0.3s ease;
}

.sticky-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  gap: 1rem;
}

.sticky-title {
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--text-main);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
}

.sticky-score-group {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.sticky-score-label {
  font-size: 0.8rem;
  color: var(--text-muted);
  font-weight: 600;
}

.sticky-score-val {
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--primary);
}

.sticky-score-original {
  font-size: 0.8rem;
  color: var(--text-muted);
  font-weight: 500;
}

.score-original {
  font-size: 0.8rem;
  color: var(--text-muted);
  font-weight: 500;
  margin-top: 0.25rem;
}

.score-delta {
  display: inline-block;
  font-size: 0.85rem;
  font-weight: 700;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  margin-left: 0.35rem;
  vertical-align: middle;
}

.score-delta.delta-improved {
  color: #059669;
  background-color: rgba(16, 185, 129, 0.15);
}

.score-delta.delta-worsened {
  color: #dc2626;
  background-color: rgba(239, 68, 68, 0.12);
}

.equivalents-row {
  display: flex;
  gap: 1.5rem;
  justify-content: center;
  flex-wrap: wrap;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--text-muted);
  align-items: center;
}

.equiv-item {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}

.equiv-info-link {
  color: var(--text-muted);
  text-decoration: none;
  opacity: 0.7;
  transition: opacity 0.2s;
  display: flex;
  align-items: center;
}

.equiv-info-link:hover {
  opacity: 1;
}

.feedback-cta {
  margin-top: 1.5rem;
  padding: 1.5rem;
}

.feedback-cta-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1.5rem;
  flex-wrap: wrap;
}

.feedback-btn {
  white-space: nowrap;
  flex-shrink: 0;
}

.feedback-iframe {
  width: 100%;
  min-height: 520px;
  border: none;
  border-radius: var(--radius);
  background: var(--surface-color);
}

.feedback-setup-notice {
  padding: 1rem 1.25rem;
  border-radius: var(--radius);
  border: 1px solid var(--border-color);
  background: var(--surface-color);
  color: var(--text-muted);
  line-height: 1.6;
}

.feedback-setup-notice code {
  font-size: 0.85rem;
  background: var(--bg-color);
  padding: 0.1rem 0.35rem;
  border-radius: 4px;
}

.info-icon {
  color: var(--text-muted);
  display: flex;
  align-items: center;
  transition: color 0.2s;
}

.info-icon:hover {
  color: var(--accent);
}

/* Theme Toggle Button Styling */
.theme-toggle-btn {
  background: transparent;
  border: 1px solid var(--border-color);
  color: var(--text-main);
  padding: 0.5rem;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  outline: none;
}

.theme-toggle-btn:hover {
  background-color: var(--surface-hover);
  border-color: var(--text-muted);
  transform: scale(1.05);
}

.theme-toggle-btn svg {
  width: 20px;
  height: 20px;
  transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

.theme-toggle-btn:active svg {
  transform: rotate(45deg) scale(0.9);
}

header nav {
  display: flex;
  align-items: center;
}

/* ── Smart Swap Suggestion Cards ──────────────────────────────────────────── */
.suggestion-card {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  background-color: var(--card-bg);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  padding: 0.85rem 1rem;
  margin-bottom: 0.75rem;
  transition: border-color 0.2s, box-shadow 0.2s, background-color 0.3s ease;
  animation: fadeSlideIn 0.3s ease;
}

@keyframes fadeSlideIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

.suggestion-card:hover {
  border-color: var(--primary);
  box-shadow: 0 0 0 2px rgba(52, 211, 153, 0.15);
}

.suggestion-info {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  flex: 1;
  min-width: 0;
}

.suggestion-swap {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  flex-wrap: wrap;
}

.suggestion-old {
  font-weight: 600;
  color: var(--text-main);
  text-decoration: line-through;
  opacity: 0.65;
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
  max-width: 120px;
}

.suggestion-new {
  font-weight: 700;
  color: var(--primary);
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
  max-width: 160px;
}

.suggestion-meta {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.suggestion-tier {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text-muted);
  background-color: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: 99px;
  padding: 0.1rem 0.55rem;
  white-space: nowrap;
}

.suggestion-pts {
  font-size: 0.8rem;
  font-weight: 700;
  color: #10b981;
  white-space: nowrap;
}

.suggestion-actions {
  display: flex;
  gap: 0.4rem;
  flex-shrink: 0;
}

.btn-accept {
  background-color: #10b981;
  color: white;
  border: none;
  padding: 0.4rem 0.85rem;
  border-radius: 8px;
  font-size: 0.82rem;
  font-weight: 700;
  cursor: pointer;
  transition: background-color 0.2s, transform 0.1s;
}

.btn-accept:hover {
  background-color: #059669;
  transform: scale(1.04);
}

.btn-decline {
  background-color: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border-color);
  padding: 0.4rem 0.6rem;
  border-radius: 8px;
  font-size: 0.82rem;
  font-weight: 700;
  cursor: pointer;
  transition: background-color 0.2s, color 0.2s;
}

.btn-decline:hover {
  background-color: #fef2f2;
  color: #ef4444;
  border-color: #fca5a5;
}

.suggestions-accepted {
  margin-top: 0.5rem;
  border-top: 1px dashed var(--border-color);
  padding-top: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.suggestion-accepted-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.85rem;
  color: var(--text-muted);
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* ── Beta badge & input info ─────────────────────────────────────────────── */
.beta-badge {
  display: inline-block;
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: #f59e0b;
  color: #1a1a1a;
  padding: 0.15rem 0.4rem;
  border-radius: 4px;
  margin-left: 0.35rem;
  vertical-align: middle;
}

.info-banner {
  font-size: 0.85rem;
  color: var(--text-muted);
  background: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  padding: 0.75rem 1rem;
  margin-bottom: 0.75rem;
  line-height: 1.5;
}

.info-banner-warning {
  border-color: rgba(245, 158, 11, 0.4);
  background: rgba(245, 158, 11, 0.08);
}

/* Recipe-photo-scan crop step (issue #17 follow-up): a full-screen modal
   letting the user tighten the OCR region before Tesseract runs. Cropping
   both removes background clutter (multi-recipe pages, sidebars) and raises
   the effective pixels-per-character for small print/fractions -- see
   tests/test-ocr-tuning.js's findings. */
.scan-crop-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
  padding: 1rem;
}

.scan-crop-panel {
  background: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.5rem;
  width: 100%;
  max-width: 640px;
  max-height: 90vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.scan-crop-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.scan-crop-header h3 {
  margin: 0;
  font-size: 1.1rem;
}

.scan-crop-close {
  background: none;
  border: none;
  font-size: 1.75rem;
  line-height: 1;
  color: var(--text-muted);
  cursor: pointer;
  padding: 0.25rem;
}

.scan-crop-close:hover {
  color: var(--text-main);
}

.scan-crop-hint {
  font-size: 0.85rem;
  color: var(--text-muted);
  margin: 0;
}

.scan-crop-stage {
  position: relative;
  display: inline-block;
  align-self: center;
  max-width: 100%;
  line-height: 0;
  touch-action: none;
  /* .scan-crop-panel is a flex column; without this, its default flex-shrink
     could compress this item below the image's actual size whenever the
     modal's total content exceeded max-height:90vh. */
  flex-shrink: 0;
  border-radius: 8px;
}

#scan-crop-image {
  display: block;
  max-width: 100%;
  max-height: 60vh;
  width: auto;
  height: auto;
  border-radius: 8px;
  user-select: none;
  -webkit-user-select: none;
}

/* Bug fix: the dim-mask's box-shadow and the corner handles have opposite
   overflow needs -- the mask must NOT bleed past the image (it was dulling
   the action buttons below), but the handles MUST overflow slightly past
   the rectangle's edges to stay grabbable when the crop touches an image
   edge (the default state -- full image selected). One shared overflow:hidden
   can't satisfy both, so the mask lives in its own clipped layer, sized
   exactly to the image, while .scan-crop-rect (handles included) is a
   sibling with no clipping at all. JS keeps #scan-crop-mask's position/size
   mirrored to #scan-crop-rect's (see syncMask() in app.js). */
.scan-crop-mask-clip {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: 8px;
  pointer-events: none;
}

.scan-crop-mask {
  position: absolute;
  box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.55);
}

.scan-crop-rect {
  position: absolute;
  border: 2px solid var(--primary);
  cursor: move;
  touch-action: none;
}

.scan-crop-handle {
  position: absolute;
  width: 28px;
  height: 28px;
  margin: -14px;
  background: var(--primary);
  border: 2px solid #fff;
  border-radius: 50%;
  touch-action: none;
}

.scan-crop-handle[data-handle="tl"] { top: 0; left: 0; cursor: nwse-resize; }
.scan-crop-handle[data-handle="tr"] { top: 0; right: 0; cursor: nesw-resize; }
.scan-crop-handle[data-handle="bl"] { bottom: 0; left: 0; cursor: nesw-resize; }
.scan-crop-handle[data-handle="br"] { bottom: 0; right: 0; cursor: nwse-resize; }

/* Two tiers, not one wrapping row: Reset/Cancel are secondary utility
   actions (left/right, small), and the actual scan-method choice
   (device vs. cloud) is a clearly separate, always-stacked pair below --
   stacking (not side-by-side + wrap) is what keeps this from rearranging
   itself unpredictably depending on how much the two long button labels
   ("Scan on This Device" / "Scan with Cloud AI (N left this month)")
   happen to fit at a given modal width. */
.scan-crop-utility-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.25rem;
}

.scan-crop-scan-actions {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-top: 0.75rem;
}

.scan-crop-scan-actions .btn {
  width: 100%;
  text-align: center;
}

.scan-crop-cloud-note {
  font-size: 0.78rem;
  color: var(--text-muted);
  margin-top: 0.75rem;
}

@media (max-width: 640px) {
  .scan-crop-panel {
    padding: 1rem;
  }

  #scan-crop-image {
    max-height: 50vh;
  }

  .scan-crop-utility-actions .btn {
    flex: 1 1 auto;
  }
}

.db-status-banner {
  margin-bottom: 1rem;
  padding: 0.75rem 1rem;
  border-radius: 8px;
  border: 1px solid #f59e0b;
  background: rgba(245, 158, 11, 0.12);
  color: var(--text-main);
  font-size: 0.875rem;
  font-weight: 500;
}

/* ── Ingredient impact table ─────────────────────────────────────────────── */
.ingredients-table-wrap {
  overflow-x: auto;
  width: 100%;
  -webkit-overflow-scrolling: touch;
}

.ingredients-table-card {
  width: 100%;
}

.ingredients-impact-table {
  /* Fixed (not auto) layout, sized to exactly 100% of the wrap: with auto
     layout + width:max-content, the table always grew to fit its widest
     unwrapped cell content (a long alternate name), forcing the horizontal
     scrollbar this is meant to avoid. Fixed layout takes column widths from
     the header row below and never grows past them -- content wraps inside
     instead. */
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  font-size: 0.875rem;
}

.ingredients-impact-table tbody tr {
  height: auto;
  min-height: 3rem;
}

.ingredients-impact-table th,
.ingredients-impact-table td {
  padding: 0.65rem 0.75rem;
  text-align: left;
  border-bottom: 1px solid var(--border-color);
  vertical-align: middle;
}

/* Column widths, as percentages of the fixed-layout table -- these apply via
   the header row; table-layout:fixed then holds every row's cells at that
   same width by column position, regardless of a cell's own class.
   Scoped to above the 768px card-view breakpoint: below it the table is
   display:block (not table-layout:fixed at all), but an unscoped percentage
   width here still has higher specificity than the mobile rules that try to
   reset it back to auto (3 classes via :not(...) vs. their 2), so it would
   otherwise silently override them and crush the mobile card layout. */
@media (min-width: 769px) {
  .ingredients-impact-table:not(.table-metrics-expanded) .col-ingredient { width: 18%; }
  .ingredients-impact-table:not(.table-metrics-expanded) .col-quantity { width: 10%; }
  .ingredients-impact-table:not(.table-metrics-expanded) .col-weight { width: 10%; }
  .ingredients-impact-table:not(.table-metrics-expanded) .col-metric { width: 12%; }
  .ingredients-impact-table:not(.table-metrics-expanded) .col-alternates { width: 50%; }

  /* col-metric-sub was 6% (~68px at typical widths) -- too narrow for its own
     header text ("Minerals") let alone a value+unit, which is what forced
     both the header overflow and the value ellipsis this is fixing. Widened
     at the expense of ingredient/quantity/alternates. */
  .ingredients-impact-table.table-metrics-expanded .col-ingredient { width: 10%; }
  .ingredients-impact-table.table-metrics-expanded .col-quantity { width: 5%; }
  .ingredients-impact-table.table-metrics-expanded .col-weight { width: 7%; }
  .ingredients-impact-table.table-metrics-expanded .col-metric-sub { width: 8%; }
  /* Same 12% as the collapsed view above, not 8% -- the ecoStrain header's
     own label + expand-button need that much room regardless of mode; less
     than that visibly overflows into the Alternates column next to it. */
  .ingredients-impact-table.table-metrics-expanded .col-metric { width: 12%; }
  .ingredients-impact-table.table-metrics-expanded .col-alternates { width: 26%; }
}

.ingredients-impact-table .col-weight {
  white-space: nowrap;
}

.ingredients-impact-table .col-score {
  white-space: nowrap;
  text-align: center;
}

.ingredients-impact-table .col-alternates {
  white-space: normal;
}

.ingredients-impact-table thead th {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  font-weight: 600;
  background: var(--surface-color);
  white-space: nowrap;
}

.ingredients-impact-table tbody tr:hover {
  background: rgba(52, 211, 153, 0.04);
}

.recipe-hero-image {
  width: 100%;
  max-height: 280px;
  object-fit: cover;
  border-radius: 12px;
  margin-bottom: 1.5rem;
  border: 1px solid var(--border-color);
}

.ingredients-impact-table .col-metric,
.ingredients-impact-table .col-score {
  text-align: center;
  white-space: nowrap;
}

.eco-strain-cell {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
}

.weight-per-item {
  font-size: 0.72rem;
  color: var(--text-muted);
  margin-top: 0.15rem;
}

.ing-detail-row td {
  padding: 0 !important;
  background: var(--surface-color);
  border-bottom: 1px solid var(--border-color);
}

.ing-detail-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8rem;
  margin: 0.5rem 0;
}

.ing-detail-table th,
.ing-detail-table td {
  padding: 0.5rem 0.65rem;
  text-align: left;
  border-bottom: 1px solid var(--border-color);
}

.ing-detail-table thead th {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  font-weight: 600;
}

.ing-detail-table tbody tr:last-child td {
  border-bottom: none;
}

.eco-strain-header {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
}

.table-expand-btn {
  flex-shrink: 0;
}

.col-alternates {
  vertical-align: middle;
}

.swap-stack {
  /* Grid (not flex) so alternate 1/2/3 line up in the same column across every
     ingredient row -- flex sized each button to its own text, so a long name
     in one row pushed that row's later slots out of alignment with the rest. */
  display: grid;
  /* minmax(0, 1fr), not bare 1fr: a bare 1fr track defaults to minmax(auto, 1fr),
     and "auto" sizes to the child's min-content width -- which ignores
     word-break, so one long unbroken alternate name silently forced the whole
     table wider and triggered the outer scrollbar this is meant to avoid. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.45rem;
  align-items: stretch;
  min-height: 2.75rem;
}

.swap-stack-empty {
  align-items: center;
}

.eco-healthy-badge {
  display: inline-block;
  font-size: 0.78rem;
  font-weight: 600;
  color: #10b981;
  padding: 0.25rem 0.5rem;
  border-radius: 6px;
  background: rgba(16, 185, 129, 0.1);
  white-space: nowrap;
}

.swap-apply-compact {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
  width: 100%;
  /* Grid items (and this button's own flex children) get an implicit
     "automatic minimum size" based on min-content unless min-width is set
     explicitly -- min-width:0 suppresses that so long text actually wraps
     within the grid column instead of forcing it wider. */
  min-width: 0;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border-color);
  border-radius: 6px;
  background: var(--surface-color);
  text-align: left;
  line-height: 1.25;
}

.swap-apply-compact:hover {
  border-color: var(--primary);
  background: rgba(52, 211, 153, 0.06);
}

.swap-btn-label {
  font-weight: 600;
  color: var(--primary);
  font-size: 0.78rem;
  white-space: normal;
  /* overflow-wrap: anywhere (not just word-break: break-word) -- break-word
     only prevents visual overflow, but per spec it's excluded from the
     min-content size calculation, so long unbroken alternate names were still
     forcing the table wider and triggering the horizontal scrollbar this is
     meant to prevent. overflow-wrap: anywhere is the one that actually lets
     the min-content size (and so the table column) shrink. */
  overflow-wrap: anywhere;
  word-break: break-word;
  line-height: 1.2;
}

.ingredients-impact-table .col-metric-sub {
  /* No overflow:hidden/ellipsis here on purpose: with the column now sized
     to actually fit a value+unit (see the width rules above) and values
     capped at 2 decimals, there's nothing that should need hiding -- if a
     value ever does overflow again, it should be visibly obvious (a real
     width bug to fix), not silently clipped like it was here before. */
  text-align: right;
  font-size: 0.72rem;
  color: var(--text-muted);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  padding-left: 0.35rem;
  padding-right: 0.35rem;
}

.ing-subtitle {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin-top: 0.15rem;
}

.row-expand-btn {
  background: none;
  border: 1px solid var(--border-color);
  border-radius: 6px;
  width: 1.75rem;
  height: 1.75rem;
  cursor: pointer;
  color: var(--text-muted);
  font-size: 0.7rem;
  line-height: 1;
}

.row-expand-btn:hover,
.row-expand-btn.expanded {
  border-color: var(--primary);
  color: var(--primary);
}

.swap-apply-btn,
.swap-revert-btn {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  font-size: 0.8rem;
  text-align: left;
  color: var(--primary);
  font-weight: 600;
}

.swap-revert-btn {
  color: var(--text-muted);
  font-weight: 500;
}

.swap-apply-btn:hover,
.swap-revert-btn:hover {
  text-decoration: underline;
}

.swap-pts {
  color: #10b981;
  font-weight: 700;
  white-space: nowrap;
}

.swap-more-btn {
  background: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  padding: 0.2rem 0.45rem;
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  color: var(--text-muted);
}

.swap-dropdown {
  position: relative;
  display: inline-block;
}

.swap-dropdown-menu {
  display: none;
  position: absolute;
  right: 0;
  top: 100%;
  z-index: 50;
  min-width: 220px;
  background: var(--card-bg);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  margin-top: 0.25rem;
  overflow: hidden;
}

.swap-dropdown-menu.open {
  display: block;
}

.swap-option {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
  width: 100%;
  padding: 0.6rem 0.75rem;
  border: none;
  background: none;
  cursor: pointer;
  text-align: left;
  font-size: 0.8rem;
  border-bottom: 1px solid var(--border-color);
}

.swap-option:last-child {
  border-bottom: none;
}

.swap-option:hover {
  background: var(--surface-color);
}

.swap-tier {
  font-size: 0.7rem;
  color: var(--text-muted);
}

.text-muted {
  color: var(--text-muted);
  font-style: italic;
}

/* ── Header auth widget (markup built by auth.js) ─────────────────────────── */
.header-actions {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  flex-shrink: 0;
}

.auth-container {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.6rem;
  /* Reserves the width of the most common (logged-out) state before
     Supabase has resolved, so the "Sign In" button filling in doesn't
     reflow the nav next to it. A signed-in user's own avatar/name can still
     be wider than this -- that's a smaller, one-time exception, not the
     every-page-load jiggle this is fixing. */
  min-width: 6.5rem;
  min-height: 2rem;
}

/* Account menu: a single trigger (avatar + name) opens a dropdown holding
   Settings/Admin/Sign out. Replaces what used to be three separate
   always-visible icon buttons -- Sign out sitting right next to Settings
   made it a one-tap accident on a phone. Now the only always-visible tap
   target is the trigger; reaching Sign out takes two deliberate taps. */
.auth-menu {
  position: relative;
}

.auth-trigger {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: none;
  border: none;
  padding: 0.25rem;
  border-radius: 99px;
  cursor: pointer;
  color: var(--text-main);
}

.auth-trigger:hover {
  background: var(--surface-hover, rgba(0, 0, 0, 0.05));
}

.auth-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  flex-shrink: 0;
}

.auth-avatar-fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-color);
  border: 1px solid var(--border-color);
  color: var(--text-muted);
}

.auth-user-name {
  font-size: 0.9rem;
  font-weight: 500;
  max-width: 12rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.auth-menu-chevron {
  flex-shrink: 0;
  color: var(--text-muted);
  transition: transform 0.15s;
}

.auth-trigger.open .auth-menu-chevron {
  transform: rotate(180deg);
}

.auth-dropdown {
  display: none;
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  min-width: 12rem;
  background: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  padding: 0.4rem;
  z-index: 200;
}

.auth-dropdown.open {
  display: block;
}

.auth-dropdown-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  padding: 0.6rem 0.75rem;
  border: none;
  background: none;
  border-radius: 6px;
  color: var(--text-main);
  font-size: 0.9rem;
  font-weight: 500;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}

.auth-dropdown-item:hover {
  background: var(--surface-hover, rgba(0, 0, 0, 0.05));
}

.auth-dropdown-item svg {
  flex-shrink: 0;
}

.auth-dropdown-item-danger {
  color: #ef4444;
}

.auth-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  padding: 0.35rem 0.75rem;
  font-size: 0.85rem;
  white-space: nowrap;
}

.auth-signin-btn svg {
  flex-shrink: 0;
}

/* ── Calculator page chrome ───────────────────────────────────────────────── */
.calc-topbar {
  margin-bottom: 1.5rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem;
}

.back-link {
  color: var(--accent);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 500;
}

.back-link svg {
  flex-shrink: 0;
}

.score-card {
  margin-bottom: 1.5rem;
  padding: 1rem 1.5rem;
  text-align: center;
}

.score-value {
  font-size: 2.25rem;
  font-weight: 800;
  color: var(--text-main);
  line-height: 1.1;
}

#recipe-stats {
  font-size: 0.95rem;
  color: var(--text-main);
  margin-top: 0.5rem;
}

.score-value-scale {
  font-size: 1.1rem;
  font-weight: 500;
  color: var(--text-muted);
  margin-left: 0.15rem;
}

.score-tier-label {
  font-size: 1rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-top: 0.35rem;
}

/* Everything below the gauge/score used to be one narrow (600px, then
   700px), centered column of stacked, differently-weighted lines inside a
   much wider card -- batch weight sat on its own line, separated from the
   footprint it produces by the whole explainer paragraph, and that
   paragraph was constrained to ~34rem when the card had roughly double
   that to give it. Widened throughout, and batch weight + footprint are
   now one visually connected band instead of two disconnected facts. */
.share-actions {
  /* .score-card is display:flex/column (via the shared .card rule), whose
     default align-items:stretch would otherwise force this row to the
     full card width -- align-self overrides that back to its own content
     size. */
  align-self: center;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem;
  margin-top: 0.85rem;
}

.share-results-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1.1rem;
  font-size: 0.9rem;
}

.badge-canvas {
  display: block;
  width: 100%;
  max-width: 360px;
  height: auto;
  margin: 0 auto;
}

.explainer-canvas {
  max-width: 280px;
}

.badge-controls {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.badge-title-field {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.35rem;
  width: 100%;
  max-width: 360px;
}

.badge-title-label {
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text-muted);
}

.badge-title-input {
  width: 100%;
  padding: 0.55rem 0.75rem;
  font-size: 0.95rem;
  font-family: inherit;
  color: var(--text-main);
  background: var(--surface);
  border: 1px solid var(--border-color);
  border-radius: 8px;
}

.badge-title-input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.badge-title-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.75rem;
  min-height: 1.1rem;
  width: 100%;
}

.badge-title-counter {
  font-size: 0.78rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.badge-title-counter.is-at-limit {
  color: #f59e0b;
  font-weight: 600;
}

.badge-title-limit-msg {
  font-size: 0.78rem;
  color: #f59e0b;
  font-weight: 500;
}

.badge-toggle-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1rem 1.5rem;
}

.badge-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  color: var(--text-main);
  cursor: pointer;
}

.badge-toggle input {
  width: 1rem;
  height: 1rem;
  cursor: pointer;
}

/* pointer-events stays auto (not none) so the title tooltip explaining why
   it's disabled still shows on hover -- app.js's onclick handler is what
   actually blocks navigation. */
.btn-disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.verdict-summary {
  max-width: 56rem;
  margin: 1rem auto 0;
  border-top: 1px solid var(--border-color);
  padding-top: 1.1rem;
}

.verdict-text {
  font-size: 1rem;
  font-weight: 500;
  margin: 0 0 1rem;
}

.footprint-band {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.6rem 1rem;
  margin-bottom: 0.85rem;
}

.footprint-batch {
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--text-main);
  white-space: nowrap;
  flex-shrink: 0;
}

.footprint-arrow {
  color: var(--text-muted);
  flex-shrink: 0;
}

.score-explainer-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  margin: 0 auto;
}

.score-explainer {
  font-size: 0.85rem;
  color: var(--text-muted);
  line-height: 1.5;
  margin: 0;
}

.ingredients-table-header {
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border-color);
}

.ingredients-table-header-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

/* Mirrors the <thead> expander, which is hidden in the stacked mobile layout */
.mobile-metrics-toggle {
  display: none;
  margin-top: 0.65rem;
  width: 100%;
  min-height: 44px;
  background: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  color: var(--text-main);
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
}

.recipe-reference-card {
  margin-top: 0;
  padding: 1.5rem;
}

#recipe-display {
  font-size: 0.95rem;
  color: var(--text-muted);
  line-height: 1.6;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  background: var(--surface-color);
  padding: 1rem;
  border-radius: 8px;
  max-height: 400px;
  overflow-y: auto;
}

/* .hide-on-mobile is hidden below 768px (see RESPONSIVE); above it the element
   keeps its natural display, so no base rule here. */

/* Default padding for content cards that tighten up on small screens */
.card-padded {
  padding: 2rem;
}

/* Shared alert()/confirm() replacement (issue #31) -- see dialogs.js.
   <dialog>'s built-in centering relies on the UA stylesheet's `margin: auto`,
   which the site's global `* { margin: 0 }` reset (above) wipes out -- center
   explicitly instead of depending on that. */
.app-dialog {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  max-width: 420px;
  width: calc(100% - 2rem);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  background-color: var(--surface-color);
  color: var(--text-main);
  box-shadow: var(--shadow);
  padding: 1.5rem;
}

.app-dialog::backdrop {
  background: rgba(15, 23, 42, 0.5);
}

.app-dialog-message {
  margin: 0 0 1.5rem 0;
  font-size: 0.95rem;
  line-height: 1.5;
  white-space: pre-wrap;
}

.app-dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.75rem;
}

.app-dialog-actions .btn,
.app-dialog-actions .btn-outline {
  padding: 0.5rem 1.1rem;
  font-size: 0.9rem;
}

/* Issue #43: wider variant of .app-dialog for the edit-recipe form -- the
   base size is tuned for a one-line alert/confirm message, not a scrollable
   list of ingredient rows. */
.edit-ingredients-dialog {
  max-width: 640px;
  max-height: 85vh;
  overflow-y: auto;
  text-align: left;
  padding: 1.75rem;
}

/* Issue #39: "Take Photo" only makes sense with a camera to take a photo
   with -- hide it for anyone whose primary input is a mouse/trackpad (desktop),
   leaving just "Choose Photo". Touchscreen laptops with a mouse attached still
   match (pointer: fine) as their primary pointer, which is the right call here:
   the camera button is only useful when the device's OWN camera is what a
   file-picker capture would open, which fine-pointer-primary devices rarely have. */
@media (pointer: fine) {
  #scan-camera-btn {
    display: none;
  }
}

/* Issue #34: 3 big "fun" vanity numbers (home page + top of Trends) */
.impact-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
  text-align: center;
}

.impact-stat-value {
  font-family: var(--font-display);
  font-size: 2.75rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--primary);
  font-variant-numeric: tabular-nums;
}

.impact-stat:nth-child(2) .impact-stat-value {
  color: var(--accent);
}

.impact-stat:nth-child(3) .impact-stat-value {
  color: var(--primary);
}

.impact-stat-label {
  margin-top: 0.4rem;
  font-size: 0.9rem;
  color: var(--text-muted);
  font-weight: 500;
}

@media (max-width: 640px) {
  .impact-stats {
    grid-template-columns: 1fr;
    gap: 1.25rem;
  }
  .impact-stat-value {
    font-size: 2.25rem;
  }
}

/* Issue #43: editable ingredient rows in the "Edit Recipe" panel */
.edit-ingredient-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.6rem;
}

.edit-ingredient-row .form-control {
  flex: 1;
}

.edit-ingredient-delete-btn {
  flex-shrink: 0;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius);
  border: 1px solid var(--border-color);
  background: var(--bg-color);
  color: var(--text-muted);
  font-size: 1rem;
  cursor: pointer;
  transition: border-color 0.2s, color 0.2s;
}

.edit-ingredient-delete-btn:hover {
  border-color: #ef4444;
  color: #ef4444;
}

/* ══════════════════════════════════════════════════════════════════════════
   RESPONSIVE
   Breakpoints: 860px collapses the nav, 768px restacks data tables,
   640px is the phone layout, 400px is the small-phone squeeze.
   ══════════════════════════════════════════════════════════════════════════ */

/* Hover effects only where a real pointer exists — otherwise a tap leaves the
   element stuck in its hover state until you tap elsewhere. */
@media (hover: none) {
  .btn:hover,
  .btn-accept:hover,
  .theme-toggle-btn:hover,
  .hero-gauge-card:hover {
    transform: none;
    box-shadow: none;
  }

  .card:hover,
  .suggestion-card:hover,
  .hero-gauge-card:hover {
    border-color: var(--border-color);
    box-shadow: none;
  }

  .swap-apply-compact:hover {
    border-color: var(--border-color);
    background: var(--surface-color);
  }

  .ingredients-impact-table tbody tr:hover,
  .metric-header:hover,
  .breakdown-row:hover,
  .swap-option:hover,
  .settings-nav-item:hover,
  .admin-table tbody tr:hover {
    background-color: transparent;
  }

  /* :not(.active) so tapping the selected tab doesn't strip its highlight */
  .tab-btn:not(.active):hover {
    background-color: transparent;
    color: var(--text-muted);
  }

  /* Declining a swap shouldn't leave the button stuck in its red state */
  .btn-decline:hover {
    background-color: transparent;
    color: var(--text-muted);
    border-color: var(--border-color);
  }

  .btn-outline:hover {
    background-color: transparent;
    border-color: var(--border-color);
  }

  .row-expand-btn:hover {
    border-color: var(--border-color);
    color: var(--text-muted);
  }
}

/* ── ≤860px: collapse the nav behind the hamburger ────────────────────────── */
@media (max-width: 860px) {
  header {
    padding: 0.75rem 1rem;
    padding-left: max(1rem, env(safe-area-inset-left));
    padding-right: max(1rem, env(safe-area-inset-right));
    gap: 0.5rem;
  }

  .logo {
    font-size: 1.15rem;
    margin-right: auto;
  }

  .nav-toggle {
    display: inline-flex;
    order: 3;
  }

  .header-actions {
    order: 2;
    gap: 0.5rem;
  }

  .auth-container {
    gap: 0.35rem;
    /* Narrower reservation matching the mobile Sign In button, not the wider
       desktop one -- see the base .auth-container rule for why this exists. */
    min-width: 5rem;
  }

  /* Collapse the trigger to just the avatar so the bar still fits a 360px
     phone -- the dropdown itself isn't width-constrained once open, so its
     items (Settings/Admin/Sign out) keep their full text and icons. */
  .auth-user-name,
  .auth-menu-chevron {
    display: none;
  }

  .auth-trigger {
    padding: 0.25rem;
    min-width: 40px;
    min-height: 40px;
    justify-content: center;
  }

  /* Sign In keeps its label — a lone Google glyph wouldn't read as an action */
  .auth-signin-btn {
    padding: 0.5rem 0.75rem;
    min-height: 40px;
  }

  .theme-toggle-btn {
    width: 40px;
    height: 40px;
  }

  /* Nav links become a dropdown panel anchored to the sticky header */
  .primary-nav {
    order: 4;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    display: none;
    background-color: var(--card-bg);
    border-bottom: 1px solid var(--border-color);
    box-shadow: var(--shadow);
    padding: 0.35rem 0;
  }

  .primary-nav.open {
    display: block;
  }

  .primary-nav ul {
    flex-direction: column;
    gap: 0;
  }

  .primary-nav a {
    display: block;
    padding: 0.9rem 1.25rem;
    font-size: 1rem;
    border-left: 3px solid transparent;
  }

  .primary-nav a.active {
    color: var(--primary);
    border-left-color: var(--primary);
    background-color: rgba(52, 211, 153, 0.08);
  }
}

/* ── ≤768px: data tables restack as cards ─────────────────────────────────── */
@media (max-width: 768px) {
  main {
    padding: 2rem 1.25rem;
    padding-left: max(1.25rem, env(safe-area-inset-left));
    padding-right: max(1.25rem, env(safe-area-inset-right));
  }

  .hide-on-mobile {
    display: none !important;
  }

  .mobile-metrics-toggle {
    display: block;
  }

  /* Ingredient impact table → one card per ingredient.
     Row 1 is [name | ecoStrain]; every other cell spans the full width with
     its column name printed from data-label. */
  .ingredients-table-wrap {
    overflow-x: visible;
  }

  .ingredients-impact-table,
  .ingredients-impact-table tbody {
    display: block;
    width: 100%;
    min-width: 0;
  }

  .ingredients-impact-table thead {
    display: none;
  }

  .ingredients-impact-table tbody tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: baseline;
    gap: 0 0.75rem;
    padding: 0.9rem 1rem;
    border-bottom: 1px solid var(--border-color);
  }

  .ingredients-impact-table tbody tr:last-child {
    border-bottom: none;
  }

  .ingredients-impact-table td {
    display: block;
    padding: 0;
    border-bottom: none;
    max-width: none;
  }

  /* Loading / empty placeholder rows still span the whole card */
  .ingredients-impact-table tbody td[colspan] {
    grid-column: 1 / -1;
    text-align: center;
  }

  .ingredients-impact-table .col-ingredient {
    grid-column: 1;
    grid-row: 1;
    width: auto;
    min-width: 0;
    max-width: none;
    font-size: 1rem;
    font-weight: 600;
    overflow-wrap: anywhere;
  }

  .ingredients-impact-table .col-score {
    grid-column: 2;
    grid-row: 1;
    width: auto;
    min-width: 0;
    max-width: none;
    text-align: right;
    font-size: 1.15rem;
  }

  /* Label/value pairs, one per line */
  .ingredients-impact-table .col-quantity,
  .ingredients-impact-table .col-weight,
  .ingredients-impact-table .col-metric-sub {
    grid-column: 1 / -1;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    width: auto;
    min-width: 0;
    max-width: none;
    padding: 0.3rem 0;
    margin-top: 0.15rem;
    border-top: 1px dashed var(--border-color);
    text-align: right;
    font-size: 0.85rem;
    white-space: normal;
  }

  .ingredients-impact-table td[data-label]:not(.col-score)::before {
    content: attr(data-label);
    color: var(--text-muted);
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    text-align: left;
    flex-shrink: 0;
  }

  .ingredients-impact-table .col-alternates {
    grid-column: 1 / -1;
    width: auto;
    min-width: 0;
    margin-top: 0.55rem;
    padding-top: 0.6rem;
    border-top: 1px dashed var(--border-color);
  }

  .ingredients-impact-table .col-alternates::before {
    display: block;
    margin-bottom: 0.45rem;
  }

  /* Swap buttons go full width, one per row, with a comfortable tap target --
     overrides the desktop 3-column grid (added for alignment across rows),
     which has no reason to apply once each ingredient is its own full-width
     card instead of a table row. */
  .swap-stack {
    grid-template-columns: 1fr;
    gap: 0.5rem;
  }

  .swap-apply-compact {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 0.1rem 0.6rem;
    width: 100%;
    max-width: none;
    min-height: 44px;
    padding: 0.55rem 0.75rem;
  }

  .swap-btn-label {
    grid-column: 1;
    grid-row: 1;
    font-size: 0.9rem;
  }

  .swap-pts {
    grid-column: 2;
    grid-row: 1;
    text-align: right;
  }

  .swap-tier {
    grid-column: 1 / -1;
  }

  .swap-revert-btn {
    min-height: 44px;
    font-size: 0.9rem;
  }

  .swap-dropdown-menu {
    left: 0;
    right: 0;
    min-width: 0;
  }
}

/* ── ≤640px: phone layout ─────────────────────────────────────────────────── */
@media (max-width: 640px) {
  main {
    padding: 1.5rem 1rem;
    padding-left: max(1rem, env(safe-area-inset-left));
    padding-right: max(1rem, env(safe-area-inset-right));
  }

  footer {
    padding: 1.5rem 1rem;
    padding-bottom: max(1.5rem, env(safe-area-inset-bottom));
  }

  .results-layout-grid {
    gap: 1.5rem;
  }

  .grid {
    grid-template-columns: 1fr;
    gap: 1.25rem;
  }

  /* Full-width CTAs read as buttons, not links, on a phone */
  .hero-actions .btn {
    width: 100%;
  }

  .tabs {
    flex-wrap: wrap;
    gap: 0.5rem;
    padding-bottom: 0.75rem;
    margin-bottom: 1.25rem;
  }

  .tab-btn {
    padding: 0.5rem 0.85rem;
    font-size: 0.9rem;
    min-height: 40px;
  }

  /* Forms: 1rem keeps iOS from zooming the viewport on focus */
  .form-control {
    font-size: 1rem;
    padding: 0.85rem 1rem;
  }

  textarea.form-control {
    min-height: 11rem;
  }

  .card-padded {
    padding: 1.25rem;
  }

  .score-card {
    padding: 1rem;
  }

  .score-value {
    font-size: 2rem;
  }

  .calc-topbar {
    gap: 0.5rem;
    margin-bottom: 1rem;
  }

  .calc-topbar h1 {
    font-size: 1.1rem !important;
    width: 100%;
  }

  .sticky-summary {
    padding: 0.6rem 0.85rem;
    margin-bottom: 1rem;
  }

  .sticky-content {
    gap: 0.6rem;
  }

  .sticky-title {
    font-size: 0.95rem;
  }

  .sticky-score-label {
    display: none;
  }

  .sticky-score-group {
    gap: 0.45rem;
  }

  .sticky-score-val {
    font-size: 1.3rem;
  }

  /* Two-up equivalents instead of a cramped single row */
  .equivalents-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem 0.75rem;
    font-size: 0.85rem;
    justify-items: start;
  }

  /* Stack batch weight above its footprint rather than fighting for room in
     one row; the arrow only made sense inline. */
  .footprint-band {
    flex-direction: column;
  }

  .footprint-arrow {
    display: none;
  }

  .recipe-hero-image {
    max-height: 180px;
    margin-bottom: 1rem;
  }

  #recipe-display {
    max-height: 260px;
    font-size: 0.9rem;
  }

  .recipe-reference-card,
  .feedback-cta {
    padding: 1.25rem;
  }

  .feedback-cta-content {
    gap: 1rem;
  }

  .feedback-btn {
    width: 100%;
    text-align: center;
  }

  .suggestion-card {
    flex-direction: column;
    align-items: stretch;
    gap: 0.75rem;
  }

  .suggestion-actions .btn-accept,
  .suggestion-actions .btn-decline {
    flex: 1;
    min-height: 44px;
  }

  .suggestion-old,
  .suggestion-new {
    max-width: 100%;
  }

  /* Dragging a bookmarklet to a bookmarks bar isn't possible on a phone */
  .bookmarklet-panel {
    display: none;
  }
}

/* ── ≤400px: small-phone squeeze ──────────────────────────────────────────── */
@media (max-width: 400px) {
  .logo {
    font-size: 1.05rem;
  }

  .logo svg {
    width: 20px;
    height: 20px;
  }

  .gauge-container,
  .gauge-base {
    width: 170px;
  }

  .gauge-container {
    height: 85px;
  }

  .gauge-base {
    height: 170px;
  }

  .gauge-needle {
    height: 68px;
  }

  .equivalents-row {
    grid-template-columns: 1fr;
  }
}

/* Respect users who ask their OS to cut down on motion */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Visible keyboard focus everywhere, including on mobile with a paired keyboard */
:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
