/* dealwright: one stylesheet, no framework. Dark is home; light follows the OS. */

:root {
  --bg: #0c1016;
  --panel: #141a23;
  --panel2: #1a2230;
  --line: #232d3d;
  --text: #e8edf4;
  --mut: #8a97a8;
  --acc: #3fcf8e;
  --accdim: rgba(63, 207, 142, 0.13);
  --amber: #e8b64c;
  --amberdim: rgba(232, 182, 76, 0.14);
  --red: #ef6a6a;
  --link: #8ab8ff;
  --shadow: 0 10px 28px rgba(0, 0, 0, 0.35);
  /* softer corners: the deal apps this audience uses daily sit at 15-20px
     and 10px reads as a spreadsheet next to them */
  --r: 14px;
}
@media (prefers-color-scheme: light) {
  :root {
    --bg: #f4f6f9;
    --panel: #ffffff;
    --panel2: #eef1f6;
    --line: #d9e0e8;
    --text: #1b2330;
    --mut: #5b6a7d;
    --acc: #0f7a4f;
    --accdim: rgba(15, 122, 79, 0.1);
    --amber: #8a6410;
    --amberdim: rgba(197, 146, 30, 0.16);
    --red: #bb4444;
    --link: #0f62d6;
    --shadow: 0 8px 22px rgba(23, 35, 56, 0.1);
  }
}

* { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 15.5px/1.55 ui-sans-serif, -apple-system, "Segoe UI", Roboto, Inter, sans-serif;
  -webkit-font-smoothing: antialiased;
}
a, button, input, select, label { touch-action: manipulation; }
a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }
pre, code { font: 12.5px/1.5 ui-monospace, Consolas, "Cascadia Mono", monospace; }
pre {
  background: var(--panel2);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px 12px;
  overflow-x: auto;
}
:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; border-radius: 4px; }

/* chrome */
header.top {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 22px;
  padding: 12px 20px;
  /* under a notch (iOS shell, standalone installs) the page draws edge to
     edge; the inset keeps the brand clear of the clock. Zero everywhere
     else. */
  padding-top: calc(12px + env(safe-area-inset-top, 0px));
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
.brand { display: inline-flex; align-items: center; gap: 7px; font-size: 18px; font-weight: 750; letter-spacing: -0.2px; color: var(--text); }
/* one flex item for the whole name, or the gap splits the word in two */
.brand .bname { font-weight: inherit; }
.brand span { color: var(--acc); font-weight: 800; }
.brand:hover { text-decoration: none; }
.bmark { width: 20px; height: 20px; flex: none; }
header.top nav { display: flex; gap: 4px; }
header.top nav a {
  color: var(--mut);
  padding: 6px 12px;
  border-radius: 999px;
  font-weight: 550;
}
header.top nav a:hover { color: var(--text); text-decoration: none; background: var(--panel2); }
header.top nav a.on { color: var(--text); background: var(--panel2); }

main { max-width: 1040px; margin: 0 auto; padding: 18px 20px 60px; }
footer { max-width: 1040px; margin: 0 auto; padding: 18px 20px 40px; color: var(--mut); font-size: 12.5px; }

.pagehead { display: flex; align-items: baseline; gap: 14px; margin: 6px 0 14px; flex-wrap: wrap; }
.pagehead h1 { font-size: 21px; margin: 0; letter-spacing: 0.2px; }
.stats { color: var(--mut); font-size: 13px; }

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 14px 16px;
  margin: 0 0 14px;
}
.panel h2 { font-size: 15px; margin: 2px 0 10px; }
.soft { color: var(--mut); }
.warn { color: var(--amber); font-weight: 600; }
.fgrow { flex: 1; }

/* filters */
.filters .frow { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.filters .frow + .frow { margin-top: 10px; }
.filters input[type="search"], .filters input[type="text"],
.filters input[type="number"], .filters select {
  background: var(--panel2);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 11px;
  font: inherit;
  appearance: none;
  -webkit-appearance: none;
}
.filters select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238a97a8' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  padding-right: 30px;
}
.btn, .chip { transition: transform 80ms ease, border-color 120ms ease, color 120ms ease; }
.btn:active, .chip:active { transform: scale(0.96); }
.filters input::placeholder { color: var(--mut); }
.filters .search { flex: 2 1 260px; min-width: 200px; }
.filters select { max-width: 220px; }
.filters .check { display: inline-flex; gap: 6px; align-items: center; color: var(--mut); cursor: pointer; }
.filters .check input { accent-color: var(--acc); }
.filters .num { display: inline-flex; gap: 7px; align-items: center; color: var(--mut); }
.filters .num input { width: 78px; }
.btn {
  display: inline-block;
  background: var(--acc);
  color: #08130d;
  font-weight: 650;
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 8px 16px;
  cursor: pointer;
  font: inherit;
}
.btn:hover { filter: brightness(1.08); text-decoration: none; }
.btn.ghost { background: transparent; color: var(--mut); border-color: var(--line); font-weight: 550; }
.btn.ghost:hover { color: var(--text); border-color: var(--mut); filter: none; }
.btn.sm { padding: 4px 10px; font-size: 12.5px; border-radius: 6px; }
.btn.danger:hover { color: var(--red); border-color: var(--red); }

