:root {
  --navy: #10182b;
  --navy-2: #1b2740;
  --orange: #ff6a3d;
  --orange-light: #ffe0d3;
  /* Darker orange for text/UI that sits on light backgrounds — the base
     --orange only hits 2.85:1 on white, failing WCAG AA (needs 4.5:1). This
     shade hits ~4.8:1 both as text-on-white and as a background under white
     text. Keep --orange for anything already on a navy/dark background
     (there it passes at 6.2:1) — don't blanket-replace. */
  --orange-text: #bf502e;
  /* The mirror of --orange-text for the other direction: --orange on a navy
     ground measures 5.23:1 as plain text and passes, but the moment it sits
     on a *tinted chip* over navy (the hero eyebrow pill) the chip lifts the
     background and the pair drops to 4.37:1 — a fail. This lighter orange
     measures 5.38:1 against that same chip. Use it only where orange sits on
     a dark ground; --orange stays correct for plain text on navy. */
  --orange-lit: #ff8a63;
  --text-dark: #1a1f2b;
  --text-light: #6b7280;
  --bg-light: #f7f8fa;
  --white: #ffffff;
  --radius: 16px;
  --shadow: 0 10px 30px rgba(16,24,43,0.08);

  /* Motion curves. The built-in CSS keywords are too soft to feel intentional:
     "ease" and "ease-out" barely decelerate, so a 250ms hover reads as lag.
     --ease-out starts fast (the element answers the cursor immediately) and
     settles slowly; use it for anything entering or responding to input.
     --ease-in-out is for things that move across the screen. Nothing on this
     site uses ease-in: it delays the first frames, which is exactly when the
     visitor is watching. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /* Logo palette (sampled from the leaf mark in Freedom_logo.png) — used
     sparingly as small per-item accents (icons, dividers), not a rebrand.
     The base tones are for decorative/background use only; each has a
     darkened "-text" pair for anywhere the color sits on a light background
     as a glyph, matching the existing --orange / --orange-text contrast
     pattern (WCAG AA, ~4.5:1+ on white). */
  --brand-gold: #fcb040;
  --brand-gold-text: #9c6d28;
  --brand-green: #40ae49;
  --brand-green-text: #2e7d35;
  --brand-red: #ef3e36;
  --brand-red-text: #bf322b;
  --brand-olive: #8cc63f;
  --brand-olive-text: #5a7d28;
}

* { box-sizing: border-box; }
/* Sitewide orphan/widow control -- text-wrap:pretty asks the browser to
   avoid leaving a single short word alone on the last line of a paragraph
   (the classic "one word by itself" look), text-wrap:balance asks it to
   spread a heading's words evenly across however many lines it takes
   instead of one long line + a short leftover. Both are layout-only (no
   effect on unsupported browsers) and apply everywhere by default, not
   just the hero sections that already had text-wrap:pretty on their own. */
p { text-wrap: pretty; }
h1, h2, h3 { text-wrap: balance; }
/* .site-header is position:sticky, so jumping to any in-page anchor
   (logo -> #top, nav "בית" links, #contact, etc.) would otherwise land the
   target flush against the viewport top and then have the sticky header
   render on top of it, covering the first ~125px (~100px on mobile) of
   whatever you jumped to -- on #top specifically, that's the hero's
   headline. scroll-padding-top reserves that space for every anchor jump
   on the page, not just this one. */
html { scroll-behavior: smooth; scroll-padding-top: 130px; }

body {
  margin: 0;
  font-family: 'Rubik', sans-serif;
  color: var(--text-dark);
  background: var(--white);
  line-height: 1.6;
}

.container {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 24px;
}

img { max-width: 100%; display: block; }

/* Browser-drawn surfaces carry the palette too: text selection, the text
   caret, native checkboxes/radios/selects, and link underlines otherwise ship
   in the browser's default blue, which belongs to no part of this site. */
::selection { background: var(--orange-light); color: var(--navy); }
html { accent-color: var(--orange-text); }
input, textarea { caret-color: var(--orange-text); }
a { text-underline-offset: .2em; }
/* Phone numbers, hours and stats line up digit-for-digit in their columns
   instead of each row's proportional digits drifting a pixel or two. */
.phone-btn, .contact-list, .footer-contact-list, .footer-hours-list, .about-stats strong {
  font-variant-numeric: tabular-nums;
}

/* Header */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(255,255,255,0.9);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid rgba(0,0,0,0.06);
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 24px;
  gap: 20px;
}
/* 50% bigger than the original 44px (the owner, 20 Oct 2026). */
.logo img { height: 66px; width: auto; }
.main-nav { display: flex; gap: 24px; }
.main-nav a {
  color: var(--text-dark);
  text-decoration: none;
  font-weight: 500;
  font-size: 15px;
  transition: color .2s;
}
.main-nav a:hover { color: var(--orange-text); }
/* Five categories, a longer crystal label and the bigger logo: keep every
   item on one line, and on narrower desktops tighten the row and let the
   call button go icon-only. */
.main-nav a, .phone-btn { white-space: nowrap; }
.logo { flex-shrink: 0; }
/* The header row needs more than the page's 1180px column on wide screens. */
.site-header .header-inner { max-width: 1440px; }
@media (max-width: 1480px) {
  .header-inner { gap: 14px; }
  .main-nav { gap: 15px; }
  .main-nav a { font-size: 14.5px; }
  .header-actions .phone-btn { display: none; }
  .phone-icon-btn { display: flex; }
}
@media (max-width: 1300px) {
  .main-nav { gap: 11px; }
  .main-nav a { font-size: 13.5px; }
  .logo img { height: 56px; }
}

/* Hover dropdown for top-nav categories that have subcategories (see
   navItemHtml in scripts/build.js) — CSS-only, no JS. :focus-within keeps
   it reachable by keyboard (Tab into the category link, then Tab into its
   dropdown links) even though nothing is clicked to open it. */
.main-nav-item { position: relative; }
/* The category link and its mobile-only expand/collapse button (.nav-toggle)
   share a row wrapper so the tap targets can be styled/positioned
   independently on mobile; on desktop the wrapper is collapsed out of the
   render tree (display:contents) so it doesn't affect the hover-dropdown
   layout at all. It's still a real DOM node though, so the arrow selector
   below has to reach through it explicitly. */
.nav-item-row { display: contents; }
.main-nav-item.has-dropdown > .nav-item-row > a::after {
  content: '▾';
  display: inline-block;
  margin-right: 4px;
  font-size: 10px;
  transform: translateY(-1px);
}
.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  padding: 4px;
  cursor: pointer;
  color: var(--text-light);
}
.nav-toggle svg { width: 18px; height: 18px; transition: transform .2s; }
.nav-close { display: none; }
.nav-backdrop { display: none; }
.nav-dropdown {
  display: none;
  flex-direction: column;
  position: absolute;
  top: 100%;
  right: 0;
  min-width: 210px;
  background: var(--white);
  border-radius: 12px;
  box-shadow: var(--shadow);
  padding: 8px;
  z-index: 150;
  /* A short arrival instead of popping in at full size: 160ms, anchored to
     the top edge it hangs from. @starting-style gives the first frame after
     display:none -> flex something to transition from, so this needs no JS.
     Browsers without it simply show the menu instantly, as before. */
  transform-origin: top center;
  transition: opacity 160ms var(--ease-out), transform 160ms var(--ease-out);
}
@starting-style {
  .nav-dropdown { opacity: 0; transform: translateY(-4px) scale(.98); }
}
/* Scoped to real-hover devices deliberately: this rule's specificity
   (.main-nav-item.has-dropdown:focus-within .nav-dropdown, 4 selectors)
   otherwise beats the mobile accordion's .main-nav-item.open > .nav-dropdown
   (3 selectors) regardless of cascade order. On touch, tapping .nav-toggle
   focuses the button -- :focus-within stays true after the tap, so this
   rule kept forcing the dropdown open even after script.js removed .open,
   meaning the *first* tap (open) appeared to work (both rules agreed) but
   the *second* tap (close) silently did nothing (this rule overrode it). */
@media (hover: hover) and (pointer: fine) {
  .main-nav-item.has-dropdown:hover .nav-dropdown,
  .main-nav-item.has-dropdown:focus-within .nav-dropdown { display: flex; }
}
.nav-dropdown a {
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 14px;
  white-space: nowrap;
}
.nav-dropdown a:hover { background: var(--bg-light); color: var(--orange-text); }

.header-actions { display: flex; align-items: center; gap: 12px; }
.phone-btn {
  color: var(--navy);
  font-weight: 700;
  text-decoration: none;
  font-size: 15px;
}
.whatsapp-btn {
  background: #25D366;
  color: white;
  padding: 9px 18px;
  border-radius: 999px;
  text-decoration: none;
  font-weight: 600;
  font-size: 14px;
  white-space: nowrap;
  transition: background-color 200ms ease, transform 160ms var(--ease-out);
}
.whatsapp-btn:hover { background: #1fbd5a; }
/* Every round/pill control gives a small physical "press" while held, so a
   tap is acknowledged before the page reacts. Subtle on purpose (0.95-0.97):
   bigger reads as a toy. */
.whatsapp-btn:active, .phone-icon-btn:active { transform: scale(.96); }
/* Icon-only call button — hidden on desktop (the text .phone-btn covers
   that), shown next to WhatsApp once the mobile breakpoint hides the text
   version, so mobile visitors still get a one-tap way to call. */
.phone-icon-btn {
  display: none;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--navy);
  color: white;
  transition: transform 160ms var(--ease-out);
}
.phone-icon-btn svg { width: 18px; height: 18px; }
.burger {
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 6px;
}
.burger span { width: 24px; height: 2px; background: var(--navy); border-radius: 2px; }

/* Site-wide search row — sits below the main nav row, filters
   search-index.json (built from every page's title/blurb) as you type. */
.header-search-row {
  border-top: 1px solid rgba(0,0,0,0.06);
  padding: 10px 24px;
}
.site-search-form {
  position: relative;
  max-width: 480px;
  margin: 0 auto;
}
.site-search-icon {
  position: absolute;
  top: 50%;
  right: 14px;
  transform: translateY(-50%);
  width: 16px;
  height: 16px;
  color: var(--text-light);
  pointer-events: none;
}
#site-search-input {
  width: 100%;
  border: 1px solid rgba(16,24,43,0.12);
  border-radius: 999px;
  padding: 9px 42px 9px 16px;
  font-size: 14px;
  font-family: inherit;
  background: var(--bg-light);
  color: var(--text-dark);
}
#site-search-input:focus { outline: 2px solid var(--orange-text); outline-offset: 1px; border-color: var(--orange-text); }
#site-search-input::-webkit-search-cancel-button { display: none; }

