/* ==========================================================================
   Buttons
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: 0.875rem 1.75rem;
  border: 2px solid transparent; border-radius: var(--radius);
  font: inherit; font-weight: 700; text-decoration: none;
  cursor: pointer; transition: var(--transition);
}
/* White text on brand teal is 2.97:1 — fails AA even at the 3:1 large-text
   floor. Navy on teal is 6.02:1. The brand teal fill itself is unchanged
   (brief-fixed); only the text colour riding on top of it changes. Hover
   uses --teal-hover, which is LIGHTER than the resting fill (7.02:1) —
   because the text is navy, lightening the background is what raises
   contrast; see --teal-hover's definition in tokens.css for why. */
/* Compound selector (.btn.btn--primary, not just .btn--primary) is
   deliberate: a plain `<a class="btn btn--primary">` is also just an `<a>`,
   so a single-class color rule here has the same specificity as the
   `.section--dark a` / `a:hover` rules in base.css and can lose to them by
   source order — which is exactly what happened during review: the button
   silently reverted to white text (2.97:1) whenever it sat in a dark
   section, or on hover. Two classes outranks those unconditionally.
   `:hover` counts as a specificity point too, though: `.section--dark
   a:hover` is (0,2,1), which still beats the non-hover `.btn.btn--primary`
   rule's (0,2,0) *while hovering* — so on a dark panel the button's text
   silently went teal-on-teal-hover (near-invisible) on hover, one more
   round of the identical bug. Restating `color: var(--navy)` on the
   `:hover` rule itself, rather than relying on it carrying over from the
   non-hover rule, closes that off for good: every state that can be
   contextually overridden now redeclares the property it depends on. */
.btn.btn--primary { background: var(--teal); color: var(--navy); }
.btn.btn--primary:hover { background: var(--teal-hover); color: var(--navy); transform: translateY(-2px); }
.btn--secondary { background: transparent; color: var(--navy); border-color: var(--navy); }
.btn--secondary:hover { background: var(--navy); color: var(--white); }
.section--dark .btn--secondary { color: var(--white); border-color: rgba(255, 255, 255, 0.6); }
/* Buttons appear on both light and dark sections. outline-offset pushes
   the ring onto the surrounding background, not the button's own fill, so
   it must match that background: teal-text on light (4.94:1+), brand teal
   on dark navy (6.02:1) — plain --teal on a light surface is 2.97:1 and
   fails even the 3:1 non-text floor. */
.btn:focus-visible { outline: 3px solid var(--teal-text); outline-offset: 3px; }
.section--dark .btn:focus-visible { outline-color: var(--teal); }

/* ==========================================================================
   Cards
   ========================================================================== */

.card {
  display: block;
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--space-4);
  color: inherit;
  text-decoration: none;
  transition: box-shadow var(--transition), transform var(--transition);
}
a.card:hover, a.card:focus-visible { box-shadow: var(--shadow-hover); transform: translateY(-4px); }
/* Same light/dark split as .btn:focus-visible above. */
.card:focus-visible { outline: 3px solid var(--teal-text); outline-offset: 3px; }
.section--dark .card:focus-visible { outline-color: var(--teal); }
.card img { display: block; width: 100%; height: auto; border-radius: calc(var(--radius) - 2px); margin-block-end: var(--space-2); }
/* `<picture>` defaults to `display: inline`, which can leave a stray
   whitespace gap under its block-level `<img>` child in some engines — see
   "Product photography" below for where `<picture>` is used. */
.card picture, .product-hero__media picture { display: block; }
/* The card's own background is always white, regardless of the section it
   sits in — so its heading must always stay navy. Without this, a card
   nested in `.section--dark` inherits that section's `h3 { color: white }`
   rule and renders invisible white text on the card's white background. */
.card h3 { margin-block-end: var(--space-1); font-size: 1.125rem; color: var(--navy); }
.card p { color: var(--charcoal); opacity: 0.85; }
/* On a dark or muted section a white card would either vanish into the
   background or double up its own shadow — trade the shadow for a hairline
   border instead, still using the palette's only neutral tint. */
