/* Page-specific layout. Components stay reusable; composition lives here. */

/* ================= home ================= */
.hero {
  background: var(--hero-bg); color: var(--hero-ink);
  border-radius: var(--r-lg); padding: var(--sp-7) var(--sp-5);
  margin-top: var(--sp-4);
}
.hero-inner { max-width: 640px; }
.hero h1 {
  font-size: var(--fs-hero); font-weight: 900; letter-spacing: -.035em;
  line-height: 1.04; margin-bottom: var(--sp-4);
}
.hero p { color: #cfc6e4; margin-bottom: var(--sp-5); }
.hero-search { display: flex; gap: var(--sp-2); align-items: center; max-width: 520px; }
.hero-search .field {
  flex: 1; display: flex; align-items: center; gap: var(--sp-2);
  background: var(--page); border-radius: var(--r-pill); padding: 12px 18px; color: var(--ink);
}
.hero-search input { flex: 1; border: 0; outline: 0; background: transparent; }
.hero-search .icon { color: var(--muted); width: 18px; height: 18px; }
.hero-stats {
  display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-5);
  margin-top: var(--sp-5); font-size: var(--fs-sm); color: #cfc6e4;
}
.hero-stats b { color: #fff; font-weight: 800; }
@media (min-width: 900px) { .hero { padding: var(--sp-8) var(--sp-7); } }

/* ================= product page ================= */
.crumbs {
  display: flex; gap: 6px; flex-wrap: wrap; min-width: 0;
  color: var(--muted); font-size: var(--fs-sm); padding: var(--sp-4) 0;
}
.crumbs a:hover { color: var(--link); }

.pd { display: grid; gap: var(--sp-6); min-width: 0; }
.pd > * { min-width: 0; }
@media (min-width: 900px) { .pd { grid-template-columns: 420px 1fr; align-items: start; } }

/* `isolation`: see .card-media. The hero blends too, and this is the largest
   blended surface on the site. */
.pd-media {
  position: relative; background: var(--surface); border-radius: var(--r-md);
  aspect-ratio: 1; display: grid; place-items: center; overflow: hidden;
  isolation: isolate;
}
.pd-media img { width: 100%; height: 100%; object-fit: contain; padding: 8%; mix-blend-mode: multiply; }
.pd-media .badge { position: absolute; top: 12px; left: 12px; }

/* The zoom affordance. Bottom-right, opposite the discount badge, and carrying
   its own translucent ground because it sits over a photograph we do not
   control. */
.pd-zoom {
  position: absolute; bottom: 12px; right: 12px;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 12px; border-radius: var(--r-pill);
  border: 0; background: rgba(255, 255, 255, .88);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  font-size: var(--fs-xs); font-weight: 700; color: var(--ink); cursor: zoom-in;
  transition: background .12s ease;
}
.pd-zoom .icon { width: 14px; height: 14px; }
.pd-zoom:hover { background: #fff; }
.pd-zoom:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }
/* `hidden` on a flex element loses to `display: inline-flex` without this — the
   button would be visible before main.js ever ran, and useless if it never
   did. */

/* The lightbox. A modal <dialog>, so the top layer, the focus trap and Escape
   are the browser's rather than ours. */
.lightbox {
  border: 0; padding: 0; margin: auto;
  /* Hugs the picture rather than sitting at a fixed width. Pinned to 1100px it
     letterboxed a square photograph inside 300px of empty panel on each side,
     which reads as a broken image rather than a considered frame. The cap still
     bounds it, so a zoomed image scrolls inside the dialog instead of growing
     past the window. */
  width: fit-content;
  max-width: min(1100px, 100vw - 2 * var(--sp-4));
  max-height: calc(100dvh - 2 * var(--sp-4));
  background: var(--page); border-radius: var(--r-lg);
  overflow: auto; overscroll-behavior: contain;
}
.lightbox::backdrop { background: rgba(15, 14, 17, .8); }
/* Fit to the window by default: the point is to see the whole picture larger
   than the 420px column showed it. */
.lightbox img {
  display: block; margin: 0 auto;
  max-width: 100%; max-height: calc(100dvh - 8 * var(--sp-4));
  object-fit: contain; cursor: zoom-in;
}
/* Natural size, and the dialog scrolls. `width: auto` rather than a scale
   transform: a transform leaves the element's layout box at its old size, so
   the dialog never gains anything to scroll and the enlarged image is simply
   clipped. */
.lightbox.is-zoomed img {
  max-width: none; max-height: none; width: auto; cursor: zoom-out;
}
.lightbox-x {
  position: sticky; top: 0; float: right; z-index: 1;
  width: 36px; height: 36px; margin: var(--sp-2);
  border: 0; border-radius: 50%; background: var(--surface);
  font-size: 20px; line-height: 1; color: var(--ink); cursor: pointer;
}
.lightbox-note {
  margin: 0; padding: var(--sp-3) var(--sp-4) var(--sp-4);
  text-align: center; font-size: var(--fs-xs); color: var(--muted); clear: both;
}

.pd-meta { margin-top: var(--sp-2); font-size: var(--fs-sm); }
/* Save, Price alert, Compare — one row, at every width.

   It used to wrap, and on a phone that meant three buttons on three lines
   below the title, each one 184px wide in a 358px column: a stack of stubs
   where a row of controls belongs. `nowrap` plus shrinkable buttons is what
   keeps them together; the labels shorten at the bottom of this file rather
   than the row breaking. */
.pd-actions {
  display: flex; align-items: center; gap: var(--sp-2);
  flex-wrap: nowrap; margin: var(--sp-4) 0;
}
/* Each control arrives wrapped — a form for Compare, a span for the alert
   button so htmx has an element to swap — and those wrappers were the flex
   items, so the three buttons could not share the row between them. The
   wrappers stay in the DOM for htmx to target and stop being boxes.

   (NOT `.cmp` — that is the comparison table on /compare/, which carries
   `width: 100%; min-width: 32rem`. Borrowed here it stretched the wrapper to
   the full column and pushed the second button onto its own line.) */
.pd-actions form,
.pd-actions .alert-button-wrap,
.pd-actions .compare-control { display: contents; }

/* Price alert and Compare.
   These were bare text with a `:hover` colour, and `.pd-action.is-on` set a
   border-color on an element that had no border to colour — so the chosen
   state was invisible. They are the two things this page asks a visitor to
   do; they get to look like controls, and they get to look the same as each
   other, because they sit side by side and neither outranks the other. */
.pd-action {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 9px 16px; border-radius: var(--r-pill);
  border: 1px solid var(--line); background: var(--page);
  font-size: var(--fs-sm); font-weight: 600; line-height: 1;
  color: var(--ink); cursor: pointer;
  transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.pd-action .icon { width: 16px; height: 16px; }
.pd-action:hover { background: var(--surface); border-color: #d4d4d9; }
.pd-action:active { transform: translateY(1px); }
.pd-action:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }

/* On. Filled rather than outlined, so "already chosen" reads at a glance
   without a second icon and without depending on colour alone — the label
   changes too. */
.pd-action.is-on {
  background: var(--cta); border-color: var(--cta); color: var(--cta-ink);
}
.pd-action.is-on:hover { background: #000; border-color: #000; }

/* How the three share the row.
   `auto` rather than `0`: they grow from their own labels, so "In comparison"
   keeps the width it needs while "Saved" gives its spare room away, instead of
   every button taking a rigid third and truncating the longest. `min-width: 0`
   is what lets any of them shrink at all — a flex item refuses to go below its
   content without it, which is how a tight row becomes an overflowing one. */
.pd-action { flex: 1 1 auto; min-width: 0; }
/* Last resort, below any width these labels were written for. */
.pd-action-label {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* A phone. Three controls in a 328px column is not the same design problem as
   three in 756px, and pretending otherwise is what made them wrap: the row
   keeps its shape and gives up padding, gap and two points of type instead. */
@media (max-width: 480px) {
  .pd-actions { gap: 6px; }
  .pd-action { padding: 8px 10px; gap: 5px; font-size: var(--fs-xs); }
  .pd-action .icon { width: 14px; height: 14px; }
}
/* A 288px column. Two of the three label states fit here exactly; the third —
   "New comparison" beside "Price alert" and "Saved" — is 26px over, and starts
   ellipsing words a visitor needs.

   The icons go, and nothing else. They cost 18px each and they are
   reinforcement: the words are what carry the meaning, and shrinking the type
   below 12px or shortening the wording only at this width would trade
   something legible for something decorative. */
@media (max-width: 360px) {
  .pd-action { padding: 8px 8px; gap: 0; }
  .pd-action .icon { display: none; }
}

.price-range { font-size: var(--fs-lg); margin: var(--sp-4) 0 var(--sp-2); }
/* Two grouped six-figure prices on one line need to shrink on a phone. */
.price-range b { font-size: clamp(1.25rem, 1rem + 2vw, 1.75rem); font-weight: 800; letter-spacing: -.025em; }
/* Key facts under the title. Strictly one per line, at every width.
   Flowing them into columns on a wide screen made the reading order jump
   across the page — and the value each label belongs to stopped being
   obvious, which is the only thing this list exists to show.

   `max-width` because a spec running the full width of a 27in monitor is
   unreadable for the opposite reason: the eye loses the line coming back. */
.spec-highlights {
  list-style: none; padding: 0;
  margin: 0 0 var(--sp-3);
  display: grid; gap: 3px;
  max-width: 720px;
  color: var(--ink-2); font-size: var(--fs-sm);
}
/* Reserved at three rows, and only where the layout can afford it. The list
   holds at most four facts and different configurations of one model carry
   wildly different numbers of them, so without a floor the whole right-hand
   column changes height every time a visitor picks a different tile. Below
   900px the page is one column and vertical space is the scarce thing, so
   the floor is lifted. */
@media (min-width: 900px) {
  .spec-highlights { min-height: calc(3 * 1.5em + 6px); align-content: start; }
}
.spec-highlights-empty { color: var(--muted); }
.spec-highlights-empty::before { background: transparent; }
/* Hanging indent: the dot is positioned out of the flow, so a value long
   enough to wrap lines up under its own text rather than under the bullet. */
.spec-highlights li { position: relative; padding-left: var(--sp-4); }
.spec-highlights li::before {
  content: ""; position: absolute; left: 4px; top: .62em;
  width: 4px; height: 4px; border-radius: 50%; background: var(--muted);
}

/* The specification sheet itself. */
.spec-h { margin-bottom: var(--sp-3); }
.spec-h3 { font-size: var(--fs-base); margin: var(--sp-5) 0 var(--sp-2); }
.spec-table { width: 100%; border-collapse: collapse; max-width: 720px; }
.spec-table th, .spec-table td {
  text-align: left; vertical-align: top;
  padding: 10px var(--sp-4) 10px 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-sm);
}
/* A fixed label column keeps the values in one vertical line, which is what
   makes a spec sheet scannable rather than a paragraph in two colours. */
.spec-table th {
  width: 34%; min-width: 120px;
  font-weight: 600; color: var(--muted);
}
.spec-table td { color: var(--ink); }
.spec-table tr:last-child th, .spec-table tr:last-child td { border-bottom: 0; }

.spec-facts { margin: 0; padding-left: var(--sp-4); display: grid; gap: 4px; }
.spec-facts li { font-size: var(--fs-sm); color: var(--ink-2); }
.spec-note { margin-top: var(--sp-4); }

@media (max-width: 560px) {
  /* Label above value: a 34% column leaves the value four words wide. */
  .spec-table th, .spec-table td { display: block; width: auto; padding-right: 0; }
  .spec-table th { border-bottom: 0; padding-bottom: 0; }
}

/* variant tiles — each carries its own price, so a config change is visible */
.variants { display: flex; gap: var(--sp-2); overflow-x: auto; padding-bottom: var(--sp-2); }
/* A fixed basis, not a min/max range. Sized from content, every tile in the
   strip resized when the webfont swapped in and again when the selection
   moved, and the whole row jumped each time. The width is now a constant, so
   the only thing that changes when you pick a configuration is which tile is
   outlined. */
.variant {
  flex: 0 0 132px; border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: var(--sp-2); text-align: center; background: var(--page);
}
/* An inset shadow rather than a thicker border: `border-width: 2px` moved the
   tile's own contents 1px and shifted every tile after it along the row. */
.variant.is-current {
  border-color: var(--cta); box-shadow: inset 0 0 0 1px var(--cta);
}
.variant-img {
  background: var(--surface); border-radius: 6px; aspect-ratio: 1;
  overflow: hidden; isolation: isolate; margin-bottom: 6px;
}
.variant-img img { width: 100%; height: 100%; object-fit: contain; padding: 8%; mix-blend-mode: multiply; }
.variant-label {
  font-size: var(--fs-xs); font-weight: 600; color: var(--ink);
  line-height: 1.25; margin-bottom: 2px;
}
.variant-price { font-size: var(--fs-sm); font-weight: 700; }

/* tabs */
.tabs {
  display: flex; gap: var(--sp-5); border-bottom: 1px solid var(--line);
  margin: var(--sp-7) 0 var(--sp-5);
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.tabs::-webkit-scrollbar { display: none; }
.tab { white-space: nowrap; flex: none; }
.tab {
  padding-bottom: var(--sp-3); font-weight: 600; font-size: var(--fs-sm); color: var(--muted);
  border-bottom: 2px solid transparent; margin-bottom: -1px; background: none; border-top: 0;
  border-inline: 0; cursor: pointer;
}
.tab.is-active { color: var(--ink); border-bottom-color: var(--cta); }

/* offers */
.offers-bar { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-3); }
.offer-name, .offer-shop { max-width: 100%; }
.offers-bar .spacer { margin-left: auto; }

.offer {
  display: grid;
  /* minmax(0, 1fr), not 1fr: a bare 1fr keeps an automatic MINIMUM equal to its
     content width, so the nowrap product title stopped the column shrinking and
     drove the row to 758px inside a 320px viewport. */
  grid-template-columns: 40px minmax(0, 1fr) auto;
  gap: var(--sp-3);
  align-items: center; padding: var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--page);
}
.offer > * { min-width: 0; }
.offer + .offer { margin-top: var(--sp-2); }
.offer.is-best { border-color: var(--ok-ink); background: var(--ok-bg); }
.offer-logo {
  width: 40px; height: 40px; border-radius: 50%; background: var(--surface);
  display: grid; place-items: center; color: var(--ink-2);
}
.offer-shop { font-weight: 700; }
/* Which finish an offer row is for, beside the shop that sells it. */
.offer-colour {
  display: inline-block; margin-left: 6px; padding: 1px 7px;
  border: 1px solid var(--line); border-radius: 999px;
  font-size: var(--fs-xs); font-weight: 600; color: var(--muted);
  vertical-align: middle;
}
.offer-name { color: var(--link); font-size: var(--fs-sm); }
.offer-meta { color: var(--muted); font-size: var(--fs-xs); margin-top: 2px; }
.offer-price { text-align: right; }
.offer-price b { font-size: var(--fs-lg); font-weight: 800; letter-spacing: -.02em; }
.offer-delta { display: block; font-size: var(--fs-xs); color: var(--muted); }

/* ================= price history ================= */
.history-head p { color: var(--ink-2); max-width: 60ch; }
/* The height belongs to the wrapper, not the canvas.
   Chart.js with `maintainAspectRatio: false` sizes the canvas from its parent
   and then writes its own inline width and height onto it — so a height set
   on the canvas is the thing being overwritten, and the box the shopper is
   looking at resized the moment the library initialised. Giving the parent
   the height makes the space exist before the chart does. */
.chart-wrap { position: relative; height: 300px; margin-top: var(--sp-5); }
.chart-wrap canvas { width: 100%; height: 100%; }
.chart-watermark {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 800; font-size: 1.4rem;
  color: rgba(124, 92, 224, .10); pointer-events: none;
}
.range { display: flex; justify-content: center; margin-top: var(--sp-4); }

/* ================= list / filters ================= */
.listing { display: grid; gap: var(--sp-5); }
@media (min-width: 960px) { .listing { grid-template-columns: 240px 1fr; align-items: start; } }
.filters { border: 1px solid var(--line); border-radius: var(--r-md); padding: var(--sp-4); }
.filters h3 { font-size: var(--fs-sm); margin-bottom: var(--sp-2); }
.filters + .filters { margin-top: var(--sp-3); }
.filter-row { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); padding: 3px 0; }
/* Same reasoning as `.rail`: with no padding on the tile, the gap is the
   only separation between neighbouring products. */
.grid-products { display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: var(--sp-4); }


/* ---- offer row on a phone ----
   Three columns cannot hold a shop name, a product title and a price with a
   button below ~560px. The price moves to its own full-width row so the number
   stays the most prominent thing, and the title finally has room to ellipse. */
@media (max-width: 560px) {
  .offer {
    grid-template-columns: 32px minmax(0, 1fr);
    row-gap: var(--sp-3); padding: var(--sp-3);
  }
  .offer-logo { width: 32px; height: 32px; }
  .offer-price {
    grid-column: 1 / -1;
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-3); text-align: left;
    padding-top: var(--sp-3); border-top: 1px solid var(--line);
  }
  .offer-price .btn { margin-top: 0 !important; }
  .offer-delta { display: inline; margin-left: var(--sp-2); }
}