.site-search-results {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  left: 0;
  background: var(--white);
  border-radius: 12px;
  box-shadow: 0 16px 40px rgba(0,0,0,0.16);
  overflow: hidden;
  z-index: 101;
  max-height: 360px;
  overflow-y: auto;
  transform-origin: top center;
  transition: opacity 150ms var(--ease-out), transform 150ms var(--ease-out);
}
.site-search-results.open { display: block; }
@starting-style {
  .site-search-results.open { opacity: 0; transform: translateY(-4px); }
}
.site-search-result {
  display: block;
  padding: 10px 16px;
  text-decoration: none;
  border-bottom: 1px solid rgba(0,0,0,0.05);
}
.site-search-result:last-child { border-bottom: none; }
.site-search-result:hover, .site-search-result.active { background: var(--bg-light); }
.site-search-result-title { display: block; color: var(--text-dark); font-weight: 600; font-size: 14px; }
.site-search-result-blurb {
  display: block;
  color: var(--text-light);
  font-size: 12px;
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.site-search-empty { padding: 14px 16px; color: var(--text-light); font-size: 13px; text-align: center; }

/* Hero */
.hero {
  background: linear-gradient(135deg, var(--navy) 0%, var(--navy-2) 100%);
  color: white;
  overflow: hidden;
  position: relative;
}
.hero-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
  padding: 90px 24px 100px;
  position: relative;
}
.hero-text { max-width: 560px; position: relative; z-index: 2; }
.eyebrow {
  color: var(--orange);
  font-weight: 700;
  letter-spacing: .5px;
  font-size: 14px;
  margin: 0 0 12px;
}
.hero h1 {
  font-size: 44px;
  line-height: 1.2;
  margin: 0 0 18px;
  font-weight: 800;
}
.hero-sub {
  font-size: 17px;
  color: rgba(255,255,255,0.8);
  margin-bottom: 32px;
}
.hero-cta { display: flex; gap: 14px; flex-wrap: wrap; }
.btn {
  display: inline-block;
  padding: 14px 28px;
  border-radius: 999px;
  font-weight: 700;
  text-decoration: none;
  font-size: 15px;
  transition: transform 160ms var(--ease-out), box-shadow 200ms var(--ease-out),
              background-color 200ms ease, border-color 200ms ease;
}
.btn-primary { background: var(--orange-text); color: white; box-shadow: 0 8px 20px rgba(255,106,61,0.35); }
.btn-outline { background: transparent; color: white; border: 1.5px solid rgba(255,255,255,0.4); }
.btn-outline-dark { background: transparent; color: var(--navy); border: 1.5px solid var(--navy); }
.btn-whatsapp { background: #25D366; color: white; }
/* Hover is a mouse idea: on a touch screen it fires on tap and then sticks,
   leaving the button hovering in mid-air after the finger has gone. Each
   variant also changes its own surface on hover, so the lift is not the only
   signal. */
@media (hover: hover) and (pointer: fine) {
  .btn:hover { transform: translateY(-2px); }
  .btn-primary:hover { background: #ab4628; box-shadow: 0 12px 26px rgba(255,106,61,0.4); }
  .btn-primary:disabled:hover { background: var(--orange-text); }
  .btn-outline:hover { border-color: rgba(255,255,255,0.8); background: rgba(255,255,255,0.06); }
  .btn-outline-dark:hover { background: rgba(16,24,43,0.05); }
  .btn-whatsapp:hover { background: #1fbd5a; }
}
/* Pressed state, on every input type -- :active releases the moment the
   finger lifts, so unlike :hover it cannot get stuck. Declared after the hover
   block so a held press wins over the hover lift. */
.btn:active { transform: scale(.97); }
.btn:disabled:active { transform: none; }

.hero-visual { flex: 1; position: relative; min-height: 280px; z-index: 2; }
.hero-video {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 20px 50px rgba(0,0,0,0.35);
}
.hero-video iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Clients */
.clients { padding: 36px 0; background: var(--bg-light); overflow: hidden; }
.clients-title { text-align: center; color: var(--text-light); font-size: 14px; margin: 0 0 16px; }

.clients-track-wrap {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 5%, #000 95%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 5%, #000 95%, transparent 100%);
  /* The whole marquee subtree is forced LTR (wrap AND track) — this page is
     RTL, and a direction mismatch between the wrap and the over-wide track
     inside it flips which edge the browser anchors the overflow to, which
     broke the seamless loop (the duplicated half ended up positioned
     somewhere translateX(-50%) never reveals, so the strip ran out of
     content and went blank each cycle). Hebrew logo names underneath still
     render correctly since Hebrew script carries its own directionality. */
  direction: ltr;
}
.clients-track {
  display: flex;
  align-items: flex-start;
  gap: 48px;
  width: max-content;
  animation: clientsScroll 32s linear infinite;
}
.clients-track-wrap:hover .clients-track { animation-play-state: paused; }
.client-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.client-item img {
  height: 52px;
  width: auto;
  max-width: 120px;
  object-fit: contain;
  transition: transform 250ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .client-item:hover img { transform: scale(1.06); }
}
.client-item span {
  font-size: 12px;
  color: var(--text-light);
  white-space: nowrap;
  direction: rtl;
}
@keyframes clientsScroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .clients-track { animation: none; }
}

/* Services */
.services { padding: 90px 0 60px; text-align: center; }
/* Slight negative tracking on every heavy display heading: at 800 weight and
   32px+ Rubik's default spacing lets the letters drift apart, and the heading
   reads looser than the body text under it. */
.section-title { font-size: 32px; margin: 0 0 8px; font-weight: 800; letter-spacing: -0.015em; }
.hero h1, .about h2, .contact-text h2, .articles-hero h1 { letter-spacing: -0.015em; }
.section-sub { color: var(--text-light); margin: 0 0 44px; }
/* Fixed-width tracks, centred, instead of four equal 1fr columns. With 1fr, a
   category holding three subcategories (crystal stickers, paper products...)
   filled three columns from the right and left a hole where the fourth card
   should be, so the row looked unfinished. auto-fit + a width cap keeps the
   same card size at four-across and centres any short last row. 262px x 4 +
   3 gaps fits the 1132px container exactly. */
.service-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 262px));
  justify-content: center;
  gap: 22px;
  text-align: right;
}
.service-card {
  background: var(--bg-light);
  border-radius: var(--radius);
  padding: 30px 24px;
  text-decoration: none;
  color: var(--text-dark);
  transition: transform 300ms var(--ease-out), box-shadow 300ms var(--ease-out), border-color 200ms ease;
  border: 1px solid transparent;
}
@media (hover: hover) and (pointer: fine) {
  .service-card:hover {
    transform: translateY(-6px);
    box-shadow: var(--shadow);
    border-color: rgba(255,106,61,0.25);
  }
}
/* Real product photo, when the subcategory has one (almost all of them do
   at this point) -- sits above the title, matching the homepage's
   .category-card-media treatment, since a photo reads far more inviting
   than an icon-only card. Falls back to icon-only (no .service-card-media
   in the markup at all) for the rare subcategory without one. */
.service-card-media { border-radius: 12px; overflow: hidden; aspect-ratio: 4 / 3; margin-bottom: 16px; background: var(--white); }
.service-card-media img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 500ms var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .service-card:hover .service-card-media img { transform: scale(1.05); }
}
/* Icon shrinks to a small inline marker beside the title once the photo is
   doing the visual work -- it used to be the card's only graphic, at 26px
   with its own margin below it. */
.service-icon {
  font-size: 16px;
  color: var(--orange-text);
  margin-left: 8px;
}
/* Cycle through the logo's leaf colors instead of one flat accent — subtle
   nod to the brand mark across subcategory grids of any length. */
.service-card:nth-child(4n+1) .service-icon { color: var(--brand-gold-text); }
.service-card:nth-child(4n+2) .service-icon { color: var(--brand-green-text); }
.service-card:nth-child(4n+3) .service-icon { color: var(--brand-red-text); }
.service-card:nth-child(4n+4) .service-icon { color: var(--brand-olive-text); }
.service-card h3 { margin: 0 0 8px; font-size: 18px; }
.service-card p { margin: 0; color: var(--text-light); font-size: 14px; }

/* Category showcase — replaces the old duplicated services-grid + feature-block
   pair. Numbered cards (01/02/03/04): image, title, small underline —
   each card links straight to its product page. Generated by
   scripts/build.js. */
.category-showcase { padding: 90px 0; text-align: center; }
.category-showcase-grid {
  display: grid;
  /* Five top categories since lexan and photometal split (20 Oct 2026). */
  grid-template-columns: repeat(5, 1fr);
  gap: 20px;
  margin-top: 24px;
}
.category-card {
  display: block;
  text-decoration: none;
  color: inherit;
  background: var(--bg-light);
  border-radius: var(--radius);
  padding: 20px 20px 26px;
  text-align: center;
  transition: transform 300ms var(--ease-out), box-shadow 300ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .category-card:hover { transform: translateY(-6px); box-shadow: var(--shadow); }
  .category-card:hover .category-card-media img { transform: scale(1.05); }
}
.category-card-number {
  display: block;
  text-align: right;
  font-size: 34px;
  font-weight: 800;
  color: var(--navy);
  opacity: .16;
  line-height: 1;
  margin-bottom: 8px;
}
.category-card-media { border-radius: 12px; overflow: hidden; aspect-ratio: 4 / 3; }
.category-card-media img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 500ms var(--ease-out); }
.category-card-body { padding-top: 18px; }
.category-card h3 { margin: 0 0 10px; font-size: 17px; font-weight: 700; }
.category-card-divider { display: inline-block; width: 32px; height: 3px; border-radius: 2px; background: var(--orange-text); }
/* Each homepage category card picks up one leaf color from the logo mark. */
.category-card:nth-child(1) .category-card-divider { background: var(--brand-gold); }
.category-card:nth-child(2) .category-card-divider { background: var(--brand-green); }
.category-card:nth-child(3) .category-card-divider { background: var(--brand-red); }
.category-card:nth-child(4) .category-card-divider { background: var(--brand-olive); }

/* About */
.about { padding: 90px 0; background: var(--navy); color: white; text-align: center; }
.about-inner { max-width: 760px; margin: 0 auto; }
.about h2 { font-size: 32px; margin: 0 0 20px; font-weight: 800; }
.about-lead { font-size: 18px; color: rgba(255,255,255,0.85); }
.about p { color: rgba(255,255,255,0.7); }
.about-stats { display: flex; justify-content: center; gap: 60px; margin-top: 40px; }
.about-stats strong { display: block; font-size: 32px; color: var(--orange); }
.about-stats span { font-size: 14px; color: rgba(255,255,255,0.6); }
.about-more-link {
  display: inline-block;
  margin-top: 32px;
  color: var(--orange);
  font-weight: 700;
  font-size: 15px;
  text-decoration: none;
  transition: transform 200ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .about-more-link:hover { transform: translateX(-4px); }
}

/* Advantages */
/* Drawn the same way as the product pages' advantages band
   (.hero-advantage-icon): a navy disc carrying a white line icon from the
   build.js icon set, the columns split by hairlines rather than boxed in
   cards. It used to be four identical grey cards with a text symbol
   (✓ ⚑ ★ ⬡) as the icon -- font glyphs render differently on every OS and
   none of them said anything about the claim beside it. Now the homepage and
   the product pages speak one visual language for "why us". */
.advantages { padding: 90px 0 56px; text-align: center; }
/* .page-eyebrow is tuned for the navy hero (--orange-lit on a translucent
   white chip). Reused here on white it measured 2.3:1 -- unreadable. The
   on-light pair is --orange-text on white, 4.8:1. */
.advantages .page-eyebrow { color: var(--orange-text); background: var(--white); border-color: rgba(191,80,46,0.28); }
.advantages-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  margin-top: 20px;
}
.advantage-card { padding: 8px 26px; text-align: center; }
.advantage-card + .advantage-card { border-inline-start: 1px solid rgba(16,24,43,0.08); }
.advantage-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 56px; height: 56px;
  border-radius: 50%;
  background: var(--navy);
  color: #fff;
  margin-bottom: 16px;
}
.advantage-icon svg { width: 28px; height: 28px; display: block; }
.advantage-card h3 { margin: 0 0 8px; font-size: 17px; color: var(--navy); }
.advantage-card p { margin: 0 auto; max-width: 30ch; color: var(--text-light); font-size: 14px; }

/* Testimonials */
/* Light peach from the logo's own palette (--orange-light, already used
   elsewhere for the same warm accent) instead of the neutral gray every
   other section uses -- gives this section its own visual identity. */
.testimonials { padding: 90px 0; background: var(--orange-light); text-align: center; }
/* The neutral grey subtitle only reached 3.9:1 on peach. A brown taken from
   the peach's own hue reads as part of the section and measures ~6:1. */
