/* ==========================================================================
   catalog.css — the catalogue design language
   --------------------------------------------------------------------------
   Loaded AFTER store.css, on the pages that use the new catalogue layout:
   the category grid on the home page, category.html, and product.html.

   WHY THIS FILE EXISTS
     store.css dresses everything in rounded cards, soft shadows and heavy
     800-weight headings. That is the look that reads as generic — every
     template built in the last few years looks like it. An industrial parts
     catalogue should look like a catalogue: quiet, dense, and structured by
     lines rather than by floating boxes.

   THE FIVE RULES OF THIS LANGUAGE
     1. Headings are LIGHT (300) and large. Never bold. Bold is reserved for
        small print — order codes, table values, active states.
     2. Small text is UPPERCASE with wide tracking. That is what carries the
        "engineering document" feel: buttons, tab labels, filter names.
     3. Structure comes from 1px HAIRLINE RULES, not shadows. Nothing floats.
     4. SQUARE CORNERS everywhere. No border-radius at all.
     5. Photography is DESATURATED. Product shots from a dozen suppliers never
        match; draining the colour out of them makes a grid look deliberate.

   Colour: flat near-black for filled buttons, the brand orange strictly for
   links, active tabs and underlines. The reference site this is modelled on
   uses its own corporate green for both — using ours in the same places keeps
   the structure without borrowing somebody else's brand.
   ========================================================================== */

/* ------------------------------- tokens -------------------------------- */
:root {
  --cg-bg: #e9eaea;          /* page ground behind the catalogue */
  --cg-panel: #ffffff;
  --cg-ink: #17191a;
  --cg-ink-soft: #55595c;
  --cg-rule: #d3d5d6;        /* the hairline that does all the structural work */
  --cg-rule-soft: #e4e6e6;
  --cg-fill: #1b1e20;        /* flat button fill */
  --cg-fill-hi: #2b2f32;
}

/* ------------------------ shared micro-typography ---------------------- */
/*
  Two type treatments do most of the work in this language. A big light
  heading, and a small uppercase label with wide tracking. Everything else is
  body copy.
*/
.cg-h1,
.cg-h2 {
  font-weight: 300;
  letter-spacing: -0.015em;
  line-height: 1.1;
  color: var(--cg-ink);
}

.cg-h1 { font-size: clamp(1.9rem, 4.2vw, 2.85rem); }
.cg-h2 { font-size: clamp(1.5rem, 3.2vw, 2.15rem); }

.cg-label {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* A link with a chevron after it, as used all over the reference site. */
.cg-link {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--brand-2);
}

.cg-link::after {
  content: "";
  width: 6px; height: 6px;
  border-right: 1.5px solid currentColor;
  border-top: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform 200ms var(--ease-out);
}

.cg-link:hover { color: var(--cg-ink); }
.cg-link:hover::after { transform: rotate(45deg) translate(2px, -2px); }

/* Flat, square, uppercase. The workhorse button of this language. */
.cg-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 1.05rem 1.6rem;
  border: 0;
  border-radius: 0;
  background: var(--cg-fill);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 200ms ease;
}

.cg-btn::after {
  content: "";
  width: 6px; height: 6px;
  border-right: 1.5px solid currentColor;
  border-top: 1.5px solid currentColor;
  transform: rotate(45deg);
}

.cg-btn:hover { background: var(--cg-fill-hi); }
.cg-btn--brand { background: var(--brand-2); }
.cg-btn--brand:hover { background: var(--cg-fill); }

.cg-btn--ghost {
  background: transparent;
  color: var(--cg-ink);
  border: 1px solid var(--cg-ink);
}

.cg-btn--ghost::after { display: none; }
.cg-btn--ghost:hover { background: var(--cg-ink); color: #fff; }


/* ========================================================================== */
/* ========================== 1. CATEGORY GRID ============================== */
/* ==========================================================================
   The block that replaces the old icon-and-blurb "Shop by category" strip.

   Six photographs in a 3 x 2 grid. At rest you see only the category name
   over a darkened, desaturated product shot. On hover the whole tile fills
   with brand colour, the name slides to the top, a hairline appears under it,
   the description fades in, and a solid bar drops in at the foot carrying
   "VIEW PRODUCTS".

   The tile is a single <a>. Everything inside is decorative, so the whole
   thing is one big click target and one tab stop.
   ========================================================================== */
.catwall {
  padding-block: clamp(2.5rem, 6vw, 4.5rem);
  background: var(--cg-bg);
}

.catwall__head { margin-bottom: clamp(1.5rem, 3vw, 2.5rem); }
.catwall__head p { margin-top: 0.9rem; max-width: 46rem; color: var(--cg-ink-soft); }

.catwall__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: clamp(0.75rem, 1.6vw, 1.35rem);
}

