/* Mobile-first: the base rules are the phone layout; the 40rem breakpoint
   (plus 48rem for the header row and 64rem for the listing's map column)
   restores multi-column layouts. The stations listing swaps table rows for
   cards below 40rem. */

/* Two families of color, never mixed: --accent (blue) is the interface —
   links, buttons, active chips, the chart line; green/amber/red are reserved
   for state (semáforo, deltas) so they keep their meaning. Status colors
   never appear without a text label next to them. */
:root {
  --bg: #f6f7f9;
  --ink: #16181b;
  --muted: #566068;
  --panel: #ffffff;
  --line: #dfe3e7;
  --accent: #256abf;
  --accent-soft: #e4eefb;
  --ok: #0e7a4e;
  --ok-soft: #e3f0e8;
  --warn: #8a6116;
  --warn-soft: #f6ecd9;
  --danger: #a33325;
  --danger-soft: #f7e3e0;
  --radius: 8px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  line-height: 1.55;
}

a { color: var(--accent); }
button { font: inherit; }

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

h1 {
  font-size: clamp(1.35rem, 2.8vw + 0.8rem, 2rem);
  line-height: 1.25;
}

h2 { font-size: 1.05rem; }

/* ---- Header: brand + nav on the first row, search bar full width below;
   one single row from 48rem up. ---- */

.header {
  border-bottom: 1px solid var(--line);
  background: var(--panel);
  padding: 0.6rem 1rem;
}

.header-inner {
  max-width: 64rem;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
}

.brand {
  font-weight: 700;
  text-decoration: none;
  color: var(--ink);
  white-space: nowrap;
}

.search-bar {
  position: relative;
  display: flex;
  gap: 0.4rem;
  flex: 1 1 100%;
  /* As a flex item its automatic minimum is the input's intrinsic width
     (~20ch), which overflows narrow phones — allow it to shrink. */
  min-width: 0;
}

.search-bar input {
  flex: 1;
  min-width: 0;
  min-height: 2.75rem;
  padding: 0.4rem 0.75rem;
  font: inherit;
  color: inherit;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.search-submit {
  min-height: 2.75rem;
  padding: 0 1rem;
  border: none;
  border-radius: var(--radius);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
}

.search-geo {
  min-height: 2.75rem;
  min-width: 2.75rem;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
  cursor: pointer;
}

.search-geo:disabled { opacity: 0.6; cursor: wait; }

.search-suggestions {
  position: absolute;
  top: calc(100% + 0.25rem);
  left: 0;
  right: 0;
  z-index: 100;
}

/* Geolocation failure notice: floats under the bar like the suggestions. */
.search-bar .geo-error {
  position: absolute;
  top: calc(100% + 0.25rem);
  right: 0;
  z-index: 100;
  margin: 0;
  padding: 0.5rem 0.75rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--muted);
  font-size: 0.85rem;
  box-shadow: 0 8px 24px rgba(23, 33, 27, 0.12);
}

.search-suggestions .suggestion-list,
.search-suggestions .suggestion-empty {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(23, 33, 27, 0.12);
}

.suggestion-list {
  list-style: none;
  margin: 0;
  padding: 0.25rem;
  max-height: 60vh;
  overflow-y: auto;
}

.suggestion-list a {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.6rem 0.75rem;
  border-radius: 6px;
  text-decoration: none;
  color: var(--ink);
}

.suggestion-list a:hover,
.suggestion-list a:focus-visible { background: var(--accent-soft); }

.suggestion-label { min-width: 0; }
.suggestion-kind {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: 0.75rem;
}

.suggestion-empty {
  margin: 0;
  padding: 0.75rem;
  color: var(--muted);
  font-size: 0.9rem;
}

/* The /buscar results page reuses the same list, statically. */
.search-results { margin-top: 1rem; }
.search-results .suggestion-list {
  max-height: none;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.search-results .suggestion-list li + li { border-top: 1px solid var(--line); }
.search-results .suggestion-empty { color: var(--muted); }

@media (min-width: 48rem) {
  .header-inner { flex-wrap: nowrap; }
  .search-bar {
    flex: 1 1 auto;
    max-width: 32rem;
    margin-left: auto;
  }
}

/* ---- Page scaffold ---- */

.page {
  max-width: 64rem;
  margin: 0 auto;
  padding: 1.25rem 1rem 3rem;
}

.hero h1 { margin: 0.5rem 0 0.4rem; }
.hero p { color: var(--muted); margin-top: 0; }

/* ---- Home stat tiles: today's national average per fuel + weekly delta. ---- */

.stat-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.6rem;
  margin: 1.25rem 0 0.4rem;
}

