@charset "UTF-8";
/* ==========================================================================
   M-TOOLS D.O.O. — design system
   --------------------------------------------------------------------------
   Machinist's drawing, not marketing brochure: hairline rules, an 8px spacing
   grid, 2px corner radius, 1px borders instead of shadows, and a single
   restrained brass accent.

   CONTENTS
     01  Design tokens
     02  Fonts
     03  Reset & base
     04  Typography
     05  Layout primitives
     06  Buttons & links
     07  Header, navigation, mobile menu
     08  Hero slider
     09  Fact bar
     10  Section furniture
     11  Home sections
     11b Interior page sections
     11c Contact, map facade, forms, legal
     12  Table
     13  FAQ
     14  Breadcrumbs
     15  Footer
     16  Floating UI — assistant, back to top
     17  Cookie consent
     18  404
     18b Preloader
     19  Preferences: reduced motion, more contrast, forced colours, print
   ========================================================================== */

/* ==========================================================================
   01  DESIGN TOKENS
   ========================================================================== */

:root {
  /* --- Core brand ------------------------------------------------------
     --c-primary is sampled from the supplied logo file: the weighted mean of
     the eight densest non-white pixel clusters is rgb(38, 51, 110). Measured
     11.79:1 against white. Do not eyeball a replacement. */
  --c-primary: #26336E;
  --c-primary-deep: #1A234C;
  --c-primary-soft: #344798;

  /* --- Machined-steel neutrals ---------------------------------------- */
  --c-ink: #14171F;
  --c-ink-muted: #555D6E;
  --c-line: #DDE2EC;          /* decorative hairlines and dividers only */
  --c-line-strong: #C3CBDB;   /* heavier dividers, still decorative */
  /* Boundaries of INTERACTIVE controls — ghost buttons, inputs, the textarea.
     WCAG 1.4.11 requires 3:1 for these because the border is the only thing
     identifying the control; measured 3.25:1 on white. --c-line at 1.30:1 is
     fine for a divider but must never be used to outline a control. */
  --c-border-strong: #868FA1;
  --c-surface: #F4F6FA;
  --c-white: #FFFFFF;

  /* --- The single accent ------------------------------------------------
     One brass/chip tone in three calibrated values. There is still exactly one
     accent hue; these are contrast variants of it, not extra colours.

       --c-accent          rules, borders and large numerals on LIGHT
                           backgrounds. 3.54:1 on white, 3.27:1 on surface.
       --c-accent-ink      small accent TEXT on light backgrounds. 5.57:1.
       --c-accent-on-dark  accent text and rules on navy or over imagery,
                           where the darker brass drops to 4.5:1 or below.
                           6.99:1 on --c-primary-deep.

     Never use any of them for body copy. */
  --c-accent: #B07F33;
  --c-accent-ink: #8A6018;
  --c-accent-on-dark: #D9A85C;

  /* --- Semantic -------------------------------------------------------- */
  --c-success: #146C42;
  --c-error: #A81E17;

  /* --- Contextual roles, remapped inside dark sections ----------------- */
  --c-bg: var(--c-white);
  --c-text: var(--c-ink);
  --c-text-muted: var(--c-ink-muted);
  --c-rule: var(--c-line);
  --c-heading: var(--c-primary);

  /* --- Type scale ------------------------------------------------------
     A FIXED scale. Use only these steps — the old site had 13 arbitrary sizes.
     The smallest step is 14px, the site-wide minimum; nothing renders below it. */
  --fs-100: 0.875rem;    /* 14px — captions, legal, table meta */
  --fs-200: 0.9375rem;   /* 15px — secondary text, nav */
  --fs-300: 1rem;        /* 16px — body */
  --fs-400: 1.25rem;     /* 20px — lead paragraphs */
  --fs-500: clamp(1.25rem, 0.95rem + 1.1vw, 1.5625rem);  /* 20 -> 25px — h3 */
  --fs-600: clamp(1.5625rem, 1.15rem + 1.8vw, 2rem);     /* 25 -> 32px — h2 */
  --fs-700: clamp(1.875rem, 1.25rem + 2.8vw, 2.75rem);   /* 30 -> 44px — h1 */
  --fs-800: clamp(2.125rem, 1.15rem + 4.4vw, 3.75rem);   /* 34 -> 60px — hero */

  --lh-tight: 1.1;
  --lh-heading: 1.18;
  --lh-body: 1.65;

  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;

  --ff-sans: 'Archivo', 'Archivo Fallback', ui-sans-serif, system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --ff-mono: 'JetBrains Mono', 'JetBrains Mono Fallback', ui-monospace, 'SFMono-Regular', 'Cascadia Mono', Consolas, monospace;

  /* --- Spacing: a strict 8px grid -------------------------------------- */
  --s-1: 0.5rem;    /*  8 */
  --s-2: 1rem;      /* 16 */
  --s-3: 1.5rem;    /* 24 */
  --s-4: 2rem;      /* 32 */
  --s-5: 3rem;      /* 48 */
  --s-6: 4rem;      /* 64 */
  --s-7: 6rem;      /* 96 */
  --s-8: 8rem;      /* 128 */
  --section-y: clamp(3.5rem, 2rem + 6vw, 7rem);

  /* --- Structure -------------------------------------------------------- */
  --wrap: 78rem;          /* 1248px */
  --wrap-narrow: 46rem;
  --measure: 68ch;        /* 60-75 characters of Serbian body copy */
  --radius: 2px;
  --hairline: 1px;
  --header-h: 72px;
  --floating-size: 56px;
  --floating-gap: clamp(1rem, 0.6rem + 1.2vw, 1.5rem);

  --dur-fast: 140ms;
  --dur: 240ms;
  --dur-slide: 600ms;
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  --z-header: 100;
  --z-float: 200;
  --z-panel: 300;
  --z-menu: 400;
  --z-consent: 500;
  --z-preloader: 900;

  color-scheme: light;
}

/* Dark context: used by the footer, the CTA band and the hero. Remapping the
   role tokens means components need no dark-specific rules of their own. */
.on-dark {
  --c-bg: var(--c-primary-deep);
  --c-text: #FFFFFF;
  --c-text-muted: #C2CAE0;      /* 9.4:1 on --c-primary-deep */
  --c-rule: rgba(255, 255, 255, 0.18);
  --c-heading: #FFFFFF;
  color-scheme: dark;
}

/* ==========================================================================
   02  FONTS
   --------------------------------------------------------------------------
   One file per family. Archivo is a variable font (weight 400-700) subset to
   Latin + Latin Extended-A, so Serbian diacritics (š č ć ž đ) are in the same
   file as the base alphabet — no second request, no reflow when a diacritic
   appears. No icon font: the icons are inline SVG.
   ========================================================================== */

/* font-display: optional, not swap.
   -------------------------------------------------------------------------
   `swap` renders the fallback and then replaces it, and any line of text
   sitting on a wrap boundary gains or loses a line when it does. The
   metrics-matched fallbacks below make that rare, but rare is not never:
   the Serbian About h1 reproduced 0.0717 CLS this way, intermittently, and
   hunting individual headings is whack-a-mole — the next copy edit puts a new
   one on the boundary.

   `optional` removes the swap period entirely. The browser gives the font a
   ~100ms block period and, if it has not arrived, uses the fallback for THAT
   PAGE VIEW and never swaps. Layout-shift-from-font-loading becomes
   structurally impossible rather than tuned away.

   The trade is that a first visit on a slow connection can render in the
   fallback. Three things make that acceptable here: both files are tiny
   (34 KB + 10 KB), both are same-origin and preloaded at the top of <head>,
   and the fallbacks below are metrics-matched, so an un-swapped page is the
   same shape and size — a slightly different typeface, not a broken layout. */
@font-face {
  font-family: 'Archivo';
  src: url('../fonts/archivo-latin-srb.woff2') format('woff2-variations'),
       url('../fonts/archivo-latin-srb.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: optional;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../fonts/jetbrains-mono-latin-srb.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: optional;
}

/* Metrics-matched fallbacks.
   -------------------------------------------------------------------------
   With font-display: optional these are what a visitor sees whenever the
   webfont misses its block period, so they matter more than before, not less:
   they re-scale the local fallback to occupy the same space as the webfont, so
   a page that renders in Arial is the same shape as one that renders in
   Archivo. They were originally added to make the `swap` reflow invisible —
   measured at 0.0081 CLS on the English homepage.

   size-adjust is MEASURED, not computed from mean glyph advances. The earlier
   95.6% came from the ratio of mean lowercase advances (Archivo 52.02% of em,
   Arial 54.39%) and was 3 points too narrow in practice — enough that the
   Serbian About h1 set two lines in the fallback and three in Archivo. The
   numbers below are the ratio of canvas-measured widths of real strings from
   this site at 100px:

     "Porodična alatnica koja je izrasla iz završne obrade"   97.85%
     hero paragraph, running Serbian text                     98.67%
     "A family toolroom grown out of finishing work"          98.86%
     "ALATNICA STUBAL — OD 2008." (mono, vs Consolas)        109.13%

   98.3% and 109.1% are the chosen values. The ascent/descent overrides are the
   webfont's own metrics divided by that ratio: Archivo is unitsPerEm 1000,
   ascent 878, descent -210, so 87.8/0.983 and 21.0/0.983. Re-measure with
   tools/qa/font-metrics.mjs if either font is re-subset. */
@font-face {
  font-family: 'Archivo Fallback';
  src: local('Arial'), local('Helvetica'), local('Liberation Sans');
  size-adjust: 98.3%;
  ascent-override: 89.3%;
  descent-override: 21.4%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'JetBrains Mono Fallback';
  src: local('Consolas'), local('Courier New'), local('Liberation Mono');
  size-adjust: 109.1%;
  ascent-override: 93.5%;
  descent-override: 27.5%;
  line-gap-override: 0%;
}

/* ==========================================================================
   03  RESET & BASE
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

* { margin: 0; }

/* The HTML `hidden` attribute must always win. Component rules such as
   `.btn { display: inline-flex }` are author-level and would otherwise beat the
   user-agent's `[hidden] { display: none }`, leaving elements on screen that
   the markup and the JavaScript both believe are hidden. */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchor targets clear the sticky header instead of hiding beneath it. */
  scroll-padding-top: calc(var(--header-h) + var(--s-2));
  /* …and clear the fixed cookie banner at the other end. Without this, tabbing
     to the hero's pause control while the banner is up scrolls it to the bottom
     edge of the viewport — i.e. underneath the banner — and the focus ring is
     invisible. --consent-h is set on :root by consent.js and removed on
     dismissal, so this term is 0 in the ordinary case. */
  scroll-padding-bottom: calc(var(--consent-h, 0px) + var(--s-2));
  -moz-tab-size: 4;
  tab-size: 4;
}

body {
  margin: 0;
  background: var(--c-white);
  color: var(--c-ink);
  font-family: var(--ff-sans);
  font-size: var(--fs-300);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  /* Belt and braces against horizontal scrollbars at 320px. */
  overflow-x: clip;
  min-height: 100vh;
}

img, picture, svg, video, canvas { display: block; max-width: 100%; }
img, video { height: auto; }
svg { flex: none; }

input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; }

p, h1, h2, h3, h4, li, figcaption { overflow-wrap: break-word; }

ul[class], ol[class] { list-style: none; padding: 0; }

table { border-collapse: collapse; }

:target { scroll-margin-top: calc(var(--header-h) + var(--s-2)); }

/* Focus: visible, consistent, never removed. The old site had six buttons with
   no accessible name and no visible focus state at all. */
:focus-visible {
  outline: 2px solid var(--c-accent-ink);
  outline-offset: 2px;
  border-radius: 1px;
}
.on-dark :focus-visible,
.hero :focus-visible { outline-color: var(--c-accent); }
:focus:not(:focus-visible) { outline: none; }