.testimonials .section-sub { color: #6e4a3c; }
/* Google reviews carousel (initReviews in script.js): three cards in view,
   the row moves on by one every 10 seconds. Arrows sit outside the row. */
.reviews-carousel {
  --gap: 24px;
  position: relative; display: flex; align-items: center; gap: 12px;
  margin-top: 24px;
}
.reviews-viewport { flex: 1; min-width: 0; overflow: hidden; padding: 8px 0 18px; }
.reviews-track {
  list-style: none; margin: 0; padding: 0;
  display: flex; gap: var(--gap);
  transition: transform 700ms var(--ease-out, ease-out);
}
.review-card {
  flex: 0 0 calc((100% - 2 * var(--gap)) / 3);
  display: flex; flex-direction: column; gap: 14px;
  background: var(--white); border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 26px 26px 22px; text-align: right;
}
.review-stars { color: #f5a623; font-size: 18px; letter-spacing: 2px; line-height: 1; }
/* Capped so one long review doesn't stretch every card in the row (they all
   share the row's height); the full text is in the card's title. */
.review-text {
  flex: 1; margin: 0; color: var(--text-dark); font-size: 15px; line-height: 1.7; text-wrap: pretty;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 5; line-clamp: 5; overflow: hidden;
}
.review-author { display: flex; align-items: center; gap: 12px; padding-top: 14px; border-top: 1px solid #f0e4dc; }
.review-avatar {
  flex: none; width: 42px; height: 42px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--navy); color: #fff; font-weight: 800; font-size: 17px;
}
.review-author strong { display: block; font-size: 15px; color: var(--navy); }
.review-author small { display: block; font-size: 12.5px; color: #6e4a3c; }
.reviews-arrow {
  flex: none; width: 44px; height: 44px; border-radius: 50%; border: 0; cursor: pointer;
  background: var(--white); color: var(--navy); font-size: 26px; line-height: 1;
  box-shadow: var(--shadow); display: grid; place-items: center;
  transition: transform 160ms var(--ease-out, ease-out);
}
@media (hover: hover) and (pointer: fine) { .reviews-arrow:hover { transform: scale(1.08); } }
.reviews-arrow:focus-visible { outline: 2px solid var(--orange-text); outline-offset: 3px; }
.reviews-all { display: inline-block; margin-top: 8px; font-weight: 700; color: #6e4a3c; text-decoration: none; }
.reviews-all:hover { color: var(--orange-text); text-decoration: underline; }
@media (max-width: 760px) {
  .reviews-carousel { --gap: 12px; gap: 6px; margin-top: 16px; }
  .review-card { flex-basis: 100%; padding: 20px 18px 18px; }
  .review-text { -webkit-line-clamp: 7; line-clamp: 7; }
  .reviews-arrow { width: 36px; height: 36px; font-size: 22px; }
}
@media (prefers-reduced-motion: reduce) { .reviews-track { transition: none; } }

/* Contact */
.contact { padding: 90px 0; }
/* Two white sections back to back stacked their full paddings into one
   180px blank band that read as a missing section. */
.advantages + .contact { padding-top: 56px; }
.contact-inner { display: flex; gap: 60px; }
.contact-text { flex: 1; }
/* .eyebrow and the Waze/Maps links default to --orange, which is the on-navy
   tone (2.8:1 on white). This section is white, so it takes the on-light one. */
.contact .eyebrow, .contact-list .footer-nav-links a { color: var(--orange-text); }
.contact-text h2 { font-size: 32px; margin: 0 0 16px; font-weight: 800; }
.contact-list { list-style: none; padding: 0; margin: 24px 0 32px; }
.contact-list li { margin-bottom: 12px; font-size: 15px; }
.contact-list span { color: var(--text-light); margin-left: 6px; }
.contact-list a { color: var(--text-dark); text-decoration: none; font-weight: 600; }
.contact-list a:hover { color: var(--orange-text); }

.contact-form {
  flex: 1;
  background: var(--bg-light);
  border-radius: var(--radius);
  padding: 32px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.contact-form-title { margin: 0; font-size: 20px; font-weight: 800; color: var(--text-dark); }
.contact-form label { font-size: 14px; font-weight: 600; color: var(--text-dark); display: flex; flex-direction: column; gap: 6px; }
.contact-form input, .contact-form textarea, .contact-form select {
  font-family: inherit;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid #dcdfe4;
  font-size: 15px;
  background: var(--white);
  color: var(--text-dark);
}
.contact-form select { cursor: pointer; }
.contact-form button { align-self: flex-start; border: none; cursor: pointer; }
.contact-form button:disabled { opacity: .6; cursor: not-allowed; transform: none; }
.form-status { font-size: 13px; margin: 0; min-height: 1.4em; }
.form-status-success { color: #1a7d3c; font-weight: 600; }
.form-status-error { color: #c0392b; font-weight: 600; }

/* Footer */
.site-footer { background: var(--navy); color: rgba(255,255,255,0.6); padding: 36px 0; }
.footer-inner { display: flex; align-items: center; justify-content: center; gap: 16px; flex-direction: column; text-align: center; }
.footer-logo { height: 32px; filter: brightness(0) invert(1); opacity: .8; }
.footer-inner p { font-size: 13px; margin: 0; }
.footer-inner a:not(.footer-admin-link) { color: rgba(255,255,255,0.7); }
.footer-inner a:not(.footer-admin-link):hover { color: white; }

/* Full footer (every page except the homepage, which already has its own
   #contact section) — contact details + Google Maps, generated by
   scripts/build.js's FOOTER_HTML constant. */
.site-footer-full { padding: 60px 0 0; text-align: right; }
.footer-columns {
  display: flex;
  gap: 50px;
  padding-bottom: 40px;
  border-bottom: 1px solid rgba(255,255,255,0.1);
}
.footer-contact { flex: 1; min-width: 0; }
.footer-contact .footer-logo { margin-bottom: 16px; }
.footer-company { font-size: 16px; font-weight: 700; color: white; margin: 0 0 16px; }
.footer-contact-list { list-style: none; padding: 0; margin: 0; }
.footer-contact-list li { font-size: 14px; margin-bottom: 10px; }
.footer-contact-list span { color: rgba(255,255,255,0.5); margin-left: 6px; }
.footer-contact-list a { color: rgba(255,255,255,0.85); text-decoration: none; }
.footer-contact-list a:hover { color: var(--orange); }

/* Waze / Google Maps quick-navigation links, shown next to the address —
   used both in the dark footer and in the light homepage #contact section
   (.contact-list reuses the same .footer-nav-links markup/class). */
.footer-nav-links { display: flex; gap: 14px; margin-top: 4px; }
.footer-nav-links a { font-size: 13px; font-weight: 600; color: var(--orange); text-decoration: none; }
.footer-nav-links a:hover { text-decoration: underline; }

.footer-hours { flex: 1; min-width: 0; }
.footer-hours-list { list-style: none; padding: 0; margin: 0; }
.footer-hours-list li { display: flex; justify-content: space-between; gap: 12px; font-size: 14px; margin-bottom: 8px; color: rgba(255,255,255,0.85); }
.footer-hours-list li span:first-child { color: rgba(255,255,255,0.5); }

.footer-map { flex: 1; min-width: 0; border-radius: var(--radius); overflow: hidden; min-height: 220px; }
.footer-map iframe { width: 100%; height: 100%; min-height: 220px; border: 0; display: block; }
.footer-bottom { padding: 20px 0; text-align: center; }
.footer-bottom p { font-size: 13px; margin: 0; }
.footer-bottom a:not(.footer-admin-link) { color: rgba(255,255,255,0.7); }
.footer-bottom a:not(.footer-admin-link):hover { color: white; }

/* Intentionally near-invisible: leads to /admin, but shouldn't draw a
   visitor's eye the way a normal link would. */
.footer-admin-link { color: rgba(255,255,255,0.15); text-decoration: none; margin-right: 6px; transition: color .2s; }
.footer-admin-link:hover { color: rgba(255,255,255,0.5); }

/* Opening hours inside the homepage's own #contact section (light bg) —
   reuses .footer-hours-list but needs dark-on-light colors instead. */
.contact-hours { margin: 0 0 24px; }
.contact-hours-title { font-size: 15px; font-weight: 700; color: var(--text-dark); margin: 0 0 10px; }
.contact-hours .footer-hours-list li { color: var(--text-dark); }
.contact-hours .footer-hours-list li span:first-child { color: var(--text-light); }

@media (max-width: 960px) {
  .footer-columns { flex-direction: column; gap: 28px; }
  .site-footer-full { text-align: center; }
  .footer-contact-list { display: inline-block; text-align: right; }
  .footer-hours-list { display: inline-block; text-align: right; }
  .footer-nav-links { justify-content: center; }
}

.whatsapp-float {
  position: fixed;
  bottom: 24px;
  right: 24px;
  background: #25D366;
  color: white;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8px 20px rgba(37,211,102,0.4);
  z-index: 200;
  transition: transform 200ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .whatsapp-float:hover { transform: scale(1.06); }
}
.whatsapp-float:active { transform: scale(.94); }

/* Chatbot widget — stacked directly above the WhatsApp float, same size, so
   the two never overlap regardless of screen width. */
.chatbot-toggle {
  position: fixed;
  bottom: 92px;
  right: 24px;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: none;
  background: var(--navy);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8px 20px rgba(16,24,43,0.35);
  cursor: pointer;
  z-index: 200;
  transition: transform 200ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .chatbot-toggle:hover { transform: scale(1.06); }
}
.chatbot-toggle:active { transform: scale(.94); }
.chatbot-toggle svg { width: 26px; height: 26px; }
.chatbot-toggle .chatbot-close-icon { display: none; }
.chatbot-toggle.open .chatbot-chat-icon { display: none; }
.chatbot-toggle.open .chatbot-close-icon { display: block; }

/* Scene-hero pages: while the CTA band under the hero is on screen, its
   call / WhatsApp buttons are right there, so the floating ones would only
   repeat them (the owner, 20 Oct 2026: "the icons appear twice"). script.js
   sets body.floats-hidden until the band scrolls away. An open chat keeps
   its toggle, so it can still be closed. */
.whatsapp-float, .chatbot-toggle {
  transition: transform 200ms var(--ease-out), opacity 250ms ease, visibility 250ms;
}
body.floats-hidden .whatsapp-float,
body.floats-hidden .chatbot-toggle:not(.open),
body.floats-hidden .chatbot-tooltip {
  opacity: 0; visibility: hidden; pointer-events: none; transform: translateY(14px) scale(.9);
}
/* On a phone the accessibility button would sit on the band's quote button;
   it steps aside with the others and is back after the first scroll. */
@media (max-width: 560px) {
  .a11y-toggle { transition: transform 200ms var(--ease-out), opacity 250ms ease, visibility 250ms; }
  body.floats-hidden .a11y-toggle { opacity: 0; visibility: hidden; pointer-events: none; }
}

/* Small attention bubble that appears near the floating icon, inviting
   visitors to try the AI chat. Shown once per browser session. */
.chatbot-tooltip {
  position: fixed;
  bottom: 92px;
  right: 88px;
  width: max-content;
  max-width: 250px;
  background: var(--white);
  color: var(--text-dark);
  border-radius: 14px;
  border-bottom-right-radius: 4px;
  padding: 12px 16px 12px 34px;
  font-size: 13px;
  line-height: 1.5;
  font-family: 'Rubik', sans-serif;
  box-shadow: 0 8px 24px rgba(0,0,0,0.18);
  z-index: 199;
  display: none;
  cursor: pointer;
  animation: chatbot-tooltip-in .25s ease-out;
}
.chatbot-tooltip.open { display: block; }
@keyframes chatbot-tooltip-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}
.chatbot-tooltip-text { display: block; }
.chatbot-tooltip-close {
  position: absolute;
  top: 2px;
  left: 6px;
  border: none;
  background: none;
  color: var(--text-light);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 4px;
}
.chatbot-tooltip-close:hover { color: var(--text-dark); }

.chatbot-window {
  position: fixed;
  bottom: 158px;
  right: 24px;
  width: 340px;
  max-width: calc(100vw - 32px);
  max-height: min(520px, calc(100vh - 190px));
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: 0 20px 50px rgba(0,0,0,0.25);
  display: none;
  flex-direction: column;
  overflow: hidden;
  z-index: 199;
  font-family: 'Rubik', sans-serif;
}
.chatbot-window.open {
  display: flex;
  /* Grows out of the round toggle it belongs to (bottom-right, directly
     under it), not out of its own centre -- a panel scaling from the middle
     looks like it came from nowhere. Starts at 0.96, never 0: nothing real
     appears from a point. */
  transform-origin: bottom right;
  transition: opacity 200ms var(--ease-out), transform 260ms var(--ease-out);
}
@starting-style {
  .chatbot-window.open { opacity: 0; transform: translateY(8px) scale(.96); }
}

.chatbot-header {
  background: linear-gradient(135deg, var(--navy) 0%, var(--navy-2) 100%);
  color: white;
  padding: 16px 18px;
  font-weight: 700;
  font-size: 15px;
  flex-shrink: 0;
}
.chatbot-header span:not(.chatbot-header-name) { display: block; font-weight: 400; font-size: 12px; color: rgba(255,255,255,0.7); margin-top: 2px; }

.chatbot-messages {
  padding: 16px;
  overflow-y: auto;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--bg-light);
}
.chatbot-bubble {
  max-width: 85%;
  padding: 10px 14px;
  border-radius: 14px;
  font-size: 14px;
  line-height: 1.6;
  white-space: pre-line;
}
.chatbot-bubble-bot {
  align-self: flex-start;
  background: var(--white);
  color: var(--text-dark);
  border-bottom-left-radius: 4px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.06);
}
.chatbot-bubble-user {
  align-self: flex-end;
  background: var(--orange-text);
  color: white;
  border-bottom-right-radius: 4px;
}
/* Typing indicator — three bouncing dots inside a bot bubble while waiting
   for the AI response. */
.chatbot-typing { display: flex; align-items: center; gap: 4px; padding: 14px; }
.chatbot-typing span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-light);
  opacity: .4;
  animation: chatbot-typing-bounce 1s infinite ease-in-out;
}
.chatbot-typing span:nth-child(2) { animation-delay: .15s; }
.chatbot-typing span:nth-child(3) { animation-delay: .3s; }
@keyframes chatbot-typing-bounce {
  0%, 60%, 100% { opacity: .4; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-3px); }
}

/* Suggestion chips shown once under the greeting message — clicking one
   sends it through the AI just like typing it would. */
.chatbot-suggestions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.chatbot-menu-btn {
  background: var(--bg-light);
  color: var(--navy);
  border: 1px solid rgba(16,24,43,0.12);
  border-radius: 999px;
  padding: 7px 14px;
  font-size: 13px;
  cursor: pointer;
  font-family: inherit;
  transition: background .2s, border-color .2s;
}
.chatbot-menu-btn:hover { background: var(--orange-light); border-color: var(--orange-text); }

/* Search-bar style input, the primary way to talk to the AI. */
.chatbot-input-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 14px;
  border-top: 1px solid rgba(0,0,0,0.06);
  flex-shrink: 0;
  background: var(--white);
}
.chatbot-input {
  flex: 1;
  border: 1px solid rgba(16,24,43,0.14);
  border-radius: 999px;
  padding: 10px 16px;
  font-size: 14px;
  font-family: inherit;
  background: var(--bg-light);
  color: var(--text-dark);
}
.chatbot-input:focus { outline: 2px solid var(--orange-text); outline-offset: 1px; border-color: var(--orange-text); }
.chatbot-send-btn {
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: none;
  background: var(--orange-text);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.chatbot-send-btn:hover { opacity: .9; }
.chatbot-send-btn svg { width: 16px; height: 16px; }

.chatbot-quicklinks {
  display: flex;
  justify-content: center;
  gap: 18px;
  padding: 0 14px 12px;
  flex-shrink: 0;
  background: var(--white);
}
.chatbot-quicklinks a {
  font-size: 12px;
  color: var(--text-light);
  text-decoration: none;
}
.chatbot-quicklinks a:hover { color: var(--orange-text); }

@media (max-width: 560px) {
  .chatbot-window { right: 16px; bottom: 150px; width: calc(100vw - 32px); }
  .chatbot-toggle { right: 16px; }
  /* Tooltip must clear the 56px-wide toggle button (right:16 + 56 + 8px gap),
     otherwise it lands directly behind the round button instead of beside
     it -- same offset logic as the desktop right:88 vs button right:24. */
  .chatbot-tooltip { right: 80px; max-width: calc(100vw - 100px); }
  .whatsapp-float { right: 16px; }
}

/* Category/subcategory page template */
.breadcrumb {
  padding: 18px 0 0;
  text-align: right;
  font-size: 13px;
  color: var(--text-light);
}
.breadcrumb a { color: var(--text-light); text-decoration: none; }
.breadcrumb a:hover { color: var(--orange-text); }
.breadcrumb span { margin: 0 6px; }

/* ---------------------------------------------------------------------------
   Product-page hero.

   This is a DARK ground, and that is the decision the whole banner rests on.
   Every product photo this site owns was shot on light studio grey. Put a
   light-grey photo on a light-grey ground and there is nothing to separate
   them: an earlier pass tried framing the photo and the frame read as "a
   silver square sitting on the page", so the frame was replaced with a radial
   mask that faded the photo's edges away -- which dissolved the product's own
   edges too, and on an edge-to-edge shot (a logo on a car door) smeared the
   subject into the background.

   Both attempts were fixing the wrong thing. The photo was never the problem;
   the ground was. On a dark ground the same light photo, given a rounded
   corner, a hairline ring and a deep shadow, reads as a specimen mounted on a
   board -- the grey stops being a mistake and becomes the mounting frame.

   It also makes this hero match the homepage hero (.hero), which has always
   been this same navy gradient. The two were the odd pair, not this. */
.page-hero {
  background: linear-gradient(135deg, var(--navy) 0%, var(--navy-2) 100%);
  color: white;
  overflow: hidden;
  position: relative;
}
/* A single soft light source behind the photo column, so the plate looks lit
   rather than pasted. 30% from the left is the visual column: .page-hero-inner
   is a flex row and the document is RTL, so the text child sits right and the
   visual child sits left. */
.page-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(58% 68% at 30% 46%, rgba(255,255,255,.07), transparent 72%);
  pointer-events: none;
}
.page-hero-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 56px;
  /* Generous on purpose. An earlier pass budgeted the hero and the advantages
     band into a single viewport and the result read as cramped, not premium.
     A small scroll to reach the advantages band is normal UX; a squeezed hero
     is not. */
  padding: 56px 24px 64px;
  position: relative;
  z-index: 2;
}
.page-hero-text { flex: 1; max-width: 600px; }
/* Eyebrow as an actual pill badge (chip + a small star mark), matching the
   reference's category-label treatment instead of plain colored text. On the
   dark ground the chip is a translucent white wash rather than the light
   peach fill -- a bright peach pill on navy shouted louder than the H1. */
