/* Coldex Kitchen - storefront pages.
 * Builds on the tokens and dark-section machinery in site.css. */

/* ---------- breadcrumbs ---------- */
.crumbs{background:var(--paper);border-bottom:1px solid var(--line);font-size:13px}
.crumbs ol{list-style:none;margin:0;padding:14px 0;display:flex;flex-wrap:wrap;gap:9px;color:var(--muted)}
.crumbs li+li:before{content:"/";margin-right:9px;color:var(--line-strong)}
.crumbs a{color:var(--navy);font-weight:500}

/* ---------- hero ----------
   The banner artwork is light on the left and navy on the right, with the
   machines already in it. So the copy takes the light half and reads in ink -
   no scrim, no cut-outs, no overlay tint fighting the photograph. */
.hero{position:relative;background:var(--paper);isolation:isolate}
.hero-bg{position:absolute;inset:0;z-index:-1;display:block}
.hero-bg img{width:100%;height:100%;object-fit:cover;object-position:right center}

.hero-in{display:flex;align-items:center;min-height:clamp(440px,40vw,600px);
  padding-top:56px;padding-bottom:56px}
/* Capped so the copy never runs under the machines on the right of the artwork.
   600px is set by the lede, which measures 578px and would otherwise wrap onto a
   second line for the sake of 18px. */
.hero-copy{max-width:min(600px,54%)}

/* Two-tone headline. The accent word gets a soft amber underlay rather than a
   flat highlight - it reads as emphasis without turning into a marker pen. */
.hero-h1{margin-bottom:18px;color:var(--ink);font-size:clamp(34px,5vw,60px);
  letter-spacing:-.03em;line-height:1.06}
.hero-h1 span{position:relative;color:var(--orange);white-space:nowrap}
.hero-h1 span::after{
  content:"";position:absolute;left:0;right:0;bottom:.06em;height:.16em;z-index:-1;
  background:linear-gradient(90deg,rgba(253,194,14,.42),rgba(239,147,33,.18));
  border-radius:2px;
}

/* No ch cap: the line is short enough that the copy column is the only limit,
   and a 44ch cap was breaking it onto a second line for no reason. */
.hero-lede{font-size:17.5px;line-height:1.6;color:var(--body);margin-bottom:30px}
.hero-actions{display:flex;gap:14px;flex-wrap:wrap}

/* ---------- USP strip ----------
   Icon + two lines. The old version was text in a four-column table: full-height
   rules between cells and nothing to look at, so it read as a spec sheet. */
/* A card lifted onto the banner's lower edge rather than a full-width band butted
   against it. Same container width as the mega panel, so the two agree. */
.usp-bar{position:relative;z-index:3;margin-top:-58px}
.usp-bar-in{
  display:grid;grid-template-columns:repeat(4,1fr);
  background:var(--white);border:1px solid var(--line);border-radius:var(--radius-lg);
  box-shadow:0 18px 44px rgba(15,34,66,.11);padding:0 20px;
}
/* Tight side padding on purpose: the card's own inset already eats 40px of the
   row, and at 30px + 22px the four titles started wrapping again. */
.usp-item{
  position:relative;display:flex;align-items:center;gap:14px;padding:26px 16px;
}
.usp-item:first-child{padding-left:0}
.usp-item:last-child{padding-right:0}
/* A short centred hairline instead of a full-height rule - it separates without
   drawing a grid. */
.usp-item + .usp-item::before{
  content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);
  width:1px;height:38px;background:var(--line);
}
.usp-ic{
  flex:none;width:46px;height:46px;border-radius:12px;
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--tint);color:var(--navy);font-size:18px;
  transition:background .22s var(--ease),color .22s var(--ease);
}
.usp-item:hover .usp-ic{background:var(--orange);color:var(--ink)}
.usp-txt{display:flex;flex-direction:column;gap:3px;min-width:0}
.usp-item strong{font-size:15.5px;color:var(--ink);font-weight:700;letter-spacing:-.01em;
  line-height:1.3}
.usp-item .usp-txt span{font-size:13.5px;color:var(--muted);line-height:1.45}

/* 1279 and not a rounder number: --wrap caps at 1280, so at any viewport from
   1280 up the four columns are a constant 306px and never wrap. Below that the
   columns shrink with the viewport and the titles break, so two per row. */
@media (max-width:1279px){
  .usp-bar-in{grid-template-columns:repeat(2,1fr);column-gap:24px}
  .usp-item{padding:22px 0}
  .usp-item + .usp-item::before{display:none}
  .usp-item:nth-child(even)::before{content:"";display:block;left:-12px}
  .usp-item:nth-child(n+3){border-top:1px solid var(--line)}
}

/* ---------- page head ---------- */
.page-head{padding:60px 0 40px;border-bottom:1px solid var(--line)}
.page-head h1{margin-bottom:12px}
/* The page head already supplies breathing room; a full section pad underneath
   it left ~130px of dead space on cart, checkout and category pages. */
.page-head + .section,
.page-head + .section-thin + .section{padding-top:52px}
.lede{font-size:18.5px;line-height:1.7;color:var(--body);max-width:64ch;margin:0 0 6px}
.count{font-size:13px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);margin:14px 0 0}
.h-sm{font-size:clamp(21px,2.3vw,29px);margin-bottom:24px}
.section-thin{padding:26px 0;border-bottom:1px solid var(--line)}
.empty{color:var(--muted);padding:30px 0;font-size:16px}
.ck-small{font-size:13.5px;color:var(--muted)}

/* ---------- chips ---------- */
.chips{display:flex;flex-wrap:wrap;gap:9px}
.chip{display:inline-flex;align-items:center;gap:9px;background:var(--white);
  border:1px solid var(--line);border-radius:4px;padding:10px 17px;
  font-size:14px;font-weight:600;color:var(--ink);
  transition:background .18s var(--ease),color .18s var(--ease),border-color .18s var(--ease)}
.chip span{background:var(--tint);color:var(--navy);border-radius:3px;padding:1px 7px;
  font-size:12px;font-weight:700}
.chip:hover,.chip.is-on{background:var(--navy);color:#fff;border-color:var(--navy)}
.chip:hover span,.chip.is-on span{background:rgba(255,255,255,.18);color:#fff}

/* ---------- home category blocks ----------
   One block per category: heading, an SEO line, then five models. The first
   block scrolls, the rest are grids, so three categories in a row do not read
   as one long identical wall. */
.cat-block-head{display:flex;align-items:flex-end;justify-content:space-between;gap:32px;
  margin-bottom:30px}
.cat-block-head h2,.cat-block-head h3.as-h2{font-size:clamp(23px,2.5vw,33px);margin:0 0 8px}
.cat-block-intro{font-size:15.5px;line-height:1.7;color:var(--muted);margin:0;max-width:70ch}
.cat-block-all{
  flex:none;display:inline-flex;align-items:center;gap:9px;white-space:nowrap;
  font-size:12.5px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
  color:var(--navy);
}
.cat-block-all i{font-size:12px;transition:transform .2s var(--ease)}
.cat-block-all:hover i{transform:translateX(4px)}

/* Four per view, not five: with five models in the track, five per view leaves
   nothing to scroll and the "slider" is just a grid with hidden arrows. */
.prod-track > li{flex:0 0 calc((100% - 60px) / 4);scroll-snap-align:start}
.prod-track .pcard{height:100%}

/* Third block: copy on the left, a two-up slider on the right. A third full
   width row of cards would have read as more of the same. */
/* The slider column is sized so its two cards come out the same width as a card
   in the four-up grid above (1224 wrap, 20px gap => 291px each), and the copy
   takes whatever is left. A wider slider made the toaster cards noticeably
   bigger than every other card on the page. */
.cat-split{display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,calc((100% - 20px) / 2));
  gap:56px;align-items:center}
.cat-split-copy h2,.cat-split-copy h3.as-h2{font-size:clamp(23px,2.4vw,31px);margin:0 0 12px}
.cat-split-copy .cat-block-intro{margin:0 0 26px}
/* Two cards in view, with the arrows tucked inside so they cannot sit over the
   copy column. */
.prod-track-2 > li{flex:0 0 calc((100% - 20px) / 2)}
.cat-split-slider .slider-prev{left:-16px}
.cat-split-slider .slider-next{right:-16px}

/* ---------- why choose ---------- */
.why-head{display:flex;align-items:flex-end;justify-content:space-between;gap:32px;
  margin-bottom:40px}
.why-head .section-head,.why-head h2,.why-head h3.as-h2{margin-bottom:0}
.why-head h2,.why-head h3.as-h2{max-width:20ch}

.why-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}
/* Bordered panels rather than loose text under an icon, so the four read as a
   set and the band has some structure to it. */
.why-item{
  position:relative;padding:28px 24px 26px;border-radius:var(--radius-lg);
  background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.09);
  transition:background .22s var(--ease),border-color .22s var(--ease);
}
.why-item:hover{background:rgba(255,255,255,.07);border-color:rgba(255,255,255,.18)}
.why-no{
  position:absolute;right:20px;top:18px;
  font-size:30px;font-weight:800;line-height:1;letter-spacing:-.03em;
  color:rgba(255,255,255,.09);font-variant-numeric:tabular-nums;
}
.why-ic{
  display:inline-flex;align-items:center;justify-content:center;
  width:46px;height:46px;border-radius:12px;margin-bottom:18px;
  background:var(--orange);color:var(--ink);font-size:18px;
}
.why-item h3{font-size:16.5px;margin-bottom:8px}
.why-item p{font-size:14px;line-height:1.65;color:rgba(255,255,255,.62);margin:0}

/* ---------- product cards ----------
   The image well is a fixed square so a grid of mismatched supplier photos
   still lines up; when the client's own photography arrives it drops straight
   in without touching the layout. */
.pgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}
.pcard{
  position:relative;display:flex;flex-direction:column;background:var(--white);
  border:1px solid var(--line);border-radius:var(--radius-lg);overflow:hidden;
  transition:transform .24s var(--ease),box-shadow .24s var(--ease),border-color .24s var(--ease);
}
.pcard:hover{transform:translateY(-5px);border-color:var(--line-strong);
  box-shadow:0 12px 30px rgba(15,34,66,.13)}
.pcard-img{
  display:block;position:relative;background:var(--paper);
  aspect-ratio:1/1;padding:22px;border-bottom:1px solid var(--line);
}
.pcard-img img{width:100%;height:100%;object-fit:contain;
  transition:transform .32s var(--ease);mix-blend-mode:multiply}
.pcard:hover .pcard-img img{transform:scale(1.06)}

/* Saving badge. Orange is the accent everywhere else on the site, so the badge
   is ink-on-amber rather than a third colour. */
.pcard-off{
  position:absolute;left:12px;top:12px;z-index:1;
  background:var(--amber);color:var(--ink);border-radius:100px;padding:5px 11px;
  font-size:12px;font-weight:800;letter-spacing:.04em;
}

.pcard-body{display:flex;flex-direction:column;gap:8px;padding:18px 20px 20px;flex:1}
.pcard-name{font-size:16px;font-weight:700;color:var(--ink);line-height:1.35;
  letter-spacing:-.01em;margin:0}
.pcard-name a{color:inherit}
/* Stretched link: the name is the accessible target, the whole card is the
   clickable one - except the button, which sits above it on z-index. */
.pcard-name a::after{content:"";position:absolute;inset:0;z-index:0}
.pcard:hover .pcard-name a{color:var(--navy)}
/* Column, not a row: the stock line sits above the price so the price block
   has the full card width and stays on one line. */
.pcard-foot{
  margin-top:auto;padding-top:14px;border-top:1px solid var(--line);
  display:flex;flex-direction:column;align-items:flex-start;gap:6px;
}
/* One line: price, struck-through MRP and the tax note sit on a shared
   baseline rather than stacking into three rows. */
.pcard-price{display:flex;flex-direction:row;align-items:baseline;flex-wrap:wrap;
  gap:2px 7px;min-width:0}
.price{font-size:19px;font-weight:800;color:var(--ink);letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;line-height:1.2}
.price-ask{font-size:14.5px;font-weight:700;color:var(--navy)}
/* Both carry money, so both take the readable neutral rather than the quiet one.
   At --muted they measured 3.77:1 on white and 3.54:1 on --paper - legible on a
   desk monitor, thin on a phone held in daylight, which is where a buyer standing
   in their own kitchen actually reads them. */
.price-mrp{text-decoration:line-through;color:var(--muted-strong);font-size:13px;font-weight:500}
.price-tax{font-size:12px;color:var(--muted-strong);font-weight:600;letter-spacing:.04em}
.pcard-stock{
  flex:none;display:inline-flex;align-items:center;gap:5px;white-space:nowrap;
  font-size:11.5px;font-weight:700;color:#1B8A54;
}
.pcard-stock.is-out{color:var(--muted)}
.pcard-stock i{font-size:11px}

/* Above the stretched link so it is clickable, and full width so the card ends
   on a clear action. */
.pcard-add{margin-top:14px;position:relative;z-index:1}
.btn-block{width:100%;justify-content:center}
.pcard .btn-block{position:relative;z-index:1}
.pcard-add .btn i{font-size:13px}

/* ---------- product detail ----------
   Three columns: gallery, details, buy box. Two columns spread the page thin - the
   catalogue carries one line of copy and three to seven specs per product and no long
   description at all, so a wide middle column read as an empty page. Lifting the buy
   box into its own rail lets the middle column carry only what exists. */
/* The bottom padding is what separates the buying half of the page from the tab
   band below it. At 12px the band butted straight onto the thumbnails and the two
   read as one block. */
.pdp{padding:38px 0 clamp(36px,4vw,60px)}
/* Full bleed rather than the .wrap container. The row carries a photograph, the copy
   and a buy box; boxed to 1280 on a wide screen the three of them were squeezed while
   the page had space either side going spare. Padding scales with the viewport so the
   edges stay comfortable instead of running to the glass. */
.pdp-lay{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.05fr) 380px;
  gap:44px;align-items:start;max-width:none;
  padding-inline:clamp(20px,3.2vw,56px)}

/* ---- gallery ---- */
.pdp-gallery{position:sticky;top:104px}
/* ---- gallery slider ----
   Every slide is stacked in the same grid cell and the active one is faded up. A
   translating track was the other option, but a fade keeps the machine centred in the
   frame instead of sliding it past the edge, which is what you want when the four
   photographs are the same object from different angles.
   With JS off nothing gets .is-on, so :not(.is-on) never hides anything - the track
   falls back to a plain stack of visible photographs. */
.pdp-stage{position:relative;background:var(--paper);border:1px solid var(--line);
  border-radius:var(--radius-lg);padding:30px;aspect-ratio:1/1;overflow:hidden}
/* The row and column are pinned to the track, not left auto.
   Every slide shares cell 1/1, so an auto row takes the height of the TALLEST slide. One
   portrait photograph in the set (507x1200 on the deck ovens) blew the row out to 869px
   inside a 367px stage: the image filled that 869, object-fit centred the machine in the
   middle of it, and the visible window only reached a third of the way down - so the
   stage showed empty padding with the top edge of the machine at the bottom.
   minmax(0,1fr) plus min-height:0 forces the cell to exactly the stage instead. */
.pdp-track{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr);
  width:100%;height:100%}
.pdp-slide{grid-area:1/1;min-width:0;min-height:0;overflow:hidden;
  display:flex;align-items:center;justify-content:center}
.js .pdp-slide{opacity:0;visibility:hidden;transition:opacity .38s var(--ease)}
.js .pdp-slide.is-on{opacity:1;visibility:visible}

/* mix-blend-mode carries the product cut-outs, which are shot on white. */
.pdp-slide img{width:100%;height:100%;object-fit:contain;display:block;
  mix-blend-mode:multiply;transition:transform .25s var(--ease)}
/* Zoom is a scale plus a transform-origin the script moves with the pointer. A
   background-image swap would need a second, larger file that does not exist. */
.pdp-stage.is-zoomable{cursor:zoom-in}
.pdp-stage.is-zoom .pdp-slide.is-on img{transform:scale(2.1);transition:none}

/* -- video slide: poster, play badge, then the real player -- */
.pdp-play{position:relative;display:block;width:100%;height:100%;padding:0;border:0;
  background:none;cursor:pointer;border-radius:10px;overflow:hidden}
.pdp-play img{width:100%;height:100%;object-fit:cover;mix-blend-mode:normal;
  border-radius:10px;transition:transform .4s var(--ease)}