::selection { background: var(--c-primary); color: #fff; }

/* ==========================================================================
   04  TYPOGRAPHY
   ========================================================================== */

h1, h2, h3, h4 {
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
  color: var(--c-heading);
  letter-spacing: -0.015em;
  text-wrap: balance;
}

h1 { font-size: var(--fs-700); }
h2 { font-size: var(--fs-600); }
h3 { font-size: var(--fs-500); letter-spacing: -0.01em; }
h4 { font-size: var(--fs-400); }

p, li { text-wrap: pretty; }

/* Body copy is left-aligned everywhere. `text-align: justify` is never used —
   it opens rivers of whitespace in Serbian, which sets long words. */
p { max-width: var(--measure); }

a { color: var(--c-primary); text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
a:hover { color: var(--c-primary-soft); }
/* :not(.btn) is essential. A bare `.on-dark a { color:#fff }` outranks
   `.btn { color: var(--btn-fg) }` on specificity, so every SOLID white button
   inside a dark section rendered white text on a white background — invisible,
   and a 1:1 contrast failure. It hit the homepage CTA band and the new
   photographic band. Buttons carry their own foreground; links do not. */
.on-dark a:not(.btn) { color: #fff; }

strong, b { font-weight: var(--fw-semibold); }

/* Technical figures — tolerances, dimensions, counts, machine specs. This
   "spec sheet" contrast is what makes the site read as engineering-precise. */
.mono {
  font-family: var(--ff-mono);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.lead {
  font-size: var(--fs-400);
  line-height: 1.55;
  color: var(--c-text-muted);
  max-width: 58ch;
}

.small { font-size: var(--fs-100); }
.muted { color: var(--c-text-muted); }

/* ==========================================================================
   05  LAYOUT PRIMITIVES
   ========================================================================== */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: clamp(1rem, 0.5rem + 2.4vw, 2.5rem);
}

.section { padding-block: var(--section-y); }
.section--surface { background: var(--c-surface); }
.section--dark { background: var(--c-primary-deep); }
.section--tight { padding-block: clamp(2.5rem, 1.5rem + 4vw, 4.5rem); }

.stack > * + * { margin-top: var(--s-3); }
.stack-sm > * + * { margin-top: var(--s-1); }

.visually-hidden:not(:focus):not(:active) {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Skip link — the first focusable element on every page. */
.skip-link {
  position: absolute;
  top: 0; left: 0;
  z-index: 1000;
  display: inline-block;
  padding: var(--s-2) var(--s-3);
  background: var(--c-primary);
  color: #fff;
  font-weight: var(--fw-semibold);
  text-decoration: none;
  transform: translateY(-110%);
  transition: transform var(--dur) var(--ease);
}
.skip-link:focus { transform: translateY(0); color: #fff; }

.hairline { border: 0; border-top: var(--hairline) solid var(--c-rule); }

/* ==========================================================================
   06  BUTTONS & LINKS
   ========================================================================== */

.btn {
  --btn-bg: var(--c-primary);
  --btn-fg: #fff;
  --btn-bd: var(--c-primary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-1);
  min-height: 48px;
  padding: 0.75rem 1.5rem;
  border: var(--hairline) solid var(--btn-bd);
  border-radius: var(--radius);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: var(--fs-200);
  font-weight: var(--fw-semibold);
  line-height: 1.2;
  letter-spacing: 0.01em;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.btn:hover { --btn-bg: var(--c-primary-soft); --btn-bd: var(--c-primary-soft); color: #fff; }
.btn .icon { width: 1.1em; height: 1.1em; }

.btn--ghost { --btn-bg: transparent; --btn-fg: var(--c-primary); --btn-bd: var(--c-border-strong); }
.btn--ghost:hover { --btn-bg: var(--c-surface); --btn-fg: var(--c-primary); --btn-bd: var(--c-primary); }

.btn--on-dark { --btn-bg: #fff; --btn-fg: var(--c-primary); --btn-bd: #fff; }
.btn--on-dark:hover { --btn-bg: var(--c-surface); --btn-fg: var(--c-primary); --btn-bd: var(--c-surface); }

.btn--ghost-dark { --btn-bg: transparent; --btn-fg: #fff; --btn-bd: rgba(255,255,255,.45); }
.btn--ghost-dark:hover { --btn-bg: rgba(255,255,255,.12); --btn-fg: #fff; --btn-bd: #fff; }

.btn--sm { min-height: 40px; padding: 0.5rem 1rem; font-size: var(--fs-100); }

/* Text link with a trailing arrow that nudges on hover. */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  font-size: var(--fs-200);
  font-weight: var(--fw-semibold);
  color: var(--c-primary);
  text-decoration: none;
  border-bottom: 1px solid var(--c-border-strong);
  padding-bottom: 2px;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.link-arrow:hover { color: var(--c-primary-soft); border-bottom-color: var(--c-primary-soft); }
.link-arrow .icon { width: 1.05em; height: 1.05em; transition: transform var(--dur) var(--ease); }
.link-arrow:hover .icon { transform: translateX(3px); }
.on-dark .link-arrow { color: #fff; border-bottom-color: rgba(255,255,255,.4); }
.on-dark .link-arrow:hover { border-bottom-color: #fff; }

/* ==========================================================================
   07  HEADER, NAVIGATION, MOBILE MENU
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: var(--c-white);
  border-bottom: var(--hairline) solid var(--c-line);
  transition: box-shadow var(--dur) var(--ease);
}
/* Shadow appears only once the page has moved — flat at rest. */
.site-header[data-scrolled='true'] { box-shadow: 0 1px 12px rgba(20, 23, 31, 0.08); }

.header__inner {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-height: var(--header-h);
}

.header__logo { display: flex; align-items: center; flex: none; text-decoration: none; }
/* Sized by height with width:auto so the intrinsic ratio from the width/height
   attributes still reserves the box and nothing shifts. */
.header__logo img { width: auto; height: 36px; object-fit: contain; }

/* The nav and the language switcher form one right-aligned cluster, so the row
   reads logo-left / everything-else-right instead of leaving a dead gap in the
   middle where the quote button used to sit.
   min-width:0 lets the nav shrink below its min-content width instead of
   forcing the header row wider than the viewport. */
.header__nav { flex: 0 1 auto; min-width: 0; margin-left: auto; }

.nav__list {
  display: flex;
  align-items: center;
  gap: clamp(0.25rem, -0.5rem + 1.4vw, 1rem);
  margin: 0;
  list-style: none;
  padding: 0;
}

.nav__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: calc((var(--header-h) - 24px) / 2) 0.5rem;
  font-size: var(--fs-200);
  font-weight: var(--fw-medium);
  color: var(--c-ink);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--dur) var(--ease);
}
.nav__link:hover { color: var(--c-primary); }

/* Current page: a 2px accent underline, plus aria-current in the markup. */
/* A product sub-page lights up its parent too (data-section-current), but only
   the page itself carries aria-current — the parent is not the current page. */
.nav__link[aria-current='page'], .nav__link[data-section-current='true'] { color: var(--c-primary); font-weight: var(--fw-semibold); }
.nav__link[aria-current='page']::after, .nav__link[data-section-current='true']::after {
  content: '';
  position: absolute;
  left: 0.5rem; right: 0.5rem; bottom: 14px;
  height: 2px;
  background: var(--c-accent);
}

.nav__item { position: relative; }

/* --- Desktop dropdown ---------------------------------------------------
   Opens on hover AND on :focus-within, so it is fully keyboard operable with
   no JavaScript at all. nav.js layers click-toggling and Escape on top. */
.nav__panel {
  position: absolute;
  top: 100%;
  left: -0.5rem;
  z-index: 10;
  min-width: 22rem;
  padding: var(--s-1);
  background: var(--c-white);
  border: var(--hairline) solid var(--c-line);
  border-radius: var(--radius);
  box-shadow: 0 6px 28px rgba(20, 23, 31, 0.10);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease), visibility var(--dur);
  list-style: none;
  margin: 0;
}
.nav__item:hover > .nav__panel,
.nav__item:focus-within > .nav__panel,
.nav__item > .nav__panel[data-open='true'] {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.nav__panel a {
  display: block;
  padding: 0.7rem 0.85rem;
  border-radius: var(--radius);
  color: var(--c-ink);
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease);
}
.nav__panel a:hover { background: var(--c-surface); }
.nav__panel a[aria-current='page'] { background: var(--c-surface); }
.nav__panel-title { display: block; font-size: var(--fs-200); font-weight: var(--fw-semibold); color: var(--c-primary); }
.nav__panel-desc { display: block; font-size: var(--fs-100); color: var(--c-ink-muted); line-height: 1.45; margin-top: 2px; }

.nav__caret { transition: transform var(--dur) var(--ease); width: 16px; height: 16px; }
.nav__item:hover .nav__caret,
.nav__item:focus-within .nav__caret { transform: rotate(180deg); }

/* Holds the language switcher and, below 1024px, the hamburger. Nothing else:
   no phone number, no quote button. */
.header__actions { display: flex; align-items: center; gap: var(--s-1); flex: none; }

/* --- Language switcher — visible at EVERY breakpoint, never in a menu ---
   It is now the last thing in the row, so the trailing 4px of link padding is
   pulled back and the "EN" glyph sits on the same gutter as the nav above and
   the content below. A hairline separates it from the nav on desktop. */
.lang {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-right: -4px;
  font-family: var(--ff-mono);
  font-size: var(--fs-100);
  font-weight: var(--fw-medium);
}
@media (min-width: 1024px) {
  .header__actions > .lang { padding-left: var(--s-2); border-left: var(--hairline) solid var(--c-line); }
}
.lang__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  min-height: 34px;
  padding: 0 4px;
  border-radius: var(--radius);
  color: var(--c-ink-muted);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}
.lang__link:hover { color: var(--c-primary); background: var(--c-surface); }
.lang__link[aria-current] { color: var(--c-primary); font-weight: var(--fw-bold); }
/* Measured at 1.63:1 as --c-line-strong, effectively invisible to a low-vision
   reader even though it is aria-hidden. Muted ink is 7.0:1 and still reads as
   punctuation rather than as a third link. */
.lang__sep { color: var(--c-ink-muted); }

/* --- Hamburger: below 1024px ONLY ---------------------------------------
   The old site hid the entire menu behind a hamburger even at 1424px wide. */
.burger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: var(--hairline) solid var(--c-line);
  border-radius: var(--radius);
  color: var(--c-primary);
}
.burger:hover { background: var(--c-surface); }

/* --- Mobile menu panel --- */
.mobile-menu {
  position: fixed;
  inset: var(--header-h) 0 0 0;
  z-index: var(--z-menu);
  display: flex;
  flex-direction: column;
  background: var(--c-white);
  border-top: var(--hairline) solid var(--c-line);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* padding-block, not the shorthand: this element is also a .wrap, and a
     horizontal 0 here was erasing the 16px side gutter on phones. */
  padding-block: var(--s-3) var(--s-6);
}
.mobile-menu[hidden] { display: none; }

.mobile-menu__list { list-style: none; margin: 0; padding: 0; }
.mobile-menu__list > li { border-bottom: var(--hairline) solid var(--c-line); }

.mobile-menu__link {
  display: block;
  padding: var(--s-2) 0;
  font-size: var(--fs-400);
  font-weight: var(--fw-medium);
  color: var(--c-ink);
  text-decoration: none;
}
.mobile-menu__link[aria-current='page'] { color: var(--c-primary); font-weight: var(--fw-semibold); }

.mobile-menu__row { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); }
.mobile-menu__toggle {
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; flex: none;
  color: var(--c-primary);
  border-left: var(--hairline) solid var(--c-line);
}
.mobile-menu__toggle .icon { transition: transform var(--dur) var(--ease); }
.mobile-menu__toggle[aria-expanded='true'] .icon { transform: rotate(180deg); }

.mobile-menu__sub { list-style: none; margin: 0; padding: 0 0 var(--s-2) var(--s-2); }
.mobile-menu__sub[hidden] { display: none; }
.mobile-menu__sub a {
  display: block;
  padding: 0.6rem 0;
  font-size: var(--fs-200);
  color: var(--c-ink-muted);
  text-decoration: none;
}
.mobile-menu__sub a:hover { color: var(--c-primary); }

/* Staggered reveal, capped at 200ms total. */
.mobile-menu[data-animate='true'] .mobile-menu__list > li {
  animation: menu-in 200ms var(--ease) backwards;
}
.mobile-menu[data-animate='true'] .mobile-menu__list > li:nth-child(1) { animation-delay: 20ms; }
.mobile-menu[data-animate='true'] .mobile-menu__list > li:nth-child(2) { animation-delay: 45ms; }
.mobile-menu[data-animate='true'] .mobile-menu__list > li:nth-child(3) { animation-delay: 70ms; }
.mobile-menu[data-animate='true'] .mobile-menu__list > li:nth-child(4) { animation-delay: 95ms; }
.mobile-menu[data-animate='true'] .mobile-menu__list > li:nth-child(5) { animation-delay: 120ms; }
.mobile-menu[data-animate='true'] .mobile-menu__list > li:nth-child(6) { animation-delay: 145ms; }
.mobile-menu[data-animate='true'] .mobile-menu__list > li:nth-child(7) { animation-delay: 170ms; }
@keyframes menu-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

body[data-menu-open='true'] { overflow: hidden; }

/* --- Language suggestion bar (dismissible, never a redirect) --- */
.lang-suggest {
  background: var(--c-surface);
  border-bottom: var(--hairline) solid var(--c-line);
  font-size: var(--fs-100);
}
/* Hidden by default and revealed by the class the inline head script sets,
   so the bar is present in the FIRST layout rather than inserted after paint.
   With no JavaScript the class is never added and the bar never shows. */
.lang-suggest { display: none; }
.suggest-lang .lang-suggest { display: block; }
.lang-suggest[hidden] { display: none !important; }
.lang-suggest__inner { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; padding-block: 0.6rem; }
.lang-suggest__dismiss { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; margin-left: auto; color: var(--c-ink-muted); }
.lang-suggest__dismiss:hover { color: var(--c-ink); }

/* Between 1024 and 1279 the full navigation is still shown, so it is tightened
   rather than hidden: the old site collapsed everything into a hamburger even
   at 1424px, which is the behaviour this breakpoint exists to avoid. */
/* Between 1024 and 1279 the row is at its tightest: seven nav items, the
   switcher and the logo. Dropping the phone and the quote button bought back
   roughly 260px here, so the links no longer have to shed their padding
   entirely — they keep readable spacing instead. */
@media (max-width: 1279px) {
  .header__logo img { height: 32px; }
  .nav__list { gap: 2px; }
  .nav__link { padding-inline: 0.45rem; font-size: var(--fs-100); }
}
@media (max-width: 1023px) {
  .header__nav { display: none; }
  .burger { display: inline-flex; }
  /* With the nav gone the switcher would collapse onto the logo; push it out. */
  .header__actions { margin-left: auto; }
}
@media (max-width: 420px) {
  .header__logo img { height: 26px; }
}
@media (min-width: 1024px) {
  .mobile-menu { display: none !important; }
}

/* Without JavaScript there is no hamburger behaviour, so the full navigation
   is shown inline and wraps. Nothing is ever unreachable. */
.no-js .burger { display: none; }
.no-js .header__nav { display: block; }
.no-js .nav__list { flex-wrap: wrap; }
@media (max-width: 1023px) {
  .no-js .header__inner { flex-wrap: wrap; padding-block: var(--s-1); }
  .no-js .nav__link { padding-block: 0.5rem; }
  .no-js .nav__panel { position: static; opacity: 1; visibility: visible; transform: none; box-shadow: none; border: 0; min-width: 0; padding-left: var(--s-2); }
}

/* ==========================================================================
   08  HERO SLIDER
   --------------------------------------------------------------------------
   The old site's hero rendered as a blank white rectangle because a background
   video failed and the white text had no fallback. Three defences here:
     1. --c-primary-deep is painted on the section itself, so even with every
        image blocked the hero is a solid navy panel with legible white text.
     2. Every slide carries a gradient scrim between media and text.
     3. Slide 1 is marked is-active in the HTML, so it shows without JS.
   ========================================================================== */

.hero {
  position: relative;
  display: grid;
  /* The sticky header sits ABOVE the hero in flow, so a literal 100svh hero
     would push its own bottom 72px past the fold — taking the slider controls
     and the WCAG-required pause button off screen. Filling the REMAINING
     viewport is what "full-viewport hero" actually means here.
     100vh first as the fallback; svh wins where supported and stops mobile
     browser chrome from causing the jump the old site had. */
     ---------------------------------------------------------------------
     min-height, NEVER height. With a fixed height the vertically-centred copy
     overflows its own box on short laptop viewports and spills over the slider
     controls pinned to the bottom — measured at 768x1024, 1024x768, 1024x900,
     1280x800 and 1440x900, where the CTA row landed directly on top of the
     WCAG-required pause button. Letting the section grow past the fold instead
     costs a little scrolling on a 13" screen and cannot ever bury a control.
     The ladder is: at least 600px, otherwise the remaining viewport, capped at
     1100px so a tall desktop monitor does not get an absurd banner. */
  min-height: max(600px, min(calc(100vh - var(--header-h)), 1100px));
  min-height: max(600px, min(calc(100svh - var(--header-h)), 1100px));
  background: var(--c-primary-deep);
  isolation: isolate;
  overflow: hidden;
}

.hero__slides { display: grid; grid-template-areas: 'stack'; }
.hero__slides > * { grid-area: stack; }

.hero__slide {
  position: relative;
  display: grid;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-slide) var(--ease), visibility var(--dur-slide);
}
.hero__slide.is-active { opacity: 1; visibility: visible; }

.hero__media { position: absolute; inset: 0; overflow: hidden; }
.hero__media picture { display: contents; }
.hero__media img,
.hero__media video {
  width: 100%;
  height: 100%;
  /* object-position is set inline per slide, from the content JSON, so each
     subject stays in frame from 21:9 down to a 9:16 phone. */
  object-fit: cover;
  object-position: 50% 50%;
  transform: scale(1);
  transition: transform var(--dur-slide) var(--ease);
}
.hero__slide.is-active .hero__media img,
.hero__slide.is-active .hero__media video { transform: scale(1.04); }

/* Scrim: sits between media and text on EVERY slide, image or video.
   ========================================================================
   TWO LAYERS, NOT ONE, AND THE REASON MATTERS.

   This used to be a single wash of brand navy, rgb(26 35 76), at 0.92-0.96
   across the left and centre of the frame. That does not darken a photograph,
   it repaints it: machined steel is neutral grey, and measured over the left
   60% of the hero at 1440x900 the result had mean saturation 0.58 and a
   blue-minus-red of +45 levels, against +8 in the client's own master file.
   The picture was not dark, it was blue.

   So the darkening and the brand are now separate jobs done by separate
   layers, and each can be tuned without the other:

     --scrim-ink    a near-neutral dark, rgb(14 17 24). Does ALL the
                    darkening, through the four gradient stops below.
     --scrim-brand  the brand navy, applied flat at --scrim-tint (0.10-0.14),
                    purely so the hero still reads as belonging to the brand.

   THE FOUR STOPS are per-slide custom properties set from the content JSON,
   because the three photographs are not equally bright: the finished assembly
   was shot against a white wall on a pale concrete floor and needs materially
   more cover than the machining close-up.

     near   the left edge, behind the copy
     mid    out to 66% of the frame, where the copy column ends
     far    the falloff
     edge   the right edge, nothing but photograph
     mobile a near-uniform vertical wash used below 1200px

   near and mid are NOT held high to protect the copy any more. That was the
   mistake behind two failed brightening passes: the copy occupies a column,
   not the frame, so covering the frame to protect the column buried the
   photograph everywhere the client was actually looking. The copy now carries
   its own contrast, locally — see .hero__content::before further down.

   The defaults below are the values for the darkest of the three slides, so a
   slide that forgets to declare its own still lands somewhere safe. Every stop
   is verified against the actual composited pixels of its own photograph — see
   tools/qa/hero-contrast.mjs — never estimated from the flat colour, and the
   whole-frame effect is measured by tools/qa/overlay-metrics.mjs. */
.hero__scrim {
  position: absolute;
  inset: 0;
  --scrim-ink: 16 19 26;
  --scrim-brand: 38 51 110;
  background:
    /* 1. brand tint, flat and thin, on top */
    linear-gradient(0deg,
      rgb(var(--scrim-brand) / var(--scrim-tint, 0.12)) 0%,
      rgb(var(--scrim-brand) / var(--scrim-tint, 0.12)) 100%),
    /* 2. the neutral darkening */
    linear-gradient(180deg,
      rgb(var(--scrim-ink) / var(--scrim-near, 0.64)) 0%,
      rgb(var(--scrim-ink) / var(--scrim-mobile, 0.66)) 55%,
      rgb(var(--scrim-ink) / var(--scrim-mobile, 0.66)) 100%);
}

/* The horizontal falloff only switches on where it is SAFE.
   ------------------------------------------------------------------------
   The .wrap is capped at 78rem, so above 1200px the copy column can never
   extend past ~65% of the viewport however wide the window gets: 65% at
   1200px, 62% at 1280px, 60% at 1440px, 58% at 1920px. Holding the gradient
   at full strength to 66% therefore covers every line of text at every width
   in this range, and the last third of the frame is free to open up and show
   the photograph.
   Below 1200px the same column runs to ~86% of the viewport — the copy would
   reach the thin end of the gradient and sit on a near-white stop — so the
   uniform wash above is kept instead. It is heavier, but no line of text can
   ever drift somewhere illegible, which is the whole point of the scrim. */
@media (min-width: 1200px) {
  .hero__scrim {
    background:
      linear-gradient(0deg,
        rgb(var(--scrim-brand) / var(--scrim-tint, 0.12)) 0%,
        rgb(var(--scrim-brand) / var(--scrim-tint, 0.12)) 100%),
      linear-gradient(100deg,
        rgb(var(--scrim-ink) / var(--scrim-near, 0.64)) 0%,
        rgb(var(--scrim-ink) / var(--scrim-mid, 0.46)) 66%,
        rgb(var(--scrim-ink) / var(--scrim-far, 0.32)) 82%,
        rgb(var(--scrim-ink) / var(--scrim-edge, 0.18)) 100%),
      /* A shallow foot, so the slider controls keep a floor to sit on without
         the whole lower third of the frame being paid for. It is 22% deep and
         neutral; the controls' own backdrops do the rest. */
      linear-gradient(to top, rgb(var(--scrim-ink) / 0.34) 0%, rgb(var(--scrim-ink) / 0) 20%);
  }
}

.hero__body {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  width: 100%;
  /* Hoisted into custom properties so the breakpoint below can retune them in
     one place. There is deliberately NO consent-banner term here any more.
     An earlier version grew this padding by --consent-h under a
     `body[data-consent-open]` override, which caused two separate defects:
     the override was (0,2,1) specific and beat the (0,1,0) max-width:700px
     rule, so a phone with the banner open silently reverted to the DESKTOP
     144px bottom padding; and growing the hero after first paint is a real
     layout shift, measured at 0.094 CLS on the homepage.
     The banner is position:fixed and now takes part in no layout at all, so
     showing or dismissing it reflows nothing. The only thing that still reacts
     to it is .hero__controls, and it does so by transform. */
  --hero-pad-top: calc(var(--header-h) + var(--s-5));
  --hero-pad-bottom: calc(var(--s-8) + var(--s-2));
  padding-block: var(--hero-pad-top) var(--hero-pad-bottom);
}

/* The copy carries its own contrast, so the frame does not have to.
   ------------------------------------------------------------------------
   A plate bound to the copy column and feathered out to nothing well before
   the edges of the viewport. This is what makes a near/mid of 0.58-0.64
   possible: the text sits on ~0.80 of near-black where it needs to, and the
   photograph is clear everywhere else — including the left third of the frame,
   above the kicker and below the buttons, which is most of what a visitor
   actually sees.

   Elliptical rather than rectangular on purpose: a rectangle with a soft edge
   still reads as a panel, and the corners of the region are exactly where the
   photograph should be showing. The centre is at 34% so the densest part sits
   under the first words of each line rather than in the middle of the block. */
.hero__content {
  position: relative;
  max-width: 46rem;
}
.hero__content::before {
  content: '';
  position: absolute;
  z-index: -1;
  /* The ellipse must reach zero INSIDE its own box, or the box clips it while
     it still has colour and the plate reads as a rectangle with a hard edge
     drawn across the photograph. The first attempt did exactly that: sized at
     112% x 104% with the last stop at 84%, it ran past the right, top and
     bottom edges and the seam was plainly visible in the render.
     The LEFT inset is deliberately huge and asymmetric. At 1440px the .wrap
     puts the copy column's left edge at about x=120, so a symmetric -120px
     inset landed the box edge at x=0 — the viewport edge — with the ellipse
     still at meaningful alpha, and the render showed a hard vertical seam
     right down the left of the frame. Pushing the box 320px left moves that
     edge off screen at every width; the ellipse itself is unchanged.

     Geometry, in a 1176px-wide box starting near x=-200: centre 45%, radii 47%
     and 48%. Horizontally it reaches zero at x=882 — just past the right of the
     copy column — and 24px beyond the left box edge, which is off screen.
     Vertically it stays inside top and bottom with room to spare. Pulling the
     right-hand radius in is worth real luminance: it is that tail, not the copy
     itself, that darkens the part of the frame with no text on it. */
  inset: -140px -120px -140px -320px;
  pointer-events: none;
  /* A plateau, then a fast feather — not a smooth falloff from the centre.
     A plain radial ramp put the kicker and the paragraph, which sit at the top
     and bottom of the copy block, out on the thin part of the curve: they
     measured 4.09:1 and 3.72:1. Holding full strength to 52% of the radius
     covers the whole copy block evenly and spends the fade on the empty
     margin instead. */
  background: radial-gradient(47% 48% at 45% 50%,
    rgb(8 11 18 / 0.82) 0%,
    rgb(8 11 18 / 0.80) 64%,
    rgb(8 11 18 / 0.52) 84%,
    rgb(8 11 18 / 0.16) 94%,
    rgb(8 11 18 / 0) 100%);
}

/* Below 1200px the copy runs to ~86% of the viewport and the vertical wash is
   doing the work, so the plate would be both redundant and nearly full-width.
   It tightens to a light lift instead. */
@media (max-width: 1199px) {
  .hero__content::before {
    /* Same trap as the desktop plate, at both edges this time: below 1200px the
       copy runs to ~86% of the viewport, so a -80px inset put BOTH box edges
       just inside the frame. The box now overhangs by 200px a side. */
    inset: -120px -200px;
    background: radial-gradient(49% 50% at 50% 50%,
      rgb(8 11 18 / 0.72) 0%,
      rgb(8 11 18 / 0.68) 56%,
      rgb(8 11 18 / 0.32) 80%,
      rgb(8 11 18 / 0.10) 93%,
      rgb(8 11 18 / 0) 100%);
  }
}

.hero__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  font-family: var(--ff-mono);
  font-size: var(--fs-100);
  font-weight: var(--fw-medium);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  /* Pure white, not the near-white this used to be. With the scrim down at
     0.34-0.43 the plate is doing the work, and #E4E8F4 allows a background of
     only 105 against white's 118 — thirteen levels that have to come from
     somewhere, and taking them from the plate darkens the frame for everyone. */
  color: #fff;
  text-shadow: 0 1px 2px rgb(8 11 18 / 0.40), 0 0 16px rgb(8 11 18 / 0.70);
}
/* The rule keeps the brass note; the LABEL is near-white because gold text at
   14px cannot reach 4.5:1 over imagery at any workable scrim opacity. */
.hero__eyebrow::before { content: ''; width: 28px; height: 2px; background: var(--c-accent-on-dark); }

/* The shadow is structural, not decorative.
   ------------------------------------------------------------------------
   The plate feathers out before the longest headline line ends, and the last
   two words measured 2.84:1 against a 3:1 requirement over the brightest part
   of the lathe. A wide, soft, low-offset shadow darkens the few square
   centimetres immediately around the glyphs and nothing else, which is exactly
   the area the measurement cares about. At 100% zoom it does not read as a
   shadow — there is no visible offset and no edge, only slightly deeper
   background right at the type. The alternative was widening the plate across
   another 200px of frame, which is the thing this whole change is undoing. */
.hero__title {
  margin-top: var(--s-3);
  font-size: var(--fs-800);
  line-height: var(--lh-tight);
  letter-spacing: -0.025em;
  color: #fff;
  text-shadow: 0 1px 2px rgb(8 11 18 / 0.50), 0 0 30px rgb(8 11 18 / 0.90);
}

.hero__sub {
  margin-top: var(--s-3);
  /* 36rem, not the 44rem this used to be. The plate's horizontal plateau ends
     around x=674 at 1440px; a 44rem paragraph ran to 816 and its last words sat
     out on the feathered tail, measuring 4.07:1 at 1920px. A shorter measure
     fixes that at the source AND is better typography — 44rem of 20px text is
     a ~95-character line, well past comfortable. */
  max-width: 36rem;
  font-size: var(--fs-400);
  line-height: 1.55;
  color: #fff;             /* see .hero__eyebrow for why this is not #E4E8F4 */
  text-shadow: 0 1px 2px rgb(8 11 18 / 0.40), 0 0 18px rgb(8 11 18 / 0.70);
}

.hero__actions { margin-top: var(--s-4); display: flex; flex-wrap: wrap; gap: var(--s-2); }

/* --- Controls ---------------------------------------------------------- */
.hero__controls {
  position: absolute;
  z-index: 2;
  left: 0; right: 0;
  bottom: calc(var(--s-4) + env(safe-area-inset-bottom, 0px));
  pointer-events: none;
  /* WCAG 2.2.2: the carousel auto-advances in every consent state, so the pause
     control must stay AVAILABLE while the cookie banner is up. Deliberately, it
     is not moved to achieve that.

     Moving it was tried twice and both ways are worse. Lifting it with `bottom`
     (and growing the hero to match) is what measured 0.094 CLS on the homepage.
     Lifting it with `transform` costs no CLS but has to be clamped against the
     hero's own CTA row, and measurement showed the clamp bites at every width
     but 1920: the control ends up moved, crowding the buttons, and STILL behind
     the banner. Motion with no benefit.

     So the banner covers it on first view, and it is reached by a short scroll
     or by keyboard — see scroll-padding-bottom on :root, which is what keeps
     the focus ring from landing underneath the banner. The banner is also one
     click from gone. See REPORT.md 2.4. */
}
.hero__controls-inner { display: flex; align-items: center; gap: var(--s-2); pointer-events: auto; }

/* Numbered indicators in mono — "01 / 02 / 03", not vague dots. */
/* The numbered indicators carry their own backdrop for the same reason the
   arrows do, and it is new: with the scrim down at 0.42-0.50 the bottom-left of
   the frame is photograph, and translucent white numerals on photograph
   measured 2.88:1. A 62% neutral plate puts the inactive ones back over 5:1
   without the frame paying for it. Neutral, not navy — a navy chip here would
   put the blue cast back exactly where the eye is drawn to it. */
.hero__tabs {
  display: flex;
  align-items: center;
  gap: 4px;
  /* Vertical padding is load-bearing, not spacing: the active indicator's 2px
     brass underline is a control boundary under WCAG 1.4.11, and with no
     padding it sat flush against the bottom of the plate, i.e. against bare
     photograph, at 2.73:1. Six pixels of plate below it is what puts it over
     3:1 without darkening the frame. */
  padding: 6px 8px;
  border-radius: var(--radius);
  background: rgb(8 11 18 / 0.62);
}
.hero__tab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 6px;
  font-family: var(--ff-mono);
  font-size: var(--fs-100);
  font-weight: var(--fw-medium);
  color: rgba(255, 255, 255, 0.62);
  border-bottom: 2px solid rgba(255, 255, 255, 0.28);
  border-radius: 0;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.hero__tab:hover { color: #fff; border-bottom-color: rgba(255, 255, 255, 0.7); }
.hero__tab[aria-current='true'] { color: #fff; border-bottom-color: var(--c-accent-on-dark); }

/* WCAG 2.2.2: auto-moving content needs a visible pause control.
   The arrows sit at ~85% of the frame, which is exactly where the scrim is
   thinnest and the photograph brightest. Rather than darkening the whole
   gradient to protect two 44px buttons — which would bury the photography the
   client paid for — each control carries its own backdrop. Over the worst case,
   pure white, a 62% plate leaves the white glyph past 4.5:1 and its 1px boundary
   past the 3:1 that WCAG 1.4.11 asks of a control.
   The plate is NEUTRAL, rgb(8 11 18), not brand navy: these sit over bare
   photograph now, and a navy chip would reintroduce the blue cast on the one
   part of the frame the eye is drawn to. */
.hero__playpause,
.hero__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  color: #fff;
  background: rgb(8 11 18 / 0.62);
  /* 0.9, not the 0.55 this used to be. The boundary is measured against what is
     immediately OUTSIDE the control, and outside is now photograph rather than
     a heavy scrim — at 0.55 the composited border fell to 1.99:1 against a
     bright patch. */
  border: 1px solid rgba(255, 255, 255, 0.9);
  border-radius: var(--radius);
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.hero__playpause:hover,
.hero__arrow:hover { background: rgb(26 35 76 / 0.92); border-color: #fff; }

.hero__arrows { display: flex; gap: 4px; margin-left: auto; }
.hero__arrow--prev .icon { transform: rotate(180deg); }

/* Media failure fallback. slider.js sets data-media-failed on any `error`
   event; hiding the media layer reveals the solid --c-primary-deep painted on
   .hero itself, so the text stays legible and the hero is never blank. This is
   the exact failure that left the old site's hero a white rectangle. */
.hero__slide[data-media-failed] .hero__media { display: none; }

/* Poster play button, created by slider.js only when autoplay is withheld
   (reduced motion, Save-Data, 2g, or a rejected play() promise). */
.hero__playposter {
  position: absolute;
  z-index: 2;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  padding: 0.75rem 1.25rem;
  background: rgba(26, 35, 76, 0.82);
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: var(--radius);
  color: #fff;
  font-size: var(--fs-200);
  font-weight: var(--fw-semibold);
}
.hero__playposter:hover { background: rgba(26, 35, 76, 0.95); }

/* Slider controls do nothing without JS, so they are not shown. */
.no-js .hero__controls { display: none; }

@media (max-width: 700px) {
  .hero { min-height: 560px; }
  .hero__arrows { display: none; }
  /* Two buttons on one row, not stacked. Worth 64px of hero height, which on a
     375x667 phone is the difference between the pause control being on screen
     and being scrolled off it. */
  .hero__actions { margin-top: var(--s-3); gap: var(--s-1); }
  .hero__actions .btn { flex: 1 1 0; min-width: 0; padding-inline: var(--s-2); }
  /* The desktop hero is generously padded; at phone size that padding is just
     empty navy pushing the WCAG 2.2.2 pause control below the fold. */
  /* The bottom padding must clear the controls strip: 44px of button + a 32px
     offset + a 16px gap. Anything less and the CTA row lands on the pause
     button again, which is exactly what happened at 375px with 64px here. */
  /* --hero-pad-top no longer carries --header-h: the header is sticky and
     already takes its 72px out of normal flow, so the hero starts below it and
     that term was 72px of dead navy. Reclaiming it is most of the headroom that
     brings the pause control back above the fold on a 667px-tall phone.
     --hero-pad-bottom must stay >= the controls strip: 44px button + a 32px
     offset + a gap. 96px is the floor, not a preference. */
  .hero__body { --hero-pad-top: var(--s-4); --hero-pad-bottom: var(--s-7); }
  .hero__title { margin-top: var(--s-2); }
  .hero__sub { margin-top: var(--s-2); }
  /* Indent clear of the assistant launcher, which is pinned bottom-left at the
     same height. Without this the launcher sits on top of the pause control —
     and the pause control is a WCAG 2.2.2 requirement, not decoration. */
  .hero__controls-inner { padding-left: calc(var(--floating-size) + var(--s-1)); }
}

/* ==========================================================================
   09  FACT BAR
   --------------------------------------------------------------------------
   A slim horizontal band, not a card grid. The first thing read after the
   hero, so it is pure substance.
   ========================================================================== */

.factbar { background: var(--c-primary); color: #fff; }
.factbar__list {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  list-style: none;
  margin: 0;
  padding: 0;
}
.factbar__item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--s-3) var(--s-2);
  border-left: 1px solid rgba(255, 255, 255, 0.16);
}
.factbar__item:first-child { border-left: 0; padding-left: 0; }
.factbar__value {
  font-family: var(--ff-mono);
  font-size: var(--fs-200);
  font-weight: var(--fw-medium);
  letter-spacing: 0.02em;
  color: #fff;
}
.factbar__label {
  font-size: var(--fs-100);
  color: #C7CFE6;     /* 7.6:1 on --c-primary */
  line-height: 1.35;
}

@media (max-width: 860px) {
  .factbar__list { grid-template-columns: repeat(2, 1fr); }
  .factbar__item:nth-child(odd) { border-left: 0; padding-left: 0; }
  .factbar__item:nth-child(n+3) { border-top: 1px solid rgba(255,255,255,.16); }
}
@media (max-width: 400px) {
  .factbar__list { grid-template-columns: 1fr; }
  .factbar__item { border-left: 0; padding-left: 0; }
  .factbar__item + .factbar__item { border-top: 1px solid rgba(255,255,255,.16); }
}

/* ==========================================================================
   10  SECTION FURNITURE
   ========================================================================== */

.eyebrow {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  font-family: var(--ff-mono);
  font-size: var(--fs-100);
  font-weight: var(--fw-medium);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--c-accent-ink);
}
.eyebrow::before { content: ''; width: 28px; height: 2px; background: var(--c-accent); flex: none; }
.on-dark .eyebrow { color: var(--c-accent-on-dark); }

.section__head { max-width: 52rem; margin-bottom: var(--s-5); }
.section__head h2 { margin-top: var(--s-2); }
.section__head .lead { margin-top: var(--s-2); }

.section__foot { margin-top: var(--s-5); }

/* ==========================================================================
   11  HOME SECTIONS
   ========================================================================== */

/* --- Intro: copy beside a spec aside --- */
.intro__grid { display: grid; gap: var(--s-5); }
@media (min-width: 900px) {
  .intro__grid { grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr); gap: var(--s-7); align-items: start; }
}
.intro__body > p + p { margin-top: var(--s-2); }

.intro__media {
  margin-bottom: var(--s-3);
  border: var(--hairline) solid var(--c-line);
  border-radius: var(--radius);
  overflow: hidden;
}
.intro__media img { width: 100%; height: auto; }

.intro__aside dl {
  display: grid;
  gap: 0;
  margin: 0;
  /* The accent rule belongs to the spec list, not to the photograph above it. */
  border-top: 2px solid var(--c-accent);
  padding-top: var(--s-1);
}
.intro__aside .row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s-2);
  padding: 0.7rem 0;
  border-bottom: var(--hairline) solid var(--c-line);
}
.intro__aside dt { font-size: var(--fs-100); color: var(--c-ink-muted); }
.intro__aside dd { margin: 0; font-family: var(--ff-mono); font-size: var(--fs-200); font-weight: var(--fw-medium); color: var(--c-primary); text-align: right; }

/* --- Services: numbered cards, 1px borders, no shadows --- */
/* 20rem min forces three columns at the 1248px wrap, so the five services lay
   out as 3 + 2 rather than 4 + 1 with a hole in the second row. */
.cards {
  display: grid;
  gap: var(--s-2);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding: var(--s-3);
  background: var(--c-white);
  border: var(--hairline) solid var(--c-line);
  border-radius: var(--radius);
  transition: border-color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.card:hover { border-color: var(--c-primary); }
.card__top { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); }
.card__num { font-family: var(--ff-mono); font-size: var(--fs-100); font-weight: var(--fw-medium); color: var(--c-accent-ink); letter-spacing: 0.1em; }
.card__icon { width: 30px; height: 30px; color: var(--c-primary); stroke-width: 1.4; }
.card h3 { font-size: var(--fs-400); }
.card p { font-size: var(--fs-200); color: var(--c-ink-muted); max-width: none; margin: 0; }
.card__link { margin-top: auto; padding-top: var(--s-1); }

/* Whole-card click target, without nesting interactive elements. */
.card__stretch::after { content: ''; position: absolute; inset: 0; border-radius: var(--radius); }

/* --- Card media -----------------------------------------------------------
   Cards with an image slot lose the top padding so the picture meets the
   border, and the aspect ratio is fixed at 4:3 to match the derivatives the
   image pipeline cuts for this role. The ratio is declared here as well as on
   the <img> so the box is reserved even before the manifest-derived
   width/height attributes are used — CLS on this page must stay at zero. */
.cards--media .card { padding: 0 var(--s-3) var(--s-3); }
.card__media {
  margin: 0 calc(-1 * var(--s-3));
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-bottom: var(--hairline) solid var(--c-line);
  background: var(--c-surface);
}
.card__media img { width: 100%; height: 100%; object-fit: cover; }

/* --- Split: copy beside a supporting photograph --------------------------- */
.split { display: grid; gap: var(--s-4); align-items: center; }
@media (min-width: 900px) {
  .split { grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); gap: var(--s-6); }
}
.split__body .section__head { margin-bottom: 0; }
.split__media { border: var(--hairline) solid var(--c-line); border-radius: var(--radius); overflow: hidden; }
.split__media img { width: 100%; height: auto; }
.split + .table-scroll { margin-top: var(--s-5); }

/* --- Full-width photographic band ---------------------------------------- */
.photoband {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--c-primary-deep);
}
.photoband__media { position: absolute; inset: 0; }
.photoband__media picture { display: contents; }
.photoband__media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 45%; }
/* Heavier and flatter than the hero scrim: the statement runs the full width
   of the band, so there is no safe thin end to fade towards. */
