
/* Hero media + panel-surface layer — SINGLE SOURCE. tools/build-hero-media.py writes this file
   into every hero-with-panel consumer listed in hero-media.json, inside a "GENERATED hero-media"
   region; the copy in a page is never edited by hand.

   Every hero on the site already stacks the same way:
     · the section is the base surface (position: relative; overflow: hidden; its own bg);
     · .hero-art is the decorative layer (absolute, inset 0, z-index 0, pointer-events none);
     · .hero-art::after is the legibility veil — dark in the page CSS core, light in the
       generated theme layer;
     · .hero .wrap is the live content (position: relative; z-index: 1) — copy, CTAs, panel.
   This file adds three things and nothing else:
     1. the PHOTOGRAPH variant of the art layer (.hero-art--image + <img class="hero-art-img">);
     2. the SAFE-ZONE classes that say where a photograph's subject is allowed to sit;
     3. the PANEL SURFACE variants, keyed on data-hero-surface="…" that the generator writes on
        the hero section from hero-media.json — paper · tinted-paper · dark-panel — so every
        wizard, planner, estimator or form beside the copy is a declared surface with its own
        foreground, whether or not the hero carries a photograph.

   Layers inside the photograph variant, bottom to top:
     0  base surface           .hero-art--image background (var(--bg-2))
     0  photograph             .hero-art-img — the ONLY element that carries a filter
     0  veil                   .hero-art--image::after — gradient only, no filter, no blend
     1  live content           .hero .wrap — untouched by anything in this file
   The page's own SVG placeholder art stays in the markup underneath a photograph (hidden by
   the adjacent-sibling rule below), so removing the photograph from hero-media.json restores
   the plain hero exactly.

   SAFE ZONES (desktop, measured on the reference 1440×900 layout — see hero-media.json):
     the copy block protects x 10–48% of the frame in its upper half; the panel protects
     x 51–89% for almost the full height. A subject that must stay visible has two homes:
       subject-far-right   the band right of the panel — x ≥ 89% of the frame (≥ 81% at 1920)
       subject-lower-left  under the copy — x 12–46%, y 52–95%; the veil is masked off there
     `none` declares that nothing in the frame needs protecting (architecture, empty space).
   A subject cannot be protected by object-position alone: the photograph is width-bound at
   every desktop ratio, so horizontal focal shifts do nothing. Faces under the panel are a
   composition failure, not a positioning task. On the stacked layout (≤1080px) the panel covers
   the whole width, so a subject photograph is hidden there and the veil alone remains.

   Dark is the base (every page's :root is dark); light hangs off :root[data-theme="light"],
   the hook the theme layer uses. Variant selectors are compounded (.hero-art.hero-art--image)
   so they tie the emirate pages' own `.dub-hero .hero-art::after` scrim on specificity and win
   on source order; surface rules are :root-prefixed so they outrank a component's own
   :root[data-theme="light"] rule wherever that region sits in the page. */

:where(.hero, .banks-hero, .dub-hero, .bk-hero, [data-hero-mode]):has(> .hero-art--image) { isolation: isolate; position: relative; overflow: hidden; }   /* any registered hero (careers-hero, brand-hero) can carry the photograph layer */
.hero-art--image ~ .wrap { position: relative; z-index: 1; }   /* live content above the media, whatever the page's own rule says */

.hero-art.hero-art--image {
  --hero-art-pos: center center;
  --hero-art-pos-mobile: 60% center;
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  background: var(--bg-2);
}
:root [data-hero-mode] .hero-art.hero-art--image { opacity: 1; }   /* a page's mobile art dimming (.svc-hero--wizard .hero-art {opacity:.55} and kin) never applies to a photograph — outranks any page rule on specificity, proven by tools/audit-hero-render.mjs */
.hero-art--image > svg { display: none; }         /* an SVG art layer never shows under a photo */
.hero-art-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--hero-art-pos);
  transform: scale(1.008);                         /* hides the 1px cover seam at the edges */
  filter: saturate(0.50) contrast(0.88) brightness(0.66);
}
.hero-art.hero-art--image::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(90deg,
    rgba(9, 11, 12, 0.78) 0%,
    rgba(9, 11, 12, 0.64) 32%,
    rgba(9, 11, 12, 0.40) 62%,
    rgba(9, 11, 12, 0.24) 100%);
}
.hero-art.hero-art--image.hero-art--veil-strong::after {
  background: linear-gradient(90deg,
    rgba(7, 9, 10, 0.91) 0%,
    rgba(7, 9, 10, 0.79) 42%,
    rgba(7, 9, 10, 0.58) 71%,
    rgba(7, 9, 10, 0.35) 100%);
}

