/* ==========================================================================
   Kinetix EV Charging — Global stylesheet
   Design tokens → base → layout → components → pages → responsive
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Design tokens
   -------------------------------------------------------------------------- */
:root {
  /* ---- Dark "energy tech" surfaces -------------------------------------- */
  --navy-950: #04080e;   /* page-dark, deepest */
  --navy-900: #071019;
  --navy-850: #0a1622;
  --navy-800: #0e1c2a;
  --navy-700: #16283a;

  /* ---- Accents ---------------------------------------------------------- */
  /* Electric green is the primary action colour — used for CTAs, numerals and
     the glow on hover. Cyan is the secondary technical accent. */
  --green-700: #00b463;
  --green-600: #00c96e;
  --green-500: #00e27a;
  --green-400: #4dffa4;
  --green-glow: 0 0 0 1px rgba(0, 226, 122, .35), 0 8px 30px -6px rgba(0, 226, 122, .45);

  /* The accent has two jobs and they need different greens.
     `--accent` is the green used as TEXT or a hairline sitting on the page
     background. On the dark theme the brightest green is legible and on-brand;
     on white it drops to about 1.4:1 and vanishes, so the light theme swaps in
     a much deeper one. `--accent-hover` is its pressed/hover partner.
     Fills are deliberately NOT part of this: a button painted --green-500 keeps
     its dark label and stays legible on either background, so the fill greens
     are identical in both themes. */
  --accent:       var(--green-400);
  --accent-hover: var(--green-500);

  /* The same accent as it must appear on a permanently-dark surface — the
     header, hero, page-head, navy bands and footer all stay dark in both
     themes, so their green must stay bright in both. Anything painting inside
     one of those bands reads these instead of --accent. */
  --d-accent:       #4dffa4;
  --d-accent-hover: #00e27a;

  /* The pale pill behind .eyebrow: a green wash and its edge. */
  --accent-tint:      rgba(0, 226, 122, .1);
  --accent-tint-line: rgba(0, 226, 122, .3);

  --cyan-500: #38d9ff;

  /* Kept for the ::selection highlight, which is the one place a light green
     fill still reads better than a translucent one. */
  --green-100: #d6fbe7;

  /* ---- Neutrals (base surfaces) ----------------------------------------- */
  /* The site is one dark theme. These base tokens are what nearly every
     component reads, so the page inverts here rather than rule by rule.
     `--ink` is the strongest text, `--muted` the weakest. */
  --ink:      rgba(255, 255, 255, .96);
  --body:     rgba(255, 255, 255, .70);
  --muted:    rgba(255, 255, 255, .52);
  --line:     rgba(255, 255, 255, .12);
  --line-soft:rgba(255, 255, 255, .075);
  --bg:       #04080e;
  --bg-soft:  #0a1622;   /* lifted band — one step up from the page */
  --bg-mute:  #0e1c2a;   /* media wells and zebra rows */
  --tint:     rgba(255, 255, 255, .035);  /* card fill over either band */
  /* Form inputs need an opaque fill, because Chrome's autofill repaint below
     can only be done with a solid colour. */
  --field:          rgba(255, 255, 255, .05);
  --field-autofill: #16283a;
  /* The opaque twin of --field, for <select> only. A native dropdown popup
     paints itself from the control's own background-color: hand it a
     translucent one and it composites over the popup's white plate, so the
     option text (--ink, near-white here) lands on white. This is that same
     5% white already flattened over the form card and the page behind it —
     5% over --tint over --bg — so the closed control looks unchanged. The value
     is sampled from the rendered page, not computed: each composite step rounds
     to 8 bits, which puts it a level below the arithmetic result. */
  --field-solid:    #181c21;

  /* Text that must stay dark because it sits on a bright green fill. */
  --on-green: #052a17;
  /* Errors need a soft red here; the light-theme pair is illegible on dark. */
  --danger:      #ff8f8f;
  --danger-fill: rgba(255, 86, 86, .12);
  --danger-line: rgba(255, 86, 86, .38);

  /* ---- Neutrals (dark sections) ----------------------------------------- */
  --d-text:   rgba(255, 255, 255, .74);
  --d-text-hi:rgba(255, 255, 255, .96);
  --d-muted:  rgba(255, 255, 255, .52);
  --d-line:   rgba(255, 255, 255, .11);
  --d-line-soft: rgba(255, 255, 255, .07);
  --d-card:   rgba(255, 255, 255, .035);
  --d-fill:   rgba(255, 255, 255, .05);   /* chips, ghost buttons, icon buttons */
  --d-fill-hi:rgba(255, 255, 255, .12);   /* the same, hovered */
  --d-line-strong: rgba(255, 255, 255, .32);

  /* The hero puts a photo behind its copy, so it needs a veil rather than a
     background colour - one the light theme can invert. */
  --hero-veil: linear-gradient(100deg, rgba(4, 8, 14, .97) 0%, rgba(4, 8, 14, .9) 34%,
                                      rgba(4, 8, 14, .62) 62%, rgba(4, 8, 14, .34) 100%);
  --hero-grid: rgba(255, 255, 255, .045);
  --band-shadow: 0 26px 60px -24px rgba(0, 0, 0, .85);
  --stuck-shadow: 0 14px 34px -16px rgba(0, 0, 0, .9);

  /* ---- Typography ------------------------------------------------------- */
  --font: Inter, "Inter var", -apple-system, BlinkMacSystemFont, "Segoe UI",
          Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB",
          "Microsoft YaHei",
          /* Arabic, deliberately listed after the Latin and CJK families: any
             of those would otherwise claim the Latin glyphs as well. Windows
             and macOS already cover Arabic through Segoe UI / -apple-system;
             these are here so Linux and Android do not fall through to tofu,
             Roboto carrying no Arabic glyphs. Nothing is downloaded - the site
             stays dependency-free. */
          "Noto Sans Arabic", "Noto Naskh Arabic", Tahoma, "Geeza Pro",
          sans-serif;
  --font-mono: "SFMono-Regular", ui-monospace, "JetBrains Mono", Consolas,
               "Liberation Mono", Menlo, monospace;

  /* Radius */
  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 14px;
  --r-xl: 20px;
  --r-pill: 999px;

  /* Elevation */
  --sh-sm: 0 1px 3px rgba(0, 0, 0, .5);
  --sh-md: 0 6px 16px rgba(0, 0, 0, .45);
  --sh-lg: 0 24px 52px -20px rgba(0, 0, 0, .78), 0 6px 16px rgba(0, 0, 0, .35);

  /* Layout */
  --container: 1220px;
  --gutter: 24px;
  --header-h: 72px;

  --ease: cubic-bezier(.22, .61, .36, 1);
}

/* ---- Light ("day") theme -------------------------------------------------
   Two token families have to move, not one, because the bands that paint their
   own backgrounds cover most of the page:

     · the --navy-* ramp, which is what the header, hero, page-head, the
       .section--navy bands, the stats strip and the footer fill with; and
     · the --d-* family, which is what everything inside those bands reads for
       its text, rules and fills.

   Re-pointing both here turns the whole page light without a single component
   rule having to know that themes exist. The exceptions are the few surfaces
   that are dark on purpose in both themes - a photo scrim, a QR code - and
   those are pinned to literal colours at their own rules instead.

   Contrast on the light page: text 8.0:1, muted 4.8:1, accent links 5.2:1 —
   all at or above WCAG AA for body copy. */
