/* =====================================================================
   Counttable — UI/UX Enhancement Layer  (ct-enhance.css)
   Shared across all pages. Additive, dark-first, with light-theme fixes.
   Loaded after each page's inline <style>, so it wins where needed.
   ===================================================================== */

:root{
  /* Inherit the page's accent so one declaration per page retints this whole
     layer; the literals are only fallbacks if a page forgets to set it. */
  --ce-accent:var(--cx-accent,#ff6a2b);
  --ce-accent-soft:rgba(var(--cx-accent-rgb,255,106,43),0.14);
  --ce-accent-line:rgba(var(--cx-accent-rgb,255,106,43),0.55);
  --ce-teal:#7fd1c7;
  --ce-ease:cubic-bezier(.2,.8,.2,1);
  --ce-radius:3px;
}

/* ---- Global type + rendering polish ---- */
html{ -webkit-text-size-adjust:100%; }
body{
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  text-rendering:optimizeLegibility;
}
::selection{ background:rgba(var(--cx-accent-rgb,255,106,43),0.32); color:#fff; }

/* ---- Custom scrollbar (site-wide) ---- */
*{ scrollbar-width:thin; scrollbar-color:rgba(var(--cx-accent-rgb,255,106,43),0.55) transparent; }
::-webkit-scrollbar{ width:10px; height:10px; }
::-webkit-scrollbar-track{ background:transparent; }
::-webkit-scrollbar-thumb{
  background:linear-gradient(180deg,rgba(var(--cx-accent-rgb,255,106,43),0.65),rgba(127,209,199,0.45));
  border-radius:20px; border:2px solid transparent; background-clip:padding-box;
}
::-webkit-scrollbar-thumb:hover{ background:rgba(var(--cx-accent-rgb,255,106,43),0.85); background-clip:padding-box; }

/* =====================================================================
   NAV — glass, hairline, animated underline, active state
   ===================================================================== */
#cx-nav{
  backdrop-filter:blur(16px) saturate(140%);
  -webkit-backdrop-filter:blur(16px) saturate(140%);
  border-bottom:1px solid var(--cx-line,rgba(255,255,255,0.08));
  transition:background .4s var(--ce-ease), border-color .4s var(--ce-ease), padding .35s var(--ce-ease);
}
#cx-nav .ct-logo-hover, #cx-nav a[aria-label="Counttable home"]{
  transition:transform .5s var(--ce-ease), filter .5s var(--ce-ease);
}
#cx-nav a[aria-label="Counttable home"]:hover{ transform:translateY(-1px) scale(1.02); }

/* nav link underline sweep */
#cx-nav ul a{
  position:relative;
  transition:color .3s var(--ce-ease);
  padding-bottom:4px;
}
#cx-nav ul a::after{
  content:""; position:absolute; left:0; right:100%; bottom:-2px; height:1.5px;
  background:linear-gradient(90deg,var(--ce-accent),var(--ce-teal));
  transition:right .38s var(--ce-ease);
}
#cx-nav ul a:hover{ color:var(--cx-text)!important; }
#cx-nav ul a:hover::after{ right:0; }

/* ---- ACTIVE PAGE ----
   ct-nav.js sets aria-current="page" on the link matching the current URL.
   The underline that hover sweeps in is simply pinned open, so "you are here"
   reads as a settled version of the hover state rather than a new idiom. */
#cx-nav ul a[aria-current="page"]{
  color:var(--cx-text)!important;
  font-weight:600;
}
#cx-nav ul a[aria-current="page"]::after{
  right:0;
  height:2px;
  box-shadow:0 0 12px rgba(var(--cx-accent-rgb,255,106,43),0.45);
}
/* a dim accent dot above the label — survives the underline being missed at
   a glance, and gives the mark a second, colour-independent cue */
#cx-nav ul a[aria-current="page"]::before{
  content:"";
  position:absolute; top:-7px; left:50%; transform:translateX(-50%);
  width:3px; height:3px; border-radius:50%;
  background:var(--ce-accent);
}
html[data-theme="light"] #cx-nav ul a[aria-current="page"]::after{
  box-shadow:0 0 10px rgba(var(--cx-accent-rgb,255,106,43),0.35);
}

