/* ==========================================================================
   KHURANA ELECTRONICS - main stylesheet
   Square-edged, no border-radius anywhere.

   CONTENTS
   0. THEME  <-- change colours + fonts here only
   1. Reset / base
   2. Layout helpers
   3. Buttons
   4. Topbar + header + navigation
   5. Hero
   6. About
   7. Choose the best
   8. Products
   9. Services
  10. Gallery
  11. Counters
  12. Top features of IFPD
  13. Testimonials
  14. CTA
  15. FAQ
  16. Footer
  17. Reveal + responsive
   ========================================================================== */

/* ==========================================================================
   0. THEME
   Everything visual is driven from this block. Replace the values below with
   your palette and font family and the whole site follows.
   ========================================================================== */
:root {
  /* --- brand colours ------------------------------------------------- */
  --primary: #38bbc1; /* primary colour     */
  --primary-dark: #17727a; /* deep teal          */
  --primary-tint: #e6f7f8; /* pale wash          */
  --secondary: #d92720; /* secondary colour   */
  --secondary-dark: #ab1d18;
  --secondary-tint: #f7dedd; /* pale wash, pairs with --primary-tint */ /* secondary hover    */

  /* Text on a coloured fill is always white. --primary is light (2.3:1 on
       white), so it is never used as a background behind text - anything
       filled uses --primary-dark (white on it is 5.6:1) or --secondary
       (4.9:1). --primary is for borders, bars, icons and hover accents.

       --secondary is deliberately sparing: call-to-action buttons, the
       floating call button, the Bestseller tag, and two single accents
       (logo underline, CTA band top border). Everything else is teal. */

  --whatsapp: #25d366;

  /* --- neutrals ------------------------------------------------------ */
  --ink: #111111; /* headings           */
  --body: #4a4a4a; /* paragraph text     */
  --muted: #6b6b6b; /* secondary text     */
  --line: #e2e2e2; /* borders            */
  --bg: #ffffff;
  --bg-alt: #f5f5f5;
  --dark: #141414; /* dark bands, footer */

  /* --- fonts ---------------------------------------------------------
       Montserrat for headings, to match the banner artwork. Inter for
       everything else - it is designed for small sizes and stays legible
       at 12px, which Montserrat does not. */
  --font-head: "Montserrat", "Segoe UI", Arial, sans-serif;
  --font-body: "Inter", "Segoe UI", Arial, sans-serif;

  /* --- type scale ----------------------------------------------------
       Six sizes, nothing else. Headings run 32 / 24 / 20 / 18 big to small,
       body is 16, secondary copy 14, and anything small - labels, eyebrows,
       captions, buttons, meta - is 12. */
  --fs-h1: 32px;
  --fs-h2: 24px;
  --fs-h3: 20px;
  --fs-h4: 18px;
  --fs-body: 16px;
  --fs-sm: 14px;
  --fs-xs: 12px;

  /* --- metrics ------------------------------------------------------- */
  --container: 1200px; /* page content            */

  /* The header shares the banner's box so the logo lines up with the
       artwork's headline. --banner-inset is a ratio, not a percentage,
       because it is multiplied inside calc(). */
  --banner-max: 1920px;
  --banner-inset: 0.05;
  --gutter: 32px;
  --header-h: 80px;
  --shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
  --shadow-lg: 0 20px 50px rgba(0, 0, 0, 0.14);
  --ease: cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

/* ==========================================================================
   1. Reset / base
   ========================================================================== */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Nothing on this site is rounded. */
*,
button,
input,
textarea,
select,
img {
  border-radius: 0;
}
button,
input,
textarea,
select {
  -webkit-appearance: none;
  appearance: none;
}

html {
  /* Reserve the scrollbar track from the first paint. Without it the page
     starts scrollbar-less, gains one when the images load, and every width
     measured before that - Swiper caches one per carousel - is then wrong by
     the scrollbar. In a looping slider that error accumulates per slide,
     which is why the banner drifted further left the further it advanced. */
  scrollbar-gutter: stable;
  /* clip, not hidden. overflow:hidden on the root makes a scroll
     container, which silently kills every position:sticky on the page -
     the header included. clip does the same job without that. */
  overflow-x: clip;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 10px);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.7;
  color: var(--body);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

h1,
h2,
h3,
h4,
h5 {
  margin: 0 0 0.6em;
  font-family: var(--font-head);
  color: var(--ink);
  line-height: 1.18;
  font-weight: 700;
  letter-spacing: -0.015em;
}
h1 {
  font-size: var(--fs-h1);
  font-weight: 800;
}
h2 {
  font-size: var(--fs-h2);
}
h3 {
  font-size: var(--fs-h3);
}
h4 {
  font-size: var(--fs-h4);
}
h5 {
  font-size: var(--fs-body);
}

p {
  margin: 0 0 1rem;
}
p:last-child {
  margin-bottom: 0;
}

/* Body text runs at 12px throughout. Class rules still win over this,
   so the ones that carried a larger size were brought down to match -
   see the sweep below. Display numerals keep their own size. */
p,
span,
li {
  font-size: var(--fs-xs);
}

/* Spans that hold a display numeral or a glyph must not be caught by the
   rule above - the counters, the carousel chevrons and the back-to-top
   arrow all wrap their content in a bare span. */
.counter-value span,
.prod-nav span,
.heroSwiper-nav span,
.testiSwiper-nav span,
.to-top span {
  font-size: inherit;
}

a {
  color: var(--primary-dark);
  text-decoration: none;
  transition: color 0.2s var(--ease);
}
a:hover {
  color: var(--ink);
}

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

:focus-visible {
  outline: 2px solid var(--primary-dark);
  outline-offset: 2px;
}

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

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 999;
  padding: 12px 20px;
  background: var(--ink);
  color: #fff;
}
.skip-link:focus {
  left: 0;
}

/* ==========================================================================
   2. Layout helpers
   ========================================================================== */
.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.section {
  padding: clamp(42px, 5.4vw, 72px) 0;
}
.section--alt {
  background: var(--bg-alt);
}

.section-head {
  max-width: 660px;
  margin: 0 0 clamp(24px, 3vw, 38px);
}
.section-head.is-center {
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}
.section-head p {
  color: var(--muted);
  font-size: var(--fs-xs);
  margin-top: 12px;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--primary-dark);
}
.eyebrow::before {
  content: "";
  width: 28px;
  height: 2px;
  background: var(--secondary);
}
.is-center .eyebrow {
  justify-content: center;
}
.on-dark .eyebrow {
  color: var(--primary);
}
.on-dark h2 {
  color: #fff;
}
.on-dark p {
  color: rgba(255, 255, 255, 0.74);
}

/* Colours a phrase inside a heading, e.g. We Provide <accent>Security System</accent> Solution */
/* font-size:inherit or the p/span/li rule shrinks the highlighted words
   inside a heading to 12px. */
.accent {
  color: var(--primary-dark);
  font-size: inherit;
}

.rule {
  width: 54px;
  height: 3px;
  background: var(--primary);
  margin-top: 22px;
}
.is-center .rule {
  margin-left: auto;
  margin-right: auto;
}

/* ==========================================================================
   3. Buttons
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 10px 20px;
  border: 1px solid transparent;
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  line-height: 1.2;
  cursor: pointer;
  white-space: nowrap;
  transition:
    background 0.22s var(--ease),
    color 0.22s var(--ease),
    border-color 0.22s var(--ease);
}
.btn-sm {
  padding: 7px 14px;
  font-size: var(--fs-xs);
}
.btn-lg {
  padding: 10px 26px;
  font-size: var(--fs-sm);
  font-size: 12px;
}

.btn-primary {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}
.btn-primary:hover {
  background: var(--secondary);
  border-color: var(--secondary);
  color: #fff;
}

.btn-secondary {
  background: var(--secondary);
  border-color: var(--secondary);
  color: #fff;
}
.btn-secondary:hover {
  background: var(--secondary-dark);
  border-color: var(--secondary-dark);
  color: #fff;
}

.btn-outline {
  background: transparent;
  border-color: var(--line);
  color: var(--ink);
}
.btn-outline:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

.btn-light {
  background: #fff;
  border-color: #fff;
  color: var(--primary-dark);
}
.btn-light:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

.btn-ghost-light {
  background: transparent;
  border-color: rgba(255, 255, 255, 0.6);
  color: #fff;
}
.btn-ghost-light:hover {
  background: #fff;
  border-color: #fff;
  color: var(--primary-dark);
}

/* ==========================================================================
   4. Topbar + header
   ========================================================================== */
.topbar {
  background: var(--dark);
  color: #b5b5b5;
  font-size: var(--fs-xs);
}
/* The topbar and header run wider than the page content so the long menu has
   room. They share their own width token, kept in step with each other. */
.topbar-inner {
  max-width: var(--banner-max);
  padding-left: calc(min(100vw, var(--banner-max)) * var(--banner-inset));
  padding-right: calc(min(100vw, var(--banner-max)) * var(--banner-inset));
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  min-height: 44px;
}
.topbar a {
  color: #b5b5b5;
}
.topbar a:hover {
  color: #fff;
}
.topbar-contact {
  display: flex;
  flex-wrap: wrap;
  gap: 26px;
}
.topbar-contact li {
  display: flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}
/* Line icons in the brand colour stand in for the old CALL / EMAIL /
   ADDRESS labels. The words are still there in .sr-only. */