/* chips */
.chips { display: flex; gap: 6px; flex-wrap: wrap; margin: 0 0 14px; }
.chip {
  display: inline-flex;
  gap: 5px;
  align-items: center;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 2.5px 10px;
  font-size: 12px;
  color: var(--mut);
  background: transparent;
  cursor: pointer;
  font-family: inherit;
  line-height: 1.5;
  white-space: nowrap;
}
.chip span { color: var(--mut); opacity: 0.75; font-size: 11px; }
a.chip:hover, button.chip:hover { color: var(--text); border-color: var(--mut); text-decoration: none; }
.chip.on { background: var(--accdim); border-color: var(--acc); color: var(--acc); }
.chip.cstore { color: var(--link); }
.chip.ccode { background: var(--amberdim); border-color: transparent; color: var(--amber); font-weight: 650; }
.chip.ccode.copied { background: var(--accdim); color: var(--acc); }
.chip.cfree { background: var(--accdim); border-color: transparent; color: var(--acc); font-weight: 650; }
.chip.cmm {
  background: linear-gradient(100deg, var(--accdim), var(--amberdim));
  border-color: var(--amber);
  color: var(--amber);
  font-weight: 750;
  font-size: 10.5px;
  letter-spacing: 0.6px;
}
.chip.clow { border-color: var(--acc); color: var(--acc); font-weight: 650; }
.chip.cnew { border-color: var(--link); color: var(--link); font-weight: 700; font-size: 10.5px; letter-spacing: 0.5px; }
.chip.cbest { background: var(--accdim); border-color: transparent; color: var(--acc); font-weight: 650; }
.qadd { display: inline; }
.qchips { justify-content: center; margin-top: 12px; }
.chip.csrc { border-style: dashed; }
.chip.cai { font-size: 10px; letter-spacing: 0.5px; padding: 1px 7px; }

/* deal cards */
.deals { display: flex; flex-direction: column; gap: 9px; }
.deal {
  display: flex;
  gap: 16px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 12px 16px;
  transition: border-color 120ms ease, transform 120ms ease;
}
.deal:hover { border-color: color-mix(in srgb, var(--acc) 45%, var(--line)); }
.dthumb {
  width: 64px;
  height: 64px;
  border-radius: 8px;
  object-fit: cover;
  background: var(--panel2);
  flex: none;
}
.dmain { flex: 1; min-width: 0; }
.dtitle {
  color: var(--text);
  font-size: 15.5px;
  font-weight: 700;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-bottom: 7px;
  overflow-wrap: anywhere;
}
.dtitle:hover { color: var(--link); }
.dbadges { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 7px; }
.dmeta { color: var(--mut); font-size: 12.5px; }
.dmeta a { color: var(--mut); text-decoration: underline; text-decoration-color: var(--line); text-underline-offset: 2px; }
.dmeta a:hover { color: var(--text); }
/* The savings IS the product. Every deal app this audience uses leads with
   the number, not the product name, and ours used to whisper it at the
   right edge in the same weight as the title. */
.dprice { display: flex; flex-direction: column; align-items: flex-end; justify-content: center; gap: 3px; min-width: 116px; }
.dprice .p, .limeta .p { color: var(--acc); font-size: 22px; font-weight: 800; letter-spacing: -0.2px; }
.dprice .w, .limeta .w { color: var(--mut); text-decoration: line-through; font-size: 13px; }
.dprice .pc, .limeta .pc {
  background: var(--accdim);
  color: var(--acc);
  font-size: 12px;
  font-weight: 750;
  border-radius: 999px;
  padding: 2px 9px;
}
/* half off or better stops being a footnote and becomes the loudest thing
   on the row. Engine-owned number, so it can shout honestly. */
