/* ============================================================
   G3T — KINEMA PREMIERE production site
   Shared design system extracted from concept 22.
   White screen. CinemaScope mattes. Scroll is the projector.
   Reduced-motion is driven by html.rm (set by kinema.js, which
   honors the system setting unless the user forces motion on).
   ============================================================ */
:root{
  --paper:#FFFFFF;
  --ink:#0A1420;
  --muted:#50627A;
  --blue:#0176FF;
  --green:#04C900;
  --teal:#00BFA8;
  --navy:#062A6E;
  --hair:#E4EAF1;
  --hair2:#C9D5E2;
  --grad:linear-gradient(100deg,var(--blue),var(--teal) 55%,var(--green));
  /* --grad is for decorative fills. As TEXT its teal and green stretches measure
     2.33:1 and 2.24:1 on white, under the 3:1 floor for large text, so gradient
     lettering uses this ramp instead — worst point along it is 4.52:1, which
     clears 4.5:1 at any size. */
  --grad-text:linear-gradient(100deg,#0159C4,#00857A 55%,#067D33);
  --shadow-blue:0 24px 60px rgba(1,118,255,.16);
  --shadow-soft:0 2px 6px rgba(10,20,32,.05),0 22px 55px rgba(10,20,32,.09);
  --fd:"Archivo",system-ui,sans-serif;
  --fb:"Inter",system-ui,sans-serif;
  --fm:"JetBrains Mono",Consolas,monospace;
  --pad:clamp(20px,4vw,52px);
  --wide:1340px;
  --mid:1120px;
  --ease:cubic-bezier(.22,1,.36,1);
}
*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
html.rm{scroll-behavior:auto}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--fb);font-size:1rem;line-height:1.65;
  -webkit-font-smoothing:antialiased;overflow-x:hidden;
}
img,svg,canvas{display:block;max-width:100%}
h1,h2,h3{font-family:var(--fd);font-weight:900;line-height:.96;letter-spacing:-.015em;margin:0 0 .45em;text-transform:uppercase}
p{margin:0 0 1em;max-width:var(--measure,66ch)}
a{color:var(--blue);text-decoration:none}
a:hover{color:#0055C4}
ul{margin:0;padding:0;list-style:none}
button{font:inherit;cursor:pointer}
::selection{background:rgba(1,118,255,.22)}
:focus-visible{outline:2px solid #0055C4;outline-offset:3px;border-radius:3px}
.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;clip-path:inset(50%);overflow:hidden;white-space:nowrap}
.wrap{max-width:var(--wide);margin:0 auto;padding-inline:var(--pad)}
.wrap-mid{max-width:var(--mid);margin:0 auto;padding-inline:var(--pad)}
.muted{color:var(--muted)}
.lead{font-size:clamp(1.05rem,1.5vw,1.3rem);color:var(--muted);line-height:1.6}

/* ---------- film progress bar ---------- */
.film-bar{position:fixed;inset:0 0 auto 0;height:4px;z-index:90;background:rgba(10,20,32,.07)}
.film-bar i{display:block;height:100%;width:0;background:var(--grad)}

/* ---------- OPENING IDENT ---------- */
.ident{position:fixed;inset:0;background:var(--paper);z-index:200;display:flex;align-items:center;justify-content:center;transition:opacity .7s var(--ease),visibility 0s linear .7s;pointer-events:none}
.ident.done{opacity:0;visibility:hidden}
.ident canvas{position:absolute;inset:0;width:100%;height:100%}
.ident-mark{position:relative;z-index:2;text-align:center;opacity:0;transform:scale(.92);transition:opacity .45s var(--ease),transform .45s var(--ease)}
.ident.reveal .ident-mark{opacity:1;transform:none}
.ident-mark svg{height:64px;width:auto;margin:0 auto 16px}
.ident-mark span{font-family:var(--fm);font-size:.7rem;letter-spacing:.5em;text-transform:uppercase;color:var(--muted);display:block;padding-left:.5em}
body.ident-lock{overflow:hidden}
html.rm .ident{display:none}

/* ---------- SCENE RAIL ---------- */
/* Scene-index rail removed per client request — markup stays for possible reinstatement. */
.rail{display:none !important}
.rail li{margin:7px 0}
.rail a{display:flex;align-items:center;gap:10px;font-family:var(--fm);font-size:.6rem;letter-spacing:.16em;text-transform:uppercase;color:var(--hair2);transition:color .2s;min-height:22px}
.rail a::before{content:"";width:14px;height:1px;background:currentColor;flex:none;transition:width .2s}
.rail a:hover{color:var(--muted)}
.rail a.on{color:var(--ink)}
.rail a.on::before{width:26px;background:var(--green)}
.rail a .rn{display:none}
.rail a.on .rn{display:inline-block;max-width:118px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background:rgba(255,255,255,.92);border:1px solid var(--hair2);border-radius:999px;padding:3px 10px}

/* ---------- CINEMASCOPE mattes + slates ---------- */
.pin-track{position:relative}
.pin-stick{position:sticky;top:0;height:100vh;min-height:600px;overflow:hidden;display:flex;align-items:center;--mh:0px}
.scene-canvas{position:absolute;inset:0;width:100%;height:100%}
.matte{position:absolute;left:0;right:0;height:var(--mh);background:var(--paper);z-index:5;pointer-events:none}
.matte-t{top:0;box-shadow:0 1px 0 var(--hair)}
.matte-b{bottom:0;box-shadow:0 -1px 0 var(--hair)}
.scene-slate{position:absolute;left:var(--pad);top:calc(var(--mh) + 16px);z-index:6;font-family:var(--fm);font-size:.66rem;letter-spacing:.22em;text-transform:uppercase;color:var(--muted);display:flex;align-items:center;gap:10px}
.scene-slate::before{content:"";width:13px;height:13px;flex:none;background:var(--grad);clip-path:polygon(0 0,100% 0,100% 62%,0 100%)}
.scene-tc{position:absolute;right:var(--pad);top:calc(var(--mh) + 16px);z-index:6;font-family:var(--fm);font-size:.66rem;letter-spacing:.2em;color:var(--muted);text-transform:uppercase;text-align:right}
.on-blue .scene-slate,.on-blue .scene-tc{color:rgba(255,255,255,.85)}
/* film grain + vignette (scene viewports only; canvas injected by JS) */
.film-grain{position:absolute;inset:0;z-index:4;pointer-events:none;opacity:.035}
.vignette{position:absolute;inset:0;z-index:4;pointer-events:none;background:radial-gradient(120% 120% at 50% 50%,transparent 62%,rgba(10,20,32,.10))}

/* ---------- slate (in-flow section header device) ---------- */
.slate{display:flex;align-items:center;gap:14px;margin-bottom:26px;font-family:var(--fm);font-size:.74rem;letter-spacing:.2em;text-transform:uppercase;color:var(--muted)}
.slate::before{content:"";width:14px;height:14px;flex:none;background:var(--grad);clip-path:polygon(0 0,100% 0,100% 62%,0 100%)}
.slate::after{content:"";flex:1;height:1px;background:var(--hair)}
.slate b{font-weight:500;color:var(--ink)}

/* wipe-in titles + rises */
.wipe{overflow:hidden}
.wipe>span{display:block;transform:translateY(112%);transition:transform .8s var(--ease)}
.wipe.in>span{transform:none}
.rise{opacity:0;transform:translateY(26px);transition:opacity .7s var(--ease),transform .7s var(--ease)}
.rise.in{opacity:1;transform:none}
.d1{transition-delay:.09s}.d2{transition-delay:.18s}.d3{transition-delay:.27s}.d4{transition-delay:.36s}
html.rm .wipe>span{transform:none;transition:none}
html.rm .rise{opacity:1;transform:none;transition:none}

/* ---------- buttons ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:10px;min-height:50px;padding:13px 30px;border-radius:4px;font-family:var(--fd);font-weight:800;font-size:.85rem;letter-spacing:.08em;text-transform:uppercase;border:1px solid transparent;transition:transform .2s var(--ease),box-shadow .2s var(--ease),background-color .2s var(--ease),color .2s var(--ease),border-color .2s var(--ease)}
.btn .arr{transition:transform .2s var(--ease)}
.btn:hover .arr{transform:translateX(4px)}
.btn-ink{background:var(--ink);color:#fff;position:relative}
.btn-ink::after{content:"";position:absolute;left:0;right:0;bottom:0;height:3px;background:var(--grad);opacity:0;transition:opacity .2s}
.btn-ink:hover{color:#fff;box-shadow:var(--shadow-blue)}
.btn-ink:hover::after{opacity:1}
.btn-line{border-color:var(--hair2);color:var(--ink);background:#fff}
.btn-line:hover{border-color:var(--blue);color:var(--ink)}
.btn-navy{background:var(--navy);color:#fff}
.btn-navy:hover{color:#fff;box-shadow:0 18px 44px rgba(6,42,110,.3)}
.ticket{position:relative;padding-left:38px}
.ticket::before{content:"";position:absolute;left:16px;top:50%;width:12px;height:12px;transform:translateY(-50%);border-radius:50%;box-shadow:inset 0 0 0 2px currentColor;opacity:.6}

/* ---------- header ---------- */
.hd{position:fixed;inset:0 0 auto 0;top:4px;z-index:70;background:rgba(255,255,255,.92);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-bottom:1px solid transparent;transition:border-color .2s}
.hd.sc{border-bottom-color:var(--hair)}
/* mobile: the header floats transparent at the top, glasses back on scroll */
@media (max-width:760px){
  body:not(.noir-body) .hd{background:transparent;backdrop-filter:none;-webkit-backdrop-filter:none;
    transition:background .3s var(--ease),border-color .2s}
  body:not(.noir-body) .hd.sc{background:rgba(255,255,255,.9);
    backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}
}
.hd-in{max-width:var(--wide);margin:0 auto;padding:0 var(--pad);height:72px;display:flex;align-items:center;gap:22px}
.logo{display:inline-flex;align-items:center;gap:12px;margin-right:auto}
.logo svg{height:38px;width:auto}
.logo .lg-sub{font-family:var(--fm);font-size:.58rem;letter-spacing:.3em;color:var(--muted);text-transform:uppercase}
.nav{display:flex;align-items:center;gap:2px}
.nav>li{position:relative}
.nlink{display:inline-flex;align-items:center;gap:7px;padding:10px 13px;min-height:44px;font-family:var(--fm);font-size:.73rem;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);background:none;border:0;border-radius:4px;transition:color .2s;white-space:nowrap}
.nlink:hover,.nlink[aria-expanded="true"]{color:var(--ink)}
.nlink.on{color:var(--ink);box-shadow:inset 0 -2px 0 var(--green)}
.nlink .caret{transition:transform .2s}
.nlink[aria-expanded="true"] .caret{transform:rotate(180deg)}
/* motion toggle */
.motion-btn{display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:8px 14px;font-family:var(--fm);font-size:.62rem;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);background:#fff;border:1px solid var(--hair2);border-radius:4px;white-space:nowrap}
.motion-btn:hover{color:var(--ink);border-color:var(--blue)}
.motion-btn i{font-style:normal;width:8px;height:8px;border-radius:50%;background:var(--hair2)}
.motion-btn.live i{background:var(--green)}

/* Centre-aligned labels and overlay lines span the frame: with the default
   measure they keep their start edge and centre the text inside it. */
.s2-sub,.s2-chain,.poster-rule,.release{--measure:none}
/* Inside a centred column, centre the measure too instead of letting it
   hug the start edge. */
