/* NoFussDeal editorial design system.
   Shared by every redesigned page. Page-specific rules stay with their page.
   No webfonts, no framework: the type stack is system-resident by design. */

:root{
  --ink:#17120d; --body:#3b332b; --muted:#6b6159; --faint:#a99f95;
  --canvas:#fffdf8; --cream:#fdf9f1; --sand:#f6efe3; --rule:#e6dccb;
  /* listing surfaces: white cards need a ground to read as white,
     so the grid sits on --ground and each card is --surface */
  --surface:#ffffff; --ground:#f4f2ee; --hairline:#e8e4dc;
  --flame:#e8451f; --flame-deep:#b1330f; --teal:#0d5157; --mustard:#f0b32a;
  --gold:#8a6100; --pro:#1c6b45; --con:#a3271f; --measure:70ch;
  /* The three faces, named once. Twenty-four rules used to spell out their
     own stack and they had drifted: the body said "Charter, Bitstream
     Charter, Sitka Text, Georgia" while tables, quotes and the buyers'
     summary said "Charter, Georgia". Charter ships with macOS but not
     Windows, so on Windows the prose fell to Sitka Text and those other
     elements fell to Georgia - two serifs in one article, from a
     copy-paste omission rather than a decision. */
  --serif-body:Charter,"Bitstream Charter","Sitka Text",Georgia,"Times New Roman",Times,serif;
  --serif-display:"Iowan Old Style","Palatino Linotype",Palatino,Charter,Georgia,serif;
  --sans:"Helvetica Neue",Helvetica,Arial,system-ui,sans-serif;
}

*{box-sizing:border-box}
html{color-scheme:only light}
body{margin:0;background:var(--canvas);color:var(--body);
  font:400 19px/1.62 var(--serif-body)}
.wrap{max-width:1200px;margin:0 auto;padding:0 28px}
.narrow{max-width:var(--measure)}
img{max-width:100%;height:auto;display:block}
a{color:inherit}
.tab{font-variant-numeric:tabular-nums}
h1,h2,h3,h4{color:var(--ink);margin:0;font-weight:400}
h2,h3,h4,.disp{font-family:var(--serif-display);letter-spacing:-.018em}
.s,button,nav,th,caption,label{font-family:var(--sans)}
p{margin:0 0 1.05em}
:focus-visible{outline:3px solid var(--flame-deep);outline-offset:3px}

.skip{position:absolute;left:-9999px}
.skip:focus{left:12px;top:12px;background:var(--ink);color:var(--canvas);padding:10px 16px;z-index:9}

/* masthead */
/* Sticky header.
   The two bars are siblings, so they are pinned as a stack rather than wrapped:
   the utility bar sits at 0 and the masthead directly beneath it at its height.
   --head-h is the total, published here so anything that has to clear the
   header - the sticky rail, :target scroll offsets - reads one number instead of
   repeating a magic one. Measured, not guessed: 42 and 76 (96 on phones, two rows). */
:root{ --topbar-h:42px; --mast-h:76px; --head-h:118px }
@media(max-width:720px){ :root{ --topbar-h:0px; --mast-h:96px; --head-h:96px } }

.topbar{position:sticky;top:0;z-index:60}
.mast{border-bottom:2px solid var(--ink);background:var(--canvas);
  position:sticky;top:var(--topbar-h);z-index:55}

/* A dropdown must sit above the bar below it, and both above the page. */
.mast .dropmenu{z-index:56}

/* An in-page anchor would otherwise land under the sticky header. */
:target{scroll-margin-top:calc(var(--head-h) + 12px)}
html{scroll-padding-top:calc(var(--head-h) + 12px)}

/* Short viewports: a 118px fixed header on a 500px-tall window leaves too
   little reading room, so only the masthead stays. */
@media(max-height:560px){
  .topbar{position:static}
  .mast{top:0}
  :root{ --head-h:76px }
}
.mast-in{display:flex;align-items:center;gap:32px;padding:15px 0}
.wm{font-family:Georgia,serif;font-size:25px;letter-spacing:-.025em;color:var(--ink);text-decoration:none}
.wm b{color:var(--flame-deep)}
.mast nav{margin-left:auto;display:flex;gap:22px}
.mast nav a{font:700 11.5px/1 var(--sans);letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink);text-decoration:none;padding:9px 0;border-bottom:2px solid transparent;transition:border-color .18s}
.mast nav a:hover{border-bottom-color:var(--flame-deep)}

/* breadcrumb */
.crumbs{padding:12px 28px}
/* Phones: 20px gutters. 28px on a 390px screen leaves a 334px measure, which
   wraps 19px serif every five or six words. Site-wide, so the masthead, crumbs
   and page content keep one left edge. */
@media(max-width:560px){
  .wrap{padding-left:20px;padding-right:20px}
  .crumbs{padding-left:20px;padding-right:20px}
}
.crumbs ol{list-style:none;display:flex;flex-wrap:wrap;align-items:center;gap:0 8px;margin:0;padding:0;
  font:400 13px/1.4 var(--sans);color:var(--muted)}
.crumbs li{display:flex;align-items:center}
.crumbs li+li::before{content:"/";padding-right:8px;color:var(--faint);line-height:1}
.crumbs a{color:var(--muted);text-decoration:none}
.crumbs a:hover{color:var(--flame-deep);text-decoration:underline}

/* :target lets the thumbnails work with zero JS */
.gal-main:has(img:target) img.is-current{display:none}
.gal-thumbs{list-style:none;display:flex;flex-direction:column;gap:6px;margin:0;padding:0 4px 0 0;
  max-height:520px;overflow-y:auto;overscroll-behavior:contain;
  scrollbar-width:none;-ms-overflow-style:none}
.gal-thumbs li{flex:0 0 auto;width:100%}
.gal-thumbs::-webkit-scrollbar{width:0;height:0;display:none}
.gal-thumbs a{display:block;border:1px solid var(--rule);background:var(--canvas);padding:3px;
  transition:border-color .16s}
.gal-thumbs a:hover{border-color:var(--flame-deep)}
.gal-thumbs a[aria-selected="true"]{border-color:var(--ink);border-width:2px;padding:2px}
.gal-thumbs img{aspect-ratio:1/1;object-fit:contain}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ---------- top bar + masthead ---------- */
/* The utility bar is a dark strip in BOTH modes, so its background cannot be
   --ink: that token inverts to near-white in dark mode while the text here stays
   pale, which measured 1.51:1 against a 4.5 floor. It was always wrong; pinning
   the header made it permanent instead of something you scrolled past. */
