/* B3GT — components. Replaces the 311 inline style attributes from the prototype.
   All spacing uses logical properties so rtl.css stays small. */

/* ---------- header ---------- */
.hdr{position:sticky;top:0;z-index:50;background:transparent;
     transition:background var(--dur-base) var(--ease-out),
                box-shadow var(--dur-base) var(--ease-out);}
.hdr__in{display:flex;align-items:center;gap:20px;
         padding-block:22px;transition:padding-block var(--dur-base) var(--ease-out)}
.hdr__lock{display:flex;align-items:center;gap:16px;text-decoration:none;flex-shrink:0}
.hdr__mark{height:44px;width:auto;transition:height var(--dur-base) var(--ease-out)}
.hdr__div{width:.5px;height:32px;background:var(--rule);
          transition:height var(--dur-base) var(--ease-out)}
.hdr__name{font-family:var(--sans);font-weight:500;font-size:17px;
           letter-spacing:.14em;text-transform:uppercase;color:var(--b3-blue);line-height:1.2}
.hdr__tag{font-size:11px;letter-spacing:.06em;color:var(--muted);
          transition:opacity var(--dur-base) var(--ease-out)}

.hdr.is-stuck{background:var(--paper);box-shadow:0 .5px 0 var(--rule)}
.hdr.is-stuck .hdr__in{padding-block:12px}
.hdr.is-stuck .hdr__mark{height:34px}
.hdr.is-stuck .hdr__div{height:24px}
.hdr.is-stuck .hdr__tag{opacity:0}

.nav{margin-inline-start:auto;display:flex;align-items:center;gap:26px}
.nav a{position:relative;text-decoration:none;font-size:14px;color:var(--ink);padding-block:6px}
.nav a::after{content:"";position:absolute;inset-block-end:0;inset-inline-start:0;
              height:1px;width:0;background:var(--brick);
              transition:width var(--dur-micro) var(--ease-out)}
.nav a:hover::after,.nav a[aria-current="page"]::after{width:100%}

.langs{display:flex;gap:2px;margin-inline-start:8px}
.langs a{font-family:var(--mono);font-size:11px;letter-spacing:.1em;
         padding:4px 7px;text-decoration:none;color:var(--muted);border-radius:3px}
.langs a[aria-current]{background:var(--b3-blue);color:var(--paper)}

.burger{display:none;margin-inline-start:auto;background:none;border:0;
        font-family:var(--mono);font-size:11px;letter-spacing:.14em;
        text-transform:uppercase;color:var(--b3-blue);cursor:pointer;padding:8px}
@media(max-width:900px){
  .nav{display:none;position:absolute;top:100%;inset-inline:0;background:var(--paper);
       flex-direction:column;align-items:flex-start;gap:0;padding:8px var(--gut) 20px;
       border-block-end:.5px solid var(--rule)}
  .nav.is-open{display:flex}
  .nav a{padding-block:12px;width:100%;border-block-end:.5px solid var(--rule)}
  .langs{margin:14px 0 0}
  .burger{display:block}
  .hdr__tag{display:none}
}

/* ---------- hero ---------- */
.hero{position:relative;background:var(--b3-deep);color:var(--paper);
      padding-block:clamp(80px,14vh,160px) clamp(60px,10vh,120px);overflow:hidden}
.hero__bg{position:absolute;inset:0;object-fit:cover;width:100%;height:100%;
          opacity:.28;will-change:transform}
.hero__in{position:relative}
/* the measure belongs on the h1: `ch` resolves against the element's own
   font-size, so 20ch here bought 204px of the 17px body font, not the heading */
.hero h1{color:var(--paper);font-size:clamp(38px,5.4vw,72px);max-width:16ch;
         margin-block-end:24px}
.hero__sub{font-size:clamp(17px,2vw,21px);max-width:52ch;color:var(--sand);margin-block-end:36px}
.hero .lbl{color:var(--sand);margin-block-end:20px}
.hero__cta{display:flex;gap:12px;flex-wrap:wrap}