.section--dark .card, .section--muted .card { box-shadow: none; border: 1px solid var(--navy-soft); }

/* ==========================================================================
   Grid
   ========================================================================== */

.grid { display: grid; gap: var(--space-4); margin-block-start: var(--space-4); }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 900px) {
  .grid--3, .grid--4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .grid--2 { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .grid--3, .grid--4 { grid-template-columns: 1fr; }
}

/* Small icon-led card variant — services teasers (no image, unaffected) and
   the sectors grid. The sectors grid used a 56px line-art SVG until
   2026-08-04; it now shows a client-supplied illustration of each sector's
   equipment WITH a hydraulic hose attached (a tractor with a hose, an
   excavator with a hose, etc.) — at 56px that hose detail, which is the
   entire point of the new artwork, is illegible. 108px keeps a >2x pixel
   ratio against the source's 240px raster (240/108 ≈ 2.22) so the hose stays
   crisp on retina, while comfortably fitting every grid breakpoint below
   (verified at 375px: card--icon cards go full-width under 560px, so 108px
   never risks overflow). */
.card--icon { text-align: center; }
.card--icon img { inline-size: 108px; block-size: 108px; margin-inline: auto; margin-block-end: var(--space-2); }
.card--icon h3 { font-size: 1rem; margin-block-end: 0; }

/* ==========================================================================
   Product photography — replaces line-art SVG for 6 of the 8 groups
   (client revision, 2026-08-04). Shared by the homepage/products.html/
   related-groups cards (`.card picture` above) and the product-page hero
   below.
   ========================================================================== */

.product-hero {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--space-4); margin-block-start: var(--space-4);
}
.product-hero__text { flex: 1 1 320px; }
.product-hero__media { flex: 1 1 280px; max-width: 26rem; margin-inline: auto; }
.product-hero__media img {
  display: block; width: 100%; height: auto;
  border-radius: var(--radius); box-shadow: var(--shadow);
}
/* Below ~600px the two-column layout has no room to sit side by side —
   stack the photo under the text instead of letting it squeeze to an
   unreadable sliver. */
@media (max-width: 600px) { .product-hero__media { max-width: 100%; } }

/* ==========================================================================
   Homepage product cards — name-only with a details/summary disclosure
   (client revision, 2026-08-04). The `<a>` (image + name) and the
   `<details>` (toggle + description) are SIBLINGS, not nested — an `<a>`
   must not contain interactive-content descendants like `<details>`/
   `<summary>` (invalid HTML, and browsers react to it by breaking the link),
   so keeping navigation and disclosure as two separate elements is not a
   style choice, it's what makes both work at all. Clicking the photo or the
   name always navigates; clicking the toggle only ever opens/closes the
   description — the two click targets never overlap, so neither can hijack
   the other. products.html and the product-page "related groups" cards
   intentionally do NOT use this component — they keep the description
   always visible, unchanged.
   ========================================================================== */

.card--product { padding: 0; overflow: hidden; }
.card--product .card--product__link {
  display: block; padding: var(--space-4) var(--space-4) var(--space-2);
  color: inherit; text-decoration: none;
}
.card--product__link picture,
.card--product__link img { margin-block-end: var(--space-2); }
.card--product__link h3 { margin-block-end: 0; }
.card--product__details { border-block-start: 1px solid var(--navy-soft); }
.card--product__summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  font-weight: 700; font-size: 0.875rem; color: var(--teal-text);
}
.card--product__summary::-webkit-details-marker { display: none; }
.card--product__summary::after {
  content: '+'; flex-shrink: 0; font-weight: 400; color: var(--teal-text);
  transition: transform var(--transition);
}
.card--product__details[open] .card--product__summary::after { transform: rotate(45deg); }
.card--product__summary:focus-visible { outline: 3px solid var(--teal-text); outline-offset: -3px; }
.card--product__desc { padding: 0 var(--space-4) var(--space-4); color: var(--charcoal); opacity: 0.85; }