.photoband__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, rgb(26 35 76 / 0.93) 0%, rgb(26 35 76 / 0.88) 55%, rgb(26 35 76 / 0.72) 100%);
}
.photoband__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-3);
  padding-block: clamp(3rem, 2rem + 4vw, 5rem);
}
.photoband__statement {
  max-width: 40rem;
  font-size: var(--fs-600);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
  letter-spacing: -0.015em;
  color: #fff;
}

/* --- Why: four numbered pillars on hairlines --- */
.pillars {
  display: grid;
  gap: var(--s-4) var(--s-5);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
}
.pillar { border-top: 2px solid var(--c-primary); padding-top: var(--s-2); }
.pillar__num { font-family: var(--ff-mono); font-size: var(--fs-100); color: var(--c-accent-ink); letter-spacing: 0.1em; }
.pillar h3 { margin-top: var(--s-1); font-size: var(--fs-400); }
.pillar p { margin-top: var(--s-1); font-size: var(--fs-200); color: var(--c-ink-muted); max-width: none; }

/* --- PET highlight --- */
.pet__body p + p { margin-top: var(--s-2); }
.pet__grid { display: grid; gap: var(--s-5); align-items: start; }
@media (min-width: 900px) {
  .pet__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 20rem); gap: var(--s-7); }
}
.pet__body > p + p { margin-top: var(--s-2); }
.pet__body p { color: var(--c-text-muted); }