.cattile {
  position: relative;
  display: block;
  overflow: hidden;
  aspect-ratio: 16 / 9;
  background: #4a4d4f;
  isolation: isolate;
}

.cattile__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* the desaturation that makes a mixed-supplier grid look deliberate */
  filter: grayscale(100%) contrast(1.05) brightness(0.82);
  transition: transform 900ms var(--ease-out), filter 500ms ease;
}

.cattile:hover .cattile__img,
.cattile:focus-visible .cattile__img {
  transform: scale(1.06);
  filter: grayscale(100%) contrast(1.05) brightness(0.4);
}

/* the colour wash that floods in on hover */
.cattile::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: color-mix(in srgb, var(--brand-deep) 82%, transparent);
  opacity: 0;
  transition: opacity 340ms ease;
}

.cattile:hover::before,
.cattile:focus-visible::before { opacity: 1; }

/*
  The body stays vertically centred and never changes its alignment. The name
  riding upward on hover is a SIDE EFFECT of the rule and the description
  growing underneath it — a centred flex column pushes its first child up as
  the ones below it gain height.

  That is deliberate. The obvious way to write this is to flip
  justify-content from center to flex-start on hover, but justify-content is
  not an animatable property, so the name would jump rather than travel. This
  way everything that moves is doing it through max-height and opacity, which
  do animate, and it self-centres at any tile size instead of needing a magic
  padding number per breakpoint.
*/
.cattile__body {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 1.5rem 1.4rem;
  text-align: center;
  color: #fff;
}

.cattile__name {
  font-size: clamp(1rem, 1.5vw, 1.12rem);
  font-weight: 400;
  letter-spacing: 0.01em;
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.5);
}

/* the hairline that draws itself in under the name */
.cattile__rule {
  width: min(72%, 300px);
  height: 1px;
  margin: 0;
  background: rgba(255, 255, 255, 0.55);
  transform: scaleX(0);
  transition: transform 380ms var(--ease-out) 60ms,
              margin 340ms var(--ease-out);
}

.cattile:hover .cattile__rule,
.cattile:focus-visible .cattile__rule {
  transform: scaleX(1);
  margin: 0.85rem 0 0.9rem;
}

.cattile__desc {
  max-width: 30ch;
  max-height: 0;
  overflow: hidden;
  font-size: 0.82rem;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.92);
  opacity: 0;
  transition: max-height 380ms var(--ease-out),
              opacity 260ms ease 120ms;
}

.cattile:hover .cattile__desc,
.cattile:focus-visible .cattile__desc {
  max-height: 9rem;
  opacity: 1;
}

/* the solid bar that drops in at the foot */
.cattile__go {
  position: absolute;
  z-index: 2;
  left: 0; right: 0; bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.95rem;
  background: var(--brand-2);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  transform: translateY(101%);
  transition: transform 340ms var(--ease-out);
}

.cattile__go::after {
  content: "";
  width: 6px; height: 6px;
  border-right: 1.5px solid currentColor;
  border-top: 1.5px solid currentColor;
  transform: rotate(45deg);
}

.cattile:hover .cattile__go,
.cattile:focus-visible .cattile__go { transform: none; }

/*
  Touch screens have no hover, so the tiles would never open up. Show the
  resting state permanently there and let the tap do the work — the
  description is on the category page they land on anyway.
*/
@media (hover: none) {
  .cattile__go { transform: none; }
  .cattile__body { padding-bottom: 3.5rem; }
  .cattile__desc { display: none; }
  .cattile__rule { display: none; }
}


/* ========================================================================== */
/* ====================== 2. CATEGORY LISTING PAGE ========================== */
/* ==========================================================================
   category.html — sidebar of subcategories and filters on the left, a bordered
   grid of products on the right.

   The grid is drawn with shared 1px lines rather than separate cards, which is
   why the cells use negative-margin overlapping borders instead of `gap`.
   ========================================================================== */
