/* ---------------------------------------------------------------------------
   GroHop — cream paper, deep grocer green, a yellow price tag.
   One stylesheet, no framework, no webfonts to load.
   --------------------------------------------------------------------------- */

   :root {
    color-scheme: dark;
    --bg: #1c241a;            /* deep forest */
    --surface: #232d20;
    --surface-2: #2a3527;
    --line: #384532;
    --ink: #eef3e8;
    --ink-soft: #a3b198;
    --accent: #7ccb80;        /* mint on forest */
    --accent-deep: #8ed492;
    --accent-soft: #2b4030;
    --tag: #f4c20d;           /* the yellow tag stays */
    --tag-soft: #3a3312;
    --warn: #e0a552;
    --danger: #f2867c;
    --radius: 16px;
    --shadow: 0 1px 2px rgb(0 0 0 / 30%), 0 6px 18px rgb(0 0 0 / 26%);
  }
  
  * { box-sizing: border-box; }
  
  body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font: 16px/1.55 ui-rounded, "SF Pro Rounded", -apple-system, "Segoe UI",
          Roboto, "Helvetica Neue", sans-serif;
    -webkit-font-smoothing: antialiased;
  }
  
  .wrap { max-width: 1040px; margin: 0 auto; padding: 0 20px; }
  .mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
  .muted { color: var(--ink-soft); }
  .small { font-size: 0.87rem; }
  .right { text-align: right; }
  
  /* Masthead ---------------------------------------------------------------- */
  
  .masthead {
    position: sticky;
    top: 0;
    z-index: 10;
    background: color-mix(in srgb, var(--bg) 90%, transparent);
    backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--line);
  }
  
  .masthead-inner {
    display: flex;
    align-items: center;
    gap: 16px;
    padding-top: 12px;
    padding-bottom: 12px;
    flex-wrap: wrap;
  }
  
  .brand {
    display: flex;
    align-items: center;
    gap: 2px;
    text-decoration: none;
    color: var(--accent);
  }
  
  .brand-word {
    font-size: 1.7rem;
    font-weight: 800;
    letter-spacing: -0.03em;
    line-height: 1;
  }
  
  .brand-o { color: var(--accent); }
  
  .brand-tag {
    width: 22px;
    height: 22px;
    margin-left: -2px;
    transform: rotate(8deg) translateY(-6px);
  }
  
  .search { flex: 1 1 240px; }
  
  .search input {
    width: 100%;
    padding: 10px 16px;
    border: 1.5px solid var(--line);
    border-radius: 999px;
    background: var(--surface);
    color: var(--ink);
    font: inherit;
    font-size: 0.95rem;
  }
  
  .search input:focus-visible {
    outline: 2.5px solid var(--accent);
    outline-offset: 1px;
    border-color: transparent;
  }
  
  /* Buttons ----------------------------------------------------------------- */
  
  .button {
    padding: 10px 18px;
    border-radius: 999px;
    border: 1.5px solid transparent;
    font: inherit;
    font-size: 0.93rem;
    font-weight: 700;
    cursor: pointer;
    transition: transform 0.1s ease, filter 0.15s ease, background 0.15s ease;
  }
  
  .button:active { transform: scale(0.98); }
  
  .button.primary {
    background: var(--accent);
    color: #14210f;
    box-shadow: 0 2px 0 rgb(0 0 0 / 25%);
  }
  .button.primary:hover { filter: brightness(1.07); }
  
  .button.primary.big {
    font-size: 1.05rem;
    padding: 13px 28px;
  }
  
  .button.ghost {
    background: var(--surface);
    border-color: var(--line);
    color: var(--ink);
  }
  .button.ghost:hover { background: var(--surface-2); }
  
  .back { margin: 22px 0 8px; }
  
  /* Hero -------------------------------------------------------------------- */
  
  .hero {
    display: flex;
    flex-direction: row-reverse;   /* copy right, mascot left */
    align-items: center;
    justify-content: flex-end;
    gap: 34px;
    margin: 34px 0 10px;
  }
  
  .hero-copy { flex: 1 1 300px; }
  
  .hero h1 {
    margin: 0 0 8px;
    font-size: clamp(1.6rem, 4vw, 2.3rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1.15;
  }
  
  .hero h1 em {
    font-style: normal;
    color: var(--accent);
    text-decoration: underline;
    text-decoration-color: var(--tag);
    text-decoration-thickness: 3px;
    text-underline-offset: 4px;
  }
  
  .hero p {
    margin: 0 0 18px;
    color: var(--ink-soft);
    font-size: 1.02rem;
    max-width: 42ch;
  }
  
  .hero-quote {
    margin-top: 16px;
    font-size: 0.92rem;
  }
  
  .hero-quote em {
    font-style: normal;
    color: var(--accent);
    font-weight: 700;
  }
  
  .hero-art {
    flex: 0 1 260px;
    display: flex;
    justify-content: center;
  }
  
  .hero-art { flex: 0 1 320px; }
  
  .hero-art img {
    max-width: 100%;
    max-height: 420px;
    filter: drop-shadow(0 14px 28px rgb(0 0 0 / 35%));
  }
  
  @media (max-width: 640px) {
    .hero { flex-direction: column-reverse; text-align: center; justify-content: center; }
    .hero p { margin-inline: auto; }
  }
  
  /* Stats — the feature-chip row -------------------------------------------- */
  
  .stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    gap: 12px;
    margin: 22px 0 8px;
    padding: 0;
  }
  
  .stats div {
    background: var(--surface);
    border: 1.5px solid var(--line);
    border-radius: var(--radius);
    padding: 14px 16px;
    box-shadow: var(--shadow);
  }
  
  .stats dt {
    font-size: 0.76rem;
    color: var(--ink-soft);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
  }
  
  .stats dd {
    margin: 3px 0 0;
    font-size: 1.55rem;
    font-weight: 800;
    color: var(--accent);
    font-variant-numeric: tabular-nums;
  }
  
  /* Product cards ----------------------------------------------------------- */
  
  .section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin: 30px 0 14px;
  }
  
  .section-head h2 {
    margin: 0;
    font-size: 1.2rem;
    font-weight: 800;
    letter-spacing: -0.01em;
  }
  
  .card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 14px;
    padding-bottom: 50px;
  }
  
  .card {
    display: block;
    width: 100%;
    text-align: left;
    background: var(--surface);
    border: 1.5px solid var(--line);
    border-radius: var(--radius);
    padding: 16px;
    cursor: pointer;
    font: inherit;
    color: inherit;
    box-shadow: var(--shadow);
    transition: transform 0.12s ease, border-color 0.12s ease;
  }
  
  .card:hover { transform: translateY(-3px); border-color: var(--accent); }
  
  .card h3 {
    margin: 0 0 4px;
    font-size: 1.02rem;
    font-weight: 700;
    overflow-wrap: anywhere;
  }
  
  .card .barcode { font-size: 0.78rem; color: var(--ink-soft); }
  
  .card .price-line {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1.5px dashed var(--line);
  }
  
  /* The price wears a shelf tag. */
  .card .price {
    position: relative;
    font-size: 1.18rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: var(--tag);
    background: var(--tag-soft);
    border: 1.5px solid var(--tag);
    border-radius: 8px;
    padding: 3px 10px 3px 16px;
  }
  
  .card .price::before {
    content: "";
    position: absolute;
    left: 6px;
    top: 50%;
    transform: translateY(-50%);
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--surface);
    border: 1.5px solid var(--tag);
  }
  
  .card .where {
    font-size: 0.82rem;
    color: var(--ink-soft);
    text-align: right;
    font-weight: 600;
  }
  
  /* Detail ------------------------------------------------------------------ */
  
  .detail-head { margin-bottom: 26px; }
  
  .detail-head h2 {
    margin: 0 0 4px;
    font-size: 1.55rem;
    font-weight: 800;
    letter-spacing: -0.02em;
  }
  
  .spread {
    display: inline-block;
    margin: 10px 0 0;
    padding: 7px 14px;
    border-radius: 999px;
    background: var(--accent-soft);
    color: var(--accent);
    font-size: 0.9rem;
    font-weight: 700;
  }
  
  h3 { font-size: 1.02rem; font-weight: 800; margin: 30px 0 10px; }
  
  .offers-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
  }
  
  .offers-head h3 { margin: 30px 0 10px; }
  
  .sort-toggle {
    display: inline-flex;
    border: 1.5px solid var(--line);
    border-radius: 999px;
    overflow: hidden;
    background: var(--surface);
  }
  
  .sort-toggle button {
    padding: 7px 15px;
    border: none;
    background: transparent;
    color: var(--ink-soft);
    font: inherit;
    font-size: 0.84rem;
    font-weight: 700;
    cursor: pointer;
  }
  
  .sort-toggle button.active { background: var(--accent); color: #14210f; }
  
  .size-warning {
    margin: 0 0 12px;
    padding: 10px 14px;
    border-radius: 10px;
    background: var(--tag-soft);
    border: 1.5px solid var(--tag);
    color: var(--warn);
    font-size: 0.88rem;
    font-weight: 600;
  }
  
  .table-scroll {
    overflow-x: auto;
    border: 1.5px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow);
  }
  
  table.offers { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
  
  table.offers th {
    text-align: left;
    font-size: 0.73rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ink-soft);
    padding: 11px 14px;
    border-bottom: 1.5px solid var(--line);
    white-space: nowrap;
  }
  
  table.offers td { padding: 12px 14px; border-bottom: 1px solid var(--line); vertical-align: top; }
  table.offers tr:last-child td { border-bottom: none; }
  table.offers.compact td { padding: 8px 14px; font-size: 0.86rem; }
  table.offers td.right, table.offers th.right { text-align: right; font-variant-numeric: tabular-nums; }
  
  tr.cheapest { background: var(--accent-soft); }
  tr.cheapest td:first-child { box-shadow: inset 4px 0 0 var(--accent); }
  
  .tag {
    display: inline-block;
    margin-left: 7px;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--tag);
    color: #3a3000;
    font-size: 0.67rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    vertical-align: 1px;
  }
  
  .stale { color: var(--warn); }
  
  a.map-link { color: var(--accent); text-decoration: none; font-size: 0.82rem; font-weight: 600; }
  a.map-link:hover { text-decoration: underline; }
  
  .empty {
    padding: 50px 20px;
    text-align: center;
    color: var(--ink-soft);
  }
  
  /* Dialog ------------------------------------------------------------------ */
  
  dialog {
    width: min(620px, calc(100vw - 32px));
    border: 1.5px solid var(--line);
    border-radius: 20px;
    background: var(--surface);
    color: var(--ink);
    padding: 24px;
    box-shadow: 0 22px 60px rgb(30 40 25 / 28%);
  }
  
  dialog::backdrop { background: rgb(35 48 31 / 45%); backdrop-filter: blur(2px); }
  dialog h2 { margin: 0 0 4px; font-size: 1.25rem; font-weight: 800; }
  
  .field-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 13px;
    margin: 18px 0 4px;
  }
  
  .field-grid .span-2 { grid-column: 1 / -1; }
  
  @media (max-width: 520px) {
    .field-grid { grid-template-columns: 1fr; }
    .field-grid .span-2 { grid-column: auto; }
  }
  
  label {
    display: flex;
    flex-direction: column;
    gap: 5px;
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--ink-soft);
  }
  
  input, select {
    padding: 10px 12px;
    border: 1.5px solid var(--line);
    border-radius: 10px;
    background: var(--bg);
    color: var(--ink);
    font: inherit;
    font-size: 0.94rem;
    font-weight: 500;
  }
  
  input:focus-visible, select:focus-visible {
    outline: 2.5px solid var(--accent);
    outline-offset: 1px;
    border-color: transparent;
  }
  
  .quantity-preview {
    margin: 12px 0 0;
    font-size: 0.86rem;
    color: var(--ink-soft);
    min-height: 1.4em;
    font-weight: 600;
  }
  
  .form-error {
    margin: 12px 0 0;
    padding: 10px 13px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    color: var(--danger);
    font-size: 0.88rem;
    font-weight: 600;
  }
  
  .dialog-actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin: 22px 0 0;
    padding: 0;
  }
  
  /* Toast ------------------------------------------------------------------- */
  
  .toast {
    position: fixed;
    left: 50%;
    bottom: 26px;
    transform: translateX(-50%);
    padding: 12px 22px;
    border-radius: 999px;
    background: var(--accent);
    color: #14210f;
    font-size: 0.9rem;
    font-weight: 700;
    box-shadow: 0 8px 26px rgb(0 0 0 / 25%);
    z-index: 50;
  }
  
  /* Nav --------------------------------------------------------------------- */
  
  .site-nav { display: flex; gap: 4px; }
  
  .site-nav a {
    padding: 8px 14px;
    border-radius: 999px;
    color: var(--ink-soft);
    text-decoration: none;
    font-weight: 700;
    font-size: 0.93rem;
  }
  
  .site-nav a:hover { background: var(--surface-2); color: var(--ink); }
  .site-nav a.active { background: var(--accent-soft); color: var(--accent); }
  
  .scan-button { display: inline-flex; align-items: center; gap: 7px; }
  
  /* Browse ------------------------------------------------------------------ */
  
  #browse-sort {
    padding: 8px 12px;
    border: 1.5px solid var(--line);
    border-radius: 999px;
    background: var(--surface);
    color: var(--ink);
    font: inherit;
    font-size: 0.88rem;
    font-weight: 700;
  }
  
  .chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 18px;
  }
  
  .chips button {
    padding: 7px 15px;
    border-radius: 999px;
    border: 1.5px solid var(--line);
    background: var(--surface);
    color: var(--ink-soft);
    font: inherit;
    font-size: 0.87rem;
    font-weight: 700;
    cursor: pointer;
  }
  
  .chips button:hover { border-color: var(--accent); color: var(--ink); }
  
  .chips button.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #14210f;
  }
  
  .chips .count { opacity: 0.65; font-weight: 600; margin-left: 4px; }
  
  .load-more-row { display: flex; justify-content: center; padding: 6px 0 50px; }
  
  /* Scanner ----------------------------------------------------------------- */
  
  .scan-stage {
    position: relative;
    margin: 14px 0 10px;
    border-radius: 14px;
    overflow: hidden;
    background: #000;
    aspect-ratio: 4 / 3;
  }
  
  #scan-video { width: 100%; height: 100%; object-fit: cover; display: block; }
  
  .scan-line {
    position: absolute;
    left: 8%;
    right: 8%;
    top: 50%;
    height: 2px;
    background: var(--tag);
    box-shadow: 0 0 12px var(--tag);
    animation: scanline 2.2s ease-in-out infinite;
  }
  
  @keyframes scanline {
    0%, 100% { transform: translateY(-46px); }
    50% { transform: translateY(46px); }
  }
  
  .scan-manual { display: flex; gap: 8px; margin-top: 6px; }
  
  .scan-manual input {
    flex: 1;
    padding: 10px 12px;
    border: 1.5px solid var(--line);
    border-radius: 10px;
    background: var(--bg);
    color: var(--ink);
    font-size: 0.95rem;
  }
  
  /* Móvil ------------------------------------------------------------------- */
  
  @media (max-width: 720px) {
    /* Four rows rather than three. The old layout gave the camera and the
       barcode scanner the same grid area, so the second one drawn sat on top
       of the first and the photo search was invisible on a phone — which is
       the one device it exists for. */
    .masthead-inner {
      display: grid;
      grid-template-columns: 1fr auto auto;
      grid-template-areas:
        "brand  lens  scan"
        "search search search"
        "add    add   add"
        "nav    nav   nav";
      gap: 10px;
      align-items: center;
    }
  
    .brand { grid-area: brand; }
    .site-nav { grid-area: nav; }
    .lens-button { grid-area: lens; }
    .scan-button { grid-area: scan; }
    #open-submit { grid-area: add; width: 100%; justify-content: center; }
    .search { grid-area: search; }
    .search input { width: 100%; }

    /* Seven destinations do not fit across 360px, and wrapping them pushes
       the page down. A scrolling strip keeps the row one line high and lets a
       thumb reach the rest. */
    .site-nav {
      display: flex;
      gap: 4px;
      overflow-x: auto;
      flex-wrap: nowrap;
      scrollbar-width: none;
      -webkit-overflow-scrolling: touch;
      margin: 0 -20px;
      padding: 2px 20px 4px;
    }

    .site-nav::-webkit-scrollbar { display: none; }
    .site-nav a { flex: 0 0 auto; white-space: nowrap; }

    /* The two camera buttons are icon-first on a phone: the words cost a line
       and say what the icons already do. */
    .lens-button, .scan-button { padding: 9px 12px; gap: 6px; }
  
    .button { padding: 9px 14px; font-size: 0.88rem; }
  
    .hero { margin-top: 20px; gap: 16px; }
    .hero-art img { max-height: 210px; }
    .hero h1 { font-size: 1.45rem; }
    .hero p { font-size: 0.95rem; }
  
    .stats { grid-template-columns: 1fr 1fr; }
    .stats dd { font-size: 1.25rem; }
  
    .card-grid { grid-template-columns: 1fr; }
  
    .section-head { flex-wrap: wrap; }
  
    .chips { overflow-x: auto; flex-wrap: nowrap; padding-bottom: 4px;
             -webkit-overflow-scrolling: touch; }
    .chips button { white-space: nowrap; flex: 0 0 auto; }
  
    /* Los diálogos ocupan casi toda la pantalla y hacen scroll por dentro,
       para que el teclado no tape los campos. */
    dialog {
      width: calc(100vw - 20px);
      max-height: 92dvh;
      overflow-y: auto;
      padding: 18px;
      border-radius: 18px;
    }
  
    .scan-stage { aspect-ratio: 3 / 4; }   /* vertical, como se sostiene el teléfono */
  
    table.offers { font-size: 0.86rem; }
    table.offers th, table.offers td { padding: 9px 10px; }
  }
  
  /* Dedos, no cursores: zonas de toque decentes en cualquier tamaño. */
  @media (pointer: coarse) {
    .chips button, .sort-toggle button { min-height: 40px; }
    /* A card is an article now, not a button: the padding belongs to the part
       that is actually tappable, and the actions row needs a finger-sized
       target of its own. */
    .card-open { padding: 18px 16px 12px; }
    .chip-button, .store-option, .shop-row, .tick { min-height: 40px; }
  }