/* ================= filter rail ================= */

.results { min-width: 0; }

.filters-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); }
.filters-head h3 { margin-bottom: 0; }
.clear-link { font-size: var(--fs-xs); color: var(--muted); }
.clear-link:hover { color: var(--link); }

/* ---- price ---- */

.presets { display: flex; flex-direction: column; gap: 2px; margin: var(--sp-2) 0 var(--sp-3); }
.preset {
  display: flex; justify-content: space-between; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-sm); color: var(--ink); padding: 4px 8px;
  border-radius: var(--r-sm); border: 1px solid transparent;
}
.preset:hover { background: var(--surface-2); }
.preset.is-on { border-color: var(--cta); background: var(--surface); font-weight: 600; }
.preset-n { color: var(--muted); font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }

.price-range { display: flex; align-items: center; gap: var(--sp-2); }
.price-input {
  width: 100%; min-width: 0; padding: 7px 9px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font: inherit; font-size: var(--fs-sm); background: var(--page); color: var(--ink);
}
.price-dash { color: var(--muted); }

/* ---- facet groups ---- */

.facet-find {
  width: 100%; margin-bottom: var(--sp-2); padding: 6px 9px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font: inherit; font-size: var(--fs-sm); background: var(--page); color: var(--ink);
}
.filter-row { cursor: pointer; }
.filter-row:hover .opt-label { color: var(--link); }
/* The label takes the slack so every count sits on the same right edge. */
.opt-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.opt-n { color: var(--muted); font-size: var(--fs-xs); }