.catpage { background: var(--cg-bg); padding-block: 0 clamp(3rem, 6vw, 5rem); }

.catpage__top {
  padding-block: clamp(1.5rem, 3vw, 2.5rem) clamp(1.25rem, 2.5vw, 2rem);
  border-bottom: 1px solid var(--cg-rule);
}

.catpage__top p { margin-top: 0.8rem; max-width: 52rem; color: var(--cg-ink-soft); }

.catpage__body {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.75rem);
  padding-top: clamp(1.5rem, 3vw, 2.25rem);
}

@media (min-width: 900px) {
  .catpage__body { grid-template-columns: 250px minmax(0, 1fr); }
}

/* ------------------------------- sidebar ------------------------------- */
.catside__tree { margin-bottom: 1.5rem; }

/*
  The nested trail. Each level steps in by 1rem, which is what makes it read
  as a tree without needing any connecting lines.
*/
.catside__tree a,
.catside__tree span {
  display: block;
  padding: 0.4rem 0;
  font-size: 0.86rem;
  color: var(--cg-ink-soft);
}

.catside__tree a:hover { color: var(--brand-2); }
.catside__tree .lv1 { padding-left: 0; }
.catside__tree .lv2 { padding-left: 1rem; }
.catside__tree .lv3 { padding-left: 2rem; font-weight: 600; color: var(--cg-ink); }
.catside__tree .lv4 { padding-left: 3rem; }

.catside__tree .is-here {
  color: var(--brand-2);
  font-weight: 600;
}

/* --------------------------- filter accordions ------------------------- */
/*
  These are <details> elements, so opening and closing needs no JavaScript at
  all — and they still work with scripting off.
*/
.catfilter {
  border-top: 1px solid var(--cg-rule);
}

.catfilter:last-of-type { border-bottom: 1px solid var(--cg-rule); }

.catfilter > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.05rem 0.2rem;
  font-size: 0.82rem;
  color: var(--cg-ink);
  cursor: pointer;
  list-style: none;
}

.catfilter > summary::-webkit-details-marker { display: none; }

/* the chevron, drawn from two borders so it needs no icon file */
.catfilter > summary::after {
  content: "";
  flex: none;
  width: 8px; height: 8px;
  margin-right: 4px;
  border-right: 1.5px solid var(--cg-ink-soft);
  border-bottom: 1.5px solid var(--cg-ink-soft);
  transform: translateY(-2px) rotate(45deg);
  transition: transform 240ms var(--ease-out);
}

.catfilter[open] > summary::after { transform: translateY(2px) rotate(-135deg); }
.catfilter > summary:hover { color: var(--brand-2); }

.catfilter__body { padding: 0 0.2rem 1.1rem; }

.catfilter__body label {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.3rem 0;
  font-size: 0.84rem;
  color: var(--cg-ink-soft);
  cursor: pointer;
}

.catfilter__body label:hover { color: var(--cg-ink); }
.catfilter__body input { accent-color: var(--brand); }

/* ----------------------------- results bar ---------------------------- */
.catbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 1.1rem;
}

.catbar__count { font-size: 0.86rem; color: var(--cg-ink-soft); }
.catbar__count b { color: var(--cg-ink); font-weight: 600; }

.catbar__sort {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.82rem;
  color: var(--cg-ink-soft);
}

/* One shared look for every <select> in this language: square, hairline, flat. */
.cg-select {
  appearance: none;
  -webkit-appearance: none;
  padding: 0.7rem 2.2rem 0.7rem 0.85rem;
  border: 1px solid var(--cg-rule);
  border-radius: 0;
  background-color: var(--cg-panel);
  /* chevron as an inline SVG so there is no extra request */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%2355595c' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.8rem center;
  background-size: 11px;
  font: inherit;
  font-size: 0.84rem;
  color: var(--cg-ink);
  cursor: pointer;
}

.cg-select:focus { outline: none; border-color: var(--brand); }

/* ---------------------------- the product grid ------------------------- */
/*
  Cells share their borders: every cell draws a right and bottom rule, and the
  container clips the outermost ones with a negative offset. That is what gives
  the continuous ruled grid instead of a field of separate boxes.
*/
.catgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  border-top: 1px solid var(--cg-rule);
  border-left: 1px solid var(--cg-rule);
  background: var(--cg-panel);
}