/* ---------- hero: ambient motion ----------
   Three slow layers over the photograph. Everything below is opt-in: the
   static rules leave the hero complete and still, and only the
   prefers-reduction: no-preference block sets anything moving. Loop lengths
   come from the --loop-* tokens in base.css, kept apart from --dur-* because
   a 28s drift and a 380ms transition are not the same kind of time.         */

/* the drift lives on the <picture>, the scroll parallax in main.js lives on
   the <img> inside it. Same visual stack, two elements, so neither overwrites
   the other's transform. */
.hero > picture{position:absolute;inset:0;display:block}
/* text sits above both the photograph and the path network, explicitly rather
   than by DOM accident */
.hero > .wrap{position:relative;z-index:2}

.b3net{position:absolute;inset:0;width:100%;height:100%;z-index:1;
       opacity:.12;color:var(--sand);pointer-events:none}
.b3net__arc{fill:none;stroke:currentColor;stroke-width:.5;
            vector-effect:non-scaling-stroke;stroke-linecap:round;
            stroke-dasharray:1;stroke-dashoffset:0}
.b3net__dot{fill:currentColor;transform-box:fill-box;transform-origin:center}

.hero__ticker{position:absolute;inset-inline:0;inset-block-end:0;z-index:1;
              overflow:hidden;padding-block:12px;pointer-events:none;
              font-family:var(--mono);font-size:11px;letter-spacing:.14em;
              text-transform:uppercase;color:var(--sand);opacity:.7;
              white-space:nowrap}
/* .7 rather than the .6 this was drawn at: over the darkest part of the
   photograph, sand at .6 composites to 4.22:1 against 11px text, under the
   4.5 floor. .66 is the first value that clears it; .7 leaves a margin. */
.hero__ticker b{display:inline-block;font-weight:400;padding-inline-end:4em}

@media (prefers-reduced-motion: no-preference){
  /* A — the photograph breathes. Linear, so it never reads as an ease.
     Off below 700px: no drift on a phone. */
  @media (min-width:701px){
    .hero > picture{animation:b3drift var(--loop-drift) linear infinite alternate}
  }

  /* B — arcs draw, hold, fade, wait. 20s each, staggered 2.6s apart so no two
     are ever in the same phase. Held to >=901px: rule 4 keeps phones still. */
  @media (min-width:901px){
    .b3net__arc{animation:b3arc var(--loop-arcs) var(--ease-out) infinite;opacity:0}
    .b3net__arc:nth-of-type(2){animation-delay:2.6s}
    .b3net__arc:nth-of-type(3){animation-delay:5.2s}
    .b3net__arc:nth-of-type(4){animation-delay:7.8s}
    .b3net__arc:nth-of-type(5){animation-delay:10.4s}
    .b3net__arc:nth-of-type(6){animation-delay:13s}
    .b3net__arc:nth-of-type(7){animation-delay:15.6s}
    .b3net__dot{animation:b3dot var(--loop-dots) var(--ease-both) infinite}
    .b3net__dot:nth-of-type(2){animation-delay:.7s}
    .b3net__dot:nth-of-type(3){animation-delay:1.5s}
    .b3net__dot:nth-of-type(4){animation-delay:2.2s}
    .b3net__dot:nth-of-type(5){animation-delay:3s}
    .b3net__dot:nth-of-type(6){animation-delay:3.8s}
    .b3net__dot:nth-of-type(7){animation-delay:4.4s}
    .b3net__dot:nth-of-type(8){animation-delay:5.1s}
  }

  /* C — the manifest. Linear and slow; the track holds two copies, so -50%
     lands exactly on the seam. Stays on phones. */
  .hero__ticker__t{animation:b3tick var(--loop-ticker) linear infinite}

  /* paused while the hero is off screen — see main.js */
  .hero.is-still > picture,
  .hero.is-still .b3net__arc,
  .hero.is-still .b3net__dot,
  .hero.is-still .hero__ticker__t{animation-play-state:paused}
}

