/* DRP BuildLab — stylesheet. Shared by every page; edit here, not per page. */
/* ─────────────────────────────────────────────
   RESET & BASE
───────────────────────────────────────────── */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;font-size:16px}
body{
  /* Black, not white, and not because the hero is black -- because both ends
     of every page are. Every page opens on a dark section and every page ends
     on the dark footer, so the only places this colour is ever seen are the
     overscroll at the top and the bottom, where a white band above a black
     hero is the page appearing to come apart in your hands. It was #fff from
     when the site was a white site. */
  background:#000;
  color:#1a1f36;
  font-family:'Plus Jakarta Sans',sans-serif;
  font-weight:400;
  line-height:1.65;
  overflow-x:hidden;
}
a{text-decoration:none;color:inherit}

/* A6 — the site had zero focus rings in 700 lines of CSS */
:focus-visible{outline:2px solid var(--blue-d);outline-offset:3px}
::-webkit-scrollbar{width:2px}
::-webkit-scrollbar-track{background:#fff}
::-webkit-scrollbar-thumb{background:#4a90e2}

/* ─────────────────────────────────────────────
   TOKENS
───────────────────────────────────────────── */
:root{
  --bg:#ffffff;
  --bg2:#f5f7fc;
  --bg3:#ebeff8;
  /* The alternate ground. Warm, where --bg2 and --bg3 are blue-tinted,
     because its job is to be a different ground rather than a paler version
     of the same one -- two cool near-whites read as a printing fault, one
     cool and one warm reads as two surfaces. Only .sec-alt uses it. */
  --bone:#f4f2eb;
  --ink:#1a1f36;
  --ink2:#2d3454;
  --blue:#4a90e2;
  --blue-d:#2e74c9;
  --blue-dd:#245ca6;
  --blue-l:#7ab3ed;
  /* Blue set as TEXT, which is a different job from blue as a brand colour.
     --blue is 2.94:1 on bone and --blue-d is 4.21, both short of 4.5 for the
     small caps labels it was used for. This one clears it on every light
     ground; .dark swaps it for the light blue, as it does for --blue. */
  --blue-t:#245ca6;
  /* Mixed to clear 4.5:1 on the *worst* light ground, which is bone, not
     white -- at .62 and .45 these measured 4.45 and 2.73 on it. */
  --muted:rgba(26,31,54,.70);
  --muted2:rgba(26,31,54,.64);
  --line:rgba(26,31,54,.09);
  --line-b:rgba(74,144,226,.2);
}

/* ─────────────────────────────────────────────
   SCROLL PROGRESS
───────────────────────────────────────────── */
#sprog{
  position:fixed;top:0;left:0;height:2px;
  background:var(--blue);z-index:9999;
  width:0;transform-origin:left;
  transition:width .05s linear;
}

/* ─────────────────────────────────────────────
   LOADER

   Once per session, 400ms, then it lifts.

   It used to be white, because the hero used to be white. The hero is solid
   black now, so a white curtain over it meant the first thing a visitor saw
   was a full-screen white flash that snapped to black — the single worst
   frame on the site, on the one page view where first impressions are the
   whole point. It is the ground it covers now, so the lift is a curtain
   rising on a page that was already there rather than a change of scene.

   Square, not rounded: 39-editorial.css rounds actions and squares
   everything else, and a splash mark is not something you press.
───────────────────────────────────────────── */
#loader{
  position:fixed;inset:0;z-index:10000;
  background:#000;
  display:flex;align-items:center;justify-content:center;
  transition:opacity .6s ease .1s, visibility .6s ease .1s;
  /* A1 — hides itself even if the JS that removes it never runs */
  animation:loaderFailsafe 0s linear 3s forwards;
}
@keyframes loaderFailsafe{to{opacity:0;visibility:hidden;pointer-events:none}}
#loader.gone{opacity:0;visibility:hidden}
.ld-inner{display:flex;flex-direction:column;align-items:center;gap:8px}
.ld-mark{
  width:64px;height:64px;background:var(--blue-d);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:2px;
  opacity:0;transform:scale(.8);
  animation:ldPop .5s cubic-bezier(.16,1,.3,1) .2s forwards;
}
.ld-drp{font-size:1.4rem;font-weight:800;color:#fff;letter-spacing:-.02em;line-height:1}
.ld-bl{font-size:.38rem;font-weight:700;color:rgba(255,255,255,.8);letter-spacing:.12em;text-transform:uppercase}
.ld-name{
  font-size:.72rem;font-weight:700;letter-spacing:.24em;text-transform:uppercase;
  /* The muted tokens are mixed for ink on paper; this sits on black. */
  color:rgba(255,255,255,.55);
  opacity:0;animation:ldUp .4s ease .5s forwards;
}
.ld-bar{
  width:48px;height:1.5px;background:rgba(255,255,255,.16);overflow:hidden;
  opacity:0;animation:ldUp .3s ease .6s forwards;margin-top:4px;
}
.ld-fill{height:100%;background:var(--blue);width:0;animation:ldFill 1.1s ease .7s forwards}
@keyframes ldPop{to{opacity:1;transform:scale(1)}}
@keyframes ldUp{to{opacity:1;transform:none}}
@keyframes ldFill{to{width:100%}}

/* The curtain is the only thing that moves for a reader who asked for no
   motion: the mark still lands, the bar still fills, and both are animations.
   31-reduced-motion.css collapses every duration to .01ms, which leaves this
   correct but instant — the loader appears fully drawn and then goes. That is
   the right outcome and it needs no rule of its own; this note exists so the
   next person does not "fix" it. */

/* ─────────────────────────────────────────────
   NAV
───────────────────────────────────────────── */
nav{
  position:fixed;top:0;left:0;right:0;z-index:500;
  padding:1.4rem 5vw;
  display:flex;justify-content:space-between;align-items:center;
  transition:padding .4s ease, background .5s ease, box-shadow .4s ease;
}
nav.s{
  background:rgba(255,255,255,.95);
  backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
  padding:1rem 5vw;
  box-shadow:0 1px 0 var(--line);
}
.nlogo{display:flex;align-items:center;gap:.7rem}
.nmark{
  width:32px;height:32px;background:var(--blue);border-radius:6px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:1px;flex-shrink:0;
}
.nmark-drp{font-size:.72rem;font-weight:800;color:#fff;letter-spacing:-.01em;line-height:1}
.nmark-bl{font-size:.32rem;font-weight:700;color:rgba(255,255,255,.75);letter-spacing:.1em}
.nname{font-size:.92rem;font-weight:800;letter-spacing:-.02em;color:var(--ink)}
.nlinks{display:flex;align-items:center;gap:2rem}
.nlinks a{font-size:.8rem;font-weight:500;color:var(--muted);transition:color .2s;position:relative}
.nlinks a::after{content:'';position:absolute;bottom:-2px;left:0;width:0;height:1px;background:var(--blue);transition:width .3s ease}
.nlinks a:hover{color:var(--ink)}
.nlinks a:hover::after{width:100%}
/* C4 — scrollspy */
.nlinks a.active{color:var(--ink)}
.nlinks a.active::after{width:100%}
.nig svg{width:14px;height:14px}
.nig{display:inline-flex;align-items:center;gap:.35rem}

/* ─────────────────────────────────────────────
   HERO  — split top/bottom layout (Rejouice)
───────────────────────────────────────────── */
.hero{
  min-height:100vh;
  display:flex;flex-direction:column;
  justify-content:space-between;
  padding:6.5rem 5vw 4.5rem;
  position:relative;overflow:hidden;
  background:var(--bg);
}
/* Eye — top anchor, always below nav */
/* Content — bottom anchor */
.hero-content{position:relative;z-index:2;width:100%}
.hero-h1{
  font-size:clamp(3.6rem,8.2vw,8.2rem);
  font-weight:800;line-height:.9;letter-spacing:-.04em;
  color:var(--ink);
  transform-origin:bottom left;
}
.hl{
  display:block;overflow:hidden;line-height:.92;
  /* Padding prevents top/bottom character clipping */
  padding:0.06em 0.06em 0.12em;
  margin:-0.06em -0.06em -0.12em;
}
.hl-i{
  display:block;transform:translateY(110%);
  animation:none;
}
.hl-i.in{
  animation:hlIn .85s cubic-bezier(.16,1,.3,1) forwards;
}
.hl-i.d1{animation-delay:.08s}
.hl-i.d2{animation-delay:.18s}
@keyframes hlIn{to{transform:translateY(0)}}
.h-accent{color:var(--blue-t)}
.h-light{font-style:italic;font-weight:300;color:var(--muted)}
.hero-foot{
  display:flex;align-items:flex-end;justify-content:space-between;
  gap:2rem;flex-wrap:wrap;margin-top:2.5rem;
  opacity:0;animation:tUp .8s cubic-bezier(.16,1,.3,1) 2s forwards;
}
.hero-acts{display:flex;gap:1rem;flex-wrap:wrap;align-items:center}
/* Logo float — right side, vertically centered in lower half */
.hero-logomark{
  position:absolute;right:6vw;bottom:18%;
  z-index:2;
  opacity:0;animation:tUp 1s cubic-bezier(.16,1,.3,1) 1.8s forwards;
}
.hero-logomark svg{
  width:130px;height:130px;
  filter:drop-shadow(0 20px 50px rgba(74,144,226,.22));
}
/* Scroll hint */
.shint{
  position:absolute;bottom:2.2rem;left:50%;transform:translateX(-50%);
  z-index:2;display:flex;flex-direction:column;align-items:center;gap:.45rem;
  opacity:0;animation:tUp .7s ease 2.2s forwards;
}
.shint span{font-size:.58rem;font-weight:700;letter-spacing:.26em;text-transform:uppercase;color:var(--muted2)}
.shint-line{width:1px;height:38px;background:linear-gradient(to bottom,var(--blue),transparent);animation:shAnim 2.2s ease-in-out infinite}
@keyframes shAnim{
  0%{transform:scaleY(0);transform-origin:top}
  45%{transform:scaleY(1);transform-origin:top}
  46%{transform-origin:bottom}
  100%{transform:scaleY(0);transform-origin:bottom}
}
@keyframes tUp{from{opacity:0;transform:translateY(26px)}to{opacity:1;transform:translateY(0)}}

/* ─────────────────────────────────────────────
   SHARED SECTION
───────────────────────────────────────────── */
/* The ground, declared. This was padding only: .sec leaned on the body being
   white, which it was until the body was blacked to stop the overscroll
   flashing white above a black hero. Every plain section then went black with
   ink text on it -- 1.1:1, invisible. A section paints its own ground now, so
   the body colour is only ever seen where it should be: past either end. */
.sec{padding:6.5rem 5vw;background:var(--bg)}
/* ── The alternate ground ────────────────────────────────────────
   This class did nothing for most of the site's life: it was
   background:var(--bg), and --bg is #ffffff, so every "alternating" section
   was the same flat white as the one before it, separated by a hairline.
   The page went slack after the hero because the light half of it was one
   uninterrupted sheet.

   It alternates now. The mechanism is 37-dark.css's rather than a new one:
   the section redefines the surface tokens instead of restyling what sits
   on it, so every panel inside picks up a ground that suits the new one
   with no per-component rules. --bg2 is the tint that lifts a panel off
   white, so on bone it becomes white and panels lift the other way.

   --bg is deliberately left alone. The cards that use it -- the pricing
   columns, the extras, the about figures, the partner terms -- are white
   panels, and white is exactly what they should stay on bone. Redefining
   it here would have painted them bone-on-bone and made them vanish. */
.sec-alt{
  background:var(--bone);
  --bg2:#ffffff;
  --bg3:#efeade;
  --line:rgba(46,38,24,.13);
}
/* C4 — anchor jumps land below the fixed nav, not underneath it */
section[id]{scroll-margin-top:90px}
/* Thin rule separates sections without heavy color change */
.sec+.sec,.sec+.sec-alt,.sec-alt+.sec,.sec-alt+.sec-alt{
  border-top:1px solid var(--line);
}
.stag{display:block;font-size:.6rem;font-weight:700;letter-spacing:.28em;text-transform:uppercase;color:var(--blue-t);margin-bottom:.85rem}
.sh{
  font-size:clamp(2.6rem,5.5vw,5.5rem);
  font-weight:800;line-height:1.0;letter-spacing:-.038em;color:var(--ink);
  margin-bottom:1.5rem;
}
.sh em{font-style:italic;font-weight:300;color:var(--muted)}
.ssub{font-size:.96rem;color:var(--muted);line-height:1.85;max-width:480px}

/* Page header — the pages that are not the home hero still need an h1 */
.phero{padding:9.5rem 5vw 3.75rem;border-bottom:1px solid var(--line)}
.phero-h1{margin-bottom:0}
.phero-sub{margin-top:1.15rem;max-width:620px}

/* Closing CTA — sends people to the contact page from any other page */
.ctastrip{padding:6.5rem 5vw;text-align:center;border-top:1px solid var(--line)}
.ctastrip .sh{margin-bottom:0}
.ctastrip .ssub{margin:1.15rem auto 2.1rem;max-width:560px}
@media(max-width:700px){
  .phero{padding:7.5rem 6vw 2.75rem}
  .ctastrip{padding:4.5rem 6vw}
}

/* ─────────────────────────────────────────────
   REVEAL SYSTEM
───────────────────────────────────────────── */
.rv{opacity:0;transform:translateY(32px);transition:opacity .85s cubic-bezier(.16,1,.3,1),transform .85s cubic-bezier(.16,1,.3,1)}
.rv.vv{opacity:1;transform:none}
.rv.fl{transform:translateX(-32px)}.rv.fl.vv{transform:none}
.rv.fr{transform:translateX(32px)}.rv.fr.vv{transform:none}
/* Scale-in reveal */
.rv.si{transform:scale(.93) translateY(16px)}.rv.si.vv{transform:none}
.d1{transition-delay:.1s}.d2{transition-delay:.2s}.d3{transition-delay:.3s}.d4{transition-delay:.42s}.d5{transition-delay:.54s}

/* ─────────────────────────────────────────────
   BUTTONS
───────────────────────────────────────────── */
.btn{
  display:inline-flex;align-items:center;gap:.5rem;
  padding:.88rem 2rem;font-family:inherit;font-size:.88rem;font-weight:700;
  border:none;transition:all .25s;
  position:relative;overflow:hidden;
}
.btn-p{background:var(--blue-d);color:#fff;box-shadow:0 8px 24px rgba(74,144,226,.28)}
.btn-p:hover{background:var(--blue-dd);transform:translateY(-2px);box-shadow:0 14px 36px rgba(74,144,226,.42)}
.btn-g{background:transparent;color:var(--ink);border:1.5px solid var(--line)}
.btn-g:hover{border-color:var(--blue-t);color:var(--blue-t);background:rgba(74,144,226,.05)}

/* ─────────────────────────────────────────────
   PROCESS
───────────────────────────────────────────── */
.proc-head{display:flex;justify-content:space-between;align-items:flex-end;margin-bottom:5rem;flex-wrap:wrap;gap:2rem}
.steps{display:flex;flex-direction:column}
.srow{
  display:grid;grid-template-columns:68px 1fr 100px;gap:2.5rem;align-items:start;
  padding:2.4rem 0;border-bottom:1px solid var(--line);
  position:relative;overflow:hidden;
}
.srow:first-child{border-top:1px solid var(--line)}
.srow::before{
  content:'';position:absolute;left:0;top:0;bottom:0;width:0;
  background:rgba(74,144,226,.05);
  transition:width .6s cubic-bezier(.16,1,.3,1);z-index:0;
}
.srow:hover::before{width:100%}
.sn{font-size:.58rem;font-weight:700;letter-spacing:.22em;color:var(--blue-t);text-transform:uppercase;padding-top:.3rem;position:relative;z-index:1}
.sbody{position:relative;z-index:1}
.stitle{font-size:clamp(1.05rem,2vw,1.5rem);font-weight:700;letter-spacing:-.02em;margin-bottom:.45rem;color:var(--ink)}
.stxt{font-size:.86rem;color:var(--muted);line-height:1.85;max-width:460px}
.stime{font-size:.58rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--blue-t);opacity:.45;text-align:right;padding-top:.35rem;position:relative;z-index:1}

/* ─────────────────────────────────────────────
   ABOUT
───────────────────────────────────────────── */
.ab-layout{display:grid;grid-template-columns:1fr 1fr;gap:9rem;align-items:center}
.ab-layout>*{min-width:0}
/* Smooth logo integration */
.ab-logo-wrap{
  margin-bottom:3rem;
  display:inline-flex;align-items:center;gap:1.2rem;
  padding:1.5rem 2rem;
  background:var(--bg2);border:1px solid var(--line);
  border-radius:12px;
}
.ab-logo-wrap svg{width:72px;height:72px;border-radius:10px;flex-shrink:0}
.ab-logo-text{display:flex;flex-direction:column}
.ab-logo-name{font-size:1.3rem;font-weight:800;letter-spacing:-.025em;color:var(--ink)}
.ab-logo-tag{font-size:.62rem;font-weight:700;letter-spacing:.2em;text-transform:uppercase;color:var(--blue-t);margin-top:.1rem}
.ab-quote{font-size:clamp(1.3rem,2.2vw,2.2rem);font-weight:700;line-height:1.2;letter-spacing:-.025em;margin-bottom:1.25rem;color:var(--ink)}
.ab-quote em{font-style:italic;font-weight:300;color:var(--blue-t)}
.ab-sig{font-size:.62rem;font-weight:700;letter-spacing:.2em;text-transform:uppercase;color:var(--muted)}
/* minmax(0,1fr), not 1fr. A bare 1fr floors each column at its content's
   min-content width, and in a market that converts, the content is a figure
   with no space in it -- Rp8.500.000, ¥82,000, $470.000. The column refused
   to go below that figure's width and the grid grew wider than the page,
   which put a horizontal scrollbar on the About page in Indonesian between
   about 500 and 620px. With a zero floor the columns shrink and the label
   wraps instead. */
.ab-nums{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px;background:var(--line);border:1px solid var(--line);margin-top:2.5rem}
.abn{background:var(--bg);padding:1.6rem 1.8rem}
.abn-v{font-size:clamp(1.45rem,6.5vw,2.5rem);font-weight:800;letter-spacing:-.04em;color:var(--blue-t);line-height:1;margin-bottom:.2rem}
.abn-l{font-size:.68rem;color:var(--muted)}
.ab-right p{font-size:.92rem;color:var(--muted);line-height:1.9;margin-bottom:1.35rem}
.ab-right p strong{color:var(--ink);font-weight:700}
.pillars{display:flex;flex-direction:column;margin-top:2rem}
.pillar{display:flex;gap:1.4rem;padding:1.3rem 0;border-bottom:1px solid var(--line)}
.pillar>*{min-width:0}
.pillar:first-child{border-top:1px solid var(--line)}
.pn{font-size:.58rem;font-weight:700;color:var(--blue-t);letter-spacing:.1em;flex-shrink:0;padding-top:.12rem}
.ptitle{font-weight:700;font-size:.88rem;margin-bottom:.18rem;color:var(--ink)}
.pbody{font-size:.8rem;color:var(--muted);line-height:1.72}

/* ─────────────────────────────────────────────
   WHY
───────────────────────────────────────────── */
.wgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--line);border:1px solid var(--line);margin-top:5rem}
.wcard{
  background:var(--bg);padding:2.5rem;position:relative;overflow:hidden;
  transition:background .3s;
}
.wcard::after{content:'';position:absolute;bottom:0;left:0;right:0;height:2px;background:var(--blue);transform:scaleX(0);transform-origin:left;transition:transform .45s cubic-bezier(.16,1,.3,1)}
.wcard:hover{background:var(--bg2)}
.wcard:hover::after{transform:scaleX(1)}
.wico{width:40px;height:40px;background:rgba(74,144,226,.08);border-radius:7px;display:flex;align-items:center;justify-content:center;margin-bottom:1.2rem}
.wico svg{width:19px;height:19px;color:var(--blue-t)}
.wtitle{font-size:.96rem;font-weight:700;margin-bottom:.42rem;letter-spacing:-.01em;color:var(--ink)}
.wbody{font-size:.82rem;color:var(--muted);line-height:1.78}