.catcell {
  display: flex;
  flex-direction: column;
  padding: 1.6rem 1.25rem 1.4rem;
  border-right: 1px solid var(--cg-rule);
  border-bottom: 1px solid var(--cg-rule);
  text-align: center;
  transition: background 220ms ease;
}

.catcell:hover { background: #fafbfb; }

.catcell__art {
  display: grid;
  place-items: center;
  height: 165px;
  margin-bottom: 1.1rem;
}

.catcell__art img {
  max-width: 100%;
  /* .catcell__art is a grid, so its implicit row auto-sizes to the image and a
     percentage max-height would resolve against THAT row, not the 165px box —
     letting a portrait photo spill over the product name. Pin it to the box
     height in px (the mobile blocks below re-pin it to their smaller boxes). */
  max-height: 165px;
  object-fit: contain;
  filter: grayscale(35%);
  transition: transform 500ms var(--ease-out), filter 300ms ease;
}

.catcell:hover .catcell__art img { transform: scale(1.05); filter: none; }

/*
  Not every part has been photographed yet. Rather than a grey placeholder
  box, those fall back to the line drawing for their family — it still tells
  you at a glance whether you are looking at a cylinder or a fitting.
*/
.catcell__glyph {
  width: 74px;
  height: 74px;
  color: var(--cg-ink-soft);
  opacity: 0.35;
  transition: opacity 300ms ease;
}

.catcell:hover .catcell__glyph { opacity: 0.6; }

.pdp__glyph {
  width: 38%;
  height: 38%;
  color: var(--cg-ink-soft);
  opacity: 0.3;
}

.catcell__name {
  font-size: 0.94rem;
  font-weight: 400;
  line-height: 1.4;
  color: var(--cg-ink);
}

.catcell:hover .catcell__name { color: var(--brand-2); }

.catcell__sku {
  margin-top: 0.5rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--cg-ink-soft);
}

.catcell__price { margin-top: 0.55rem; font-size: 0.86rem; color: var(--cg-ink); }

.catgrid__empty {
  padding: clamp(3rem, 8vw, 5rem) 1.5rem;
  border-right: 1px solid var(--cg-rule);
  border-bottom: 1px solid var(--cg-rule);
  text-align: center;
  color: var(--cg-ink-soft);
  grid-column: 1 / -1;
}

.catgrid__empty b { display: block; margin-bottom: 0.5rem; color: var(--cg-ink); font-weight: 600; }


/* ========================================================================== */
/* ===================== 3. PRODUCT PAGE, RESTYLED ========================== */
/* ==========================================================================
   Overrides for product.html so it reads like the rest of the catalogue:
   square, ruled, light headings, and a tab strip under the fold.
   ========================================================================== */
.pdp-page { background: var(--cg-bg); }

.pdp-page .pdp__stage,
.pdp-page .pdp__thumb {
  border-radius: 0;
  border-color: var(--cg-rule);
  background: var(--cg-panel);
}

.pdp-page .pdp h1 {
  font-weight: 800;
  color: #1d1d1f;
  letter-spacing: -0.02em;
  font-size: clamp(2rem, 4.4vw, 3rem);
  line-height: 1.12;
}

.pdp-page .pdp__eyebrow { color: var(--cg-ink-soft); letter-spacing: 0.14em; }
.pdp-page .pdp__sub { font-size: 0.98rem; color: var(--cg-ink-soft); }

/* the two-up action buttons under the title */
.pdp-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 0.75rem;
  margin: 1.5rem 0 1.1rem;
}

.pdp-links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem 2.5rem;
  padding-bottom: 1.35rem;
  border-bottom: 1px solid var(--cg-rule);
}

/* Collapsible "Product Description", open by default. */
.pdp-fold { border-bottom: 1px solid var(--cg-rule); }

.pdp-fold > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.2rem 0;
  font-size: 1.05rem;
  font-weight: 400;
  color: var(--cg-ink);
  cursor: pointer;
  list-style: none;
}

.pdp-fold > summary::-webkit-details-marker { display: none; }

.pdp-fold > summary::after {
  content: "+";
  font-size: 1.2rem;
  font-weight: 300;
  color: var(--cg-ink-soft);
}

.pdp-fold[open] > summary::after { content: "\2013"; }
.pdp-fold__body { padding-bottom: 1.4rem; }