/* Map ---------------------------------------------------------------------
   Leaflet's own stylesheet is loaded at runtime, after this file, so every
   override below is written one level more specific than Leaflet's own rule
   in order to win without a single !important.
   ------------------------------------------------------------------------- */

.map-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}

.map-search {
  flex: 1 1 240px;
  min-width: 0;
  padding: 10px 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
}

.map-search:focus-visible,
#map-radius:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

#map-radius {
  padding: 9px 12px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
}

#map-pick.active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-deep);
}

.map-status {
  margin: 0 0 12px;
  min-height: 1.2em;
  color: var(--ink-soft);
  font-size: 0.87rem;
}

.map-status.bad { color: var(--warn); }

.map-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(260px, 1fr);
  gap: 14px;
  align-items: stretch;
}

.map-canvas {
  height: 480px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background:
    repeating-linear-gradient(45deg,
      var(--surface) 0 12px, var(--surface-2) 12px 24px);
  overflow: hidden;
  z-index: 0;   /* keeps Leaflet panes under the sticky masthead */
}

.map-canvas.picking { cursor: crosshair; }

.map-results {
  height: 480px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-right: 4px;
}

.result {
  display: block;
  width: 100%;
  text-align: left;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  cursor: pointer;
  transition: border-color 0.15s, transform 0.15s;
}