:root[data-theme="light"] .hero-art-img {
  filter: saturate(0.70) contrast(0.94) brightness(1.00) sepia(0.02);
}
:root[data-theme="light"] .hero-art.hero-art--image::after {
  /* protects the copy column, then lets go quickly so the photo is present behind the panel */
  background: linear-gradient(90deg,
    rgba(246, 243, 235, 0.82) 0%,
    rgba(246, 243, 235, 0.68) 27%,
    rgba(246, 243, 235, 0.37) 48%,
    rgba(246, 243, 235, 0.16) 72%,
    rgba(246, 243, 235, 0.06) 100%);
}
:root[data-theme="light"] .hero-art.hero-art--image.hero-art--veil-strong::after {
  background: linear-gradient(90deg,
    rgba(246, 243, 235, 0.90) 0%,
    rgba(246, 243, 235, 0.78) 36%,
    rgba(246, 243, 235, 0.50) 58%,
    rgba(246, 243, 235, 0.24) 78%,
    rgba(246, 243, 235, 0.08) 100%);
}

/* ambient — a subject-free paper / work-surface texture (hero-media.json veil: "ambient").
   The image is decorative depth, not a scene: light keeps it faintly legible under a flat ivory
   wash no heavier than .12; dark keeps the component filter under a flat charcoal wash so the
   texture stays perceptible instead of vanishing into the base. Image layer only. */
.hero-art.hero-art--image.hero-art--veil-ambient .hero-art-img { filter: saturate(0.50) contrast(0.88) brightness(0.62); }
.hero-art.hero-art--image.hero-art--veil-ambient::after { background: rgba(9, 11, 12, 0.42); }
:root[data-theme="light"] .hero-art.hero-art--image.hero-art--veil-ambient .hero-art-img { filter: saturate(0.72) contrast(0.92) brightness(1.02); }
:root[data-theme="light"] .hero-art.hero-art--image.hero-art--veil-ambient::after { background: rgba(248, 246, 239, 0.12); }

/* ---- split media (hero-media.json placement: "split") -----------------------------------
   A contained, uncovered media column beside the copy — for heroes with no panel where the
   picture is meaningful (a person, an office). The generator writes data-hero-media="split" on
   the section and the figure as the grid's last child; the grid itself is the page's .hero-grid
   or, where the page has none, this two-column rule. The image is the only layer that carries a
   filter (dark only); nothing sits over it. */
[data-hero-media="split"] .hero-grid { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); gap: clamp(32px, 4vw, 56px); align-items: center; }
.hero-visual.hero-media--split {
  position: relative; overflow: hidden; isolation: isolate; margin: 0;
  aspect-ratio: 4 / 5; max-height: 560px; width: 100%;
  border: 1px solid var(--line); border-radius: 16px; background: var(--bg-2);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.28), 0 6px 18px rgba(0, 0, 0, 0.14);
}
[data-hero-split-frame="landscape"] .hero-visual.hero-media--split { aspect-ratio: 4 / 3; max-height: 400px; }   /* a service hero keeps its band height (hero-media.json media.frame, 2026-09-08) */
:root[data-theme="light"] .hero-visual.hero-media--split { box-shadow: 0 22px 54px rgba(47, 42, 32, 0.12), 0 6px 18px rgba(47, 42, 32, 0.06); }
.hero-visual.hero-media--split::before, .hero-visual.hero-media--split::after { content: none; }   /* a former .frame placeholder drew its label with pseudo-elements */
.hero-media-split-img {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  object-fit: cover; object-position: var(--hero-split-pos, center center);
  filter: saturate(0.82) contrast(0.94) brightness(0.86);
}
:root[data-theme="light"] .hero-media-split-img { filter: none; }
@media (max-width: 1080px) {
  [data-hero-media="split"] .hero-grid { grid-template-columns: 1fr; gap: 28px; }
  .hero-visual.hero-media--split { aspect-ratio: 4 / 3; max-height: 420px; }
  .hero-media-split-img { object-position: var(--hero-split-pos-mobile, var(--hero-split-pos, center center)); }   /* the stacked 4:3 crop declares its own focal point (hero-media.json positionMobile, 2026-09-08) */
}