/* ---- THEME / LANGUAGE TOGGLES: wired up, not shown yet ----
   ct-theme.js and ct-i18n.js still run in full — logo swap, aria-current
   colour, localStorage persistence, RTL layout, the lot — so turning the
   switch back on is a one-line change once light mode and Arabic are ready
   for visitors. Until then the mount points just render nothing. */
[data-theme-mount], [data-language-mount]{ display:none!important; }

/* =====================================================================
   BUTTONS — unified lift / glow micro-interactions
   Robust selector: the standalone CTAs are .ct-cursor-hot links that
   are NOT nav items, pipeline nodes, or instrument cards.
   (Avoids matching runtime-normalized inline-style substrings.)
   ===================================================================== */
a.ct-cursor-hot:not(#cx-nav a):not([data-node]):not([data-tilt]){
  transition:transform .35s var(--ce-ease), box-shadow .35s var(--ce-ease), background .35s var(--ce-ease), border-color .35s var(--ce-ease), color .3s var(--ce-ease);
}
a.ct-cursor-hot:not(#cx-nav a):not([data-node]):not([data-tilt]):hover{
  transform:translateY(-2px);
  box-shadow:0 10px 38px rgba(var(--cx-accent-rgb,255,106,43),0.30);
}
/* the compact "Start" button in the nav (a link inside a div, not the ul) */
#cx-nav div a.ct-cursor-hot:hover{ transform:translateY(-1px); }

/* =====================================================================
   CARDS — pipeline nodes, instrument cards: elevation + glow
   ===================================================================== */
[data-node]{
  border-radius:var(--ce-radius);
  transition:transform .4s var(--ce-ease), border-color .4s var(--ce-ease), box-shadow .4s var(--ce-ease), background .4s var(--ce-ease)!important;
}
[data-node]:hover{
  transform:translateY(-8px)!important;
  border-color:var(--ce-accent-line)!important;
  box-shadow:0 18px 50px rgba(0,0,0,0.35);
}
[data-tilt]{
  border-radius:var(--ce-radius);
  transition:transform .4s var(--ce-ease), border-color .4s var(--ce-ease), box-shadow .4s var(--ce-ease)!important;
}
[data-tilt]:hover{
  border-color:var(--ce-accent-line)!important;
  box-shadow:0 26px 70px rgba(0,0,0,0.45), 0 0 0 1px rgba(var(--cx-accent-rgb,255,106,43),0.18) inset;
}

/* =====================================================================
   PIPELINE — redesigned as a no-scroll responsive grid.
   The original was a horizontal-scroll flex row (clipped titles,
   ugly scrollbar). Now: all 7 steps visible, wrapping cleanly,
   numbered 01–07, with an animated top accent line. No sideways scroll.
   Targets the pipeline track on both the homepage and /pipeline.
   ===================================================================== */
[data-panel]:has(> [data-node]){
  display:grid!important;
  /* 4 across, so the 7 steps land as 4 + 3 on two rows. Seven in a single row
     squeezed every card to ~130px, which is what made the labels unreadable. */
  grid-template-columns:repeat(4,1fr)!important;
  gap:16px!important;
  overflow:visible!important;
  padding-bottom:0!important;
  -webkit-mask-image:none!important; mask-image:none!important;
  counter-reset:ctstep;
}
/* hide the old inline connector lines between cards */
[data-panel]:has(> [data-node]) > *:not([data-node]){ display:none!important; }