/* Centered single-CTA row under a grid (e.g. "View All Sectors"). */
.section__cta { text-align: center; margin-block-start: var(--space-4); }

/* ==========================================================================
   Hero
   ========================================================================== */

/* Layout only — `.hero` is combined with `.section` and `.section--dark` in
   the markup, so background/text colour and h1/lead colour already come from
   those (see base.css); this block only adds the centred, capped-width hero
   layout on top. */
.hero { text-align: center; }
.hero__title { max-width: 46rem; margin-inline: auto; }
.hero__body { max-width: 40rem; margin-inline: auto; margin-block-start: var(--space-3); }
.hero__actions {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--space-3); margin-block-start: var(--space-4);
}

/* ==========================================================================
   Trust indicators — stat cards (v3, 2026-08-06 — horizontal layout, richer
   colour, motion; full rationale in the report at
   .superpowers/sdd/2026-08-03-elsalam-hydraulic-site/stat-cards-v3-report.md)
   ========================================================================== */

/* Alternating navy/teal fills (v1/v2 were five identical flat-teal blocks)
   plus a border-inline-start accent rule in the opposing colour. Every
   text/background pair here is a WCAG relative-luminance calculation, not
   an eyeball guess — contrast ratio is symmetric, so a pair's ratio is the
   same regardless of which colour is foreground vs background:
     - navy #001440 on teal #00A98F  → 6.02:1 (same pairing `.btn--primary`
       already uses; clears AA for normal AND large text)
     - teal #00A98F on navy #001440  → 6.02:1 (same two colours, reversed)
     - white #FFFFFF on navy #001440 → 17.89:1 (AA + AAA)
   White-on-teal (2.97:1) is never used anywhere in this component — it
   fails even the 3:1 large-text floor (see tokens.css for the full
   derivation). Both fills here are dark/mid-tone, never white/--grey-light,
   so that constraint doesn't come up. */
.stat-grid {
  display: grid; grid-template-columns: repeat(5, 1fr);
  gap: var(--space-3); margin-block-start: var(--space-4);
}

/* Horizontal strip — the explicit 2026-08-06 client ask: figure/icon and
   label share one line instead of stacking (v1/v2 stacked them, which made
   tall cards and a long mobile scroll). `border-inline-start`, not `-left`
   — the accent rule lands on the correct edge automatically in both RTL
   (right) and LTR (left), no per-language override needed. Applies at
   every width; see the single breakpoint below for the column count. */
.stat-card {
  display: flex; align-items: center; gap: var(--space-2);
  border-radius: var(--radius);
  padding: var(--space-2) var(--space-3);
  border-inline-start: 4px solid transparent;
}
.stat-card--navy { background: var(--navy); color: var(--white); border-inline-start-color: var(--teal); }
.stat-card--navy .stat-card__figure,
.stat-card--navy .stat-card__icon { color: var(--teal); }
.stat-card--teal { background: var(--teal); color: var(--navy); border-inline-start-color: var(--navy); }
.stat-card--teal .stat-card__figure,
.stat-card--teal .stat-card__icon { color: var(--navy); }

.stat-card__figure { font-size: 1.75rem; font-weight: 700; line-height: 1.1; white-space: nowrap; }
.stat-card__figure--text { font-size: 1rem; font-weight: 700; line-height: 1.3; white-space: normal; }
.stat-card__label { font-size: 0.8125rem; font-weight: 600; line-height: 1.35; }

/* Reserves the figure's box at its FINAL rendered width so the count-up
   (main.js, animateCount) never resizes this flex item while it ticks —
   if it did, the label sitting next to it in the row would shift
   sideways on every animation frame. The Layout Instability API counts
   that as a real layout shift (CLS) even though it happens after scroll,
   not on load — this page's CLS is ~0.001 and is a hard requirement to
   keep. 4.4ch (with tabular/fixed-width digits) comfortably covers both
   counters on this page ("1997" and "+38") so neither the reserved box
   nor the digits inside it move. */
.stat-card__figure[data-count-to] {
  display: inline-block; min-width: 4.4ch; text-align: center;
  font-variant-numeric: tabular-nums;
}