.result:hover { border-color: var(--accent); transform: translateY(-1px); }

.result-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
}

.result-distance {
  display: inline-block;
  margin-top: 6px;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-deep);
  font-size: 0.78rem;
}

.result-matches {
  list-style: none;
  margin: 8px 0 0;
  padding: 8px 0 0;
  border-top: 1px solid var(--line);
  font-size: 0.87rem;
}

.result-matches li {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2px 10px;
  padding: 3px 0;
}

.result-matches li strong { grid-row: span 2; align-self: center; }

.unlocated { margin-top: 26px; }
.card.static { cursor: default; }

.coord-help {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* Pins ------------------------------------------------------------------- */

.pin-wrap { background: none; border: 0; }

.pin {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 28px;
  padding: 0 9px;
  border-radius: 999px;
  border: 1.5px solid var(--accent);
  background: var(--surface);
  color: var(--ink);
  font-size: 0.8rem;
  font-weight: 700;
  white-space: nowrap;
  box-shadow: var(--shadow);
}

.pin-best {
  background: var(--tag);
  border-color: var(--tag);
  color: #241f05;
}

.pin-me {
  background: var(--accent);
  border-color: var(--accent-deep);
  color: #10210f;
}

.range-ring {
  stroke: var(--accent);
  stroke-width: 1.5;
  stroke-dasharray: 5 6;
  fill: var(--accent);
  fill-opacity: 0.06;
}

/* Popups ----------------------------------------------------------------- */

.map-canvas .leaflet-popup-content-wrapper,
.map-canvas .leaflet-popup-tip {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
}

.map-canvas .leaflet-popup-content { margin: 12px 14px; }
.map-canvas .leaflet-popup-content a { color: var(--accent); }
.map-canvas .leaflet-container a.leaflet-popup-close-button { color: var(--ink-soft); }

.pop h4 { margin: 0 0 2px; font-size: 1rem; }

.pop-distance {
  display: inline-block;
  margin-top: 6px;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-deep);
  font-size: 0.78rem;
}