/* the step cards — wider now, so they can afford real padding */
[data-panel]:has(> [data-node]) > [data-node]{
  min-width:0!important;
  padding:30px 24px 26px!important;
  counter-increment:ctstep;
  display:flex; flex-direction:column;
}
/* step number 01–07, top-right */
[data-panel]:has(> [data-node]) > [data-node]::before{
  content:counter(ctstep,decimal-leading-zero);
  position:absolute; top:12px; right:14px;
  font-family:'Space Grotesk',sans-serif; font-weight:700; font-size:13px;
  letter-spacing:1px; color:var(--cx-muted); opacity:.7;
}
/* animated top accent line (flow feel that replaces the connectors) */
[data-panel]:has(> [data-node]) > [data-node]::after{
  content:""; position:absolute; top:0; left:0; right:0; height:2px;
  background:linear-gradient(90deg,var(--ce-accent),var(--ce-teal));
  transform:scaleX(.18); transform-origin:left;
  transition:transform .5s var(--ce-ease); opacity:.9;
}
[data-panel]:has(> [data-node]) > [data-node]:hover::after{ transform:scaleX(1); }
/* titles: never break mid-word */
[data-panel]:has(> [data-node]) > [data-node] > div:nth-child(2){
  white-space:normal!important; overflow-wrap:normal!important;
  word-break:keep-all!important; hyphens:none!important;
  line-height:1.2; font-size:19px!important; letter-spacing:-0.3px!important;
  margin-bottom:8px!important;
}
/* the one-line description under each title */
[data-panel]:has(> [data-node]) > [data-node] > div:nth-child(3){
  font-size:14px!important; line-height:1.45!important;
}
/* responsive column counts — always wraps to rows, never scrolls sideways */
@media (max-width:1080px){ [data-panel]:has(> [data-node]){ grid-template-columns:repeat(3,1fr)!important; } }
@media (max-width:760px){  [data-panel]:has(> [data-node]){ grid-template-columns:repeat(2,1fr)!important; } }
@media (max-width:760px){
  [data-panel]:has(> [data-node]) > [data-node]{ padding:24px 18px 20px!important; }
}
/* The title above is pinned to 19px and forbidden from breaking mid-word, so a
   long single word like "Construction" (112px at 19px Space Grotesk 700) can still spill
   out of a 163px card. The cards go to three columns at 1080px, which is where
   they get narrow enough for that to happen — so the type has to come down at
   the same point, not at 760px. */
@media (max-width:1080px){
  [data-panel]:has(> [data-node]) > [data-node] > div:nth-child(2){ font-size:16px!important; }
}
@media (max-width:420px){
  [data-panel]:has(> [data-node]){ grid-template-columns:1fr!important; gap:12px!important; }
  [data-panel]:has(> [data-node]) > [data-node]{ padding:20px 18px 18px!important; }
}

/* =====================================================================
   FOCUS-VISIBLE — accessibility (keyboard) rings, no mouse noise
   ===================================================================== */
a:focus-visible, button:focus-visible, [tabindex]:focus-visible,
[data-node]:focus-visible, [data-tilt]:focus-visible{
  outline:2px solid var(--ce-accent);
  outline-offset:3px;
  border-radius:2px;
}
a:focus:not(:focus-visible), button:focus:not(:focus-visible){ outline:none; }

/* =====================================================================
   LIGHT THEME — the lower sections were dark-first; lift contrast
   ===================================================================== */
html[data-theme="light"]{
  --cx-glass:rgba(19,22,28,0.045);
  --cx-line:rgba(19,22,28,0.14);
  --cx-muted:#4b5568;
}
html[data-theme="light"] [data-node],
html[data-theme="light"] [data-tilt]{
  background:linear-gradient(160deg,rgba(255,255,255,0.9),rgba(255,255,255,0.55))!important;
  border-color:rgba(19,22,28,0.12)!important;
  box-shadow:0 2px 18px rgba(19,22,28,0.06);
}
html[data-theme="light"] [data-node]:hover,
html[data-theme="light"] [data-tilt]:hover{
  border-color:var(--ce-accent-line)!important;
  box-shadow:0 16px 44px rgba(19,22,28,0.14);
}
html[data-theme="light"] #cx-nav{
  border-bottom-color:rgba(19,22,28,0.10);
}
/* keep the giant display headings legible over the bright webgl floor */
html[data-theme="light"] [data-screen-label] h1,
html[data-theme="light"] [data-screen-label] h2{
  text-shadow:0 2px 30px rgba(233,237,242,0.6);
}

/* =====================================================================
   DARK THEME — soften the webgl floor glare behind hero copy
   ===================================================================== */

/* subtle readability scrim behind hero paragraph/label blocks */
[data-screen-label="Cinematic / Hero"] p,
[data-screen-label*="Hero"] p{ position:relative; }

/* =====================================================================
   MOBILE / RESPONSIVE
   None of the six pages carries a single media query of its own — every inline
   style is desktop-sized — so all responsive behaviour lives here.

   Where there's no semantic hook, rules match on the serialized inline style.
   Two things make that safe: the runtime writes shorthand with spaces (hence
   the doubled selectors), and "px 44px" only ever occurs in a section gutter,
   never in something like height:44px.
   ===================================================================== */