.page-eyebrow {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--orange-lit);
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,138,99,0.28);
  font-weight: 700; font-size: 13px; letter-spacing: .3px;
  padding: 6px 14px; border-radius: 999px; margin: 0 0 18px; text-wrap: balance;
}
.page-eyebrow::before { content: "✦"; font-size: 12px; }
/* Fluid instead of a breakpoint step. The old rule jumped 46px -> 22px at
   960px and again to 19px lower down, so a 700px-wide window got the full
   46px headline with half the column to put it in. clamp() grows it with the
   window and needs no media query of its own. */
.page-hero-text h1 {
  font-size: clamp(23px, 3.6vw + 8px, 46px);
  line-height: 1.15; margin: 0 0 18px; font-weight: 800;
  color: white; letter-spacing: -0.01em; text-wrap: balance;
}
/* Short decorative rule under the H1 -- a quiet structural beat between the
   heading and the body copy, no content of its own. --orange (not
   --orange-text) because this sits on navy now, where the brighter tone is
   the legible one. */
.hero-accent-line { display: block; width: 52px; height: 3px; margin: 0 0 22px; background: var(--orange); border-radius: 2px; }
/* 9.9:1 against the lighter end of the hero gradient. The old
   "color:--text-dark; opacity:.8" pair is a light-ground rule and would be
   invisible here. */
.page-hero-text p { font-size: 17px; line-height: 1.65; color: rgba(255,255,255,0.78); text-wrap: pretty; }

/* --- the photo -----------------------------------------------------------
   Column width follows the photo's real shape (data-orient is written by
   build.js from the file's own pixel dimensions). A 3:2 plate wants a wide
   column; a tall shot of a car door in that same wide column grows a hero
   twice the height of the text beside it. The photo's shape decides the grid,
   not the other way round. */
.page-hero-visual { flex: 1.15; display: flex; justify-content: center; align-items: center; }
.page-hero-visual[data-orient="square"] { flex: 1; }
.page-hero-visual[data-orient="tall"] { flex: 0.8; }
/* Positioning context for .hero-inset, and the width cap for the plate. */
/* --stage-cap is the banner file's own pixel width, written inline by
   build.js. min() keeps a small legacy photo at its natural size rather than
   upscaling it into mush; a full-size photo never hits the cap and just uses
   the design width. The fallback is deliberately huge so a page whose image
   couldn't be measured behaves exactly as if the cap didn't exist. */
.hero-photo-stage {
  position: relative;
  width: 100%;
  max-width: min(560px, var(--stage-cap, 9999px));
  animation: heroFadeUp .8s ease-out both;
}
.page-hero-visual[data-orient="square"] .hero-photo-stage { max-width: min(470px, var(--stage-cap, 9999px)); }
.page-hero-visual[data-orient="tall"] .hero-photo-stage { max-width: min(380px, var(--stage-cap, 9999px)); }
/* Plain heroImage fallback (pages not yet switched to bannerImage). */
.page-hero-visual > img {
  max-width: 100%;
  border-radius: 18px;
  animation: heroFadeUp .8s ease-out both;
}
/* A real rectangular photo: framed as a mounted plate. The ring is what keeps
   a light photo from bleeding into the dark ground at its own pale edges, and
   the shadow is what puts it in front of the ground rather than on it.
   aspect-ratio comes from the file itself (inline, per page) so nothing is
   cropped to a house height any more -- object-fit:cover only ever trims a
   hair, never reframes the shot. */
.page-hero-visual .hero-photo-card {
  width: 100%;
  border-radius: 18px;
  overflow: hidden;
  box-shadow: 0 34px 60px -18px rgba(0,0,0,.62), 0 10px 24px rgba(0,0,0,.34);
  outline: 1px solid rgba(255,255,255,.10);
  outline-offset: -1px;
}
.page-hero-visual .hero-photo-card img {
  display: block; width: 100%; height: 100%; object-fit: cover;
}
/* A background-removed product cutout (bannerImage filename ending
   "-cutout.png"): floats directly on the hero ground with a shadow drawn by
   filter:drop-shadow, which follows the product's real silhouette instead of
   a rectangle. All 16 cutouts in images/ were checked and carry genuine
   alpha, so there is no white box hiding behind any of them. No frame here --
   a frame around a cutout would put back the rectangle it exists to avoid. */
.page-hero-visual .hero-photo-cutout {
  width: 100%;
}
.page-hero-visual .hero-photo-cutout img {
  display: block; width: 100%; height: 100%; object-fit: contain;
  filter: drop-shadow(0 26px 30px rgba(0, 0, 0, .55)) drop-shadow(0 8px 12px rgba(0, 0, 0, .35));
}
/* Nothing in this hero loops. The photo used to carry
   "heroFloat 4s infinite", bobbing forever -- the same fake dynamism as the
   CSS rotate that was tried and reverted on these photos earlier. Animation
   here may only make something that is already on the page arrive. */

/* --- the detail inset ----------------------------------------------------
   The small close-up that floats over a corner of the plate, with its own tag
   and one caption line (the reference's round 3M adhesive detail). Written
   before the caption in the DOM, so RTL puts the photo at the start edge and
   the words beside it with no left/right rule anywhere.

   It sits under the photo as an ordinary row at every width -- see the
   desktop block further down for why it is never positioned over the photo. */
.hero-inset {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 14px 0 0;
}
.hero-inset-photo {
  flex: none;
  width: 96px; height: 96px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--white);
  box-shadow: 0 14px 28px -8px rgba(0,0,0,.6);
  outline: 3px solid rgba(255,255,255,.14);
  outline-offset: -1px;
}
.hero-inset-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.hero-inset-text { margin: 0; min-width: 0; }
.hero-inset-tag {
  display: inline-block;
  background: var(--orange-text);
  color: white;
  font-size: 12px; font-weight: 700; letter-spacing: .2px;
  padding: 4px 12px; border-radius: 4px; margin-bottom: 6px;
}
.hero-inset-text p {
  margin: 0;
  font-size: 13px; line-height: 1.45;
  color: rgba(255,255,255,0.72);
  text-wrap: pretty;
}
@media (min-width: 961px) {
  /* The inset stays in normal flow on desktop too -- it is NOT absolutely
     positioned any more.
     Two earlier attempts positioned it over the photo: first inside the box
     (it covered merchandise outright), then pinned to the bottom of a
     reserved 100px strip so it overlapped the photo's bottom edge by ~18px.
     The second still collided, because "18px into the box" only means "into
     empty margin" for a photo whose product stops short of the bottom. On a
     diagonally-composed cutout -- a roll of labels running corner to corner --
     the product reaches that edge, so the card landed on it.
     In flow, the geometry cannot collide on any page, at any caption length,
     whatever the photo's composition. The negative inline-end margin lets it
     jut past the column edge so it still reads as a hung detail card rather
     than a stacked caption. */
  .hero-inset {
    margin: 20px 0 0;
    margin-inline-end: -44px;
    max-width: 360px;
  }
  .hero-inset-photo { width: 118px; height: 118px; }
}
/* About page's factory photo: a real, plain snapshot, not a styled product
   shot — no arrival animation and no plate framing, just an ordinary photo
   with a caption underneath. */
.page-hero-visual-plain img {
  animation: none;
  max-width: 100%;
  border-radius: var(--radius);
  box-shadow: 0 24px 44px -16px rgba(0,0,0,.55);
}
.plain-photo { margin: 0; }
.plain-photo figcaption {
  margin-top: 10px;
  text-align: center;
  font-size: 13px;
  /* --text-light is a mid grey for light grounds; .page-hero is navy now. */
  color: rgba(255,255,255,0.68);
}
@keyframes heroFadeUp {
  from { opacity: 0; transform: translateY(24px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes heroFloat {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-10px); }
}

/* Scroll-reveal: script.js tags cards/sections with this class and adds
   .is-visible via IntersectionObserver the first time each one enters the
   viewport. The :not(:hover) guard on the visible state keeps this from
   fighting .service-card's own hover lift (same specificity, so without it
   whichever rule is later in the file would permanently win over hover). */
/* 16px, not 28: a reveal should suggest arrival, not make the reader wait for
   the card to travel. script.js strips these classes (and the stagger delay)
   once the reveal finishes, so the card's own fast hover transition takes
   back over -- otherwise every hover inherited this 600ms curve plus up to
   350ms of stagger delay. */
.reveal-on-scroll { opacity: 0; transform: translateY(16px); transition: opacity 600ms var(--ease-out), transform 700ms var(--ease-out); }
.reveal-on-scroll.is-visible { opacity: 1; }
.reveal-on-scroll.is-visible:not(:hover) { transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .reveal-on-scroll { opacity: 1; transform: none; transition: none; }
}

/* Fanned-card hero: several real product photos staggered like a spread hand
   of cards, instead of one photo. Cards keep their own edge (unlike the
   single-photo hero above), so the edge-fade mask and single-image float
   are reset here and replaced with a per-card entrance + idle float. */
.hero-card-fan {
  position: relative;
  width: 100%;
  max-width: 480px;
  height: 300px;
}
.hero-card-fan img {
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: contain;
  padding: 14px;
  box-sizing: border-box;
  display: block;
  -webkit-mask-image: none;
  mask-image: none;
  animation: none;
}
.hero-card {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 150px;
  height: 200px;
  border-radius: 14px;
  overflow: hidden;
  background: #fff;
  border: 4px solid #fff;
  box-shadow: 0 14px 30px rgba(16,24,43,.18);
  animation: heroCardIn .7s ease-out both, heroCardFloat 5s ease-in-out infinite;
  transition: transform .25s ease, box-shadow .25s ease;
  cursor: pointer;
}
/* The pop-out-and-enlarge effect below is gated to devices with real mouse
   hover (hover:hover, pointer:fine). On touch, tapping a card triggers
   :hover with no corresponding "move away" gesture, so the enlarged card
   (scale 1.22, lifted 26px, z-index 20) gets stuck open on top of the
   heading/description text until the visitor taps elsewhere -- on a mouse
   this resolves naturally when the cursor moves off the card. */
@media (hover: hover) and (pointer: fine) {
  .hero-card:hover {
    /* Only pause the idle float, never the entrance — pausing both would let a
       hover that lands mid-entrance freeze the card at whatever partial
       opacity/position it was mid-fade, permanently until reload. */
    animation-play-state: running, paused;
    opacity: 1 !important;
    z-index: 20 !important;
    transform: translate(-50%,-50%) translate(var(--tx), calc(var(--ty) - 26px)) rotate(0deg) scale(1.22) !important;
    box-shadow: 0 28px 55px rgba(16,24,43,.32);
  }
}
/* Touch-safe equivalent of the hover pop above -- deliberately smaller
   (scale 1.1, not 1.22) and NOT gated to a media query. :active only
   applies while the finger is actually down and releases the instant it
   lifts, unlike :hover on touch (which stuck "on" after a tap with no
   corresponding "move away" gesture, the original bug this file's
   :hover fix addresses) -- so a card can safely pop here without risking
   getting stuck open over the text above it. */
.hero-card:active {
  animation-play-state: running, paused;
  opacity: 1 !important;
  z-index: 20 !important;
  transform: translate(-50%,-50%) translate(var(--tx), calc(var(--ty) - 12px)) rotate(0deg) scale(1.1) !important;
  box-shadow: 0 20px 40px rgba(16,24,43,.28);
}
.hero-card-1 { --rot: -16deg; --tx: -170px; --ty: 22px;  z-index: 1; animation-delay: 0s,   .9s; }
.hero-card-2 { --rot: -8deg;  --tx: -90px;  --ty: 4px;   z-index: 2; animation-delay: .1s,  1s; }
.hero-card-3 { --rot: 0deg;   --tx: 0px;    --ty: -12px; z-index: 3; animation-delay: .2s,  1.1s; }
.hero-card-4 { --rot: 8deg;   --tx: 90px;   --ty: 4px;   z-index: 4; animation-delay: .3s,  1.2s; }
.hero-card-5 { --rot: 16deg;  --tx: 170px;  --ty: 22px;  z-index: 5; animation-delay: .4s,  1.3s; }
@keyframes heroCardIn {
  from { opacity: 0; transform: translate(-50%,-50%) translate(var(--tx), calc(var(--ty) + 50px)) rotate(var(--rot)) scale(.8); }
  to   { opacity: 1; transform: translate(-50%,-50%) translate(var(--tx), var(--ty)) rotate(var(--rot)) scale(1); }
}
@keyframes heroCardFloat {
  0%, 100% { transform: translate(-50%,-50%) translate(var(--tx), var(--ty)) rotate(var(--rot)); }
  50%      { transform: translate(-50%,-50%) translate(var(--tx), calc(var(--ty) - 8px)) rotate(var(--rot)); }
}

/* "Read more" scroll cue at the bottom of the hero, under the product
   photos -- a small nudge that there's more below (subcategory grid /
   photo strip / detail copy) for visitors who land on the hero and stop
   scrolling. Click handler (scrolls to .page-hero's next sibling section)
   lives in script.js. Mobile-only by design (desktop heroes already show
   enough without a scroll hint) -- hidden here, shown again in the
   max-width:960px block below. Without this, it was a THIRD flex item in
   .hero-inner/.page-hero-inner's desktop row (alongside the text and
   video/image columns) with width:100%, squeezing the video/visual column
   down to nothing on desktop. */
.hero-scroll-cue {
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 100%;
  margin-top: 12px;
  padding: 0 0 8px;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-light);
  font-size: 13px;
  font-weight: 600;
}
.hero-scroll-cue:hover { color: var(--orange-text); }
.hero-scroll-cue svg { width: 20px; height: 20px; animation: heroScrollCueBounce 1.6s ease-in-out infinite; }
@keyframes heroScrollCueBounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(5px); }
}
/* Homepage on a computer too (the owner, 20 Oct 2026): pinned to the bottom
   centre of the hero, out of the text/video row so it squeezes neither. */