.pop-matches {
  list-style: none;
  margin: 10px 0;
  padding: 10px 0 0;
  border-top: 1px solid var(--line);
  font-size: 0.87rem;
}

.pop-matches li {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 10px;
  padding: 4px 0;
}

.pop-matches li strong { grid-row: span 2; align-self: center; }
.pop-size, .pop-unit { color: var(--ink-soft); font-size: 0.8rem; }

/* Leaflet chrome --------------------------------------------------------- */

.map-canvas .leaflet-control-zoom a {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--line);
}

.map-canvas .leaflet-control-zoom a:hover { background: var(--surface-2); }

.map-canvas .leaflet-control-attribution {
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  color: var(--ink-soft);
  font-size: 0.7rem;
}

.map-canvas .leaflet-control-attribution a { color: var(--accent); }

@media (max-width: 760px) {
  .map-layout { grid-template-columns: 1fr; }
  .map-canvas { height: 340px; }
  .map-results { height: auto; max-height: 420px; }
}

  /* Store picker ------------------------------------------------------------
     A combobox over the licensed-store catalogue. The options list is
     positioned rather than inline so a long list doesn't shove the price
     field off the bottom of a phone screen mid-typing. */

  .store-picker { display: flex; flex-direction: column; gap: 8px; }

  .picker-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
  }

  .picker-head label {
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--ink-soft);
  }

  .linkish {
    border: 0;
    background: none;
    padding: 0;
    color: var(--accent);
    font: inherit;
    font-size: 0.83rem;
    font-weight: 700;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 3px;
  }

  .linkish:hover { color: var(--accent-deep); }

  .combo { position: relative; }
  .combo input { width: 100%; }

  #store-options {
    position: absolute;
    z-index: 5;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    max-height: 262px;
    overflow-y: auto;
    margin: 0;
    padding: 5px;
    list-style: none;
    background: var(--surface-2);
    border: 1.5px solid var(--line);
    border-radius: 12px;
    box-shadow: var(--shadow);
  }

  #store-options li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 9px 10px;
    border-radius: 8px;
    cursor: pointer;
  }

  #store-options li.empty {
    cursor: default;
    color: var(--ink-soft);
    font-size: 0.87rem;
    justify-content: flex-start;
  }

  #store-options li:hover,
  #store-options li.active {
    background: var(--accent-soft);
  }

  .option-main { display: flex; flex-direction: column; min-width: 0; }

  .option-name {
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .option-main .small {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .option-meta {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    flex: 0 0 auto;
    text-align: right;
  }

  .option-distance {
    font-weight: 800;
    font-size: 0.85rem;
    color: var(--tag);
  }

  .chosen-store {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 11px 13px;
    border: 1.5px solid var(--accent);
    background: var(--accent-soft);
    border-radius: 12px;
  }

  .chosen-store strong { display: block; }

  /* With a store chosen, the search box has nothing left to do. */
  .store-picker.has-store .combo { display: none; }

  .manual-store {
    margin: 2px 0 0;
    padding: 13px;
    border: 1.5px dashed var(--line);
    border-radius: 12px;
  }

  @media (max-width: 520px) {
    #store-options li { padding: 11px 10px; }
    .option-meta { min-width: 62px; }
  }

  /* Product photo ------------------------------------------------------------
     Hidden until we know whether a picture already exists, so the form isn't
     asking for something nobody needs. */

  .photo-field { display: flex; flex-direction: column; gap: 8px; }

  .photo-field .picker-head span:first-child {
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--ink-soft);
  }

  .photo-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

  .photo-preview {
    display: flex;
    align-items: center;
    gap: 10px;
  }

  .photo-preview img {
    width: 64px;
    height: 64px;
    object-fit: cover;
    border-radius: 10px;
    border: 1.5px solid var(--line);
    background: var(--bg);
  }

  .photo-pick { display: inline-flex; }
  .photo-pick .button { cursor: pointer; }

  /* Deal dots ----------------------------------------------------------------
     How this price compares with the citywide median for the same product,
     per unit. The glyph inside carries the same meaning as the colour: a
     red-green scale that relies on colour alone is unreadable to roughly one
     man in twelve. */

  .deal-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 17px;
    height: 17px;
    margin-left: 6px;
    border-radius: 50%;
    font-size: 0.68rem;
    font-weight: 800;
    line-height: 1;
    vertical-align: middle;
    cursor: help;
  }

  .deal-cheap     { background: #2f7d43; color: #eaffee; }
  .deal-average   { background: #7a6420; color: #fff6dd; }
  .deal-expensive { background: #8e3a34; color: #ffecea; }

  .deal-unknown {
    background: transparent;
    color: var(--ink-soft);
    border: 1.5px dashed var(--line);
  }

  .deal-legend {
    margin: 10px 0 0;
    display: flex;
    align-items: center;
    gap: 4px;
    flex-wrap: wrap;
  }

  .deal-legend .deal-dot { margin-left: 2px; margin-right: 2px; }

  /* The colours above are chosen for contrast against the dark surface rather
     than for hue alone, so they stay distinguishable in greyscale too. */

/* Shopping list and cart ---------------------------------------------------
   Two screens with one idea between them: a list is a want, a cart is a
   decision. The list is a stack of items with three ways to buy each; the
   cart is a column per shop, with cards you can drag between them. */

.nav-count {
  display: inline-block;
  min-width: 18px;
  margin-left: 6px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 0.75rem;
  font-weight: 700;
  text-align: center;
}

.who { margin: 0 0 14px; }

.list-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

.inline-field {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--ink-soft);
  font-size: 0.9rem;
}

.inline-field.checkbox { cursor: pointer; }

/* --- List items --------------------------------------------------------- */

.list-item {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin-bottom: 12px;
}

.list-item-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
}

.list-item h3 { margin: 0 0 2px; font-size: 1.05rem; }

.list-item-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

.qty { color: var(--ink-soft); font-variant-numeric: tabular-nums; }

.icon-button {
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink-soft);
  border-radius: 8px;
  width: 26px;
  height: 26px;
  line-height: 1;
  cursor: pointer;
  font-size: 1rem;
}