.dprice .pc.big, .limeta .pc.big {
  background: var(--acc);
  color: var(--panel);
  font-size: 12.5px;
  font-weight: 800;
}

/* save to list: the one-tap move every cash-back app is built around, and
   the thing that makes list.php discoverable instead of a tab nobody opens */
.dsave { flex: none; margin: 0; display: flex; align-items: center; }
.savebtn {
  position: relative;
  width: 32px;
  height: 32px;
  border-radius: 11px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--acc);
  font: 700 20px/1 inherit;
  font-family: inherit;
  cursor: pointer;
  padding: 0;
}
.savebtn:hover { border-color: var(--acc); background: var(--accdim); }
.savebtn::before { content: ""; position: absolute; inset: -6px; }
.savebtn.saved { background: var(--acc); border-color: var(--acc); font-size: 0; }
.savebtn.saved::after { content: "\2713"; color: var(--panel); font-size: 17px; font-weight: 800; }

/* density: one line per deal, the rest one tap away. No js: the checkbox
   carries the open state, which is the same trick the filter drawer uses. */
.densebar { display: inline-flex; align-items: center; gap: 6px; }
.densebar .soft { font-size: 12px; }
.chip.dens.on { border-color: var(--acc); color: var(--acc); }
/* comfy needs neither control, and 50 hidden checkboxes would be 50 dead
   tab stops. Compact brings the box back visually hidden but still
   focusable, so the row opens from the keyboard as well as a thumb. */
.dx, .dexp { display: none; }
.deal { position: relative; }
.deals.d-compact .dx {
  display: block;
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.deals.d-compact .dx:focus-visible ~ .dexp { outline: 2px solid var(--acc); outline-offset: 2px; }
.dvia { color: var(--mut); font-size: 12.5px; margin-top: 4px; }
/* price history: the compounding asset made visible. Only ever drawn from
   prices we watched ourselves, which is why the copy counts them out loud. */
.dhist { display: flex; align-items: center; gap: 9px; margin-top: 6px; color: var(--acc); font-size: 12.5px; }
.dhist span { color: var(--mut); }
.spark { flex: none; opacity: 0.9; }
.dvia a { color: var(--mut); text-decoration: underline; text-decoration-color: var(--line); text-underline-offset: 2px; }
.dvia a:hover { color: var(--text); }

.deals.d-compact .deal,
.deals.d-compact .deal.hasimg {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
}
.deals.d-compact .dthumb { width: 40px; height: 40px; border-radius: 6px; }
.deals.d-compact .dmain { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* two-line clamp, measured need: the one-line row was designed against a
   134px median title and corpus drift starved it to 54-85px once most of
   the top fifty wore a chip. A short title still takes one line; only long
   ones grow the row. */
.deals.d-compact .dtitle { -webkit-line-clamp: 2; font-size: 14px; margin-bottom: 0; flex: 1 1 auto; min-width: 0; }
/* new-to-you is a 6px dot in compact, not a chip: when 600 deals arrived
   since the last visit the word NEW carries nothing, and the chip was the
   single biggest title-starver on the page */
.deals.d-compact .deal.isnew .dtitle::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--acc);
  margin-right: 6px;
  vertical-align: 2px;
}
.deals.d-compact .dx:checked ~ .dmain .dtitle::before { display: none; }
.deals.d-compact .dbadges .chip.cnew { display: none; }
.deals.d-compact .dbadges { margin-bottom: 0; flex: none; flex-wrap: nowrap; }
.deals.d-compact .dbadges .chip:not(.key) { display: none; }
/* a full coupon code is 145px of chip and ate the title whole. Clipping is
   safe: the chip is a copy button and data-code still holds the real value */
.deals.d-compact .dbadges .chip.key { max-width: 84px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }
.deals.d-compact .dmeta, .deals.d-compact .dvia, .deals.d-compact .dhist { display: none; }
/* stacked, not inline: a row this tight cannot spend 100px on the price */
.deals.d-compact .dprice { flex-direction: column; align-items: flex-end; gap: 1px; min-width: 0; flex: none; }
.deals.d-compact .dprice .p { font-size: 17px; }
.deals.d-compact .dprice .pc { font-size: 11px; padding: 1px 7px; }
.deals.d-compact .dprice .w { display: none; }
/* a chevron, never a plus: "+" is the add-to-list verb and two identical
   plus buttons side by side taught the row two different meanings */
