/* ============================================================================
   product.css — the standalone pages at /shop/<slug>.html and /brands/*.html

   shop.css already draws a product: .pdp__grid, .pdp__gallery, .pdp__side,
   .pdp__features, .pdp__buy and the rest are the panel shop.js opens, and
   .relgrid/.relcard are the small cards it recommends with. This file does
   NOT redraw any of that. It supplies only what a panel never needed because
   it floated over a page that already existed:

     - the page frame the panel got from .pdp__card
     - a breadcrumb
     - a stock line (the panel says it in a flag over the image; a page with
       a whole column to itself can say it in words)
     - the heading over the related-products strip
     - the brand pages' hero, tag row and directory cards
     - since 2026-09-13, the sections a page has and a panel never did: the
       specifications table, the "works with" chips, the variant row, the
       datasheet link, the stock-alert fold-out, the questions block with its
       form, the recommendation strips, the zoom button and the lightbox

   Everything here reads the same tokens as the rest of the site. No new
   colours, no new spacing values — bar one: the lightbox ground, which no
   alias carries. It is the page's own ground, nearly opaque, in either
   theme, so the photograph is the only thing left to look at.
   ========================================================================= */

:root { --lightbox-ground: rgba(3, 6, 15, 0.94); }

:root[data-theme="light"],
:root:not([data-theme]) [data-surface="light"] {
  --lightbox-ground: rgba(248, 250, 253, 0.96);
}

.pdppage { padding-top: calc(var(--nav-h) + var(--s-6)); }

/* The panel had a card around it. On the page, the grid IS the card. */
.pdppage .pdp__grid {
  gap: var(--s-6);
  align-items: start;
}
@media (min-width: 760px) {
  .pdppage .pdp__grid { gap: var(--s-8); }
}

.pdppage .pdp__side { padding: 0; }
.pdppage .pdp__title { font-size: var(--t-h2); }

.pdppage .pdp__media {
  background: var(--bg-raised);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  overflow: hidden;
}

.pdppage .pdp__summary { font-size: var(--t-body); }




/* ---- the stock line ----------------------------------------------------- */

.pdp__stock {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-size: var(--t-small);
  font-weight: 500;
  color: var(--text-secondary);
}
.pdp__stock::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.pdp__stock[data-state="in_stock"] { color: var(--good); }
.pdp__stock[data-state="low"]      { color: var(--warn); }
.pdp__stock[data-state="on_order"] { color: var(--accent); }
.pdp__stock[data-state="discontinued"],
.pdp__stock[data-state="out"]      { color: var(--text-tertiary); }


/* ---- reviews ------------------------------------------------------------ */

.pdppage .pdp__reviews:not(:empty) {
  margin-top: var(--s-8);
  padding-top: var(--s-7);
  border-top: 1px solid var(--rule);
}


/* ---- save, compare and share on the page ------------------------------- */

.pdppage .pdp__tools { padding-top: var(--s-2); }
.pdppage .sharerow { border-top: 1px solid var(--rule-faint); }
.pdppage .pdp__brandlink { color: inherit; }


/* ---- related, on the page -----------------------------------------------
   .relgrid and .relcard themselves live in shop.css now, because the shop
   page draws them too (under the panel, and in the recently-viewed strip).
   This is the heading, and the stack of up to three strips — goes with,
   other brands for the same job, more from the brand — in one section. */

.relblocks { display: grid; gap: var(--s-8); }
.relblock + .relblock { padding-top: var(--s-7); border-top: 1px solid var(--rule); }

.reltitle {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-4); flex-wrap: wrap;
  font-size: var(--t-h4);
  letter-spacing: var(--track-tight);
  margin-bottom: var(--s-5);
}
/* "All Energy meters →" measured 102x12 on a phone. It is a standalone link
   in a heading rather than a link inside a sentence, so the inline exemption
   in WCAG 2.5.8 does not cover it and 12px high fails the 24px minimum
   outright. inline-flex with a min-height is the whole fix — the type stays
   the size it was, and the box around it grows to something a thumb can
   find. */