.icon-button:hover { color: var(--ink); border-color: var(--accent); }

/* Three ways to buy the same thing, side by side. None of them is the
   "right" one, which is why they are all buttons rather than one default. */
.pills { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 12px; }

.pill {
  display: flex;
  align-items: baseline;
  gap: 7px;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--ink);
  cursor: pointer;
  font: inherit;
  font-size: 0.9rem;
}

.pill:hover { border-color: var(--accent); background: var(--accent-soft); }
.pill-label { color: var(--accent); font-weight: 700; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; }
/* .pill-store was removed: no markup has rendered that class for some time,
   and leaving the rule here is what made a selector for it look deliberate. */
.empty-pill { color: var(--ink-soft); border-style: dashed; cursor: default; }

.list-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

/* --- Cart columns ------------------------------------------------------- */

.cart-columns {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 14px;
  align-items: start;
}

.cart-column {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px;
  min-height: 130px;
  transition: border-color 0.12s, background 0.12s;
}

/* The drop target lights up, because a drag with no feedback is a guess. */
.cart-column.over {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.cart-column header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  padding-bottom: 10px;
  margin-bottom: 10px;
  border-bottom: 1px solid var(--line);
}

.cart-column h3 { margin: 0; font-size: 0.98rem; flex: 1 1 100%; }
.column-total { margin-left: auto; color: var(--tag); font-weight: 700; }
.drop-hint { border: 1px dashed var(--line); border-radius: 10px; padding: 14px; text-align: center; }

.cart-card {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 10px;
  margin-bottom: 9px;
  cursor: grab;
}

.cart-card:active { cursor: grabbing; }
.cart-card.dragging { opacity: 0.45; }

.cart-card-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 8px;
}

.cart-card-price { margin: 5px 0; display: flex; align-items: baseline; gap: 7px; }

.cart-card-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 8px;
}

.move-select {
  flex: 1 1 100%;
  margin-top: 4px;
  font-size: 0.82rem;
}

/* A price that has moved since it went in the cart. The cart keeps what was
   agreed; this is the offer to update it, never an automatic change. */
.drift {
  font-size: 0.82rem;
  color: var(--warn);
  margin: 4px 0;
}

/* --- The plan ----------------------------------------------------------- */

.plan {
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  padding: 16px 18px;
  margin-bottom: 20px;
}

.plan-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px; }
.plan-message { margin: 0 0 4px; font-size: 1.08rem; font-weight: 600; }

.plan-figures {
  display: flex;
  gap: 28px;
  flex-wrap: wrap;
  margin: 14px 0;
}

.plan-figures dt { color: var(--ink-soft); font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.04em; }
.plan-figures dd { margin: 3px 0 0; font-size: 1.25rem; font-weight: 700; }
.saving { color: var(--accent); }
.plan-table { margin-top: 8px; }
.plan-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 12px; }

@media (max-width: 620px) {
  .cart-columns { grid-template-columns: 1fr; }
  .plan-figures { gap: 18px; }
}

/* Supermarket affordances ---------------------------------------------------
   A card is a thing you can buy, not just a link to a page. The two actions
   a shopper actually wants sit on the card itself. */

.card { display: flex; flex-direction: column; text-align: left; padding: 0; overflow: hidden; }

.card-open {
  flex: 1;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  padding: 16px 16px 10px;
  cursor: pointer;
  width: 100%;
}

.card-actions {
  display: flex;
  gap: 8px;
  padding: 0 16px 14px;
}