html[data-theme="light"] {
  color-scheme: light;

  --ink:      #0a1a26;
  --body:     #3b4f60;
  --muted:    #556a7b;
  --line:     rgba(10, 32, 48, .14);
  --line-soft:rgba(10, 32, 48, .08);
  --bg:       #f6f9fb;
  --bg-soft:  #eef3f8;   /* lifted band */
  --bg-mute:  #e5edf3;   /* media wells and zebra rows */
  --tint:     rgba(10, 32, 48, .03);
  --field:          #ffffff;
  --field-autofill: #ffffff;
  --field-solid:    #ffffff;   /* already opaque here; see the dark block */

  /* #4dffa4 on white is about 1.4:1 — a bright green only works on a dark
     surface, so the text accent drops to a deep one here. */
  --accent:       #067a45;
  --accent-hover: #045c33;
  --accent-tint:      rgba(6, 122, 69, .09);
  --accent-tint-line: rgba(6, 122, 69, .26);

  /* --on-green is unchanged: the buttons are still bright green, so their
     label is still near-black. */
  --danger:      #c0392f;
  --danger-fill: rgba(192, 57, 47, .07);
  --danger-line: rgba(192, 57, 47, .32);

  /* Shadows read as grey haze on white rather than depth, so they go shorter,
     tighter and cooler. The black-tuned dark versions look like smudges. */
  --sh-sm: 0 1px 2px rgba(10, 32, 48, .07);
  --sh-md: 0 6px 16px rgba(10, 32, 48, .09);
  --sh-lg: 0 20px 44px -18px rgba(10, 32, 48, .22), 0 4px 12px rgba(10, 32, 48, .07);
  --green-glow: 0 0 0 1px rgba(6, 122, 69, .3), 0 8px 24px -8px rgba(6, 122, 69, .38);

  /* The band backgrounds, walked down the same ramp the dark theme uses so the
     page keeps its sense of stacked sheets rather than going uniformly white. */
  --navy-950: #ffffff;   /* header, footer, hero base */
  --navy-900: #f1f6fa;   /* .section--navy, .stats-band, mobile nav */
  --navy-850: #edf3f8;
  --navy-800: #e8eff6;   /* media wells */
  --navy-700: #e9f1f7;   /* matrix table head */

  --d-text:        var(--body);
  --d-text-hi:     var(--ink);
  --d-muted:       var(--muted);
  --d-line:        var(--line);
  --d-line-soft:   var(--line-soft);
  --d-line-strong: rgba(10, 32, 48, .30);
  --d-fill:        rgba(10, 32, 48, .04);
  --d-fill-hi:     rgba(10, 32, 48, .09);
  --d-card:        var(--tint);
  --d-accent:      var(--accent);
  --d-accent-hover:var(--accent-hover);

  --hero-veil: linear-gradient(100deg, rgba(246, 249, 251, .97) 0%, rgba(246, 249, 251, .93) 34%,
                                      rgba(246, 249, 251, .72) 62%, rgba(246, 249, 251, .42) 100%);
  --hero-grid: rgba(10, 32, 48, .05);
  --band-shadow: var(--sh-lg);
  --stuck-shadow: var(--sh-sm);
}

/* The select's chevron is a background-image data-URI, so it cannot read a
   token: it carries its stroke colour inline. On the light theme the pale
   grey would sit on white at about 1.6:1 and vanish, so it needs its own
   copy with a dark stroke. */
html[data-theme="light"] .field select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235c7183' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; color-scheme: dark; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.65;
  color: var(--body);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4, h5 {
  margin: 0 0 .5em;
  color: var(--ink);
  font-weight: 700;
  line-height: 1.22;
  letter-spacing: -.018em;
}
h1 { font-size: clamp(2rem, 4.2vw, 3.25rem); }
h2 { font-size: clamp(1.55rem, 2.9vw, 2.3rem); }
h3 { font-size: clamp(1.15rem, 1.7vw, 1.4rem); }
h4 { font-size: 1.06rem; }

p { margin: 0 0 1rem; }
p:last-child { margin-bottom: 0; }

a { color: var(--accent); text-decoration: none; transition: color .18s var(--ease); }
a:hover { color: var(--accent-hover); }

img { max-width: 100%; height: auto; display: block; }

ul, ol { margin: 0 0 1rem; padding-inline-start: 1.15rem; }
li { margin-bottom: .4rem; }

/* The `hidden` attribute is how the product filter hides a non-matching card,
   and it works by inheriting the UA sheet's `[hidden] { display: none }`. That
   rule has zero specificity, so any component that sets its own `display` —
   `.product-card` is `display: flex` — silently overrides it and the filter
   appears to do nothing at all. Pin it here instead of at each call site. */
[hidden] { display: none !important; }

:focus-visible {
  outline: 3px solid var(--green-500);
  outline-offset: 2px;
  border-radius: 4px;
}

::selection { background: var(--green-100); color: var(--navy-900); }

/* Accessibility helpers */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; top: -60px; inset-inline-start: 16px; z-index: 200;
  background: var(--navy-800); color: var(--d-text-hi); padding: 10px 18px;
  border-radius: 0 0 var(--r-sm) var(--r-sm); transition: top .2s var(--ease);
}
.skip-link:focus { top: 0; color: var(--d-text-hi); }

/* --------------------------------------------------------------------------
   3. Layout primitives
   -------------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding: clamp(56px, 7vw, 104px) 0; }
.section--soft { background: var(--bg-soft); }
.section--mute { background: var(--bg-mute); }
.section--navy {
  background:
    radial-gradient(120% 90% at 12% 0%, rgba(0, 226, 122, .07) 0%, transparent 55%),
    linear-gradient(165deg, var(--navy-900) 0%, var(--navy-950) 100%);
  color: var(--d-text);
}
.section--navy h2, .section--navy h3, .section--navy h4 { color: var(--d-text-hi); }
.section--navy .section-head p { color: var(--d-muted); }
/* `:not(.btn)` matters. A band-level link colour otherwise wins over the button
   variants on specificity (.section--navy a is 0,1,1; .btn--primary is 0,1,0),
   which paints the green CTA's label green on a green fill — 1.3:1, all but
   invisible, and it did that in the dark theme before there was a light one. */
.section--navy a:not(.btn) { color: var(--d-accent); }
.section--navy a:not(.btn):hover { color: var(--d-accent-hover); }

/* A thin green rule that separates two adjacent dark bands. */
.section--navy + .section--navy { border-top: 1px solid var(--d-line-soft); }

.section-head { max-width: 760px; margin-bottom: clamp(32px, 4vw, 56px); }
.section-head--center { margin-inline: auto; text-align: center; }
.section-head p { color: var(--muted); font-size: 1.06rem; margin: 0; }

.eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: .78rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--accent);
  background: var(--accent-tint); border: 1px solid var(--accent-tint-line);
  padding: 6px 14px; border-radius: var(--r-pill); margin-bottom: 18px;
}
.eyebrow::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--green-500);
}
/* --------------------------------------------------------------------------
   4. Buttons
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  font-family: inherit; font-size: .95rem; font-weight: 600; line-height: 1;
  padding: 14px 26px; border-radius: var(--r-sm);
  border: 1.5px solid transparent; cursor: pointer;
  text-align: center; white-space: nowrap;
  transition: background-color .2s var(--ease), border-color .2s var(--ease),
              color .2s var(--ease), transform .2s var(--ease), box-shadow .2s var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn svg { width: 18px; height: 18px; flex: none; }

/* Primary = electric green. Dark text on the bright fill keeps contrast above
   WCAG AA at this weight, which white on #00e27a would not. */
.btn--primary { background: var(--green-500); color: var(--on-green); box-shadow: var(--sh-sm); }
.btn--primary:hover {
  background: var(--green-400); color: var(--on-green);
  transform: translateY(-2px); box-shadow: var(--green-glow);
}
.btn--primary svg { color: currentColor; }

.btn--green { background: var(--green-600); color: var(--on-green); }
.btn--green:hover { background: var(--green-500); color: var(--on-green); transform: translateY(-2px); }

/* The default secondary button — a quiet glass edge on the dark page. */
.btn--outline { border-color: var(--line); background: var(--tint); color: var(--ink); }
.btn--outline:hover {
  border-color: var(--green-500); color: var(--accent);
  transform: translateY(-2px); box-shadow: 0 8px 22px -10px rgba(0, 226, 122, .55);
}

/* Outline variant for use on dark sections. */
.btn--outline-light { border-color: var(--d-line-strong); background: transparent; color: var(--d-text-hi); }
.btn--outline-light:hover { border-color: var(--green-500); color: var(--d-accent); transform: translateY(-2px); }

.btn--ghost-light { border-color: var(--d-line-strong); color: var(--d-text-hi); background: var(--d-fill); }
.btn--ghost-light:hover { background: var(--d-fill-hi); color: var(--d-text-hi); border-color: var(--d-line-strong); }