@media (min-width: 961px) {
  .hero { position: relative; }
  .hero .hero-inner { position: static; }
  .hero .hero-scroll-cue {
    display: flex; position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%);
    width: auto; margin: 0; padding: 4px 8px;
    color: rgba(255,255,255,.82); font-size: 15px;
  }
  .hero .hero-scroll-cue:hover { color: #fff; }
}

.page-cta-row {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  justify-content: center;
  padding: 28px 24px;
  background: var(--white);
  border-bottom: 1px solid rgba(0,0,0,0.06);
}
.page-cta-row .btn-primary { background: var(--navy); box-shadow: 0 8px 20px rgba(16,24,43,0.2); }

/* Category/subcategory hero CTAs -- three buttons living inside the hero
   text (call / WhatsApp / open the quote modal), not a separate section
   below the hero like .page-cta-row above. */
.hero-cta-row { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 26px; }
@media (max-width: 960px) { .hero-cta-row { justify-content: center; } }
button.btn { font-family: inherit; cursor: pointer; appearance: none; -webkit-appearance: none; }

/* Full-width band directly under the hero -- up to 3 short value props
   (content.pages/*.json's "heroAdvantages"), each its own column with an
   icon, divided by a thin rule like the rest of the site's column groups. */
/* Nearly the same tone as .page-hero's own ground -- the reference's band
   reads as a continuation of the hero, not a visually separate gray strip. */
.hero-advantages-band { background: #fafafb; padding: 20px 0; border-bottom: 1px solid rgba(0,0,0,0.06); }
.hero-advantages-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.hero-advantage-item { text-align: center; padding: 0 20px; }
.hero-advantage-item + .hero-advantage-item { border-inline-start: 1px solid rgba(0,0,0,0.08); }
/* A filled navy disc with a white glyph, which is how the owner's own
   marketing sheets draw these. An earlier pass used a bare orange line icon
   on the flat band; the disc is what makes the row read as a set of badges
   rather than three loose scribbles, and it gives specific glyphs -- the 3M
   wordmark, braille dots -- a solid ground to sit on. */
.hero-advantage-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 52px; height: 52px;
  border-radius: 50%;
  background: var(--navy);
  color: #fff;
  margin-bottom: 10px;
  flex: none;
}
.hero-advantage-icon svg { width: 27px; height: 27px; display: block; }
.hero-advantage-item p { margin: 0; font-size: 15px; font-weight: 700; color: var(--navy); line-height: 1.4; text-wrap: pretty; }
@media (max-width: 720px) {
  /* The compact horizontal icon+text row tried here previously (to
     guarantee no scrolling) read as cramped -- reverted per feedback and
     the owner's own reference, which keeps the 3-column icon-over-text
     shape on mobile too, just at a slightly smaller scale than desktop,
     with real breathing room. Some scroll to reach this band on mobile is
     the accepted tradeoff for that. */
  .hero-advantages-band { padding: 28px 0; }
  .hero-advantages-grid { grid-template-columns: repeat(3, 1fr); gap: 10px; }
  .hero-advantage-item { padding: 0 6px; }
  .hero-advantage-icon { width: 42px; height: 42px; margin-bottom: 8px; }
  .hero-advantage-icon svg { width: 22px; height: 22px; }
  .hero-advantage-item p { font-size: 12.5px; line-height: 1.3; }
}

/* ---------------------------------------------------------------------------
   Scene hero (content.pages/*.json "sceneHero", renderSceneHero in build.js).

   The owner's own banner rebuilt as a page: a full-bleed photo plate with the
   headline, subtitle and four icon features laid over its bright left side,
   exactly where his design puts them, filling one screen under the header
   together with the CTA band. This is the landscape design; portrait has its
   own stacked layout, further down.

   The copy has to stay glued to the empty part of the photo whatever the
   screen shape, so both are positioned in the PLATE's coordinate space, not
   the screen's. The plate covers the hero (like object-fit: cover):
     --sw / --sh  the plate's rendered size: whichever of hero width or
                  height * ratio is larger, so it always fills;
     --st         its top offset. The overflow is cropped 35% from the top
                  on landscape (keeps the label's lower edge) and entirely
                  from the top on portrait (the plate's top is empty blur,
                  the bottom is the label and the magnifier).
   It is always pinned to the left edge, where the copy is, so a crop only
   ever trims the server rack on the right.

   The copy box is then "the empty region of the plate" -- left 48% / top
   5-62% on landscape, left 60% / top 8-59% on portrait, measured off his
   files -- and is itself a size container, so every font, icon and gap is
   sized off that box (min of its width and height). That is what lets one
   composition fit a 1440x900 desktop and a 375px phone without a scroll.

   Light ground, so dark ink: the navy and bright blue are his banner's, not
   the site's --navy, which is near-black and would go flat on the bokeh. */
.scene-hero {
  --ink: #0d2563;
  --accent: #1590e8;
  --R: calc(var(--plate-ratio));
  --ay: .35;
  position: relative;
  /* One screen minus the header AND the CTA band under it, so the buttons are
     visible without scrolling. Both heights are measured by script.js. */
  height: calc(100svh - var(--header-h, 69px) - var(--cta-h, 76px));
  /* Low enough that a small laptop or a zoomed-in browser (1366x768 at 125%
     leaves ~480px) still shows the buttons; the copy scales with the box. */
  min-height: 260px;
  overflow: hidden;
  background: #e8ecf1;
  color: var(--ink);
  container-type: size;
}
.scene-hero > * {
  --sw: max(100cqw, calc(100cqh * var(--R)));
  --sh: calc(var(--sw) / var(--R));
  --st: calc((100cqh - var(--sh)) * var(--ay));
}
.scene-stage { position: absolute; left: 0; top: var(--st); width: var(--sw); height: var(--sh); }
.scene-stage img { display: block; width: 100%; height: 100%; object-fit: cover; }

.scene-copy {
  --top: max(14px, calc(var(--st) + var(--sh) * .05));
  position: absolute;
  /* First in the HTML so crawlers and screen readers meet the H1 before the
     photo's caption; z-index keeps it painted above the plate that follows. */
  z-index: 1;
  left: 0;
  top: var(--top);
  width: min(calc(var(--sw) * var(--copy-w, .42)), 46cqw);
  height: calc(var(--st) + var(--sh) * .62 - var(--top));
  container-type: size;
  isolation: isolate;
  padding-left: max(14px, 1.5cqw);
  display: flex; flex-direction: column; align-items: center; justify-content: safe center;
  text-align: center;
  text-shadow: 0 0 14px rgba(255,255,255,.7);
  animation: heroFadeUp .7s var(--ease-out, ease-out) both;
}
/* A soft light wash behind the copy, so text that reaches the blurred edge of
   the rack still sits on a bright ground. It reads as more of the same bokeh. */