.reltitle a {
  display: inline-flex; align-items: center; min-height: 2.75rem;
  font-family: var(--font-text); font-size: var(--t-tiny); font-weight: 400; letter-spacing: 0;
  color: var(--text-secondary); text-decoration: none;
}
.reltitle a:hover { color: var(--accent); }
.reltitle a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-xs); }


/* ============================================================================
   THE PAGE'S OWN SECTIONS — added 2026-09-13

   Everything below is drawn only when build-product-pages.py had the data
   for it, except the ask-a-question form and the zoom button, which every
   page carries. Same tokens as the rest of the site; no new colours.
   ========================================================================= */


/* ---- zoom button and the stage ------------------------------------------
   The button sits over the top-right corner of the photograph, outside
   #pdpMedia so a thumbnail click (which empties that element) cannot remove
   it. The stage itself is a target too — a magnifier cursor says so. */

.pdppage .pdp__gallery { position: relative; }
.pdppage .pdp__media.is-zoomable { cursor: zoom-in; }
.pdp__zoom {
  position: absolute; top: var(--s-3); right: var(--s-3); z-index: 2;
  width: 2.25rem; height: 2.25rem;
  display: grid; place-items: center;
  border-radius: var(--r-pill);
  border: 1px solid var(--rule-strong);
  background: var(--glass); backdrop-filter: blur(10px);
  color: var(--text-secondary); cursor: zoom-in;
  transition: border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.pdp__zoom svg { width: 16px; height: 16px; }
@media (hover: hover) and (pointer: fine) {
  .pdp__zoom:hover { border-color: var(--rule-accent); color: var(--accent); }
}
.pdp__zoom:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }


/* ---- lightbox ------------------------------------------------------------
   Built by product.js on first open. One picture, two arrows, a close, a
   count. The theme's ground rather than a card: the photograph is the whole
   point. */

.lightbox {
  position: fixed; inset: 0; z-index: calc(var(--z-overlay) + 10);
  display: grid; place-items: center;
  padding: var(--s-6);
  background: var(--lightbox-ground);
  backdrop-filter: blur(6px);
  animation: lightbox-in var(--dur-base) var(--ease-out);
}
.lightbox[hidden] { display: none; }
@keyframes lightbox-in { from { opacity: 0; } to { opacity: 1; } }

.lightbox__stage {
  margin: 0; max-width: 100%; max-height: 100%;
  display: grid; place-items: center;
  overflow: hidden;
}
.lightbox__img {
  display: block;
  max-width: min(92vw, 60rem);
  max-height: 84vh;
  width: auto; height: auto;
  object-fit: contain;
  cursor: zoom-in;
  transition: transform var(--dur-base) var(--ease-out);
  will-change: transform;
}
.lightbox__img.is-zoomed { transform: scale(2); cursor: zoom-out; }

.lightbox__btn {
  position: absolute;
  width: 2.75rem; height: 2.75rem;
  display: grid; place-items: center;
  border-radius: var(--r-pill);
  border: 1px solid var(--rule-strong);
  background: var(--glass); backdrop-filter: blur(10px);
  color: var(--text-primary); cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.lightbox__btn svg { width: 18px; height: 18px; }
.lightbox__btn[hidden] { display: none; }
@media (hover: hover) and (pointer: fine) {
  .lightbox__btn:hover { border-color: var(--rule-accent); color: var(--accent); }
}
.lightbox__btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lightbox__close { top: var(--s-5); right: var(--s-5); }
.lightbox__prev  { left: var(--s-4); top: 50%; transform: translateY(-50%); }
.lightbox__next  { right: var(--s-4); top: 50%; transform: translateY(-50%); }
.lightbox__count {
  position: absolute; bottom: var(--s-5); left: 50%; transform: translateX(-50%);
  margin: 0;
  font-family: var(--font-data); font-size: var(--t-micro);
  letter-spacing: var(--track-wide); color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}
@media (prefers-reduced-motion: reduce) {
  .lightbox { animation: none; }
  .lightbox__img { transition: none; }
}


/* ---- works with ---------------------------------------------------------- */

.works { display: grid; gap: var(--s-2); }
.works__label { margin: 0; }
.works__list { display: flex; flex-wrap: wrap; gap: var(--s-2); list-style: none; margin: 0; padding: 0; }
.works__list .chip { text-transform: none; letter-spacing: 0; font-family: var(--font-text); font-size: var(--t-tiny); }


/* ---- the small link row: datasheet, specifications, questions ----------- */

.pdp__links {
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-5);
  margin: 0;
  font-size: var(--t-tiny);
}
.doclink {
  display: inline-flex; align-items: center; gap: var(--s-2);
  color: var(--text-secondary); text-decoration: none;
  border-bottom: 1px solid var(--rule-strong);
  transition: color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.doclink svg { width: 13px; height: 13px; flex: none; }
@media (hover: hover) and (pointer: fine) {
  .doclink:hover { color: var(--accent); border-color: var(--rule-accent); }
}
.doclink:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-xs); }