.stat-tile {
  display: flex;
  flex-direction: column;
  gap: 0.05rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.7rem 0.9rem;
}

.stat-label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}

.stat-value {
  font-size: 1.35rem;
  font-weight: 700;
  line-height: 1.25;
}

.stat-delta { font-size: 0.8rem; }

.stat-source {
  color: var(--muted);
  font-size: 0.85rem;
  margin: 0 0 0.5rem;
}

@media (min-width: 40rem) {
  .stat-grid { grid-template-columns: repeat(4, 1fr); }
}

.province-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
  gap: 0.6rem;
  margin-top: 0.75rem;
}

.province-card {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.15rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.7rem 0.9rem;
  min-height: 2.75rem;
  text-decoration: none;
}

.province-name { font-weight: 650; color: var(--ink); }
.province-count { font-size: 0.8rem; color: var(--muted); }

/* ---- Product picker: one scrollable, thumb-sized row that stays pinned
   while the listing scrolls; a plain wrapping row from 40rem up. ---- */

.product-picker {
  display: flex;
  gap: 0.5rem;
  margin: 1rem 0 1.25rem;
  overflow-x: auto;
  padding: 0.5rem 0;
}

#listing .product-picker {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--bg);
}

.chip {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  min-height: 2.6rem;
  border: 1px solid var(--line);
  background: var(--panel);
  border-radius: 999px;
  padding: 0.4rem 1rem;
  font-size: 0.9rem;
  text-decoration: none;
  color: var(--ink);
}

.chip-active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

@media (min-width: 40rem) {
  .product-picker { flex-wrap: wrap; overflow-x: visible; }
  #listing .product-picker { position: static; }
}

/* HTMX feedback: while a swap is in flight the target dims and ignores taps. */
#listing.htmx-request,
#historial.htmx-request,
#informe-provincias.htmx-request {
  opacity: 0.45;
  pointer-events: none;
  transition: opacity 0.15s ease;
}

/* ---- Tables. .price-table is the shared table skin (station page, weekly
   report); .stations-table is the listing variant that becomes cards below
   40rem. ---- */

.price-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  font-size: 0.92rem;
}

.price-table th,
.price-table td {
  text-align: left;
  padding: 0.55rem 0.8rem;
  border-bottom: 1px solid var(--line);
}

.price-table th {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.price-table tr:last-child td { border-bottom: none; }

.price-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-weight: 650;
  white-space: nowrap;
}

.price-table .empty { color: var(--muted); text-align: center; }

.col-station a {
  font-weight: 650;
  text-decoration: none;
}
.col-station a:hover { text-decoration: underline; }

.cell-sub {
  display: block;
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 400;
}

.stations-table tbody tr:hover { background: var(--accent-soft); }

/* Rows highlight their marker on the map (map.js); the pointer only where a
   map actually exists — #map and the results wrapper are siblings inside
   #listing. */
#map ~ .listing-results .stations-table tbody tr { cursor: pointer; }

@media (max-width: 39.999rem) {
  .stations-table,
  .stations-table td { display: block; }
  .stations-table thead { display: none; }
  .stations-table {
    border: none;
    background: none;
    overflow: visible;
    font-size: 0.9rem;
  }
  .stations-table tbody {
    display: grid;
    gap: 0.6rem;
  }
  .stations-table tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 0.1rem 0.75rem;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 0.7rem 0.85rem;
  }
  .stations-table tbody tr:hover { background: var(--panel); }
  .stations-table td {
    padding: 0;
    border: none;
    min-width: 0;
  }
  .stations-table .col-station {
    grid-column: 1;
    grid-row: 1;
    font-weight: 650;
  }
  .stations-table .col-price {
    grid-column: 2;
    grid-row: 1;
    align-self: start;
    font-size: 1.2rem;
  }
  .stations-table .col-place {
    grid-column: 1;
    grid-row: 2;
    color: var(--muted);
    font-size: 0.85rem;
  }
  .stations-table .col-place .cell-sub {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .stations-table .col-distance {
    grid-column: 2;
    grid-row: 2;
    align-self: end;
    font-weight: 500;
    font-size: 0.85rem;
    color: var(--muted);
  }
  .stations-table .empty {
    grid-column: 1 / -1;
    padding: 0.5rem 0;
  }
}