.chip-button {
  flex: 1;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--ink-soft);
  font: inherit;
  font-size: 0.84rem;
  font-weight: 600;
  cursor: pointer;
}

.chip-button:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
}

/* --- Typing something onto the list ------------------------------------- */

.add-box {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-bottom: 16px;
}

.add-row { display: flex; gap: 10px; align-items: center; }
.add-row input { flex: 1; }
.button.round { width: 38px; height: 38px; border-radius: 50%; padding: 0; font-size: 1.3rem; line-height: 1; }

.add-results { list-style: none; margin: 10px 0 0; padding: 0; }

.add-results li button {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  text-align: left;
  padding: 9px 10px;
  border: 0;
  border-radius: 10px;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.add-results li button:hover { background: var(--surface-2); }
.add-miss { padding: 9px 10px; color: var(--ink-soft); font-size: 0.9rem; }

/* --- Ticking things off -------------------------------------------------- */

.list-item-head { gap: 12px; }

.tick {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  margin-top: 2px;
  border: 2px solid var(--line);
  border-radius: 50%;
  background: none;
  color: var(--accent);
  font-size: 0.95rem;
  line-height: 1;
  cursor: pointer;
}

.tick[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-soft); }

/* Crossed off, not gone: you want to see what is already in the trolley. */
.list-item.checked { opacity: 0.55; }
.list-item.checked h3 { text-decoration: line-through; }

.no-price { margin: 8px 0 0; font-size: 0.88rem; color: var(--warn); }

/* --- Shops --------------------------------------------------------------- */

.sub-head { margin: 22px 0 10px; font-size: 1rem; color: var(--ink-soft); }

.chosen-shops { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 6px; }

.shop-chip {
  padding: 7px 12px;
  border: 1px solid var(--accent);
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font: inherit;
  font-size: 0.88rem;
  cursor: pointer;
}

.shop-rows { display: flex; flex-direction: column; gap: 8px; }

.shop-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  text-align: left;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.shop-row:hover { border-color: var(--accent); }
.shop-row.on { border-color: var(--accent); background: var(--accent-soft); }
.shop-name { display: flex; flex-direction: column; flex: 1; }

.shop-tick {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  color: var(--accent);
  display: grid;
  place-items: center;
  font-size: 0.9rem;
}

.shop-row.on .shop-tick { border-color: var(--accent); background: var(--accent-soft); }


/* Pictures ------------------------------------------------------------------
   Every product shows something. A real photo where one exists, a drawn tile
   derived from the product's own category and name where none does — stable,
   distinguishable at a glance, and never mistakable for a photograph. */

.product-image {
  display: block;
  flex-shrink: 0;
  width: 52px;
  height: 52px;
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface-2);
}

.product-image.sm { width: 34px; height: 34px; border-radius: 8px; }
.product-image.lg { width: 64px; height: 64px; border-radius: 12px; }

.product-image img,
.product-image .product-art {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}

/* The drawn tile sits behind the photo and takes over if it fails to load. */
.product-image img + .product-art { display: none; }

.card-top { display: flex; gap: 12px; align-items: flex-start; }
.card-top h3 { margin: 0 0 3px; }

/* Shops ---------------------------------------------------------------------
   A shop tile is wider than a product tile because the useful thing about it
   is the storefront: you recognise the awning before you read the name. */

.store-image {
  display: block;
  flex-shrink: 0;
  width: 64px;
  height: 64px;
  border-radius: 12px;
  overflow: hidden;
  background: var(--surface-2);
}

.store-image.xl { width: 108px; height: 108px; border-radius: 16px; }

.store-image img,
.store-image .store-art {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}

.store-image img + .store-art { display: none; }

.store-marks {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}

.store-card .card-open { text-align: left; }

.store-hero {
  display: flex;
  gap: 18px;
  align-items: flex-start;
  flex-wrap: wrap;
  margin: 18px 0 28px;
}

.store-hero-copy { flex: 1 1 260px; }
.store-hero-copy h2 { margin: 0 0 4px; font-size: 1.5rem; letter-spacing: -0.01em; }
.store-hero-actions { margin-top: 14px; }

/* The rail ------------------------------------------------------------------
   Horizontal, snapping, and it keeps its scrollbar off the page. A taster of
   the Stores tab rather than a second copy of it. */

.rail-block { margin-bottom: 26px; }

.rail {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  padding: 2px 2px 12px;
  scrollbar-width: thin;
}

.rail-card {
  flex: 0 0 auto;
  width: 190px;
  scroll-snap-align: start;
  padding: 12px;
}

.rail-card .card-open {
  display: block;
  width: 100%;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-align: left;
}