/*
  The product descriptions — the longest prose on the site, three or four
  paragraphs of it. Set a size up from the 16px default, and capped at 68
  characters a line: past about 75 the eye loses its place coming back to the
  left margin, and on a wide monitor this column was running to well over 100.
*/
.pdp-fold__body p {
  max-width: 68ch;
  margin-bottom: 1rem;
  color: var(--cg-ink-soft);
  font-size: 1.05rem;
  line-height: 1.78;
}

.pdp-fold__body p:last-child { margin-bottom: 0; }

/* ------------------------------- tab strip ---------------------------- */
.ptabs {
  border-top: 1px solid var(--cg-rule);
  border-bottom: 1px solid var(--cg-rule);
  background: var(--cg-bg);
}

.ptabs__list {
  display: flex;
  gap: clamp(1.25rem, 4vw, 3.5rem);
  overflow-x: auto;
  scrollbar-width: none;
}

.ptabs__list::-webkit-scrollbar { display: none; }

.ptabs__tab {
  flex: none;
  padding: 1.2rem 0;
  border: 0;
  border-bottom: 3px solid transparent;
  background: none;
  font-size: 0.71rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--cg-ink-soft);
  white-space: nowrap;
  cursor: pointer;
  transition: color 200ms ease, border-color 200ms ease;
}

.ptabs__tab:hover { color: var(--cg-ink); }

.ptabs__tab[aria-selected="true"] {
  color: var(--brand-2);
  border-bottom-color: var(--brand);
}

.ptab-panel { padding-block: clamp(2rem, 4vw, 3rem); background: var(--cg-bg); }


/* ========================================================================== */
/* ================ 4. THE SIZES SECTION (variant finder) =================== */
/* ==========================================================================
   The "different sizes" block on each product page: a bank of filter
   dropdowns, a result count, and one ruled row per orderable variant with its
   own order code, attribute table and quantity box.

   This is the part that turns a description page into something a fitter can
   actually order from.
   ========================================================================== */
.vf__sel { margin-bottom: 1.1rem; font-size: 0.82rem; color: var(--cg-ink-soft); }

.vf__filters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 0 clamp(1rem, 2.5vw, 2rem);
  margin-bottom: 1.75rem;
}

/* Each filter is a real <select>, so it works on a phone with no extra code. */
.vf__filter {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.95rem 0;
  border-bottom: 1px solid var(--cg-rule);
}

.vf__filter > span {
  font-size: 0.7rem;
  /* 800 (ExtraBold), a clear step up from 700 so the size-option headings
     (Length, Diameter, Models…) read as properly bold on the product page and
     the finder, mobile and desktop alike. The 800 weight is added to the Inter
     import on every page that shows these headings. */
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--cg-ink);
}

.vf__filter select {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  max-width: 55%;
  padding: 0.2rem 1.3rem 0.2rem 0.4rem;
  border: 0;
  background: transparent;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%2355595c' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right center;
  background-size: 10px;
  font: inherit;
  font-size: 0.82rem;
  color: var(--cg-ink-soft);
  text-align: right;
  cursor: pointer;
  direction: rtl;                     /* keeps long option text next to the chevron */
}

.vf__filter select:focus { outline: none; color: var(--brand-2); }
.vf__filter.is-set select { color: var(--brand-2); font-weight: 600; }

/* The inline buy-box configurator on the product page reuses the finder's
   dropdown look, but its values are short ("40 mm"), so read them left-to-right
   rather than the finder's RTL (which is there to suit long option text). */
.buybox__filters { margin: 0.1rem 0 1.1rem; }
.buybox__filters select { direction: ltr; text-align: left; }
.buybox__hint { color: var(--cg-ink-soft); }

/* Validation: a size option still on "Choose…" when the customer taps "Add to
   cart". The dropdown gets a red border, its heading turns red, and a red
   message appears right below the button (.buybox__err). Cleared the moment the
   customer picks that option. */
.vf__filter--err {
  background: #fdeaea;
  border-radius: 10px;
  padding-left: 0.65rem;
  padding-right: 0.65rem;
}
.vf__filter--err > span { color: #c0261a; }
.vf__filter--err select {
  border: 1.5px solid #c0261a;
  border-radius: 8px;
  padding: 0.28rem 1.4rem 0.28rem 0.5rem;
  color: #c0261a;
  font-weight: 600;
}
.buybox__err {
  margin: 0.55rem 0 0;
  color: #c0261a;
  font-weight: 700;
  font-size: 0.86rem;
  line-height: 1.35;
}

/* The price in the product header — lifted out of the small grey meta row so it
   reads at a glance, and it turns fully brand-red the moment a size resolves. */
.pdp__meta .pdp__price {
  margin-left: auto;
  font-size: 1.4rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--brand-2);
  font-variant-numeric: tabular-nums;
}
@media (max-width: 480px) {
  .pdp__meta .pdp__price { margin-left: 0; font-size: 1.25rem; }
}