.scene-copy::before {
  content: ""; position: absolute; inset: -12% -18% -12% -30%; z-index: -1;
  background: radial-gradient(closest-side, rgba(238,242,247,.9), rgba(238,242,247,.6) 60%, transparent);
  pointer-events: none;
}
.scene-copy h1 { margin: 0; font-weight: 800; line-height: 1.02; letter-spacing: -0.015em; font-size: min(10cqw, 14.5cqh); }
.scene-copy h1 span { display: block; }
.scene-title-main { color: var(--ink); }
.scene-title-accent { color: var(--accent); }
.scene-subtitle { margin: 2.6cqh 0 0; font-size: max(13px, min(4.2cqw, 6.2cqh)); line-height: 1.3; font-weight: 500; color: #1f2a44; text-wrap: balance; }
.scene-features {
  list-style: none; margin: 5.5cqh 0 0; padding: 0; width: 100%;
  display: grid; grid-template-columns: repeat(var(--n, 4), 1fr); gap: 3cqh 1.5cqw;
}
.scene-feature { display: flex; flex-direction: column; align-items: center; }
.scene-feature .hero-advantage-icon {
  width: min(13cqw, 19cqh); height: min(13cqw, 19cqh);
  margin: 0 0 1.6cqh; background: var(--ink);
  box-shadow: 0 6px 16px rgba(13,37,99,.25);
}
.scene-feature .hero-advantage-icon svg { width: 52%; height: 52%; }
.scene-feature strong { font-size: max(13px, min(2.8cqw, 4.2cqh)); font-weight: 800; line-height: 1.2; }
.scene-feature span:not(.hero-advantage-icon) { font-size: max(12px, min(2.6cqw, 3.8cqh)); line-height: 1.3; color: #2b3445; text-wrap: balance; }

/* His mobile banner only: the caption next to the magnifier. Placed in the
   plate's own coordinates (it sits inside .scene-stage), so it stays beside
   the lens at any crop. */
.scene-callout { display: none; }

/* Portrait (phones, upright tablets): a separate, stacked design after the
   owner's mobile banners -- headline and subtitle on top, the photo in the
   middle, a row of four icon features under it, then the CTA band. Nothing
   is laid over the photo except the caption, so the photo can shrink freely:
   it takes whatever height is left (flex: 1) and crops from the top, keeping
   the label and the magnifier at its bottom.

   .scene-copy turns into display: contents so its H1, subtitle and feature
   list become direct flex items of the hero and can sit around the photo
   (order), while the HTML keeps the H1 first. */
@media (orientation: portrait) {
  .scene-hero {
    display: flex; flex-direction: column; align-items: center;
    min-height: 340px;
    padding: 2.4svh 16px 1.8svh;
    background: linear-gradient(#f1f4f8, #e4e9ef);
    text-align: center;
  }
  .scene-hero > * { --st: 0px; }
  .scene-copy { display: contents; container-type: normal; }
  .scene-copy::before { display: none; }
  .scene-copy h1 { order: 1; font-size: min(10.5cqw, 6.6cqh); line-height: 1.05; }
  .scene-subtitle { order: 2; margin: 1cqh 0 0; font-size: max(14px, min(4.6cqw, 2.9cqh)); }
  .scene-stage {
    order: 3; position: relative; top: auto; left: auto;
    flex: 1 1 0; min-height: 0;
    width: calc(100% + 32px); height: auto; margin: 1.8cqh -16px;
  }
  .scene-stage picture { display: block; height: 100%; }
  .scene-stage img { object-position: var(--m-focus, 50% 100%); }
  .scene-features {
    order: 4; margin: 0; gap: 0 2cqw;
    grid-template-columns: repeat(var(--n, 4), 1fr);
  }
  .scene-feature .hero-advantage-icon { width: min(16cqw, 8.5cqh); height: min(16cqw, 8.5cqh); margin-bottom: .8cqh; }
  .scene-feature strong { font-size: max(12px, min(3.6cqw, 2.3cqh)); text-wrap: balance; }
  .scene-feature span:not(.hero-advantage-icon) { display: none; }
  .scene-callout {
    display: block;
    /* Top corner: the site's floating chat / WhatsApp buttons sit over the
       bottom of the screen, and the magnifier holds the bottom-left. */
    position: absolute; right: 12px; top: 12px; width: 44%;
    margin: 0; padding: .6em .9em;
    background: var(--ink); color: rgba(255,255,255,.88);
    border-radius: 12px; box-shadow: 0 10px 24px rgba(0,0,0,.3);
    font-size: clamp(11px, 3cqw, 17px); line-height: 1.3; text-align: center;
    text-shadow: none;
  }
  .scene-callout strong { display: block; color: #fff; font-size: 1.15em; margin-bottom: .15em; }
}

/* The three CTA buttons live in a slim band directly under the scene: his
   composition has no buttons, and putting them inside it would sit them on
   top of the product. */
.scene-cta-band { background: var(--navy); padding: 14px 0; }
.scene-cta-band .hero-cta-row { margin: 0; justify-content: center; }
/* A screen-filling hero reads as a static page (the owner, 20 Oct 2026). On a
   computer the hero and band take 90% of the screen under the header, so the
   next section shows in the bottom tenth. A plain "more info" cue, the words
   and a bouncing arrow on one line, gets its own gap between the band and that section
   (clear of the buttons). The .scene-hero height above stays the phone rule. */
.scene-scroll-cue {
  position: absolute; left: 50%; top: 100%; z-index: 2; transform: translateX(-50%);
  margin-top: 14px;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 2px 10px; border: 0; border-radius: 6px; cursor: pointer;
  background: none; color: var(--text-dark);
  font: inherit; font-size: 16.5px; font-weight: 700; white-space: nowrap;
}
.scene-scroll-cue svg { width: 24px; height: 24px; color: var(--orange-text); animation: heroScrollCueBounce 1.6s ease-in-out infinite; }
.scene-scroll-cue:hover { color: var(--orange-text); }
.scene-scroll-cue:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
@media (orientation: landscape) and (min-width: 761px) {
  .scene-hero { height: calc((100svh - var(--header-h, 69px)) * .9 - var(--cta-h, 76px)); }
  .scene-cta-band { position: relative; z-index: 2; }
  /* The next section starts with a 64px gap that holds the cue, then its
     heading. The breadcrumb takes no height and sits at the far (left) end of
     the heading's line, so it doesn't add a third strip. */
  .scene-cta-band + .breadcrumb {
    position: relative; z-index: 1; height: 0; padding: 0;
    text-align: left; transform: translateY(82px);
  }
  .scene-cta-band ~ .examples, .scene-cta-band ~ .services { padding-top: 74px; }
}
/* Phones and upright tablets: the buttons take the width, so the cue is a
   slim row under them, inside the band. */
@media (orientation: portrait), (max-width: 760px) {
  .scene-cta-band { padding-bottom: 4px; }
  .scene-scroll-cue {
    position: static; transform: none; display: flex; flex-direction: row; gap: 4px; margin: 4px auto 0;
    padding: 2px 4px; background: none; box-shadow: none;
    font-size: 14px; font-weight: 600; color: rgba(255,255,255,.85);
  }
  .scene-scroll-cue:hover { color: #fff; }
  .scene-scroll-cue svg { width: 18px; height: 18px; color: inherit; }
}
@media (prefers-reduced-motion: reduce) {
  .scene-scroll-cue svg { animation: none; }
}


.page-more-info { padding: 70px 0; }
.page-more-info h2 { font-size: 26px; margin: 0 0 18px; font-weight: 800; }
.page-more-info p { color: var(--text-light); font-size: 16px; margin-bottom: 14px; }

/* ---------------------------------------------------------------------------
   Examples (build.js renderExamples, script.js initExamples) - the owner's
   layout, Oct 2026: a grid of captioned cards, one per variation of the
   product, each opening large in a viewer with the other examples along the
   bottom. The caption is the point of each card: it names the variation. */
.examples { padding: 56px 0 24px; background: var(--bg-light); }
.examples .section-title { text-align: start; margin-bottom: 6px; }
.examples-hint { margin: 0 0 22px; font-size: 14px; color: var(--text-light); }
.examples-grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 18px;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
.example-card {
  display: flex; flex-direction: column; width: 100%; height: 100%;
  padding: 0; border: 0; border-radius: var(--radius); overflow: hidden;
  background: var(--white); box-shadow: var(--shadow);
  font: inherit; color: var(--text-dark); text-align: start; cursor: zoom-in;
  transition: transform 160ms var(--ease-out), box-shadow 200ms ease;
}
.example-media { display: block; aspect-ratio: 4 / 3; overflow: hidden; background: #eef0f3; }
.example-media img { display: block; width: 100%; height: 100%; object-fit: cover; }
.example-caption { display: block; padding: 12px 14px 14px; font-size: 14.5px; font-weight: 600; line-height: 1.4; text-wrap: pretty; }
@media (hover: hover) and (pointer: fine) {
  .example-card:hover { transform: translateY(-3px); box-shadow: 0 16px 34px rgba(16,24,43,.14); }
}
.example-card:focus-visible { outline: 3px solid var(--orange-text); outline-offset: 3px; }
@media (max-width: 560px) {
  .examples { padding: 40px 0 16px; }
  .examples-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .example-caption { padding: 9px 10px 11px; font-size: 13px; }
}

/* The viewer: one example large, its caption, a counter, arrows, and the
   product's other examples as a strip along the bottom. */
html.ex-open { overflow: hidden; }
.ex-viewer {
  position: fixed; inset: 0; z-index: 900;
  display: flex; flex-direction: column;
  background: #0a0e19; color: #fff;
  padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
}
.ex-viewer[hidden] { display: none; }
.ex-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 16px; }
.ex-back, .ex-close {
  display: inline-flex; align-items: center; gap: 6px;
  border: 0; border-radius: 999px; cursor: pointer; font: inherit;
  background: rgba(255,255,255,.1); color: #fff;
}
.ex-back { padding: 9px 16px 9px 18px; font-size: 15px; font-weight: 600; }
.ex-back svg { width: 18px; height: 18px; }
.ex-close { width: 42px; height: 42px; justify-content: center; }
.ex-close svg { width: 20px; height: 20px; }
.ex-count { font-size: 14px; font-weight: 600; color: rgba(255,255,255,.7); font-variant-numeric: tabular-nums; }
.ex-stage {
  position: relative; flex: 1; min-height: 0; margin: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  padding: 0 64px;
}
.ex-img {
  display: block; max-width: 100%; max-height: calc(100% - 50px); min-height: 0;
  object-fit: contain; border-radius: 12px; box-shadow: 0 24px 60px rgba(0,0,0,.5); background: #fff;
}
.ex-caption { font-size: 17px; font-weight: 600; text-align: center; text-wrap: balance; }
/* The arrows sit on the photo's own edges, not the screen's (the owner, 20 Oct
   2026: on a wide screen they were far from the picture). script.js measures
   the photo into --img-l / --img-r / --img-mid; the fallbacks are the old
   screen-edge spots. Dark discs, since they now lie over a light photo. */
.ex-arrow {
  position: absolute; top: var(--img-mid, 50%); transform: translateY(-50%);
  width: 46px; height: 46px; border: 2px solid rgba(255,255,255,.85); border-radius: 50%; cursor: pointer;
  background: rgba(10,14,25,.6); color: #fff; font-size: 26px; line-height: 1;
  box-shadow: 0 4px 14px rgba(0,0,0,.35);
  display: flex; align-items: center; justify-content: center;
}
/* "Previous" sits on the side the reader came from: the right, in Hebrew. */
.ex-prev { right: var(--img-r, 10px); }
.ex-next { left: var(--img-l, 10px); }
/* What the site's header and floating buttons do, inside the viewer, which
   covers them: the visitor can act on the example in front of them. */
.ex-cta { display: flex; justify-content: center; flex-wrap: wrap; gap: 10px; padding: 12px 16px 0; }
.ex-cta .btn { padding: 10px 22px; font-size: 15px; }
.ex-cta .btn-outline { color: #fff; border-color: rgba(255,255,255,.6); }
.ex-thumbs {
  display: flex; gap: 10px; justify-content: safe center; overflow-x: auto;
  padding: 14px 16px 18px; scrollbar-width: none;
}
.ex-thumbs::-webkit-scrollbar { display: none; }
.ex-thumb {
  flex: none; width: 74px; height: 56px; padding: 0; border: 0; border-radius: 8px; overflow: hidden;
  cursor: pointer; background: #222; opacity: .55; outline: 2px solid transparent; outline-offset: 2px;
  transition: opacity 160ms ease;
}
.ex-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ex-thumb[aria-current="true"] { opacity: 1; outline-color: var(--orange); }
@media (hover: hover) and (pointer: fine) {
  .ex-back:hover, .ex-close:hover, .ex-arrow:hover { background: rgba(255,255,255,.22); }
  .ex-thumb:hover { opacity: .9; }
}
.ex-viewer button:focus-visible { outline: 2px solid var(--orange); outline-offset: 3px; }
@media (max-width: 560px) {
  .ex-stage { padding: 0 12px; }
  .ex-arrow { width: 38px; height: 38px; font-size: 22px; }
  .ex-cta { gap: 8px; padding-top: 10px; }
  .ex-cta .btn { padding: 10px 4px; font-size: 13.5px; flex: 1 1 0; min-width: 0; white-space: nowrap; text-align: center; }
  .ex-img { max-height: calc(100% - 64px); }
  .ex-caption { font-size: 15px; }
  .ex-back { font-size: 14px; padding: 8px 14px; }
}
@media (prefers-reduced-motion: reduce) {
  .example-card, .ex-thumb { transition: none; }
}

/* Responsive */
@media (max-width: 960px) {
  html { scroll-padding-top: 104px; }
  .main-nav { display: none; }
  .burger { display: flex; }
  /* Puts the burger at the leading (right) edge next to the logo, instead
     of the trailing/left edge -- previously the toggle sat clear across the
     screen from the logo/menu content it controls, which read as
     disconnected from what it opens. header-actions (call/WhatsApp) keeps
     its default order and ends up on the left instead. */
  .burger { order: -1; }
  .header-actions .phone-btn { display: none; }
  .phone-icon-btn { display: flex; }
  /* Homepage hero on mobile: text -> video -> action buttons -> "read more"
     cue, all meant to fit in one screen without scrolling. .hero-inner's
     base rule carries gap:40px (sized for the desktop two-column layout);
     .hero-text collapses out of the render tree here so its children
     (eyebrow/h1/sub/cta) become direct flex items of .hero-inner too, which
     would otherwise inherit that same 40px between every one of them, not
     just text-vs-visual -- the exact bug already fixed once for the
     category-page hero (.page-hero-inner). Zeroed here for the same
     reason; every gap below is explicit margin instead. */
  .hero-inner { flex-direction: column; text-align: center; padding: 14px 24px 8px; gap: 0; }
  .hero-text { max-width: 100%; display: contents; }
  .eyebrow { margin: 0 0 8px; font-size: 13px; line-height: 1.15; }
  /* Sized (not just text-wrap:balance'd) to fit the current headline on one
     line at ~375px width -- verified via scrollWidth against the available
     327px (375 - 2x24px padding): 20px fits at 323px, 21px doesn't at
     339px. */
  .hero h1 { font-size: 20px; line-height: 1.2; margin: 0 0 8px; }
  .hero-sub { font-size: 15px; line-height: 1.4; margin: 0 0 16px; }
  .hero-text > p,
  .hero-text > h1 { order: 1; }
  .hero-visual { width: 100%; min-height: 0; order: 2; margin: 0 0 16px; }
  .hero-cta { justify-content: center; order: 3; gap: 6px; margin: 0 0 16px; }
  .hero-cta .btn { padding: 8px 12px; font-size: 12px; }
  /* .hero-scroll-cue reuses the category-page component (same class,
     same script.js handler), but that one's default color (var(--text-
     light), a mid gray) assumes a light background -- this hero is a dark
     navy gradient with white text, so it needs its own light-colored
     override to stay legible. */
  .hero-scroll-cue { display: flex; }
  .hero .hero-scroll-cue { order: 4; color: rgba(255,255,255,0.75); margin-top: 0; }
  .hero .hero-scroll-cue:hover { color: white; }
  /* Product/category hero: the advantages band now fits without scrolling,
     so the "read more" cue prompting a scroll is stale and just adds an
     odd extra element between the hero and the band. Homepage's own
     .hero .hero-scroll-cue (above) is untouched -- different context. */
  .page-hero .hero-scroll-cue { display: none; }
  .service-grid { grid-template-columns: repeat(2, 1fr); }
  .contact-inner { flex-direction: column; }
  /* Homepage content sections below the hero -- each was built for
     desktop's 90px vertical rhythm and (for category-showcase/advantages)
     a grid that collapsed to a single column under 560px, which turned a
     4-item 2x2 grid into 4 full-width stacked rows: a whole extra screen
     of scrolling per section. Compacted throughout so each section's full
     content (heading + grid) is visible in one glance once scrolled to,
     instead of needing a second scroll within the section itself. */
  .services, .category-showcase, .about, .advantages, .testimonials, .contact { padding: 32px 0; }
  .section-title { font-size: 22px; margin-bottom: 4px; }
  .section-sub { margin-bottom: 20px; font-size: 14px; }

  .category-showcase-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; margin-top: 16px; }
  /* Five cards in two columns: the last one takes the full row. */
  .category-card:last-child:nth-child(odd) { grid-column: 1 / -1; }
  .category-card { padding: 10px 10px 14px; }
  .category-card-number { font-size: 20px; margin-bottom: 4px; }
  .category-card-body { padding-top: 8px; }
  .category-card h3 { font-size: 13px; margin-bottom: 6px; }

  .about h2 { font-size: 20px; margin-bottom: 10px; }
  .about-lead { font-size: 14px; margin-bottom: 8px; }
  .about p { font-size: 13px; }
  .about-stats { gap: 20px; flex-wrap: wrap; margin-top: 16px; }
  .about-stats strong { font-size: 22px; }
  .about-stats span { font-size: 11px; }
  .about-more-link { margin-top: 14px; font-size: 13px; }

  /* Advantages restyled to match category-card's compact centered-square
     shell instead of its own taller, right-aligned, text-heavy card --
     the description paragraph is dropped on mobile (kept for desktop)
     since a title-only card is what actually reads as a "small square"
     matching the category cards, not a card with two lines of body copy. */
  .advantages-grid { grid-template-columns: repeat(2, 1fr); gap: 20px 0; margin-top: 16px; }
  .advantage-card { padding: 4px 10px; }
  /* Hairlines only between the two columns of the 2x2 -- the desktop
     "every card after the first" rule would draw one down the start edge of
     the second row too. */
  .advantage-card + .advantage-card { border-inline-start: none; }
  .advantage-card:nth-child(even) { border-inline-start: 1px solid rgba(16,24,43,0.08); }
  .advantage-icon { width: 44px; height: 44px; margin-bottom: 8px; }
  .advantage-icon svg { width: 22px; height: 22px; }
  .advantage-card h3 { font-size: 13px; margin: 0; }
  .advantage-card p { display: none; }
  .advantages + .contact { padding-top: 32px; }

  /* Breadcrumb and the header search row are useful chrome but not part of
     the hero itself -- on mobile they were eating ~85px before the hero
     even started, the single biggest obstacle to fitting heading/text/
     buttons/examples in one screen. Hidden/shrunk here rather than in the
     hero rules below. */
  .breadcrumb { display: none; }
  .header-search-row { padding: 4px 20px; }
  /* .page-hero-inner's base rule carries "gap: 50px", sized for the desktop
     two-column layout (space between the text column and the visual
     column). .page-hero-text collapses out of the render tree on mobile
     (display:contents, below), so its children become direct flex items of
     THIS container -- meaning that same 50px gap silently applied between
     *every* adjacent element (eyebrow/H1/description/buttons/cards), not
     just text-vs-visual. That was the real source of "too much space"
     throughout this file, no matter how tightly the individual
     margins were tuned. Zeroed here; spacing between elements is fully
     margin-driven below instead. */
  .page-hero-inner { flex-direction: column; text-align: center; padding: 24px 20px 16px; gap: 0; }
  .page-hero-text { max-width: 100%; }
  .page-eyebrow { padding: 3px 10px; margin-bottom: 12px; font-size: 11px; line-height: 1.15; gap: 4px; }
  .page-eyebrow::before { font-size: 10px; }
  /* No font-size here: the base rule is a clamp() that already lands at
     ~23px on a phone and grows smoothly from there, so a hard override at
     this breakpoint would only reintroduce the step it replaced. */
  .page-hero-text h1 { line-height: 1.2; margin-bottom: 14px; }
  .page-hero-text p { font-size: 15px; line-height: 1.45; margin: 0 0 14px; }
  /* Mobile hero order is Header > H1 > short text > action buttons >
     product examples, so the buttons a visitor can act on are reachable
     without scrolling, with the card-fan as supporting content right after.
     The buttons live nested inside .page-hero-text (so desktop keeps its
     single text-with-buttons column), so on mobile we un-box that wrapper
     with display:contents and reorder its children individually against
     .page-hero-visual, rather than restructuring the DOM. */
  .page-hero-text { display: contents; }
  .page-hero-text > h1,
  .page-hero-text > p,
  .page-hero-text > .hero-accent-line { order: 1; }
  .hero-accent-line { margin: 0 auto 14px; }
  .hero-cta-row { order: 2; margin-top: 0; gap: 6px; }
  .hero-cta-row .btn { padding: 8px 12px; font-size: 12px; }
  /* .page-hero-visual carries "flex: 1" (flex-basis: 0%) for the desktop
     row layout, where that only affects width. Once .page-hero-inner
     switches to flex-direction:column here, the flex main axis becomes
     vertical, so that same flex-basis:0% collapses this element's height
     to 0 regardless of the explicit height set on .hero-card-fan below --
     the fan's cards (position:absolute, centered via top:50%) then center
     against a 0-height box instead of the intended tall one, landing high
     enough to overlap whatever sits above them. flex:none restores
     flex-basis:auto so the explicit height applies as the flex basis.
     The [data-orient] variants have to be listed too: they set flex on the
     same element with higher specificity than the bare class, and a media
     query adds none, so without them the desktop orientation rule would win
     here and undo this. */
  .page-hero-visual,
  .page-hero-visual[data-orient="wide"],
  .page-hero-visual[data-orient="square"],
  .page-hero-visual[data-orient="tall"] { order: 3; flex: none; width: 100%; }
  /* Cards are position:absolute, so they contribute no height to
     .hero-card-fan's own box -- if their rotated bounding box exceeds this
     fixed height, they spill visually onto whatever sits next to them
     (nothing here clips it, unlike the .page-hero ancestor's overflow:
     hidden, which is too far up to help). Sized with real margin above to
     keep clear of the buttons now preceding it. */
  .hero-card-fan { max-width: 320px; height: 215px; margin: 16px auto 0; }
  .hero-card { width: 95px; height: 125px; }
  /* Width only. The fixed heights that used to live here (230px / 210px)
     forced every page's photo into the same box and cropped whatever didn't
     fit; the wrapper now carries the file's own aspect-ratio, so capping the
     width is all that's needed and each product keeps its real proportions
     at every size. */
  .hero-photo-stage { max-width: min(320px, var(--stage-cap, 9999px)); margin: 20px auto 0; }
  .page-hero-visual[data-orient="square"] .hero-photo-stage,
  .page-hero-visual[data-orient="tall"] .hero-photo-stage { max-width: min(260px, var(--stage-cap, 9999px)); }
  /* Halving the vertical stagger (--ty) for mobile keeps the cards the same
     size (width/height untouched) while needing meaningfully less container
     height to fit them without spilling past .hero-card-fan's own box --
     the outer two cards' offset (plus float-animation travel) is what drives
     how tall that box has to be, not the cards' own width/height. */
  .hero-card-1 { --ty: 12px; }
  .hero-card-2 { --ty: 2px; }
  .hero-card-4 { --ty: 2px; }
  .hero-card-5 { --ty: 12px; }
  /* Compact on mobile specifically -- this is the element the "push
     everything up" request is ultimately about, it needs to actually be
     inside the first viewport, not just close to it. */
  .hero-scroll-cue { margin-top: 2px; padding-bottom: 2px; font-size: 12px; gap: 2px; }
  .hero-scroll-cue svg { width: 15px; height: 15px; }
  .header-inner { padding: 6px 20px; }
}

@media (max-width: 560px) {
  .hero h1 { font-size: 19px; }
  /* Two across, compact, the same way the homepage category grid handles a
     phone. One column made every subcategory card a full-width 300px-tall
     block, so a category's three or four options took two to three screens of
     scrolling to compare. */
  .service-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
  /* An odd last card sits centred under the pair, matching the centred
     desktop rows, instead of hanging off one side. */
  .service-card:last-child:nth-child(odd) { grid-column: 1 / -1; justify-self: center; width: calc(50% - 6px); }
  .service-card { padding: 10px 10px 14px; }
  .service-card-media { margin-bottom: 10px; border-radius: 10px; }
  .service-card h3 { font-size: 14px; margin-bottom: 4px; }
  .service-icon { display: none; }
  .service-card p { font-size: 12px; line-height: 1.45; }
  /* Tighten the header row so logo + call icon + WhatsApp + burger all fit
     without wrapping on narrow phones (~320-375px) -- the new phone-icon-btn
     added ~50px of required width that the previous layout never accounted
     for. */
  .header-inner { padding: 6px 16px; gap: 10px; }
  .header-actions { gap: 8px; }
  .logo img { height: 54px; }
  .phone-icon-btn { width: 34px; height: 34px; }
  .phone-icon-btn svg { width: 16px; height: 16px; }
  .header-actions .whatsapp-btn { padding: 8px 12px; font-size: 13px; }
  /* Second hard step removed for the same reason as the 22px one above --
     the clamp() in the base rule covers this width. */
  /* Smaller cards get a shallower fan too (reduced --rot), not just closer
     together (--tx) -- a tighter rotation keeps each card's true bounding
     box closer to its declared width/height, which is what actually
     prevents spillover past .hero-card-fan's fixed-height box, on top of
     just looking tidier at this size. */
  .hero-card-fan { max-width: 280px; height: 190px; }
  .hero-card { width: 85px; height: 112px; }
  .hero-card-1 { --tx: -100px; --rot: -12deg; }
  .hero-card-2 { --tx: -52px;  --rot: -6deg; }
  .hero-card-4 { --tx: 52px;   --rot: 6deg; }
  .hero-card-5 { --tx: 100px;  --rot: 12deg; }
}

.main-nav.open {
  display: flex;
  flex-direction: column;
  gap: 0;
  position: absolute;
  top: 100%;
  right: 0;
  left: 0;
  background: white;
  padding: 8px 24px;
  box-shadow: var(--shadow);
  max-height: calc(100vh - 130px);
  overflow-y: auto;
  z-index: 150;
}
/* Sticky "close" button pinned to the top of the open menu -- the burger
   itself toggles the menu too, but it can scroll out of view once the
   category list is long enough to need .main-nav.open's own scrollbar, so
   this stays reachable independent of scroll position and reads
   unambiguously as "this is how you close this". */
.main-nav.open .nav-close {
  display: flex;
  align-items: center;
  justify-content: center;
  position: sticky;
  top: 0;
  margin: 0 0 4px auto;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--bg-light);
  color: var(--navy);
  font-size: 16px;
  border: none;
  cursor: pointer;
  z-index: 1;
}
/* Links inherit zero padding from the desktop horizontal nav, where the
   surrounding whitespace was enough; stacked in the mobile menu that leaves
   each link's real tap target only as tall as its text (~20px, well under
   the 44px touch-target guideline) despite the visual gap around it. */
.main-nav.open a {
  padding: 13px 2px;
  font-size: 16px;
  border-bottom: 1px solid rgba(16,24,43,0.06);
}
.main-nav.open a:last-child { border-bottom: none; }
/* The desktop dropdown above only ever opens on :hover/:focus-within, which
   doesn't exist on touch. On mobile a category's subcategories start
   collapsed -- .nav-toggle (click handler in script.js) adds/removes .open
   on the .main-nav-item to reveal them, rather than every category dumping
   its full list into view at once. */
.main-nav.open .main-nav-item.has-dropdown { position: static; }
.main-nav.open .nav-item-row {
  display: flex;
  align-items: center;
  border-bottom: 1px solid rgba(16,24,43,0.06);
}
/* The row now owns the divider line above, so the link itself doesn't need
   its own (it would only span the link's own width next to the toggle
   button, not the full row, and double up with the row's border). flex:1
   keeps the tap target as wide as the space left by the toggle button. */
.main-nav.open .nav-item-row > a { border-bottom: none; flex: 1; }
.main-nav.open .nav-toggle {
  display: flex;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
}
.main-nav-item.open > .nav-item-row > .nav-toggle svg { transform: rotate(180deg); }
.main-nav.open .nav-dropdown {
  display: none;
  position: static;
  box-shadow: none;
  background: none;
  padding: 0 0 6px 18px;
}
.main-nav-item.open > .nav-dropdown { display: flex; }
.main-nav.open .nav-dropdown a {
  font-size: 14px;
  color: var(--text-light);
  padding: 10px 2px;
  border-bottom: none;
}
/* Dimmed backdrop behind the open mobile menu -- tapping anywhere outside
   the menu (handled in script.js) closes it, a second, more discoverable
   way to get out of it besides re-tapping the burger or the .nav-close
   button above.
   Lives as a sibling right after </header> (not nested inside .site-header)
   deliberately: .site-header has backdrop-filter:blur, and a semi-
   transparent element painted *inside* an ancestor using backdrop-filter
   silently fails to render its own translucency in Chrome (a compositing-
   layer quirk, confirmed by testing -- solid colors render fine, only the
   alpha channel gets lost). Sitting outside sidesteps that entirely.
   z-index 90 is deliberately *below* .site-header's 100: the header --
   logo, search, call/WhatsApp, and the open menu itself, which lives
   inside the header's stacking context -- stays fully bright and usable
   above the dimmed backdrop; only the rest of the page (hero, etc., all at
   the default stacking level) gets dimmed. */
.nav-backdrop.open {
  display: block;
  position: fixed;
  inset: 0;
  background: rgba(16,24,43,0.4);
  z-index: 90;
}

/* Popup system — driven by content/popups.json, editable via the CMS.
   Deliberately does NOT lock body scroll (no overflow:hidden on <body>),
   per spec: popups must never block scrolling. */
.site-popup-overlay {
  position: fixed;
  inset: 0;
  background: rgba(16,24,43,0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 300;
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s ease;
}
.site-popup-overlay.open { opacity: 1; pointer-events: auto; }
.site-popup-card {
  position: relative;
  width: 100%;
  max-width: 420px;
  border-radius: var(--radius);
  box-shadow: 0 24px 60px rgba(0,0,0,0.3);
  padding: 32px 28px 28px;
  text-align: center;
  transform: translateY(18px) scale(.96);
  transition: transform 300ms var(--ease-out);
  font-family: 'Rubik', sans-serif;
}
.site-popup-overlay.open .site-popup-card { transform: translateY(0) scale(1); }
.site-popup-close {
  position: absolute;
  top: 10px;
  left: 10px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: none;
  background: rgba(16,24,43,0.08);
  color: var(--text-dark);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.site-popup-close:hover { background: rgba(16,24,43,0.16); }
.site-popup-image {
  width: calc(100% + 56px);
  margin: -32px -28px 18px;
  max-height: 180px;
  object-fit: cover;
  border-radius: var(--radius) var(--radius) 0 0;
  display: block;
}
.site-popup-title { font-size: 21px; font-weight: 800; margin: 0 0 10px; color: var(--navy); }
.site-popup-body { font-size: 15px; color: var(--text-light); line-height: 1.6; margin: 0 0 22px; }
.site-popup-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.site-popup-actions:empty { display: none; }
.site-popup-btn { display: inline-block; }

@media (max-width: 560px) {
  .site-popup-card { max-width: 100%; padding: 28px 20px 22px; }
  .site-popup-image { width: calc(100% + 40px); margin: -28px -20px 16px; }
}

/* Quote-request modal -- opened by the "קבלו הצעת מחיר" hero button on every
   category/subcategory page (see initQuoteModal in script.js). Reuses the
   .site-popup-overlay/.site-popup-close plumbing above (same open/close
   mechanics, same non-scroll-locking behavior) but needs its own card：
   wider for a multi-field form, right-aligned instead of centered, and
   background set explicitly since a form's own white fields need contrast
   against something: */
.quote-modal-card {
  max-width: 480px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  text-align: right;
  background: var(--white);
}
.quote-modal-title { font-size: 21px; font-weight: 800; margin: 0 0 6px; color: var(--navy); }
.quote-modal-product {
  display: inline-block;
  background: var(--bg-light);
  color: var(--orange-text);
  font-weight: 700;
  font-size: 13px;
  padding: 6px 14px;
  border-radius: 999px;
  margin-bottom: 20px;
}
.quote-modal-card .contact-form { gap: 14px; }
.quote-modal-card .contact-form input[type="file"] {
  padding: 8px;
  border: 1px dashed #dcdfe4;
  background: var(--bg-light);
  font-size: 13px;
  cursor: pointer;
}
.quote-modal-card .contact-form button[type="submit"] { align-self: stretch; text-align: center; }
.quote-modal-hint { font-size: 12px; color: var(--text-light); margin: -8px 0 0; }

@media (max-width: 560px) {
  .quote-modal-card { max-width: 100%; padding: 26px 20px 20px; }
}

/* Articles / blog */
.article-tag {
  display: inline-block;
  background: var(--orange-light);
  color: var(--orange-text);
  font-size: 12px;
  font-weight: 700;
  padding: 5px 14px;
  border-radius: 999px;
  margin-bottom: 14px;
}
.article-meta { color: var(--text-light); font-size: 13px; margin-top: -8px; }
/* The article hero is a .page-hero, which is a dark ground -- --text-light
   is a mid grey meant for white backgrounds and disappears on it. */
.page-hero .article-meta { color: rgba(255,255,255,0.65); }
.article-body h2 { font-size: 22px; margin: 36px 0 14px; font-weight: 800; }
.article-body h2:first-child { margin-top: 0; }
.article-back-link { padding: 0 0 70px; text-align: center; }

.articles-hero {
  padding: 70px 0 20px;
  text-align: center;
  background: linear-gradient(135deg, var(--bg-light) 0%, var(--orange-light) 100%);
}
.articles-pill {
  display: inline-block;
  background: var(--white);
  color: var(--navy);
  font-size: 13px;
  font-weight: 700;
  padding: 7px 20px;
  border-radius: 999px;
  box-shadow: var(--shadow);
  margin-bottom: 20px;
}
.articles-hero h1 { font-size: 40px; line-height: 1.25; font-weight: 800; margin: 0 0 40px; color: var(--navy); }

.articles-listing { padding: 20px 0 90px; }

/* Bento-grid magazine layout — every article is one photo tile with a
   gradient overlay (brand navy/rust, alternating by index rather than
   random per-card hues, since these are real product photos, not stock
   lifestyle shots) and tag/title/read-time anchored to the bottom. The
   first tile renders larger; everything after wraps as regular 1x1 tiles,
   so this stays correct however many articles content/articles/ ends up
   holding — nothing here is hardcoded to today's article count. */
.articles-bento-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 220px;
  gap: 20px;
}
.bento-card:first-child { grid-column: span 2; grid-row: span 2; }
.bento-card {
  position: relative;
  display: block;
  border-radius: var(--radius);
  overflow: hidden;
  text-decoration: none;
  color: white;
  box-shadow: var(--shadow);
}
.bento-card img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 500ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .bento-card:hover img { transform: scale(1.05); }
}
.bento-card-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(16,24,43,0.1) 0%, rgba(16,24,43,0.88) 100%);
}
.bento-card:nth-child(even) .bento-card-overlay {
  background: linear-gradient(180deg, rgba(120,45,25,0.12) 0%, rgba(120,45,25,0.9) 100%);
}
.bento-card-content {
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-start;
  padding: 20px;
  gap: 10px;
}
.bento-card-tag {
  background: rgba(255,255,255,0.2);
  color: white;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .3px;
  padding: 5px 12px;
  border-radius: 999px;
}
.bento-card-content h3 { margin: 0; font-size: 17px; font-weight: 800; line-height: 1.35; }
.bento-card:first-child .bento-card-content h3 { font-size: 25px; }
.bento-card-cta {
  background: white;
  color: var(--navy);
  font-size: 12px;
  font-weight: 700;
  padding: 7px 14px;
  border-radius: 999px;
}

@media (max-width: 768px) {
  .articles-bento-grid { grid-template-columns: repeat(2, 1fr); }
  .bento-card:first-child { grid-column: span 2; grid-row: span 2; }
}
@media (max-width: 560px) {
  .articles-hero h1 { font-size: 28px; }
  .articles-bento-grid { grid-template-columns: 1fr; grid-auto-rows: 200px; }
  .bento-card:first-child { grid-column: span 1; grid-row: span 1; }
  .bento-card:first-child .bento-card-content h3 { font-size: 19px; }
}

/* Skip-to-content link — invisible until keyboard-focused, first thing a
   keyboard/screen-reader user can reach. */
.skip-link {
  position: fixed;
  top: -60px;
  right: 16px;
  z-index: 1000;
  background: var(--navy);
  color: white;
  padding: 12px 20px;
  border-radius: 8px;
  text-decoration: none;
  font-weight: 700;
  font-size: 14px;
  transition: top .2s;
}
.skip-link:focus { top: 16px; }

/* Cookie consent banner — fixed bar across the bottom, above everything
   else. Removed from the DOM entirely once the visitor chooses. */
.cookie-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 300;
  background: var(--navy);
  color: rgba(255,255,255,0.9);
  padding: 18px 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 16px;
  box-shadow: 0 -8px 24px rgba(0,0,0,0.2);
}
.cookie-banner p { margin: 0; font-size: 14px; max-width: 640px; text-align: center; }
.cookie-banner-actions { display: flex; gap: 10px; flex-shrink: 0; }
.cookie-banner .btn { padding: 10px 20px; font-size: 14px; }
.cookie-banner .btn-outline-dark { color: white; border-color: rgba(255,255,255,0.5); }
.cookie-banner .btn-outline-dark:hover { border-color: white; }

@media (max-width: 560px) {
  .cookie-banner { flex-direction: column; padding: 16px; }
}

/* The cookie banner spans the full width of the viewport bottom, so while
   it's showing it would otherwise sit on top of (and block clicks on) every
   other bottom-fixed button. Push them all above it. */
body.has-cookie-banner .whatsapp-float { bottom: 112px; }
body.has-cookie-banner .chatbot-toggle { bottom: 180px; }
body.has-cookie-banner .chatbot-tooltip { bottom: 180px; }
body.has-cookie-banner .a11y-toggle { bottom: 112px; }
body.has-cookie-banner .a11y-panel { bottom: 164px; }

/* Generic visible focus ring for anything relying on the browser default —
   guarantees keyboard focus is always visible sitewide, not just on the
   handful of elements with a custom :focus rule. */
a:focus-visible, button:focus-visible, input:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--orange-text);
  outline-offset: 2px;
}