@keyframes b3drift{from{transform:scale(1)}to{transform:scale(1.06)}}
@keyframes b3arc{
  0%{stroke-dashoffset:1;opacity:0}
  3%{opacity:1}
  21%{stroke-dashoffset:0;opacity:1}
  46%{stroke-dashoffset:0;opacity:1}
  62%{stroke-dashoffset:0;opacity:0}
  100%{stroke-dashoffset:0;opacity:0}
}
@keyframes b3dot{
  0%,100%{opacity:.4;transform:scale(1)}
  50%{opacity:1;transform:scale(1.4)}
}
@keyframes b3tick{from{transform:translate3d(0,0,0)}to{transform:translate3d(-50%,0,0)}}

.btn{display:inline-block;font-family:var(--sans);font-size:15px;font-weight:500;
     padding:14px 26px;border-radius:4px;text-decoration:none;border:.5px solid transparent;
     position:relative;overflow:hidden;cursor:pointer;
     transition:color var(--dur-base) var(--ease-out)}
.btn::before{content:"";position:absolute;inset-inline:0;inset-block-end:0;height:0;
             background:var(--brick-deep);z-index:-1;
             transition:height var(--dur-base) var(--ease-out)}
.btn{z-index:0}
.btn:hover::before{height:100%}
.btn--solid{background:var(--brick-deep);color:#fff}
.btn--solid:hover::before{background:var(--brick)}
.btn--ghost{border-color:rgba(246,244,239,.45);color:var(--paper)}
.btn--ghost:hover{color:#fff}

/* ---------- office locator plate ---------- */
/* A schematic, not a map of the world: a graticule and six points at their real
   coordinates. No coastlines to get wrong, and no line between any two points —
   see the note in build.py for why that matters. */
/* this ratio must equal GEO_BOX in build.py. The grid is an SVG with that
   viewBox and the pins are percentages of this box: if the two disagree the
   SVG letterboxes and the markers drift off their own graticule. */
.geo{position:relative;aspect-ratio:445/255;margin-block-end:56px}
.geo__grid{position:absolute;inset:0;width:100%;height:100%;
           stroke:var(--rule);stroke-width:.5;fill:none}
.geo__land{fill:var(--sand);stroke:none;opacity:.55}
.geo__grid line{vector-effect:non-scaling-stroke;opacity:.5}
/* equator and prime meridian carry the frame — without them the graticule is
   just paper, and nothing tells a reader which way the world is facing */
.geo__axis{opacity:1;stroke:var(--muted)}
/* the pin is a zero-size anchor sitting exactly on the coordinate; the dot and
   the name hang off it. Centring the whole pin instead would put the dot half
   a label-width away from the place it claims to mark. */
.geo__pin{position:absolute;inset-inline-start:var(--x);inset-block-start:var(--y);
          inline-size:0;block-size:0}
.geo__dot{position:absolute;inset-inline-start:-3.5px;inset-block-start:-3.5px;
          inline-size:7px;block-size:7px;border-radius:50%;background:var(--brick-deep)}
.geo__pin--head .geo__dot{inset-inline-start:-5px;inset-block-start:-5px;
                          inline-size:10px;block-size:10px;background:var(--b3-blue)}
.geo__name{position:absolute;inset-inline-start:11px;inset-block-start:0;
           transform:translateY(-50%);white-space:nowrap;
           font-family:var(--mono);font-size:11px;letter-spacing:.1em;
           text-transform:uppercase;color:var(--muted)}
.geo__pin--before .geo__name{inset-inline-start:auto;inset-inline-end:11px}
.geo__pin--head .geo__name{color:var(--ink)}
@media (prefers-reduced-motion: no-preference){
  .geo__pin--head .geo__dot{animation:b3dot var(--loop-dots) var(--ease-both) infinite}
  .geo.is-still .geo__dot{animation-play-state:paused}
}
@media(max-width:700px){
  /* the ratio is fixed by the projection, so the phone gets tighter tracking
     on the names instead of a taller plate */
  .geo__name{letter-spacing:.04em}
}

/* ---------- sections ---------- */
.sec{padding-block:clamp(72px,11vw,160px)}
.sec--surface{background:var(--surface)}
.sec--deep{background:var(--b3-deep);color:var(--paper)}
.sec--deep h2{color:var(--paper)}
.sec__head{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.6fr);
           gap:clamp(24px,5vw,72px);align-items:start;margin-block-end:56px}
.sec__head p{color:var(--muted);margin:0;font-size:18px}
.sec--deep .sec__head p{color:var(--sand)}
.sec__num{font-family:var(--mono);font-size:11px;letter-spacing:.16em;
          color:var(--brick-deep);margin-block-end:10px}
@media(max-width:820px){.sec__head{grid-template-columns:1fr;gap:16px;margin-block-end:36px}}

/* ---------- stats band ---------- */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
       gap:clamp(20px,4vw,48px);border-block-start:.5px solid var(--rule);padding-block-start:40px}