.vf__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 1.1rem;
}

.vf__count { font-size: 0.88rem; color: var(--cg-ink-soft); }
.vf__count b { color: var(--cg-ink); font-weight: 600; }
.vf__tools { display: flex; flex-wrap: wrap; gap: 0.6rem; }

/* ------------------------------ variant rows -------------------------- */
.vf__rows { border-top: 1px solid var(--cg-rule); }

.vrow {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr);
  gap: 1.25rem;
  padding: 1.35rem 0;
  border-bottom: 1px solid var(--cg-rule);
  background: var(--cg-panel);
  padding-inline: clamp(0.85rem, 2vw, 1.4rem);
}

/*
  Below 820px the row is two columns — thumbnail and detail — which leaves the
  price-and-add block as a third child with nowhere to go. Left alone the grid
  drops it into the 92px thumbnail column and the Add button comes out about a
  word wide. Span it instead so it gets the full width of the row.
*/
.vrow__buy { grid-column: 1 / -1; }

@media (min-width: 820px) {
  .vrow { grid-template-columns: 92px minmax(0, 1fr) 190px; }
  .vrow__buy { grid-column: auto; }
}

.vrow__art {
  display: grid;
  place-items: center;
  height: 78px;
}

.vrow__art img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  filter: grayscale(40%);
}

.vrow__code {
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--brand-2);
}

.vrow__code:hover { text-decoration: underline; }
.vrow__desc { margin-top: 0.3rem; font-size: 0.9rem; line-height: 1.5; color: var(--cg-ink); }

/* the little attribute table under each variant's description */
.vrow__attrs {
  width: 100%;
  margin-top: 0.9rem;
  border-collapse: collapse;
  font-size: 0.78rem;
  text-align: left;
}

.vrow__attrs th {
  padding: 0 1.5rem 0.3rem 0;
  font-weight: 400;
  color: var(--cg-ink-soft);
  white-space: nowrap;
}

.vrow__attrs td {
  padding: 0.35rem 1.5rem 0 0;
  border-top: 1px solid var(--cg-rule-soft);
  font-weight: 600;
  color: var(--cg-ink);
}

.vrow__buy {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.6rem;
}

.vrow__price { font-size: 1rem; font-weight: 600; color: var(--cg-ink); text-align: right; }

.vrow__qty {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.5rem;
  font-size: 0.78rem;
  color: var(--cg-ink-soft);
}

.vrow__qty input {
  width: 62px;
  padding: 0.5rem 0.55rem;
  border: 1px solid var(--cg-rule);
  border-radius: 0;
  font: inherit;
  font-size: 0.85rem;
  text-align: center;
  color: var(--cg-ink);
  -moz-appearance: textfield;
  appearance: textfield;
}

.vrow__qty input::-webkit-outer-spin-button,
.vrow__qty input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.vrow__qty input:focus { outline: none; border-color: var(--brand); }

.vrow__add {
  padding: 0.8rem 1rem;
  border: 1px solid var(--cg-ink);
  border-radius: 0;
  background: transparent;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--cg-ink);
  cursor: pointer;
  transition: background 200ms ease, color 200ms ease;
}

.vrow__add:hover { background: var(--cg-ink); color: #fff; }

/*
  On the narrow layout the buy block spans the whole row (see .vrow above), so
  stacking price over quantity over button leaves a button the height of a
  paragraph. Lay it out as one line instead.

  This block has to sit AFTER the .vrow__buy / .vrow__price / .vrow__add rules
  above, not up beside .vrow where it logically belongs — a media query carries
  no extra specificity, so declared first it would simply lose to them.
*/
@media (max-width: 819px) {
  .vrow__buy {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem 0.75rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--cg-rule-soft);
  }

  .vrow__price { text-align: left; }
  .vrow__qty { justify-content: flex-start; }
  .vrow__add { flex: 1 1 9rem; }
}