.stat-card__icon { flex-shrink: 0; }
.stat-card__icon svg { display: block; inline-size: 1.625rem; block-size: 1.625rem; }

/* Single breakpoint, not the old two-tier 900px/560px fallback: with a
   horizontal card, there is no longer a tall/cramped shape to fix at small
   widths, so this only ever needs two states — one row of 5 (desktop) or
   one full-width column of 5 (everything narrower). A 2- or 3-column
   fallback is deliberately avoided: 5 cards don't divide evenly into either,
   which is exactly the orphaned-card bug fixed on 2026-08-06 (see
   .superpowers/sdd/2026-08-03-elsalam-hydraulic-site/maps-and-stat-cards-report.md)
   — going back to a 3-column mid-tier would reintroduce it. */
@media (max-width: 900px) {
  .stat-grid { grid-template-columns: 1fr; gap: var(--space-2); }
}

/* Staggered scroll-reveal: `.reveal` itself (opacity/transform toggle +
   prefers-reduced-motion override) is defined once, in the "Scroll reveal"
   section below — this only staggers ITS transition-delay per card so the
   five settle in sequence instead of all at once. main.js hardcodes the
   same five delay values (STAT_STAGGER_STEP_MS) so the count-up start time
   for cards 1–2 lines up with each card's own fade-in instead of ticking
   while still invisible. Kept quick (320ms total spread) and a plain
   ease — calm, not bouncy, per the brief's "industrial, not consumer" note.
   Under reduced motion `.reveal`'s start state already equals its end
   state (see below), so a transition-delay before a no-op transition has
   nothing to visibly wait for — no extra override needed here. */
.stat-grid .stat-card:nth-child(1) { transition-delay: 0ms; }
.stat-grid .stat-card:nth-child(2) { transition-delay: 80ms; }
.stat-grid .stat-card:nth-child(3) { transition-delay: 160ms; }
.stat-grid .stat-card:nth-child(4) { transition-delay: 240ms; }
.stat-grid .stat-card:nth-child(5) { transition-delay: 320ms; }

/* ==========================================================================
   Trust bar
   ========================================================================== */

.trust-bar { background: var(--grey-light); padding-block: var(--space-4); }
/* .stat-grid/.stat-card (above, "Trust indicators — stat cards") is the
   current markup — v3 as of 2026-08-06. */

/* ==========================================================================
   Branch cards — map embed, address/hours, directions CTA
   ========================================================================== */

.branch-card {
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.branch-card__map {
  display: block; inline-size: 100%; aspect-ratio: 16 / 9; border: 0;
}
.branch-card__body { padding: var(--space-4); }
.branch-card__title { margin-block-end: var(--space-2); }
.branch-card__meta { color: var(--charcoal); opacity: 0.85; margin-block-end: var(--space-1); }
.branch-card__meta strong { color: var(--navy); opacity: 1; }
/* .button-row is the shared layout: a wrapping flex row of .btn elements.
   Used both for the branch card's directions/call/WhatsApp trio (contact.html
   — the homepage's own branch cards only ever carry the single Directions
   button, so this rule was never needed there) and for the contact-details /
   social-links button rows further down contact.html. */
.branch-card__actions, .button-row { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-block-start: var(--space-3); }

/* ==========================================================================
   Top bar — phone / WhatsApp, short hours, language toggle
   ========================================================================== */

.topbar {
  background: var(--navy);
  color: rgba(255, 255, 255, 0.86);
  font-size: 0.8125rem;
}
.topbar__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-1) var(--space-3);
  padding-block: var(--space-1);
}
.topbar__contact { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.topbar__contact a {
  display: inline-flex; align-items: center; gap: 0.375rem;
  color: inherit; text-decoration: none; transition: var(--transition);
}
.topbar__contact a:hover { color: var(--teal); }
.topbar__contact a:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; border-radius: 2px; }
.topbar__hours { opacity: 0.85; }