.tb-icon {
  flex: 0 0 15px;
  width: 15px;
  height: 15px;
  fill: none;
  stroke: var(--primary);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.tb-sep {
  color: #6a6a6a;
  margin: 0 2px;
}
.topbar-social {
  display: flex;
}
.topbar-social a {
  display: grid;
  place-items: center;
  width: 40px;
  min-height: 44px;
  border-left: 1px solid rgba(255, 255, 255, 0.08);
  transition: background 0.2s var(--ease), color 0.2s var(--ease);
}
.tb-social-icon {
  width: 16px;
  height: 16px;
  fill: currentColor;
}
.topbar-social a:last-child {
  border-right: 1px solid rgba(255, 255, 255, 0.08);
}
.topbar-social a:hover {
  background: var(--ink);
  color: #fff;
}

/* Glass header: translucent white over a blurred, slightly saturated view of
   whatever is scrolling beneath it. It firms up once the page has moved. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  min-height: var(--header-h);
  display: flex;
  align-items: stretch;
  background: rgba(255, 255, 255, 0.62);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  backdrop-filter: blur(16px) saturate(180%);
  border-bottom: 1px solid rgba(255, 255, 255, 0.5);
  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.06);
  transition:
    background 0.3s var(--ease),
    box-shadow 0.3s var(--ease),
    border-color 0.3s var(--ease);
}
.site-header.is-stuck {
  background: rgba(255, 255, 255, 0.82);
  border-bottom-color: rgba(255, 255, 255, 0.7);
  box-shadow:
    inset 0 -1px 0 rgba(0, 0, 0, 0.08),
    var(--shadow);
}

/* Browsers without backdrop-filter get a solid header rather than an
   unreadable see-through one. */
@supports not (
  (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))
) {
  .site-header,
  .site-header.is-stuck {
    background: #fff;
    border-bottom-color: var(--line);
  }
}

.header-inner {
  max-width: var(--banner-max);
  padding-left: calc(min(100vw, var(--banner-max)) * var(--banner-inset));
  padding-right: calc(min(100vw, var(--banner-max)) * var(--banner-inset));
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  gap: 24px;
  min-height: var(--header-h);
}

/* Logo is a transparent PNG at 536x186 (2.88:1), so it is sized by height
   and the width follows. It reads on both the light header and the dark
   footer, so no separate inverted version is needed. */
.logo {
  display: inline-flex;
  align-items: center;
  align-self: center;
}
.logo img {
  height: 54px;
  width: auto;
  display: block;
}

/* Nav items run the full height of the header. That leaves no dead gap
   between a parent link and its dropdown, so the menu does not flicker
   shut when the pointer travels down into it. */
.main-nav {
  display: flex;
  align-items: stretch;
  gap: 20px;
}
.main-nav > ul {
  display: flex;
  align-items: stretch;
  gap: 30px;
}
.main-nav > ul > li {
  position: relative;
  display: flex;
  align-items: center;
}
.nav-cta {
  align-self: center;
}

.nav-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 100%;
  padding: 6px 0;
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--ink);
}
/* The link fills the header height so the dropdown has no gap to fall
   through, but the underline is measured from the centre of the label so it
   sits just under the text instead of way down at the header's edge. */
.nav-link::after {
  content: "";
  position: absolute;
  left: 0;
  top: calc(50% + 11px);
  width: 0;
  height: 2px;
  background: var(--primary-dark);
  transition: width 0.25s var(--ease);
}
.nav-link:hover,
.nav-link.is-active {
  color: var(--primary-dark);
}
.nav-link:hover::after,
.nav-link.is-active::after {
  width: 100%;
}

/* --- Dropdown menus --------------------------------------------------- */
.caret {
  width: 6px;
  height: 6px;
  flex: 0 0 6px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.28s var(--ease);
}
.has-dropdown:hover > .nav-link .caret,
.has-dropdown:focus-within > .nav-link .caret,
.has-dropdown.is-open > .nav-link .caret {
  transform: translateY(1px) rotate(-135deg);
}

.has-dropdown:hover > .nav-link::after,
.has-dropdown:focus-within > .nav-link::after {
  width: 100%;
}

.dropdown {
  position: absolute;
  top: 100%;
  left: -20px;
  min-width: 290px;
  background: #fff;
  border: 1px solid var(--line);
  border-top: 3px solid var(--primary);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(14px);
  transition:
    opacity 0.28s var(--ease),
    transform 0.28s var(--ease),
    visibility 0.28s;
  z-index: 20;
}
.has-dropdown:hover > .dropdown,
.has-dropdown:focus-within > .dropdown,
.has-dropdown.is-open > .dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.dropdown li + li {
  border-top: 1px solid var(--line);
}

.dropdown a {
  position: relative;
  display: block;
  padding: 13px 22px;
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: 1.45;
  color: var(--ink);
  transition:
    color 0.22s var(--ease),
    background 0.22s var(--ease),
    padding-left 0.22s var(--ease);
}
/* Accent bar wipes in from the left as the row tints and the label steps across. */
.dropdown a::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 0;
  background: var(--primary);
  transition: width 0.22s var(--ease);
}
.dropdown a:hover,
.dropdown a:focus-visible {
  background: var(--bg-alt);
  color: var(--primary-dark);
  padding-left: 30px;
}
.dropdown a:hover::before,
.dropdown a:focus-visible::before {
  width: 4px;
}

/* No fill, no border - just the icon. */
.nav-toggle {
  display: none;
  align-self: center;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: none;
  color: var(--ink);
  cursor: pointer;
}
.nav-toggle svg {
  width: 26px;
  height: 26px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: square;
}
/* view-box, not fill-box: a <line> has no height, so a fill-box origin
   collapses and the rotation pivots off the end of the stroke. */
.nav-toggle line {
  transform-box: view-box;
  transform-origin: center;
  transition:
    transform 0.3s var(--ease),
    opacity 0.2s var(--ease);
}
.nav-toggle[aria-expanded="true"] .nav-bar-1 {
  transform: translateY(6px) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] .nav-bar-2 {
  opacity: 0;
}
.nav-toggle[aria-expanded="true"] .nav-bar-3 {
  transform: translateY(-6px) rotate(-45deg);
}

/* Only ever visible with the drawer; the desktop nav has no use for either. */
.nav-backdrop,
.nav-head {
  display: none;
}

/* ==========================================================================
   5. Hero
   ========================================================================== */
/* Full-bleed banner hero. The artwork carries the headline, sub-line and its
   own "Explore Solutions" button, so nothing is laid over it - the banner is
   shown whole at its natural ratio and the whole image is the link. */
/* White, not dark - past 1920px the banner stops growing and this shows at
   the edges, and every banner has a light background to blend into. */
.hero {
  position: relative;
  overflow: hidden;
  background: var(--bg);
}

/* --- Swiper carousel (unique classes so other sliders never collide) --- */
/* Capped at the artwork width so the banners are shown at their own size and
   never blown up past it. Below 1920px they scale down to fit, which is the
   only alternative to a horizontal scrollbar. */
.heroSwiper {
  position: relative;
  width: 100%;
  max-width: 1920px;
  margin: 0 auto;
}
.heroSwiper .hero-slide {
  height: auto;
}

/* --- Banner slide ---------------------------------------------------- */
.hero-banner {
  position: relative;
  display: block;
}
.hero-banner img {
  width: 100%;
  height: auto;
  display: block;
}

.heroSwiper-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 5;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  padding: 0;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.35);
  color: #fff;
  font-size: 24px; /* chevron glyph, not text */
  line-height: 1;
  cursor: pointer;
  transition:
    background 0.2s var(--ease),
    color 0.2s var(--ease),
    border-color 0.2s var(--ease);
}
.heroSwiper-nav:hover {
  background: var(--ink);
  border-color: var(--primary-dark);
  color: #fff;
}
.heroSwiper-nav.is-disabled {
  opacity: 0.3;
  cursor: default;
}
.heroSwiper-prev {
  left: 20px;
}
.heroSwiper-next {
  right: 20px;
}

/* Hidden by main.js while there is only one banner to show. */
.heroSwiper-nav.is-hidden,
.heroSwiper-pagination.is-hidden {
  display: none;
}

.heroSwiper-pagination {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 20px;
  z-index: 5;
  display: flex;
  justify-content: center;
  gap: 9px;
}
.heroSwiper-bullet {
  width: 26px;
  height: 4px;
  background: rgba(255, 255, 255, 0.4);
  border: none;
  padding: 0;
  cursor: pointer;
  transition:
    background 0.25s var(--ease),
    width 0.25s var(--ease);
}
.heroSwiper-bullet:hover {
  background: rgba(255, 255, 255, 0.7);
}
.heroSwiper-bullet-active {
  width: 46px;
  background: var(--primary);
}

/* ==========================================================================
   5b. Marquee
   Sits between the hero and About. The track holds two identical lists and
   slides -50%, so at the loop point copy two is exactly where copy one
   started and there is no visible seam. Change the item count freely - the
   -50% still holds because it is half of whatever the track measures.
   ========================================================================== */
.marquee {
  overflow: hidden;
  background: var(--ink);
  color: #fff;
  border-top: 3px solid var(--primary);
}

.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee-scroll 34s linear infinite;
}
.marquee:hover .marquee-track {
  animation-play-state: paused;
}

.marquee-list {
  display: flex;
  align-items: center;
}
.marquee-list li {
  display: flex;
  align-items: center;
  gap: 26px;
  padding: 15px 0;
  padding-right: 26px;
  margin-right: 26px;
  font-family: var(--font-head);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  white-space: nowrap;
}
/* Square separator, decorative only. */
.marquee-list li::after {
  content: "";
  width: 7px;
  height: 7px;
  flex: 0 0 7px;
  background: var(--secondary);
  margin-right: -26px;
}