.btn--sm { padding: 10px 18px; font-size: .875rem; }
/* Square icon-only button (WhatsApp shortcut on product cards). */
.btn--icon { width: 42px; height: 42px; padding: 0; flex: none; }
.btn--icon svg { width: 20px; height: 20px; color: var(--accent); }
.btn--icon:hover svg { color: var(--accent-hover); }
.btn--lg { padding: 17px 34px; font-size: 1rem; }
.btn--block { width: 100%; }

.btn-row { display: flex; flex-wrap: wrap; gap: 14px; }

/* --------------------------------------------------------------------------
   5. Header
   -------------------------------------------------------------------------- */
/* Solid, not translucent: the bar sits above the hero in normal flow rather
   than over it, so a translucent fill would composite against the white page
   background. Solid also lets it merge seamlessly into the dark hero. */
.header {
  position: sticky; top: 0; z-index: 100;
  background: var(--navy-950);
  border-bottom: 1px solid var(--d-line-soft);
  transition: box-shadow .25s var(--ease);
}
.header.is-stuck { box-shadow: var(--stuck-shadow); }

.header__inner {
  display: flex; align-items: center; gap: 22px;
  height: var(--header-h);
}

.brand { display: flex; align-items: center; gap: 10px; flex: none; }
.brand img { height: 33px; width: auto; flex: none; }
.brand span {
  color: var(--d-text-hi); font-size: 1.42rem; font-weight: 800;
  letter-spacing: -.025em; line-height: 1;
}

.nav { margin-inline-start: auto; }
.nav__list {
  display: flex; align-items: center; gap: 4px;
  list-style: none; margin: 0; padding: 0;
}
.nav__list li { margin: 0; }
.nav__link {
  position: relative;
  display: block; padding: 9px 14px; border-radius: var(--r-sm);
  color: var(--d-text); font-size: .94rem; font-weight: 500;
  transition: color .18s var(--ease), background-color .18s var(--ease);
}
.nav__link:hover { color: var(--d-text-hi); background: var(--d-fill); }
.nav__link[aria-current="page"] { color: var(--d-accent); font-weight: 600; }
/* Underline marker rather than a filled pill — reads as "current" without
   adding another button to the bar. */
.nav__link[aria-current="page"]::after {
  content: ""; position: absolute; inset-inline: 14px; bottom: 2px;
  height: 2px; border-radius: 2px; background: var(--d-accent-hover);
}

.header__actions { display: flex; align-items: center; gap: 10px; flex: none; }

/* The in-menu CTA duplicates the header CTA — desktop hides it, mobile shows it. */
.nav__cta { display: none; }

/* The theme toggle borrows the language toggle's shape: they are the same kind
   of control and sit side by side in the bar. Like the language toggle, each
   one names the state you would switch TO — in the dark theme it offers day
   mode, and vice versa. */
.lang-toggle,
.theme-toggle {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 14px; border-radius: var(--r-pill);
  border: 1.5px solid var(--d-line);
  color: var(--d-text); font-size: .85rem; font-weight: 600;
  background: var(--d-fill); cursor: pointer; font-family: inherit;
  transition: background-color .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
}
.lang-toggle:hover,
.theme-toggle:hover { background: var(--d-fill-hi); border-color: var(--d-line-strong); color: var(--d-text-hi); }
.lang-toggle svg { width: 15px; height: 15px; }
.theme-toggle svg { width: 15px; height: 15px; }

/* Only the pair matching the current theme is shown. `display: none` also
   takes the hidden one out of the accessibility tree, so the button never
   announces two labels at once. */
.theme-toggle__sun { display: inline-flex; }
.theme-toggle__moon,
.theme-toggle__to-dark { display: none; }
html[data-theme="light"] .theme-toggle__sun,
html[data-theme="light"] .theme-toggle__to-light { display: none; }
html[data-theme="light"] .theme-toggle__moon { display: inline-flex; }
html[data-theme="light"] .theme-toggle__to-dark { display: inline; }

/* ---- Language menu ------------------------------------------------------
   Appears only once the site has more than two languages; below that the
   switcher is a plain link and none of this applies. The summary borrows the
   toggle's pill so the pair stays visually identical, and the list hangs off
   its right edge — right-aligned because the control is the last thing in the
   bar, so a list growing leftwards can never push the page sideways.

   The summary holds only the globe and the caret, never the language's name:
   that keeps its width fixed no matter which language is current, which is
   what stops "Português" from pushing a 390px phone's header sideways. */
.lang-menu { position: relative; }
.lang-menu__summary { list-style: none; cursor: pointer; }
.lang-menu__summary::-webkit-details-marker { display: none; }
/* The caret is drawn rather than typed, so it cannot be reordered or read out
   as punctuation — the summary's own text carries the meaning. */
.lang-menu__summary::after {
  content: ""; width: 6px; height: 6px; margin-inline-start: 1px;
  border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
  transform: rotate(45deg) translate(-1px, -1px);
  transition: transform .18s var(--ease);
}
.lang-menu[open] .lang-menu__summary::after { transform: rotate(-135deg) translate(-1px, -1px); }
.lang-menu__list {
  position: absolute; top: calc(100% + 8px); inset-inline-end: 0; z-index: 1;
  min-width: 100%; margin: 0; padding: 6px; list-style: none;
  display: grid; gap: 2px;
  background: var(--navy-950); border: 1.5px solid var(--d-line);
  border-radius: var(--r-md); box-shadow: 0 22px 48px -12px rgba(0, 0, 0, .55);
}
.lang-menu__list a {
  display: block; padding: 9px 14px; border-radius: var(--r-sm);
  color: var(--d-text); font-size: .88rem; font-weight: 600; white-space: nowrap;
  transition: background-color .15s var(--ease), color .15s var(--ease);
}
.lang-menu__list a:hover { background: var(--d-fill-hi); color: var(--d-text-hi); }
/* The current language stays in the list — it is the one entry a visitor can
   already read, and removing it would make the menu a different height and a
   different order on every page. */
.lang-menu__list a[aria-current="page"] { color: var(--d-accent); }
.lang-menu__list a[aria-current="page"]::after { content: " ✓"; }

.nav-toggle {
  display: none; width: 42px; height: 42px; padding: 0;
  border: 1.5px solid var(--d-line); border-radius: var(--r-sm);
  background: var(--d-fill); cursor: pointer; color: var(--d-text-hi);
  align-items: center; justify-content: center;
}
.nav-toggle svg { width: 22px; height: 22px; }
.nav-toggle .icon-close { display: none; }
.nav-toggle[aria-expanded="true"] .icon-close { display: block; }
.nav-toggle[aria-expanded="true"] .icon-menu { display: none; }

@media (max-width: 1024px) {
  .nav {
    position: fixed; inset: var(--header-h) 0 auto 0;
    background: var(--navy-900); border-top: 1px solid var(--d-line-soft);
    border-bottom: 1px solid var(--d-line);
    padding: 12px var(--gutter) 26px;
    max-height: calc(100vh - var(--header-h)); overflow-y: auto;
    transform: translateY(-12px); opacity: 0; visibility: hidden;
    transition: opacity .22s var(--ease), transform .22s var(--ease), visibility .22s;
    box-shadow: 0 26px 50px rgba(0, 0, 0, .55);
  }
  .nav.is-open { transform: none; opacity: 1; visibility: visible; }
  .nav__list { flex-direction: column; align-items: stretch; gap: 2px; }
  .nav__link { padding: 14px 16px; font-size: 1rem; }
  .nav__link[aria-current="page"]::after { display: none; }
  .nav__link[aria-current="page"] { background: rgba(0, 226, 122, .1); }
  .nav__cta { display: block; margin-top: 14px; }
  .nav-toggle { display: inline-flex; margin-inline-start: auto; }
  .header__actions .btn { display: none; }
  .header__actions .lang-toggle { display: inline-flex; }
}

/* --------------------------------------------------------------------------
   6. Hero
   -------------------------------------------------------------------------- */
.hero {
  position: relative; overflow: hidden;
  background: var(--navy-950);
  color: var(--d-text);
  isolation: isolate;
}
.hero__media { position: absolute; inset: 0; z-index: -3; }
.hero__media img { width: 100%; height: 100%; object-fit: cover; object-position: center 42%; }
.hero__media::after {
  content: ""; position: absolute; inset: 0;
  background: var(--hero-veil);
}
/* Technical grid + a green bloom behind the copy — the "energy" cue that
   separates this from a generic corporate hero. */