.station-meta { color: var(--muted); overflow-wrap: anywhere; }

.breadcrumb { font-size: 0.85rem; margin-bottom: 0.5rem; }
.breadcrumb a { text-decoration: none; }

/* ---- Municipality index: full-width tappable rows, columns from 40rem. ---- */

.muni-section { margin-top: 2.5rem; }

.muni-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0 1.5rem;
  font-size: 0.9rem;
}

.muni-link {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  padding: 0.4rem 0.25rem;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
}

.muni-count { color: var(--muted); font-size: 0.8rem; flex: 0 0 auto; }

@media (min-width: 40rem) {
  .muni-grid { grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); }
}

.source {
  font-size: 0.8rem;
  color: var(--muted);
}

.near-btn {
  margin-top: 0.75rem;
  border: none;
  background: var(--accent);
  color: #fff;
  border-radius: 999px;
  padding: 0.7rem 1.4rem;
  min-height: 2.75rem;
  font-size: 1rem;
  cursor: pointer;
}

.near-btn:disabled { opacity: 0.6; cursor: wait; }

.near-error {
  color: var(--muted);
  font-size: 0.85rem;
}

/* ---- Map island. z-index: 0 fences Leaflet's internal z-indexes (up to
   1000) into their own stacking context, so the sticky picker and the search
   dropdown can sit above the map with small values. The station page keeps
   the map inline; inside #listing it is a full-screen layer below 64rem
   (map.js toggles .map-open) and a sticky side column from 64rem up, so the
   cheapest station is on the first screen at every width. ---- */

.map {
  position: relative;
  z-index: 0;
  height: min(45vh, 24rem);
  margin: 0 0 1.25rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

/* White pills floating over the map: the touch drag guard (station page)
   and the layer's close button. 1100 clears Leaflet's own panes. */
.map-guard,
.map-close {
  position: absolute;
  z-index: 1100;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--ink);
  padding: 0.45rem 1rem;
  font-size: 0.85rem;
  box-shadow: 0 2px 10px rgba(23, 33, 27, 0.18);
  cursor: pointer;
}

.map-guard {
  bottom: 0.75rem;
  left: 50%;
  transform: translateX(-50%);
}

.map-close {
  top: 0.75rem;
  right: 0.75rem;
}

/* Entry button to the layer, floating over the listing (map.js). */
.map-toggle {
  position: fixed;
  bottom: 1rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 150;
  min-height: 2.75rem;
  padding: 0 1.25rem;
  border: none;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  box-shadow: 0 2px 10px rgba(23, 33, 27, 0.18);
  cursor: pointer;
}

@media (max-width: 63.999rem) {
  #listing .map { display: none; }
  #listing .map.map-open {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 200;
    height: auto;
    margin: 0;
    border: none;
    border-radius: 0;
  }
  /* Inside the query so a resize past 64rem restores scrolling by itself. */
  body.map-open { overflow: hidden; }
}

@media (min-width: 64rem) {
  /* :has() keeps a listing without a map (no stations for this product)
     at full width instead of reserving an empty column. */
  #listing:has(.map) {
    display: grid;
    /* The table stops growing at a readable 40rem; the map takes the rest. */
    grid-template-columns: minmax(0, 40rem) minmax(24rem, 1fr);
    column-gap: 1.25rem;
    align-items: start;
  }
  /* Listing pages with a map may use wide screens: header and page widen
     together so the brand stays aligned with the content. */
  body:has(#listing .map) .header-inner,
  body:has(#listing .map) .page { max-width: 96rem; }
  #listing .product-picker { grid-column: 1 / -1; }
  /* Both columns share one height, --listing-height, set by map.js to the
     viewport minus everything above the listing: header, chips and the
     scrolling table fill the screen exactly like the map. Without the
     variable (no JS) the map keeps its sticky full-height column. */
  #listing .listing-results {
    grid-column: 1;
    grid-row: 2;
    height: var(--listing-height, auto);
    overflow-y: auto;
  }
  #listing .map {
    grid-column: 2;
    grid-row: 2;
    position: sticky;
    top: 1rem;
    height: var(--listing-height, calc(100vh - 2rem));
    margin: 0;
  }
  /* The column header stays visible while the panel scrolls; the shadow
     replaces the collapsed border, which would scroll away with the row. */
  #listing .stations-table thead th {
    position: sticky;
    top: 0;
    background: var(--panel);
    box-shadow: 0 1px 0 var(--line);
  }
  .map-toggle,
  .map-close { display: none; }
}