/* Hook for the language switch wired in a later task — `.lang-toggle` is the
   visual treatment, `[data-lang-toggle]` is the behavioural hook, so styling
   holds regardless of which element carries the attribute. */
.lang-toggle, [data-lang-toggle] {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.4);
  color: inherit;
  border-radius: var(--radius);
  padding: 0.25rem 0.75rem;
  font: inherit; font-weight: 700;
  cursor: pointer;
  transition: var(--transition);
}
.lang-toggle:hover, [data-lang-toggle]:hover { border-color: var(--teal); color: var(--teal); }
.lang-toggle:focus-visible, [data-lang-toggle]:focus-visible { outline: 3px solid var(--teal); outline-offset: 2px; }

@media (max-width: 640px) {
  .topbar__hours { display: none; }
}

/* ==========================================================================
   Chrome-mount CLS reservation
   ========================================================================== */

/* components.js mounts the topbar/nav/footer into these `[data-mount]`
   placeholders at runtime (see components.js's doc-comment) — the initial
   HTML has no content in them. Without a reserved size the placeholder
   paints at zero height and everything below it jumps down once the mount
   finishes, which is exactly the layout shift the Lighthouse mobile
   Performance regression (2026-08-03 acceptance pass, criterion 5) traced
   to this refactor. `replaceWith()` swaps the placeholder for a brand-new
   element without the `data-mount` attribute, so these rules stop applying
   the instant the real chrome lands — they only hold space before mount,
   never after.
   Values were measured with Playwright against the real rendered chrome
   (identical across all 16 pages, since the chrome markup is shared) at
   the same widths this repo's own tests/gates use: 375-480px (mobile —
   Lighthouse's 412px mobile emulation and Playwright's 390px iPhone 13
   profile both land here) and >=1024px (desktop — Playwright's 1280px
   Desktop Chrome profile). The topbar's height does not change with
   width, so it needs no media query. */
[data-mount="topbar"] { min-height: 48px; }

/* ==========================================================================
   Main nav — logo, page links, contact CTA
   ========================================================================== */

.nav {
  background: var(--white);
  border-block-end: 1px solid var(--navy-soft);
  position: sticky;
  inset-block-start: 0;
  z-index: 40;
}
.nav__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  padding-block: var(--space-2);
}
.nav__logo { display: inline-flex; }
.nav__logo img { display: block; height: 40px; width: auto; }
.nav__list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-4);
  margin-inline-start: auto;
}
.nav__link {
  display: inline-block;
  color: var(--charcoal);
  text-decoration: none;
  font-weight: 500;
  padding-block: var(--space-1);
  border-block-end: 2px solid transparent;
  transition: var(--transition);
}
.nav__link:hover, .nav__link[aria-current="page"] { color: var(--navy); border-block-end-color: var(--teal); }
.nav__cta { flex-shrink: 0; }
/* .nav is always a white surface (see above) — --teal-text is the correct
   ring colour unconditionally here, no dark-context variant needed. */
.nav__link:focus-visible { outline: 3px solid var(--teal-text); outline-offset: 2px; }
/* The "Contact Us" nav-list item (components.js buildNav's .nav__item--contact)
   duplicates the .nav__cta button's text wherever both are visible on
   screen at once — client-reported "تواصل معنا" appearing twice in the
   header (2026-08-06). Hidden here by default; unhidden only in the
   max-width:640px band below, where .nav__cta itself is hidden and this
   item becomes the page's only header contact link. */
.nav__item--contact { display: none; }