.stats__n{font-family:var(--mono);font-weight:500;
          font-size:clamp(40px,5.2vw,72px);line-height:1;color:var(--b3-blue)}
.sec--deep .stats__n{color:var(--sand)}
.stats__l{margin-block-start:10px}

/* ---------- product grid ---------- */
/* The hairlines are drawn by the cells, not by a colour behind the grid.
   Seven families never divide evenly into 4, 3 or 2 columns, so the grid
   always has a leftover cell; painting --rule behind it turned that leftover
   into a filled block. Each cell now carries its own 1px ring, the rings meet
   inside the 2px gap to make the same line, and a cell with nothing in it
   shows the section instead of a slab of colour. overflow:hidden trims the
   ring where it would otherwise draw a border around the whole grid. */
.fams{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:2px;
      overflow:hidden}
.fam{background:var(--paper);padding:0;text-decoration:none;display:block;
     position:relative;overflow:hidden;box-shadow:0 0 0 1px var(--rule)}
.fam__frame{aspect-ratio:1;overflow:hidden;background:var(--sand);
            display:flex;align-items:center;justify-content:center}
/* the <picture> is the flex item, so the img below sizes against it, not the
   frame — without this it fills only by coincidence of intrinsic sizing */
.fam__frame picture{width:100%;height:100%;display:block}
.fam__frame img{width:100%;height:100%;object-fit:cover;
                transition:transform var(--dur-base) var(--ease-out)}
.fam__ph{font-family:var(--mono);font-size:11px;letter-spacing:.1em;
         text-transform:uppercase;color:var(--muted)}
.fam__body{padding:20px 22px 26px;position:relative}
.fam__name{font-family:var(--serif);font-size:21px;font-weight:600;line-height:1.2;
           margin-block-end:8px}
.fam__orig{font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;
           color:var(--muted);display:block;
           transition:transform var(--dur-base) var(--ease-out),color var(--dur-base) var(--ease-out)}
.fam__arrow{position:absolute;inset-inline-end:22px;inset-block-end:26px;
            transition:transform var(--dur-base) var(--ease-out);color:var(--brick-deep)}
.fam__bar{position:absolute;inset-inline:0;inset-block-end:0;height:2px;background:var(--brick);
          transform:scaleX(0);transform-origin:inline-start;
          transition:transform 320ms var(--ease-out)}
.fam:hover .fam__frame img{transform:scale(1.06)}
.fam:hover .fam__orig{transform:translateY(-6px);color:var(--ink)}
.fam:hover .fam__arrow{transform:translateX(6px)}
.fam:hover .fam__bar{transform:scaleX(1)}

/* ---------- certification strip ---------- */
.certs{display:flex;flex-wrap:wrap;gap:0;border-block:.5px solid var(--rule)}
.cert{flex:1 1 220px;padding:28px 26px;border-inline-end:.5px solid var(--rule)}
.cert:last-child{border-inline-end:0}
.cert__n{font-family:var(--sans);font-weight:500;font-size:17px;color:var(--sap);
         margin-block-end:6px}
.cert__d{font-size:14px;color:var(--muted);margin:0}