@keyframes marquee-scroll {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

/* ==========================================================================
   6. About
   ========================================================================== */
/* Tinted, and tighter than the shared rhythm. Named like the other
   per-section bands rather than reusing .section--alt, so the padding and
   the colour travel together. */
.about-section {
  padding-top: clamp(30px, 3.8vw, 52px);
  padding-bottom: clamp(30px, 3.8vw, 52px);
  background: var(--bg-alt);
}

.about-grid {
  display: grid;
  grid-template-columns: 0.94fr 1.06fr;
  align-items: center;
  gap: clamp(32px, 5vw, 64px);
}

.about-copy h2 {
  margin-bottom: 16px;
}
/* Held to a measure - a short paragraph run full width across a wide
   column reads as a single stranded line. */
.about-copy > p {
  max-width: 46ch;
  line-height: 1.75;
}

/* Button, phone and the social chip on one line. The chip used to sit on its
   own below everything, which left the column trailing off into white space. */
.about-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px 28px;
  margin-top: 28px;
}
.about-call {
  display: grid;
}
.about-call span {
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}
.about-call a {
  font-family: var(--font-head);
  font-size: var(--fs-h4);
  font-weight: 700;
  color: var(--ink);
}
.about-call a:hover {
  color: var(--ink);
}

.about-copy .social {
  margin-top: 0;
}
/* .social is styled for the dark footer, where a 6%-white chip reads.
   Here it would be filled with the band's own colour, so it takes white
   on a hairline instead. */
.about-copy .social a {
  background: var(--bg);
  border: 1px solid var(--line);
  color: var(--ink);
}
.about-copy .social a:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

/* --- Credentials: one fused block, not four separate slabs -------------- */
/* Shared hairlines rather than gaps - four short facts do not need four
   containers, and the fused grid reads as a single spec panel, which also
   keeps it distinct from the separated boxes in Why Choose. */
.about-cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  background: var(--bg);
  border: 1px solid var(--line);
}
.about-card {
  padding: clamp(20px, 2.2vw, 30px);
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
}
.about-card:nth-child(-n + 2) {
  border-top: none;
}
.about-card:nth-child(odd) {
  border-left: none;
}

.about-card-icon {
  display: block;
  margin-bottom: 14px;
}
.about-card-icon img {
  width: 26px;
  height: 26px;
}

.about-card h3 {
  margin: 0 0 6px;
  font-size: var(--fs-h4);
  color: var(--ink);
}
.about-card p {
  color: var(--body);
  line-height: 1.6;
}

/* ==========================================================================
   7. Choose the best
   ========================================================================== */
/* Plain square cards - a hairline border and nothing else. Kept distinct
   from the Services grid (icon above a centred label, top bar) and the
   Product cards (image on top) by being left-aligned and unadorned, so the
   three sections do not read as one repeated block. */
.choose-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 22px;
}
/* No hover state: the cards are not links. */
.choose-card {
  position: relative;
  padding: 28px 26px;
  background: #fff;
  border: 1px solid var(--line);
}

.choose-icon {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin-bottom: 18px;
  background: var(--bg-alt);
}
.choose-icon img {
  width: 24px;
  height: 24px;
}

.choose-card h3 {
  margin-bottom: 8px;
  font-size: var(--fs-h4);
}
.choose-card p {
  font-size: var(--fs-xs);
  color: var(--body);
}

/* ==========================================================================
   7b. Why choose us
   ========================================================================== */
/* Artwork rather than a drawn grid. The file is already near-white - mean
   luminance 250/255, nothing darker than 226 - so it needs no scrim over it
   to stay out of the copy’s way; #111 measures 14:1 against even its
   darkest pixel. background-color carries the band if the file 404s. */
.whyus-section {
  /* Tighter than the shared .section rhythm - the boxes carry their own
     padding, so the band does not need the full 104px top and bottom. */
  padding-top: clamp(38px, 4.6vw, 62px);
  padding-bottom: clamp(28px, 3.4vw, 44px);
  background-color: var(--bg);
  background-image: url("../images/bg-pattern2.webp");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  position: relative;
  z-index: 10;
  &::after {
    content: "";
    position: absolute;
    top: 0;
    top: 0;
    background-color: rgba(255, 255, 255, 0.64);
    width: 100%;
    height: 100%;
    z-index: -10;
  }
}
/* The intro is the one paragraph in the section that runs long, so it gets a
   measure rather than spanning the full container. */
.whyus-section .section-head {
  margin-bottom: clamp(22px, 2.8vw, 34px);
}
.whyus-section .section-head p {
  max-width: 68ch;
}

.whyus-grid,
.info-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(14px, 1.6vw, 22px);
}

/* Four contact methods, one row. Why Choose has six cards and reads better
   three up, so only the info grid takes this. */
.info-grid {
  grid-template-columns: repeat(4, 1fr);
}
/* A four-up card is narrow, and the email address is one long token. */
.info-card p {
  overflow-wrap: anywhere;
}

/* Solid white against the patterned field, held by a hairline - the box is
   what separates one claim from the next, so it does not also need a shadow. */
.whyus-card,
.info-card {
  padding: 24px 24px 26px;
  background: var(--bg);
  border: 1px solid var(--line);
}
.whyus-card-icon,
.info-card-icon {
  display: grid;
  place-items: center start;
  width: 44px;
  height: 34px;
  margin-bottom: 12px;
}
.whyus-card-icon img,
.info-card-icon img {
  width: 30px;
  height: 30px;
}

.whyus-card h3,
.info-card h3 {
  margin-bottom: 8px;
  font-size: var(--fs-h4);
  color: var(--ink);
}
.whyus-card p,
.info-card p {
  color: var(--body);
  line-height: 1.65;
}

/* These must sit after the shared .whyus-card/.info-card rules above, not
   before them: same specificity, so source order is what decides it, and
   earlier the padding was simply being overwritten again further down.
   Tighter because these cards hold two or three short lines rather than a
   paragraph. */
.info-card {
  padding: 10px 10px 10px;
}
.info-card-icon {
  margin-bottom: 10px;
}
.info-card h3 {
  margin-bottom: 6px;
}

/* ==========================================================================
   7c. What we offer here
   Third icon-and-name grid on the page, so it is the deliberate inverse of
   the Industries grid: solid teal tile with a white glyph, and cards lifted
   by shadow rather than outlined by a border.
   ========================================================================== */

#offer {
  background-image: url("../images/bg-offer.webp");
  background-position: center center;
  background-size: 40%;
  position: relative;
  z-index: 10;
  &::after {
    content: "";
    width: 100%;
    height: 100%;
    position: absolute;
    left: 0;
    top: 0;
    z-index: -10;
    background-color: rgba(229, 229, 229, 0.741);
  }
}

.offer-grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 10px;
}
.offer-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 10px 10px;
  background: #fff;
  box-shadow: var(--shadow);
  text-align: center;
  transition:
    box-shadow 0.25s var(--ease),
    transform 0.25s var(--ease);
}
.offer-item:hover {
  box-shadow: var(--shadow-lg);
  transform: translateY(-5px);
}

.offer-icon {
  display: grid;
  place-items: center;
  width: 100%;
  height: 64px;
  background: var(--primary-dark);
  transition: background 0.25s var(--ease);
}
.offer-icon img {
  width: 30px;
  height: 30px;
}
.offer-item:hover .offer-icon {
  /* background: var(--ink); */
}

.offer-name {
  font-family: var(--font-head);
  font-size: var(--fs-xs);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
}

/* ==========================================================================
   7d. Surveillance redefined
   A full-bleed photo panel with the copy held to the left half.
   ========================================================================== */

/* The photo is the panel's background, not the copy's. Text painted onto an
   image is only legible where that image happens to be pale - the scrim
   below removes that dependency. */
.surv-panel {
  position: relative;
  min-height: clamp(320px, 30vw, 440px);
  display: flex;
  align-items: center;
  padding: clamp(28px, 4vw, 56px);
  background-color: var(--bg-alt);
  background-image: url("../images/bg-middle.webp");
  background-size: cover;
  background-position: center right;
  background-repeat: no-repeat;
  overflow: hidden;
  box-shadow: 0px 10px 20px -10px gray;
}

/* Fades out before the camera, so the subject stays clear. */
.surv-panel::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    rgba(245, 245, 245, 0.96) 0%,
    rgba(245, 245, 245, 0.9) 40%,
    rgba(245, 245, 245, 0.35) 62%,
    rgba(245, 245, 245, 0) 78%
  );
}

.surv-copy {
  position: relative; /* above the scrim */
  max-width: 52%;
}

.surv-copy h2 {
  margin-bottom: 14px;
}
.surv-copy p {
  color: var(--body);
  line-height: 1.7;
}
.surv-copy .btn {
  align-self: flex-start;
  margin-top: 20px;
}

/* ==========================================================================
   8. Products
   ========================================================================== */
/* Ten items, so tiles rather than cards: artwork over a name, nothing else.
   Five across on desktop keeps two tidy rows. */
.product-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 20px;
}
/* No hover state, matching every other card set on the page. The whole
   card is still the link - it just does not react to the pointer. */
.product-card {
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid var(--line);
  text-align: center;
}

.product-media {
  display: block;
  overflow: hidden;
  background: var(--bg-alt);
  border-bottom: 1px solid var(--line);
}
.product-media img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: contain;
  padding: 10px;
  background-color: #fff;
}

.product-name {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: center;
  padding: 16px 12px 18px;
  font-family: var(--font-head);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
  font-size: 10px;
}