/* Never allow a sideways scrollbar — but ONLY on body.
   overflow-x:hidden on <html> makes the root a scroll container, and then
   window.scrollY reports 0 while documentElement.scrollTop carries the value.
   That silently broke the homepage's scroll-driven camera, which reads
   window.scrollY. The pages already set it on body themselves. */
body{ overflow-x:hidden; }

/* ---- CROPPED TEXT ----
   Every hero is `height:100vh; min-height:620px; overflow:hidden`. A fixed box
   with hidden overflow crops its own contents the moment the type grows — which
   is exactly what happened when the font floor went up. Let heroes grow on
   short/narrow screens instead of clipping. */
@media (max-width:900px), (max-height:760px){
  section[data-screen-label*="Hero"],
  section[style*="min-height:620px"],
  section[style*="min-height: 620px"]{
    height:auto!important;
    min-height:100svh!important;
    overflow:visible!important;
    padding-top:132px!important;
    padding-bottom:56px!important;
  }
}
/* the homepage hero is a sticky inner div inside a 130vh section */
@media (max-width:900px), (max-height:760px){
  [data-screen-label="Cinematic / Hero"] > div{
    height:auto!important; min-height:100svh!important;
    padding-top:132px!important; padding-bottom:56px!important;
  }
}

/* ---- NAV: tighten the flat bar as it narrows ----
   These two steps only buy the flat bar more room; they are not what decides
   whether it survives. That decision is measured at runtime by ct-nav.js,
   which collapses the bar to a hamburger the moment the links stop fitting —
   see the .is-collapsed rules further down, next to the rest of the
   phone-layout pass. So these are a genuine progressive tightening, and if
   they are not enough at some width the measurement catches it rather than
   letting a link slide under the Start button. ---- */
@media (max-width:1280px){
  #cx-nav ul{ gap:24px!important; }
  #cx-nav ul a{ font-size:12px!important; letter-spacing:1.1px!important; }
}
@media (max-width:1040px){
  #cx-nav{ padding-left:26px!important; padding-right:26px!important; }
  #cx-nav ul{ gap:16px!important; }
}
@media (max-width:860px){
  #cx-nav{ padding:14px 20px!important; }
  #cx-nav > a[aria-label="Counttable home"] span{ height:34px!important; }
}

/* ---- GUTTERS: 44px each side leaves 272px of a 360px screen ---- */
@media (max-width:760px){
  [style*="px 44px"],[style*="px 44px 60px"]{ padding-left:24px!important; padding-right:24px!important; }
  [data-tilt]{ padding:34px 22px 30px!important; }
}
@media (max-width:420px){
  [style*="px 44px"],[style*="px 44px 60px"]{ padding-left:16px!important; padding-right:16px!important; }
}

/* ---- STORY PANELS: fixed 480px cards inset 44px don't fit a phone ---- */
@media (max-width:860px){
  [data-panel][style*="sticky"]{
    margin-left:16px!important; margin-right:16px!important;
    max-width:none!important; width:auto!important;
    padding:30px 22px!important; top:16vh!important;
  }
}

/* ---- GRIDS: every inline grid is a fixed column count with no fallback ----
   Note the parentheses are kept balanced inside the attribute strings. A
   selector like [style*="repeat(4"] is legal CSS, but some engines tokenize the
   paren even inside the quotes and silently match nothing, so both the
   comma and comma-space serializations are spelled out instead. */
@media (max-width:980px){
  [style*="repeat(4,1fr)"]:not([data-panel]),
  [style*="repeat(4, 1fr)"]:not([data-panel]){ grid-template-columns:repeat(2,1fr)!important; }
}
@media (max-width:900px){
  [style*="repeat(3,1fr)"]:not([data-panel]),
  [style*="repeat(3, 1fr)"]:not([data-panel]){ grid-template-columns:repeat(2,1fr)!important; }
}
@media (max-width:820px){
  [style*="1.1fr 1fr"]{ grid-template-columns:1fr!important; gap:34px!important; }
}
@media (max-width:640px){
  [style*="repeat(4,1fr)"]:not([data-panel]),
  [style*="repeat(4, 1fr)"]:not([data-panel]),
  [style*="repeat(3,1fr)"]:not([data-panel]),
  [style*="repeat(3, 1fr)"]:not([data-panel]),
  [style*="1fr 1fr"]:not([data-panel]){ grid-template-columns:1fr!important; gap:18px!important; }
}

