/* ============================================================================
   Aram Kalaye Sahand — design system
   Ported from the approved handoff: "Aram Kalaye Sahand - Handoff Design System"
   and its source of truth "Aram Kalaye Sahand - Homepage FINAL".

   The handoff's rules, kept verbatim:
     green = action (buttons), teal = state & labels, navy = structure & headings.
     RTL uses logical properties only (inset-inline / padding-inline).
     The orange/copper palette of earlier drafts is fully removed.
   ============================================================================ */

/* ----------------------------------------------------------------------------
   THEMING

   Two kinds of colour live here and they must not be confused:

   1. BRAND colours (--navy, --teal, --green, --leaf) are fixed. They paint the
      top bar, buttons, the process panel and the footer — surfaces that are dark
      in BOTH themes, so their white text stays correct either way.

   2. SURFACE and TEXT colours flip. --navy was doing double duty: a background
      seven times and a text colour thirty-two times. As a background it must stay
      navy; as text it has to go light. That is why headings read --heading, not
      --navy — flipping one token would have inverted the top bar with them.
   -------------------------------------------------------------------------- */

:root {
  color-scheme: light;

  /* -- brand (fixed in both themes) -------------------------------------- */
  --navy: #10243D;
  --teal: #0E6E70;
  --green: #1F6B45;
  --green-deep: #17563A;
  --leaf: #57A03A;
  --leaf-light: #9FD08A;

  /* -- surfaces ---------------------------------------------------------- */
  --white: #ffffff;
  --offwhite: #F6F5F1;
  --warm: #EFEEE8;
  --footer: #0B1A2E;
  --navy-soft: #1B2C42;

  /* -- text (flips) ------------------------------------------------------ */
  --heading: #10243D;    /* the navy, but only ever as TEXT */
  --teal-text: #0E6E70;  /* teal and green need lighter values on a dark ground */
  --green-text: #1F6B45;
  --body: #4A5560;
  --muted: #5E6771;      /* 5.7:1 */
  --muted-2: #6B747E;    /* 4.6:1 */
  --ink-strong: #26313D;

  /* -- lines & tints ----------------------------------------------------- */
  --divider: #EAE8E0;
  --control-border: #E3E0D7;
  --card-border: #EFECE4;
  --hairline: #F1EFE9;
  --tint-green: #ECF4EF;
  --tint-teal: #E9F2F2;
  --danger: #B3261E;
  --danger-tint: #FDF7F7;
  --ok-text: #14512F;
  --ok-border: #CFE3D8;
  --control-border-hover: #CFCBBE;
  /* Translucent ground for the scrolled header — see .chrome.is-compact. */
  --chrome-blur: rgba(255, 255, 255, .88);

  /* -- typography -------------------------------------------------------- */
  --font-fa: 'IRANSansX', 'Vazirmatn', Tahoma, system-ui, sans-serif;
  --font-en: 'Inter', 'IRANSansX', 'Vazirmatn', system-ui, sans-serif;

  /* -- layout ------------------------------------------------------------ */
  --content: 1320px;
  --wide: 1560px;
  --pad: clamp(18px, 4vw, 52px);
  --header-h: 88px;
  --header-h-compact: 66px;

  /* -- motion ------------------------------------------------------------ */
  --ease: cubic-bezier(.2, .6, .25, 1);

  /* -- elevation --------------------------------------------------------- */
  --shadow-card: 0 28px 52px -40px rgba(16, 36, 61, .5);
  --shadow-card-hover: 0 34px 60px -40px rgba(16, 36, 61, .4);
  --shadow-feature: 0 26px 50px -34px rgba(16, 36, 61, .3);

  /* Live pin offset. JS keeps this in step with the header's real height so the
     sticky products/process panels never sit under it. */
  --pin-top: 100px;

  /* Grounds the scroll engine interpolates between, as raw "r g b" triples.
     These used to be literals inside site.js, which meant the factory and CTA
     bands stayed light-to-navy no matter what theme the page was in. Declaring
     them here lets the theme own the colour and leaves JS doing only the maths. */
  --fac-from: 246 245 241;
  --fac-to: 16 36 61;
  --cta-from: 246 245 241;
  --cta-to: 11 26 46;
  /* Ink for the cursor-following fibres over a normal (non-navy) ground. */
  --fibre-ink: 26 74 56;
}

/* Dark. Only surfaces, text and lines are redefined — every brand value above is
   deliberately left alone. The page ground is darker than the card surface so
   cards still read as raised, the same relationship the light theme has. */
[data-theme="dark"] {
  color-scheme: dark;

  --white: #161D27;          /* raised: cards, panels, inputs */
  --offwhite: #0E141B;       /* section grounds */
  --warm: #1D2530;           /* image placeholders behind photos */
  --navy-soft: #172231;

  --heading: #E9EEF4;
  --teal-text: #59C6C9;
  --green-text: #63C892;
  --body: #B7C1CC;
  --muted: #9BA7B4;
  --muted-2: #8B98A6;
  --ink-strong: #F1F5F9;

  --divider: #24303F;
  --control-border: #2C3849;
  --card-border: #232E3C;
  --hairline: #1B2431;
  /* These two are hover pills and icon chips sitting ON the card surface, so on
     dark they have to be LIGHTER than it, not darker — matched to the light
     theme's values they came out within a few points of #161D27 and the nav
     hover was effectively invisible. */
  --tint-green: #1B3327;
  --tint-teal: #173036;
  --danger: #FF9A91;         /* #B3261E is unreadable on a dark ground */
  --danger-tint: #2A1618;
  /* The quote-request success alert: #14512F on a now-dark green tint was dark
     green on dark green. It only shows after a successful post, so no static
     sweep of the page would ever have caught it. */
  --ok-text: #8FE0B0;
  --ok-border: #2C5942;
  --control-border-hover: #3D4B5E;
  --chrome-blur: rgba(20, 27, 36, .88);

  /* Shadows do almost nothing on a dark ground; the borders above carry the
     separation instead, so these are dropped to near-nothing rather than left
     as black smears. */
  --shadow-card: 0 20px 40px -34px rgba(0, 0, 0, .8);
  --shadow-card-hover: 0 26px 48px -34px rgba(0, 0, 0, .75);
  --shadow-feature: 0 20px 40px -30px rgba(0, 0, 0, .7);

  /* The factory and CTA bands still darken as they scroll in, but from the dark
     ground toward a lighter, bluer navy — running them to #10243D as the light
     theme does would be a transition between two near-identical darks. */
  --fac-from: 14 20 27;
  --fac-to: 26 44 70;
  --cta-from: 14 20 27;
  --cta-to: 20 36 60;
  --fibre-ink: 176 205 190;
}

/* ============================================================================
   BASE
   ========================================================================= */

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: 96px;
  overflow-x: hidden;
  /* Native scrollbar hidden — the progress line and edge rail replace it.
     Scrolling itself stays fully intact for wheel, keyboard, touch and trackpad. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
html::-webkit-scrollbar { width: 0; height: 0; display: none; }

body {
  margin: 0;
  /*
    NO overflow-x here on purpose.

    `overflow-x: hidden` forces `overflow-y` to compute to `auto`, which turns
    <body> into a scroll container. Every `position: sticky` descendant then
    sticks to <body> — which never scrolls — so the pinned products, applications
    and process panels silently stopped pinning and left 1500-3000px of blank
    wrapper behind them. This is the same trap the handoff flags for the header.

    Horizontal overflow is contained on <html> alone: the root element's overflow
    propagates to the viewport, and html is then treated as visible for its
    descendants, so sticky still resolves against the viewport.
  */
  background: var(--white);
  color: var(--body);
  font-family: var(--font-fa);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-wrap: pretty;
  scrollbar-width: none;
}
body::-webkit-scrollbar { width: 0; height: 0; display: none; }

a { color: var(--green-text); text-decoration: none; }
a:hover { color: var(--green-deep); }
::selection { background: var(--green); color: #fff; }

:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 3px;
  border-radius: 12px;
}

img { max-width: 100%; display: block; }
h1, h2, h3, h4 { margin: 0; }
p { margin: 0; }

/* Latin text and numerals. IRANSansX/Vazirmatn follow Inter in the stack so
   Persian digits (U+06F0–06F9), which Inter lacks, still resolve. */
.en { font-family: var(--font-en); }

.container { max-width: var(--content); margin: 0 auto; }
.container-wide { max-width: var(--wide); margin: 0 auto; }
.section { padding: clamp(50px, 5.4vw, 82px) var(--pad); }
.section-lg { padding: clamp(54px, 5.8vw, 92px) var(--pad); }
.bg-offwhite { background: var(--offwhite); }
.bg-white { background: var(--white); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ============================================================================
   SECTION HEADINGS
   ========================================================================= */

.eyebrow {
  display: flex; align-items: center; gap: 11px;
  margin-bottom: 18px;
  font-size: 13px; font-weight: 500; color: var(--teal-text);
}
.eyebrow .rule {
  width: 24px; height: 2px; background: var(--teal);
  transform-origin: right; flex: none;
}
.eyebrow--onDark { color: var(--leaf-light); }
.eyebrow--onDark .rule { background: var(--leaf); }

.h-section {
  margin: 0 0 20px;
  font-size: clamp(24px, 2.6vw, 36px);
  line-height: 1.55; font-weight: 800; color: var(--heading);
}
.h-about { font-size: clamp(23px, 2.5vw, 34px); line-height: 1.6; }
.h-card { font-size: 17.5px; font-weight: 700; line-height: 1.7; color: var(--heading); }
.lede { font-size: 16px; line-height: 2.15; color: var(--body); }
.note { font-size: 13.5px; line-height: 2; color: var(--muted); }

.rule-accent {
  display: block; width: 54px; height: 2px;
  background: var(--leaf); transform-origin: right;
}

/* ============================================================================
   SCROLL INDICATORS — native bar is hidden, these stand in for it
   ========================================================================= */

.scroll-progress {
  position: fixed; top: 0; inset-inline: 0; height: 2px;
  z-index: 160; pointer-events: none;
}
.scroll-progress__fill { height: 100%; width: 0; background: var(--green); }

.scroll-rail {
  position: fixed; inset-inline-end: 9px; top: 22vh; bottom: 22vh;
  width: 3px; border-radius: 2px; background: rgba(16, 36, 61, .08);
  z-index: 155; pointer-events: none;
}
.scroll-rail__fill { width: 100%; height: 0; background: var(--teal); border-radius: 2px; }

/* ============================================================================
   BACK TO TOP
   The native scrollbar is hidden, so there is no thumb to drag the page back up
   with — from the footer the only way home was to scroll the whole way. The ring
   around it doubles as a read of how far through the page the reader is.
   ========================================================================= */

.totop {
  position: fixed; z-index: 165;
  inset-inline-end: 22px; bottom: 26px;
  width: 54px; height: 54px; padding: 0;
  display: grid; place-items: center;
  cursor: pointer; border: 0; border-radius: 50%;
  color: var(--green-text); background: var(--white);
  box-shadow: 0 12px 30px -14px rgba(16, 36, 61, .55), 0 0 0 1px var(--card-border);
  /* Parked just below its resting place, and untouchable, until the engine
     brings it in. pointer-events rather than visibility so the fade can run. */
  opacity: 0; pointer-events: none;
  transform: translateY(16px) scale(.82);
  transition: opacity .34s var(--ease), transform .46s var(--ease),
              background .3s var(--ease), color .3s var(--ease),
              box-shadow .3s var(--ease);
}
.totop.is-on { opacity: 1; pointer-events: auto; transform: none; }

/* The halo. Sits behind the button and never takes a click. */
.totop::after {
  content: ''; position: absolute; inset: -10px; z-index: -1;
  border-radius: 50%; pointer-events: none;
  background: radial-gradient(closest-side, rgba(87, 160, 58, .32), transparent 72%);
  opacity: 0; transform: scale(.7);
  transition: opacity .38s var(--ease), transform .38s var(--ease);
}
.totop.is-on:hover::after,
.totop.is-on:focus-visible::after { opacity: 1; transform: none; }

.totop.is-on:hover {
  color: #fff; background: var(--green);
  box-shadow: 0 18px 38px -14px rgba(31, 107, 69, .68), 0 0 0 1px transparent;
}
.totop.is-on:active { transform: scale(.93); }
.totop:focus-visible { outline: 2px solid var(--leaf); outline-offset: 3px; }

/* -- the ring ------------------------------------------------------------- */

/* Rotated so it starts filling from twelve o'clock rather than three. */
.totop__ring {
  position: absolute; inset: 0; width: 100%; height: 100%;
  transform: rotate(-90deg); pointer-events: none;
}
.totop__track { fill: none; stroke: var(--divider); stroke-width: 2; }
.totop__fill {
  fill: none; stroke: var(--leaf); stroke-width: 2; stroke-linecap: round;
  /* pathLength="100" on the circle, so these are percentages in all but name
     and no one has to carry a circumference around. */
  stroke-dasharray: 100; stroke-dashoffset: 100;
  transition: stroke .3s var(--ease);
}
.totop.is-on:hover .totop__fill { stroke: rgba(255, 255, 255, .9); }
.totop.is-on:hover .totop__track { stroke: rgba(255, 255, 255, .28); }

/* -- the arrows ----------------------------------------------------------- */

/* A mask exactly one arrow tall: the first leaves through the top as the second
   arrives from the bottom, so the pair reads as one arrow taking off. */
.totop__arrows {
  position: relative; display: block; width: 19px; height: 19px; overflow: hidden;
}
.totop__arrows svg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  fill: none; stroke: currentColor; stroke-width: 2.1;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .42s var(--ease), opacity .42s var(--ease);
}
.totop__arrows svg + svg { transform: translateY(105%); opacity: 0; }
.totop.is-on:hover .totop__arrows svg { transform: translateY(-105%); opacity: 0; }
.totop.is-on:hover .totop__arrows svg + svg { transform: none; opacity: 1; }