/* The product strip is a carousel. Arrows sit just outside the slides so they
   never cover a product name, and drop out on a phone where the strip is
   swiped rather than clicked. */
.our-product {
  position: relative;
  margin-top: clamp(26px, 3.4vw, 44px);
}
.prod-nav {
  position: absolute;
  top: 38%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  transform: translateY(-50%);
  background: var(--bg);
  border: 1px solid var(--line);
  font-size: 22px;
  line-height: 1;
  color: var(--ink);
  cursor: pointer;
  transition:
    background 0.22s var(--ease),
    border-color 0.22s var(--ease),
    color 0.22s var(--ease);
}
.prod-nav:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}
.ourProducts-prev {
  left: -20px;
}
.ourProducts-next {
  right: -20px;
}

/* ==========================================================================
   9. Services (tabbed)
   ========================================================================== */
/* The names scroll sideways rather than wrapping - a tab row that reflows to
   two lines stops reading as one row of choices. */
.svc-tablist {
  position: relative;
  display: flex;
  gap: clamp(16px, 2.6vw, 44px);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  scrollbar-width: none;
}
.svc-tablist::-webkit-scrollbar {
  display: none;
}

/* Added by main.js, so it never shows without the script to place it. */
.svc-tab-indicator {
  position: absolute;
  bottom: -1px;
  left: 0;
  width: 0;
  height: 2px;
  background: var(--primary-dark);
  transition:
    transform 0.42s var(--ease),
    width 0.42s var(--ease);
}
/* With the bar in place the per-tab underlines would double up. */
.svc-tablist.has-indicator .svc-tab::after {
  display: none;
}

.svc-tab {
  position: relative;
  flex: 0 0 auto;
  padding: 0 0 13px;
  background: none;
  border: 0;
  font-family: var(--font-head);
  font-size: var(--fs-sm);
  font-weight: 400;
  line-height: 1.3;
  color: var(--body);
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.22s var(--ease);
}
.svc-tab:hover {
  color: var(--ink);
}
.svc-tab.is-active {
  color: var(--primary-dark);
}
/* The underline sits on the tablist rule rather than above it, so the active
   name looks joined to its panel. */
.svc-tab::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: var(--primary-dark);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.3s var(--ease);
}
.svc-tab.is-active::after {
  transform: scaleX(1);
}

/* Every panel sits in the same grid cell, so one can fade out while the
   next fades in and the row keeps the height of the tallest. */
.svc-tabs {
  display: grid;
  grid-template-columns: 1fr;
}
.svc-tablist {
  grid-row: 1;
}

.svc-panel {
  grid-row: 2;
  grid-column: 1;
  display: grid;
  grid-template-columns: 0.86fr 1.14fr;
  align-items: stretch;
  gap: clamp(20px, 2.4vw, 34px);
  padding-top: clamp(30px, 4vw, 54px);
  opacity: 0;
  visibility: hidden;
  /* Vertical, like every other reveal on the page. The inactive panels are
     still laid out - visibility:hidden does not remove them - so a sideways
     offset pushed five full-width blocks past the container edge. */
  transform: translateY(18px);
  pointer-events: none;
  transition:
    opacity 0.42s var(--ease),
    transform 0.42s var(--ease),
    visibility 0s linear 0.42s;
}
.svc-panel.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
  pointer-events: auto;
  transition:
    opacity 0.42s var(--ease),
    transform 0.42s var(--ease),
    visibility 0s;
}
/* No-script fallback. main.js clears the attribute on load so the panels
   can stack and cross-fade; without it, only the first panel shows. */
.svc-panel[hidden] {
  display: none;
}

/* A soft grey block against the white band, matched in height to the picture
   beside it. Its own contents are centred, so a short service description
   does not sit at the top of a tall block. */
.svc-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(26px, 3vw, 44px);
  background: var(--bg-alt);
}

/* The single place secondary appears in this section. */
.svc-copy::before {
  content: "";
  display: block;
  width: 40px;
  height: 3px;
  margin-bottom: 20px;
  background: var(--secondary);
}
.svc-copy h3 {
  margin-bottom: 14px;
  font-size: var(--fs-h1);
  color: var(--ink);
}
.svc-copy p {
  max-width: 46ch;
  color: var(--body);
  line-height: 1.75;
}
.svc-copy .btn {
  margin-top: 24px;
  /* A flex column stretches its children; without this the button would
     run the full width of the grey block. */
  align-self: flex-start;
}
.svc-note {
  margin-top: 16px;
  color: var(--muted);
}

/* The slot holds its 3:2 whether or not the photograph has loaded, so the
   panel does not jump height as you move between tabs. */
.svc-media {
  margin: 0;
  aspect-ratio: 3 / 2;
  background: var(--bg);
  border: 1px solid var(--line);
}
.svc-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ==========================================================================
   9a. Our process
   ========================================================================== */
/* A stepper. The rail is two layers stacked in the same place: a grey track,
   and a teal fill that scales from zero when the row scrolls in, so the line
   reads as drawing from 01 through to 04.

   gap is 0 and the spacing lives in each item's own padding. The rail has to
   begin and end on the centres of the first and last nodes; with four equal
   columns those are at 12.5% and 87.5%, and any gap would move them. */
/* Pale primary band. The section carries no .section--alt, so the tint is
   set here rather than by swapping the shared band class. */
.process-section {
  background-image: url("../images/bg-camera-image.webp");
  background-position: center center;
  background-size: 85%;
  background-repeat: no-repeat;
  position: relative;
  z-index: 10;
  background-attachment: fixed;
  &::after {
    content: "";
    width: 100%;
    height: 100%;
    /* 70%, down from 87% - enough of the cameras to read as a photograph. */
    background: #00000065;
    backdrop-filter: blur(3px);
    z-index: -10;
    position: absolute;
    
    left: 0;
    top: 0;

  }
}

/* --- Numeral boxes -------------------------------------------------------
   Solid white with a secondary border - which is what the base rules two
   sections up already say, so the band needs no overrides of its own.
   White is opaque, so there is nothing for a backdrop-filter to show
   through and it comes off with the rest.
   On white: numerals --secondary 4.9:1, --muted 5.3:1. */

/* --- Text on the darkened band ------------------------------------------
   The section carries a photograph under an 87% black scrim, so the ink
   and body greys the rest of the page uses measure between 1.0 and 3.1:1
   here - which is what made the copy disappear. These are measured against
   the scrim result (about #212121 at its lightest), not the photograph
   underneath, which the scrim all but removes.
     white       16.1:1     #b5b5b5   7.9:1     --primary  6.9:1
   Scoped to the section so nothing else on the page is affected. */
.process-section h2,
.process-section .process-step h3 {
  color: #fff;
}
.process-section .section-head p,
.process-section .process-step p {
  color: white;
}
/* --primary-dark is the teal for light backgrounds - 2.9:1 on this one.
   The lighter teal is what the other dark bands already use. */
.process-section .eyebrow,
.process-section .accent {
  color: var(--primary);
}

.process-grid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.process-grid::before,
.process-grid::after {
  content: "";
  position: absolute;
  top: 22px; /* node half-height, less half the rail */
  left: 12.5%;
  right: 12.5%;
  height: 2px;
}
.process-grid::before {
  background: var(--secondary-tint);
}
/* Held back a moment so the row has faded in before the line starts. */
.process-grid::after {
  background: var(--secondary);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1.15s var(--ease) 0.25s;
}
.process-grid.is-drawn::after {
  transform: scaleX(1);
}

.process-step {
  padding: 0 clamp(8px, 1.4vw, 20px);
  text-align: center;
}
/* Each node lights as the line reaches it - a quarter of the draw apart. */
.process-step:nth-child(1) {
  --i: 0;
}
.process-step:nth-child(2) {
  --i: 1;
}
.process-step:nth-child(3) {
  --i: 2;
}
.process-step:nth-child(4) {
  --i: 3;
}

/* Sits on the rail, so it needs a solid fill and to stack above it. */
.process-node {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin: 0 auto 18px;
  background: #ffffff85;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid var(--secondary-tint);
  transition: border-color 0.45s var(--ease);
  transition-delay: calc(var(--i, 0) * 260ms);
}
.process-grid.is-drawn .process-node {
  border-color: var(--secondary);
}

.process-num {
  font-family: var(--font-head);
  font-size: var(--fs-xs);
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.04em;
  color: var(--muted);
  transition: color 0.45s var(--ease);
  transition-delay: calc(var(--i, 0) * 260ms);
}
.process-grid.is-drawn .process-num {
  color: var(--secondary);
}

.process-step h3 {
  margin-bottom: 8px;
  font-size: var(--fs-h4);
  color: var(--ink);
}
.process-step p {
  color: var(--body);
  line-height: 1.65;
}

/* ==========================================================================
   9b. Industries we serve
   A fused hairline grid - one shared 1px background showing through the
   gaps. Distinct from the Product tiles (separate bordered tiles) and the
   Service cards (separate cards with a top rule), so three consecutive
   sections do not repeat the same pattern.
   ========================================================================== */
.industry-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.industry-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 32px 18px;
  background: #fff;
  text-align: center;
  transition: background 0.25s var(--ease);
}
.industry-item:hover {
  background: var(--primary-tint);
}

.industry-icon {
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  background: var(--primary-tint);
  transition: background 0.25s var(--ease);
}
.industry-icon img {
  width: 30px;
  height: 30px;
}
.industry-item:hover .industry-icon {
  background: #fff;
}

.industry-name {
  font-family: var(--font-head);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
}