.specs { list-style: none; margin: 0; padding: 0; border-top: var(--hairline) solid var(--c-rule); }
.specs li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2);
  padding: 0.85rem 0;
  border-bottom: var(--hairline) solid var(--c-rule);
}
.specs dt, .specs .k { font-size: var(--fs-100); color: var(--c-text-muted); letter-spacing: 0.04em; text-transform: uppercase; }
.specs dd, .specs .v { margin: 0; font-family: var(--ff-mono); font-size: var(--fs-400); font-weight: var(--fw-medium); color: var(--c-heading); text-align: right; }
.on-dark .specs .v { color: #fff; }

/* --- Industries --- */
.industries { display: grid; gap: var(--s-2); grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr)); list-style: none; margin: 0; padding: 0; }
.industry { padding: var(--s-3); background: var(--c-white); border: var(--hairline) solid var(--c-line); border-radius: var(--radius); }
.industry h3 { font-size: var(--fs-400); }
.industry p { margin-top: var(--s-1); font-size: var(--fs-200); color: var(--c-ink-muted); max-width: none; }

/* --- CTA band --- */
.ctaband { background: var(--c-primary-deep); }
.ctaband__grid { display: grid; gap: var(--s-4); align-items: center; }
@media (min-width: 860px) { .ctaband__grid { grid-template-columns: minmax(0, 1fr) auto; gap: var(--s-6); } }
.ctaband h2 { color: #fff; margin-top: var(--s-2); }
.ctaband p { margin-top: var(--s-2); color: #C2CAE0; }
.ctaband__actions { display: flex; flex-direction: column; gap: var(--s-2); align-items: flex-start; }
.ctaband__phone { display: inline-flex; align-items: center; gap: var(--s-1); color: #fff; font-family: var(--ff-mono); font-size: var(--fs-400); text-decoration: none; }
.ctaband__phone:hover { text-decoration: underline; }
.ctaband__phones { display: grid; gap: 0.25rem; margin-top: calc(-1 * var(--s-1)); }
.ctaband .ctaband__line { margin-top: 0; }
.ctaband__line { display: flex; flex-wrap: wrap; align-items: center; column-gap: var(--s-2); row-gap: 0; }

/* Viber: the sprite's outline glyph in currentColor — brand navy on light
   surfaces, the surrounding light ink on dark ones. Never Viber purple. */
.viber-link { display: inline-flex; align-items: center; gap: 0.35rem; color: var(--c-primary); font-size: var(--fs-100); font-weight: var(--fw-medium); letter-spacing: 0.02em; text-decoration: none; }
.viber-link:hover { text-decoration: underline; }
.on-dark .viber-link, .on-dark a.viber-link:not(.btn) { color: #E4E8F4; }
.viber-link .icon, .footer__contact .line .viber-link .icon { color: currentColor; margin-top: 0; }
.contact__tel, .footer__tel { display: inline-flex; flex-wrap: wrap; align-items: center; column-gap: var(--s-2); }

/* ==========================================================================
   11b  INTERIOR PAGE SECTIONS
   --------------------------------------------------------------------------
   Everything built by build/pages/standard.mjs. The homepage keeps its own
   full-viewport hero; interior pages get a compact navy header instead, so the
   first screen of a product page is content rather than decoration.
   ========================================================================== */

/* --- Page header --------------------------------------------------------- */
.pagehead {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--c-primary-deep);
}
.pagehead__media { position: absolute; inset: 0; }
.pagehead__media picture { display: contents; }
.pagehead__media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 45%; }
/* Flatter and heavier than the hero scrim: the header copy runs the full width
   of the wrap, so there is no safe thin end to fade towards. Measured against
   the real composited pixels, same as the hero. */
.pagehead__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, rgb(26 35 76 / 0.94) 0%, rgb(26 35 76 / 0.90) 60%, rgb(26 35 76 / 0.78) 100%);
}
.pagehead__inner {
  position: relative;
  z-index: 1;
  padding-block: var(--s-3) clamp(2.5rem, 1.5rem + 3vw, 4rem);
}
.pagehead h1 { margin-top: var(--s-2); color: #fff; max-width: 20ch; }
.pagehead .lead { margin-top: var(--s-3); max-width: 60ch; color: #E4E8F4; }
.pagehead__cta { margin-top: var(--s-4); }

/* Breadcrumbs sit inside the navy header, so they need the dark treatment. */
.pagehead .crumbs { padding-block: 0 var(--s-3); border-bottom: 0; }
.pagehead .crumbs li { color: #C2CAE0; }
.pagehead .crumbs a { color: #C2CAE0; }
.pagehead .crumbs a:hover { color: #fff; }
.pagehead .crumbs li + li::before { color: rgba(255, 255, 255, 0.45); }
.pagehead .crumbs [aria-current='page'] { color: #fff; }

/* --- Prose --------------------------------------------------------------- */
.prose > p + p { margin-top: var(--s-2); }
.prose p { max-width: var(--measure); }

/* Ticked list: a check glyph, not a bullet, because these are capabilities. */
.ticks { list-style: none; margin: var(--s-3) 0 0; padding: 0; display: grid; gap: var(--s-1); }
.ticks li { display: flex; align-items: flex-start; gap: var(--s-1); max-width: var(--measure); }
.ticks .icon { flex: none; margin-top: 3px; color: var(--c-accent-ink); }
.on-dark .ticks .icon { color: var(--c-accent-on-dark); }

/* --- Process steps ------------------------------------------------------- */
.steps {
  display: grid;
  gap: var(--s-3);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: none;
}
.step { position: relative; padding-top: var(--s-3); border-top: 2px solid var(--c-accent); }
.step__num { display: block; font-size: var(--fs-100); font-weight: var(--fw-medium); color: var(--c-accent-ink); letter-spacing: 0.1em; }
.step h3 { margin-top: var(--s-1); font-size: var(--fs-400); }
.step p { margin-top: var(--s-1); font-size: var(--fs-200); color: var(--c-ink-muted); }

/* --- Spec strip ---------------------------------------------------------- */
.specstrip {
  display: grid;
  gap: 0;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: var(--hairline) solid var(--c-line);
}
.specstrip li {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--s-2) var(--s-2) var(--s-2) 0;
  border-bottom: var(--hairline) solid var(--c-line);
}
.specstrip .k { font-size: var(--fs-100); color: var(--c-ink-muted); }
.specstrip .v { font-size: var(--fs-300); font-weight: var(--fw-medium); color: var(--c-primary); }

/* --- Feature block media ------------------------------------------------- */
.feature__media { border: var(--hairline) solid rgba(255, 255, 255, 0.22); border-radius: var(--radius); overflow: hidden; }
.feature__media img { width: 100%; height: auto; }

/* --- CTA band over a photograph ------------------------------------------ */
.ctaband--media { position: relative; isolation: isolate; overflow: hidden; }
.ctaband__media { position: absolute; inset: 0; }
.ctaband__media picture { display: contents; }
.ctaband__media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 45%; }
.ctaband__scrim { position: absolute; inset: 0; background: linear-gradient(100deg, rgb(26 35 76 / 0.95) 0%, rgb(26 35 76 / 0.92) 60%, rgb(26 35 76 / 0.84) 100%); }
.ctaband__wrap { position: relative; z-index: 1; }
.ctaband__formats { margin-top: var(--s-2); font-size: var(--fs-100); letter-spacing: 0.06em; color: #C7CFE6; }

/* ==========================================================================
   11c  CONTACT, MAP FACADE, FORMS, LEGAL
   ========================================================================== */

.contact__grid { display: grid; gap: var(--s-5); }
@media (min-width: 900px) {
  .contact__grid { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); gap: var(--s-6); align-items: start; }
}
.contact__details h3, .contact__map h3 { font-size: var(--fs-400); margin-top: var(--s-4); }
.contact__details h3:first-child { margin-top: 0; }
.contact__map h3:first-child { margin-top: 0; }
.contact__address { font-style: normal; margin-top: var(--s-2); line-height: 1.7; }
.contact__list { list-style: none; margin: var(--s-2) 0 0; padding: 0; display: grid; gap: var(--s-2); }
.contact__list li { display: flex; align-items: flex-start; gap: var(--s-2); }
.contact__list .icon { flex: none; margin-top: 3px; color: var(--c-primary); }
.contact__label { display: block; font-size: var(--fs-100); color: var(--c-ink-muted); }
.contact__list--hours li { justify-content: space-between; gap: var(--s-3); border-bottom: var(--hairline) solid var(--c-line); padding-bottom: var(--s-1); }

/* --- Map facade ----------------------------------------------------------
   No request reaches Google until the button is pressed. Embedding the iframe
   directly would set third-party cookies on first paint and contradict the
   site's own consent banner. */
.mapfacade {
  position: relative;
  margin-top: var(--s-2);
  aspect-ratio: 4 / 3;
  display: grid;
  place-items: center;
  background:
    repeating-linear-gradient(0deg, rgba(38, 51, 110, 0.05) 0 1px, transparent 1px 28px),
    repeating-linear-gradient(90deg, rgba(38, 51, 110, 0.05) 0 1px, transparent 1px 28px),
    var(--c-surface);
  border: var(--hairline) solid var(--c-line);
  border-radius: var(--radius);
  /* No overflow:hidden: it switches off aspect-ratio's automatic minimum
     height, and at 390px the note and the Maps link were clipped. With it
     gone the box keeps 4:3 where the content fits and grows where it does not. */
}
.mapfacade__body { text-align: center; padding: var(--s-3); display: grid; justify-items: center; gap: var(--s-2); }
.mapfacade__pin { color: var(--c-primary); }
.mapfacade__addr { font-weight: var(--fw-medium); max-width: 28ch; }
.mapfacade__note { font-size: var(--fs-100); color: var(--c-ink-muted); max-width: 34ch; }
.mapfacade__links { display: flex; flex-wrap: wrap; justify-content: center; gap: 0 var(--s-3); }
.mapfacade iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* --- Forms --------------------------------------------------------------- */
.quoteform { max-width: 52rem; }
.form__legend { font-size: var(--fs-100); color: var(--c-ink-muted); margin-bottom: var(--s-3); }
.form__grid { display: grid; gap: var(--s-3); }
@media (min-width: 700px) {
  .form__grid { grid-template-columns: 1fr 1fr; }
  .field--wide { grid-column: 1 / -1; }
}
.field { display: grid; gap: 6px; align-content: start; }
.field label { font-size: var(--fs-200); font-weight: var(--fw-medium); }
.field .req { color: var(--c-error); }
.field input, .field select, .field textarea {
  width: 100%;
  min-height: 48px;
  padding: 0.7rem 0.85rem;
  font: inherit;
  font-size: var(--fs-200);
  color: var(--c-ink);
  background: var(--c-white);
  /* --c-border-strong, not --c-line: WCAG 1.4.11 wants 3:1 for the boundary of
     a control, and the decorative hairline is only 1.30:1 on white. */
  border: var(--hairline) solid var(--c-border-strong);
  border-radius: var(--radius);
}
.field textarea { min-height: 9rem; resize: vertical; line-height: 1.6; }
.field input[type='file'] { padding: 0.55rem; background: var(--c-surface); }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible { border-color: var(--c-primary); }
.field__hint { font-size: var(--fs-100); color: var(--c-ink-muted); }
.field__error { font-size: var(--fs-100); font-weight: var(--fw-medium); color: var(--c-error); }
.field[data-invalid] input, .field[data-invalid] select, .field[data-invalid] textarea { border-color: var(--c-error); border-width: 2px; }

.checkbox { display: flex; align-items: flex-start; gap: var(--s-1); font-weight: var(--fw-regular); font-size: var(--fs-200); }
.checkbox input { width: 20px; height: 20px; min-height: 0; flex: none; margin-top: 2px; accent-color: var(--c-primary); }

.form__summary {
  margin-bottom: var(--s-3);
  padding: var(--s-2) var(--s-3);
  background: #FDF0EF;
  border: var(--hairline) solid var(--c-error);
  border-left-width: 3px;
  border-radius: var(--radius);
}
.form__summary-title { font-weight: var(--fw-semibold); color: var(--c-error); }
.form__summary ul { margin: var(--s-1) 0 0; padding-left: 1.2rem; font-size: var(--fs-200); }
.form__summary a { color: var(--c-error); }

.form__actions { margin-top: var(--s-4); display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3); }
.form__privacy { font-size: var(--fs-100); color: var(--c-ink-muted); max-width: 40ch; }
.form__status { margin-top: var(--s-3); padding: var(--s-2) var(--s-3); border-radius: var(--radius); font-weight: var(--fw-medium); }
.form__status[data-state='ok'] { background: #EAF6EF; border: var(--hairline) solid var(--c-success); color: var(--c-success); }
.form__status[data-state='error'] { background: #FDF0EF; border: var(--hairline) solid var(--c-error); color: var(--c-error); }

/* Honeypot: off-screen, out of the tab order, hidden from assistive tech.
   display:none would let a naive bot detect and skip it. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* --- Legal --------------------------------------------------------------- */
.legal { max-width: var(--measure); }
.legal h2 { margin-top: var(--s-5); font-size: var(--fs-500); }
.legal h2:first-of-type { margin-top: var(--s-3); }
.legal p { margin-top: var(--s-2); }
.legal ul { margin-top: var(--s-2); padding-left: 1.25rem; display: grid; gap: 0.35rem; }
.legal__updated { font-size: var(--fs-100); color: var(--c-ink-muted); }

/* ==========================================================================
   12  TABLE
   ========================================================================== */

.table-scroll {
  overflow-x: auto;
  border: var(--hairline) solid var(--c-line);
  border-radius: var(--radius);
  /* Keyboard users must be able to scroll the region, so it is focusable. */
}
.table-scroll:focus-visible { outline: 2px solid var(--c-accent-ink); outline-offset: 2px; }

table.spec { width: 100%; min-width: 40rem; border-collapse: collapse; font-size: var(--fs-200); }
table.spec caption { text-align: left; padding: var(--s-2) var(--s-3); font-size: var(--fs-100); color: var(--c-ink-muted); border-bottom: var(--hairline) solid var(--c-line); }
table.spec th, table.spec td { padding: 0.8rem var(--s-3); text-align: left; border-bottom: var(--hairline) solid var(--c-line); vertical-align: top; }
table.spec thead th {
  font-size: var(--fs-100);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--c-primary);
  background: var(--c-surface);
  white-space: nowrap;
}
table.spec tbody tr:last-child th, table.spec tbody tr:last-child td { border-bottom: 0; }
table.spec tbody tr:hover { background: var(--c-surface); }
table.spec .num, table.spec .qty { font-family: var(--ff-mono); font-variant-numeric: tabular-nums; white-space: nowrap; }
table.spec .unknown { color: var(--c-ink-muted); font-family: var(--ff-mono); }
table.spec th[scope='row'] { font-weight: var(--fw-medium); color: var(--c-ink); }
/* Machine photograph beside its row. Rows without a photograph show none —
   no placeholder — and are indented so the machine names stay in one column. */
.spec__machine { display: flex; align-items: center; gap: var(--s-2); }
.spec__machine picture { flex: none; }
.spec__thumb { display: block; width: 80px; height: 80px; object-fit: cover; border-radius: var(--radius); }
table.spec th.spec__bare { padding-left: calc(var(--s-3) + 80px + var(--s-2)); }
table.spec tr:has(.spec__machine) td { vertical-align: middle; }

.table-note { margin-top: var(--s-2); font-size: var(--fs-100); color: var(--c-ink-muted); max-width: var(--measure); }

/* ==========================================================================
   13  FAQ
   ========================================================================== */

.faq { border-top: var(--hairline) solid var(--c-line); max-width: 56rem; }
.faq__item { border-bottom: var(--hairline) solid var(--c-line); }
.faq__item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  padding: var(--s-3) 0;
  font-size: var(--fs-400);
  font-weight: var(--fw-semibold);
  color: var(--c-primary);
  cursor: pointer;
  list-style: none;
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary::after {
  content: '';
  flex: none;
  width: 14px; height: 14px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--dur) var(--ease);
}
.faq__item[open] summary::after { transform: rotate(-135deg) translate(-4px, -4px); }
.faq__item summary:hover { color: var(--c-primary-soft); }
.faq__answer { padding-bottom: var(--s-3); }
.faq__answer p { color: var(--c-ink-muted); }

/* ==========================================================================
   14  BREADCRUMBS
   ========================================================================== */

.crumbs { padding-block: var(--s-2); border-bottom: var(--hairline) solid var(--c-line); }
.crumbs ol { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; list-style: none; margin: 0; padding: 0; font-size: var(--fs-100); }
.crumbs li { display: flex; align-items: center; gap: 0.4rem; color: var(--c-ink-muted); }
.crumbs li + li::before { content: '/'; color: var(--c-line-strong); }
.crumbs a { color: var(--c-ink-muted); text-decoration: none; }
.crumbs a:hover { color: var(--c-primary); text-decoration: underline; }
.crumbs [aria-current='page'] { color: var(--c-ink); }

/* ==========================================================================
   15  FOOTER
   ========================================================================== */

.site-footer { background: var(--c-primary-deep); color: #fff; padding-block: var(--s-6) var(--s-4); }
.site-footer h2, .site-footer h3 { color: #fff; }

.footer__grid { display: grid; gap: var(--s-5); }
@media (min-width: 720px) { .footer__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .footer__grid { grid-template-columns: 1.5fr 1fr 1fr 1.3fr; gap: var(--s-5); } }

.footer__logo img { width: 145px; height: 36px; object-fit: contain; }
.footer__tagline { margin-top: var(--s-2); font-size: var(--fs-200); color: #C2CAE0; max-width: 30ch; }
.footer__legalname { margin-top: var(--s-3); font-size: var(--fs-100); color: #C2CAE0; }
.footer__legalname .mono { color: #fff; }

.footer__title {
  font-size: var(--fs-100);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--c-accent-on-dark);
  margin-bottom: var(--s-2);
}

.footer__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.55rem; }
.footer__list a { color: #E4E8F4; font-size: var(--fs-200); text-decoration: none; }
.footer__list a:hover { color: #fff; text-decoration: underline; }

.footer__contact { display: grid; gap: var(--s-2); font-size: var(--fs-200); }
.footer__contact .line { display: flex; gap: var(--s-1); align-items: flex-start; color: #E4E8F4; }
.footer__contact .line .icon { width: 18px; height: 18px; flex: none; margin-top: 3px; color: var(--c-accent-on-dark); }
.footer__contact a { color: #E4E8F4; text-decoration: none; }
.footer__contact a:hover { color: #fff; text-decoration: underline; }
.footer__contact .mono { white-space: nowrap; }
.footer__contact .line--hours { align-self: stretch; justify-content: space-between; gap: var(--s-2); }

.footer__bottom {
  margin-top: var(--s-6);
  padding-top: var(--s-3);
  border-top: 1px solid rgba(255, 255, 255, 0.18);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-4);
  align-items: center;
  font-size: var(--fs-100);
  color: #C2CAE0;
}
.footer__bottom nav { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-3); margin-left: auto; }
.footer__bottom a { color: #C2CAE0; text-decoration: none; }
.footer__bottom a:hover { color: #fff; text-decoration: underline; }
.footer__bottom button { color: #C2CAE0; font-size: inherit; text-decoration: underline; text-underline-offset: 0.18em; }
.footer__bottom button:hover { color: #fff; }

/* ==========================================================================
   16  FLOATING UI
   --------------------------------------------------------------------------
   Assistant bottom-LEFT, back-to-top bottom-RIGHT, matched in size and offset.
   Both sit above the fold at every breakpoint and clear the cookie banner.
   ========================================================================== */

.float {
  position: fixed;
  bottom: calc(var(--floating-gap) + env(safe-area-inset-bottom, 0px));
  z-index: var(--z-float);
  width: var(--floating-size);
  height: var(--floating-size);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  transition: transform var(--dur) var(--ease), background-color var(--dur) var(--ease), opacity var(--dur) var(--ease);
}

/* Both floats are pushed up while the consent banner is on screen. */
/* The floating buttons are withdrawn while a consent decision is pending,
   rather than lifted above the banner.
   Lifting them moved a fixed-position element after first paint, which Chrome
   counts as a layout shift — measured as part of a 0.094 CLS on the homepage,
   with the assistant launcher jumping 325px. They are secondary UI and the
   banner is not; they return the instant a choice is made. */
body[data-consent-open='true'] .float { display: none; }

/* The hero controls are lifted clear of the banner in .hero__controls itself
   (section 08), by transform and by a clamped amount. The hero's own padding is
   NOT touched in either consent state — that is what keeps CLS at 0. */

/* --- Assistant launcher (bottom-left) --- */
.assist-launch {
  left: var(--floating-gap);
  background: var(--c-primary);
  color: #fff;
  border: 1px solid var(--c-primary);
}
.assist-launch:hover { background: var(--c-primary-soft); border-color: var(--c-primary-soft); transform: scale(1.05); }
.assist-launch .icon { width: 25px; height: 25px; }
.assist-launch__badge {
  position: absolute;
  top: 4px; right: 4px;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--c-accent-on-dark);
  border: 2px solid var(--c-primary);
}
.assist-launch[data-seen='true'] .assist-launch__badge { display: none; }

/* --- Back to top (bottom-right) --- */
.to-top {
  right: var(--floating-gap);
  background: var(--c-white);
  color: var(--c-primary);
  border: 1px solid var(--c-border-strong);
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
}
.to-top[data-visible='true'] { opacity: 1; visibility: visible; transform: none; }
.to-top:hover { background: var(--c-surface); border-color: var(--c-primary); }
.to-top .icon { width: 22px; height: 22px; position: relative; z-index: 1; }

/* Thin scroll-progress ring, brand navy on --c-line. */
.to-top__ring { position: absolute; inset: -1px; transform: rotate(-90deg); pointer-events: none; }
.to-top__ring circle { fill: none; stroke-width: 2; }
.to-top__ring .track { stroke: var(--c-line); }
.to-top__ring .bar { stroke: var(--c-primary); stroke-linecap: round; transition: stroke-dashoffset 90ms linear; }

.no-js .to-top { display: none; }

/* --- Assistant panel --- */
.assist-panel {
  position: fixed;
  left: var(--floating-gap);
  bottom: calc(var(--floating-gap) + var(--floating-size) + var(--s-1) + env(safe-area-inset-bottom, 0px));
  z-index: var(--z-panel);
  display: flex;
  flex-direction: column;
  width: 380px;
  height: 560px;
  max-height: calc(100svh - var(--floating-size) - var(--s-6));
  background: var(--c-white);
  border: var(--hairline) solid var(--c-border-strong);
  border-radius: var(--radius);
  box-shadow: 0 12px 40px rgba(20, 23, 31, 0.18);
  overflow: hidden;
}
.assist-panel[hidden] { display: none; }

.assist-panel__head {
  display: flex;
  align-items: flex-start;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-2) var(--s-2) var(--s-3);
  background: var(--c-primary);
  color: #fff;
}
.assist-panel__head h2 { font-size: var(--fs-200); color: #fff; margin: 0; }
.assist-panel__disclaimer { font-size: var(--fs-100); color: #C7CFE6; line-height: 1.4; margin-top: 2px; }
.assist-panel__close {
  margin-left: auto; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px;
  color: #fff;
  border-radius: var(--radius);
}
.assist-panel__close:hover { background: rgba(255, 255, 255, 0.16); }

.assist-log {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--s-2) var(--s-3);
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  background: var(--c-surface);
}

.msg { max-width: 86%; font-size: var(--fs-200); line-height: 1.55; }
.msg__body { padding: 0.7rem 0.9rem; border-radius: var(--radius); }
.msg--bot { align-self: flex-start; }
.msg--bot .msg__body { background: var(--c-white); border: var(--hairline) solid var(--c-line); color: var(--c-ink); }
.msg--user { align-self: flex-end; }
.msg--user .msg__body { background: var(--c-primary); color: #fff; }
.msg__who { font-size: var(--fs-100); color: var(--c-ink-muted); margin-bottom: 3px; }
.msg--user .msg__who { text-align: right; }
.msg__cta { margin-top: var(--s-1); }

.assist-chips { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 var(--s-3) var(--s-2); background: var(--c-surface); }
.assist-chip {
  padding: 0.4rem 0.7rem;
  font-size: var(--fs-100);
  color: var(--c-primary);
  background: var(--c-white);
  border: var(--hairline) solid var(--c-border-strong);
  border-radius: var(--radius);
  transition: border-color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}
.assist-chip:hover { border-color: var(--c-primary); background: var(--c-white); }

.assist-form { display: flex; gap: var(--s-1); padding: var(--s-2); border-top: var(--hairline) solid var(--c-line); background: var(--c-white); }
.assist-form textarea {
  flex: 1 1 auto;
  min-height: 44px;
  max-height: 120px;
  padding: 0.6rem 0.7rem;
  font-size: var(--fs-200);
  font-family: inherit;
  line-height: 1.45;
  color: var(--c-ink);
  background: var(--c-white);
  border: var(--hairline) solid var(--c-border-strong);
  border-radius: var(--radius);
  resize: none;
}
.assist-form textarea:focus { border-color: var(--c-primary); }
.assist-send {
  flex: none;
  width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--c-primary);
  color: #fff;
  border-radius: var(--radius);
}
.assist-send:hover { background: var(--c-primary-soft); }
.assist-privacy { padding: 0 var(--s-2) var(--s-2); font-size: var(--fs-100); color: var(--c-ink-muted); background: var(--c-white); }

/* Full-screen sheet on small viewports. */
@media (max-width: 640px) {
  .assist-panel {
    left: 0; right: 0; bottom: 0; top: 0;
    width: auto; height: auto; max-height: none;
    border: 0; border-radius: 0;
  }
}

/* ==========================================================================
   17  COOKIE CONSENT
   ========================================================================== */

.consent {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: var(--z-consent);
  background: var(--c-white);
  border-top: 2px solid var(--c-primary);
  box-shadow: 0 -6px 30px rgba(20, 23, 31, 0.14);
  padding: var(--s-3) 0 calc(var(--s-3) + env(safe-area-inset-bottom, 0px));
  /* The banner must never take over the screen it is asking about.
     Measured at 320x568 it grew to ~400px — over 70% of the viewport — and
     covered the hero's kicker and headline entirely, so the visitor was asked
     to consent to a page they could no longer see. Capping it and letting it
     scroll internally keeps every control reachable while leaving the page
     legible behind it. min() rather than a bare vh so it never gets silly on a
     tall desktop monitor either. */
  max-height: min(60vh, 30rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.consent[hidden] { display: none; }

/* Short viewports — a 320x568 phone, or a landscape handset.
   Two separate problems show up only here, both measured:
     - even a 60vh banner still reached the hero headline, so the cap tightens;
     - the floating assistant button is lifted clear of the banner, and on a
       568px-tall screen that lift lands it directly on top of the hero kicker.
       While a consent decision is pending the floats are simply withdrawn:
       they are secondary UI, the banner is not, and hiding them is better than
       having them obscure the page the visitor is being asked about. They
       return the moment a choice is made. */
@media (max-height: 700px) {
  .consent { max-height: 50vh; }
  body[data-consent-open='true'] .float { display: none; }
}

/* Tighter at phone widths, where the same copy wraps to twice the height. */
@media (max-width: 480px) {
  .consent { padding-block: var(--s-2) calc(var(--s-2) + env(safe-area-inset-bottom, 0px)); }
  .consent__grid { gap: var(--s-2); }
  .consent h2 { font-size: var(--fs-300); }
  .consent__actions .btn { min-width: 7rem; }
}
.consent__grid { display: grid; gap: var(--s-3); }
@media (min-width: 900px) { .consent__grid { grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--s-5); } }
.consent h2 { font-size: var(--fs-400); }
.consent p { margin-top: var(--s-1); font-size: var(--fs-200); color: var(--c-ink-muted); max-width: 62ch; }

/* "Reject all" is exactly as prominent as "Accept all". */
.consent__actions { display: flex; flex-wrap: wrap; gap: var(--s-1); }
.consent__actions .btn { flex: 1 1 auto; min-width: 9rem; }

.consent__cats { margin-top: var(--s-3); display: grid; gap: var(--s-2); border-top: var(--hairline) solid var(--c-line); padding-top: var(--s-3); }
.consent__cats[hidden] { display: none; }
.consent__cat { display: grid; grid-template-columns: auto 1fr; gap: var(--s-1) var(--s-2); align-items: start; }
.consent__cat input { width: 20px; height: 20px; margin: 2px 0 0; accent-color: var(--c-primary); }
.consent__cat label { font-weight: var(--fw-semibold); font-size: var(--fs-200); }
.consent__cat p { grid-column: 2; margin: 0; font-size: var(--fs-100); }

/* ==========================================================================
   18  404
   ========================================================================== */

.notfound { padding-block: clamp(3rem, 2rem + 6vw, 7rem); }
.notfound__code {
  font-family: var(--ff-mono);
  font-size: var(--fs-100);
  letter-spacing: 0.2em;
  color: var(--c-accent-ink);
}
.notfound h1 { margin-top: var(--s-2); }
.notfound p { margin-top: var(--s-2); }
.notfound__links { margin-top: var(--s-4); display: grid; gap: 0; max-width: 34rem; border-top: var(--hairline) solid var(--c-line); }
.notfound__links a {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-2);
  padding: var(--s-2) 0;
  border-bottom: var(--hairline) solid var(--c-line);
  color: var(--c-ink);
  text-decoration: none;
  font-weight: var(--fw-medium);
}
.notfound__links a:hover { color: var(--c-primary); }
.notfound__links .icon { color: var(--c-primary); width: 18px; height: 18px; }

/* ==========================================================================
   18b PRELOADER
   --------------------------------------------------------------------------
   Markup and rationale: build/partials/preloader.mjs. These rules are
   duplicated into critical.css by design — the preloader has to paint from the
   inlined <head> block or it is a blank screen waiting on a stylesheet, which
   is the failure it exists to avoid.
   ========================================================================== */

.preloader {
  position: fixed;              /* out of flow: contributes nothing to CLS */
  inset: 0;
  z-index: var(--z-preloader);
  display: grid;
  place-items: center;
  /* A background COLOUR, not an image. Background images are LCP candidates;
     colours are not, and neither is the inline <svg> below. */
  background: var(--c-primary-deep);

  /* Removal mechanism 1 of 3, and the only one that does not involve script:
     ends in visibility:hidden + pointer-events:none and stays there because of
     `forwards`. This is what fires when JavaScript is disabled. */
  animation: preloader-out 1400ms var(--ease) forwards;
}

/* Mechanism 2 and 3 (window.load, and a hard 1200ms timer) both land here. */
.preloader.is-done {
  animation: none;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 200ms linear, visibility 0s linear 200ms;
}

/* Set before first paint by the inline <head> script when the preloader has
   already been seen this session, or when the URL carries a #fragment. */
.no-preloader .preloader { display: none; }

.preloader__mark {
  color: var(--c-white);
  animation: preloader-mark 560ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
}

/* A single determinate sweep in the accent colour. Not a spinner, not a
   percentage, not dots: this should read as a machine coming up to speed. */
.preloader__line {
  position: absolute;
  top: calc(50% + 78px);
  width: 116px;
  height: 2px;
  overflow: hidden;
  background: rgb(255 255 255 / 0.16);
}
.preloader__line i {
  display: block;
  height: 100%;
  background: var(--c-accent-on-dark);
  transform: scaleX(0);
  transform-origin: left center;
  animation: preloader-sweep 1000ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

@keyframes preloader-mark {
  from { opacity: 0; transform: scale(0.94); }
  to   { opacity: 1; transform: none; }
}
@keyframes preloader-sweep {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
@keyframes preloader-out {
  0%, 66% { opacity: 1; visibility: visible; pointer-events: auto; }
  67%     { opacity: 1; visibility: visible; pointer-events: none; }
  99%     { opacity: 0; visibility: visible; pointer-events: none; }
  100%    { opacity: 0; visibility: hidden;  pointer-events: none; }
}

/* ==========================================================================
   18b  PHOTOGRAPHS — tiles, gallery filters, lightbox
   Every content photograph on the site is 4:3 and is cut to 4:3 by the image
   pipeline, so no image ever sits in a box of a different ratio. One hover
   treatment for all of them: the frame stays put, the picture inside scales
   to 1.02 over 300ms; nothing under reduced motion.
   ========================================================================== */

.card__media img,
.split__media img,
.intro__media img,
.feature__media img,
.tile__frame img {
  transition: transform 300ms var(--ease);
}
.card:hover .card__media img,
.split__media:hover img,
.intro__media:hover img,
.feature__media:hover img,
.tile__link:hover .tile__frame img,
.tile__link:focus-visible .tile__frame img { transform: scale(1.02); }

.tiles {
  display: grid;
  gap: var(--s-3);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr));
}
@media (min-width: 700px) { .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.tile { min-width: 0; transition: opacity var(--dur) var(--ease); }
/* The homepage teaser is a taste, not the gallery: two columns on a phone keep
   six photographs to six small files. */
.tiles--teaser { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2); }
@media (min-width: 1100px) { .tiles--teaser { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-3); } }
.tile[hidden] { display: none; }
.tile.is-fading { opacity: 0; }
.tile__link {
  display: block;
  color: inherit;
  text-decoration: none;
  border-radius: var(--radius);
}
.tile__frame {
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border: var(--hairline) solid var(--c-line);
  border-radius: var(--radius);
  background: var(--c-surface);
  transition: border-color var(--dur) var(--ease);
}
.tile__frame img { width: 100%; height: 100%; object-fit: cover; }
.tile__link:hover .tile__frame,
.tile__link:focus-visible .tile__frame { border-color: var(--c-border-strong); }
.tile__link:active .tile__frame { border-color: var(--c-primary); }
.tile__caption {
  display: block;
  margin-top: var(--s-1);
  font-family: var(--ff-mono);
  font-size: var(--fs-100);
  color: var(--c-text-muted);
  letter-spacing: 0.02em;
}
.tiles + .table-note,
.tiles + .section__foot { margin-top: var(--s-3); }

/* --- Gallery filters ------------------------------------------------------ */
.chips {
  display: flex;
  gap: var(--s-1);
  margin-bottom: var(--s-2);
  /* Overflow scrolls sideways on a phone instead of wrapping into a ragged
     second row; the chips keep their 44px height either way. */
  overflow-x: auto;
  scrollbar-width: thin;
  padding: 2px 2px var(--s-1);
  -webkit-overflow-scrolling: touch;
}
.chip {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--s-2);
  font: inherit;
  font-size: var(--fs-200);
  font-weight: var(--fw-medium);
  color: var(--c-primary);
  background: var(--c-white);
  border: var(--hairline) solid var(--c-border-strong);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.chip:hover { border-color: var(--c-primary); }
.chip:active { background: var(--c-surface); }
.chip[aria-pressed='true'] { color: #fff; background: var(--c-primary); border-color: var(--c-primary); }
.gallery__count { margin: 0 0 var(--s-3); }
/* Pre-filtered arrival from a homepage teaser tile: set on <html> by the inline
   head script before first paint, cleared by gallery.js once it takes over. */
[data-gallery-filter='masine'] .tiles--gallery .tile:not([data-group='masine']),
[data-gallery-filter='alati'] .tiles--gallery .tile:not([data-group='alati']),
[data-gallery-filter='delovi'] .tiles--gallery .tile:not([data-group='delovi']),
[data-gallery-filter='pogon'] .tiles--gallery .tile:not([data-group='pogon']) { display: none; }

/* --- Lightbox ------------------------------------------------------------- */
.lightbox {
  width: 100vw;
  max-width: 100vw;
  height: 100vh;
  height: 100dvh;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  color: #fff;
  background: transparent;
}
.lightbox::backdrop { background: rgb(8 11 18); }
.lightbox[open] { animation: lb-in var(--dur) var(--ease); }
@keyframes lb-in { from { opacity: 0; } to { opacity: 1; } }
.lightbox__inner {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  padding: var(--s-6) var(--s-2) var(--s-2);
}
.lightbox__figure { margin: 0; display: grid; justify-items: center; gap: var(--s-2); max-width: 90vw; }
.lightbox__stage, .lightbox__stage picture { display: contents; }
.lightbox__img {
  display: block;
  width: auto;
  height: auto;
  max-width: 90vw;
  max-height: calc(90vh - 7rem);
  max-height: calc(90dvh - 7rem);
  object-fit: contain;
  border-radius: var(--radius);
  background: rgb(255 255 255 / 0.04);
}
.lightbox__caption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: var(--s-1) var(--s-3);
  max-width: 68ch;
  text-align: center;
  font-size: var(--fs-200);
  color: #fff;
}
.lightbox__link { color: var(--c-accent-on-dark); }
.lightbox__count { font-size: var(--fs-100); color: rgb(255 255 255 / 0.78); }
.lightbox__btn {
  position: absolute;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  color: #fff;
  background: rgb(8 11 18 / 0.62);
  border: 1px solid rgb(255 255 255 / 0.9);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease);
}
.lightbox__btn:hover { background: rgb(26 35 76 / 0.92); }
.lightbox__btn:active { background: var(--c-primary-deep); }
.lightbox :focus-visible { outline: 2px solid var(--c-accent-on-dark); outline-offset: 2px; }
.lightbox__close { top: var(--s-2); right: var(--s-2); }
.lightbox__btn--prev { left: var(--s-2); top: 50%; transform: translateY(-50%); }
.lightbox__btn--prev .icon { transform: rotate(180deg); }
.lightbox__btn--next { right: var(--s-2); top: 50%; transform: translateY(-50%); }
/* One-handed on a phone: both arrows drop to the bottom corners, within thumb
   reach, instead of sitting over the middle of the photograph. */
@media (max-width: 700px) {
  .lightbox__inner { padding: var(--s-6) var(--s-2) calc(var(--s-6) + var(--s-2)); }
  .lightbox__btn--prev,
  .lightbox__btn--next { top: auto; bottom: var(--s-2); transform: none; }
}
html.lb-open { overflow: hidden; }

/* ==========================================================================
   18c  POLISH — rhythm, states, targets, reveal, drop zone
   No new colours, fonts or layouts: tokens only.
   ========================================================================== */

/* Spacing rhythm. Two consecutive sections on the same ground used to stack
   two full paddings (224px of nothing at 1440). The second drops its top
   padding, so every gap on the page is exactly one --section-y. */
.section:not(.section--surface, .section--dark, .ctaband) + .section:not(.section--surface, .section--dark, .ctaband),
.section--surface + .section--surface { padding-top: 0; }
.notfound { padding-block: var(--section-y); }

/* Split blocks: the heading sat flush against the first paragraph. */
.split__body .section__head + .prose { margin-top: var(--s-3); }

/* Image treatment: the card picture meets the card's own rounded corners. */
.card__media { border-radius: var(--radius) var(--radius) 0 0; }

/* One button height across the site — the small variant included. */
.btn--sm { min-height: 48px; }

/* Interactive states: every control shows hover, focus-visible AND active. */
.btn:active { --btn-bg: var(--c-primary-deep); --btn-bd: var(--c-primary-deep); }
.btn--ghost:active { --btn-bg: var(--c-line); }
.btn--on-dark:active, .btn--ghost-dark:active { --btn-bg: rgba(255, 255, 255, 0.82); --btn-fg: var(--c-primary-deep); }
.link-arrow:active { color: var(--c-primary-deep); border-bottom-color: var(--c-primary-deep); }
.card:has(.card__stretch:focus-visible) { border-color: var(--c-primary); }
.card:active { border-color: var(--c-primary-deep); }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--c-ink-muted); }
.footer__list a:active, .footer__bottom a:active { color: var(--c-accent-on-dark); }
.crumbs a:active { color: var(--c-primary-deep); }

/* Tap targets: 44px on touch-sized screens. Measured with
   tools/qa/polish-audit.mjs; inline links inside running text are exempt
   (WCAG 2.5.8), everything that stands alone is not. */
@media (max-width: 1023px) {
  .link-arrow { min-height: 44px; }
  .lang__link { min-width: 44px; min-height: 44px; }
  .header__logo { min-height: 44px; }
  .ctaband__phone { min-height: 44px; }
  .viber-link { min-height: 44px; }
  .crumbs { padding-block: var(--s-1); }
  .crumbs a { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; min-width: 44px; }
  .footer__contact { gap: var(--s-1); }
  .footer__contact .line { align-items: center; }
  .footer__contact .line .icon { margin-top: 0; }
  .footer__contact a { display: inline-flex; align-items: center; min-height: 44px; }
  .contact__list li { align-items: center; }
  .contact__list a { display: inline-flex; align-items: center; min-height: 44px; }
  .footer__list { gap: 0; }
  .footer__list a { display: inline-flex; align-items: center; min-height: 44px; }
  .footer__bottom a, .footer__bottom button { display: inline-flex; align-items: center; min-height: 44px; }
  .checkbox { min-height: 44px; align-items: center; }
  .checkbox input { margin-top: 0; }
  .mapfacade .link-arrow { min-height: 44px; }
}

/* Scroll reveal: one restrained fade-up, once per element. Added by main.js
   ONLY to elements that start below the fold, so nothing in the first
   viewport — and so never the LCP element — is ever hidden. Opacity and
   transform only: neither moves layout, so CLS stays 0. Off under reduced
   motion, and with JavaScript off the class is never added at all. */
.reveal { opacity: 0; transform: translateY(12px); transition: opacity 400ms var(--ease), transform 400ms var(--ease); }
.reveal.is-in { opacity: 1; transform: none; }

/* Upload drop zone. The real <input type="file"> stays in the page and
   covers the zone, so click, keyboard and drop are all native; form.js only
   reports state. Without JavaScript the input is shown as it is. */
.dropzone {
  position: relative;
  display: grid;
  place-items: center;
  gap: var(--s-1);
  min-height: 8rem;
  padding: var(--s-3);
  text-align: center;
  color: var(--c-ink-muted);
  font-size: var(--fs-200);
  background: var(--c-surface);
  border: var(--hairline) dashed var(--c-border-strong);
  border-radius: var(--radius);
  transition: border-color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.dropzone__icon { width: 28px; height: 28px; color: var(--c-primary); }
.dropzone__prompt { color: var(--c-ink); font-weight: var(--fw-medium); }
.dropzone__files { margin: 0; padding: 0; list-style: none; font-family: var(--ff-mono); font-size: var(--fs-100); color: var(--c-ink); }
.dropzone__files:empty { display: none; }
.js .dropzone input[type='file'] { position: absolute; inset: 0; width: 100%; height: 100%; min-height: 0; opacity: 0; cursor: pointer; }
.no-js .dropzone__prompt, .no-js .dropzone__icon { display: none; }
.dropzone:hover { border-color: var(--c-primary); }
.dropzone:focus-within { outline: 2px solid var(--c-accent-ink); outline-offset: 2px; border-color: var(--c-primary); }
.dropzone[data-state='drag'] { border-style: solid; border-color: var(--c-primary); background: var(--c-white); }
.dropzone[data-state='files'] { border-style: solid; border-color: var(--c-success); background: var(--c-white); }
.dropzone[data-state='error'] { border-style: solid; border-width: 2px; border-color: var(--c-error); background: var(--c-white); }

/* ==========================================================================
   19  PREFERENCES
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  /* The preloader collapses to a plain fade. It keeps a real duration rather
     than the blanket 0.001ms above so that it still reads as a deliberate
     dismissal rather than a flash, but 150ms is the ceiling: no scale on the
     mark, no sweep on the line, no motion of any kind. */
  .preloader { animation-duration: 150ms !important; }
  .preloader__mark { animation: none !important; opacity: 1; transform: none; }
  .preloader__line { display: none; }
  /* Crossfade becomes an instant switch; the media no longer scales. */
  .hero__slide.is-active .hero__media img,
  .hero__slide.is-active .hero__media video { transform: none; }
  .link-arrow:hover .icon { transform: none; }
  .assist-launch:hover { transform: none; }
  .card:hover .card__media img, .split__media:hover img, .intro__media:hover img,
  .feature__media:hover img, .tile__link:hover .tile__frame img, .tile__link:focus-visible .tile__frame img { transform: none; }
  .lightbox[open] { animation: none; }
  .reveal { opacity: 1; transform: none; transition: none; }
}

@media (prefers-contrast: more) {
  :root {
    --c-ink: #000000;
    --c-ink-muted: #33383F;
    --c-line: #767C8A;
    --c-line-strong: #4A5160;
    --c-primary: #1B2557;
    --c-accent-ink: #6B4A0E;
    --c-border-strong: #454B58;
    --hairline: 2px;
  }
  .on-dark { --c-text-muted: #FFFFFF; --c-rule: rgba(255,255,255,.6); }
  .hero__scrim {
    background: linear-gradient(100deg, rgba(20, 26, 58, 0.96) 0%, rgba(20, 26, 58, 0.9) 45%, rgba(20, 26, 58, 0.78) 100%);
  }
  .hero__sub, .factbar__label, .ctaband p { color: #FFFFFF; }
  a { text-decoration-thickness: 2px; }
  :focus-visible { outline-width: 3px; }
}

@media (forced-colors: active) {
  .btn, .card, .industry, .nav__panel, .assist-panel, .consent { border: 1px solid ButtonBorder; }
  .hero__scrim { background: Canvas; opacity: 0.86; }
  .hero__tab[aria-current='true'] { border-bottom-color: Highlight; }
  .to-top__ring .bar { stroke: Highlight; }
}

@media print {
  .site-header, .hero__controls, .float, .assist-panel, .consent, .mobile-menu, .lang-suggest { display: none !important; }
  body { color: #000; }
  .hero { min-height: 0; height: auto; background: none; }
  .hero__scrim, .hero__media { display: none; }
  .hero__title, .hero__sub, .hero__eyebrow { color: #000; }
  a[href^='http']::after { content: ' (' attr(href) ')'; font-size: 0.8em; }
  .section { padding-block: 1rem; }
}