.pdp-play:hover img{transform:scale(1.03)}
.pdp-play-btn{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:66px;height:66px;border-radius:50%;display:inline-flex;align-items:center;
  justify-content:center;background:rgba(255,255,255,.94);color:var(--navy);
  font-size:22px;padding-left:4px;box-shadow:0 6px 22px rgba(10,23,48,.28);
  transition:background .2s var(--ease),color .2s var(--ease),transform .2s var(--ease)}
.pdp-play:hover .pdp-play-btn{background:var(--orange);color:#fff;
  transform:translate(-50%,-50%) scale(1.06)}
/* The caption sits on the photograph, so it needs its own ground rather than trusting
   whatever happens to be behind it. */
.pdp-play-cap{position:absolute;left:0;right:0;bottom:0;padding:26px 16px 14px;
  font-size:13px;font-weight:650;color:#fff;text-align:left;
  background:linear-gradient(transparent,rgba(10,23,48,.82))}
.pdp-player{width:100%;height:100%;border:0;border-radius:10px;background:#000;
  display:block;object-fit:contain}

/* -- controls --
   Arrows fade in on hover on a mouse, but stay put on touch where there is no hover to
   reveal them and the swipe is not discoverable on its own. */
.pdp-arrow{position:absolute;top:50%;transform:translateY(-50%);width:40px;height:40px;
  display:inline-flex;align-items:center;justify-content:center;
  border:1px solid var(--line);border-radius:50%;background:rgba(255,255,255,.94);
  color:var(--navy);cursor:pointer;box-shadow:var(--shadow-sm);z-index:2;
  opacity:0;transition:opacity .2s var(--ease),background .18s var(--ease),
    color .18s var(--ease)}