.rail-card h3 {
  margin: 10px 0 2px;
  font-size: 0.95rem;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.rail-card .store-marks { margin-top: 8px; }

.cart-card-head { align-items: center; }
.cart-card-head strong { flex: 1; }

/* Where you can buy it ------------------------------------------------------
   A list, not a single recommendation. The cheapest shop may be the one you
   are never near, and forty cents does not beat a shop on the way home. */

.list-item-title { flex: 1; }

.store-options {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 12px;
}

.store-options .option-slot.extra { display: none; }
.store-options.expanded .option-slot.extra { display: block; }

.store-option {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  text-align: left;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-2);
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.store-option:hover { border-color: var(--accent); background: var(--accent-soft); }

.option-price {
  flex-shrink: 0;
  min-width: 88px;
  display: flex;
  align-items: baseline;
  gap: 5px;
  font-size: 1.02rem;
}

.option-store { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.option-name { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.option-meta { display: flex; flex-direction: column; align-items: flex-end; flex-shrink: 0; }

.option-add {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 1px solid var(--line);
  color: var(--accent);
  display: grid;
  place-items: center;
  font-size: 1rem;
}

.store-option:hover .option-add { border-color: var(--accent); background: var(--accent-soft); }

.badge {
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 2px 7px;
  border-radius: 999px;
  border: 1px solid currentColor;
}

.badge-cheapest { color: var(--accent); }
.badge-nearest { color: var(--tag); }
.badge-verified { color: var(--accent-deep); }
.badge-open { color: var(--accent); }
.badge-shut { color: var(--ink-soft); }

.more-stores { margin-top: 9px; }

/* Choosing from the offers table -------------------------------------------
   Thirty-one shops sell Gala apples; four are ones you'd walk to. The table
   needs to be something you filter and act on, not just read. */

.offer-filters {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin: 14px 0 10px;
}

.offer-filters .map-search { flex: 1; min-width: 180px; max-width: 320px; }

/* A star, because favouriting a shop from the row you are already looking at
   is easier than remembering to go to another tab. */
.star {
  border: 0;
  background: none;
  color: var(--ink-soft);
  font-size: 1.05rem;
  line-height: 1;
  padding: 0 6px 0 0;
  cursor: pointer;
}

.star:hover { color: var(--tag); }
.star.on { color: var(--tag); }

.offers td .chip-button { white-space: nowrap; padding: 6px 12px; }

@media (max-width: 620px) {
  .offer-filters .map-search { max-width: none; }
}

/* 🐇 Hops --------------------------------------------------------------------
   The reward for an unpaid chore done in a shop aisle. Warm, a bit silly, and
   honest: the level is decoration and never gates anything. */

.hop-hero {
  display: flex;
  align-items: center;
  gap: 28px;
  flex-wrap: wrap;
  padding: 20px 22px;
  margin-bottom: 18px;
  background: linear-gradient(135deg, var(--accent-soft), var(--surface));
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.hop-total { display: flex; align-items: center; gap: 14px; }
.hop-bunny { font-size: 2.6rem; line-height: 1; }
.hop-number { font-size: 2.4rem; font-weight: 800; color: var(--accent); line-height: 1; }

.hop-level { flex: 1; min-width: 220px; }
.hop-level-name { font-size: 1.15rem; font-weight: 700; }

.hop-bar {
  height: 9px;
  margin: 9px 0 5px;
  background: var(--surface-2);
  border-radius: 999px;
  overflow: hidden;
}

.hop-bar span {
  display: block;
  height: 100%;
  width: 0;
  background: var(--accent);
  border-radius: 999px;
  transition: width 0.4s ease;
}

.hop-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 12px;
  margin-bottom: 8px;
}

.hop-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.hop-card.bounty { border-color: var(--tag); }
.hop-card.locked { opacity: 0.6; }
.hop-card.coupon { border-style: dashed; border-color: var(--accent); }

.hop-card-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; }
.hop-card-head strong { line-height: 1.3; }

.hop-pill {
  flex-shrink: 0;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 0.82rem;
  font-weight: 700;
  white-space: nowrap;
}

.hop-card.bounty .hop-pill { background: var(--tag-soft); color: var(--tag); }

.hop-card-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-top: auto;
  padding-top: 8px;
}

.coupon-code {
  font-size: 1.15rem;
  letter-spacing: 0.08em;
  padding: 8px 10px;
  text-align: center;
  background: var(--surface-2);
  border-radius: 8px;
  color: var(--tag);
}

.hop-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 26px;
  margin-top: 24px;
}

.hop-rules, .hop-ledger { list-style: none; margin: 0; padding: 0; }

.hop-rules li, .hop-ledger li {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
}

.hop-rules li span:nth-child(2), .hop-ledger li span:nth-child(2) {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.hop-rules li.soon { opacity: 0.5; }

.hop-rule-hops {
  min-width: 40px;
  font-weight: 800;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.hop-rule-hops.spent { color: var(--ink-soft); }

/* Search by photo ------------------------------------------------------------
   The barcode scanner answers "what is this exact thing"; the lens answers
   "what is this, roughly" — the question you have when the barcode is
   scratched or the thing is a loose apple. It shows a ranked list, never a
   verdict. */

#lens-dialog { max-width: 560px; width: calc(100vw - 32px); }

.lens-stage {
  display: grid;
  place-items: center;
  padding: 34px 16px;
  margin: 14px 0;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
}

.lens-preview {
  display: flex;
  gap: 14px;
  align-items: center;
  margin: 14px 0;
}

.lens-preview img {
  width: 92px;
  height: 92px;
  object-fit: cover;
  border-radius: 12px;
  background: var(--surface-2);
}

.lens-status { margin: 0 0 4px; font-weight: 600; }

.lens-list { display: flex; flex-direction: column; gap: 8px; margin: 12px 0; }

.lens-hit {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
}

.lens-hit-body { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.lens-hit-actions { display: flex; flex-direction: column; gap: 6px; flex-shrink: 0; }

.lens-confidence {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
  font-size: 0.8rem;
  color: var(--ink-soft);
}

.lens-bar {
  width: 64px;
  height: 5px;
  border-radius: 999px;
  background: var(--surface-2);
  overflow: hidden;
}

.lens-bar i { display: block; height: 100%; background: var(--accent); }
.lens-none { margin-top: 6px; }

/* A starred product ---------------------------------------------------------
   The same star as a favourite shop, on the thing rather than the place. */
.button.starred { color: var(--tag); border-color: var(--tag); }

/* Phones ---------------------------------------------------------------------
   Everything added since the original breakpoint was written: the offers
   table gained an action column, the list gained store rows, the cart gained
   columns, and Hops gained a hero. None of it had been looked at below
   420px. */

@media (max-width: 620px) {
  /* The offers table now has seven columns. Rather than squeeze them, the
     ones a shopper can live without on a phone step aside: they are still in
     the DOM for anyone widening the window or using a screen reader on a
     tablet, and the price, the shop and the button are what remain. */
  table.offers th:nth-child(4),
  table.offers td:nth-child(4),
  table.offers th:nth-child(6),
  table.offers td:nth-child(6) { display: none; }

  table.offers th, table.offers td { padding: 8px 8px; }
  .offers td .chip-button { padding: 8px 10px; font-size: 0.8rem; }

  /* Filters stack instead of squashing. */
  .offer-filters { gap: 8px; }
  .offer-filters .sort-toggle { width: 100%; }
  .offer-filters .sort-toggle button { flex: 1; }

  /* A store option is three columns of text on a desktop and two lines on a
     phone; the price stays on its own line so it is scannable down the page. */
  .store-option { flex-wrap: wrap; row-gap: 4px; }
  .option-price { min-width: 0; flex: 1 0 auto; }
  .option-meta { flex-direction: row; gap: 8px; align-items: baseline; width: 100%; }
  .option-add { margin-left: auto; }

  /* One column of cart, one column of Hops. */
  .cart-columns, .hop-cards { grid-template-columns: 1fr; }
  .hop-hero { gap: 16px; padding: 16px; }
  .hop-number { font-size: 2rem; }
  .plan-figures { gap: 14px; }
  .plan-figures dd { font-size: 1.05rem; }
  .plan-head { flex-direction: column; gap: 8px; }

  /* The list bar is four controls; let them wrap rather than shrink. */
  .list-bar { gap: 8px; }
  .list-bar .inline-field, .list-bar .button { flex: 1 1 auto; }
  .add-row input { min-width: 0; }

  /* Search-by-photo results: the thumbnail and the two buttons cannot all sit
     on one line at 360px. */
  .lens-hit { flex-wrap: wrap; }
  .lens-hit-body { flex: 1 1 60%; }
  .lens-hit-actions { flex-direction: row; width: 100%; }
  .lens-hit-actions .chip-button { flex: 1; }
  .lens-preview img { width: 72px; height: 72px; }

  /* A dialog on a phone should reach the edges rather than float in a box. */
  #lens-dialog, #submit-dialog, #scan-dialog { width: calc(100vw - 16px); }
}

/* Very narrow — an iPhone SE is 320px. */
@media (max-width: 380px) {
  /* The camera buttons keep their icons and drop their words: "Photo" and
     "Scan" are what the icons already say, and the two words cost the row. */
  .lens-button span, .scan-button span { display: none; }
  .brand-word { font-size: 1.25rem; }
  .stats { grid-template-columns: 1fr; }
}

/* Seller mode --------------------------------------------------------------

   A shop administrating itself. Visually quieter than the shopper-facing
   screens on purpose: this is a back office, and it should not compete with
   the price cards for attention.
   -------------------------------------------------------------------------- */

/* A horizontal group that wraps rather than overflowing. Used throughout the
   seller forms, where a label, two inputs and a button share a line on a
   laptop and stack on a phone. */
.row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.row.small > span { color: var(--ink-soft); font-size: 0.87rem; }

#view-business input,
#view-business select {
  padding: 9px 12px;
  border-radius: 10px;
  border: 1.5px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 0.93rem;
  min-width: 0;
}

#view-business input:focus,
#view-business select:focus {
  outline: none;
  border-color: var(--accent);
}

#view-business input::placeholder { color: var(--ink-soft); }

#view-business h2 { margin: 0 0 4px; }
#view-business h3 { margin: 0; font-size: 1.05rem; }

/* Sign in ------------------------------------------------------------------ */

.business-auth {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 420px;
  margin-top: 16px;
}

.field-label {
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--ink-soft);
  margin-bottom: -4px;
}

