/* Xtoys.UK storefront — ported from theme 2 "Bright Retail", recoloured to the logo. */
:root{
  --bg:#ffffff; --alt:#f5f7fa; --line:#e2e7ee; --text:#101418; --muted:#646d7a;
  --red:#d84315; --red-d:#b23600; --navy:#222831; --blue:#f59e0b; --cyan:#ffc061;
  /* Brand orange at ~15% over white — reads as the same colour family but stays
     quiet enough to outline a card without competing with the product photo.
     #d84315 itself clears WCAG AA (4.8:1) on white, so it is safe as link text
     and as a button fill under white, not just as decoration. */
  --red-soft:#ffe3d3;
  /* Darkened from #0a8a48, which failed WCAG AA at 4.43:1 even on plain white,
     and 3.96–4.13:1 on the pale green tints it sits on in .flash, .pill-ok,
     .badge-ok and .verified — all at 11–13.5px, so none of them qualify as
     large text. #07713b clears 5.4:1 on every one of those backgrounds, and
     white-on-green (.confirm .tick, .timeline) improves from 4.43 to 6.11. */
  --green:#07713b; --amber:#f5a623;
}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--bg);color:var(--text);font-family:system-ui,-apple-system,"Segoe UI",sans-serif;-webkit-font-smoothing:antialiased}
a{color:inherit;text-decoration:none}
img{max-width:100%}
.wrap{max-width:1320px;margin:0 auto;padding:0 20px}

/* ---------- header ---------- */
/* Bold throughout, white throughout. At 12px on a navy bar, regular weight
   reads as thin and washed even at 13.9:1 contrast — weight does more for
   legibility here than colour does, and the colour was already maxed. */