.more > summary {
  cursor: pointer; font-size: var(--fs-xs); color: var(--muted);
  padding-top: var(--sp-2); list-style: none;
}
.more > summary::-webkit-details-marker { display: none; }
.more > summary::before { content: "+ "; }
.more[open] > summary::before { content: "− "; }
.more > summary:hover { color: var(--link); }

.filter-apply { width: 100%; justify-content: center; margin-top: var(--sp-3); }

/* ---- applied chips and sort ---- */

.results-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-3); margin-bottom: var(--sp-4); flex-wrap: wrap;
}
.chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.fchip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-xs); padding: 4px 10px;
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--surface); color: var(--ink); white-space: nowrap;
}
.fchip:hover { border-color: var(--cta); }
.fchip-x { color: var(--muted); font-size: 14px; line-height: 1; }
.fchip:hover .fchip-x { color: var(--ink); }
.fchip-clear { background: transparent; border-style: dashed; color: var(--muted); }


.sort-select {
  font: inherit; font-size: var(--fs-sm); padding: 6px 9px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--page); color: var(--ink); cursor: pointer;
}

.empty p { margin: 0 0 var(--sp-2); }
.empty .btn { margin-top: var(--sp-2); }

/* ---- mobile: the rail collapses behind a button ---- */

.filter-toggle { display: none; }
@media (max-width: 959px) {
  /* Only offer the toggle once the script that drives it has run, so the rail
     stays open and usable when JavaScript never arrives. */
  .js-filters .filter-toggle {
    display: inline-flex; width: 100%; justify-content: center; margin-bottom: var(--sp-3);
  }
  .js-filters .filter-panel { display: none; }
  .js-filters.filters-open .filter-panel { display: block; }
  .sortbar { margin-left: 0; width: 100%; }
  .sort-select { width: 100%; }
}