/* ==========================================================================
   10. Gallery
   ========================================================================== */
.gallery-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px 34px;
  margin-bottom: clamp(28px, 4vw, 44px);
}
.gallery-head .section-head {
  margin-bottom: 0;
}

.gallery-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.gallery-filter {
  padding: 9px 18px;
  background: transparent;
  border: 1px solid var(--line);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--body);
  cursor: pointer;
  transition:
    background 0.2s var(--ease),
    border-color 0.2s var(--ease),
    color 0.2s var(--ease);
}
.gallery-filter:hover {
  border-color: var(--primary-dark);
  color: var(--primary-dark);
}
.gallery-filter.is-active {
  background: var(--primary-dark);
  border-color: var(--primary-dark);
  color: #fff;
}

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}
/* Filtered-out tiles leave the grid entirely, so the remaining ones reflow
   and close the gaps - no masonry library needed. */
.gallery-item[hidden] {
  display: none;
}
.gallery-item.is-entering {
  animation: galleryIn 0.32s var(--ease) both;
}
@keyframes galleryIn {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.gallery-item {
  position: relative;
  margin: 0;
  overflow: hidden;
}
.gallery-item img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform 0.55s var(--ease);
}
.gallery-item:hover img {
  transform: scale(1.07);
}
.gallery-item figcaption {
  position: absolute;
  inset: auto 0 0 0;
  display: grid;
  gap: 3px;
  padding: 44px 22px 20px;
  background: linear-gradient(transparent, rgba(8, 16, 24, 0.9));
  color: #fff;
}
.gallery-item figcaption span {
  font-size: var(--fs-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--primary);
}
.gallery-item figcaption strong {
  font-family: var(--font-head);
  font-size: var(--fs-h4);
  font-weight: 700;
}

.gallery-empty {
  padding: 40px 0;
  text-align: center;
  color: var(--muted);
}

/* ==========================================================================
   11. Counters
   ========================================================================== */
/* No band. The section is only here to give the card somewhere to sit and to
   keep it clear of the section below. */
.counters {
  /* No top padding: the card is pulled up past this edge, so any padding
     here would just cancel the overlap out. */
  padding: 0 0 clamp(22px, 2.8vw, 40px);
  background: none;
  position: relative;
  z-index: 20;
}

/* Crosses the join between the two sections by a little - enough to read as
   deliberate, not enough to look like it has slipped. The section above
   still has 42-72px of its own bottom padding, so nothing is crowded. */
.counter-grid {
  position: relative;
  z-index: 2;
  margin-top: -14px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  background: var(--bg);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
}

.counter {
  padding: clamp(18px, 2vw, 26px) clamp(12px, 1.6vw, 24px);
  border-left: 1px solid var(--line);
  text-align: center;
}
.counter:first-child {
  border-left: none;
}

/* place-items rather than text-align: img is display:block site-wide, so
   the cell's centring never reaches it. */
.counter-icon {
  display: grid;
  place-items: center;
  margin-bottom: 9px;
}
/* Drawn in teal for light backgrounds, which is what this is now - no filter. */
.counter-icon img {
  width: 22px;
  height: 22px;
}

.counter-value {
  display: flex;
  align-items: baseline;
  justify-content: center;
  font-family: var(--font-head);
  font-size: clamp(26px, 2.9vw, 38px); /* display numeral */
  font-weight: 800;
  line-height: 1;
  color: var(--ink);
}
/* --primary is a 2.3:1 mark on white; the plus carries meaning, so it takes
   the darker teal instead. */
.counter-value .plus {
  color: var(--primary-dark);
}

.counter-label {
  display: block;
  margin-top: 8px;
  font-size: var(--fs-xs);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ==========================================================================
   12. Top features of IFPD
   ========================================================================== */
/* Spec labels only. No card and no fill behind them - Industries already
   uses a fused grid and What We Offer uses shadow cards, so this one is
   just an outlined box so all three stay distinguishable. */
.feature-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 22px;
}
.feature-spec {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  text-align: center;
}
.feature-icon {
  display: grid;
  place-items: center;
  width: 78px;
  height: 78px;
  background: #fff;
  border: 1px solid var(--line);
  transition:
    border-color 0.25s var(--ease),
    background 0.25s var(--ease),
    transform 0.25s var(--ease);
}
.feature-icon img {
  width: 34px;
  height: 34px;
}
.feature-spec:hover .feature-icon {
  border-color: var(--primary-dark);
  background: var(--bg-alt);
  transform: translateY(-4px);
}
.feature-label {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 700;
  line-height: 1.35;
  color: var(--ink);
}

/* ==========================================================================
   12b. Brand strip
   Same seamless technique as the hero marquee - two identical lists, track
   slides -50%.
   ========================================================================== */
.brands {
  padding-bottom: clamp(44px, 6vw, 70px);
}
.brand-marquee {
  overflow: hidden;
}
.brand-track {
  display: flex;
  width: max-content;
  animation: brand-scroll 38s linear infinite;
}
.brand-marquee:hover .brand-track {
  animation-play-state: paused;
}

.brand-list {
  display: flex;
  align-items: center;
}
.brand-list li {
  padding: 0 26px;
}
/* grayscale() on its own does nothing here - black line art has no colour
   to remove. contrast() is what greys it: at 0.4 the black resolves to
   roughly #4d4d4d. Hover brings the artwork back to full strength. */
.brand-list img {
  width: 150px;
  height: auto;
  filter: grayscale(100%) contrast(0.4);
  transition: filter 0.25s var(--ease);
}
.brand-list li:hover img {
  filter: none;
}

@keyframes brand-scroll {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

/* ==========================================================================
   13. Testimonials
   ========================================================================== */
/* Carousel rather than a grid: three visible at a time, four in the set.
   Namespaced so it cannot collide with the hero carousel. */
.testiSwiper {
  padding-bottom: 54px;
}

/* height:auto lets Swiper stretch every slide to the tallest in view, so
   the cards line up however long a quote runs. */
.testiSwiper .testi-slide {
  height: auto;
}
.testiSwiper .quote {
  height: 100%;
}

.testiSwiper-pagination {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 8px;
  z-index: 5;
  display: flex;
  justify-content: center;
  gap: 9px;
}
.testiSwiper-bullet {
  width: 26px;
  height: 4px;
  background: var(--line);
  border: none;
  padding: 0;
  cursor: pointer;
  transition:
    background 0.25s var(--ease),
    width 0.25s var(--ease);
}
.testiSwiper-bullet:hover {
  background: var(--muted);
}
.testiSwiper-bullet-active {
  width: 46px;
  background: var(--primary-dark);
}
.quote {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 30px 30px 26px;
  background: #fff;
  border: 1px solid var(--line);
  border-top: 3px solid var(--primary);
  transition:
    border-top-color 0.25s var(--ease),
    box-shadow 0.25s var(--ease);
}
.quote:hover {
  border-top-color: var(--primary-dark);
  box-shadow: var(--shadow);
}

.quote-head {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 20px;
}
.quote-avatar {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  flex: 0 0 48px;
  background: var(--primary-dark);
  color: #fff;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: var(--fs-body);
  letter-spacing: 0.02em;
}
.quote-who {
  display: grid;
  line-height: 1.3;
}
.quote-who strong {
  font-family: var(--font-head);
  font-size: var(--fs-h4);
  font-weight: 700;
  color: var(--ink);
}
.quote-who small {
  font-size: var(--fs-xs);
  color: var(--primary-dark);
}

.quote > p {
  flex: 1;
  font-size: var(--fs-xs);
  color: var(--body);
}

.quote-foot {
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
.quote-stars {
  font-size: var(--fs-body);
  letter-spacing: 0.18em;
  color: var(--primary-dark);
}

/* ==========================================================================
   14. CTA
   ========================================================================== */
.cta {
  padding: clamp(44px, 5.5vw, 68px) 0;
  background: var(--primary-dark);
}
.cta-grid {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  align-items: center;
  gap: clamp(30px, 4vw, 60px);
}

.cta-copy .eyebrow {
  color: #fff;
}
.cta-copy .eyebrow::before {
  background: var(--secondary);
}
.cta h2 {
  color: #fff;
  margin-bottom: 0.4em;
}
.cta p {
  color: rgba(255, 255, 255, 0.88);
  max-width: 44ch;
}

.cta-points {
  display: grid;
  gap: 9px;
  margin-top: 20px;
}
.cta-points li {
  position: relative;
  padding-left: 22px;
  color: #fff;
  font-size: var(--fs-xs);
}
.cta-points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 11px;
  width: 7px;
  height: 7px;
  background: var(--secondary);
}
.cta-points a {
  color: #fff;
}
.cta-points a:hover {
  color: rgba(255, 255, 255, 0.72);
}

/* .js-validate is a JavaScript hook only - deliberately unstyled, so do not
   add rules for it here. It marks a form for the validation in main.js. */

/* --- Quote form ------------------------------------------------------- */
.quote-form {
  display: grid;
  gap: 10px;
  padding: clamp(18px, 2.2vw, 26px);
  background: #fff;
}
.quote-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
/* min-width: 0 because a grid item defaults to min-width: auto and will
   not shrink below its content - which is what pushes the file input and
   its CHOOSE FILE button past the edge of the column. */
.field {
  display: grid;
  gap: 4px;
  min-width: 0;
}

/* The date input has no placeholder to fall back on, so its label shows. */
.field-label {
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--body);
}