/* Measured with the real six Global nav labels (docs/copy-deck.md) at
   375×667: the unpatched .nav rendered 262.6px tall and stayed
   `position: sticky`, permanently consuming 39% of the viewport during
   scroll. Two changes: drop sticky below 640px (a sticky header is a
   nice-to-have; one eating 39% of a phone screen is a defect), and tighten
   the wrapped list itself — smaller gap, smaller link padding, a smaller
   logo — so the unavoidable multi-line wrap of a six-item Arabic nav costs
   much less height. See the Task 5 report for the before/after numbers. A
   real collapsing hamburger menu is left to Task 9/8, which have the JS.
*/
@media (max-width: 640px) {
  .nav { position: static; }
  .nav__inner { justify-content: center; padding-block: var(--space-1); gap: var(--space-1) var(--space-2); }
  .nav__logo img { height: 30px; }
  .nav__list { margin-inline-start: 0; justify-content: center; gap: 0 var(--space-2); font-size: 0.875rem; }
  .nav__link { padding-block: 0.25rem; }
  /* "Contact Us" is already one of the six nav links at this width — the
     separate CTA button is redundant and costs real height on a phone. */
  .nav__cta { display: none; }
  /* ...and since the CTA is gone, the nav-list item is what shows it. */
  .nav__item--contact { display: list-item; }
}

/* See "Chrome-mount CLS reservation" above the topbar rules for why this
   exists.
   MEASURED 2026-08-03 (review-fixes pass): the previous two-band version of
   this rule (92px desktop / 123px mobile) was only correct at the two exact
   widths it was eyeballed against (412px and 1280px) — a Playwright sweep of
   the real rendered `.nav` across 320-1280px found actual heights ranging
   50-263px, with the worst mismatches at 641px (+171px) and 768px (+117px),
   both *inside* the old "desktop" band. `.nav__inner` is a flex-wrap list
   that reflows continuously as width changes; it does not have just two
   states. The six bands below were binary-searched against the real
   rendered chrome (identical markup on every page) to match its actual wrap
   points, in Arabic — the default, pre-toggle language, and the one
   Lighthouse's own CLS audit actually measures with no stored preference.
   English wraps at slightly different widths (longer words), and in two
   specific bands (roughly 826-1001px, and exactly at 1024px) repeated
   measurement at the SAME width produced DIFFERENT results from run to run
   — a genuine sub-pixel flex-wrap/font-metric race in the browser itself,
   not something a static min-height can pin down further. Sizing to the
   Arabic value means an English visitor with a stored `en` preference may
   still see a residual shift specifically in those bands; there is no
   static-CSS fix for a layout the browser itself renders non-deterministically
   at a given width. See the review-fixes report for the full before/after
   measurement table. */
[data-mount="nav"] { min-height: 93px; }                                  /* >=1002px */
@media (max-width: 1001px) { [data-mount="nav"] { min-height: 154px; } }  /* 826-1001px */
@media (max-width: 825px)  { [data-mount="nav"] { min-height: 210px; } }  /* 659-825px */
@media (max-width: 658px)  { [data-mount="nav"] { min-height: 264px; } }  /* 641-658px */
@media (max-width: 640px)  { [data-mount="nav"] { min-height: 90px;  } }  /* 522-640px */
@media (max-width: 521px)  { [data-mount="nav"] { min-height: 123px; } }  /* <=521px */

/* ==========================================================================
   Footer
   ========================================================================== */

.footer {
  background: var(--navy);
  color: rgba(255, 255, 255, 0.7);
  padding-block: var(--space-8) var(--space-4);
}
.footer__logo img { display: block; height: 44px; width: auto; margin-block-end: var(--space-2); }
.footer__grid {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: repeat(4, 1fr);
}
.footer__heading { color: var(--white); font-size: 1rem; margin-block-end: var(--space-2); }
.footer__col ul { list-style: none; }
.footer__col li + li { margin-block-start: var(--space-1); }
/* overflow-wrap: anywhere — the footer email address has no natural break
   point, and base.css's `body { overflow-x: hidden }` means an unbroken
   string that doesn't fit the column doesn't just look bad, it gets
   silently clipped with no way for a visitor to reach the rest of it
   (measured: 4px of the address clipped at 320px in English). Verified
   2026-08-03. */
.footer__col a { color: inherit; text-decoration: none; transition: var(--transition); overflow-wrap: anywhere; }
.footer__col a:hover { color: var(--teal); }
.footer__col a:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; border-radius: 2px; }
.footer__bottom {
  margin-block-start: var(--space-6);
  padding-block-start: var(--space-3);
  border-block-start: 1px solid rgba(255, 255, 255, 0.15);
  font-size: 0.8125rem;
  text-align: center;
}