/* ---- pagination ---- */

.pager {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-6); justify-content: center;
}
.page-n, .page-step {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 36px; height: 36px; padding: 0 var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font-size: var(--fs-sm); color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.page-n:hover, .page-step:hover { border-color: var(--cta); }
.page-n.is-current {
  background: var(--cta); border-color: var(--cta); color: var(--cta-ink); font-weight: 600;
}
/* Disabled steps keep their slot so the row does not shift between pages. */
.page-step.is-off { color: var(--muted); border-color: var(--line-soft, var(--line)); opacity: .5; }
.page-gap { color: var(--muted); padding: 0 2px; }
.page-note { text-align: center; margin-top: var(--sp-3); }

/* ---- per-page and sort ---- */

.viewbar { display: flex; align-items: center; gap: var(--sp-3); margin-left: auto; }
.pagesize { display: inline-flex; align-items: center; gap: var(--sp-1); }
.pagesize-label { font-size: var(--fs-xs); color: var(--muted); margin-right: 2px; }
.size-n {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 30px; height: 30px; padding: 0 var(--sp-2);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font-size: var(--fs-xs); color: var(--ink); font-variant-numeric: tabular-nums;
}
.size-n:hover { border-color: var(--cta); }
.size-n.is-current {
  background: var(--cta); border-color: var(--cta); color: var(--cta-ink); font-weight: 600;
}

@media (max-width: 959px) {
  .viewbar { margin-left: 0; width: 100%; flex-wrap: wrap; }
  .sortbar { flex: 1; min-width: 160px; }
}

/* An option with nothing behind it keeps its place, greyed. Removing it is
   what made the rail collapse under the pointer mid-selection. */
.filter-row.is-empty { cursor: default; opacity: .38; }
.filter-row.is-empty:hover .opt-label { color: inherit; }
.filter-row.is-empty input { cursor: default; }

/* ---- in-flight ----
   Only the results dim. The rail stays crisp and clickable so ticking two
   boxes in a row feels continuous instead of gated on a round trip. */
#listing .results { transition: opacity .14s ease-out; }
#listing.htmx-request .results { opacity: .5; }
@media (prefers-reduced-motion: reduce) {
  #listing .results { transition: none; }
}

/* ---- home hero: the comparison, drawn ----
   Single column by default; the art becomes a second grid column only where
   there is genuinely room for it. Below 900px it is hidden so it can never
   push the search box off a phone screen — and hiding rather than omitting
   costs nothing here, because the panel is text and CSS with no image behind
   it. */
.hero-art { display: none; }

@media (min-width: 900px) {
  .hero {
    display: grid; grid-template-columns: 1.15fr 1fr;
    gap: var(--sp-7); align-items: center;
  }
  .hero-inner { max-width: none; }
  .hero-art { display: block; position: relative; }
}

/* The two tags, offset like the site's mark. Sizes are in ch and rem rather
   than fixed pixels so a longer shop name or a lakh-grouped price widens the
   tag instead of spilling out of it. */
.tagpair { position: relative; padding: var(--sp-6) 0; }

.tag {
  position: relative; display: grid; gap: 2px;
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--r-md); width: fit-content; min-width: 13rem;
}
.tag-shop { font-size: var(--fs-xs); letter-spacing: .02em; opacity: .75; }
.tag-price {
  font-family: var(--font-display); font-weight: 800;
  font-size: 1.5rem; letter-spacing: -.02em; line-height: 1.1;
}