.pdp-arrow-prev{left:12px}
.pdp-arrow-next{right:12px}
.pdp-stage:hover .pdp-arrow,.pdp-arrow:focus-visible{opacity:1}
.pdp-arrow:hover{background:var(--navy);color:#fff;border-color:var(--navy)}
@media (hover:none){ .pdp-arrow{opacity:1} }

.pdp-count{position:absolute;left:14px;top:14px;margin:0;padding:4px 11px;
  border-radius:999px;background:rgba(10,23,48,.72);color:#fff;
  font-size:12px;font-weight:700;font-variant-numeric:tabular-nums;z-index:2}

.pdp-expand{position:absolute;right:12px;bottom:12px;width:38px;height:38px;
  display:inline-flex;align-items:center;justify-content:center;
  border:1px solid var(--line);border-radius:50%;background:var(--white);
  color:var(--navy);cursor:pointer;box-shadow:var(--shadow-sm);z-index:2;
  transition:background .18s var(--ease),color .18s var(--ease)}
.pdp-expand:hover{background:var(--navy);color:#fff;border-color:var(--navy)}

/* The stage has zoomed on hover since it was built and nothing ever said so. Hidden
   where there is no hover, because there the hint would be a lie. */
.pdp-zoom-hint{position:absolute;left:14px;bottom:14px;margin:0;
  display:inline-flex;align-items:center;gap:7px;font-size:12px;font-weight:600;
  color:var(--muted);opacity:0;transition:opacity .2s var(--ease);pointer-events:none}
.pdp-stage.is-zoomable:hover .pdp-zoom-hint{opacity:1}
/* :hover repeated, or this loses to the rule above on specificity and the hint stays up
   over the zoomed photograph it was only ever there to advertise. */
.pdp-stage.is-zoomable.is-zoom:hover .pdp-zoom-hint{opacity:0}
@media (hover:none){ .pdp-zoom-hint{display:none} }

/* 19 of the 45 products have no photograph. The empty state keeps the column the
   same height as a real gallery so the row does not collapse around it. */
.pdp-stage-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:8px;color:var(--muted);text-align:center}
.pdp-stage-empty i{font-size:44px;color:var(--line-strong)}
.pdp-stage-empty p{margin:0;font-size:14px;font-weight:600}
.pdp-ask-photo{font-size:13px;font-weight:700;color:var(--navy)}
.pdp-ask-photo:hover{color:var(--orange)}

/* -- thumbs --
   A slider: one row that scrolls, driven by arrows rather than by a bare scrollbar.

   It was a raw scroll strip with a visible scrollbar, which reads as unfinished and hides
   pictures behind a gesture people miss. It was briefly a wrapping grid, which showed
   everything but is not what was wanted here. This keeps the single row and gives it proper
   controls, on the SAME generic mechanism as the related-models row - .slider-track plus a
   .slider-nav naming it through aria-controls - so there is one slider behaviour on the site
   rather than two that drift.

   The wrapper is the positioning context for the arrows, which sit over the two ends.
   overflow:visible would let the outer arrow escape the column, so the wrapper is padded
   instead of the arrows being pulled outside it.

   scrollbar hidden, not removed: the track still scrolls with a wheel, a trackpad swipe and
   a touch drag, and still scrolls with JS off. Only the grey bar goes. */
.pdp-thumbs-wrap{position:relative;margin-top:12px}
/* margin and padding are RESET, not inherited. .slider-track in site.css carries
   `margin:-12px 0 -44px; padding:12px 0 44px` so a card's hover shadow is not sliced off by
   the overflow - real there, absurd here, where it would hang 44px of empty space under a
   74px thumb row. Everything else of that rule is wanted, so the class stays and only this
   is undone. store.css loads after site.css, so an equal-specificity override wins. */
.pdp-thumbs{display:flex;gap:10px;margin:0;padding:0;
  overflow-x:auto;scroll-snap-type:x proximity;
  scrollbar-width:none;-ms-overflow-style:none}
.pdp-thumbs::-webkit-scrollbar{display:none}
.pdp-thumb{position:relative;flex:none;width:74px;height:74px;padding:7px;
  background:var(--white);border:1px solid var(--line);border-radius:8px;cursor:pointer;
  scroll-snap-align:start;
  transition:border-color .18s var(--ease),box-shadow .18s var(--ease)}

/* The arrows sit ON the row, at its ends, because the row is only ~420px wide and a nav
   above it would cost a line of height for two small buttons. Hidden until the script finds
   the track actually overflows, and disabled at each end by the same script. */
/* Deliberately NOT the stage arrow.
   The stage carries a 40px white circle with a shadow, and .slider-btn is a 44px white circle
   with a shadow - so the two sat one above the other looking like the same control operating
   different things. These are square with the tile's own 8px radius, smaller, flat and
   borderless-on-rest, so they read as part of the thumbnail strip rather than as a second
   pair of gallery arrows. Still 30px, above the 24px minimum for a pointer target, and the
   row is dragged rather than clicked on touch where they are hidden anyway. */
.pdp-thumb-nav{position:static}
.pdp-thumb-nav .slider-btn{position:absolute;top:50%;transform:translateY(-50%);z-index:2;
  width:30px;height:30px;border-radius:8px;border:1px solid var(--line);
  background:rgba(255,255,255,.96);box-shadow:none;font-size:11px;color:var(--body)}
.pdp-thumb-nav .slider-btn:hover:not(:disabled){background:var(--navy);border-color:var(--navy);
  color:#fff}
.pdp-thumb-nav .slider-prev{left:0}
.pdp-thumb-nav .slider-next{right:0}
/* Fades at the ends, so a half-visible thumb reads as "there is more" rather than as a
   clipped picture. pointer-events:none or they would swallow clicks on the end thumbs. */
.pdp-thumbs-wrap::before,.pdp-thumbs-wrap::after{content:"";position:absolute;top:0;bottom:0;
  width:34px;pointer-events:none;z-index:1}
.pdp-thumbs-wrap::before{left:0;background:linear-gradient(90deg,var(--paper),transparent)}
.pdp-thumbs-wrap::after{right:0;background:linear-gradient(270deg,var(--paper),transparent)}
.pdp-thumb img{width:100%;height:100%;object-fit:contain;mix-blend-mode:multiply}
.pdp-thumb:hover{border-color:var(--line-strong)}
.pdp-thumb.is-on{border-color:var(--navy);box-shadow:0 0 0 2px rgba(32,67,125,.16)}
/* A video thumb has to be tellable from a photograph at 74px. */
.pdp-thumb-play{position:absolute;inset:0;display:flex;align-items:center;
  justify-content:center;border-radius:8px;background:rgba(10,23,48,.42);
  color:#fff;font-size:13px}
.pdp-thumb-play i{margin-left:2px}
/* ---- details ---- */
.pdp-eyebrow{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 12px;
  font-size:12px;font-weight:800;letter-spacing:.12em;text-transform:uppercase}
.pdp-eyebrow a{color:var(--navy)}
.pdp-eyebrow a:hover{color:var(--orange)}
/* .pdp-model removed with the markup - the eyebrow carried the model beside the
   category and the buy box printed it again a screen-width away. */
.pdp-info h1{font-size:clamp(24px,2.5vw,32px);line-height:1.22;letter-spacing:-.02em;
  margin:0 0 12px}
.pdp-lede{font-size:16px;line-height:1.65;color:var(--body);margin:0 0 22px}

/* The specs are the product's real content, so a few sit next to the price rather
   than only in the table below. */

/* Key points, under the one-line description. Ticked list, plain text from the
   admin - the tick, the weight and the spacing are all decided here, so a product
   with ten points looks like a product with two. */
.pdp-points{list-style:none;margin:0 0 22px;padding:0;display:grid;gap:9px}
.pdp-points li{display:flex;gap:11px;align-items:flex-start;font-size:15px;
  line-height:1.55;color:var(--body)}
.pdp-points i{flex:none;margin-top:4px;font-size:11px;color:#1E5B26;
  width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;
  background:#EDF7EE;border-radius:50%}

/* Applications render as the home page industries block - .ind-grid and .ind-item,
   shared, not copied. Only the ground differs: white here, between the tinted tab band
   above and the tinted related rail below. */
.pdp-apps{background:var(--white)}

/* The heading carries the product name, and those run to 45 characters - "Where the
   Commercial Contact Grill - Double Jumbo Plate is used" is 62. Inside the 62ch measure
   .section-head applies (about 620px, since ch is the body font not the heading's) every
   long name broke onto a second line. There is no intro paragraph under this heading, so
   the measure was not buying readability - it was only forcing the wrap. The row is
   free, so the heading gets it, one size down so the longest name still lands on one
   line at desktop widths. */
.pdp-apps .section-head{max-width:none}
.pdp-apps .section-head h2,.pdp-apps .section-head h3.as-h2{font-size:clamp(21px,2.4vw,32px)}

/* Order-level assurances, deliberately quieter than the key points above: no card, no
   colour, a hairline to separate them. They are reassurance a buyer checks for, not
   something to compete with what the machine actually does.

   One per row, not two up: at two columns every line wrapped and an odd third item was
   left stranded beside a hole. Stacked, nothing wraps and the rows fill the gap the
   column had below the key points, which is what this block is here to do. */
.pdp-assure{list-style:none;margin:0;padding:18px 0 0;border-top:1px solid var(--line);
  display:grid;gap:13px}
.pdp-assure li{display:flex;gap:12px;align-items:center;font-size:14px;
  line-height:1.45;color:var(--body)}
.pdp-assure-ic{flex:none;width:32px;height:32px;border-radius:9px;
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--paper);border:1px solid var(--line);color:var(--navy);font-size:13px}


/* ---- buy box ---- */
.pdp-buy{position:sticky;top:104px}
.pdp-buy-in{border:1px solid var(--line);border-radius:var(--radius-lg);
  background:var(--white);padding:22px;box-shadow:var(--shadow-sm)}
.pdp-price{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.pdp-now{font-size:30px;font-weight:800;letter-spacing:-.02em;color:var(--ink);
  font-variant-numeric:tabular-nums}
.pdp-was{font-size:16px;color:var(--muted);text-decoration:line-through;
  font-variant-numeric:tabular-nums}
.pdp-off{font-size:12px;font-weight:800;color:#1E5B26;background:#EDF7EE;
  border:1px solid #B4DDB8;border-radius:4px;padding:3px 8px}
/* The price above is the landed number. This line carries the other half a GST-registered
   buyer needs: the rate, and the taxable value they claim input credit on. It stays one
   quiet note - the heavy weight used to sit here because this line held the inclusive
   figure, and that figure has moved up into .pdp-now. */
.pdp-gst{margin:8px 0 0;font-size:13px;color:var(--muted)}
.pdp-gst span{color:var(--ink-soft,#4A5B75);font-weight:600}
.pdp-onask{margin:0;font-size:22px;font-weight:700;color:var(--ink)}

.pdp-stock{display:flex;align-items:center;gap:8px;margin:14px 0 18px;
  font-size:13.5px;font-weight:700}
.pdp-stock.is-in{color:#1E5B26}
.pdp-stock.is-out{color:var(--muted)}

/* Stepper and button on one line, which is what a buy box should look like. It only
   fits because the rail went to 380: "Add to Cart" needs 202px on one line and the
   old 330px rail left it 156 beside the stepper, so it wrapped onto two lines. The
   stepper is trimmed here too, to keep the button clear of that limit. */
.pdp-form{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:10px}
.pdp-qty{display:flex;align-items:center;flex:none;
  border:1px solid var(--line-strong);border-radius:4px;overflow:hidden}
.qty-btn{width:32px;align-self:stretch;border:0;background:var(--paper);cursor:pointer;
  font-size:17px;font-weight:700;color:var(--navy);line-height:1;
  transition:background .15s var(--ease)}
.qty-btn:hover{background:var(--tint)}
.pdp-qty input{width:38px;padding:12px 0;border:0;text-align:center;font:inherit;
  font-size:15px;font-weight:700;color:var(--ink);background:var(--white);
  -moz-appearance:textfield}
.pdp-qty input::-webkit-outer-spin-button,
.pdp-qty input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.pdp-qty input:focus{outline:none}
/* flex-basis is the whole trick: the button asks for 200px, so wherever the rail
   leaves less than that beside the stepper it drops to its own line and takes the
   full width instead of squeezing the label onto two. No breakpoint has to guess
   where that happens. */
.pdp-form .btn{flex:1 1 200px;white-space:nowrap;padding-inline:18px}
.pdp-quote{margin-bottom:16px}

.pdp-reach{display:flex;flex-direction:column;gap:10px;padding-top:16px;
  border-top:1px solid var(--line)}
.pdp-reach a{display:inline-flex;align-items:center;gap:9px;font-size:14px;font-weight:700}
.pdp-wa{color:#128C4B}
.pdp-wa:hover{color:#0E6E3B}
.pdp-call{color:var(--navy)}
.pdp-call:hover{color:var(--orange)}
.pdp-hsn{margin:14px 0 0;padding-top:12px;border-top:1px solid var(--line);
  font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}

/* ---- detail tabs ----
   A column of tabs on the left, the panel on the right. Four horizontal treatments -
   a full-width band, a pill group, a card with a tab strip, an accordion - and none
   read as controls. A list beside a panel does, and it fills a full-width row instead
   of leaving 1800px of empty space above the content. */
/* A tinted band, not white. The hero above and the related rail below are both white,
   so all three ran together as one unbroken page and the card here had nothing to lift
   off. Giving the middle section a ground turns the join into an edge you can see, and
   it is the section that deserves it - it is where the page changes from selling to
   explaining. Hairlines on both edges keep it crisp where the colours are this close. */
.pdp-detail{padding-block:clamp(32px,3.5vw,52px);background:var(--paper);
  border-block:1px solid var(--line)}
.pdp-detail-in{padding-inline:clamp(20px,3.2vw,56px)}
.pdp-vt{display:grid;grid-template-columns:264px minmax(0,1fr);
  border:1px solid var(--line);border-radius:var(--radius-lg);
  background:var(--white);box-shadow:var(--shadow-sm);overflow:hidden}

/* --tint, not --paper: the section behind the card is now paper, and a paper rail
   inside a white card on a paper ground made the card look like it was missing its
   left third. One step deeper keeps the rail recessed against the panel while still
   reading as part of the card. */
.pdp-vt-nav{display:flex;flex-direction:column;background:var(--tint);
  border-right:1px solid var(--line);padding:14px 0}
.pdp-vt-tab{
  display:flex;align-items:center;gap:13px;text-align:left;position:relative;
  padding:15px 22px;border:0;background:none;cursor:pointer;font:inherit;
  font-size:14.5px;font-weight:650;color:var(--body);
  transition:background .16s var(--ease),color .16s var(--ease);
}
.pdp-vt-tab i{flex:none;width:18px;font-size:14px;color:var(--line-strong);
  transition:color .16s var(--ease)}

/* A hairline between rows. Without one the three labels sat in an undivided block and
   read as a paragraph rather than a list of choices.
   Drawn as ::after on the second tab onwards, so there is a line between rows but none
   above the first or below the last. Inset to the label so it reads as a list rule and
   not a border across the rail. It is suppressed around the active tab: the active tab
   is white and runs into the panel, and a grey line crossing that join would cut the
   one surface the two are meant to share. */
.pdp-vt-tab + .pdp-vt-tab::after{content:"";position:absolute;left:22px;right:0;top:0;
  height:1px;background:var(--line)}
.pdp-vt-tab.is-on::after,
.pdp-vt-tab.is-on + .pdp-vt-tab::after{display:none}
.pdp-vt-tab:hover{background:rgba(255,255,255,.75);color:var(--ink)}
.pdp-vt-tab:hover i{color:var(--muted)}
/* Active: white, so it runs into the panel beside it, with an orange bar on the edge
   the eye starts from. margin-right covers the nav border - that join is what makes
   the tab and the panel read as one surface rather than two boxes. */
.pdp-vt-tab.is-on{background:var(--white);color:var(--navy);font-weight:700;
  margin-right:-1px;border-radius:0}
.pdp-vt-tab.is-on i{color:var(--orange)}
.pdp-vt-tab.is-on::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;
  background:var(--orange)}

/* Fills the empty foot of the rail. margin-top:auto pins it to the bottom so it sits
   against the panel's lower edge instead of floating in the middle of the gap, and it
   stays put whichever tab is open. */
.pdp-vt-help{margin-top:auto;padding:20px 22px 22px;border-top:1px solid var(--line);
  display:grid;gap:7px;justify-items:start}
.pdp-vt-help > i{font-size:16px;color:var(--orange)}
.pdp-vt-help-t{margin:0;font-size:14px;font-weight:700;color:var(--ink);line-height:1.35}
/* --body, not --muted: the rail went a step darker to sit against the tinted section,
   and muted grey on it measured 3.3:1 - under AA for text this size. */
.pdp-vt-help-p{margin:0 0 6px;font-size:13px;line-height:1.5;color:var(--body)}

.pdp-vt-body{padding:26px 28px;min-width:0}
.pdp-panel-h{margin:0 0 18px;font-size:18px;letter-spacing:-.01em;color:var(--ink)}
.pdp-panel{scroll-margin-top:var(--anchor-top)}
.pdp-panel + .pdp-panel{margin-top:34px}   /* only seen with JS off */
/* ---- inside a panel ----
   The table brings its own card, and inside this one that is a box in a box. */
.pdp-vt-body .spec-wrap{border:0;border-radius:0;box-shadow:none;overflow:visible}
.pdp-vt-body .spec{min-width:0}
/* The tinted label column was a slab that stopped in the middle of the panel with a
   hard edge and nothing beside it. Rules across the row read as a spec sheet; the
   label carries its weight through type instead of a fill. */
.pdp-vt-body .spec th,.pdp-vt-body .spec td{padding:13px 0;border-bottom:1px solid var(--line);
  font-size:15px;vertical-align:baseline}
.pdp-vt-body .spec th{width:220px;background:none;color:var(--muted);
  font-size:12px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;
  padding-right:24px}
.pdp-vt-body .spec td{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums}
.pdp-vt-body .spec tr:last-child th,.pdp-vt-body .spec tr:last-child td{border-bottom:0}
.pdp-vt-body .spec-note{margin-top:16px;padding-top:14px;border-top:1px solid var(--line)}

.pdp-vt-body.prose,.pdp-panel.prose{max-width:none}
/* The opening paragraph carries the summary, so it is set a size up - the panel reads
   as written copy rather than as a wall. */
.pdp-panel.prose > p:first-of-type{font-size:16.5px;color:var(--body)}
.pdp-panel.prose > p{margin:0 0 15px;line-height:1.75}
.pdp-panel.prose > p:last-child{margin-bottom:0}

/* No outer border: the panel is already the surface it sits on. */
.pdp-vt-body .pdp-faqs{border:0;border-radius:0}
.pdp-vt-body .pdp-faq:first-child{border-top:1px solid var(--line)}
.pdp-vt-body .pdp-faq summary{padding:15px 2px}
.pdp-vt-body .pdp-faq[open] summary{background:none}
.pdp-vt-body .pdp-faq summary:hover{background:none;color:var(--navy)}
.pdp-vt-body .pdp-faq-a{padding:0 2px 16px;color:var(--body)}

@media (max-width:820px){
  /* The column becomes a row above the panel, scrollable if the labels do not fit. */
  .pdp-vt{grid-template-columns:minmax(0,1fr)}
  .pdp-vt-nav{flex-direction:row;padding:0;border-right:0;
    border-bottom:1px solid var(--line);overflow-x:auto;scrollbar-width:none}
  .pdp-vt-nav::-webkit-scrollbar{display:none}
  .pdp-vt-tab{flex:none;padding:14px 18px;white-space:nowrap}
  /* The rail is a row here, so the divider has to turn with it - a line across the top
     of each tab would read as a border under the whole strip. */
  .pdp-vt-tab + .pdp-vt-tab::after{left:0;right:auto;top:10px;bottom:10px;
    width:1px;height:auto}
  .pdp-vt-tab.is-on{margin-right:0;margin-bottom:-1px}
  .pdp-vt-tab.is-on::before{left:0;right:0;top:0;bottom:auto;width:auto;height:3px}
  /* The rail is a scrolling row of tabs here - there is no empty foot to fill, and a
     card wedged into it would push the tabs off screen. The buy box already carries
     Get a quote on this width. */
  .pdp-vt-help{display:none}
  .pdp-vt-body{padding:20px}
}
@media (max-width:560px){
  .pdp-vt-body{padding:16px}
  .pdp-panel-h{font-size:16.5px;margin-bottom:14px}
}

/* ---- quote dialog ----
   [hidden] guard first: the attribute only sets display:none through the user-agent
   stylesheet, so any display here outranks it and the overlay would sit invisible over
   the whole page eating clicks. That exact bug shipped once already on the lightbox. */
.pdp-modal[hidden]{display:none}
.pdp-modal{position:fixed;inset:0;z-index:90;background:rgba(9,18,35,.62);
  display:flex;align-items:flex-start;justify-content:center;
  /* overscroll-behavior:contain - the dialog scrolls its own overflow, and without
     this, reaching its end hands the wheel to the page behind it. */
  padding:clamp(16px,5vh,64px) 18px;overflow-y:auto;overscroll-behavior:contain;
  animation:pdp-fade .18s var(--ease)}
@keyframes pdp-fade{from{opacity:0}to{opacity:1}}
.pdp-modal-card{position:relative;width:min(560px,100%);background:var(--white);
  border-radius:var(--radius-lg);padding:30px;box-shadow:0 30px 70px rgba(9,18,35,.34);
  animation:pdp-rise .22s var(--ease)}
@keyframes pdp-rise{from{transform:translateY(14px)}to{transform:translateY(0)}}
@media (prefers-reduced-motion:reduce){
  .pdp-modal,.pdp-modal-card{animation:none}
}
.pdp-modal-close{position:absolute;top:14px;right:16px;width:36px;height:36px;border:0;
  border-radius:50%;background:var(--paper);color:var(--muted);font-size:24px;line-height:1;
  cursor:pointer;transition:background .18s var(--ease),color .18s var(--ease)}
.pdp-modal-close:hover{background:var(--tint);color:var(--ink)}
.pdp-modal-head{margin-bottom:20px;padding-right:40px}
.pdp-modal-k{margin:0 0 6px;font-size:12px;font-weight:800;letter-spacing:.14em;
  text-transform:uppercase;color:var(--orange)}
.pdp-modal-h{margin:0 0 8px;font-size:20px;font-weight:700;line-height:1.3;
  letter-spacing:-.01em;color:var(--ink)}
.pdp-modal-sub{margin:0;font-size:14px;line-height:1.6;color:var(--muted)}
.pdp-modal-alt{margin:16px 0 0;padding-top:16px;border-top:1px solid var(--line);
  font-size:13.5px;color:var(--muted)}
.pdp-modal-alt a{color:var(--navy);font-weight:700}
.pdp-modal-alt a:hover{color:var(--orange)}
/* The form ships as its own bordered card, which is right on the contact page but
   makes a box inside a box here - the dialog is already the card. */
.pdp-modal .enq-form{border:0;background:none;box-shadow:none;padding:0}

/* ---- related models ----
   A slider rather than a grid: a category can hold fifteen models and a grid of four
   was showing an arbitrary quarter of them with no way to see the rest. The arrows sit
   in the heading row beside the category link, not floating over the cards, so nothing
   ever covers a price. */
.pdp-rel .rel-head{display:flex;align-items:flex-end;justify-content:space-between;
  gap:28px;flex-wrap:wrap;margin-bottom:26px}
.rel-k{margin:0 0 6px;font-size:12px;font-weight:800;letter-spacing:.14em;
  text-transform:uppercase;color:var(--orange)}
.rel-title h2,.rel-title h3.as-h2{margin:0;font-size:clamp(21px,2.2vw,28px);letter-spacing:-.01em}
.rel-act{display:flex;align-items:center;gap:18px;flex:none}
.rel-all{display:inline-flex;align-items:center;gap:9px;white-space:nowrap;
  font-size:13.5px;font-weight:700;color:var(--navy)}
.rel-all i{font-size:11px;transition:transform .2s var(--ease)}
.rel-all:hover{color:var(--orange)}
.rel-all:hover i{transform:translateX(3px)}
/* In the flow of the heading row, so they need no offset and cannot overlap a card. */
.pdp-rel .slider-nav{position:static;display:flex;gap:8px}
.pdp-rel .slider-btn{position:static;transform:none}

@media (max-width:640px){
  /* The link goes under the heading and the arrows keep the right edge. */
  .pdp-rel .rel-head{align-items:flex-start}
  /* flex-wrap, because this row could not fit and had no way to say so. `.rel-all` carries
     white-space:nowrap and its text is "View all <category>", so its width follows the
     category name - on a Bread & Bun Toaster it measured 207px. With 18px of gap and 96px
     of arrows that needs 321px, against the 280px a 320px-wide phone has, and the arrows
     were pushed 21px off the side of the page: a real horizontal scroll on the product
     page, present before any of today's work.

     Wrapping costs nothing when the row already fits - it only engages when it does not,
     which is why it is safe here rather than behind a narrower query. A narrower query
     would also be guesswork: the width that breaks depends on how long the category is
     called, not on the phone.

     margin-left:auto keeps the arrows on the right edge in both cases - beside the link
     when they fit, and on their own line under it when they do not. Without it
     space-between drops them to the left the moment they wrap. */
  .rel-act{width:100%;justify-content:space-between;flex-wrap:wrap;row-gap:14px}
  .pdp-rel .slider-nav{margin-left:auto}
}

/* ---- FAQs ----
   <details> rather than a scripted accordion: it works with JS off, the answers stay
   in the markup for a crawler, and it cannot be left half open by a failed script. */
.pdp-faqs{border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}
.pdp-faq + .pdp-faq{border-top:1px solid var(--line)}
.pdp-faq summary{display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:16px 20px;cursor:pointer;list-style:none;
  font-size:15px;font-weight:650;color:var(--ink);
  transition:background .16s var(--ease)}
.pdp-faq summary::-webkit-details-marker{display:none}
.pdp-faq summary:hover{background:var(--paper)}
.pdp-faq summary i{flex:none;font-size:12px;color:var(--muted);
  transition:transform .2s var(--ease)}
.pdp-faq[open] summary{background:var(--paper);color:var(--navy)}
.pdp-faq[open] summary i{transform:rotate(180deg);color:var(--orange)}
/* --body, not --muted. An FAQ answer is the content, not a caption, and muted at 14.5px
   is 3.77:1 - under AA. The product page never showed it because .pdp-vt-body overrides
   this to --body inside the tabs; the blog uses the rule as written and did. */
.pdp-faq-a{padding:2px 20px 18px;font-size:14.5px;line-height:1.7;color:var(--body);
  max-width:76ch}

/* ---- sticky bar ---- */
.pdp-bar{position:fixed;left:0;right:0;bottom:0;z-index:60;background:var(--white);
  border-top:1px solid var(--line);box-shadow:0 -8px 24px rgba(15,34,66,.1);
  transform:translateY(100%);transition:transform .22s var(--ease)}
.pdp-bar.is-up{transform:translateY(0)}
.pdp-bar-in{display:flex;align-items:center;justify-content:space-between;gap:24px;
  padding-block:9px}

/* flex:1 1 auto, and min-width:0 so the name can actually truncate.
   Without the grow this block was `flex:0 1 auto` and shrank to its image: below 560px
   the product name vanished completely and the bar showed a thumbnail, a wide gap, and
   the button. The name is the one thing telling you which product the bar belongs to. */
.pdp-bar-id{display:flex;align-items:center;gap:12px;flex:1 1 auto;min-width:0}
.pdp-bar-id img{width:40px;height:40px;object-fit:contain;flex:none;
  background:var(--paper);border-radius:4px;padding:3px;mix-blend-mode:multiply}
.pdp-bar-txt{display:grid;gap:2px;min-width:0}
.pdp-bar-name{font-size:14.5px;font-weight:700;color:var(--ink);line-height:1.25;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pdp-bar-meta{display:flex;align-items:center;gap:6px;font-size:12px;font-weight:600;
  color:var(--body);line-height:1.25;white-space:nowrap}
.pdp-bar-meta i{font-size:11px;color:#1E5B26}
.pdp-bar-sep{color:var(--line-strong)}

.pdp-bar-act{display:flex;align-items:center;gap:12px;flex:none}
.pdp-bar-price{display:grid;gap:1px;text-align:right;
  font-size:17px;font-weight:800;color:var(--ink);line-height:1.2;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.pdp-bar-price small{font-size:12px;font-weight:600;color:var(--body);margin-left:5px}
.pdp-bar-gross{margin-left:0 !important;font-size:12px;font-weight:600;color:var(--muted)}
.pdp-bar-ask{font-size:15px;font-weight:700;color:var(--body)}

/* The stepper is the buy box's, one size down to sit in a 9px-padded bar. */
.pdp-bar-qty{flex:none}
.pdp-bar-qty .qty-btn{width:28px;font-size:15px}
.pdp-bar-qty input{width:34px;padding:6px 0;font-size:13.5px}

@media (max-width:1080px){
  /* First to go: the taxable-value note and the model code. Both are detail the buy box
     carries in full - the bar only has to be enough to act on, and the inclusive price it
     leads with is the number that must never be hidden. */
  .pdp-bar-gross,.pdp-bar-sep{display:none}
}
@media (max-width:900px){
  /* Then the second action. Add to cart is the job of this bar; a quote is one scroll
     away in the buy box. */
  .pdp-bar-quote{display:none}
}
@media (max-width:680px){
  /* Then the stepper - one is the quantity nearly every order starts at, and the buy
     box still has the full control. */
  .pdp-bar-qty{display:none}
  .pdp-bar-in{gap:14px}
}
@media (max-width:520px){
  /* Then the thumbnail and the stock line, leaving the name, the price and the button.
     Below this the name is what stops the bar being anonymous, so it is the last thing
     to lose room rather than the first. */
  .pdp-bar-id img,.pdp-bar-meta{display:none}
  .pdp-bar-price{font-size:15px}
  .pdp-bar-in{padding-block:8px}
}
/* ---- lightbox ----
   The [hidden] guard is load bearing. The hidden attribute only sets display:none
   through the user-agent stylesheet, which any rule here outranks - so display:flex
   left this overlay open at all times. It is 93% opaque and covers the viewport, so
   the whole product page sat under it and every click landed on the overlay instead of
   the button beneath. Nothing looked wrong in the markup; only hit-testing showed it. */
.pdp-lb{position:fixed;inset:0;z-index:80;background:rgba(9,18,35,.93);
  display:flex;align-items:center;justify-content:center;padding:56px 20px;
  overscroll-behavior:contain}
.pdp-lb[hidden]{display:none}
.pdp-bar[hidden]{display:none}
.pdp-lb figure{margin:0;max-width:min(900px,100%);max-height:100%;
  display:flex;flex-direction:column;gap:14px}
.pdp-lb img{max-width:100%;max-height:78vh;object-fit:contain;
  background:#fff;border-radius:var(--radius)}

/* The video box had no rule at all, and a YouTube video opened here at about 300x150 while
   the same video filled its slide in the gallery.
   .pdp-player is width:100%/height:100%. In a slide that works, because the slide has a size
   of its own. Here its parent is a plain <div>, so 100% resolved against nothing and the
   iframe fell back to its intrinsic 300x150.

   Sized from the VIEWPORT, not from the parent, and that is the whole fix. `width:100%` was
   tried first and changed nothing: `.pdp-lb figure` has a max-width but no width, so as a
   flex item its width comes from its content - which is this box. Each was waiting on the
   other, and the browser broke the loop with the iframe's intrinsic 300px. Viewport units
   have no such dependency.

   The three terms: 900px matches the figure's own cap; 100vw - 40px is the room left by the
   overlay's 20px side padding; 78vh x 16/9 is the widest box whose height still lands inside
   the 78vh the images are held to, so a video and a photograph open at the same size.
   The ratio is on the WIDTH for that reason - with aspect-ratio, a max-height would clamp
   the height while the width stayed, and the video would come out squashed. */
.pdp-lb #pdp-lb-video{width:min(900px, 100vw - 40px, 78vh * 16 / 9);
  aspect-ratio:16/9;margin-inline:auto;
  border-radius:var(--radius);overflow:hidden;background:#000}
/* Same trap as the overlay above: a display rule here would outrank the hidden attribute
   and leave a silent player sitting on top of every photograph. */
.pdp-lb #pdp-lb-video[hidden]{display:none}
.pdp-lb figcaption{text-align:center;font-size:13.5px;color:rgba(255,255,255,.66)}
.pdp-lb-close{position:absolute;top:16px;right:20px;width:42px;height:42px;border:0;
  border-radius:50%;background:rgba(255,255,255,.1);color:#fff;font-size:26px;
  line-height:1;cursor:pointer;transition:background .18s var(--ease)}
.pdp-lb-close:hover{background:rgba(255,255,255,.2)}
.pdp-lb-nav{position:absolute;top:50%;transform:translateY(-50%);width:46px;height:46px;
  border:0;border-radius:50%;background:rgba(255,255,255,.1);color:#fff;cursor:pointer;
  transition:background .18s var(--ease)}
.pdp-lb-nav:hover{background:rgba(255,255,255,.22)}
.pdp-lb-prev{left:16px}
.pdp-lb-next{right:16px}

@media (max-width:1240px){
  /* The buy rail is the first thing to give: it can sit under the details and still
     be the loudest block on the page. */
  .pdp-lay{grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);gap:36px}
  .pdp-buy{grid-column:1 / -1;position:static}
  /* Sticky only works while something tall stands beside it. Once the buy box drops
     to a full-width row underneath, a pinned gallery stays put and sits on top of it -
     492 by 400 pixels of the buy box were unclickable at 1100. */
  .pdp-gallery{position:static}
  .pdp-buy-in{display:grid;grid-template-columns:minmax(0,1fr) minmax(320px,auto);
    gap:18px 28px;align-items:center}
  .pdp-buy-in > .pdp-price{grid-column:1}
  .pdp-reach{flex-direction:row;gap:22px;grid-column:1 / -1}
}
@media (max-width:900px){
  .pdp-lay{grid-template-columns:minmax(0,1fr);gap:28px}
  .pdp-buy-in{grid-template-columns:minmax(0,1fr)}
}
@media (max-width:560px){
  .pdp{padding-top:22px}
  .pdp-stage{padding:18px}
  /* Smaller tiles on a phone. The arrows are already gone by here - site.css hides every
     .slider-nav below 640px, because a strip is dragged with a thumb at this size and a 44px
     button would sit on top of the end tiles. The fades stay, so it still reads as
     scrollable. */
  .pdp-thumb{width:60px;height:60px}
  .pdp-thumbs{gap:8px}
  .pdp-modal-card{padding:22px}
  .pdp-reach{flex-direction:column;gap:12px}
  /* `.pdp-bar-id span{display:none}` used to sit here, from when the bar's name was a
     bare span. The name is wrapped in .pdp-bar-txt now, and that is a span too, so this
     rule hid the entire text block - the bar rendered as a thumbnail, a gap, and the
     button. The bar's own breakpoints above drop things one at a time instead, and the
     name is the last to go. */
  .pdp-lb{padding:52px 12px}
  .pdp-lb-nav{width:38px;height:38px}
}
/* ---------- spec table ---------- */
.spec-wrap{overflow-x:auto;border:1px solid var(--line);border-radius:var(--radius);
  background:var(--white);box-shadow:var(--shadow-sm)}
.spec{width:100%;border-collapse:collapse;min-width:440px}
.spec th,.spec td{text-align:left;padding:16px 22px;border-bottom:1px solid var(--line);font-size:15px}
.spec th{width:34%;color:var(--muted);font-weight:600;background:var(--paper);
  font-size:13px;letter-spacing:.06em;text-transform:uppercase}
.spec td{color:var(--ink);font-weight:500}
.spec tr:last-child th,.spec tr:last-child td{border-bottom:0}
.spec-note{font-size:13px;color:var(--muted);margin-top:14px}

/* ---------- prose ---------- */
.prose{max-width:72ch}

/* The .wrap.prose pair is gone: page.php was its only user and it now lays out as
   .policy-layout below. The rules it needed are kept here as a warning rather than as
   code, because the reason they went wrong is easy to write again.

   They read `.wrap.prose > * { max-width:72ch }`, and ch is measured in the ELEMENT'S OWN
   font. A 16.5px paragraph got 746px and a 27px h2 got 1224px off the same declaration,
   so headings ran almost half as wide again as the text under them. Any measure meant to
   hold across mixed type sizes has to be set in one place, in a unit that does not follow
   the font - which is what .policy-body does. */
.prose h2,.prose h3.as-h2{font-size:27px;margin:38px 0 14px}
.prose h3{font-size:20px;margin:30px 0 10px}
.prose p,.prose li{font-size:16.5px;line-height:1.8}
.prose ul,.prose ol{padding-left:22px}
.prose li{margin-bottom:9px}
.prose strong{color:var(--ink);font-weight:650}

/* ---------- policy pages ----------
   A policy is read to answer one question - can I return this, who pays the freight -
   and the reader usually has a second question right after. So the page is a column of
   text with the other policies beside it, rather than a column of text beside nothing:
   the old single-column layout left the right 45% of a 1280px page empty. */
.policy-layout{display:grid;grid-template-columns:minmax(0,1fr) 290px;gap:56px;align-items:start}

/* One measure, in rem, so headings and body share it. Set here and nowhere else - see the
   note beside the deleted .wrap.prose rules for what happens when it is set in ch. */
.policy-body{max-width:47rem;min-width:0}
.policy-body > :first-child{margin-top:0}

.policy-stamp{margin:38px 0 0;padding-top:16px;border-top:1px solid var(--line);
  font-size:13.5px;color:var(--body)}

.policy-side{position:sticky;top:104px;display:flex;flex-direction:column;gap:22px}
.policy-side-h{margin:0;font-size:12px;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--body)}
.policy-nav{display:flex;flex-direction:column;gap:2px;margin-top:-8px}
.policy-nav a{padding:10px 14px;border-radius:7px;font-size:14.5px;color:var(--body);
  text-decoration:none;border-left:2px solid transparent}
.policy-nav a:hover{background:var(--tint);color:var(--navy)}
.policy-nav a:focus-visible{outline:2px solid var(--orange);outline-offset:2px}
/* The current page is marked with the orange rail rather than a navy fill: a solid block
   in a quiet sidebar pulls the eye away from the text, which is the point of the page. */
.policy-nav a.is-on{background:var(--tint);color:var(--ink);font-weight:650;
  border-left-color:var(--orange)}

.policy-ask{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);
  padding:18px 20px}
.policy-ask-h{margin:0 0 6px;font-size:15px;font-weight:700;color:var(--ink)}
.policy-ask p{margin:0 0 14px;font-size:13.5px;line-height:1.65;color:var(--body)}
.policy-ask-tel{display:inline-flex;align-items:center;gap:8px;font-size:15px;font-weight:700;
  color:var(--navy);text-decoration:none}
.policy-ask-tel i{color:var(--orange);font-size:13px}
.policy-ask-tel:hover{color:var(--ink)}
.policy-ask-link{display:block;margin-top:10px;font-size:13.5px;color:var(--body)}
.policy-ask-link:hover{color:var(--navy)}

/* The sidebar becomes a footer to the policy below 980: sticky navigation that has to be
   scrolled past to reach the text it navigates is worse than no navigation. */
@media (max-width:980px){
  .policy-layout{grid-template-columns:1fr;gap:36px}
  .policy-body{max-width:none}
  .policy-side{position:static;padding-top:26px;border-top:1px solid var(--line)}
  .policy-nav{margin-top:0}
}

/* ---------- enquiry ---------- */
.enq-wrap{display:grid;grid-template-columns:1fr 1.1fr;gap:56px;align-items:start}
.enq-alt{font-size:15px;color:var(--muted)}
.enq-form{background:var(--white);border:1px solid var(--line);border-radius:var(--radius);
  padding:30px;box-shadow:var(--shadow)}
.enq-form label{display:block;font-size:13px;font-weight:700;color:var(--ink);margin-bottom:18px;
  letter-spacing:.03em}
.enq-form label span{color:var(--orange)}
/* The select has to be listed alongside the inputs. It was added to the contact
   form later and matched none of these rules, so it rendered as a native control
   sitting half the height of every field beside it. */
/* line-height is explicit so the select matches the inputs exactly. Left to
   `normal` a select computes a shorter line box than a text input and came out 3px
   short of the field beside it. */
.enq-form input,.enq-form textarea,.enq-form select{width:100%;margin-top:8px;padding:14px 15px;
  border:1px solid var(--line-strong);border-radius:4px;font-size:15px;font-family:inherit;
  font-weight:400;line-height:1.5;color:var(--ink);background:var(--white)}
.enq-form input:focus,.enq-form textarea:focus,.enq-form select:focus{outline:none;
  border-color:var(--navy);box-shadow:0 0 0 3px rgba(32,67,125,.11)}
/* Native arrow off, ours on - otherwise the control keeps the OS look and the
   padding above does nothing on Windows. The chevron is an inline SVG data URI so
   it needs no icon font and no extra request. */
.enq-form select{
  appearance:none;-webkit-appearance:none;padding-right:42px;cursor:pointer;
  background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%237185A0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 15px center;
}
/* The +91 is part of the field, not a separate control - one border round both
   so it reads as one input with a fixed prefix. focus-within moves the focus ring
   onto the wrapper, because the real input has no border of its own here. */
.enq-tel{display:flex;align-items:stretch;margin-top:8px;
  border:1px solid var(--line-strong);border-radius:4px;background:var(--white);
  overflow:hidden}
.enq-tel:focus-within{border-color:var(--navy);box-shadow:0 0 0 3px rgba(32,67,125,.11)}
/* Self-contained, and deliberately not scoped to .enq-form. phone_field() is used
   in .auth-form (register), the account forms and checkout too, and there the host
   form styles the input itself - it kept its own border, radius and margin-top and
   rendered as a box inside the box.
   `.enq-tel .enq-cc` (two classes) outranks `.enq-form label span`, which paints
   every span in a label orange for the required asterisk.
   `.enq-tel input[type=tel]` (two classes + an attribute) outranks any host form
   rule like `.auth-form input`, whatever order the stylesheets load in. */
.enq-tel .enq-cc{
  display:flex;align-items:center;padding:0 13px;flex:none;
  background:var(--paper);border-right:1px solid var(--line-strong);
  font-size:15px;font-weight:700;color:var(--muted);font-variant-numeric:tabular-nums;
}
/* Only the reset - no padding, size or colour. Those keep coming from whichever
   form the field is dropped into (.enq-form is 14/15, .auth-form is 13/14), so the
   wrapper ends up exactly as tall as the fields beside it instead of 2px taller. */
.enq-tel input[type="tel"]{margin:0;border:0;border-radius:0;box-shadow:none;
  width:100%;font-variant-numeric:tabular-nums;letter-spacing:.02em}
.enq-tel input[type="tel"]:focus{outline:none;box-shadow:none}

.enq-row{display:grid;grid-template-columns:1fr 1fr;gap:0 18px}
.enq-note{font-size:13px;color:var(--muted);margin:16px 0 0}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* ---------- contact ---------- */

/* ---------- about ---------- */
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:28px;text-align:center}
.stat-n{font-size:clamp(36px,4.6vw,56px);font-weight:800;color:var(--navy);line-height:1.05;
  letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.stat-n span{color:var(--orange)}
/* line-height stated, not inherited. These labels take the body's 1.65, which is a
   reading measure and far too airy for a two-word caption - once the grid went two across
   on a phone "Equipment categories" wrapped, and the two halves sat 21px apart as though
   they were separate lines of prose. 1.35 keeps a wrapped label reading as one label. */
.stat-l{font-size:13px;font-weight:600;letter-spacing:.06em;color:var(--muted);margin-top:8px;
  line-height:1.35}
.section-dark .stat-n{color:#fff}
.section-dark .stat-l{color:rgba(255,255,255,.6)}

.usp-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}
.usp{background:var(--white);border:1px solid var(--line);border-top:3px solid var(--orange);
  border-radius:0 0 var(--radius) var(--radius);padding:26px}
.usp h3{font-size:17px;margin-bottom:9px}
.usp p{font-size:14.5px;color:var(--muted);margin:0;line-height:1.6}

/* Copy on the left with both paragraphs stacked, the three reasons on the right,
   numbers across the bottom. */
.about-split{display:grid;grid-template-columns:1.05fr 1fr;gap:60px;align-items:start}

/* Sized to hold on one line: at the global h2 size the heading measured 623px
   against a 596px column. Capped at 35px, which leaves room at every width where
   the section is still two columns. */
#about h2,#about h3.as-h2{font-size:clamp(23px,2.6vw,35px);text-wrap:nowrap;margin-bottom:20px}

/* Lede carries the claim, the body carries the evidence - so the second one
   steps down a size rather than running as a second lede. */
.about-lede{font-size:17px;line-height:1.75;color:var(--body);margin:0 0 16px}
.about-body{font-size:15.5px;line-height:1.75;color:var(--muted);margin:0}
/* Justified, with hyphenation on - without it a column this narrow opens rivers
   of white space between words. Turned off again on phones below. */
.about-lede,.about-body{text-align:justify;hyphens:auto}
.about-actions{display:flex;gap:14px;flex-wrap:wrap;margin-top:30px}

/* Centred against the copy: the left column is the taller of the two, and
   top-aligning the list left an obvious hole under it. */
.about-points{
  list-style:none;margin:0;padding:0;align-self:center;
  display:flex;flex-direction:column;gap:26px;
}
.about-points li{display:flex;gap:16px;align-items:flex-start}
.about-ic{
  flex:none;width:44px;height:44px;border-radius:12px;
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--tint);color:var(--navy);font-size:17px;
}
.about-points li > span:last-child{display:flex;flex-direction:column;gap:4px}
.about-points strong{font-size:16.5px;color:var(--ink);letter-spacing:-.01em}
.about-points strong + span{font-size:14.5px;color:var(--muted);line-height:1.6}

/* One rule above, hairlines between - no box, so the numbers read as a footing
   for the section rather than a separate card. */
.about-stats{
  display:grid;grid-template-columns:repeat(4,1fr);
  margin-top:56px;padding-top:38px;border-top:1px solid var(--line);
}
.about-stats .stat{position:relative;padding:0 26px}
.about-stats .stat:first-child{padding-left:0}
.about-stats .stat + .stat::before{
  content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);
  width:1px;height:46px;background:var(--line);
}
.about-stats .stat-n{font-size:clamp(32px,3.4vw,44px)}
.about-stats .stat-l{font-size:13px;margin-top:6px}
/* Tabular figures and a reserved min-width so the row does not jitter while the
   numbers count up from 0 to 2500.
   color:inherit is not optional - `.stat-n span` (class+type) paints every span
   orange for the "+" suffix, and the number is now a span too, so without this
   the whole figure turns orange. Two classes to outrank it. */
/* No min-width, and no text-align.
   This carried `min-width:1.6ch; text-align:right` to stop the box resizing while the
   figure counts up from zero, and both halves caused a visible fault.

   1ch is the width of "0" - 21px here - so 1.6ch reserved 33.6px. "12" is only 30.6px
   wide, because Poppins draws a narrow "1", so it was the one figure of the four that
   fitted inside the reservation. Right-aligned, that pushed it 3px in from the left and
   it read as indented in the stacked mobile layout. Aligned left instead, the same slack
   reappeared on the other side as a gap between "12" and its "+".

   The reservation was never worth either: the number grows from one digit to four as it
   counts, so the box resizes regardless and the suffix moves anyway - 1.6ch only ever
   propped up the first few frames. Removed, the figure is exactly as wide as itself, the
   left edges line up and the "+" sits tight against every number.

   What is left is the 2px left bearing inside Poppins' own "5", so "56" paints 2px in.
   Deliberately not chased: the labels under these figures vary by 1px between themselves
   for the same reason, so 2px is inside the noise this typeface already carries. */
.stat-n .stat-num{display:inline-block;color:inherit;font-variant-numeric:tabular-nums}
/* The rule above the numbers must read against the tinted section too. */
.section-tint .about-stats{border-top-color:var(--line-strong)}
.section-tint .about-stats .stat + .stat::before{background:var(--line-strong)}
.section-tint .about-ic{background:var(--white)}

/* ---------- blog ---------- */
.bgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:28px}
/* Overlay card: the cover fills the whole card and the words sit on it, over a
   gradient. Product and category cards are all "picture in a box, text in a white
   panel underneath" - text ON the image is the one shape they never take, which is
   what stops these reading as more of the same.
   Landscape 4:3, three across instead of four - a wider card gives the headline
   two lines instead of three and leaves more of the photograph showing above the
   gradient. No max-height: a cap on the height makes the ratio pull the width back
   down, and the card then stopped filling its own column (587px in a 640px slot).
   The tallest a card ever gets is 480px, at the single-column breakpoint. */
/* The cover carries nothing but the picture. The overlay version put the date and
   the headline on top of it, which only works while every cover is a clean photo -
   the client's own artwork has type baked in, and two sets of words on one image
   read as neither.
   So: image on top, words below. What keeps it from being the product card shape is
   the treatment rather than the arrangement - a wider crop, a dated kicker instead
   of a stock line, a headline set larger than any product name, and no price or
   button block at the foot. */
/* The cover carries nothing but the picture. The overlay version put the date and
   the headline on top of it, which only works while every cover is a clean photo -
   the client's own artwork has type baked in, and two sets of words on one image
   read as neither.
   So: image on top, words below, and the words on their own dark ground. A white
   body under a photo is the product card shape exactly; the ink block is what makes
   the two read as different things at a glance, and it costs the cover nothing. */
.bcard{display:flex;flex-direction:column;background:var(--navy-dark);
  border:1px solid var(--navy-dark);border-radius:var(--radius-lg);overflow:hidden;
  box-shadow:var(--shadow-sm);
  transition:transform .24s var(--ease),box-shadow .24s var(--ease)}
.bcard:hover{transform:translateY(-5px);box-shadow:var(--shadow-lg)}

/* flex:none + min-height:0 are load bearing. .bcard is a column flex container, so
   this box is a flex item and picks up min-height:auto - which resolves to the
   intrinsic height of the image inside and beats the aspect-ratio. A 900x900 cover
   rendered 289px tall instead of 181px, and a portrait one 443px, so no two cards
   in a row matched. */
/* 16/9, matching the artwork. It was 16/10 while every cover is 800x450, so object-fit:cover
   scaled to fill the taller box and took about 10% off the width - 5% from each side. On
   these covers that is destructive rather than cosmetic: they are designed banners with the
   headline and the logo close to the edges, so the crop ate the logo corner.
   Kept as cover rather than contain: contain never crops, but it letterboxes anything that
   is not exactly this ratio, and grey bars inside a card read as a mistake. Matching the
   ratio means these images are shown whole with no bars at all. */
.bcard-img{position:relative;display:block;flex:none;min-height:0;aspect-ratio:16/9;
  background:var(--paper);overflow:hidden}
.bcard-img img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .55s var(--ease)}
.bcard:hover .bcard-img img{transform:scale(1.04)}

.bcard-body{position:relative;display:flex;flex-direction:column;flex:1;gap:11px;
  padding:22px 22px 20px;background:var(--navy-dark);color:rgba(255,255,255,.7)}
/* Same glow language as the dark bands, so the block belongs to the system rather
   than reading as a flat navy rectangle. */
.bcard-body::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(420px 220px at 88% 0%, rgba(46,86,150,.55), transparent 70%);
}
.bcard-body > *{position:relative;z-index:1}

/* The date in small caps on orange - a dated kicker is the newspaper device, and
   the accent is what carries the eye down from the picture. */
.bcard-meta{display:flex;flex-wrap:wrap;align-items:center;gap:4px 10px;
  font-size:11px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
  color:var(--orange);font-variant-numeric:tabular-nums}
.bcard-meta > span + span::before{content:"/";margin-right:10px;
  color:rgba(255,255,255,.28)}
.bcard-meta i{display:none}   /* the kicker reads better without the little glyphs */
/* Bigger and tighter than a product name: a headline, not a label. */
.bcard-title{font-size:18.5px;font-weight:700;color:#fff;line-height:1.3;
  letter-spacing:-.02em;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
/* Clamped: the excerpt is the only variable-height part of the card, and a stray
   extra line pushed one card taller than its neighbours in the same row. */
.bcard-ex{font-size:14px;color:rgba(255,255,255,.72);line-height:1.62;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
/* Pinned to the bottom so every card ends on the same line however the headline
   wrapped, and separated by a hairline rather than a button - a button here would
   put the product card's shape straight back. */
.bcard-go{
  margin-top:auto;padding-top:16px;border-top:1px solid rgba(255,255,255,.12);
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  font-size:12.5px;font-weight:700;color:#fff;
  transition:color .2s var(--ease);
}
.bcard-go i{font-size:11px;color:var(--orange);transition:transform .22s var(--ease)}
.bcard:hover .bcard-go{color:var(--orange)}
.bcard:hover .bcard-go i{transform:translateX(4px)}
/* Home blog slider: three per view. The product tracks run four, so the blog row
   deliberately does not line up with them - a wider card is part of what makes
   this section read as articles rather than another shelf of stock. */
.blog-track > li{flex:0 0 calc((100% - 40px) / 3);scroll-snap-align:start}
.blog-track .bcard{height:100%}
/* 1279, matching the USP strip: --wrap caps at 1280, so from there up a card is a
   constant 395px. Below that the three columns shrink with the viewport and by
   1181 the text is already 57% of the card, so drop to two. */
@media (max-width:1279px){
  .blog-track > li{flex:0 0 calc((100% - 20px) / 2)}
}
/* One per view below 800, not 640. Two landscape cards on a narrow viewport get
   short enough that the headline runs to three lines and the text takes 59% of the
   card at 760 and 71% at 641 - measured, and at that point the photograph is gone.
   86% leaves the next card peeking so the row still reads as scrollable. */
@media (max-width:800px){
  .blog-track > li{flex:0 0 86%}
}
/* Portrait on a phone. The 4:3 box is only ~200px tall there and the overlay
   swallows it, but a min-height cannot be the fix: combined with aspect-ratio the
   box resolves its automatic minimum size through the ratio, so a 300px floor
   demanded 400px of width and overflowed a 390px screen by 31px (and min-width:0
   does not stop it). Changing the ratio does the same job with no blowout, because
   the ratio then only ever resolves height from a width the column already fixed. */
/* ---------- inner page subheader ----------
   The trail and the H1, nothing else. It replaces a light breadcrumb strip stacked
   above a separate white page-head, which read as two unrelated bars before the
   page had even started. Shared component - the other inner pages can move onto
   page_hero() the same way. Keeping it to two things is also what keeps it short:
   an eyebrow, a lede and a figure block made it a 440px rectangle with an empty
   right half. */
.phero{position:relative;background:var(--ink);overflow:hidden;
  border-bottom:2px solid transparent;
  border-image:linear-gradient(90deg,var(--orange),rgba(239,147,33,.14) 44%,transparent 74%) 1}
.phero::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(880px 480px at 78% 0%, rgba(32,67,125,.66), transparent 64%),
    radial-gradient(520px 340px at 2% 100%, rgba(239,147,33,.10), transparent 66%);
}
/* The same faint grid the dark sections use, so this band belongs to that family. */
.phero::after{
  content:"";position:absolute;inset:0;pointer-events:none;opacity:.05;
  background-image:linear-gradient(rgba(255,255,255,.8) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(255,255,255,.8) 1px,transparent 1px);
  background-size:64px 64px;
}
/* Left-aligned, matching everything else on the site - the nav, the hero copy,
   every section head, and the content that starts directly under this band. A
   centred banner over left-aligned content was the one inconsistency.
   Tall enough to read as a banner rather than a strip. */
/* padding-block, not the padding shorthand: .phero-in is also a .wrap, and
   `padding:58px 0 62px` wipes its 28px inline padding - the banner text then sat
   28px left of every line of content below it. Same trap as .foot-base. */
.phero-in{position:relative;z-index:1;padding-block:58px 62px}
/* The optional aside is still supported by page_hero(); About no longer uses it. */
.phero-split .phero-in{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,430px);
  gap:64px;align-items:center}
/* No max-width. `24ch` is measured in the h1's own 52px font, so it capped the heading
   at 820px inside a 1280px row - 460px of the band sat empty while long titles broke
   onto three lines. A page title is one phrase read at a glance, not a paragraph, so it
   does not need a reading measure; it needs the row it is already in. */
/* One size on every page. 36px is the largest the longest title in the catalogue - 66
   characters - still fits on one line at, measured against the 1224px the copy column
   gets at the 1280 wrap. Every shorter title therefore also fits, so no page's band is
   a different height from any other's, which is the whole point.
   The vw term takes it down below 1280 where the column narrows; 2.81vw is 36px at
   exactly 1280, so the size holds at its maximum across every desktop width and only
   scales where it has to. */
.phero h1{color:#fff;margin:0;font-size:clamp(24px,2.81vw,36px);letter-spacing:-.03em;
  line-height:1.15}
/* No guard needed for the split band: `.phero-split .phero-in` is a grid, so the copy
   column already bounds the heading. (A rule written for it here would also never have
   matched - .phero-split IS the .phero, not an ancestor of one.) */
/* A short rule under the title. Scoped to .phero-copy, not .phero-in -
   page_hero() always wraps the heading in .phero-copy, so an `.phero-in > h1`
   child selector never matched and the rule simply never rendered. */
.phero-copy > h1::after{content:"";display:block;width:56px;height:3px;margin:22px 0 0;
  background:var(--orange);border-radius:2px}
.phero .eyebrow{margin:0 0 14px}
.phero-lede{margin:18px 0 0;font-size:16.5px;line-height:1.7;max-width:56ch;
  color:rgba(255,255,255,.68)}

/* Breadcrumb inside the band: no strip of its own, no wrap, and it reads on dark. */
.crumbs-bare{background:none;border:0;font-size:13px;margin-bottom:22px}
.crumbs-bare ol{padding:0;color:rgba(255,255,255,.5)}
.crumbs-bare a{color:rgba(255,255,255,.7);font-weight:500}
.crumbs-bare a:hover{color:var(--orange)}
.crumbs-bare li+li:before{color:rgba(255,255,255,.3)}

/* ---------- about page ----------
   Note the section class is .about-main, not .about-body: `.about-lede,.about-body`
   already exists for the home page about copy and carries text-align:justify, which
   this page inherited by accident. */
/* Copy left, photo right. No card, no rail, no centring - the photo is what uses
   the other half of the row, and it is sticky so the right column is not a hole for
   the length of a long read. */
.about-lay{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,420px);gap:64px;
  align-items:start}
.about-copy .eyebrow{margin-bottom:14px}
.about-copy > h2,.about-copy > h3.as-h2{font-size:clamp(24px,2.6vw,34px);line-height:1.2;letter-spacing:-.02em;
  margin:0 0 28px;max-width:20ch}

.about-photo{position:sticky;top:104px;margin:0;overflow:hidden;
  border-radius:var(--radius-lg);border:1px solid var(--line);background:var(--paper);
  box-shadow:0 16px 40px rgba(15,34,66,.09)}
.about-photo img{display:block;width:100%;height:auto;aspect-ratio:4/5;object-fit:cover}

/* Justified, the same as the home page about copy. hyphens:auto keeps the word
   spacing from opening up into rivers at this measure. */
.about-prose{max-width:none;text-align:justify;hyphens:auto}
/* Headings stay flush left - justifying a two-line heading looks like a mistake. */
.about-prose h2,.about-prose h3,.about-prose h3.as-h2{text-align:left;hyphens:manual}
.about-prose > :first-child{margin-top:0}
/* The opening paragraph carries the page, so it is set larger than the body. */
.about-prose > p:first-of-type{font-size:19px;line-height:1.75;color:var(--ink)}
/* Section headings get a short accent rule above them instead of relying on margin
   alone - it gives the long read visible chapter breaks. */
.about-prose h2,.about-prose h3.as-h2{position:relative;padding-top:26px;margin-top:44px;font-size:23px}
.about-prose h2::before,.about-prose h3.as-h2::before{content:"";position:absolute;left:0;top:0;width:34px;height:3px;
  background:var(--orange);border-radius:2px}
.about-prose h2:first-child,.about-prose h3.as-h2:first-child{margin-top:0}

@media (max-width:1080px){
  .about-lay{grid-template-columns:minmax(0,1fr) minmax(0,340px);gap:44px}
}
@media (max-width:900px){
  /* Photo above the copy: below this the column is too narrow for the picture to
     be worth its width, and the text has nothing left to breathe with. */
  .about-lay{grid-template-columns:minmax(0,1fr);gap:30px}
  .about-photo{position:static;order:-1}
  .about-photo img{aspect-ratio:16/9}
}
@media (max-width:760px){
  .phero-in{padding-block:40px 44px}
  .crumbs-bare{margin-bottom:18px}
  .phero-copy > h1::after{margin-top:18px}
  /* Too narrow to justify: the gaps between words start to show. */
  .about-prose{text-align:left;hyphens:manual}
  .about-prose > p:first-of-type{font-size:17px}
  .about-prose h2,.about-prose h3.as-h2{margin-top:34px;padding-top:22px;font-size:21px}
  .phero-split .phero-in{grid-template-columns:minmax(0,1fr);gap:30px}
}
/* ---------- how we work (About) ----------
   Numbered discs on a connector line. Ordered list markup, because it genuinely is
   a sequence - the numbers carry meaning here, unlike the why band where they are
   only a device to tie four points together. A row of thin top rules with a small
   number under each read as four unrelated columns; the track is what makes it a
   process at a glance. */
.how-list{position:relative;list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:0 28px}
.how-list li{position:relative}

/* One segment per gap rather than a single line across the row: a full-width line
   inset by half a disc at each end assumed the last disc ended at the container
   edge, and it does not - the line ran on past step 04 to the wrap edge. Each
   segment runs from its own disc centre (28px) to the next one (100% + gap + 28px),
   which is a width of 100% + gap. */
/* The segment stops where the arrowhead starts rather than running on under the
   next disc. Measured from the li: this disc's centre is 28px in, the next disc's
   ring starts at 100% + 21px, and the head is 7px wide - so the line ends at
   100% + 2px and the head sits from there, leaving 12px of air before the ring.
   At the old numbers the tip was 5px off the ring and looked stuck to it. */
.how-list li:not(:last-child)::before{
  content:"";position:absolute;left:28px;top:27px;height:2px;
  width:calc(100% - 26px);border-radius:2px;
  background:linear-gradient(90deg,var(--line-strong),var(--line) 55%,var(--line-strong));
}
/* An arrowhead, so the row reads left to right rather than as four things that
   happen to be joined. */
.how-list li:not(:last-child)::after{
  content:"";position:absolute;left:calc(100% + 2px);top:23px;
  border:5px solid transparent;border-left:7px solid var(--line-strong);
}

.how-no{
  position:relative;z-index:1;
  display:inline-flex;align-items:center;justify-content:center;
  width:56px;height:56px;border-radius:50%;margin-bottom:24px;
  background:var(--navy);color:#fff;
  font-size:14.5px;font-weight:800;letter-spacing:.06em;
  font-variant-numeric:tabular-nums;
  /* Inner hairline for a little depth, outer ring in the section colour so the
     connector appears to stop at the circle instead of running under it. */
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.18),
             0 0 0 7px var(--white),
             0 8px 20px rgba(32,67,125,.28);
  transition:background .22s var(--ease),transform .22s var(--ease),
             box-shadow .22s var(--ease);
}
/* On a tinted section the ring has to match that ground instead. */
.section-tint .how-no{
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.18),
             0 0 0 7px var(--paper),
             0 8px 20px rgba(32,67,125,.22);
}
.how-list li:hover .how-no{background:var(--orange);color:var(--ink);
  transform:translateY(-3px)}
.section-tint .how-list li:hover .how-no{
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.3),
             0 0 0 7px var(--paper),
             0 10px 24px rgba(239,147,33,.36);
}

/* The words sit on a card so the four line up along the bottom instead of ending
   wherever their copy runs out. Same white-card-on-tint pattern as the industries
   block on the home page, so this is not a new shape for the site to carry.
   The li is a column flex so the card can take the leftover height. */
.how-list li{display:flex;flex-direction:column}
.how-card{
  flex:1;background:var(--white);border:1px solid var(--line);
  border-radius:var(--radius-lg);padding:24px 22px 22px;
  transition:border-color .22s var(--ease),box-shadow .22s var(--ease),
             transform .22s var(--ease);
}
.how-list li:hover .how-card{border-color:var(--line-strong);
  box-shadow:0 12px 30px rgba(15,34,66,.08);transform:translateY(-3px)}
.how-card h3{font-size:17px;line-height:1.3;letter-spacing:-.015em;margin:0 0 9px;
  transition:color .2s var(--ease)}
.how-list li:hover .how-card h3{color:var(--navy)}
.how-card p{font-size:14.5px;line-height:1.65;color:var(--muted);margin:0}

@media (max-width:1000px){
  /* Two across: the connector would have to jump a row, so it goes and each disc
     stands on its own. */
  .how-list{grid-template-columns:repeat(2,minmax(0,1fr));gap:40px 28px}
  .how-list li:not(:last-child)::before,
  .how-list li:not(:last-child)::after{display:none}
  .how-no{width:50px;height:50px;margin-bottom:18px;
    box-shadow:inset 0 0 0 1px rgba(255,255,255,.18),0 6px 16px rgba(32,67,125,.22)}
  .section-tint .how-no{box-shadow:inset 0 0 0 1px rgba(255,255,255,.18),
    0 6px 16px rgba(32,67,125,.2)}
}
@media (max-width:560px){
  /* Single column, and the disc overlaps the top-left corner of its card rather
     than sitting above it - four full-width circles stacked down a phone screen is
     a lot of height spent on numbering. */
  .how-list{grid-template-columns:minmax(0,1fr);gap:22px}
  .how-list li{display:block;padding-top:22px}
  .how-no{position:absolute;top:0;left:16px;width:44px;height:44px;margin:0;
    font-size:13px}
  .how-card{padding:34px 20px 20px}
}
/* ---------- contact ----------
   Three ways to reach us across the top, then the form beside the map. The cards
   replace text blocks with an orange left edge: every one carries its own action
   now, which is what the page is for. Icon tile + label + value is the same shape
   the footer contact strip uses, so the two agree. */
.contact-top{padding-bottom:0}
.ways{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px}
.way{
  display:flex;flex-direction:column;align-items:flex-start;
  padding:28px 26px 26px;border-radius:var(--radius-lg);
  background:var(--white);border:1px solid var(--line);
  transition:border-color .22s var(--ease),box-shadow .22s var(--ease),
             transform .22s var(--ease);
}
.way:hover{border-color:var(--line-strong);box-shadow:0 14px 34px rgba(15,34,66,.08);
  transform:translateY(-3px)}
.way-ic{
  display:inline-flex;align-items:center;justify-content:center;
  width:48px;height:48px;border-radius:13px;margin-bottom:18px;
  background:var(--tint);color:var(--navy);font-size:18px;
  transition:background .22s var(--ease),color .22s var(--ease);
}
.way:hover .way-ic{background:var(--orange);color:var(--ink)}
.way-lbl{font-size:12px;font-weight:800;letter-spacing:.13em;text-transform:uppercase;
  color:var(--muted);margin:0 0 8px}
/* One size for all three. The phone used to be set at 21px against 16px for the
   email and the address, which is a big enough jump that the three stopped reading
   as one set. 17px holds a three-line address without dominating the row. */
/* One of these values is info@coldexkitchenequipments.com - 32 characters with no space
   in them, which no browser breaks on its own. At 17px it wants 318px, so on a 320px
   phone it pushed the whole page 43px sideways and took every other element with it.

   `anywhere`, not `break-word`, and the difference is the whole fix: break-word breaks
   the line visually but leaves the element's min-content width at the length of the
   longest word, so this flex item still refused to shrink below 318px and the page still
   scrolled. `anywhere` reduces the intrinsic minimum too, which is what lets a flex or
   grid item actually narrow. min-width:0 for the same reason - a flex item will not go
   below its automatic minimum without it.

   The address and phone number are unaffected: they contain spaces, so an ordinary break
   is always available and this never fires on them. */
.way-val{font-size:17px;font-weight:700;color:var(--ink);letter-spacing:-.015em;margin:0;
  line-height:1.5;overflow-wrap:anywhere;min-width:0}
/* Tabular figures on the phone number only - the address has digits in it too and
   they look wrong spaced out. */
a[href^="tel"].way-val{font-variant-numeric:tabular-nums;letter-spacing:0}
a.way-val:hover{color:var(--orange)}
.way-note{font-size:13.5px;line-height:1.6;color:var(--muted);margin:10px 0 0}
/* One rule, not three fighting each other. margin-top:auto pushes the action to
   the bottom of the card, and because the cards stretch to equal height the three
   buttons land on the same line. The minimum gap has to come from the note below
   it - auto eats the whole remainder, so on the tallest card there would otherwise
   be none. */
.way-note{margin-bottom:22px}
.way .btn{margin-top:auto;padding:13px 20px;font-size:12px}

/* WhatsApp green. This class was on the markup already but had no rule anywhere,
   so the button rendered as bare text. */
/* A deeper green than the brand's #25D366, which carries white text at only 1.98:1 -
   the one button on the contact page that a customer could not read was the one asking
   them to get in touch. #0F8043 is 5.01:1 and still unmistakably WhatsApp. */
.btn-wa{background:#0F8043;color:#fff;border-color:#0F8043;
  box-shadow:0 6px 18px rgba(15,128,67,.28)}
.btn-wa:hover{background:#0C6A38;border-color:#0C6A38;color:#fff;transform:translateY(-2px)}
.btn-wa i{font-size:15px}

/* stretch, not start: the form is taller than any sensible map height, so a fixed
   map left a 200px hole down the right of the row. The map now takes the column. */
.contact-grid{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);
  gap:44px;align-items:stretch}
.contact-form{background:var(--white);border:1px solid var(--line);
  border-radius:var(--radius-lg);padding:34px 34px 30px;
  box-shadow:0 14px 36px rgba(15,34,66,.06)}
.contact-form h2,.contact-form h3.as-h2{font-size:clamp(21px,2.2vw,27px);line-height:1.25;margin:0 0 12px;
  letter-spacing:-.02em}
.contact-form .eyebrow{margin-bottom:14px}
.contact-intro{font-size:15px;line-height:1.7;color:var(--muted);margin:0 0 26px}

/* The iframe is absolutely positioned rather than height:100%. A percentage
   height against a grid-stretched parent is not definite when the embed first
   lays itself out, and Google renders the map at zero and never reflows - the
   panel came out grey. inset:0 resolves against a box the grid has already sized. */
.contact-map{position:relative;overflow:hidden;min-height:420px;
  border-radius:var(--radius-lg);border:1px solid var(--line);
  box-shadow:0 14px 36px rgba(15,34,66,.06);background:var(--paper)}
.contact-map iframe{position:absolute;inset:0;display:block;width:100%;height:100%;border:0}

@media (max-width:1000px){
  .ways{grid-template-columns:minmax(0,1fr)}
  .way{flex-direction:row;flex-wrap:wrap;align-items:center;column-gap:18px;
    padding:22px 24px}
  .way-ic{margin-bottom:0}
  .way-lbl{flex:1 1 auto;margin:0}
  .way-val{flex:1 1 100%;margin-top:6px}
  .way-note{flex:1 1 100%}
  .way .btn{margin-top:16px}
  .contact-grid{grid-template-columns:minmax(0,1fr);gap:32px}
  /* Height on the container, not the iframe: the iframe is absolutely positioned,
     so with min-height:0 the container had nothing to give it and collapsed to 2px
     - the map simply vanished below 1000. */
  .contact-map{min-height:0;height:340px}
}
@media (max-width:560px){
  /* flex-wrap:nowrap is the important one. The 1000px rule turns these cards into
     wrapping rows; switching only the direction back to column left the wrap on,
     and a wrapping column flex container spills its items into fresh columns to
     the right - each card was running 585px past its own width. */
  .way{flex-direction:column;flex-wrap:nowrap;align-items:flex-start;row-gap:0}
  .way-ic{margin-bottom:16px}
  .way-val{margin-top:0}
  .way .btn{width:100%}
  .contact-form{padding:26px 20px 24px}
}
/* ---------- blog index ----------
   The filter row and the count share a line: the count is what tells you the
   filter did anything, so it belongs beside the filter rather than floating above
   the grid on its own. */
.blog-bar{display:flex;align-items:center;justify-content:space-between;gap:20px 28px;
  flex-wrap:wrap;margin-bottom:36px;padding-bottom:26px;border-bottom:1px solid var(--line)}
.blog-count{flex:none;margin:0;font-size:13px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);font-variant-numeric:tabular-nums}