/* ---- TOUCH TARGETS: 44px minimum, per WCAG 2.5.5 ---- */
@media (pointer:coarse){
  #cx-nav a, a.ct-cursor-hot, button{ min-height:44px; display:inline-flex; align-items:center; }
  #cx-nav ul a{ min-height:32px; }
}


/* =====================================================================
   PHONE LAYOUT — measured at 390x844, the common iPhone viewport.
   Before this block every page overflowed its viewport horizontally
   (403-469px of content in 390px) and body's overflow-x:hidden was quietly
   cropping whatever stuck out. Clipping is not fixing: the footer lost two
   of its six links, stat rows lost their last column, and the hero display
   type lost the end of its longest word. Each rule below removes a cause of
   that overflow rather than hiding it.
   ===================================================================== */

/* ---- DISPLAY TYPE: only the very smallest phones now need help ----
   The heroes size themselves with min(clamp(FLOORpx, Nvw, MAXpx), Nvh), and
   these headings put each word on its own line with <br>, so a word that
   doesn't fit cannot wrap — it gets cut off.

   How much fits is a property of the typeface, so this had to be recalculated
   when the site moved from Syne to Space Grotesk. Measured at weight 700 with
   -0.04em tracking, the longest words cost:

       word            Syne 800    Space Grotesk 700
       Understand.       9.49            5.55
       Construction      9.88            5.89
       Everything.       8.34            5.13

   (px of width per px of font-size.) Space Grotesk is ~41% narrower, which
   moves the widest word at 390px from a 37px ceiling to a 59px one — above the
   48px floor the design already asks for. The elaborate ladder of overrides
   that used to live here existed only to survive Syne; keeping it would now
   shrink the heroes for no reason.

   What remains: below 400px the 48px floor still overruns the ~232px of line a
   320px phone leaves, so the floor comes down there and only there. */
@media (max-width:400px){
  h1[style*="clamp(48px"], h2[style*="clamp(48px"]{ font-size:min(clamp(34px,12vw,48px),14.5vh)!important; }
  h1[style*="clamp(44px"], h2[style*="clamp(44px"]{ font-size:min(clamp(32px,11vw,44px),14vh)!important; }
  h1[style*="clamp(42px"], h2[style*="clamp(42px"]{ font-size:clamp(30px,10.5vw,42px)!important; }
  h1[style*="clamp(40px"], h2[style*="clamp(40px"]{ font-size:min(clamp(29px,10vw,40px),13.5vh)!important; }
}

/* Long single words break rather than overflow. Cheap insurance: this only
   ever takes effect when a word genuinely cannot fit its box. */
@media (max-width:1200px){
  h1,h2,h3,h4,p,li{ overflow-wrap:break-word; }
}

/* ---- GRIDS: multi-column layouts do not fit a phone ----
   The pages carry their column counts inline, so the collapse has to match
   inline values too.

   IMPORTANT: match the shortest distinctive fragment, never a whole declaration.
   The Design Component runtime re-serialises every inline style through the
   CSSOM, so `display:flex` in the source HTML arrives in the DOM as
   `display: flex` and `repeat(3,1fr)` as `repeat(3, 1fr)`. Selectors written
   against the authored spelling match on some elements and silently miss on
   others — which is exactly how the stat rows kept overflowing after the first
   pass of these rules appeared to fix everything else. */
@media (max-width:760px){
  [style*="repeat(4"],
  [style*="repeat(3"],
  [style*="grid-template-columns:2.2fr"],
  [style*="grid-template-columns: 2.2fr"]{
    grid-template-columns:repeat(2,minmax(0,1fr))!important;
  }
}
@media (max-width:560px){
  [style*="repeat(4"],
  [style*="repeat(3"],
  [style*="grid-template-columns:2.2fr"],
  [style*="grid-template-columns: 2.2fr"],
  [style*="1fr 1fr"],
  [style*="grid-template-columns:1.1fr"],
  [style*="grid-template-columns: 1.1fr"]{
    grid-template-columns:minmax(0,1fr)!important;
  }
}

/* ---- grid items refuse to shrink ----
   A grid item's default min-width is auto, i.e. its content width, so one long
   unbreakable child forces the whole track wider than the screen. */
@media (max-width:900px){
  [style*="display:grid"] > *,
  [style*="display: grid"] > *{ min-width:0; }
}