/* Dimmed and behind: the price you would have paid. */
.tag-high {
  background: rgba(255, 255, 255, .10); color: #cfc6e4;
  margin-left: 8%;
}
.tag-high .tag-price { text-decoration: line-through; text-decoration-thickness: 2px; }

/* Bright and in front: the one you want. Pulled up so the pair overlaps the
   way the favicon's tags do. */
.tag-low {
  background: #fff; color: var(--ink);
  margin-top: -12px; margin-left: 0;
  box-shadow: 0 12px 32px rgba(0, 0, 0, .28);
}
.tag-low .tag-shop { opacity: .6; }

.tag-save {
  display: grid; gap: 1px; margin-top: var(--sp-4); margin-left: 8%;
  font-size: var(--fs-sm);
}
.tag-save b {
  font-family: var(--font-display); font-size: 1.05rem; font-weight: 800;
  color: var(--watch-bg);
}
.tag-save span { color: #cfc6e4; opacity: .8; }

/* One entrance, then still. A hero that keeps moving competes with its own
   search box, so nothing here loops and nothing responds to hover.

   The resting state is the finished state: each piece animates FROM an
   offset INTO place, so a reader whose browser never runs the animation —
   or who asks for reduced motion — sees a complete composition rather than
   an empty box waiting on a script. */
@media (prefers-reduced-motion: no-preference) {
  .tag-high { animation: tag-rise .32s cubic-bezier(.2, .7, .3, 1) both; }
  .tag-low  { animation: tag-drop .40s cubic-bezier(.2, .9, .3, 1.08) .12s both; }
  .tag-save { animation: tag-rise .36s ease-out .38s both; }
}

@keyframes tag-rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@keyframes tag-drop {
  from { opacity: 0; transform: translateY(-14px) scale(.97); }
  to   { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------- all categories */

/* One card per department. auto-fill rather than a fixed column count, so the
   grid reflows from four across to one without a breakpoint per step.

   `align-items: start` is what stops a card stretching to the height of the
   tallest in its row. Six of the twenty departments have no shelves at all,
   and the largest of them sorts first, so the page opened on a tall empty box.
   CSS columns would pack the vertical space tighter still, but they fill
   top-to-bottom before moving across, which would break the size ordering the
   view sorts by — the second-largest department would sit under the first
   rather than beside it. */
/* ------------------------------------------------------- all categories */

.cat-head { margin-bottom: var(--sp-4); }
.cat-head h1 {
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: 900;
  letter-spacing: -.03em;
  margin: 0;
}
/* The same stat vocabulary the hero uses, so a number means the same thing
   wherever it appears on the site. */
.cat-stats {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  margin: var(--sp-2) 0 0;
  color: var(--muted);
  font-size: var(--fs-sm);
}
.cat-stats .num {
  color: var(--ink);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

/* Sticky under the header, which is itself sticky — hence the offset rather
   than `top: 0`. Scrolls horizontally on narrow screens instead of wrapping
   into a four-line wall of chips. */
.cat-jump {
  position: sticky;
  top: var(--nav-h);
  z-index: 5;
  display: flex;
  gap: var(--sp-1);
  overflow-x: auto;
  scrollbar-width: none;
  padding: var(--sp-3) 0;
  margin-bottom: var(--sp-5);
  background: var(--page);
  border-bottom: 1px solid var(--line);
  /* Fades the last chip out at the right edge instead of guillotining it, so
     the strip reads as scrollable rather than broken. */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 40px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 40px), transparent);
}
.cat-jump::-webkit-scrollbar { display: none; }
.cat-jump a {
  flex: none;
  padding: 5px var(--sp-3);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink-2);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.cat-jump a:hover, .cat-jump a:focus-visible {
  background: var(--cta);
  color: var(--cta-ink);
}

.dept-grid {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  /* Single-width cards backfill the gap a double-width card leaves at the end
     of a row, so the grid stays solid at any column count. */
  grid-auto-flow: dense;
  align-items: start;
}

.dept {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--sp-4);
  background: var(--page);
  /* Clears the sticky header and the sticky jump bar when an anchor lands. */
  scroll-margin-top: calc(var(--nav-h) + 76px);
  transition: border-color .12s ease, box-shadow .12s ease;
}
.dept:hover {
  border-color: #d6d6db;
  box-shadow: var(--shadow-card);
}

/* The six largest departments. Two columns wide only once there is room for
   two: below that the span would force a single column for the whole grid. */
.dept--lead { background: var(--surface-2); }
@media (min-width: 900px) {
  .dept--lead { grid-column: span 2; }
  .dept--lead .dept-list {
    columns: 2;
    column-gap: var(--sp-5);
  }
  .dept--lead .dept-list li { break-inside: avoid; }
}
.dept--lead .dept-icon {
  width: 40px; height: 40px;
  background: var(--pop-bg);
  color: var(--pop-ink);
}
.dept--lead .dept-name { font-size: var(--fs-lg); }

.dept-head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  color: inherit;
  text-decoration: none;
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--line);
}
.dept-head:hover .dept-name { text-decoration: underline; }