/* Accessibility toolbar — floating button + panel, bottom-left (the
   WhatsApp/chat icons own bottom-right). Deliberately smaller than those —
   a secondary utility, not a primary CTA. All content lives in plain JS
   below; nothing here depends on any paid third-party widget service. */
.a11y-toggle {
  position: fixed;
  bottom: 24px;
  left: 24px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: var(--navy);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 8px 20px rgba(16,24,43,0.35);
  z-index: 200;
  transition: transform 200ms var(--ease-out);
}
.a11y-toggle svg { width: 21px; height: 21px; }
@media (hover: hover) and (pointer: fine) {
  .a11y-toggle:hover { transform: scale(1.06); }
}
.a11y-toggle:active { transform: scale(.94); }

.a11y-panel {
  position: fixed;
  bottom: 76px;
  left: 24px;
  width: 300px;
  max-width: calc(100vw - 32px);
  max-height: min(560px, calc(100vh - 120px));
  overflow-y: auto;
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: 0 20px 50px rgba(0,0,0,0.25);
  z-index: 201;
  display: none;
  font-family: 'Rubik', sans-serif;
}
.a11y-panel.open {
  display: block;
  /* Same origin rule as the chat window: out of its toggle, bottom-left. */
  transform-origin: bottom left;
  transition: opacity 200ms var(--ease-out), transform 260ms var(--ease-out);
}
@starting-style {
  .a11y-panel.open { opacity: 0; transform: translateY(8px) scale(.96); }
}
.a11y-panel-header {
  background: linear-gradient(135deg, var(--navy) 0%, var(--navy-2) 100%);
  color: white;
  padding: 16px 18px;
  font-weight: 700;
  font-size: 15px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: sticky;
  top: 0;
}
.a11y-panel-close { background: none; border: none; color: white; font-size: 20px; cursor: pointer; line-height: 1; padding: 4px; }
.a11y-panel-body { padding: 16px 18px; display: flex; flex-direction: column; gap: 14px; }
.a11y-group { display: flex; flex-direction: column; gap: 8px; }
.a11y-group-label { font-size: 13px; font-weight: 700; color: var(--text-dark); }
.a11y-row { display: flex; align-items: center; gap: 8px; }
.a11y-btn {
  flex: 1;
  background: var(--bg-light);
  color: var(--text-dark);
  border: 1px solid rgba(16,24,43,0.12);
  border-radius: 10px;
  padding: 9px 10px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  transition: background .2s, border-color .2s;
}
.a11y-btn:hover { background: var(--orange-light); border-color: var(--orange-text); }
.a11y-btn.active { background: var(--navy); color: white; border-color: var(--navy); }
.a11y-reset { color: var(--orange-text); font-weight: 700; border-color: var(--orange-text); }
.a11y-statement-link { font-size: 13px; color: var(--orange-text); text-decoration: underline; }