/* A filtered view that finds nothing needs a way back, not a full stop. */
.blog-none{display:flex;flex-direction:column;align-items:flex-start;gap:6px;
  padding:20px 0 40px}
.blog-none .empty{padding:0}

@media (max-width:640px){
  .blog-bar{margin-bottom:28px;padding-bottom:20px}
  .blog-count{order:-1}
}

/* ---------- products (shop) ----------
   One flat grid with a filter rail, instead of a section per category. The old
   arrangement grew with the catalogue and gave a visitor no way to narrow it. */
.shop-lay{display:grid;grid-template-columns:minmax(0,264px) minmax(0,1fr);gap:44px;
  align-items:start}
/* Sticky, so the filters are still reachable at the bottom of a long grid. */
.shop-side{position:sticky;top:104px}
.shop-side-toggle{display:none}

/* The rail is its own panel rather than loose text in the margin. On a white page
   next to a grid of white cards the filters had no surface of their own, so the two
   columns read as one continuous area. Tinted ground plus a border is what separates
   them - the cards stay the only white things in the row. */
.shop-side-in{
  display:flex;flex-direction:column;gap:22px;
  padding:22px;border:1px solid var(--line);border-radius:var(--radius-lg);
  background:var(--paper);
}
/* Rules between blocks, carried on the block below rather than the one above, so
   that a hidden last block never leaves a border hanging over the panel's padding. */