.dept-icon {
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  flex: none;
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink-2);
}

.dept-name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-base);
  letter-spacing: -.02em;
  min-width: 0;
}

/* A department's count is a badge; a shelf's is plain text. The two used to
   be the same muted grey at the same size, which flattened the hierarchy —
   nothing distinguished an aisle holding 2,769 products from a shelf holding
   eleven except where it sat. */
.dept-count {
  margin-left: auto;
  flex: none;
  padding: 2px var(--sp-2);
  border-radius: var(--r-pill);
  background: var(--surface);
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.dept--lead .dept-count { background: var(--page); }

.dept-list { list-style: none; margin: var(--sp-3) 0 0; padding: 0; }
.dept-list li { display: block; }
/* The whole row is the target, not just the words. */
.dept-list a {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  padding: 5px 6px;
  margin: 0 -6px;
  border-radius: var(--r-sm);
  color: var(--ink-2);
  text-decoration: none;
  font-size: var(--fs-sm);
}
.dept-list a:hover, .dept-list a:focus-visible {
  background: var(--surface);
  color: var(--link);
}
.dept--lead .dept-list a:hover { background: var(--page); }
.dept-shelf-name { min-width: 0; }
/* Tabular so the counts line up down the column however wide the names run. */
.dept-shelf-count {
  margin-left: auto;
  font-size: var(--fs-sm);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.dept-more {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  /* Pinned to the bottom of the card however tall its shelf list runs. */
  margin-top: auto;
  padding-top: var(--sp-3);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--link);
  text-decoration: none;
}
.dept-more .icon { width: 14px; height: 14px; }
.dept-more:hover { text-decoration: underline; }
.dept-more:hover .icon { transform: translateX(2px); }
.dept-more .icon { transition: transform .12s ease; }

/* Touch targets, and no horizontal scroll on a phone. */
@media (max-width: 640px) {
  .dept-list a { padding: 9px 6px; }
  .cat-jump { margin-bottom: var(--sp-4); }
}

@media (prefers-reduced-motion: reduce) {
  .dept, .dept-more .icon { transition: none; }
  .dept-more:hover .icon { transform: none; }
}

/* ------------------------------------------------------- price alert modal */

/* A native <dialog>: focus trapping, Esc and the backdrop come for free, and
   there is no z-index race with the sticky header. */
.modal {
  border: 0;
  border-radius: var(--r-lg);
  padding: 0;
  width: min(480px, calc(100vw - 2 * var(--sp-4)));
  background: var(--page);
  color: var(--ink);
  box-shadow: var(--shadow-pop);

  /* Centred explicitly, because `* { margin: 0 }` in base.css un-does it.
     A modal <dialog> is centred by the browser with `inset: 0; margin: auto`,
     and the global reset overrides the margin — leaving inset:0 to pin the
     box to the top-left corner. */
  margin: auto;

  /* A tall modal scrolls inside itself rather than off the screen: the
     advanced settings expand, and on a short window the buttons were the part
     that disappeared. */
  max-height: calc(100dvh - 2 * var(--sp-5));
  overflow: auto;
}
.modal::backdrop { background: rgba(15, 14, 17, .45); }

.modal-head {
  display: flex; align-items: center; justify-content: center;
  position: relative;
  padding: var(--sp-5) var(--sp-5) var(--sp-3);
}
.modal-head h2 { font-size: var(--fs-h2); margin: 0; }
.modal-x {
  position: absolute; right: var(--sp-4); top: var(--sp-4);
  border: 0; background: none; cursor: pointer;
  font-size: 22px; line-height: 1; color: var(--muted);
}
.modal-body { padding: 0 var(--sp-5); display: grid; gap: var(--sp-3); }
.modal-foot {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3);
  padding: var(--sp-5);
}
.btn-cta { background: var(--cta); color: var(--cta-ink); border-color: var(--cta); }

.alert-product {
  display: flex; gap: var(--sp-3); align-items: center;
  background: var(--surface); border-radius: var(--r-md); padding: var(--sp-3);
}
.alert-thumb { width: 56px; height: 56px; flex: none; }
.alert-thumb img { width: 100%; height: 100%; object-fit: contain; }
.alert-name { font-size: var(--fs-sm); font-weight: 600; }
.alert-price { font-size: var(--fs-lg); font-weight: 700; }

/* The menu the card's heart opens.

   `position: fixed` with no offsets of its own — alerts.js writes `top`/`left`
   from the heart's bounding box. A popover is in the top layer, so those
   coordinates are viewport coordinates and no ancestor's overflow, transform or
   z-index can touch it.

   `inset: auto` matters: the UA stylesheet centres a popover with
   `inset: 0; margin: auto`, and leaving that in place fights the positioning —
   the menu snapped back to the middle of the screen on the first paint. */
.popmenu {
  position: fixed; inset: auto; margin: 0;
  min-width: 13rem; padding: var(--sp-2);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--page); box-shadow: var(--shadow-pop);
  display: grid; gap: 2px;
}
.popmenu::backdrop { background: transparent; }

.popmenu-item {
  display: flex; align-items: center; gap: var(--sp-3);
  width: 100%; padding: 9px var(--sp-3);
  border: 0; border-radius: var(--r-sm); background: none;
  font: inherit; font-size: var(--fs-sm); font-weight: 600; line-height: 1.2;
  color: var(--ink); text-align: left; text-decoration: none; cursor: pointer;
}
.popmenu-item .icon { width: 18px; height: 18px; color: var(--muted); flex: none; }
.popmenu-item:hover { background: var(--surface); }
.popmenu-item:focus-visible { outline: 2px solid var(--link); outline-offset: -2px; }
/* Already set, already in the tray. The icon takes the colour rather than the
   whole row: a filled row in a two-item menu reads as a selected tab. */
