/* ==========================================================================
   PL Keys storefront design system
   Dark near-black chrome around a clean white catalog, one loud orange
   action color, bold condensed headings over a humanist sans body.
   Palette and type mirror the reference trade-store look without copying
   any of its code or assets.
   ========================================================================== */

:root {
  /* ======================================================================
     Theme tokens.
     Every one of these is settable from Settings > Theme, and every one of
     them is READ by a selector below. That second half is the rule: a token
     nothing reads is a control that does nothing, which is worse than a
     missing control because it looks like it works.

     `bin/console theme:check` compares each default here against the default
     declared in Ds\Store\Theme and fails on any drift, so the two cannot
     quietly disagree.
     ====================================================================== */

  /* ---- general ------------------------------------------------------- */
  --ink: #0e1014;
  --ink-2: #121212;
  --body: #333333;
  --muted: #5e5e5e;
  --line: #dddddd;
  --bg: #ffffff;
  --bg-soft: #f5f5f5;
  --wash:#f6f6f6;              /* tinted panel behind spec tables and identikey hits */

  /* ---- accent -------------------------------------------------------- */
  --cta: #fa4616;
  --cta-dark: #d93a0f;

  /* ---- status -------------------------------------------------------- */
  --sale: #cc1313;
  --stock-ok: #268c0b;
  /* Gold, not the CTA colour. The layout used to write --cta into --star as
     well, so an orange button forced orange stars and a gold star was not
     expressible. They are independent tokens. */
  --star: #f5a623;

  /* ---- buttons ------------------------------------------------------- */
  --btn-text: #ffffff;
  --btn-dark-bg: #0e1014;
  --btn-dark-hover: #000000;
  --btn-radius: 3px;

  /* ---- logo ---------------------------------------------------------- */
  --logo-height: 34px;

  /* ---- header -------------------------------------------------------- */
  --header-bg: #0e1014;
  --header-text: #ffffff;
  --logo-text: #ffffff;
  --logo-accent: #fa4616;
  --announce-bg: #121212;
  --announce-text: #ffffff;

  /* ---- inputs -------------------------------------------------------- */
  --input-bg: #ffffff;
  --input-border: #dddddd;
  --search-border: #2c2f36;

  /* ---- footer -------------------------------------------------------- */
  --footer-bg: #121212;
  --footer-text: #cfcfcf;
  --footer-link-hover: #ffffff;
  --footer-line: #262626;

  /* ---- type ---------------------------------------------------------- */
  --font-body: 'Barlow';
  --font-head: 'Archivo Black';
  --font-body-weight: 500;
  --font-head-weight: 400;
  --font-base: 15px;
  --head-transform: none;
  --head-tracking: 0.2px;
  --btn-transform: uppercase;
  --btn-tracking: 2px;
  --btn-size: 13px;

  /* ---- layout -------------------------------------------------------- */
  --maxw: 1400px;
  --radius: 3px;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
/* Guard, not a cure: the overflow causes are fixed at source above. `clip`
   rather than `hidden` because `overflow: hidden` on body breaks the sticky
   header. */
html, body { overflow-x: clip; max-width: 100%; }
@supports not (overflow: clip) {
  body { overflow-x: hidden; }
}
body {
  margin: 0;
  font-family: var(--font-body), 'Segoe UI', Arial, sans-serif;
  font-weight: var(--font-body-weight);
  font-size: var(--font-base);
  color: var(--body);
  background: var(--bg);
  line-height: 1.55;
}
img { max-width: 100%; display: block; }
a { color: inherit; }
h1, h2, h3, .display {
  font-family: var(--font-head), 'Arial Black', Impact, sans-serif;
  font-weight: var(--font-head-weight);
  color: var(--ink);
  letter-spacing: var(--head-tracking);
  text-transform: var(--head-transform);
  line-height: 1.15;
}
.container {
  max-width: var(--maxw); margin: 0 auto;
  /* Gutter grows with the viewport instead of staying at a flat 20px,
     which read as cramped on a phone and mean on a wide screen. */
  padding-inline: clamp(16px, 4vw, 40px);
}
.visually-hidden { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); }
.u-muted { color: var(--muted); }
/* Used by checkout and the account pages. It existed in admin.css and never
   here, so those lines rendered at full size on the storefront. */
.u-small { font-size: 12.5px; }
.u-right { text-align: right; }
.u-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }

/* ---- buttons ----------------------------------------------------------- */
.btn {
  display: inline-block;
  background: var(--cta);
  color: var(--btn-text);
  border: none;
  border-radius: var(--btn-radius);
  padding: 12px 26px;
  font-family: var(--font-body), sans-serif;
  font-size: var(--btn-size);
  font-weight: 500;
  letter-spacing: var(--btn-tracking);
  text-transform: var(--btn-transform);
  cursor: pointer;
  text-decoration: none;
  transition: background .15s ease;
}
.btn:hover { background: var(--cta-dark); }
.btn-dark { background: var(--btn-dark-bg); }
.btn-dark:hover { background: var(--btn-dark-hover); }
.btn-outline { background: transparent; color: var(--ink); border: 1px solid var(--ink); }

/* A submit button that has to read as a link: used where an action must post a
   token but sits in running text, such as removing a cart line. */
.link-btn {
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; font-size: 12.5px; color: var(--sale);
  cursor: pointer; text-decoration: none;
}
.link-btn:hover { text-decoration: underline; }
.btn[disabled] { opacity:.5; cursor:not-allowed; }
/* A smaller button. admin.css had this and the storefront never did, so every
   .btn-sm on the shop side rendered at full size -- including the no-JavaScript
   Apply button on the sort control. */
.btn-sm { padding:8px 14px; font-size:12px; letter-spacing:1px; }

/* Form field grouping, used by the review form and the account pages. Same
   name and same shape as the admin's, because a shopper filling in a form and
   an operator filling in a form want the same thing. */
.field { margin-bottom:14px; }
.field > label {
  display:block; font-size:12px; letter-spacing:1.2px; text-transform:uppercase;
  color:var(--muted); margin-bottom:6px;
}
.field input[type=text], .field input[type=email], .field input[type=url],
.field input[type=tel], .field input[type=number], .field select, .field textarea {
  width:100%; padding:11px 12px; font:inherit; font-size:15px; color:var(--body);
  border:1px solid var(--input-border); border-radius:var(--radius); background:var(--input-bg);
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline:none; border-color:var(--ink); box-shadow:0 0 0 3px rgba(14,16,20,.07);
}
.field-help { font-size:12.5px; color:var(--muted); margin-top:5px; }

/* A single breadcrumb link. The plural .crumbs container already existed but
   the item class it wraps did not. */
.crumb { color:var(--muted); text-decoration:none; }
.crumb:hover { color:var(--cta); }

/* The separator dot used in the product meta line. */
.dot { color:var(--line); margin:0 7px; }

.search-flydown {
  position:absolute; top:calc(100% + 6px); left:0; right:0;
  background:#fff; color:var(--ink); border-radius:var(--radius);
  box-shadow:0 14px 40px rgba(0,0,0,.28);
  overflow:hidden; display:none; text-align:left;
}
.search-flydown.open { display:block; }
.sf-group-label {
  font-size:11px; letter-spacing:1.6px; text-transform:uppercase;
  color:var(--muted); padding:10px 14px 4px;
}
.sf-item {
  display:flex; gap:12px; align-items:center;
  padding:8px 14px; text-decoration:none;
}
.sf-item:hover { background:var(--bg-soft); }
.sf-item img { width:42px; height:42px; object-fit:cover; border-radius:3px; flex-shrink:0; }
.sf-item .t { font-size:13.5px; color:var(--ink); line-height:1.3; }
.sf-item .p { font-size:13px; font-weight:700; }
.sf-empty { padding:14px; color:var(--muted); font-size:13.5px; }