.shop-side-in > * + *{border-top:1px solid var(--line);padding-top:22px}

.side-h{font-size:12px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);margin:0 0 14px}

.side-list{list-style:none;margin:0;padding:0}
.side-list a{
  /* Pulled 12px out on both sides so the label lines up with the heading above it
     while the highlight still reads as a full-width row. */
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:9px 12px;margin-inline:-12px;border-radius:var(--radius);
  font-size:14.5px;font-weight:600;color:var(--body);
  transition:background .18s var(--ease),color .18s var(--ease);
}
.side-list a span{flex:none;font-size:12px;font-weight:700;color:var(--muted);
  font-variant-numeric:tabular-nums}
.side-list a:hover{background:var(--white);color:var(--ink)}
.side-list a.is-on{background:var(--navy);color:#fff}
.side-list a.is-on span{color:rgba(255,255,255,.7)}

/* ---- price range ----
   Two range inputs laid over one rail, ends read off the catalogue. Letting go of a
   handle applies the filter, so there is no Apply button. */
.rng-out{display:flex;align-items:baseline;gap:8px;margin-bottom:16px;
  font-size:15.5px;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.rng-dash{font-size:12px;font-weight:600;color:var(--muted)}

.rng{--thumb:18px;position:relative;height:var(--thumb)}
.rng-rail,.rng-fill{position:absolute;top:50%;height:4px;margin-top:-2px;
  border-radius:2px;pointer-events:none}
.rng-rail{left:0;right:0;background:var(--line-strong)}
/* Placed in pixels by the script, not in per cent: the browser insets a thumb by
   half its own width so it never hangs off the track, so a straight percentage puts
   the fill up to 9px away from the handle it is supposed to end at. */
.rng-fill{background:var(--navy)}

/* Both inputs cover the whole rail, so the track is transparent and only the thumbs
   take the pointer - otherwise the upper input would swallow every click meant for
   the lower one. */
.rng input[type="range"]{
  position:absolute;left:0;top:0;width:100%;height:var(--thumb);margin:0;
  appearance:none;-webkit-appearance:none;background:transparent;pointer-events:none;
}
.rng input[type="range"]:focus{outline:none}
/* Raised when the pair sits in the top half of the rail, where the two thumbs are
   close enough that the later one in the markup would otherwise cover this one. */
.rng input[type="range"].is-over{z-index:2}

.rng input[type="range"]::-webkit-slider-thumb{
  -webkit-appearance:none;pointer-events:auto;
  width:var(--thumb);height:var(--thumb);border-radius:50%;
  background:var(--white);border:2px solid var(--navy);
  box-shadow:0 1px 3px rgba(15,26,45,.24);cursor:grab;
  transition:transform .15s var(--ease),box-shadow .15s var(--ease);
}
.rng input[type="range"]::-moz-range-thumb{
  pointer-events:auto;box-sizing:border-box;
  width:var(--thumb);height:var(--thumb);border-radius:50%;
  background:var(--white);border:2px solid var(--navy);
  box-shadow:0 1px 3px rgba(15,26,45,.24);cursor:grab;
  transition:transform .15s var(--ease),box-shadow .15s var(--ease);
}
.rng input[type="range"]:hover::-webkit-slider-thumb{transform:scale(1.12)}
.rng input[type="range"]:hover::-moz-range-thumb{transform:scale(1.12)}
.rng input[type="range"]:active::-webkit-slider-thumb{cursor:grabbing;transform:scale(1.12)}
.rng input[type="range"]:active::-moz-range-thumb{cursor:grabbing;transform:scale(1.12)}
.rng input[type="range"]:focus-visible::-webkit-slider-thumb{
  box-shadow:0 0 0 4px rgba(32,67,125,.2)}
.rng input[type="range"]:focus-visible::-moz-range-thumb{
  box-shadow:0 0 0 4px rgba(32,67,125,.2)}
/* Firefox draws its own track behind the thumb. */
.rng input[type="range"]::-moz-range-track{background:transparent;height:4px}

.rng-ends{display:flex;justify-content:space-between;gap:10px;margin-top:11px;
  font-size:12px;font-weight:700;color:var(--muted);font-variant-numeric:tabular-nums}

/* The filter is live, so the button only exists for a browser that cannot run it. */
.side-price noscript .btn{margin-top:14px}

/* Full width of the panel, like the category rows above it. Sized to its words it
   only carried the separator rule across half the panel, which read as a broken line
   rather than a divider. */
.side-clear{display:flex;align-items:center;justify-content:flex-start;gap:8px;
  font-size:13px;font-weight:700;color:var(--navy)}
.side-clear i{font-size:11px}
.side-clear:hover{color:var(--orange)}

/* A block of its own under the filter panel, not a compartment inside it - it is what
   to do when no filter answers the question.
   Dark, because it is the one thing in the column that is an offer rather than a
   control, and because a white box on the tinted panel read as a lighter version of
   the panel with an orange slab dropped in it. On ink the accent belongs to something
   - it is the same pairing the dark bands use. */
.side-help{position:relative;overflow:hidden;margin-top:20px;
  padding:22px;border-radius:var(--radius-lg);background:var(--ink);color:#fff}
/* Same glow as the other dark blocks, so it reads as part of the system rather than
   a flat navy rectangle. */
.side-help::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(300px 180px at 100% 0%, rgba(32,67,125,.6), transparent 72%)}
.side-help > *{position:relative;z-index:1}

.side-help-k{display:flex;align-items:center;gap:7px;margin:0 0 10px;
  font-size:10.5px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;
  color:var(--orange)}
.side-help-h{margin:0 0 7px;font-size:16px;font-weight:700;line-height:1.32;
  letter-spacing:-.01em;color:#fff}
.side-help-p{margin:0 0 16px;font-size:13.5px;line-height:1.6;
  color:rgba(255,255,255,.62)}
/* Sized to its words rather than the panel - .btn is already inline-flex, it was the
   btn-block that made it a slab, and that slab was the loudest thing on the page from
   three columns away. The orange drop shadow goes too: it reads as a halo on ink. */
.side-help-go{gap:9px;box-shadow:none}
.side-help-go:hover{box-shadow:0 8px 20px rgba(239,147,33,.26)}
.side-help-go i{font-size:11px;transition:transform .22s var(--ease)}
.side-help-go:hover i{transform:translateX(3px)}

/* Buying guidance under the grid, full container width. An earlier pass capped this
   at a reading measure and it read as a narrow column stranded in an empty band - the
   heading wrapped onto two lines for no reason and the section looked unfinished. */
/* ---------- the category directory under the all-products grid ----------
   Text tiles, deliberately, and not another row of image cards - the home page already has
   the picture version and repeating it here would add a second navigation control and none of
   the reading content this page was short of.
   The FIRST attempt was a flat two-column box with hairline gaps, which looked like a
   spreadsheet dropped into the page: it matched nothing else on the site, because nothing else
   on the site is a table. This uses the language every other block uses - a tinted section, an
   eyebrow, and white cards that lift on hover.
   Three columns, so twelve categories fill four even rows with nothing orphaned. */
.cat-dir{background:var(--paper)}
.cat-dir-list{list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px}
.cat-dir-card{
  display:block;height:100%;padding:22px 22px 20px;
  background:var(--white);border:1px solid var(--line);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-sm);
  transition:transform .24s var(--ease),box-shadow .24s var(--ease),border-color .24s var(--ease);
}
.cat-dir-card:hover{transform:translateY(-4px);box-shadow:var(--shadow-lg);border-color:var(--line-strong)}
/* The whole tile is the link, so the heading must not paint itself blue - it is a heading
   that happens to be clickable, not a link inside a card. */
.cat-dir-card h3{margin:0;font-size:16.5px;line-height:1.35;color:var(--ink)}
.cat-dir-card:hover h3{color:var(--navy)}
/* A chip, not a second sentence. The count qualifies the name; on its own line and in body
   type it competes with the description underneath instead of labelling what is above it. */
.cat-dir-n{display:inline-block;margin-top:8px;padding:3px 9px;border-radius:99px;
  background:var(--paper);border:1px solid var(--line);
  font-size:11.5px;font-weight:600;letter-spacing:.03em;color:var(--muted-strong)}
.cat-dir-card p{margin:12px 0 0;font-size:14px;line-height:1.65;color:var(--body)}
@media (max-width:1000px){.cat-dir-list{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:620px){
  .cat-dir-list{grid-template-columns:minmax(0,1fr);gap:14px}
  .cat-dir-card{padding:18px}
}

.cat-guide h2,.cat-guide h3.as-h2{margin:0 0 14px}
.cat-guide-lede{margin:0;font-size:16px;line-height:1.7;color:var(--body)}
/* .prose carries max-width:72ch, a reading measure meant for a policy page where the text
   is the whole page. Here it is not: the H2 and the lede above it run the full 1224px of
   the wrap, so the body stopping at 723px left the right half of the section empty and the
   block read as broken rather than as a column.

   Same override the product page already uses for .pdp-panel.prose, and scoped the same way
   so the policy pages keep their measure. */
.cat-guide .prose{margin-top:18px;max-width:none;
  /* Justified, the same as .about-prose and .post-body. The three settings go together and
     none of them is optional here:

     hyphens:auto, because justification alone only stretches the word spaces to fill a line,
     and at 1224px that opens white rivers straight down the paragraph. Hyphenation gives the
     browser somewhere else to take up the slack. It works because <html lang="en"> is set.

     text-align-last:left, so the closing line of a paragraph stays ragged. A justified last
     line is how a paragraph ends up as four words spread across the whole column. */
  text-align:justify;text-align-last:left;
  hyphens:auto;-webkit-hyphens:auto;overflow-wrap:break-word}
/* Headings and list markers stay flush left. Justifying a two-line heading reads as a
   mistake, and a justified list item spreads its own short lines the same way. */
.cat-guide .prose :is(h2,h3,h4,blockquote,figcaption,th,td){text-align:left;hyphens:manual}
/* Too narrow to justify: the gaps between words start to show, the same reason
   .about-prose drops it at this width. This block has to sit AFTER the rule it
   overrides - both selectors are (0,2,0), so source order is what decides, and an
   earlier media query would simply never win. */
@media (max-width:760px){
  .cat-guide .prose{text-align:left;text-align-last:auto;hyphens:manual}
}

/* ---- toolbar ---- */
.shop-bar{display:flex;align-items:center;justify-content:space-between;gap:20px;
  flex-wrap:wrap;margin-bottom:24px;padding-bottom:18px;border-bottom:1px solid var(--line)}
.shop-count{margin:0;font-size:13px;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;color:var(--muted);font-variant-numeric:tabular-nums}
.shop-sort{display:flex;align-items:center;gap:10px;font-size:12.5px;font-weight:700;
  letter-spacing:.05em;text-transform:uppercase;color:var(--muted)}
.shop-sort select{
  appearance:none;-webkit-appearance:none;
  padding:9px 34px 9px 13px;border:1px solid var(--line-strong);border-radius:4px;
  font:inherit;font-size:14px;font-weight:600;text-transform:none;letter-spacing:0;
  color:var(--ink);background-color:var(--white);cursor:pointer;
  background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%237185A0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center;
}
.shop-sort select:focus{outline:none;border-color:var(--navy);
  box-shadow:0 0 0 3px rgba(32,67,125,.11)}

/* Three across, not four: the grid sits next to a 264px rail, so a four-up row
   would put the cards well under the 291px they are elsewhere on the site.
   Two classes throughout, because the generic `.pgrid` responsive rules sit later
   in this file at the same specificity and would otherwise win every breakpoint -
   the grid was following .pgrid's columns, not its own. */
.pgrid.pgrid-shop{grid-template-columns:repeat(3,minmax(0,1fr))}

/* A column, because the sentence has to sit above whatever follows it. The buttons then
   need their own row - a category with nothing in it offers two ways out, and stacked
   they read as one choice repeated rather than a pair. */
.shop-none{display:flex;flex-direction:column;align-items:flex-start;gap:8px;
  padding:20px 0 40px}
.shop-none .empty{padding:0;margin-bottom:6px}
/* Its own row inside the column. margin between the buttons would do nothing here -
   .shop-none is a column, so every child is already on its own line. */
.shop-none-acts{display:flex;flex-wrap:wrap;gap:12px}
@media (max-width:480px){
  .shop-none-acts{width:100%}
  .shop-none-acts .btn{flex:1 1 100%;justify-content:center}
}

/* ---- pager ---- */
.pager{display:flex;align-items:center;justify-content:space-between;gap:20px;
  flex-wrap:wrap;margin-top:44px;padding-top:28px;border-top:1px solid var(--line)}
.pager-step{display:inline-flex;align-items:center;gap:9px;
  font-size:12.5px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
  color:var(--navy)}
.pager-step i{font-size:11px;transition:transform .2s var(--ease)}
.pager-step:hover i{transform:translateX(3px)}
.pager-step:first-child:hover i{transform:translateX(-3px)}
/* Kept in the flow rather than hidden, so the number row stays centred on page 1
   and on the last page instead of sliding sideways.

   --line-strong is a border colour, and as text it measured 1.56:1 - kept in the flow
   but not actually visible, which is the same as hidden and contradicts the line above.
   A disabled control is exempt from the 4.5:1 minimum, so this does not have to read
   like live text; it does have to be seen to exist. */
.pager-step.is-off{color:#9AACC6;pointer-events:none}

.pager-nums{list-style:none;display:flex;align-items:center;gap:6px;margin:0;padding:0}
.pager-nums a{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:40px;height:40px;padding:0 10px;border-radius:var(--radius);
  border:1px solid var(--line);font-size:14px;font-weight:700;color:var(--ink);
  font-variant-numeric:tabular-nums;
  transition:background .18s var(--ease),border-color .18s var(--ease),color .18s var(--ease);
}
.pager-nums a:hover{border-color:var(--line-strong);background:var(--paper)}
.pager-nums a.is-on{background:var(--navy);border-color:var(--navy);color:#fff}
.pager-gap{color:var(--muted);padding:0 4px;font-weight:700}

@media (max-width:1180px){
  .shop-lay{grid-template-columns:minmax(0,232px) minmax(0,1fr);gap:32px}
  .pgrid.pgrid-shop{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:900px){
  /* The rail becomes a panel above the grid, collapsed behind a button - at this
     width it is not worth a third of the row. */
  .shop-lay{grid-template-columns:minmax(0,1fr);gap:0}
  .shop-side{position:static;margin-bottom:28px}
  .shop-side-toggle{display:inline-flex;width:100%}
  .shop-side-in{display:none;margin-top:12px}
  /* flex, not block - the panel's spacing and its between-block rules both come
     from the column flex layout. */
  .shop-side.is-open .shop-side-in{display:flex}
  .side-help{display:none}   /* the same offer sits in the footer of every page */
}
@media (max-width:560px){
  .pgrid.pgrid-shop{grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}
  .pager{gap:14px;justify-content:center}
  .pager-nums{order:-1;flex-wrap:wrap;justify-content:center}
  .pager-nums a{min-width:36px;height:36px;font-size:13px}
}
/* One across below 550, not 400. Measured against the longest price in the
   catalogue: a card needs ~253px to keep the price, the struck MRP and "+ GST" on
   one line, and two across drops under that at 545. Price on one line was an
   explicit call, so the column goes rather than the price wrapping. */
@media (max-width:550px){
  .pgrid.pgrid-shop{grid-template-columns:minmax(0,1fr)}
}
/* ---------- blog post ----------
   Article and a contents rail.

   The row is held to 1120 and centred rather than filling the 1280 wrap. At full width
   the article kept its own 76ch measure and the rail sat hard against the right edge,
   leaving 192px of nothing between them - the rail read as a stray box rather than part
   of the page. Sizing the row so the two columns add up to it puts the rail beside the
   article, and the column now sets the reading measure so the article does not need a
   max-width fighting it. */
/* The section carries a tint and the article sits on it as a white panel, so the two
   columns read as two things. On a white section against white cards the article and the
   rail ran together as one undivided area - a rail is only a rail if you can see where
   the content stops. The rail's own cards then read as separate boxes beside the panel
   rather than as more of the same surface. */
.post{background:var(--paper)}
.post-lay{display:grid;grid-template-columns:minmax(0,1fr) 288px;
  gap:clamp(28px,3vw,44px);align-items:start;
  max-width:1180px;margin-inline:auto}
.post-main{min-width:0;background:var(--white);border:1px solid var(--line);
  border-radius:var(--radius-lg);box-shadow:var(--shadow-sm);
  padding:clamp(24px,3vw,44px)}

/* The byline. A row of grey text reading "14 July 2026 - Shree Khodiyar Enterprise" was
   two facts of equal weight fighting on one line and neither reading as anything. The
   initial anchors it, the name leads, and the date sits under it as the secondary fact
   it actually is. */
/* Under the cover, so it reads as a credit on the picture and the article that follows
   rather than a delay before either. */
.post-by{display:flex;align-items:center;gap:12px;margin:0 0 30px;
  padding-bottom:22px;border-bottom:1px solid var(--line)}
.post-by-ic{flex:none;width:40px;height:40px;border-radius:50%;
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--navy);color:#fff;font-size:15px;font-weight:800;line-height:1}
.post-by-txt{display:grid;gap:2px;min-width:0}
.post-by-name{font-size:14.5px;font-weight:700;color:var(--ink);line-height:1.3}
.post-by-date{font-size:13px;color:var(--body);line-height:1.3}
/* A separator glyph, not content - but line-strong on white is 1.56:1 and reads as a
   rendering fault rather than a deliberate mark. */
.post-by-sep{color:var(--muted);margin:0 3px}

/* A fixed 16:9 window, cropped, rather than whatever shape the upload happens to be.
   A square cover rendered at the article width came out 690px tall and pushed the first
   paragraph off the screen; pinning the ratio also reserves the right space before the
   image loads, so the article does not jump. */
.post-cover{width:100%;aspect-ratio:16/9;object-fit:cover;display:block;
  /* No border: the article is a bordered panel now, and a bordered image inside it is
     a box in a box. */
  border-radius:var(--radius);margin:0 0 22px;background:var(--paper)}

/* Key takeaways. A tinted card with an orange edge - it has to read as a different kind
   of block from the article, or it is just a bulleted list that happens to be first. */
.post-key{margin:0 0 36px;padding:24px 26px;background:var(--paper);
  border:1px solid var(--line);border-left:3px solid var(--orange);
  border-radius:var(--radius)}
.post-key-h{margin:0 0 14px;display:flex;align-items:center;gap:9px;
  font-size:12px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;
  color:var(--navy)}
.post-key-h i{color:var(--orange);font-size:14px}
.post-key ul{list-style:none;margin:0;padding:0;display:grid;gap:11px}
.post-key li{position:relative;padding-left:23px;font-size:15.5px;line-height:1.6;
  color:var(--body)}
.post-key li::before{content:"";position:absolute;left:0;top:9px;width:7px;height:7px;
  border-radius:50%;background:var(--orange)}

/* -- the contents rail --
   Numbered, because an article's sections genuinely are a sequence and the number tells
   the reader how far in they are. A hairline runs down the list and the active item
   pulls it orange, so position is readable at a glance without reading the labels. */
.post-side{position:sticky;top:100px}
.post-toc{border:1px solid var(--line);border-radius:var(--radius-lg);
  background:var(--white);padding:20px;box-shadow:var(--shadow-sm)}
.post-toc-h{margin:0 0 14px;padding-bottom:12px;border-bottom:1px solid var(--line);
  font-size:11px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
  color:var(--navy)}
.post-toc ol{list-style:none;margin:0;padding:0;counter-reset:toc}
.post-toc li{counter-increment:toc}
.post-toc a{display:flex;gap:11px;padding:8px 10px 8px 0;
  font-size:13.5px;line-height:1.5;color:var(--body);
  transition:color .15s var(--ease)}
.post-toc a::before{content:counter(toc,decimal-leading-zero);flex:none;
  font-size:11px;font-weight:800;color:var(--line-strong);padding-top:2px;
  font-variant-numeric:tabular-nums;transition:color .15s var(--ease)}
.post-toc a:hover{color:var(--ink)}
.post-toc a:hover::before{color:var(--muted)}
/* Set by the script as the reader passes each heading. */
.post-toc a.is-on{color:var(--navy);font-weight:700}
.post-toc a.is-on::before{color:var(--orange)}
/* An H3 is a step inside the section above it, so it indents and drops its number. */
.post-toc li.lvl-3{counter-increment:none}
/* The indent and the missing number carry the hierarchy, so the colour does not have
   to - and muted at 13px is the same 3.77:1 the meta line just failed on. No post has an
   H3 today, which is exactly why it is worth fixing before one does. */
.post-toc li.lvl-3 a{padding-left:26px;font-size:13px;color:var(--body)}
.post-toc li.lvl-3 a::before{content:"";width:0}
.post-toc li.lvl-3 a:hover{color:var(--ink)}

/* The same list inline, for the width where the rail has gone. */
.post-toc-inline{margin:0 0 30px;border:1px solid var(--line);
  border-radius:var(--radius);background:var(--paper)}
.post-toc-inline > summary{display:flex;align-items:center;justify-content:space-between;
  gap:12px;list-style:none;cursor:pointer;padding:14px 18px;
  font-size:13.5px;font-weight:700;color:var(--ink);
  letter-spacing:.02em}
.post-toc-inline > summary::-webkit-details-marker{display:none}
.post-toc-inline > summary i{font-size:12px;color:var(--muted);
  transition:transform .22s var(--ease)}
.post-toc-inline[open] > summary{border-bottom:1px solid var(--line)}
.post-toc-inline[open] > summary i{transform:rotate(180deg)}
.post-toc-inline ol{list-style:none;margin:0;padding:10px 12px;display:grid;gap:1px}
.post-toc-inline a{display:block;padding:7px 10px;border-radius:7px;
  font-size:13.5px;line-height:1.45;color:var(--body)}
.post-toc-inline a:hover{background:var(--white);color:var(--ink)}
.post-toc-inline li.lvl-3 a{padding-left:24px;font-size:13px;color:var(--body)}

/* -- the article body --
   Justified, with hyphens on. Justification alone stretches the word spaces to fill each
   line, and at this measure that opens white rivers down the paragraph; letting the
   browser hyphenate gives it somewhere else to take up the slack. text-align-last keeps
   the closing line of a paragraph ragged, because a justified last line is the classic
   way a paragraph ends up as five words spread across the full column. */
.post-body{text-align:justify;text-align-last:left;
  hyphens:auto;-webkit-hyphens:auto;overflow-wrap:break-word}
/* Headings and short lines stay ragged - justifying a two-word heading is what produces
   letters spaced across a whole line. */
.post-body :is(h2,h3,h4,blockquote,figcaption,th,td){text-align:left;hyphens:manual}

/* A heading landed on from the contents list must not sit under the sticky header. */
.post-body :is(h2,h3){scroll-margin-top:var(--anchor-top)}
.post-body h2,.post-body h3.as-h2{font-size:clamp(21px,2.2vw,26px);line-height:1.3;letter-spacing:-.015em;
  margin:42px 0 14px}
/* An article is read, not scanned, so the copy gets a little more room than the rest of
   the site and the paragraph gap does the separating rather than an indent. */
.post-body p{margin:0 0 20px;line-height:1.85}
.post-body ul,.post-body ol{margin:0 0 20px;padding-left:24px}
.post-body li{margin-bottom:10px;line-height:1.8}
.post-body li::marker{color:var(--orange)}
.post-body a{color:var(--navy);font-weight:600;
  text-decoration:underline;text-decoration-color:var(--line-strong);
  text-underline-offset:3px;transition:text-decoration-color .15s var(--ease)}
.post-body a:hover{text-decoration-color:var(--orange)}
.post-body img{max-width:100%;height:auto;border-radius:var(--radius);
  border:1px solid var(--line);margin:8px 0 24px}
.post-body blockquote{margin:26px 0;padding:4px 0 4px 22px;
  border-left:3px solid var(--orange);font-size:17.5px;line-height:1.7;
  color:var(--ink);font-style:normal}
.post-body blockquote p:last-child{margin-bottom:0}
.post-body hr{border:0;border-top:1px solid var(--line);margin:34px 0}
/* A table in an article is nearly always wider than the column on a phone. */
.post-body table{width:100%;border-collapse:collapse;margin:0 0 24px;font-size:15px}
.post-body :is(th,td){padding:11px 12px;border-bottom:1px solid var(--line)}
.post-body th{background:var(--paper);font-weight:700;color:var(--ink)}

.post-faq{margin-top:48px;padding-top:34px;border-top:1px solid var(--line)}
.post-faq > h2,.post-faq > h3.as-h2{margin:0 0 18px;font-size:clamp(19px,2vw,24px)}
/* The FAQ list is a bordered card on the product page, where it sits on a bare section.
   Inside this bordered panel that is a box in a box, so here it drops its frame and the
   rows separate themselves with hairlines. */
.post-faq .pdp-faqs{border:0;border-radius:0}
.post-faq .pdp-faq{border-bottom:1px solid var(--line)}
.post-faq .pdp-faq:last-child{border-bottom:0}
.post-faq .pdp-faq > summary{padding-inline:0}
.post-faq .pdp-faq-a{padding-inline:0}

/* -- end of the article --
   It used to stop dead on the last paragraph. */
.post-end{display:flex;align-items:center;justify-content:space-between;gap:20px;
  flex-wrap:wrap;margin-top:40px;padding-top:26px;border-top:1px solid var(--line)}
.post-end-back{display:inline-flex;align-items:center;gap:9px;
  font-size:14px;font-weight:700;color:var(--navy)}
.post-end-back:hover{color:var(--orange)}
.post-end-back i{font-size:12px}

.post-share{display:flex;align-items:center;gap:9px}
/* --body: muted at 12px measured 3.77:1 on the white panel, under AA. */
.post-share-k{font-size:12px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;
  color:var(--body);margin-right:2px}
.post-share-b{width:38px;height:38px;border-radius:50%;flex:none;padding:0;
  display:inline-flex;align-items:center;justify-content:center;
  border:1px solid var(--line);background:var(--white);color:var(--body);
  font-size:15px;cursor:pointer;
  transition:background .16s var(--ease),color .16s var(--ease),
    border-color .16s var(--ease)}
.post-share-b:hover{background:var(--navy);border-color:var(--navy);color:#fff}
.post-share-b.is-wa:hover{background:#25D366;border-color:#25D366;color:#fff}
/* Set by the script for a moment after a successful copy - the click has no other
   visible result, and a button that appears to do nothing gets clicked again. */
.post-share-b.is-done{background:#1E5B26;border-color:#1E5B26;color:#fff}

/* Under the contents card. Navy so it reads as an action rather than a third card of
   reference material - it is the only thing in the rail asking for something. */
.post-cta{margin-top:16px;padding:22px 20px;border-radius:var(--radius-lg);
  background:var(--navy);color:#fff;display:grid;gap:8px;justify-items:start}
.post-cta > i{font-size:17px;color:var(--orange)}
.post-cta-t{margin:0;font-size:15px;font-weight:700;line-height:1.35;color:#fff}
.post-cta-p{margin:0 0 6px;font-size:13.5px;line-height:1.55;color:rgba(255,255,255,.78)}
.post-cta .btn{width:100%;justify-content:center}
.post-cta-alt{font-size:13px;font-weight:650;color:rgba(255,255,255,.8);
  display:inline-flex;align-items:center;gap:7px;margin-top:2px}
.post-cta-alt:hover{color:var(--orange)}
.post-cta-alt i{font-size:11px}

/* The blog cards in the related slider need a width, or a flex track collapses them.
   The stretch matters as much: a two-line title made one card 26px shorter than the one
   beside it, so the row of "Read article" links stepped up and down across the track. */
.post-track > li{flex:none;width:clamp(268px,30vw,336px);scroll-snap-align:start;
  display:flex}
.post-track .bcard{width:100%;display:flex;flex-direction:column}
.post-track .bcard-img{flex:none}
/* The body takes the slack and pushes its own last child - the "Read article" row -
   to the bottom, so that row lands level across the track however the titles wrap. */
.post-track .bcard-body{flex:1;display:flex;flex-direction:column}
.post-track .bcard-body > :last-child{margin-top:auto}

@media (max-width:980px){
  /* The rail goes and the inline contents list below the takeaways takes over its job.
     The article needs its own measure back here: without the rail beside it the column
     is the full row, and body copy ran to 924px - well past the point where the eye
     loses the start of the next line. */
  .post-lay{grid-template-columns:minmax(0,1fr)}
  .post-side{display:none}
  .post-main{max-width:76ch;margin-inline:auto}
}
@media (min-width:981px){
  /* And above it, the inline one would be a second copy of the rail. */
  .post-toc-inline{display:none}
}
@media (max-width:560px){
  .post-key{padding:18px 18px}
}
/* ---------- CTA band ---------- */
.cta-band{text-align:center;padding:96px 0}
.cta-band h2,.cta-band h3.as-h2{max-width:20ch;margin:0 auto 16px}
.cta-band p{color:rgba(255,255,255,.76);max-width:54ch;margin:0 auto 32px;font-size:17.5px}

/* Divider between two category blocks. Full bleed like the why band, but one
   low row instead of a section: copy left, a single action right. The tall
   centred .cta-band (still used on the inner pages) would have read as a
   section of its own and broken the run of product blocks. */
.cta-divider{padding:34px 0}
.cta-divider .wrap{display:flex;align-items:center;gap:26px}
.cta-divider-ic{
  display:inline-flex;align-items:center;justify-content:center;
  width:60px;height:60px;border-radius:16px;flex:none;
  background:var(--orange);color:var(--ink);font-size:23px;
}
.cta-divider-copy{flex:1 1 auto;min-width:0}
.cta-divider-copy h2,.cta-divider-copy h3.as-h2{color:#fff;font-size:clamp(20px,1.9vw,25px);line-height:1.2;margin:0 0 6px}
.cta-divider-copy p{margin:0;font-size:15px;line-height:1.6;color:rgba(255,255,255,.7);max-width:66ch}
.cta-divider .btn{flex:none}

/* Button drops under the copy, but the icon stays beside it - giving the copy
   its own row left the icon alone on a line and doubled the band's height. */
@media (max-width:700px){
  .cta-divider .wrap{flex-wrap:wrap;row-gap:20px}
  .cta-divider-copy{flex:1 1 240px}
  .cta-divider .btn{flex:1 1 100%;max-width:280px;margin-left:86px}
}
@media (max-width:640px){
  .cta-divider{padding:28px 0}
  .cta-divider .wrap{gap:18px}
  .cta-divider-ic{width:50px;height:50px;border-radius:14px;font-size:19px}
  .cta-divider .btn{margin-left:0;max-width:none}
}

/* ---------- industries ----------
   Its own ground: white above (toasters) and --paper below (blog), so this takes
   the bluer --tint and all three read as separate bands. Cards stay white and
   bordered - the why band already uses filled panels, and two filled grids on one
   page start to look like the same section twice. */
.industries{background:var(--tint)}
/* Heading and intro run the full wrap. Capped at 62ch they broke over two lines
   with half the row empty beside them. */
.industries .section-head{max-width:none}
.industries .section-head h2,.industries .section-head h3.as-h2{max-width:none}
.industries .cat-intro{max-width:none}
.ind-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}
.ind-item{
  padding:26px 24px 24px;border:1px solid var(--line);border-radius:var(--radius-lg);
  background:var(--white);
  transition:border-color .22s var(--ease),box-shadow .22s var(--ease),
             transform .22s var(--ease);
}
.ind-item:hover{border-color:var(--line-strong);box-shadow:0 12px 30px rgba(15,34,66,.09);
  transform:translateY(-3px)}
.ind-ic{
  display:inline-flex;align-items:center;justify-content:center;
  width:48px;height:48px;border-radius:13px;margin-bottom:17px;
  background:var(--tint);color:var(--navy);font-size:19px;
  transition:background .22s var(--ease),color .22s var(--ease);
}
/* Same hover language as the USP strip, so the two icon rows behave alike. */
.ind-item:hover .ind-ic{background:var(--orange);color:var(--ink)}
.ind-item h3{font-size:16.5px;margin:0 0 8px;letter-spacing:-.01em}
.ind-item p{font-size:14px;line-height:1.6;color:var(--muted);margin:0}

@media (max-width:1180px){
  .ind-grid{grid-template-columns:repeat(3,1fr)}
}
@media (max-width:860px){
  .ind-grid{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:560px){
  .ind-grid{grid-template-columns:minmax(0,1fr);gap:14px}
  .ind-item{padding:22px 20px}
  .ind-ic{width:42px;height:42px;border-radius:11px;margin-bottom:14px;font-size:17px}
}
@media (max-width:1180px){
  .pgrid{grid-template-columns:repeat(3,1fr)}
  .prod-track > li{flex:0 0 calc((100% - 40px) / 3)}
  .why-grid{grid-template-columns:repeat(2,1fr)}
  /* Copy column no longer has room beside a two-up slider. minmax(0,1fr) and
     not 1fr: a bare 1fr track takes min-content as its floor, and the product
     card pushed the column 45px wider than the wrap, scrolling the whole page. */
  .cat-split{grid-template-columns:minmax(0,1fr);gap:30px;align-items:start}
  .cat-split-slider .slider-prev{left:-18px}
  .cat-split-slider .slider-next{right:-18px}

  /* Below 1180 the copy stops clearing the artwork's navy diagonal, so the
     banner becomes a band under the copy at its own ratio - nothing cropped.
     Narrowing the copy instead made it worse: the headline wrapped onto more
     lines, the hero grew taller, and a taller hero crops more off the sides,
     which drags the diagonal further left than the copy was saved by. */
  .hero{display:flex;flex-direction:column;background:var(--white)}
  .hero-bg{position:static;order:2;width:100%}
  .hero-bg img{height:auto;aspect-ratio:1920/700;object-position:center}
  .hero-in{order:1;display:block;min-height:0;padding-top:44px;padding-bottom:40px}
  .hero-copy{max-width:none}

  /* The hero now ends with the photograph, so the card must not ride up onto it
     and cover the machines. It sits below with a clear gap instead. */
  .usp-bar{margin-top:0;padding-top:36px}
}
@media (max-width:980px){
  .pgrid{grid-template-columns:repeat(2,1fr)}
  .prod-track > li{flex:0 0 calc((100% - 26px) / 2.3)}
  .prod-track-2 > li{flex:0 0 calc((100% - 26px) / 2.3)}
  /* Heading and the "view all" link stop fitting on one line together. */
  .cat-block-head{flex-direction:column;align-items:flex-start;gap:16px}
  .bgrid{grid-template-columns:repeat(2,1fr)}
  .usp-grid{grid-template-columns:repeat(2,1fr)}
  .enq-wrap,.about-split{grid-template-columns:1fr;gap:40px}
  /* Stacked, so there is nothing beside it to centre against. */
  .about-points{align-self:stretch}
  .stats{grid-template-columns:repeat(2,1fr);gap:34px}
  /* Two per row, so the vertical hairline only belongs between the pair. */
  .about-stats{grid-template-columns:repeat(2,1fr);gap:32px 0;margin-top:44px;padding-top:32px}
  .about-stats .stat{padding:0 22px}
  .about-stats .stat:nth-child(odd){padding-left:0}
  .about-stats .stat:nth-child(odd)::before{display:none}
}
@media (max-width:640px){
  /* Below roughly 45 characters a line, justification stops closing gaps and
     starts making them. Left-aligned reads better on a phone. */
  .about-lede,.about-body{text-align:left;hyphens:manual}
  /* nowrap would push the heading off the screen once the column is this narrow. */
  #about h2,#about h3.as-h2{text-wrap:balance}
}
@media (max-width:520px){
  /* Two by two, centred, right down to the narrowest phone - not a single column.
     Stacked one per row the four figures ran down the left edge with most of the width
     empty beside them, and every difference in glyph width showed against that shared
     edge. Two across fills the row, halves the height of the block, and centring means
     there is no shared edge left to compare against.
     The dividers go: they belong to the four-across desktop row, and between two narrow
     centred cells they read as a table rule. */
  .about-stats{grid-template-columns:repeat(2,1fr);gap:26px 14px;text-align:center}
  .about-stats .stat{padding:0}
  .about-stats .stat::before{display:none}
  .about-actions .btn{flex:1 1 auto;justify-content:center}
}
@media (max-width:860px){
  /* Phone crop is the right-hand cluster only, so it is much less wide. */
  .hero-bg img{aspect-ratio:3/2}
  .hero-lede{font-size:16.5px;margin-bottom:26px}
  .hero-actions .btn{flex:1 1 auto;justify-content:center}
}
@media (max-width:640px){
  .pgrid,.bgrid,.usp-grid{grid-template-columns:1fr}
  .why-grid{grid-template-columns:1fr;gap:16px}
  .why-head{flex-direction:column;align-items:flex-start;gap:20px}
  .prod-track-2 > li{flex:0 0 82%}
  /* A peeking half card is what tells a touch user the row scrolls. */
  .prod-track > li{flex:0 0 82%}
  .usp-bar-in{grid-template-columns:1fr;column-gap:0}
  .usp-item:nth-child(even)::before{display:none}
  .usp-item + .usp-item{border-top:1px solid var(--line)}
  .usp-item{padding:18px 0}
  .enq-row{grid-template-columns:1fr}
  .buy{flex-wrap:wrap}
  .buy .btn{width:100%}
  .cta-band{padding:64px 0}
}