/* ---- variants: the other sizes and colours, as links -------------------- */

.variants { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.variants__label {
  font-family: var(--font-data); font-size: var(--t-micro);
  letter-spacing: var(--track-wide); text-transform: uppercase; color: var(--text-tertiary);
  margin-right: var(--s-2);
}
.variant {
  display: inline-flex; align-items: center;
  min-height: 2.25rem; padding: 0 var(--s-4);
  border: 1px solid var(--rule); border-radius: var(--r-sm);
  background: var(--bg-panel);
  font-family: var(--font-data); font-size: var(--t-tiny);
  color: var(--text-secondary); text-decoration: none;
  transition: border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  a.variant:hover { border-color: var(--rule-accent); color: var(--accent); }
}
a.variant:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.variant[aria-current="page"] {
  border-color: var(--accent); color: var(--text-primary);
  box-shadow: 0 0 0 1px var(--rule-accent);
}
@media (pointer: coarse) { .variant { min-height: 2.75rem; } }

/* The rest of the product page's targets, same rule and same reasoning. */
@media (pointer: coarse) {
  /* Full-screen photographs. It sits over the corner of the image, which is
     itself a target, so a miss opens nothing and reads as a dead button. */
  .pdp__zoom { width: 2.75rem; height: 2.75rem; }
  /* The brand line above the title and the datasheet link below it: both
     set as text beside other text, both padded out rather than grown so
     that nothing on the page moves. */
  .pdp__brandlink,
  .doclink { display: inline-flex; align-items: center; min-height: 2.75rem; }
  /* "Tell me when it is in" - 42px, two short of the floor. */
  .notify__summary { min-height: 2.75rem; }
}


/* ---- "tell me when it is in stock" --------------------------------------- */

.notify {
  border: 1px dashed var(--rule); border-radius: var(--r-sm);
  font-size: var(--t-tiny); color: var(--text-secondary);
}
.notify__summary {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-3);
  cursor: pointer; list-style: none;
  color: var(--text-secondary);
  transition: color var(--dur-fast) var(--ease-out);
}
.notify__summary::-webkit-details-marker { display: none; }
.notify__summary svg { width: 14px; height: 14px; flex: none; color: var(--accent); }
@media (hover: hover) and (pointer: fine) {
  .notify__summary:hover { color: var(--accent); }
}
.notify__summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--r-sm); }
.notify[open] .notify__summary { border-bottom: 1px dashed var(--rule); }
.notify__form { display: grid; gap: var(--s-3); padding: var(--s-4) var(--s-3); }
.notify__lead, .notify__note { margin: 0; line-height: var(--lead-text); }
.notify__note { color: var(--text-quiet); }
.notify__row { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.notify__row .field__input { flex: 1 1 12rem; padding-block: var(--s-3); }
.notify__row .btn { flex: none; }
.notify__form .field__error { display: none; }
.notify__form.has-error .field__error { display: block; }
.notify__form.has-error .field__input { border-color: color-mix(in srgb, var(--alert) 50%, transparent); }
.notify__form.is-sent .notify__row,
.notify__form.is-sent .notify__lead,
.notify__form.is-sent .notify__note,
.notify__form.is-sent .field__error { display: none; }


/* ---- the sections under the grid ----------------------------------------- */

.pdp__more {
  display: grid; gap: var(--s-8);
  margin-top: var(--s-8);
  align-items: start;
}
@media (min-width: 900px) {
  .pdp__more { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: var(--s-9); }
  /* One section alone should not sit in a half-width column. */
  .pdp__more > :only-child { grid-column: 1 / -1; max-width: 46rem; }
}
.pdp__block { padding-top: var(--s-7); border-top: 1px solid var(--rule); min-width: 0; }

/* "More information" — the supplier's description, which used to sit beside
   the price. It reads across the full width, and where it is the only thing
   above one other section that section gets the width too rather than
   standing in a half column with nothing beside it. */
.pdp__block--wide { grid-column: 1 / -1; max-width: 46rem; }
@media (min-width: 900px) {
  .pdp__more > .pdp__block--wide:first-child + .pdp__block:last-child {
    grid-column: 1 / -1; max-width: 46rem;
  }
}

/* Two paragraphs of prose, and the page's reset gives a <p> no margin at
   all — without this the repeated lead and the description read as one
   unbroken block. The panel gets the same air from .pdp__foldbody's gap. */
.pdp__about p + p { margin-top: var(--s-4); }

/* Nothing in it but the lead repeated, so it waits for product.js to say the
   clamp upstairs actually cut something. .is-ledeclipped and .pdp__ledefull
   are shop.css's, which this page loads first. */
.pdp__block--ifclipped { display: none; }
.is-ledeclipped .pdp__block--ifclipped { display: block; }
.pdp__h2 {
  font-size: var(--t-h4); letter-spacing: var(--track-tight);
  margin-bottom: var(--s-5);
  display: flex; align-items: baseline; gap: var(--s-3);
}
.pdp__h2count {
  font-family: var(--font-data); font-size: var(--t-tiny); font-weight: 400;
  letter-spacing: 0; color: var(--text-quiet);
}


/* ---- specifications ------------------------------------------------------ */

.specs__scroll { overflow-x: auto; }
.specs__table {
  width: 100%; border-collapse: collapse;
  font-size: var(--t-small); line-height: var(--lead-text);
}
.specs__table th, .specs__table td {
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--rule-faint);
  text-align: left; vertical-align: top;
}
.specs__table th {
  width: 38%;
  font-family: var(--font-data); font-size: var(--t-micro); font-weight: 500;
  letter-spacing: var(--track-wide); text-transform: uppercase;
  color: var(--text-tertiary);
}
.specs__table th[colspan] { color: var(--text-secondary); text-transform: none; letter-spacing: 0; font-family: var(--font-text); font-size: var(--t-small); }
.specs__table td { color: var(--text-primary); font-variant-numeric: tabular-nums; }
.specs__table tr:nth-child(odd) th, .specs__table tr:nth-child(odd) td { background: var(--bg-raised); }