/* ---- hero ------------------------------------------------------------------ */
.hero { position:relative; overflow:hidden; background:var(--ink); }
.hero-slide {
  min-height:380px; display:none; position:relative;
  background-size:cover; background-position:center;
  align-items:center;
}
.hero-slide.active { display:flex; }
.hero-slide::after { content:''; position:absolute; inset:0; background:linear-gradient(90deg, rgba(14,16,20,.82) 0%, rgba(14,16,20,.25) 70%); }
.hero-copy {
  position:relative; z-index:2; color:#fff; max-width:640px; padding:56px 24px;
}
.hero-copy .kicker { font-size:13px; letter-spacing:3px; text-transform:uppercase; color:var(--cta); font-weight:700; }
.hero-copy h2 { color:#fff; font-size:clamp(28px, 4.6vw, 46px); margin:10px 0 14px; }
.hero-copy p { font-size:16px; color:#e8e8e8; margin-bottom:22px; }
.hero-dots { position:absolute; bottom:16px; right:22px; display:flex; gap:8px; z-index:3; }
.hero-dots button { width:10px; height:10px; border-radius:50%; border:none; background:rgba(255,255,255,.45); cursor:pointer; }
.hero-dots button.active { background:var(--cta); }

/* ---- highlights strip ------------------------------------------------------- */
.highlights { border-bottom:1px solid var(--line); background:#fff; }
.highlights-inner { display:grid; grid-template-columns:repeat(auto-fit, minmax(210px,1fr)); }
.highlight {
  display:flex; align-items:center; gap:14px; padding:18px 22px;
  border-left:1px solid var(--line); text-decoration:none;
}
.highlight:first-child { border-left:none; }
.highlight svg { width:30px; height:30px; stroke:var(--cta); flex-shrink:0; }
.highlight b { display:block; color:var(--ink); font-size:14.5px; letter-spacing:.3px; }
.highlight small { color:var(--muted); font-size:12.5px; }

/* ---- section headers + product rails ---------------------------------------- */
.section { padding-block: 34px 8px; }  /* padding-block, not padding: as a
   plain `padding` here resets the horizontal padding `.container` sets,
   and every <section class="section container"> lost its side gutters. */
.section-head { display:flex; align-items:baseline; justify-content:space-between; margin-bottom:18px; gap:14px; }
.section-head h2 { font-size:clamp(20px,2.6vw,27px); margin:0; }
.section-head .see-all { font-size:13px; letter-spacing:1.6px; text-transform:uppercase; font-weight:700; color:var(--muted); text-decoration:none; }
.section-head .see-all:hover { color:var(--cta); }


/* circles rail (top sellers) */
.circles { display:grid; grid-template-columns:repeat(auto-fit,minmax(120px,1fr)); gap:22px; }
.circle-cat { text-align:center; text-decoration:none; }
.circle-cat img {
  width:128px; height:128px; border-radius:50%; object-fit:cover; margin:0 auto 10px;
  border:3px solid var(--ink); transition:border-color .15s;
}
.circle-cat:hover img { border-color:var(--cta); }
.circle-cat span { display:block; font-weight:700; color:var(--ink); font-size:13.5px; letter-spacing:.4px; }

/* category tiles */
.cat-tiles { display:grid; grid-template-columns:repeat(auto-fill,minmax(200px,1fr)); gap:16px; }
.cat-tile { position:relative; border-radius:var(--radius); overflow:hidden; aspect-ratio:4/3; background:var(--ink-2); text-decoration:none; display:block; }
.cat-tile img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; opacity:.72; transition:transform .4s ease, opacity .2s; }
.cat-tile:hover img { transform:scale(1.05); opacity:.85; }
.cat-tile span {
  position:absolute; left:14px; bottom:12px; z-index:2;
  color:#fff; font-weight:700; font-size:15px; letter-spacing:1px; text-transform:uppercase;
  text-shadow:0 1px 8px rgba(0,0,0,.65);
}

/* testimonials */
.testimonials { background:var(--bg-soft); padding:38px 0; }
.testi-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:18px; }
.testi { background:#fff; border-radius:var(--radius); padding:20px 22px; border:1px solid #eee; }
.stars { color:var(--star); font-size:14px; letter-spacing:2px; }
/* The half-star: an outlined glyph filled from the left, so the rail can show
   4.5 without depending on a half-star character that renders as a box on half
   the platforms that matter. */
.star-half {
  position: relative; display: inline-block; color: transparent;
  background: linear-gradient(90deg, var(--star) 50%, #d9d9d9 50%);
  -webkit-background-clip: text; background-clip: text;
}
.testi p { font-size:14px; color:var(--body); margin:8px 0 0; }
.testi b { display:block; margin-top:10px; color:var(--ink); font-size:13px; }

/* newsletter */
.newsletter { background:var(--ink); color:#fff; padding:40px 0; }
.newsletter-inner { display:flex; flex-wrap:wrap; gap:24px; align-items:center; justify-content:space-between; }
.newsletter h3 { color:#fff; margin:0 0 4px; font-size:20px; }
.newsletter p { margin:0; color:#c9c9c9; font-size:14px; }
.newsletter form { display:flex; gap:0; flex-grow:1; max-width:480px; min-width:min(280px, 100%); }
.newsletter input {
  flex:1; padding:12px 14px; border:none; border-radius:var(--radius) 0 0 var(--radius);
  font-size:14px; font-family:var(--font-body);
}
.newsletter button { border-radius:0 var(--radius) var(--radius) 0; }


/* ---- ATC banner --------------------------------------------------------------- */
.atc-banner {
  position:fixed; top:0; left:0; right:0; z-index:90;
  background:#fff; box-shadow:0 8px 30px rgba(0,0,0,.18);
  transform:translateY(-110%); transition:transform .25s ease;
}
.atc-banner.show { transform:none; }
.atc-inner { display:flex; align-items:center; gap:16px; padding:12px 20px; max-width:var(--maxw); margin:0 auto; flex-wrap:wrap; }
.atc-inner img { width:54px; height:54px; object-fit:cover; border-radius:4px; }
.atc-info { flex:1; min-width:0; }
.atc-info b { color:var(--ink); font-size:14px; display:-webkit-box; -webkit-line-clamp:1; -webkit-box-orient:vertical; overflow:hidden; }
.ship-meter { flex-basis:100%; }
.ship-track { height:8px; background:#eee; border-radius:4px; overflow:hidden; }
.ship-fill { height:100%; background:var(--stock-ok); width:0; transition:width .4s ease; }
.ship-note { font-size:12.5px; color:var(--muted); margin-top:4px; }
.atc-actions { display:flex; gap:10px; }
/* The banner buttons carry an icon, so they have to be flex rows. Scoped here
   rather than put on .btn, which is inline-block on hundreds of controls and
   would shift text across the whole site. It also makes the narrow-screen rule
   below work: it already asks for justify-content, which an inline-block
   ignores. */
.atc-actions .btn { display: inline-flex; align-items: center; justify-content: center; }
.atc-actions .btn svg { flex: none; margin-right: 8px; }
.atc-close { background:none;border:none;font-size:22px;cursor:pointer;color:#888; }

/* ---- breadcrumbs + PDP ---------------------------------------------------------- */
.crumbs { font-size:12.5px; color:var(--muted); margin:16px 0 14px; }
.crumbs a { color:var(--muted); text-decoration:none; }
.crumbs a:hover { color:var(--cta); }
/* The label column is a <th> now that the table is built from derived facts
   rather than a flat list -- it is a header for its row, and screen readers
   announce it as one. The existing td rules stay so nothing else that uses this
   class changes appearance. */
.spec-table { width:100%; max-width:560px; border-collapse:collapse; font-size:14px; }
.spec-table td, .spec-table th { border:1px solid var(--line); padding:7px 11px; text-align:left; vertical-align:top; }
.spec-table td:first-child, .spec-table th { color:var(--muted); width:42%; font-weight:600; }
.spec-table td { color:var(--body); width:auto; font-weight:400; }

.section-sub { margin:4px 0 0; font-size:13.5px; color:var(--muted); }

/* ---- collection / listing --------------------------------------------------------- */
.listing { display:grid; grid-template-columns:240px 1fr; gap:32px; align-items:start; }
.filters h3 { font-size:13px; letter-spacing:1.6px; text-transform:uppercase; margin:0 0 10px; }
.filter-group { border-bottom:1px solid var(--line); padding:14px 0; }
.filter-group summary { cursor:pointer; font-weight:700; color:var(--ink); font-size:13.5px; list-style:none; display:flex; justify-content:space-between; }
.filter-group summary::-webkit-details-marker { display:none; }
.filter-group summary::after { content:'+'; color:var(--muted); }
.filter-group[open] summary::after { content:'-'; }
.filter-opts { padding-top:10px; display:flex; flex-direction:column; gap:6px; font-size:13.5px; }
.filter-opts a { text-decoration:none; color:var(--body); }
.filter-opts a.on, .filter-opts a:hover { color:var(--cta); font-weight:600; }
.result-count { font-size:13.5px; color:var(--muted); }
.view-toggle { display:flex; border:1px solid var(--line); border-radius:var(--radius); overflow:hidden; }
.view-toggle button { background:#fff; border:none; padding:8px 12px; cursor:pointer; font-size:13px; color:var(--muted); }
.view-toggle button.on { background:var(--ink); color:#fff; }
.pagination { display:flex; gap:6px; margin:30px 0 10px; flex-wrap:wrap; }
.pagination a, .pagination span {
  min-width:38px; text-align:center; padding:8px 10px; border:1px solid var(--line);
  border-radius:var(--radius); font-size:13.5px; text-decoration:none; color:var(--ink);
}
.pagination .cur { background:var(--ink); color:#fff; border-color:var(--ink); }
.pagination a:hover { border-color:var(--ink); }
.list-view .grid-products { grid-template-columns:1fr; }
.list-view .card { flex-direction:row; align-items:stretch; }
.list-view .card-media { width:220px; aspect-ratio:auto; }
.list-view .card-body { flex:1; }
.empty-state { text-align:center; padding:60px 0; color:var(--muted); }

/* ---- static pages --------------------------------------------------------------- */
.page-body { max-width:860px; }
.page-body h1 { font-size:clamp(24px,3vw,32px); margin:18px 0 18px; }
.page-body h2 { font-size:19px; margin:26px 0 10px; }
.page-body p, .page-body li { font-size:15px; }
.page-body .faq details { border:1px solid var(--line); border-radius:var(--radius); padding:14px 18px; margin:10px 0; background:#fff; }
.page-body .faq summary { font-weight:700; color:var(--ink); cursor:pointer; font-size:15px; }
.page-body .faq p { margin:10px 0 0; }

/* flash */
.flash-msg {
  background:#eef7ee; border-left:4px solid var(--stock-ok);
  padding:12px 16px; border-radius:var(--radius); margin:14px 0; font-size:14px;
}
.err-msg { background:#fdecea; border-left:4px solid var(--sale); }

@media (max-width: 900px) {
  /* The chrome's own 900px rules live with the chrome at the foot of this
     file; what is left here is page layout. */
  .pdp { grid-template-columns:1fr; }
  .listing { grid-template-columns:1fr; }
  .filters { border:1px solid var(--line); border-radius:var(--radius); padding:6px 16px 10px; }
  .hero-slide { min-height:300px; }
}

/* ==========================================================================
   Customer accounts
   Sign in, sign up, order history, saved addresses. Kept in the storefront
   sheet rather than inline in the views, so the six account pages cannot
   drift apart the way the admin views did.
   ========================================================================== */

/* --- the narrow, centred auth pages (sign in / create account) --- */
.auth-wrap { max-width:430px; margin:44px auto 60px; padding:0 20px; }
.auth-wrap h1 { font-size:26px; margin:0 0 6px; }
.auth-lede { color:var(--muted); font-size:14.5px; margin:0 0 22px; }
.auth-card {
  border:1px solid var(--line); border-radius:var(--radius);
  padding:26px 24px; background:#fff;
}
.auth-alt { text-align:center; font-size:14px; color:var(--muted); margin-top:18px; }
.auth-alt a { color:var(--ink); font-weight:700; }

/* --- forms, shared by every account page --- */
.form-field { margin-bottom:16px; }
.form-field label {
  display:block; font-size:12px; font-weight:700; letter-spacing:.6px;
  text-transform:uppercase; color:var(--muted); margin-bottom:6px;
}
.form-field input[type=text], .form-field input[type=email],
.form-field input[type=password], .form-field input[type=tel],
.form-field select, .form-field textarea {
  width:100%; padding:11px 12px; font:inherit; font-size:15px; color:var(--body);
  border:1px solid var(--input-border); border-radius:var(--radius); background:var(--input-bg);
}
.form-field input:focus, .form-field select:focus, .form-field textarea:focus {
  outline:none; border-color:var(--ink); box-shadow:0 0 0 3px rgba(14,16,20,.07);
}
.form-field .hint { font-size:12.5px; color:var(--muted); margin-top:5px; }
.form-row { display:flex; gap:14px; }
.form-row > * { flex:1; min-width:0; }
.form-check { display:flex; align-items:flex-start; gap:9px; font-size:14px; margin-bottom:16px; }
.form-check input { margin-top:2px; flex:none; }
.btn-full { width:100%; justify-content:center; text-align:center; }

/* --- the signed-in shell --- */
.acct { display:grid; grid-template-columns:210px 1fr; gap:34px; align-items:start; }
.acct-nav { list-style:none; margin:0; padding:0; border:1px solid var(--line); border-radius:var(--radius); overflow:hidden; }
.acct-nav a {
  display:block; padding:12px 15px; font-size:14px; font-weight:600;
  color:var(--body); text-decoration:none; border-bottom:1px solid #eee;
}
.acct-nav li:last-child a { border-bottom:0; }
.acct-nav a:hover { background:var(--bg-soft); color:var(--ink); }
.acct-nav a.on { background:var(--ink); color:#fff; }
.acct-nav form { margin:0; border-top:1px solid #eee; }
.acct-nav button {
  width:100%; text-align:left; padding:12px 15px; font:inherit; font-size:14px;
  font-weight:600; color:var(--muted); background:none; border:0; cursor:pointer;
}
.acct-nav button:hover { background:var(--bg-soft); color:var(--sale); }

.acct-card {
  border:1px solid var(--line); border-radius:var(--radius);
  padding:22px 24px; background:#fff; margin-bottom:20px;
}
.acct-card h2 { font-size:17px; margin:0 0 4px; }
.acct-card .sub { font-size:13.5px; color:var(--muted); margin:0 0 16px; }
.acct-card.flush { padding:0; }
.acct-card.flush > h2 { padding:20px 24px 0; }

.acct-stats { display:flex; gap:14px; flex-wrap:wrap; margin-bottom:20px; }
.acct-stat {
  flex:1; min-width:min(150px, 100%); border:1px solid var(--line); border-radius:var(--radius);
  padding:16px 18px; background:#fff;
}
.acct-stat b { display:block; font-size:24px; line-height:1.15; color:var(--ink); }
.acct-stat span { font-size:12px; letter-spacing:.6px; text-transform:uppercase; color:var(--muted); }

/* --- order history --- */
.order-list { width:100%; border-collapse:collapse; font-size:14.5px; }
.order-list th {
  text-align:left; font-size:11.5px; letter-spacing:.7px; text-transform:uppercase;
  color:var(--muted); padding:12px 24px; border-bottom:1px solid var(--line); font-weight:700;
}
.order-list td { padding:14px 24px; border-bottom:1px solid #eee; vertical-align:top; }
.order-list tr:last-child td { border-bottom:0; }
.order-list a { color:var(--ink); font-weight:700; }
.order-list .right { text-align:right; }

.status-pill {
  display:inline-block; font-size:11px; font-weight:700; letter-spacing:.6px;
  text-transform:uppercase; padding:3px 9px; border-radius:20px;
  background:var(--bg-soft); color:var(--muted); white-space:nowrap;
}
.status-pill.ok      { background:#eaf6e7; color:#1d6b13; }
.status-pill.wait    { background:#fff5e5; color:#a5620a; }
.status-pill.go      { background:#e8f1fd; color:#14509b; }
.status-pill.stop    { background:#fdecea; color:#a51c10; }

.order-lines { width:100%; border-collapse:collapse; font-size:14px; }
.order-lines td { padding:12px 24px; border-bottom:1px solid #eee; vertical-align:middle; }
.order-lines img { width:52px; height:52px; object-fit:contain; background:var(--bg-soft); border-radius:var(--radius); }
.order-lines .right { text-align:right; white-space:nowrap; }
.order-total td { border-bottom:0; padding-top:8px; padding-bottom:4px; }
.order-total .right { font-weight:700; }

/* --- addresses --- */
.addr-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(255px,1fr)); gap:16px; }
.addr-card {
  border:1px solid var(--line); border-radius:var(--radius); padding:16px 18px;
  font-size:14px; line-height:1.55; background:#fff; position:relative;
}
.addr-card.is-default { border-color:var(--ink); }
.addr-card .tag {
  display:inline-block; font-size:10.5px; font-weight:700; letter-spacing:.7px;
  text-transform:uppercase; background:var(--ink); color:#fff;
  padding:2px 7px; border-radius:2px; margin-bottom:8px;
}
.addr-card .acts { margin-top:12px; display:flex; gap:12px; flex-wrap:wrap; }
.addr-card .acts button, .addr-card .acts a {
  font:inherit; font-size:13px; font-weight:600; background:none; border:0;
  padding:0; cursor:pointer; color:var(--muted); text-decoration:underline;
}
.addr-card .acts .danger { color:var(--sale); }

@media (max-width: 780px) {
  .acct { grid-template-columns:1fr; gap:22px; }
  .acct-nav { display:flex; flex-wrap:wrap; }
  .acct-nav li { flex:1; min-width:min(120px, 100%); }
  .acct-nav a { border-bottom:1px solid #eee; text-align:center; }
  .form-row { flex-direction:column; gap:0; }
  .order-list th, .order-list td, .order-lines td { padding-left:14px; padding-right:14px; }
}


.pager { display:flex; gap:6px; align-items:center; justify-content:center; flex-wrap:wrap; margin:34px 0 0; }
.pager a, .pager .cur { min-width:38px; padding:9px 12px; text-align:center; text-decoration:none; border:1px solid var(--line); border-radius:var(--radius); font-size:13.5px; }
.pager a { color:var(--body); }
.pager a:hover { border-color:var(--ink); color:var(--ink); }
.pager .cur { background:var(--ink); color:#fff; border-color:var(--ink); font-weight:700; }
.pager .pager-gap { color:var(--muted); padding:0 2px; border:0; }
.pager-step { font-weight:600; }

.empty-results { text-align:center; padding:52px 20px; }
.empty-results h2 { margin:0 0 8px; }
.empty-results p { color:var(--muted); margin:0 0 16px; }

.collection-intro { max-width:70ch; color:var(--muted); font-size:14.5px; margin:6px 0 0; }

.search-again { display:flex; gap:8px; max-width:620px; margin:14px 0 26px; }
.search-again input {
  flex:1; padding:12px 14px; font:inherit; font-size:15px;
  border:1px solid var(--input-border); border-radius:var(--radius); background:var(--input-bg);
}

@media (max-width: 900px) {
  .listing { grid-template-columns:1fr; gap:18px; }
  .facets { position:static; }
  /* Two columns of filters on a phone rather than one long list to scroll
     past before reaching a single product. */
  .facet-group ul { display:grid; grid-template-columns:1fr 1fr; gap:0 14px; }
}

/* ---- demand capture ---------------------------------------------------------
   Shown when a product is genuinely unavailable, and on a search that found
   nothing. Both are the last moment before somebody leaves. */
.notify-box { border:1px solid var(--line); border-radius:var(--radius); padding:16px 18px; margin:16px 0; background:var(--bg-soft); }
.notify-box h3 { margin:0 0 4px; font-size:15px; }
.notify-box p { margin:0 0 12px; font-size:13.5px; color:var(--muted); }
.notify-form { display:flex; gap:8px; flex-wrap:wrap; }
.notify-form input[type=email], .source-form input[type=email] {
  flex:1; min-width:min(200px, 100%); padding:11px 12px; font:inherit; font-size:14.5px;
  border:1px solid var(--input-border); border-radius:var(--radius); background:var(--input-bg);
}
.source-form { max-width:520px; margin:0 auto; }
.notify-ok { color:var(--stock-ok); font-weight:600; margin:0; }
.notify-err { color:var(--sale); font-size:13px; margin:0 0 10px; }

/* ---- reviews ----------------------------------------------------------------
   Ours and the supplier's are drawn differently on purpose. The supplier's is a
   muted single line with its provenance stated, because it describes a listing
   somebody else sells -- it is useful, and it is not a review of this product. */
.reviews { padding-bottom:36px; }
.review-summary { display:flex; align-items:center; gap:20px; margin-bottom:6px; }
.review-score { display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; }
.review-score strong { font-size:30px; font-family:var(--font-head), sans-serif; color:var(--ink); }

.supplier-rating {
  font-size:13px; color:var(--muted); margin:4px 0 18px;
  padding:9px 12px; background:var(--bg-soft); border-radius:var(--radius);
  border-left:3px solid var(--line);
}
.supplier-rating .stars { font-size:12.5px; }

.review-list { list-style:none; margin:18px 0 0; padding:0; }
.review { border-top:1px solid var(--line); padding:16px 0; }
.review-head { display:flex; align-items:center; gap:10px; flex-wrap:wrap; font-size:13px; color:var(--muted); }
.review-head strong { color:var(--ink); }
.review h3 { font-size:15px; margin:8px 0 4px; }
.review p { margin:0; font-size:14.5px; }
.verified {
  font-size:11px; letter-spacing:.6px; text-transform:uppercase; font-weight:700;
  color:var(--stock-ok); border:1px solid var(--stock-ok); border-radius:2px; padding:1px 6px;
}
.review-reply { margin-top:10px; padding:10px 14px; background:var(--bg-soft); border-radius:var(--radius); }
.review-reply strong { display:block; font-size:12px; text-transform:uppercase; letter-spacing:1px; color:var(--muted); }

.review-form-card { border:1px solid var(--line); border-radius:var(--radius); padding:18px 20px; margin:18px 0; }
.review-form-head { display:flex; gap:12px; align-items:center; margin-bottom:14px; }
.review-form-head img { width:56px; height:56px; object-fit:cover; border-radius:var(--radius); flex:none; }
.star-pick { border:0; padding:0; margin:0 0 14px; }
.star-pick legend { font-size:12px; letter-spacing:1px; text-transform:uppercase; color:var(--muted); padding:0; }
/* Reversed so five stars reads first, which is where most people start. */
.star-pick label { display:inline-flex; align-items:center; gap:5px; margin-right:14px; font-size:14px; }


/* ---- volume pricing ------------------------------------------------- */
.pdp-tiers{width:100%;border-collapse:collapse;margin:14px 0 4px;font-size:14px}
.pdp-tiers caption{text-align:left;font-family:var(--font-head);font-weight:700;
  font-size:13px;color:var(--ink);padding-bottom:8px;letter-spacing:.02em}
.pdp-tiers th,.pdp-tiers td{border:1px solid var(--line);padding:7px 10px;text-align:center}
.pdp-tiers th{text-align:left;background:var(--wash);font-weight:600;color:var(--muted);
  white-space:nowrap;font-size:13px}
.pdp-tiers td b{color:var(--ink)}
.pdp-tiers td small{display:block;color:var(--cta);font-weight:700;font-size:11px}
.pdp-tiers-note{font-size:12.5px;color:var(--muted);margin:0 0 16px}
.tier-flag{display:inline-block;margin-left:6px;padding:1px 7px;border-radius:3px;
  background:var(--wash);color:var(--cta);font-weight:700;font-size:11px;
  text-transform:uppercase;letter-spacing:.03em}

.u-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}
.line-eta{font-size:12.5px;color:var(--muted);margin-top:3px}
.line-eta-slow{color:var(--warning,#a15c00);font-weight:600}


/* ---- responsive: catalogue grids -------------------------------------------
   Chrome breakpoints live with the chrome, at the foot of this file. What is
   left here is the product grid, which is a different problem. */
@media (max-width: 700px) {
  .grid-products { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .section { padding-block: 26px; }  /* padding-block, never the shorthand: the
     shorthand here undid .container's gutter below 700px, which is the same
     collision as line 343 and is why content once touched the edge at 360. */
}
@media (max-width: 460px) {
  .grid-products { grid-template-columns: 1fr; }
}

/* ---- payment marks -------------------------------------------------------
   Were plain text spans reading "VISA MASTERCARD AMEX DISCOVER". */
.pay-icons { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.pay-icons svg { width: 40px; height: 26px; display: block; }
.pay-icons svg rect { fill: #fff; stroke: var(--line); stroke-width: 1; }
.pay-icons svg text { font-size: 9px; font-weight: 700; fill: #1a1f36; letter-spacing: .5px; }
.pay-icons svg path { fill: none; stroke: #1a1f36; stroke-width: 2; }
.pay-icons svg .mc-l { fill: #eb001b; }
.pay-icons svg .mc-r { fill: #f79e1b; opacity: .85; }

.kf-note h2 { margin: 0 0 8px; font-size: 16px; }
.kf-note p { margin: 0 0 8px; color: var(--body); font-size: 13.5px; line-height: 1.6; max-width: 74ch; }
.kf-note p:last-child { margin-bottom: 0; }


/* ---- overflow discipline --------------------------------------------------
   A flex child defaults to `min-width: auto`, which means long text will widen
   its parent rather than truncate. With 8,128 products whose titles run to 100
   characters and category names to 40, that is the difference between a tidy
   row and a page that scrolls sideways. Every flex child here carries text. */
.card-body, .card-title, .card-price, .card-specs,
.dept-head, .dept-head b, .dept-card li a,
.mega-links a, .mega-links li,
.make-chip, .finder-card,
.highlight, .highlight span, .highlight b, .highlight small,
.band-head, .band-head b,
.masthead, .hsearch,
.atc-info b,
.toolbar, .toolbar-count,
.crumbs, .crumbs a,
.footer-main > div, .footer-cols > div,
.kf-route h2, .kf-route p, .ik-hit-head {
  min-width: 0;
}

/* Long unbroken part numbers (KR55WK49622, 89904-06140) have no break
   opportunity, so they need an explicit one or they set the minimum width of
   whatever holds them. */
.card-title, .dept-card li a, .mega-links a, .crumbs, .kf-eg {
  overflow-wrap: anywhere;
}

/* Wide content scrolls inside its own box rather than the page. */
.spec-table, .pdp-tiers, table {
  display: block; max-width: 100%; overflow-x: auto;
}

/* Media never exceeds its box. */
img, svg, video, iframe { max-width: 100%; }


/* ---- target sizes ---------------------------------------------------------
   Two different standards, applied where each belongs rather than one number
   everywhere:

     WCAG 2.2 SC 2.5.8  24x24 CSS px minimum, any pointer
     touch guideline     44x44, which matters where a finger is the pointer

   So links get a 24px floor generally, and everything inside the mobile
   drawer, plus the whole storefront under 900px where the drawer is the only
   navigation, gets 44px. */
.mega-links a { padding: 7px 8px; min-height: 24px; }
.dept-card li a { padding: 5px 0; min-height: 24px; }
.site-footer a,
.crumbs a,
.footer-cols li a { display: inline-block; min-height: 24px; padding: 3px 0; }
.make-chip { min-height: 36px; }
.mega-cta, .mega-tool { min-height: 24px; }

/* Coarse pointer, or the narrow layouts where the drawer is the navigation. */
@media (pointer: coarse), (max-width: 900px) {
  .drawer-help a,
  .drawer-kids a,
  .dept-card li a,
  .footer-cols li a,
  .site-footer a,
  .acct-nav a,
  .toolbar-sort select,
  .pager a, .pager .cur {
    min-height: 44px;
    display: flex;
    align-items: center;
  }
  .make-chip { min-height: 44px; }
  /* The drawer is the only way to navigate at these widths, so its rows are
     full-width targets rather than text-width ones. */
  .drawer-help a { padding: 10px 2px; }
  .hact { min-width: 44px; min-height: 44px; }
  #megaOpen { min-width: 44px; min-height: 44px; }
}

/* Interactive states must be visible, and focus must never be removed without
   a replacement. Both are Vercel guideline rules and neither was declared. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--cta);
  outline-offset: 2px;
  border-radius: 2px;
}
/* Sticky header must not sit on top of whatever has focus. */
/* The sticky header is the masthead plus the department row, so an
   anchored heading has to clear both or it lands underneath them. */
:target, h1[id], h2[id], h3[id] { scroll-margin-top: 128px; }

/* The last WCAG 2.2 SC 2.5.8 offenders, measured rather than guessed:
   .see-all rendered 20px high, .dept-head 22px, and one anchor 23px wide. */
.see-all {
  display: inline-flex; align-items: center;
  min-height: 24px; padding: 2px 4px; margin: -2px -4px;
}
.dept-head { min-height: 26px; padding: 1px 0; }
.hero-dot { min-width: 24px; min-height: 24px; }
.dept > a, .deptnav-tools a { min-height: 24px; display: inline-flex; align-items: center; }

/* Section heads stack below the tablet breakpoint. Side by side, a three-line
   heading and a two-line subtitle fight for a 360px row. */
@media (max-width: 860px) {
  .section-head {
    flex-direction: column; align-items: flex-start; gap: 4px;
  }
  .section-head .section-sub { margin-top: 0; }
  .section-head .see-all { margin-left: 0; }
}
/* Headings avoid widows, per the Vercel typography rule. */
h1, h2, .section-head h2 { text-wrap: balance; }

/* ===========================================================================
   HOME PAGE
   Philosophy: show the tools, not tiles. Search is the call to action; the
   catalogue is the argument. Nothing here is decoration.
   =========================================================================== */

/* ---- 1. hero ---------------------------------------------------------------
   Two columns: search and the three facts on the left, one real product on the
   right. The previous hero was a tall dark band holding a headline and nothing
   else, which wasted the most valuable screen in the store. */
.hero2 {
  background:
    radial-gradient(1100px 420px at 88% 12%, rgba(250, 70, 22, .16), transparent 62%),
    var(--ink);
  color: #fff;
  border-bottom: 1px solid rgba(255, 255, 255, .09);
}
.hero2-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
  gap: clamp(24px, 4vw, 60px);
  align-items: center;
  padding-block: clamp(32px, 5vw, 64px);
}
.hero2-copy { min-width: 0; }

.hero2-eyebrow {
  display: flex; align-items: center; gap: 9px; margin: 0 0 16px;
  font-size: 11.5px; letter-spacing: 2.2px; text-transform: uppercase;
  font-weight: 700; color: rgba(255, 255, 255, .6);
}
.hero2-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--cta); flex: 0 0 auto; }

.hero2 h1 {
  margin: 0 0 14px; color: #fff;
  font-size: clamp(30px, 4.6vw, 52px); line-height: 1.06; letter-spacing: -.8px;
  text-wrap: balance;
}
.hero2 h1 em { font-style: normal; color: var(--cta); }

.hero2-sub {
  margin: 0 0 26px; max-width: 52ch;
  font-size: clamp(14.5px, 1.4vw, 16.5px); line-height: 1.58;
  color: rgba(255, 255, 255, .72);
}

/* Search: icon inside the field so the whole thing reads as one object. */
.hero2-search {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  background: #fff; border-radius: var(--radius);
  border: 2px solid transparent; padding: 4px 4px 4px 14px;
  max-width: 560px;
}
.hero2-search:focus-within { border-color: var(--cta); }
.hero2-search-ico { width: 18px; height: 18px; stroke: #8a8a8a; fill: none; }
.hero2-search input {
  min-width: 0; border: 0; background: none; font: inherit;
  font-size: 16px;   /* 16px keeps iOS from zooming the page on focus */
  padding: 12px; color: var(--ink);
}
.hero2-search input:focus { outline: none; }
.hero2-search input::placeholder { color: #9a9a9a; }
.hero2-search .btn { min-height: 44px; padding: 11px 22px; font-size: 14.5px; }

.hero2-hints { margin: 14px 0 0; display: flex; flex-wrap: wrap; gap: 8px; font-size: 12.5px; }
.hero2-hints a {
  display: inline-flex; align-items: center; min-height: 28px;
  padding: 3px 11px; border-radius: 999px; text-decoration: none;
  background: rgba(255, 255, 255, .09); color: rgba(255, 255, 255, .88);
  font-variant-numeric: tabular-nums;
}
.hero2-hints a:hover { background: var(--cta); color: #fff; }
.hero2-hints-alt { background: none; border: 1px solid rgba(255, 255, 255, .28); }

.hero2-facts {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px; list-style: none; margin: 30px 0 0; padding: 26px 0 0;
  border-top: 1px solid rgba(255, 255, 255, .13);
}
.hero2-facts li { min-width: 0; }
.hero2-facts strong { display: block; font-size: 15px; color: #fff; margin-bottom: 3px; }
.hero2-facts span { display: block; font-size: 12px; color: rgba(255, 255, 255, .55); line-height: 1.4; }

.hero2-media {
  position: relative; display: block; border-radius: var(--radius);
  background: #fff; overflow: hidden; min-width: 0;
}
.hero2-media img { width: 100%; height: auto; display: block; aspect-ratio: 1/1; object-fit: contain; }
.hero2-media-tag {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding: 12px 16px; background: rgba(14, 16, 20, .9); color: #fff;
  font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.hero2-media-tag b {
  font-size: 10.5px; letter-spacing: 2px; text-transform: uppercase;
  color: var(--cta); font-weight: 700;
}

/* ---- 2. maker marquee ------------------------------------------------------
   A marquee rather than a wrapping list, so however many brands qualify the
   row never breaks. Paused on hover AND on keyboard focus, because a moving
   target you cannot click is worse than a static one. The track is duplicated
   in the markup so the loop has no visible seam. */
/* ---- 2. brand ticker -------------------------------------------------------
   WHITE, not --wash. The manufacturer artwork is opaque on white (see
   tools/build-brand-logos.py for why the white is kept rather than keyed out),
   so on a tinted band every mark sat in a visible white rectangle. On white
   the join disappears and the logos read as if they were cut out, with none of
   the halos a key at 200x100 would leave. The band is defined by rules top and
   bottom instead of by fill. */
.marq {
  background: #fff;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding-block: 16px 20px;
}
.marq-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 12px;
}
.marq-head h2 {
  font-size: 12px; letter-spacing: 2px; text-transform: uppercase;
  font-weight: 700; margin: 0; color: var(--muted);
}
.marq-window {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}
.marq-track {
  display: flex; align-items: center; list-style: none; margin: 0; padding: 0;
  width: max-content; animation: marq 52s linear infinite;
}
.marq-track > li { flex: 0 0 auto; }
.marq-window:hover .marq-track,
.marq-window:focus-within .marq-track,
.marq-window.is-paused .marq-track { animation-play-state: paused; }
@keyframes marq { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* A FIXED cell with the mark capped inside it, never a fixed image height.
   These range from 197x22 to 182x74 after trimming, so a common height would
   render ALIENTECH nine times wider than CGDI and the row would read as a
   ransom note. Capping both axes in one box is what makes a logo row look like
   one row. */
.marq-track a {
  display: grid; place-items: center;
  width: 128px; height: 36px; padding: 0 14px;
  opacity: .88; transition: opacity .15s ease;
}
.marq-track a:hover, .marq-track a:focus-visible { opacity: 1; }
.marq-track img {
  max-width: 100%; max-height: 100%; width: auto; height: auto;
  display: block; object-fit: contain;
}
.marq-word {
  font-size: 13px; font-weight: 700; color: var(--ink);
  letter-spacing: .4px; white-space: nowrap;
}

/* The duplicate pass exists only to hide the loop seam, so it must never be
   reachable by keyboard or read aloud. */
.marq-track > li[aria-hidden="true"] a { pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  /* One line on every device, always. This branch has now been wrong twice:
     first as flex-wrap (every brand shown twice, 600px wall), then as
     overflow-x: auto (a live scrollbar under the strip). Both replaced a
     ticker with a different component.

     It stays a single running line here and only slows down, which keeps the
     strip identical everywhere and still takes the preference seriously: a
     slow drift is not what the setting is there to prevent, and stopping dead
     is what produced both bugs. Pause on hover and on focus still applies. */
  .marq-track { animation-duration: 150s; }
}

/* ---- 3. round category tiles ---- */
.tiles {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: clamp(12px, 2vw, 22px); list-style: none; margin: 0; padding: 0;
}
.tiles > li { min-width: 0; }
.tiles a { display: flex; flex-direction: column; align-items: center; gap: 9px; text-decoration: none; text-align: center; min-width: 0; }
.tiles-media {
  width: 100%; aspect-ratio: 1/1; border-radius: 50%; overflow: hidden;
  background: var(--wash); border: 1px solid var(--line);
  display: grid; place-items: center;
  transition: border-color .16s ease, transform .16s ease;
}
.tiles a:hover .tiles-media { border-color: var(--cta); transform: translateY(-2px); }
.tiles-media img { width: 78%; height: 78%; object-fit: contain; }
.tiles-name { font-size: 13.5px; font-weight: 600; color: var(--ink); line-height: 1.3; min-width: 0; overflow-wrap: anywhere; }
.tiles-n { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
@media (prefers-reduced-motion: reduce) {
  .tiles-media { transition: none; }
  .tiles a:hover .tiles-media { transform: none; }
}

/* ---- 4. feature ---- */
.feat {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: clamp(20px, 4vw, 52px); align-items: center;
  padding: clamp(18px, 3vw, 32px);
  background: var(--wash); border: 1px solid var(--line); border-radius: var(--radius);
}
.feat-media { display: block; background: #fff; border-radius: var(--radius); overflow: hidden; }
.feat-media img { width: 100%; height: auto; display: block; aspect-ratio: 1/1; object-fit: contain; }
.feat-body { min-width: 0; }
.feat-kicker { margin: 0 0 9px; font-size: 11px; letter-spacing: 2px; text-transform: uppercase; font-weight: 700; color: var(--cta); }
.feat-body h2 { margin: 0 0 12px; font-size: clamp(20px, 2.4vw, 28px); line-height: 1.2; text-wrap: balance; }
.feat-body h2 a { color: var(--ink); text-decoration: none; }
.feat-body h2 a:hover { color: var(--cta); }
.feat-blurb { margin: 0 0 18px; color: var(--body); font-size: 14.5px; line-height: 1.6; max-width: 54ch; }
.feat-price { margin: 0 0 20px; display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.feat-price span { font-size: clamp(22px, 2.4vw, 28px); font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.feat-price small { color: var(--muted); font-size: 12.5px; }

/* ---- 5. product rails -----------------------------------------------------
   EXPLICIT columns, not auto-fill. A rail carries 8 items and the grid is 4 or
   2 wide, so 8 always divides evenly. auto-fill resolved to 5 or 6 columns
   against a fixed count of 8, which is what left orphan cells in row two. */
.rail { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(12px, 1.6vw, 20px); }

/* ---- 6. faq ---------------------------------------------------------------
   Rebuilt. The old block was one 900px column, and three things went wrong
   because of it:

     - summary used justify-content: space-between across the full 900px, so
       every chevron sat most of a screen away from the question it belonged
       to and read as unrelated furniture;
     - nothing separated a question from its answer, so an open row ran
       together as a single paragraph;
     - the heading reused .section-head, which is built for product rails with
       a "See all" on the right, and that left the "Full FAQ" link stranded
       alone at the far edge of an otherwise empty line.

   Now: a narrow left rail carries the heading, the standfirst and the link
   together as one piece of typography, and the accordion takes a column narrow
   enough that the chevron lands beside its own question. The answer is marked
   by an accent rule down its left edge, which separates it from the question
   without adding another horizontal line to a list already built from them. */
.section.faq { padding-block: clamp(40px, 5vw, 64px); border-top: 1px solid var(--line); }
.faq-wrap {
  display: grid; grid-template-columns: minmax(0, 280px) minmax(0, 640px);
  gap: clamp(28px, 5vw, 72px); align-items: start;
  /* Capped and centred. Left to fill 1400px the accordion column ran past
     840px, which is what put a chevron half a screen from its own question.
     640px is close to the reading measure the answers already use, so the
     control lands just past the end of the text instead of adrift from it. */
  max-width: 1000px; margin-inline: auto;
}
.faq-eyebrow {
  margin: 0 0 10px; font-size: 11px; letter-spacing: 2px; text-transform: uppercase;
  font-weight: 700; color: var(--cta);
}
.faq-intro h2 { margin: 0 0 12px; font-size: clamp(23px, 2.8vw, 32px); line-height: 1.14; }
.faq-standfirst { margin: 0 0 22px; font-size: 14.5px; line-height: 1.66; color: var(--muted); }
.faq-more {
  display: inline-flex; align-items: center; min-height: 24px; padding-bottom: 3px;
  font-size: 13px; font-weight: 700; color: var(--ink); text-decoration: none;
  border-bottom: 2px solid var(--cta);
}
.faq-more:hover, .faq-more:focus-visible { color: var(--cta); }

/* Rules only between rows, so the list reads as one object rather than six
   floating cards. */
.faq-list { display: grid; border-top: 1px solid var(--line); }
.faq-list details { border-bottom: 1px solid var(--line); }
.faq-list summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: flex-start; justify-content: space-between; gap: 20px;
  padding: 17px 14px; min-height: 44px; border-radius: var(--radius);
  font-size: 15.5px; font-weight: 600; line-height: 1.42; color: var(--ink);
  transition: background .15s ease;
}
/* The tint spans the whole row on hover, so the chevron is visibly part of the
   question rather than a stray control sitting near it. */
.faq-list summary:hover { background: var(--wash); }
.faq-list summary:focus-visible { outline: 2px solid var(--cta); outline-offset: -2px; }
.faq-list summary::-webkit-details-marker { display: none; }
.faq-list summary:hover .faq-q { color: var(--cta); }
.faq-q { flex: 1 1 auto; }
.faq-list .chev {
  flex: 0 0 auto; box-sizing: border-box; width: 24px; height: 24px; padding: 4px;
  margin-top: 1px; border: 1px solid var(--line); border-radius: 50%; color: var(--muted);
  transition: transform .18s ease, color .18s ease, border-color .18s ease;
}
.faq-list details[open] .chev {
  transform: rotate(180deg); color: var(--cta); border-color: var(--cta);
}
.faq-a { padding: 0 14px 20px; }
.faq-a p {
  margin: 0; padding-left: 16px; border-left: 2px solid var(--cta);
  font-size: 14px; line-height: 1.72; color: var(--body); max-width: 68ch;
}
@media (prefers-reduced-motion: reduce) {
  .faq-list .chev, .faq-list summary { transition: none; }
}

/* ---- 8. assurance ---- */
.assurance { margin-top: 46px; background: var(--ink); color: rgba(255, 255, 255, .8); }
.assurance-inner { padding-block: clamp(28px, 4vw, 46px); }
.assurance dl { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(16px, 3vw, 34px); margin: 0 0 24px; }
.assurance dt { font-size: 11px; letter-spacing: 2px; text-transform: uppercase; font-weight: 700; color: var(--cta); margin-bottom: 7px; }
.assurance dd { margin: 0; font-size: 14px; line-height: 1.5; color: #fff; }
.assurance dd a { color: #fff; text-decoration: underline; text-underline-offset: 2px; }
.assurance-note {
  margin: 0; padding-top: 20px; border-top: 1px solid rgba(255, 255, 255, .14);
  font-size: 13px; line-height: 1.6; max-width: 78ch; color: rgba(255, 255, 255, .62);
}
.assurance-note a { color: #fff; }


/* ---- 7b. testimonials -----------------------------------------------------
   Styled, but nothing renders here until an operator enters real quotes. The
   empty state is the absent state on purpose: see the note in home.php. */
.quote-grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(12px, 1.6vw, 20px);
}
.quote {
  display: flex; flex-direction: column; gap: 14px; padding: 24px;
  background: var(--wash); border: 1px solid var(--line); border-radius: var(--radius);
}
.quote-mark { flex: 0 0 auto; color: var(--cta); }
.quote blockquote { margin: 0; flex: 1 1 auto; }
.quote blockquote p { margin: 0; font-size: 15px; line-height: 1.7; color: var(--ink); }
.quote-by {
  margin: 0; font-size: 12.5px; font-weight: 700; letter-spacing: .3px; color: var(--muted);
}
/* A short accent rule instead of an em dash before the name. */
.quote-by::before {
  content: ""; display: block; width: 24px; border-top: 2px solid var(--cta); margin-bottom: 10px;
}

/* ---- home responsive ------------------------------------------------------
   Column counts step so item counts always divide evenly: tiles 6, 4, 3;
   rails 4, 2. Never a partial row. */
@media (max-width: 1100px) {
  .tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .hero2-grid { grid-template-columns: 1fr; }
  .hero2-media { max-width: 460px; }
  .rail { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .feat { grid-template-columns: 1fr; }
  .feat-media img { aspect-ratio: 16/10; }
  .assurance dl { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .faq-wrap { grid-template-columns: 1fr; gap: 26px; }
  .quote-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 680px) {
  .quote-grid { grid-template-columns: 1fr; }
  .faq-list summary { font-size: 15px; gap: 14px; }
  .tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* Three across, still, not stacked. Stacking turned the three facts into
     six lines of prose filling most of a phone screen before any product was
     visible. They are reassurance, not content, so they compress: the
     supporting line under each is dropped and the figure carries it. */
  .hero2-facts {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px; padding-top: 16px; margin-top: 20px;
  }
  .hero2-facts strong { font-size: 13px; margin-bottom: 0; line-height: 1.3; }
  .hero2-facts span { display: none; }
  .hero2-search { grid-template-columns: auto minmax(0, 1fr); padding: 4px 4px 4px 12px; }
  .hero2-search .btn { grid-column: 1 / -1; width: 100%; justify-content: center; margin-top: 4px; }
}
@media (max-width: 420px) {
  .assurance dl { grid-template-columns: 1fr; }
}

/* ==========================================================================
   SITE CHROME
   Header, mega menus, mobile drawer, footer. Rebuilt, not adjusted.

   Uses only existing design tokens, so `bin/console theme:check` stays green.
   Every colour below resolves to one of the 43 custom properties already
   declared in :root and mirrored in Ds\Store\Theme::TOKENS.
   ========================================================================== */

/* ---- shared utilities ---------------------------------------------------- */
.icon-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.ico { display: block; flex: 0 0 auto; fill: currentColor; }

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

/* First tab stop on every page. Off-screen until focused, which is the only
   correct way to do this: display:none removes it from the tab order and makes
   it useless to the people it exists for. */
.skip-link {
  position: absolute; left: 8px; top: -60px; z-index: 200;
  background: var(--cta); color: var(--btn-text);
  padding: 10px 16px; border-radius: var(--radius);
  font-size: 14px; font-weight: 700; text-decoration: none;
  transition: top .15s ease;
}
.skip-link:focus { top: 8px; }

/* One visible focus treatment for the whole of the chrome. Never `outline:
   none` without a replacement: a keyboard user then navigates blind. */
.site-header a:focus-visible,
.site-header button:focus-visible,
.site-footer a:focus-visible,
.site-footer button:focus-visible,
.drawer a:focus-visible,
.drawer button:focus-visible,
.drawer summary:focus-visible {
  outline: 2px solid var(--cta); outline-offset: 2px; border-radius: 2px;
}

/* ---- 1. topbar ----------------------------------------------------------- */
.topbar {
  background: var(--announce-bg); color: var(--announce-text);
  font-size: 12.5px; line-height: 1;
}
.topbar-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; min-height: 36px; padding-block: 6px;
}
.topbar-msg { display: flex; align-items: center; gap: 8px; margin: 0; }
.topbar-msg .ico { color: var(--cta); }
.topbar-links { display: flex; align-items: center; gap: 4px; }
.topbar-links a {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 10px; border-radius: var(--radius);
  color: inherit; text-decoration: none; opacity: .82;
  transition: opacity .15s ease, background-color .15s ease;
}
.topbar-links a:hover { opacity: 1; background: rgba(255, 255, 255, .08); }
.topbar-call { font-weight: 700; opacity: 1 !important; }
.topbar-call .ico { color: var(--cta); }

/* ---- 2. masthead --------------------------------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 60;
  background: var(--header-bg); color: var(--header-text);
}
.masthead {
  display: flex; align-items: center; gap: clamp(10px, 2vw, 22px);
  min-height: 68px; padding-block: 10px;
}

.burger {
  display: none; align-items: center; justify-content: center;
  width: 44px; height: 44px; margin-left: -10px;
  background: none; border: 0; border-radius: var(--radius);
  color: inherit; cursor: pointer;
}
.burger:hover { background: rgba(255, 255, 255, .09); }

.logo {
  display: flex; align-items: center; flex: 0 0 auto; min-width: 0;
  font-family: var(--font-head), sans-serif; font-weight: 700;
  font-size: 21px; letter-spacing: 1px; text-transform: uppercase;
  color: var(--logo-text); text-decoration: none;
}
.logo span { color: var(--logo-accent); }
.logo img { max-height: var(--logo-height, 34px); width: auto; display: block; }

/* THE SEARCH IS THE WIDEST THING ON THE ROW, ON PURPOSE.
   A locksmith arrives holding a key with a code stamped on it. That is a
   search, not a browse, so the field gets the space and the departments get
   the row below. */
.hsearch {
  position: relative; flex: 1 1 auto; min-width: 0; max-width: 660px;
  display: flex; align-items: center;
  background: var(--input-bg); border: 1px solid var(--search-border);
  border-radius: var(--radius);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.hsearch:focus-within {
  border-color: var(--cta); box-shadow: 0 0 0 3px rgba(250, 70, 22, .18);
}
.hsearch-ico { margin: 0 -4px 0 13px; color: var(--muted); }
.hsearch input {
  flex: 1 1 auto; min-width: 0;
  padding: 12px 12px 12px 14px; border: 0; background: none;
  color: var(--ink); font: inherit; font-size: 14.5px;
}
.hsearch input:focus { outline: none; }
.hsearch input::placeholder { color: var(--muted); }
.hsearch-go {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  margin: 4px; padding: 0 18px; min-height: 36px; min-width: 44px;
  background: var(--cta); color: var(--btn-text);
  border: 0; border-radius: var(--radius); cursor: pointer;
  font-family: var(--font-body), sans-serif;
  font-size: var(--btn-size); font-weight: 700;
  letter-spacing: var(--btn-tracking); text-transform: var(--btn-transform);
  transition: background-color .15s ease;
}
.hsearch-go:hover { background: var(--cta-dark); }
.hsearch-go-ico { display: none; }

/* ---- masthead actions ---------------------------------------------------- */
/* flex: 0 0 auto, or the actions shrink below their own content and the cart
   is clipped off the end of the row. Default flex-shrink is 1, which is right
   for the search field beside them and wrong for a fixed group of controls. */
.hactions { display: flex; align-items: center; gap: 2px; margin-left: auto; flex: 0 0 auto; }
.hact {
  display: inline-flex; align-items: center; gap: 9px;
  min-height: 44px; padding: 6px 11px; border-radius: var(--radius);
  color: inherit; text-decoration: none;
  font-size: 12px; line-height: 1.25; font-weight: 600; white-space: nowrap;
  transition: background-color .15s ease;
}
.hact:hover { background: rgba(255, 255, 255, .09); }
.hact b { font-weight: 700; }
.hact .ico { opacity: .9; }

/* The finder is the highest-intent link in the store, so it reads as a button
   rather than as one more icon. */
.hact-key {
  background: rgba(250, 70, 22, .14);
  box-shadow: inset 0 0 0 1px rgba(250, 70, 22, .45);
}
.hact-key .ico { color: var(--cta); opacity: 1; }
.hact-key:hover { background: rgba(250, 70, 22, .24); }

.hact-cart-ico { position: relative; display: block; }
.cart-count {
  position: absolute; top: -7px; right: -9px;
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--cta); color: var(--btn-text);
  font-size: 11px; font-weight: 700; line-height: 18px; text-align: center;
}

/* ---- 3. department nav --------------------------------------------------- */
.deptnav { background: var(--ink-2); border-top: 1px solid rgba(255, 255, 255, .07); }
.deptnav-inner {
  /* The mega panels are pinned to THIS, not to each <li>. A per-item panel
     with a min-width floor cannot stay inside the viewport on the right-hand
     items, which is what used to make the page scroll sideways. */
  position: relative;
  display: flex; align-items: stretch; justify-content: space-between; gap: 16px;
}

/* THE ONE-ROW GUARANTEE, HALF ONE.
   nowrap means wrapping is not available to this row even before JavaScript
   runs. overflow:hidden means a row that is still too long is clipped rather
   than allowed to widen the page; store.js then moves the clipped items into
   the More menu. Clipping is a worse outcome than the More menu and a far
   better one than a second row or a sideways-scrolling page. */
.deptnav-list {
  display: flex; flex-wrap: nowrap; align-items: stretch;
  list-style: none; margin: 0; padding: 0; min-width: 0; overflow: hidden;
}
.dept { flex: 0 0 auto; }
.dept > a {
  display: inline-flex; align-items: center; gap: 6px;
  height: 100%; min-height: 44px; padding: 0 13px;
  color: var(--header-text); text-decoration: none; white-space: nowrap;
  font-size: 12.5px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase;
  transition: background-color .15s ease, color .15s ease;
}
.dept > a:hover,
.dept.has-mega:hover > a,
.dept.has-mega:focus-within > a { background: var(--cta); color: var(--btn-text); }
.dept-caret { opacity: .7; transition: transform .15s ease; }
.dept.has-mega:hover > a .dept-caret,
.dept.has-mega:focus-within > a .dept-caret { transform: rotate(180deg); }

.deptnav-tools { display: flex; align-items: center; flex: 0 0 auto; }
.deptnav-tools a {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 44px; padding: 0 13px;
  color: var(--cta); text-decoration: none; white-space: nowrap;
  font-size: 12.5px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase;
}
.deptnav-tools a:hover { color: var(--btn-text); background: var(--cta); }

/* ---- mega panels --------------------------------------------------------- */
.mega {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 70;
  background: var(--bg); border: 1px solid var(--line); border-top: 2px solid var(--cta);
  border-radius: 0 0 var(--radius) var(--radius);
  box-shadow: 0 18px 40px rgba(0, 0, 0, .16);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  /* Named properties, never `all`: transitioning everything animates layout. */
  transition: opacity .16s ease, transform .16s ease, visibility .16s;
}
.dept.has-mega:hover > .mega,
.dept.has-mega:focus-within > .mega,
.dept.has-mega.is-open > .mega { opacity: 1; visibility: visible; transform: none; }

.mega-inner {
  display: grid; grid-template-columns: minmax(0, 1fr) 268px;
  gap: 28px; padding: 22px 24px 20px;
}
.mega-links ul {
  display: grid; grid-template-columns: repeat(var(--mega-cols, 4), minmax(0, 1fr));
  gap: 1px 22px; list-style: none; margin: 0; padding: 0;
}
.mega-links a {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 6px 8px; border-radius: 3px; text-decoration: none;
  color: var(--body); font-size: 13.5px; line-height: 1.35;
}
.mega-links a:hover { background: var(--wash); color: var(--cta); }
.mega-name { min-width: 0; }
.mega-count {
  flex: 0 0 auto; color: var(--muted); font-size: 11px;
  font-variant-numeric: tabular-nums;
}

/* The right rail is the reason this is a mega panel and not a dropdown. A wall
   of links answers "what do you have". These answer "I am holding a key, now
   what", which is the question that ends in an order. */
.mega-aside {
  display: flex; flex-direction: column; gap: 8px;
  padding-left: 26px; border-left: 1px solid var(--line);
}
.mega-cta {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 15px; border-radius: var(--radius);
  background: var(--ink); color: #fff; text-decoration: none;
  transition: background-color .15s ease;
}
.mega-cta:hover { background: var(--cta); }
.mega-cta b { font-size: 13.5px; }
.mega-cta span { margin-left: auto; font-size: 11.5px; opacity: .7; }
.mega-cta .ico { flex: 0 0 auto; opacity: .8; }
.mega-tool {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 11px 13px; border-radius: var(--radius);
  border: 1px solid var(--line); text-decoration: none;
  transition: border-color .15s ease, background-color .15s ease;
}
.mega-tool:hover { border-color: var(--cta); background: var(--wash); }
.mega-tool .ico { color: var(--cta); margin-top: 1px; }
.mega-tool span { display: block; font-size: 11.5px; color: var(--muted); line-height: 1.4; }
.mega-tool b { display: block; font-size: 13.5px; color: var(--ink); margin-bottom: 1px; }

.dept-more .mega-inner { grid-template-columns: minmax(0, 1fr); }

/* ---- mobile drawer ------------------------------------------------------- */
.drawer { position: fixed; inset: 0; z-index: 100; visibility: hidden; }
.drawer.open { visibility: visible; }
.drawer-scrim {
  position: absolute; inset: 0; background: rgba(14, 16, 20, .55);
  opacity: 0; transition: opacity .2s ease;
}
.drawer.open .drawer-scrim { opacity: 1; }
.drawer-panel {
  position: absolute; inset: 0 auto 0 0;
  width: min(370px, 88vw); background: var(--bg);
  display: flex; flex-direction: column; overflow-y: auto;
  transform: translateX(-100%); transition: transform .22s ease;
  overscroll-behavior: contain;
}
.drawer.open .drawer-panel { transform: none; }
/* DARK, deliberately, and not merely to match the masthead.
   logo.svg is a light-on-dark asset: its "PL" is explicitly white so it can
   sit on the near-black header. On a white drawer head the white half simply
   disappeared and the mark read as "KEYS". The fix is the background, not a
   CSS colour override, because an SVG loaded through <img> is an isolated
   document and cannot inherit colour from this page at all. A light-background
   logo would have to be a second file. */
.drawer-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 14px 16px;
  position: sticky; top: 0; z-index: 2;
  background: var(--header-bg); color: var(--header-text);
}
.drawer-logo {
  display: flex; align-items: center;
  font-family: var(--font-head), sans-serif; font-size: 18px;
  letter-spacing: 1px; text-transform: uppercase;
  color: var(--logo-text); text-decoration: none;
}
.drawer-logo span { color: var(--logo-accent); }
.drawer-logo img { max-height: 30px; width: auto; }
.drawer-close {
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; margin-right: -10px;
  background: none; border: 0; color: inherit; cursor: pointer;
}
.drawer-close:hover { color: var(--cta); }

.drawer-tools { display: grid; gap: 8px; padding: 14px 16px; }
.drawer-tools a {
  display: flex; align-items: center; gap: 12px; min-height: 44px;
  padding: 11px 13px; border: 1px solid var(--line); border-radius: var(--radius);
  text-decoration: none;
}
.drawer-tools .ico { color: var(--cta); }
.drawer-tools span { font-size: 11.5px; color: var(--muted); line-height: 1.4; }
.drawer-tools b { display: block; font-size: 14px; color: var(--ink); }

.drawer-nav { border-top: 1px solid var(--line); }
.drawer-dept { border-bottom: 1px solid var(--line); }
.drawer-dept summary {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 50px; padding: 13px 16px; cursor: pointer; list-style: none;
  font-size: 14.5px; font-weight: 700; color: var(--ink);
}
.drawer-dept summary::-webkit-details-marker { display: none; }
.drawer-caret { color: var(--muted); transition: transform .15s ease; }
.drawer-dept[open] .drawer-caret { transform: rotate(180deg); color: var(--cta); }
.drawer-kids { padding: 0 16px 12px; }
.drawer-kids a {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 40px; padding: 8px 12px; border-radius: 3px;
  color: var(--body); font-size: 13.5px; text-decoration: none;
}
.drawer-kids a:hover { background: var(--wash); color: var(--cta); }
.drawer-kids a span { color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.drawer-all { color: var(--cta) !important; font-weight: 700; }

.drawer-help { padding: 14px 16px 4px; border-top: 1px solid var(--line); }
.drawer-help h4 {
  margin: 0 0 6px; font-family: var(--font-body), sans-serif;
  font-size: 11px; letter-spacing: 1.6px; text-transform: uppercase;
  font-weight: 700; color: var(--muted);
}
.drawer-help a {
  display: flex; align-items: center; gap: 11px; min-height: 44px;
  color: var(--ink); font-size: 14px; font-weight: 600; text-decoration: none;
}
.drawer-help a:hover { color: var(--cta); }
.drawer-help .ico { color: var(--muted); }

.drawer-call {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  margin: 14px 16px 20px; min-height: 46px; border-radius: var(--radius);
  background: var(--cta); color: var(--btn-text);
  font-size: 14px; font-weight: 700; text-decoration: none;
}

/* ---- footer -------------------------------------------------------------- */
.site-footer {
  margin-top: 56px; background: var(--footer-bg); color: var(--footer-text);
  font-size: 13.5px;
}
.site-footer a { color: var(--footer-text); text-decoration: none; }
.site-footer a:hover { color: var(--footer-link-hover); }

/* At the TOP of the footer, not the bottom: it is the last thing read before
   the back button, not filler for the end. */
.footer-assure { border-bottom: 1px solid var(--footer-line); }
.footer-assure-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(16px, 3vw, 34px); padding-block: 26px;
}
.footer-assure-grid > div { display: grid; grid-template-columns: auto 1fr; gap: 2px 13px; }
.footer-assure-grid .ico { grid-row: 1 / 3; color: var(--cta); margin-top: 2px; }
.footer-assure-grid b { color: #fff; font-size: 14px; }
.footer-assure-grid span { font-size: 12.5px; line-height: 1.5; opacity: .78; }
.footer-assure-grid a { text-decoration: underline; text-underline-offset: 2px; }

.footer-main {
  display: grid;
  /* The last column has a floor, and it is not decorative: Turnstile refuses
     to render below 300px, so a 289px column made the widget hang 11px past
     the signup field it belongs to. min() keeps the floor from becoming an
     overflow of its own on a narrow screen, where this collapses to one
     column anyway. */
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 3fr) minmax(min(300px, 100%), 1.4fr);
  gap: clamp(24px, 4vw, 52px); padding-block: 40px 32px;
}
.footer-logo {
  display: inline-flex; align-items: center; margin-bottom: 14px;
  font-family: var(--font-head), sans-serif; font-size: 20px;
  letter-spacing: 1px; text-transform: uppercase; color: #fff;
}
.footer-logo span { color: var(--cta); }
.footer-logo img { max-height: 34px; width: auto; }
.footer-blurb { margin: 0 0 16px; font-size: 13px; line-height: 1.65; opacity: .78; max-width: 42ch; }
.footer-contact { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
/* Centred, not top-aligned.

   The links in here carry the footer's 24px tap-target floor, which is 3px of
   padding above and below the text. A top-aligned icon therefore sat 3.5px
   above the words next to it, and 13.5px above them under a coarse pointer,
   where that floor rises to 44px. Centring is right at every size because it
   is relative to whatever box the label ends up with. */
.footer-contact li { display: flex; align-items: center; gap: 10px; font-size: 13px; line-height: 1.5; }
.footer-contact .ico { color: var(--cta); }
/* The exception, and the reason this was top-aligned to begin with: a postal
   address wraps, and an icon hovering in the middle of three lines reads as a
   mistake. Only this row opts out. */
.footer-contact li.is-stacked { align-items: flex-start; }
.footer-contact li.is-stacked .ico { margin-top: 1px; }
.footer-social { list-style: none; margin: 16px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.footer-social a {
  display: inline-block; padding: 6px 11px; border-radius: var(--radius);
  border: 1px solid var(--footer-line);
  font-size: 11px; letter-spacing: 1.2px; text-transform: uppercase; font-weight: 700;
}
.footer-social a:hover { border-color: var(--cta); color: #fff; }

.footer-cols { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(16px, 2.5vw, 30px); }
.site-footer h5 {
  margin: 0 0 12px; font-family: var(--font-body), sans-serif;
  font-size: 11px; letter-spacing: 1.8px; text-transform: uppercase;
  font-weight: 700; color: #fff;
}
.footer-cols ul { list-style: none; margin: 0; padding: 0; }
.footer-cols li { margin: 0 0 8px; }
.footer-cols a { font-size: 13px; line-height: 1.5; }

.footer-news p { margin: 0 0 12px; font-size: 12.5px; line-height: 1.6; opacity: .78; }
.footer-news-form { display: flex; }
.footer-news-form input {
  flex: 1 1 auto; min-width: 0; padding: 11px 13px;
  border: 1px solid var(--footer-line); border-right: 0;
  border-radius: var(--radius) 0 0 var(--radius);
  background: #fff; color: var(--ink); font: inherit; font-size: 13.5px;
}
.footer-news-form input:focus { outline: 2px solid var(--cta); outline-offset: -2px; }
.footer-news-form .btn { border-radius: 0 var(--radius) var(--radius) 0; padding: 11px 18px; }

.footer-note { margin: 0 0 20px; font-size: 12.5px; line-height: 1.6; opacity: .7; max-width: 90ch; }

.footer-legal { border-top: 1px solid var(--footer-line); }
.footer-legal-inner {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 14px; padding-block: 18px 24px; font-size: 12.5px;
}
.footer-legal-links { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 18px; }
.footer-legal-links a { font-size: 12.5px; }

/* ---- chrome responsive --------------------------------------------------- */
@media (max-width: 1200px) {
  .mega-links ul { gap: 1px 16px; }
  .mega-inner { grid-template-columns: minmax(0, 1fr) 236px; gap: 22px; }
}
@media (max-width: 1080px) {
  /* Five columns stop being readable well before the row itself breaks. */
  .mega-links ul { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
  .dept > a { padding: 0 10px; letter-spacing: .3px; }
  /* .hact-label, not `.hact span`: the latter also matched the span wrapping
     the cart icon and rendered the cart as an empty box. The link keeps its
     aria-label, so dropping the caption costs a screen reader nothing. */
  .hact-label { display: none; }
  .hact { padding: 6px 9px; }
}
@media (max-width: 1000px) {
  .topbar { display: none; }
}
@media (max-width: 900px) {
  /* The drawer is the only navigation at this width, so the desktop row and
     its panels must not merely be transparent, they must be gone. */
  .deptnav { display: none; }
  .burger { display: inline-flex; }
  .masthead { flex-wrap: wrap; min-height: 0; row-gap: 10px; }
  .hsearch { order: 3; flex-basis: 100%; max-width: none; }
  .hactions { margin-left: auto; }
  .footer-main { grid-template-columns: minmax(0, 1fr); }
  .footer-assure-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .hsearch-go { padding: 0; width: 40px; }
  .hsearch-go-text { display: none; }
  .hsearch-go-ico { display: block; }
  .footer-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .logo { font-size: 18px; }
}
@media (max-width: 430px) {
  .hact-key { display: none; }
  .footer-assure-grid { grid-template-columns: minmax(0, 1fr); }
  .footer-legal-inner { justify-content: flex-start; }
}

@media (prefers-reduced-motion: reduce) {
  .mega, .drawer-panel, .drawer-scrim, .dept-caret, .drawer-caret,
  .skip-link, .hsearch { transition: none; }
}

/* ==========================================================================
   EDITORIAL: static pages, blogs, articles

   One treatment for all three. A reader who arrives on the transponder guide
   from search and then opens the returns policy should not feel they have
   changed website.

   Existing tokens only, so `bin/console theme:check` stays green.
   ========================================================================== */

/* An article and a static page are ONE reading column, so the head, the body,
   the closing call to action and the read-next rail all share one measure and
   one left edge. Left at the full 1400px container the H1 ran the width of the
   screen over a 640px paragraph, which reads as two different pages stacked.
   Scoped to .doc, so the blog feeds keep the wide grid they want. */
.doc .container { max-width: 1040px; }

/* ---- page and article head ----------------------------------------------- */
.doc-head { border-bottom: 1px solid var(--line); padding-bottom: clamp(20px, 3vw, 30px); }
.doc-head .crumbs { margin-top: 20px; }
.doc-head h1 {
  margin: 0 0 14px; max-width: 22ch;
  font-size: clamp(28px, 4.4vw, 46px); line-height: 1.08;
}
.doc-stand {
  margin: 0; max-width: 60ch;
  font-size: clamp(15.5px, 1.7vw, 18px); line-height: 1.6; color: var(--muted);
}
.doc-meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  margin: 16px 0 0; font-size: 13px; color: var(--muted);
}
.doc-meta .ico { color: var(--cta); }
.doc-meta time { font-variant-numeric: tabular-nums; }

.doc-hero {
  margin: clamp(20px, 3vw, 30px) 0 0; border-radius: var(--radius); overflow: hidden;
  border: 1px solid var(--line);
}
.doc-hero img { display: block; width: 100%; height: auto; }

/* ---- the two-column body ------------------------------------------------- */
.doc-wrap {
  display: grid; grid-template-columns: 232px minmax(0, 1fr);
  gap: clamp(28px, 5vw, 64px); align-items: start;
  padding-block: clamp(28px, 4vw, 48px) clamp(20px, 3vw, 34px);
}
/* Fewer than three headings and there is no rail, so the prose centres in the
   measure rather than hugging the left edge of an empty grid. */
.doc-wrap-solo { grid-template-columns: minmax(0, 1fr); max-width: 76ch; margin-inline: auto; }

.doc-toc {
  position: sticky; top: 128px;      /* clears the sticky masthead + dept row */
  padding-left: 14px; border-left: 2px solid var(--line);
}
.doc-toc h2 {
  margin: 0 0 10px; font-family: var(--font-body), sans-serif;
  font-size: 11px; letter-spacing: 1.8px; text-transform: uppercase;
  font-weight: 700; color: var(--muted);
}
.doc-toc ol { list-style: none; margin: 0; padding: 0; counter-reset: toc; }
.doc-toc li { counter-increment: toc; }
.doc-toc a {
  display: block; padding: 6px 0; min-height: 24px;
  font-size: 13px; line-height: 1.45; color: var(--body); text-decoration: none;
}
.doc-toc a::before {
  content: counter(toc) ". "; color: var(--muted); font-variant-numeric: tabular-nums;
}
.doc-toc a:hover { color: var(--cta); }

/* ---- prose ---------------------------------------------------------------
   Capped near 68 characters because that is where a line stops being
   comfortable to read, not because of the grid. */
.prose { max-width: 68ch; font-size: 16px; line-height: 1.72; color: var(--body); }
.prose > *:first-child { margin-top: 0; }
.prose h2 {
  margin: 44px 0 12px; font-size: clamp(21px, 2.4vw, 27px); line-height: 1.2;
  color: var(--ink); scroll-margin-top: 128px;
}
.prose h3 { margin: 30px 0 8px; font-size: 17.5px; line-height: 1.3; color: var(--ink); }
.prose h4 { margin: 24px 0 6px; font-size: 15.5px; color: var(--ink); }
.prose p { margin: 0 0 18px; }
.prose ul, .prose ol { margin: 0 0 20px; padding-left: 22px; }
.prose li { margin: 0 0 8px; }
.prose li::marker { color: var(--cta); }
.prose a { color: var(--cta); text-decoration: underline; text-underline-offset: 2px; }
.prose a:hover { color: var(--cta-dark); }
.prose strong { color: var(--ink); }
.prose hr { margin: 34px 0; border: 0; border-top: 1px solid var(--line); }
.prose blockquote {
  margin: 24px 0; padding: 4px 0 4px 20px;
  border-left: 3px solid var(--cta); color: var(--ink); font-size: 17px;
}
.prose blockquote p:last-child { margin-bottom: 0; }
.prose code {
  background: var(--wash); border: 1px solid var(--line); border-radius: 3px;
  padding: 1px 5px; font-size: .92em; color: var(--ink);
}
.prose table { margin: 0 0 22px; border-collapse: collapse; font-size: 14.5px; }
.prose th, .prose td { padding: 9px 12px; border: 1px solid var(--line); text-align: left; }
.prose th { background: var(--wash); font-weight: 700; color: var(--ink); }
.prose img { border-radius: var(--radius); border: 1px solid var(--line); }
.prose figure { margin: 24px 0; }
.prose figcaption { margin-top: 8px; font-size: 12.5px; color: var(--muted); }

/* A questions block inside prose gets the same accordion as the home page. */
.prose details {
  border-bottom: 1px solid var(--line); padding: 2px 0;
}
.prose summary {
  cursor: pointer; list-style: none; padding: 14px 0; min-height: 44px;
  font-size: 16px; font-weight: 700; color: var(--ink);
}
.prose summary::-webkit-details-marker { display: none; }
.prose summary::after { content: "+"; float: right; color: var(--cta); font-weight: 400; }
.prose details[open] summary::after { content: "\2212"; }
.prose details > *:not(summary) { padding-bottom: 10px; }

.doc-tags { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; margin: 34px 0 0; padding: 26px 0 0; border-top: 1px solid var(--line); }
.doc-tags a {
  display: inline-block; padding: 6px 12px; min-height: 24px;
  border: 1px solid var(--line); border-radius: 100px;
  font-size: 12.5px; color: var(--muted); text-decoration: none;
}
.doc-tags a:hover { border-color: var(--cta); color: var(--cta); }

.doc-empty { padding: 40px 0; color: var(--muted); font-size: 15px; }

/* ---- the closing call to action ------------------------------------------ */
.doc-cta {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 20px;
  margin-bottom: 12px; padding: clamp(22px, 3vw, 32px);
  background: var(--ink); border-radius: var(--radius); color: #fff;
}
.doc-cta h2 { margin: 0 0 6px; font-size: clamp(19px, 2.2vw, 24px); color: #fff; }
.doc-cta p { margin: 0; max-width: 56ch; font-size: 14px; line-height: 1.6; color: rgba(255, 255, 255, .74); }
.doc-cta-links { display: flex; flex-wrap: wrap; gap: 10px; }
.doc-cta .btn-outline { color: #fff; border-color: rgba(255, 255, 255, .45); }
.doc-cta .btn-outline:hover { background: #fff; color: var(--ink); border-color: #fff; }

/* ---- blog index: pick a feed --------------------------------------------- */
.blog-picker {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(12px, 1.8vw, 20px); list-style: none; margin: 0; padding: 0;
}
.blog-picker a {
  display: flex; flex-direction: column; gap: 10px; height: 100%;
  padding: clamp(20px, 2.6vw, 28px);
  border: 1px solid var(--line); border-radius: var(--radius);
  text-decoration: none; transition: border-color .15s ease, box-shadow .15s ease;
}
.blog-picker a:hover { border-color: var(--cta); box-shadow: 0 4px 18px rgba(0, 0, 0, .07); }
.blog-picker-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.blog-picker-head b { font-size: clamp(18px, 2.1vw, 22px); color: var(--ink); }
.blog-picker-head span { flex: 0 0 auto; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.blog-picker-intro { font-size: 14px; line-height: 1.6; color: var(--body); }
.blog-picker-go {
  display: inline-flex; align-items: center; gap: 6px; margin-top: auto;
  font-size: 12.5px; font-weight: 700; letter-spacing: 1px;
  text-transform: uppercase; color: var(--cta);
}

/* ---- feed switcher ------------------------------------------------------- */
.blog-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 20px; }
.blog-tabs a {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 15px; min-height: 40px;
  border: 1px solid var(--line); border-radius: 100px;
  font-size: 13.5px; font-weight: 600; color: var(--body); text-decoration: none;
}
.blog-tabs a span { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.blog-tabs a:hover { border-color: var(--ink); color: var(--ink); }
.blog-tabs a[aria-current="page"] { background: var(--ink); border-color: var(--ink); color: #fff; }
.blog-tabs a[aria-current="page"] span { color: rgba(255, 255, 255, .6); }

/* ---- the lead article ---------------------------------------------------- */
.art-lead-solo { grid-template-columns: minmax(0, 1fr) !important; }
.art-lead-solo .art-lead-body { max-width: 62ch; }
.art-lead {
  display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: clamp(20px, 3.5vw, 44px); align-items: center;
  padding: clamp(20px, 2.6vw, 30px);
  background: var(--wash); border: 1px solid var(--line); border-radius: var(--radius);
}
.art-lead-media { display: block; border-radius: var(--radius); overflow: hidden; background: #fff; }
.art-lead-media img { display: block; width: 100%; height: auto; aspect-ratio: 16/10; object-fit: cover; }
.art-lead-kicker {
  margin: 0 0 8px; font-size: 11px; letter-spacing: 2px;
  text-transform: uppercase; font-weight: 700; color: var(--cta);
}
.art-lead h2 { margin: 0 0 12px; font-size: clamp(22px, 2.9vw, 32px); line-height: 1.14; }
.art-lead h2 a { color: var(--ink); text-decoration: none; }
.art-lead h2 a:hover { color: var(--cta); }
.art-lead-sum { margin: 0 0 14px; font-size: 15px; line-height: 1.65; color: var(--body); }
.art-lead-meta {
  display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 18px;
  font-size: 12.5px; color: var(--muted);
}
.art-lead-meta span::before { content: "\00b7"; margin-right: 8px; }

/* ---- article cards ------------------------------------------------------- */
.art-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(12px, 1.8vw, 22px); list-style: none; margin: 0; padding: 0;
}
.art-card > a {
  display: flex; flex-direction: column; height: 100%;
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
  background: #fff; text-decoration: none;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.art-card > a:hover { border-color: var(--cta); box-shadow: 0 4px 18px rgba(0, 0, 0, .07); }
.art-card-media { display: block; background: var(--wash); }
.art-card-media img { display: block; width: 100%; height: auto; aspect-ratio: 16/9; object-fit: cover; }
.art-card-body { display: flex; flex-direction: column; gap: 7px; padding: 18px; height: 100%; }
.art-card-kicker {
  font-size: 10.5px; letter-spacing: 1.6px; text-transform: uppercase;
  font-weight: 700; color: var(--cta);
}
.art-card-title { font-size: 16px; font-weight: 700; line-height: 1.32; color: var(--ink); }
.art-card-sum { font-size: 13.5px; line-height: 1.6; color: var(--muted); }
.art-card-date {
  margin-top: auto; padding-top: 8px;
  font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums;
}

.pager-back { transform: rotate(180deg); }

/* ---- editorial responsive ------------------------------------------------ */
@media (max-width: 1000px) {
  .doc-wrap { grid-template-columns: minmax(0, 1fr); }
  /* Not sticky once it is above the prose rather than beside it: a sticky
     contents list that scrolls with the body covers what it is pointing at. */
  .doc-toc {
    position: static; padding: 16px 18px; border-left: 0;
    border: 1px solid var(--line); border-radius: var(--radius); background: var(--wash);
  }
  .doc-toc ol { columns: 2; column-gap: 24px; }
  .prose { max-width: none; }
  .art-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .art-lead { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 620px) {
  .blog-picker { grid-template-columns: minmax(0, 1fr); }
  .art-grid { grid-template-columns: minmax(0, 1fr); }
  .doc-toc ol { columns: 1; }
  .doc-cta { flex-direction: column; align-items: flex-start; }
  .doc-cta-links { width: 100%; }
  .doc-cta-links .btn { flex: 1 1 auto; justify-content: center; }
}

/* ==========================================================================
   COMMERCE: listing head, cards, filter rail, toolbar, category index
   Rebuilt. Existing tokens only, so theme:check stays green.
   ========================================================================== */

/* ---- the head every listing shares --------------------------------------- */
.list-head { border-bottom: 1px solid var(--line); padding-bottom: 18px; }
.list-head .crumbs { margin: 20px 0 12px; }
.list-head-row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.list-head-row h1 { margin: 0; font-size: clamp(24px, 3.4vw, 38px); line-height: 1.12; }
.list-head-n {
  margin: 0; flex: 0 0 auto; font-size: 13px; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.list-head-sub { margin: 12px 0 0; max-width: 66ch; font-size: 14.5px; line-height: 1.6; color: var(--muted); }
.list-head-sub a { color: var(--cta); }

/* ---- product card --------------------------------------------------------- */
.grid-products { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(12px, 1.6vw, 20px); }

.card {
  display: flex; flex-direction: column; position: relative;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.card:hover { border-color: var(--cta); box-shadow: 0 6px 22px rgba(0, 0, 0, .08); }
.card-out { opacity: .72; }

.card-media { display: block; position: relative; aspect-ratio: 1/1; background: var(--wash); overflow: hidden; }
.card-media img { width: 100%; height: 100%; object-fit: cover; transition: transform .35s ease; }
.card:hover .card-media img { transform: scale(1.04); }
/*
   The sale badge.

   THE PERCENTAGE IS THE HEADLINE, SO IT IS SET LIKE ONE

   Three versions got here. "-15 %" read as a negative number and the tracking
   split the percent sign off its digits. "Save 15%" fixed the meaning but ran
   to four words on one line, which at 220px of card was forty percent of the
   width and competed with the photograph it was sitting on.

   Stacking it solves both. The number carries the message and gets the size;
   OFF is a caption and gets 8px. The block is now roughly square and about
   half the width it was, so the product is still the loudest thing on the
   tile, which on a shopping grid it must be.

   Bottom-left rather than top-left: product photography puts the subject in
   the middle and the top corners are where a shopper's eye lands first
   looking for the product itself. The badge is the second thing they should
   see, not the first.

   Contrast: white on #cc1313 is 5.9:1, past the 4.5:1 floor. It is never the
   only signal either. The struck price and the cash saving repeat it in the
   card body, so a shopper who cannot separate the red still gets it.
*/
.card-badge {
  position: absolute; left: 10px; bottom: 10px; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-width: 42px; padding: 5px 6px 4px;
  background: var(--sale); color: #fff;
  border-radius: 3px;
  line-height: 1;
  /* Lifts it off the photograph without a border, which would compete with the
     product outline underneath. */
  box-shadow: 0 2px 10px rgba(0,0,0,.3);
}
.card-badge b {
  display: block;
  font-size: 15px; font-weight: 800; letter-spacing: -.3px;
  font-variant-numeric: tabular-nums;   /* a grid of badges lines up */
}
.card-badge i {
  display: block; font-style: normal;
  font-size: 8px; font-weight: 700; letter-spacing: 1.4px;
  text-transform: uppercase; opacity: .92;
  margin-top: 2px;
}
/* A custom label such as Clearance is a word, not a figure, so it goes back to
   a single tracked line rather than being stacked into a column. */
.card-badge.is-word {
  flex-direction: row; min-width: 0;
  padding: 5px 9px;
  font-size: 10px; font-weight: 800; letter-spacing: .9px; text-transform: uppercase;
}

/* Out of stock keeps the old top-left pill: it is a status, not an offer, and
   it should not look like one. */
.card-badge-out {
  background: var(--ink); left: 10px; top: 10px; bottom: auto;
  flex-direction: row; min-width: 0; padding: 4px 8px;
  font-size: 10.5px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase;
  box-shadow: none;
}

.card-body { display: flex; flex-direction: column; gap: 7px; padding: 13px 14px 14px; flex: 1; }
.card-brand {
  margin: 0; font-size: 10.5px; letter-spacing: 1.4px; text-transform: uppercase;
  font-weight: 700; color: var(--cta);
}
.card-title { margin: 0; font-size: 13.5px; font-weight: 600; line-height: 1.38; }
.card-title a {
  color: var(--ink); text-decoration: none;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.card:hover .card-title a { color: var(--cta); }

/* THE SPEC CHIPS. A locksmith scanning a grid of blanks is looking for a
   keyway code, not reading titles. Only above the confidence gate: a guessed
   keyway on a card is worse than none. */
.card-specs { display: flex; flex-wrap: wrap; gap: 5px; list-style: none; margin: 0; padding: 0; }
.card-specs li {
  padding: 2px 7px; border: 1px solid var(--line); border-radius: 100px;
  background: var(--wash);
  font-size: 10.5px; font-weight: 700; letter-spacing: .4px; color: var(--body);
}
.card-specs abbr { text-decoration: none; border: 0; }

.card-price { display: flex; align-items: baseline; gap: 8px; margin: auto 0 0; padding-top: 4px; }
.price-now { font-size: 17px; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.price-was { font-size: 13px; color: var(--muted); text-decoration: line-through; }
.price-saved {
  /* The cash figure, beside the numbers it refers to. On a $4,000 machine this
     is the line that sells, and it is the one thing a percentage cannot say.

     Given its own row rather than a third item on the price line: three
     numbers side by side made the reader parse which was which, and on a
     narrow card the last one wrapped on its own anyway. */
  flex: 1 0 100%;
  margin-top: 1px;
  font-size: 11.5px; font-weight: 700; color: var(--sale);
  font-variant-numeric: tabular-nums;
}
.card-price { flex-wrap: wrap; }

.card-stock { margin: 0; font-size: 11.5px; font-weight: 700; }
.card-stock.low { color: var(--sale); }
/* Outline at rest, solid on hover. Twenty-four solid orange blocks in a grid
   compete with each other and with the one real CTA in the header, and they
   bury the product photography and the spec chips, which are what a locksmith
   is actually scanning. Solid orange is reserved for the product page, where
   there is one decision to make. */
.card-atc {
  width: 100%; justify-content: center; text-align: center;
  padding: 10px 8px; font-size: 11.5px;
  background: transparent; color: var(--cta); border: 1px solid var(--cta);
}
.card-atc:hover, .card:hover .card-atc { background: var(--cta); color: var(--btn-text); }
/* Titles reserve two lines so prices and buttons line up across a row even
   when one product is named in four words and the next in fourteen. */
.card-title a { min-height: 2.76em; }
.card form { margin: 0; }

/* ---- listing layout ------------------------------------------------------- */
/* No facets, no rail column. Without this the grid still reserved 258px and
   the products rendered inside it, which looked like a broken page. */
.listing-solo { grid-template-columns: minmax(0, 1fr) !important; }
.listing {
  display: grid; grid-template-columns: 258px minmax(0, 1fr);
  gap: clamp(20px, 3vw, 40px); align-items: start;
  padding-block: 24px 56px;
}
.listing-main { min-width: 0; }

/* ---- filter rail ---------------------------------------------------------- */
.facets { position: sticky; top: 128px; }
.facets-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding-bottom: 12px; border-bottom: 1px solid var(--line);
}
.facets-head h2 {
  display: flex; align-items: center; gap: 8px; margin: 0;
  font-family: var(--font-body), sans-serif;
  font-size: 11px; letter-spacing: 1.8px; text-transform: uppercase; font-weight: 700;
}
.facets-clear { font-size: 12px; font-weight: 700; color: var(--sale); text-decoration: none; }
.facets-clear:hover { text-decoration: underline; }

.facet-group { border-bottom: 1px solid var(--line); }
.facet-group summary {
  display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
  padding: 13px 2px; min-height: 44px;
  font-size: 13px; font-weight: 700; color: var(--ink);
}
.facet-group summary::-webkit-details-marker { display: none; }
.facet-group summary > span:first-child { flex: 1 1 auto; min-width: 0; }
.facet-on {
  flex: 0 0 auto; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--cta); color: var(--btn-text);
  font-size: 11px; line-height: 18px; text-align: center;
}
.facet-caret { flex: 0 0 auto; color: var(--muted); transition: transform .15s ease; }
.facet-group[open] .facet-caret { transform: rotate(180deg); }
.facet-group ul { list-style: none; margin: 0; padding: 0 0 12px; }
/* Long groups scroll inside themselves rather than pushing the products down. */
.facet-scroll { max-height: 268px; overflow-y: auto; overscroll-behavior: contain; }

.facet-opt {
  display: flex; align-items: center; gap: 9px; padding: 6px 4px; min-height: 24px;
  border-radius: 3px; text-decoration: none; color: var(--body); font-size: 13.5px;
}
.facet-opt:hover { background: var(--wash); }
.facet-opt .box {
  flex: 0 0 auto; width: 15px; height: 15px; position: relative;
  border: 1px solid var(--input-border); border-radius: 3px; background: var(--bg);
}
.facet-opt.on .box { background: var(--cta); border-color: var(--cta); }
/* Drawn rather than an image, so it follows the accent colour and costs no request. */
.facet-opt.on .box::after {
  content: ''; position: absolute; left: 4px; top: 1px; width: 4px; height: 8px;
  border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.facet-opt .lab { flex: 1 1 auto; min-width: 0; }
.facet-opt .n { flex: 0 0 auto; color: var(--muted); font-size: 11.5px; font-variant-numeric: tabular-nums; }
.facet-opt.on .lab { font-weight: 700; color: var(--ink); }

/* ---- toolbar and active filter chips -------------------------------------- */
.toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  padding-bottom: 12px; margin-bottom: 16px; border-bottom: 1px solid var(--line);
}
.toolbar-count { margin: 0; font-size: 13.5px; color: var(--muted); }
.toolbar-count strong { color: var(--ink); font-variant-numeric: tabular-nums; }
.toolbar-sort { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.toolbar-sort label { color: var(--muted); }
.toolbar-sort select {
  padding: 8px 10px; border: 1px solid var(--input-border); border-radius: var(--radius);
  background: var(--input-bg); font-family: inherit; font-size: 13.5px; min-height: 38px;
}

/* With the rail collapsed on a narrow screen, these are the only thing telling
   a shopper why the grid is short. */
.chips { display: flex; flex-wrap: wrap; gap: 7px; list-style: none; margin: 0 0 18px; padding: 0; }
.chips a {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 11px; min-height: 32px; border-radius: 100px;
  background: var(--ink); color: #fff; font-size: 12.5px; text-decoration: none;
}
.chips a:hover { background: var(--cta); }
.chips .ico { opacity: .7; }
.chips-clear a { background: none; color: var(--sale); border: 1px solid var(--line); }
.chips-clear a:hover { background: none; color: var(--sale); border-color: var(--sale); }

/* ---- empty and miss states ------------------------------------------------ */
.empty-results {
  display: flex; flex-direction: column; align-items: flex-start; gap: 12px;
  padding: clamp(28px, 5vw, 56px) 0;
}
.empty-results h2 { margin: 0; font-size: clamp(19px, 2.4vw, 25px); }
.empty-results p { margin: 0; max-width: 56ch; color: var(--muted); font-size: 15px; line-height: 1.6; }
.empty-results .btn { margin-top: 6px; margin-right: 8px; }

.miss { padding-block: 28px 56px; max-width: 760px; }
.miss-first {
  display: flex; gap: 18px; align-items: flex-start;
  padding: clamp(20px, 3vw, 28px); margin-bottom: 24px;
  border: 1px solid var(--cta); border-radius: var(--radius); background: var(--wash);
}
.miss-first .ico { flex: 0 0 auto; color: var(--cta); margin-top: 2px; }
.miss-first h2 { margin: 0 0 8px; font-size: clamp(18px, 2.2vw, 23px); }
.miss-first p { margin: 0 0 14px; color: var(--body); font-size: 14.5px; line-height: 1.6; }
.miss-more h3, .miss-form h3 { margin: 0 0 8px; font-size: 15px; }
.miss-more ul { margin: 0 0 28px; padding-left: 20px; color: var(--body); font-size: 14.5px; line-height: 1.8; }
.miss-more a { color: var(--cta); }
.miss-form { padding-top: 24px; border-top: 1px solid var(--line); }
.miss-form p { margin: 0 0 12px; color: var(--muted); font-size: 14px; }
.miss-form-row { display: flex; flex-wrap: wrap; gap: 8px; }
.miss-form-row input {
  flex: 1 1 240px; min-width: 0; padding: 11px 13px;
  border: 1px solid var(--input-border); border-radius: var(--radius);
  font-family: inherit; font-size: 14px;
}

.search-again { position: relative; display: flex; align-items: center; gap: 8px; max-width: 640px; margin: 0 0 18px; }
.search-again-ico { position: absolute; left: 13px; color: var(--muted); pointer-events: none; }
.search-again input {
  flex: 1 1 auto; min-width: 0; padding: 12px 14px 12px 40px;
  border: 1px solid var(--input-border); border-radius: var(--radius);
  background: var(--input-bg); font-family: inherit; font-size: 14.5px;
}
.search-again input:focus { outline: 2px solid var(--cta); outline-offset: -2px; }

/* ---- copy under the grid --------------------------------------------------- */
.list-about { margin-top: 44px; padding-top: 28px; border-top: 1px solid var(--line); }
.list-about h2 { margin: 0 0 12px; font-size: clamp(18px, 2.2vw, 23px); }

/* ---- category index -------------------------------------------------------- */
.dept-cards {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(12px, 1.8vw, 20px); list-style: none; margin: 0; padding: 0;
}
.dept-card {
  display: flex; flex-direction: column;
  padding: 20px; border: 1px solid var(--line); border-radius: var(--radius); background: #fff;
}
.dept-card-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px solid var(--line);
}
.dept-card-head h2 { margin: 0; font-size: 17px; }
.dept-card-head h2 a { color: var(--ink); text-decoration: none; }
.dept-card-head h2 a:hover { color: var(--cta); }
.dept-card-head span { flex: 0 0 auto; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.dept-card ul { list-style: none; margin: 0 0 12px; padding: 0; }
.dept-card li a {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 5px 0; min-height: 24px; text-decoration: none; color: var(--body); font-size: 13.5px;
}
.dept-card li a:hover { color: var(--cta); }
.dept-card li .n { flex: 0 0 auto; color: var(--muted); font-size: 11.5px; font-variant-numeric: tabular-nums; }
.dept-card-all {
  display: inline-flex; align-items: center; gap: 6px; margin-top: auto; min-height: 24px;
  font-size: 12px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase;
  color: var(--cta); text-decoration: none;
}

.cat-index {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 26px 36px;
}
.cat-index h3 {
  margin: 0 0 10px; padding-bottom: 8px; border-bottom: 2px solid var(--ink);
  font-family: var(--font-body), sans-serif;
  font-size: 12px; letter-spacing: 2px; text-transform: uppercase; font-weight: 700;
}
.cat-index ul { list-style: none; margin: 0; padding: 0; }
.cat-index a {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 7px 0; min-height: 24px; border-bottom: 1px solid var(--line);
  text-decoration: none; color: var(--body); font-size: 13.5px;
}
.cat-index a:hover { color: var(--cta); }
.cat-index .n { flex: 0 0 auto; color: var(--muted); font-size: 11.5px; font-variant-numeric: tabular-nums; }

/* ---- commerce responsive --------------------------------------------------- */
@media (max-width: 1200px) {
  .grid-products { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .dept-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 1000px) {
  /* The rail becomes one disclosure above the grid. A 258px sidebar beside a
     320px grid is neither a rail nor a grid. */
  .listing { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .facets {
    position: static; margin-bottom: 20px;
    border: 1px solid var(--line); border-radius: var(--radius); padding: 4px 14px 8px;
  }
  .facets-head { border-bottom: 0; padding-block: 10px; }
  .facets-body { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 24px; }
  .facet-group:last-child { border-bottom: 0; }
}
@media (max-width: 760px) {
  .grid-products { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .facets-body { grid-template-columns: minmax(0, 1fr); }
  .dept-cards { grid-template-columns: minmax(0, 1fr); }
  .miss-first { flex-direction: column; gap: 12px; }
}
@media (max-width: 420px) {
  .card-specs { display: none; }   /* two per row leaves no width for chips */
  .card-body { padding: 11px 11px 12px; }
}

/* ==========================================================================
   PRODUCT PAGE, rebuilt
   ========================================================================== */
.pdp {
  display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 56px); align-items: start;
  padding-block: 18px 8px;
}
.pdp-media { position: sticky; top: 128px; min-width: 0; }

.gallery-main {
  border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; background: #fff; aspect-ratio: 1/1;
}
.gallery-main img { width: 100%; height: 100%; object-fit: contain; transition: transform .18s ease; }
.gallery-main.zooming img { transform: scale(1.75); }

.thumbs { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.thumb {
  width: 68px; height: 68px; padding: 0; cursor: pointer; overflow: hidden;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  transition: border-color .15s ease;
}
.thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thumb:hover { border-color: var(--muted); }
.thumb.sel { border-color: var(--cta); box-shadow: 0 0 0 1px var(--cta) inset; }

/* ---- the buy column ------------------------------------------------------- */
.pdp-buy { min-width: 0; }
.pdp-brand {
  margin: 0 0 6px; font-size: 11.5px; letter-spacing: 1.8px; text-transform: uppercase;
  font-weight: 700; color: var(--cta);
}
.pdp h1 { margin: 0 0 8px; font-size: clamp(21px, 2.7vw, 31px); line-height: 1.18; }
.pdp-sku { margin: 0 0 12px; font-size: 12.5px; color: var(--muted); }
.pdp-rating { display: flex; align-items: center; gap: 9px; margin: 0 0 12px; font-size: 13.5px; color: var(--muted); }
.pdp-rating .stars { color: var(--star); }

/* THE IDENTIFIERS. Above the fold because for this trade they ARE the buying
   decision: nobody wants "a Toyota remote", they want HU100 at 433MHz with an
   ID47. Only values at or above the confidence gate reach here. */
.pdp-idents {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  gap: 1px; margin: 0 0 18px; padding: 0;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--line); overflow: hidden;
}
.pdp-idents > div { padding: 10px 12px; background: var(--wash); }
.pdp-idents dt {
  font-size: 10.5px; letter-spacing: 1.2px; text-transform: uppercase;
  font-weight: 700; color: var(--muted); margin-bottom: 3px;
}
.pdp-idents dd { margin: 0; font-size: 14px; font-weight: 700; color: var(--ink); overflow-wrap: anywhere; }

.pdp-price { display: flex; align-items: baseline; flex-wrap: wrap; gap: 12px; margin: 0 0 6px; }
.pdp-price .now { font-size: clamp(26px, 3.2vw, 34px); font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.pdp-price .was { font-size: 17px; color: var(--muted); text-decoration: line-through; }
.pdp-price .save {
  padding: 3px 9px; border-radius: 2px; background: #fdecea;
  color: var(--sale); font-size: 12px; font-weight: 700;
}

.stock-line { margin: 10px 0 18px; font-size: 13.5px; font-weight: 600; }
.stock-line.ok { color: var(--stock-ok); }
/* NO ::before marker. The variant picker script rewrites this line and writes
   its own bullet into the text, so a CSS marker produced two of them side by
   side. One owner per decoration: the script owns it, because it is the one
   that also has to say "Select options above". */
.stock-line.out { color: var(--sale); }

.pdp-form { margin: 0 0 18px; }
/* The subtotal sits BESIDE the stepper. It is the running total for the
   quantity in the box next to it, and pushing it to the far edge broke the one
   relationship the row exists to show. The dead space that caused is answered
   by the buttons below going full width, not by spreading this row. */
.qty-row {
  display: flex; align-items: flex-end; flex-wrap: wrap;
  gap: 10px 20px; margin-bottom: 16px;
}
.qty label {
  display: block; margin-bottom: 6px;
  font-size: 11px; letter-spacing: 1.4px; text-transform: uppercase;
  font-weight: 700; color: var(--muted);
}
.qty-stepper { display: flex; width: 138px; border: 1px solid var(--input-border); border-radius: var(--radius); overflow: hidden; }
.qty-stepper button {
  width: 42px; min-height: 44px; border: 0; cursor: pointer;
  background: var(--wash); color: var(--ink); font-size: 18px;
}
.qty-stepper button:hover { background: var(--line); }
.qty-stepper input {
  flex: 1 1 auto; width: 54px; min-width: 0; border: 0; text-align: center;
  font-family: inherit; font-size: 15px; font-weight: 700; color: var(--ink);
}
.subtotal-line { display: flex; flex-direction: column; gap: 2px; margin: 0; }
.subtotal-line span { font-size: 11px; letter-spacing: 1.4px; text-transform: uppercase; color: var(--muted); font-weight: 700; }
.subtotal-line b { font-size: 19px; color: var(--ink); font-variant-numeric: tabular-nums; }

/* Full width, both of them, stacked. Card buttons are outlined so these are
   unmistakably the decision on the page. */
.pdp-buttons { display: grid; gap: 10px; }
.pdp-atc, .pdp-buynow { width: 100%; justify-content: center; padding: 15px 20px; font-size: 14px; }
.pdp-atc[disabled] { background: var(--muted); }
/* Dark, not a second orange. Two saturated buttons of the same colour make the
   shopper compare them instead of choosing; the express route is an
   alternative to the primary action, not a rival to it. */
.pdp-buynow { background: var(--btn-dark-bg); }
.pdp-buynow:hover { background: var(--btn-dark-hover); }

.trust-list { list-style: none; margin: 0 0 14px; padding: 16px 0 0; border-top: 1px solid var(--line); font-size: 13.5px; color: var(--body); }
.trust-list li { display: flex; align-items: center; gap: 10px; margin: 9px 0; }
.trust-list .ico { flex: 0 0 auto; color: var(--stock-ok); }

.pdp-trade {
  display: flex; align-items: flex-start; gap: 10px; margin: 0;
  padding: 13px 15px; border: 1px dashed var(--line); border-radius: var(--radius);
  font-size: 13.5px; line-height: 1.55; color: var(--body);
}
.pdp-trade .ico { flex: 0 0 auto; color: var(--cta); margin-top: 2px; }
.pdp-trade a { color: var(--cta); font-weight: 700; }

/* ---- stacked detail, formerly tabs ---------------------------------------- */
.pdp-detail { margin-top: clamp(28px, 4vw, 44px); border-top: 1px solid var(--line); }
.pdp-jump { display: flex; flex-wrap: wrap; gap: 8px; padding: 16px 0 4px; }
.pdp-jump a {
  padding: 8px 14px; min-height: 34px; border: 1px solid var(--line); border-radius: 100px;
  font-size: 12.5px; font-weight: 700; color: var(--body); text-decoration: none;
}
.pdp-jump a:hover { border-color: var(--cta); color: var(--cta); }
.pdp-sec { padding: 26px 0; border-bottom: 1px solid var(--line); scroll-margin-top: 128px; }
.pdp-sec > h2 { margin: 0 0 14px; font-size: clamp(18px, 2.2vw, 23px); }
.pdp-sec .prose { max-width: 74ch; font-size: 15px; }

.spec-table { width: 100%; max-width: 620px; border-collapse: collapse; font-size: 14px; }
.spec-table th, .spec-table td { padding: 9px 12px; border: 1px solid var(--line); text-align: left; vertical-align: top; }
.spec-table th { width: 38%; background: var(--wash); font-weight: 700; color: var(--ink); }

@media (max-width: 900px) {
  .pdp { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  /* Not sticky once it is above the buy column rather than beside it: a
     sticky gallery would cover the price it sits over. */
  .pdp-media { position: static; }
  .pdp-atc { max-width: none; }
}
@media (max-width: 480px) {
  /* auto-fit, not a fixed 2. A product with one confirmed identifier left an
     empty grey cell beside it, which reads as a missing value rather than as
     a product that simply has one. */
  .pdp-idents { grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); }
  .qty-row { gap: 12px; }
}

/* ==========================================================================
   CART AND CHECKOUT, rebuilt
   ========================================================================== */

/* ---- cart ----------------------------------------------------------------- */
.cart {
  display: grid; grid-template-columns: minmax(0, 1fr) 340px;
  gap: clamp(20px, 3vw, 40px); align-items: start;
  padding-block: 24px 56px;
}
.cart-main { min-width: 0; }

/* A bar rather than a sentence. "38.12 away" is a number people act on, and a
   bar is how they read it at a glance.

   NAMED .cart-ship, NOT .ship-meter. The add-to-cart banner in the layout
   already owns .ship-meter, and redefining it here as a bordered box turned
   that banner's progress track into a large empty rectangle. Shared class
   names in one global stylesheet are a collision waiting for the next
   component. */
.cart-ship {
  padding: 14px 16px; margin-bottom: 20px;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--wash);
}
.cart-ship p { display: flex; align-items: center; gap: 9px; margin: 0; font-size: 13.5px; }
.cart-ship .ico { flex: 0 0 auto; color: var(--cta); }
.cart-ship b { color: var(--ink); }
.cart-ship.done .ico { color: var(--stock-ok); }
.cart-ship-bar { height: 7px; margin-top: 10px; border-radius: 4px; background: var(--line); overflow: hidden; }
.cart-ship-bar > span { display: block; height: 100%; background: var(--stock-ok); transition: width .4s ease; }

.cart-lines { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
.cart-line {
  display: grid; grid-template-columns: 88px minmax(0, 1fr) 96px 96px;
  gap: 14px; align-items: start; padding: 16px 0; border-bottom: 1px solid var(--line);
}
.cart-line-media {
  display: block; border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; background: var(--wash); aspect-ratio: 1/1;
}
.cart-line-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cart-line-body { min-width: 0; }
.cart-line-title { display: block; font-size: 14.5px; font-weight: 600; color: var(--ink); text-decoration: none; line-height: 1.4; }
.cart-line-title:hover { color: var(--cta); }
.cart-line-opts { margin: 4px 0 0; font-size: 12.5px; color: var(--cta); }
.cart-line-unit { margin: 6px 0 0; font-size: 13px; color: var(--muted); }
.cart-line-unit s { margin-left: 5px; }
.cart-line-remove {
  margin-top: 8px; padding: 0; min-height: 24px;
  background: none; border: 0; cursor: pointer;
  font: inherit; font-size: 12.5px; color: var(--sale); text-decoration: underline;
}
/* The quantity stepper. Both buttons are real submits, so this works with
   JavaScript off; store.js intercepts them for the instant path. */
.qty-step {
  display: inline-flex; align-items: stretch;
  border: 1px solid var(--input-border); border-radius: var(--radius);
  background: #fff; overflow: hidden;
}
.qty-btn {
  flex: 0 0 auto; width: 34px; min-height: 40px; padding: 0;
  background: var(--wash); border: 0; cursor: pointer;
  font: inherit; font-size: 17px; line-height: 1; color: var(--ink);
  transition: background .12s ease;
}
.qty-btn:hover { background: var(--line); }
.qty-btn:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }
.qty-btn[disabled] { opacity: .35; cursor: not-allowed; }
.qty-btn[disabled]:hover { background: var(--wash); }

.cart-line-qty .qty-step input {
  width: 46px; min-height: 40px; padding: 9px 2px; text-align: center;
  border: 0;
  border-left: 1px solid var(--input-border);
  border-right: 1px solid var(--input-border);
  border-radius: 0; background: #fff;
  font-family: inherit; font-size: 14px; font-variant-numeric: tabular-nums;
}
/* The native spinners are a 10px target and look different in every browser.
   The buttons either side replace them. */
.cart-line-qty .qty-step input { -moz-appearance: textfield; appearance: textfield; }
.cart-line-qty .qty-step input::-webkit-outer-spin-button,
.cart-line-qty .qty-step input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* A thumb needs more than a cursor does. */
@media (pointer: coarse) {
  .qty-btn { width: 44px; min-height: 44px; }
  .cart-line-qty .qty-step input { min-height: 44px; width: 52px; }
}
.cart-line-total { margin: 0; text-align: right; font-size: 15px; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }

.cart-actions { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; padding-top: 18px; }
.cart-keep { display: inline-flex; align-items: center; gap: 6px; min-height: 24px; font-size: 13.5px; color: var(--body); text-decoration: none; }
.cart-keep .ico { transform: rotate(180deg); color: var(--muted); }
.cart-keep:hover { color: var(--cta); }

.cart-summary {
  position: sticky; top: 128px;
  padding: 22px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--wash);
}
.cart-summary h2 { margin: 0 0 14px; font-size: 17px; }
.cart-totals { margin: 0 0 14px; }
.cart-totals > div { display: flex; justify-content: space-between; gap: 12px; margin: 0 0 8px; font-size: 14px; }
.cart-totals dt, .cart-totals dd { margin: 0; }
.cart-totals dd { font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.cart-totals .is-off dd { color: var(--stock-ok); }
.cart-totals .is-muted { color: var(--muted); }
.cart-totals .is-muted dd { font-weight: 400; color: var(--muted); }

.cart-code { display: flex; gap: 8px; margin: 12px 0; }
.cart-code input {
  flex: 1 1 auto; min-width: 0; padding: 10px 11px; text-transform: uppercase;
  border: 1px solid var(--input-border); border-radius: var(--radius);
  font-family: inherit; font-size: 13.5px;
}
.cart-code.applied { align-items: center; }
.cart-code.applied span { flex: 1 1 auto; font-size: 13px; font-weight: 700; letter-spacing: 1px; color: var(--ink); }
.cart-code.applied button {
  padding: 0; min-height: 24px; background: none; border: 0; cursor: pointer;
  font: inherit; font-size: 12.5px; color: var(--sale); text-decoration: underline;
}
.cart-grand {
  display: flex; justify-content: space-between; gap: 12px;
  margin: 12px 0 0; padding-top: 14px; border-top: 1px solid var(--line);
  font-family: var(--font-head), sans-serif; font-size: 18px; color: var(--ink);
}
.cart-grand b { font-variant-numeric: tabular-nums; }
/* .btn is display:inline-block, so the justify-content this rule used to carry
   did nothing and the label sat against the left padding. Flex centres it and
   gives the lock icon a place to sit. */
.cart-checkout {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  width: 100%; margin-top: 16px; padding: 14px; text-align: center;
}
.cart-checkout .ico { flex: 0 0 auto; }

/* The icon layout belongs to cart-note-ico, NOT to cart-note.
   The sign-in note shares cart-note and begins with a link. While the base
   class was display:flex that link was a flex item, shrank to its minimum
   content width and wrapped as "Sign" / "in" down the left edge. */
.cart-note { margin: 12px 0 0; font-size: 12.5px; line-height: 1.55; color: var(--muted); }
.cart-note-ico { display: flex; align-items: flex-start; gap: 8px; }
.cart-note .ico { flex: 0 0 auto; margin-top: 1px; }
.cart-note a { color: var(--ink); font-weight: 700; }

/* ---- checkout -------------------------------------------------------------- */
.checkout { max-width: 1080px; padding-block: 22px 56px; }
.checkout h1 { margin: 6px 0 14px; font-size: clamp(24px, 3vw, 32px); }
.checkout-guest { margin: 0 0 18px; font-size: 13.5px; color: var(--muted); }
.checkout-guest a { color: var(--ink); font-weight: 700; }
.checkout-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) 348px;
  gap: clamp(18px, 3vw, 32px); align-items: start;
}
.checkout-grid > div:last-child { position: sticky; top: 128px; }

/* Delivery options. These classes are emitted by BOTH the server and the
   requote script, so first paint and every repaint are identical. They
   disagreed before, so choosing a state silently restyled the page under the
   one person on the site who is about to pay. */
.ship-opt {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 15px; margin-bottom: 10px; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--radius); background: #fff;
}
.ship-opt:hover { border-color: var(--muted); }
.ship-opt.on { border-color: var(--ink); box-shadow: 0 0 0 1px var(--ink) inset; }
.ship-opt input { flex: 0 0 auto; width: 18px; height: 18px; accent-color: var(--cta); }
.ship-opt-body { flex: 1 1 auto; min-width: 0; font-size: 14px; }
.ship-opt-body b { display: block; color: var(--ink); }
.ship-opt-body span { display: block; margin-top: 2px; font-size: 12.5px; color: var(--muted); }
.ship-opt-price { flex: 0 0 auto; font-size: 14px; color: var(--body); font-variant-numeric: tabular-nums; }
.ship-opt-price.is-free { color: var(--stock-ok); }
.checkout .ship-note { margin: 0; font-size: 13.5px; color: var(--muted); }
.checkout .ship-note.is-bad { color: var(--sale); }

/* The basket on the checkout page. Replaces .sum-items, which was two table
   cells holding a title truncated at 46 characters and a total: no photograph
   and no variant, on the last screen before payment. */
.sum-lines { list-style: none; margin: 0 0 16px; padding: 0; }
.sum-line {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 11px 0; border-bottom: 1px solid var(--line);
}
.sum-line:first-child { padding-top: 0; }
.sum-line:last-child { border-bottom: 0; padding-bottom: 4px; }

/* No overflow clipping here: the quantity badge deliberately sits outside the
   frame, and the frame is on the image itself so it can. */
.sum-line-media { position: relative; flex: 0 0 auto; width: 54px; height: 54px; }
.sum-line-media img {
  display: block; width: 100%; height: 100%; object-fit: contain;
  border: 1px solid var(--line); border-radius: var(--radius); background: #fff;
}
.sum-line-q {
  position: absolute; top: -7px; right: -7px;
  min-width: 20px; height: 20px; padding: 0 5px; border-radius: 999px;
  background: var(--ink); color: #fff;
  font-size: 11px; font-weight: 700; line-height: 20px; text-align: center;
  font-variant-numeric: tabular-nums;
}

/* min-width:0, or a long unbroken title pushes the row wider than the column
   and the summary grows a horizontal scrollbar. */
.sum-line-body { flex: 1 1 auto; min-width: 0; }
.sum-line-title {
  display: block; font-size: 13.5px; line-height: 1.4;
  color: var(--ink); text-decoration: none; overflow-wrap: anywhere;
}
.sum-line-title:hover { color: var(--cta); }
.sum-line-opts { display: block; margin-top: 3px; font-size: 12px; color: var(--body); }
.sum-line-unit {
  display: block; margin-top: 3px; font-size: 12px; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.sum-line-amt {
  flex: 0 0 auto; font-size: 14px; color: var(--ink);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.sum-row { display: flex; justify-content: space-between; gap: 12px; margin-bottom: 9px; font-size: 14px; }
.sum-row b { color: var(--ink); font-variant-numeric: tabular-nums; }
.sum-row.is-good b { color: var(--stock-ok); }
.sum-row .is-pending { font-weight: 400; color: var(--muted); }
.sum-grand {
  display: flex; justify-content: space-between; gap: 12px;
  margin: 10px 0 0; padding-top: 12px; border-top: 1px solid var(--line);
  font-family: var(--font-head), sans-serif; font-size: 18px; color: var(--ink);
}
.sum-grand b { font-variant-numeric: tabular-nums; }
.sum-pay { margin-top: 16px; padding: 14px; }
.sum-note { margin: 10px 0 0; font-size: 12.5px; line-height: 1.55; color: var(--muted); }

/* ---- a field that stopped the order ---------------------------------------
   There was no error state for a form field at all: a shopper who left the ZIP
   empty got the browser's own bubble, or on submit a message at the top of a
   page whose offending field was somewhere below the fold.

   Three things happen together, and they are deliberately separable: is-invalid
   marks it for as long as it is wrong, the message says what to do, and
   is-flash pulses it once, just after the page has scrolled it into view. */
.form-field.is-invalid > input,
.form-field.is-invalid > select,
.form-field.is-invalid > textarea { border-color: var(--sale); }
.form-err { margin-top: 5px; font-size: 12.5px; font-weight: 500; color: var(--sale); }

.form-field.is-flash > input,
.form-field.is-flash > select,
.form-field.is-flash > textarea { animation: fieldFlash .5s ease-in-out 3; }
@keyframes fieldFlash {
  0%, 100% { outline: 2px solid transparent; outline-offset: 2px; }
  50%      { outline: 2px solid var(--sale); outline-offset: 2px; }
}
/* The marking is the point; the movement is not. Someone who asked for less
   motion still gets the field picked out, and this is the branch the
   screenshot rig renders. */
@media (prefers-reduced-motion: reduce) {
  .form-field.is-flash > input,
  .form-field.is-flash > select,
  .form-field.is-flash > textarea {
    animation: none; outline: 2px solid var(--sale); outline-offset: 2px;
  }
}

@media (max-width: 900px) {
  .cart, .checkout-grid { grid-template-columns: minmax(0, 1fr); }
  .cart-summary, .checkout-grid > div:last-child { position: static; }
}
@media (max-width: 560px) {
  .cart-line { grid-template-columns: 64px minmax(0, 1fr); grid-template-areas: "media body" "qty total"; }
  .cart-line-media { grid-area: media; }
  .cart-line-body { grid-area: body; }
  .cart-line-qty { grid-area: qty; }
  .cart-line-total { grid-area: total; align-self: center; }
}

/* ==========================================================================
   THE FINDER APPS, rebuilt
   ========================================================================== */

/* ---- identify a key -------------------------------------------------------- */
.ik-form {
  position: relative; display: flex; align-items: center; gap: 8px;
  max-width: 620px; margin: 18px 0 10px;
}
/* Positioned against the field, not the form, so wrapping cannot move it. */
.ik-field { position: relative; display: flex; align-items: center; flex: 1 1 auto; min-width: 0; }
.ik-form-ico { position: absolute; left: 15px; top: 50%; transform: translateY(-50%); color: var(--cta); pointer-events: none; }
.ik-form input {
  flex: 1 1 auto; min-width: 0; padding: 15px 16px 15px 46px;
  border: 1px solid var(--input-border); border-radius: var(--radius);
  background: var(--input-bg); color: var(--ink);
  font-family: var(--font-body), sans-serif; font-size: 17px;
  letter-spacing: .06em; text-transform: uppercase;
}
.ik-form input::placeholder { text-transform: none; letter-spacing: 0; color: var(--muted); }
.ik-form input:focus { outline: none; border-color: var(--cta); box-shadow: 0 0 0 3px rgba(250, 70, 22, .18); }
.ik-form .btn { padding: 15px 24px; }

.ik-eg { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; margin: 0; font-size: 13px; color: var(--muted); }
.ik-eg a {
  padding: 3px 9px; border: 1px solid var(--line); border-radius: 100px;
  color: var(--body); text-decoration: none; letter-spacing: .05em;
}
.ik-eg a:hover { border-color: var(--cta); color: var(--cta); }

.ik-help h2 { margin: 0 0 18px; font-size: clamp(19px, 2.3vw, 24px); }
.ik-help-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(14px, 2vw, 22px); list-style: none; margin: 0 0 18px; padding: 0;
}
.ik-help-grid li { padding: 20px; border: 1px solid var(--line); border-radius: var(--radius); }
.ik-help-grid .ico { color: var(--cta); margin-bottom: 10px; }
.ik-help-grid h3 { margin: 0 0 7px; font-size: 15.5px; }
.ik-help-grid p { margin: 0; font-size: 13.5px; line-height: 1.6; color: var(--body); }
.ik-help code {
  padding: 1px 6px; border: 1px solid var(--line); border-radius: 3px;
  background: var(--wash); font-size: .92em; color: var(--ink);
}
.ik-help-more { margin: 0; font-size: 13.5px; color: var(--muted); }
.ik-help-more a { color: var(--cta); }

/* The hit banner leads with WHAT WAS RECOGNISED. Somebody who typed HU92 needs
   to know we read it as a keyway before they trust the grid underneath. */
.ik-hit {
  padding: 16px 18px; margin-bottom: 22px;
  border: 1px solid var(--stock-ok); border-left-width: 3px;
  border-radius: var(--radius); background: var(--wash);
}
.ik-hit-soft { border-color: var(--line); border-left-color: var(--cta); }
.ik-hit-head { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin: 0; font-size: 15px; }
.ik-hit .ico { flex: 0 0 auto; color: var(--stock-ok); }
.ik-hit-soft .ico { color: var(--cta); }
.ik-hit b { letter-spacing: .06em; color: var(--ink); }
.ik-hit-n { margin-left: auto; font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }
.ik-hit-warn { margin: 10px 0 0; font-size: 13px; line-height: 1.55; color: var(--body); }

/* ---- find your key --------------------------------------------------------- */
.kf-routes {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(16px, 2.4vw, 26px); align-items: start;
}
.kf-route { padding: clamp(20px, 2.8vw, 28px); border: 1px solid var(--line); border-radius: var(--radius); }
/* The code route is genuinely better than the make route, so it is weighted
   rather than numbered. Numbering them told somebody standing next to a car
   that they had failed step one. */
.kf-route-best { border-color: var(--cta); background: var(--wash); }
.kf-tag {
  margin: 0 0 8px; font-size: 10.5px; letter-spacing: 1.8px;
  text-transform: uppercase; font-weight: 700; color: var(--muted);
}
.kf-route-best .kf-tag { color: var(--cta); }
.kf-route h2 { display: flex; align-items: center; gap: 10px; margin: 0 0 8px; font-size: clamp(17px, 2vw, 21px); }
.kf-route h2 .ico { flex: 0 0 auto; color: var(--cta); }
.kf-route > p { margin: 0 0 16px; font-size: 14px; line-height: 1.6; color: var(--body); }

.kf-code-form { display: flex; flex-wrap: wrap; gap: 8px; }
.kf-code-form input {
  flex: 1 1 220px; min-width: 0; padding: 12px 14px;
  border: 1px solid var(--input-border); border-radius: var(--radius);
  background: var(--input-bg); color: var(--ink);
  font-family: inherit; font-size: 15px; letter-spacing: .05em; text-transform: uppercase;
}
.kf-code-form input::placeholder { text-transform: none; letter-spacing: 0; color: var(--muted); }
.kf-code-form input:focus { outline: 2px solid var(--cta); outline-offset: 1px; }
.kf-eg { display: flex; flex-wrap: wrap; align-items: baseline; gap: 7px; margin: 12px 0 0; font-size: 13px; color: var(--muted); }
.kf-eg a { color: var(--cta); letter-spacing: .05em; }
.kf-help { margin: 10px 0 0; font-size: 13px; }
.kf-help a { color: var(--cta); }

.kf-thin { margin-top: 14px; }
.kf-thin summary { cursor: pointer; padding: 8px 0; min-height: 24px; font-size: 13.5px; color: var(--muted); }
.kf-thin summary:hover { color: var(--cta); }
.kf-thin > div { margin-top: 10px; }

.kf-note {
  padding: clamp(20px, 3vw, 26px);
  border: 1px solid var(--line); border-left: 3px solid var(--cta);
  border-radius: var(--radius); background: var(--wash);
}
.kf-note h2 { margin: 0 0 10px; font-size: clamp(17px, 2vw, 21px); }
.kf-note p { margin: 0 0 10px; max-width: 76ch; font-size: 14px; line-height: 1.65; color: var(--body); }
.kf-note p:last-child { margin-bottom: 0; }
.kf-note a { color: var(--cta); }

@media (max-width: 900px) {
  .kf-routes { grid-template-columns: minmax(0, 1fr); }
  .ik-help-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 560px) {
  .ik-form { flex-wrap: wrap; }
  /* The field takes the row now, not the input inside it. */
  .ik-form .ik-field { flex-basis: 100%; }
  .ik-form input { font-size: 16px; }
  .ik-form .btn { flex: 1 1 auto; justify-content: center; }
  .ik-hit-n { margin-left: 0; flex-basis: 100%; }
}

/* ---- sticky buy bar --------------------------------------------------------
   Appears once the real add button scrolls out of view. It carries no form of
   its own: the button is form="pdpForm", so it submits the actual form with
   whatever variant and quantity are selected. A second form would be a second
   source of truth for the sku. */
.buybar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 85;
  background: #fff; border-top: 1px solid var(--line);
  box-shadow: 0 -6px 24px rgba(0, 0, 0, .12);
  animation: buybar-in .18s ease;
}
@keyframes buybar-in { from { transform: translateY(100%); } to { transform: none; } }
@media (prefers-reduced-motion: reduce) { .buybar { animation: none; } }

.buybar-inner {
  display: flex; align-items: center; gap: clamp(10px, 2vw, 18px);
  padding-block: 10px; min-height: 68px;
}
.buybar-img {
  flex: 0 0 auto; width: 44px; height: 44px; object-fit: cover;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--wash);
}
.buybar-info { flex: 1 1 auto; min-width: 0; }
.buybar-info b {
  display: block; font-size: 13.5px; line-height: 1.3; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.buybar-info span { display: block; margin-top: 2px; font-size: 12px; color: var(--cta); }
.buybar-info span:empty { display: none; }
.buybar-price {
  flex: 0 0 auto; font-size: 18px; font-weight: 700; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.buybar-btn { flex: 0 0 auto; padding: 13px 26px; }

@media (max-width: 700px) {
  /* The thumbnail and the title are the first things to go: on a phone the
     price and the button are the whole reason the bar exists, and the product
     is already on the screen behind it. */
  .buybar-img, .buybar-info { display: none; }
  .buybar-inner { justify-content: space-between; }
  .buybar-btn { flex: 1 1 auto; justify-content: center; }
}

/* ---- add-to-cart banner on a phone -----------------------------------------
   The banner is a single flex row with the thumbnail, the title, a progress
   track carrying an inline min-width:200px, the free-shipping note and two
   buttons. At 360 that wrapped to four rows, covered the top third of the
   screen, and squeezed the title down to "4...".

   The progress BAR goes and the sentence stays: "Add $57.47 more" is the part
   that changes behaviour, and the bar is a nicety that costs a whole row. */
@media (max-width: 640px) {
  .atc-inner { gap: 10px; padding: 10px 14px; }
  .atc-inner img { width: 42px; height: 42px; }
  .atc-info { flex: 1 1 140px; }
  .atc-info b { font-size: 13px; }
  /* The track only. The note beside it keeps its own .ship-meter box. */
  .atc-banner .ship-track { display: none; }
  .atc-banner .ship-meter { flex: 1 1 100%; }
  .atc-banner .ship-note { margin: 0; font-size: 12.5px; }
  .atc-actions { flex: 1 1 100%; }
  .atc-actions .btn { flex: 1 1 auto; justify-content: center; padding: 11px 10px; }
  .atc-close { position: absolute; top: 8px; right: 10px; }
  .atc-banner { position: fixed; }
  .atc-inner { position: relative; padding-right: 40px; }
}

/* ==========================================================================
   THE TWO FINDERS
   /keyfinder and /machine-finder share every class here. They ask different
   questions of different tables and the shopper job is identical: narrow three
   axes and look at what came back, so making them look or behave differently
   would be a cost with no benefit.

   The layout is a two-column split at desktop, picker left and the "other way
   in" panel right, collapsing to one column early. The picker itself is a
   three-up grid of steps that becomes a stack below 720px, because a 33%-wide
   select holding "Dolphin XP-005L" truncates on a phone, and a truncated
   option label is a wrong choice waiting to happen.
   ========================================================================== */

.finder {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: clamp(16px, 2.4vw, 28px);
  align-items: start;
}

.finder-form {
  padding: clamp(18px, 2.4vw, 26px);
  border: 1px solid var(--line);
  border-top: 3px solid var(--cta);
  border-radius: var(--radius);
  background: var(--bg);
}

.finder-steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.finder-step { display: flex; flex-direction: column; gap: 6px; min-width: 0; }

.finder-step label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}

/* The caret is ours, drawn over a select whose own arrow is removed. One
   appearance across every browser matters more here than anywhere else on the
   site: these three controls ARE the page. */
.finder-control { position: relative; display: block; }

.finder-control select {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  min-height: 46px;
  padding: 11px 38px 11px 13px;
  font: inherit;
  font-size: 15px;
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
  text-overflow: ellipsis;
}

.finder-control select:hover:not(:disabled) { border-color: var(--ink); }
.finder-control select:focus-visible { outline: 2px solid var(--cta); outline-offset: 1px; }

.finder-control select:disabled {
  color: var(--muted);
  background: var(--bg-soft);
  cursor: not-allowed;
}

.finder-caret {
  position: absolute;
  top: 50%;
  right: 12px;
  transform: translateY(-50%);
  pointer-events: none;
  color: var(--muted);
}

.finder-control select:disabled ~ .finder-caret { opacity: .45; }

/* One submit per step, for the no-JavaScript path. store.js sets
   data-finder-live on the form once it has taken over the cascade, and these
   go away: with live cascading they submit a half-finished selection. */
.finder-go { align-self: start; margin-top: 2px; padding: 8px 14px; font-size: 13px; }
.finder-form[data-finder-live] .finder-go { display: none; }

.finder-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

/* .btn is display:inline-block sitewide and .ico is display:block, so an SVG
   dropped inside a button takes a line of its own and the label wraps under
   it. These three Show parts buttons are the only ones on the site that carry
   an icon, so there was no convention to follow and nothing else to break:
   the button becomes a flex row here rather than .btn changing everywhere.
   gap replaces the icon margin, so there is one owner for the spacing. */
.finder-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 12px 22px;
  font-size: 15px;
  line-height: 1.2;
  white-space: nowrap;
}

/* The other way in. Quieter than the picker on purpose: it is the better route
   when it applies, but it applies less often, so it gets the sidebar rather
   than the top of the page. */
.finder-aside {
  padding: clamp(18px, 2.4vw, 24px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--wash);
}

.finder-aside h2 {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 8px;
  font-size: 16px;
}

.finder-aside h2 .ico { flex: 0 0 auto; color: var(--cta); }
.finder-aside > p { margin: 0 0 14px; font-size: 13.5px; line-height: 1.6; color: var(--body); }

.finder-code { display: flex; flex-wrap: wrap; gap: 8px; }

.finder-code input {
  flex: 1 1 190px;
  min-width: 0;
  min-height: 44px;
  padding: 10px 12px;
  font: inherit;
  font-size: 14px;
  letter-spacing: .06em;
  text-transform: uppercase;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg);
}

.finder-code input::placeholder { text-transform: none; letter-spacing: 0; color: var(--muted); }
.finder-code input:focus-visible { outline: 2px solid var(--cta); outline-offset: 1px; }
.finder-aside-note { margin: 12px 0 0; font-size: 13px; }
.finder-aside-note a { color: var(--cta); }

.finder-chips { display: flex; flex-wrap: wrap; gap: 8px; }

.finder-chip {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 7px 12px;
  font-size: 13px;
  color: var(--ink);
  text-decoration: none;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 100px;
}

.finder-chip:hover { border-color: var(--ink); }
.finder-chip.is-on { color: #fff; background: var(--ink); border-color: var(--ink); }

/* The claim label above a result set. Stated plainly rather than as an icon
   with a tooltip, because the whole point is that it gets read. */
.finder-claim {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 0 0 16px;
  padding: 11px 14px;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--body);
  background: var(--wash);
  border-left: 3px solid var(--cta);
  border-radius: 0 var(--radius) var(--radius) 0;
}

.finder-claim .ico { flex: 0 0 auto; margin-top: 2px; color: var(--cta); }
.finder-claim em { font-style: normal; font-weight: 700; color: var(--ink); }

@media (max-width: 1100px) {
  /* The aside drops below the picker well before the picker itself stacks.
     At 1024 with a sidebar, each of the three selects is about 110px, and
     "Choose a model first" truncates to "Choose a mo...". A placeholder a
     shopper cannot read is a control they do not understand. */
  .finder { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 720px) {
  /* Stacked, full width. A third of a phone screen cannot hold
     "Condor XC-MINI Plus", and a truncated option is a wrong choice. */
  .finder-steps { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .finder-go { align-self: stretch; }
  .finder-submit { flex: 1 1 100%; justify-content: center; }
}

/* ---- the header finder dropdowns ----------------------------------------
   Two buttons in the department row that open the same picker as the page.
   They are details elements so they work with the keyboard and with no
   script, and they carry the same markup, so everything above styles the
   panel with no duplication. */

.deptnav-finders { display: flex; align-items: center; gap: 8px; margin-left: auto; }

.findmenu { position: relative; }

.findmenu > summary {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 34px;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 600;
  color: inherit;
  white-space: nowrap;
  list-style: none;
  cursor: pointer;
  border: 1px solid currentColor;
  border-radius: 100px;
}

.findmenu > summary::-webkit-details-marker { display: none; }
.findmenu > summary:hover { color: var(--cta); }
.findmenu > summary:focus-visible { outline: 2px solid var(--cta); outline-offset: 2px; }
.findmenu[open] > summary { color: var(--cta); }
.findmenu > summary .ico { flex: 0 0 auto; }
.findmenu[open] > summary .findmenu-caret { transform: rotate(180deg); }
.findmenu-caret { transition: transform .18s ease; }

.findmenu-panel {
  position: absolute;
  z-index: 60;
  top: calc(100% + 10px);
  right: 0;
  width: min(360px, calc(100vw - 32px));
  padding: 18px;
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--line);
  border-top: 3px solid var(--cta);
  border-radius: var(--radius);
  box-shadow: 0 18px 40px rgba(0, 0, 0, .16);
}

.findmenu-panel .finder-steps { grid-template-columns: minmax(0, 1fr); gap: 12px; }
.findmenu-panel .finder-actions { margin-top: 14px; padding-top: 12px; }
.findmenu-panel .finder-submit { flex: 1 1 auto; justify-content: center; }
.findmenu-panel .finder-go { display: none; }

@media (max-width: 1080px) {
  /* The department row is already fighting for space at this width, and each
     finder has a full page of its own. The mobile drawer carries them. */
  .deptnav-finders { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .findmenu-caret { transition: none; }
}

/* The "All Ford ->" link beside a result heading.
 *
 * This class had no definition at all, which is why the arrow sat on its own
 * line: .ico is display:block, so an unstyled <a> puts the label on one line
 * and the SVG on the next. white-space: nowrap could never have fixed that,
 * because the SVG was not wrapping, it was a block. The rails elsewhere use
 * .see-all; this is the finder's own, so it is defined here rather than
 * borrowed. */
.section-more {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  gap: 6px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
}

.section-more:hover { color: var(--cta); }
.section-more .ico { transition: transform .15s ease; }
.section-more:hover .ico { transform: translateX(3px); }

@media (prefers-reduced-motion: reduce) {
  .section-more .ico { transition: none; }
  .section-more:hover .ico { transform: none; }
}

/* ==========================================================================
   Urgency, sale badges and the promo bar.

   ONE SIGNAL, ONE LINE, NO PULSE

   There is no animation on any of this and that is a decision, not an
   omission. A throbbing red timer is the visual grammar of a scam site, and
   this catalogue sells four thousand dollar key machines to tradespeople who
   have seen that grammar before and know what it usually precedes. The
   urgency here comes from the sentence being true, not from the pixels
   moving.

   The one place motion would have been justified, a digit rolling over, is
   also the one place it costs the most: the clock reflows the line every
   second, so the digits are locked to a reserved width instead.
   ========================================================================== */

/* ------------------------------------------------------------- the one line */
.urgency {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px;
  margin: 0 0 18px; padding: 9px 12px;
  border-radius: var(--radius);
  font-size: 13.5px; font-weight: 600; line-height: 1.35;
}

/* Stock and a closing sale earn the red panel. Interest does not: "40 people
   viewed this" is worth saying and is not an emergency, and putting it in the
   same red box as "last one in stock" is what teaches a reader that the red
   box means nothing. */
.urgency-high {
  background: #fdecea;
  color: var(--sale);
}
.urgency-low {
  background: var(--bg-soft);
  color: var(--body);
  font-weight: 500;
}

/* The dot, matching the availability line two rows up rather than introducing
   a second visual language for the same kind of statement. */
.urgency::before {
  content: ""; flex: 0 0 auto;
  width: 7px; height: 7px; border-radius: 50%;
  background: currentColor;
  transform: translateY(-1px);
}

.urgency-text { flex: 1 1 auto; min-width: 0; }

/* ---------------------------------------------------------- the flip clock */
/*
   A split-flap board, hinged the way a real one is.

   Four panels per digit, two static and two hinged:

     .flip-upper       top half, already carrying the NEW character
     .flip-lower       bottom half, still carrying the OLD one
     .flip-fold-front  the OLD top half, hinged along its bottom edge
     .flip-fold-back   the NEW bottom half, hinged along its top edge

   NOTHING TOGGLES display, AND THAT IS THE POINT

   The first version hid the hinged panels with `display: none` and switched
   them to `block` in the same frame the animation started. Browsers are not
   obliged to run an animation on an element that was display:none a moment
   ago, and the common result is the first frames being dropped: the flap jumps
   to halfway, or does not move at all. That is the stutter.

   So both hinged panels are always laid out, and geometry alone hides them:

     .flip-fold-front rests at 0deg, directly over .flip-upper, showing the
       same character. Covering an identical glyph is invisible.
     .flip-fold-back rests at 90deg, edge-on, which has no width to see.

   Adding .is-flipping only starts two animations. There is no layout change,
   no paint change, and nothing for the compositor to re-resolve.

   NO filter IN THE KEYFRAMES

   The earlier version animated `filter: brightness()` to fake light catching
   the flap. `filter` is not a compositor-only property: every frame forces a
   repaint of the panel, and with six digits ticking that is where a phone
   starts dropping frames. Transform alone stays on the compositor.

   THE VARIABLE IS LOAD-BEARING

   --flip-h drives the card height, the glyph line-height and the two glyph
   offsets at once. Set the height without it and the fold seam lands somewhere
   other than the middle of the character, which is the one thing that stops it
   reading as a flap.
*/
.urgency-clockrow { align-items: center; gap: 10px 14px; }
.urgency-clockrow .urgency-text {
  flex: 0 0 auto;
  font-size: 13px; letter-spacing: .4px; text-transform: uppercase;
  opacity: .85;
}

.flipclock {
  display: inline-flex; align-items: flex-start; gap: 4px;
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
}

.flip-col { display: inline-flex; flex-direction: column; align-items: center; gap: 5px; }
.flip-digits { display: inline-flex; gap: 3px; }

.flip-label {
  font-size: 9px; font-weight: 700; letter-spacing: 1.2px;
  text-transform: uppercase; opacity: .55;
}

.flip-sep {
  align-self: flex-start; padding-top: 4px;
  font-size: 20px; font-weight: 700; opacity: .3; line-height: 1;
}

.flip-card {
  --flip-h: 36px;
  --flip-w: 26px;
  --flip-size: 22px;
  position: relative; display: inline-block;
  width: var(--flip-w); height: var(--flip-h);
  border-radius: 4px;
  background: var(--ink);
  color: #fff;
  font-size: var(--flip-size); font-weight: 700;
  text-align: center;
  perspective: 190px;      /* shallow, so digits at the ends do not skew */
}

.flip-panel {
  position: absolute; left: 0; right: 0;
  height: 50%;
  overflow: hidden;
  background: var(--ink);
  backface-visibility: hidden;
}
.flip-upper, .flip-fold-front {
  top: 0;
  transform-origin: 50% 100%;
  border-radius: 4px 4px 0 0;
  /* The seam. One hairline reads as the join between two flaps. */
  box-shadow: inset 0 -1px 0 rgba(0,0,0,.55);
}
.flip-lower, .flip-fold-back {
  bottom: 0;
  transform-origin: 50% 0;
  border-radius: 0 0 4px 4px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.07);
}

.flip-glyph {
  position: absolute; left: 0; width: 100%;
  height: var(--flip-h);
  line-height: var(--flip-h);
  display: block;
}
.flip-upper .flip-glyph, .flip-fold-front .flip-glyph { top: 0; }
/* Pulled up half a card, so the lower panel crops the character's bottom half
   rather than its top. */
.flip-lower .flip-glyph, .flip-fold-back .flip-glyph { top: calc(var(--flip-h) * -0.5); }

/* Resting geometry. See the note above: this is what hides the hinged panels,
   not display. */
.flip-fold-front { z-index: 3; transform: rotateX(0deg); }
.flip-fold-back  { z-index: 3; transform: rotateX(90deg); }

/*
   NO will-change HERE, AND THAT IS THE FIX NOT AN OMISSION

   It used to be set on this same rule, which meant the compositor was asked to
   promote the panel to its own layer in the very frame the animation started.
   Promotion is not free and not instant, so the first frames go to setting up
   the layer instead of drawing the movement. Declaring an intention at the
   moment you act on it is the documented way to get a hitch out of will-change.
   A plain transform animation composites perfectly well without it.

   THE EASING IS THE OTHER HALF, AND IT WAS THE VISIBLE ONE

   The curves here were cubic-bezier(.42, 0, .8, .38) falling and its mirror
   landing. Seeking the animation frame by frame showed what that does:

     0ms 0deg | 45ms 4deg | 90ms 17deg | 135ms 43deg | 180ms 90deg

   Nineteen percent of the movement in half the time, then the rest in a rush.
   The flap looks frozen and then snaps, and a snap after a pause is read as a
   stutter, which is exactly what it was.

   A flap falls under gravity, and gravity covers a quarter of the distance in
   half the time. Plain ease-in lands at 31 percent, which is close enough and
   is a curve every browser tunes for. The landing half is ease-out, so the two
   join at full speed in the middle and the flap decelerates into its stop
   instead of arriving and then creeping.
*/
.flip-card.is-flipping .flip-fold-front {
  animation: flap-fall .17s ease-in both;
}
.flip-card.is-flipping .flip-fold-back {
  animation: flap-land .17s ease-out .17s both;
}

@keyframes flap-fall {
  from { transform: rotateX(0deg); }
  to   { transform: rotateX(-90deg); }
}
@keyframes flap-land {
  from { transform: rotateX(90deg); }
  to   { transform: rotateX(0deg); }
}

/* Bigger on the product page, where the countdown is a headline rather than a
   footnote. One variable, and the halves stay aligned. */
.urgency-clockrow.is-lg .flip-card {
  --flip-h: 46px; --flip-w: 34px; --flip-size: 28px;
}
.urgency-clockrow.is-lg .flip-sep { font-size: 26px; padding-top: 6px; }
.urgency-clockrow.is-lg .flip-label { font-size: 10px; }

/* The promo bar is already dark, so a black card on a black strip disappears. */
.promo-bar .flip-card {
  --flip-h: 26px; --flip-w: 20px; --flip-size: 15px;
  background: rgba(255,255,255,.16);
}
.promo-bar .flip-panel { background: rgba(255,255,255,.16); }
.promo-bar .flipclock { gap: 3px; }
.promo-bar .flip-label { display: none; }   /* no room, and the colons carry it */
.promo-bar .flip-sep { font-size: 15px; padding-top: 2px; }

@media (prefers-reduced-motion: reduce) {
  /* The number still changes, it just does not hinge. store.js writes the
     resting panels on a timer rather than on animationend, so the digit stays
     correct with the movement removed.

     The hinged panels keep their resting transforms here, which is what makes
     the static case correct: the front already shows the right character and
     the back is still edge-on. */
  .flip-card.is-flipping .flip-fold-front,
  .flip-card.is-flipping .flip-fold-back { animation: none; }
}

@media (max-width: 480px) {
  .urgency-clockrow { gap: 8px; }
  .urgency-clockrow .urgency-text { flex: 1 1 100%; }
  .urgency-clockrow.is-lg .flip-card { --flip-h: 40px; --flip-w: 30px; --flip-size: 24px; }
}

/* --------------------------------------------------------- card sale price */
/* The struck price is a real one. See Ds\Store\Promotions for why nothing
   renders here unless it is. */
.price-now.is-sale { color: var(--sale); }

/* ------------------------------------------------------------ the promo bar */
/* Lives in the announcement slot. It is a link because a shopper told about a
   sale and given nowhere to go is being teased rather than sold to. */
.promo-bar {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 6px 14px;
  padding: 0;
  font-size: 12.5px; font-weight: 700;
  letter-spacing: 0.4px;
  text-decoration: none;
  color: inherit;
}
.promo-bar:hover { text-decoration: underline; text-underline-offset: 3px; }


/* -------------------------------------------------- free shipping progress */
/* Reads the real threshold from Shipping settings. Hidden entirely once it is
   met, because a full progress bar that says "you did it" is a row of pixels
   asking for attention it no longer needs. */
.ship-progress { margin: 0 0 16px; }
.ship-progress p {
  margin: 0 0 7px;
  font-size: 13px; font-weight: 600; color: var(--body);
}
.ship-progress b { color: var(--cta); }
.ship-progress-track {
  height: 6px; border-radius: 999px;
  background: var(--line); overflow: hidden;
}
.ship-progress-fill {
  height: 100%; border-radius: 999px;
  background: var(--cta);
  transition: width .3s ease;
}
@media (prefers-reduced-motion: reduce) {
  .ship-progress-fill { transition: none; }
}

/* ------------------------------------------------------------- cart savings */
.cart-line-was {
  display: block;
  font-size: 12px; color: var(--muted);
  text-decoration: line-through;
  font-variant-numeric: tabular-nums;
}
.cart-saved {
  color: var(--sale); font-weight: 700;
}

/* --------------------------------------------------------------- small screens */
@media (max-width: 480px) {
  .urgency { gap: 4px 8px; }
}

/* ------------------------------------------------ confirm / unsubscribe page */
/* One narrow column, generous whitespace, one way out. See
   storefront/newsletter_state.php: somebody who just left the list is not a
   lead to be recovered, and this page is deliberately quiet. */
.state-card {
  max-width: 560px; margin: 0 auto; padding: 8px 0 40px;
  text-align: center;
}
.state-card h1 { margin: 0 0 14px; font-size: clamp(24px, 3vw, 32px); }
.state-card p { margin: 0 0 20px; color: var(--body); line-height: 1.6; }
.state-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

/* ---------------------------------- offer on the two hand-built home blocks */
/* The hero tag and the feature price are the only product prices outside
   _product_card. These give them the same vocabulary as a card: struck former
   price in muted, saving in the sale colour. */
.hero2-media-tag s,
.feat-price s {
  color: rgba(255,255,255,.6);
  text-decoration: line-through;
  font-weight: 400;
  margin-right: 2px;
}
.feat-price s { color: var(--muted); }
.hero2-media-tag i,
.feat-price i {
  font-style: normal; font-weight: 700;
  background: var(--sale); color: #fff;
  padding: 2px 6px; border-radius: 2px;
  font-size: 11px; letter-spacing: .5px;
  margin-left: 6px;
}
.feat-price.is-sale span { color: var(--sale); }

/* ------------------------------------------------------------ spam defences */
/*
   The honeypot.

   Positioned off-screen rather than display:none or type="hidden", both of
   which are exactly what a form-filling bot looks for to decide what to skip.
   A field it can see in the DOM and measure, that a person never encounters,
   is the one that catches things.

   aria-hidden and tabindex="-1" on the markup keep it away from screen readers
   and the tab order, so it is invisible to everybody it should be invisible
   to and present for the one thing it should not be.
*/
/* "From" before a card's price, when that product's variants differ.

   Deliberately quieter than the number it qualifies: it is a qualifier, not the
   price, and at the same weight it competes with the figure people are actually
   scanning for. */
.price-from {
  font-size: 12px; font-weight: 600; color: var(--muted);
  letter-spacing: .2px;
}

/* The variant on a customer's own order line.

   Not decoration: it is the answer to "did I order the right one", and this
   catalogue has products carrying eighty-odd variants. Kept quiet enough to sit
   under the title without competing with it, and never truncated. */
.line-variant {
  display: block; margin: 3px 0 0;
  font-size: 12.5px; line-height: 1.45; color: var(--muted);
}
/* Inline where it trails a shipment line rather than heading its own row. */
span.line-variant { display: inline; }

.hp-field {
  position: absolute !important;
  left: -9999px !important;
  top: auto; width: 1px; height: 1px;
  overflow: hidden;
}

.captcha-slot { margin: 12px 0; min-height: 66px; }
/* Reserved height, so the widget arriving does not shove the submit button
   down the page under somebody's thumb. */
.captcha-slot:empty { min-height: 0; }

/* A challenge on its own row, in a form that is otherwise one line.

   Two forms here are a field and a button welded into a single pill: the footer
   newsletter and the back-in-stock alert. A 300px widget dropped into either as
   a flex sibling squeezes the field down to nothing.

   Grid rather than flex-wrap because the widget has to sit BETWEEN the field
   and the button in the markup, which is the order somebody tabs through, and a
   wrapping flex row would then push the button onto a third line below the
   challenge. Placing all three by grid line keeps document order and visual
   order independent, which is the one thing flex cannot do here. */
.footer-news-form,
.notify-form {
  display: grid;
  grid-template-columns: 1fr auto;
  /* NOT align-items:start.

     These two forms are a field and a button welded into one pill, and the
     button only matches the field's height because it is stretched to it.
     Flex did that by default; naming `start` when this became a grid quietly
     shrank every JOIN button to its own text height and left a step down the
     right side of the pill. The captcha row below has its own fixed height, so
     stretching costs it nothing. */
  align-items: stretch;
}
.footer-news-form > input[type=email],
.notify-form > input[type=email] { grid-column: 1; grid-row: 1; }
.footer-news-form > .btn,
.notify-form > .btn { grid-column: 2; grid-row: 1; }
.footer-news-form > .captcha-slot,
.notify-form > .captcha-slot { grid-column: 1 / -1; grid-row: 2; margin: 12px 0 0; }
/* No widget, no row: the gap would otherwise leave a gutter under the pill. */
.footer-news-form > .captcha-slot:empty,
.notify-form > .captcha-slot:empty { margin: 0; }

/* Cards that hold a challenge give up some padding on a phone.

   Turnstile will not render narrower than 300px, at any setting except the
   150px-wide compact one that is twice as tall. Every card below is far wider
   than 300px on a desktop and none of them are on a 360px phone: the page
   gutter takes 32px and the card's own padding another 40 to 48, which leaves
   under 290 and the widget hangs over the card's own border by a visible
   margin. Twelve pixels of inset is unremarkable at that size and it is the
   only lever short of scaling the widget, whose contents are a fixed-size
   iframe we do not control. */
@media (max-width: 520px) {
  .auth-card,
  .notify-box,
  .review-form-card { padding-inline: 12px; }
}

/* The answer to the last signup. Quiet, because it sits in a dark footer and
   is read once. */
.footer-news-msg {
  margin: 0 0 12px; padding: 8px 11px; font-size: 12.5px; line-height: 1.5;
  background: rgba(255, 255, 255, .08); border-left: 3px solid var(--cta);
  border-radius: 0 var(--radius) var(--radius) 0;
}

/* ---- track your order -----------------------------------------------------

   One question, asked by somebody who is slightly worried: where is my parcel.
   The layout is ordered by how badly each answer is wanted -- progress, then
   the tracking link, then what is in the box, then where it is going.

   The page it replaced stacked four `spec-table` blocks, which is a two-column
   key/value component built for product specifications. Used for line items it
   truncated titles at 70 characters and appended the quantity, so a product
   read as "...ID49-7945P Chip For x 1", and it printed the phrase "Fulfillment
   status per item" at a customer. */
.track-page { max-width: 720px; }

/* The moment after paying. Bigger than a page heading normally is, because
   relief is the thing being communicated and everything below it is detail. */
.paid-hero { margin: 0 0 22px; }
.paid-hero h1 { margin: 0 0 8px; line-height: 1.2; }
.paid-hero .track-lede { margin: 0; }
.track-lede { color: var(--muted); font-size: 14.5px; margin: 0 0 20px; max-width: 60ch; }

.track-form {
  display: grid; grid-template-columns: 1fr 1fr auto; gap: 12px;
  align-items: end; margin: 0 0 26px;
}
.track-form .form-field { margin: 0; }
.track-form .btn { height: 42px; white-space: nowrap; }

.track-card {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 20px 22px; margin: 0 0 16px; background: #fff;
}
.track-card-title {
  margin: 0 0 12px; font-size: 15px; font-weight: 700; color: var(--ink);
}
.track-note { margin: 10px 0 0; font-size: 13.5px; line-height: 1.6; color: var(--muted); }

.track-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; margin-bottom: 18px;
}
.track-head h2 { margin: 0; font-size: 20px; }
.track-sub { margin: 3px 0 0; font-size: 13.5px; color: var(--muted); }
.track-status {
  padding: 5px 12px; border-radius: 100px;
  font-size: 12px; font-weight: 700; letter-spacing: .4px; white-space: nowrap;
}
.track-status-live { background: var(--cta); color: #fff; }
.track-status-stopped { background: var(--bg-soft); color: var(--muted); border: 1px solid var(--line); }
.track-stopped { margin: 0; font-size: 14px; line-height: 1.6; color: var(--muted); }

/* The progress line. A rule behind the dots, drawn on the row itself so it
   cannot drift out of line with them at any width. */
.track-steps {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; position: relative;
}
.track-step { position: relative; padding-top: 26px; text-align: center; }
.track-step::before {
  content: ''; position: absolute; top: 7px; left: 0; right: 0;
  height: 2px; background: var(--line);
}
.track-step:first-child::before { left: 50%; }
.track-step:last-child::before { right: 50%; }
.track-step.is-done::before { background: var(--cta); }
.track-dot {
  position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  width: 16px; height: 16px; border-radius: 50%;
  background: #fff; border: 2px solid var(--line);
}
.track-step.is-done .track-dot { border-color: var(--cta); background: var(--cta); }
/* The step you are actually on gets a ring, so "done" and "here" are not the
   same picture. */
.track-step.is-now .track-dot { box-shadow: 0 0 0 4px rgba(250, 70, 22, .18); }
.track-step-label { display: block; font-size: 12.5px; font-weight: 700; color: var(--muted); }
.track-step.is-done .track-step-label { color: var(--ink); }
.track-step-note { display: block; font-size: 11.5px; color: var(--muted); margin-top: 1px; }

/* ---- parcels ---- */
.parcel {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
  padding: 14px 0; border-top: 1px solid var(--line);
}
.track-card-title + .parcel, .track-note + .parcel { border-top: 0; padding-top: 4px; }
.parcel-main { min-width: 0; }
.parcel-name { font-size: 12px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 1px; }
.parcel-num { margin-top: 4px; font-size: 14.5px; word-break: break-all; }
.parcel-carrier { font-weight: 700; margin-right: 6px; }
.parcel-waiting { margin-top: 4px; font-size: 13.5px; color: var(--muted); line-height: 1.55; max-width: 46ch; }
.parcel-btn { flex: 0 0 auto; }
.parcel-when { margin-top: 4px; font-size: 12.5px; color: var(--muted); }

.parcel-items {
  list-style: none; margin: 0 0 6px; padding: 0 0 0 2px;
  color: var(--muted); line-height: 1.6;
}
/* On the li, not the ul. `.page-body li` sets 15px and beats a font-size
   inherited from the parent, so the parcel contents were rendering the same
   size as body copy and competing with the item list below them. */
.parcel-items li { font-size: 13px; }

/* ---- what is in it ---- */
.track-items { list-style: none; margin: 0; padding: 0; }
.track-item {
  display: flex; gap: 14px; align-items: flex-start;
  padding: 14px 0; border-bottom: 1px solid var(--line);
}
.track-item:first-child { padding-top: 0; }
.track-thumb {
  flex: 0 0 auto; width: 56px; height: 56px; object-fit: cover;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--bg-soft);
}
.track-thumb-empty { display: block; }
.track-item-body { flex: 1 1 auto; min-width: 0; }
.track-item-title { font-size: 14px; font-weight: 600; line-height: 1.45; color: var(--ink); }
.track-item-qty { margin-top: 3px; font-size: 12.5px; color: var(--muted); }
.track-item-price { flex: 0 0 auto; font-size: 14px; font-weight: 600; white-space: nowrap; }

.track-totals {
  display: grid; grid-template-columns: 1fr auto; gap: 7px 20px;
  margin: 16px 0 0; font-size: 14px;
}
.track-totals dt { color: var(--muted); }
.track-totals dd { margin: 0; text-align: right; font-weight: 600; }
.track-totals .is-total {
  padding-top: 10px; margin-top: 3px; border-top: 1px solid var(--line);
  font-size: 16px; font-weight: 700; color: var(--ink);
}
.track-totals .is-refund { color: var(--sale); }

.track-addr { font-style: normal; font-size: 14px; line-height: 1.6; }
.track-foot { margin: 20px 0 0; font-size: 13.5px; color: var(--muted); }

@media (max-width: 640px) {
  /* The form stacks, and the button spans, because a 33% wide Track button
     next to two stacked fields looks like a mistake. */
  .track-form { grid-template-columns: 1fr; }
  .track-form .btn { width: 100%; }
  /* Four steps do not fit across a phone, so they become two rows of two. */
  .track-steps { grid-template-columns: repeat(2, 1fr); gap: 18px 0; }
  .track-step::before { display: none; }
  .parcel-btn { width: 100%; text-align: center; }
}


/* ---- <picture> must never become the layout box ----
   The AVIF and WebP wrappers were added around <img> elements that already
   existed, and every rule that sizes or centres those images targets the img:
   .tiles-media img is 78% of a centring grid cell, .card-media img is 100% of
   a square. Wrapping them put an auto-sized <picture> in between, so those
   percentages resolved against the wrapper instead of the tile and the images
   sat off centre or overflowed their circle. display:contents removes the
   wrapper's box entirely, so the img goes back to being the grid or flex child
   it has always been. The <source> elements still work: format selection is
   done by the parser, not by layout. */
picture { display: contents; }


/* The way out of a short /alt/ grid. Centred, because it is the only thing on
   its row and a button hard against the left edge reads as a stray control. */
.alt-more { margin: 26px 0 4px; text-align: center; }

/* Brand cell with no mark of its own.
   Initials were here first and read as a failed image: fourteen cells of two
   grey letters is what a broken logo row looks like. One consistent key mark
   says "brand" once and then stops competing with the name beside it. */
.marq-mono { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
.marq-mono-mark {
  display: grid; place-items: center;
  width: 26px; height: 26px; border-radius: 50%;
  color: var(--brand, #d33a2c);
  background: color-mix(in srgb, var(--brand, #d33a2c) 10%, transparent);
}
.marq-mono-mark .ico { display: block; }
.marq-mono-name {
  font-size: 12.5px; font-weight: 650; color: var(--ink); letter-spacing: .2px;
}

/* ---- audit fixes ----------------------------------------------------------

   1. THE BRAND LABEL ON EVERY PRODUCT CARD FAILED CONTRAST.
   --cta is #fa4616, which is 3.53:1 on white. That is fine for a button, where
   the text sits on the orange rather than being the orange, and fine for a
   border. It is not fine for .card-brand: 10.5px uppercase text needs 4.5:1,
   and this appears on every card in every grid on the site.

   --cta-ink is the same hue darkened until it passes on white (5.04:1) and on
   the tinted panel (4.67:1), so the brand still reads as the brand. The button
   orange is untouched. */
:root { --cta-ink: #d23004; }
.card-brand { color: var(--cta-ink); }

/*
   2. THE TILE ROW ORPHANED TWO CELLS ON A TABLET.
   The grid is 6 / 4 / 3 across the breakpoints and there are six departments,
   so it filled at desktop and on a phone but left two empty cells at 1100px.
   Three columns divides six exactly, and a 3-up tile at tablet width is larger
   and easier to hit than a 4-up one. */
@media (max-width: 1100px) {
  .tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ---- pack-quantity note ----
   Sits under the quantity stepper on a product sold in tens, and under the
   quantity box on its cart line. One class, both places, because it is one
   sentence saying one thing and two classes would drift apart.
   padding-block, never the shorthand: the shorthand resets the gutter. */
.pack-note {
  display: block;
  margin: 6px 0 0;
  padding-block: 0;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--muted);
}
.cart-line-qty .pack-note { font-size: 11.5px; max-width: 12ch; }

/* ------------------------------------------- product page countdown, refined
   The pink slab stretched the full width of the buy column while the label
   and clock filled two thirds of it, so a third of a loud red panel was empty.
   Now it is a quiet white card with one red edge: what it says on the left,
   the clock on the right, and nothing left over.

   Still no motion beyond the flap itself, for the reason given above the
   .urgency block: urgency comes from the date being true, not the pixels.
   Scoped to .is-lg so the smaller clocks elsewhere are untouched.
   padding-block/inline rather than the shorthand, per the gutter trap. */
.urgency-clockrow.is-lg {
  justify-content: space-between;
  gap: 12px 20px;
  padding-block: 14px;
  padding-inline: 18px;
  background: #fff;
  color: var(--body);
  border: 1px solid rgba(204, 19, 19, .16);
  border-left: 3px solid var(--sale);
  border-radius: 6px;
  box-shadow: 0 1px 2px rgba(14, 16, 20, .04);
}
/* The dot moves inside the label, where it reads as part of the heading. */
.urgency-clockrow.is-lg::before { display: none; }

.urgency-meta {
  display: flex; flex-direction: column; gap: 4px;
  min-width: 0;
}
.urgency-clockrow.is-lg .urgency-text {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12px; font-weight: 700; letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--sale); opacity: 1;
}
.urgency-clockrow.is-lg .urgency-text::before {
  content: ""; flex: 0 0 auto;
  width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
}
.urgency-when {
  font-size: 13.5px; font-weight: 500; line-height: 1.35;
  color: var(--muted);
}
/* The smaller clocks have no room for a date line. */
.urgency-clockrow:not(.is-lg) .urgency-when { display: none; }

/* Labels and colons belong to the clock, not to the red: neutral ink. */
.urgency-clockrow.is-lg .flip-label { color: var(--muted); opacity: 1; letter-spacing: 1.4px; }
.urgency-clockrow.is-lg .flip-sep { color: var(--ink); opacity: .25; }
.urgency-clockrow.is-lg .flip-card { box-shadow: 0 2px 5px rgba(14, 16, 20, .16); }

@media (max-width: 480px) {
  .urgency-clockrow.is-lg { padding-inline: 14px; }
  .urgency-clockrow.is-lg .urgency-meta { flex: 1 1 100%; }
}