.topbar{background:#17120d;color:#fdf9f1}

.topbar-in{display:flex;justify-content:space-between;align-items:center;gap:16px;
  padding:7px 0;font:400 13px/1.4 var(--sans)}
.topbar p{margin:0;color:#cfc6ba}
.topbar nav{display:flex;gap:18px}
.topbar a{color:#cfc6ba;text-decoration:none;transition:color .16s}
.topbar a:hover{color:var(--flame)}
@media(max-width:720px){.topbar{display:none}}

.brand{display:flex;align-items:center;gap:11px;text-decoration:none;flex:0 0 auto}
.brand img{width:44px;height:44px;object-fit:contain}
.brand-txt{display:flex;flex-direction:column;line-height:1.1}
.brand-txt b{font-family:var(--serif-display);
  font-size:23px;font-weight:400;color:var(--ink);letter-spacing:-.02em}
/* The tagline sits directly under the wordmark, so it takes the same display
   serif: a sans line under a serif name read as two brands stacked. */
.brand-txt em{font:400 12.5px/1.3 var(--serif-display);font-style:normal;
  color:var(--muted);letter-spacing:.01em}
/* Surprise Me was the same solid flame as "Check price on Amazon", so the
   masthead's discovery link and the page's buy button read as one action.
   Flame now belongs to buying alone. Surprise Me takes the mustard the header
   band uses for its labels, with a shuffle mark that turns on hover: playful,
   and unmistakably not a purchase. Ink on mustard is 10:1. */
.surprise{display:inline-flex;align-items:center;gap:8px;background:var(--mustard);color:#241a00;
  text-decoration:none;padding:10px 16px;
  font:800 11.5px/1 var(--sans);letter-spacing:.09em;text-transform:uppercase;
  white-space:nowrap;box-shadow:inset 0 -2px 0 rgba(36,26,0,.22);
  transition:background-color .18s,transform .12s}
.surprise svg{flex:0 0 auto;transition:transform .45s cubic-bezier(.2,.9,.3,1)}
.surprise:hover{background:#e3a41d}
.surprise:hover svg{transform:rotate(180deg)}
.surprise:active{transform:translateY(1px)}
.surprise:focus-visible{outline:3px solid var(--ink);outline-offset:2px}
@media(prefers-reduced-motion:reduce){.surprise svg{transition:none}.surprise:hover svg{transform:none}}
.searchbtn{display:inline-flex;padding:9px;color:var(--ink);text-decoration:none;
  border:1px solid var(--rule);transition:border-color .18s,color .18s}
.searchbtn:hover{border-color:var(--flame-deep);color:var(--flame-deep)}

@media(max-width:900px){.brand-txt em{display:none}}
@media(max-width:720px){
  /* Phones: two rows instead of three. Row one is the brand on the left with
     search and Surprise Me as matching square buttons on the right; row two is
     the four sections spread across the full width under a hairline. The old
     layout let a full-width Surprise Me push search onto a row of its own and
     cut the section list off at "Buying Gui".
     .mast-in shares its element with .wrap, so the side padding is restated
     here: a bare "padding:10px 0" put the logo against the screen edge. */
  .mast-in{flex-wrap:wrap;gap:0 8px;padding:10px 28px 0}
  .brand{order:1;flex:1 1 auto;min-width:0;gap:9px}
  .brand img{width:36px;height:36px}
  .brand-txt b{font-size:21px;white-space:nowrap}
  .searchbtn{order:2;padding:8px}
  .surprise{order:3;padding:9px;border:1px solid transparent}
  /* The label stays for screen readers; the icon carries it on screen. */
  .surprise-txt{position:absolute;width:1px;height:1px;overflow:hidden;
    clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}
  .mast nav{order:4;width:100%;margin:10px 0 0;gap:12px;justify-content:space-between;
    border-top:1px solid var(--rule)}
  .mast nav a{white-space:nowrap;flex:0 0 auto;font-size:11px;letter-spacing:.07em;padding:12px 0 11px}
}
/* 360px Androids: slightly tighter type so all four sections still fit. */
@media(max-width:389px){
  .mast nav{gap:8px}
  .mast nav a{font-size:10.5px;letter-spacing:.04em}
}
/* Below that they no longer fit side by side, so the row scrolls sideways
   instead of wrapping. Kept narrow on purpose: a scrolling row clips the
   Categories dropdown, which opens normally on wider phones. */
@media(max-width:349px){
  .mast nav{justify-content:flex-start;gap:16px;overflow-x:auto;
    scrollbar-width:none;-webkit-overflow-scrolling:touch}
  .mast nav::-webkit-scrollbar{display:none}
}
/* after the 720px block, so the phone gutter is not overridden by its 28px */
@media(max-width:560px){.mast-in{padding-left:20px;padding-right:20px}}

/* ---------- footer ----------
   Sits on the deep teal rather than the ink used by the verdict panel, so the
   two dark blocks read as separate zones instead of one long slab. Teal also
   bookends the buy bar near the top of the page. */
.foot{background:var(--teal);color:#eef7f6}
.foot h2{color:#fff;font:700 11px/1 var(--sans);
  letter-spacing:.15em;text-transform:uppercase;margin:0 0 15px}
.foot h2::before{content:none}
.foot h2 a{text-decoration:none;color:inherit}
.foot a{color:#cfe4e3;text-decoration:none}

/* newsletter: copy left, form right, so it does not read as a centred AI banner */
.foot-news{background:#0a4247;border-bottom:1px solid rgba(255,255,255,.1)}
.foot-news-in{display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:center;
  padding-top:38px;padding-bottom:38px}
@media(max-width:860px){.foot-news-in{grid-template-columns:1fr;gap:20px}}
.fn-copy h2{font:400 27px/1.2 var(--serif-display);
  letter-spacing:-.02em;text-transform:none;margin:0 0 7px;color:#fff}
.fn-copy p{margin:0;color:#bcd6d5;font-size:16px;line-height:1.5;max-width:44ch}
.foot-news form{display:flex;flex-wrap:wrap;gap:9px}
.foot-news input{flex:1 1 210px;min-width:0;padding:13px 15px;border:1px solid rgba(255,255,255,.28);
  background:#083539;color:#fff;font:400 15.5px/1 var(--sans)}
.foot-news input::placeholder{color:#8fb0af}
.foot-news input:focus-visible{outline:2px solid var(--mustard);outline-offset:1px;border-color:var(--mustard)}
.foot-news button{background:var(--flame);color:#2a0d05;border:0;padding:13px 25px;cursor:pointer;
  font:800 12.5px/1 var(--sans);letter-spacing:.1em;text-transform:uppercase;
  transition:background-color .18s}
.foot-news button:hover{background:#ff8055}
.foot-news .fine{flex:1 0 100%;font:400 12px/1 var(--sans);color:#8fb0af}

/* brand block sits apart from the link groups rather than becoming a 5th column */
.foot-main{display:grid;grid-template-columns:300px 1fr;gap:56px;
  padding-top:44px;padding-bottom:40px}
@media(max-width:960px){.foot-main{grid-template-columns:1fr;gap:34px}}
.foot-logo{display:flex;align-items:center;gap:12px;text-decoration:none;margin-bottom:14px}
/* The mark is a full-colour badge (navy interior at #073C65) on transparency.
   It measures about 1.3:1 against the teal, so it cannot sit bare, and it
   cannot be inverted without losing the green and red. A fitted cream disc
   reads as a seal rather than a stray white rectangle, and the source art's
   illegible ".com" strip is cropped out (see nofussdeal-badge.webp). */
.foot-logo img{width:58px;height:58px;object-fit:contain;background:var(--cream);
  padding:6px;border-radius:50%;box-shadow:0 0 0 1px rgba(255,255,255,.28)}
.foot-logo span{display:flex;flex-direction:column;line-height:1.15}
.foot-logo b{font-family:var(--serif-display);
  font-size:23px;font-weight:400;color:#fff;letter-spacing:-.02em}
/* Same lockup as the masthead: serif name, serif tagline. */
.foot-logo em{font:400 12.5px/1.3 var(--serif-display);font-style:normal;color:#9fc0bf}
.foot-blurb{color:#bcd6d5;font-size:15.5px;line-height:1.55;margin:0 0 18px;max-width:36ch}
.foot-social{display:flex;gap:8px}
.foot-social a{display:inline-flex;padding:9px;border:1px solid rgba(255,255,255,.2);color:#cfe4e3;
  transition:border-color .18s,color .18s,background-color .18s}
.foot-social a:hover{border-color:var(--flame);color:#fff;background:rgba(255,106,69,.14)}

.foot-links{display:grid;grid-template-columns:repeat(4,1fr);gap:30px}
@media(max-width:760px){.foot-links{grid-template-columns:repeat(2,1fr);gap:26px}}
@media(max-width:420px){.foot-links{grid-template-columns:1fr}}
.foot ul{list-style:none;margin:0;padding:0}
.foot li{margin-bottom:10px}
.foot li a{font:400 15px/1.4 var(--serif-body);
  border-bottom:1px solid transparent;transition:color .18s,border-color .18s}
.foot li a:hover{color:#fff;border-bottom-color:var(--flame)}

.foot-bar{border-top:1px solid rgba(255,255,255,.12)}
.foot-bar .wrap{display:flex;justify-content:space-between;flex-wrap:wrap;gap:10px;
  padding-top:18px;padding-bottom:18px}
.foot-bar p{margin:0;font:400 13px/1.4 var(--sans);color:#9fc0bf}
.foot-bar-links{display:flex;gap:22px}
.foot-bar-links a{color:#cfe4e3;border-bottom:1px solid rgba(255,255,255,.25)}
.foot-bar-links a:hover{color:#fff;border-bottom-color:var(--flame)}

@media print{.foot-news,.foot-social{display:none}}

/* ---------- touch targets ----------
   WCAG 2.2 AA (2.5.8) wants 24x24 CSS px minimum, and Google treats tap-target
   spacing as a mobile-usability signal. Padding is added rather than font size
   so the visual rhythm is unchanged. */
/* Applied at every width, not just coarse pointers: WCAG 2.5.8 is input
   agnostic, and the padding costs nothing visually. */
.topbar a{padding-top:5px;padding-bottom:5px;display:inline-block}
.crumbs a,.crumbs li[aria-current]{padding-top:5px;padding-bottom:5px;display:inline-block}
/* the column heading, not just its link: only "Categories" wraps its text in
   an anchor, so padding on the anchor alone would misalign the four columns */
.foot li a{padding-top:5px;padding-bottom:5px;display:inline-block}
.foot-bar-links a{padding-top:6px;padding-bottom:6px;display:inline-block}

@media(pointer:coarse),(max-width:1080px){
  .topbar a{padding-top:6px;padding-bottom:6px}
  .crumbs a,.crumbs li{padding-top:5px;padding-bottom:5px;display:inline-block}
  .filters a{padding-top:11px;padding-bottom:11px}
}

/* back to top: appears once the reader is past the first screen. Sits above
   the mobile buy bar so the two never overlap. */
#to-top{position:fixed;right:20px;bottom:24px;z-index:45;width:48px;height:48px;
  display:grid;place-items:center;cursor:pointer;border-radius:50%;
  background:var(--flame-deep);color:#fff;border:0;
  box-shadow:0 3px 14px rgba(23,18,13,.28);
  opacity:0;transform:translateY(8px);pointer-events:none;
  transition:opacity .22s ease,transform .22s ease,background-color .18s}
#to-top.show{opacity:1;transform:none;pointer-events:auto}
#to-top:hover{background:#8d280b}
#to-top:active{transform:translateY(1px)}
#to-top:focus-visible{outline:3px solid var(--flame-deep);outline-offset:3px}
@media(max-width:1080px){#to-top{bottom:76px;right:14px;width:46px;height:46px}}
@media(prefers-reduced-motion:reduce){#to-top{transition:opacity .01ms}}
@media print{#to-top{display:none}}

/* quotes */

/* ---------- shared components used by every page ---------- */
.buy{background:var(--flame-deep);color:#fff;text-decoration:none;padding:15px 28px;
  font:800 13px/1 var(--sans);letter-spacing:.1em;text-transform:uppercase;
  white-space:nowrap;transition:background-color .18s,transform .12s;display:inline-block}
.buy:hover{background:#8d280b}
.buy:active{transform:translateY(1px)}
.buy:focus-visible{outline:3px solid var(--mustard);outline-offset:3px}
/* "Check price on Amazon" set in tracked-out caps with 28px of side padding
   measures 277px and will not wrap, which is wider than the 265px content
   column on a 320px screen - so the whole page scrolled sideways. On small
   screens it wraps and fills the column instead, which is a better tap
   target anyway. */
@media(max-width:560px){
  .buy{display:block;width:100%;text-align:center;white-space:normal;
    padding:14px 18px;letter-spacing:.06em;line-height:1.3}
}


.sechead{margin:0 0 22px;padding-bottom:11px;border-bottom:2px solid var(--ink);
  display:flex;align-items:baseline;gap:13px;scroll-margin-top:22px}
.sechead h2{font-size:29px}

/* page masthead for listing pages: title + standfirst on the cream band */
/* Compact by design: this band names the page, it is not a hero. Every pixel
   here pushes the first card further below the fold. */
.pagehead{background:var(--cream);border-bottom:1px solid var(--rule);
  padding-top:26px;padding-bottom:24px}
.pagehead h1{font-family:var(--serif-display);
  font-size:clamp(31px,3.6vw,46px);line-height:1.06;letter-spacing:-.02em;
  margin:0;max-width:24ch;text-wrap:balance}
.pagehead p{font-size:17px;line-height:1.5;color:var(--muted);margin:10px 0 0;max-width:62ch}
.pagehead .count{font:700 11.5px/1 var(--sans);letter-spacing:.14em;
  text-transform:uppercase;color:var(--flame-deep);display:block;margin-bottom:10px}

/* card grid shared by reviews / roundups / guides listings.
   The card is a white surface on a light ground, not text sitting directly on
   the page: the surface edge is what lets the eye take one card at a time.
   Everything inside earns its line — the rating appears once (the plate on the
   image), the title is capped at two lines, and the foot row is price and one
   action, so no card is a wall of text. */
.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:26px 24px;margin:0;padding:0;list-style:none}
@media(max-width:1000px){.cards{grid-template-columns:repeat(2,1fr);gap:24px 20px}}
@media(max-width:620px){.cards{grid-template-columns:1fr;gap:20px}}
.card{display:flex;flex-direction:column;min-width:0;
  background:var(--surface);border:1px solid var(--hairline);
  /* shadow carries the page's warmth rather than neutral black */
  box-shadow:0 1px 2px rgba(60,48,34,.05);
  transition:border-color .18s ease,box-shadow .18s ease,transform .18s ease}
.card:hover{border-color:var(--rule);box-shadow:0 6px 20px rgba(60,48,34,.10);transform:translateY(-2px)}
@media(prefers-reduced-motion:reduce){.card,.card:hover{transition:none;transform:none}}

.card a.shot-link{display:block;text-decoration:none;position:relative;
  background:var(--surface);border-bottom:1px solid var(--hairline)}
.card a.shot-link img{aspect-ratio:4/3;object-fit:contain;width:100%;padding:20px;
  transition:opacity .18s}
.card a.shot-link:hover img{opacity:.92}
.card .score{position:absolute;left:12px;top:12px;background:var(--teal);color:#f2fbfa;
  padding:5px 10px;font:400 15.5px/1 Georgia,serif;font-variant-numeric:tabular-nums}


/* text block: padded, so nothing runs to the card edge */
.card .eyebrow{font:700 10.5px/1 var(--sans);letter-spacing:.13em;
  text-transform:uppercase;color:var(--teal);margin:0;padding:16px 18px 0}

/* Two lines are RESERVED, not just the maximum.
   The clamp alone was enough while every title was a 130-character listing
   string that always wrapped to two lines, so the row lined up by accident.
   Trimming titles to the product name made them one or two lines, and the
   excerpt, price and action below them stopped sharing a baseline across the
   row - measured at 55/31/31px and excerpts 24px apart. Reserving the second
   line costs nothing when it is used and keeps the row square when it is not. */
.card h2,.card h3{font-size:18.5px;line-height:1.3;margin:0;padding:7px 18px 0;
  min-height:calc(2 * 1.3em + 7px);
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}
/* Not every product has a category, so the title has to carry the top gap
   itself when no eyebrow precedes it — otherwise it butts against the image. */
.card .shot-link + h2,.card .shot-link + h3{padding-top:16px}
/* One stretched link per card.
   The card advertises "Read review" with an arrow in its footer, but that cue
   is a decorative span and the only real link was on the heading - so clicking
   the thing that looks most like the button selected text instead of
   navigating. The heading's anchor is now stretched over the whole card, which
   makes every part of it clickable while still exposing a single link carrying
   the product name to a screen reader.
   .card must be the containing block for that to work: an absolutely
   positioned ::after resolves against the nearest POSITIONED ancestor, and
   without this it would size itself to .shot-link instead of the card. */
.card{position:relative}
.card h2 a,.card h3 a{text-decoration:none;color:var(--ink)}
.card h2 a::after,.card h3 a::after{content:"";position:absolute;inset:0;z-index:1}
/* Anything that must stay separately clickable sits above the stretched link. */
.card .meta a,.card .buy,.card .eyebrow a{position:relative;z-index:2}
.card h2 a:hover,.card h3 a:hover{color:var(--flame-deep)}
/* vertical spacing is margin, not padding: a clamped -webkit-box paints the
   next line inside its own bottom padding, so padding here leaks a third line */
.card .blurb{font:400 14.5px/1.55 var(--serif-body);color:var(--muted);
  margin:8px 0 16px;padding:0 18px;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}

/* foot row: the price and the one action, on a rule, pinned to the bottom so
   the row of cards shares a baseline whatever the title length */
.card .meta{margin-top:auto;padding:12px 18px;border-top:1px solid var(--hairline);
  font:400 13px/1.4 var(--sans);color:var(--muted);
  display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.card .meta .price{font:600 17px/1.2 var(--sans);color:var(--ink);
  font-variant-numeric:tabular-nums}
/* A struck-through price still carries information — how much the discount is
   — so it has to meet AA like any other value, not sit at decoration contrast. */
.card .meta .was{margin-left:6px;font-size:13px;color:var(--muted);
  font-variant-numeric:tabular-nums;font-weight:400}
.card .meta .go{font:700 11.5px/1 var(--sans);letter-spacing:.09em;
  text-transform:uppercase;color:var(--flame-deep);white-space:nowrap}
.card .meta .go svg{vertical-align:-1px;margin-left:3px;transition:transform .18s ease}
.card:hover .meta .go svg{transform:translateX(3px)}
@media(prefers-reduced-motion:reduce){.card .meta .go svg,.card:hover .meta .go svg{transition:none;transform:none}}

/* empty state */
.empty{border:1px solid var(--rule);background:var(--sand);padding:34px 30px;text-align:center}
.empty p{margin:0 0 6px;font-size:18px;color:var(--ink)}
.empty a{color:var(--flame-deep)}

/* ---------- current section ----------
   The masthead says where the reader is, not only where they can go. Weight
   is not used as the signal: the rule underneath carries it, so the nav row
   does not reflow when the active item changes between pages. */
.mast nav a[aria-current]{border-bottom-color:var(--flame);color:var(--flame-deep)}

/* ---------- feature list ----------
   Used by Best Of and Buying Guides. Both have very few published entries, and
   a three-up card grid at that count reads as a half-empty shelf; a stacked
   editorial list reads as a contents page and gives each entry room for the
   excerpt that actually sells the click. */
.flist{list-style:none;margin:0;padding:0;border-top:1px solid var(--rule)}
.flist>li{border-bottom:1px solid var(--rule);padding:34px 0}
.fitem{display:grid;grid-template-columns:210px 1fr;gap:34px;align-items:start}
.fitem-shot{position:relative;display:block;background:var(--sand);
  border:1px solid var(--rule);aspect-ratio:4/3;overflow:hidden}
.fitem-shot img{width:100%;height:100%;object-fit:contain;padding:12px;
  mix-blend-mode:multiply}
/* no lead product on a guide, so the slot carries the entry number instead of
   an empty box */
.fitem-num{display:grid;place-items:center;background:var(--cream);
  border:1px solid var(--rule);aspect-ratio:4/3;
  font:700 44px/1 var(--serif-display);
  color:var(--flame-deep);font-variant-numeric:tabular-nums}
.fitem h2{margin:6px 0 10px;font:400 27px/1.22
  var(--serif-display);
  letter-spacing:-.005em;color:var(--ink);text-wrap:balance}
.fitem h2::before{content:none}
.fitem h2 a{color:inherit;text-decoration:none;
  background-image:linear-gradient(var(--flame),var(--flame));
  background-size:0 2px;background-repeat:no-repeat;background-position:0 100%;
  transition:background-size .22s ease}
.fitem h2 a:hover{background-size:100% 2px;color:var(--flame-deep)}
.fitem p{margin:0;color:var(--body);font-size:16.5px;line-height:1.62;max-width:66ch}
.fitem .eyebrow{margin:0}
/* the facts row: counts and dates carry the credibility, so they get tabular
   figures and the ink colour rather than the muted metadata grey */
.facts{display:flex;flex-wrap:wrap;gap:8px 22px;margin:15px 0 0;padding:0;list-style:none;
  font:400 13px/1.3 var(--sans);color:var(--muted)}
.facts b{color:var(--ink);font-weight:700;font-variant-numeric:tabular-nums}
@media(max-width:720px){
  .fitem{grid-template-columns:118px 1fr;gap:18px}
  .fitem h2{font-size:22px}
  .fitem-num{font-size:30px}
  .fitem p{font-size:15.5px}
}

/* ---------- category index ----------
   Grouped by parent so the page is a map of the catalogue rather than 71 flat
   links, and counts are the real number of published reviews behind each one. */
.catgrid{display:grid;grid-template-columns:repeat(2,1fr);gap:26px;list-style:none;margin:0;padding:0;
  /* cards size to their own content: stretching a four-child card to match a
     twelve-child one leaves a dead half-column */
  align-items:start}
.catcard{border:1px solid var(--hairline);background:var(--surface);
  padding:24px 26px 22px;box-shadow:0 1px 2px rgba(60,48,34,.05);
  transition:border-color .18s,box-shadow .18s}
.catcard:hover{border-color:var(--rule);box-shadow:0 6px 20px rgba(60,48,34,.10)}
.catcard h2{margin:0;font:400 22px/1.25
  var(--serif-display);color:var(--ink)}
.catcard h2::before{content:none}
.catcard h2 a{color:inherit;text-decoration:none}
.catcard h2 a:hover{color:var(--flame-deep)}
.catcard .n{display:block;margin:6px 0 0;
  font:700 11px/1 var(--sans);letter-spacing:.11em;
  text-transform:uppercase;color:var(--gold);font-variant-numeric:tabular-nums}
.subcats{margin:16px 0 0;padding:15px 0 0;border-top:1px solid var(--hairline);
  list-style:none;display:flex;flex-wrap:wrap;gap:7px}
.subcats a{display:inline-block;padding:6px 11px;background:var(--sand);
  font:400 13.5px/1.3 var(--serif-body);color:var(--body);text-decoration:none;
  transition:background-color .16s,color .16s}
.subcats a:hover{background:var(--flame);color:#fff}
.subcats .sn{color:var(--faint);font-size:11.5px;font-variant-numeric:tabular-nums}
.subcats a:hover .sn{color:#ffe3d8}
@media(max-width:820px){.catgrid{grid-template-columns:1fr;gap:20px}}

/* chapter chips: what a guide actually covers, derived from which sections
   hold content, so the promise on the listing matches the page behind it */
.chips{display:flex;flex-wrap:wrap;gap:7px;margin:15px 0 0;padding:0;list-style:none}
.chips li{padding:5px 10px;background:var(--sand);border:1px solid var(--rule);
  font:400 12.5px/1.35 var(--sans);color:var(--body)}

/* --- corrections found by measuring the rendered page --- */
/* the sub-count was --faint on --sand: 2.27:1, and it is a number the reader is
   meant to read, not decoration. --gold clears AA on the same chip. */
.subcats .sn{color:var(--gold)}
/* white on --flame is 3.5:1, under AA for this size; --flame-deep clears it */
.subcats a:hover{background:var(--flame-deep);color:#fff}
.subcats a:hover .sn{color:#ffd9cc}
/* the footer column link was a 12px-tall target inside a padded heading; the
   anchor now fills the heading's padded box instead of sitting inside it */
.foot h2{padding-top:7px;padding-bottom:7px}
.foot h2 a{display:block;margin:-7px 0;padding:7px 0}

/* Below this width the two-column feature item leaves the text about 215px to
   work with, which wraps a headline over six ragged lines. Stack instead and
   cap the lead image so it stays a thumbnail rather than a hero. */
@media(max-width:560px){
  .fitem{grid-template-columns:1fr;gap:14px}
  .fitem-shot,.fitem-num{width:132px}
  .fitem-num{font-size:34px}
  .fitem h2{font-size:23px}
}


/* ---------- listing ground ----------
   Pages that present a grid of cards set body.listing, which paints the light
   ground the white cards sit on. Reading pages keep the warm canvas: a grey
   ground behind a column of prose would be the wrong call there. */
body.listing{background:var(--ground)}
body.listing .pagehead{background:var(--surface)}

/* ---------- header band ----------
   Every page that opens with a breadcrumb and a head - the listings, category
   and author pages, Best Of and buying-guide articles, reviews and the standing
   documents - sets that head on the site's deep teal, running unbroken from the
   masthead rule through the breadcrumb. It replaces a mix of white, cream and
   ink heads under a grey breadcrumb strip, which read as unrelated slabs. The
   footer and the review price bar already use this teal, so it bookends the
   page. Fixed values rather than --teal, which turns pale in dark mode. Each
   page stylesheet recolours what sits inside its own head. */
:root{--band:#0d5157;--band-deep:#0a4247;--band-text:#d3e6e5;--band-muted:#a9c9c8;
  --band-rule:rgba(255,255,255,.18)}


/* The breadcrumb is a centred .wrap, so its paint is pushed out to the viewport
   edges with a filled border-image outset (a spread shadow left a hairline seam
   at fractional zoom), and the head tucks 1px under it. Only a breadcrumb that
   is directly followed by one of these heads joins the band. */
.crumbs:has(+ :is(.pagehead,.rhead,.ghead,.dochead,.sm-head,.hero)){
  border-image:conic-gradient(var(--band) 0 0) fill 0//0 100vmax;
  padding-top:14px;padding-bottom:0;position:relative;z-index:1}
.crumbs:has(+ :is(.pagehead,.rhead,.ghead,.dochead,.sm-head,.hero)) :is(ol,a){color:var(--band-muted)}
.crumbs:has(+ :is(.pagehead,.rhead,.ghead,.dochead,.sm-head,.hero)) li+li::before{color:#6f9d9c}
.crumbs:has(+ :is(.pagehead,.rhead,.ghead,.dochead,.sm-head,.hero)) li:last-child{color:#fff}
.crumbs:has(+ :is(.pagehead,.rhead,.ghead,.dochead,.sm-head,.hero)) a:hover{color:#fff}
.crumbs + :is(.pagehead,.rhead,.ghead,.dochead,.sm-head,.hero){margin-top:-1px}

.pagehead,body.listing .pagehead{background:var(--band);border-bottom:0;padding-top:20px;padding-bottom:30px}
.pagehead h1{color:#fff}
.pagehead p{color:var(--band-text)}
/* mustard on the band is 4.8:1; the flame label it replaces would be 1.6:1 */
.pagehead .count{color:var(--mustard)}
/* Phones: a trail of three or more stops before the current page, which the
   headline directly below already names. Otherwise its cut-off title wraps onto
   a second line that opens on a stray separator. */
@media(max-width:560px){
  .crumbs:has(+ :is(.pagehead,.rhead,.ghead,.dochead,.sm-head,.hero)) li:nth-child(n+3):last-child{display:none}
}

/* ---------- categories dropdown ----------
   Opens on hover and on focus-within with no JavaScript, so it works for
   keyboard users and before any script runs. The trigger is a real link to
   /categories: pointing a menu at a dead <button> would hide a whole section
   from crawlers and from anyone without JS. */
.hasdrop{position:relative;display:inline-flex}
.drop-trigger{display:inline-flex;align-items:center;gap:5px}
.drop-trigger svg{transition:transform .18s ease}
.hasdrop:hover .drop-trigger svg,
.hasdrop:focus-within .drop-trigger svg,
.hasdrop.open .drop-trigger svg{transform:rotate(180deg)}
.dropmenu{position:absolute;top:100%;left:-14px;z-index:60;min-width:246px;
  margin:0;padding:6px 0;list-style:none;
  background:var(--surface);border:1px solid var(--rule);
  box-shadow:0 10px 30px rgba(60,48,34,.16);
  opacity:0;visibility:hidden;transform:translateY(-4px);
  transition:opacity .16s ease,transform .16s ease,visibility .16s}
.hasdrop:hover .dropmenu,
.hasdrop:focus-within .dropmenu,
.hasdrop.open .dropmenu{opacity:1;visibility:visible;transform:none}
@media(prefers-reduced-motion:reduce){.dropmenu{transition:none}.drop-trigger svg{transition:none}}
/* the gap between trigger and panel would drop the hover; this bridges it */
.dropmenu::before{content:"";position:absolute;top:-10px;left:0;right:0;height:10px}
.mast nav .dropmenu a{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding:10px 18px;text-transform:none;letter-spacing:0;
  font:400 15px/1.3 var(--serif-body);color:var(--body);
  text-decoration:none;border-bottom:0;white-space:nowrap}
.mast nav .dropmenu a:hover,.mast nav .dropmenu a:focus-visible{background:var(--sand);color:var(--flame-deep)}
.dropmenu .dm-n{font:400 12px/1 var(--sans);color:var(--muted);
  font-variant-numeric:tabular-nums}
.dropmenu a:hover .dm-n{color:var(--flame-deep)}
.dropmenu .dm-all{border-top:1px solid var(--rule);margin-top:6px;padding-top:6px}
.mast nav .dropmenu .dm-all a{font:700 12px/1 var(--sans);
  letter-spacing:.08em;text-transform:uppercase;color:var(--flame-deep)}

/* On narrow screens the masthead nav is a scrolling row, where an absolutely
   positioned panel would be clipped by the scroller. The list is one tap away
   at /categories, so the panel simply does not open there. */
@media(max-width:1080px){
  .dropmenu{display:none}
  .drop-trigger svg{display:none}
}

/* ============================ search overlay ============================ */
/* A native <dialog>, so the backdrop, focus trap and ESC are the browser's.
   Zero radius, hairline rules, one accent: the same system as the rest of the
   site, at the density a result list needs rather than the density of a page. */

.sdlg{border:0;padding:0;background:transparent;max-width:none;max-height:none;
  width:100%;height:100%;color:var(--body)}
.sdlg::backdrop{background:rgba(23,18,13,.44);backdrop-filter:blur(2px)}


.sdlg-box{width:min(620px,calc(100% - 32px));margin:12vh auto 0;background:var(--canvas);
  border:1px solid var(--ink);display:flex;flex-direction:column;max-height:76vh}
@media(max-width:640px){ .sdlg-box{margin:0 auto;width:100%;max-height:100%;height:100%;border:0} }

/* --- the field ------------------------------------------------------- */
.sdlg-field{display:flex;align-items:center;gap:12px;padding:16px 18px;
  border-bottom:1px solid var(--rule)}
.sdlg-icon{flex:0 0 auto;color:var(--muted)}
.sdlg-input{flex:1 1 auto;min-width:0;border:0;background:transparent;color:var(--ink);
  font:400 19px/1.3 Georgia,"Times New Roman",serif;padding:2px 0;outline:0}
/* Placeholder contrast is checked, not assumed: --muted on --canvas clears AA. */
.sdlg-input::placeholder{color:var(--muted);opacity:1}
.sdlg-input::-webkit-search-cancel-button{display:none}
/* The focus ring goes on the field, since the input itself has no border. */
.sdlg-field:focus-within{box-shadow:inset 0 0 0 2px var(--flame-deep)}

.sdlg-close{flex:0 0 auto;border:1px solid var(--rule);background:transparent;
  color:var(--muted);font:700 10px/1 var(--sans);
  letter-spacing:.1em;text-transform:uppercase;padding:6px 8px;cursor:pointer}
.sdlg-close:hover{border-color:var(--flame-deep);color:var(--flame-deep)}

/* --- results --------------------------------------------------------- */
.sdlg-results{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain}

.sdlg-row{display:flex;gap:13px;align-items:flex-start;padding:11px 18px;
  text-decoration:none;color:inherit;border-bottom:1px solid var(--hairline)}
.sdlg-row:last-child{border-bottom:0}
/* One highlight for keyboard and pointer, so they cannot disagree. */
.sdlg-row.is-active{background:var(--sand);box-shadow:inset 3px 0 0 var(--flame-deep)}

.sdlg-thumb{flex:0 0 44px;width:44px;height:44px;object-fit:contain;
  background:var(--surface);border:1px solid var(--hairline)}
.sdlg-thumb--none{background:var(--sand)}
.sdlg-body{min-width:0;display:flex;flex-direction:column;gap:3px}
.sdlg-title{font:400 15px/1.35 Georgia,"Times New Roman",serif;color:var(--ink);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.sdlg-meta{font:700 10px/1 var(--sans);letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted)}

.sdlg-msg{margin:0;padding:34px 18px;text-align:center;color:var(--muted);
  font:400 15px/1.5 Georgia,"Times New Roman",serif}
.sdlg-msg[data-state="error"]{color:var(--con)}

/* Skeletons hold the shape the rows will take, so nothing jumps on arrival. */
.sdlg-skel{display:flex;gap:13px;align-items:center;padding:11px 18px;
  border-bottom:1px solid var(--hairline)}
.sk-thumb{flex:0 0 44px;height:44px;background:var(--sand)}
.sk-lines{flex:1 1 auto;display:flex;flex-direction:column;gap:7px}
.sk-l1,.sk-l2{height:9px;background:var(--sand)}
.sk-l2{width:38%}
@media (prefers-reduced-motion: no-preference){
  .sdlg-skel{animation:sdlgPulse 1.15s ease-in-out infinite}
  .sdlg-skel:nth-child(2){animation-delay:.11s}
  .sdlg-skel:nth-child(3){animation-delay:.22s}
}
@keyframes sdlgPulse{0%,100%{opacity:1}50%{opacity:.52}}

/* --- footer ---------------------------------------------------------- */
.sdlg-foot{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;
  gap:14px;padding:10px 18px;border-top:1px solid var(--rule);background:var(--cream)}
.sdlg-keys{font:400 11px/1 var(--sans);color:var(--muted)}
.sdlg-keys kbd{font:700 10px/1 var(--sans);border:1px solid var(--rule);
  padding:3px 5px;margin-right:3px;color:var(--body);background:var(--canvas)}
@media(max-width:520px){ .sdlg-keys{display:none} }

.sdlg-all{border:1px solid var(--ink);background:var(--ink);color:var(--canvas);
  font:700 10px/1 var(--sans);letter-spacing:.1em;
  text-transform:uppercase;padding:9px 13px;cursor:pointer}
.sdlg-all:hover{background:var(--flame-deep);border-color:var(--flame-deep)}
.sdlg-all:active{transform:translateY(1px)}

@media (prefers-reduced-motion: no-preference){
  .sdlg[open] .sdlg-box{animation:sdlgIn .16s cubic-bezier(.16,1,.3,1)}
}
@keyframes sdlgIn{from{opacity:0;transform:translateY(-7px)}to{opacity:1;transform:none}}

/* ============================== search page ============================= */
/* A results list, not a card grid. Cards would put a box around every item and
   make the page about the containers; hairline-separated rows let the reader
   scan titles down a single edge, which is the only thing they are doing here. */

/* No max-width of its own: .wrap already sets 1200 with 28px gutters, and a
   second cap here made the results column narrower than the masthead above
   it, which reads as a mistake rather than as a measure. */
.srch{padding:34px 0 80px}

.srch-head{border-bottom:2px solid var(--ink);padding-bottom:20px;margin-bottom:4px}
.srch-head h1{font:400 clamp(30px,4.4vw,44px)/1.12 var(--serif-display);letter-spacing:-.02em;margin:0 0 8px}
/* The searched term is the one italic on the page, so it reads as quoted rather
   than as decoration. leading has room for descenders in words like "query". */
.srch-head h1 em{font-style:italic;color:var(--flame-deep);line-height:1.15}
.srch-count{color:var(--muted);font-size:13px;margin:0}
.srch-page{margin-left:10px;padding-left:10px;border-left:1px solid var(--rule)}

.srch-form{display:flex;gap:0;margin-top:18px}
.srch-form input{flex:1 1 auto;min-width:0;border:1px solid var(--rule);border-right:0;
  background:var(--canvas);color:var(--ink);padding:13px 15px;
  font:400 17px/1.3 Georgia,"Times New Roman",serif}
.srch-form input::placeholder{color:var(--muted);opacity:1}
.srch-form input:focus{outline:0;border-color:var(--flame-deep);box-shadow:inset 0 0 0 1px var(--flame-deep)}
.srch-form button{flex:0 0 auto;border:1px solid var(--ink);background:var(--ink);color:var(--canvas);
  font:800 11px/1 var(--sans);letter-spacing:.1em;text-transform:uppercase;
  padding:0 22px;cursor:pointer;transition:background-color .16s}
.srch-form button:hover{background:var(--flame-deep);border-color:var(--flame-deep)}
.srch-form button:active{transform:translateY(1px)}

/* --- results --------------------------------------------------------- */
.srch-list{list-style:none;margin:0;padding:0}
.srch-item{border-bottom:1px solid var(--hairline)}
.srch-link{display:flex;gap:20px;align-items:flex-start;padding:22px 0;
  text-decoration:none;color:inherit}
/* The whole row is the target, so the hover state belongs to the row. */
.srch-link:hover .srch-title{color:var(--flame-deep)}
.srch-link:hover .srch-thumb{border-color:var(--flame-deep)}

.srch-thumb{flex:0 0 104px;width:104px;height:104px;object-fit:contain;
  background:var(--surface);border:1px solid var(--hairline);transition:border-color .16s}
.srch-thumb--none{background:var(--sand)}

.srch-body{min-width:0;display:flex;flex-direction:column;gap:6px}
.srch-kind{font-size:10px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;
  color:var(--muted)}
.srch-title{font:400 21px/1.28 var(--serif-display);
  color:var(--ink);letter-spacing:-.012em;transition:color .16s;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.srch-ex{font:400 15px/1.5 Georgia,"Times New Roman",serif;color:var(--body);
  max-width:62ch;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.srch-facts{display:flex;align-items:center;flex-wrap:wrap;gap:0 9px;
  font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
/* A drawn rule between facts instead of a middle dot. */
.srch-sep{display:inline-block;width:12px;height:1px;background:var(--rule)}

/* --- empty and landing states ---------------------------------------- */
.srch-start,.srch-none{padding:38px 0 10px}
.srch-start h2,.srch-none h2{font:400 25px/1.25 var(--serif-display);margin:0 0 14px}
.srch-none h2 em{font-style:italic;color:var(--flame-deep);line-height:1.15}
.srch-none p{color:var(--body);max-width:60ch;font-size:17px}
.srch-chips{list-style:none;display:flex;flex-wrap:wrap;gap:9px;margin:18px 0 0;padding:0}
.srch-chips a{display:inline-block;border:1px solid var(--rule);padding:8px 13px;
  font:400 14px/1 Georgia,"Times New Roman",serif;color:var(--body);text-decoration:none;
  transition:border-color .16s,color .16s}
.srch-chips a:hover{border-color:var(--flame-deep);color:var(--flame-deep)}
.srch-tip{margin-top:22px;color:var(--muted);font-size:14px}
.srch-tip a{color:var(--flame-deep)}

/* --- pager ------------------------------------------------------------ */
.srch-pager{display:flex;align-items:center;justify-content:space-between;gap:16px;
  margin-top:34px;padding-top:20px;border-top:2px solid var(--ink)}
.srch-pager a{font:800 11px/1 var(--sans);letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink);text-decoration:none;
  border:1px solid var(--ink);padding:11px 17px;transition:background-color .16s,color .16s}
.srch-pager a:hover{background:var(--ink);color:var(--canvas)}
.srch-pos{color:var(--muted);font-size:12px;margin-left:auto;margin-right:auto}
.srch-next{margin-left:auto}

@media(max-width:640px){
  .srch{padding:24px 18px 60px}
  .srch-link{gap:14px;padding:18px 0}
  .srch-thumb{flex-basis:74px;width:74px;height:74px}
  .srch-title{font-size:18px}
  .srch-ex{display:none}
  .srch-form{flex-direction:column;gap:9px}
  .srch-form input{border-right:1px solid var(--rule)}
  .srch-form button{padding:13px 22px}
}

/* Long listing titles need a measure, even on a wide page: a serif line past
   about 90 characters is hard to track back from. The list stays wide so the
   thumbnail, title and facts share a row comfortably; the text inside it does
   not stretch to the full width. */
/* The title is trimmed in PHP, so it no longer needs a width to hold it back.
   The description keeps a measure: it is the only multi-line prose in the row. */
.srch-ex{max-width:86ch}

/* --- filter tabs ------------------------------------------------------ */
/* Links, not buttons: each filter is a URL that can be shared and reached with
   the back button. They sit on a rule that the active tab interrupts, so the
   selected one reads as attached to the results below it. */
.srch-tabs{display:flex;flex-wrap:wrap;gap:0 26px;align-items:flex-end;
  border-bottom:1px solid var(--rule);margin:22px 0 0}
.srch-tab{display:inline-flex;align-items:baseline;gap:7px;padding:11px 0 10px;
  text-decoration:none;color:var(--muted);border-bottom:2px solid transparent;
  font:700 11.5px/1 var(--sans);letter-spacing:.1em;
  text-transform:uppercase;margin-bottom:-1px;transition:color .16s,border-color .16s}
.srch-tab:hover{color:var(--ink);border-bottom-color:var(--rule)}
.srch-tab.is-on{color:var(--ink);border-bottom-color:var(--flame-deep)}
/* A tab with nothing behind it stays in place and says so, rather than vanishing
   between searches and moving the others. */
.srch-tab.is-none{color:var(--faint);cursor:default;padding:11px 0 10px;
  display:inline-flex;align-items:baseline;gap:7px;
  font:700 11.5px/1 var(--sans);letter-spacing:.1em;text-transform:uppercase}
.srch-n{font-style:normal;font-size:11px;font-weight:400;color:var(--faint);
  font-variant-numeric:tabular-nums;letter-spacing:0}
.srch-tab.is-on .srch-n{color:var(--flame-deep)}
.srch-tabs+.srch-list{margin-top:0}
@media(max-width:640px){
  .srch-tabs{gap:0 16px;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}
  .srch-tabs::-webkit-scrollbar{display:none}
  .srch-tab,.srch-tab.is-none{white-space:nowrap;font-size:10.5px}
}

/* --- load more -------------------------------------------------------- */
.srch-more{display:flex;flex-direction:column;align-items:center;gap:10px;
  margin-top:30px;padding-top:26px;border-top:2px solid var(--ink)}
.srch-more-btn{border:1px solid var(--ink);background:transparent;color:var(--ink);
  font:800 11px/1 var(--sans);letter-spacing:.1em;
  text-transform:uppercase;padding:14px 30px;cursor:pointer;
  transition:background-color .16s,color .16s}
.srch-more-btn:hover{background:var(--ink);color:var(--canvas)}
.srch-more-btn:active{transform:translateY(1px)}
.srch-more-btn:disabled{cursor:default;color:var(--muted);border-color:var(--rule)}
.srch-more-btn:disabled:hover{background:transparent;color:var(--muted)}
.srch-more-pos{color:var(--muted);font-size:12px;margin:0;font-variant-numeric:tabular-nums}
/* The button is the progress indicator while it works, so there is no second
   thing to look at. */
@media (prefers-reduced-motion: no-preference){
  .srch-more.is-busy .srch-more-btn{animation:srchPulse 1s ease-in-out infinite}
}
@keyframes srchPulse{0%,100%{opacity:1}50%{opacity:.55}}

/* display:flex beats the hidden attribute, so the pager the script replaces
   stays on screen showing a page number that is no longer true. The attribute
   has to be given back its authority explicitly. */
.srch-pager[hidden]{display:none}