/* -- dark, and out of the administrator's way ----------------------------- */

[data-theme="dark"] .totop {
  box-shadow: 0 14px 34px -12px rgba(0, 0, 0, .8), 0 0 0 1px var(--card-border);
}
[data-theme="dark"] .totop::after {
  background: radial-gradient(closest-side, rgba(99, 200, 146, .3), transparent 72%);
}

/* The editor's bar is fixed across the bottom for a signed-in administrator. */
.totop--raised { bottom: 62px; }

@media (max-width: 620px) {
  .totop { width: 46px; height: 46px; inset-inline-end: 14px; bottom: 16px; }
  .totop--raised { bottom: 58px; }
  .totop__arrows { width: 17px; height: 17px; }
}

/* Motion is the whole effect here, so with it turned off the button simply is
   or is not there — no drift, no launching arrow, no growing halo. */
@media (prefers-reduced-motion: reduce) {
  .totop, .totop::after, .totop__arrows svg, .totop__fill { transition: none; }
  .totop { transform: none; }
  .totop.is-on:active { transform: none; }
}

/* ============================================================================
   CONTEXTUAL CURSOR — desktop only, never blocks a click
   ========================================================================= */

.cursor {
  position: fixed; top: 0; inset-inline-start: 0;
  z-index: 158; pointer-events: none; opacity: 0;
  transform: translate3d(-120px, -120px, 0);
  transition: opacity .3s var(--ease);
}
.cursor__inner {
  display: flex; align-items: center; justify-content: center;
  min-width: 14px; height: 14px; padding: 0;
  border-radius: 999px; background: rgba(31, 107, 69, .94);
  color: #fff; font-size: 12.5px; font-weight: 500; white-space: nowrap;
  transform: translate(-50%, -50%);
  transition: min-width .28s var(--ease), height .28s var(--ease), padding .28s var(--ease);
}
.cursor__label { opacity: 0; transition: opacity .2s; }
.cursor.is-labelled .cursor__inner { min-width: 82px; height: 82px; padding: 0 14px; }
.cursor.is-labelled .cursor__label { opacity: 1; }

/* Mouse-follow elastic fibre — fixed, inert, below the header. The drawing is
   local to the pointer (a small woven patch plus a trailing tuft), never a
   full-screen web, so it can sit over content without hurting readability. */
.fibre-field {
  position: fixed; inset: 0;
  /* Below the header (150), cursor (158), menu (170) and lightbox (180). */
  z-index: 120; pointer-events: none;
  opacity: 0; transition: opacity .8s var(--ease);
}
.fibre-field.is-on { opacity: 1; }

/* ============================================================================
   TOP BAR
   ========================================================================= */

/* Top bar + header travel together as one fixed block. */
.chrome { position: fixed; inset-inline: 0; top: 0; z-index: 150; }

.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  height: 40px; padding: 0 var(--pad);
  background: var(--navy); color: rgba(255, 255, 255, .62); font-size: 12.5px;
  overflow: hidden;
  transition: height .3s var(--ease);
}
/* Collapses once you start scrolling, handing its 40px back to the page. */
.chrome.is-compact .topbar { height: 0; }
.topbar__group { display: flex; align-items: center; gap: 26px; }
.topbar__group--end { gap: 22px; }
.topbar b, .topbar strong { color: #fff; font-weight: 500; }
.topbar a { color: inherit; transition: color .25s var(--ease); }
.topbar a:hover { color: #fff; }
.topbar a:hover b { color: var(--leaf-light); }
.topbar__domain {
  color: rgba(255, 255, 255, .45);
  letter-spacing: .12em; font-size: 11px;
}

/* ============================================================================
   HEADER — fixed with a matching spacer, so sticky can never be broken by an
   ancestor's overflow (that bug is called out in the handoff, item 2).
   ========================================================================= */

/* JS keeps this equal to the chrome's live height, so content never hides beneath it. */
.header-spacer { height: calc(var(--header-h) + 40px); }

.header {
  background: var(--white); border-bottom: 1px solid var(--divider);
  transition: box-shadow .3s var(--ease), background .3s var(--ease);
}
/* Hairline of brand green along the very bottom of the chrome. */
.header::after {
  content: ""; position: absolute; inset-inline: 0; bottom: -1px; height: 1px;
  background: linear-gradient(to left, transparent, rgba(31,107,69,.28) 22%, rgba(14,110,112,.28) 78%, transparent);
  pointer-events: none;
}
.header { position: relative; }
/* The scrolled header is translucent so the page shows through the blur, which
   means it cannot use --white — it needs its own alpha value per theme. Left as
   a literal white it turned the whole bar light again the moment you scrolled. */
.chrome.is-compact .header {
  background: var(--chrome-blur);
  backdrop-filter: blur(14px) saturate(1.4);
  box-shadow: 0 14px 34px -24px rgba(16, 36, 61, .55);
}

.header__row {
  display: flex; align-items: center; justify-content: space-between; gap: 26px;
  height: var(--header-h); padding: 0 var(--pad);
  max-width: var(--wide); margin: 0 auto;
  transition: height .3s var(--ease);
}
.chrome.is-compact .header__row { height: var(--header-h-compact); }

.brand { display: flex; align-items: center; gap: 13px; flex: none; color: inherit; }
.brand__mark { box-shadow: 0 6px 16px -10px rgba(16, 36, 61, .5); }
.brand__mark {
  width: 48px; height: 48px; flex: none; border-radius: 8px; background: var(--white);
  transition: width .3s var(--ease), height .3s var(--ease);
}
.chrome.is-compact .brand__mark { width: 40px; height: 40px; }
.brand__text { display: flex; flex-direction: column; gap: 5px; }
.brand__name { font-size: 17.5px; font-weight: 700; color: var(--heading); line-height: 1; }
.brand__sub {
  font-size: 11.5px; color: var(--teal-text); line-height: 1;
  overflow: hidden; max-height: 16px;
  transition: opacity .3s, max-height .3s;
}
.chrome.is-compact .brand__sub { opacity: 0; max-height: 0; }

.nav { display: flex; align-items: center; gap: 2px; font-size: 14.5px; font-weight: 500; }
.nav__link {
  position: relative; padding: 10px 14px; border-radius: 8px;
  color: var(--body);
  transition: color .25s var(--ease), background .25s var(--ease);
}
.nav__link::before {
  content: ""; position: absolute; inset: 0; border-radius: 8px;
  background: var(--tint-teal); opacity: 0;
  transition: opacity .25s var(--ease);
}
.nav__link:hover { color: var(--teal-text); }
.nav__link:hover::before { opacity: 1; }
.nav__link.is-active { color: var(--teal-text); font-weight: 600; }
/* Lifts the label and the underline above the ::before hover pill. This only
   works because the label is wrapped in a <span> in _Layout — a bare text node
   is not an element and would be painted over. */
.nav__link > * { position: relative; }
.nav__bar {
  position: absolute; inset-inline: 14px; bottom: 2px; height: 2px; border-radius: 2px;
  background: var(--teal); transform: scaleX(0); transform-origin: right;
  transition: transform .3s var(--ease);
}
.nav__link.is-active .nav__bar { transform: scaleX(1); }

.header__end { display: flex; align-items: center; gap: 14px; flex: none; }
.header__phone {
  display: flex; flex-direction: column; gap: 3px; text-align: end;
  padding-inline-end: 16px; margin-inline-end: 2px;
  border-inline-end: 1px solid var(--divider);
}
.header__phone span { font-size: 11px; color: var(--muted); }
.header__phone a { font-size: 14.5px; font-weight: 600; color: var(--heading); }

.burger {
  display: none; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  width: 48px; height: 48px; background: var(--white);
  border: 1px solid var(--control-border); border-radius: 6px; cursor: pointer;
}
/* --heading, not --navy: the button sits on the header SURFACE, which flips with
   the theme, so a fixed brand navy left the three lines invisible in dark. */
.burger span { width: 20px; height: 2px; background: var(--heading); }

/* ============================================================================
   MOBILE MENU
   ========================================================================= */

.menu {
  position: fixed; inset: 0; z-index: 170;
  /* Frosted brand wash rather than flat white, so the panel reads as a layer
     above the page instead of a second page. */
  background: linear-gradient(160deg, var(--white) 0%, var(--white) 58%, var(--tint-green) 100%);
  visibility: hidden; opacity: 0;
  transform: translateY(-8px) scale(.985);
  transition: opacity .32s var(--ease), transform .42s var(--ease), visibility .32s;
  display: flex; flex-direction: column;
}
.menu.is-open { visibility: visible; opacity: 1; transform: none; }

.menu__head {
  display: flex; align-items: center; justify-content: space-between;
  height: 84px; padding: 0 20px; border-bottom: 1px solid var(--divider);
}
.menu__head span { font-size: 17px; font-weight: 700; color: var(--heading); }
.menu__close {
  width: 48px; height: 48px; background: var(--offwhite);
  border: 1px solid var(--control-border); border-radius: 10px;
  font-size: 22px; color: var(--heading); cursor: pointer; line-height: 1;
  transition: background .25s var(--ease), transform .25s var(--ease), color .25s var(--ease);
}
.menu__close:hover, .menu__close:active { background: var(--navy); color: #fff; transform: rotate(90deg); }

.menu__nav { display: flex; flex-direction: column; padding: 8px 20px; overflow-y: auto; }
.menu__nav a {
  position: relative;
  padding: 18px 2px; font-size: 17px; color: var(--heading);
  border-bottom: 1px solid var(--hairline);
  /* Each row slides in from the leading edge, staggered by --i. */
  opacity: 0; transform: translateX(22px);
  transition: opacity .4s var(--ease), transform .5s var(--ease), color .25s var(--ease);
}
.menu.is-open .menu__nav a { opacity: 1; transform: none; }
.menu__nav a:nth-child(1) { transition-delay: .06s; }
.menu__nav a:nth-child(2) { transition-delay: .10s; }
.menu__nav a:nth-child(3) { transition-delay: .14s; }
.menu__nav a:nth-child(4) { transition-delay: .18s; }
.menu__nav a:nth-child(5) { transition-delay: .22s; }
.menu__nav a:nth-child(6) { transition-delay: .26s; }
.menu__nav a:nth-child(7) { transition-delay: .30s; }
.menu__nav a:last-child { border-bottom: 0; }
/* Green rule that grows from the leading edge on the active row. */
.menu__nav a::after {
  content: ""; position: absolute; inset-inline-start: 0; bottom: -1px;
  height: 2px; width: 100%; background: var(--green);
  transform: scaleX(0); transform-origin: right;
  transition: transform .35s var(--ease);
}
.menu__nav a.is-active { color: var(--teal-text); font-weight: 600; }
.menu__nav a.is-active::after { transform: scaleX(1); }

.menu__foot {
  margin-top: auto; padding: 20px;
  display: flex; flex-direction: column; gap: 12px;
  border-top: 1px solid var(--divider);
  opacity: 0; transform: translateY(14px);
  transition: opacity .4s var(--ease) .3s, transform .45s var(--ease) .3s;
}
.menu.is-open .menu__foot { opacity: 1; transform: none; }
.menu__cta {
  display: flex; align-items: center; justify-content: center; height: 58px;
  background: var(--green); color: #fff; font-size: 16px; font-weight: 500;
  border-radius: 12px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .16), 0 14px 30px -18px rgba(23, 86, 58, .8);
}
.menu__tel {
  display: flex; align-items: center; justify-content: center; height: 54px;
  border: 1px solid var(--control-border); border-radius: 12px;
  font-size: 15px; font-weight: 600; color: var(--heading); background: var(--white);
}

/* Burger morphs into a close mark while the panel is open. */
.burger span { transition: transform .3s var(--ease), opacity .2s var(--ease); }
.burger.is-open span:first-child { transform: translateY(4px) rotate(45deg); }
.burger.is-open span:last-child { transform: translateY(-4px) rotate(-45deg); }

/* ============================================================================
   BUTTON SYSTEM (handoff §04)
   Shell + fill layer + label + arrow disc. Asymmetric padding: 26–32px on the
   label side, 6–8px on the disc side. In RTL the fill grows from the disc side
   (left) and the label and arrow drift left — the direction of travel in Persian.
   ========================================================================= */

.btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: space-between; gap: 14px;
  height: 58px;
  padding-inline-start: 28px; padding-inline-end: 7px;
  border: 1px solid transparent; border-radius: 12px;
  overflow: hidden; white-space: nowrap; cursor: pointer;
  font-family: inherit; font-size: 15px; font-weight: 500;
  transition: box-shadow .3s var(--ease), border-color .3s var(--ease),
              background .3s var(--ease), color .3s var(--ease), transform .45s var(--ease);
}
.btn__fill {
  position: absolute; inset: 0;
  transform: scaleX(0); transform-origin: left;
  transition: transform .5s var(--ease); pointer-events: none;
}
.btn__label { position: relative; transition: transform .35s var(--ease); }
.btn__disc {
  position: relative; flex: none;
  display: flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: 50%;
  /* A faint inner ring keeps the disc readable on every ground. */
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14);
  transition: background .35s var(--ease), transform .35s var(--ease),
              box-shadow .35s var(--ease);
}
.btn:hover .btn__disc { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0); }
.btn__arrow {
  display: flex; align-items: center; justify-content: center;
  transition: transform .35s var(--ease), color .35s var(--ease);
}