/* ---- questions and answers ---------------------------------------------- */

.qa__list { margin-bottom: var(--s-6); }
.qa .acc__trigger { font-size: var(--t-body); padding-block: var(--s-4); }
.qa .acc__body { padding-bottom: var(--s-5); padding-right: var(--s-6); white-space: pre-line; }

.ask { display: grid; gap: var(--s-4); }
.ask__lead { margin: 0; font-size: var(--t-small); color: var(--text-secondary); line-height: var(--lead-text); }
.ask__row { display: grid; gap: var(--s-4); }
@media (min-width: 560px) { .ask__row { grid-template-columns: 1fr 1fr; } }
.ask .field__textarea { min-height: 5.5rem; }
.ask .field__input, .ask .field__textarea { padding-block: var(--s-3); }
.field__opt { text-transform: none; letter-spacing: 0; color: var(--text-quiet); }
.ask__foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3) var(--s-5); }
.ask__note { font-size: var(--t-tiny); color: var(--text-quiet); }
.ask.is-sent .field, .ask.is-sent .ask__row, .ask.is-sent .ask__foot, .ask.is-sent .ask__lead { display: none; }


/* ---- the sent / manual line both forms share ----------------------------- */

.sent {
  font-size: var(--t-small); line-height: var(--lead-text); color: var(--text-secondary);
  padding: var(--s-4);
  border: 1px solid var(--rule); border-radius: var(--r-sm);
  background: var(--bg-raised);
}
.sent[hidden] { display: none; }
.sent:focus { outline: none; }
.sent b { color: var(--text-primary); font-weight: 600; }
.sent__who { color: var(--text-primary); }
.sent__ref {
  display: block; margin-top: var(--s-2);
  font-family: var(--font-data); font-size: var(--t-micro);
  letter-spacing: var(--track-wide); text-transform: uppercase; color: var(--text-quiet);
}
.is-manual .sent { border-color: var(--rule-accent); }
.sent__acts { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-4); }
.is-busy .btn__label { opacity: 0.7; }