.deals.d-compact .dexp {
  display: block;
  flex: none;
  width: 26px;
  height: 26px;
  border: 0;
  color: var(--mut);
  cursor: pointer;
  font-size: 13px;
  line-height: 26px;
  text-align: center;
}
.deals.d-compact .dexp:hover { color: var(--acc); }
.deals.d-compact .dexp::after { content: "\25BE"; }
.deals.d-compact .dx:checked ~ .dexp::after { content: "\25B4"; }
/* the visible box stays 30px so the row stays short, but the thumb gets a
   44px target: the same reasoning as the 16px input floor */
.deals.d-compact .dexp::before { content: ""; position: absolute; inset: -7px -9px; }
.deals.d-compact .dexp { position: relative; }
/* THE WHOLE COLLAPSED ROW IS THE EXPAND SURFACE. The expander label's hit
   area stretches over the card while it is collapsed, so tapping anywhere
   opens the details instead of doing nothing; the real controls sit above
   it. Once expanded, the label shrinks back to the caret so taps inside
   the open card do not slam it shut. */
.deals.d-compact .deal { position: relative; }
.deals.d-compact .dx:not(:checked) ~ .dexp { position: static; }
.deals.d-compact .dx:not(:checked) ~ .dexp::before { inset: 0; }
.deals.d-compact .dtitle, .deals.d-compact .dbadges, .deals.d-compact .dsave,
.deals.d-compact .dprice, .deals.d-compact .dmeta, .deals.d-compact .dvia,
.deals.d-compact .dhist { position: relative; z-index: 2; }
/* the deliberate exit: only inside an expanded compact card */
.dgo { display: none; }
.deals.d-compact .dx:checked ~ .dmain .dgo { display: inline-block; margin: 2px 0 8px; position: relative; z-index: 2; }
/* expanded: the full card returns, for this row only */
/* expanded: the card re-composes instead of squeezing. Line one is a strip
   of thumb + price + actions; the detail (title, badges, meta, via) takes
   the FULL card width underneath, so badges flow three to a line instead
   of stacking one per line beside an empty price column. */
.deals.d-compact .deal:has(.dx:checked) { flex-wrap: wrap; align-items: center; }
.deals.d-compact .dx:checked ~ .dmain { display: block; flex: 1 1 100%; order: 9; }
.deals.d-compact .dx:checked ~ .dprice { margin-left: auto; }
.deals.d-compact .dx:checked ~ .dmain .dtitle { -webkit-line-clamp: 6; margin-bottom: 7px; }
.deals.d-compact .dx:checked ~ .dmain .dbadges { flex-wrap: wrap; margin-bottom: 7px; }
.deals.d-compact .dx:checked ~ .dmain .dbadges .chip { display: inline-flex; }
/* the 84px key-chip clip is a collapsed-row measure; expanded it cut
   MONEYMAKER off mid-word */
.deals.d-compact .dx:checked ~ .dmain .dbadges .chip.key { max-width: none; }
.deals.d-compact .dx:checked ~ .dmain .dmeta,
.deals.d-compact .dx:checked ~ .dmain .dvia { display: block; }
.deals.d-compact .dx:checked ~ .dmain .dhist { display: flex; }
.deals.d-compact .dx:checked ~ .dprice .w { display: inline; }

/* digest */
.digest summary, .explainer summary { cursor: pointer; font-weight: 620; display: flex; gap: 8px; align-items: center; }
.explainer p { margin: 8px 0 0; }
.digest-body { margin-top: 10px; }
.digest-body h4 { margin: 12px 0 6px; font-size: 13.5px; color: var(--acc); }
.digest-body ul { margin: 4px 0; padding-left: 20px; }
.digest-body p { margin: 6px 0; }

/* the setup page: no account, so every control here is a preference stored
   against one random browser id */