.hero::before {
  content: ""; position: absolute; inset: 0; z-index: -2; pointer-events: none;
  background-image:
    linear-gradient(var(--hero-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--hero-grid) 1px, transparent 1px);
  background-size: 72px 72px;
  mask-image: linear-gradient(to bottom, #000 0%, transparent 78%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, transparent 78%);
}
.hero::after {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  inset-inline-start: -18%; top: 8%; width: 62%; aspect-ratio: 1;
  background: radial-gradient(circle, rgba(0, 226, 122, .16) 0%, transparent 62%);
}
.hero__inner { padding: clamp(88px, 11vw, 152px) 0 clamp(78px, 9vw, 124px); max-width: 780px; }
.hero h1 {
  color: var(--d-text-hi); margin-bottom: 22px;
  font-size: clamp(2.2rem, 5vw, 3.9rem);
  font-weight: 800; letter-spacing: -.03em; line-height: 1.08;
}
.hero__sub {
  font-size: clamp(1.02rem, 1.35vw, 1.18rem);
  color: var(--d-text); margin-bottom: 34px; max-width: 64ch;
}
.hero .eyebrow {
  color: var(--d-accent);
  background: rgba(0, 226, 122, .1);
  border-color: rgba(0, 226, 122, .3);
}

.hero__certs {
  display: flex; flex-wrap: wrap; gap: 10px; margin-top: 44px;
  padding-top: 26px; border-top: 1px solid var(--d-line);
}
.chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 14px; border-radius: var(--r-pill);
  background: var(--d-fill); border: 1px solid var(--d-line);
  font-size: .82rem; font-weight: 600; color: var(--d-text-hi);
}
.chip svg { width: 14px; height: 14px; color: var(--d-accent-hover); }

/* --------------------------------------------------------------------------
   7. Cards & grids
   -------------------------------------------------------------------------- */
.grid { display: grid; gap: 24px; }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.card {
  background: var(--tint); border: 1px solid var(--line);
  border-radius: var(--r-lg); overflow: hidden;
  transition: transform .25s var(--ease), box-shadow .25s var(--ease), border-color .25s var(--ease);
}

/* Trust cards */
.trust-card { padding: 30px 26px; }
.trust-card:hover { transform: translateY(-4px); box-shadow: var(--sh-lg); border-color: rgba(0, 226, 122, .45); }
.trust-card__icon {
  width: 50px; height: 50px; border-radius: var(--r-md); margin-bottom: 18px;
  display: grid; place-items: center;
  background: var(--accent-tint);
  color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent-tint-line);
}
.trust-card__icon svg { width: 25px; height: 25px; }
.trust-card h3 { font-size: 1.1rem; margin-bottom: 8px; }
.trust-card p { font-size: .94rem; color: var(--muted); margin: 0; }

/* Product cards */
.product-card { display: flex; flex-direction: column; height: 100%; }
.product-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 28px 54px -22px rgba(0, 0, 0, .85), 0 0 0 1px rgba(0, 226, 122, .18);
  border-color: rgba(0, 226, 122, .5);
}
.product-card__media {
  position: relative; display: block; aspect-ratio: 4 / 3;
  background: var(--bg-mute); overflow: hidden;
}
.product-card__media img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform .5s var(--ease);
}
.product-card:hover .product-card__media img { transform: scale(1.045); }

.product-card__tag {
  position: absolute; top: 14px; inset-inline-start: 14px;
  padding: 5px 12px; border-radius: var(--r-pill);
  background: rgba(6, 24, 47, .82); backdrop-filter: blur(6px);
  color: #fff; font-size: .74rem; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
}
.product-card__body { padding: 22px 22px 24px; display: flex; flex-direction: column; flex: 1; }
.product-card__model {
  font-family: var(--font-mono);
  font-size: .78rem; font-weight: 700; letter-spacing: .03em;
  color: var(--accent); text-transform: uppercase; margin-bottom: 8px;
  min-height: 1.3em; /* keeps titles aligned when a product has no model number */
}
.product-card h3 { font-size: 1.09rem; line-height: 1.35; margin-bottom: 10px; }
.product-card h3 a { color: inherit; }
.product-card h3 a:hover { color: var(--accent); }
.product-card__desc { font-size: .92rem; color: var(--muted); margin-bottom: 18px; flex: 1; }

.product-card__specs {
  list-style: none; margin: 0 0 20px; padding: 16px 0 0;
  border-top: 1px solid var(--line-soft); display: grid; gap: 7px;
}
.product-card__specs li {
  margin: 0; font-size: .855rem; color: var(--body);
  display: flex; justify-content: space-between; gap: 14px;
}
.product-card__specs span:first-child { color: var(--muted); flex: none; }
.product-card__specs span:last-child { font-weight: 600; color: var(--ink); text-align: end; }

.product-card__actions { display: flex; gap: 10px; align-items: center; }
.product-card__actions .btn:not(.btn--icon) { flex: 1; }

/* Application cards */
.app-card {
  position: relative; border-radius: var(--r-lg); overflow: hidden;
  aspect-ratio: 4 / 3; background: var(--navy-800); display: block;
  box-shadow: inset 0 0 0 1px var(--d-line-soft);
}
.app-card img { width: 100%; height: 100%; object-fit: cover; transition: transform .6s var(--ease); }
.app-card::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(4, 8, 14, .93) 0%, rgba(4, 8, 14, .4) 48%, transparent 76%);
}
/* Green rule that grows across the card on hover. */
.app-card::before {
  content: ""; position: absolute; z-index: 3; inset-inline: 22px; bottom: 0;
  height: 2px; background: var(--green-500); border-radius: 2px;
  transform: scaleX(0); transform-origin: left;
  transition: transform .45s var(--ease);
}
.app-card:hover img { transform: scale(1.055); }
.app-card:hover::before { transform: scaleX(1); }
.app-card__label {
  position: absolute; inset: auto 0 0 0; z-index: 2;
  padding: 22px 22px 20px; color: #fff;
}
.app-card__label strong { display: block; font-size: 1.05rem; font-weight: 700; }
/* Pinned to a literal, not --d-muted: this label sits on a photo scrim that
   stays dark in both themes, so it must not follow the page the way the --d-*
   family now does. */
.app-card__label span { font-size: .85rem; color: rgba(255, 255, 255, .62); }

/* Stats */
.stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 20px; }
/* Written against the page surface, not the dark tokens: the About page drops
   this grid inside a plain light section. The stats band below is dark and
   re-colours it from there. */
.stat { text-align: center; padding: 26px 16px; border-radius: var(--r-md); background: var(--tint); border: 1px solid var(--line-soft); }
.stat__value {
  display: block; font-size: clamp(1.7rem, 3vw, 2.3rem); font-weight: 800;
  color: var(--accent); letter-spacing: -.02em; line-height: 1.1; margin-bottom: 6px;
}
.stat__label { font-size: .87rem; color: var(--muted); }

/* Stats band — full-bleed strip directly under the hero. */
.stats-band {
  background: var(--navy-900);
  border-top: 1px solid var(--d-line-soft);
  border-bottom: 1px solid var(--d-line-soft);
  padding: clamp(30px, 3.6vw, 46px) 0;
}
.stats-band .stats { gap: 0; }
.stats-band .stat {
  background: none; border: 0; border-radius: 0;
  padding: 6px 20px; text-align: start;
}
.stats-band .stat + .stat { border-inline-start: 1px solid var(--d-line-soft); }
.stats-band .stat__value { font-size: clamp(1.6rem, 2.6vw, 2.25rem); color: var(--d-accent); }
.stats-band .stat__label { display: block; margin-top: 2px; color: var(--d-muted); }

/* Feature list */
.feature-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 15px; }
.feature-list li {
  position: relative; margin: 0; padding-inline-start: 34px;
  font-size: .97rem; color: var(--body);
}
.feature-list li::before {
  content: ""; position: absolute; inset-inline-start: 0; top: .28em;
  width: 21px; height: 21px; border-radius: 50%;
  background: rgba(0, 226, 122, .16) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234dffa4' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center/12px no-repeat;
}
/* Media figure */
.figure {
  border-radius: var(--r-lg); overflow: hidden;
  box-shadow: var(--sh-lg); background: var(--bg-mute);
  border: 1px solid var(--line);
}
.figure img { width: 100%; height: 100%; object-fit: cover; }