/* ---- flex rows must WRAP, not squeeze ----
   The stat rows ("38,400 M³ CONCRETE / 5,120 T STEEL / 9x % COST MAPPED") are
   plain display:flex with a 32px gap and no wrap, sitting inside a panel with
   overflow:hidden. On a phone the third stat was clipped clean off. Note this
   deliberately does NOT set min-width:0 on flex children: that lets an item
   shrink below its content and hides the overflow by cutting the text, which
   is the same bug wearing a different hat. Wrapping keeps every value legible. */
@media (max-width:600px){
  [style*="display:flex"],
  [style*="display: flex"]{ flex-wrap:wrap; }
}

/* ---- FOOTER: the link row was 497px wide inside a 380px footer ----
   Six links plus a 60px gap on one non-wrapping flex line. Two of them were
   simply cut off — and this was the single biggest source of sideways overflow
   left on the interior pages, which carry a different footer markup to the
   homepage (no #contact, wrap already set on the <footer> but not on the inner
   row that actually holds the links). So: every flex row anywhere in a footer
   wraps and centres, and the 44px side padding comes down. */
@media (max-width:760px){
  footer{ padding-left:20px!important; padding-right:20px!important; }
  footer,
  footer div{
    flex-wrap:wrap!important;
    justify-content:center!important;
    gap:14px 18px!important;
    text-align:center;
  }
}

/* ---- NAV: collapses into a hamburger panel when the row runs out of room ----
   #cx-nav-toggle (built by ct-nav.js) is display:none inline and only ever
   shown here. Collapsed, the link list hides by default and only appears while
   #cx-nav carries .is-menu-open, dropping down as one opaque panel instead of
   wrapping the bar into extra rows — background fading to 0.6 alpha made
   headings scrolling underneath the old two-row bar read as broken, so this
   panel is solid too.

   Keyed off .is-collapsed, not a media query. ct-nav.js measures the finished
   bar against the space it has and sets the class; see the long note by
   flatWidth() for why a pixel breakpoint could not get this right. Every
   selector here is therefore state-based, and works at any viewport width. */
#cx-nav.is-collapsed #cx-nav-toggle{ display:inline-flex!important; }
#cx-nav.is-collapsed{
  background:var(--cx-bg,#020304)!important;
  border-bottom:1px solid var(--cx-line,rgba(255,255,255,0.08));
}
/* The <ul> ships display:flex/align-items:center/padding:0 as inline
   style, which beats any unqualified stylesheet rule — hence !important
   on every property that inline also sets. */
#cx-nav.is-collapsed > ul{
  display:none!important;
  position:absolute; top:100%; left:0; right:0;
  flex-direction:column!important; align-items:stretch!important;
  gap:0!important; margin:0; padding:8px!important;
  background:var(--cx-bg,#020304);
  border-bottom:1px solid var(--cx-line,rgba(255,255,255,0.08));
  box-shadow:0 26px 50px rgba(0,0,0,.35);
  max-height:calc(100svh - 100%);
  overflow-y:auto;
}
html[data-theme="light"] #cx-nav.is-collapsed > ul{ background:var(--cx-bg,#e9edf2); }
#cx-nav.is-collapsed.is-menu-open > ul{ display:flex!important; }
#cx-nav.is-collapsed ul li{ width:100%; flex-shrink:0!important; }
#cx-nav.is-collapsed ul li + li{ border-top:1px solid var(--cx-line); }
#cx-nav.is-collapsed ul a{
  display:block; width:100%; padding:14px 10px!important;
  font-size:14px!important; letter-spacing:1px!important;
}
#cx-nav.is-collapsed ul a::after{ display:none; }
#cx-nav.is-collapsed ul a[aria-current="page"]::before{ display:none; }
#cx-nav.is-collapsed ul a[aria-current="page"]{
  background:rgba(var(--cx-accent-rgb,255,106,43),.08);
  padding-left:16px!important;
}

/* the hamburger draws itself as an X while the panel is open */
#cx-nav-toggle path{ transition:transform .3s var(--ce-ease), opacity .2s ease; transform-origin:9px 9px; }
#cx-nav.is-menu-open #cx-nav-toggle [data-ct-menu-line-1]{ transform:translateY(4px) rotate(45deg); }
#cx-nav.is-menu-open #cx-nav-toggle [data-ct-menu-line-2]{ opacity:0; }
#cx-nav.is-menu-open #cx-nav-toggle [data-ct-menu-line-3]{ transform:translateY(-4px) rotate(-45deg); }