/* An error under a form is only useful if it does not read like help text. */
.bad { color: var(--warn); font-weight: 600; }

.button[disabled] { opacity: 0.55; cursor: default; }
.button[disabled]:active { transform: none; }

/* Signed in ---------------------------------------------------------------- */

.business-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}

.business-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  margin-bottom: 18px;
}

.business-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

/* Open / closed. The one thing on this screen worth reading from across the
   room, so it gets the only strong colour here. */
.business-status {
  font-size: 0.87rem;
  font-weight: 700;
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--ink-soft);
}

.business-status.open {
  background: var(--accent-soft);
  color: var(--accent-deep);
}

.business-status.shut {
  background: var(--tag-soft);
  color: var(--warn);
}

/* The schedule, and the price list — same row shape for both ---------------- */

.appearance-list {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.appearance-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--surface-2);
  border: 1px solid var(--line);
}

/* Paused, or a price past its authoritative window. Dimmed rather than
   hidden: it is still there, it just is not doing anything. */
.appearance-row.inactive {
  opacity: 0.55;
}

.appearance-row strong { margin-right: 8px; }

/* A location the appearance carries itself, as opposed to the shop's own.
   Worth marking, because it is the difference between "we open at nine" and
   "we are somewhere else that day". */
.appearance-where {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-deep);
  font-size: 0.8rem;
  font-weight: 700;
}

.button.small {
  padding: 6px 12px;
  font-size: 0.83rem;
}

/* Add a time --------------------------------------------------------------- */

.appearance-add {
  margin-top: 16px;
  border-top: 1px solid var(--line);
  padding-top: 14px;
}

.appearance-add summary {
  cursor: pointer;
  font-weight: 700;
  font-size: 0.93rem;
  color: var(--accent);
}

.appearance-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 14px;
}

.appearance-form input[type="time"],
.appearance-form input[type="date"] { flex: 0 0 auto; }

#appearance-address,
#business-barcode,
#business-product { flex: 1 1 160px; }

@media (max-width: 620px) {
  /* On a phone every field takes the full width; a half-width latitude box
     next to a half-width longitude box is unusable at 360px. */
  .appearance-form .row > input,
  .appearance-form .row > select { flex: 1 1 100%; }

  .business-head { flex-direction: column; }
  .appearance-row { align-items: flex-start; }
}

/* Seller mode: a price row that turns into a form -------------------------- */

.price-edit {
  width: 92px;
  padding: 6px 10px;
  border-radius: 8px;
}

/* A shopper's price that does not match the shop's own is the only row on
   this list worth acting on, so it is the only one that draws the eye. */
.appearance-row.disagrees { border-color: var(--warn); }

.field-row { margin-bottom: 10px; }
.field-row .field-label { display: block; margin-bottom: 4px; }
.field-row input,
.field-row select { width: 100%; }

#business-new summary { cursor: pointer; padding: 4px 0; }

/* Neighbourhood analytics ---------------------------------------------------
   The seller's stats block reuses the home page's, at a smaller size. */

.insight-heading {
  margin: 18px 0 8px;
  font-size: 0.92rem;
  font-weight: 800;
  color: var(--ink-soft);
}

#business-insight-stats { grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 12px 0 0; }
#business-insight-stats dd { font-size: 1.1rem; }

.popular-card .price { display: block; margin-top: 6px; font-weight: 800; }

/* One add-price form, two callers ------------------------------------------ */

.seller-banner {
  margin: 10px 0 0;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1.5px solid var(--accent);
  background: var(--accent-soft);
  font-size: 0.9rem;
}

/* The barcode / loose switch. Reuses the category chip styling so it reads as
   the same kind of control people already use on Products. */
#identity-mode { margin-bottom: 10px; }
#identity-field .field-grid { margin: 0; }
#identity-hint { margin: 4px 0 0; }