/* ---------- spec table ---------- */
.spec{width:100%;border-collapse:collapse;font-size:15px}
.spec th{text-align:start;font-family:var(--mono);font-size:11px;letter-spacing:.12em;
         text-transform:uppercase;color:var(--muted);font-weight:500;
         padding:14px 16px;border-block-end:1px solid var(--brick)}
.spec td{padding:16px;border-block-end:.5px solid var(--rule);vertical-align:top;
         position:relative;transition:background var(--dur-micro) var(--ease-out)}
.spec tbody tr{position:relative}
.spec tbody tr::after{content:"";position:absolute;inset-block:0;inset-inline-start:0;width:2px;
                      background:var(--brick);transform:scaleX(0);transform-origin:inline-start;
                      transition:transform var(--dur-micro) var(--ease-out)}
.spec tbody tr:hover td{background:var(--surface)}
.spec tbody tr:hover::after{transform:scaleX(1)}
.spec td:first-child{font-weight:500}
.spec .mono{font-family:var(--mono);font-size:12.5px;letter-spacing:.06em;color:var(--muted)}
@media(max-width:720px){
  .spec thead{display:none}
  .spec tr{display:block;border-block-end:.5px solid var(--rule);padding-block:12px}
  .spec td{display:block;border:0;padding:4px 0}
}

/* ---------- offices ---------- */
/* same as .fams: six offices leave two cells empty at four columns */
.offs{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:2px;
      overflow:hidden}
.off{background:var(--paper);padding:26px 24px;box-shadow:0 0 0 1px var(--rule)}
.off__role{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
           color:var(--brick-deep);margin-block-end:10px}
.off__city{font-family:var(--serif);font-size:24px;font-weight:600;margin-block-end:4px}
.off__country{font-size:14px;color:var(--muted);margin-block-end:14px}
.off__addr{font-size:14.5px;margin-block-end:10px}
.off__line{font-family:var(--mono);font-size:12.5px;color:var(--muted);display:block}
.off__line a{text-decoration:none}
.off__line a:hover{color:var(--brick-deep)}

/* ---------- form ---------- */
.form{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:18px;
      padding-block-start:56px}
.field{display:flex;flex-direction:column}
.field--full{grid-column:1/-1}
.field label{font-size:13.5px;font-weight:500;margin-block-end:6px}
.field input,.field select,.field textarea{
  font-family:var(--sans);font-size:15px;padding:12px 14px;
  border:.5px solid var(--rule);border-radius:4px;background:var(--surface);color:var(--ink)}
.field textarea{min-height:120px;resize:vertical}
.field .req{color:var(--brick-deep)}
.consent{display:flex;gap:10px;align-items:flex-start;font-size:14px;color:var(--muted)}
/* honeypot: off screen rather than display:none, which some bots skip */
.hp{position:absolute;inset-inline-start:-10000px;inline-size:1px;block-size:1px;overflow:hidden}
/* shown by the #sent / #failed fragment the form handler redirects to */
.notice{display:none;margin:0 0 24px;padding:14px 18px;border-inline-start:3px solid var(--sap);
        background:var(--surface);font-size:15px;scroll-margin-block-start:96px}
.notice--err{border-inline-start-color:var(--brick-deep)}
.notice bdi{white-space:nowrap}
.notice:target{display:block}

/* progressive form: product first, then the essentials, then optional fields
   the visitor adds one chip at a time. CSS only. Without :has() the chips
   would do nothing, so they stay hidden and every field shows instead. */
.picks,.chips{border:0;margin:0;padding:0;min-inline-size:0}
.picks legend,.chips legend,.form__head{font-size:13.5px;font-weight:500;padding:0;margin:0 0 12px}
.form__head{margin-block-start:14px}
.chips legend{color:var(--muted);font-weight:400}
.picks__opts,.chips__opts{display:flex;flex-wrap:wrap;gap:10px}
.pick,.chip{position:relative;cursor:pointer}
.pick input,.chip input{position:absolute;opacity:0;inline-size:1px;block-size:1px;margin:0}
.pick span,.chip span{display:inline-block;padding:11px 18px;border:.5px solid var(--rule);
  border-radius:999px;background:var(--surface);font-size:14.5px;color:var(--ink);
  transition:background-color var(--dur-micro) var(--ease-out),color var(--dur-micro) var(--ease-out),
             border-color var(--dur-micro) var(--ease-out),transform var(--dur-micro) var(--ease-out)}