@media (max-width: 860px) {
  .footer__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
  .footer__grid { grid-template-columns: 1fr; }
}

/* See "Chrome-mount CLS reservation" above the topbar rules.
   MEASURED 2026-08-03 (review-fixes pass): the previous three-band version
   of this rule was 35px short at every width tested — including 390px and
   1280px, the two widths its own numbers claimed to be measured against. A
   Playwright sweep of the real rendered `.footer` found its height is
   driven by two things, not one: the column count (`.footer__grid`'s own
   4/2/1 breakpoints at 860px/480px) AND, specifically inside the
   single-column band below 480px, how many lines the nav-links/contact
   columns wrap onto, which keeps changing as the width narrows further.
   The seven bands below match the real column-count and wrap-count
   transitions, measured in Arabic (see the equivalent note on the nav rule
   above for why: it is the default, pre-toggle, Lighthouse-audited
   language). English's transition points are close but not identical, and
   in two bands (roughly 341-420px and 861-890px) repeated measurement at
   the same width produced different results run to run — the same
   sub-pixel flex/font-metric non-determinism documented on the nav rule,
   not a gap in these numbers. See the review-fixes report for the full
   before/after table. */
[data-mount="footer"] { min-height: 467px; }                                 /* >=891px */
@media (max-width: 890px) { [data-mount="footer"] { min-height: 494px; } }   /* 861-890px */
@media (max-width: 860px) { [data-mount="footer"] { min-height: 614px; } }   /* 521-860px */
@media (max-width: 520px) { [data-mount="footer"] { min-height: 642px; } }   /* 481-520px */
@media (max-width: 480px) { [data-mount="footer"] { min-height: 897px; } }   /* 421-480px */
@media (max-width: 420px) { [data-mount="footer"] { min-height: 919px; } }   /* 341-420px */
@media (max-width: 340px) { [data-mount="footer"] { min-height: 946px; } }   /* <=340px */

/* ==========================================================================
   Enquiry modal
   ========================================================================== */

/* `[hidden]` alone would be enough under the UA stylesheet, but author
   styles always outrank the UA stylesheet regardless of specificity — so
   `.modal { display: grid; }` below would win and keep the dialog visible
   even while the `hidden` attribute is set. This rule (class + attribute,
   two selectors) is what keeps it actually hidden. */
.modal[hidden] { display: none; }
.modal {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center;
  background: rgba(0, 20, 64, 0.6);
  padding: var(--space-3);
}
.modal__panel {
  position: relative;
  background: var(--white); border-radius: var(--radius);
  padding: var(--space-4); width: min(28rem, 100%);
  box-shadow: var(--shadow-hover);
}
.modal__product { color: var(--teal-text); font-weight: 700; margin-block: var(--space-1) var(--space-3); }
.modal__field { display: block; margin-block-end: var(--space-3); }
.modal__field span { display: block; margin-block-end: 0.375rem; font-weight: 600; font-size: 0.875rem; color: var(--charcoal); }
.modal__field input, .modal__field select {
  inline-size: 100%; padding: 0.75rem; font: inherit;
  border: 1px solid var(--navy-soft); border-radius: var(--radius);
  background: var(--white); color: var(--charcoal);
}
.modal__field input:focus-visible, .modal__field select:focus-visible {
  outline: 3px solid var(--teal-text); outline-offset: 2px;
}
/* No dedicated error/danger colour exists in the five-value palette — the
   message text itself carries the meaning (WCAG requires that anyway, never
   colour alone), so this stays inside the palette rather than inventing a
   sixth token. */
[data-inquiry-error] { color: var(--navy); font-weight: 700; font-size: 0.875rem; margin-block-end: var(--space-3); }
[data-inquiry-error][hidden] { display: none; }

/* ==========================================================================
   Sticky contact buttons
   ========================================================================== */