/* ---- safe zones ------------------------------------------------------------------------ */
@media (min-width: 1081px) {
  /* subject-lower-left: the veil protects the copy block only; below it the photograph is clear */
  .hero-art.hero-art--image.hero-art--zone-lower-left::after {
    -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 46%, transparent 64%);
    mask-image: linear-gradient(180deg, #000 0%, #000 46%, transparent 64%);
  }
}

/* ---- panel surfaces ---------------------------------------------------------------------
   The panel families the site has: .glass (setup planners, quick check), .wiz-card (wizard
   engine), .fzfit-panel (fit check), .wzs-shell / .gv-shell / .vw-shell (bank and visa wizards),
   .cwp-panel and aside.wiz (service-page wizards), .hsw-preview (the static "What to expect" list). Each surface sets background, border,
   shadow AND its foreground tokens; nothing is translucent enough to show the photograph
   through controls, nothing is blurred, nothing carries whole-card opacity. */
:root [data-hero-surface] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* paper — the approved setup-planner surface: lifted warm charcoal on dark, warm paper on light */
:root [data-hero-surface="paper"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) {
  background: rgba(28, 30, 31, 0.94);
  border-color: var(--line-on-dark);
  box-shadow: 0 28px 72px rgba(0, 0, 0, 0.42), 0 8px 24px rgba(0, 0, 0, 0.22);
  color: var(--text);
}
:root[data-theme="light"] [data-hero-surface="paper"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) {
  background: rgba(250, 248, 242, 0.96);
  border-color: rgba(48, 44, 36, 0.14);
  box-shadow: 0 26px 62px rgba(47, 42, 32, 0.14), 0 8px 22px rgba(47, 42, 32, 0.08);
  color: var(--text);
}

/* tinted-paper — a stone panel that separates from an ivory or image-backed hero without
   becoming a white modal; option cards sit as paper on the stone so controls stay visible */
:root [data-hero-surface="tinted-paper"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) {
  background: var(--surface-tinted);
  border-color: rgba(255, 255, 255, 0.14);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.36), 0 6px 18px rgba(0, 0, 0, 0.18);
  color: var(--text);
}
:root[data-theme="light"] [data-hero-surface="tinted-paper"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) {
  background: var(--surface-tinted);
  border-color: rgba(48, 44, 36, 0.22);
  box-shadow: 0 22px 54px rgba(47, 42, 32, 0.12), 0 6px 18px rgba(47, 42, 32, 0.06);
  color: var(--text);
}
:root[data-theme="light"] [data-hero-surface="tinted-paper"] .wrap .wiz-opt {
  background: rgba(255, 253, 247, 0.62);
  border-color: rgba(20, 24, 27, 0.24);
}
:root[data-theme="light"] [data-hero-surface="tinted-paper"] .wrap .wiz-opt:hover { background: rgba(255, 253, 247, 0.88); }
:root[data-theme="light"] [data-hero-surface="tinted-paper"] .wrap .wiz-opt.is-selected { background: rgba(122, 106, 72, 0.12); }

/* dark-panel — a deliberate warm-charcoal tool surface in BOTH themes. The theme tokens are
   remapped inside the panel, so every token-driven part of the wizard (headings, option labels,
   dividers, checkbox outlines, kicker) takes the on-dark values and the primary button flips to
   the dark theme's light button. No scrim, no opacity, no filter. */