/* Chevrons are SVG, not "‹": those glyphs are Bidi_Mirrored and flipped in RTL. */
.chev { display: block; }
.chev--back { transform: scaleX(-1); }

.btn:hover .btn__fill { transform: scaleX(1); }
.btn:hover .btn__label { transform: translateX(-3px); }
.btn:hover .btn__disc { transform: scale(1.08); }
.btn:hover .btn__arrow { transform: translateX(-3px); }

.btn--sm { height: 52px; padding-inline-start: 22px; font-size: 14.5px; }
.btn--sm .btn__disc { width: 38px; height: 38px; }
.btn--sm .btn__arrow { font-size: 14px; }
.btn--lg { height: 60px; padding-inline-start: 30px; font-size: 15.5px; }
.btn--lg .btn__disc { width: 44px; height: 44px; }

/* primary — green */
.btn--primary {
  background: var(--green); color: #fff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15),
              0 10px 24px -16px rgba(23, 86, 58, .7);
}
.btn--primary .btn__fill { background: var(--green-deep); }
.btn--primary .btn__disc { background: rgba(255, 255, 255, .22); }
.btn--primary .btn__arrow { color: #fff; }
.btn--primary:hover {
  color: #fff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15),
              0 20px 40px -16px rgba(23, 86, 58, .85);
}
.btn--primary:hover .btn__disc { background: rgba(255, 255, 255, .96); }
.btn--primary:hover .btn__arrow { color: var(--green); }
.btn--primary:active { box-shadow: inset 0 2px 8px rgba(0, 0, 0, .26); }

/* dark — navy */
.btn--dark {
  background: var(--navy); color: #fff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14);
}
.btn--dark .btn__fill { background: var(--teal); }
.btn--dark .btn__disc { background: rgba(255, 255, 255, .2); }
.btn--dark .btn__arrow { color: #fff; }
.btn--dark:hover {
  color: #fff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14), 0 18px 34px -18px rgba(16, 36, 61, .75);
}
.btn--dark:hover .btn__disc { background: rgba(255, 255, 255, .96); }
/* This arrow sits on a near-white disc, not on the page, so it stays navy in
   both themes — --heading would turn it white on white. */
.btn--dark:hover .btn__arrow { color: var(--navy); }
.btn--dark:active { box-shadow: inset 0 2px 8px rgba(0, 0, 0, .3); }

/* outline */
.btn--outline {
  background: var(--white); color: var(--heading); border-color: var(--control-border);
  box-shadow: 0 6px 18px -14px rgba(16, 36, 61, .55);
}
.btn--outline .btn__fill { background: var(--tint-green); }
.btn--outline .btn__disc { background: var(--warm); }
.btn--outline .btn__arrow { color: var(--heading); }
.btn--outline:hover {
  color: var(--heading); border-color: var(--heading);
  box-shadow: 0 16px 32px -18px rgba(16, 36, 61, .5);
}
.btn--outline:hover .btn__disc { background: var(--navy); }
.btn--outline:hover .btn__arrow { color: #fff; }
.btn--outline:active { box-shadow: inset 0 2px 8px rgba(16, 36, 61, .14); }

/* ghost-on-dark — transparent with a light border, for navy/green grounds */
.btn--onDark {
  background: rgba(255, 255, 255, .07); color: #fff;
  border-color: rgba(255, 255, 255, .5);
  backdrop-filter: blur(6px);
}
.btn--onDark .btn__fill { background: rgba(255, 255, 255, .12); }
.btn--onDark .btn__disc { background: rgba(255, 255, 255, .24); }
.btn--onDark .btn__arrow { color: #fff; }
.btn--onDark:hover { color: #fff; border-color: #fff; }
.btn--onDark:hover .btn__disc { background: #fff; }
/* Same as .btn--dark above: the disc is white, so the arrow stays navy. */
.btn--onDark:hover .btn__arrow { color: var(--navy); }

/* white — for the green CTA band */
/* This one lives on the permanently green CTA band, so it stays a white button
   with green type in both themes — the themed tokens would darken it against a
   ground that never darkens. */
.btn--white { background: #fff; color: var(--green); }
.btn--white .btn__fill { background: #F6F5F1; }
.btn--white .btn__disc { background: #ECF4EF; }
.btn--white .btn__arrow { color: var(--green); }
.btn--white:hover { color: var(--green); box-shadow: 0 20px 38px -18px rgba(9, 22, 38, .6); }
.btn--white:hover .btn__disc { background: var(--green); }
.btn--white:hover .btn__arrow { color: #fff; }

.btn:active { transform: translateY(1px); }
.btn[aria-disabled="true"], .btn:disabled { opacity: .45; pointer-events: none; }

.btn-row { display: flex; flex-wrap: wrap; gap: 12px; }

/* ghost link — label + 30px circle */
.ghost-link {
  display: inline-flex; align-items: center; gap: 11px;
  font-size: 14.5px; font-weight: 500; color: var(--green-text);
}
.ghost-link__label { position: relative; transition: transform .3s var(--ease); }
.ghost-link__line {
  position: absolute; inset-inline: 0; bottom: -3px; height: 1px; background: var(--green-text);
  transform: scaleX(0); transform-origin: right; transition: transform .3s var(--ease);
}
.ghost-link__disc {
  display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%;
  border: 1px solid var(--control-border); background: transparent;
  transition: background .3s var(--ease), border-color .3s var(--ease), transform .3s var(--ease);
}
.ghost-link__arrow {
  display: flex; align-items: center; justify-content: center;
  color: var(--green-text); transition: color .3s var(--ease);
}
.ghost-link__arrow .chev { width: 13px; height: 13px; }

/* ============================================================================
   HERO
   ========================================================================= */

.hero {
  position: relative;
  height: min(700px, calc(100vh - 128px));
  min-height: 500px;
  background: var(--navy);
  overflow: hidden;
}
.hero__media { position: absolute; inset: -6% 0; overflow: hidden; }
.hero__layer {
  position: absolute; inset: 0; opacity: 0;
  transform: scale(1.045);
  transition: opacity .95s var(--ease), transform 1.6s var(--ease);
}
.hero__layer.is-front { opacity: 1; transform: scale(1); }
.hero__kb {
  position: absolute; inset: 0;
  transition: transform 9s linear;
}
.hero__kb img { width: 100%; height: 100%; object-fit: cover; }
.hero__veil {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to left,
    rgba(9, 22, 38, .8) 0%, rgba(9, 22, 38, .5) 40%,
    rgba(9, 22, 38, .12) 76%, rgba(9, 22, 38, .04) 100%);
}

.hero__copy {
  position: relative; height: 100%;
  display: flex; align-items: center;
  padding: 0 var(--pad) 132px;
  pointer-events: none;
}
.hero__copyInner { position: relative; z-index: 5; max-width: 670px; pointer-events: auto; }
.hero__slide { display: none; }
.hero__slide.is-active { display: block; }

/* Each line of the active slide rises in turn, so a slide change reads as a
   deliberate transition instead of a straight swap. */
@keyframes heroLineIn {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}
.hero__slide.is-active > * { animation: heroLineIn .75s var(--ease) both; }
.hero__slide.is-active > *:nth-child(1) { animation-delay: .05s; }
.hero__slide.is-active > *:nth-child(2) { animation-delay: .14s; }
.hero__slide.is-active > *:nth-child(3) { animation-delay: .23s; }
.hero__eyebrow {
  display: flex; align-items: center; gap: 11px; margin-bottom: 20px;
  font-size: 13px; font-weight: 500; color: var(--leaf-light);
}
.hero__eyebrow .rule { width: 26px; height: 2px; background: var(--leaf); flex: none; }
.hero__title {
  margin: 0 0 18px;
  font-size: clamp(26px, 3.4vw, 45px);
  line-height: 1.5; font-weight: 800; color: #fff;
}
.hero__sub { font-size: clamp(15px, 1.3vw, 17px); line-height: 2.05; color: rgba(255, 255, 255, .78); }
.hero__cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }

.hero__ctl {
  position: absolute; bottom: 0; inset-inline: 0;
  /* Clears the feature-card band, which rides 58px up over the hero edge and
     otherwise painted straight over the arrows and dots. */
  padding-bottom: 78px; z-index: 12;
  transition: opacity .3s;
}
.hero__ctlRow {
  max-width: var(--wide); margin: 0 auto; padding: 0 var(--pad);
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
}
.hero__arrows { display: flex; gap: 10px; }
.hero__arrow {
  width: 48px; height: 48px; border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .34);
  background: rgba(255, 255, 255, .12); color: #fff;
  cursor: pointer; padding: 0;
  display: flex; align-items: center; justify-content: center;
  backdrop-filter: blur(4px);
  transition: background .3s var(--ease), transform .3s var(--ease), border-color .3s var(--ease);
}
.hero__arrow:hover { background: var(--green); border-color: var(--green-text); transform: scale(1.06); }
.hero__dots { display: flex; gap: 8px; }
.hero__dot {
  width: 44px; height: 4px; border: 0; padding: 0; border-radius: 2px;
  background: rgba(255, 255, 255, .32); cursor: pointer;
  position: relative; overflow: hidden;
}
.hero__dot.is-active { background: rgba(255, 255, 255, .42); }
.hero__dotProg {
  position: absolute; inset: 0; background: var(--white);
  transform: scaleX(0); transform-origin: right;
}
@keyframes akProg { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* ============================================================================
   FEATURE CARDS — overlap the hero's lower edge
   ========================================================================= */

.featwrap {
  position: relative; background: var(--white); z-index: 8;
  border-start-start-radius: 16px; border-start-end-radius: 16px;
  margin-top: -16px;
}
.feat {
  position: relative; margin: -58px auto 0;
  max-width: var(--wide); padding: 0 var(--pad);
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;
}
.feat__card {
  background: var(--white); border-radius: 10px; padding: 28px 26px;
  box-shadow: var(--shadow-feature);
  display: flex; gap: 18px; align-items: flex-start;
  transition: transform .3s var(--ease), box-shadow .3s;
}
.feat__card:hover { transform: translateY(-4px); box-shadow: var(--shadow-card-hover); }
.feat__icon {
  flex: none; width: 46px; height: 46px; border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  background: var(--tint-green); color: var(--green-text);
}
.feat__icon--teal { background: var(--tint-teal); color: var(--teal-text); }
.feat__card h3 { margin: 0 0 8px; font-size: 16.5px; font-weight: 700; color: var(--heading); line-height: 1.6; }
.feat__card p { font-size: 14px; line-height: 1.95; color: var(--muted); }

/* ============================================================================
   ABOUT
   ========================================================================= */

.split {
  max-width: var(--content); margin: 0 auto;
  display: grid; grid-template-columns: 1fr 1.02fr;
  gap: clamp(34px, 5vw, 72px); align-items: center;
}
.about__quote {
  border-inline-start: 3px solid var(--leaf);
  padding-inline-start: 18px; margin: 26px 0 30px;
}
.about__quote p { font-size: 15.5px; line-height: 2.05; color: var(--heading); font-weight: 500; }
.about__figure { position: relative; }
.about__main {
  border-radius: 10px; overflow: hidden;
  aspect-ratio: 4 / 3.3; background: var(--warm);
}
.about__collage {
  position: absolute; inset-inline-start: -26px; bottom: -30px;
  width: 46%; aspect-ratio: 4 / 3;
  border-radius: 10px; overflow: hidden;
  border: 6px solid var(--white); background: var(--warm);
  box-shadow: 0 26px 50px -36px rgba(16, 36, 61, .4);
}
.about__collage img { width: 100%; height: 100%; object-fit: cover; }
.about__grid {
  max-width: var(--content); margin: clamp(42px, 4.4vw, 66px) auto 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;
}
.about__cell {
  border-top: 1px solid var(--divider); padding-top: 22px;
}
.about__cell h3 { margin: 0 0 10px; font-size: 16.5px; font-weight: 700; color: var(--heading); line-height: 1.7; }
.about__cell p { font-size: 14.5px; line-height: 2; color: var(--muted); }

/* Reusable masked image — clip-path wipe + slow zoom-out on reveal */
.mask { position: relative; overflow: hidden; border-radius: 10px; background: var(--warm); }
.mask__zoom { width: 100%; height: 100%; }
.mask__zoom img { width: 100%; height: 100%; object-fit: cover; }

/* ============================================================================
   PRODUCTS — pinned. Wrapper height is computed by JS from the sticky child's
   real height plus real travel; never a vh guess (handoff, item 1).
   ========================================================================= */

.products { background: var(--offwhite); padding: clamp(50px, 5.4vw, 82px) 0 clamp(30px, 4vw, 54px); }
.products__intro { max-width: var(--content); margin: 0 auto; padding: 0 var(--pad); }
.pwrap { position: relative; }
.ppin {
  /* Height follows the content. A fixed 100vh panel holding a ~560px layout
     centred itself and pushed a 100px+ gap below the section heading. */
  position: sticky; top: var(--pin-top);
  padding-block: clamp(24px, 4vh, 52px);
  display: flex; align-items: center;
}
.ppin__inner { width: 100%; max-width: var(--content); margin: 0 auto; padding: 0 var(--pad); }
.pgrid {
  display: grid; grid-template-columns: 1.05fr .95fr;
  gap: clamp(26px, 4vw, 60px); align-items: center;
}
.pvis {
  position: relative; height: min(580px, 62vh);
  border-radius: 12px; overflow: hidden; background: var(--warm);
  box-shadow: 0 30px 60px -46px rgba(16, 36, 61, .5);
  cursor: zoom-in;
}
.pvis__layer { position: absolute; inset: 0; opacity: 0; transition: opacity .55s var(--ease); }
.pvis__layer.is-front { opacity: 1; }
.pvis__layer img { width: 100%; height: 100%; object-fit: cover; }
.pvis__veil {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to top, rgba(9, 22, 38, .34), rgba(9, 22, 38, 0) 46%);
}
.pvis__dots {
  position: absolute; bottom: 16px; inset-inline-start: 16px;
  display: flex; gap: 7px;
}
.pvis__dot {
  width: 26px; height: 3px; border-radius: 2px;
  background: rgba(255, 255, 255, .4); transition: background .3s var(--ease);
}
.pvis__dot.is-active { background: #fff; }

/* The three product steps OVERLAP on desktop: only the active one is visible and
   the scroll engine cross-fades between them. Left in normal flow they stacked
   vertically and the column ran 688px past the pinned panel, pushing two of the
   three steps off-screen. */
.psteps { position: relative; height: min(580px, 62vh); }
.pstep {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; justify-content: center;
  opacity: 0; transform: translateY(18px); pointer-events: none;
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.pstep.is-active { opacity: 1; transform: none; pointer-events: auto; }
.pstep h3 { margin: 0 0 14px; font-size: clamp(21px, 2.2vw, 30px); font-weight: 800; color: var(--heading); line-height: 1.6; }
.pstep p { font-size: 15.5px; line-height: 2.1; color: var(--body); margin-bottom: 24px; }
.pstep__sep { display: none; }

.specs { display: flex; flex-direction: column; gap: 1px; background: var(--card-border);
  border-radius: 8px; overflow: hidden; margin-bottom: 26px; }
.specs__row {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  background: var(--white); padding: 14px 18px; font-size: 14px;
}
.specs__row span:first-child { color: var(--muted); }
.specs__value { color: var(--heading); font-weight: 600; }
/* Pending values render as an explicit bracket placeholder, never as a guess. */
.specs__value--pending { color: var(--muted-2); font-weight: 400; }

/* ============================================================================
   APPLICATIONS — horizontal pin. JS disables the pin entirely when the real
   travel is <= 40px, so a short rail never eats a screen of scroll.
   ========================================================================= */

.hwrap { position: relative; }
.hpin {
  /* --pin-top tracks the live chrome height; a hardcoded offset put this
     panel underneath the chrome whenever the top bar was expanded.

     It fills the viewport below the chrome and centres its contents. An earlier
     full-viewport pin was reverted for leaving 218px of dead air "between the
     heading and the rail" — but that gap existed because the heading sat OUTSIDE
     the pin, so centring the rail alone pushed it away from a heading that could
     not follow. The heading is inside now, so heading, rail and progress bar
     centre together as one block and the gap cannot reappear.

     The panel deliberately does NOT fill the viewport. It did for a while, to
     centre the group vertically, but the group is only ~520px tall against a
     660px box, so the leftover slack showed up as a band of empty page above the
     heading. Hugging the content removes the slack entirely, and top:--pin-top
     already parks it just under the header. */
  position: sticky; top: var(--pin-top);
  padding-block: clamp(24px, 4vh, 52px);
  /* Column, so the progress bar sits in flow BELOW the rail. It used to be
     absolutely positioned 48px off the bottom, which was clear of the cards
     while the pin was a full viewport tall — once the pin shrank to hug its
     content that offset landed the bar 15px on top of the cards. */
  display: flex; flex-direction: column; justify-content: center;
  gap: clamp(18px, 2.4vh, 30px);
  overflow: hidden;
}
/* The pin is a flex column, and .container carries `margin: 0 auto`. On a flex
   item an auto cross-axis margin cancels the stretch, so the container collapsed
   to the width of its own text and those auto margins then centred it — the
   heading drifted to the middle of the screen while every other section's sits
   on the right edge. Stretching it back restores the normal block behaviour. */
.hpin > .container { width: 100%; }

.htrack {
  display: flex; gap: 20px;
  padding-inline: clamp(18px, 10vw, 170px);
  scrollbar-width: none;
}
.htrack::-webkit-scrollbar { display: none; }
.appcard { flex: none; width: min(370px, 82vw); scroll-snap-align: center; }
.appcard__inner {
  background: var(--white); border: 1px solid var(--card-border); border-radius: 12px;
  overflow: hidden; position: relative;
  transition: transform .3s var(--ease), box-shadow .3s;
}
.appcard:hover .appcard__inner { box-shadow: var(--shadow-card); }
.appcard__frame { aspect-ratio: 4 / 3; overflow: hidden; background: var(--warm); }
.appcard__img { width: 100%; height: 100%; transition: transform .5s var(--ease); }
.appcard__img img { width: 100%; height: 100%; object-fit: cover; }
.appcard:hover .appcard__img { transform: scale(1.07); }
.appcard__body { padding: 22px 22px 26px; }
.appcard__line {
  display: block; width: 22px; height: 2px; background: var(--leaf);
  margin-bottom: 14px; transform-origin: right;
  transition: transform .35s var(--ease);
}
.appcard:hover .appcard__line { transform: scaleX(2.4); }
.appcard h3 { margin: 0 0 8px; font-size: 17px; font-weight: 700; color: var(--heading); line-height: 1.7; }
.appcard p { font-size: 14px; line-height: 1.9; color: var(--muted); }

.hbar {
  display: flex; justify-content: center; pointer-events: none;
  flex: none;
}
.hbar__track { width: min(280px, 40vw); height: 3px; border-radius: 2px; background: rgba(16, 36, 61, .1); overflow: hidden; }
.hbar__fill { height: 100%; width: 0; background: var(--teal); border-radius: 2px; }

/* ============================================================================
   ADVANTAGES
   ========================================================================= */

.g4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
.adv {
  background: var(--white); border: 1px solid var(--card-border); border-radius: 12px;
  padding: 30px 26px;
  transition: transform .3s var(--ease), box-shadow .3s;
}
.adv:hover { transform: translateY(-4px); box-shadow: var(--shadow-card); }
.adv__icon {
  width: 46px; height: 46px; border-radius: 8px; margin-bottom: 20px;
  display: flex; align-items: center; justify-content: center;
  background: var(--tint-green); color: var(--green-text);
}
.adv h3 { margin: 0 0 10px; font-size: 16.5px; font-weight: 700; color: var(--heading); line-height: 1.7; }
.adv p { font-size: 14px; line-height: 1.95; color: var(--muted); }

/* ============================================================================
   FACTORY — grid widens and the ground lerps offwhite -> navy on scroll
   ========================================================================= */

.factory { background: var(--offwhite); transition: none; }
.factory__head { max-width: var(--content); margin: 0 auto; }
.stack {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 28px; margin-bottom: clamp(30px, 4vw, 46px);
}
.factory__imgwrap { margin: 0 auto; max-width: var(--content); padding-inline: var(--pad); }
/* Both columns are driven by ONE row height instead of their own aspect ratios.
   Left to themselves the side column (two 4:3 frames) grew to 683px while the
   16:10 main frame was only 472px, leaving 211px of dead space beneath it — and
   over 350px once the grid widens on scroll. */
.facgrid {
  display: grid; grid-template-columns: 1.55fr 1fr; gap: 16px;
  height: min(540px, 56vh);
}
.facgrid .mask { aspect-ratio: auto; height: 100%; cursor: zoom-in; }
.facside { display: flex; flex-direction: column; gap: 16px; height: 100%; }
.facside > div {
  position: relative;
  border-radius: 10px; overflow: hidden; background: var(--warm);
  flex: 1; min-height: 0;
}
/* The photo pans inside a frame that never moves. It is oversized 8% top and
   bottom — more than the parallax can shift it at any viewport height — so the
   pan can never drag a bare edge into view. */
.facside img {
  position: absolute; left: 0; right: 0; top: -8%;
  width: 100%; height: 116%; object-fit: cover;
}

/* Colours JS lerps between; declared here so the section is correct without JS. */
.factory__title { color: var(--heading); transition: color .3s var(--ease); }
.factory__body { color: var(--body); transition: color .3s var(--ease); }
.factory.is-dark .factory__title { color: #fff; }
.factory.is-dark .factory__body { color: rgba(255, 255, 255, .7); }
.factory.is-dark .eyebrow { color: var(--leaf-light); }

/* ============================================================================
   PROCESS — pinned, navy ground
   ========================================================================= */

.process { background: var(--navy); padding: clamp(46px, 4.8vw, 74px) 0; }
.process .h-section { color: #fff; }
.process .note { color: rgba(255, 255, 255, .6); }
.prwrap { position: relative; }
.prpin {
  position: sticky; top: var(--pin-top);
  padding-block: clamp(24px, 4vh, 52px);
  display: flex; align-items: center;
}
.prpin__inner { width: 100%; max-width: var(--content); margin: 0 auto; padding: 0 var(--pad); }
.prgrid {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(26px, 4vw, 60px);
  align-items: stretch;
}
.prvis {
  /* Fills the row so both columns end level — see .facgrid for the same fix. */
  position: relative; height: 100%; min-height: min(430px, 46vh);
  border-radius: 12px; overflow: hidden; background: var(--navy-soft);
}
.prvis__layer { position: absolute; inset: 0; opacity: 0; transition: opacity .55s var(--ease); }
.prvis__layer.is-front { opacity: 1; }
.prvis__layer img { width: 100%; height: 100%; object-fit: cover; }
.prvis__veil {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to top, rgba(9, 22, 38, .55), rgba(9, 22, 38, .05) 60%);
}
.prsteps { display: flex; gap: 22px; }
.prrail {
  position: relative; flex: none; width: 3px; border-radius: 2px;
  background: rgba(255, 255, 255, .14);
}
.prrail__fill {
  position: absolute; top: 0; inset-inline: 0; height: 0;
  background: var(--leaf); border-radius: 2px;
  transition: height .4s var(--ease);
}
.prstep {
  padding: 13px 0; opacity: .32;
  transition: opacity .4s var(--ease), transform .4s var(--ease);
}
.prstep.is-active { opacity: 1; transform: translateX(-6px); }
.prstep__head { display: flex; align-items: baseline; gap: 12px; }
/* The six step numbers are ۰۱ to ۰۶, and in this face those are 9.8px to 14.6px
   wide — so the six titles beside them started on five different edges, a 5px
   ragged column. tabular-nums is the right tool and this face has the feature;
   the min-width is the guarantee that survives the swap to IRANSansX, whose
   files are not in the repo yet and may not carry tabular figures. */
.prstep__num {
  font-size: 13px; font-weight: 600; color: rgba(255, 255, 255, .5);
  font-variant-numeric: tabular-nums; min-width: 1.3em;
  transition: color .3s;
}
.prstep.is-active .prstep__num { color: var(--leaf-light); }
.prstep h3 { margin: 0; font-size: 17px; font-weight: 700; color: #fff; line-height: 1.7; }
.prstep p { margin-top: 5px; font-size: 14px; line-height: 1.9; color: rgba(255, 255, 255, .62); }

/* ============================================================================
   QUALITY
   ========================================================================= */

.qc__figure { position: relative; }
.qc__figure .mask { aspect-ratio: 4 / 3.4; }
.marker {
  position: absolute; display: flex; align-items: center; gap: 10px;
  opacity: 0; transform: translateY(8px);
  transition: opacity .5s var(--ease), transform .5s var(--ease);
}
.marker.is-in { opacity: 1; transform: none; }
.marker__dot {
  width: 10px; height: 10px; border-radius: 50%; flex: none;
  background: var(--leaf); box-shadow: 0 0 0 5px rgba(87, 160, 58, .28);
}
.qc__list { display: flex; flex-direction: column; gap: 1px; background: var(--card-border);
  border-radius: 8px; overflow: hidden; margin: 26px 0; }
.qc__row {
  display: flex; align-items: center; gap: 14px;
  background: var(--offwhite); padding: 15px 18px; font-size: 14.5px; color: var(--body);
  transition: background .25s var(--ease);
}
.qc__row:hover { background: var(--warm); }
.qc__row span:first-child { color: var(--teal-text); font-weight: 600; flex: none; }

/* ============================================================================
   GALLERY
   ========================================================================= */

.galg { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.galitem {
  position: relative; border-radius: 12px; overflow: hidden;
  background: var(--warm); cursor: zoom-in; aspect-ratio: 1 / 1;
  border: 0; padding: 0;
}
.galitem--big { grid-column: span 2; grid-row: span 2; }
.galitem__img { width: 100%; height: 100%; transition: transform .5s var(--ease); }
.galitem__img img { width: 100%; height: 100%; object-fit: cover; }
.galitem:hover .galitem__img { transform: scale(1.07); }

/* ============================================================================
   ARTICLES
   ========================================================================= */

.g3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
.artcard {
  background: var(--white); border: 1px solid var(--card-border); border-radius: 12px;
  overflow: hidden; display: flex; flex-direction: column;
  transition: transform .3s var(--ease), box-shadow .3s, border-color .3s;
}
.artcard:hover { transform: translateY(-4px); box-shadow: var(--shadow-card); }
/* 16/10 gave the photo 51% of the card's height on the articles index, which put
   the headline and summary — the part being scanned — below the fold. */
.artcard__frame { position: relative; aspect-ratio: 16 / 9; overflow: hidden; background: var(--warm); }
.artcard__img { width: 100%; height: 100%; transition: transform .5s var(--ease); }
.artcard__img img { width: 100%; height: 100%; object-fit: cover; }
.artcard:hover .artcard__img { transform: scale(1.06); }
/* Frosted glass over a photograph.

   Two things need this — the date on an article card and the spec markers on the
   quality photograph — and they have to stay identical, so it is written once
   rather than copied. Both used to be near-solid white chips, which read as
   stickers laid on top of the picture rather than part of it.

   The tint is dark and the text white on purpose: the photograph underneath is
   whatever the client uploads, and a light chip with dark text stops being
   legible the moment somebody posts a bright picture.

   .62 is not a taste decision. Composited over pure white it leaves the chip at
   about #68717D, which is 4.9:1 against the white text — over the AA floor of
   4.5 for text this small. At .38, where this started, the same worst case was
   2.4:1. Over the photographs actually on the site it lands nearer 9:1 and still
   reads as glass, because the blur keeps the picture visible through it.

   Not themed. These sit on a photograph, not on the page's own ground, and the
   photograph does not change when the reader switches to light.

   -webkit- as well as the plain property, unlike the rest of the glass on this
   site: those sit on solid colours and simply look flat without it, whereas
   these hold white text over an arbitrary picture. iOS Safari before 18 needs
   the prefix. */
.artcard__date,
.marker__label {
  padding: 6px 11px; border-radius: 8px;
  font-size: 11.5px; font-weight: 500; color: #fff;
  background: rgba(11, 26, 46, .62);
  border: 1px solid rgba(255, 255, 255, .28);
  -webkit-backdrop-filter: blur(14px) saturate(1.6);
  backdrop-filter: blur(14px) saturate(1.6);
  box-shadow: 0 8px 20px -12px rgba(0, 0, 0, .7);
  text-shadow: 0 1px 2px rgba(0, 0, 0, .3);
}
/* Nothing to frost: without the blur the tint alone would leave the text sitting
   on a busy photograph, so it goes opaque enough to read on its own. */
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .artcard__date,
  .marker__label { background: rgba(11, 26, 46, .78); }
}

.artcard__date { position: absolute; top: 14px; inset-inline-start: 14px; }
.marker__label { white-space: nowrap; font-size: 12.5px; padding: 7px 11px; }
.artcard__body { padding: 24px 24px 26px; display: flex; flex-direction: column; flex: 1; }
.artcard__cat { font-size: 12px; font-weight: 600; color: var(--teal-text); margin-bottom: 12px; }
.artcard h3 { margin: 0 0 10px; font-size: 17.5px; font-weight: 700; color: var(--heading); line-height: 1.7; }
.artcard p { font-size: 14px; line-height: 1.95; color: var(--muted); margin-bottom: 20px; }
.artcard__more { margin-top: auto; }
.artcard:hover .ghost-link__disc { background: var(--green); border-color: var(--green-text); transform: translateX(-3px); }
.artcard:hover .ghost-link__arrow { color: #fff; }
.artcard:hover .ghost-link__label { transform: translateX(-2px); }
.artcard:hover .ghost-link__line { transform: scaleX(1); }

/* ============================================================================
   SALES CTA — ground lerps offwhite -> footer navy on scroll
   ========================================================================= */

.cta { padding: clamp(40px, 4vw, 60px) var(--pad) clamp(44px, 4.4vw, 66px); background: var(--offwhite); }
.ctaband {
  max-width: var(--content); margin: 0 auto;
  display: flex; align-items: center; justify-content: space-between; gap: 34px;
  background: var(--green); border-radius: 14px; padding: clamp(26px, 4vw, 52px);
  box-shadow: 0 40px 80px -50px rgba(23, 86, 58, .85);
}
.ctaband h2 { margin: 0 0 14px; font-size: clamp(19px, 2vw, 26px); line-height: 1.85; font-weight: 700; color: #fff; }
.ctaband p { font-size: 14.5px; line-height: 2; color: rgba(255, 255, 255, .8); }
.ctaband__tel { display: flex; flex-wrap: wrap; gap: 22px; margin-top: 18px; font-size: 14px; color: rgba(255, 255, 255, .75); }
.ctaband__tel a { color: #fff; font-weight: 600; }
.ctaband__actions { display: flex; flex-direction: column; gap: 12px; flex: none; }

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

.footer { background: var(--footer); color: rgba(255, 255, 255, .64); padding: clamp(46px, 6vw, 74px) var(--pad) 0; }
.footer__inner { max-width: var(--content); margin: 0 auto; }
.footg { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1.2fr; gap: clamp(26px, 4vw, 50px); padding-bottom: 42px; }
.footer__brand { display: flex; align-items: center; gap: 13px; margin-bottom: 20px; }
.footer__logo {
  width: 54px; height: 54px; border-radius: 10px; overflow: hidden;
  background: var(--white); flex: none; display: flex; align-items: center; justify-content: center;
}
.footer__logo img { width: 100%; height: 100%; object-fit: contain; }
.footer__name { font-size: 16.5px; font-weight: 700; color: #fff; display: block; }
.footer__desc { font-size: 12.5px; color: rgba(255, 255, 255, .5); margin-top: 6px; display: block; }
.footer p { font-size: 14px; line-height: 2.05; color: rgba(255, 255, 255, .58); }
.footer__social { display: flex; gap: 10px; margin-top: 22px; }
.footer__social a,
.footer__social span {
  width: 42px; height: 42px; border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .18); color: rgba(255, 255, 255, .78);
  display: flex; align-items: center; justify-content: center;
  transition: background .3s var(--ease), border-color .3s var(--ease),
              color .3s var(--ease), transform .3s var(--ease);
}
.footer__social a:hover { transform: translateY(-2px); }
.footer__social a:hover { background: var(--green); border-color: var(--green-text); color: #fff; }
/* Pending tiles: visibly inert, and not in the tab order (rendered as spans). */
.footer__social span[aria-disabled="true"] { opacity: .4; cursor: default; }
.footer__title { font-size: 14px; font-weight: 700; color: #fff; margin-bottom: 18px; }
.footer__links { display: flex; flex-direction: column; gap: 12px; }
.footer__links a { font-size: 14px; color: rgba(255, 255, 255, .62); transition: color .25s; }
.footer__links a:hover { color: #fff; }
.footer__contact { display: flex; flex-direction: column; gap: 16px; }
.footer__contact > div > div { font-size: 12px; color: rgba(255, 255, 255, .42); margin-bottom: 5px; }
.footer__contact a, .footer__contact span { font-size: 14.5px; color: #fff; font-weight: 500; }
.footer__contact .pending { color: rgba(255, 255, 255, .5); font-weight: 400; }
.footer__bottom {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  border-top: 1px solid rgba(255, 255, 255, .1);
  padding: 24px 0 30px; font-size: 12.5px; color: rgba(255, 255, 255, .45);
}
.footer__credit { color: rgba(255, 255, 255, .45); }
.footer__credit a {
  color: rgba(255, 255, 255, .74); font-weight: 500;
  border-bottom: 1px solid rgba(255, 255, 255, .22);
  transition: color .25s var(--ease), border-color .25s var(--ease);
}
.footer__credit a:hover { color: var(--leaf-light); border-color: var(--leaf-light); }

/* ============================================================================
   LIGHTBOX
   ========================================================================= */

.lb {
  position: fixed; inset: 0; z-index: 180;
  background: rgba(9, 22, 38, .93);
  display: flex; align-items: center; justify-content: center;
  padding: clamp(16px, 4vw, 52px);
  opacity: 0; visibility: hidden; cursor: zoom-out;
  transition: opacity .3s var(--ease), visibility .3s;
}
.lb.is-open { opacity: 1; visibility: visible; }
.lb img {
  max-width: 100%; max-height: 100%; object-fit: contain;
  border-radius: 10px; transform: scale(.96);
  transition: transform .35s var(--ease);
}
.lb.is-open img { transform: scale(1); }
.lb__close {
  position: absolute; top: 20px; inset-inline-end: 20px;
  width: 48px; height: 48px; border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .3); background: rgba(255, 255, 255, .1);
  color: #fff; font-size: 24px; line-height: 1; cursor: pointer;
}

/* ============================================================================
   REVEAL — initial states. JS adds .is-in; the no-JS fallback below guarantees
   nothing stays invisible if scripting is off or an observer misfires.
   ========================================================================= */

.js [data-rv],
.js [data-stg] { opacity: 0; transform: translateY(16px); }
.js [data-rv].is-in,
.js [data-stg].is-in { opacity: 1; transform: none; }

.js [data-line] { transform: scaleX(0); }
.js [data-stg].is-in [data-line],
.js [data-line].is-in { transform: scaleX(1); }

/* A mask is clipped to nothing at rest, so its whole duration is time the reader
   spends looking at an empty frame. 1.05s + a 1.3s zoom on top made the About
   photo read as arriving long after the text beside it. The observer now fires
   these before the frame reaches the fold (see setupReveals); these durations are
   the second half of that fix. */
.js [data-mask="v"] { clip-path: inset(100% 0 0 0); transition: clip-path .7s var(--ease); }
.js [data-mask="h"] { clip-path: inset(0 0 0 100%); transition: clip-path .7s var(--ease); }
.js [data-mask].is-in { clip-path: inset(0 0 0 0); }
.js [data-mask] .mask__zoom { transform: scale(1.12); transition: transform .9s var(--ease); }
.js [data-mask].is-in .mask__zoom { transform: scale(1); }

/* ============================================================================
   ADMIN EDIT BAR — only ever rendered for a signed-in administrator
   ========================================================================= */

/* Fixed to the bottom rather than the top: the top is already a fixed header and
   a second bar there would push the whole page down and change every measurement
   the scroll engine takes. */
.editbar {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 190;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 8px 16px;
  background: #0B1A2E; color: rgba(255, 255, 255, .72);
  font-size: 12.5px; box-shadow: 0 -8px 24px -18px rgba(0, 0, 0, .8);
}
.editbar__tag {
  background: var(--leaf); color: #0B1A2E; font-weight: 700;
  border-radius: 5px; padding: 2px 9px; margin-inline-end: 6px;
}
.editbar a { color: rgba(255, 255, 255, .82); padding: 5px 11px; border-radius: 6px; }
.editbar a:hover { background: rgba(255, 255, 255, .12); color: #fff; }

.editbar__btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; margin-inline-end: 4px; cursor: pointer;
  font: inherit; font-size: 12.5px; font-weight: 700;
  color: #0B1A2E; background: #fff; border: 0; border-radius: 6px;
}
.editbar__btn svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.editbar__btn[aria-pressed="true"] { background: var(--leaf); }

/* Keeps the footer clear of the bar so nothing is hidden behind it. */
.editbar ~ footer { padding-bottom: 52px; }

/* ============================================================================
   ON-SITE EDITING

   Everything below applies only under .ed-on, which the bar's button toggles.
   An administrator reading their own site sees it exactly as a visitor does
   until they ask to edit.
   ========================================================================= */

.ed-t { cursor: inherit; }

.ed-on .ed-t {
  cursor: text; border-radius: 3px;
  box-shadow: 0 0 0 1px rgba(31, 107, 69, .35);
  transition: box-shadow .16s ease, background-color .16s ease;
}
.ed-on .ed-t:hover { background: rgba(31, 107, 69, .09); box-shadow: 0 0 0 2px rgba(31, 107, 69, .55); }
.ed-on .ed-t:focus-visible { outline: 2px solid var(--green-text); outline-offset: 2px; }

.ed-t.is-editing {
  background: var(--surface); box-shadow: 0 0 0 2px var(--green-text); outline: none;
}
.ed-t.is-saving { opacity: .55; }
.ed-t.is-saved { box-shadow: 0 0 0 2px var(--green-text); background: rgba(31, 107, 69, .14); }

/* The pencil over a picture, and the "manage" link over a section. Both are
   hidden until editing is switched on. */
.ed-pencil, .ed-manage {
  position: absolute; z-index: 20; inset-inline-start: 12px; top: 12px;
  display: none; align-items: center; gap: 6px;
  padding: 7px 12px; cursor: pointer;
  font-family: inherit; font-size: 12.5px; font-weight: 700;
  color: #0B1A2E; background: rgba(255, 255, 255, .94);
  border: 0; border-radius: 8px; box-shadow: 0 6px 20px -8px rgba(0, 0, 0, .5);
}
.ed-on .ed-pencil, .ed-on .ed-manage { display: inline-flex; }
.ed-pencil:hover, .ed-manage:hover { background: #fff; color: var(--green-text); }
.ed-pencil svg, .ed-manage svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }

/* The footer's row of social icons is 42px circles with no spare room, so the
   floating button landed squarely on the last one. There it joins the row as an
   ordinary item on a line of its own, and sheds the circle shape the row gives
   every anchor inside it. */
.footer__social { flex-wrap: wrap; }
.ed-on .footer__social > .ed-manage {
  position: static;
  flex: 0 0 100%; order: 99; align-self: flex-start;
  width: fit-content; height: auto; margin-top: 10px; white-space: nowrap;
  padding: 7px 12px; border: 0; border-radius: 8px;
  color: #0B1A2E; background: rgba(255, 255, 255, .94);
}
.ed-on .footer__social > .ed-manage:hover {
  transform: none; color: var(--green-text); background: #fff; border-color: transparent;
}
/* The row styles every span inside it as a 42px circle in translucent white,
   which caught the button's own label: white text on a white chip, inside a
   circle. It is plain text here. */
.ed-on .footer__social > .ed-manage span {
  display: inline; width: auto; height: auto;
  border: 0; border-radius: 0; color: inherit; transition: none;
}

/* -- the picture chooser -------------------------------------------------- */

.ed-pick {
  border: 0; padding: 0; border-radius: 14px;
  width: min(760px, calc(100vw - 28px)); max-height: calc(100vh - 60px);
  background: var(--surface); color: var(--body);
  box-shadow: 0 40px 90px -50px rgba(0, 0, 0, .85);
}
.ed-pick::backdrop { background: rgba(9, 18, 30, .55); backdrop-filter: blur(2px); }

.ed-pick__head {
  display: flex; align-items: center; gap: 10px;
  padding: 16px 20px; border-bottom: 1px solid var(--hairline);
}
.ed-pick__head strong { font-size: 15px; color: var(--heading); }
.ed-pick__what { flex: 1; font-size: 12.5px; color: var(--muted); }
.ed-pick__x {
  width: 30px; height: 30px; flex: none; cursor: pointer; font-size: 20px; line-height: 1;
  color: var(--muted); background: none; border: 0; border-radius: 7px;
}
.ed-pick__x:hover { background: var(--offwhite); color: var(--heading); }

.ed-pick__grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px;
  padding: 18px 20px; max-height: 62vh; overflow-y: auto;
}
.ed-pick__opt {
  display: flex; flex-direction: column; gap: 7px; padding: 0; cursor: pointer;
  font: inherit; text-align: start;
  background: none; border: 1px solid var(--hairline); border-radius: 10px; overflow: hidden;
}
.ed-pick__opt:hover { border-color: var(--green-text); }
.ed-pick__opt img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; display: block; }
.ed-pick__opt span { padding: 0 10px 10px; font-size: 12.5px; color: var(--heading); }

.ed-pick__foot { padding: 14px 20px; border-top: 1px solid var(--hairline); font-size: 12.5px; }

/* -- the line of feedback ------------------------------------------------- */

.ed-toast {
  position: fixed; z-index: 200; inset-inline-start: 16px; bottom: 62px;
  padding: 10px 16px; border-radius: 9px;
  font-size: 13px; color: #fff; background: #14512F;
  opacity: 0; transform: translateY(8px); pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
}
.ed-toast.is-on { opacity: 1; transform: none; }
.ed-toast.is-bad { background: #8E1F19; }

@media (max-width: 620px) {
  .editbar { font-size: 12px; padding: 6px 10px; }
  .editbar a { padding: 5px 8px; }
}

/* ============================================================================
   THEME TOGGLE
   ========================================================================= */

.themetoggle {
  width: 40px; height: 40px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--control-border); border-radius: 10px;
  background: var(--white); color: var(--heading);
  cursor: pointer; padding: 0;
  transition: border-color .25s var(--ease), background .25s var(--ease), color .25s var(--ease);
}
.themetoggle:hover { border-color: var(--teal-text); color: var(--teal-text); }
.themetoggle:focus-visible { outline: 2px solid var(--teal-text); outline-offset: 2px; }
.themetoggle__icon { width: 18px; height: 18px; }
.themetoggle__sun { fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; }
.themetoggle__moon { fill: currentColor; }

/* Show the scheme you would switch TO, which is the opposite of the one you are
   in — a moon while light, a sun while dark. */
.themetoggle__sun { display: none; }
[data-theme="dark"] .themetoggle__moon { display: none; }
[data-theme="dark"] .themetoggle__sun { display: block; }

/* ============================================================================
   PRELOADER

   Shown only while the page is actually still arriving. The content sits in the
   DOM behind it the whole time, so crawlers and no-JS visitors are unaffected.
   ========================================================================= */

/* Default is hidden. Without scripting nothing would ever dismiss this, so it
   must not render at all — the head script adds .pl to opt in. */
.preloader { display: none; }

.pl .preloader {
  position: fixed; inset: 0; z-index: 300;
  display: grid; place-content: center; justify-items: center;
  background: var(--offwhite);
  /* Failsafe. If site.js never arrives, CSS alone still clears the overlay —
     the site must never be stranded behind a loader nothing can dismiss. */
  animation: pl-failsafe 0s 8s forwards;
}
.preloader.is-done {
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .45s var(--ease), visibility .45s var(--ease);
}
@keyframes pl-failsafe { to { opacity: 0; visibility: hidden; pointer-events: none; } }

.preloader__mark { position: relative; display: grid; place-items: center; width: 116px; height: 116px; }
.preloader__mark img { width: 58px; height: 58px; object-fit: contain; }
.preloader__ring { position: absolute; inset: 0; width: 116px; height: 116px; transform: rotate(-90deg); }
/* The ring is now the only indicator, so it carries a little more weight. */
.preloader__ring circle { fill: none; stroke-width: 4; }
.preloader__track { stroke: rgba(16, 36, 61, .10); }
.preloader__fill {
  stroke: var(--leaf); stroke-linecap: round;
  transition: stroke-dashoffset .32s var(--ease);
}

/* The ring reports real progress, so it stays; only the easing is dropped. */
@media (prefers-reduced-motion: reduce) {
  .preloader__fill { transition: none; }
  .preloader.is-done { transition: none; }
}

/* ============================================================================
   RESPONSIVE
   ========================================================================= */

@media (max-width: 1240px) {
  .nav__link { padding-inline: 8px; font-size: 13.5px; }
  .header__phone { display: none; }
}

@media (max-width: 1080px) {
  /* Handoff: at <=1080 there is no pinning, no forced horizontal scroll,
     no parallax, no custom cursor and no canvas — only reveal and crossfade. */
  .desk-only { display: none !important; }
  .burger { display: flex; }
  .topbar, .scroll-rail, .cursor, .fibre-field { display: none !important; }

  .split, .prgrid, .pgrid, .facgrid { grid-template-columns: 1fr !important; }
  /* Portrait crops get too tall once the split collapses to one column. */
  .about__main { aspect-ratio: 16 / 10; }
  .qc__figure .mask { aspect-ratio: 16 / 10; }
  .split { gap: 32px; }
  .g3, .g4, .about__grid { grid-template-columns: repeat(2, 1fr); }

  .feat { position: static; margin: 0 auto; }
  .featwrap { padding: 26px 0 0; margin-top: 0; border-radius: 0; }
  .hero { height: 520px; }
  .about__collage { display: none; }
  .facgrid { height: auto; }
  .facgrid .mask { aspect-ratio: 16 / 10; height: auto; }
  .facside { flex-direction: row; height: auto; }
  .facside > div { aspect-ratio: 4 / 3; }

  .pwrap, .hwrap, .prwrap { height: auto !important; }
  .ppin, .prpin { position: static; height: auto; }
  /* min-height too: with no pin there is nothing to centre inside, and a
     viewport-tall panel would just be a screen of white above the cards. */
  .hpin { position: static; height: auto; min-height: 0; overflow: visible; }


  /* Two full-width buttons took most of the first screen on a phone. */
  .hero__cta--desk { display: none; }

  /* The "۰۱ / ۰۳" counter belongs to the pinned desktop panel, where it says
     which of three frames you are on. Stacked on a phone every step is visible
     at once, so it counts nothing and only adds a line. */
  /* Scoped to the case where nothing else owns the transform: below 760px the
     slider drives this track, and an !important reset there would pin it to the
     first card forever. */
  .hslide:not(.is-slider) .htrack {
    transform: none !important;
    overflow-x: auto; scroll-snap-type: x mandatory;
    padding-inline: var(--pad); padding-bottom: 12px;
  }
  .hbar { display: none; }

  /* relative, NOT static: .pvis__layer and .pvis__dots are position:absolute and
     need this element as their containing block. Setting it static handed them to
     .pwrap instead, and the image rendered 1642px tall over the whole section. */
  .pvis { position: relative; height: auto; aspect-ratio: 16 / 10; margin: 4px 0 18px; }
  .psteps { position: static; height: auto; }
  .pstep { position: static; height: auto; padding: 0 0 10px; opacity: 1; transform: none; pointer-events: auto; }
  .pstep__sep { display: block; height: 1px; background: var(--card-border); margin-bottom: 26px; }
  /* Same as .pvis above — .prvis__layer, __veil and __num are absolute. */
  .prvis { position: relative; height: auto; min-height: 0; max-height: none; aspect-ratio: 16 / 10; margin: 4px 0 16px; }
  /* .prstep.is-active is more specific, so resetting only .prstep left the
     active nudge in place — and on a phone every step is active at once and
     already spans the column, so all six sat 6px outside the text column and
     pushed 6px of horizontal overflow behind html's overflow-x. Both selectors,
     or the reset does nothing. */
  .prstep,
  .prstep.is-active { opacity: 1; transform: none; }
  .prrail { display: none; }

  .galg { grid-template-columns: repeat(2, 1fr); }
  /* max-height as well as aspect-ratio: the ratio alone left this tile square
     and 69% of the viewport tall on tablet, and a hard cap cannot be ignored. */
  .galg .galitem--big {
    grid-column: span 2; grid-row: auto;
    aspect-ratio: 16 / 10; max-height: 46vh;
  }
}

@media (max-width: 760px) {
  .g3, .g4, .about__grid, .galg { grid-template-columns: 1fr; }
  .section, .section-lg { padding-top: 54px; padding-bottom: 54px; }
  .stack, .footer__bottom { flex-direction: column; align-items: flex-start; }
  .btn-row, .ctaband__actions, .hero__cta { flex-direction: column; align-items: stretch; }
  .btn { justify-content: space-between; }
  .facside { flex-direction: column; }
  .facside > div { aspect-ratio: 16 / 10; }
  .hero { height: auto; }
  .hero__media { position: relative; inset: 0; height: 60vh; min-height: 330px; }
  .hero__copy { position: absolute; inset: 0; padding-bottom: 54px; }
  .hero__title { font-size: 25px; }
  .hero__arrows { display: none; }
  .footg { grid-template-columns: 1fr; }
  .ctaband { flex-direction: column; align-items: flex-start; }
  .galg .galitem--big { grid-column: auto; aspect-ratio: 16 / 11; max-height: 40vh; }

  /* -- sliders ------------------------------------------------------------
     Three sections stacked their tiles into one very tall column here: the
     gallery ran to about five screens of photographs, and the factory and the
     articles cost three more between them. One item at a time is the same
     content in a fraction of the height.

     The class is added by the engine, not written here. The track only travels
     because something is driving it, and CSS that hid four of five pictures
     with no way to reach them would be worse than the tall stack. */
  [data-slider].is-slider { overflow: hidden; touch-action: pan-y; }
  [data-slider].is-slider > [data-slidertrack] {
    display: flex; gap: 0;
    transition: transform .55s var(--ease);
  }
  /* A box between the track and the items has to stop being one, or everything
     inside it would travel together as a single slide. */
  [data-slider].is-slider [data-slidefold] { display: contents; }
  [data-slider].is-slider [data-slide] { flex: 0 0 100%; max-width: 100%; }

  /* One shared ratio across the items of a track. Separate ratios per item is
     the dead-space bug from the facts and products grids, and in a track it
     also makes the whole thing change height as it moves. */
  .galwrap.is-slider { border-radius: 12px; }
  .galwrap.is-slider .galitem,
  .galwrap.is-slider .galitem--big {
    aspect-ratio: 16 / 11; max-height: none; border-radius: 12px;
  }
  /* The wrapper carries the rounding and the hairline now. */
  .galwrap.is-slider .galitem { outline: 0; box-shadow: none; }

  .factory__imgwrap.is-slider { border-radius: 14px; }
  .factory__imgwrap.is-slider .facgrid { height: auto; }
  .factory__imgwrap.is-slider .mask,
  .factory__imgwrap.is-slider .facside > div {
    aspect-ratio: 16 / 10; height: auto;
  }

  /* Cards, not pictures: they size themselves, and the flex row already makes
     every one as tall as the tallest so the track cannot jump between them.
     The padding is headroom for the card's own drop shadow, which the
     wrapper's overflow would otherwise cut off square. */
  /* The rail already lays its cards out in a row; in slider mode it just stops
     scrolling natively and starts being moved a whole card at a time. */
  /* margin, not padding: overflow clips at the PADDING box, so an inset written
     as padding leaves a strip the next card is still visible through. */
  .hslide.is-slider { margin-inline: var(--pad); }
  .hslide.is-slider .htrack {
    overflow-x: visible; scroll-snap-type: none;
    padding-inline: 0; padding-bottom: 0;
  }
  .hslide.is-slider .appcard { width: 100%; }

  .artwrap.is-slider { padding-bottom: 12px; }
  .artwrap.is-slider .artcard:hover { transform: none; }

  .sldots { display: flex; gap: 7px; justify-content: center; margin-top: 14px; }
  .sldot {
    width: 30px; height: 4px; padding: 0; border: 0; border-radius: 2px;
    background: var(--control-border); cursor: pointer;
    transition: background .3s var(--ease), width .3s var(--ease);
  }
  .sldot[aria-current="true"] { width: 46px; background: var(--green-text); }
  .sldot:focus-visible { outline: 2px solid var(--leaf); outline-offset: 3px; }
}

/* ============================================================================
   REDUCED MOTION — the whole scroll engine, canvas and cursor go quiet and
   every element renders in its final state.
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .cursor, .fibre-field { display: none !important; }
  .js [data-rv], .js [data-stg] { opacity: 1; transform: none; }
  .js [data-mask] { clip-path: none; }
  .js [data-mask] .mask__zoom { transform: none; }
  .js [data-line] { transform: scaleX(1); }
  .pstep, .prstep { opacity: 1; transform: none; pointer-events: auto; }
  .pwrap, .prwrap, .hwrap { height: auto !important; }
  .ppin, .prpin, .hpin { position: static; height: auto; }
}

/* ============================================================================
   INNER PAGES
   ========================================================================= */

/* This banner holds a breadcrumb, an eyebrow and a title — about 134px of text.
   At the old clamps it padded that out to a 264px band: half the element was
   empty, and with the following section's own top padding the reader met 333px
   of nothing before the first card. The padding is now proportionate to what it
   frames. */
.pagehead {
  background: var(--offwhite);
  border-bottom: 1px solid var(--divider);
  padding: clamp(24px, 3vw, 40px) var(--pad) clamp(22px, 2.5vw, 34px);
}
.pagehead__inner { max-width: var(--content); margin: 0 auto; }
/* Do not tighten this below 1.6. Persian sets taller than Latin at the same
   size: at 38.4px the glyph box measures 60px, so 1.35 gave a 51.8px line the
   type overflowed by 5px above and 3px below — the title collided with the
   breadcrumb. The mobile rule below has always used 1.6 for the same reason. */
.pagehead h1 {
  margin: 0 0 14px;
  font-size: clamp(25px, 3vw, 40px); line-height: 1.6; font-weight: 800; color: var(--heading);
}
/* Three pages pass no lede, and there the title's trailing margin was 14px of
   invisible space stacked on top of the padding below it. */
.pagehead h1:last-child { margin-bottom: 0; }
.pagehead .lede { max-width: 760px; }

/* Every inner page is .pagehead followed by .section, so the banner's bottom
   padding and the section's top padding always stacked. Only one of them needs
   to carry that separation. */
.pagehead + .section { padding-top: clamp(30px, 3.4vw, 46px); }

/* Same stacking at the other end: the footer opens with 74px of its own padding,
   and the last section added 69px under its content — 143px of nothing between
   the last card and the first line of the footer. */
main > .section:last-child,
main > .section-lg:last-child { padding-bottom: clamp(22px, 2.6vw, 34px); }

.crumbs { display: flex; align-items: center; gap: 9px; margin-bottom: 10px; font-size: 12.5px; color: var(--muted); }
.crumbs a { color: var(--muted); }
.crumbs a:hover { color: var(--teal-text); }
.crumbs span[aria-current] { color: var(--heading); }

/* A frank notice where the design says content is still owed by the client. */
.awaiting {
  border-inline-start: 3px solid var(--leaf);
  background: var(--offwhite); border-radius: 8px;
  padding: 18px 20px; font-size: 13.5px; line-height: 2; color: var(--muted);
  margin: 26px 0;
}
.awaiting strong { color: var(--heading); font-weight: 600; }

.prose { max-width: 760px; }
.prose p { font-size: 16px; line-height: 2.15; color: var(--body); margin-bottom: 18px; }

/* ---------------------------------------------------------------------------
   A body written in the panel's editor. The tags here are exactly the ones
   RichText.Sanitize allows through, so nothing else can turn up in this block.
   ------------------------------------------------------------------------ */

.rich > *:last-child { margin-bottom: 0; }
.rich p { font-size: 16px; line-height: 2.15; color: var(--body); margin: 0 0 18px; }

.rich h2, .rich h3, .rich h4 { color: var(--heading); margin: 34px 0 14px; }
.rich > h2:first-child, .rich > h3:first-child { margin-top: 0; }
.rich h2 { font-size: clamp(21px, 2.4vw, 26px); font-weight: 800; line-height: 1.65; }
.rich h3 { font-size: clamp(18px, 2vw, 21px); font-weight: 700; line-height: 1.7; }
.rich h4 { font-size: 17px; font-weight: 700; line-height: 1.75; }

.rich ul, .rich ol { margin: 0 0 18px; padding-inline-start: 24px; }
.rich li { font-size: 16px; line-height: 2.15; color: var(--body); margin-bottom: 8px; }

.rich blockquote {
  margin: 24px 0; padding: 16px 22px;
  font-size: 16.5px; line-height: 2.1; color: var(--heading);
  background: var(--offwhite); border-inline-start: 3px solid var(--green-text);
  border-radius: 0 10px 10px 0;
}

.rich a { color: var(--teal-text); text-decoration: underline; text-underline-offset: 3px; }
.rich a:hover { text-decoration-thickness: 2px; }

.rich figure { margin: 30px 0; }
.rich img { display: block; width: 100%; height: auto; border-radius: 12px; }
.rich figcaption {
  margin-top: 10px; font-size: 13.5px; line-height: 1.9; color: var(--muted); text-align: center;
}

.rich hr { margin: 30px 0; border: 0; border-top: 1px solid var(--hairline); }

.rich video {
  display: block; max-width: 100%; height: auto;
  border-radius: 12px; background: #0B1A2E;
}

/* ---------------------------------------------------------------------------
   The classes the panel's toolbar writes.

   Repeated from admin.css on purpose: the two stylesheets are deliberately
   separate, and this is the half that makes what an editor saw while writing
   match what a visitor sees. The same names are the allow-list in
   RichText.AllowedClasses — all three move together or not at all.
   ------------------------------------------------------------------------ */

/* typefaces — only faces the site actually ships or can rely on finding */
.rich .rt-f-vazir  { font-family: 'Vazirmatn', var(--font-fa); }
.rich .rt-f-iran   { font-family: 'IRANSansX', 'Vazirmatn', var(--font-fa); }
.rich .rt-f-tahoma { font-family: Tahoma, 'Vazirmatn', var(--font-fa); }
.rich .rt-f-serif  { font-family: Georgia, 'Times New Roman', serif; }
.rich .rt-f-inter  { font-family: 'Inter', var(--font-fa); }
.rich .rt-f-mono   { font-family: 'Cascadia Mono', Consolas, 'Courier New', monospace; }

/* sizes, relative so they compose with whatever block they sit in */
.rich .rt-s-xs { font-size: 0.78em; }
.rich .rt-s-sm { font-size: 0.88em; }
.rich .rt-s-md { font-size: 1em; }
.rich .rt-s-lg { font-size: 1.18em; }
.rich .rt-s-xl { font-size: 1.42em; }

/* the two the first version of the editor wrote, kept so older bodies hold */
.rich .rt-lg { font-size: 1.18em; }
.rich .rt-sm { font-size: 0.88em; }

.rich .rt-right   { text-align: right; }
.rich .rt-center  { text-align: center; }
.rich .rt-left    { text-align: left; }
.rich .rt-justify { text-align: justify; }

.rich .rt-c-green { color: var(--green-text); }
.rich .rt-c-teal  { color: var(--teal-text); }
.rich .rt-c-muted { color: var(--muted); }

.rich .rt-w-full { width: 100%; }
.rich .rt-w-half { width: 52%; margin-inline: auto; }

@media (max-width: 620px) {
  /* A half-width picture in a phone column is a stamp; on that width everything
     takes the full column. */
  .rich .rt-w-half { width: 100%; }
}

.pcard {
  background: var(--white); border: 1px solid var(--card-border); border-radius: 12px;
  overflow: hidden; display: flex; flex-direction: column;
  transition: transform .3s var(--ease), box-shadow .3s;
}
.pcard:hover { transform: translateY(-4px); box-shadow: var(--shadow-card); }
.pcard__frame { aspect-ratio: 4 / 3; overflow: hidden; background: var(--warm); }
.pcard__frame img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s var(--ease); }
.pcard:hover .pcard__frame img { transform: scale(1.06); }
.pcard__body { padding: 24px; display: flex; flex-direction: column; flex: 1; gap: 12px; }
.pcard h3 { font-size: 17.5px; font-weight: 700; color: var(--heading); line-height: 1.7; }
.pcard p { font-size: 14px; line-height: 1.95; color: var(--muted); }
.pcard__foot { margin-top: auto; padding-top: 6px; }

/* ============================================================================
   FORM — quote request
   ========================================================================= */

.form { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; max-width: 720px; }
.field { display: flex; flex-direction: column; gap: 8px; }
.field--full { grid-column: 1 / -1; }
.field label { font-size: 13.5px; font-weight: 500; color: var(--heading); }
.field label .opt { color: var(--muted-2); font-weight: 400; }
.field input, .field select, .field textarea {
  font-family: inherit; font-size: 15px; color: var(--heading);
  background: var(--white); border: 1px solid var(--control-border); border-radius: 10px;
  padding: 0 16px; height: 54px;
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease);
}
.field textarea { height: auto; min-height: 132px; padding: 15px 16px; line-height: 1.9; resize: vertical; }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--control-border-hover); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--teal-text); box-shadow: 0 0 0 3px rgba(14, 110, 112, .12);
}
.field .err { font-size: 12.5px; color: var(--danger); }
.field input[aria-invalid="true"],
.field select[aria-invalid="true"],
.field textarea[aria-invalid="true"] { border-color: var(--danger); background: var(--danger-tint); }

.form__actions { grid-column: 1 / -1; display: flex; gap: 12px; flex-wrap: wrap; margin-top: 6px; }

.alert {
  display: flex; gap: 14px; align-items: flex-start;
  border-radius: 12px; padding: 20px 22px; margin-bottom: 26px;
  font-size: 14.5px; line-height: 2;
}
.alert--ok { background: var(--tint-green); color: var(--ok-text); border: 1px solid var(--ok-border); }
.alert--bad { background: var(--danger-tint); color: var(--danger); border: 1px solid var(--danger); }

/* The arithmetic check. The sum sits in its own tile beside a short answer box so
   it reads as one small task rather than another form field to fill in. */
/* row-reverse, and the two together read as one line.

   The sum is written left-to-right, so its "= ?" sits at the RIGHT end of the
   question box. In an ordinary RTL row the answer box lands to the LEFT of that,
   which puts the question mark against nothing and the box behind the equation.
   Reversed, the box follows the "= ?" directly and the whole thing reads
   ۸ − ۵ = [ ]. Reversing also moves the pair to the left of the field, which is
   where it was asked to sit. */
.quiz { display: flex; flex-direction: row-reverse; justify-content: flex-start; align-items: stretch; gap: 10px; }
.quiz__q {
  display: flex; align-items: center; justify-content: center;
  min-width: 116px; padding: 0 18px; height: 54px;
  background: var(--tint-teal); border: 1px solid var(--control-border);
  border-radius: 10px;
  font-size: 19px; font-weight: 700; color: var(--heading);
  letter-spacing: .06em; user-select: none;
}
.quiz__a { width: 108px; text-align: center; font-size: 17px; font-weight: 600; }

/* The error line follows the row across. Left where every other field puts it, it
   sat at the far edge of a full-width field with nothing above it. */
.field--quiz > .err { text-align: end; }

/* Honeypot. Not display:none — some form-fillers skip hidden inputs, and the point
   is that a script SHOULD find and fill this one. It is moved off-screen instead,
   and taken out of the tab order and the accessibility tree in the markup. */
.hp {
  position: absolute !important; width: 1px; height: 1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.alert--ok strong { display: block; color: var(--ok-text); font-weight: 700; margin-bottom: 4px; }

.contact__grid { display: grid; grid-template-columns: 1.3fr 1fr; gap: clamp(34px, 5vw, 64px); align-items: start; }
/* The card is 479px against a 730px form, so it used to end a quarter of a page
   early and leave the column dead — the same unequal-column problem .facgrid
   was built to avoid. Sticking it keeps the phone number beside the field the
   visitor is actually filling in, and uses the space instead of padding it.
   Only above 1080px: below that the grid is one column and the card follows the
   form in normal flow. */
@media (min-width: 1081px) {
  .contact__card { position: sticky; top: var(--pin-top); }
}
.contact__card {
  background: var(--offwhite); border: 1px solid var(--divider);
  border-radius: 12px; padding: 28px 26px;
}
/* The form and the info card are two columns of one row, so their headings are
   literally the same rule — at 21px against the card's 17px the pair read as a
   section and a footnote rather than as peers. */
.contact__card h2,
.contact__colhead { font-size: 17px; font-weight: 700; color: var(--heading); margin: 0 0 20px; }
.contact__row { display: flex; flex-direction: column; gap: 5px; padding: 14px 0; border-bottom: 1px solid var(--divider); }
.contact__row:last-child { border-bottom: 0; }
.contact__row span:first-child { font-size: 12px; color: var(--muted); }
.contact__row a, .contact__row > span:last-child { font-size: 15.5px; font-weight: 600; color: var(--heading); }
.contact__row .pending { color: var(--muted-2); font-weight: 400; font-size: 14px; }

@media (max-width: 1080px) {
  .contact__grid { grid-template-columns: 1fr; }
}
@media (max-width: 760px) {
  .form { grid-template-columns: 1fr; }
}

/* ============================================================================
   TOUCH TARGETS

   The handoff's accessibility note requires a >=48px touch height. Several
   controls are visually small by design — the hero's 44x4px progress dots, the
   footer's text links, the inline tel links — so they get an enlarged hit area
   on coarse pointers WITHOUT changing how they look.
   ========================================================================= */

@media (pointer: coarse) {
  /* Dots stay 4px tall visually; the ::before gives them a 44px tall target. */
  .hero__dot { position: relative; }
  .hero__dot::before {
    content: ""; position: absolute;
    inset-inline: 0; top: 50%;
    height: 44px; transform: translateY(-50%);
  }

  .footer__links a,
  .menu__nav a { min-height: 48px; display: flex; align-items: center; }

  /* Inline phone/email links inside running text. */
  .footer__contact a,
  .ctaband__tel a,
  .contact__row a,
  .footer__credit a,
  .topbar a { display: inline-flex; align-items: center; min-height: 44px; }

  /* 6px of padding only took a 20px line to 32px. The same ::before trick the
     hero dots use gives a full 44px target without adding a pixel to the layout,
     which matters here because the banner's height was tuned deliberately. */
  .crumbs a { position: relative; }
  .crumbs a::before {
    content: ""; position: absolute;
    inset-inline: 0; top: 50%;
    height: 44px; transform: translateY(-50%);
  }
}

/* ============================================================================
   MOBILE TYPOGRAPHY & FOOTER

   Persian needs generous leading to stay comfortable, and several supporting
   sizes that read fine at 1440px become strained on a 390px screen. These raise
   the smallest sizes and open the line-height rather than shrinking anything.
   ========================================================================= */

@media (max-width: 760px) {
  /* Nothing below 13px, and body copy gets a touch more air. */
  .lede            { font-size: 16.5px; line-height: 2.2; }
  .note            { font-size: 14px;   line-height: 2.05; }
  .feat__card p,
  .adv p,
  .appcard p,
  .artcard p,
  .about__cell p   { font-size: 14.5px; line-height: 2.05; }
  .eyebrow         { font-size: 13.5px; }
  .artcard__cat,
  .specs__row      { font-size: 14.5px; padding: 15px 16px; }
  .qc__row         { font-size: 15px; }
  .footer p        { font-size: 14.5px; line-height: 2.1; }

  /* Headings tighten their leading a little as they get smaller, so they do not
     drift apart into separate lines of unrelated text. */
  .h-section       { font-size: clamp(21px, 6.4vw, 26px); line-height: 1.62; }
  .h-about         { font-size: clamp(21px, 6.2vw, 25px); line-height: 1.65; }
  .pagehead h1     { font-size: clamp(22px, 6.6vw, 27px); line-height: 1.6; }
  .artcard h3,
  .pcard h3,
  .appcard h3      { font-size: 17px; line-height: 1.75; }

  /* ---- footer ---------------------------------------------------------- */
  .footer { padding-inline: var(--pad); }
  .footg { gap: 34px; padding-bottom: 34px; }

  /* Link columns become two-up so the footer is not one long ladder. */
  .footer__links { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 18px; }
  .footer__links a { min-height: 46px; }

  .footer__brand { gap: 14px; margin-bottom: 16px; }
  .footer__logo { width: 48px; height: 48px; }
  .footer__title {
    font-size: 13px; letter-spacing: .02em;
    padding-bottom: 10px; margin-bottom: 12px;
    border-bottom: 1px solid rgba(255, 255, 255, .12);
  }
  .footer__social { margin-top: 18px; }
  .footer__contact { gap: 14px; }

  /* Centre the bottom bar and give the three lines room to breathe. */
  .footer__bottom {
    flex-direction: column; align-items: center; text-align: center;
    gap: 10px; padding: 22px 0 28px; line-height: 1.9;
  }
  .footer__site { opacity: .8; }
}

/* Very small phones: one column of footer links reads better than a cramped two. */
@media (max-width: 380px) {
  .footer__links { grid-template-columns: 1fr; }
}

/* ============================================================================
   REDUCED MOTION — menu stagger must not animate either
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
  .menu__nav a,
  .menu__foot { opacity: 1 !important; transform: none !important; }
}

/* ============================================================================
   MINIMUM LEGIBLE TYPE ON SMALL SCREENS

   A few supporting labels sit at 11.5-12px, which is fine on a 1440px desktop
   but strains the eye on a phone — Persian letterforms carry more detail per
   glyph than Latin at the same size. Nothing here shrinks; it only raises the
   floor to 13px and opens the leading to match.
   ========================================================================= */

@media (max-width: 760px) {
  .artcard__date        { font-size: 13px; padding: 7px 12px; }
  .footer__desc         { font-size: 13px; line-height: 1.8; }
  .marker__label        { font-size: 13px; padding: 8px 12px; }
  .footer__contact > div > div { font-size: 13px; }
  .footer__bottom       { font-size: 13px; }
  .footer__links a      { font-size: 14.5px; }
  .footer__social a,
  .footer__social span  { font-size: 13px; }
  .menu__nav a          { font-size: 17.5px; }
  .pvis__dot            { width: 30px; height: 4px; }
  .crumbs               { font-size: 13px; }
  .prstep__num,
  .artcard__cat         { font-size: 13px; }
}

/* ============================================================================
   POLISH PASS

   Small refinements applied across the whole site: image frames get a hairline
   and a resting lift so they sit ON the page rather than being punched into it,
   cards share one hover language, and the dark sections get a little depth.
   ========================================================================= */

/* ---- image frames --------------------------------------------------------
   Every photo previously sat flush on its background with no edge, which is
   what made the large frames read as flat slabs. */
.mask,
.pvis,
.prvis,
.facside > div,
.about__main,
.about__collage,
.galitem,
.appcard__frame,
.artcard__frame,
.pcard__frame {
  box-shadow: 0 1px 0 rgba(16, 36, 61, .05),
              0 18px 38px -30px rgba(16, 36, 61, .55);
}
.mask, .pvis, .prvis, .facside > div, .about__main, .galitem {
  outline: 1px solid rgba(16, 36, 61, .06);
  outline-offset: -1px;
}
/* On the navy process section the hairline has to be light, not dark. */
.process .prvis { outline-color: rgba(255, 255, 255, .1); }

/* ---- zoomable frames get an affordance ---------------------------------- */
.mask[data-galsrc],
.pvis[data-galsrc],
.galitem {
  transition: box-shadow .35s var(--ease), transform .35s var(--ease);
}
.mask[data-galsrc]:hover,
.pvis[data-galsrc]:hover,
.galitem:hover {
  box-shadow: 0 1px 0 rgba(16, 36, 61, .05),
              0 30px 56px -32px rgba(16, 36, 61, .6);
}

/* ---- cards: one shared hover language ----------------------------------- */
.feat__card, .adv, .artcard, .pcard, .appcard__inner, .about__cell {
  will-change: transform;
}
.about__cell {
  padding: 22px 0 0;
  transition: border-color .3s var(--ease);
}
.about__cell:hover { border-top-color: var(--leaf); }

/* Advantage and feature icons pick up their tile colour on hover. */
.adv__icon, .feat__icon {
  transition: background .3s var(--ease), color .3s var(--ease), transform .3s var(--ease);
}
.adv:hover .adv__icon,
.feat__card:hover .feat__icon {
  background: var(--green); color: #fff; transform: scale(1.06);
}
.feat__card:hover .feat__icon--teal { background: var(--teal); }

/* ---- section headings --------------------------------------------------- */
/* The accent rule under a section title grows in rather than just appearing. */
.rule-accent { transition: width .6s var(--ease); }

/* ---- specs table -------------------------------------------------------- */
.specs__row { transition: background .25s var(--ease); }
.specs__row:hover { background: var(--offwhite); }

/* ---- the dark process panel -------------------------------------------- */
.process { position: relative; }
.process::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(120% 80% at 78% 0%, rgba(87, 160, 58, .12), transparent 62%);
  pointer-events: none;
}
.process > * { position: relative; }

/* ---- CTA band ----------------------------------------------------------- */
.ctaband { position: relative; overflow: hidden; }
.ctaband::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(90% 120% at 88% 10%, rgba(255, 255, 255, .14), transparent 58%);
  pointer-events: none;
}
.ctaband > * { position: relative; }

/* ---- footer ------------------------------------------------------------- */
.footer { position: relative; }
.footer::before {
  content: ""; position: absolute; inset-inline: 0; top: 0; height: 1px;
  background: linear-gradient(to left, transparent, rgba(87, 160, 58, .4) 30%, rgba(14, 110, 112, .4) 70%, transparent);
}

/* ---- reduced motion ----------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .mask, .pvis, .galitem, .adv__icon, .feat__icon, .about__cell, .rule-accent {
    transition: none !important;
  }
  /* The gallery still changes tile — it just stops gliding, and stops doing
     it on its own. The engine turns the timer off; this is the travel. */
  [data-slider].is-slider > [data-slidertrack], .sldot { transition: none !important; }
}

/* ============================================================================
   SECTION REWORKS

   Three sections read as plain or loose in review: the advantages grid, the
   factory block and the sales band. These give them structure rather than more
   decoration.
   ========================================================================= */

/* ---- advantages: cards that feel built, not floating ---------------------
   They were four identical white rectangles with an icon on top. Now each one
   carries a numbered rule that fills in on hover, and the icon sits in a tinted
   well rather than on the card face. */
.adv {
  position: relative;
  padding: 34px 26px 30px;
  background: var(--white);
  border: 1px solid var(--card-border);
  border-radius: 14px;
  overflow: hidden;
}
.adv::before {
  content: ""; position: absolute; inset-inline: 0; top: 0; height: 3px;
  background: linear-gradient(to left, var(--green), var(--leaf));
  transform: scaleX(0); transform-origin: right;
  transition: transform .45s var(--ease);
}
.adv:hover::before { transform: scaleX(1); }
.adv__icon {
  width: 52px; height: 52px; border-radius: 14px; margin-bottom: 22px;
  background: var(--tint-green); color: var(--green-text);
  box-shadow: inset 0 0 0 1px rgba(31, 107, 69, .1);
}
.adv h3 { font-size: 17px; margin-bottom: 12px; }
.adv p { font-size: 14.5px; line-height: 2; }
/* Quiet index in the corner, so the four read as a sequence. */
.adv__no {
  position: absolute; top: 22px; inset-inline-start: 24px;
  font-size: 13px; font-weight: 600; color: var(--muted-2); opacity: .55;
  transition: color .3s var(--ease), opacity .3s var(--ease);
}
.adv:hover .adv__no { color: var(--green-text); opacity: 1; }

/* ---- factory: frame the pair and let the heading sit with it ------------- */
.factory .stack { align-items: flex-end; margin-bottom: clamp(26px, 3vw, 38px); }

/* The rule above sets flex-end for the DESKTOP row, where the cross axis is
   vertical and flex-end means "bottom" — it lines the button up with the
   heading. Once the stack becomes a column the cross axis is horizontal, and in
   RTL flex-end means LEFT: the heading shrank to its own text width and drifted
   off the right edge while the images below still ran full width. This has to
   sit AFTER that rule — both are (0,2,0) and a media query adds no specificity,
   so an earlier copy simply lost. */
@media (max-width: 1080px) {
  .factory .stack { align-items: stretch; }

  /* The section already pads its content; .factory__imgwrap pads again so the
     frames can widen past the text on desktop. With that gesture switched off on
     a phone the second pad is just a double inset, leaving the pictures 18px
     narrower than the heading above them. */
  .factory__imgwrap { padding-inline: 0; }
}
.facgrid { border-radius: 14px; }
.facgrid .mask,
.facside > div { border-radius: 12px; }
/* On the dark half of the lerp the frames need a light edge, not a dark one. */
.factory.is-dark .facgrid .mask,
.factory.is-dark .facside > div {
  outline-color: rgba(255, 255, 255, .14);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .06),
              0 22px 44px -30px rgba(0, 0, 0, .7);
}

/* ---- sales band: give the flat green panel some architecture ------------- */
.ctaband {
  padding: clamp(30px, 3.4vw, 46px) clamp(26px, 3.4vw, 48px);
  border-radius: 18px;
  background:
    radial-gradient(120% 140% at 92% -10%, rgba(87, 160, 58, .38), transparent 55%),
    linear-gradient(200deg, #23794E 0%, var(--green) 45%, #17563A 100%);
  box-shadow: 0 40px 80px -46px rgba(23, 86, 58, .9),
              inset 0 1px 0 rgba(255, 255, 255, .16);
}
/* A hairline grid, echoing the fibre language, instead of a flat fill. */
.ctaband::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(to left, rgba(255, 255, 255, .07) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, .07) 1px, transparent 1px);
  background-size: 46px 46px;
  mask-image: radial-gradient(120% 100% at 90% 0%, #000 0%, transparent 70%);
  -webkit-mask-image: radial-gradient(120% 100% at 90% 0%, #000 0%, transparent 70%);
}
.ctaband h2 { font-size: clamp(20px, 2.1vw, 28px); line-height: 1.8; margin-bottom: 16px; }
.ctaband p { font-size: 15px; max-width: 62ch; }
.ctaband__tel {
  margin-top: 22px; padding-top: 18px;
  border-top: 1px solid rgba(255, 255, 255, .18);
  gap: 26px;
}
.ctaband__actions { min-width: 260px; }

@media (max-width: 760px) {
  .adv { padding: 30px 22px 26px; }
  .adv__no { top: 18px; }
  .ctaband__actions { min-width: 0; width: 100%; }
  .ctaband__tel { gap: 14px; }
}

/* ============================================================================
   PROCESS COLUMN

   The section heading now sits inside the pinned column rather than in a
   full-width band above it. In RTL that band left its entire left half as empty
   background, and the heading scrolled away before the steps had advanced.
   ========================================================================= */

.prcol { display: flex; flex-direction: column; gap: clamp(20px, 3vh, 34px); }
.prcol__intro .h-section { margin-bottom: 12px; }
.prcol__intro .note { color: rgba(255, 255, 255, .62); }
.prcol .prsteps { flex: 1; }

@media (max-width: 1080px) {
  .prcol { gap: 24px; }
}