/* Media figure on a dark section. */
.figure--dark {
  background: var(--navy-850);
  border-color: var(--d-line-soft);
  box-shadow: var(--band-shadow);
}

/* --------------------------------------------------------------------------
   7b. Certification wall
   -------------------------------------------------------------------------- */
/* Flex rather than a fixed-column grid, so a short last row centres itself
   instead of stranding a card at the left edge. Six marks divide evenly at
   every width the wall sees (2+2+2 / 4+2 / 6 across), which is part of why the
   list is six: a seventh reintroduces a one-card orphan row. */
.cert-wall {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 12px;
}
.cert-wall__item {
  /* The cap stops a short row's cards stretching to the full container. */
  flex: 1 1 150px; max-width: 225px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 7px; padding: 20px 10px; text-align: center;
  border-radius: var(--r-md);
  background: var(--d-card); border: 1px solid var(--d-line-soft);
  transition: border-color .22s var(--ease), background-color .22s var(--ease);
}
.cert-wall__item:hover { border-color: rgba(0, 226, 122, .45); background: rgba(0, 226, 122, .06); }
.cert-wall__item strong {
  font-size: .92rem; font-weight: 800; color: var(--d-text-hi); letter-spacing: .04em;
}
.cert-wall__item span { font-size: .72rem; color: var(--d-muted); line-height: 1.35; }
.cert-wall__item svg { width: 22px; height: 22px; color: var(--accent); }

/* Sales team. The three source portraits have different aspect ratios, so the
   frame fixes 4:5 and `object-fit: cover` normalises them; `object-position`
   keeps faces in frame when the crop bites. */
.team-card {
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--tint); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--sh-md);
  transition: border-color .22s var(--ease), transform .22s var(--ease);
}
.team-card:hover { border-color: rgba(0, 226, 122, .4); transform: translateY(-3px); }
/* The img is absolutely positioned so it stops contributing its own height:
   an in-flow child would win over `aspect-ratio` and every card would end up
   as tall as its photo's intrinsic ratio — three different heights. */
.team-card__photo { position: relative; aspect-ratio: 4 / 5; background: var(--bg-mute); }
.team-card__photo img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; object-position: center 8%;
}
.team-card__body {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 22px 20px 26px; text-align: center; flex: 1;
}
.team-card__name { font-size: 1.15rem; font-weight: 800; color: var(--ink); margin: 0; }
.team-card__num {
  font-size: .95rem; font-weight: 700; color: var(--accent);
  letter-spacing: .01em; margin: 0; font-variant-numeric: tabular-nums;
}
/* Quieter than the number above it, and allowed to break mid-address: these run
   to ~19 characters with no space in them, so at 320px they would otherwise
   widen the card past its column. `anywhere` is the part that matters —
   `overflow-wrap: break-word` will not break a run that contains no break
   opportunity at all. */
.team-card__mail {
  font-size: .84rem; color: var(--muted); margin: 0;
  overflow-wrap: anywhere; line-height: 1.35;
}
.team-card__mail a { color: inherit; }
.team-card__mail a:hover { color: var(--accent); }
/* The QR is a fixed square: the intrinsic size is declared in the markup so a
   lazily-loaded image cannot shift the card when it decodes. */
.team-card__qr {
  width: 132px; height: 132px; margin-top: 4px;
  /* The images are square and are never shown larger than 132px, so there is
     nothing to fit around — `contain` is just insurance, so that a replacement
     asset with a different aspect cannot be stretched out of spec. A QR with
     non-square modules stops scanning. */
  object-fit: contain;
  border-radius: var(--r-sm); background: #fff; padding: 6px;
  border: 1px solid var(--line-soft);
}
.team-card__qr-cap { font-size: .76rem; color: var(--muted); }
.team-card__body .btn { margin-top: 6px; }
.team-card__body .btn svg { width: 16px; height: 16px; }

/* The protocol line under the wall. It is deliberately quieter than the marks
   above it — OCPP is a supported protocol, not a certificate, and should not
   read as one. */
.cert-note {
  margin: 18px auto 0; max-width: 620px; text-align: center;
  font-size: .84rem; color: var(--d-muted);
}

/* --------------------------------------------------------------------------
   7c. Company / factory block
   -------------------------------------------------------------------------- */
.company-collage { display: grid; gap: 16px; }
.company-collage .figure { margin: 0; }
.company-collage--2 { grid-template-columns: 1fr 1fr; }

@media (max-width: 720px) {
  .company-collage--2 { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   7d. Range grid (home) & process steps (home)
   -------------------------------------------------------------------------- */
/* Both live on light surfaces, so they read the base `--muted` rather than the
   `--d-muted` the navy bands use. */

/* The band that opens "Our Range". It borrows `section--navy` for the text
   colours and overrides only the surface, so it has to sit below that rule in
   this file: same specificity, so source order is what settles it. The scrim is
   vertical rather than diagonal because the heading here is centred — there is
   no near side to darken, so nothing about it mirrors in RTL.
   The surface is held in a custom property so the RTL block at the foot of this
   file can re-apply it: `[dir="rtl"] .section--navy` is more specific than
   `.range-band` alone and would otherwise put the plain navy gradient back. */
.range-band {
  --band-surface:
    linear-gradient(to bottom, rgba(4, 8, 14, .78) 0%, rgba(4, 8, 14, .58) 55%, rgba(4, 8, 14, .74) 100%),
    url("../img/range-band.jpg") center / cover no-repeat,
    linear-gradient(160deg, var(--navy-900) 0%, var(--navy-950) 100%);
  background: var(--band-surface);
  padding: clamp(56px, 7vw, 100px) 0 clamp(48px, 6vw, 84px);
}
/* The heading is the only thing on the band, so the shared bottom margin would
   just add to the band's own padding. */
.range-band .section-head { margin-bottom: 0; }

/* The cards carry a name and one line, nothing more — the specification for
   these lines lives in the manufacturer's catalogue, not on this site, so the
   card deliberately has no spec row to fill. The index is the one thing added:
   six text-only cards needed a shape to scan. It is decoration, not a sequence,
   and is aria-hidden in the markup. */
.range-card { padding: 26px 24px 28px; }
.range-card__num {
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 28px; block-size: 28px; border-radius: 9px; margin-bottom: 14px;
  background: var(--accent-tint); border: 1px solid var(--accent-tint-line);
  color: var(--accent); font-size: .8rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.range-card h3 { font-size: 1.1rem; line-height: 1.35; margin-bottom: 8px; }
.range-card p { font-size: .92rem; color: var(--muted); margin: 0; }

.range-note {
  margin: 26px auto 0; max-width: 640px; text-align: center;
  font-size: .84rem; color: var(--muted);
}

/* A numbered timeline. The number is real text in the markup, so the count is
   whatever i18n.json holds. The connecting rule is drawn on the item itself
   rather than as a pseudo-element between neighbours, so the first item has
   nothing to its inline-start edge to draw from. */
.steps {
  list-style: none; padding: 0; margin: 0;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 28px 24px;
}
.step { position: relative; }
.step::after {
  content: ""; position: absolute; inset-block-start: 19px;
  inset-inline-start: 52px; inset-inline-end: -24px; height: 1px;
  background: var(--line);
}
/* No rule runs off the end of a row, and none enters from the inline-start of
   the first column. */
.step:nth-child(3n)::after { display: none; }
.step__num {
  position: relative; z-index: 1;
  width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center; margin-bottom: 16px;
  background: var(--accent-tint); color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent-tint-line);
  font-weight: 700; font-size: .95rem; font-variant-numeric: tabular-nums;
}
.step h3 { font-size: 1.02rem; margin-bottom: 6px; }
.step p { font-size: .92rem; color: var(--muted); margin: 0; }

@media (max-width: 900px) {
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .step:nth-child(3n)::after { display: block; }
  .step:nth-child(2n)::after { display: none; }
}
@media (max-width: 600px) {
  /* Stacked: the rule would point at nothing, and the numbers already carry
     the sequence. */
  .steps { grid-template-columns: 1fr; gap: 24px; }
  .step::after { display: none; }
}

/* Category filter (products page) */
.btn.is-active,
.btn.is-active:hover {
  background: var(--green-500); border-color: var(--green-500); color: var(--on-green);
}

/* --------------------------------------------------------------------------
   8. Forms
   -------------------------------------------------------------------------- */
.form-card {
  background: var(--tint); border: 1px solid var(--line);
  border-radius: var(--r-xl); padding: clamp(26px, 3.4vw, 44px);
  box-shadow: var(--sh-lg);
}
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
.field { display: flex; flex-direction: column; gap: 7px; }
.field--full { grid-column: 1 / -1; }

.field label { font-size: .875rem; font-weight: 600; color: var(--ink); }
.field label .req { color: var(--danger); margin-inline-start: 3px; }

.field input, .field select, .field textarea {
  font-family: inherit; font-size: .95rem; color: var(--ink);
  padding: 13px 15px; border: 1.5px solid var(--line); border-radius: var(--r-sm);
  background: var(--field); width: 100%;
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease);
}
.field textarea { resize: vertical; min-height: 124px; }
.field input::placeholder, .field textarea::placeholder { color: var(--muted); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--green-500);
  box-shadow: 0 0 0 4px rgba(0, 226, 122, .16);
}
/* Chrome autofill paints its own pale yellow; repaint it for the dark field. */
.field input:-webkit-autofill,
.field input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--ink);
  box-shadow: inset 0 0 0 100px var(--field-autofill);
}
.field select {
  appearance: none;
  /* Opaque, unlike the other fields — the dropdown popup inherits this value as
     its own plate colour, and a translucent one composites to white. The option
     rule below is what actually pins the popup text; this is the backdrop it
     sits on. */
  background-color: var(--field-solid);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a9bacd' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center; background-size: 17px;
  padding-inline-end: 42px;
}
/* Windows/Linux render the option list with the page's palette, so both halves
   of the pair are set explicitly rather than left to the platform default. */