:root [data-hero-surface="dark-panel"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview),
:root[data-theme="light"] [data-hero-surface="dark-panel"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) {
  --bg: var(--surface-dark); --bg-2: var(--surface-dark-2); --surface: var(--surface-dark); --surface-2: var(--surface-dark-2); --glass: var(--surface-dark);
  --text: var(--text-on-dark); --muted: var(--muted-on-dark); --faint: var(--faint-on-dark); --text-mute: var(--muted-on-dark);
  --line: var(--line-on-dark); --line-soft: var(--line-soft-on-dark); --line-strong: var(--line-strong-on-dark);
  --mineral: #E6E0D2; --mineral-hi: #F0EBDF; --sand: #E6E0D2; --brass: #C2A26A; --sage: #9AACB0;
  background: var(--surface-dark);
  border-color: var(--line-on-dark);
  box-shadow: 0 22px 56px rgba(0, 0, 0, 0.28), 0 6px 18px rgba(0, 0, 0, 0.16);
  color: var(--text);
}
:root [data-hero-surface="dark-panel"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) .btn-primary,
:root[data-theme="light"] [data-hero-surface="dark-panel"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) .btn-primary { background: #F5F2EA; color: #14181B; }
:root [data-hero-surface="dark-panel"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) .btn-primary:hover,
:root[data-theme="light"] [data-hero-surface="dark-panel"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) .btn-primary:hover { background: #FBF9F3; }
/* The wizard engine declares --wiz-* as var(--text) etc. in light (theme layer), so it follows the
   remapped tokens on its own; only the theme layer's literal light-mode control colours need the
   on-dark values here. Everything is scoped to the panel — the copy-side CTAs are not touched. */
:root[data-theme="light"] [data-hero-surface="dark-panel"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) .wiz-progress-bar { background: var(--line-on-dark); }
:root[data-theme="light"] [data-hero-surface="dark-panel"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) .wiz-opt { border-color: var(--line-on-dark); background: var(--control-surface-dark); }
:root[data-theme="light"] [data-hero-surface="dark-panel"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) .wiz-opt:hover { border-color: rgba(230, 224, 210, 0.35); background: rgba(230, 224, 210, 0.05); }
:root[data-theme="light"] [data-hero-surface="dark-panel"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) .wiz-opt.is-selected { border-color: #E6E0D2; background: rgba(230, 224, 210, 0.08); }
:root[data-theme="light"] [data-hero-surface="dark-panel"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) .wiz-opt-dot { border-color: var(--line-strong-on-dark); }
:root[data-theme="light"] [data-hero-surface="dark-panel"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) .wiz-opt.is-selected .wiz-opt-dot { color: #14181B; }
:root[data-theme="light"] [data-hero-surface="dark-panel"] .wrap :is(.glass, .wiz-card, .fzfit-panel, .wzs-shell, .gv-shell, .vw-shell, .cwp-panel, aside.wiz, .hsw-preview) .btn-ghost { color: var(--text-on-dark); border-color: var(--line-strong-on-dark); background: var(--control-surface-dark); }

/* Stacked layout: the copy sits above the panel, so the veil runs top to bottom and a subject
   photograph (which the stacked panel would cover) gives way to the veil over the base surface.
   1080px is where the widest hero grid (index, uae, vietnam) stacks; narrower grids stack
   sooner and simply meet the vertical veil a little early. */
@media (max-width: 1080px) {
  .hero-art-img { object-position: var(--hero-art-pos-mobile); }
  .hero-art--zone-far-right .hero-art-img,
  .hero-art--zone-lower-left .hero-art-img { display: none; }
  .hero-art.hero-art--image::after,
  .hero-art.hero-art--image.hero-art--veil-strong::after {
    background: linear-gradient(180deg,
      rgba(7, 9, 10, 0.88) 0%,
      rgba(7, 9, 10, 0.72) 52%,
      rgba(7, 9, 10, 0.56) 100%);
  }
  :root[data-theme="light"] .hero-art.hero-art--image::after,
  :root[data-theme="light"] .hero-art.hero-art--image.hero-art--veil-strong::after {
    background: linear-gradient(180deg,
      rgba(245, 242, 234, 0.88) 0%,
      rgba(245, 242, 234, 0.72) 52%,
      rgba(245, 242, 234, 0.56) 100%);
  }
  .hero-art.hero-art--image.hero-art--veil-ambient::after { background: rgba(9, 11, 12, 0.48); }
  :root[data-theme="light"] .hero-art.hero-art--image.hero-art--veil-ambient::after { background: rgba(248, 246, 239, 0.22); }
}

@media (prefers-reduced-motion: reduce) {
  .hero-art-img { transform: none; }
}


/* ---- no-media heroes (hero-media.json mode: wizardNoMedia | noMedia) ------------------------
   The copy (and the panel) ARE the hero. The generator removes the placeholder art layer from
   the markup, so there is nothing to hide; the section paints the base surface with a quiet
   tonal gradient so it reads as intentional rather than flat. Both themes resolve through tokens. */
/* the tonal gradient for these modes lives in _shared/theme.css so that non-consumer pages get it too */
      /* hero-media.css · page config from hero-media.json */
      .hero-art.hero-art--image { --hero-art-pos: center center; --hero-art-pos-mobile: 40% center; }
    