.quote-form input,
.quote-form select,
.quote-form textarea {
  width: 100%;
  padding: 7px 13px;
  background: var(--bg-alt);
  border: 1px solid var(--line);
  font-family: inherit;
  font-size: var(--fs-sm);
  color: var(--ink);
  resize: vertical;
  transition:
    border-color 0.2s var(--ease),
    background 0.2s var(--ease);
}
.quote-form input::placeholder,
.quote-form textarea::placeholder {
  color: var(--muted);
}
.quote-form input:focus,
.quote-form select:focus,
.quote-form textarea:focus {
  outline: none;
  background: #fff;
  border-color: var(--primary-dark);
}

/* appearance:none is set globally in the reset, so the select needs its
   chevron drawing back in. */
.quote-form select {
  padding-right: 36px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2317727a' stroke-width='2.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 16px;
}

.quote-form .btn {
  justify-self: start;
}
/* Honeypot. Positioned away rather than display:none - plenty of bots skip
   anything hidden that way, and aria-hidden plus tabindex keeps it out of
   the reading order and the tab order for everyone else. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* File inputs. The button half is the one part of a file input that can be
   styled, so it takes the site button treatment and the field around it
   matches every other input. */
.quote-form input[type="file"] {
  padding: 8px 10px;
  font-size: var(--fs-xs);
  cursor: pointer;
}
.quote-form input[type="file"]::file-selector-button {
  margin-right: 12px;
  padding: 7px 14px;
  background: var(--ink);
  border: none;
  color: #fff;
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.22s var(--ease);
}
.quote-form input[type="file"]::file-selector-button:hover {
  background: var(--secondary);
}
/* Sits under a field rather than labelling it - the label is above. */
.field-note {
  margin: 0;
  color: var(--muted);
}

.quote-form .form-note {
  min-height: 1.3em;
  margin: 0;
  font-size: var(--fs-xs);
}
.quote-form .form-note.is-ok {
  color: var(--primary-dark);
}
.quote-form .form-note.is-error {
  color: var(--secondary);
}

/* ==========================================================================
   15. FAQ
   ========================================================================== */
.faq-layout {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: clamp(30px, 4vw, 60px);
  align-items: start;
}
.faq-aside .section-head {
  margin-bottom: 26px;
}
.faq-help {
  padding: 28px 26px;
  background: var(--ink);
  color: #fff;
}
.faq-help h4 {
  color: #fff;
  margin-bottom: 8px;
}
.faq-help p {
  color: rgba(255, 255, 255, 0.78);
  font-size: var(--fs-xs);
  margin-bottom: 18px;
}

.faq-list {
  border: 1px solid var(--line);
  background: #fff;
}
.faq-item + .faq-item {
  border-top: 1px solid var(--line);
}
.faq-q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: 100%;
  padding: 22px 24px;
  background: none;
  border: none;
  font-family: var(--font-head);
  font-size: var(--fs-body);
  font-weight: 600;
  line-height: 1.45;
  text-align: left;
  color: var(--ink);
  cursor: pointer;
  transition:
    color 0.2s var(--ease),
    background 0.2s var(--ease);
}
.faq-q:hover {
  color: var(--primary-dark);
}
.faq-q[aria-expanded="true"] {
  color: var(--primary-dark);
  background: var(--bg-alt);
}
.faq-icon {
  position: relative;
  flex: 0 0 22px;
  width: 22px;
  height: 22px;
  background: var(--bg-alt);
}
.faq-icon::before,
.faq-icon::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  background: var(--ink);
  transform: translate(-50%, -50%);
  transition:
    transform 0.25s var(--ease),
    opacity 0.2s var(--ease);
}
.faq-icon::before {
  width: 10px;
  height: 2px;
}
.faq-icon::after {
  width: 2px;
  height: 10px;
}
.faq-q[aria-expanded="true"] .faq-icon {
  background: var(--ink);
}
.faq-q[aria-expanded="true"] .faq-icon::before,
.faq-q[aria-expanded="true"] .faq-icon::after {
  background: #fff;
}
.faq-q[aria-expanded="true"] .faq-icon::after {
  transform: translate(-50%, -50%) rotate(90deg);
  opacity: 0;
}

/* 0fr -> 1fr animates the panel's real height. No measuring, and no
   max-height guess that has to be bigger than the longest answer. */
.faq-a {
  display: grid;
  grid-template-rows: 0fr;
  visibility: hidden;
  color: var(--muted);
  font-size: var(--fs-xs);
  transition:
    grid-template-rows 0.4s var(--ease),
    visibility 0s linear 0.4s;
}
/* min-height:0 is not optional: grid items default to min-height:auto,
   which refuses to shrink below the content and defeats the collapse. */
.faq-a-inner {
  overflow: hidden;
  min-height: 0;
  padding: 0 24px;
  opacity: 0;
  transition: opacity 0.28s var(--ease);
}
.faq-q[aria-expanded="true"] + .faq-a {
  grid-template-rows: 1fr;
  visibility: visible;
  transition:
    grid-template-rows 0.4s var(--ease),
    visibility 0s;
}
/* The copy fades a beat behind the opening, so it is not sliding and
   fading at the same time. */
.faq-q[aria-expanded="true"] + .faq-a .faq-a-inner {
  padding: 22px 24px 24px;
  opacity: 1;
  transition:
    opacity 0.3s var(--ease) 0.12s,
    padding 0.4s var(--ease);
}
/* No-script fallback: main.js clears the attribute on load. */
.faq-a[hidden] {
  display: none;
}

/* ==========================================================================
   15b. Inner page head + map
   ========================================================================== */
/* --- Contact: the four ways in ------------------------------------------ */
/* Tighter than the shared section rhythm. Four cards of two short lines do
   not need the space a section of paragraphs does, and the heading sat a
   long way above them. */
.contact-reach {
  padding-top: clamp(26px, 3.2vw, 44px);
  padding-bottom: clamp(22px, 2.8vw, 36px);
}
.contact-reach .section-head {
  margin-bottom: clamp(16px, 2vw, 26px);
}

/* --- Contact: form left, framed map right -------------------------------- */
/* align-items:stretch is what makes this work. Both columns take the row height
   and the map fills whatever that turns out to be, so a five-field form and a
   map can never be out of step the way they were when the map carried a height
   of its own. */
.contact-layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  gap: clamp(20px, 2.6vw, 34px);
}

.contact-panel {
  padding: clamp(22px, 2.6vw, 34px);
  background: var(--bg);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
}
.contact-panel h2 {
  margin-bottom: 8px;
}
.contact-panel > p {
  margin-bottom: 22px;
  color: var(--muted);
}
/* The card supplies the padding now. */
.contact-panel .quote-form {
  padding: 0;
  background: none;
}

/* The careers form has no map beside it, so its card is centred and held to
   a measure rather than filling a column. */
.career-panel {
  max-width: 780px;
  margin: 0 auto;
}

/* 10px of white around the frame and a shadow under it. */
.contact-map {
  display: flex;
  margin: 0;
  padding: 10px;
  min-height: 420px;
  background: var(--bg);
  box-shadow: var(--shadow-lg);
}
/* flex:1 rather than height:100%: a percentage height needs a resolved height
   on every ancestor, and this grid row is sized by its content. */
.contact-map iframe {
  flex: 1;
  width: 100%;
  border: 0;
}

/* --- About: the opening statement --------------------------------------- */
.about-story {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  align-items: start;
  gap: clamp(28px, 4vw, 56px);
}
.about-story h2 {
  margin-bottom: 14px;
}
.about-story p + p {
  margin-top: 14px;
}
.about-story .about-lead {
  font-size: var(--fs-sm);
  line-height: 1.75;
  color: var(--body);
}

/* ==========================================================================
   15c. Client logos
   ========================================================================== */
/* A static row, not the scrolling strip the home page used to carry: five
   logos fit without moving, and motion for its own sake reads as filler.
   Greyscale so a row of unrelated brand colours does not fight the page -
   the palette here is 80% black and white. No hover: these are not links. */
.client-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  align-items: stretch;
  gap: clamp(12px, 1.6vw, 20px);
  margin: 0;
  padding: 0;
  list-style: none;
}
.client-grid li {
  display: grid;
  place-items: center;
  padding: clamp(16px, 2vw, 24px) clamp(10px, 1.4vw, 18px);
  background: var(--bg);
  border: 1px solid var(--line);
}
.client-grid img {
  width: 100%;
  max-width: 150px;
  height: auto;
  filter: grayscale(1);
  opacity: 0.8;
}

/* ==========================================================================
   15d. Product detail
   One pattern for all ten product pages: shot on the left, copy and specs
   on the right.
   ========================================================================== */
.product-layout {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  align-items: start;
  gap: clamp(26px, 4vw, 56px);
}

/* Named .product-shot, not .product-media - that one is already the tile
   inside the home page carousel and means something else. */
.product-shot {
  margin: 0;
  padding: 10px;
  background: var(--bg);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
}
.product-shot img {
  display: block;
  width: 100%;
  height: auto;
}

.product-copy h1 {
  margin-bottom: 14px;
  font-size: var(--fs-h1);
  color: var(--ink);
}
.product-copy > p {
  max-width: 56ch;
  line-height: 1.75;
}
.product-copy h2 {
  margin: 26px 0 4px;
  font-size: var(--fs-h4);
}
.product-copy .btn {
  margin-top: 26px;
}

/* Ticks drawn from two borders on a rotated box - no icon file for a mark
   this small. */
.spec-list {
  display: grid;
  gap: 9px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.spec-list li {
  position: relative;
  padding-left: 26px;
  color: var(--body);
  line-height: 1.6;
}
.spec-list li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 4px;
  width: 11px;
  height: 6px;
  border-left: 2px solid var(--primary-dark);
  border-bottom: 2px solid var(--primary-dark);
  transform: rotate(-45deg);
}