.field select option, .field select optgroup {
  background-color: var(--field-solid); color: var(--ink);
}
.field .error-msg { font-size: .8rem; color: var(--danger); display: none; }
.field.has-error input, .field.has-error textarea, .field.has-error select { border-color: var(--danger); }
.field.has-error .error-msg { display: block; }

.form-foot { margin-top: 22px; display: flex; flex-wrap: wrap; align-items: center; gap: 16px; }
.form-note { font-size: .82rem; color: var(--muted); }

.form-status {
  display: none; margin-top: 20px; padding: 15px 18px;
  border-radius: var(--r-sm); font-size: .92rem; font-weight: 500;
}
.form-status.is-visible { display: block; }
.form-status--ok {
  background: var(--accent-tint); color: var(--accent);
  border: 1px solid var(--accent-tint-line);
}
.form-status--err {
  background: var(--danger-fill); color: var(--danger);
  border: 1px solid var(--danger-line);
}

/* Honeypot — hidden from humans, visible to naïve bots */
.hp-field { position: absolute; inset-inline-start: -9999px; opacity: 0; height: 0; overflow: hidden; }

/* --------------------------------------------------------------------------
   9. Page header (inner pages)
   -------------------------------------------------------------------------- */
/* The photograph is a CSS background rather than an <img>, so every inner page
   gets it without a line of markup per page and without an alt string per
   language. The scrim under it is near-opaque on the side the copy sits on and
   thins to the far side, so the heading stays legible while the picture still
   reads. 105deg mirrors to 255deg; the whole stack is restated in the
   [dir="rtl"] block at the foot of this file, because `background` is a
   shorthand and cannot be half-overridden.
   One consequence of doing it here: `url()` cannot carry the ?v= the markup
   assets get, so replacing this file later needs the filename changed too. */
.pagehead {
  position: relative;
  background:
    radial-gradient(90% 120% at 8% 0%, rgba(0, 226, 122, .1) 0%, transparent 58%),
    linear-gradient(105deg, rgba(4, 8, 14, .94) 12%, rgba(4, 8, 14, .78) 44%, rgba(4, 8, 14, .42) 100%),
    url("../img/pagehead.jpg") center 42% / cover no-repeat,
    linear-gradient(160deg, var(--navy-900) 0%, var(--navy-950) 100%);
  border-bottom: 1px solid var(--d-line-soft);
  color: var(--d-text);
  padding: clamp(48px, 6vw, 84px) 0 clamp(44px, 5vw, 72px);
}
/* Both photographed surfaces (.pagehead here, .range-band further down) stay
   dark whatever the theme. The light theme is not the dark one with different
   ink — it re-skins every band (--navy-900 becomes #f1f6fa) and flips the --d-*
   tokens to dark. Left alone that paints dark text, and a dark-green eyebrow,
   onto a dark photograph. Restoring the tokens is enough; no property below
   needs to know.
   --accent is included because it is a token too: the light theme darkens it to
   #067a45 for white backgrounds, which is close to invisible on a photo. */
html[data-theme="light"] .pagehead,
html[data-theme="light"] .range-band {
  --d-text:   rgba(255, 255, 255, .74);
  --d-text-hi:rgba(255, 255, 255, .96);
  --d-muted:  rgba(255, 255, 255, .52);
  --d-line-soft: rgba(255, 255, 255, .14);
  --accent:           var(--green-400);
  --accent-hover:     var(--green-500);
  --accent-tint:      rgba(0, 226, 122, .1);
  --accent-tint-line: rgba(0, 226, 122, .3);
}
.pagehead h1 { color: var(--d-text-hi); margin-bottom: 14px; }
.pagehead p { color: var(--d-text); max-width: 660px; margin: 0; font-size: 1.05rem; }

.breadcrumb {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  font-size: .84rem; color: var(--d-muted); margin-bottom: 18px;
  list-style: none; padding: 0;
}
.breadcrumb li { margin: 0; display: flex; align-items: center; gap: 8px; }
.breadcrumb li + li::before { content: "/"; color: var(--d-line-strong); }
.breadcrumb a { color: var(--d-text); }
.breadcrumb a:hover { color: var(--d-accent); }

/* --------------------------------------------------------------------------
   10. Product detail
   -------------------------------------------------------------------------- */
.pdp { display: grid; grid-template-columns: minmax(0, 1.06fr) minmax(0, 1fr); gap: clamp(30px, 4vw, 56px); align-items: start; }

.gallery__main {
  border-radius: var(--r-lg); overflow: hidden; background: var(--bg-mute);
  border: 1px solid var(--line); aspect-ratio: 4 / 3;
}
.gallery__main img { width: 100%; height: 100%; object-fit: cover; }
.gallery__thumbs { display: flex; gap: 12px; margin-top: 14px; flex-wrap: wrap; }
.gallery__thumb {
  width: 88px; height: 68px; border-radius: var(--r-sm); overflow: hidden;
  border: 2px solid var(--line); background: var(--bg-mute); cursor: pointer; padding: 0;
  transition: border-color .18s var(--ease);
}
.gallery__thumb img { width: 100%; height: 100%; object-fit: cover; }
.gallery__thumb:hover { border-color: var(--green-500); }
.gallery__thumb[aria-pressed="true"] { border-color: var(--green-500); box-shadow: var(--green-glow); }

.pdp__model {
  font-family: var(--font-mono);
  font-size: .8rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 10px;
}
.pdp__cat {
  display: inline-block; padding: 5px 13px; border-radius: var(--r-pill);
  background: rgba(0, 226, 122, .1); border: 1px solid rgba(0, 226, 122, .3);
  color: var(--accent); font-size: .78rem; font-weight: 600; margin-bottom: 14px;
}
.pdp h1 { font-size: clamp(1.6rem, 2.7vw, 2.15rem); }
.pdp__tagline { color: var(--muted); font-size: 1rem; margin-bottom: 24px; }

.pdp__highlights {
  list-style: none; padding: 0; margin: 0 0 28px;
  display: grid; gap: 10px;
}
.pdp__highlights li {
  margin: 0; padding: 12px 16px; border-radius: var(--r-sm);
  background: var(--bg-soft); border-inline-start: 3px solid var(--green-500);
  font-size: .92rem; color: var(--body);
}

.pdp__actions { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 22px; }