/* ─────────────────────────────────────────────
   OPPORTUNITY COST
───────────────────────────────────────────── */
.opp-layout{display:grid;grid-template-columns:1fr 1fr;gap:8rem;align-items:start}
.opp-layout>*{min-width:0}
.opp-box{
  background:var(--bg2);border:1px solid var(--line-b);padding:3rem;
  position:relative;
}
.opp-box::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--blue),transparent)}
.orow{display:flex;justify-content:space-between;align-items:center;padding:.82rem 0;border-bottom:1px solid var(--line);gap:1rem}
.orow:last-child{border-bottom:none}
.olbl{font-size:.83rem;color:var(--muted)}
.oval{font-size:.92rem;font-weight:700;color:var(--ink)}
.oval.n{color:#dc2626}
.oval.p{color:#16a34a}
.ototl{margin-top:1.5rem;padding-top:1.5rem;border-top:1px solid var(--line-b);display:flex;justify-content:space-between;align-items:baseline}
.otlbl{font-size:.58rem;font-weight:700;letter-spacing:.22em;text-transform:uppercase;color:var(--muted)}
.otval{font-size:2rem;font-weight:800;color:var(--blue-t);letter-spacing:-.035em}
.onote{margin-top:1.5rem;padding:1.15rem 1.4rem;background:var(--bg3);border-left:2.5px solid var(--blue);font-size:.82rem;color:var(--muted);line-height:1.75}
.onote strong{color:var(--ink);font-weight:700}
.opoints{display:flex;flex-direction:column}
.opt{display:flex;gap:1.25rem;padding:1.3rem 0;border-bottom:1px solid var(--line)}
.opt:first-child{border-top:1px solid var(--line)}
.opt-title{font-weight:700;font-size:.88rem;margin-bottom:.18rem;color:var(--ink)}
.opt-body{font-size:.8rem;color:var(--muted);line-height:1.7}
.opt-marker{width:6px;height:6px;border-radius:50%;background:var(--blue);flex-shrink:0;margin-top:.45rem}

/* ─────────────────────────────────────────────
   COMPETITORS
───────────────────────────────────────────── */
.ctbl{width:100%;margin-top:5rem;border:1px solid var(--line);overflow:hidden}
/* On bone the table becomes a white panel with a recessed header, rather
   than a transparent grid whose header is the only thing lifted. The hover
   has to move with it: --bg2 is white here, which is the panel it would be
   highlighting against. */
.sec-alt .ctbl{background:#fff}
.sec-alt .chd{background:var(--bg3)}
.sec-alt .crow:hover{background:var(--bg3)}
.chd{display:grid;grid-template-columns:2fr 1.2fr 1.2fr 1fr;background:var(--bg2);border-bottom:1px solid var(--line)}
.crow{display:grid;grid-template-columns:2fr 1.2fr 1.2fr 1fr;border-bottom:1px solid var(--line);transition:background .25s}
.crow:last-child{border-bottom:none}
.crow:hover{background:var(--bg2)}
.crow.us{background:rgba(74,144,226,.05);border-left:2.5px solid var(--blue)}
.crow.us:hover{background:rgba(74,144,226,.1)}
.chc{padding:.72rem 1.1rem;font-size:.58rem;font-weight:700;letter-spacing:.24em;text-transform:uppercase;color:var(--muted);border-right:1px solid var(--line);display:flex;align-items:center;min-width:0}
.chc:last-child{border-right:none}
.cc{padding:1.1rem 1.1rem;font-size:.83rem;display:flex;align-items:center;border-right:1px solid var(--line);min-width:0;overflow-wrap:break-word}
.cc:last-child{border-right:none}
/* Flex items default to min-width:auto, so min-width:0 on .cc alone did not
   let a long price shrink -- it stayed at its min-content width, declared
   itself clipped, and sent fitTable() into its pinned-and-scrolling mode.
   Rp 16.417.744-Rp 51.305.449 needs to be allowed to wrap. */
.cc>*,.chc>*{min-width:0;overflow-wrap:anywhere}
.cnm{font-weight:700;color:var(--ink)}
.cnm.u{color:var(--blue-t)}
.cbdg{display:inline-block;background:var(--blue-d);color:#fff;font-size:.52rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;padding:.14rem .48rem;margin-left:.45rem;border-radius:2px;vertical-align:middle}
.ck{color:#16a34a;font-weight:700}
.cx{color:var(--muted2)}
.cp{font-weight:700;color:var(--ink)}
.cp.g{color:var(--blue-t)}
.cp.b{color:var(--muted2)}
.cnote{margin-top:1.5rem;padding:1.1rem 1.4rem;background:var(--bg2);border:1px solid var(--line-b);font-size:.82rem;color:var(--muted);line-height:1.78}
.cnote strong{color:var(--ink)}

/* ─────────────────────────────────────────────
   PRICING
───────────────────────────────────────────── */
.pgrid{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;background:var(--line);border:1px solid var(--line);margin-top:5rem}
.pgrid>*{min-width:0}
.plan{background:var(--bg);padding:3rem 2.5rem;position:relative;transition:background .3s}
.plan:hover{background:var(--bg2)}
.plan.feat{background:var(--bg2);border:1px solid var(--line-b);box-shadow:0 0 50px rgba(74,144,226,.08);margin:-1px;z-index:1}
.pbadge{display:inline-block;background:var(--blue-d);color:#fff;font-size:.56rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;padding:.24rem .72rem;margin-bottom:1.5rem}
.pname{font-size:.6rem;font-weight:700;letter-spacing:.24em;text-transform:uppercase;color:var(--muted);margin-bottom:.7rem}
.pprice{font-size:3.5rem;font-weight:800;letter-spacing:-.04em;line-height:1;margin-bottom:.2rem;color:var(--ink)}
.pprice sup{font-size:1.2rem;vertical-align:super;font-weight:600}
.pperiod{font-size:.8rem;color:var(--muted);margin-bottom:2rem;padding-bottom:1.4rem;border-bottom:1px solid var(--line)}
.pfeats{list-style:none;margin-bottom:2rem}
.pfeats li{font-size:.83rem;color:rgba(26,31,54,.65);padding:.4rem 0;display:flex;align-items:flex-start;gap:.6rem;border-bottom:1px solid rgba(26,31,54,.05)}
.pfeats li::before{content:'✓';color:var(--blue-t);font-weight:700;flex-shrink:0}
.pbtn{display:block;text-align:center;padding:.88rem;font-size:.84rem;font-weight:700;letter-spacing:.03em;transition:all .25s}
.pbtn.f{background:var(--blue-d);color:#fff;box-shadow:0 6px 20px rgba(74,144,226,.26)}
.pbtn.f:hover{background:var(--blue-dd);box-shadow:0 10px 32px rgba(74,144,226,.4)}
.pbtn.o{border:1.5px solid var(--line);color:var(--ink)}
.pbtn.o:hover{border-color:var(--blue-t);color:var(--blue-t);background:rgba(74,144,226,.05)}
.exgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--line);border:1px solid var(--line);margin-top:1.4rem}
.ex{background:var(--bg);padding:1.2rem 1.4rem;display:flex;justify-content:space-between;align-items:center;gap:.9rem;transition:background .25s}
.ex:hover{background:var(--bg2)}
/* Grid items keep min-width:auto -- their min-content width -- and the label
   here is a flex item beside a price that never shrinks. A long word or a long
   converted price ("Auf Anfrage", "Rp 3.034.342") therefore propped the whole
   grid open, making sixteen pricing pages up to 148px wider than the screen
   between 769px and 900px. Let the cell shrink and the label wrap instead. */
.exgrid>*{min-width:0}
/* hyphens:auto breaks a long word where the language allows, in browsers that
   carry a dictionary for it (Safari, Firefox, Chrome on Mac and Android).
   Chrome and Edge on Windows carry none, so a word that must break there does
   so at a soft hyphen in the copy -- German "hinzu&shy;fügen" -- or, failing
   that, anywhere (overflow-wrap). */
.ex-n{font-size:.83rem;color:var(--muted);line-height:1.45;min-width:0;overflow-wrap:break-word;hyphens:auto;-webkit-hyphens:auto}
.ex-p{font-size:.86rem;font-weight:700;color:var(--blue-t);flex-shrink:0}
/* C2 — 11 items in a 4-col grid: the closer spans 2 so the last row is flush */
.ex-wide{grid-column:span 2}
/* Footer social row — three links now, so let them wrap on narrow screens */
.ft-socials{display:flex;align-items:center;gap:1.4rem;flex-wrap:wrap}
.ft-follow{font-size:.7rem;font-weight:700;letter-spacing:.18em;text-transform:uppercase;color:rgba(255,255,255,.55)}
.addon>*{min-width:0}
.addon{
  margin-top:1.6rem;border:1px solid var(--line);background:var(--bg2);
  padding:1.6rem 1.8rem;display:flex;justify-content:space-between;
  align-items:center;gap:1.6rem;flex-wrap:wrap;
}
.addon-tag{font-size:.6rem;font-weight:700;letter-spacing:.24em;text-transform:uppercase;color:var(--blue-t);display:block;margin-bottom:.5rem}
.addon-n{font-size:1.15rem;font-weight:800;letter-spacing:-.02em;color:var(--ink)}
.addon-b{font-size:.84rem;color:var(--ink2);line-height:1.6;margin-top:.45rem;max-width:520px}
.addon-r{display:flex;align-items:baseline;gap:.9rem;flex-shrink:0;flex-wrap:wrap;min-width:0}
.addon-p{font-size:clamp(1.1rem,5vw,1.5rem);font-weight:800;letter-spacing:-.03em;color:var(--blue-t);white-space:nowrap}
.addon-p span{font-size:.78rem;font-weight:600;color:var(--ink2);letter-spacing:0}
.addon-or{font-size:.72rem;color:var(--muted);text-transform:uppercase;letter-spacing:.16em}

/* ─────────────────────────────────────────────
   SOCIAL
───────────────────────────────────────────── */
.soc-sec{background:var(--bone);padding:8rem 5vw;display:grid;grid-template-columns:1fr 1fr;gap:7rem;align-items:center}
.soc-card{
  position:relative;aspect-ratio:1;max-width:400px;
  background:var(--blue);border-radius:18px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:.4rem;overflow:hidden;
  box-shadow:0 32px 80px rgba(74,144,226,.25);
}
.soc-card::before{content:'';position:absolute;inset:0;background:radial-gradient(ellipse at 40% 35%,rgba(255,255,255,.15) 0%,transparent 65%)}
.soc-big{font-size:6rem;font-weight:800;letter-spacing:-.04em;color:#fff;line-height:1;position:relative;z-index:1}
.soc-sub{font-size:1rem;font-weight:700;letter-spacing:.28em;text-transform:uppercase;color:rgba(255,255,255,.8);position:relative;z-index:1}
/* .soc-text IS the paragraph. The old rule was `.ig-text p`, a descendant
   selector that matched nothing at all, so both paragraphs here rendered
   with browser defaults: full-strength colour, tight leading, no gap. */
.soc-text{font-size:.92rem;color:var(--muted);line-height:1.9;margin-bottom:1.3rem}
/* A converted price can be far longer than the euro figure the columns were
   sized for -- "Rp 8.535.395" against "€499". When that happens the table
   scrolls sideways instead of clipping, since the figures are the whole point
   of it. locale.js measures the columns and sets these, and only adds
   .scrolls when the content genuinely does not fit, so the euro layout is
   untouched. Every row gets the same explicit template, which is what keeps
   the columns aligned once they stop being fr-proportional. */
.ctbl.scrolls{overflow-x:auto;-webkit-overflow-scrolling:touch}
.ctbl.scrolls .chd,.ctbl.scrolls .crow{
  grid-template-columns:var(--c1) var(--c2) var(--c3);
  min-width:max-content;
}
.ctbl.scrolls .cc,.ctbl.scrolls .chc{white-space:nowrap}
.ctbl.measuring .cc,.ctbl.measuring .chc{white-space:nowrap}

/* Wraps rather than overflows: three buttons do not fit one line on a phone. */
.soc-links{display:flex;flex-wrap:wrap;gap:.7rem;margin-top:.4rem}
.soc-link{
  display:inline-flex;align-items:center;gap:.7rem;
  border:1.5px solid var(--line-b);color:var(--ink);
  padding:.88rem 1.7rem;font-size:.86rem;font-weight:600;
  transition:all .25s;
}
.soc-link:hover{background:var(--blue);color:#fff;border-color:var(--blue-t);box-shadow:0 8px 26px rgba(74,144,226,.28)}
.soc-link svg{width:18px;height:18px}

/* ─────────────────────────────────────────────
   CONTACT
───────────────────────────────────────────── */
.ct-layout{display:grid;grid-template-columns:1fr 1fr;gap:8rem;align-items:start}
.ct-layout>*{min-width:0}
.ct-lede{font-size:.92rem;color:var(--muted);line-height:1.9;margin-top:1.1rem;margin-bottom:2rem}
.ct-items{display:flex;flex-direction:column}
.ct-item{display:flex;gap:1.2rem;align-items:flex-start;padding:1.2rem 0;border-bottom:1px solid var(--line)}
.ct-item:first-child{border-top:1px solid var(--line)}
.ci-ico{color:var(--blue-t);flex-shrink:0;margin-top:.1rem}
.ci-lbl{font-size:.58rem;font-weight:700;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);margin-bottom:.22rem}
.ci-val{font-size:.88rem;color:var(--ink)}
.ci-val a{color:var(--blue-t)}
.fwrap{background:var(--bg2);border:1px solid var(--line);padding:3rem;position:relative}
.fwrap::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,var(--blue-d),var(--blue-l))}
.frow{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
.field{display:flex;flex-direction:column;gap:.38rem;margin-bottom:.9rem}
.field label{font-size:.58rem;font-weight:700;letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
.field input,.field select,.field textarea{
  background:#fff;border:1px solid var(--line);color:var(--ink);
  padding:.82rem 1rem;font-family:inherit;font-size:.88rem;
  outline:none;transition:border-color .25s,box-shadow .25s;width:100%;appearance:none;
}
.field input:focus,.field select:focus,.field textarea:focus{border-color:rgba(74,144,226,.38);box-shadow:0 0 0 3px rgba(74,144,226,.06)}
.field input::placeholder,.field textarea::placeholder{color:var(--muted2)}
.field select option{background:#fff;color:var(--ink)}
.field textarea{min-height:96px;resize:none}
.fsubmit{
  width:100%;margin-top:.4rem;background:var(--blue-d);color:#fff;border:none;
  padding:.95rem;font-family:inherit;font-size:.88rem;font-weight:700;
  letter-spacing:.04em;transition:all .25s;box-shadow:0 8px 22px rgba(74,144,226,.24);
}
.fsubmit:hover{background:var(--blue-dd);transform:translateY(-1px);box-shadow:0 12px 34px rgba(74,144,226,.38)}
/* A2 — failed submissions get an error state, not the success screen */
.ferr{display:none;margin-top:1.1rem;padding:1.1rem 1.3rem;background:rgba(220,38,38,.05);border:1px solid rgba(220,38,38,.25);border-left:3px solid #dc2626}
.ferr.on{display:block}
.ferr-t{font-size:.86rem;font-weight:700;color:#b91c1c;margin-bottom:.35rem}
.ferr-b{font-size:.81rem;color:var(--ink2);line-height:1.75}
.ferr-b a{color:var(--blue-t);font-weight:700;text-decoration:underline}
/* A10 — GDPR consent */
.fconsent{display:flex;align-items:flex-start;gap:.65rem;margin:.35rem 0 1.1rem}
.fconsent input{width:16px;height:16px;flex-shrink:0;margin-top:.16rem;appearance:auto;accent-color:var(--blue-t)}
.fconsent label{font-size:.78rem;font-weight:400;letter-spacing:0;text-transform:none;color:var(--muted);line-height:1.65}
.succ{display:none;text-align:center;padding:3rem 1rem}
.succ.on{display:block}
.succ-chk{font-size:2.2rem;color:var(--blue-t);margin-bottom:.9rem}
.succ h3{font-size:1.4rem;font-weight:800;color:var(--ink);margin-bottom:.45rem}
.succ p{font-size:.88rem;color:var(--muted)}

/* ─────────────────────────────────────────────
   WHATSAPP FLOAT
───────────────────────────────────────────── */
.wa-float{
  position:fixed;bottom:2rem;right:2rem;z-index:800;
  width:54px;height:54px;background:#25D366;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  box-shadow:0 4px 22px rgba(37,211,102,.42);
  transition:transform .22s,box-shadow .22s;
}
.wa-float:hover{transform:scale(1.1);box-shadow:0 8px 32px rgba(37,211,102,.58)}
.wa-float svg{width:28px;height:28px;fill:#fff}

/* ─────────────────────────────────────────────
   FOOTER
───────────────────────────────────────────── */
footer{background:var(--ink);padding:4rem 5vw 2.5rem;color:#fff}
.ft-top{display:flex;justify-content:space-between;gap:3rem;flex-wrap:wrap;padding-bottom:3rem;border-bottom:1px solid rgba(255,255,255,.07);margin-bottom:2.5rem}
.ft-brand{display:flex;align-items:center;gap:.75rem;margin-bottom:.65rem}
.ft-mark{width:40px;height:40px;background:var(--blue);border-radius:7px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;flex-shrink:0}
.ft-mark-drp{font-size:.8rem;font-weight:800;color:#fff;letter-spacing:-.01em;line-height:1}
.ft-mark-bl{font-size:.34rem;font-weight:700;color:rgba(255,255,255,.7);letter-spacing:.1em}
.ft-name{font-size:1.05rem;font-weight:800;letter-spacing:-.02em;color:#fff}
.ft-tag{font-size:.72rem;color:rgba(255,255,255,.5)}
.ft-cols{display:flex;gap:4rem;flex-wrap:wrap}
.ft-col h4{font-size:.58rem;font-weight:700;letter-spacing:.24em;text-transform:uppercase;color:rgba(255,255,255,.5);margin-bottom:.9rem}
.ft-col a{display:block;font-size:.8rem;color:rgba(255,255,255,.62);margin-bottom:.45rem;transition:color .22s}
.ft-col a:hover{color:#fff}
.ft-bot{display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap}
.ft-copy{font-size:.7rem;color:rgba(255,255,255,.55)}
.ft-ig{display:inline-flex;align-items:center;gap:.45rem;font-size:.76rem;color:rgba(255,255,255,.6);transition:color .22s}
.ft-ig:hover{color:var(--blue-l)}
.ft-ig svg{width:13px;height:13px}

/* ─────────────────────────────────────────────
   WORD REVEAL
───────────────────────────────────────────── */
.wr-w{
  display:inline-block;overflow:hidden;vertical-align:bottom;
  /* A single long word must not be able to set a floor wider than the
     screen. German and Indonesian compounds did exactly that at 320px. */
  max-width:100%;overflow-wrap:break-word;word-break:break-word;
  /* Prevent edge-character clipping (negative letter-spacing + descenders) */
  padding:0.1em 0.08em 0.22em;
  margin:-0.1em -0.08em -0.22em;
}
.wr{display:inline-block;transform:translateY(110%);transition:transform .72s cubic-bezier(.16,1,.3,1)}
.wr.in{transform:translateY(0)}

/* ─────────────────────────────────────────────
   LANGUAGE SWITCHER
───────────────────────────────────────────── */
.nav-right{display:flex;align-items:center;gap:1rem;min-width:0}
/* The switcher now lists seven languages, not four. min-width:0 lets it
   shrink below its content size (the flexbox default is auto, which never
   shrinks), and overflow-x:auto turns any width it cannot fit into a
   horizontal scroll instead of pushing the hamburger off-screen -- which is
   what happened at 320-360px before this. nav-tog is flex-shrink:0 so it is
   never the thing that gives, whatever the language count grows to. */
/* Market picker. A native select rather than a row of codes: 17 markets do
   not fit a nav bar, and the OS picker is better on a phone than anything
   custom. min-width:0 lets it shrink so it can never push the hamburger off
   screen, which a row of buttons previously did at 320px. */
.market-sw{display:flex;align-items:center;min-width:0}
.market-sw select{
  -webkit-appearance:none;appearance:none;
  background:none;border:1px solid var(--line);border-radius:3px;
  padding:.26rem 1.35rem .26rem .5rem;max-width:11rem;
  font-family:inherit;font-size:.68rem;font-weight:700;letter-spacing:.04em;
  color:var(--muted);cursor:pointer;transition:all .2s;
  text-overflow:ellipsis;
  background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%236b7280' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right .45rem center;background-size:8px;
}
.market-sw select:hover{color:var(--ink);border-color:var(--line-b)}
.market-sw select:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
@media(max-width:560px){
  .market-sw select{max-width:7.5rem;font-size:.64rem;padding:.22rem 1.2rem .22rem .4rem}
}

.lang-sw{
  display:flex;align-items:center;gap:.25rem;
  min-width:0;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;
}
.lang-sw::-webkit-scrollbar{display:none}
.lang-btn{
  background:none;border:1px solid transparent;border-radius:3px;
  padding:.22rem .45rem;font-family:inherit;font-size:.68rem;font-weight:700;
  letter-spacing:.06em;color:var(--muted);transition:all .2s;
  text-transform:uppercase;line-height:1;flex-shrink:0;
}
.lang-btn:hover{color:var(--ink);border-color:var(--line)}
.lang-btn.active{color:var(--blue-t);border-color:rgba(74,144,226,.35);background:rgba(74,144,226,.06)}

/* ─────────────────────────────────────────────
   MOBILE NAV  (A4 + C4)

   The menu is a page of its own rather than a stack of links in the middle of
   the screen: a bar carrying the wordmark and the close cross, then the links
   grouped under headings set in the same caps as the sections, then the offer
   at the foot. Reading order top to bottom, the way the rest of the site
   reads, and it scrolls when a language list makes it taller than the screen.
───────────────────────────────────────────── */
.nav-tog{
  display:none;width:34px;height:30px;padding:0;background:none;border:none;
  flex-direction:column;justify-content:center;align-items:flex-end;gap:5px;
  flex-shrink:0;
}
.nav-tog span{
  display:block;height:2px;width:22px;background:var(--ink);border-radius:2px;
  transition:transform .3s cubic-bezier(.16,1,.3,1),opacity .2s,width .3s;
}
.nav-tog span:nth-child(2){width:15px}
.nav-tog[aria-expanded="true"] span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.nav-tog[aria-expanded="true"] span:nth-child(2){opacity:0}
.nav-tog[aria-expanded="true"] span:nth-child(3){transform:translateY(-7px) rotate(-45deg);width:22px}

.nav-ov{
  /* Above the bar (500), the WhatsApp bubble (800) and the sticky offer (850),
     all of which used to float over the menu -- at 450 the bar's own logo and
     picker showed through the menu's header and read as a doubled wordmark.
     Below the progress bar and the loader, which outrank everything. */
  position:fixed;inset:0;z-index:900;
  background:var(--bg2);
  display:flex;flex-direction:column;
  padding:0 0 3rem;overflow-y:auto;
  opacity:0;visibility:hidden;transform:translateY(-10px);
  transition:opacity .34s cubic-bezier(.16,1,.3,1),visibility .34s,transform .34s cubic-bezier(.16,1,.3,1);
}
.nav-ov.on{opacity:1;visibility:visible;transform:none}

/* The bar. Sticky, so the way out stays in reach down a long menu. */
.nav-ov-top{
  position:sticky;top:0;z-index:1;
  display:flex;align-items:center;justify-content:space-between;gap:1rem;
  padding:1.15rem 6vw;background:var(--bg2);border-bottom:1px solid var(--line);
}
.nav-ov-mark{font-size:.95rem;font-weight:800;letter-spacing:-.02em;color:var(--ink)}
.nav-ov-mark::before{content:'[ '}
.nav-ov-mark::after{content:' ]'}
.nav-ov-x{
  background:none;border:none;padding:.35rem;margin:-.35rem;
  color:var(--ink);line-height:0;cursor:pointer;
}
.nav-ov-x svg{width:26px;height:26px}

.nav-ov-group{padding:2.3rem 6vw 0}
.nav-ov-h{
  font-size:clamp(1.9rem,8.4vw,2.6rem);font-weight:800;
  text-transform:uppercase;letter-spacing:-.035em;line-height:1;
  color:var(--ink);margin-bottom:1rem;
}
/* Links read as a list under the heading, not as headlines of their own. */
.nav-ov a{
  display:block;font-size:1.05rem;font-weight:500;letter-spacing:0;
  line-height:1.4;color:var(--muted);padding:.62rem 0;
  border-bottom:1px solid var(--line);
  opacity:0;transform:translateY(16px);
  transition:opacity .45s cubic-bezier(.16,1,.3,1),transform .45s cubic-bezier(.16,1,.3,1),color .2s;
}
.nav-ov a:last-child{border-bottom:none}
.nav-ov.on a{opacity:1;transform:none}
.nav-ov.on .nav-ov-group:nth-of-type(1) a:nth-of-type(1){transition-delay:.04s}
.nav-ov.on .nav-ov-group:nth-of-type(1) a:nth-of-type(2){transition-delay:.08s}
.nav-ov.on .nav-ov-group:nth-of-type(1) a:nth-of-type(3){transition-delay:.12s}
.nav-ov.on .nav-ov-group:nth-of-type(1) a:nth-of-type(4){transition-delay:.16s}
.nav-ov.on .nav-ov-group:nth-of-type(2) a{transition-delay:.2s}
.nav-ov a:hover,.nav-ov a.active{color:var(--ink)}
.nav-ov a.active{font-weight:700}

.nav-ov .nav-ov-ig{
  display:flex;align-items:center;gap:.6rem;
  font-size:.98rem;color:var(--muted);
}
.nav-ov .nav-ov-ig svg{width:16px;height:16px;flex-shrink:0}

.nav-ov .nav-ov-cta{
  margin:2.4rem 6vw 0;border-bottom:none;text-align:center;
  background:var(--blue-d);color:#fff;font-weight:700;font-size:.98rem;
  padding:1rem 1.4rem;border-radius:999px;
  box-shadow:0 8px 24px rgba(74,144,226,.28);
  transition-delay:.24s;
}
.nav-ov .nav-ov-cta:hover{background:var(--blue-dd);color:#fff}
body.nav-open{overflow:hidden}

/* ─────────────────────────────────────────────
   RESPONSIVE
───────────────────────────────────────────── */
/* Five nav links + CTA + language switcher gets tight before 980px */
@media(max-width:1180px){
  .nlinks{gap:1.15rem}
  .nlinks a{font-size:.76rem}
  /* Four extras per row needs about 250px a cell once a price is converted
     or a label is German. Below 1180px that is not there, so two per row,
     which is what the grid already falls back to on a tablet. */
  .exgrid{grid-template-columns:1fr 1fr}
}
@media(max-width:1100px){
  .ab-layout,.opp-layout,.ct-layout{grid-template-columns:1fr;gap:4rem}
  .shint{display:none}
  .soc-sec{grid-template-columns:1fr;gap:3rem;padding:6rem 6vw}
  .soc-card{max-width:100%;aspect-ratio:2.5/1}
  .soc-big{font-size:4rem}
}
@media(max-width:980px){
  .nlinks{display:none}
  .nav-tog{display:flex}
}
@media(max-width:768px){
  /* Reveal upward, not sideways.
   *
   * .rv.fl and .rv.fr enter from translateX(-32px)/(+32px). On a wide
   * screen the 5vw gutter absorbs that; at 320px there is no gutter, so a
   * full-width block sat 32px past the edge and made the document 32px
   * wider until the section revealed -- a horizontal scrollbar that came
   * and went with the scroll position. Vertical entry cannot overflow,
   * and it is what .rv already does everywhere else. */
  .rv.fl,.rv.fr{transform:translateY(32px)}
  .rv.fl.vv,.rv.fr.vv{transform:none}
  .sec{padding:5rem 6vw}
  .soc-sec{padding:6rem 6vw}
  .hero{padding:5.5rem 6vw 4rem}
  .hero-logomark{display:none}
  .hero-h1{font-size:clamp(3rem,11vw,5.5rem)}
  .hero-foot{flex-direction:column;align-items:flex-start;gap:1.5rem}
  .proc-head{flex-direction:column}
  .srow{grid-template-columns:56px 1fr;gap:1.5rem}
  .stime{display:none}
  .wgrid{grid-template-columns:1fr 1fr}
  .pgrid{grid-template-columns:1fr}
  .plan{padding:2.5rem 1.8rem}
  .plan.feat{margin:0}
  .pprice{font-size:3.5rem}
  .pprice[style]{font-size:1.9rem !important}
  .exgrid{grid-template-columns:1fr 1fr}
  .chd,.crow{grid-template-columns:2fr 1fr 1fr}
  .chc:nth-child(n+4),.cc:nth-child(n+4){display:none}
  .ft-cols{gap:2.5rem}
  /* FAQ cards full-width on mobile */
  #faq details{padding:1.1rem 1.2rem !important}
  #faq details summary{font-size:.98rem !important}
  /* Services intro + helper text readable */
  #diensten .ssub{font-size:.95rem}
}
/* Two figures side by side need about 270px a cell once a price is
   converted -- the same sum as the extras grid above, for the same reason.
   Below 640px that is not there, and it was 480 before, which left a band
   of widths where the grid was wider than the screen. */
@media(max-width:640px){
  .ab-nums{grid-template-columns:1fr}
}
@media(max-width:560px){
  .nav-right{gap:.7rem}
  .lang-btn{padding:.2rem .3rem;font-size:.64rem}
}
@media(max-width:480px){
  .wgrid{grid-template-columns:1fr}
  .exgrid{grid-template-columns:1fr}
  .ex-wide{grid-column:span 1}
  .addon{flex-direction:column;align-items:flex-start;padding:1.3rem 1.4rem}
  .abn{padding:1.25rem 1.3rem}
  .plan{padding:2rem 1.4rem}
  .pprice{font-size:clamp(1.9rem,9vw,3rem)}
  .pprice[style]{font-size:1.7rem !important;line-height:1.1 !important}
  .pname{font-size:1.15rem}
  .pfeats li{font-size:.88rem}
  .pbtn{font-size:.9rem;padding:.9rem 1.2rem}
  /* Footer columns stack on very small */
  .ft-cols{flex-direction:column;gap:2rem}
  .ft-top{flex-direction:column;gap:2.5rem}

  /* Market overview — 1.1rem of cell padding left the value columns with
     almost no room, so prices wrapped mid-figure.

     Narrowing the padding was not enough once a converted figure arrived.
     Three columns leave about 93px each and Rp 163.895.984 needs 100, so it
     still broke mid-number: "Rp 10.223." on one line, "012" on the next,
     which reads as a different price. Two columns give the price column the
     room to keep each figure whole. Provider against start price is the
     comparison this table exists to make; maintenance is stated in the copy
     beside it and on the pricing page. */
  .chd,.crow{grid-template-columns:1.35fr 1fr}
  .chc:nth-child(n+3),.cc:nth-child(n+3){display:none}
  .chc{font-size:.52rem;letter-spacing:.08em;padding:.62rem .55rem}
  .cc{font-size:.78rem;padding:.85rem .55rem}
  .cbdg{margin-left:0;margin-top:.32rem}
  .cnm{display:flex;flex-direction:column;align-items:flex-start}

  /* Cost calculation — 3rem of padding each side is 96px of a 320px screen.
     The total also stacks: "+EUR7.473/jaar" is one unbreakable token and at
     2rem it alone is wider than the remaining space. */
  .opp-box{padding:1.5rem 1.2rem}
  .orow{gap:.7rem}
  .olbl{font-size:.78rem;min-width:0}
  .oval{font-size:.85rem;flex-shrink:0}
  .ototl{flex-direction:column;align-items:flex-start;gap:.45rem}
  .otval{font-size:1.6rem}
  .onote{padding:1rem 1.1rem;font-size:.78rem}
}

@media(max-width:360px){
  .chc{font-size:.48rem;letter-spacing:.04em;padding:.55rem .42rem}
  .cc{font-size:.72rem;padding:.75rem .42rem}
  .otval{font-size:1.35rem}
  .opp-box{padding:1.3rem 1rem}
}

/* ─────────────────────────────────────────────
   STICKY MOBILE CTA
───────────────────────────────────────────── */
/* Phones had no persistent call to action: the hero buttons scroll away and
   the next one is a whole section further down. Phone-only — desktop keeps
   the nav CTA in view the entire time. */
.scta{
  position:fixed;left:0;right:0;bottom:0;z-index:850;
  display:none;align-items:center;justify-content:space-between;gap:.9rem;
  padding:.7rem 1rem;padding-bottom:calc(.7rem + env(safe-area-inset-bottom,0px));
  background:rgba(255,255,255,.97);border-top:1px solid var(--line-b);
  box-shadow:0 -6px 24px rgba(26,31,54,.08);
  visibility:hidden;transform:translateY(110%);
  transition:transform .34s cubic-bezier(.16,1,.3,1),visibility 0s .34s;
}
.scta.on{visibility:visible;transform:none;transition:transform .34s cubic-bezier(.16,1,.3,1)}
.scta-txt{font-size:.78rem;font-weight:600;color:var(--ink);line-height:1.3;min-width:0;overflow-wrap:anywhere}
.scta-btn{
  flex-shrink:0;background:var(--blue-d);color:#fff;
  padding:.72rem 1.1rem;font-size:.82rem;font-weight:700;white-space:nowrap;
  box-shadow:0 4px 16px rgba(74,144,226,.3);
}
/* Converted-price disclaimer. Sits with the prices, not in the footer. */
.cur-note{
  margin-top:1rem;font-size:.74rem;line-height:1.65;color:var(--muted2);
}
@media(max-width:768px){
  .scta{display:flex}
  /* Lift the WhatsApp button clear of the bar instead of stacking the two. */
  body.scta-on .wa-float{bottom:5.6rem}
}

/* ─────────────────────────────────────────────
   ANNOTATION RAIL — the page's own folio

   The zoom section already had this idea and used it once: four corner
   labels naming where you are while the statistic holds the middle. This is
   that annotation plane extended over the whole document.

   It is a second plane, not decoration. The strip carries every section
   label laid out in document order and translates at roughly a tenth of
   scroll speed, so the label sitting against the blue playhead is always the
   section you are actually in, with what came before still visible above and
   what is coming below. That ratio is not a taste value -- it is
   (strip travel / document travel), which is what makes the mapping true.

   Vertical-rl rather than a rotation: Latin turns ninety degrees and reads
   top-to-bottom, which is the magazine convention, and Japanese sets
   properly vertical instead of being tipped on its side. One rule, ten
   languages.

   Desktop only, and only in the gutter .sec already reserves (5vw). Below
   1280px that gutter is narrower than the strip, so the rail is not there.
───────────────────────────────────────────── */
.arail{
  position:fixed;left:20px;top:13vh;bottom:13vh;width:30px;
  z-index:400;pointer-events:none;
  opacity:0;transition:opacity .55s ease;
}
.arail.on{opacity:1}
.arail-line{position:absolute;left:14px;top:0;bottom:0;width:1px;background:var(--line)}
/* The playhead. Whatever sits against it is where you are. */
.arail-mark{position:absolute;left:8px;top:60%;width:13px;height:1px;background:var(--blue)}
.arail-mark::before{
  content:'';position:absolute;left:-3px;top:-2px;
  width:5px;height:5px;border-radius:50%;background:var(--blue);
}
.arail-strip{
  position:absolute;inset:0;overflow:hidden;
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 12%,#000 88%,transparent 100%);
          mask-image:linear-gradient(180deg,transparent 0,#000 12%,#000 88%,transparent 100%);
}
.arail-items{position:absolute;left:0;top:0;width:100%;will-change:transform}
.arail-i{
  position:absolute;left:0;width:100%;
  display:flex;align-items:center;gap:.6rem;
  writing-mode:vertical-rl;
  font-size:.56rem;font-weight:700;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted2);opacity:.5;
  transform:translateY(-50%);
  transition:color .4s ease,opacity .4s ease;
  white-space:nowrap;
}
.arail-i i{font-style:normal;font-variant-numeric:tabular-nums;letter-spacing:.08em}
.arail-i.on{opacity:1;color:var(--blue-t)}
.arail-i.on b{color:var(--ink)}
@media(max-width:1279px){.arail{display:none}}

/* ─────────────────────────────────────────────
   NAV CTA — the desktop conversion path

   Desktop had none. Four text links and a market picker, with the nearest
   button 7.4 screens down the home page; mobile meanwhile had a sticky bar
   and an overlay CTA. This closes that, and it closes the 769-980px band
   where .nlinks has already gone and .scta has not yet arrived.

   Copy comes from nav.cta via data-nav, which the mobile overlay was already
   using -- so it arrived translated into all ten languages and cost nothing.
   Polish sets it longest by some margin, which is what max-width is sized
   against.
───────────────────────────────────────────── */
.nav-cta{
  display:inline-flex;align-items:center;
  background:var(--blue-d);color:#fff;
  font-size:.72rem;font-weight:700;letter-spacing:.01em;
  padding:.52rem .9rem;border-radius:4px;
  box-shadow:0 4px 14px rgba(74,144,226,.26);
  transition:transform .25s ease,box-shadow .25s ease,background .25s ease;
  white-space:nowrap;max-width:15rem;overflow:hidden;text-overflow:ellipsis;
  flex-shrink:0;
}
.nav-cta:hover{background:var(--blue-dd);transform:translateY(-1px);box-shadow:0 7px 20px rgba(74,144,226,.34)}
.nav-cta:active{transform:translateY(0)}
/* Already on the contact page: the form is the CTA. */
body[data-page="contact"] .nav-cta{display:none}
@media(max-width:768px){.nav-cta{display:none}}

/* ─────────────────────────────────────────────
   COST-CALCULATOR CTA — the last row of the ledger

   The box totals to a benefit figure and then stopped. This is the highest
   intent moment on the page and there was nothing to press for another four
   screens. Squared to the box rather than pill-shaped, because it is a row
   of the table and not a floating button.
───────────────────────────────────────────── */
.opp-act{
  display:block;margin-top:1.75rem;
  background:var(--blue-d);color:#fff;text-align:center;
  padding:1.05rem 1.25rem;border-radius:3px;
  font-size:.86rem;font-weight:700;letter-spacing:-.005em;
  box-shadow:0 8px 24px rgba(74,144,226,.24);
  transition:background .25s ease,box-shadow .25s ease;
}
.opp-act:hover{background:var(--blue-dd);box-shadow:0 12px 30px rgba(74,144,226,.32)}

/* ─────────────────────────────────────────────
   A7 — REDUCED MOTION
───────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important;
  }
  html{scroll-behavior:auto}
  .rv,.hl-i,.wr,.nav-ov a{opacity:1!important;transform:none!important}  .shint-line{animation:none!important}
  .arail{display:none!important}
}

/* ─────────────────────────────────────────────
   LANGUAGE OFFER — suggested, never forced
───────────────────────────────────────────── */
.lang-offer{
  position:fixed;left:1rem;bottom:1rem;z-index:60;
  display:flex;align-items:center;gap:.25rem;
  background:var(--ink,#12141a);color:#fff;
  border-radius:999px;padding:.15rem .35rem .15rem 1rem;
  box-shadow:0 6px 24px rgba(0,0,0,.18);
  font-size:.85rem;max-width:calc(100vw - 2rem);
}
.lang-offer a{
  color:inherit;text-decoration:underline;text-underline-offset:2px;
  padding:.45rem 0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.lang-offer a:hover{text-decoration-thickness:2px}
.lang-offer-x{
  flex:none;background:none;border:0;color:inherit;cursor:pointer;
  font-size:1.15rem;line-height:1;padding:.35rem .5rem;border-radius:999px;
}
.lang-offer-x:hover{background:rgba(255,255,255,.14)}
.lang-offer-x:focus-visible,.lang-offer a:focus-visible{outline:2px solid #fff;outline-offset:2px}
/* The sticky mobile CTA owns the bottom of a small screen; sit above it. */
@media (max-width:700px){
  .lang-offer{bottom:auto;top:calc(var(--navh,64px) + .5rem);left:.75rem;right:.75rem;font-size:.8rem}
}

/* ─────────────────────────────────────────────
   COOKIE CONSENT   (.ccb — .cc is the comparison cell)
   Accept and Reject share one class on purpose:
   refusing must not be the quieter button.
───────────────────────────────────────────── */
.ccb{
  position:fixed;left:1rem;right:1rem;bottom:1rem;z-index:80;
  max-width:34rem;margin-inline:auto;
  background:#fff;color:var(--ink,#12141a);
  border:1px solid rgba(0,0,0,.08);border-radius:14px;
  box-shadow:0 18px 50px rgba(0,0,0,.16);
  padding:1.15rem 1.25rem;
}
.ccb-body{margin:0 0 .9rem;font-size:.86rem;line-height:1.6;color:var(--muted,#5a5f6b)}

.ccb-opts{display:grid;gap:.55rem;margin:0 0 1rem}
.ccb-row{display:flex;gap:.6rem;align-items:flex-start;cursor:pointer}
.ccb-row>*{min-width:0}
.ccb-row.is-locked{cursor:default;opacity:.7}
.ccb-row input{width:16px;height:16px;flex:none;margin-top:.18rem;appearance:auto;accent-color:var(--blue-d,#1b4ee0)}
.ccb-row strong{display:block;font-size:.82rem;font-weight:600}
.ccb-row small{display:block;font-size:.76rem;line-height:1.5;color:var(--muted,#5a5f6b)}

.ccb-btns{display:flex;flex-wrap:wrap;gap:.5rem}
.ccb-b{
  flex:1 1 auto;min-width:8rem;
  font-family:inherit;font-size:.82rem;font-weight:600;
  padding:.6rem 1rem;border-radius:999px;cursor:pointer;
  border:1px solid transparent;
}
/* Identical weight for accept and reject. */
.ccb-b-solid{background:var(--ink,#12141a);color:#fff}
.ccb-b-solid:hover{opacity:.88}
.ccb-b-ghost{background:transparent;color:var(--ink,#12141a);border-color:rgba(0,0,0,.16)}
.ccb-b-ghost:hover{background:rgba(0,0,0,.04)}
.ccb-b:focus-visible{outline:2px solid var(--blue-d,#1b4ee0);outline-offset:2px}

/* The permanent way back, so consent can be withdrawn as easily as given. */
.ccb-manage{
  background:none;border:0;padding:0;margin:.4rem 0 0;
  font-family:inherit;font-size:inherit;color:inherit;opacity:.8;
  text-decoration:underline;text-underline-offset:2px;cursor:pointer;
}
.ccb-manage:hover{opacity:1}

@media (max-width:700px){
  .ccb{left:.6rem;right:.6rem;bottom:.6rem;padding:1rem}
  .ccb-b{flex:1 1 100%}
}

/* ─────────────────────────────────────────────
   RIGHT-TO-LEFT — added on top, never instead

   Arabic is the first right-to-left language on the site. Rather than convert
   the stylesheet to logical properties -- 53 physical left/right declarations
   across 17 files, each one a chance to move something on 21 markets that
   were already right -- the flips live here, every one scoped to
   [dir="rtl"], so nothing in this file can reach a left-to-right page.

   Most of the layout needs nothing. Grid and flex already run in reading
   order, so the columns, the nav, the hero footer and the comparison table
   reverse on their own. What is listed below is only what was pinned to a
   physical side.

   Keep this file last. It overrides rules from across the stylesheet, by
   specificity where it can and by order where it cannot.
───────────────────────────────────────────── */

/* Things that grow or slide in from an edge */
[dir="rtl"] #sprog{left:auto;right:0}
[dir="rtl"] .nlinks a::after{left:auto;right:0}
[dir="rtl"] .srow::before{left:auto;right:0}
[dir="rtl"] .wcard::after{transform-origin:right}
[dir="rtl"] .hero-h1{transform-origin:bottom right}
[dir="rtl"] .stime{text-align:left}

/* The pinned statistic's corner labels swap sides */

/* Accent rules sit on the side reading starts from */
[dir="rtl"] .onote{border-left:0;border-right:2.5px solid var(--blue)}
[dir="rtl"] .crow.us{border-left:0;border-right:2.5px solid var(--blue)}
[dir="rtl"] .ferr{border-left:1px solid rgba(220,38,38,.25);border-right:3px solid #dc2626}

/* Comparison table: the column rules and the badge gap */
[dir="rtl"] .chc,[dir="rtl"] .cc{border-right:0;border-left:1px solid var(--line)}
[dir="rtl"] .chc:last-child,[dir="rtl"] .cc:last-child{border-left:0}
[dir="rtl"] .cbdg{margin-left:0;margin-right:.45rem}
@media(max-width:480px){[dir="rtl"] .cbdg{margin-right:0}}

/* Floating controls change corners. The language bar only on desktop: below
   700px it already spans the width. Its padding follows the bar's own
   direction rather than the page's, because an Arabic offer can appear on a
   Latin page and the other way round. */
[dir="rtl"] .wa-float{right:auto;left:2rem}
@media(min-width:701px){[dir="rtl"] .lang-offer{left:auto;right:1rem}}
.lang-offer[dir="rtl"]{padding:.15rem 1rem .15rem .35rem}

/* The market picker's chevron moves to the start of the reading line */
[dir="rtl"] .market-sw select{padding:.26rem .5rem .26rem 1.35rem;background-position:left .45rem center}

/* Reveals enter from the mirrored side -- desktop only. Below 769px every
   reveal is vertical already, and a sideways entry there is what made the
   320px page scrollable; in RTL it would overflow to the left instead. The
   .si rules restate the scale-in, which the .fl override would otherwise
   replace on the one element that is both. */
@media(min-width:769px){
  [dir="rtl"] .rv.fl{transform:translateX(32px)}
  [dir="rtl"] .rv.fr{transform:translateX(-32px)}
  [dir="rtl"] .rv.si{transform:scale(.93) translateY(16px)}
  [dir="rtl"] .rv.fl.vv,[dir="rtl"] .rv.fr.vv,[dir="rtl"] .rv.si.vv{transform:none}
}

/* The annotation rail moves to the right-hand gutter */
[dir="rtl"] .arail{left:auto;right:20px}
[dir="rtl"] .arail-line{left:auto;right:14px}
[dir="rtl"] .arail-mark{left:auto;right:8px}
[dir="rtl"] .arail-mark::before{left:auto;right:-3px}

/* Things that read left to right whatever the page does. A phone number laid
   out right to left reverses its groups -- the WhatsApp number on the contact
   page came out as "31 44 74 473 32+" -- and a handle loses its @ to the far
   end. The contact values and the footer's link columns are isolated whole:
   an inline run of Arabic inside a left-to-right isolate still reads right to
   left, so the Arabic links among them are unaffected. The icon-and-label
   social buttons are in neither list, and keep their icon on the reading
   side. An email address or a phone field that flips mid-entry is unusable. */
[dir="rtl"] a[href^="tel:"],[dir="rtl"] a[href^="mailto:"],
[dir="rtl"] .ci-val a,[dir="rtl"] .ft-col a{direction:ltr;unicode-bidi:isolate}
[dir="rtl"] input[type="tel"],[dir="rtl"] input[type="email"]{direction:ltr;text-align:right}

/* The footer's legal line is mostly Latin -- the company, the Hallaar address,
   the VAT number -- with Arabic between them. Laid out right to left, bidi
   splits the Latin into runs that reorder around the separators, and the
   address reads before the company name. plaintext lets the line take its
   direction from its own first strong character, which keeps the parts in
   the order they were written. */
[dir="rtl"] .ft-copy{unicode-bidi:plaintext}

/* ── Arabic typography ─────────────────────────── */

/* Tracking breaks Arabic. The letters of a word are joined, and letter-spacing
   pulls the joins apart into visible gaps. The site tracks 62 things, from
   the uppercase eyebrows to the tightened display headings, and none of it
   survives contact with the script. !important because the tracked rules run
   up to two classes deep and this has to beat all of them. */
html[lang="ar"] *{letter-spacing:normal!important}

/* Arabic has no italic. Asked for one, a browser slants the glyphs, which
   reads as broken rather than as emphasis; the light weight and the muted
   colour already mark the accent. */
html[lang="ar"] em,html[lang="ar"] .h-light{font-style:normal}

/* Taller lines and roomier clip boxes. Arabic dots and marks sit well above
   and below the Latin cap height and baseline these were tuned to, and the
   reveal boxes are overflow:hidden, so at a line-height of .9 they were
   sliced off. */
html[lang="ar"] body{line-height:1.85}
html[lang="ar"] .hero-h1{line-height:1.2}
html[lang="ar"] .hl{line-height:1.25;padding:.2em .06em .32em;margin:-.2em -.06em -.32em}
html[lang="ar"] .sh{line-height:1.4}
html[lang="ar"] .wr-w{padding:.3em .1em .4em;margin:-.3em -.1em -.4em}
html[lang="ar"] .abn-v,html[lang="ar"] .pprice,html[lang="ar"] .otval{line-height:1.25}

/* ─────────────────────────────────────────────
   LANGUAGE SWITCH — countries published in more than one language

   Links beside the country picker, one per language the country is
   published in, each to the same page in that language at the same
   currency. Only multilingual countries render them; everywhere else this
   file matches nothing.

   Short codes by default and each language's own name on wide screens,
   because the nav bar is already carrying the logo, four links, the demo
   button and the country picker. Below 560px there is room for the logo, the
   picker and the menu button only, so the choice moves into the menu, where
   it is shown as a row of pills above the closing call to action.
───────────────────────────────────────────── */
.lang-switch{display:flex;align-items:center;gap:.15rem;flex-shrink:0}
.lang-switch a{
  font-size:.68rem;font-weight:700;letter-spacing:.04em;line-height:1;
  color:var(--muted);padding:.34rem .45rem;border-radius:3px;
  border:1px solid transparent;white-space:nowrap;
  transition:color .2s,border-color .2s,background .2s;
}
.lang-switch a:hover{color:var(--ink);border-color:var(--line)}
.lang-switch a[aria-current="true"]{
  color:var(--blue-t);border-color:rgba(74,144,226,.35);background:rgba(74,144,226,.06);
}
.lang-switch .ls-full{display:none}
@media(min-width:1281px){
  .lang-switch .ls-full{display:inline}
  .lang-switch .ls-short{display:none}
}
@media(max-width:560px){.lang-switch{display:none}}

/* In the mobile menu. Overrides the menu's own large link style, which would
   otherwise set each language at the size of a page link. */
.nav-ov .nav-ov-langs{
  display:flex;flex-wrap:wrap;gap:.5rem;
  margin:2.3rem 6vw 0;
}
.nav-ov .nav-ov-langs a{
  font-size:.95rem;font-weight:700;letter-spacing:0;
  padding:.5rem 1rem;border:1px solid var(--line);border-radius:999px;
  color:var(--muted);
}
.nav-ov .nav-ov-langs a[aria-current="true"]{
  color:var(--blue-t);border-color:var(--blue-t);background:rgba(74,144,226,.06);
}
.nav-ov .nav-ov-langs .ls-short{display:none}

/* ─────────────────────────────────────────────
   PARTNERS

   Cards, in the shape the client asked for after the Impact reference:
   a 5:6 image flush to the top of a square-cornered card, then a counted
   label, the partner's name set large in caps, the body, and a tag on the
   last line.

   The reference sets white cards on a tinted ground. This inverts that --
   tinted cards on the white section -- because the home page alternates
   light, dark, light, and the section before this one is already the tinted
   treatment. Two tinted grounds running together would lose the seam between
   two sections that say different things. The card itself is what the
   reference makes it: square, borderless, image flush, text padded.

   Nothing here needed new copy. The number is a CSS counter, the name and
   the tagline are the partners' own words that were already on the page,
   and the tagline becomes the tag on the last line.
───────────────────────────────────────────── */
/* 1040px keeps each card near 500px wide, which is what the 600w/1000w WebP
   files are cut for; wider and a 1440px screen would show two images taller
   than the viewport. */
.prt-grid{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:2.6rem;margin-top:3.5rem;max-width:1040px;
  counter-reset:prt;
}
.prt{
  margin:0;min-width:0;counter-increment:prt;
  /* A column, so .prt-body can push the tag to the bottom and the two cards'
     last lines agree however long the copy above them runs. */
  display:flex;flex-direction:column;
  background:var(--bg2);
}

/* ── The image ───────────────────────────────────────────────────────────
   Flush to three edges of the card. overflow:hidden is load-bearing: the
   hover in 38-depth.css scales the image, and without it the artwork would
   grow past the card instead of filling more of its frame. */
.prt-shot{display:block;overflow:hidden}
.prt-shot:focus-visible{outline:2px solid var(--blue);outline-offset:-3px}
/* width/height on the tag reserve the space before the lazy image arrives;
   aspect-ratio keeps that true once CSS makes the width fluid. The border,
   the radius and the shadow are gone -- the card carries all three now. */
.prt img{
  display:block;width:100%;height:auto;
  aspect-ratio:5/6;object-fit:cover;background:var(--bg3);
}

/* ── The text ────────────────────────────────────────────────────────────
   flex:1 so the column fills the card and the tag can sit on the floor of
   it. align-items:flex-start so the name and the tag are only as wide as
   their own text -- a stretched inline-flex would put the arrow at the far
   edge of the card, a hand's width from the word it belongs to. */
.prt-body{
  flex:1;display:flex;flex-direction:column;align-items:flex-start;
  padding:1.9rem 2rem 2rem;
}
/* The count, bracketed, the way every other label on the site is set. CSS
   rather than markup, as on the numbered cards: it renumbers itself if a
   third partner is ever added. */
.prt-body::before{
  content:'[ ' counter(prt,decimal-leading-zero) ' ]';
  font-size:.6rem;font-weight:700;letter-spacing:.24em;
  font-variant-numeric:tabular-nums;color:var(--blue-t);
  margin-bottom:1.1rem;
}

/* ── The name, which is also the link out ────────────────────────────────
   Both partners have a site of their own, and the image is what a reader
   reaches for -- so the image is a link too, taken out of the tab order and
   hidden from the accessibility tree. This one carries the label, and is the
   only stop a keyboard makes. */
.prt-name{
  display:inline-flex;align-items:baseline;gap:.5rem;
  font-size:clamp(1.25rem,2.1vw,1.85rem);font-weight:800;
  letter-spacing:-.03em;text-transform:uppercase;line-height:1.06;
  color:var(--ink);margin-bottom:.85rem;
  transition:color .2s;
}
/* The arrow is the affordance: in caps at this weight an underline reads as
   damage, and nothing else says "this leaves the site". */
a.prt-name::after{content:'↗';font-size:.62em;font-weight:700;transition:transform .25s}
a.prt-name:hover{color:var(--blue-t)}
a.prt-name:hover::after{transform:translate(2px,-2px)}
/* Right to left, the arrow leads rather than trails, and points the way the
   text runs. */
[dir="rtl"] a.prt-name::after{content:'↖'}

.prt-b{font-size:.9rem;color:var(--ink2);line-height:1.75;margin-bottom:1.5rem}

/* ── The tag ─────────────────────────────────────────────────────────────
   The partners' own English tagline, on the last line of the card.

   Square, where the reference rounds it. 39-editorial.css states the rule --
   round actions, square everything else -- and this is a label, not
   something to click. Rounding it would be the one pill on the site that
   does nothing when pressed. */
.prt-line{
  display:inline-block;margin-top:auto;
  padding:.5rem .9rem;border:1px solid var(--line-b);
  font-size:.56rem;font-weight:700;letter-spacing:.18em;text-transform:uppercase;
  color:var(--muted);
}
/* The tagline is English on every page. On an Arabic page it inherited the
   right-to-left direction and its full stop jumped to the front
   (".TECHNOLOGY SUPPORTS BEAUTY"); read it left to right. */
[dir="rtl"] .prt-line{direction:ltr}

@media(max-width:768px){
  .prt-grid{grid-template-columns:1fr;gap:2rem;max-width:520px;margin-top:2.5rem}
  .prt-body{padding:1.5rem 1.6rem 1.7rem}
}

/* ─────────────────────────────────────────────
   DARK SECTIONS

   The page alternates light and dark rather than running white throughout:
   the hero in the dark, the four steps in the light, the hidden cost dark
   again. Contrast is the rhythm.

   One class does it. Every component here draws its colours from the tokens
   in 02-tokens.css, so redefining those tokens on a section repaints
   everything inside it -- headings, rules, muted text, table borders -- with
   no per-component dark rules to keep in step. Only the handful of colours
   that are hard-coded for meaning (the red and green figures) are restated
   below.

   --blue-d and --blue-dd stay as they are: they are the filled button's
   background, and a lighter blue there would leave white label text on a
   pale field. The accent token goes lighter instead, because on near-black
   it is text.
───────────────────────────────────────────── */
.dark{
  /* Solid black, at the client's request -- it was #080b16, a near-black
     with enough blue in it to read as dark grey against the white the page
     used to be. On true black the bone grounds land harder and the globe's
     limb has nothing to compete with. */
  --bg:#000000;
  --bg2:#0f142a;
  --bg3:#151b33;
  --ink:#ffffff;
  --ink2:rgba(255,255,255,.86);
  --muted:rgba(255,255,255,.66);
  /* .52, not the .45 of the light theme: white at 44% over this near-black
     measures 4.35:1, and the corner labels and the currency note set in it
     are small text, which wants 4.5. */
  --muted2:rgba(255,255,255,.52);
  --line:rgba(255,255,255,.10);
  --line-b:rgba(122,179,237,.26);
  --blue:#7ab3ed;
  --blue-t:#7ab3ed;
  position:relative;
  /* Contains the aurora: without it the blurred glow, which is deliberately
     larger than the section, widens the document and puts a horizontal
     scrollbar on every page. */
  overflow:hidden;
  /* Own stacking context, so the negative-z backdrops below sit behind this
     section's content and not behind the page. */
  isolation:isolate;
  background:var(--bg);
  color:var(--ink);
}
/* The seam where light meets dark */
.dark{box-shadow:inset 0 1px 0 rgba(255,255,255,.06),inset 0 -1px 0 rgba(255,255,255,.06)}

/* Aurora — three coloured clouds, drifting. Transform and nothing else, so
   it animates on the compositor; `alternate` means it never jumps back. */
.dark::before{
  content:'';position:absolute;inset:-25%;z-index:-2;pointer-events:none;
  background:
    radial-gradient(38% 42% at 18% 22%, rgba(74,144,226,.065) 0%, transparent 68%),
    radial-gradient(32% 34% at 82% 26%, rgba(122,179,237,.035) 0%, transparent 70%),
    radial-gradient(44% 40% at 60% 92%, rgba(46,116,201,.05) 0%, transparent 72%);
  animation:auroraDrift 28s cubic-bezier(.45,0,.55,1) infinite alternate;
  will-change:transform;
}
@keyframes auroraDrift{
  from{transform:translate3d(-2%,-1%,0) scale(1)}
  to{transform:translate3d(3%,2%,0) scale(1.09)}
}
/* Grid, grain and vignette in one layer. The grid is the hero's, at the same
   88px, so the two read as the same drawing. The grain is an inline SVG
   turbulence -- it costs no request and keeps the big gradients from
   banding into stripes on an 8-bit screen. */
.dark::after{
  content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:
    linear-gradient(rgba(255,255,255,.028) 1px,transparent 1px),
    linear-gradient(90deg,rgba(255,255,255,.028) 1px,transparent 1px),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.24'/%3E%3C/svg%3E");
  background-size:88px 88px,88px 88px,180px 180px;
  -webkit-mask-image:radial-gradient(ellipse 88% 78% at 50% 45%,#000 28%,transparent 100%);
          mask-image:radial-gradient(ellipse 88% 78% at 50% 45%,#000 28%,transparent 100%);
  opacity:.6;
}

/* Figures that carry meaning by colour, restated for a dark field: the
   crimson and green of the cost table are unreadable at 3:1 on near-black. */
.dark .oval.n{color:#ff7a7a}
.dark .oval.p{color:#5fd68b}
/* The ghost button's border is the token line, which is now a white film. */
.dark .btn-g:hover{border-color:var(--blue-t);color:var(--blue-t);background:rgba(122,179,237,.10)}
/* The calculator panel sits on the section's own glow, so it needs a surface
   of its own to stay legible rather than the flat tint it has in the light. */
.dark .opp-box{
  background:linear-gradient(180deg,rgba(255,255,255,.055),rgba(255,255,255,.02));
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  border-color:rgba(255,255,255,.12);
}
.dark .onote{background:rgba(255,255,255,.04)}
/* Cards on dark: a film of white rather than a lighter grey, so the aurora
   behind them still shows through. */
.dark .wgrid{background:rgba(255,255,255,.09);border-color:rgba(255,255,255,.09)}
.dark .wcard{background:rgba(9,13,26,.72)}
.dark .wcard:hover{background:rgba(23,30,54,.82)}
.dark .wico{background:rgba(122,179,237,.14)}

/* ── The closing offer ───────────────────────────────────────────────────
   Last thing before the footer, and the footer is dark too: the two now
   read as one closing block rather than a white strip wedged between. */
.ctastrip.dark{padding-block:8rem}
.ctastrip.dark .sh{text-shadow:0 22px 60px rgba(0,0,0,.7)}

/* The rail floats over whatever is behind it, so over a dark section its
   ink-coloured labels disappear. app.js watches which section is at the
   playhead and flips these. */
.arail.on-dark .arail-line{background:rgba(255,255,255,.14)}
.arail.on-dark .arail-i{color:rgba(255,255,255,.5)}
.arail.on-dark .arail-i.on{color:var(--blue-l)}
.arail.on-dark .arail-i.on b{color:#fff}

@media(max-width:768px){
  /* The drift is a slow luxury on a laptop and a battery cost on a phone,
     where the section is a single screen tall and the movement is barely
     legible anyway. */
  .dark::before{animation:none}
  .ctastrip.dark{padding-block:5.5rem}
}

/* ─────────────────────────────────────────────
   DEPTH — pointer tilt and light

   Cards lean towards the pointer and catch a highlight where it sits. The
   rotation is small on purpose (6 degrees at the corner): enough to read as
   a physical object catching the light, not enough to distort the text on it.

   Everything here is driven by four custom properties that app.js sets
   (--rx/--ry for the lean, --mx/--my for the highlight). Untouched, they fall
   back to flat and centred, so a card that never sees a pointer -- a phone, a
   crawler, a prerender -- is exactly the card it was before.

   Gated on a real pointer: on a touch screen "hover" sticks after the tap and
   would leave cards frozen mid-lean.
───────────────────────────────────────────── */
@media (hover:hover) and (pointer:fine){
  .tilt{
    transform:perspective(900px) rotateX(var(--ry,0deg)) rotateY(var(--rx,0deg));
    transform-style:preserve-3d;
    transition:transform .55s cubic-bezier(.16,1,.3,1),box-shadow .55s cubic-bezier(.16,1,.3,1);
  }
  /* While the pointer is on it, the lean must track the pointer rather than
     ease towards it, or the card lags behind the cursor by half a second. */
  .tilt.on{transition:transform .09s linear,box-shadow .4s ease}

  /* The highlight. A background layer, not an overlay element, so it works on
     cards whose ::before and ::after are already spoken for. */
  .tilt::after,.tilt::before{pointer-events:none}
  .wcard.tilt,.plan.tilt{
    background-image:radial-gradient(260px circle at var(--mx,50%) var(--my,50%),rgba(74,144,226,.10),transparent 62%);
  }
  .dark .wcard.tilt{
    background-image:radial-gradient(260px circle at var(--mx,50%) var(--my,50%),rgba(255,255,255,.10),transparent 60%);
  }
  .plan.tilt.on{box-shadow:0 30px 70px rgba(26,31,54,.14)}
  .dark .wcard.tilt.on{box-shadow:0 26px 60px rgba(0,0,0,.45)}

  /* The partner cards lift rather than glow -- artwork of someone else's
     brand should not have our blue washed over it.

     The lift moved from the image to the card when the card gained a ground
     of its own: a shadow under the image alone would have been a shadow
     cast inside the thing holding it. The image still answers, by filling
     more of its frame -- .prt-shot clips it, so this reads as the artwork
     coming forward rather than the picture growing.

     Only the shadow is set here. .tilt above already owns transform (the
     lean itself) and transition (which .tilt.on swaps for pointer tracking);
     restating either at this specificity would have overwritten the lean
     with a flat translate and put the half-second ease back on a card that
     is supposed to follow the cursor. */
  .prt.tilt.on{box-shadow:0 38px 90px rgba(26,31,54,.17)}
  .prt.tilt img{transition:transform .7s cubic-bezier(.16,1,.3,1)}
  .prt.tilt.on img{transform:scale(1.045)}
}

/* The logomark drifts, the way a thing hanging in space does. Three seconds
   up, three down, never resting on a keyframe the eye can predict. */
/* The wrapper already fades and lifts it into place; this is only the drift
   that starts once that has finished. */
.hero-logomark svg{animation:floatY 7s ease-in-out 2.8s infinite}
@keyframes floatY{
  0%,100%{transform:translateY(0) rotate(0deg)}
  50%{transform:translateY(-14px) rotate(-1.5deg)}
}

@media (prefers-reduced-motion: reduce){
  .tilt{transform:none!important}
  .hero-logomark svg{animation:none!important}
}

/* ─────────────────────────────────────────────
   EDITORIAL SYSTEM

   The layout language the client picked: a measured centre column rather than
   a full-bleed page, display type set in caps, small bracketed labels over
   every section, pills for actions and square corners on everything else, and
   a dark hero with the headline at the bottom of the screen above a row of
   proof points.

   The palette is unchanged -- the same blue, the same near-black, the same
   bone-white grounds. Where the reference uses red for actions, this uses the
   blue that was already the site's accent.

   Nothing here restyles a component individually. The grounds and the type
   roles are set once and the existing sections inherit them, which is why this
   file is short for the size of the change.
───────────────────────────────────────────── */
:root{
  --maxw:1296px;
  --gutter:5vw;
}

/* ── The centre column ───────────────────────────────────────────────────
   Padding, not a max-width on the section: the grounds stay full-bleed and
   edge to edge while the content inside them holds a 1296px measure. One
   declaration gives every section the same column without a wrapper element
   in the markup. */
.sec,.ctastrip,.soc-sec,.hero,.phero,footer,.mq-wrap{
  padding-inline:max(var(--gutter),calc((100% - var(--maxw)) / 2));
}

/* ── Labels ──────────────────────────────────────────────────────────────
   Set in brackets, the way a running head is marked up in print. The hero's
   label loses its rule and joins them, so every eyebrow on the site is the
   same object. */
.stag{
  font-size:.6rem;font-weight:700;letter-spacing:.24em;text-transform:uppercase;
}
.stag::before{content:'[ '}
.stag::after{content:' ]'}

/* ── Display type ────────────────────────────────────────────────────────
   Caps, tight tracking, heavy weight. The italic light face stays -- it is
   the site's own voice and the only thing in the type that is not shouted. */
.sh,.hero-h1,.phero-h1{text-transform:uppercase;letter-spacing:-.035em}
/* Caps set roughly a fifth wider than the same words in sentence case, and
   the section headings live in half-width columns: at the old 5.5rem
   "AANWEZIGHEID" broke across lines mid-word and "ONDERNEMERS," ran past its
   column on the about page. The scale comes down where the measure is narrow
   and stays large where the heading has the full column to itself. */
.sh{font-size:clamp(1.9rem,3.6vw,3.6rem);line-height:1}
.ctastrip .sh,.soc-sec .sh{font-size:clamp(2.2rem,4.6vw,4.4rem)}
.hero-h1{font-size:clamp(3rem,8.6vw,7.6rem);line-height:.92}
/* A last resort, not the plan: the sizes above are chosen so the longest word
   in any of the twelve languages fits. This only keeps a word that still does
   not fit inside its column instead of over the edge of the page. */
.sh,.hero-h1,.phero-h1{overflow-wrap:break-word}

/* ── Pills ───────────────────────────────────────────────────────────────
   Round actions, square everything else. */
.btn,.pbtn,.nav-cta,.soc-link,.fsubmit,.market-sw select,.opp-act{
  border-radius:999px;
}
.btn{padding:.95rem 2.1rem;font-size:.83rem;letter-spacing:.04em}
.pbtn{padding:1rem;letter-spacing:.04em}
.nav-cta{padding:.6rem 1.15rem}
/* Square corners for the surfaces, so the pills are the only round thing. */
.prt img,.soc-card,.wico,.ab-logo-wrap{border-radius:0}

/* ── Proof row ───────────────────────────────────────────────────────────
   Five short claims under the headline, each ticked. Built from the same
   translation key the moving band used, so it arrived in twelve languages. */
.trust{display:flex;flex-wrap:wrap;gap:.55rem 1.7rem;margin:1.9rem 0 2.4rem;list-style:none;padding:0}
.trust li{display:flex;align-items:center;gap:.6rem;font-size:.82rem;font-weight:600;color:var(--ink2)}
.trust li::before{
  content:'✓';flex:none;width:18px;height:18px;border-radius:50%;
  background:var(--blue-d);color:#fff;
  font-size:10px;line-height:18px;text-align:center;font-weight:700;
}

/* ── The hero ────────────────────────────────────────────────────────────
   Bottom-anchored: label, headline, proof, then the standfirst and the two
   actions side by side on the last line. The ground is the dark section
   treatment, so the aurora, the grid and the grain come with it. */
/* Full screen, and the same full screen on a phone.
   It was 92vh below 768px, which was a fudge for the mobile URL bar: 100vh
   on a phone is the viewport with the bar hidden, so a 100vh hero is taller
   than what you can actually see and its last line sits under the chrome.
   svh is that measurement done properly -- the smallest the viewport gets,
   with the bar showing -- so the hero fills the screen and nothing is cut.
   vh stays as the fallback for anything that has not got svh. */
.hero{justify-content:flex-end;padding-block:9rem 4.5rem;min-height:100vh;min-height:100svh}
.hero-content{width:100%;padding-inline:0}
.hero-h1{margin-bottom:0}
.hero-foot{align-items:flex-end;margin-top:0}

/* ── Page headers ────────────────────────────────────────────────────────
   The inner pages get the same dark opening, one notch shorter. */
.phero{padding-block:11rem 4.5rem;border-bottom:none}
.phero-h1{font-size:clamp(2.6rem,6.4vw,5.4rem);line-height:.96}
.phero-sub{max-width:620px;font-size:1rem}

/* ── The bar over a dark opening ─────────────────────────────────────────
   Every page now opens dark, so until the bar takes its white ground at 50px
   it is sitting on near-black and its ink-coloured type is invisible. It gets
   a scrim of its own rather than a veil on the hero: the hero's ::after is
   spoken for by the grain layer. */
nav:not(.s){background:linear-gradient(180deg,rgba(0,0,0,.86) 0%,rgba(0,0,0,0) 100%)}
nav:not(.s) .nname{color:#fff}
nav:not(.s) .nlinks a{color:rgba(255,255,255,.74)}
nav:not(.s) .nlinks a:hover,nav:not(.s) .nlinks a.active{color:#fff}
nav:not(.s) .nav-tog span{background:#fff}
nav:not(.s) .lang-btn{color:rgba(255,255,255,.7)}
nav:not(.s) .lang-btn.active{color:#fff}
nav:not(.s) .lang-switch a{color:rgba(255,255,255,.68)}
nav:not(.s) .lang-switch a[aria-current="true"]{color:#fff}
nav:not(.s) .market-sw select{
  color:rgba(255,255,255,.82);border-color:rgba(255,255,255,.28);
  background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23ffffff' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
}
nav:not(.s) .market-sw select:hover{color:#fff;border-color:rgba(255,255,255,.5)}
/* The scroll hint sits on the dark hero too. */
.hero .shint span{color:rgba(255,255,255,.5)}

@media(max-width:768px){
  .hero{padding-block:7rem 3.5rem}
  .phero{padding-block:8.5rem 3rem}
  .trust{gap:.5rem 1.1rem;margin:1.4rem 0 1.8rem}
  .trust li{font-size:.76rem}
  .hero-foot{align-items:flex-start}
}

/* ── Numbered cards ──────────────────────────────────────────────────────
   The six reasons, set the way the reference sets its six routes: a counted
   number over a heading in caps, on a hairline grid with no card edges of its
   own. The number is CSS, not markup -- decimal-leading-zero gives 01..06 and
   renumbers itself if a card is ever added or dropped.

   The icons they replace are gone rather than moved: a number and a pictogram
   on the same card are two systems for one job, and the number is the one the
   grid reads by. */
.wgrid{counter-reset:wcard}
.wcard{counter-increment:wcard;padding-top:2.1rem}
.wcard .wico{display:none}
.wcard::before{
  content:counter(wcard,decimal-leading-zero);
  display:block;margin-bottom:1.5rem;
  font-size:.68rem;font-weight:700;letter-spacing:.18em;
  font-variant-numeric:tabular-nums;color:var(--blue-t);
}
.wtitle{text-transform:uppercase;font-size:1rem;letter-spacing:-.01em;margin-bottom:.6rem}
.wbody{font-size:.84rem}
/* The steps already carry their own numbers; they get the same caps heading so
   the two sections read as one system. */
.stitle{text-transform:uppercase;letter-spacing:-.02em}

/* ─────────────────────────────────────────────
   HERO — the lattice, placed

   assets/hero3d.js draws a turning wireframe cube into this canvas. Every
   rule here is about where it sits and what it must not cover: the editorial
   hero is bottom-anchored, so the type occupies the lower-left and the cube
   takes the space above and to the right of it that the rebuild left empty.

   A positioned box rather than inset:0. The scene is centred in its own
   canvas, so a full-bleed canvas would centre the cube on the screen -- which
   is exactly where the headline is. Giving the canvas the corner puts the
   cube in the corner, and costs a fraction of the pixels to fill.
───────────────────────────────────────────── */
#hero3d{
  position:absolute;
  /* Cropped off the right edge the way the reference crops it, but high
     rather than low, and smaller than the first attempt at it.

     It cannot take the bottom-right corner the reference uses: on this hero
     that corner holds the two actions, and the lower-left holds a headline
     set at 7rem. Sized to fill the one quarter of the frame the editorial
     layout leaves empty -- at min(78vw,980px) the limb cut straight through
     "PRESENCE." and came out behind the demo button, which is a planet
     competing with the two things on the page that have a job. */
  top:-15%;
  right:-9%;
  width:min(58vw,735px);
  height:min(86vh,735px);
  /* Above the aurora (z-index -2) and the grain, below .hero-content (2). */
  z-index:1;
  /* Decorative, and it sits over the top half of the hero: without this it
     would eat the pointer on its way to the nav and the scroll hint. */
  pointer-events:none;
  /* The canvas is sized in device pixels by the script; these keep the CSS
     box authoritative whatever it writes into width/height. */
  display:block;
  /* Nothing is drawn until the context is up and the first frame is out, so
     the canvas fades in rather than appearing mid-turn. Roughly with the
     headline, which finishes its rise at 1.6s. */
  opacity:0;
  transition:opacity 1.2s cubic-bezier(.16,1,.3,1) .35s;
  /* Dissolve the edges. Without it the cube ends on four hard canvas edges
     that read as a box sitting on the hero rather than a depth in it. */
  -webkit-mask-image:radial-gradient(64% 64% at 52% 44%,#000 0%,rgba(0,0,0,.78) 62%,transparent 88%);
  mask-image:radial-gradient(64% 64% at 52% 44%,#000 0%,rgba(0,0,0,.78) 62%,transparent 88%);
}
#hero3d.on{opacity:1}

/* Right-to-left markets set the headline to the right, so the cube takes the
   other corner with it. The scene itself is symmetric; only the box moves. */
[dir="rtl"] #hero3d{right:auto;left:-6%}

/* ── Narrow screens ──────────────────────────────────────────────────────
   There is no empty corner on a phone -- the hero is one column and the type
   fills it. The cube goes behind the type instead, larger and much fainter,
   where it works as a texture on the ground rather than as an object beside
   the words. */
@media(max-width:900px){
  #hero3d{
    top:2%;
    right:-22%;
    width:118vw;
    height:min(62vh,560px);
  }
  #hero3d.on{opacity:.55}
}

/* The one place the canvas is a liability: a hero shorter than it is wide, on
   a phone held sideways, leaves the cube sitting on the headline with no room
   above it to go. */
@media(max-height:520px) and (orientation:landscape){
  #hero3d{display:none}
}

/* prefers-reduced-motion: the script already draws a single still frame and
   never starts the loop, so the cube is kept -- it is a shape on the hero, not
   a movement. Only the fade-in is dropped, because that is the animation. */
@media(prefers-reduced-motion:reduce){
  #hero3d{transition:none}
}

/* ─────────────────────────────────────────────
   INNER PAGES — the editorial system, finished

   39-editorial.css set the grounds and the type roles once and let the
   sections inherit them, which carried most of the rebuild onto About,
   Pricing and Contact for free: bracketed labels, caps display type, pills
   for actions and square corners everywhere else, the numbered cards.

   Two things it did not reach, because they are markup and not tokens, are
   here:

   1. The page headers opened flat -- label, headline, standfirst -- where the
      home hero had gained a ticked row of proof under its headline. Three
      pages opening on a different anatomy from the fourth is the kind of
      seam a visitor cannot name but can see.

   2. The pricing FAQ was still the old design underneath the new one: five
      rounded cards on a tinted ground, laid out by inline styles, sitting in
      a section where everything else is a hairline rule. It is rebuilt below
      as counted rows, which is what the rest of the site does with a list.
───────────────────────────────────────────── */

/* ── The proof row on a page header ──────────────────────────────────────
   The same .trust object as the hero, so it inherits the ticks, the weight
   and the twelve translations. Only the space around it differs: the header
   ends here, and the section's own bottom padding is the gap to what
   follows, so the row's lower margin comes off. */
.phero-trust{margin:2.2rem 0 0}

/* ── FAQ ─────────────────────────────────────────────────────────────────
   Counted rows on hairlines, the way the numbered cards and the contact
   details are set. The number is CSS rather than markup, as it is on the
   cards: decimal-leading-zero gives 01..05 and renumbers itself if a
   question is added or dropped, and applyLang refills the summary text
   without touching it. */
.faq{
  counter-reset:faq;
  /* Flush left across the measure, not a centred block. Every other list on
     the site -- the contact details, the extras grid, the pricing columns --
     starts where its heading starts and runs the width of the column, and a
     narrower box floating in the middle of the section was the last thing on
     these pages that did not line up with the heading above it. The answers
     keep a reading measure of their own below. */
  margin:3.4rem 0 0;
  border-top:1px solid var(--line);
}
.faq-i{counter-increment:faq;border-bottom:1px solid var(--line)}

.faq-q{
  display:flex;align-items:baseline;gap:1.3rem;
  padding:1.45rem 0;cursor:pointer;
  font-size:clamp(.92rem,1.5vw,1.08rem);font-weight:700;
  text-transform:uppercase;letter-spacing:-.015em;line-height:1.35;
  color:var(--ink);
  transition:color .25s;
  /* The default triangle, twice: Firefox and the old WebKit spelling. It is
     replaced by the marker drawn in ::after below. */
  list-style:none;
}
.faq-q::-webkit-details-marker{display:none}
.faq-q:hover{color:var(--blue-t)}
/* Keyboard focus lands on the summary, and without this the only signal is
   the row opening -- which is also what a mouse does, so there is none. */
.faq-i:focus-within .faq-q{color:var(--blue-t)}

.faq-q::before{
  content:counter(faq,decimal-leading-zero);
  flex:none;width:2.4rem;
  font-size:.68rem;font-weight:700;letter-spacing:.18em;
  font-variant-numeric:tabular-nums;color:var(--blue-t);
  text-transform:none;
}

/* The marker is two crossed gradients rather than a glyph, so it is the same
   1.5px as the hairlines it sits among at any size, and rotating it 45deg
   turns the plus into a cross on open -- one element, both states. */
.faq-q::after{
  content:'';
  flex:none;margin-inline-start:auto;
  width:13px;height:13px;
  align-self:center;
  background:
    linear-gradient(var(--blue),var(--blue)) center/100% 1.5px no-repeat,
    linear-gradient(var(--blue),var(--blue)) center/1.5px 100% no-repeat;
  transition:transform .3s cubic-bezier(.16,1,.3,1);
}
.faq-i[open] .faq-q::after{transform:rotate(45deg)}

/* Indented to the number's column, so every answer starts on the same line
   the questions do. */
.faq-a{padding:0 2.4rem 1.7rem calc(2.4rem + 1.3rem)}
.faq-a p{
  font-size:.88rem;line-height:1.85;color:var(--ink2);
  max-width:68ch;
}

@media(max-width:768px){
  .phero-trust{margin-top:1.6rem}
  .faq{margin-top:2.4rem}
  .faq-q{gap:.9rem;padding:1.25rem 0}
  .faq-q::before{width:1.9rem}
  .faq-a{padding:0 0 1.4rem calc(1.9rem + .9rem)}
}

/* ─────────────────────────────────────────────
   PARTNER PROGRAMME

   The page is built almost entirely from components that already existed --
   the dark page header with its proof row, the numbered steps from the home
   page, the form wrapper from Contact, the counted FAQ rows from Pricing.
   That is deliberate: a page selling a commission deal has to look like the
   rest of the company, and the fastest way to look like the rest of the
   company is to be made of it.

   Two things are new, and only because nothing on the site did their job:
   the terms panel, and the line that tells a referred visitor their discount
   is attached.
───────────────────────────────────────────── */

/* ── The terms ───────────────────────────────────────────────────────────
   Six facts, each a label over a figure, on the same hairline grid the
   extras and the pricing columns use. A panel rather than prose because
   these are the numbers somebody will come back to check, and a reader
   checking a commission rate should not have to find it inside a paragraph.

   Three columns for six cells, so it is two clean rows at every width that
   can hold them. */
.terms{
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:1px;background:var(--line);border:1px solid var(--line);
  margin-top:3rem;
}
.terms>*{min-width:0}
.term{
  background:var(--bg);padding:1.6rem 1.7rem;
  display:flex;flex-direction:column;gap:.55rem;
  transition:background .25s;
}
.term:hover{background:var(--bg2)}
.term-n{
  font-size:.6rem;font-weight:700;letter-spacing:.24em;text-transform:uppercase;
  color:var(--muted);
}
.term-v{
  font-size:1.02rem;font-weight:800;letter-spacing:-.02em;line-height:1.35;
  color:var(--ink);
  /* "Maandelijks, per overschrijving" in German is one long word plus one
     longer word, and these cells are a third of the column. */
  overflow-wrap:break-word;hyphens:auto;-webkit-hyphens:auto;
}

/* ── The referred-visitor note ───────────────────────────────────────────
   Shown on the demo form when the visitor arrived on a partner's link, so
   the discount they were promised is visible before they submit rather than
   only on the quote that turns up later.

   It is hidden in the markup and unhidden by applyLang, and only in the
   languages that carry the string -- see the note in the contact form. The
   hidden field beside it is filled either way, so a market without the copy
   still attributes the referral; it just does not say so out loud. */
.ref-note{
  margin:0 0 1rem;padding:.75rem .95rem;
  border-left:2px solid var(--blue-d);
  background:rgba(74,144,226,.06);
  font-size:.8rem;line-height:1.65;color:var(--ink2);
}
.ref-note strong{color:var(--blue-t);font-weight:700}
/* The border is the one thing that has to move: on an Arabic page a rule on
   the left of the text is a rule at the end of it. */
[dir="rtl"] .ref-note{border-left:none;border-right:2px solid var(--blue-d)}

@media(max-width:900px){
  .terms{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:560px){
  .terms{grid-template-columns:1fr;margin-top:2.2rem}
  .term{padding:1.3rem 1.4rem}
}

/* ─────────────────────────────────────────────
   LIGHT SECTIONS — the same material as the dark ones

   The dark sections carry three layers: a drifting aurora, an 88px grid and
   a grain. The light sections carried nothing, which is half of why the page
   went flat below the hero — not only were the grounds all one colour, they
   were one *texture*, and the two halves of the page read as two different
   materials with a seam between them.

   This is the dark sections' own layer, re-tinted. Same 88px module, same
   SVG turbulence, same radial mask that fades it out at the edges so it
   never ends on a hard line. Only the alpha changes: ink at 3.5% where the
   dark uses white at 5%, because a grid that is legible on near-black is a
   grid you can count on paper.

   Deliberately quiet. At this weight it is not a pattern a visitor will
   notice or be able to describe; it is the difference between a screen and a
   sheet of paper, and it is doing its job when nobody mentions it.

   ── Why ::after and not a background-image on the section ──
   The sections already use background for their ground, and .sec-alt now
   redefines tokens on top of that. A separate layer keeps the texture
   independent of whichever ground it lands on, so white and bone get the
   same drawing without either rule knowing about the other.
───────────────────────────────────────────── */

/* isolation, not overflow:hidden. The pseudo-element below sits at z-index:-1
   so it paints above the section's own background and below its content, and
   that only works inside a stacking context -- without isolation it would
   drop behind the ground and be invisible. overflow:hidden would have done
   it too and would also have clipped the pricing column's 50px glow and the
   cards' hover shadows, which reach past their section. */
.sec:not(.dark),.soc-sec{position:relative;isolation:isolate}

.sec:not(.dark)::after,.soc-sec::after{
  content:'';
  position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:
    linear-gradient(rgba(26,31,54,.035) 1px,transparent 1px),
    linear-gradient(90deg,rgba(26,31,54,.035) 1px,transparent 1px),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.16'/%3E%3C/svg%3E");
  background-size:88px 88px,88px 88px,180px 180px;
  /* Fades the drawing out before it reaches the edge, so the grid never
     collides with the hairline between two sections and turn the seam into a
     ladder. The same ellipse the dark sections use, one notch wider because
     a light section is usually shorter. */
  -webkit-mask-image:radial-gradient(ellipse 94% 84% at 50% 45%,#000 30%,transparent 100%);
          mask-image:radial-gradient(ellipse 94% 84% at 50% 45%,#000 30%,transparent 100%);
}

/* The grid is a drawing, not information. On a screen that cannot resolve a
   1px line at 3.5% it is either invisible or it is banding, and the grain is
   the part that survives. Drop the lines and keep the paper. */
@media (max-width:560px){
  .sec:not(.dark)::after,.soc-sec::after{
    background-image:
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.16'/%3E%3C/svg%3E");
    background-size:180px 180px;
  }
}

/* ─────────────────────────────────────────────
   PAGE ART — the illustration in a page header, and the team

   Two things, in one file because they share one decision: the site has no
   photography and buying some would have been a different project, so both
   are drawn in line rather than shot. Thin strokes, square ends, the blue
   used once per drawing -- the same hand as the icons that were already
   here, at four times the size.

   The home page is not included on purpose. Its hero already carries the
   turning lattice from 40-hero-3d.css, and a second illustration beside it
   would be two drawings competing for the same screen.

   Placement in the cascade: after 43 because it overrides the single-column
   .phero set in 39-editorial.css, and it carries its own breakpoints, which
   26-responsive.css (earlier in the concatenation) cannot reach.
───────────────────────────────────────────── */

/* ── The page header, as two columns ─────────────────────────────────────
   The copy keeps the measure it had -- the drawing takes the space that was
   empty to the right of it, not space off the headline. minmax(0,…) on both
   tracks because the headline is caps with break-word: without it a long
   word in German or Dutch sets the column's min-content width and pushes
   the drawing off the page. */
.phero-grid{
  display:grid;
  grid-template-columns:minmax(0,1.12fr) minmax(0,.88fr);
  align-items:center;
  gap:clamp(2rem,5vw,4.5rem);
}
.phero-copy{min-width:0}

/* The headline comes down a notch, because its column did.
   39-editorial.css sizes .phero-h1 for the full width of the page, and at
   that size the longest word on these four pages -- RECOMMENDATION, and
   RECOMMANDATION in French -- no longer fits half of it: it hit the
   break-word backstop and set as RECOMMENDATI / ON. This is the same
   calculation redone against the narrower measure, and it only applies
   inside the two-column header, so a page header without a drawing would
   keep the larger size. */
.phero-grid .phero-h1{font-size:clamp(2.4rem,4.6vw,4.2rem)}
/* Below 960px the columns collapse and the copy has the full width back, so
   the headline goes back up to the size 39-editorial.css sets -- with one
   change to that size, which is the floor.

   clamp(2.6rem,6.4vw,5.4rem) stops responding below about 406px, because
   under that width 6.4vw is smaller than the 2.6rem floor and the floor
   wins. The type then stays 41.6px while the screen keeps narrowing, and by
   320px the longest word on these pages is wider than the page: measured,
   RECOMMENDATION wanted 381px in a 288px column, Uberraschungen 384, and
   verrassingen 301. All three hit the break-word backstop and set with a
   letter or two orphaned on a line of their own.

   9.2vw with a 1.85rem floor keeps scaling all the way down and leaves the
   worst of those three about 7% of clearance at every width from 320 up. */
@media(max-width:960px){
  .phero-grid .phero-h1{font-size:clamp(1.85rem,9.2vw,5.4rem)}
}

/* The drawing. A square box that never grows past its natural size, pinned
   to the outer edge of its column so the gap between copy and art is the
   gutter and not a pool of dead space in the middle. */
.phero-art{
  min-width:0;
  justify-self:end;
  width:100%;max-width:440px;
  /* Decorative. It is aria-hidden in the markup too; this is for anything
     that reaches the SVG some other way. */
  pointer-events:none;
}
.phero-art svg{display:block;width:100%;height:auto;overflow:visible}

/* The three ink weights every drawing is built from, so a new one inherits
   the palette instead of restating it. On .dark these resolve to white and
   the light blue; on a light ground they would resolve to near-black, which
   is what makes the same markup safe if a header ever stops being dark. */
.pa-line{fill:none;stroke:var(--ink);stroke-opacity:.34;stroke-width:1.25;stroke-linejoin:round}
.pa-key {fill:none;stroke:var(--blue);stroke-opacity:.95;stroke-width:1.5;stroke-linejoin:round}
.pa-fill{fill:var(--ink);fill-opacity:.045}
.pa-fill-key{fill:var(--blue);fill-opacity:.12}
.pa-dot{fill:var(--blue)}
.pa-t{
  fill:var(--ink);fill-opacity:.5;
  font-family:inherit;font-size:8px;font-weight:700;letter-spacing:.18em;
  text-transform:uppercase;
}

/* The graph-paper backdrop each drawing sits on: one tile, repeated by the
   pattern, so the grid is four lines of markup rather than forty. */
.pa-grid{stroke:var(--ink);stroke-opacity:.09;stroke-width:1;fill:none}

/* Motion: the whole drawing breathes, and one or two parts drift against it.
   Transform only, so it stays on the compositor, and 31-reduced-motion.css
   already stops every animation on the site at the root. */
@keyframes pa-float{from{transform:translateY(-5px)}to{transform:translateY(5px)}}
@keyframes pa-drift{from{transform:translateY(3px)}to{transform:translateY(-7px)}}
@keyframes pa-pulse{0%,100%{opacity:.25}50%{opacity:1}}
.pa-float{animation:pa-float 7s ease-in-out infinite alternate}
.pa-drift{animation:pa-drift 5.2s ease-in-out infinite alternate}
.pa-pulse{animation:pa-pulse 3.4s ease-in-out infinite}

/* Under 960px the two columns become one and the drawing goes below the
   standfirst, smaller and centred -- it is support for the headline, and on
   a phone the headline should still be the first full thing on screen. */
@media(max-width:960px){
  .phero-grid{grid-template-columns:1fr;gap:2.6rem}
  .phero-art{justify-self:center;max-width:340px}
}
@media(max-width:560px){
  .phero-art{max-width:270px}
}

/* ─────────────────────────────────────────────
   THE TEAM  --  not on the page at the moment

   The markup is out of src/over-ons/index.html until the four portraits
   have been taken. It is not lost: it is on the branch `our-team-section`
   of the drp-compro remote, with that page as it stood with the section in.

       git checkout our-team-section -- src/over-ons/index.html
       npm run build

   Everything the section needs is still here and costs nothing without it:
   the rules below, the team.* keys in all twelve languages in
   assets/i18n.js, and the block in applyLang() that fills them. Only the
   markup went, and only because placeholder names reading "Naam
   Achternaam" in the shipped HTML of thirty-four markets is not a thing to
   leave lying around while it waits. Comments in src/ are served verbatim,
   so this note lives here rather than in the page.


   Four people, set the way the rest of the site sets a list: hairline rules,
   a counted number, caps headings. The portraits are placeholders -- a
   monogram over a drawn bust -- and they are sized and framed exactly as a
   photograph will be, so replacing one is swapping the contents of .tm-ph
   for an <img> and nothing else moves. See the note in the markup.
───────────────────────────────────────────── */
.team-grid{
  display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(1.4rem,2.6vw,2.4rem);
  margin-top:3.4rem;
  counter-reset:tm;
}
.tm{counter-increment:tm;min-width:0}

/* The frame. 4:5 because that is the crop a portrait is taken in, and fixing
   it here means four photographs of four different shapes still line up
   along the bottom.

   The ground is flat. The graph paper the page headers are drawn on was
   tried here and did not survive being repeated four times across a row:
   at this size it stopped being a backdrop and became the loudest thing in
   the section. The frames carry a gradient instead, and the crop marks do
   the work of saying a picture belongs here. */
.tm-ph{
  position:relative;
  aspect-ratio:4/5;
  border:1px solid var(--line);
  background:
    linear-gradient(180deg,rgba(26,31,54,.02) 0%,rgba(26,31,54,.055) 100%),
    var(--bg2);
  overflow:hidden;
}
/* Crop marks in two corners, the way a photograph is marked up for the
   printer -- the thing that says "a picture belongs here" without a word of
   copy to translate. They go when a real portrait lands. */
.tm-ph::before,.tm-ph::after{
  content:'';position:absolute;width:14px;height:14px;
  border:1px solid var(--blue);opacity:.55;
}
.tm-ph::before{top:10px;left:10px;border-right:0;border-bottom:0}
.tm-ph::after{bottom:10px;right:10px;border-left:0;border-top:0}

/* Drop a real photograph in and it fills the same frame -- and covers the
   crop marks and the figure, because it is painted over both. */
.tm-ph img{position:relative;z-index:1;display:block;width:100%;height:100%;object-fit:cover}

/* The placeholder figure. Centred and held to a fraction of the frame, so
   it stays a small drawing on a large ground instead of growing into a
   pictogram the size of the card. */
.tm-fig{
  position:absolute;left:50%;top:46%;transform:translate(-50%,-50%);
  width:56%;height:auto;max-width:150px;
}

/* The monogram, bottom-left inside the frame, where a caption would sit. */
.tm-mono{
  position:absolute;z-index:2;left:0;bottom:0;
  padding:.5rem .7rem;
  font-size:.62rem;font-weight:700;letter-spacing:.2em;
  color:var(--blue-t);
  background:var(--bg);
}

.tm-n{
  display:block;margin:1.1rem 0 .5rem;
  font-size:.68rem;font-weight:700;letter-spacing:.18em;
  font-variant-numeric:tabular-nums;color:var(--blue-t);
}
.tm-n::before{content:counter(tm,decimal-leading-zero)}
.tm-name{
  font-size:1rem;font-weight:700;line-height:1.2;
  text-transform:uppercase;letter-spacing:-.01em;color:var(--ink);
}
.tm-role{
  margin-top:.35rem;
  font-size:.66rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted2);
}
.tm-body{margin-top:.75rem;font-size:.84rem;line-height:1.6;color:var(--muted)}

/* Two up on a tablet, one up on a phone. Four 1fr columns at 600px gives
   each portrait about 120px, at which point the monogram is wider than the
   face it sits on. */
@media(max-width:900px){
  .team-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:2rem 1.6rem}
}
@media(max-width:520px){
  .team-grid{grid-template-columns:1fr;gap:2.4rem}
  .tm-ph{aspect-ratio:3/2}
}

/* ── Right to left ───────────────────────────────────────────────────────
   The drawings read across the page: the partner link runs from the link
   out to its two ends, the contact drawing puts the site first and the call
   second. In Arabic that order is back to front, so the whole drawing is
   mirrored. Safe to do bluntly because none of them contains a glyph -- the
   one thing a scaleX would reverse. The monogram in a team portrait is
   text, and it sits outside the SVG.

   Stacked on the float transform rather than replacing it: an animation on
   the same element would win, so the flip goes on the <svg> and the motion
   stays on the wrapper. */
[dir="rtl"] .phero-art svg{transform:scaleX(-1)}

/* ─────────────────────────────────────────────
   THE OPEN DROPDOWN OF A <select>

   A select's closed box is ours to style. The list it opens is not: it is
   drawn by the operating system, in a window that is not part of the page,
   and on Windows and Android that window's background is white no matter
   what the page is doing. What the OS does take from us is the colour of
   the <option> text -- and with nothing set, an option inherits the colour
   of the select it belongs to.

   That is the bug. 39-editorial.css gives the market picker white text
   while the bar is over a dark hero:

       nav:not(.s) .market-sw select{color:rgba(255,255,255,.82)}

   which is right for the closed box on black, and wrong for the list, where
   it painted white text onto the OS's white window. Every market was
   invisible except the one under the cursor, which the system paints with
   its own highlight and its own white-on-blue -- so the list looked empty
   apart from a single blue row that moved with the mouse.

   Literal values, not tokens. --ink is what the page has just redefined in
   .dark, so var(--ink) here would resolve to white in exactly the places
   this rule exists to rescue -- which is also why the contact form's own
   option rule, written with var(--ink), is restated below rather than left
   alone. It works today only because those forms happen to sit on a light
   ground, and it would fail the moment one did not.

   color-scheme tells the OS to draw the whole popup -- window, scrollbar,
   highlight -- in its light set, so the colours below sit on the surface
   they were chosen against rather than on a dark one on a machine set to
   dark mode.
───────────────────────────────────────────── */
select{color-scheme:light}

/* The .field selector repeats the one in 20-contact.css so this wins on
   document order rather than needing !important; the bare `select option`
   covers the market picker and anything added later. */
select option,
select optgroup,
.field select option{
  color:#1a1f36;
  background-color:#fff;
}