/* ==========================================================================
   15e. Service detail
   Shares the product page layout for the top of the page. The numbered
   rows below it are their own thing: the stepper on the home page is
   built around exactly four nodes on a rail, and these lists run to five
   or more, so a row per step carries any count without breaking.
   ========================================================================== */
.step-rows {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}
.step-rows li {
  display: grid;
  grid-template-columns: 52px 1fr;
  align-items: start;
  gap: 6px 16px;
  padding: 16px 0;
  border-bottom: 1px solid var(--line);
}
.step-rows .step-n {
  font-family: var(--font-head);
  font-size: var(--fs-h4);
  font-weight: 700;
  line-height: 1.5;
  color: var(--primary-dark);
}
.step-rows p {
  color: var(--body);
  line-height: 1.6;
}

/* ==========================================================================
   16. Footer
   ========================================================================== */
.site-footer {
  padding: clamp(20px, 7vw, 20px) 0 0;
  background: var(--dark);
  color: #a3a3a3;
  font-size: var(--fs-xs);
}
.site-footer .logo img {
  height: 58px;
}
.site-footer h4 {
  position: relative;
  margin-bottom: 24px;
  padding-bottom: 12px;
  color: #fff;
  font-size: var(--fs-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.site-footer h4::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 34px;
  height: 2px;
  background: var(--primary);
}
.site-footer a {
  color: #a3a3a3;
}
.site-footer a:hover {
  color: #fff;
}

/* Logo alone, on a rule. */

/* The brand column no longer carries the logo, so it needs less room. */
/* The grid is the first thing in the footer now, so it owns the top space
   that the removed logo strip used to provide. */
.footer-grid {
  display: grid;
  grid-template-columns: 1.25fr 1fr 1fr 1.2fr;
  gap: clamp(26px, 3.4vw, 44px);
  /* Longhand, deliberately. This div is class="container footer-grid" and
     the container supplies the left and right gutter. A padding shorthand
     here would set left/right to 0 and the footer text would sit flush
     against the edge of the screen. */
  padding-top: 36px;
  padding-bottom: 44px;
}
.footer-brand p {
  max-width: 34ch;
}
.footer-col ul {
  display: grid;
  gap: 11px;
}
.footer-col ul a {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
/* var(--ink) here was #111111 on a #141414 footer - 1.02:1, invisible.
   Teal reads at 7.9:1 and ties the list to the rules under the headings.
   Excluding .contact-list matters now it is visible: those rows already
   have an icon, and were quietly carrying a marker as well. */
.footer-col ul:not(.contact-list) a::before {
  content: "";
  width: 6px;
  height: 2px;
  background: var(--primary);
  flex: 0 0 6px;
  transition: width 0.2s var(--ease);
}
.footer-col ul:not(.contact-list) a:hover::before {
  width: 12px;
}

.contact-list {
  display: grid;
  gap: 16px;
}
.contact-list li {
  display: flex;
  align-items: flex-start;
  gap: 13px;
}
.contact-list li > span:last-child {
  display: grid;
  gap: 3px;
  line-height: 1.5;
}
.contact-icon {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  background: rgba(255, 255, 255, 0.07);
  color: var(--primary);
}
.contact-icon svg {
  width: 17px;
  height: 17px;
  display: block;
}
.contact-list a {
  color: #e0e0e0;
  font-weight: 500;
}
.contact-list a:hover {
  color: #fff;
}

.social {
  display: flex;
  gap: 8px;
  margin-top: 22px;
}
.social a {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  background: rgba(255, 255, 255, 0.06);
  color: #e0e0e0;
  font-size: var(--fs-xs);
  font-weight: 600;
  box-shadow: 0px 0px 0px 0.5px white;
  transition:
    background 0.2s var(--ease),
    color 0.2s var(--ease);
}
.social a:hover {
  background: var(--ink);
  color: #fff;
}
.social-icon {
  width: 18px;
  height: 18px;
  fill: currentColor;
}

/* Copyright alone, centred. */
.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 8px 20px;
  padding-top: 20px;
  padding-bottom: 22px;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  font-size: var(--fs-xs);
}
.footer-bottom p {
  margin: 0;
}

/* --- Floating action rail ------------------------------------------------
   Anchored bottom-right. Back-to-top is the FIRST child so that when it
   fades in the call and WhatsApp buttons below it do not shift position. */
.float-rail {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 95;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.float-btn {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border: none;
  padding: 0;
  color: #fff;
  cursor: pointer;
  box-shadow: var(--shadow);
  transition:
    background 0.22s var(--ease),
    transform 0.22s var(--ease);
}
.float-btn svg {
  width: 20px;
  height: 20px;
  display: block;
}
.float-btn:hover {
  transform: translateY(-3px);
  color: #fff;
}

.float-call {
  background: var(--secondary);
}
.float-call:hover {
  background: var(--secondary-dark);
}

.float-whatsapp {
  background: var(--whatsapp);
}
.float-whatsapp:hover {
  background: #128c7e;
}

.to-top {
  background: var(--ink);
  /* Near-black on a near-black band leaves nothing to see. A hard white
     ring gives it an edge on any background and a soft halo lifts it off
     dark ones; over the pale sections both are white on white, so they
     cost nothing there. The dark shadow underneath still does the work
     of separating it from light backgrounds. */
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.55),
    0 0 18px rgba(255, 255, 255, 0.28),
    var(--shadow);
  font-size: 18px; /* glyph, not text */
  line-height: 1;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition:
    opacity 0.25s var(--ease),
    transform 0.25s var(--ease),
    visibility 0.25s,
    background 0.22s var(--ease);
}
.to-top.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.to-top:hover {
  background: var(--ink);
  transform: translateY(-3px);
}

/* ==========================================================================
   18. 404
   One centred column: the numeral, the message, one button. The numeral is
   artwork rather than a heading, so it carries aria-hidden and the h1 below
   it is what a screen reader announces.
   ========================================================================== */
.notfound-inner {
  display: grid;
  justify-items: center;
  text-align: center;
  /* Longhand: .container supplies the horizontal gutter and a shorthand
     here would zero it. */
  padding-top: clamp(20px, 5vw, 60px);
  padding-bottom: clamp(20px, 5vw, 60px);
}
/* Flat and large, in the primary. At 0.16 it rendered #dff4f5 - 1.14:1 on
   white, so it was barely on the page at all; 0.3 keeps it clearly a mark
   without competing with the heading beside it. */
.notfound-code {
  margin: 0;
  font-family: var(--font-head);
  font-size: clamp(110px, 22vw, 260px);
  font-weight: 800;
  line-height: 0.8;
  letter-spacing: -0.04em;
  color: var(--primary);
  opacity: 0.3;
}
.notfound-inner h1 {
  margin: clamp(10px, 2vw, 18px) 0 clamp(26px, 3.4vw, 36px);
}

/* ==========================================================================
   17. Reveal + responsive
   ========================================================================== */
/* --- AOS refinements ---------------------------------------------------
   AOS travels 100px by default, which on a full-width block reads as a
   lurch rather than a settle. A third of the distance over a longer
   duration is what makes it look considered.

   The selector deliberately mirrors the one AOS ships -
   html:not(.no-js) [data-aos=fade-up] - so the two tie on specificity and
   load order decides it. That is why style.css is linked after aos.css.
   The .aos-animate reset is a whole class more specific, so it still wins
   once an element animates in. */
html:not(.no-js) [data-aos="fade-up"] {
  transform: translate3d(0, 34px, 0);
}
html:not(.no-js) [data-aos="fade-down"] {
  transform: translate3d(0, -34px, 0);
}

/* AOS owns the reveals now. Its stylesheet is what sets the starting
   opacity, so if aos.js fails to load every [data-aos] element would stay
   invisible. main.js adds .no-aos to <html> in that case and this puts
   the page back. */
.no-aos [data-aos] {
  opacity: 1 !important;
  transform: none !important;
}

/* ==========================================================================
   Responsive
   max-width queries only, and emitted widest first. With max-width the
   cascade is settled by source order, so a narrower query has to come
   later to win. Anything added out of order will be overridden by a
   wider block and look like it simply did not apply.
   ========================================================================== */

@media (max-width: 1280px) {
  /* Header: tighten the spacing rather than collapse. The four links and the
     Contact button need about 560px, so the full menu holds down to 992px. */
  .main-nav > ul {
    gap: 22px;
  }
  .logo img {
    height: 48px;
  }
  .topbar-contact {
    gap: 20px;
  }

  .counter-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  /* Two rows now, so the divider has to run between them too. */
  .counter:nth-child(3),
  .counter:nth-child(4) {
    border-top: 1px solid var(--line);
  }
  .counter:nth-child(3) {
    border-left: none;
  }
}

@media (max-width: 1199px) {
  .heroSwiper-nav {
    display: none;
  }
  /* The address is the longest item and is also in the footer, so it is
     the first to go when the bar runs short. */
  .tb-address {
    display: none !important;
  }
}

@media (max-width: 1080px) {
  /* Four steps across a 900px screen leaves about 200px each, which is
     narrower than the copy in them wants. Two rows from here - and a
     single horizontal rail no longer joins anything across two rows, so
     the numbered nodes carry the sequence on their own. */
  .process-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 30px 0;
  }
  .process-grid::before,
  .process-grid::after {
    display: none;
  }
  /* Centring existed to sit each node on the rail. With the rail gone there
     is nothing to centre on, and centred text in a narrow column gives every
     line a different starting edge. Numbers align with the copy. */
  .process-step {
    text-align: left;
  }
  .process-node {
    margin: 0 0 14px;
  }
  .whyus-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  /* One step behind Why Choose - the info grid started two columns wider,
     so 4 -> 3 -> 2 rather than dropping straight to two. */
  .info-grid {
    grid-template-columns: repeat(3, 1fr);
  }
  .footer-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 991px) {
  /* Menu collapses to the drawer from here down - keep NAV_BREAKPOINT in
     main.js in step with this value.
     The glass header has to give up its blur here. backdrop-filter creates
     a containing block for fixed-position descendants, which would trap the
     drawer inside the header box instead of the viewport. Solid white on a
     phone loses nothing - there is no banner showing through behind it. */
  .site-header,
  .site-header.is-stuck {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background: var(--bg);
  }

  .nav-toggle {
    display: grid;
  }

  /* position:sticky + z-index:100 makes the header a stacking context, so
     nothing inside it can paint above 100 however high its own z-index -
     which is why the backdrop stopped at the topbar. Lifting the whole
     context clears everything above it. */
  .site-header {
    z-index: 200;
  }

  /* Logo left, close right. The toggle in the header is behind the
     backdrop once the drawer is open, so this is the only way out. */
  .nav-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 0 16px;
    margin-bottom: 6px;
    border-bottom: 1px solid var(--line);
  }
  .nav-head-logo img {
    width: auto;
    height: 38px;
  }
  .nav-close {
    display: grid;
    place-items: center;
    flex: 0 0 40px;
    width: 40px;
    height: 40px;
    padding: 0;
    background: none;
    border: none;
    color: var(--ink);
    cursor: pointer;
  }
  .nav-close svg {
    width: 22px;
    height: 22px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: square;
  }

  /* A left drawer, not a panel under the header. 320px so it never
     reaches the toggle at the right of the header - a full-width panel
     would cover its own close control. Above the header's z-index 100
     so it sits over the logo rather than under it. */
  .main-nav {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 120;
    /* Near full width on a phone, capped so a tablet drawer does not
       swallow the whole screen. */
    width: min(400px, 95vw);
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0 var(--gutter) 28px;
    background: var(--bg);
    border-right: 1px solid var(--line);
    box-shadow: var(--shadow-lg);
    transform: translateX(-100%);
    transition: transform 0.36s var(--ease);
    overflow-y: auto;
    /* Stops a flick at the end of the list scrolling the page behind. */
    overscroll-behavior: contain;
  }
  .main-nav.is-open {
    transform: translateX(0);
  }

  /* Addressed as the nav's sibling, so the open state lives in one class
     and the backdrop needs no JavaScript of its own to appear. */
  .nav-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 110;
    background: rgba(17, 17, 17, 0.45);
    opacity: 0;
    visibility: hidden;
    transition:
      opacity 0.36s var(--ease),
      visibility 0s linear 0.36s;
  }
  .main-nav.is-open + .nav-backdrop {
    opacity: 1;
    visibility: visible;
    transition:
      opacity 0.36s var(--ease),
      visibility 0s;
  }
  .main-nav > ul {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }
  .main-nav > ul > li {
    display: block;
    position: static;
  }
  .main-nav > ul li {
    border-bottom: 1px solid var(--line);
  }
  .nav-link {
    display: flex;
    justify-content: space-between;
    height: auto;
    padding: 15px 2px;
  }
  .nav-link::after {
    display: none;
  }
  .nav-cta {
    margin-top: 16px;
    align-self: stretch;
  }
  /* Accordion instead of a floating panel. */
  .dropdown {
    position: static;
    min-width: 0;
    opacity: 1;
    visibility: visible;
    transform: none;
    background: var(--bg-alt);
    border: none;
    box-shadow: none;
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.35s var(--ease);
  }
  .has-dropdown.is-open > .dropdown {
    max-height: 640px;
  }
  .dropdown li:last-child {
    border-bottom: none;
  }
  .dropdown a {
    padding: 13px 16px;
    font-size: var(--fs-xs);
  }
  .dropdown a:hover {
    padding-left: 22px;
  }
  .caret {
    transform: translateY(-2px) rotate(45deg);
  }
}