.vf__none {
  padding: 2.5rem 1rem;
  border-bottom: 1px solid var(--cg-rule);
  background: var(--cg-panel);
  text-align: center;
  color: var(--cg-ink-soft);
  font-size: 0.9rem;
}

.vf__more { display: flex; justify-content: center; padding-top: 1.5rem; }

/* --------------------------- specification tab ------------------------ */
.spectable {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
  text-align: left;
  background: var(--cg-panel);
}

.spectable th,
.spectable td {
  padding: 0.85rem 1.1rem;
  border-bottom: 1px solid var(--cg-rule);
  vertical-align: top;
}

.spectable th {
  width: 38%;
  min-width: 11rem;
  font-weight: 400;
  color: var(--cg-ink-soft);
}

.spectable td { font-weight: 600; color: var(--cg-ink); }

/* ------------------------------ features tab -------------------------- */
.featlist { display: grid; gap: 0; border-top: 1px solid var(--cg-rule); }

.featlist li {
  display: grid;
  grid-template-columns: 2.2rem minmax(0, 1fr);
  gap: 0.5rem;
  padding: 1.05rem 1.1rem;
  border-bottom: 1px solid var(--cg-rule);
  background: var(--cg-panel);
  font-size: 1rem;
  line-height: 1.7;
  color: var(--cg-ink);
}

.featlist li > span:first-child {
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--brand-2);
  padding-top: 0.2rem;
}


/* =========================================================================
   MOBILE RESPONSIVE PASS — category listing page   (appended 2026-09-17)
   -------------------------------------------------------------------------
   The category page (.catgrid / .catcell / .catside) is styled in THIS sheet,
   and catalog.css loads AFTER store.css on category.html, so the mobile
   overrides belong here to win the cascade (store.css handles .grid/.card).

   Apple-style clean phone layout: two compact ruled product columns, and the
   verbose breadcrumb tree folds down to one tidy wrapping row of subcategory
   chips instead of eating the whole first screen.
   ========================================================================= */
@media (max-width: 640px) {

  /* the two-column body already stacks below 900px; tighten the gap on phones */
  .catpage__body { gap: 1rem; }

  /* --- sidebar tree -> a wrapping row of subcategory chips --- */
  .catside { margin-bottom: 0.25rem; }
  .catside__tree {
    display: flex;
    flex-wrap: wrap;
    gap: 0.45rem;
    margin-bottom: 0;
  }
  /* breadcrumb levels (Products / 5M / category name) and unavailable subs
     are redundant on a phone — the page already has its title */
  .catside__tree .lv1,
  .catside__tree .lv2,
  .catside__tree .lv3,
  .catside__tree span.lv4 { display: none; }
  .catside__tree a.lv4 {
    display: inline-block;
    padding: 0.45rem 0.9rem;
    border: 1px solid var(--cg-rule);
    border-radius: 999px;
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--cg-ink-soft);
    white-space: nowrap;
  }
  .catside__tree a.lv4.is-here {
    border-color: var(--brand);
    color: var(--brand-2);
    background: var(--brand-soft);
    font-weight: 600;
  }

  /* --- results bar: count + sort on one wrapping line --- */
  .catbar { gap: 0.6rem 1rem; padding-bottom: 0.85rem; }

  /* --- two compact product columns, ruled like the desktop grid --- */
  .catgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .catcell { padding: 0.9rem 0.7rem 1rem; }
  .catcell__art { height: 108px; margin-bottom: 0.65rem; }
  /* the art box is a grid whose implicit row auto-sizes to the image, so the
     image's own max-height:100% resolves against that row, not the 108px box,
     and a portrait photo spills over the name. Cap it explicitly. */
  .catcell__art img { max-height: 108px; }
  .catcell__glyph { width: 54px; height: 54px; }
  .catcell__name {
    font-size: 0.82rem;
    line-height: 1.3;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .catcell__sku { margin-top: 0.35rem; font-size: 0.6rem; }
  .catcell__price { margin-top: 0.35rem; font-size: 0.82rem; }
}

/* very small phones: a touch tighter, still two-up */
@media (max-width: 360px) {
  .catcell { padding: 0.75rem 0.55rem 0.85rem; }
  .catcell__art { height: 96px; }
  .catcell__art img { max-height: 96px; }
  .catcell__name { font-size: 0.78rem; }
}