.pick:hover span,.chip:hover span{border-color:var(--b3-blue)}
.pick:active span,.chip:active span{transform:scale(.97)}
.pick input:checked+span{background:var(--b3-blue);border-color:var(--b3-blue);color:var(--paper)}
.chip span::before{content:"+";font-family:var(--mono);margin-inline-end:8px;color:var(--brick-deep)}
.chip input:checked+span{border-color:var(--sap);color:var(--sap)}
.chip input:checked+span::before{content:"\2713";color:var(--sap)}
.pick input:focus-visible+span,.chip input:focus-visible+span{outline:2px solid var(--brick);outline-offset:3px}
.step{display:contents}
.chips{display:none}
@supports selector(:has(*)){
  .chips{display:block}
  .opt,.step{display:none}
  .form:has([name="product"]:checked) .step{display:contents}
  .form:has(#add-phone:checked) .opt--phone,
  .form:has(#add-quantity:checked) .opt--quantity,
  .form:has(#add-port:checked) .opt--port,
  .form:has(#add-position:checked) .opt--position{display:flex}
}
@media (min-width:900px) and (prefers-reduced-motion:no-preference){
  .step>*,.opt{animation:b3fieldin var(--dur-base) var(--ease-out)}
}
@keyframes b3fieldin{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* ---------- 404 ---------- */
.nf__langs{margin-block-start:28px;font-size:16px;color:var(--muted)}
.nf__langs a{color:var(--b3-blue);font-weight:500}

/* ---------- family sections (products page) ----------
   Anchored from the tiles above and from the home page. scroll-margin keeps
   the sticky header off the heading when the browser jumps to one. */
.pfam{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,2fr);gap:20px 48px;
      padding-block:40px;border-block-start:.5px solid var(--rule);scroll-margin-block-start:96px}
.pfam:first-child{border-block-start:0;padding-block-start:0}
.pfam h2{font-size:clamp(26px,3vw,36px)}
.pfam__body{display:flex;flex-direction:column;gap:18px}
.pfam__meta .lbl{margin-block-end:4px}
.pfam__val{font-family:var(--mono);font-size:13px;color:var(--ink);margin:0}
.pfam__certs{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:8px}
.pfam__certs li{font-size:13.5px;padding:5px 12px;border:.5px solid var(--sap);border-radius:999px;color:var(--sap)}
.pfam__note{font-size:13.5px;color:var(--muted);margin:10px 0 0;max-width:56ch}
.pfam__list{list-style:none;margin:0;padding:0;columns:2 220px;column-gap:32px}
.pfam__list li{padding-block:7px;border-block-end:.5px solid var(--rule);break-inside:avoid;font-size:15.5px}
.pfam__more{margin:0}
.pfam__more a{color:var(--b3-blue);font-weight:500}
@media (max-width:760px){.pfam{grid-template-columns:minmax(0,1fr)}}

/* ---------- ExpressaTech credit ----------
   The designer's snippet, held to this sheet's rules: logical insets, the
   site's motion tokens, transform and opacity the only animated properties.
   The grayscale filter therefore switches rather than fades — the opacity
   fade carries the change. Rest opacity is set for the dark footer, and the
   label stays at .75 so it keeps 4.5:1 against --b3-deep. */
.ftr__credit{display:flex;justify-content:center;margin-block-start:24px;padding-block-start:24px;
             border-block-start:.5px solid rgba(246,244,239,.18)}
.et-credit{display:inline-flex;flex-direction:column;align-items:center;gap:8px;padding:10px 16px;
           text-decoration:none;border-radius:8px;color:var(--sand)}
.et-lbl{font-family:var(--mono);font-size:11px;letter-spacing:.28em;text-transform:uppercase;
        opacity:.75;transition:opacity var(--dur-base) var(--ease-out)}
.et-mark{display:flex;align-items:center;gap:10px}
.et-x,.et-w{position:relative;display:block;line-height:0}
.et-x img{inline-size:34px;block-size:auto}
.et-w img{inline-size:clamp(150px,16vw,190px);block-size:auto}
.et-mark img{filter:grayscale(1) contrast(.85);opacity:.45;
  transition:opacity var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out)}
/* the X's flash */
.et-x::after{content:"";position:absolute;inset:-25%;border-radius:50%;
  background:radial-gradient(circle,var(--et-white) 0 6%,var(--et-cyan) 14%,transparent 46%),
    conic-gradient(from 0deg,transparent 0 40deg,var(--et-ray) 45deg,transparent 50deg 130deg,
      var(--et-ray) 135deg,transparent 140deg 220deg,var(--et-ray) 225deg,transparent 230deg 310deg,
      var(--et-ray) 315deg,transparent 320deg);
  opacity:0;transform:scale(.2);pointer-events:none;mix-blend-mode:screen}
/* the light that crosses the wordmark; .et-mark is dir="ltr", so inline-start is the left */
.et-w{overflow:hidden}
.et-w::after{content:"";position:absolute;inset-block:-20%;inset-inline-start:-40%;inline-size:30%;
  background:linear-gradient(100deg,transparent,var(--et-white) 45%,var(--et-sweep) 55%,transparent);
  transform:skewX(-18deg) translateX(-200%);opacity:0;pointer-events:none;mix-blend-mode:screen}
.et-credit:hover .et-lbl,.et-credit:focus-visible .et-lbl{opacity:1}
.et-credit:hover .et-mark img,.et-credit:focus-visible .et-mark img{filter:none;opacity:1}
.et-credit:hover .et-x img,.et-credit:focus-visible .et-x img{transform:scale(1.08)}
@media (prefers-reduced-motion:no-preference){
  .et-credit:hover .et-x::after,.et-credit:focus-visible .et-x::after{
    animation:b3etflash var(--dur-reveal) var(--ease-out) both}
  .et-credit:hover .et-w::after,.et-credit:focus-visible .et-w::after{
    animation:b3etsweep var(--dur-hero) var(--ease-out) 150ms both}
}
@keyframes b3etflash{
  0%{opacity:0;transform:scale(.2) rotate(0)}
  35%{opacity:1;transform:scale(1.1) rotate(25deg)}
  100%{opacity:0;transform:scale(1.5) rotate(45deg)}}
@keyframes b3etsweep{
  0%{opacity:1;transform:skewX(-18deg) translateX(-200%)}
  100%{opacity:1;transform:skewX(-18deg) translateX(560%)}}
@media (hover:none){.et-mark img{opacity:.6}}
@media (max-width:520px){.et-x img{inline-size:28px}.et-w img{inline-size:150px}}

/* ---------- footer ---------- */
.ftr{background:var(--b3-deep);color:var(--paper);padding-block:64px 32px}
.ftr a{text-decoration:none}
.ftr__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
           gap:36px;padding-block-end:40px}
.ftr h4{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
        color:var(--sand);margin:0 0 14px;font-weight:500}
.ftr ul{list-style:none;margin:0;padding:0}
.ftr li{margin-block-end:9px;font-size:14px}
.ftr li a:hover{color:var(--sand)}
.ftr__legal{border-block-start:.5px solid rgba(246,244,239,.18);padding-block-start:24px;
            display:flex;flex-wrap:wrap;gap:16px;justify-content:space-between;
            font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--sand)}

/* ---------- CTA band ---------- */
.cta{background:var(--b3-blue);color:var(--paper);padding-block:clamp(56px,8vw,96px)}
.cta__in{display:flex;flex-wrap:wrap;gap:28px;align-items:center;justify-content:space-between}
.cta h2{color:var(--paper);max-width:18ch}

/* ---------- map ---------- */
.map{position:relative}
.map__mark{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
           pointer-events:none;opacity:.035}
.map__mark img{width:min(900px,90%)}