.s2-copy p{margin-inline:auto}

/* ---------- who we are: technology stack panel ----------
   Reads as a display rather than a film slate: the dark bezel bar is the same
   device as .st-bar on the project stills, labels are mono, rows are hairline
   separated. The spine beside the layers runs navy at the bottom to green at
   the top, so the stack is ordered physical infrastructure -> intelligence. */
/* the year is split into a static prefix and a counted span */
@media (max-width:860px){
}

/* ---------- who we are: system display ----------
   Reads as an instrument rather than a film slate: a bezel frame around a
   cool-tinted screen with a faint graticule, holding the stack as connected
   nodes. Colour lives on the decorative dots, never on text -- the accents
   fail contrast as type on a light surface (green 2.2:1, teal 2.3:1). */
.sysdisp{border-radius:14px;padding:10px;background:linear-gradient(#fff,#EFF4FA);border:1px solid var(--hair2);box-shadow:0 2px 6px rgba(10,20,32,.05),0 26px 60px rgba(10,20,32,.10)}
.sd-screen{position:relative;overflow:hidden;border-radius:9px;background:#F7F9FC;border:1px solid var(--hair);box-shadow:inset 0 1px 0 #fff;padding:20px 24px 0}
.sd-screen::before{content:"";position:absolute;inset:0;pointer-events:none;background-image:linear-gradient(to right,rgba(10,20,32,.04) 1px,transparent 1px),linear-gradient(to bottom,rgba(10,20,32,.04) 1px,transparent 1px);background-size:30px 30px}
.sd-screen>*{position:relative}
.sd-top{display:flex;align-items:baseline;justify-content:space-between;gap:14px;padding-bottom:13px;border-bottom:1px solid var(--hair)}
.sd-title{margin:0;font-family:var(--fd);font-weight:800;font-size:1rem;line-height:1.2;letter-spacing:0;text-transform:none;color:var(--ink)}
.sd-loc{margin:0;font-family:var(--fm);font-size:.66rem;letter-spacing:.08em;color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}
.sd-stack{list-style:none;margin:0;padding:0}
.sd-node{position:relative;display:grid;grid-template-columns:9px 88px 1fr;gap:13px;align-items:baseline;padding:13px 0;border-bottom:1px solid var(--hair)}
.sd-node:last-child{border-bottom:0}
.sd-dot{width:9px;height:9px;border-radius:50%;background:var(--nd);align-self:start;margin-top:5px;box-shadow:0 0 0 3px #F7F9FC}
.sd-node:not(:last-child)::after{content:"";position:absolute;left:4px;top:20px;bottom:-3px;width:1px;background:var(--hair2)}
.sd-name{font-family:var(--fd);font-weight:800;font-size:.92rem;color:var(--ink);text-transform:none;letter-spacing:0}
.sd-note{color:var(--muted);font-size:.9rem;line-height:1.5}
.sd-fields{display:grid;grid-template-columns:110px 1fr;gap:13px;align-items:baseline;padding:14px 0;border-top:1px solid var(--hair)}
.sd-lbl{font-family:var(--fm);font-size:.62rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.sd-val{color:var(--ink);font-size:.9rem;line-height:1.55}
.sd-figs{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin:0 -24px;padding:16px 24px 18px;border-top:1px solid var(--hair);background:rgba(255,255,255,.62)}
.sd-figs b{display:block;font-family:var(--fd);font-weight:900;font-size:clamp(1.3rem,2vw,1.7rem);line-height:1;color:var(--ink);white-space:nowrap;font-variant-numeric:tabular-nums}
.sd-figs b i{font-style:normal}
.sd-figs b .cnt{font:inherit;color:inherit;display:inline}
.sd-figs span{display:block;margin-top:6px;font-family:var(--fm);font-size:.58rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);line-height:1.4}
@media (max-width:860px){
  .sd-node{grid-template-columns:9px 1fr;row-gap:3px}
  .sd-note{grid-column:2}
  .sd-fields{grid-template-columns:1fr;gap:4px}
  .sd-figs{grid-template-columns:1fr;gap:16px}
}

/* mega */
.mega{position:absolute;top:calc(100% + 12px);left:50%;transform:translateX(-56%) translateY(8px);width:min(880px,calc(100vw - 40px));background:#fff;border:1px solid var(--hair);border-radius:10px;box-shadow:var(--shadow-soft);padding:26px;display:grid;grid-template-columns:1.6fr 1fr;gap:26px;opacity:0;visibility:hidden;pointer-events:none;transition:opacity .2s var(--ease),transform .2s var(--ease),visibility 0s linear .2s;z-index:60}
.mega.open{opacity:1;visibility:visible;pointer-events:auto;transform:translateX(-56%) translateY(0);transition-delay:0s}
.mg-list{display:grid;grid-template-columns:1fr 1fr;gap:6px}
.mg-it{display:block;padding:13px 15px;border-radius:8px;transition:background-color .15s}
.mg-it:hover{background:#F2F7FC}
.mg-it strong{display:block;font-family:var(--fd);font-weight:800;font-size:.92rem;color:var(--ink);text-transform:uppercase;letter-spacing:.02em;margin-bottom:3px}
.mg-it span{font-size:.82rem;color:var(--muted);line-height:1.45;display:block}
.mg-feat{border-left:1px solid var(--hair);padding-left:26px;display:flex;flex-direction:column;justify-content:center;gap:10px}
.tagchip{display:inline-block;align-self:flex-start;font-family:var(--fm);font-size:.64rem;letter-spacing:.16em;text-transform:uppercase;color:#0055C4;border:1px solid rgba(1,118,255,.35);border-radius:3px;padding:5px 10px}
.mg-feat strong{font-family:var(--fd);font-weight:800;font-size:1.05rem;text-transform:uppercase}
.mg-feat p{font-size:.85rem;color:var(--muted);margin:0}
.mg-feat .flink{font-family:var(--fm);font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;color:#067D33}
.hd-cta{margin-left:6px;white-space:nowrap;min-height:44px;padding:10px 22px}
.burger{display:none;width:46px;height:46px;border:1px solid var(--hair2);border-radius:6px;background:#fff;color:var(--ink);align-items:center;justify-content:center}
.drawer{display:none;position:fixed;inset:76px 0 0 0;background:#fff;z-index:65;overflow-y:auto;padding:26px var(--pad) 60px}
.drawer.open{display:block}
.drawer .dl{display:block;padding:16px 4px;font-family:var(--fd);font-weight:800;font-size:1.3rem;text-transform:uppercase;color:var(--ink);border-bottom:1px solid var(--hair)}
.drawer .ds{display:block;padding:12px 4px 12px 22px;font-size:.98rem;color:var(--muted);border-bottom:1px solid var(--hair)}
.drawer .ds:hover{color:var(--ink)}
.drawer .btn{margin-top:24px;width:100%}
/* language control — matches .motion-btn so the header reads as one row of controls */
.lang-btn{display:inline-flex;align-items:center;gap:9px;min-height:44px;padding:8px 11px;background:#fff;border:1px solid var(--hair2);border-radius:4px;white-space:nowrap;flex-shrink:0}
.lang-btn:hover{border-color:var(--blue)}
/* The language pair reads as flags. Selection is NOT carried by colour alone:
   the chosen flag is also at full opacity and wears a ring, so the state survives
   greyscale vision and a monochrome display. */
.lang-btn .lang-o{display:inline-flex;align-items:center;filter:grayscale(1);opacity:.45;
  transition:filter .18s var(--ease),opacity .18s var(--ease)}
.lang-btn .lang-o.on{filter:none;opacity:1}
.lang-btn .lang-flag{display:block;width:18px;height:18px;border-radius:50%;
  box-shadow:0 0 0 1px rgba(10,20,32,.22)}
.lang-btn .lang-o.on .lang-flag{box-shadow:0 0 0 1px rgba(10,20,32,.30),0 0 0 3px rgba(1,118,255,.30)}
.lang-btn:hover .lang-o{opacity:.7}
.lang-btn:hover .lang-o.on{opacity:1}
html.rm .lang-btn .lang-o{transition:none}
.drawer .lang-btn,.drawer .motion-btn{margin-top:24px}
.drawer .motion-btn{margin-right:10px}
/* Serbian nav labels run longer, so hand over to the drawer earlier than
   the English-only layout needed, keeping the language toggle clear of the edge. */
/* Once the burger owns the navigation, the language control belongs inside the
   menu with it rather than loose in the header — the drawer already carries
   its own copy. The burger takes the auto margin so it stays pinned right. */
@media (max-width:1240px){.nav,.hd-cta{display:none}
  .burger{display:inline-flex;margin-left:auto}
  .hd-in .lang-btn,.hd-in .motion-btn{display:none}}
/* Serbian labels run longer than English; keep the nav on one line and
   reclaim header space before it has to collapse. */
.logo{flex-shrink:0}
.nlink{white-space:nowrap}
@media (max-width:1340px){.hd-in{gap:12px}.nlink{padding-left:9px;padding-right:9px}}
@media (max-width:460px){.lg-sub{display:none}.lang-btn{padding:8px 9px;gap:7px}}

/* ---------- hero (scene 1) ---------- */
.hero-copy{position:relative;z-index:3;max-width:var(--wide);margin:0 auto;padding:90px var(--pad) 0;width:100%}
.kicker{font-family:var(--fm);font-size:clamp(.68rem,1.3vw,.82rem);letter-spacing:.3em;color:var(--muted);text-transform:uppercase;margin:0 0 26px;display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.kicker b{color:#067D33;font-weight:500}
h1.mega-title{font-size:clamp(2.7rem,8.2vw,7rem);max-width:12ch}
.grad-word{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent}
.hero-sub{font-weight:700;color:var(--ink);font-size:clamp(1.05rem,1.6vw,1.35rem);margin:14px 0 6px;max-width:44ch}
.hero-p{color:var(--muted);max-width:52ch}
.hero-btns{display:flex;flex-wrap:wrap;gap:14px;margin-top:34px}
/* "(Scroll to Explore)" hint removed per client request. */
.scroll-hint{display:none !important}
.ai-caption{position:absolute;left:0;right:0;bottom:calc(var(--mh) + 8vh);z-index:3;text-align:center;--measure:none;margin:0;font-family:var(--fm);font-size:.76rem;letter-spacing:.24em;text-transform:uppercase;color:var(--muted);opacity:0;transform:translateY(14px);transition:opacity .4s,transform .4s}
.ai-caption.on{opacity:1;transform:none}
html.rm .ai-caption{opacity:1;transform:none;transition:none}
@media (max-width:560px){.hero-btns .btn{width:100%}.scene-tc{display:none}}

/* ---------- subpage hero (non-pinned film opening) ---------- */
.page-hero{position:relative;padding:calc(76px + clamp(64px,9vw,120px)) 0 clamp(56px,7vw,96px);overflow:hidden;border-bottom:1px solid var(--hair)}
.page-hero .scene-canvas{opacity:.5}
.page-hero .wrap{position:relative;z-index:2}
.page-hero h1{font-size:clamp(2.3rem,6vw,4.6rem);max-width:16ch}
.film-no{font-family:var(--fm);font-size:.66rem;letter-spacing:.3em;text-transform:uppercase;color:var(--muted);margin-bottom:24px;display:flex;align-items:center;gap:12px}
.film-no::before{content:"";width:13px;height:13px;flex:none;background:var(--grad);clip-path:polygon(0 0,100% 0,100% 62%,0 100%)}
.page-tc{position:absolute;right:var(--pad);top:calc(76px + 20px);z-index:3;font-family:var(--fm);font-size:.66rem;letter-spacing:.2em;color:var(--muted);text-transform:uppercase}

/* ---------- generic section chrome ---------- */
.sec{padding-block:clamp(84px,10vw,150px);position:relative}
.sec-tint{background:#F6F9FC;border-block:1px solid var(--hair)}
.head-xl{font-size:clamp(2rem,4.6vw,3.6rem)}
.head-lg{font-size:clamp(1.7rem,3.6vw,2.7rem)}

/* split + stats */
.split{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(36px,6vw,90px);align-items:center}
@media (max-width:920px){.split{grid-template-columns:1fr}}
/* headline flourishes */
.head-rule{width:96px;height:4px;border-radius:2px;background:linear-gradient(90deg,#0176FF,#04C900);margin:18px 0 26px}
.mark{background:linear-gradient(transparent 62%,rgba(4,201,0,.28) 62%);padding:0 2px}
.mark-b{background:linear-gradient(transparent 62%,rgba(1,118,255,.22) 62%);padding:0 2px}

.stat-strip{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--hair);border:1px solid var(--hair);border-radius:10px;overflow:hidden}
.stat{background:#fff;padding:26px 22px}
.stat b{display:block;font-family:var(--fd);font-weight:900;font-size:clamp(1.9rem,3.4vw,2.8rem);line-height:1;color:var(--ink)}
.stat b i{font-style:normal;color:var(--blue)}
.stat span{font-family:var(--fm);font-size:.66rem;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);display:block;margin-top:8px}
@media (max-width:560px){.stat-strip{grid-template-columns:1fr}}

/* capability reel */
.cap-list{display:grid;gap:10px;margin-top:40px}
.cap{display:grid;grid-template-columns:260px 1fr;gap:20px;align-items:center;background:#fff;border:1px solid var(--hair);border-radius:8px;padding:20px 24px;position:relative;overflow:hidden;transition:border-color .2s,box-shadow .2s,transform .2s}
.cap::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--cap-c,var(--blue));transform:scaleY(0);transform-origin:top;transition:transform .6s var(--ease)}
.cap.in::before{transform:none}
.cap:hover{border-color:var(--hair2);box-shadow:var(--shadow-soft);transform:translateX(4px)}
.cap .cl{font-family:var(--fm);font-size:.78rem;letter-spacing:.14em;color:var(--cap-c,var(--blue))}
.cap strong{font-family:var(--fd);font-weight:800;text-transform:uppercase;font-size:1rem;letter-spacing:.02em}
.cap span{color:var(--muted);font-size:.94rem}
html.rm .cap::before{transform:none;transition:none}
html.rm .cap,html.rm .btn,html.rm .poster,html.rm .still{transition:none}
@media (max-width:860px){.cap{grid-template-columns:1fr}.cap span{grid-column:1/-1}}

/* solution posters */
.posters{display:grid;grid-template-columns:1fr 1fr;gap:22px}
@media (max-width:900px){.posters{grid-template-columns:1fr}}
/* three-up variant; must come after the .posters collapse above so it wins on
   source order at equal specificity */
.posters-3{grid-template-columns:repeat(3,1fr)}
@media (max-width:1180px){.posters-3{grid-template-columns:1fr 1fr}}
@media (max-width:760px){.posters-3{grid-template-columns:1fr}}
.poster{display:block;border-radius:10px;overflow:hidden;border:1px solid var(--hair);background:#fff;transition:box-shadow .25s var(--ease),transform .25s var(--ease)}
/* the artwork strip every poster card wears, light pages included */
.po-strip{display:block;height:150px;border-bottom:1px solid var(--hair);overflow:hidden}
.po-strip img{width:100%;height:100%;object-fit:cover;display:block}
/* Who we are rises over the drained final frame — the seam carries no blank scroll */
#who{position:relative;z-index:2;margin-top:clamp(-400px,-38vh,-170px);
  padding-top:clamp(30px,4vw,60px)}
.poster:hover{box-shadow:var(--shadow-blue);transform:translateY(-4px)}
.poster .po-band{height:110px;position:relative;overflow:hidden}
.poster .po-band::after{content:"";position:absolute;inset:0;background:repeating-linear-gradient(115deg,rgba(255,255,255,.18) 0 2px,transparent 2px 26px)}
.po-b1{background:linear-gradient(115deg,#0176FF,#00BFA8)}
.po-b2{background:linear-gradient(115deg,#04C900,#00BFA8)}
.po-b3{background:linear-gradient(115deg,#062A6E,#0176FF)}
.po-b4{background:linear-gradient(115deg,#00BFA8,#0176FF)}
.po-b5{background:linear-gradient(115deg,#0176FF,#04C900)}
.po-b6{background:linear-gradient(115deg,#0A1420,#00BFA8)}
.poster .po-body{padding:26px 28px 30px}
.poster .po-slogan{font-family:var(--fm);font-size:.68rem;letter-spacing:.2em;text-transform:uppercase;color:#0055C4;display:block;margin-bottom:10px}
.poster h3{font-size:1.4rem;margin-bottom:8px}
.poster p{color:var(--muted);font-size:.95rem;margin:0}
.poster .po-cta{display:inline-flex;gap:8px;margin-top:18px;font-family:var(--fm);font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;color:var(--ink)}
.poster:hover .po-cta{color:#0055C4}

/* ---------- Our solutions: artwork cards ----------
   Generated SVG artwork fills the card; the caption sits in a slight glass
   panel. Legibility comes from the scrim baked into the lower third of each
   artwork, not from the glass, so the panel can stay genuinely light. */
.poster-art{position:relative;display:flex;flex-direction:column;justify-content:flex-end;min-height:354px;background:#08131F;border-color:rgba(255,255,255,.10)}
.poster-art .po-art{position:absolute;inset:0;display:block}
.poster-art .po-art img{width:100%;height:100%;object-fit:cover;display:block}
.poster-art .po-glass{position:relative;margin:16px;padding:18px 20px 20px;border-radius:8px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.16);box-shadow:0 12px 34px rgba(4,10,20,.34);backdrop-filter:blur(14px) saturate(115%);-webkit-backdrop-filter:blur(14px) saturate(115%)}
.poster-art .po-slogan{color:#7FE3D4;letter-spacing:.18em;margin-bottom:8px}
.poster-art h3{color:#fff;margin:0 0 .3em;font-size:clamp(1.1rem,1.6vw,1.45rem)}
/* reserve two lines of body copy so all four glass panels are the same height
   and their slogans, titles and CTAs line up across the grid — the copy runs
   one line on two cards and two on the other two */
.poster-art p{color:rgba(255,255,255,.84);font-size:.9rem;line-height:1.5;margin:0;--measure:none;min-height:2.7rem}
.poster-art .po-cta{color:#fff;margin-top:14px}
/* Tag chips are styled for a white card — --muted ink on a --hair2 border. On the
   dark glass they measured 1.70:1, so inside an art card they invert to the same
   light values the body copy uses. Scoped to .poster-art, so the chips on the
   light-background pages are untouched. */
.poster-art .tags i{color:#D6DBE1;border-color:rgba(255,255,255,.26)}

/* ---------- project poster: the logo on a mounted plate ----------
   For cards that point at a named project rather than a solution area. Same
   registration-tick device as the Selected Projects nameplates, so the two read as
   one house style, but it keeps the poster's anchor and its white body — which also
   means the copy never sits on the plate, so contrast needs no scrim.
   --plate is per logo because the supplied marks differ: most are dark on
   transparent and want a light plate, while BlackBOX ships its own dark tile. */
.poster-logo{--tick:rgba(10,20,32,.26)}
.poster-logo .po-plate{position:relative;height:158px;background:var(--plate,#F2F6FA);
  border-bottom:1px solid var(--hair);display:grid;place-items:center;padding:22px 30px}
/* height-driven, not max-height: these marks range from a 34px badge to a 3067px
   wordmark, and max-height would leave the small ones tiny */
.poster-logo .po-plate img{display:block;width:auto;height:var(--lh,56px);max-width:100%;object-fit:contain}
.poster-logo .po-plate::after{content:"";position:absolute;inset:10px;pointer-events:none;background:
  linear-gradient(var(--tick) 0 0) left top/1px 12px no-repeat,
  linear-gradient(var(--tick) 0 0) left top/12px 1px no-repeat,
  linear-gradient(var(--tick) 0 0) right top/1px 12px no-repeat,
  linear-gradient(var(--tick) 0 0) right top/12px 1px no-repeat,
  linear-gradient(var(--tick) 0 0) left bottom/1px 12px no-repeat,
  linear-gradient(var(--tick) 0 0) left bottom/12px 1px no-repeat,
  linear-gradient(var(--tick) 0 0) right bottom/1px 12px no-repeat,
  linear-gradient(var(--tick) 0 0) right bottom/12px 1px no-repeat}
@media (max-width:560px){.poster-art{min-height:320px}.poster-art .po-glass{margin:12px}}
/* Three-up variant, reusing the same artwork as the home page.
   Taller cards for two reasons. At 354px the narrower column made the caption wrap
   tall enough to push its glass to 0.27 of the card — above the 0.46 where the
   scrim baked into that artwork reaches full strength — and captions measured as
   low as 1.60:1. And the three panels came out 194 / 216 / 173px tall because the
   copy lengths differ, which is what actually read as untidy.
   So: more height, and the copy blocks reserve their tallest line count so all
   three panels are identical and the slogans, titles and CTAs line up. */
/* ONE height and ONE reservation at every breakpoint, so the shape is uniform by
   construction rather than per-range guesswork. The body is 0.9rem/1.5 (one line =
   1.5em) and reaches five lines on the narrowest card, so 7.6em covers every case;
   titles get 2.3em because "Environmental Intelligence" wraps to two lines while
   the other two do not. 500px of card then leaves the glass at ~0.46 — inside the
   zone where the scrim baked into this artwork is at full strength. */
/* Measured, not guessed: the only blocks that actually differ between the three
   cards are the SLOGAN (36px vs 30px — "Technology for a Sustainable Future" wraps
   to two lines while the other two stay on one) and the TITLE ("Environmental
   Intelligence" likewise). The bodies wrap to the same count at every width, so
   the bodies vary too (Smart Mobility's copy is a line shorter than the other two).
   Reservations and card height are both sized to what each regime MEASURABLY needs,
   so no card carries space it isn't using. A single 620px height was sized for the
   320px-viewport worst case; cards wider than ~440px only need ~340.
   Tight cards (roughly 300-430px wide): slogan wraps to two lines, title to two,
   body to three -> panel 234, so 472px leaves the glass at 0.47. */
.posters-3 .poster-art{min-height:472px}
.posters-3 .poster-art .po-slogan{min-height:3.4em}
.posters-3 .poster-art h3{min-height:2em}
.posters-3 .poster-art p{min-height:4.55em}
/* Roomy cards (>=440px wide: two-up above 980, one-up above 480). Nothing wraps
   twice here, so the panel is 169 and the card only needs 352. */
@media (min-width:980px) and (max-width:1180px),(min-width:480px) and (max-width:760px){
  .posters-3 .poster-art{min-height:352px}
  .posters-3 .poster-art .po-slogan{min-height:1.7em}
  .posters-3 .poster-art h3{min-height:1em}
  .posters-3 .poster-art p{min-height:3.05em}
}
/* Small phones: the body takes a fourth line. */
@media (max-width:400px){
  .posters-3 .poster-art{min-height:508px}
  .posters-3 .poster-art p{min-height:6.05em}
}

/* ---------- the six Solutions cards (solutions.html) ----------
   Same treatment, but these carry a tags row as well, and that row is the biggest
   variable: the chips sit on one line on a wide card (26px) and wrap to two on a
   narrow one (60px). Measured maxima drive both the reservations and the height.
   Narrow cards are the default; wide cards override downward so no card carries
   space it isn't using. */
.posters-art6 .poster-art{min-height:624px}
.posters-art6 .poster-art .po-slogan{min-height:3.4em}
.posters-art6 .poster-art h3{min-height:2em}
.posters-art6 .poster-art p{min-height:6.05em}
.posters-art6 .poster-art .tags{min-height:60px}
/* Cards >=560px wide: nothing wraps twice, panel is 213 so 432 is enough.
   That is the two-up grid above 1236px, and the one-up grid from 640 to 900. */
@media (min-width:1236px),(min-width:640px) and (max-width:900px){
  .posters-art6 .poster-art{min-height:432px}
  .posters-art6 .poster-art .po-slogan{min-height:1.7em}
  .posters-art6 .poster-art h3{min-height:1em}
  .posters-art6 .poster-art p{min-height:3.05em}
  .posters-art6 .poster-art .tags{min-height:26px}
}
/* Below ~340px the body takes six lines and the chips three rows (measured panel
   373), which no smaller card can hold while keeping the glass off the artwork. */
@media (max-width:365px){
  .posters-art6 .poster-art{min-height:724px}
  .posters-art6 .poster-art p{min-height:7.6em}
  .posters-art6 .poster-art .tags{min-height:93px}
}

/* ---------- tracking shot / dolly ---------- */
.dolly-head{position:absolute;left:0;right:0;top:calc(var(--mh) + 60px);z-index:4;pointer-events:none}
.dolly-head .wrap{pointer-events:auto}
.dolly-vp{width:100%;overflow:hidden;position:relative;z-index:3}
.dolly{display:flex;gap:26px;padding:0 var(--pad);will-change:transform;width:max-content;align-items:stretch}
.dolly-counter{position:absolute;right:var(--pad);bottom:calc(var(--mh) + 22px);z-index:4;font-family:var(--fm);font-size:.7rem;letter-spacing:.24em;color:var(--muted);text-transform:uppercase}
/* the filmography strip sits below its header band, never under it */
#filmography{justify-content:flex-start}
#filmography > .scene-slate{display:none}
#filmography .dolly-head{top:calc(var(--mh) + 36px)}
#filmography .dolly-head .muted{font-size:.85rem;max-width:96ch;margin-top:6px}
#filmography .dolly-vp{margin-top:calc(var(--mh) + 152px)}
#filmography .matte-b{height:54px}
.pin-track.no-pin #filmography .dolly-vp{margin-top:0}
/* the showcase frames: full-bleed animated posters, copy over the scene */
.still.frame{flex:0 0 min(1020px,90vw);height:clamp(360px,56vh,440px)}
.frame .fr-stage{position:relative;flex:1;min-height:0;background:var(--stage,#F4F8FC);overflow:hidden}
.frame .fr-canvas{position:absolute;inset:0;width:100%;height:100%}
.still .st-plate .fr-canvas,.poster-logo .po-plate .fr-canvas{position:absolute;inset:0;width:100%;height:100%}
.frame .fr-stage>img,.frame .fr-stage>.st-word{position:absolute;left:50%;top:33%;
  transform:translate(-50%,-50%);z-index:1;width:auto;max-width:70%}
.frame .fr-copy{position:absolute;left:0;right:0;bottom:0;z-index:2;
  padding:44px 30px 20px;display:flex;flex-direction:column;gap:8px;align-items:flex-start;
  background:linear-gradient(180deg,rgba(244,248,252,0) 0%,rgba(247,250,253,.88) 34%,rgba(249,251,254,.97) 100%)}
.frame.fr-dark .fr-copy{background:linear-gradient(180deg,rgba(6,11,20,0) 0%,rgba(6,11,20,.86) 34%,rgba(5,10,18,.97) 100%)}
.frame .fr-title{font-family:var(--fd);font-weight:900;text-transform:uppercase;
  font-size:clamp(1.4rem,2.2vw,2rem);letter-spacing:-.01em;line-height:1.05;margin:0;color:var(--ink)}
.frame .pr-slogan{font-family:var(--fm);font-size:.68rem;letter-spacing:.2em;text-transform:uppercase;color:var(--pc,#0176FF)}
.frame .fr-copy>p{margin:0;color:var(--muted);font-size:.94rem;line-height:1.55;max-width:64ch}
.frame .fr-cta{margin:4px 0 0}
.frame.fr-dark .fr-title{color:#fff}
.frame.fr-dark .fr-copy>p{color:#B9C7D9}
.frame.fr-dark .tags i{border-color:rgba(255,255,255,.26);color:#CBD8E8}
.frame.fr-dark .btn-line{background:transparent;color:#fff;border-color:rgba(255,255,255,.42)}
.frame.fr-dark .btn-line:hover{background:rgba(255,255,255,.08);border-color:#fff;color:#fff}
.frame{opacity:.55;transform:scale(.975);
  transition:box-shadow .45s var(--ease),transform .45s var(--ease),opacity .45s var(--ease)}
.frame.on{opacity:1;transform:none;box-shadow:0 30px 70px rgba(10,20,32,.16);border-color:var(--pc,#0176FF)}
.frame .fr-copy>*{opacity:.2;transform:translateY(12px);transition:opacity .5s var(--ease),transform .5s var(--ease)}
.frame.on .fr-copy>*{opacity:1;transform:none}
.frame.on .fr-copy>*:nth-child(2){transition-delay:.06s}
.frame.on .fr-copy>*:nth-child(3){transition-delay:.12s}
.frame.on .fr-copy>*:nth-child(4){transition-delay:.18s}
.frame.on .fr-copy>*:nth-child(5){transition-delay:.24s}
@media (max-width:900px){
  .still.frame{height:auto}
  .frame .fr-stage{min-height:430px}
  .frame .fr-stage>img,.frame .fr-stage>.st-word{top:22%}
  .frame,.frame .fr-copy>*{opacity:1;transform:none}
}
html.rm .frame,html.rm .frame .fr-copy>*{opacity:1;transform:none}
/* ---------- selected projects: logo nameplates ----------
   Each card is built around the project's own logo, mounted on a plate with
   registration ticks so it reads as one closed unit. The plate tone is set per
   project because the supplied assets differ: some are dark-on-transparent,
   others carry white ink or ship their own dark tile, and a single plate colour
   cannot serve both. --pc is decoration only: the brand blue, green and teal all
   fail 4.5:1 on white, so every string stays on ink/muted/#067D33. */
.still{--tick:rgba(10,20,32,.26);flex:0 0 min(460px,84vw);border-radius:10px;overflow:hidden;border:1px solid var(--hair2);background:#fff;display:flex;flex-direction:column;transition:box-shadow .25s,border-color .25s}
.still:hover{box-shadow:var(--shadow-soft);border-color:#C4D2E2}
.still.card-link{cursor:pointer}
.still .st-bar{height:30px;background:var(--ink);display:flex;align-items:center;gap:12px;padding:0 14px;font-family:var(--fm);font-size:.6rem;letter-spacing:.22em;color:#fff;text-transform:uppercase;justify-content:space-between}
.still .st-sect{display:inline-flex;align-items:center;gap:9px;white-space:nowrap}
.still .st-sect i{font-style:normal;width:7px;height:7px;border-radius:50%;background:var(--pc,#0176FF);flex:none}
.still .st-feat{color:rgba(255,255,255,.58);white-space:nowrap;font-size:.55rem}
/* the logo well */
.still .st-plate{position:relative;height:196px;background:var(--plate,#F2F6FA);border-bottom:1px solid var(--hair);display:grid;place-items:center;padding:30px 38px}
/* Drive the size from height, not max-height: these assets range from a 34px
   badge to a 3067px wordmark, and max-height only ever shrinks — the small ones
   would stay tiny. --lh is tuned per logo so all five carry similar optical
   weight. object-fit:contain keeps the aspect if max-width has to clamp. */
.still .st-plate img{display:block;width:auto;height:var(--lh,68px);max-width:100%;object-fit:contain}
/* AntiLost has no logo of its own, so its plate carries a typographic wordmark in
   the site's display face. The other plates hold wordmark logos too (gReact,
   iDrivy, BLACK BOX), so it sits in the same register rather than reading as a
   gap. aria-hidden: the <h3> below already announces the name.
   The size tracks the card, which is min(460px,84vw) with 39px of plate padding
   either side — below 547px viewport the card is on the vw branch, so the type
   follows it there instead of overflowing. */
.still .st-word{font-family:var(--fd);font-weight:900;font-size:52px;line-height:1;
  letter-spacing:-.022em;color:#fff;white-space:nowrap}
@media (max-width:547px){.still .st-word{font-size:calc(11.38vw - 10.56px)}}
/* four L-shaped registration ticks, drawn as eight hairlines on one element */
.still .st-plate::after{content:"";position:absolute;inset:11px;pointer-events:none;background:
  linear-gradient(var(--tick) 0 0) left top/1px 13px no-repeat,
  linear-gradient(var(--tick) 0 0) left top/13px 1px no-repeat,
  linear-gradient(var(--tick) 0 0) right top/1px 13px no-repeat,
  linear-gradient(var(--tick) 0 0) right top/13px 1px no-repeat,
  linear-gradient(var(--tick) 0 0) left bottom/1px 13px no-repeat,
  linear-gradient(var(--tick) 0 0) left bottom/13px 1px no-repeat,
  linear-gradient(var(--tick) 0 0) right bottom/1px 13px no-repeat,
  linear-gradient(var(--tick) 0 0) right bottom/13px 1px no-repeat}
.still .st-body{padding:18px 22px 20px;display:flex;flex-direction:column;flex:1}
.still .st-slogan{font-family:var(--fm);font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;color:#067D33;display:block;margin-bottom:7px}
.still .st-title{font-family:var(--fd);font-weight:900;font-size:clamp(1.15rem,1.5vw,1.4rem);line-height:1.12;text-transform:uppercase;letter-spacing:.01em;color:var(--ink);margin:0 0 .55em;text-wrap:balance}
.still p{color:var(--muted);font-size:.9rem;margin:0 0 14px;--measure:none}
/* footer pinned to the card foot so the CTA lines up across the row */
.still .st-foot{margin:auto 0 0;padding-top:15px;border-top:1px solid var(--hair)}
.still .st-more{font-family:var(--fm);font-size:.66rem;letter-spacing:.18em;text-transform:uppercase;color:var(--ink)}
.still .st-more:hover{color:#0055C4}
.tags{display:flex;flex-wrap:wrap;gap:7px}
.tags i{font-style:normal;font-family:var(--fm);font-size:.62rem;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);border:1px solid var(--hair2);border-radius:3px;padding:4px 9px}
/* dolly fallback */
.pin-track.no-pin{height:auto !important}
.pin-track.no-pin .pin-stick{position:relative;height:auto;min-height:0;overflow:visible;padding-block:clamp(84px,10vw,150px);display:block}
.pin-track.no-pin .dolly-head{position:static;margin-bottom:26px}
.pin-track.no-pin .dolly{overflow-x:auto;scroll-snap-type:x mandatory;width:auto;padding-bottom:18px;cursor:grab;-webkit-overflow-scrolling:touch;transform:none !important}
.pin-track.no-pin .dolly .still{scroll-snap-align:start}
.pin-track.no-pin .dolly-counter,.pin-track.no-pin .matte,.pin-track.no-pin .scene-slate,.pin-track.no-pin .scene-tc{display:none}
.pin-track.no-pin .dolly::-webkit-scrollbar{height:8px}
.pin-track.no-pin .dolly::-webkit-scrollbar-thumb{background:var(--hair2);border-radius:4px}

/* ---------- braid scene DOM ---------- */
/* the copy sits at the top of the pinned frame — the braid is confined to the
   band below it (see initBraid) so the heading reads clearly over open space */
.s2-copy{position:relative;z-index:3;align-self:flex-start;text-align:center;max-width:820px;margin:0 auto;padding:calc(var(--mh) + clamp(46px,7vh,86px) + 50px) var(--pad) 0;width:100%}
.s2-labels{position:absolute;inset:0;z-index:2;pointer-events:none}
.s2-lab{position:absolute;font-family:var(--fd);font-weight:800;font-size:clamp(.8rem,1.6vw,1.05rem);letter-spacing:.06em;text-transform:uppercase;color:var(--ink);background:#fff;border:1px solid var(--hair2);border-radius:5px;padding:8px 14px;opacity:0;transform:scale(.8);transition:opacity .35s var(--ease),transform .35s var(--ease),border-color .35s}
.s2-lab.on{opacity:1;transform:none;border-color:var(--lab-c,var(--blue));box-shadow:0 10px 30px rgba(1,118,255,.14)}
.s2-lab::before{content:"";display:inline-block;width:9px;height:9px;border-radius:50%;background:var(--lab-c,var(--blue));margin-right:9px}
.s2-chain{position:absolute;left:0;right:0;bottom:calc(var(--mh) + 8vh);z-index:3;display:flex;justify-content:center;gap:clamp(8px,2vw,18px);flex-wrap:wrap;font-family:var(--fm);font-size:clamp(.72rem,1.5vw,.95rem);letter-spacing:.18em;text-transform:uppercase}
.s2-chain span{opacity:0;transform:translateY(12px);transition:opacity .35s var(--ease),transform .35s var(--ease);color:var(--ink)}
.s2-chain span.on{opacity:1;transform:none}
.s2-chain .ar{color:#067D33}
.s2-sub{position:absolute;left:0;right:0;bottom:calc(var(--mh) + 3.5vh);z-index:3;text-align:center;font-size:.9rem;color:var(--muted);opacity:0;transition:opacity .4s}
.s2-sub.on{opacity:1}
html.rm .s2-lab,html.rm .s2-chain span,html.rm .s2-sub{opacity:1;transform:none;transition:none}

/* ---------- marquee + industries ---------- */
.marquee{overflow:hidden;border-block:1px solid var(--hair);padding-block:18px;background:#fff}
.mq-row{display:flex;gap:54px;width:max-content;animation:mq 36s linear infinite;font-family:var(--fd);font-weight:900;font-size:clamp(1.6rem,3.6vw,2.8rem);text-transform:uppercase;color:var(--ink);align-items:center;padding-inline:27px}
.mq-row .dot{width:12px;height:12px;border-radius:50%;background:var(--grad);flex:none}
@keyframes mq{from{transform:translateX(0)}to{transform:translateX(-50%)}}
html.rm .mq-row{animation:none}
/* ---------- industries: field plates on a board ----------
   Six domains, not a sequence, so no numbering. Each plate carries a glyph drawn
   from that industry's own instruments — pylon, contours, route, mast, mesh,
   plinth — as a badge and again as an oversized watermark. --ac is the domain
   accent and is used for graphics only: brand green and teal measure 2.24:1 and
   2.33:1 as strokes on white, so the accents are the darkened #067D33 / #00857A
   and text stays on ink/muted. */
.ind-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:44px}
@media (max-width:1100px){.ind-grid{grid-template-columns:repeat(2,1fr)}}
@media (max-width:720px){.ind-grid{grid-template-columns:1fr}}
/* the plates are not interactive, so no hover shadow implying a click target */
.ind{position:relative;overflow:hidden;isolation:isolate;background:#fff;border:1px solid var(--hair);border-radius:8px;padding:22px 24px 24px}
.ind::before{content:"";position:absolute;inset:0 0 auto;height:2px;background:var(--ac,var(--blue))}
.ind-glyph{display:grid;place-items:center;width:38px;height:38px;border-radius:7px;margin-bottom:15px;color:var(--ac,var(--blue));background:#F1F5FA;background:color-mix(in srgb,var(--ac,#0176FF) 11%,#fff)}
.ind-glyph svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
/* oversized domain stamp, clipped by the plate */
.ind-wm{position:absolute;z-index:-1;right:-16px;bottom:-18px;width:112px;height:112px;color:var(--ac,var(--blue));opacity:.07;fill:none;stroke:currentColor;stroke-width:1.1;stroke-linecap:round;stroke-linejoin:round;pointer-events:none}
.ind strong{font-family:var(--fd);font-weight:800;text-transform:uppercase;display:block;margin-bottom:6px;font-size:1.02rem}
.ind span{color:var(--muted);font-size:.92rem}

/* ---------- DNA ---------- */
/* --- the build path, as a contact sheet -------------------------------------
   Built from the site's own furniture rather than a fresh card idea: the 30px ink
   bar and the four L-shaped registration ticks both come from the .still
   nameplates, and the numbering matches .ask-q's decimal-leading-zero counter.
   Six steps are ONE sheet of frames, not six cards — the claim is a continuous
   path, so the frames touch and are divided only by hairlines. The bar names the
   two ends so the sheet has a direction; the gradient rule under it is that
   direction drawn. */
.sheet{--tick:rgba(10,20,32,.26);position:relative;margin-top:36px;background:#fff;
  border:1px solid var(--hair2);border-radius:10px;overflow:hidden}
.sheet-bar{height:30px;background:var(--ink);display:flex;align-items:center;
  justify-content:space-between;padding:0 14px;font-family:var(--fm);font-size:.6rem;
  letter-spacing:.22em;text-transform:uppercase;color:#fff}
.sheet-bar span{display:inline-flex;align-items:center;gap:9px;white-space:nowrap}
.sheet-bar span::before,.sheet-bar span::after{content:"";width:7px;height:7px;border-radius:50%;flex:none}
/* the dots bracket the sheet: one outside each end, so they mark where the path
   starts and finishes rather than both pointing the same way */
.sheet-bar .sh-a::before{background:var(--blue)}
.sheet-bar .sh-a::after{display:none}
.sheet-bar .sh-b::before{display:none}
.sheet-bar .sh-b::after{background:#04C900}
.sheet-rule{height:2px;background:var(--grad)}
/* the hairlines ARE the grid gaps, so the division stays correct however it wraps */
.sheet-grid{counter-reset:sh;list-style:none;display:grid;grid-template-columns:repeat(3,1fr);
  gap:1px;background:var(--hair);margin:0;padding:0}
.sheet-grid>li{counter-increment:sh;background:#fff;padding:20px 22px 22px}
.sheet-grid .sh-n{display:block;font-family:var(--fm);font-size:.66rem;letter-spacing:.2em;
  color:#0159C4;margin-bottom:9px}
.sheet-grid .sh-n::before{content:counter(sh,decimal-leading-zero)}
.sheet-grid strong{font-family:var(--fd);font-weight:800;text-transform:uppercase;display:block;
  font-size:.98rem;letter-spacing:.01em;color:var(--ink);margin-bottom:5px}
.sheet-grid p{color:var(--muted);font-size:.92rem;margin:0;--measure:none}
/* one set of ticks around the sheet — twenty-four around the frames would be noise.
   Top inset clears the 30px bar plus the 2px rule. */
.sheet::after{content:"";position:absolute;inset:41px 9px 9px;pointer-events:none;background:
  linear-gradient(var(--tick) 0 0) left top/1px 13px no-repeat,
  linear-gradient(var(--tick) 0 0) left top/13px 1px no-repeat,
  linear-gradient(var(--tick) 0 0) right top/1px 13px no-repeat,
  linear-gradient(var(--tick) 0 0) right top/13px 1px no-repeat,
  linear-gradient(var(--tick) 0 0) left bottom/1px 13px no-repeat,
  linear-gradient(var(--tick) 0 0) left bottom/13px 1px no-repeat,
  linear-gradient(var(--tick) 0 0) right bottom/1px 13px no-repeat,
  linear-gradient(var(--tick) 0 0) right bottom/13px 1px no-repeat}
@media (max-width:1000px){.sheet-grid{grid-template-columns:1fr 1fr}}
@media (max-width:620px){.sheet-grid{grid-template-columns:1fr}
  .sheet::after{display:none}   /* ticks around a tall single column read as a box */
}

.dna-vals{display:grid;gap:12px}
.dna{display:flex;gap:18px;align-items:flex-start;background:#fff;border:1px solid var(--hair);border-radius:8px;padding:20px 22px}
.dna b{flex:none;font-family:var(--fm);font-size:.76rem;letter-spacing:.14em;color:#fff;background:var(--dna-c,var(--blue));border-radius:4px;padding:6px 10px}
.dna strong{font-family:var(--fd);font-weight:800;text-transform:uppercase;display:block;font-size:.98rem;margin-bottom:3px}
.dna span{color:var(--muted);font-size:.92rem}

/* ---------- blue vision scene ---------- */
.blue-stick{background:var(--blue);align-items:stretch}
.blue-stick .matte{background:var(--paper)}
/* Padding has to clear whichever is taller: the letterbox matte (which paints over
   this content at z-index 5) or the fixed header at 77px. A flat 110px cleared
   neither reliably — and because the column is centred, content taller than the
   padded box overflows ABOVE the padding, straight under the header. The type
   sizes below were cut so the content actually fits the space that remains. */
.s3-in{position:relative;z-index:2;width:100%;max-width:var(--mid);margin:0 auto;
  padding:calc(max(var(--mh),82px) + 14px) var(--pad) calc(max(var(--mh),22px) + 14px);
  display:flex;flex-direction:column;justify-content:center}
.s3-slate{font-family:var(--fm);font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;color:rgba(255,255,255,.85);margin-bottom:20px;display:flex;gap:14px;align-items:center}
.s3-slate::after{content:"";flex:1;height:1px;background:rgba(255,255,255,.35)}
.s3-title{color:#fff;font-size:clamp(1.85rem,4.3vw,3.45rem);margin-bottom:14px}
/* The vision scenes are otherwise pure type on the blue field — eyebrow, title,
   words, formula — so a navy card in the middle read as a UI widget dropped into
   a poster. The copy is set as a lead statement instead, with one short rule as
   its only structural mark (the same hairline device as .s3-slate::after).
   Why the size floor matters: white on #0176FF measures 4.17:1, which fails the
   4.5:1 normal-text minimum — that is precisely why the card existed. At 24.67px
   and above this counts as large text and the bar drops to 3:1, so the clamp
   floor is 25.6px and the colour is pure white, never a tinted white. */
/* Full-bleed band. The copy needs a darker ground — white on the brand blue is
   only 4.17:1 — but a bounded card read as a widget dropped into the poster.
   Bleeding it past the viewport on both sides makes it a stripe with no side
   edges: composition rather than container. The -50vw inline margin is cancelled
   by an equal 50vw inline padding, so the text stays exactly on the scene's left
   edge while the ground runs edge to edge; .pin-stick clips the overspill.
   #0159C4 puts white at 6.51:1, so the type no longer depends on the large-text
   exemption, and it sits only 1.56 off the field — a tonal shift, where the old
   navy was 3.22 and read as a slab. */
/* Scroll state: the band opens light blue with grey text — data, undifferentiated
   — and the deep blue / white state is WIPED IN behind the scene's white sweep
   bar, so the colour change travels with the line instead of switching. The
   engine writes --wipe (and --wipe-t for the text) from the same expression that
   positions the sweep, so the two are locked together by construction.
   Both ends are legible on their own: grey #50627A on #E4EFFB is 5.35:1, white on
   #0159C4 is 6.51:1. With no JS --wipe stays 0 and the band simply reads light,
   which is why the light side is the CSS default.
   No transition here on purpose — the position is driven per frame, and a
   transition would lag behind the bar and smear the edge. */
.s3-lead{--wipe:0px;--wipe-t:0px;margin:20px 0 0;margin-inline:-50vw;padding:clamp(20px,2.4vh,28px) 50vw;
  background:linear-gradient(90deg,#0159C4 0 calc(var(--wipe) - 3px),#E4EFFB calc(var(--wipe) + 3px) 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18),inset 0 -1px 0 rgba(255,255,255,.18)}
/* Set in the display face, not the body face: everything else in this scene is
   Archivo or mono, so Inter here was what made it read as plain paragraph text.
   The two paragraphs step 600 -> 800 so the section builds to the thesis. */
.s3-lead p{max-width:920px;font-family:var(--fd);font-weight:600;color:#50627A;font-size:clamp(1.32rem,1.62vw,1.5rem);line-height:1.28;letter-spacing:-.012em;margin:0 0 .5em;--measure:none;text-wrap:pretty}
.s3-lead p:last-child{font-weight:800;font-size:clamp(1.42rem,1.86vw,1.72rem);line-height:1.22;letter-spacing:-.02em;margin:0}
/* The text wipes with the bar too, so glyphs flip grey -> white as it passes. The
   grey `color` above stays as the fallback: if background-clip:text is missing,
   colour:transparent would make the copy invisible, so it is only applied where
   the clip is supported. --wipe-t is the same edge in the paragraph's own
   coordinate space (its box starts at the scene's content edge, not the band's). */
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .s3-lead p{background-image:linear-gradient(90deg,#fff 0 calc(var(--wipe-t) - 3px),#50627A calc(var(--wipe-t) + 3px) 100%);
    -webkit-background-clip:text;background-clip:text;color:transparent}
}
.s3-words{display:flex;flex-wrap:wrap;gap:clamp(10px,2.2vw,26px);margin:26px 0 16px}
.s3-word{font-family:var(--fd);font-weight:900;font-size:clamp(1.15rem,2.9vw,2.35rem);text-transform:uppercase;color:#fff;opacity:.18;transform:translateY(10px);transition:opacity .35s var(--ease),transform .35s var(--ease)}
.s3-word.on{opacity:1;transform:none}
.s3-word .wtc{display:block;font-family:var(--fm);font-weight:400;font-size:.62rem;letter-spacing:.24em;color:rgba(255,255,255,.7);margin-top:6px}
.s3-formula{font-family:var(--fm);letter-spacing:.22em;font-size:.82rem;color:#fff;text-transform:uppercase}
/* above .s3-in (z-index 2) so the wipe still crosses the band instead of being
   interrupted by it */
.s3-sweep{position:absolute;top:0;bottom:0;left:0;width:3px;background:#fff;box-shadow:0 0 30px rgba(255,255,255,.9);z-index:3;transform:translateX(-10px)}
.s3-chip{position:absolute;top:calc(var(--mh) + 48px);right:var(--pad);z-index:3;background:#fff;border-radius:6px;padding:8px 12px;display:flex;align-items:center}
.s3-chip svg{height:26px;width:auto}
/* The lead runs taller than the card it replaced and overflowed the pinned frame
   on short viewports, so the whole scene tightens below 840px tall. This block
   must sit after every .s3-* base rule it overrides: the selectors have equal
   specificity, so source order decides and .s3-words would otherwise win.
   The band gives white 6.51:1, so unlike the boxless version the type here is
   free to shrink without breaking contrast. */
@media (max-height:840px){
  .s3-in{padding-block:calc(max(var(--mh),82px) + 8px) calc(max(var(--mh),18px) + 8px)}
  .s3-title{font-size:clamp(1.6rem,3.3vw,2.5rem);margin-bottom:10px}
  .s3-slate{margin-bottom:12px}
  .s3-lead{margin-top:14px;padding-block:16px}
  .s3-lead p{font-size:clamp(1.12rem,1.36vw,1.28rem);margin-bottom:.4em}
  .s3-lead p:last-child{font-size:clamp(1.2rem,1.55vw,1.42rem)}
  .s3-words{margin:16px 0 10px}
  .s3-word{font-size:clamp(1.05rem,2.4vw,1.9rem)}
}
/* the unpinned stick sets overflow:visible, which would let the band's bleed
   create a horizontal scrollbar — clip the x axis only, so nothing scrolls */
.pin-track.no-pin .blue-stick{overflow-x:clip}
html.rm .s3-word{opacity:1;transform:none;transition:none}
/* reduced motion has no sweep to follow, so the engine pushes the wipe past the
   right edge and the band renders fully resolved */
html.rm .s3-sweep{display:none}

/* ---------- detection scene ---------- */
.det-log{position:absolute;right:var(--pad);bottom:calc(var(--mh) + 60px);z-index:4;background:#fff;border:1px solid var(--hair2);border-radius:8px;box-shadow:var(--shadow-soft);padding:16px 18px;font-family:var(--fm);font-size:.68rem;letter-spacing:.12em;text-transform:uppercase;min-width:250px}
.det-log .dl-head{color:var(--muted);border-bottom:1px solid var(--hair);padding-bottom:8px;margin-bottom:8px;display:flex;align-items:center;gap:8px}
.det-log .dl-head i{font-style:normal;width:7px;height:7px;border-radius:50%;background:var(--green)}
.det-log .dl-line{padding:3px 0;opacity:.25;transition:opacity .3s}
.det-log .dl-line.on{opacity:1}
.det-log .dl-amber{color:#B26A00}
.det-log .dl-green{color:#067D33}
.det-log .dl-blue{color:#0055C4}
html.rm .det-log .dl-line{opacity:1}
@media (max-width:700px){.det-log{left:var(--pad);right:var(--pad);min-width:0}}

/* ---------- final CTA — film poster ---------- */
.final{padding-block:clamp(96px,12vw,170px);text-align:center;position:relative;overflow:hidden}
.final::before{content:"";position:absolute;inset:auto 0 0 0;height:6px;background:var(--grad)}
.poster-rule{display:flex;align-items:center;gap:16px;justify-content:center;font-family:var(--fm);font-size:.66rem;letter-spacing:.34em;text-transform:uppercase;color:var(--muted);margin-bottom:30px}
.poster-rule::before,.poster-rule::after{content:"";width:clamp(30px,8vw,120px);height:1px;background:var(--hair2)}
.final h2{font-size:clamp(2.1rem,5.8vw,4.8rem);max-width:20ch;margin-inline:auto}
.final .lead{max-width:60ch;margin-inline:auto}
.final .hero-btns{justify-content:center}
.final .release{font-family:var(--fm);font-size:.7rem;letter-spacing:.3em;text-transform:uppercase;color:var(--muted);margin-top:34px}
.final .release b{color:#0055C4;font-weight:500}

/* ---------- footer — end credits ---------- */
.ft{border-top:1px solid var(--hair);padding:clamp(50px,7vw,86px) 0 40px;background:#fff;overflow:hidden}
.credits-roll{transition:none}
.credits-roll.go{animation:creditsUp 5.5s var(--ease) both}
.credits-roll.go:hover{animation-play-state:paused}
@keyframes creditsUp{from{transform:translateY(190px);opacity:0}to{transform:none;opacity:1}}
html.rm .credits-roll.go{animation:none}
.ft-head{font-family:var(--fm);font-size:.64rem;letter-spacing:.34em;text-transform:uppercase;color:var(--muted);text-align:center;margin-bottom:44px}
.ft-grid{display:grid;grid-template-columns:1.4fr 1fr 1fr 1fr;gap:36px}
@media (max-width:900px){.ft-grid{grid-template-columns:1fr 1fr}}
@media (max-width:560px){
  .ft-grid{grid-template-columns:1fr 1fr}
  .ft-brand{grid-column:1 / -1}
}
.ft h4{font-family:var(--fm);font-size:.68rem;letter-spacing:.22em;text-transform:uppercase;color:var(--muted);margin:0 0 18px;font-weight:400}
.ft a.fl{display:block;color:var(--muted);padding:6px 0;font-size:.92rem;transition:color .15s}
.ft a.fl:hover{color:var(--ink)}
.ft-brand p{color:var(--muted);font-size:.9rem;max-width:34ch}
.ft-brand svg{height:34px;width:auto;margin-bottom:14px}
.ft-title-card{text-align:center;margin-top:60px;padding-top:44px;border-top:1px solid var(--hair)}
.ft-title-card .motto{font-family:var(--fm);letter-spacing:.3em;text-transform:uppercase;font-size:.72rem;background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent;display:inline-block}
.ft-bot{margin-top:40px;padding-top:24px;border-top:1px solid var(--hair);display:flex;flex-wrap:wrap;gap:14px;justify-content:space-between;align-items:center;font-size:.82rem;color:var(--muted)}

/* ---------- forms (film-styled) ---------- */
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:18px}
@media (max-width:720px){.form-grid{grid-template-columns:1fr}}
.field{display:flex;flex-direction:column;gap:8px}
.field.full{grid-column:1/-1}
.field label{font-family:var(--fm);font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;color:var(--muted);transition:color .2s var(--ease)}
/* the label answers when its control has focus — 6.51:1 on white, and it pairs
   with the blue focus ring already on the control below */
.field:focus-within label{color:#0159C4}
.field label b{color:#067D33;font-weight:500}
.field input,.field select,.field textarea{background:#fff;border:1px solid var(--hair2);border-radius:6px;color:var(--ink);padding:14px 16px;font:inherit;min-height:50px;transition:border-color .2s;width:100%}
.field textarea{min-height:140px;resize:vertical}
.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3px rgba(1,118,255,.15)}
.field select{appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' fill='none'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%2350627A' stroke-width='1.5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 16px center;cursor:pointer}
.field .error-msg{color:#C22525;font-size:.8rem;display:none}
.field.invalid input,.field.invalid select,.field.invalid textarea{border-color:#C22525}
.field.invalid .error-msg{display:block}
.form-note{font-size:.8rem;color:var(--muted);margin-top:16px}
.form-success{display:none;border:1px solid rgba(4,201,0,.5);background:rgba(4,201,0,.06);border-radius:8px;padding:22px;margin-top:20px}
.form-success.show{display:block}
.form-success strong{color:#067D33;font-family:var(--fd);text-transform:uppercase}
#contextual-q{display:none}
#contextual-q.show{display:flex}

/* ---------- cookie banner ---------- */
.cookie-banner{position:fixed;bottom:20px;left:20px;right:20px;margin:0 auto;max-width:640px;background:#fff;border:1px solid var(--hair2);border-radius:10px;padding:20px 24px;z-index:95;box-shadow:var(--shadow-soft);display:none;gap:18px;align-items:center;flex-wrap:wrap}
.cookie-banner.show{display:flex}
.cookie-banner p{margin:0;font-size:.86rem;color:var(--muted);flex:1 1 300px}
.cookie-banner .btn{min-height:42px;padding:9px 18px;font-size:.72rem}
.cookie-actions{display:flex;gap:10px}

/* ---------- legal pages ---------- */
.legal-body{max-width:760px}
.legal-body h2{font-size:1.4rem;margin-top:2.2em}
.legal-body h3{font-size:1.05rem;margin-top:1.6em}
.legal-body p,.legal-body li{color:var(--muted)}
.legal-body ul{list-style:disc;padding-left:22px;margin-bottom:1em}
.legal-body table{width:100%;border-collapse:collapse;font-size:.9rem}
.legal-body th,.legal-body td{border:1px solid var(--hair2);padding:10px 14px;text-align:left;color:var(--muted)}
.legal-body th{color:var(--ink);font-family:var(--fm);font-size:.72rem;letter-spacing:.12em;text-transform:uppercase}
.table-scroll{overflow-x:auto}

/* ---------- misc ---------- */
.contact-details{font-style:normal;display:grid;gap:6px;color:var(--muted)}
.contact-details a{color:var(--ink)}
.contact-details a:hover{color:#0055C4}
.chain-line{display:flex;flex-wrap:wrap;gap:clamp(8px,2vw,18px);font-family:var(--fm);font-size:clamp(.72rem,1.5vw,.95rem);letter-spacing:.18em;text-transform:uppercase;color:var(--ink)}
.chain-line .ar{color:#067D33}

/* --- the value chain: a sequence set as one unbroken line -------------------
   Used wherever a process has to read as a chain rather than a list. Broken
   across rows it stops reading as a chain, so everything is sized against the
   CONTAINER, which is where the constraint lives: the type was previously sized
   in vw while the container is capped at --mid, so it overshot once the viewport
   passed ~1120px, and fixed 26px gaps x8 added 208px on top of 832px of content
   in a 1016px box. Steps carry a state caption; .lit marks the two that matter.
   3.6cqw is set by the worst chain in either language — Serbian IoT, UREĐAJ ->
   PODACI -> AI -> INTELIGENCIJA -> AKCIJA, which needs ~3.8cqw or less to fit
   including the 8 inter-item gaps. Raising it wraps that page. */
.value-chain{container-type:inline-size;display:flex;flex-wrap:nowrap;align-items:center;
  justify-content:space-between;gap:clamp(3px,.7cqw,13px);margin-top:40px}
.vc-step{font-family:var(--fd);font-weight:900;text-transform:uppercase;white-space:nowrap;
  font-size:min(2.3rem,3.6cqw);line-height:1.05;color:var(--ink)}
/* the gradient is an enhancement: colour first, so an engine without
   background-clip:text shows solid type instead of nothing at all */
.vc-step.lit{color:#0159C4}
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .vc-step.lit{background:var(--grad-text);-webkit-background-clip:text;background-clip:text;color:transparent}
}
.vc-ar{font-family:var(--fm);color:#067D33;font-size:min(1.4rem,2.3cqw);flex:none;line-height:1}
.vc-cap{font-family:var(--fm);font-size:.62rem;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);display:block;margin-top:5px;white-space:nowrap}
/* Below this the captions alone are wider than the container, so they step aside
   rather than break the line — the step words carry the meaning, and the
   container's aria-label already spells the sequence out. */
@container (max-width:640px){
  .vc-cap{display:none}
  .vc-ar{font-size:3.1cqw}   /* 2.3cqw here reads as a dash, not an arrow */
}
/* ---------- the four layers: scroll assembles the stack ----------
   Scroll is the only clock here: the engine writes one number per slab (--k, 0..1)
   and every property below is derived from it, so scrubbing back up plays the
   assembly in reverse instead of replaying a canned animation. The stack builds
   bottom-up — IoT first, AI last — which is the argument the copy just made.
   Progressive enhancement: these defaults are the finished state. The engine adds
   .live before it starts driving, so with no JS, and under reduced motion, all
   four layers are simply present and readable. */
.stk-stick{background:#fff;align-items:center}
/* the slabs are opaque white, so the background world only ever shows in the
   gutters around them — no text ever sits on the canvas */
.stk{position:relative;z-index:2;width:100%;max-width:var(--mid);margin:0 auto;padding:0 var(--pad)}
.stk-body{display:grid;grid-template-columns:34px 1fr;gap:clamp(14px,2.4vw,26px);align-items:stretch}
/* spine: fills upward with overall progress, its bright cap is the signal front */
.stk-spine{position:relative;width:4px;justify-self:center;margin-top:34px;border-radius:99px;
  background:rgba(10,20,32,.10)}
.stk-spine i{position:absolute;left:0;right:0;bottom:0;height:var(--fill,100%);border-radius:99px;
  background:#0176FF}
.stk-spine i::after{content:"";position:absolute;left:0;right:0;top:0;height:6px;background:#fff;opacity:.5;filter:blur(2px)}
/* the switch at the end of the rail: fills as you scroll, snaps on at the top */
.stk-spine::before{content:"";position:absolute;left:50%;top:-30px;transform:translateX(-50%);
  width:20px;height:20px;border-radius:50%;
  background:conic-gradient(#0176FF var(--sw,0%),rgba(10,20,32,.12) 0);
  -webkit-mask:radial-gradient(circle,transparent 5.4px,#000 6px);
  mask:radial-gradient(circle,transparent 5.4px,#000 6px)}
.stk-spine::after{content:"";position:absolute;left:50%;top:-24px;
  width:8px;height:8px;border-radius:50%;background:#0176FF;
  transform:translateX(-50%) scale(var(--swp,0));transition:transform .2s var(--ease)}
.stk-list{list-style:none;margin:0;padding:0;display:grid;gap:clamp(10px,1.5vh,16px)}
.stk-l{position:relative;overflow:hidden;display:grid;grid-template-columns:clamp(150px,17vw,230px) 1fr;
  gap:clamp(12px,2vw,28px);align-items:center;background:#fff;border:1px solid var(--hair2);border-radius:10px;
  padding:clamp(16px,2.2vh,26px) clamp(18px,2.4vw,30px);box-shadow:0 1px 2px rgba(10,20,32,.03)}
/* the accent rail that fills as the layer locks — decoration only: brand green and
   teal both fail contrast as text, so no string ever takes --lc */
.stk-l::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--lc,var(--blue))}
.stk-l::after{content:"";position:absolute;left:0;bottom:0;height:2px;width:var(--rail,100%);background:var(--lc,var(--blue));opacity:.55}
.stk-k{font-family:var(--fd);font-weight:900;text-transform:uppercase;font-size:clamp(1rem,1.9vw,1.5rem);
  line-height:1.1;color:var(--ink);letter-spacing:-.01em}
.stk-d{color:var(--muted);font-size:clamp(.9rem,1.15vw,1.02rem);line-height:1.45}
@media (max-width:720px){
  .stk-body{grid-template-columns:22px 1fr;gap:14px}
  .stk-l{grid-template-columns:1fr;gap:6px;align-items:start}
}
/* --- driven state: every value comes from --k, so it scrubs both directions ---
   The slab's frame stays visible at k=0 — only tilted and unlit — so the full
   structure of the stack reads from the scene's first frame instead of opening on
   an empty viewport. The copy is what fades in, and it goes from 0 straight to
   full: a half-opaque label would just be low-contrast text. */
.stk.live .stk-list{perspective:1400px}
.stk.live .stk-l{box-shadow:none;
  transform:translateY(calc((1 - var(--k,0)) * 22px)) rotateX(calc((1 - var(--k,0)) * -6deg));
  transform-origin:50% 100%}
.stk.live .stk-k,.stk.live .stk-d{opacity:var(--k,0)}
.stk.live .stk-l::after{width:calc(var(--k,0) * 100%)}
.stk.live .stk-l::before{transform:scaleY(var(--k,0));transform-origin:50% 100%}
/* ---------- the questions we ask first: scroll asks them in order ----------
   Same grammar as the layer stack — the row frame is always there and the copy is
   what arrives — so the two scenes read as one house style. What differs is the
   axis: the background camera pans sideways here rather than climbing, because
   the content is a sequence in time, not a stack in space.
   The numerals come from a CSS counter, not text nodes, so the scene adds nothing
   to the translation dictionary. They stay --muted (6.23:1) rather than taking an
   accent: brand blue is 4.17:1 and would fail as small text. */
.ask-stick{background:#F6F9FC;align-items:center}
.ask{position:relative;z-index:2;width:100%;max-width:var(--mid);margin:0 auto;padding:0 var(--pad)}
.ask-list{counter-reset:aq;list-style:none;margin:0;padding:0;display:grid;gap:clamp(6px,1.1vh,12px)}
.ask-q{counter-increment:aq;position:relative;display:grid;grid-template-columns:auto 1fr;
  gap:clamp(14px,2vw,26px);align-items:baseline;padding:clamp(11px,1.6vh,18px) 0;
  border-bottom:1px solid var(--hair);
  font-family:var(--fd);font-weight:800;text-transform:uppercase;letter-spacing:-.01em;
  font-size:clamp(1.05rem,2.4vw,1.95rem);line-height:1.14;color:var(--ink)}
/* --ink, not --muted: the background world sits directly behind these rows (unlike
   the layer stack, whose slabs are opaque), and muted numerals capped the world at
   0.14 alpha before they dropped under 4.5:1. In ink they hold 8.8:1 even at the
   raised 0.34 peak, which is what lets the background be legible at all. */
.ask-q::before{content:counter(aq,decimal-leading-zero);font-family:var(--fm);font-weight:400;
  font-size:clamp(.6rem,.85vw,.72rem);letter-spacing:.2em;color:var(--ink);text-transform:none}
/* the sweep that runs under a question as it is asked */
.ask-q::after{content:"";position:absolute;left:0;bottom:-1px;height:2px;width:var(--sweep,100%);
  background:var(--grad)}
@media (max-width:600px){.ask-q{grid-template-columns:1fr;gap:4px}}
/* --- driven state: one --k per row, so it scrubs in both directions --- */
.ask.live .ask-q span{opacity:var(--k,0)}
.ask.live .ask-q::after{width:calc(var(--k,0) * 100%)}

/* ---------- our DNA: the strand ----------
   Deliberately NOT another pinned scene. Each value is linked to its own position
   in the viewport, so the section scrolls normally and the values draw themselves
   as they pass — reversible, and nothing takes the scroll hostage.
   Scoped to .strand because .dna is shared by four pages.
   Progressive enhancement again: these defaults are the drawn state, and the
   engine adds .live before it starts driving, so no-JS and reduced motion both
   show the finished strand. */
.strand{position:relative;display:grid;gap:clamp(12px,2vh,22px)}
/* the spine the values hang off, running the brand sequence top to bottom */
.strand::before{content:"";position:absolute;left:8px;top:12px;bottom:12px;width:2px;border-radius:2px;
  background:linear-gradient(to bottom,#0176FF,#04C900 26%,#00BFA8 52%,#062A6E 76%,#0176FF)}
.str-i{position:relative;display:grid;grid-template-columns:14px 1fr;gap:clamp(16px,2.2vw,28px);
  align-items:center;min-height:46px;padding-left:2px}
.str-i i{width:14px;height:14px;border-radius:50%;background:var(--c,var(--blue));box-shadow:0 0 0 5px #fff}
/* the rung, from the node out to the label */
.str-i::after{content:"";position:absolute;left:16px;top:50%;height:2px;width:var(--rung,22px);
  background:var(--c,var(--blue));opacity:.5}
.str-i strong{font-family:var(--fd);font-weight:800;text-transform:uppercase;letter-spacing:-.005em;
  font-size:clamp(1rem,1.9vw,1.4rem);line-height:1.15;color:var(--ink);
  background-image:linear-gradient(var(--c,var(--blue)),var(--c,var(--blue)));
  background-repeat:no-repeat;background-position:0 100%;background-size:100% 2px;padding-bottom:5px}
/* --- driven state: one --k per value, everything below derives from it ---
   The nodes stay on the spine at all times so the strand's structure is visible
   before anything is drawn; the labels are what arrive, and they go from 0 to
   full rather than resting at a low opacity — half-opaque copy is just
   low-contrast text. */
.strand.live .str-i i{transform:scale(calc(.5 + .5 * var(--k,0)))}
.strand.live .str-i::after{width:calc(6px + var(--k,0) * 18px);opacity:calc(.15 + var(--k,0) * .35)}
/* Opacity reaches full at a third of the band, not at the end. Because this is
   scroll-LINKED rather than time-based, a reader who stops mid-cascade would
   otherwise leave a label parked at partial opacity indefinitely; the remaining
   two thirds drive the slide and the underline, which are safe to sit part-way. */
.strand.live .str-i strong{opacity:min(1,calc(var(--k,0) * 3));
  transform:translateX(calc((1 - var(--k,0)) * 22px));
  background-size:calc(var(--k,0) * 100%) 2px}

/* ---------- Explore more: the ecosystem dial ----------
   Deliberately unlike the other scroll pieces on this site: nothing is pinned, the
   camera does not travel, and the motion is ANGULAR — a needle sweeps an arc and
   lights each area as it passes. The page you are on is the hub at the bottom; the
   five sibling areas sit on the arc, which is what "one technology ecosystem"
   actually describes.
   Node positions are hardcoded per node (--nx/--ny) rather than computed with
   transform trigonometry, so long labels can be checked for collision directly and
   every chip stays upright and readable at all times.
   Progressive enhancement: these defaults are the resolved dial with every area
   lit, so no-JS and reduced motion both get a complete, usable set of links. */
.eco{position:relative;height:clamp(300px,34vw,392px);margin-top:38px}
/* the spokes: hub -> node, with a signal running outward along each. Drawn on
   canvas because they are curved and animated; it sits under the chips, which are
   opaque, so no copy is ever over it. */
.eco-wire{position:absolute;inset:0;width:100%;height:100%;z-index:0;pointer-events:none}
.eco-hub,.eco-node{z-index:2}
.eco-arc{position:absolute;left:9%;right:9%;bottom:30px;height:74%;
  border:1px solid var(--hair);border-bottom:0;border-radius:50% 50% 0 0/100% 100% 0 0;pointer-events:none}
/* the hub: this page, at the centre of its own ecosystem */
.eco-hub{position:absolute;left:50%;bottom:0;transform:translateX(-50%);
  display:flex;flex-direction:column;align-items:center;gap:8px;text-align:center}
.eco-hub img{width:44px;height:44px}
.eco-hub b{font-family:var(--fm);font-size:.58rem;letter-spacing:.22em;text-transform:uppercase;color:var(--muted);font-weight:400}
.eco-hub strong{font-family:var(--fd);font-weight:900;text-transform:uppercase;font-size:clamp(.9rem,1.5vw,1.15rem);color:var(--ink);max-width:22ch;line-height:1.1}
/* the five sibling areas on the arc */
.eco-node{position:absolute;left:var(--nx);top:var(--ny);transform:translate(-50%,-50%);
  display:inline-flex;align-items:center;gap:10px;max-width:min(240px,40%);
  background:#fff;border:1px solid var(--hair2);border-radius:999px;padding:9px 16px 9px 12px;
  font-family:var(--fd);font-weight:800;text-transform:uppercase;letter-spacing:.01em;
  font-size:clamp(.72rem,1.05vw,.84rem);line-height:1.15;color:var(--ink);
  transition:border-color .3s var(--ease),box-shadow .3s var(--ease)}
.eco-node i{font-style:normal;flex:none;width:9px;height:9px;border-radius:50%;background:var(--nc,var(--blue))}
.eco-node:hover{color:var(--ink);border-color:var(--hair2);box-shadow:var(--shadow-soft)}
.eco-node .arr{margin-left:2px;opacity:.55}
/* --- driven state: unlit until the needle reaches them --- */
.eco.live .eco-node{border-color:var(--hair);box-shadow:none}
.eco.live .eco-node i{opacity:.25;transform:scale(.7)}
.eco.live .eco-node.lit{border-color:var(--hair2);box-shadow:var(--shadow-soft)}
.eco.live .eco-node.lit i{opacity:1;transform:none}
.eco.live .eco-node i{transition:opacity .3s var(--ease),transform .3s var(--ease)}
/* Below this an arc cannot hold five chips without collisions, so the dial becomes
   a plain column — same links, same order, no geometry. */
@media (max-width:820px){
  .eco{height:auto;display:grid;gap:10px;justify-items:start}
  .eco-arc,.eco-wire{display:none}
  .eco-hub{position:static;transform:none;flex-direction:row;align-items:center;gap:12px;text-align:left;margin-bottom:8px}
  .eco-node{position:static;transform:none;max-width:100%}
}

/* --- the dial, pinned: the section holds on screen while the network builds ---
   Three planes move at different rates against the scroll, so the copy rides ahead
   of the dial and the arc falls behind it. Only planes the wires do NOT connect are
   parallaxed — hub, chips and canvas travel together as one plane, so a wire can
   never come unstuck from its chip. --p is the pinned progress, written by the
   engine; every transform below resolves to none at --p:0, which is the state
   no-JS and reduced motion get. */
.eco-track{height:280vh}
.eco-track .pin-stick{align-items:center;padding-block:calc(max(var(--mh,0px),86px) + 8px) 44px}
.eco-in{width:100%}
.eco-in .slate{transform:translateY(calc(var(--p,0) * -46px))}
.eco-in .head-xl{transform:translateY(calc(var(--p,0) * -30px))}
.eco{transform:translateY(calc(var(--p,0) * -14px))}
.eco-arc{transform:translateY(calc(var(--p,0) * 22px))}
.eco-track.live .eco-in .slate,.eco-track.live .eco-in .head-xl,
.eco-track.live .eco,.eco-track.live .eco-arc{will-change:transform}
/* Unpinned (narrow, or reduced motion): the generic .no-pin / html.rm rules above
   give the section its own height back, so the planes must sit still. */
.eco-track.no-pin .eco-in .slate,.eco-track.no-pin .eco-in .head-xl,
.eco-track.no-pin .eco,.eco-track.no-pin .eco-arc,
html.rm .eco-in .slate,html.rm .eco-in .head-xl,
html.rm .eco,html.rm .eco-arc{transform:none}
.eco-track.no-pin,html.rm .eco-track{height:auto}
@media (max-height:760px){
  .eco-track .pin-stick{padding-block:calc(max(var(--mh,0px),82px) + 4px) 24px}
  .eco{height:clamp(268px,30vw,320px)}
}

/* reduced-motion pin unwinding */
html.rm .pin-track{height:auto !important}
html.rm .pin-stick{position:relative;height:auto;min-height:0;padding-block:80px;--mh:0px !important}
html.rm .blue-stick{padding-block:0}
/* When the braid scene is unpinned the stick collapses to the height of the copy,
   leaving the canvas no room — the disc then lands on top of the heading. Reserve
   a band below the copy for it. */
html.rm .pin-track[data-engine="braid"] .pin-stick,
.pin-track.no-pin[data-engine="braid"] .pin-stick{min-height:860px}
/* the chain and sub are normally offset in vh, which drifts against a stick of
   fixed height — pin them to the stick in px while unpinned */
/* --- the technology model, unpinned ------------------------------------------
   Below 900px the pinned composition has nowhere to put four edge-anchored
   labels: the copy block takes most of a phone-height frame and the labels end
   up over the sub-line and the chain (measured at 360, 390 and 768). Unpinned,
   everything returns to normal flow — copy, then the braid in a band of its own,
   then the four layers as a legend, then the chain. Nothing can overlap because
   nothing is absolutely positioned any more. */
.pin-track.no-pin[data-engine="braid"]{height:auto !important}
/* the DOM order is canvas, labels, copy, chain — which is the overlay stacking
   order, not a reading order. A flex column with explicit order puts it right
   without touching the markup on the page. */
.pin-track.no-pin[data-engine="braid"] .pin-stick{position:relative;height:auto;min-height:0;
  overflow:visible;display:flex;flex-direction:column;align-items:stretch;
  padding-block:clamp(64px,9vw,110px);--mh:0px !important}
.pin-track.no-pin[data-engine="braid"] .s2-copy{order:1}
.pin-track.no-pin[data-engine="braid"] .scene-canvas{order:2}
.pin-track.no-pin[data-engine="braid"] .s2-labels{order:3}
.pin-track.no-pin[data-engine="braid"] .s2-chain{order:4}
.pin-track.no-pin[data-engine="braid"] .s2-sub{order:5}
.pin-track.no-pin[data-engine="braid"] .s2-copy{position:static;align-self:auto;padding:0 var(--pad);
  max-width:none}
.pin-track.no-pin[data-engine="braid"] .scene-canvas{position:relative;inset:auto;
  height:clamp(230px,52vw,320px);margin-top:28px}
.pin-track.no-pin[data-engine="braid"] .matte,
.pin-track.no-pin[data-engine="braid"] .scene-slate,
.pin-track.no-pin[data-engine="braid"] .scene-tc{display:none}
/* the labels stop being tags on the ribbon ends and become a legend */
.pin-track.no-pin[data-engine="braid"] .s2-labels{position:static;inset:auto;pointer-events:auto;
  display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:0 var(--pad);margin-top:20px}
.pin-track.no-pin[data-engine="braid"] .s2-lab{position:static;left:auto;top:auto;
  display:flex;align-items:center;opacity:1;transform:none}
.pin-track.no-pin[data-engine="braid"] .s2-chain{position:static;inset:auto;bottom:auto;
  margin-top:22px;padding:0 var(--pad)}
.pin-track.no-pin[data-engine="braid"] .s2-sub{position:static;inset:auto;bottom:auto;
  margin-top:12px;padding:0 var(--pad);opacity:1}
@media (max-width:430px){
  .pin-track.no-pin[data-engine="braid"] .s2-labels{grid-template-columns:1fr}
}

html.rm .matte,html.rm .film-grain,html.rm .vignette{display:none}

/* ---------- touch snap stops (paired with TOUCH PACING in kinema-scenes.js)
   scroll-snap-stop:always forbids a fling from passing more than one stop,
   so the maximum travel per gesture is one grid step — a native, compositor-
   driven speed lock that cannot stutter. The .snap-grid markers are laid out
   by initSnapStops(). ---------- */
@media (pointer: coarse){
  /* .snap-scenes is added by initSnapStops() — AI & Innovation page only */
  html.snap-scenes:not(.rm){scroll-snap-type:y mandatory}
  .snap-grid{position:absolute;top:0;left:0;width:1px;height:0;pointer-events:none}
  .snap-grid i{position:absolute;left:0;width:1px;height:2px;scroll-snap-align:start;scroll-snap-stop:always}
  /* the half-second dwell after landing on a stop: touch-action is read by
     the browser at gesture start, so while this class is on, new pan
     gestures simply don't begin — no JS runs during scrolling at all */
  html.scroll-hold{touch-action:none}
}