.popmenu-item.is-on .icon { color: var(--cta); }
/* The control is a form, and the form must not add a row of its own. */
.popmenu form { margin: 0; display: contents; }
.popmenu .compare-control { display: contents; }

/* Each choice is a card, so the whole row is a click target rather than the
   radio's own 14 pixels. */
.alert-option {
  display: flex; align-items: center; gap: var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
  cursor: pointer;
}
.alert-option-block { display: block; cursor: default; }
.alert-option-block > label {
  display: flex; align-items: center; gap: var(--sp-3); cursor: pointer;
}
.alert-option:has(input:checked) { border-color: var(--cta); }

.alert-target { margin-top: var(--sp-4); }
/* Dimmed, never removed: the fields still post, so the server stays the
   authority on what a submission meant. */
.is-off { opacity: .45; }

.field-box {
  display: flex; align-items: center; gap: var(--sp-2);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 6px var(--sp-3);
}
.field-box input[type="number"], .field-box input[type="date"], .field-box select {
  border: 0; outline: 0; flex: 1; width: 100%;
  font: inherit; font-variant-numeric: tabular-nums; background: none; color: inherit;
}
.field-label { font-size: var(--fs-xs); color: var(--muted); }
.field-suffix { color: var(--muted); }
.field-error { color: var(--err); font-size: var(--fs-sm); margin: 4px 0 0; }

.alert-slider { width: 100%; margin-top: var(--sp-4); accent-color: var(--cta); }
.alert-ticks {
  display: flex; justify-content: space-between;
  font-size: var(--fs-xs); color: var(--muted); font-variant-numeric: tabular-nums;
}

.alert-check { display: flex; align-items: center; gap: var(--sp-3); cursor: pointer; }
.alert-advanced summary { cursor: pointer; font-weight: 600; font-size: var(--fs-sm); }
.alert-advanced[open] { display: grid; gap: var(--sp-3); }

/* ---- confirmation and the alerts page ---- */

/* `.toast` is the pill and nothing else. It used to carry its own
   `position: fixed` too, which made the class mean "a message" AND "pinned to
   the middle of the window" — so the comparison tray's refusal, which is a
   message that belongs in the dock at the bottom, inherited a position it
   could not use and was painted on top of the tray it was talking about.
   Where a toast sits is the host's business; see `.toast-host` and
   `.toast-float` in components.css. */
.toast {
  display: flex; align-items: center; gap: var(--sp-3);
  background: var(--cta); color: var(--cta-ink);
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-pill);
  box-shadow: var(--shadow-pop); font-size: var(--fs-sm);
}
.toast a { color: var(--cta-ink); text-decoration: underline; }

.alert-rows { display: grid; gap: var(--sp-3); }
.alert-row {
  display: grid; grid-template-columns: 56px 1fr auto auto;
  gap: var(--sp-4); align-items: center;
  border: 1px solid var(--line); border-radius: var(--r-md); padding: var(--sp-3);
}
.alert-row-thumb img { width: 56px; height: 56px; object-fit: contain; }
.alert-row-main a { color: inherit; text-decoration: none; font-weight: 600; }
.alert-row-main a:hover { text-decoration: underline; }
.alert-row-price { font-weight: 700; }
.narrow { max-width: 560px; }

/* ---- header account control ---- */

.account { position: relative; flex: none; }
/* The name is the visitor's own and can be any length. It gets a share of the
   row and no more — the menu behind it is where the account actually lives. */
.account-btn {
  list-style: none; cursor: pointer; padding: 8px 12px; font-size: var(--fs-sm);
  max-width: 8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.account-btn::-webkit-details-marker { display: none; }
.account-menu {
  position: absolute; right: 0; top: calc(100% + 4px); min-width: 180px;
  background: var(--page); border: 1px solid var(--line);
  border-radius: var(--r-md); box-shadow: var(--shadow-pop);
  padding: var(--sp-2); display: grid; gap: 2px; z-index: 40;
}
.account-menu a, .account-menu button {
  display: block; width: 100%; text-align: left;
  padding: 8px 10px; border: 0; background: none; border-radius: var(--r-sm);
  font: inherit; color: inherit; text-decoration: none; cursor: pointer;
}
.account-menu a:hover, .account-menu button:hover { background: var(--surface); }

@media (max-width: 640px) {
  .alert-row { grid-template-columns: 44px 1fr; }
  .alert-row-price, .alert-row form { grid-column: 2; }
}

/* ------------------------------------------------------------ sign-in page */

.entrance { display: grid; place-items: center; padding: var(--sp-7) 0; }
.entrance-card {
  width: min(420px, 100%);
  display: grid; gap: var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: var(--sp-6); background: var(--page);
}
.entrance-card h1 { font-size: var(--fs-h2); margin: 0; }
.entrance-card p { margin: 0; }
.entrance-card form { display: grid; gap: var(--sp-3); }

/* Google's brand guidance: their mark on a neutral surface, full width so it
   reads as the primary action rather than one option among several. */
.btn-google {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-3);
  width: 100%; padding: 12px var(--sp-4);
  font-weight: 600; font-size: var(--fs-base);
}
.btn-google .icon { width: 18px; height: 18px; }

.alert-thumb-empty {
  display: grid; place-items: center; width: 100%; height: 100%;
  border-radius: var(--r-sm); background: var(--surface-2); color: var(--muted);
}
/* Reads as belonging to the checkbox above it rather than as a field of its own. */
.field-indent { margin-left: 28px; }

/* ---- compare page -------------------------------------------------------
   The table is read across, which is the whole point and also the constraint:
   it is wide by nature, so it scrolls inside its own wrapper and the page
   never scrolls sideways. The first column stays put, because a spec value
   with its label off-screen says nothing. */