/* ============================================================================
   BRAND PAGES — /brands/<slug>.html and /brands/index.html

   Generated by scripts/build-product-pages.py from the same template as the
   product pages. The grid is the shop's own .product card, drawn statically,
   so a brand page looks like the shop narrowed to one brand — which is what
   it is, with an address.
   ========================================================================= */

/* Top clears the fixed nav; bottom is the shop hero's, so the light grid
   section sits as close under the brand's name as it does under the shop's. */
.brandpage { padding-top: calc(var(--nav-h) + var(--s-6)); padding-bottom: var(--s-8); }

.brandhero { display: grid; gap: var(--s-4); max-width: 46rem; }
.brandhero__title { font-size: var(--t-h1); letter-spacing: var(--track-tight); line-height: var(--lead-tight); }
.brandhero__meta {
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-5);
  padding-top: var(--s-4); border-top: 1px solid var(--rule);
  font-family: var(--font-data); font-size: var(--t-tiny);
  letter-spacing: var(--track-wide); text-transform: uppercase; color: var(--text-tertiary);
}
.brandhero__meta b { color: var(--accent); font-weight: 500; }
.brandhero__meta a { color: var(--text-secondary); text-decoration: none; }
.brandhero__meta a:hover { color: var(--accent); }

/* What this brand solves — links into the shop with both filters set. */
.brandhero__tags { display: flex; gap: var(--s-2); flex-wrap: wrap; }
.brandhero__tags .chip { text-decoration: none; }
.brandhero__tags .chip:hover { border-color: var(--rule-accent); color: var(--accent); }
.brandhero__tags .chip span { color: var(--text-quiet); }

.brandgrid__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-4); flex-wrap: wrap;
  margin-bottom: var(--s-5);
}
.brandgrid__head .eyebrow { margin: 0; }
.brandgrid__count {
  font-family: var(--font-data); font-size: var(--t-tiny);
  letter-spacing: var(--track-wide); text-transform: uppercase; color: var(--text-tertiary);
}

/* The brand directory: one card per brand. */
.brandcards {
  display: grid; gap: var(--s-4);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
}
.brandcard {
  display: grid; gap: var(--s-3); align-content: start;
  padding: var(--s-5);
  background: var(--bg-panel);
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  color: inherit; text-decoration: none;
  position: relative; overflow: hidden;
  transition: border-color var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.brandcard::after {
  content: ''; position: absolute; inset: auto 0 0 0; height: 1px;
  background: var(--accent); transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur-base) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .brandcard:hover { transform: translateY(-2px); border-color: var(--rule-strong); }
  .brandcard:hover::after { transform: scaleX(1); }
}
.brandcard:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.brandcard__name { font-family: var(--font-display); font-size: var(--t-h4); letter-spacing: var(--track-snug); }
.brandcard__blurb { font-size: var(--t-small); color: var(--text-secondary); line-height: var(--lead-text); }
.brandcard__count {
  font-family: var(--font-data); font-size: var(--t-micro);
  letter-spacing: var(--track-mono); text-transform: uppercase; color: var(--text-quiet);
}
.brandcard__thumbs { display: flex; gap: var(--s-2); }
.brandcard__thumbs span {
  width: 3rem; height: 3rem; border-radius: var(--r-sm);
  border: 1px solid var(--rule); background: var(--bg-sunk); overflow: hidden;
  display: grid; place-items: center;
}
.brandcard__thumbs img { width: 100%; height: 100%; object-fit: contain; padding: 4px; }