/* ---- last resort: nothing may push the page sideways ---- */
@media (max-width:900px){
  img,svg,canvas,video,table,pre{ max-width:100%; }
}

/* =====================================================================
   THE HERO IS THE FOOTAGE, NOT BOTH
   Interior pages run a scene-kit WebGL scene on #hero-canvas — wireframe
   facets and drifting particles. Over the old flat background that WAS the
   hero visual. Layered on top of graded video it is just noise fighting the
   footage, which is what made the heroes look messy.
   Note the selector is .ct-backdrop-video, not .ct-has-backdrop: phones get
   the still rather than the clip, and there these graphics are the only motion
   on the page, so they stay.
   ===================================================================== */
.ct-backdrop-video #hero-canvas{ display:none!important; }

/* =====================================================================
   LEGIBILITY OVER FOOTAGE
   The glass panels use --cx-glass at 0.035 alpha with a blur. That was tuned
   against a flat, near-black WebGL scene, where 3.5% white over black is
   plenty. Over graded video the same panel is effectively transparent and body
   copy sits directly on moving highlights — the text is all still there, it
   just cannot be read. ct-backdrop.js sets .ct-has-backdrop when footage is
   actually mounted, so this only applies where the problem exists.
   ===================================================================== */
.ct-has-backdrop [style*="backdrop-filter"]{
  background:rgba(2,3,4,0.62)!important;
  border-color:rgba(255,255,255,0.10)!important;
}
html[data-theme="light"].ct-has-backdrop [style*="backdrop-filter"]{
  background:rgba(233,237,242,0.78)!important;
  border-color:rgba(0,0,0,0.10)!important;
}
/* Headline blocks that sit on the footage with no panel behind them at all */
.ct-has-backdrop [data-screen-label*="Hero"] h1,
.ct-has-backdrop [data-screen-label*="Hero"] h2,
.ct-has-backdrop [data-screen-label*="Hero"] p{
  text-shadow:0 2px 24px rgba(0,0,0,0.55), 0 1px 3px rgba(0,0,0,0.45);
}
html[data-theme="light"].ct-has-backdrop [data-screen-label*="Hero"] h1,
html[data-theme="light"].ct-has-backdrop [data-screen-label*="Hero"] h2,
html[data-theme="light"].ct-has-backdrop [data-screen-label*="Hero"] p{
  text-shadow:0 2px 24px rgba(233,237,242,0.75), 0 1px 3px rgba(233,237,242,0.6);
}

/* =====================================================================
   LOADER FAILSAFE — the overlay must never be able to trap the page
   The homepage loader is a fixed, opaque, z-index:300 sheet that is dismissed
   by componentDidMount. That is a single point of failure over the entire
   site: when the component failed to mount, the loader stayed at 0% and the
   page sat behind it, fully rendered and completely unreachable.
   This dismisses it after 8s with no JavaScript involved. The normal path
   finishes in about 2.5s, so this only ever fires when something has already
   gone wrong — and then it degrades to a visible page instead of a dead one.
   ===================================================================== */
@keyframes ctLoaderFailsafe{ to{ opacity:0; visibility:hidden; } }
#cx-loader{ animation:ctLoaderFailsafe .6s ease 8s forwards; }

/* =====================================================================
   ENTRY FADE — navigation should read as a transition, not a hard cut
   Pure CSS on purpose. A JS-driven fade means a page that stays invisible
   when the script fails; this site has been bitten by that once already.
   Opacity only, no transform: a transformed ancestor becomes the containing
   block for position:fixed children, which would drag the header off with the
   page scroll. Opacity creates a stacking context but never a containing
   block, so the fixed nav stays put.
   ===================================================================== */
@keyframes ctEnter{ from{ opacity:0; } to{ opacity:1; } }
body > div:first-of-type{ animation:ctEnter .24s ease both; }

/* Tab is in the background: stop paying for decoration nobody can see. */
html.ct-hidden *{ animation-play-state:paused!important; }

/* =====================================================================
   REDUCED MOTION — respect user preference
   ===================================================================== */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms!important;
    animation-iteration-count:1!important;
    transition-duration:.12s!important;
    scroll-behavior:auto!important;
  }
}