@media (max-width: 980px) {
  /* Stacked, so the map takes a height of its own - there is nothing left
     beside it to match. */
  .contact-layout {
    grid-template-columns: 1fr;
  }
  .contact-map {
    min-height: 0;
    height: 340px;
  }
  .client-grid {
    grid-template-columns: repeat(3, 1fr);
  }
  .about-story,
  .product-layout {
    grid-template-columns: 1fr;
  }
  .ourProducts-prev {
    left: 0;
  }
  .ourProducts-next {
    right: 0;
  }
  /* Copy above the picture - side by side needs the width. */
  .svc-panel {
    grid-template-columns: 1fr;
  }
  .about-grid {
    grid-template-columns: 1fr;
  }
  .faq-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 860px) {
  /* Below this the bar cannot hold three items on one line. The email and
     address go - both are in the footer - and the numbers stay, because a
     phone number in a topbar is there to be tapped. */
  .topbar-contact li:nth-child(2),
  .topbar-contact li:nth-child(3) {
    display: none;
  }
}

.swiper-slide {
  margin-right: 20px !important;
}
.hero {
  .swiper-slide {
    margin-right: 0px !important;
  }
}
@media (max-width: 620px) {
  /* Two inputs side by side leaves each about 150px on a phone - too
     narrow to read a placeholder in, and far too narrow for a file
     input that has to show a button and a filename. One per row. */
  .quote-row {
    grid-template-columns: 1fr;
  }

  /* Already one centred column; the numeral just needs less leading. */
  .notfound-code {
    line-height: 0.9;
  }

  /* The strip is clipped by .brand-marquee anyway, so the padding only
     spreads the row out; on a phone it wastes the width. */
  .brand-list li {
    padding: 0;
  }
  .brand-list img {
    width: 112px;
  }

  /* Footer on a phone. The columns already stack; these stop the pieces
     that were laid out as rows from fighting the narrow width. */
  /* Two short link lists side by side rather than four stacked rows.
     That alone takes a column's height out of the footer. Brand and
     Contact Details span both tracks - a paragraph and a postal
     address wrap badly in half a phone screen. */
  .footer-grid {
    grid-template-columns: 1fr 1fr;
    gap: 24px 18px;
    padding-top: 24px;
    padding-bottom: 26px;
  }
  .footer-brand,
  .footer-grid > .footer-col:nth-child(4) {
    grid-column: 1 / -1;
  }

  /* Desktop spacing was still in force here: 24px margin plus 12px
     padding put 36px of air between every heading and its own list. */
  .site-footer h4 {
    margin-bottom: 13px;
    padding-bottom: 9px;
  }
  .footer-col ul {
    gap: 7px;
  }
  .contact-list {
    gap: 12px;
  }
  .footer-brand p {
    max-width: none;
  }
  /* Two ends of a bar makes no sense once they are stacked. */
  .footer-bottom {
    justify-content: center;
    text-align: center;
    gap: 4px;
  }
  /* A long address is one unbreakable run at this width. */
  .contact-list li > span:last-child {
    overflow-wrap: anywhere;
  }

  .client-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  /* The counters and the About credentials stay two up, which is what their
     hairline logic further up already assumes - nothing to add here. Only
     the padding needs to come in for the narrower column. */
  .about-card {
    padding: 18px 15px 20px;
  }

  .about-actions {
    gap: 18px 20px;
  }

  .counters {
    margin: 1.5rem 0;
  }
  .counter {
    padding: 18px 10px 20px;
  }
  /* Two up. A single column of six short cards is a long scroll for very
     little content. */
  .whyus-grid,
  .info-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
  }
  .whyus-card {
    padding: 14px 14px 14px;
  }
  /* Swipe, not arrows. */
  .prod-nav {
    display: none;
  }
  .svc-tab {
    font-size: var(--fs-xs);
  }
  .svc-copy h3 {
    font-size: var(--fs-h2);
  }
  .process-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 26px 0;
  }
  .process-step {
    padding: 0 8px;
  }
  :root {
    --gutter: 24px;
    /* The desktop scale is set for a wide column. At 360px a 32px heading
       wraps after two words, so the top of the scale comes down while the
       steps between the sizes stay proportional. */
    --fs-h1: 26px;
    --fs-h2: 21px;
    --fs-h3: 18px;
    --fs-h4: 16px;
  }
  /* One row, not three stacked. */
  .topbar-inner {
    gap: 10px;
    min-height: 40px;
  }
  .topbar-contact {
    gap: 14px;
  }
  /* The hairlines framed the chip as a box once it was the only thing on
     its side of the bar. */
  .topbar-social a,
  .topbar-social a:last-child {
    width: 36px;
    min-height: 32px;
    border-left: none;
    border-right: none;
    border: 1px solid #a2a2a2;
  }
  /* Only the form's primary action goes full width. Stretching an inline "Read More" across the screen is what made the buttons look oversized on a phone. */
  .about-actions .btn {
    flex: 0 0 auto;
  }
  .about-call {
    width: auto;
  }
  .float-rail {
    right: 14px;
    bottom: 14px;
    gap: 8px;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  /* The blanket animation-duration override below would make the marquee jump. Stop it outright and let the row be scrolled by hand instead. */
  .marquee {
    overflow-x: auto;
  }
  .marquee-track {
    animation: none !important;
    transform: none !important;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
  [data-aos] {
    opacity: 1;
    transform: none;
  }
}