.top{background:var(--navy);color:#fff;font-size:12px;font-weight:700}
/* gap is not optional here: space-between alone left the items touching once
   they were direct children, because the row is nearly full at desktop width
   and there was no whitespace between inline flex items to fall back on.
   flex-wrap:nowrap plus the ellipsis below keeps it one line at any width down
   to the 768px breakpoint, where the whole bar is hidden anyway. */
.top .wrap{display:flex;justify-content:space-between;align-items:center;height:36px;
  gap:26px;flex-wrap:nowrap;overflow:hidden}
/* Every item is a direct child of the row, so space-between spreads them edge
   to edge. Wrapping three of them in a .pills div made the bar two flex items:
   one label hard left, a cluster hard right, and a gap in the middle.

   White, matching the text beside it. #dbe6ef before this, #b4c6d6 before
   that. The first change was an accessibility fix — #b4c6d6 was 4.0:1 on the
   navy, under the 4.5:1 minimum. This one was not: #dbe6ef already measured
   10.97:1 and passed comfortably, it simply READ as grey next to white, which
   is a saturation problem rather than a contrast one. White is 13.9:1. */
.top .wrap > a{color:#fff;font-weight:700;white-space:nowrap}
/* The leading label is the only thing here that may be truncated — every other
   item is a link that has to stay clickable and readable in full. */
.top .wrap > span:first-child{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.top .wrap > a:hover{color:var(--cyan)}

/* The star sits on the text baseline rather than the box's, or it rides high
   against the cap height and looks like a stray glyph. */
.top-trustpilot{display:inline-flex;align-items:center;gap:5px}
.top-trustpilot svg{color:#00b67a}   /* Trustpilot's own green, on their star only */

/* Social icons: same size as the text they sit beside, and a target big
   enough to hit — a 16px icon with no padding is well under the 24px minimum
   a touch target should be. */
.socials{display:inline-flex;align-items:center;gap:6px;margin-left:4px}
.social{display:inline-flex;align-items:center;justify-content:center;
  width:26px;height:26px;border-radius:6px;color:inherit;transition:background .15s,color .15s}
.social:hover{background:rgba(255,255,255,.14);color:#fff}
.social:focus-visible{outline:2px solid var(--cyan);outline-offset:2px}
.socials-footer{margin:14px 0 0}
.socials-footer .social{width:32px;height:32px}
/* body > header, NOT a bare `header`. As an element selector this pinned EVERY
   <header> on the site: the article title block on a blog post, the page title
   on /returns, /faqs, /delivery, /about, /privacy, /terms, the brand page head
   and the blog index head — ten of them, each covering the content beneath it
   as you scrolled. The site header is the only one that should stick. */
body > header{border-bottom:1px solid var(--line);position:sticky;top:0;z-index:25;background:#fff}
.bar{display:flex;align-items:center;gap:22px;height:78px}
.hamburger{display:none;flex-direction:column;justify-content:center;gap:5px;width:42px;height:42px;
  border:1px solid var(--line);border-radius:8px;background:#fff;cursor:pointer;padding:0;flex:none}
.hamburger span{display:block;width:20px;height:2px;background:var(--navy);margin:0 auto;border-radius:2px;transition:.2s}
body.nav-open .hamburger span:nth-child(1){transform:translateY(7px) rotate(45deg)}
body.nav-open .hamburger span:nth-child(2){opacity:0}
body.nav-open .hamburger span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
.logo{display:flex;align-items:center;gap:10px;font-size:26px;font-weight:800;letter-spacing:-.03em;color:var(--navy)}
.logo img{width:34px;height:34px;display:block}
.logo b{font-weight:800}
.logo span{color:var(--red)}
.search{flex:1;display:flex;border:2px solid var(--navy);border-radius:8px;overflow:hidden;max-width:640px}
.search input{flex:1;border:0;padding:12px 16px;font-size:16px;outline:none;font-family:inherit;min-width:0}
.search button{background:var(--navy);color:#fff;border:0;padding:0 22px;font-size:15px;cursor:pointer;flex:none}
.acts{display:flex;gap:26px;font-size:12px;text-align:center;color:var(--navy);font-weight:600}
/* Account / Wishlist / Basket were var(--muted) — 5.24:1 at 12px, which scrapes
   past the WCAG minimum but reads as washed-out grey. These are primary
   navigation, not secondary text: navy at 600 weight takes them to 12.6:1. */
.acts .act{display:block}
.acts b{display:block;font-size:19px;color:var(--navy);margin-bottom:2px}
.navbar{background:var(--alt);border-bottom:1px solid var(--line)}
.navbar .wrap{display:flex;gap:2px;height:46px;align-items:center;overflow-x:auto}
.navbar a{font-size:14px;font-weight:600;padding:8px 14px;border-radius:6px;white-space:nowrap}
.navbar a:hover,.navbar a[aria-current]{background:#fff;color:var(--red)}
/* Account/Wishlist live in the drawer only; the header icons cover desktop. */
.nav-drawer-only{display:none}

/* ---------- hero ---------- */
.hero{background:linear-gradient(100deg,#fff2f1,#e9f6fd)}
/* The wrap is a single column: the SLIDER spans it and each SLIDE is the
   two-column copy/products grid. It used to be the two-column grid itself with
   one fixed product panel on the right, which cannot work now that the products
   change with the slide. */
.hero .wrap{padding:16px 20px}
.flag{display:inline-block;background:var(--red);color:#fff;font-size:11px;font-weight:800;
  letter-spacing:.1em;text-transform:uppercase;padding:6px 12px;border-radius:5px;margin-bottom:18px}
h1{font-size:50px;line-height:1.06;letter-spacing:-.035em;margin-bottom:16px}
h1 span{color:var(--red)}
/* The sale clause is the only part that drops on a phone — one <h1> either
   way, because two in the DOM leaves the page with no single subject. */
.hero-sale{display:inline}
.hero-search{display:none}       /* mobile-only in-hero search; shown at ≤768 */
/* The home page's h1, at every width. Modest on desktop: it states what the
   shop is, above a slider whose own headings are promotions (h2) and change
   with the stock. Enlarged on ≤768, where it is the only heading in the hero. */
.hero-h1{font-size:15px;line-height:1.3;font-weight:700;color:var(--navy);
  margin:0 0 10px;letter-spacing:-.01em}
.lede{color:var(--muted);font-size:15px;line-height:1.5;margin-bottom:14px;max-width:46ch}
.btn{display:inline-block;padding:15px 30px;border-radius:8px;font-weight:700;font-size:15px;
  border:0;cursor:pointer;font-family:inherit}
.btn-p{background:var(--red);color:#fff;box-shadow:0 8px 20px -8px rgba(213,18,26,.75)}
.btn-p:hover{background:var(--red-d)}
.btn-o{border:2px solid var(--navy);color:var(--navy);margin-left:10px}
.hero-art{background:#fff;border-radius:16px;padding:14px;box-shadow:0 24px 60px -30px rgba(10,46,77,.45)}

/* Three products from the slide's brand. Images only — no name, no price —
   both are one click away on the product page. */
.hero-picks{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.hero-pick{display:block;border:1px solid var(--line);border-radius:10px;padding:8px;
  transition:border-color .15s,transform .15s}
.hero-pick:hover{border-color:var(--navy);transform:translateY(-2px)}
/* Tall enough that the panel fills the hero rather than floating in the middle
   of it. Three portrait tiles read as a shop window; three squat ones read as
   an afterthought. */
.hero-pick img{width:100%;border-radius:8px;display:block;height:172px;object-fit:contain}

/* A brand whose stock has not landed yet. Dashed, muted, and clearly a
   placeholder rather than a product that failed to load. */
.hero-pick-empty{display:flex;align-items:center;justify-content:center;
  border-style:dashed;background:var(--alt);min-height:188px}
.hero-pick-empty:hover{border-color:var(--line);transform:none}
.hero-pick-empty span{font-size:12px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}

/* The one link out of the hero, and the reason it earns its place for search:
   it passes the home page's authority to the three brand pages that are
   actually competing for "<brand> UK". */
/* The product names under the lede. Compact, but real links — this is the
   crawlable text the hero previously lacked entirely. */
.hero-names{list-style:none;margin:0 0 12px;padding:0}
.hero-names li{margin:0 0 3px}
.hero-names a{font-size:13.5px;line-height:1.4;color:var(--navy);
  /* One line each: these names run past 50 characters and a wrapped list reads
     as a paragraph rather than a list of products. */
  display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hero-names a:hover{color:var(--red);text-decoration:underline}

.hero-link{display:inline-block;font-weight:700;font-size:15px;color:var(--red)}
.hero-link:hover{text-decoration:underline}

/* ---------- hero slider ---------- */
/* Slides are stacked and cross-faded, never display:none and never inserted by
   JS — a slide a crawler cannot see is a slide that never gets indexed, which
   is how heroes like this usually lose rankings rather than gain them.
   The grid keeps all three in one cell so the hero cannot change height as it
   rotates; a jumping hero is a CLS penalty on the largest element on the page. */
/* Two rows: the stacked slides, then the dots. The dots used to share the
   slides' single cell with align-self:end, which worked while a slide was two
   short paragraphs and collided with the brand link the moment slides grew. */
.hero-slider{display:grid;grid-template-rows:1fr auto;gap:12px}
/* Each slide is itself the two-column copy/products grid, stacked in the
   slider's single cell so the hero cannot change height as it rotates — a
   jumping hero is a CLS penalty on the largest element on the page. */
.hero-slide{grid-area:1/1;display:grid;grid-template-columns:1fr 1fr;gap:40px;
  align-items:center;opacity:0;visibility:hidden;transition:opacity .45s ease;
  pointer-events:none;
  /* Height held here, not on the heading: brand names differ in length, so
     without this the hero resized mid-rotation. On the slide it costs nothing
     visually, because the product panel is the tall side anyway. */
  min-height:265px}
.hero-slide.is-on{opacity:1;visibility:visible;pointer-events:auto}
/* Sized on the CLASS, not the tag.
   Slide 1 is an h1 and slides 2-3 are h2s — one h1 per page — so they were
   inheriting the global h1 (50px) and h2 (28px) rules and the hero visibly
   changed size as it rotated. The heading level is a document-structure
   decision and must not leak into how the slide looks. */
/* No min-height here.
   Reserving three lines to stop the hero resizing left a short heading floating
   above a visible gap — the fix for one problem became a worse-looking one. The
   height is held on the SLIDE instead (below), so the hero still cannot jump
   while each heading sits directly on top of its own copy. */
.hero-title{font-size:34px;line-height:1.1;letter-spacing:-.03em;margin-bottom:10px}
.hero-title em{font-style:normal;color:var(--red)}

.hero-dots{grid-row:2;display:flex;gap:8px}
.hero-dots button{width:26px;height:5px;border:0;border-radius:99px;padding:0;cursor:pointer;
  background:rgba(10,46,77,.22);transition:background .2s}
.hero-dots button[aria-selected="true"]{background:var(--red)}
/* Keyboard users must be able to see which dot they are on. */
.hero-dots button:focus-visible{outline:2px solid var(--navy);outline-offset:3px}

/* Anyone who has asked their OS not to animate gets slide 1, still, with
   working dots. prefers-reduced-motion is an accessibility requirement, not a
   preference to style around. */
@media (prefers-reduced-motion:reduce){
  .hero-slide{transition:none}
}

/* ---------- trust ---------- */
.trust{border-bottom:1px solid var(--line)}
.trust .wrap{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;padding:20px}
.trust div{display:flex;gap:11px;align-items:center;font-size:13px;color:var(--muted)}
.trust b{display:block;color:var(--text);font-size:13.5px}
.trust .ic{width:36px;height:36px;border-radius:8px;background:#fdeeed;color:var(--red);
  display:grid;place-items:center;font-size:17px;flex:none}

/* ---------- sections ---------- */
section{padding:32px 0}
.head{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}
h2{font-size:28px;letter-spacing:-.02em}
/* Section headings read as pill labels in the brand navy, paired with the
   red "See all" link on the right. */
/* h1 as well as h2: the brands page carries its heading at level 1 — it is the
   page's own title, not a section label — and must still look like the others. */
.head h1,.head h2{display:inline-block;background:var(--navy);color:#fff;font-size:13.5px;font-weight:800;
  letter-spacing:.05em;text-transform:uppercase;padding:8px 18px;border-radius:999px;line-height:1;
  box-shadow:0 6px 14px -9px rgba(10,46,77,.75)}
.head a{color:var(--red);font-weight:700;font-size:14px}

/* 4 per row → 8 categories show as 2 rows; square, larger cards. */
/* Two rows of six. The tiles are square, so six across keeps the whole range
   visible without scrolling past three rows of mostly-white cards. */
.cats{display:grid;grid-template-columns:repeat(6,1fr);gap:16px}
/* Home "Our Range": 5-across so its ten tiles make two clean rows. Two-class
   selector so it wins over the .cats breakpoints below without editing each. */
.cats.cats-home{grid-template-columns:repeat(5,1fr)}

/* The category directory (/categories): one block per parent, its children as
   tiles. Reuses .cats and .cat so a tile looks the same here as on the home
   page — two visual languages for the same object is how a shop starts to feel
   assembled from parts. */
.cat-group{padding:6px 0 30px}
.cat-group .head{display:flex;justify-content:space-between;align-items:baseline;gap:16px;margin-bottom:14px}
.cat-group .head h2{font-size:22px;margin:0}
.cat-group .head h2 a{color:inherit}
.cat-group .head h2 a:hover{color:var(--red)}
.cat-group .head > a{font-size:13.5px;color:var(--muted);white-space:nowrap}
.cat-group .head > a:hover{color:var(--red)}
/* A soft red outline, not the near-white --line: at this tile size the pale
   grey border disappeared and the cards read as one connected block. */
.cat{border:2px solid var(--red-soft);border-radius:12px;text-align:center;transition:.16s;
  aspect-ratio:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding:0;overflow:hidden}
.cat:hover{border-color:var(--red);box-shadow:0 10px 22px -12px rgba(213,18,26,.3);transform:translateY(-2px)}
.cat .ic{width:64px;height:64px;border-radius:50%;background:var(--alt);
  display:grid;place-items:center;font-size:30px;margin:auto}
/* The favicon fallback: the shop's mark inside the same circle, sized to sit
   with a little breathing room rather than filling the disc edge to edge. */
.cat .ic-logo img{width:40px;height:40px;object-fit:contain;display:block}
/* The name sits in a solid navy footer rather than floating as dark text over
   the collage, where product photos pushed right up against it. */
.cat b{align-self:stretch;margin-top:auto;background:linear-gradient(160deg,var(--navy),#082439);
  color:#fff;border-top:3px solid var(--red-soft);font-size:13.5px;font-weight:700;
  letter-spacing:.2px;line-height:1.25;padding:9px 8px;min-height:42px;
  display:flex;align-items:center;justify-content:center}
.cat:hover b{background:linear-gradient(160deg,var(--red),var(--red-d));border-top-color:var(--red)}
/* Step down before the tiles get too small to read: 6 → 4 → 3 → 2. Twelve
   divides evenly by all four, so every layout ends on a full row. */
@media(max-width:1200px){.cats{grid-template-columns:repeat(4,1fr)}}

/* ---------- product cards ---------- */
/* Cards are sized by WIDTH, not by a fixed column count.
   repeat(4,1fr) made a card as wide as whatever container it landed in, so the
   same card was 236px on a category page (grid narrowed by the filter sidebar)
   and 307px on the home page and under "You might also like" — 30% bigger, for
   no reason other than the absence of a sidebar. Sizing by width makes every
   grid on the site render the same card and simply fit more of them across when
   there is more room: category stays 4-up, home and related go 5-up. */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:18px}
/* The home page rows show a denser 6-across grid on desktop (smaller cards),
   so a featured category's six products form one clean row. Scoped to .is-home
   so the brand/listing grids keep their own column counts. */
.is-home .grid{grid-template-columns:repeat(6,1fr);gap:14px}
.card{border:1px solid var(--line);border-radius:10px;overflow:hidden;background:#fff;transition:.16s;position:relative;
  display:flex;flex-direction:column}
.card:hover{box-shadow:0 16px 34px -18px rgba(10,46,77,.5);transform:translateY(-2px)}
.thumb{aspect-ratio:1;background:#fff;position:relative;display:block}
/* feed photography is shot on white — contain, never crop */
.thumb img{width:100%;height:100%;object-fit:contain;display:block;padding:8px}
.tag{position:absolute;top:10px;left:10px;background:var(--red);color:#fff;font-size:10px;font-weight:800;
  padding:4px 8px;border-radius:4px;letter-spacing:.05em;text-transform:uppercase}
.wish{position:absolute;top:10px;right:10px;width:30px;height:30px;border-radius:50%;background:#fff;
  display:grid;place-items:center;font-size:14px;box-shadow:0 2px 6px rgba(0,0,0,.15);color:var(--muted)}
.card .body{padding:14px;display:flex;flex-direction:column;flex:1}
.brand{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.08em;margin-bottom:5px;font-weight:700}
.card h3{font-size:13.5px;font-weight:500;line-height:1.4;margin-bottom:8px;min-height:38px;color:#1b2330}
.rate{font-size:11.5px;color:var(--muted);margin-bottom:9px}
.rate i{color:var(--amber);font-style:normal;letter-spacing:.5px}
.price{display:flex;align-items:baseline;gap:8px;margin-bottom:4px}
.price b{font-size:18px;color:var(--red)}
.price s{font-size:12px;color:var(--muted)}
.stock{font-size:11.5px;color:var(--green);font-weight:600;margin-bottom:10px}
.stock.out{color:var(--muted)}
.add{width:100%;padding:10px;border:0;border-radius:7px;background:var(--navy);color:#fff;
  font-weight:700;font-size:13px;cursor:pointer;font-family:inherit}

/* The auto margin has to go on whichever element is the FLEX CHILD of .body.
   It used to sit on .add, but an in-stock card wraps that button in a <form> —
   so the form was the flex child, the button's margin did nothing, and the
   buttons floated at whatever height the product name left them. The
   out-of-stock card has no form, hence both selectors. */
.card .body > form,
.card .body > .add{margin-top:auto}
.card .body > form .add{margin-top:0}
.add:hover{background:var(--red)}
.add:disabled{background:var(--line);color:var(--muted);cursor:not-allowed}

/* ---------- listing ---------- */
/* Category header. The banner is optional, so both of these have to look
   deliberate on their own — the page must not depend on either existing. */
.cat-banner{width:100%;height:auto;max-height:260px;object-fit:cover;
  border-radius:12px;margin:6px 0 4px;display:block}
/* Held to a reading measure like every other block of prose on the site; run
   the full 1200px and it is 160 characters a line. */
.cat-intro{max-width:75ch;margin:18px 0 4px;color:var(--muted);line-height:1.75;font-size:14.5px}
/* Spacing set explicitly: the site's reset zeroes p margins, so without this
   two paragraphs of category copy butt together and read as one. */
.cat-intro p{margin:0 0 12px}
.cat-intro ul,.cat-intro ol{margin:0 0 12px;padding-left:20px}
.cat-intro li{margin:3px 0}
.cat-intro h3{font-size:15px;font-weight:700;color:var(--navy);margin:18px 0 6px}
.cat-intro a{color:var(--red);text-decoration:underline}
.cat-intro > *:first-child{margin-top:0}
.cat-intro > *:last-child{margin-bottom:0}

.listing{display:grid;grid-template-columns:250px 1fr;gap:32px;padding:20px 0 40px}

/* The filter panel is a <details>. On desktop it is always open and the
   disclosure toggle is hidden, so it looks and behaves exactly as the plain
   sidebar did; the collapsing only exists for the narrow layout below. */
/* 98px, not 20px: the site header is position:sticky at top:0 with a 78px bar,
   so a 20px offset parked this 58px underneath it and the first heading in the
   panel was permanently hidden. The account sidebar already uses 96px, which is
   how you can tell 20px predates the sticky header. */
.filter-panel{align-self:start;position:sticky;top:98px}
.filter-panel > summary{display:none}
/* Safari and Chrome each add their own marker, through different selectors. */
.filter-panel > summary::-webkit-details-marker{display:none}
.filter-panel > summary::marker{content:""}
/* Sticky and self-alignment moved to .filter-panel, which is now the grid item. */
.filters{border:1px solid var(--line);border-radius:10px;padding:18px}
.filters h4{font-size:12px;text-transform:uppercase;letter-spacing:.08em;margin:16px 0 10px;color:var(--muted)}
.filters h4:first-child{margin-top:0}
.filters label{display:flex;align-items:center;gap:8px;font-size:13.5px;margin-bottom:7px;cursor:pointer}
/* Long brand lists scroll inside the sidebar rather than pushing it down the page. */
.filters .facet{max-height:220px;overflow-y:auto;padding-right:4px}
.filters .money{display:flex;gap:8px;align-items:center}
/* min-width:0 — a flex item defaults to min-width:auto, which for a number
   input resolves to its intrinsic size (roughly 100–140px with spinners). Two
   of those plus the dash exceeded the ~262px available at 320px and pushed the
   sidebar wide. Every other flex input on the site already guards this. */
.filters .money input{width:100%;min-width:0;border:1px solid var(--line);border-radius:6px;padding:8px;font-size:13px;font-family:inherit}
.filters .apply{width:100%;margin-top:16px;padding:10px;border:0;border-radius:7px;background:var(--navy);
  color:#fff;font-weight:700;font-size:13px;cursor:pointer;font-family:inherit}
.filters .clear{display:block;text-align:center;margin-top:10px;font-size:12.5px;color:var(--muted)}
.toolbar{display:flex;justify-content:space-between;align-items:center;margin-bottom:18px;gap:16px;flex-wrap:wrap}
/* The listing heading is an <h1> now — it is what the page is about. Sized to
   what it looked like as an <h2>, because the global h1 is the 50px hero rule
   and a category name at that size dwarfs the products underneath it. */
.toolbar h1{font-size:28px;letter-spacing:-.02em;line-height:1.2;margin:0}
.toolbar select{border:1px solid var(--line);border-radius:7px;padding:9px 12px;font-size:13.5px;font-family:inherit;background:#fff}
.crumbs{font-size:12.5px;color:var(--muted);padding:12px 0 0}
.crumbs a:hover{color:var(--red)}
.empty{border:1px dashed var(--line);border-radius:10px;padding:56px 20px;text-align:center;color:var(--muted)}
.pager{display:flex;gap:6px;justify-content:center;margin-top:36px;flex-wrap:wrap}
.pager a,.pager span{border:1px solid var(--line);border-radius:7px;padding:8px 13px;font-size:13.5px}
.pager .on{background:var(--navy);color:#fff;border-color:var(--navy)}
.pager .off{color:var(--muted);opacity:.5}

/* ---------- product detail ---------- */
.pdp{display:grid;grid-template-columns:1fr 1fr;gap:48px;padding:22px 0 40px}

/* Page body beside a sidebar, rather than a third column inside the product
   grid.
   As a third column the sidebar set the grid ROW height: a 640px rail against a
   ~340px gallery+buy row left a 300px hole between the images and the
   description tabs, and no amount of margin would close it because the row was
   simply that tall. Out here the sidebar spans the gallery AND the tabs, the
   tabs sit straight under the images, and the sidebar is free to be whatever
   height it likes.
   align-items:start stops the two columns stretching to match each other, and
   position:sticky keeps the rail in view while the description is read. */
@media(min-width:1100px){
  .pdp-layout{display:grid;grid-template-columns:minmax(0,1fr) 280px;gap:34px;align-items:start}
  .pdp{gap:34px}

  /* Not sticky, deliberately. It was, briefly: but the sidebar is 640px against
     a page body of 750-870px, so it had barely 230px of travel even with the
     description expanded — an extra wrapper element and two rules to make the
     rail creep a fraction of a screen. Plain flow is simpler and honest. */
}
.gallery .main{border:1px solid var(--line);border-radius:12px;background:#fff;aspect-ratio:1;display:grid;place-items:center;overflow:hidden}
.gallery .main img{width:100%;height:100%;object-fit:contain;padding:20px}

/* Rail beside the image. The rail column is fixed at 72px and the main image
   takes the rest, so the photo keeps its square aspect and the rail matches its
   height exactly — which is what makes "does this overflow?" a real question
   rather than a guess. */
.gallery.has-rail{display:grid;grid-template-columns:72px minmax(0,1fr);gap:12px;align-items:start}
.thumb-rail{display:flex;flex-direction:column;gap:6px;min-width:0;
  /* Matches the square main image beside it. */
  height:0;min-height:100%}
.gallery .thumbs{display:flex;flex-direction:column;gap:10px;flex:1;
  /* auto, not hidden: a hidden box is not a scroll container, so even
     scrollTop set from script stayed at 0 and the arrows did nothing. The
     scrollbar itself is suppressed below — the arrows are the control, and a
     native bar beside 72px thumbnails is all bar and no thumbnail. */
  overflow-y:auto;overflow-x:hidden;
  /* No scroll-behavior:smooth. With it set, scrollBy() from the arrow buttons
     was accepted and then silently discarded — the rail never moved. Instant
     is the honest trade: a thumbnail strip that jumps 3 images is fine; one
     that animates beautifully and does not scroll is not. */
  scrollbar-width:none}
.gallery .thumbs::-webkit-scrollbar{width:0;height:0}
/* The thumbnail is now a <button> wrapping the <img> so it is keyboard
   operable. The button is stripped back to nothing and the flex sizing moves
   onto it — the img inside keeps the visible frame, so the appearance is
   unchanged. */
.gallery .thumbs .thumb-btn{flex:0 0 72px;padding:0;border:0;background:none;
  cursor:pointer;display:block;line-height:0;border-radius:8px}
.gallery .thumbs .thumb-btn:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.gallery .thumbs img{width:72px;height:72px;object-fit:contain;border:1px solid var(--line);
  border-radius:8px;padding:4px;cursor:pointer;background:#fff;display:block}
.gallery .thumbs img.on{border-color:var(--red)}

.rail-arrow{flex:0 0 22px;height:22px;border:1px solid var(--line);border-radius:6px;background:#fff;
  color:var(--navy);font-size:9px;line-height:1;cursor:pointer;display:grid;place-items:center;
  font-family:inherit;padding:0;transition:.15s}
.rail-arrow:hover:not(:disabled){border-color:var(--red);color:var(--red)}
.rail-arrow:disabled{opacity:.35;cursor:default}
.rail-arrow[hidden]{display:none}

/* Phone: a 72px vertical rail costs width the photo needs more, so the strip
   goes back under the image and scrolls sideways with a finger. The arrows are
   pointless on a touch screen, so they stay hidden. */
@media(max-width:600px){
  .gallery.has-rail{grid-template-columns:1fr}
  .thumb-rail{flex-direction:row;height:auto;min-height:0;order:2;margin-top:12px}
  .gallery .thumbs{flex-direction:row;overflow-x:auto;overflow-y:hidden;
    -webkit-overflow-scrolling:touch}
  .gallery .main{order:1}
  .rail-arrow{display:none !important}
}
.pdp h1{font-size:30px;margin-bottom:10px}
.pdp .pricing{display:flex;align-items:baseline;gap:12px;margin:18px 0}
.pdp .pricing b{font-size:32px;color:var(--red)}
.pdp .pricing s{color:var(--muted)}
.pdp .save{background:#fdeeed;color:var(--red);font-size:12px;font-weight:800;padding:4px 9px;border-radius:5px}
.pdp .desc,.tab-panel .desc{color:var(--muted);line-height:1.75;font-size:14.5px;margin:18px 0}
/* The summary line under the price — slightly darker and tighter than the full
   description so it reads as a lead-in, not as body copy. */
.pdp .desc-short{color:var(--text);line-height:1.6;font-size:14.5px;margin:14px 0 0}
/* Supplier descriptions carry their feature list as embedded <ul> markup, which
   Blade escapes into visible tags. ProductDescription splits it out so it can be
   rendered as a real list here. */
.pdp .feature-title,.tab-panel .feature-title{font-size:14px;font-weight:700;color:var(--navy);margin:18px 0 8px;letter-spacing:.2px}
.pdp .features,.tab-panel .features{list-style:none;margin:0 0 18px;padding:0}
.pdp .features li,.tab-panel .features li{position:relative;padding:5px 0 5px 20px;color:var(--muted);line-height:1.6;font-size:14.5px}
.pdp .features li::before,.tab-panel .features li::before{content:"";position:absolute;left:2px;top:13px;width:6px;height:6px;border-radius:50%;background:var(--red)}
.specs{width:100%;border-collapse:collapse;margin:22px 0;font-size:13.5px}
.specs th,.specs td{text-align:left;padding:10px 0;border-bottom:1px solid var(--line)}
.specs th{color:var(--muted);font-weight:600;width:38%}
.buy{display:flex;gap:12px;margin-top:8px}
/* Add-to-basket and Save are two SEPARATE forms — a form inside a form is
   invalid HTML — so this row keeps them looking like one control group. */
.buy-row{display:flex;gap:12px;align-items:flex-start;flex-wrap:wrap;margin-top:8px}
.buy-row .buy{margin-top:0}
.wish-save{margin:0}
/* Saved state: filled, so the button says which way it will go. */
.wish-on{border-color:var(--red);color:var(--red)}
.buy .btn-p{flex:1;text-align:center}

/* ---------- basket & checkout ---------- */
.basket-link:hover{color:var(--red)}
.flash{background:#eefaf2;border-bottom:1px solid #c9ecd8}
.flash .wrap{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:12px 20px;
  font-size:13.5px;color:var(--green);font-weight:600}
.flash a{color:var(--navy);text-decoration:underline}
/* Same banner, different meaning — red so a failure never reads as a
   confirmation. Previously an out-of-stock notice used the green one. */
.flash-error{background:#fdeeee;border-bottom-color:#f3c9c9}
.flash-error .wrap{color:var(--red-d)}

.cart-layout{display:grid;grid-template-columns:1fr 340px;gap:28px;align-items:start;padding-bottom:64px}
.cart-lines{border:1px solid var(--line);border-radius:10px;overflow:hidden}
.cart-line{display:grid;grid-template-columns:84px 1fr auto auto auto;gap:16px;align-items:center;
  padding:16px;border-bottom:1px solid var(--line)}
.cart-line:last-child{border-bottom:0}
.cart-thumb{width:84px;height:84px;border:1px solid var(--line);border-radius:8px;background:#fff;display:block}
.cart-thumb img{width:100%;height:100%;object-fit:contain;padding:6px}
.cart-info strong{font-size:14px;font-weight:600;display:block;margin-bottom:4px}
.cart-info a:hover strong{color:var(--red)}
.muted{color:var(--muted);font-size:12.5px}
.cart-qty{display:flex;gap:6px;align-items:center}
.cart-qty input{width:62px;border:1px solid var(--line);border-radius:7px;padding:8px;font-size:13.5px;
  font-family:inherit;text-align:center}
.cart-qty button{border:1px solid var(--line);background:#fff;border-radius:7px;padding:8px 10px;font-size:12px;
  cursor:pointer;font-family:inherit;color:var(--muted)}
.cart-qty button:hover{border-color:var(--navy);color:var(--navy)}
.cart-total{font-weight:800;font-size:16px;min-width:76px;text-align:right}
.cart-remove{border:0;background:transparent;color:var(--muted);font-size:16px;cursor:pointer;padding:6px}
.cart-remove:hover{color:var(--red)}

.summary{border:1px solid var(--line);border-radius:10px;padding:20px;position:sticky;top:98px;background:#fff}
.summary h3{font-size:16px;margin-bottom:16px}
.summary .row{display:flex;justify-content:space-between;gap:12px;font-size:13.5px;padding:7px 0}
.summary hr{border:0;border-top:1px solid var(--line);margin:10px 0}
.summary .total{font-size:19px;font-weight:800;border-top:1px solid var(--line);margin-top:8px;padding-top:14px}
.free{color:var(--green)}
.nudge{background:#fdeeed;border-radius:8px;padding:10px 12px;font-size:12.5px;color:var(--red-d);margin:8px 0}
.summary .clear{display:block;text-align:center;margin-top:10px;font-size:13px;color:var(--muted)}
.reassure{list-style:none;margin-top:18px;border-top:1px solid var(--line);padding-top:16px}
.reassure li{font-size:12.5px;color:var(--muted);margin-bottom:9px}

.panel{border:1px solid var(--line);border-radius:10px;padding:20px;margin-bottom:20px;background:#fff}
.panel h3{font-size:16px;margin-bottom:16px}
/* The order page builds its lines from the same .row markup as the basket
   summary, but that rule was scoped to .summary — so on /account/orders/* the
   spans stayed inline and rendered as "Subtotal£29.96", with the price glued to
   the label and nothing lining up down the right. */
.panel .row,.acct-card .row{display:flex;justify-content:space-between;gap:12px;font-size:13.5px;padding:7px 0}
.panel hr,.acct-card hr{border:0;border-top:1px solid var(--line);margin:10px 0}
.panel .total,.acct-card .total{font-size:19px;font-weight:800;border-top:1px solid var(--line);margin-top:8px;padding-top:14px}
.panel .row.discount span,.acct-card .row.discount span{color:var(--green);font-weight:600}
.fields{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.fields .full{grid-column:1/-1}
.fields label{display:flex;flex-direction:column;gap:6px;font-size:13px}
.fields label>span{font-weight:600}
.fields input,.fields textarea{border:1px solid var(--line);border-radius:7px;padding:11px;font-size:14px;
  font-family:inherit;width:100%}
.fields input:focus,.fields textarea:focus{outline:2px solid var(--navy);outline-offset:-1px}
.fields input:disabled{background:var(--alt);color:var(--muted)}
.fields small{color:var(--muted);font-size:11.5px}
.fields em,.field-error{color:var(--red);font-size:12px;font-style:normal}

.option{display:flex;align-items:center;gap:14px;border:1px solid var(--line);border-radius:8px;
  padding:14px;margin-bottom:10px;cursor:pointer}
.option:has(input:checked){border-color:var(--navy);background:#f7fbfe}
.option-body{flex:1;display:flex;flex-direction:column;gap:3px}
.option-body strong{font-size:14px}
.option-body small{color:var(--muted);font-size:12.5px}
.option-price{font-weight:700;font-size:14px}

.terms{display:flex;gap:9px;align-items:flex-start;font-size:13px;margin:14px 0 6px;cursor:pointer}
.alert{background:#fdeeed;border:1px solid #f5c9c7;color:var(--red-d);border-radius:8px;padding:12px 14px;
  font-size:13px;margin-bottom:18px}
.alert.warn{background:#fff8e6;border-color:#f3dfa8;color:#7a5a06;margin:14px 0}
.alert code{font-family:ui-monospace,monospace;font-size:12px}

.buy .qty{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:600}
.buy .qty input{width:66px;border:1px solid var(--line);border-radius:7px;padding:13px 8px;font-size:14px;
  font-family:inherit;text-align:center}

/* ---------- product detail tabs ----------
   Full width below the .pdp grid, driven by radio inputs so no JS is involved:
   the checked radio reveals its sibling panel and styles its own label. */
/* Closed by a rule of its own, with real space either side — the related-products
   pill sat right on top of the open panel and read as part of it. */
.tabs{margin:34px 0 38px;padding-bottom:30px;border-bottom:1px solid var(--line)}
.tab-in{position:absolute;opacity:0;pointer-events:none;width:0;height:0}
.tab-strip{display:flex;gap:8px;border-bottom:2px solid var(--red);flex-wrap:wrap}
/* Styled as buttons, matching .btn-p — both start collapsed, so a bare text
   label with nothing open under it read as a heading rather than a control. */
.tab-label{display:inline-flex;align-items:center;gap:9px;cursor:pointer;
  padding:9px 24px;font-size:14px;font-weight:700;color:#fff;
  background:var(--red);border:2px solid var(--red);border-bottom:0;
  border-radius:10px 10px 0 0;margin-bottom:-2px;
  box-shadow:0 8px 20px -10px rgba(213,18,26,.75);
  transition:background .15s,border-color .15s}
.tab-label:hover{background:var(--red-d);border-color:var(--red-d)}
/* Chevron drawn from borders — no icon font or SVG request. */
.tab-label .chev{width:8px;height:8px;flex:none;
  border-right:2.5px solid currentColor;border-bottom:2.5px solid currentColor;
  transform:rotate(45deg);transform-origin:60% 60%;transition:transform .2s}
/* The open tab: the deeper red, pressed flat (no lift shadow) and seated onto
   the panel below. With both tabs red the chevron does most of the work of
   saying which one is open, so it flips up. */
#tab-desc:checked ~ .tab-strip .tab-label[for="tab-desc"],
#tab-specs:checked ~ .tab-strip .tab-label[for="tab-specs"],
#tab-faqs:checked ~ .tab-strip .tab-label[for="tab-faqs"],
#tab-reviews:checked ~ .tab-strip .tab-label[for="tab-reviews"]{
  background:var(--red-d);border-color:var(--red-d);box-shadow:none}
#tab-desc:checked ~ .tab-strip .tab-label[for="tab-desc"] .chev,
#tab-specs:checked ~ .tab-strip .tab-label[for="tab-specs"] .chev,
#tab-faqs:checked ~ .tab-strip .tab-label[for="tab-faqs"] .chev,
#tab-reviews:checked ~ .tab-strip .tab-label[for="tab-reviews"] .chev{
  transform:rotate(225deg)}
.tab-in:focus-visible ~ .tab-strip .tab-label[for="tab-desc"],
#tab-reviews:focus-visible ~ .tab-strip .tab-label[for="tab-reviews"],
#tab-faqs:focus-visible ~ .tab-strip .tab-label[for="tab-faqs"],
#tab-specs:focus-visible ~ .tab-strip .tab-label[for="tab-specs"]{
  outline:2px solid var(--red);outline-offset:2px}
/* One reading column for everything in the panel.
   The measure cap used to sit on the paragraphs alone, so the prose stopped at
   712px while the bullets underneath ran the full 966px — which is what made
   the white space look like a fault rather than a margin. Capping the panel
   itself keeps prose, headings, bullets and the specifications table on the
   same left column, and there is one number to change instead of three.
   The panel itself is no longer capped: the prose column below carries the
   reading measure instead, and the key features sit in the space that cap used
   to leave empty. The specifications table keeps a cap of its own — a two
   column table stretched to 966px puts half a screen between label and value. */
.tab-panel{display:none;padding:24px 2px 0}
#panel-specs{max-width:712px}

/* Description: prose left, key features right.
   Holding prose to a readable measure left ~256px of the panel empty, which
   read as a fault rather than a margin. Beside it, that space carries the list
   people actually scan. The prose column gets NARROWER as a result — about 88
   characters a line rather than 99 — so readability improves at the same time
   as the gap disappears. */
.desc-layout{display:grid;gap:32px}
/* The measure still has to hold when the two columns stack. Without this the
   prose ran the full 955px below 1000px — 137 characters a line, the very
   number the original cap existed to prevent. In the two-column layout the
   grid track is narrower than this, so the cap simply never applies there. */
.desc-prose{max-width:712px}
.desc-features{background:var(--alt);border:1px solid var(--line);border-radius:12px;padding:16px 18px}
.desc-features .feature-title{margin-top:0}
.desc-features .features{margin-bottom:0}

@media(min-width:1000px){
  /* align-items:start so the features box hugs its content instead of
     stretching to the full height of a long description. */
  .desc-layout{grid-template-columns:minmax(0,1fr) 300px;align-items:start}
}
#tab-desc:checked ~ #panel-desc,
#tab-specs:checked ~ #panel-specs,
#tab-faqs:checked ~ #panel-faqs,
#tab-reviews:checked ~ #panel-reviews{display:block}

/* Questions. Capped to the same measure as the specifications table and the
   reviews — an answer running the full panel width is 130 characters a line. */
.pdp-faqs{max-width:712px}
.pdp-faqs h3{font-size:15px;font-weight:700;color:var(--navy);margin:22px 0 6px}
.pdp-faqs h3:first-child{margin-top:0}
.pdp-faqs p{color:var(--muted);line-height:1.75;font-size:14.5px;margin:0}
.tab-panel .desc{margin-top:0}
.tab-panel .specs{margin-top:0}
.tab-panel .feature-title{margin-top:20px}
/* Section headings inside the AI-written full description. */
.tab-panel .copy-heading{font-size:16px;font-weight:700;color:var(--navy);margin:22px 0 8px;letter-spacing:-.01em}
.tab-panel .copy-heading:first-child{margin-top:0}
@media(max-width:600px){
  .tab-label{padding:9px 12px;font-size:13.5px;flex:1;justify-content:center}
}

.confirm{text-align:center;padding:56px 0 40px}
.confirm .tick{width:64px;height:64px;border-radius:50%;background:var(--green);color:#fff;font-size:30px;
  display:grid;place-items:center;margin:0 auto 22px}
.confirm h1{font-size:34px;margin-bottom:14px}
.next{padding-left:18px;font-size:13px;color:var(--muted);line-height:1.7}
.next li{margin-bottom:12px}
.next strong{color:var(--text)}

/* ---------- promo + footer ---------- */
.promo{background:var(--navy);color:#fff}
.promo .wrap{display:grid;grid-template-columns:repeat(3,1fr);gap:26px;padding:30px 20px}
.pbox{background:rgba(255,255,255,.07);border-radius:12px;padding:24px;border:1px solid rgba(143,221,243,.18)}
.pbox b{display:block;font-size:17px;margin-bottom:8px;color:var(--cyan)}
.pbox p{color:#c0d0dd;font-size:13.5px;line-height:1.6}
/* Dark navy footer with light, high-contrast text (was low-contrast
   light-blue-on-grey). Sits a shade darker than the navy promo band above it. */
footer{background:#082439;padding:36px 0 22px;font-size:13.5px;line-height:1.6;color:#dbe6ef}
.fgrid{display:grid;grid-template-columns:2fr 1fr 1fr 1fr;gap:36px;margin-bottom:24px}
footer p{color:#c6d4e1}
footer .logo b{color:#fff}
footer h4{color:#fff;font-size:13px;margin-bottom:14px;font-weight:800;letter-spacing:.02em}
footer li{list-style:none;margin-bottom:10px}
footer a{color:#e8f0f7}
footer a:hover{color:var(--cyan)}
.fbot{border-top:1px solid rgba(255,255,255,.14);padding-top:20px;display:flex;
  justify-content:space-between;font-size:12px;gap:16px;flex-wrap:wrap;color:#8ea3b8}

/* Sticky mobile "add to basket" bar (product page); hidden by default. */
.buy-bar{display:none}
.pdp-space{display:none}

/* ---------- tablet (≤1000) ---------- */
@media(max-width:1000px){
  .hero .wrap,.grid,.trust .wrap,.fgrid,.promo .wrap,.pdp{grid-template-columns:1fr 1fr}
  .is-home .grid{grid-template-columns:repeat(3,1fr)}
  .cats{grid-template-columns:repeat(3,1fr)}
  h1{font-size:34px}
  .listing,.cart-layout{grid-template-columns:1fr}
  .filters,.summary{position:static}

  /* One column means the filter panel sits ABOVE the products rather than
     beside them. Expanded, that put a screen and a half of checkboxes between
     the shopper and the first product — on the page whose entire job is to
     show products. Collapsed to a single bar, the grid starts immediately. */
  /* 98px, not 20px: the site header is position:sticky at top:0 with a 78px bar,
   so a 20px offset parked this 58px underneath it and the first heading in the
   panel was permanently hidden. The account sidebar already uses 96px, which is
   how you can tell 20px predates the sticky header. */
.filter-panel{position:static;margin-bottom:4px}
  .filter-panel > summary{
    display:flex;align-items:center;justify-content:space-between;gap:10px;
    padding:13px 16px;border:1px solid var(--line);border-radius:10px;
    font-weight:700;font-size:14.5px;color:var(--navy);background:var(--alt);
    cursor:pointer;list-style:none;user-select:none}
  /* Chevron drawn from borders, matching the product tabs — no icon request. */
  .filter-panel > summary::after{
    content:"";width:8px;height:8px;flex:none;margin-left:auto;
    border-right:2.5px solid currentColor;border-bottom:2.5px solid currentColor;
    transform:rotate(45deg) translate(-2px,-2px);transition:transform .2s}
  .filter-panel[open] > summary::after{transform:rotate(225deg) translate(-2px,-2px)}
  .filter-panel[open] > summary{border-radius:10px 10px 0 0;border-bottom:0}
  /* Seated onto the bar above it when open, so the two read as one control. */
  .filter-panel[open] .filters{border-radius:0 0 10px 10px}

  .filter-count{
    display:inline-grid;place-items:center;min-width:22px;height:22px;padding:0 6px;
    border-radius:11px;background:var(--red);color:#fff;font-size:12px;font-weight:700}
}

/* ---------- mobile header + drawer nav (≤768) ---------- */
@media(max-width:768px){
  .top{display:none}                       /* overflowing ticker; trust bar/specs cover it */
  .bar{flex-wrap:wrap;height:auto;padding:12px 0;gap:12px 14px}
  .hamburger{display:flex;order:0}
  .logo{order:1;font-size:22px}
  .logo img{width:30px;height:30px}
  .acts{order:2;margin-left:auto;gap:0}
  .acts .act-desktop{display:none}         /* account/wishlist not primary on mobile */
  .acts .basket-link b{font-size:24px;margin:0}
  .acts .basket-link span{display:none}    /* basket = icon only */
  .search{order:3;flex-basis:100%;max-width:none}

  /* nav collapses into a drawer toggled by the hamburger */
  .navbar{display:none}
  body.nav-open .navbar{display:block}
  .navbar .wrap{flex-direction:column;height:auto;align-items:stretch;overflow:visible;padding:6px 0}
  .navbar a{padding:14px 4px;border-radius:0;border-bottom:1px solid var(--line);font-size:15px}
  .navbar a:last-child{border-bottom:0}
  /* The two the header hides on mobile — without these the drawer has no
     route to a saved item or a sign-in. */
  .nav-drawer-only{display:block;font-weight:700;color:var(--navy)}

  /* sticky buy bar keeps the CTA reachable on the conversion page */
  .buy-bar{display:flex;position:fixed;left:0;right:0;bottom:0;z-index:30;background:#fff;
    border-top:1px solid var(--line);box-shadow:0 -4px 18px rgba(10,46,77,.12);
    padding:10px 16px;gap:14px;align-items:center}
  .buy-bar .price{font-size:20px;font-weight:800;color:var(--red);white-space:nowrap}
  .buy-bar .price s{font-size:13px;color:var(--muted);margin-left:6px;font-weight:400}
  .buy-bar .btn{flex:1;text-align:center;padding:15px;margin:0}
  .pdp-space{display:block;height:74px}

  /* The fixed buy bar sits over the bottom of the page, so the LAST thing on
     it needs clearing too. .pdp-space above only pads the product content —
     scrolled fully down, the bar was covering the final 46px of the footer
     (the copyright and payment line). */
  footer{padding-bottom:84px}

  /* Touch targets. Apple asks for 44px, Android 48px; these were 30-42px, which
     is the difference between tapping a thing and tapping near it. The visible
     boxes are left alone — the target is grown with padding, so nothing about
     the design changes. */
  .wish{width:44px;height:44px}
  .tab-label{min-height:44px}
  .acts .basket-link{min-width:44px;min-height:44px;display:grid;place-items:center}
  .hamburger{width:46px;height:46px}
  .buy{flex-wrap:wrap}
  .buy .btn-p{flex:1 1 150px}
  .buy .btn-o{flex:1 1 120px}

  /* Mobile hero leads with search: the box is the biggest, most prominent thing
     here; the message and badges below are deliberately small and secondary.
     The header search is hidden on the home page so search isn't duplicated. */
  .hero .wrap{grid-template-columns:1fr;padding:14px 20px 18px;text-align:center}
  .hero-art{display:none}
  .hero .btn{display:none}
  .hero .flag{display:none}          /* delivery/packaging strip */
  .hero-sale{display:none}     /* legacy sale clause — desktop only */
  /* No slider on a phone.

     It had already been reduced to a single pinned slide with its dots hidden —
     a carousel with nothing carouselling — and what remained was 277px of brand
     copy and product names sitting between the search box and the shop: a third
     of the first screen, above everything a shopper actually came for.

     The slides stay in the markup and are still crawlable and still linked;
     they are simply not painted at this width. The h1 they carried is replaced
     by .hero-h1 above, so the page keeps a visible top-level heading. */
  .hero-slider{display:none}

  /* The h1 costs no space on a phone, but it still exists.
     Same technique as .sr-only — NOT display:none, which is the tempting
     one-liner and the wrong one: display:none drops the element from the
     accessibility tree entirely, so a screen-reader user on a phone would land
     on the home page with no top-level heading at all, and Google (which
     renders with a mobile viewport) would see a home page whose only statement
     of what the shop sells is not rendered.
     Clipped instead: zero pixels, still read aloud, still crawled. */
  .hero-h1{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
    overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

  .hero-search{display:flex;margin:0 0 14px;background:#fff;border:2px solid var(--navy);
    border-radius:12px;overflow:hidden;box-shadow:0 12px 26px -14px rgba(10,46,77,.55)}
  .hero-search input{flex:1;min-width:0;border:0;outline:0;padding:16px 16px;font-size:16px;
    font-family:inherit;color:var(--text);background:transparent}
  .hero-search button{border:0;background:var(--red);color:#fff;padding:0 22px;font-size:19px;cursor:pointer}

  body.is-home > header .search{display:none}   /* moved into the hero */

  /* Trust badges: a compact 2×2 of small cards, not the visual focus. */
  .trust .wrap{grid-template-columns:repeat(2,1fr);gap:8px;padding:12px 20px}
  .trust div{flex-direction:column;text-align:center;gap:5px;background:var(--alt);
    border-radius:10px;padding:11px 8px;font-size:10.5px}
  .trust b{font-size:11.5px}
  .trust .ic{margin:0;width:28px;height:28px;font-size:14px}
}

/* ---------- phone (≤600) ---------- */
@media(max-width:600px){
  .grid,.fgrid,.promo .wrap,.pdp,.hero .wrap,.fields{grid-template-columns:1fr}
  .is-home .grid{grid-template-columns:repeat(2,1fr)}
  .cats,.cats.cats-home{grid-template-columns:repeat(2,1fr)}
  h1{font-size:29px}
  .pdp h1{font-size:26px}
  .toolbar{flex-direction:column;align-items:stretch}
  /* Stack the basket line rather than squeeze five columns onto a phone.
     All five children are placed explicitly: leave any of them to auto
     placement and it lands in an IMPLICIT extra column, which pushed the page
     30px wider than a 320px screen.

     Two columns, not three. The quantity form is an input plus an Update
     button, so its min-content is ~140px and it will not compress; reserving a
     third column beside it for the line total left 320px screens short again.
     Thumbnail down the left, everything else stacked beside it, with the total
     and the remove button sharing the last row at opposite ends.

     minmax(0,1fr) because a bare 1fr refuses to shrink below the longest
     product name — the other half of the same overflow. */
  /* And the grid item ABOVE it: .cart-layout's column was being sized to the
     basket's min-content (330px) rather than to the screen, because a grid item
     defaults to min-width:auto and so refuses to shrink below its contents.
     Without this the line has no width to shrink into and the two rules below
     have nothing to work with. */
  .cart-layout>*{min-width:0}
  .cart-line{grid-template-columns:56px minmax(0,1fr);row-gap:8px;column-gap:12px}
  .cart-thumb{width:56px;height:56px;grid-column:1;grid-row:1/4;align-self:start}
  .cart-info{grid-column:2;grid-row:1;min-width:0}
  .cart-qty{grid-column:2;grid-row:2;justify-self:start}
  .cart-total{grid-column:2;grid-row:3;justify-self:start;text-align:left}
  .cart-line>form:last-child{grid-column:2;grid-row:3;justify-self:end}

  /* Hero: the product-name links are nowrap, so one long name ("LELO F1S V3 AI
     Interactive…") set a 311px min-content floor that the slide inherited via
     min-width:auto — dragging the FIRST screen of the site sideways on a 320px
     phone. Let them wrap: a name split over two lines still says which product
     it is, where an ellipsis does not. */
  .hero-slide,.hero-copy{min-width:0}
  .hero-names li,.hero-names a{min-width:0;white-space:normal}
}

/* --- Blog / The Xtoys Guide ------------------------------------------------ */
.blog-head{padding:24px 0 8px;max-width:60ch}
.blog-head h1{font-size:34px;line-height:1.15;color:var(--navy)}
.blog-head p{color:var(--muted);margin-top:8px;font-size:16px;line-height:1.6}
.blog-empty{padding:40px 0;color:var(--muted)}

/* Five across.
   At a 1320px wrap that is about 238px a card, so the card's own type and
   padding come down with it — 18px headings and 18px padding were sized for a
   third of the row and look cramped at a fifth. */
.blog-list{display:grid;grid-template-columns:repeat(5,1fr);gap:16px;padding:14px 0 28px}
.blog-card{border:1px solid var(--line);border-radius:12px;overflow:hidden;background:#fff;
  display:flex;flex-direction:column;transition:box-shadow .15s,transform .15s}
.blog-card:hover{box-shadow:0 14px 30px -18px rgba(10,46,77,.5);transform:translateY(-2px)}
.blog-card-img{display:block;aspect-ratio:16/10;background:var(--alt)}
.blog-card-img img{width:100%;height:100%;object-fit:cover}
.blog-card-body{padding:12px 13px 15px;display:flex;flex-direction:column;gap:6px}
.blog-card-body time{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.03em}
/* Clamped, not truncated with an ellipsis mid-word: a review title carries the
   product name and cutting it at three lines keeps every card the same height
   without losing which product it is about. */
.blog-card-body h2,.blog-card-body h3{font-size:15px;line-height:1.32;color:var(--navy);
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.blog-card-body h2 a,.blog-card-body h3 a{color:inherit}
.blog-card-body p{color:var(--muted);font-size:12.5px;line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.blog-card-more{margin-top:auto;padding-top:4px;color:var(--red);font-weight:700;font-size:12.5px}
.blog-pager{padding:0 0 40px}

.blog-article{max-width:760px;margin:0 auto;padding:6px 0 32px}
.blog-article-head h1{font-size:32px;line-height:1.2;color:var(--navy)}
.blog-article-head time{display:block;margin-top:8px;color:var(--muted);font-size:13px}
.blog-hero{width:100%;max-height:440px;object-fit:cover;border-radius:14px;margin:18px 0 6px;background:var(--alt)}

/* Article lead: a fixed left column holds the image, its caption and the buy
   button; the verdict sits in the column beside it. Everything else in the
   article runs full width BELOW this block (see .blog-body), not wrapped around
   the image — align-items:start lines the two columns up from the top. */
.blog-lead{display:grid;grid-template-columns:320px minmax(0,1fr);gap:32px;align-items:start;margin:20px 0 24px}
.blog-lead-media,.blog-lead-text,.blog-lead-side{min-width:0}
.blog-figure{margin:0}
.blog-figure img{width:100%;display:block;border-radius:14px;background:var(--alt)}
.blog-figure .review-disclosure{margin-top:12px}
/* The buy card sits directly under the opinion, so the call to action follows
   the judgement that earns it rather than hanging under the photograph. */
.blog-figure-buy{margin-top:16px;border:1px solid var(--line);border-radius:12px;padding:16px 20px;background:var(--alt);
  display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}
.blog-figure-buy-text{min-width:0}
.blog-figure-buy b{display:block;color:var(--navy);font-size:16px;line-height:1.3}
.blog-figure-buy span{display:block;color:var(--muted);font-size:13.5px;margin-top:4px}
.blog-figure-buy .btn{padding:12px 24px;white-space:nowrap;flex:none}
/* The verdict beside the image; its heading lines up with the image top. When
   it is a real verdict it gets a callout box, when it is the intro fallback it
   is plain prose. */
.blog-lead-text > :first-child{margin-top:0}
.blog-lead-text.is-verdict{border:1px solid var(--line);border-radius:14px;padding:20px 24px;background:var(--alt)}
.blog-lead-text.is-verdict > :first-child{margin-top:0}
.blog-lead-text h2,.blog-lead-text h3{font-size:21px;color:var(--navy);margin:22px 0 12px}
.blog-lead-text p{font-size:16.5px;line-height:1.75;color:var(--text);margin:0 0 14px}
.blog-lead-text p:last-child{margin-bottom:0}
.blog-body > :first-child{margin-top:0}

/* Page-wide article with a right rail. The article fills the main column
   (overriding its centred 760px) and the sidebar carries related products and
   more guides. minmax(0,1fr) lets the main column shrink instead of the whole
   grid overflowing when the body has a long unbreakable string. */
.blog-layout{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:40px;align-items:start;padding-bottom:16px}
.blog-layout > .blog-article{max-width:none;margin:0;padding-bottom:16px}
/* 98px matches the other sticky rails on the site, clearing the 78px header. */
.blog-aside{position:sticky;top:98px}
.aside-block{border:1px solid var(--line);border-radius:14px;padding:16px 18px;margin-bottom:18px;background:#fff}
.aside-block > h2{font-size:16px;color:var(--navy);margin:0 0 12px}
.aside-products,.aside-guides{display:flex;flex-direction:column;gap:13px}
.aside-product,.aside-guide{display:flex;gap:12px;align-items:center;text-decoration:none}
.aside-product-img{flex:none;width:56px;height:56px;border-radius:8px;overflow:hidden;background:var(--alt)}
.aside-product-img img{width:100%;height:100%;object-fit:contain}
.aside-product-info{min-width:0;display:flex;flex-direction:column;line-height:1.3}
.aside-product-info em{font-style:normal;font-size:11px;text-transform:uppercase;letter-spacing:.03em;color:var(--muted)}
.aside-product-info b{font-size:13.5px;color:var(--navy);font-weight:600;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.aside-price{font-weight:700;color:var(--navy);font-size:13.5px;margin-top:3px}
.aside-guide img{flex:none;width:64px;height:48px;object-fit:cover;border-radius:8px;background:var(--alt)}
.aside-guide b{font-size:13px;color:var(--navy);font-weight:600;line-height:1.35;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.aside-product:hover b,.aside-guide:hover b{text-decoration:underline}
/* One column below this: the article, then the rail underneath it. */
@media(max-width:900px){
  .blog-layout{grid-template-columns:1fr;gap:8px}
  .blog-aside{position:static;margin-top:8px}
}

.blog-buy{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;
  border:1px solid var(--line);border-radius:12px;padding:16px 20px;margin:22px 0;background:var(--alt)}
.blog-buy b{display:block;color:var(--navy);font-size:16px}
.blog-buy span{color:var(--muted);font-size:14px}
.blog-buy .btn{padding:12px 24px;white-space:nowrap}
.blog-buy-foot{background:#fff}

.blog-body{font-size:16.5px;line-height:1.75;color:var(--text)}
.blog-body h2{font-size:22px;color:var(--navy);margin:28px 0 10px}
.blog-body p{margin:0 0 16px}

.blog-faq{margin:28px 0}
.blog-faq h2{font-size:22px;color:var(--navy);margin-bottom:12px}
.blog-faq details{border:1px solid var(--line);border-radius:10px;padding:14px 16px;margin-bottom:10px}
.blog-faq summary{font-weight:700;color:var(--navy);cursor:pointer}
.blog-faq p{margin:10px 0 0;color:var(--text);line-height:1.6}

.blog-more{padding:6px 0 32px}
.blog-more h2{font-size:22px;color:var(--navy);margin-bottom:14px}

@media(max-width:1200px){.blog-list{grid-template-columns:repeat(4,1fr)}}
@media(max-width:1000px){.blog-list{grid-template-columns:repeat(3,1fr)}}
@media(max-width:760px){.blog-list{grid-template-columns:repeat(2,1fr)}}
/* Below this the verdict column beside the image gets too narrow, so the lead
   stacks: image, caption, buy button, then the verdict, then the article. */
@media(max-width:720px){
  .blog-lead{grid-template-columns:1fr;gap:16px}
  .blog-figure img{max-height:420px;object-fit:cover}
}
@media(max-width:600px){
  .blog-figure-buy{flex-direction:column;align-items:stretch;text-align:center}
  .blog-figure-buy .btn{width:100%}
}
@media(max-width:600px){
  .blog-list{grid-template-columns:1fr}
  .blog-head h1{font-size:27px}
  .blog-article-head h1{font-size:25px}
  .blog-buy{flex-direction:column;align-items:stretch;text-align:center}
  .blog-buy .btn{width:100%}
}

/* --- Static content pages (About, Delivery, Returns, FAQs, Privacy, Terms) --- */
.page{max-width:820px;margin:0 auto;padding:8px 0 36px}
.page-head{padding:14px 0 6px}
.page-head h1{font-size:34px;line-height:1.15;color:var(--navy)}
.page-head p.page-lead{color:var(--muted);margin-top:10px;font-size:17px;line-height:1.6;max-width:60ch}
.page-body{font-size:16px;line-height:1.75;color:var(--text);margin-top:8px}
.page-body h2{font-size:21px;color:var(--navy);margin:30px 0 10px}
.page-body h3{font-size:16.5px;color:var(--navy);margin:20px 0 6px}
.page-body p{margin:0 0 15px}
.page-body ul{margin:0 0 18px;padding-left:0;list-style:none;display:grid;gap:9px}
.page-body ul li{position:relative;padding-left:24px}
.page-body ul li::before{content:"—";position:absolute;left:0;color:var(--red);font-weight:800}
.page-body a:not(.btn){color:var(--red);font-weight:600}
.page-body a:not(.btn):hover{text-decoration:underline}
.page-note{background:var(--alt);border:1px solid var(--line);border-radius:12px;padding:16px 20px;margin:18px 0}
.page-note b{color:var(--navy)}
.page-cta{margin-top:26px}

/* Info cards (delivery options, contact strip) */
.info-cards{display:grid;grid-template-columns:repeat(2,1fr);gap:16px;margin:18px 0}
.info-card{border:1px solid var(--line);border-radius:12px;padding:18px 20px;background:#fff}
.info-card b{display:block;color:var(--navy);font-size:16px;margin-bottom:4px}
.info-card .price{color:var(--red);font-weight:800;font-size:18px;float:right}
.info-card p{color:var(--muted);font-size:14px;margin:6px 0 0;line-height:1.55}

/* FAQ accordion (shared look with the blog FAQ) */
.faq details{border:1px solid var(--line);border-radius:10px;padding:14px 18px;margin-bottom:10px;background:#fff}
.faq summary{font-weight:700;color:var(--navy);cursor:pointer;font-size:15.5px}
.faq details p{margin:10px 0 0;color:var(--text);line-height:1.6}
.faq h2{font-size:20px;color:var(--navy);margin:26px 0 12px}

/* Track order form + status timeline */
.track-form{display:flex;gap:12px;flex-wrap:wrap;align-items:flex-end;background:var(--alt);
  border:1px solid var(--line);border-radius:12px;padding:20px;margin:16px 0 24px}
.track-form .fld{flex:1 1 220px;display:flex;flex-direction:column;gap:6px}
.track-form label{font-size:13px;font-weight:700;color:var(--navy)}
.track-form input{border:1px solid var(--line);border-radius:8px;padding:12px 14px;font-size:15px;font-family:inherit}
.track-form .btn{padding:12px 26px}
.track-error{background:#fdeeed;border:1px solid #f3c9c7;color:var(--red-d);border-radius:10px;padding:12px 16px;margin:0 0 18px;font-size:14px}
.track-result{border:1px solid var(--line);border-radius:12px;padding:22px 24px;margin-top:8px}
.track-result .track-head{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:10px;margin-bottom:16px}
.track-result .track-head b{color:var(--navy);font-size:18px}
.track-badge{display:inline-block;padding:5px 12px;border-radius:999px;font-weight:800;font-size:12px;
  text-transform:uppercase;letter-spacing:.04em;background:var(--alt);color:var(--navy)}
.track-badge.ok{background:#e6f5ec;color:var(--green)}
.track-badge.warn{background:#fdeeed;color:var(--red-d)}
.timeline{list-style:none;padding:0;margin:0;display:grid;gap:0}
.timeline li{position:relative;padding:0 0 20px 30px;color:var(--muted);font-size:14.5px}
.timeline li::before{content:"";position:absolute;left:7px;top:3px;width:11px;height:11px;border-radius:50%;
  background:#fff;border:2px solid var(--line)}
.timeline li::after{content:"";position:absolute;left:12px;top:14px;bottom:0;width:2px;background:var(--line)}
.timeline li:last-child::after{display:none}
.timeline li.done{color:var(--text)}
.timeline li.done::before{background:var(--green);border-color:var(--green)}
.timeline li.done b{color:var(--navy)}
.timeline li.current::before{background:var(--red);border-color:var(--red);box-shadow:0 0 0 4px rgba(213,18,26,.15)}

@media(max-width:600px){
  .info-cards{grid-template-columns:1fr}
  .page-head h1{font-size:27px}
  .track-form .fld{flex-basis:100%}
}

/* --- 100-question FAQ page ------------------------------------------------- */
.faq-page{max-width:1080px;margin:0 auto;padding:8px 0 36px}
.faq-nav{display:flex;flex-wrap:wrap;gap:8px;margin:18px 0 28px;padding-bottom:22px;border-bottom:1px solid var(--line)}
.faq-nav a{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--line);border-radius:999px;
  padding:8px 14px;font-size:13.5px;font-weight:600;color:var(--navy);background:#fff;transition:.15s}
.faq-nav a:hover{border-color:var(--red);color:var(--red)}
.faq-nav a span{background:var(--alt);color:var(--muted);border-radius:999px;padding:1px 7px;font-size:11.5px;font-weight:700}
.faq-nav a:hover span{background:#fdeeed;color:var(--red)}
.faq-group{scroll-margin-top:90px;margin-bottom:34px}
.faq-group h2{font-size:22px;color:var(--navy);margin-bottom:14px}
.faq-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px 18px;align-items:start}
@media(max-width:860px){.faq-grid{grid-template-columns:1fr}}

/* Pill headings shrink on phones so they never wrap awkwardly. */
@media(max-width:600px){
  .head h2{font-size:12.5px;letter-spacing:.04em;padding:9px 16px}
  /* Stack the heading pill over its "Shop all …" link: a long category name
     otherwise wraps the link to two lines beside the pill and reads as cramped. */
  .head{flex-direction:column;align-items:flex-start;gap:8px}
  .head a{font-size:13.5px}

  /* Touch targets on phones: footer links become full-width rows at least 44px
     tall, and the social icons grow to a 44px box — the WCAG 2.5.5 minimum, so
     they are comfortable to tap rather than fiddly. */
  footer li{margin-bottom:2px}
  footer li a{display:block;padding:11px 0;min-height:44px}
  .fbot a{display:inline-block;padding:8px 0;min-height:40px}
  .socials-footer .social{width:44px;height:44px}
}

/* --- Discount codes -------------------------------------------------------- */
.summary .row.discount span,
.checkout-summary .row.discount span{color:var(--green);font-weight:600}
.row.discount b{font-weight:800;letter-spacing:.02em}
.coupon-remove{border:0;background:none;color:var(--muted);cursor:pointer;font-size:12px;padding:0 0 0 6px;line-height:1}
.coupon-remove:hover{color:var(--red)}

.coupon{margin-top:16px;padding-top:14px;border-top:1px solid var(--line)}
.coupon label{display:block;font-size:12px;font-weight:700;color:var(--navy);margin-bottom:6px}
.coupon-row{display:flex;gap:8px}
.coupon-row input{flex:1;min-width:0;border:1px solid var(--line);border-radius:8px;padding:10px 12px;
  font-size:14px;font-family:inherit;text-transform:uppercase}
.coupon-row input::placeholder{text-transform:none}
.coupon-row button{border:0;background:var(--navy);color:#fff;font-weight:700;font-size:13px;
  padding:0 18px;border-radius:8px;cursor:pointer;font-family:inherit}
.coupon-row button:hover{background:var(--red)}
.coupon-error{color:var(--red-d);font-size:12.5px;margin-top:8px;line-height:1.5}

/* --- Category tiles (generated from each category's own products) ---------- */
/* Inset by its own margin rather than the card's padding, so the name strip
   below can still run edge to edge. */
.cat-img{align-self:stretch;flex:1;min-height:0;margin:10px 10px 8px;
  display:grid;place-items:center;overflow:hidden;border-radius:8px}
.cat-img img{width:100%;height:100%;object-fit:contain;display:block}
@media(max-width:600px){.cat b{font-size:12.5px;min-height:38px;padding:8px 6px}}

/* ---------- brands ---------- */
/* The brand label on a product page links through to its brand page. It keeps
   the muted uppercase treatment; only the hover marks it as a link, so the
   product name stays the loudest thing in that block. */
.pdp .brand a{color:var(--muted)}
.pdp .brand a:hover{color:var(--red)}

/* A–Z jump bar. Sticky so it stays reachable while scrolling a long index. */
.az{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 26px;padding:12px 0;
  position:sticky;top:78px;background:var(--bg);z-index:5;border-bottom:1px solid var(--line)}
.az a,.az span{display:grid;place-items:center;min-width:34px;height:34px;padding:0 6px;
  border-radius:8px;font-size:14px;font-weight:700;line-height:1}
.az a{background:var(--alt);color:var(--navy);border:1px solid var(--line);transition:.14s}
.az a:hover{background:var(--red);border-color:var(--red);color:#fff}
/* Letters with no brands stay in place rather than collapsing the bar, so its
   width doesn't shift as the catalogue turns over. */
.az span{color:#c2cad4;border:1px solid transparent;cursor:default}

.az-group{margin-bottom:30px}
.az-letter{display:flex;align-items:baseline;gap:14px;font-size:22px;color:var(--navy);
  border-bottom:2px solid var(--red-soft);padding-bottom:8px;margin-bottom:16px;
  scroll-margin-top:132px}   /* clears the sticky header + A–Z bar on jump */
.az-top{font-size:12px;font-weight:600;color:var(--muted);margin-left:auto}
.az-top:hover{color:var(--red)}

.brand-list{list-style:none;display:grid;grid-template-columns:repeat(4,1fr);gap:10px;padding:0}
.brand-list a{display:flex;align-items:center;gap:12px;padding:10px 12px;border:1px solid var(--line);
  border-radius:10px;transition:.14s;background:#fff}
.brand-list a:hover{border-color:var(--red);box-shadow:0 8px 18px -14px rgba(213,18,26,.6)}
.brand-name{font-size:14.5px;font-weight:600;color:var(--navy);line-height:1.3}

/* Wordmark tile standing in for a logo we don't have. Initials on brand navy
   read as deliberate, where a stretched placeholder image would not. */
.brand-mark{width:44px;height:44px;flex:none;border-radius:9px;display:grid;place-items:center;
  background:linear-gradient(160deg,var(--navy),#082439);color:#fff;font-weight:800;font-size:15px;
  letter-spacing:.02em;overflow:hidden}
.brand-mark img{width:100%;height:100%;object-fit:contain;background:#fff}
.brand-mark-lg{width:96px;height:96px;border-radius:16px;font-size:32px}

.brand-head{display:flex;gap:24px;align-items:flex-start;padding:22px 0 4px}
.brand-head h1{font-size:36px;margin-bottom:12px}
.brand-intro{color:var(--muted);line-height:1.7;font-size:15px;max-width:76ch;margin-bottom:10px}

/* Category pills left, sort control hard right, sharing one baseline. The pills
   take the slack so the dropdown stays pinned to the right edge however many
   categories a brand has. */
.brand-bar{display:flex;align-items:center;justify-content:space-between;gap:16px;
  flex-wrap:wrap;padding:14px 0 0}
.brand-bar .brand-cats{flex:1 1 auto;padding:0}
.brand-sort{display:flex;align-items:center;gap:8px;flex:0 0 auto;margin-left:auto}
.brand-sort label{font-size:13px;font-weight:600;color:var(--muted);white-space:nowrap}
.brand-sort select{font-family:inherit;font-size:13px;font-weight:600;color:var(--navy);
  padding:7px 30px 7px 12px;border:1px solid var(--line);border-radius:999px;background:#fff;
  cursor:pointer;appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 4.5L6 8.5L10 4.5' stroke='%230a2e4d' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 10px center;background-size:11px}
.brand-sort select:hover{border-color:var(--navy)}
/* Below this the pills need the full width, so the control drops beneath them
   and still sits right — a 5-option dropdown beside pills is unreadable on a
   phone. */
@media(max-width:640px){
  .brand-bar{align-items:stretch}
  .brand-sort{width:100%;justify-content:flex-end;margin-top:4px}
}
.brand-cats{display:flex;flex-wrap:wrap;gap:8px;padding:14px 0 0}
.brand-cats a{font-size:13px;font-weight:600;padding:7px 14px;border-radius:999px;
  background:var(--alt);border:1px solid var(--line);color:var(--navy);transition:.14s}
.brand-cats a:hover{background:var(--navy);border-color:var(--navy);color:#fff}

.brand-copy{border-top:1px solid var(--line);padding:26px 0 10px;max-width:76ch}
.brand-copy h2{font-size:18px;color:var(--navy);margin:20px 0 8px}
.brand-copy h2:first-child{margin-top:0}
.brand-copy p{color:var(--muted);line-height:1.75;font-size:14.5px;margin-bottom:12px}

.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0,0,0,0);white-space:nowrap;border:0}

@media(max-width:1000px){.brand-list{grid-template-columns:repeat(3,1fr)}}
@media(max-width:768px){
  .brand-list{grid-template-columns:repeat(2,1fr)}
  .brand-head{gap:16px}
  .brand-head h1{font-size:27px}
  .brand-mark-lg{width:68px;height:68px;border-radius:12px;font-size:23px}
  /* NOT top:0. At this breakpoint .bar becomes height:auto and wraps to about
     two rows, so the sticky site header is TALLER than on desktop — pinning the
     jump bar to 0 put it underneath the header entirely. position:static is the
     honest answer on a screen this short: the bar scrolls with the page and the
     letters stay reachable. */
  .az{position:static}
}
@media(max-width:600px){.brand-list{grid-template-columns:1fr}}

/* ---- Review articles -------------------------------------------------------
   The guide used to render a features list and a specifications table, which
   made every article read as a second product page. These are the review
   furniture that replaced them: a verdict up top, the good and the bad side by
   side, and a plain statement of who should not buy it. */

.review-disclosure{margin:8px 0 0;font-size:13px;line-height:1.5;color:var(--muted);
  border-left:3px solid var(--line);padding-left:10px;max-width:60ch}

.review-verdict{background:#f6f9fc;border:1px solid var(--line);border-left:5px solid var(--navy);
  border-radius:10px;padding:18px 20px;margin:0 0 24px}
.review-verdict h2{margin:0 0 8px;font-size:18px}
.review-verdict p:last-child{margin-bottom:0}

.review-pros-cons{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin:0 0 26px}
.review-pros,.review-cons{border:1px solid var(--line);border-radius:10px;padding:16px 18px;background:#fff}
.review-pros{border-top:4px solid var(--green)}
.review-cons{border-top:4px solid var(--amber)}
.review-pros h3,.review-cons h3{margin:0 0 10px;font-size:16px}
.review-pros ul,.review-cons ul{margin:0;padding-left:0;list-style:none;display:grid;gap:9px}
.review-pros li,.review-cons li{position:relative;padding-left:26px;line-height:1.5}
.review-pros li::before{content:"✔";position:absolute;left:0;color:var(--green);font-weight:800}
/* An exclamation, not a cross: these are trade-offs to weigh, not failures. */
.review-cons li::before{content:"!";position:absolute;left:6px;color:var(--amber);font-weight:800}

.review-audience{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin:0 0 26px}
.review-for,.review-not-for{border-radius:10px;padding:16px 18px}
.review-for{background:#f1f9f4;border:1px solid #cde9d7}
.review-not-for{background:#fdf6ec;border:1px solid #f0e0c2}
.review-for h3,.review-not-for h3{margin:0 0 6px;font-size:16px}
.review-for p,.review-not-for p{margin:0;line-height:1.55}

.review-bottom-line{border-top:2px solid var(--line);padding-top:14px}

@media(max-width:760px){
  .review-pros-cons,.review-audience{grid-template-columns:1fr}
}

/* ---- Customer accounts, wishlist ------------------------------------------ */

.wish-form{position:absolute;top:0;right:0;z-index:2}
.wish{cursor:pointer;border:1px solid var(--line);font-size:15px;line-height:1;color:var(--muted);
  display:grid;place-items:center;transition:.15s}
.wish:hover{color:var(--red);border-color:var(--red)}
.wish-on{color:var(--red);border-color:var(--red)}

.auth-page{display:grid;place-items:center;padding:14px 0 44px}
.auth-card{width:100%;max-width:460px;border:1px solid var(--line);border-radius:14px;background:#fff;padding:26px 26px 30px}
.auth-card h1{font-size:24px;color:var(--navy);margin-bottom:6px}
.auth-lede{color:var(--muted);font-size:14px;line-height:1.5;margin-bottom:14px}
.auth-form{display:grid;gap:13px;margin-top:6px}
.auth-form label{display:grid;gap:5px;font-size:13px;font-weight:600;color:var(--navy)}
.auth-form input[type=text],.auth-form input[type=email],.auth-form input[type=tel],.auth-form input[type=password]{
  /* 16px: anything smaller makes iOS zoom the page on focus. */
  border:1px solid var(--line);border-radius:9px;padding:11px 12px;font-size:16px;font-weight:400;width:100%}
.auth-form input:focus{outline:2px solid var(--blue);outline-offset:1px;border-color:var(--blue)}
.auth-form .hint{font-weight:400;font-size:12px;color:var(--muted);font-style:normal}
.auth-form .check{display:flex;gap:9px;align-items:flex-start;font-weight:400;font-size:13px;color:#333;line-height:1.45}
.auth-form .check input{margin-top:2px}
.two-up{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.auth-row{display:flex;justify-content:space-between;align-items:center;font-size:13px;gap:12px;flex-wrap:wrap}
.btn-wide{width:100%;justify-content:center;padding:12px}
.auth-alt{text-align:center;font-size:13px;color:var(--muted);margin-top:4px}
.auth-resend{margin-top:12px;text-align:center}
/* A real anchor that has to stay visible inside muted body text. Without it an
   <a> in a .muted paragraph inherits the grey and reads as ordinary prose —
   "Sign in to write a review" looked like a statement, not something to click. */
.link{color:var(--red);text-decoration:underline;text-underline-offset:2px;font-weight:600}
.link:hover{color:var(--red-d)}

.linkish{background:none;border:0;color:var(--red);font-size:13px;cursor:pointer;text-decoration:underline}
.linkish[disabled]{color:var(--muted);cursor:default;text-decoration:none}
.otp-input{letter-spacing:.42em;font-size:22px !important;text-align:center;font-weight:700}
.hidden{display:none}

.notice{border:1px solid var(--line);background:var(--alt);border-radius:9px;padding:11px 13px;font-size:13.5px;line-height:1.5;margin-bottom:14px}
.notice-ok{background:#f1f9f4;border-color:#cde9d7}
.notice-bad{background:#fdf3f3;border-color:#f2cdcd}

.account-head{display:flex;justify-content:space-between;align-items:center;gap:16px;margin:6px 0 18px}
.account-head h1{font-size:26px;color:var(--navy)}
.account-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:14px;margin-bottom:22px}
.account-tile{border:1px solid var(--line);border-radius:12px;padding:18px;text-align:center;background:#fff;transition:.15s}
.account-tile:hover{border-color:var(--red)}
.account-tile b{display:block;font-size:24px;color:var(--navy);margin-bottom:4px}
.account-tile span{font-size:13px;color:var(--muted)}
.acc-order{display:flex;justify-content:space-between;align-items:center;gap:14px;padding:12px 0;border-bottom:1px solid var(--line);flex-wrap:wrap}
.acc-order:last-child{border-bottom:0}
.acc-order .muted{display:block;font-size:12.5px;margin-top:2px}
.acc-order-right{display:flex;align-items:center;gap:12px}
.badge{font-size:11px;font-weight:700;padding:3px 9px;border-radius:999px;text-transform:uppercase;letter-spacing:.03em}
.badge-ok{background:#e8f6ed;color:#0a8a48}
.badge-wait{background:#fdf3e6;color:#a86a10}

@media(max-width:600px){
  .two-up{grid-template-columns:1fr}
  .auth-card{padding:20px 18px 24px}
}

/* ---- Product-page sidebar rails -------------------------------------------
   Desktop only. On a phone the .pdp grid collapses to one column, so these
   would land between the buy button and the description — pushing the things
   that actually sell the product below ten thumbnails. Hidden outright rather
   than restyled: the "You might also like" row further down already covers
   "show me more like this" on mobile. */

.pdp-rails{display:grid;gap:18px;align-content:start}
.rail{border:1px solid var(--line);border-radius:12px;padding:14px 16px;background:#fff}
.rail h3{font-size:13px;text-transform:uppercase;letter-spacing:.06em;color:var(--navy);margin-bottom:10px}
.rail-head{display:flex;justify-content:space-between;align-items:baseline;gap:10px}
.rail-clear{background:none;border:0;color:var(--muted);font-size:11.5px;cursor:pointer;
  text-decoration:underline;font-family:inherit;padding:0}
.rail-clear:hover{color:var(--red)}

.mini{display:flex;gap:11px;align-items:center;padding:8px 0;border-top:1px solid var(--line)}
.rail h3 + .mini,.rail-head + .mini{border-top:0}
.mini-thumb{flex:0 0 56px;width:56px;height:56px;border:1px solid var(--line);border-radius:8px;
  background:#fff;display:grid;place-items:center;overflow:hidden}
/* Feed photography is shot on white — contain, never crop, same as the cards. */
.mini-thumb img{width:100%;height:100%;object-fit:contain;padding:4px}
.mini-body{display:flex;flex-direction:column;gap:3px;min-width:0}
.mini-name{font-size:12.5px;line-height:1.35;color:#1b2330;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.mini:hover .mini-name{color:var(--red)}
.mini-price{font-size:13px;font-weight:800;color:var(--red)}

/* Hidden below the three-column breakpoint: without a column of its own this
   would land under the buy button, which is exactly what it was moved out of. */
@media(max-width:1099px){
  .pdp-rails{display:none}
}

/* ---- Full-size image viewer ------------------------------------------------ */

/* The main image is a <button> now, so its default chrome has to go. */
.gallery .main{border:1px solid var(--line);border-radius:12px;background:#fff;padding:0;
  cursor:zoom-in;position:relative;width:100%;font:inherit}
.gallery .main .zoom-hint{position:absolute;right:10px;bottom:10px;width:30px;height:30px;
  border-radius:8px;background:rgba(255,255,255,.92);border:1px solid var(--line);
  display:grid;place-items:center;font-size:14px;color:var(--navy);pointer-events:none;
  opacity:0;transition:.15s}
.gallery .main:hover .zoom-hint,.gallery .main:focus-visible .zoom-hint{opacity:1}

.zoom[hidden]{display:none}
.zoom{position:fixed;inset:0;z-index:200;display:grid;place-items:center;padding:24px}
.zoom-backdrop{position:absolute;inset:0;background:rgba(8,36,57,.86)}
.zoom-inner{position:relative;max-width:min(92vw,900px);max-height:92vh;display:grid;place-items:center}
.zoom-inner img{max-width:100%;max-height:86vh;object-fit:contain;background:#fff;
  border-radius:12px;padding:12px}

.zoom-close{position:absolute;top:-14px;right:-14px;width:38px;height:38px;border-radius:50%;
  border:1px solid var(--line);background:#fff;color:var(--navy);font-size:24px;line-height:1;
  cursor:pointer;display:grid;place-items:center;font-family:inherit;z-index:2}
.zoom-close:hover{background:var(--red);border-color:var(--red);color:#fff}

.zoom-nav{position:absolute;top:50%;transform:translateY(-50%);width:42px;height:42px;
  border-radius:50%;border:1px solid var(--line);background:rgba(255,255,255,.94);
  color:var(--navy);font-size:16px;cursor:pointer;display:grid;place-items:center;
  font-family:inherit;z-index:2}
.zoom-nav:hover{background:var(--red);border-color:var(--red);color:#fff}
.zoom-prev{left:-14px}
.zoom-next{right:-14px}
.zoom-count{position:absolute;bottom:-30px;left:0;right:0;text-align:center;color:#fff;
  font-size:13px;letter-spacing:.04em}

@media(max-width:600px){
  .zoom{padding:12px}
  /* Inside the edges on a small screen, where -14px would sit off-screen. */
  .zoom-close{top:6px;right:6px}
  .zoom-prev{left:2px}
  .zoom-next{right:2px}
  .zoom-inner img{max-height:74vh}
}

/* Admin-formatted copy. The allowlist in RichText is small, so this is all of
   it — enough that a rich-edited description looks deliberate rather than a
   wall of text. */
.desc.rich p{margin:0 0 14px}
.desc.rich p:last-child{margin-bottom:0}
.desc.rich ul,.desc.rich ol{margin:0 0 14px;padding-left:20px}
.desc.rich li{margin:4px 0;line-height:1.6}
.desc.rich h3,.desc.rich h4{font-size:15px;font-weight:700;color:var(--navy);margin:18px 0 8px}
.desc.rich a{color:var(--red);text-decoration:underline}
.desc.rich strong,.desc.rich b{color:#1b2330}
.desc.rich blockquote{margin:14px 0;padding-left:14px;border-left:3px solid var(--line);color:var(--muted)}


/* Product reviews */
/* Now a tab panel rather than a section of its own, so it carries neither the
   grid placement nor the top margin — the panel's own padding does that. The
   measure is capped for the same reason the specifications table is: review
   prose running the full 966px is 130+ characters a line. */
.pdp-reviews{max-width:712px}
.pdp-reviews .review-score{font-size:1.05rem;margin:0 0 18px}
.pdp-reviews .stars{color:var(--amber);letter-spacing:1px}
.review{border-top:1px solid #e6ecf1;padding:16px 0}
.review-meta{display:flex;flex-wrap:wrap;gap:10px;align-items:center;font-size:.875rem;margin:0 0 6px;color:#5b6b7a}
.review-meta b{color:var(--navy)}
.review-meta .verified{background:#e8f6ee;color:var(--green);border-radius:999px;padding:2px 10px;font-size:.75rem;font-weight:600}
.review h4{margin:4px 0 6px;font-size:1rem}
.review p{margin:0;line-height:1.55}
.review-form{margin-top:24px;padding:20px;background:var(--alt);border-radius:12px;max-width:640px}
.review-form h3{margin-top:0}
.review-form label{display:block;margin-bottom:12px}
.review-form input,.review-form select,.review-form textarea{width:100%;padding:10px;border:1px solid #cfd9e2;border-radius:8px;font:inherit}

/* ============================================================
   Signed-in account area
   ------------------------------------------------------------
   Same tokens as the shop: --navy for structure, --red for the
   active state and anything destructive, --line for edges, the
   same 12px card radius and the same .btn. The account pages
   used to be bare .wrap blocks with no shared frame, which read
   as a different, older site bolted onto the shop.
   ============================================================ */
.acct{padding:22px 0 56px;background:var(--alt)}
.acct-grid{display:grid;grid-template-columns:250px minmax(0,1fr);gap:24px;align-items:start}

/* ---- sidebar ---- */
.acct-side{position:sticky;top:96px;border:1px solid var(--line);border-radius:12px;background:#fff;overflow:hidden}
.acct-who{display:flex;align-items:center;gap:12px;padding:16px;background:var(--navy);color:#fff}
.acct-avatar{flex:none;width:38px;height:38px;border-radius:50%;background:var(--red);color:#fff;
  display:grid;place-items:center;font-weight:800;font-size:16px}
.acct-who b{display:block;font-size:14px;line-height:1.3}
.acct-who span{display:block;font-size:11.5px;color:#c6d6e4;overflow:hidden;text-overflow:ellipsis;max-width:150px}

.acct-nav{padding:8px}
.acct-link{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;
  font-size:14px;color:var(--text);transition:.12s}
.acct-link:hover{background:var(--alt)}
/* Left bar rather than a fill: the row stays readable and the marker reads as
   "you are here" instead of as a button waiting to be pressed. */
.acct-link.is-on{background:#fff5f5;color:var(--red-d);font-weight:700;box-shadow:inset 3px 0 0 var(--red)}
.acct-ico{width:18px;text-align:center;font-size:14px}
.acct-link em{margin-left:auto;font-style:normal;font-size:11.5px;font-weight:700;
  background:var(--alt);color:var(--muted);border-radius:20px;padding:2px 8px}
.acct-link.is-on em{background:var(--red);color:#fff}

.acct-out{border-top:1px solid var(--line);padding:10px}
.acct-out button{width:100%;background:none;border:1px solid var(--line);border-radius:8px;
  padding:9px;font:inherit;font-size:13.5px;color:var(--muted);cursor:pointer}
.acct-out button:hover{border-color:var(--red);color:var(--red-d)}

/* ---- main column ---- */
.acct-main{min-width:0;display:grid;gap:18px}
.acct-head{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;flex-wrap:wrap}
.acct-head h1{font-size:23px;color:var(--navy);letter-spacing:-.02em}
.acct-head p{font-size:13.5px;color:var(--muted);margin-top:3px}

/* .acct-card, NOT .card. A product card and an account panel are different
   things, and both were called .card — so this later definition won on equal
   specificity and gave every product card 20px of padding it was not designed
   around, a 12px radius instead of 10px, and made every static account panel
   lift on hover from .card:hover above. */
.acct-card{border:1px solid var(--line);border-radius:12px;background:#fff;padding:20px}
.acct-card > h2{font-size:15px;color:var(--navy);margin-bottom:14px;display:flex;
  justify-content:space-between;align-items:center;gap:12px}
.acct-card > h2 a{font-size:12.5px;font-weight:600;color:var(--red-d)}
.card-empty{text-align:center;padding:26px 16px;color:var(--muted);font-size:13.5px}
.card-empty b{display:block;color:var(--text);font-size:15px;margin-bottom:6px}

/* ---- the four figures on the dashboard ---- */
.acct-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:14px}
.acct-stat{border:1px solid var(--line);border-radius:12px;background:#fff;padding:14px 16px}
.acct-stat b{display:block;font-size:22px;color:var(--navy);line-height:1.2}
.acct-stat span{font-size:12px;color:var(--muted)}

/* ---- order rows ---- */
.ord{display:flex;align-items:center;gap:14px;padding:13px 0;border-top:1px solid var(--line)}
.ord:first-of-type{border-top:0}
.ord-main{min-width:0;flex:1}
.ord-main b{font-size:14px;color:var(--navy)}
.ord-main span{display:block;font-size:12.5px;color:var(--muted);margin-top:2px}
.ord-right{text-align:right;flex:none;display:grid;gap:5px;justify-items:end}
.ord-right b{font-size:15px}

/* Status pills. Colour carries meaning, but the word is always there too —
   colour alone fails for anyone who cannot distinguish these. */
.pill{display:inline-block;font-size:11px;font-weight:700;letter-spacing:.03em;
  text-transform:uppercase;border-radius:20px;padding:3px 9px}
.pill-ok{background:#e6f6ed;color:var(--green)}
.pill-wait{background:#fff4e0;color:#8a5a00}
.pill-go{background:#e7f2fb;color:#0b5f92}
.pill-off{background:var(--alt);color:var(--muted)}
.pill-bad{background:#fdeeed;color:var(--red-d)}

/* ---- address book ---- */
.addr-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px}
.addr{border:1px solid var(--line);border-radius:12px;padding:16px;background:#fff;position:relative;display:flex;flex-direction:column}
.addr.is-default{border-color:var(--red-soft);background:#fffafa}
.addr-tag{position:absolute;top:12px;right:12px;font-size:10.5px;font-weight:800;letter-spacing:.04em;
  text-transform:uppercase;color:var(--red-d)}
.addr b{font-size:14px;color:var(--navy);display:block;margin-bottom:7px;padding-right:60px}
.addr address{font-style:normal;font-size:13px;color:var(--muted);line-height:1.65;flex:1}
.addr-acts{display:flex;gap:14px;margin-top:13px;padding-top:12px;border-top:1px solid var(--line);font-size:12.5px}
.addr-acts a,.addr-acts button{color:var(--navy);background:none;border:0;padding:0;font:inherit;
  font-size:12.5px;cursor:pointer;text-decoration:underline;text-underline-offset:2px}
.addr-acts .danger{color:var(--red-d);margin-left:auto}

/* ---- forms inside the account ---- */
.acct-form{display:grid;gap:14px;max-width:520px}
.acct-form .two{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.acct-form label{display:block;font-size:12.5px;font-weight:600;color:var(--navy);margin-bottom:5px}
.acct-form input,.acct-form select{width:100%;border:1px solid var(--line);border-radius:8px;
  padding:10px 12px;font:inherit;font-size:14px;background:#fff}
.acct-form input:focus,.acct-form select:focus{outline:2px solid var(--blue);outline-offset:-1px;border-color:var(--blue)}
.acct-form .hint{font-size:12px;color:var(--muted);margin-top:5px}
.acct-form .row-check{display:flex;align-items:center;gap:9px;font-size:13.5px}
.acct-form .row-check input{width:auto}

/* A boxed-off dangerous action, kept visually apart from the ordinary ones. */
.danger-zone{border:1px solid var(--red-soft);border-radius:12px;padding:16px;background:#fffafa}
.danger-zone h3{font-size:14px;color:var(--red-d);margin-bottom:6px}
.danger-zone p{font-size:13px;color:var(--muted);margin-bottom:12px;line-height:1.6}

@media(max-width:900px){
  .acct-grid{grid-template-columns:1fr}
  /* Unpinned on mobile: a sticky sidebar above the content would eat the
     screen on the pages people actually open on a phone. */
  .acct-side{position:static}
  .acct-nav{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr))}
  .acct-form .two{grid-template-columns:1fr}
}

/* ---------- 404 ----------
   Reached by real customers, not just by mistake: this catalogue churns, so a
   product URL outlives the product in search results for weeks. */
.notfound{max-width:620px;margin:0 auto;text-align:center;padding:40px 0 60px}
.notfound-code{font-size:64px;font-weight:800;color:var(--red-soft);line-height:1;letter-spacing:-.04em}
.notfound h1{font-size:28px;color:var(--navy);margin:6px 0 12px}
.notfound .lede{color:var(--muted);font-size:15px;line-height:1.7;margin-bottom:26px}
.notfound-search{display:flex;gap:10px;margin-bottom:22px}
.notfound-search input{flex:1;border:2px solid var(--navy);border-radius:8px;padding:12px 16px;font:inherit;font-size:15px;min-width:0}
.notfound-links{display:flex;gap:10px;justify-content:center;flex-wrap:wrap}
.notfound-links .btn{margin-left:0}
@media(max-width:600px){
  .notfound-search{flex-direction:column}
  .notfound-links{flex-direction:column}
  /* 15px zooms the page on focus in iOS Safari. This box is the main way back
     into the shop from a dead link, so it is the last place to make someone
     fight the keyboard. */
  .notfound-search input{font-size:16px;min-height:44px}
}

/* ---------- cookie consent bar ---------- */
/* Fixed to the bottom rather than a modal: it must not block the page (a
   consent wall that traps the visitor is its own compliance problem), but it
   must be seen before anything optional is set. */
.cookie-bar{position:fixed;left:0;right:0;bottom:0;z-index:120;background:#fff;
  border-top:2px solid var(--navy);box-shadow:0 -8px 28px rgba(10,46,77,.16)}
.cookie-bar-inner{max-width:1320px;margin:0 auto;padding:16px 20px;display:flex;align-items:center;
  gap:24px;flex-wrap:wrap;justify-content:space-between}
.cookie-bar-text{flex:1 1 420px;min-width:0}
.cookie-bar-text b{display:block;color:var(--navy);font-size:15px;margin-bottom:4px}
.cookie-bar-text p{margin:0;font-size:13.5px;line-height:1.6;color:var(--text)}
.cookie-bar-text a{color:var(--red);text-decoration:underline}
/* Both buttons the same size: declining must be no harder than accepting. */
.cookie-bar-actions{display:flex;gap:10px;flex:none;flex-wrap:wrap}
.cookie-bar-actions .btn{padding:12px 22px;font-size:14px;cursor:pointer;font-family:inherit}
.cookie-bar-actions .btn-o{margin-left:0;background:none}
/* Compact on a phone. At full size this bar took 232px — 29% of an iPhone
   screen — and on checkout it sat over the form the shopper was filling in.
   The wording is unchanged (it has to stay honest about what is being asked);
   only the spacing and type size come down, and the two buttons share a row. */
@media(max-width:700px){
  .cookie-bar-inner{padding:12px 14px;gap:10px}
  .cookie-bar-text b{font-size:14px;margin-bottom:2px}
  .cookie-bar-text p{font-size:12.5px;line-height:1.45}
  .cookie-bar-actions{width:100%;gap:8px}
  .cookie-bar-actions .btn{flex:1 1 0;text-align:center;padding:11px 8px;font-size:13px}
}

/* ---------- policy tables (privacy / terms) ---------- */
/* Wrapped in .table-scroll so a wide table scrolls in its own box rather than
   forcing the whole page to scroll sideways on a phone. */
.table-scroll{overflow-x:auto;margin:14px 0 22px;-webkit-overflow-scrolling:touch}
.policy-table{width:100%;border-collapse:collapse;min-width:520px;font-size:14.5px}
.policy-table th,.policy-table td{text-align:left;vertical-align:top;padding:11px 14px;border:1px solid var(--line);line-height:1.6}
.policy-table thead th{background:var(--alt);color:var(--navy);font-size:13px;text-transform:uppercase;letter-spacing:.03em}
.policy-table tbody td:first-child{color:var(--navy);font-weight:600}
.page-body h3{font-size:17px;color:var(--navy);margin:22px 0 8px}
.page-small{font-size:13.5px;color:var(--muted);line-height:1.6;margin-top:22px}

/* ---------- mobile touch targets & legibility (≤768) ----------
   Most sales arrive on a phone, so the controls that take money have to be
   thumb-sized. Measured before changing anything: "Add to basket" came out at
   35px and the brand filter rows at ~18px, against the 44px both Apple and
   Google treat as the minimum comfortable target. Nothing here changes the
   desktop layout — it is all inside the mobile breakpoint. */
@media(max-width:768px){
  /* The primary conversion control on every card. */
  .add{min-height:44px;padding:12px;font-size:14.5px}

  /* Filter rows: the label already wraps its checkbox, so making the ROW tall
     enough turns the whole line into the target rather than the 13px box. */
  .filters label{min-height:44px;margin-bottom:2px;font-size:14.5px;padding:2px 0}
  .filters label input[type=checkbox]{width:20px;height:20px;flex:none}
  .filters .apply{min-height:44px;font-size:14.5px}
  .filters .clear{min-height:44px;display:flex;align-items:center;justify-content:center;font-size:13.5px}
  .filters .money input{min-height:44px;font-size:16px}

  /* 16px on every text input: below that iOS Safari zooms the page on focus,
     which on checkout reads as the form "jumping" mid-typing. */
  input[type=text],input[type=email],input[type=tel],input[type=password],
  input[type=number],input[type=search],select,textarea{font-size:16px}

  /* 11px is too small to read at arm's length on a phone. */
  .brand{font-size:12px}
  .stock{font-size:12.5px}

  /* Breadcrumbs are navigation, not decoration — give them a real target. */
  .crumbs a{display:inline-block;padding:6px 0;min-height:32px}

  /* The sort dropdown and the search submit were the last two under 44. */
  .toolbar select,.listing-top select{min-height:44px}
  .search button{min-height:44px}

  /* ---- checkout: the page that takes the money ----
     .fields input sets 14px, which beats the generic rule above on specificity.
     Under 16px iOS Safari zooms the viewport the moment a field is focused, so
     the form appears to lurch sideways mid-typing — on the one screen where a
     shopper is least willing to forgive it. */
  .fields input,.fields textarea,.fields select{font-size:16px;min-height:44px}
  .fields textarea{min-height:88px}

  /* Delivery choice and the terms tickbox were 13px targets — and terms is
     REQUIRED to place the order, so a missed tap is a lost sale. */
  .fields input[type=radio],.fields input[type=checkbox],
  label input[type=radio],label input[type=checkbox]{width:22px;height:22px;min-height:22px;flex:none}
  /* Any label wrapping a tickbox becomes a full-height row, wherever it lives.
     Scoped to .fields first missed the age/terms confirmation, which sits
     outside it and is the one tick a shopper MUST hit to place the order. */
  label:has(> input[type=radio]),label:has(> input[type=checkbox]){
    min-height:44px;display:flex;align-items:center;gap:10px}

  /* ---- the four inputs the generic 16px rule above does not reach ----
     Each of these sets its own font-size with a class in the selector, which
     outranks the bare `input`/`select` rule on specificity — so they stayed
     under 16px and iOS Safari still zoomed on focus. Listed individually
     rather than by raising the generic rule, because a blanket !important
     would also inflate the deliberately small text inside filter chips. */

  /* The quantity box in the buy panel: 14px. The single most costly one to get
     wrong — the viewport jumps at the exact moment a shopper commits to a
     purchase, and on a phone that reads as the page breaking. */
  .buy .qty input{font-size:16px;min-height:44px}

  /* Sort dropdowns: 13.5px on category/search, 13px on the brand bar. The
     first two already had min-height here; the brand bar is newer and had
     neither, so it needs the height as well as the font size. */
  .toolbar select,.listing-top select,.brand-sort select{font-size:16px}
  .brand-sort select{min-height:44px;padding-top:0;padding-bottom:0}

  /* The address book. Saving an address is how a repeat customer checks out in
     one tap next time, so a form that fights back here costs future orders,
     not just this one. */
  .acct-form input,.acct-form select,.acct-form textarea{font-size:16px;min-height:44px}

  /* ---- tap targets that were still short of 44px ---- */

  /* Pagination: page numbers were 34x34. This is how a shopper reaches product
     30 onwards, and a missed tap lands on the adjacent page number — not on
     nothing, which makes the error silent and the recovery annoying. */
  .pager a,.pager span{min-height:44px;min-width:44px;
    display:inline-flex;align-items:center;justify-content:center;font-size:14.5px}

  /* Sign in / Create account / Send me a code — all 42px, all the last tap of
     their journey. */
  .btn-wide{min-height:44px}

  /* Account sidebar links (39px) and sign out (36px). */
  .acct-link{min-height:44px}
  .acct-out button{min-height:44px;width:100%}

  /* Track order: the page a customer opens when they are already anxious about
     where their parcel is. The number field was 15px (zoom on focus) and the
     button 42px. Full-width button because the two fields stack here anyway. */
  .track-form input{font-size:16px;min-height:44px}
  .track-form .btn{min-height:44px;width:100%;justify-content:center}

  /* ---- the basket: the last screen before checkout ----
     These only appear once the basket has something in it, which is why an
     empty-basket check reads as clean. Every control here is one a shopper
     uses while deciding whether to go through with the order. */

  /* Quantity: 13.5px field, 32px Update button. Mis-tapping Update and hitting
     Remove instead empties a line the shopper meant to keep. */
  .cart-qty input{font-size:16px;min-height:44px}
  .cart-qty button{min-height:44px;font-size:14px}

  /* The ✕ was a 31px target sat right beside the quantity controls. */
  .cart-remove{min-width:44px;min-height:44px;display:inline-flex;
    align-items:center;justify-content:center;padding:0}

  /* Coupon: a 14px field zoomed the page, and a shopper who cannot enter the
     code they were sent has a reason to abandon rather than pay full price. */
  .coupon-row input{font-size:16px;min-height:44px}
  .coupon-row button{min-height:44px;font-size:14.5px}
  .coupon-remove{min-height:44px;min-width:32px}
}

/* A disabled .btn looked identical to a live one — same red fill, same weight —
   so an out-of-stock product appeared to have a working buy button, while the
   sticky bar on the same page correctly said "Out of stock". */
.btn[disabled],.btn:disabled{background:var(--alt);color:var(--muted);border-color:var(--line);
  box-shadow:none;cursor:not-allowed;pointer-events:none}
/* Explains a coupon that stopped applying, in the summary where it vanished. */
.coupon-problem{margin:10px 0 0;font-size:13px;line-height:1.5;color:var(--red-d);
  background:#fdeeee;border:1px solid #f3c9c9;border-radius:8px;padding:9px 12px}

/* Customer-facing return rows on the order page. */
.return-row + .return-row{border-top:1px solid var(--line);margin-top:14px;padding-top:14px}
.return-next{font-size:13.5px;color:var(--muted);line-height:1.6;margin:6px 0 10px}
.return-declined{border:1px solid #f3c9c9;background:#fdeeee;border-radius:8px;padding:12px 14px;margin-top:8px}
.return-declined b{display:block;color:var(--red-d);font-size:13.5px;margin-bottom:4px}
.return-declined p{font-size:13.5px;line-height:1.6;margin:0}

/* ---------- community forum ---------- */
/* Text-first throughout. A forum is read, not looked at, so the styling here is
   about line length and scanning rather than decoration. */
.forum-head{margin:18px 0 20px}
.forum-head h1{font-size:26px;line-height:1.25;margin-bottom:8px}
.forum-head p{color:var(--muted);font-size:14px;line-height:1.65;max-width:70ch}
.forum-head-links{margin-top:8px}
.forum-head-links a{color:var(--blue);font-weight:700}

.forum-boards{display:grid;gap:10px;margin-bottom:32px}
.forum-board{display:grid;grid-template-columns:44px minmax(0,1fr) auto;align-items:center;gap:14px;
  border:1px solid var(--line);border-radius:10px;padding:14px 16px;background:var(--bg)}
.forum-board:hover{border-color:var(--blue);background:var(--alt)}
.forum-board-icon{font-size:24px;text-align:center}
.forum-board-main{min-width:0}
.forum-board-main b{display:block;font-size:15.5px;margin-bottom:2px}
.forum-board-desc{display:block;color:var(--muted);font-size:13px;line-height:1.55}
.forum-board-stats{text-align:center;color:var(--muted);font-size:11.5px;line-height:1.3}
.forum-board-stats b{display:block;color:var(--text);font-size:16px}

.forum-recent{margin-bottom:32px}
.forum-recent h2{font-size:17px;margin-bottom:10px}
.forum-recent-list{list-style:none}
.forum-recent-list li{padding:9px 0;border-bottom:1px solid var(--line)}
.forum-recent-list a{font-weight:700;font-size:14.5px}
.forum-recent-list a:hover{color:var(--blue)}
.forum-recent-meta{display:block;color:var(--muted);font-size:12px;margin-top:2px}

.forum-actions{margin-bottom:16px}
.forum-empty{color:var(--muted);font-size:14px;padding:24px 0}

.forum-threads{list-style:none;border-top:1px solid var(--line)}
.forum-thread-row{display:grid;grid-template-columns:minmax(0,1fr) 80px 150px;gap:14px;align-items:center;
  padding:13px 4px;border-bottom:1px solid var(--line)}
.forum-thread-main{min-width:0}
.forum-thread-main a{font-weight:700;font-size:15px;line-height:1.4}
.forum-thread-main a:hover{color:var(--blue)}
.forum-thread-meta{display:block;color:var(--muted);font-size:12px;margin-top:3px}
.forum-pin{margin-right:4px}
.forum-locked{color:var(--red-d);font-weight:700}
.forum-thread-stats{text-align:center;color:var(--muted);font-size:11.5px;line-height:1.3}
.forum-thread-stats b{display:block;color:var(--text);font-size:15px}
.forum-thread-last{color:var(--muted);font-size:12px;line-height:1.4;text-align:right}
.forum-thread-lastby{display:block}

.forum-posts{list-style:none;margin-bottom:8px}
.forum-post{border:1px solid var(--line);border-radius:10px;padding:14px 16px;margin-bottom:12px}
/* A held post is the author's own, shown only to them. Tinted so it reads as
   "not live yet" without needing the label to be read first. */
.forum-post-held{background:#fffaf0;border-color:#f0dcae}
.forum-post-head{display:flex;flex-wrap:wrap;gap:8px;align-items:baseline;
  padding-bottom:9px;margin-bottom:11px;border-bottom:1px solid var(--line)}
.forum-post-author{font-size:14px}
.forum-post-head time{color:var(--muted);font-size:12px}
.forum-post-flag{color:#8a6100;font-size:12px;font-weight:700}
/* max-width in ch, not px: line length is what makes long posts readable, and
   ch tracks the font rather than the viewport. */
.forum-post-body{font-size:14.5px;line-height:1.7;max-width:75ch;overflow-wrap:anywhere}
.forum-post-body p+p{margin-top:11px}
.forum-post-body a{color:var(--blue);text-decoration:underline}

.forum-report{margin-top:11px}
.forum-report summary{color:var(--muted);font-size:12px;cursor:pointer;display:inline-block}
.forum-report summary:hover{color:var(--red-d)}
.forum-report form{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:9px;
  padding:11px;background:var(--alt);border-radius:8px}
.forum-report label{font-size:12.5px;font-weight:700;width:100%}
.forum-report select,.forum-report input{border:1px solid var(--line);border-radius:6px;padding:7px 9px;font-size:13px;font-family:inherit}
.forum-report input{flex:1;min-width:180px}
.forum-report button{background:var(--navy);color:#fff;border:0;border-radius:6px;padding:8px 14px;font-size:13px;font-weight:700;cursor:pointer}

.forum-form,.forum-reply{border:1px solid var(--line);border-radius:10px;padding:18px;margin:8px 0 32px;max-width:75ch}
.forum-reply h2{font-size:17px;margin-bottom:12px}
.forum-form label,.forum-reply label{display:block;font-weight:700;font-size:13.5px;margin-bottom:5px}
.forum-form input[type=text],.forum-form textarea,.forum-reply textarea,.forum-reply input[type=text]{
  width:100%;border:1px solid var(--line);border-radius:8px;padding:10px 12px;
  font-size:14px;font-family:inherit;line-height:1.6;margin-bottom:14px}
.forum-form textarea,.forum-reply textarea{resize:vertical}
.forum-name-field{background:var(--alt);border-radius:8px;padding:13px;margin-bottom:16px}
.forum-name-field p{color:var(--muted);font-size:12.5px;line-height:1.6;margin-bottom:9px}
.forum-signin{border:1px solid var(--line);border-radius:10px;padding:16px;font-size:14px;line-height:1.65;color:var(--muted);margin-bottom:32px}
.forum-signin a{color:var(--blue);font-weight:700}

/* The honeypot. Off-screen rather than display:none, because a bot that reads
   computed styles skips anything hidden outright but happily fills this. */
.forum-hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

@media(max-width:760px){
  /* Reply counts and "last post" are the first things to go: on a phone the
     title is what people tap, and three columns squeeze it to two words. */
  .forum-thread-row{grid-template-columns:minmax(0,1fr) auto}
  .forum-thread-last{display:none}
  .forum-board{grid-template-columns:32px minmax(0,1fr) auto;gap:10px;padding:12px}
  .forum-board-icon{font-size:19px}
  .forum-head h1{font-size:22px}
}

@media(max-width:600px){
  /* 16px stops iOS zooming the page on focus; 44px is the tap-target floor. */
  .forum-form input[type=text],.forum-form textarea,
  .forum-reply textarea,.forum-reply input[type=text],
  .forum-report select,.forum-report input{font-size:16px}
  .forum-form input[type=text],.forum-reply input[type=text],.forum-report select,.forum-report input{min-height:44px}
  .forum-form button,.forum-reply button,.forum-report button{min-height:44px}
  .forum-report summary{min-height:44px;display:inline-flex;align-items:center}
  .forum-form,.forum-reply{padding:14px}
  .forum-post{padding:12px 13px}
  .forum-board-desc{display:none}
}