.cert-row { display: flex; flex-wrap: wrap; gap: 9px; }
.cert-badge {
  padding: 7px 15px; border-radius: var(--r-sm);
  border: 1px solid rgba(0, 226, 122, .35);
  background: var(--accent-tint); font-size: .82rem; font-weight: 700; color: var(--accent);
}

/* Spec table */
.spec-table { width: 100%; border-collapse: collapse; font-size: .93rem; }
.spec-table caption { text-align: start; font-weight: 700; color: var(--ink); padding: 0 0 14px; }
.spec-table th, .spec-table td {
  padding: 13px 18px; text-align: start; vertical-align: top;
  border-bottom: 1px solid var(--line-soft);
}
.spec-table th {
  width: 42%; font-weight: 600; color: var(--muted);
  background: var(--bg-soft); font-size: .885rem;
}
.spec-table td { color: var(--ink); font-weight: 500; }
.spec-table tbody tr:last-child th, .spec-table tbody tr:last-child td { border-bottom: 0; }
.spec-wrap {
  border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; background: var(--tint);
}

/* Matrix variant — several product versions across the top, one row per
   attribute. Wide content scrolls inside the wrapper rather than breaking the
   page layout on narrow screens. */
.spec-table--matrix { font-size: .875rem; min-width: 640px; }
.spec-table--matrix thead th {
  background: var(--navy-700); color: var(--d-text-hi);
  font-size: .8rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; border-bottom: 0; width: auto; white-space: nowrap;
}
.spec-table--matrix thead th:first-child { color: var(--accent); }
.spec-table--matrix th[scope="row"] { width: 20%; min-width: 150px; }
.spec-table--matrix td { font-size: .875rem; }
.spec-table--matrix tbody tr:nth-child(even) th,
.spec-table--matrix tbody tr:nth-child(even) td { background: var(--bg-soft); }
.spec-table--matrix tbody tr:nth-child(even) th { background: var(--bg-mute); }
.spec-table--matrix .spec-table__section th {
  width: auto; padding: 11px 18px;
  background: rgba(0, 226, 122, .12) !important;
  color: var(--accent); font-size: .8rem; font-weight: 800;
  letter-spacing: .07em; text-transform: uppercase;
  border-top: 1px solid rgba(0, 226, 122, .3);
  border-bottom: 1px solid rgba(0, 226, 122, .3);
}
.spec-wrap:has(.spec-table--matrix) { overflow-x: auto; }

/* FAQ accordion */
.faq { border: 1px solid var(--line); border-radius: var(--r-md); background: var(--tint); margin-bottom: 12px; overflow: hidden; }
.faq summary {
  cursor: pointer; list-style: none; padding-block: 18px; padding-inline: 22px 56px;
  font-weight: 600; color: var(--ink); font-size: .97rem; position: relative;
  transition: background-color .18s var(--ease);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { background: var(--bg-soft); }
.faq summary::after {
  content: ""; position: absolute; inset-inline-end: 22px; top: 50%; width: 15px; height: 15px;
  margin-top: -7px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a9bacd' stroke-width='2.6' stroke-linecap='round'%3E%3Cline x1='12' y1='5' x2='12' y2='19'/%3E%3Cline x1='5' y1='12' x2='19' y2='12'/%3E%3C/svg%3E") center/contain no-repeat;
  transition: transform .22s var(--ease);
}
.faq[open] summary::after { transform: rotate(45deg); }
.faq__body { padding: 0 22px 20px; color: var(--body); font-size: .94rem; }
.faq__body p:last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   11. WhatsApp floating button
   -------------------------------------------------------------------------- */
.wa-float {
  position: fixed; inset-inline-end: 22px; bottom: 22px; z-index: 90;
  display: inline-flex; align-items: center; gap: 11px;
  padding-block: 13px; padding-inline: 15px 20px; border-radius: var(--r-pill);
  /* Near-black on the brand green, the same pairing the primary buttons use.
     White on #25d366 is 2.0:1 — a fail, and this is the site's most-clicked
     control. */
  background: #25d366; color: var(--on-green); font-weight: 700; font-size: .93rem;
  box-shadow: 0 10px 26px rgba(37, 211, 102, .38), 0 3px 8px rgba(6, 24, 47, .16);
  transition: transform .22s var(--ease), box-shadow .22s var(--ease);
}
.wa-float:hover { transform: translateY(-3px) scale(1.02); color: var(--on-green); box-shadow: 0 14px 32px rgba(37, 211, 102, .48); }
.wa-float svg { width: 26px; height: 26px; flex: none; }
.wa-float__text { white-space: nowrap; }
@media (max-width: 640px) {
  .wa-float { inset-inline-end: 16px; bottom: 16px; padding: 14px; }
  .wa-float__text { display: none; }
}

/* --------------------------------------------------------------------------
   12. Footer
   -------------------------------------------------------------------------- */
.footer { background: var(--navy-950); color: var(--d-text); border-top: 1px solid var(--d-line-soft); padding: clamp(52px, 6vw, 78px) 0 0; }
.footer__grid { display: grid; grid-template-columns: 1.55fr 1fr 1fr 1.25fr; gap: 40px; }
.footer h4 {
  color: var(--d-text-hi); font-size: .84rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; margin-bottom: 20px;
}
.footer__logo {
  display: flex; align-items: center; gap: 11px; margin-bottom: 20px;
}
.footer__logo img { height: 34px; width: auto; }
.footer__logo span {
  color: var(--d-text-hi); font-size: 1.5rem; font-weight: 800;
  letter-spacing: -.02em; line-height: 1;
}
.footer p { font-size: .9rem; line-height: 1.7; }
.footer ul { list-style: none; padding: 0; margin: 0; }
.footer li { margin-bottom: 11px; }
.footer a { color: var(--d-text); font-size: .9rem; }
.footer a:hover { color: var(--d-accent); }
.footer__contact li { display: flex; gap: 11px; align-items: flex-start; font-size: .9rem; }
.footer__contact svg { width: 17px; height: 17px; flex: none; margin-top: 3px; color: var(--d-accent-hover); }
.footer__bottom {
  margin-top: clamp(40px, 5vw, 64px); padding: 24px 0;
  border-top: 1px solid var(--d-line);
  display: flex; flex-wrap: wrap; gap: 14px; justify-content: space-between; align-items: center;
  font-size: .85rem;
}
.footer__bottom p { margin: 0; }

/* --------------------------------------------------------------------------
   13. Utilities
   -------------------------------------------------------------------------- */
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
.mt-4 { margin-top: 24px; }
.mt-6 { margin-top: 38px; }
.text-center { text-align: center; }
.two-col { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(30px, 4vw, 58px); align-items: center; }
/* A grid item's `min-width` defaults to `auto`, which resolves to its
   min-content size. The inquiry form's <select> carries a long country list, so
   that column had a ~290px floor it could not shrink below: on a 320px phone the
   track overran the container and the whole page scrolled sideways. Let the
   items shrink to their share of the grid instead — the select clips its own
   label, which is the lesser cost. */
.two-col > * { min-width: 0; }

/* --------------------------------------------------------------------------
   15. Responsive
   -------------------------------------------------------------------------- */
@media (max-width: 1080px) {
  .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 34px; }
  .pdp { grid-template-columns: 1fr; }
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .stats-band .stat + .stat { border-inline-start: 0; }
  .stats-band .stat { border-top: 1px solid var(--d-line-soft); padding: 16px 0; }
  .stats-band .stat:nth-child(-n+2) { border-top: 0; }
}

@media (max-width: 860px) {
  .grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .two-col { grid-template-columns: 1fr; }
  .hero__inner { max-width: none; }
}