/* --- Modes toggled on <html> by the widget --- */
html.a11y-contrast, html.a11y-contrast body { background: #000 !important; color: #fff !important; }
html.a11y-contrast a { color: #ffd54a !important; }
html.a11y-contrast .btn, html.a11y-contrast button:not(.a11y-toggle):not(.a11y-panel-close) { background: #000 !important; color: #ffd54a !important; border: 2px solid #ffd54a !important; }
html.a11y-contrast img { filter: grayscale(0.3) contrast(1.1); }
html.a11y-contrast .site-header, html.a11y-contrast .a11y-panel, html.a11y-contrast .chatbot-window { background: #000 !important; }

html.a11y-grayscale { filter: grayscale(1); }

html.a11y-underline-links a { text-decoration: underline !important; }

html.a11y-highlight-headings h1, html.a11y-highlight-headings h2, html.a11y-highlight-headings h3 {
  background: #ffeb3b !important;
  color: #000 !important;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

html.a11y-readable-font, html.a11y-readable-font body, html.a11y-readable-font * {
  font-family: Arial, Helvetica, sans-serif !important;
  line-height: 1.8 !important;
  letter-spacing: .01em !important;
}

html.a11y-stop-animations, html.a11y-stop-animations * {
  animation: none !important;
  transition: none !important;
  scroll-behavior: auto !important;
}

html.a11y-big-cursor, html.a11y-big-cursor * {
  cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24"><path d="M4 2l14 8-6 2 4 7-3 2-4-7-4 5V2z" fill="black" stroke="white" stroke-width="1"/></svg>') 4 4, auto !important;
}

@media (max-width: 560px) {
  .a11y-toggle { bottom: 16px; left: 16px; }
  .a11y-panel { bottom: 68px; left: 16px; }
}

/* Reduced motion means gentler, not dead: fades that help explain a change
   of state stay, anything that travels, scales or loops is removed. The
   fanned hero cards and the "read more" cue are the only things on the site
   that move on their own forever. */
@media (prefers-reduced-motion: reduce) {
  .hero-card { animation: heroCardIn .01s both; }
  .hero-scroll-cue svg { animation: none; }
  .btn:hover, .btn:active,
  .whatsapp-float:hover, .whatsapp-float:active,
  .chatbot-toggle:hover, .chatbot-toggle:active,
  .a11y-toggle:hover, .a11y-toggle:active,
  .service-card:hover, .category-card:hover { transform: none; }
  .nav-dropdown, .site-search-results, .chatbot-window.open, .a11y-panel.open { transition: opacity 150ms ease; }
}
@media (prefers-reduced-motion: reduce) {
  @starting-style {
    .nav-dropdown, .site-search-results.open, .chatbot-window.open, .a11y-panel.open { transform: none; }
  }
}