.float-stack {
  position: fixed; inset-block-end: var(--space-3); inset-inline-end: var(--space-3);
  z-index: 90; display: flex; flex-direction: column; gap: var(--space-2);
}
/* Both fills (WhatsApp green, brand teal) are light enough that white text
   fails AA — navy is the only one of the five palette colours that clears
   4.5:1 on either. See docs: navy-on-teal 6.02:1, navy-on-#25D366 ~9.0:1. */
.float-btn {
  inline-size: 3.5rem; block-size: 3.5rem; border-radius: 50%;
  display: grid; place-items: center; color: var(--navy);
  box-shadow: var(--shadow-hover); transition: var(--transition);
}
.float-btn svg { inline-size: 1.75rem; block-size: 1.75rem; }
/* WhatsApp's own brand mark — the official white-glyph-on-green lockup, so it
   is instantly recognisable. Not one of the site's five palette values, but it
   is WhatsApp's brand colour rather than a site UI colour, so it is outside the
   five-value rule.

   The green is #1DA751, WhatsApp's #25D366 darkened ~21%. The authentic white
   glyph on the exact brand green is only 1.98:1 — well under the 3:1 floor
   WCAG 1.4.11 sets for meaningful non-text content. Darkening the green to
   #1DA751 gives 3.14:1 with the white glyph, keeping the mark recognisable
   AND legible. Do not "restore" #25D366 with a white glyph: it looks right
   and fails the contrast gate. */
.float-btn--whatsapp { background: #1DA751; color: #FFFFFF; }
.float-btn--call { background: var(--teal); }
.float-btn:hover { transform: scale(1.08); }
.float-btn:focus-visible { outline: 3px solid var(--teal-text); outline-offset: 3px; }
/* Calling is a phone capability — hide the call button on desktop. */
@media (min-width: 768px) { .float-btn--call { display: none; } }

/* ==========================================================================
   Breadcrumb — product-group and (later) product-detail pages
   ========================================================================== */

.breadcrumb__list {
  list-style: none;
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 0.375rem;
  font-size: 0.875rem;
  padding: 0;
}
.breadcrumb__list a { color: var(--charcoal); text-decoration: none; }
.breadcrumb__list a:hover { color: var(--teal-text); text-decoration: underline; }
.breadcrumb__list li[aria-current="page"] { color: var(--navy); font-weight: 700; }
.breadcrumb__sep { opacity: 0.5; }

/* ==========================================================================
   Product type list — group-page type codes (e.g. R1/1SN, R2/2SN…)
   ========================================================================== */

.type-list {
  list-style: none;
  display: flex; flex-wrap: wrap; gap: var(--space-2);
  margin-block-start: var(--space-4);
  padding: 0;
}
.type-list__item {
  background: var(--white);
  border: 1px solid var(--navy-soft); border-radius: var(--radius);
  padding: 0.625rem 1.25rem;
  font-weight: 700; color: var(--navy);
}

/* ==========================================================================
   FAQ — faq.html, native <details>/<summary> (no JS needed for open/close)
   ========================================================================== */

.faq-list { display: flex; flex-direction: column; gap: var(--space-2); margin-block-start: var(--space-4); }
.faq-item {
  background: var(--white);
  border: 1px solid var(--navy-soft); border-radius: var(--radius);
  padding: var(--space-2) var(--space-3);
}
.faq-item__question {
  cursor: pointer;
  font-weight: 700; color: var(--navy);
  list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
}
.faq-item__question::-webkit-details-marker { display: none; }
.faq-item__question::after {
  content: '+';
  flex-shrink: 0;
  font-weight: 400; color: var(--teal-text);
  transition: transform var(--transition);
}
.faq-item[open] .faq-item__question::after { transform: rotate(45deg); }
.faq-item__question:focus-visible { outline: 3px solid var(--teal-text); outline-offset: 3px; }
.faq-item__answer { color: var(--charcoal); opacity: 0.9; margin-block-start: var(--space-2); }

/* ==========================================================================
   Scroll reveal
   ========================================================================== */

.reveal { opacity: 0; transform: translateY(16px); transition: opacity 0.5s ease, transform 0.5s ease; }
.reveal.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; transform: none; } }