@media (max-width: 640px) {
  :root { --gutter: 18px; --header-h: 66px; }
  /* The language and theme buttons each carry a word. Two words plus the
     wordmark and the hamburger already overflow a 390px bar, so the theme
     one drops to its icon. The light-theme selector is repeated because it
     is the rule that would otherwise win on specificity. */
  .theme-toggle__to-light,
  .theme-toggle__to-dark,
  html[data-theme="light"] .theme-toggle__to-dark { display: none; }
  .theme-toggle { padding: 8px 11px; }
  .grid--2, .grid--3, .grid--4 { grid-template-columns: 1fr; }
  .form-grid { grid-template-columns: 1fr; }
  .stats { grid-template-columns: 1fr; }
  .stats-band .stat:nth-child(-n+2) { border-top: 1px solid var(--d-line-soft); }
  .stats-band .stat:first-child { border-top: 0; }
  .footer__grid { grid-template-columns: 1fr; gap: 30px; }
  .btn-row .btn { width: 100%; }
  .spec-table th, .spec-table td { padding: 11px 14px; font-size: .88rem; }
  .spec-table th { width: 46%; }

  /* Team cards go side-by-side on a phone. Stacked at full width each card is
     ~780px tall, so three of them is 2300px of scrolling for three names — and
     a QR is unscannable on the handset already holding it, so the button, not
     the code, is what has to stay prominent. */
  .team-card { flex-direction: row; }
  /* `aspect-ratio` has to go: stretched to the row's height it would resolve the
     width back out of the ratio (~216px) and blow the card past the viewport.
     Letting it stretch and cropping with object-fit keeps the width honest. */
  .team-card__photo { flex: 0 0 118px; width: 118px; aspect-ratio: auto; }
  .team-card__body { align-items: flex-start; text-align: start; padding: 16px 16px 18px; gap: 6px; }
  .team-card__name { font-size: 1.05rem; }
  .team-card__qr { width: 100px; height: 100px; margin-top: 2px; }
  .team-card__qr-cap { font-size: .72rem; }
  /* `min-width: auto` on a flex item resolves to its min-content size, so the
     body would refuse to shrink below its widest child and overrun the card —
     which clips, so the damage only shows up as cut-off text. Let it shrink to
     its share of the row, and let the CTA's label wrap onto a second line
     instead of holding a 183px floor the phone cannot pay. */
  .team-card__body { min-width: 0; }
  .team-card__body .btn { width: 100%; justify-content: center; margin-top: 8px; white-space: normal; }
}

/* Smallest phones. Three controls now share the bar with the wordmark, and at
   this size the flex gaps alone decide whether the page scrolls sideways. Every
   element gives up a little air rather than any of them being dropped — the
   wordmark stays, the language switch keeps its label, and the theme switch
   stays on screen. Between them these shave ~30px off the bar. */
@media (max-width: 380px) {
  .header__inner { gap: 10px; }
  .header__actions { gap: 5px; }
  .brand { gap: 8px; }
  .brand span { font-size: 1.26rem; }
  .lang-toggle { padding: 8px 9px; gap: 6px; }
  .theme-toggle { padding: 8px 8px; }
  /* The team row's fixed photo column is 118px of a 282px card, which leaves
     the body too narrow for the phone number on one line. */
  .team-card__photo { flex: 0 0 96px; width: 96px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  .header, .footer, .wa-float, .admin-bar { display: none; }
}

/* ==========================================================================
   Right to left (Arabic)
   --------------------------------------------------------------------------
   Most of this file needs nothing here. Flex rows, grid columns,
   `justify-content` and `text-align: start/end` all mirror themselves once
   <html dir="rtl"> is set, and the declarations that did not follow on their
   own were converted to logical properties where they appear.

   What is left are the cases CSS gives no logical keyword for. They cannot be
   stated once and mirrored, so they are restated here, together, rather than
   scattered as afterthoughts through the file above.
   ========================================================================== */

/* Arabic is a cursive script: letter-spacing prises apart the joins that carry
   the word, so a rule that reads as "refined" in Latin reads as "broken" here.
   Every letter-spacing in this file was chosen for a Latin face, so the whole
   group is cancelled at once rather than rule by rule.
   `!important` is load-bearing, not laziness: it also has to beat the inline
   -.04em the hero eyebrow ships with, and the rules being cancelled otherwise
   tie with this selector on specificity, leaving source order to decide. */
[dir="rtl"] * { letter-spacing: normal !important; }

/* The hero veil exists to keep the headline legible over the photograph. It is
   opaque on the left and thins to the right; with the copy moved to the right
   it would sit on the brightest part of the image. 100deg mirrors to 260deg
   (a horizontal flip maps an angle t to 360-t). Scoped to html so it can be
   told apart from the light-theme value below, which is more specific and so
   wins wherever both match. */
html[dir="rtl"] {
  --hero-veil: linear-gradient(260deg, rgba(4, 8, 14, .97) 0%, rgba(4, 8, 14, .9) 34%,
                                      rgba(4, 8, 14, .62) 62%, rgba(4, 8, 14, .34) 100%);
}
html[dir="rtl"][data-theme="light"] {
  --hero-veil: linear-gradient(260deg, rgba(246, 249, 251, .97) 0%, rgba(246, 249, 251, .93) 34%,
                                      rgba(246, 249, 251, .72) 62%, rgba(246, 249, 251, .42) 100%);
}

/* Corner glow: `at 12% 0%` and `at 8% 0%` have no logical form, so the stop is
   mirrored by hand. The second layer of each is only a slight diagonal over
   two near-identical navies, but it is flipped too so the pair stays in step. */
[dir="rtl"] .section--navy {
  background:
    radial-gradient(120% 90% at 88% 0%, rgba(0, 226, 122, .07) 0%, transparent 55%),
    linear-gradient(195deg, var(--navy-900) 0%, var(--navy-950) 100%);
}
/* Restated in full rather than partly, for the reason given at the .pagehead
   rule: a shorthand background cannot be overridden one layer at a time, so the
   photo has to be named again here. The scrim flips to 255deg (105 mirrored) so
   it is still the copy's side that stays opaque; the photograph's own position
   is `center`, which needs no mirroring. */
[dir="rtl"] .pagehead {
  background:
    radial-gradient(90% 120% at 92% 0%, rgba(0, 226, 122, .1) 0%, transparent 58%),
    linear-gradient(255deg, rgba(4, 8, 14, .94) 12%, rgba(4, 8, 14, .78) 44%, rgba(4, 8, 14, .42) 100%),
    url("../img/pagehead.jpg") center 42% / cover no-repeat,
    linear-gradient(200deg, var(--navy-900) 0%, var(--navy-950) 100%);
}

/* The band overrides the surface `section--navy` gives it, and the RTL navy rule
   just above outranks the band's own — so the override is re-applied here, after
   it. Nothing about the value changes: its scrim runs vertically, so unlike
   .pagehead there is no direction in it to flip. */
[dir="rtl"] .range-band { background: var(--band-surface); }

/* transform-origin has no logical equivalent, so the green rule has to be told
   which edge to grow from: inline-start, which is the right-hand edge in RTL. */
[dir="rtl"] .app-card::before { transform-origin: right; }

/* A background-image cannot be positioned logically either - `right 14px` is
   the select caret, which belongs on the inline-end edge. Its matching
   `padding-inline-end: 42px` above already mirrors; only the caret needs this. */
html[dir="rtl"] .field select { background-position: left 14px center; }

/* Bidi: an Arabic paragraph that embeds a Latin run - an address, a phone
   number, a model code like BHDC-BH-10B-120KW - can have that run's
   punctuation reordered by the bidi algorithm. Isolating the element and
   pinning it to LTR keeps such values reading left to right, as they are
   written everywhere else on the site. */
[dir="rtl"] .footer__contact a,
[dir="rtl"] .product-card__model,
[dir="rtl"] .pdp__model,
[dir="rtl"] a[href^="mailto:"] { unicode-bidi: isolate; direction: ltr; }

/* Directional icons cannot mirror themselves. The arrow is drawn pointing
   right for "forward"; in RTL forward is to the left. The same rule serves the
   back arrow, which is drawn pointing left: flipping it puts "back" on the
   right, which is where it belongs in RTL. */
[dir="rtl"] .icon-arrow { transform: scaleX(-1); }

/* The language caret is two borders rotated 45deg, so mirroring it means
   swapping which borders are drawn and negating the angle - neither has a
   logical keyword. The list itself already hangs off `inset-inline-end`, which
   mirrors on its own; only the caret needs telling. */
[dir="rtl"] .lang-menu__summary::after {
  border-right: 0; border-left: 1.6px solid currentColor;
  transform: rotate(-45deg) translate(1px, -1px);
}
[dir="rtl"] .lang-menu[open] .lang-menu__summary::after {
  transform: rotate(135deg) translate(1px, -1px);
}