.cmp-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-4);
}
.cmp-head form { margin: 0; }
.cmp-hint { color: var(--muted); font-size: var(--fs-sm); margin-bottom: var(--sp-4); }

.cmp-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.cmp { border-collapse: collapse; width: 100%; min-width: 32rem; }
.cmp th, .cmp td {
  border-bottom: 1px solid var(--line); padding: var(--sp-3);
  text-align: left; vertical-align: top; font-size: var(--fs-sm);
}
.cmp tbody th[scope="row"] {
  position: sticky; left: 0; z-index: 1;
  background: var(--page); color: var(--muted); font-weight: 600;
  min-width: 8.5rem; white-space: nowrap;
}
.cmp-col { min-width: 12rem; width: 12rem; }
.cmp thead th { border-bottom-width: 2px; vertical-align: bottom; }

.cmp-card { position: relative; }
.cmp-remove { position: absolute; top: 0; right: 0; margin: 0; }
.cmp-remove button {
  border: 0; background: none; cursor: pointer; color: var(--muted);
  font-size: 18px; line-height: 1; padding: 2px 4px;
}
.cmp-remove button:hover { color: var(--sale-ink); }
.cmp-media {
  display: grid; place-items: center; aspect-ratio: 1;
  background: var(--surface); border-radius: var(--r-sm); overflow: hidden;
  margin-bottom: var(--sp-2);
}
.cmp-media img { width: 100%; height: 100%; object-fit: contain; padding: 10%; }
.cmp-name {
  display: block; color: inherit; text-decoration: none;
  font-weight: 600; line-height: 1.35; overflow-wrap: anywhere;
}
.cmp-name:hover { text-decoration: underline; }
.cmp-price { font-size: var(--fs-lg); font-weight: 800; display: block; }
.cmp-go { width: 100%; justify-content: center; }

/* A heading inside the body, so the specification block announces itself
   without needing a second table. */
.cmp-section th {
  background: var(--surface); font-weight: 700; color: var(--ink);
  text-transform: none; letter-spacing: 0;
}
/* Rows where every product says the same thing. Dimmed rather than dropped:
   the fact that two machines agree is itself worth seeing. */
.cmp-same th, .cmp-same td { opacity: .62; }

.cmp-nospecs { margin-top: var(--sp-5); }
.cmp-share { margin-top: var(--sp-5); overflow-wrap: anywhere; }

/* ------------------------------------------------- privacy policy and terms
   A reading column, not a page-width slab. Legal text is the one thing on
   this site somebody reads top to bottom, and the measure that makes a grid
   of product cards work is far too wide to read a paragraph across.
*/
.legal {
  max-width: 74ch; margin: 0 auto var(--sp-8);
  font-size: var(--fs-base); line-height: 1.7;
}
.legal-head { margin-bottom: var(--sp-6); }
.legal h1 {
  font-family: var(--font-display); font-size: var(--fs-h1);
  font-weight: 900; letter-spacing: -.025em; margin-bottom: var(--sp-2);
}
.legal-date {
  font-size: var(--fs-sm); color: var(--muted); margin-bottom: var(--sp-4);
}
.legal-lede { font-size: var(--fs-lg); line-height: 1.6; color: var(--ink-2); }

/* The contents list. Long documents are navigated, not scrolled. */
.legal-toc {
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: var(--sp-4) var(--sp-5);
  margin-bottom: var(--sp-6);
}
.legal-toc-h {
  font-size: var(--fs-xs); font-weight: 700; text-transform: uppercase;
  letter-spacing: .08em; color: var(--muted); margin-bottom: var(--sp-2);
}
.legal-toc ol {
  margin: 0; padding-left: 1.3em; columns: 2; column-gap: var(--sp-5);
  font-size: var(--fs-sm);
}
.legal-toc li { margin-bottom: 2px; break-inside: avoid; }
.legal-toc a { color: var(--link); text-decoration: none; }
.legal-toc a:hover { text-decoration: underline; }

.legal section { margin-bottom: var(--sp-6); }
/* `scroll-margin-top` so a jump from the contents does not park the heading
   underneath the sticky header. */
.legal section > h2 {
  font-family: var(--font-display); font-size: var(--fs-h2); font-weight: 800;
  letter-spacing: -.015em; margin-bottom: var(--sp-3);
  padding-top: var(--sp-2); scroll-margin-top: calc(var(--nav-h) + var(--sp-4));
}
.legal h3 {
  font-size: var(--fs-base); font-weight: 700;
  margin: var(--sp-4) 0 var(--sp-2);
}
.legal p { margin-bottom: var(--sp-3); }
.legal ul { margin: 0 0 var(--sp-3); padding-left: 1.25em; }
.legal li { margin-bottom: var(--sp-2); }
.legal a { color: var(--link); }

/* The one paragraph on either page that has to be read even by someone
   skimming: confirm the price before you travel. */
.legal-callout {
  background: var(--pop-bg); color: var(--pop-ink);
  border-radius: var(--r-md); padding: var(--sp-4) var(--sp-5);
  margin-bottom: var(--sp-4);
}

.legal-table {
  width: 100%; border-collapse: collapse; margin-bottom: var(--sp-4);
  font-size: var(--fs-sm);
}
.legal-table th, .legal-table td {
  text-align: left; padding: var(--sp-3); border-bottom: 1px solid var(--line);
  vertical-align: top;
}
.legal-table th {
  font-weight: 700; font-size: var(--fs-xs); text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted);
}
.legal-table td:first-child { font-weight: 600; white-space: nowrap; }

.legal-cross {
  margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px solid var(--line); font-size: var(--fs-sm);
  color: var(--muted);
}

@media (max-width: 640px) {
  .legal-toc ol { columns: 1; }
  /* A nowrap first column pushes the table sideways on a phone; the label is
     short enough to wrap without becoming ambiguous. */
  .legal-table td:first-child { white-space: normal; }
}