.panel.flash { border-color: var(--acc); color: var(--acc); }
.setup + .setup { margin-top: 14px; }
.setup h3 { margin: 0 0 4px; font-size: 15px; }
.setup h3 + p { margin-top: 0; }
.setup > p.soft { font-size: 13.5px; }
.pickgrid { display: flex; flex-wrap: wrap; gap: 7px; margin: 10px 0 16px; }
.pick {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 7px 13px;
  cursor: pointer;
  font-size: 13.5px;
  color: var(--mut);
  background: transparent;
}
.pick:hover { border-color: color-mix(in srgb, var(--acc) 45%, var(--line)); color: var(--text); }
.pick.on { border-color: var(--acc); color: var(--acc); background: var(--accdim); }
.pick input { accent-color: var(--acc); margin: 0; }
.synccode {
  display: inline-block;
  background: var(--panel2);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 12px;
  cursor: pointer;
  overflow-wrap: anywhere;
  font-size: 13px;
}
.synccode:hover { border-color: var(--acc); color: var(--acc); }
.btn.danger { background: var(--red); color: #fff; }
.chip.cmine.on { background: var(--accdim); border-color: var(--acc); color: var(--acc); }
.acc { color: var(--acc); }
/* the visit counter is a real link, so it should say so: there is no hover
   on a phone, and accent colour alone reads as emphasis, not as a door */
.newsince { font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }
/* the price check reads as an action, and its answer reads as a fact */
.kcheck { border-color: var(--acc); color: var(--acc); }
.kro { display: inline-flex; flex-wrap: wrap; gap: 6px; align-items: baseline; font-size: 13px; }
.kro strong { font-size: 15px; }
.kwas { text-decoration: line-through; color: var(--mut); }

/* the digest: picks, not prose. The model chose these by id and wrote the
   one-line why; every number and link on the row comes from our own record. */
.dgsec { margin-top: 14px; }
.dgsec:first-child { margin-top: 4px; }
.dgsec h4 { margin: 0 0 6px; font-size: 13px; color: var(--acc); letter-spacing: 0.3px; text-transform: uppercase; }
.dgitem { border-top: 1px solid var(--line); padding: 9px 0; }
.dgsec h4 + .dgitem { border-top: 0; padding-top: 2px; }
.dgrow { display: flex; gap: 10px; align-items: baseline; }
.dgtitle { color: var(--text); font-weight: 650; flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.dgtitle:hover { color: var(--link); }
.dgprice { display: inline-flex; gap: 7px; align-items: baseline; flex: none; }
.dgprice .p { color: var(--acc); font-size: 17px; font-weight: 800; }
.dgwhy { margin: 5px 0 0; color: var(--mut); font-size: 13.5px; }
.dgtags { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.dgitem .dsave { align-self: center; }
.dgitem .savebtn { width: 28px; height: 28px; font-size: 18px; border-radius: 9px; }

/* the Lab: structured plays, not paragraphs. Headline, the net figure as a
   money chip, the cited deals as chips, and the walkthrough one tap down. */
.play { border-top: 1px solid var(--line); padding: 11px 0 3px; }
.play:first-child { border-top: 0; padding-top: 2px; }
.playhead { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.playhead h4 { margin: 0; font-size: 14.5px; color: var(--text); flex: 1 1 auto; min-width: 0; }
.netchip {
  background: var(--accdim);
  color: var(--acc);
  border-radius: 999px;
  padding: 3px 12px;
  font-size: 14px;
  font-weight: 750;
  white-space: nowrap;
}
.playuses { display: flex; gap: 6px; flex-wrap: wrap; margin: 8px 0 0; }
.chip.cuse { color: var(--text); border-color: color-mix(in srgb, var(--acc) 35%, var(--line)); }
.chip.cuse:hover { border-color: var(--acc); text-decoration: none; }
.playhow { margin-top: 8px; }
.playhow summary { cursor: pointer; color: var(--mut); font-size: 12.5px; }
.playhow p { margin: 6px 0 0; }
.playage { font-size: 12px; margin-top: 6px; }

/* shopping list */
.listing { display: flex; flex-direction: column; gap: 12px; }
.litem.off { opacity: 0.55; }
.lihead { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.lihead h3 { margin: 0; font-size: 15px; }
.limatches { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.limatches li {
  display: flex;
  gap: 10px;
  align-items: baseline;
  flex-wrap: wrap;
  border-top: 1px solid var(--line);
  padding-top: 7px;
}
.limatches li > a { flex: 1 1 300px; min-width: 200px; color: var(--text); overflow-wrap: anywhere; }
.limatches li > a:hover { color: var(--link); }
.limeta { display: inline-flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.limeta .p { font-size: 15px; }
.limeta .p.best { text-shadow: 0 0 18px var(--accdim); }

/* status */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; margin-bottom: 14px; }
.tile {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.tile b { font-size: 22px; font-weight: 750; letter-spacing: 0.2px; }
.tile span { color: var(--mut); font-size: 12px; }
.tablewrap { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font-size: 13px; }
th { text-align: left; color: var(--mut); font-weight: 600; font-size: 12px; }
th, td { padding: 6px 10px 6px 0; border-bottom: 1px solid var(--line); vertical-align: top; }
tr:last-child td { border-bottom: 0; }
tr.off { opacity: 0.5; }
.dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; }
.dot.green { background: var(--acc); }
.dot.amber { background: var(--amber); }
.dot.grey { background: var(--mut); opacity: 0.5; }
.meter { min-width: 90px; }
.meter span { display: block; height: 7px; border-radius: 4px; background: var(--acc); min-width: 2px; }
.gaps { margin: 4px 0; padding-left: 20px; }
.gaps li { margin: 3px 0; }

/* pager + empty */
.pager { display: flex; gap: 14px; align-items: center; justify-content: center; margin: 18px 0; color: var(--mut); font-size: 13px; }
.empty { text-align: center; padding: 34px 20px; }
.empty h2 { margin: 0 0 8px; }
.empty p { color: var(--mut); margin: 6px 0; }
.empty pre { display: inline-block; text-align: left; }

/* filters: the secondary row folds away on phones via the checkbox hack */
/* the drawer is now universal, not a mobile afterthought: the search box is
   the only control that earns permanent space above the deals */
.fmore-btn { display: inline-flex; white-space: nowrap; }
.filters .f2 { display: none; }
.fmore-box:checked ~ .f2 { display: flex; }
/* visually hidden but focusable, so the drawer opens from the keyboard */
.fmore-box {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.fmore-box:focus-visible ~ .frow .fmore-btn,
.filters:focus-within .fmore-btn:hover { outline: 2px solid var(--acc); outline-offset: 2px; }
.fcount {
  background: var(--acc);
  color: var(--panel);
  border-radius: 999px;
  min-width: 17px;
  height: 17px;
  padding: 0 5px;
  font-size: 11px;
  font-weight: 750;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
/* the first-run card: one sitting, one job, then gone forever */
.intro {
  position: relative;
  border-color: color-mix(in srgb, var(--acc) 35%, var(--line));
  padding-right: 44px;
}
.intro h2 { margin: 0 0 6px; font-size: 18px; }
.intro p { margin: 0 0 10px; color: var(--mut); font-size: 14px; }
.intro .chips { flex-wrap: wrap; }
.introx {
  position: absolute;
  top: 6px;
  right: 8px;
  width: 34px;
  height: 34px;
  line-height: 34px;
  text-align: center;
  font-size: 18px;
  color: var(--mut);
  border-radius: 9px;
}
.introx:hover { color: var(--text); background: var(--panel2); text-decoration: none; }

/* the toast: the page's one transient voice, used by the watch flow */
#dwtoast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translate(-50%, 16px);
  max-width: min(92vw, 480px);
  padding: 11px 16px;
  border-radius: 12px;
  background: var(--panel2);
  border: 1px solid color-mix(in srgb, var(--acc) 45%, var(--line));
  color: var(--text);
  font-size: 14px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
  z-index: 40;
}
#dwtoast.show { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
#dwtoast a { color: var(--acc); }
@media (max-width: 700px) {
  /* clear the bottom tab bar */
  #dwtoast { bottom: 76px; }
}
.watchnote { margin: -6px 0 12px; }

/* the You page pickers, grouped the way a shopper thinks */
.pickhead {
  margin: 14px 0 7px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.7px;
  text-transform: uppercase;
  color: var(--mut);
}
.pickfold { margin-top: 10px; }
.pickfold summary.pickhead { cursor: pointer; margin: 0 0 7px; }
.pickfold summary.pickhead:hover { color: var(--text); }

/* active filters stay visible as pills so the drawer can stay shut */
.activef { display: flex; gap: 6px; flex-wrap: wrap; margin: 0 0 10px; }
.chip.pill { color: var(--text); border-color: color-mix(in srgb, var(--acc) 40%, var(--line)); }
.chip.pill:hover { border-color: var(--acc); text-decoration: none; }
.chip.pill .x { color: var(--mut); font-size: 14px; line-height: 1; }
.chip.pill:hover .x { color: var(--acc); }
.chip.pill.clearall { color: var(--mut); border-style: dashed; }
.explainer p { margin: 4px 0; }

/* mobile first-class: a real app shell. The PAGE never scrolls; the content
   pane does, pinned between a fixed header and a fixed tab bar. */
@media (max-width: 700px) {
  html, body { height: 100%; }
  body {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  /* backdrop-filter on an ancestor makes it the containing block for FIXED
     descendants, so the blur inherited from the desktop rule anchored the
     "bottom" tab bar to the header's own box: it rendered at the TOP of the
     screen, sitting on the brand, and the bottom bar never existed on a
     phone. Nothing scrolls under this header (main is its own scroll pane),
     so the blur bought nothing here anyway. */
  header.top { position: static; flex: none; backdrop-filter: none; background: var(--bg); }
  main {
    flex: 1 1 0;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-y: contain;
    max-width: none;
    width: 100%;
  }
  main { padding: 14px 12px 40px; }
  header.top { gap: 12px; padding: 10px 12px; padding-top: calc(10px + env(safe-area-inset-top, 0px)); }
  header.top nav {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 10;
    display: flex;
    justify-content: space-around;
    gap: 0;
    background: color-mix(in srgb, var(--panel) 92%, transparent);
    backdrop-filter: blur(10px);
    border-top: 1px solid var(--line);
    padding: 6px calc(6px + env(safe-area-inset-right, 0px))
             calc(6px + env(safe-area-inset-bottom, 0px))
             calc(6px + env(safe-area-inset-left, 0px));
  }
  /* 44px minimum touch targets per the Apple sizing guidance; four tabs
     now share the bar, so each also gets a quarter of the width */
  header.top nav a { flex: 1; text-align: center; padding: 13px 4px; font-size: 14px; font-weight: 600; border-radius: 10px; }
  main { padding-bottom: calc(100px + env(safe-area-inset-bottom, 0px)); }
  .deal { flex-direction: column; gap: 8px; }
  .deal.hasimg { display: grid; grid-template-columns: 56px 1fr; gap: 8px 10px; }
  .deal.hasimg .dthumb { width: 56px; height: 56px; }
  .deal.hasimg .dprice { grid-column: 1 / -1; }
  .dprice { flex-direction: row; align-items: baseline; gap: 10px; min-width: 0; }
  /* the search box claimed min-width 200px inside a 318px row, which pushed
     the filters button onto a second line and cost 40px of screen above the
     first deal. On a phone they share one line. */
  .filters .search { flex: 1 1 auto; min-width: 0; }
  .filters .frow { flex-wrap: nowrap; }
  .filters .f2 { flex-wrap: wrap; }
  .filters select { max-width: none; flex: 1 1 130px; }
  .filters .f2 { flex-direction: column; align-items: stretch; }
  .filters .f2 .btn { width: 100%; text-align: center; }
  .chips { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; padding-bottom: 4px; overscroll-behavior-x: contain; }
  .chips::-webkit-scrollbar { display: none; }
  /* expanded AI panels scroll inside themselves, never hijack the page */
  .digest-body { max-height: 46vh; overflow-y: auto; -webkit-overflow-scrolling: touch; }

  /* 'auto' is the no-cookie default, and on a phone it means compact. Same
     rules as .d-compact; the duplication is deliberate, because the choice
     is a viewport question here and an explicit one there. */
  .deals.d-auto .deal,
  .deals.d-auto .deal.hasimg {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
  }
  .deals.d-auto .dthumb { width: 40px; height: 40px; border-radius: 6px; }
  .deals.d-auto .dmain { display: flex; align-items: center; gap: 8px; min-width: 0; }
  .deals.d-auto .dtitle { -webkit-line-clamp: 2; font-size: 14px; margin-bottom: 0; flex: 1 1 auto; min-width: 0; }
  .deals.d-auto .deal.isnew .dtitle::before {
    content: "";
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--acc);
    margin-right: 6px;
    vertical-align: 2px;
  }
  .deals.d-auto .dx:checked ~ .dmain .dtitle::before { display: none; }
  .deals.d-auto .dbadges .chip.cnew { display: none; }
  .deals.d-auto .dbadges { margin-bottom: 0; flex: none; flex-wrap: nowrap; }
  .deals.d-auto .dbadges .chip:not(.key) { display: none; }
  .deals.d-auto .dbadges .chip.key { max-width: 84px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }
  .deals.d-auto .dmeta, .deals.d-auto .dvia, .deals.d-auto .dhist { display: none; }
  .deals.d-auto .dprice { flex-direction: column; align-items: flex-end; gap: 1px; min-width: 0; flex: none; }
  .deals.d-auto .dprice .p { font-size: 17px; }
  .deals.d-auto .dprice .pc { font-size: 11px; padding: 1px 7px; }
  .deals.d-auto .dprice .w { display: none; }
  .deals.d-auto .dexp {
    display: block;
    flex: none;
    width: 28px;
    height: 30px;
    border: 0;
    color: var(--mut);
    cursor: pointer;
    font-size: 13px;
    line-height: 30px;
    text-align: center;
  }
  .deals.d-auto .dexp::after { content: "\25BE"; }
  .deals.d-auto .dx:checked ~ .dexp::after { content: "\25B4"; }
  .deals.d-auto .dx {
    display: block;
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .deals.d-auto .dx:focus-visible ~ .dexp { outline: 2px solid var(--acc); outline-offset: 2px; }
  .deals.d-auto .dexp { position: relative; }
  .deals.d-auto .dexp::before { content: ""; position: absolute; inset: -7px -9px; }
  .deals.d-auto .deal { position: relative; }
  .deals.d-auto .dx:not(:checked) ~ .dexp { position: static; }
  .deals.d-auto .dx:not(:checked) ~ .dexp::before { inset: 0; }
  .deals.d-auto .dtitle, .deals.d-auto .dbadges, .deals.d-auto .dsave,
  .deals.d-auto .dprice, .deals.d-auto .dmeta, .deals.d-auto .dvia,
  .deals.d-auto .dhist { position: relative; z-index: 2; }
  .deals.d-auto .dx:checked ~ .dmain .dgo { display: inline-block; margin: 2px 0 8px; position: relative; z-index: 2; }
  .deals.d-auto .deal:has(.dx:checked) { flex-wrap: wrap; align-items: center; }
  .deals.d-auto .dx:checked ~ .dmain { display: block; flex: 1 1 100%; order: 9; }
  .deals.d-auto .dx:checked ~ .dprice { margin-left: auto; }
  .deals.d-auto .dx:checked ~ .dmain .dtitle { -webkit-line-clamp: 6; margin-bottom: 7px; }
  .deals.d-auto .dx:checked ~ .dmain .dbadges { flex-wrap: wrap; margin-bottom: 7px; }
  .deals.d-auto .dx:checked ~ .dmain .dbadges .chip { display: inline-flex; }
  .deals.d-auto .dx:checked ~ .dmain .dbadges .chip.key { max-width: none; }
  .deals.d-auto .dx:checked ~ .dmain .dmeta,
  .deals.d-auto .dx:checked ~ .dmain .dvia { display: block; }
  .deals.d-auto .dx:checked ~ .dmain .dhist { display: flex; }
  .deals.d-auto .dx:checked ~ .dprice .w { display: inline; }
  /* the tap target has to clear 44px even when the row is 40px tall */
  .deals.d-compact .dexp { width: 30px; height: 30px; line-height: 28px; }
}
@media (pointer: coarse) {
  .chip { padding: 6px 12px; }
  /* the drawer handle is a primary control on a phone, so it gets a real
     44px target rather than the 32px a chip would give it */
  .fmore-btn { padding: 12px 16px; font-size: 14px; }
  /* the setup page is nothing but tap targets; 37px is not one */
  .pick { padding: 11px 15px; font-size: 14.5px; }
  .btn { padding: 11px 18px; font-size: 16px; }
  /* 16px floor: anything smaller makes iOS zoom the page on focus */
  .filters input[type="search"], .filters input[type="text"],
  .filters input[type="number"], .filters select {
    padding: 11px 12px;
    font-size: 16px;
  }
  .dtitle { margin-bottom: 9px; }
}

/* touch feedback: fingers get the press state hover never gives them */
@media (hover: none) {
  header.top nav a:active { background: var(--panel2); transform: scale(0.96); }
  .btn:active, .pick:active { transform: scale(0.97); filter: brightness(1.12); }
  .deal:active { background: var(--panel2); }
  header.top nav a, .btn, .pick { transition: transform 0.08s ease, background 0.12s ease; }
}

/* pull to refresh (app shells; app.js mounts #ptr only there). The dot
   rides above the content, arms at the threshold, spins while reloading. */
#ptr {
  position: fixed;
  top: -44px;
  left: 50%;
  z-index: 20;
  width: 30px;
  height: 30px;
  margin-left: -15px;
  border-radius: 50%;
  background: var(--panel);
  border: 1px solid var(--line);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
  opacity: 0;
  pointer-events: none;
}
#ptr::after {
  content: "";
  position: absolute;
  inset: 7px;
  border-radius: 50%;
  border: 2.5px solid var(--line);
  border-top-color: var(--acc);
  transform: rotate(40deg);
}
#ptr.show { opacity: 1; }
#ptr.armed::after { border-color: var(--acc); border-top-color: var(--acc); }
#ptr.spin::after { animation: ptrspin 0.7s linear infinite; }
@keyframes ptrspin { to { transform: rotate(400deg); } }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}