/* Price pills replace the default pin on listing maps (map.js), so the map
   itself compares prices. The cheapest gets --accent: emphasis, not state.
   `translate` centres the pill on its coordinate without touching the
   `transform` Leaflet positions the icon with; background and border are
   explicit so Leaflet's div-icon defaults never show through. */
.price-marker {
  translate: -50% -50%;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--ink);
  padding: 0.1rem 0.4rem;
  font-size: 0.78rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  line-height: 1.4;
  white-space: nowrap;
  box-shadow: 0 2px 10px rgba(23, 33, 27, 0.18);
}

.price-marker-min {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* ---- Station history ---- */

.history { margin-top: 2.5rem; }
.history .product-picker { margin: 0.6rem 0; }

.history-now { margin: 0.75rem 0 0.25rem; }

.semaforo {
  display: inline-block;
  border-radius: 999px;
  padding: 0.1rem 0.7rem;
  font-size: 0.8rem;
  font-weight: 650;
  margin-left: 0.4rem;
}

.semaforo-barata { background: var(--ok-soft); color: var(--ok); }
.semaforo-media { background: var(--warn-soft); color: var(--warn); }
.semaforo-cara { background: var(--danger-soft); color: var(--danger); }

.trend { color: var(--muted); font-size: 0.9rem; margin: 0.25rem 0 0.75rem; }
.trend strong { color: var(--ink); }

/* ---- Weekly report ---- */

.report-week { color: var(--muted); }
.report-section { margin-top: 2.5rem; }
.report-section h3 { font-size: 0.95rem; margin-bottom: 0.4rem; }
.report-lines { list-style: none; padding: 0; margin: 0.5rem 0 0; }
.report-lines li { padding: 0.45rem 0; border-bottom: 1px solid var(--line); }
.report-lines li:last-child { border-bottom: none; }
.report-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.5rem;
}
.delta-up { color: var(--danger); }
.delta-down { color: var(--ok); }
.delta-flat { color: var(--muted); }

/* ---- SVG chart: on narrow screens it keeps a legible width and scrolls
   sideways instead of shrinking its 12px labels into illegibility. ---- */

.chart-scroll { overflow-x: auto; }

.chart {
  display: block;
  width: 100%;
  min-width: 40rem;
  height: auto;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.chart-grid { stroke: var(--line); stroke-width: 1; }
.chart-line { fill: none; stroke: var(--accent); stroke-width: 2.5; }
.chart-dot { fill: var(--accent); }

.chart-ylabel {
  fill: var(--muted);
  font-size: 12px;
  text-anchor: end;
  font-variant-numeric: tabular-nums;
}

/* text-anchor comes from the SVG attribute: edge labels anchor inwards. */
.chart-xlabel {
  fill: var(--muted);
  font-size: 12px;
}

/* Hover/tap cursor; geo.js toggles .is-on and positions it. */
.chart-cursor { visibility: hidden; }
.chart-cursor.is-on { visibility: visible; }
.chart-cursor-line { stroke: var(--line); stroke-width: 1; }
.chart-cursor-dot { fill: var(--panel); stroke: var(--accent); stroke-width: 2.5; }
.chart-cursor-label {
  fill: var(--ink);
  font-size: 12px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  /* Panel-coloured halo so the text stays legible over the line and grid. */
  paint-order: stroke;
  stroke: var(--panel);
  stroke-width: 4px;
  stroke-linejoin: round;
}

.empty { color: var(--muted); }

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

.footer-nav { margin-bottom: 0.4rem; }
.footer-nav a { text-decoration: none; }
.footer-nav a:hover { text-decoration: underline; }

.error-page { text-align: center; padding-top: 4rem; }
