/* ─────────────────────────────────────────────────────────────────────────────
   SAHRO — sahro.in
   Built on SAHRO's own brand: navy #0d1b3e and orange #f97316, the two colours
   the product app has used all along, now worked as a LIGHT system. Navy is the
   ink and the structure; orange is reserved for action, so it still means
   something when it appears. Only two dark surfaces survive - the hero and the
   footer - as bookends; everything between them is paper.

   Depth comes from a real elevation ramp, not from glow. Every ratio quoted in
   a comment was computed, not guessed.
   ───────────────────────────────────────────────────────────────────────────── */

:root {
  /* ── brand ──────────────────────────────────────────────────────────────── */
  --navy:         #0d1b3e;   /* ink + structure */
  --navy-2:       #16294f;   /* nested dark: hover fill, phone chrome, insets */
  --navy-3:       #24365e;   /* secondary text on light — 11.08:1 on paper */
  --orange:       #f97316;   /* CTA fill, and accents ON NAVY only */
  --orange-lite:  #fb923c;   /* orange on navy: eyebrows, icons — 7.46:1 */
  --orange-hover: #fb8c3c;
  --orange-ink:   #a94c07;   /* orange as TEXT on light — 5.64 white / 5.25 paper / 4.85 band */
  --orange-fill:  #d25b08;   /* orange as a meaningful FILL on light */

  /* aliases, so rules written against the old names keep working */
  --ink: var(--navy);   --ink-2: var(--navy-3);
  --gold: var(--orange-lite);
  --accent: var(--orange-ink);

  /* ── light surfaces ─────────────────────────────────────────────────────── */
  --paper:   #f4f7fc;   /* page — cool and navy-tinted, never beige */
  --paper-2: #e9eef8;   /* the alternating band */
  --card:    #ffffff;
  --track:   #e3e9f3;   /* bar tracks and pill grounds */
  --line:    #dbe2ee;   /* decorative hairline */
  --line-2:  #c3cddf;   /* card and chip border */
  --line-ui: #8794b4;   /* input boundary — 3.03:1, clears WCAG 1.4.11 */
  --muted:   #566180;   /* 6.15 / 5.72 / 5.28 on card / paper / paper-2 */

  /* ── text on navy ───────────────────────────────────────────────────────── */
  --on-ink:        #ffffff;   /* 16.89:1 */
  --on-ink-body:   #d6ddec;   /* 12.40:1 */
  --on-ink-dim:    #b3bfda;   /*  9.15:1 */
  --on-ink-faint:  #8e9cbd;   /*  6.14:1 — the smallest legal label */
  --on-ink-line:   rgba(255,255,255,.14);
  --on-ink-line-2: rgba(255,255,255,.26);

  /* ── chart / demo fills ─────────────────────────────────────────────────────
     Fixed order, never reassigned by rank. Every pair is at least CIE-Lab dE 23
     apart (categorical floor ~20) and every fill clears 3:1 on both white and
     the track; c4 was pulled off the blue axis to a graphite specifically to
     open the c4/c6 gap from dE 15 to 32.6. */
  --c1: #1d4e89;  --c2: #d25b08;  --c3: #16706a;
  --c4: #6f7280;  --c5: #6b3fa0;  --c6: #2f86c4;
  /* the three that are legal as fills but not as small text */
  --c2-ink: #b4530a;  --c4-ink: #5f6479;  --c6-ink: #1b6ba8;
  --male: #1d4e89;  --female: #bf3f5c;

  /* ── navy tint ramp: heatmaps and wash panels ───────────────────────────── */
  --n5: #0d1b3e;  --n4: #1d4e89;  --n3: #3f74a8;
  --n2: #a8c3de;  --n1: #d3e0ef;  --n0: #e9eef8;

  /* ── status ─────────────────────────────────────────────────────────────── */
  --ok:      #157f4f;  --ok-bg:      #dcf1e5;  --ok-ink:      #0f6b43;
  --warn:    #a85a05;  --warn-bg:    #fdeccf;  --warn-ink:    #8a4a04;
  --hot:     #b3261e;  --hot-bg:     #fbe3e0;  --hot-ink:     #99231c;
  --neutral: #5b6684;  --neutral-bg: #e3e9f3;  --neutral-ink: #3c4763;

  /* ── the button contract. A SURFACE says what buttons look like on it; the
     button itself only reads these. That is the whole fix for the bug where an
     ink button landed on an ink background and disappeared. ──────────────── */
  --btn-bg: var(--navy);  --btn-fg: #fff;  --btn-bd: var(--navy);  --btn-bg-h: var(--navy-2);
  --btn2-fg: var(--navy); --btn2-bd: var(--line-2); --btn2-bg-h: rgba(13,27,62,.06);

  /* ── elevation: navy-tinted, never black, never a glow ──────────────────── */
  --e1: 0 1px 2px rgba(13,27,62,.06);
  --e2: 0 1px 2px rgba(13,27,62,.05), 0 6px 16px -6px rgba(13,27,62,.10);
  --e3: 0 2px 4px rgba(13,27,62,.05), 0 14px 32px -10px rgba(13,27,62,.14);
  --e4: 0 4px 8px rgba(13,27,62,.06), 0 28px 60px -16px rgba(13,27,62,.22);
  --e-ink: 0 18px 44px -14px rgba(13,27,62,.45);   /* navy objects on paper */
  --shadow: var(--e2);
  --ring: 0 0 0 3px rgba(29,78,137,.22);

  --gutter: 16px;
  --maxw: 1280px;
  --radius: 10px;
  --hdr-h: 68px;
}

/* A dark surface declares its own contract. Anything inside it - buttons,
   cards, borders, muted text - reads these instead of the light defaults, so a
   dark panel can be dropped anywhere without a single new colour rule. */
.on-ink, .hero, .ftr, .sec-dark {
  --card:    rgba(255,255,255,.06);
  --track:   rgba(255,255,255,.12);
  --line:    var(--on-ink-line);
  --line-2:  var(--on-ink-line-2);
  --line-ui: rgba(255,255,255,.42);
  --muted:   var(--on-ink-dim);
  --ink:     var(--on-ink);
  --ink-2:   var(--on-ink-body);
  --accent:  var(--orange-lite);
  --ring:    0 0 0 3px rgba(249,115,22,.34);
  --btn-bg: var(--orange);  --btn-fg: var(--navy);
  --btn-bd: var(--orange);  --btn-bg-h: var(--orange-hover);
  --btn2-fg: #fff;  --btn2-bd: rgba(255,255,255,.42);  --btn2-bg-h: rgba(255,255,255,.12);
  background: var(--navy);
  color: var(--on-ink-body);
}
.on-ink h1, .on-ink h2, .on-ink h3,
.hero h1, .hero h2, .hero h3,
.sec-dark h1, .sec-dark h2, .sec-dark h3 { color: var(--on-ink); }
.on-ink .lead, .hero .lead, .sec-dark .lead,
.on-ink .muted, .hero .muted, .sec-dark .muted { color: var(--on-ink-dim); }

*, *::before, *::after { box-sizing: border-box; }

/* Keyboard focus, once, for everything. There was exactly one focus rule in the
   whole stylesheet and it removed an outline. */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }
.hero :focus-visible, .ftr :focus-visible, .on-ink :focus-visible { outline-color: var(--orange); }

.sr-only {
  position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
/* Eleven tab stops stood between the top of the page and the content. */
.skip {
  position: absolute; left: 16px; top: -72px; z-index: 200;
  background: var(--navy); color: #fff; padding: 12px 18px; border-radius: 0 0 8px 8px;
  font: 600 14px/1 Manrope, sans-serif; text-decoration: none; transition: top .18s ease;
}
.skip:focus { top: 0; }
/* `hidden` must actually hide. Any author rule with a display (.btn is
   inline-flex) beats the browser's own [hidden] rule, so an element marked
   hidden stayed on screen. */
[hidden] { display: none !important; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: Manrope, "Noto Sans Devanagari", system-ui, -apple-system, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;            /* belt and braces: no sideways scroll on phones */
}
img, svg { max-width: 100%; }
a { color: inherit; }

/* Space Grotesk over the old Fraunces: the serif read bookish and its soft,
   quirky letterforms are what felt off. This is modern and technical without
   being a generic geometric sans, which suits an intelligence company. */
h1, h2, h3, .serif {
  font-family: "Space Grotesk", "Manrope", system-ui, sans-serif;
  font-weight: 700;
  letter-spacing: -.028em;
  line-height: 1.12;
  margin: 0;
}
h1 { font-size: clamp(34px, 6.2vw, 62px); }
h2 { font-size: clamp(27px, 4.2vw, 42px); }
h3 { font-size: clamp(17px, 2vw, 20px); font-weight: 600; letter-spacing: -.005em; line-height: 1.3; }
p  { margin: 0; }
.hi { font-family: "Noto Sans Devanagari", Manrope, sans-serif; }

/* ── layout ─────────────────────────────────────────────────────────────── */
.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter); }
section { padding: clamp(56px, 8vw, 104px) 0; }
/* The alternating band. Light rhythm: about · [services] · research ·
   [intelligence] · datagrid · [why] · contact, with the hero and the footer as
   the only dark surfaces. */
.sec-2 { background: var(--paper-2); }
/* Anchors have to clear the sticky header, or every nav click lands with the
   heading hidden behind it - which is most of what "exploring the site" is. */
section[id] { scroll-margin-top: calc(var(--hdr-h) + 14px); }
/* NB: a dark surface paints from --navy, never from --ink. Inside the contract
   --ink is redefined to the TEXT colour (white), so `background: var(--ink)`
   turned the hero white-on-white the moment the contract landed. */

.eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 7px 15px 7px 12px; border-radius: 30px;
  background: rgba(249,115,22,.09); border: 1px solid rgba(249,115,22,.28);
  font-size: 13px; font-weight: 700; letter-spacing: .005em;
  text-transform: none; color: var(--accent);
}
/* a dot that keeps a pulse, so even the label is alive */
.eyebrow::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--orange); box-shadow: 0 0 0 0 rgba(249,115,22,.55);
  animation: ping 2.4s cubic-bezier(.4,0,.2,1) infinite;
}
@keyframes ping {
  0%   { box-shadow: 0 0 0 0 rgba(249,115,22,.5); }
  70%  { box-shadow: 0 0 0 9px rgba(249,115,22,0); }
  100% { box-shadow: 0 0 0 0 rgba(249,115,22,0); }
}
.hero .eyebrow, .on-ink .eyebrow, .ftr .eyebrow {
  color: var(--orange-lite); background: rgba(249,115,22,.14); border-color: rgba(249,115,22,.34);
}

.lead { font-size: clamp(16px, 1.6vw, 18px); color: var(--muted); line-height: 1.55; max-width: 62ch; }
.muted { color: var(--muted); }
.sec-head { max-width: 46rem; }
.sec-head h2 { margin-top: 14px; }
html.js .rv .sec-head h2, html.js .sec-head.rv h2 { clip-path: inset(0 0 105% 0); transition: clip-path .7s cubic-bezier(.2,.7,.3,1) .1s; }
html.js .rv.in .sec-head h2, html.js .sec-head.rv.in h2 { clip-path: inset(0 0 -10% 0); }
.sec-head .lead { margin-top: 16px; }

/* ── buttons ────────────────────────────────────────────────────────────────
   One rule. A button knows nothing about which section it is in - it reads the
   contract its surface published. That is why the old
   `.sec-dark .btn, .hero .btn, .cta-band .btn { ... }` chain is gone: it keyed
   off class names, so any dark surface that was not one of those three got an
   ink button on an ink ground and it vanished. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  min-height: 46px; padding: 12px 22px;
  border: 1.5px solid var(--btn-bd); border-radius: 8px;
  background: var(--btn-bg); color: var(--btn-fg);
  font: 600 14.5px/1 Manrope, sans-serif; letter-spacing: .01em;
  text-decoration: none; cursor: pointer;
  box-shadow: var(--e1);
  transition: background .18s ease, border-color .18s ease, transform .16s ease, box-shadow .18s ease;
}
.btn:hover  { background: var(--btn-bg-h); border-color: var(--btn-bg-h); transform: translateY(-1px); box-shadow: var(--e2); }
/* Touch has no hover, so the pressed state is what most visitors will ever
   feel. Every affordance on this site has one. */
.btn:active { transform: translateY(0) scale(.985); box-shadow: var(--e1); }
.btn:focus-visible { outline: none; box-shadow: var(--ring); }
.btn-ghost { background: transparent; color: var(--btn2-fg); border-color: var(--btn2-bd); box-shadow: none; }
.btn-ghost:hover { background: var(--btn2-bg-h); color: var(--btn2-fg); border-color: var(--btn2-bd); box-shadow: none; transform: translateY(-1px); }
.btn-ghost:active { transform: translateY(0) scale(.985); }
/* The orange primary, safe on ANY surface because it carries its own tokens. */
.btn-cta { --btn-bg: var(--orange); --btn-fg: var(--navy); --btn-bd: var(--orange); --btn-bg-h: var(--orange-hover); }
.btn-sm { min-height: 40px; padding: 9px 16px; font-size: 13.5px; }

/* ── header ─────────────────────────────────────────────────────────────── */
.hdr {
  position: sticky; top: 0; z-index: 60;
  background: rgba(244,247,252,.92);
  border-bottom: 1px solid transparent;
  transition: border-color .2s ease, box-shadow .2s ease;
}
@supports (backdrop-filter: blur(8px)) { .hdr { backdrop-filter: blur(8px); } }
/* Once you have scrolled, the bar is a plane floating over the page rather
   than something welded to it. */
.hdr.stuck { border-bottom-color: var(--line); box-shadow: var(--e2); background: rgba(244,247,252,.96); }
/* How far through the page you are - the cheapest thing that makes something
   long feel explorable. */
.hdr-prog { position: absolute; left: 0; bottom: -1px; height: 2px; width: 100%; transform: scaleX(0); transform-origin: 0 50%; background: var(--orange); pointer-events: none; }
/* The header stays on the SAME grid as the page - a bar that runs wider than
   the content column lines its logo and its CTA up with nothing. The room comes
   from widening that one column to 1280 and compacting the bar, not from
   letting the bar escape. (It used to want 1264px against a 1148px wrap, so it
   was clipped at every desktop width including 1920; body{overflow-x:hidden}
   swallowed the symptom.) */
/* The version and size are menu detail, not bar furniture - worth 67px. */
.hdr-cta .ga-sub { display: none; }
.hdr-in { display: flex; align-items: center; gap: 14px; height: var(--hdr-h); min-width: 0; }
.hdr-logo { display: flex; align-items: center; flex: none; text-decoration: none; }
.hdr-logo img { height: 30px; width: auto; display: block; }
.nav { display: flex; align-items: center; gap: 2px; margin-left: auto; min-width: 0; }
.nav a {
  position: relative; padding: 9px 10px; border-radius: 7px; text-decoration: none;
  font-size: 14px; font-weight: 500; color: var(--ink-2); white-space: nowrap;
  transition: color .15s ease;
}
/* A rule that grows from the middle, so the current section is legible at a
   glance and a hover is not just a colour change. */
.nav a::after {
  content: ""; position: absolute; left: 10px; right: 10px; bottom: 4px; height: 2px;
  background: var(--orange); border-radius: 2px;
  transform: scaleX(0); transform-origin: center; transition: transform .22s ease;
}
.nav a:hover, .nav a:focus-visible { color: var(--ink); background: rgba(13,27,62,.05); }
.nav a.on { color: var(--ink); font-weight: 700; }
.nav a:hover::after, .nav a.on::after, .nav a:focus-visible::after { transform: scaleX(1); }
.nav a:focus-visible { outline: none; box-shadow: var(--ring); }
.hdr-cta { display: flex; align-items: center; gap: 8px; flex: none; }
/* Social, in the bar, so somebody can reach us without scrolling. Small on
   purpose - these are signposts, not calls to action. */
.hdr-social { display: inline-flex; align-items: center; gap: 1px; }
.hdr-social a {
  width: 32px; height: 32px; border-radius: 8px; display: grid; place-items: center;
  color: var(--muted); transition: color .16s ease, background .16s ease, transform .16s ease;
}
.hdr-social a:hover { color: var(--orange-ink); background: rgba(249,115,22,.1); transform: translateY(-1px); }
.hdr-social a:active { transform: translateY(0); }
.hdr-social a:focus-visible { outline: none; box-shadow: var(--ring); }
.mnav-social { padding: 4px 0 18px; display: flex; justify-content: center; }
.mnav-soc a { width: 42px; height: 42px; }
.hdr-sep { width: 1px; height: 24px; background: var(--line); flex: none; }

/* Get App — only rendered once the server says an APK exists */
.getapp {
  display: none; align-items: center; gap: 8px;
  min-height: 40px; padding: 8px 14px;
  border: 1.5px solid var(--line); border-radius: 8px; background: var(--card);
  font: 600 13.5px/1 Manrope, sans-serif; color: var(--ink); text-decoration: none;
  transition: border-color .18s ease, background .18s ease;
}
.getapp.show { display: inline-flex; }
.getapp:hover { border-color: var(--orange); background: #fff; box-shadow: var(--e1); }
.getapp .ga-sub { font-size: 10.5px; font-weight: 600; color: var(--muted); letter-spacing: .04em; white-space: nowrap; }
.getapp:active { transform: scale(.985); }
.getapp:focus-visible { outline: none; box-shadow: var(--ring); }
.getapp-txt { display: flex; flex-direction: column; gap: 1px; align-items: flex-start; line-height: 1.1; }

/* mobile menu */
.burger {
  display: none; width: 44px; height: 44px; flex: none; margin-left: auto;
  border: 1.5px solid var(--line); border-radius: 8px; background: var(--card);
  cursor: pointer; padding: 0; place-items: center;
}
.burger span, .burger span::before, .burger span::after {
  content: ""; display: block; width: 17px; height: 1.8px; background: var(--navy); border-radius: 2px;
  transition: transform .2s ease, opacity .2s ease;
}
.burger span::before { transform: translateY(-5.5px); }
.burger span::after  { transform: translateY(3.7px); }
.burger[aria-expanded="true"] span { background: transparent; }
.burger[aria-expanded="true"] span::before { transform: rotate(45deg); }
.burger[aria-expanded="true"] span::after  { transform: rotate(-45deg) translateY(-1.8px); }
.mnav { display: none; border-top: 1px solid var(--line); background: var(--paper); }
/* The menu lives inside a sticky header, so anything past the fold simply could
   not be reached - on an iPhone SE the two buttons that matter, Partner Login
   and Book a Consultation, were 51px below the screen with no way to scroll to
   them. Now the menu scrolls itself. */
.mnav.open {
  display: block;
  max-height: calc(100vh - var(--hdr-h));
  max-height: calc(100dvh - var(--hdr-h));
  overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
}
.mnav > .wrap { padding-bottom: calc(16px + env(safe-area-inset-bottom)); }
.mnav a { display: block; padding: 13px 0; border-bottom: 1px solid var(--line); text-decoration: none; font-weight: 500; }
.mnav .mnav-cta { display: grid; gap: 9px; padding: 16px 0 20px; }
.mnav .mnav-cta .btn, .mnav .mnav-cta .getapp { width: 100%; }

/* Three steps down, so the bar never has to be clipped:
   >=1300  everything, with the APK size beside "Get App"
   1160-1299  the Get App subtitle goes, the nav tightens
   <1160   the burger takes over, because even the compact bar will not fit */
/* Two steps down, each measured against what the bar actually needs:
   >=1280  everything (needs 1207px of 1248px available)
   1101-1279  Home goes (the logo IS home), Get App becomes an icon
   <=1100  the burger, because below that nothing compact enough is left */
@media (max-width: 1279px) {
  .hdr-in { gap: 12px; }
  .nav { gap: 0; }
  .nav a { padding: 9px 8px; font-size: 13.5px; }
  .nav a::after { left: 8px; right: 8px; }
  .nav a[href="#top"] { display: none; }
  .hdr-sep { display: none; }
  /* The words stay. An unlabelled glyph is the reason nobody found the app. */
  .getapp { padding: 8px 11px; font-size: 13px; }
  .hdr-cta .hdr-social { display: none; }
}
@media (max-width: 1100px) {
  .nav, .hdr-cta, .hdr-sep { display: none; }
  .burger { display: grid; }
}

/* ── touch ──────────────────────────────────────────────────────────────────
   A tablet in landscape gets the full desktop header, so its nav links and
   social icons were 40px and 32px tall - fine under a mouse, under the 44px
   floor for a thumb. Only the height grows, so the bar still fits. */
a.nav-tall, .nav a { min-height: 44px; display: inline-flex; align-items: center; }
.hdr-social a { width: 42px; height: 42px; }
.mnav-soc a { width: 46px; height: 46px; }
.modal-x, .pw-eye { width: 44px; height: 44px; }
/* the labels under "Built for" are not buttons, so they do not lift like one */
.tag { cursor: default; }
.tag:hover { transform: none; box-shadow: var(--e1); }

/* ── hero ───────────────────────────────────────────────────────────────── */
.hero { background: var(--navy); color: var(--on-ink-body); padding: clamp(52px, 8vw, 92px) 0 0; position: relative; overflow: hidden; }
/* a quiet ledger rule, not a glow */
.hero::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 1px; background: var(--on-ink-line);
}
.hero-grid { display: grid; grid-template-columns: 1.15fr .85fr; gap: clamp(28px, 5vw, 64px); align-items: center; }
.hero h1 { margin-top: 18px; color: var(--on-ink); }
.hero h1 em { font-style: normal; color: var(--gold); }
.hero .lead { margin-top: 20px; color: var(--on-ink-dim); }
.hero-btns { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }
.hero-hi { margin-top: 26px; font-size: 15px; color: var(--gold); letter-spacing: .02em; }
.hero-art { display: grid; place-items: center; padding: 0 14px; }

/* ── the hero as a real 3D scene ──────────────────────────────────────────────
   Not a picture of depth - actual perspective. The stage carries a slow idle
   rotation of its own so the scene is never frozen, and a pointer tilt on top
   of it. Every layer sits at its own Z and drifts on its own clock, so they
   separate as the scene turns. All of it is compositor-only transform work:
   the keyframes never touch JS, and the pointer writes two custom properties.
   ────────────────────────────────────────────────────────────────────────── */
.scene { perspective: 1250px; perspective-origin: 50% 45%; width: 100%; max-width: 344px; }
/* the plates stand behind the console, so they have to be its height */
.plate { height: 330px; }
.scene-rot {
  transform-style: preserve-3d;
  animation: sceneIdle 19s ease-in-out infinite;
}
.scene-tilt {
  transform-style: preserve-3d;
  transform: rotateY(calc(var(--mx, 0) * 9deg)) rotateX(calc(var(--my, 0) * -7deg));
  transition: transform .5s cubic-bezier(.2,.7,.3,1);
}
@keyframes sceneIdle {
  0%, 100% { transform: rotateY(-3.2deg) rotateX(1.6deg); }
  50%      { transform: rotateY( 3.2deg) rotateX(-1.2deg); }
}
.layer { position: absolute; transform-style: preserve-3d; will-change: transform; }
.layer > * { transform: translateZ(var(--z, 0px)); transform-style: preserve-3d; }
/* each on its own clock, so nothing ever lines up and stops */
.l-card  { position: relative; animation: bobA 7.5s ease-in-out infinite; }
.l-back  { inset: 18px -26px auto 34px; animation: bobB 11s ease-in-out infinite; }
.l-mid   { inset: -14px 26px auto -30px; animation: bobC 9s  ease-in-out infinite; }
.l-chip1 { right: -56px; top: -24px;    animation: bobB 6.5s ease-in-out infinite; }
.l-chip2 { left: -70px;  bottom: -26px;  animation: bobC 8.5s ease-in-out infinite; }
@keyframes bobA { 0%,100% { transform: translate3d(0,-7px,0) } 50% { transform: translate3d(0,7px,0) } }
@keyframes bobB { 0%,100% { transform: translate3d(0,9px,0) }  50% { transform: translate3d(0,-9px,0) } }
@keyframes bobC { 0%,100% { transform: translate3d(0,-11px,0) } 50% { transform: translate3d(0,6px,0) } }

/* the two plates behind the card: thickness, not decoration */
.plate {
  border-radius: 16px; height: 330px;
  background: rgba(255,255,255,.045); border: 1px solid rgba(255,255,255,.1);
}
.l-back  .plate { --z: -150px; }
.l-mid   .plate { --z: -78px; }

/* ── ROSHi AI, running in the hero ────────────────────────────────────────────
   Futuristic without neon: the depth comes from real perspective and a lit
   edge, the "alive" comes from the thing actually working. Navy and orange
   only. ───────────────────────────────────────────────────────────────────── */
.ai-console {
  --z: 0px;
  position: relative; overflow: hidden;
  width: 100%; max-width: 344px;
  background: linear-gradient(180deg, #16294f 0%, #101f42 100%);
  border: 1px solid rgba(255,255,255,.16); border-radius: 16px;
  box-shadow: 0 34px 80px -22px rgba(0,0,0,.72), 0 1px 0 0 rgba(255,255,255,.1) inset;
}
/* a thin sweep that crosses the panel, the way a readout refreshes */
.ai-scan {
  position: absolute; left: 0; right: 0; top: -40%; height: 40%;
  background: linear-gradient(180deg, transparent, rgba(249,115,22,.09), transparent);
  animation: aiScan 6.5s linear infinite; pointer-events: none; z-index: 2;
}
@keyframes aiScan { 0% { top: -40%; } 100% { top: 120%; } }

.ai-head { display: flex; align-items: center; gap: 11px; padding: 14px 16px 12px; border-bottom: 1px solid rgba(255,255,255,.1); }
.ai-mark { position: relative; width: 36px; height: 36px; flex: none; display: grid; place-items: center; }
/* a ring that keeps turning around the mark */
.ai-mark i {
  position: absolute; inset: 0; border-radius: 50%;
  border: 1.5px solid rgba(249,115,22,.28); border-top-color: var(--orange);
  animation: aiSpin 3.4s linear infinite;
}
@keyframes aiSpin { to { transform: rotate(360deg); } }
.ai-mark b { font-family: "Space Grotesk", sans-serif; font-size: 16px; font-weight: 650; color: var(--orange-lite); }
.ai-id { display: flex; flex-direction: column; gap: 2px; line-height: 1.1; flex: 1; min-width: 0; }
.ai-id b { font-size: 14px; color: #fff; font-weight: 700; letter-spacing: .01em; }
.ai-id small { font-size: 10.5px; color: var(--on-ink-faint); display: flex; align-items: center; gap: 6px; }
.ai-live { width: 6px; height: 6px; border-radius: 50%; background: var(--c3); flex: none; animation: blink 1.6s infinite; }

.ai-log { height: 224px; padding: 13px 15px; display: flex; flex-direction: column; gap: 9px; justify-content: flex-end; overflow: hidden; }
.ai-msg { max-width: 92%; font-size: 12.5px; line-height: 1.45; padding: 9px 12px; border-radius: 13px; animation: aiPop .34s cubic-bezier(.2,.7,.3,1); }
.ai-msg.q { align-self: flex-end; background: var(--orange); color: #14101a; font-weight: 600; border-bottom-right-radius: 4px; }
.ai-msg.a { align-self: flex-start; background: rgba(255,255,255,.07); border: 1px solid rgba(255,255,255,.12); color: #e7ecf8; border-bottom-left-radius: 4px; }
.ai-msg.a b { color: var(--orange-lite); }
@keyframes aiPop { from { opacity: 0; transform: translateY(8px) scale(.97) } to { opacity: 1; transform: none } }

.ai-think { display: flex; gap: 4px; padding: 11px 13px; align-self: flex-start; }
.ai-think i { width: 6px; height: 6px; border-radius: 50%; background: var(--orange-lite); animation: blink 1s infinite; }
.ai-think i:nth-child(2) { animation-delay: .16s } .ai-think i:nth-child(3) { animation-delay: .32s }

/* the little readout that comes back with an answer */
.ai-bars { display: flex; gap: 5px; align-items: flex-end; height: 36px; margin: 9px 0 4px; }
.ai-bars span { flex: 1; background: var(--c6); border-radius: 2px 2px 0 0; transform-origin: 50% 100%; animation: aiGrow .6s cubic-bezier(.2,.7,.3,1) both; }
@keyframes aiGrow { from { transform: scaleY(0) } to { transform: scaleY(1) } }

.ai-bar { display: flex; align-items: center; gap: 2px; margin: 0 15px 14px; padding: 9px 13px; border: 1px solid rgba(255,255,255,.14); border-radius: 22px; background: rgba(0,0,0,.2); font-size: 12px; color: #aab6d2; min-height: 38px; }
.ai-typed { white-space: nowrap; overflow: hidden; }
.ai-caret { width: 2px; height: 14px; background: var(--orange); flex: none; animation: aiCaret 1.05s steps(1) infinite; }
@keyframes aiCaret { 0%, 50% { opacity: 1 } 50.01%, 100% { opacity: 0 } }

/* the card itself, lifted off the page */
.hero-card-3d {
  --z: 0px;
  background: #142549; border: 1px solid rgba(255,255,255,.14); border-radius: 14px;
  padding: 22px 22px 20px; box-shadow: 0 30px 70px -20px rgba(0,0,0,.65), 0 2px 0 0 rgba(255,255,255,.06) inset;
}

/* data chips that float in front of the card */
.fchip {
  --z: 90px;
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
  background: #1b3059; border: 1px solid rgba(255,255,255,.16); border-radius: 30px;
  padding: 9px 15px; font-size: 12.5px; font-weight: 700; color: #fff;
  box-shadow: 0 16px 34px -12px rgba(0,0,0,.6);
}
.fchip i { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.l-chip2 .fchip { --z: 64px; }

/* the ground plane: a perspective grid that keeps drifting, so the hero has a
   floor and the floor is moving */
.hero-floor {
  position: absolute; inset: auto 0 -12% 0; height: 62%;
  pointer-events: none; overflow: hidden;
  -webkit-mask-image: linear-gradient(to top, #000 0%, transparent 78%);
          mask-image: linear-gradient(to top, #000 0%, transparent 78%);
}
.hero-floor::before {
  content: ""; position: absolute; left: -60%; right: -60%; top: 0; bottom: -40%;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,.075) 0 1px, transparent 1px 84px),
    repeating-linear-gradient(0deg,  rgba(255,255,255,.075) 0 1px, transparent 1px 84px);
  transform: perspective(520px) rotateX(70deg);
  transform-origin: 50% 0;
  animation: floorRun 9s linear infinite;
}
@keyframes floorRun { from { background-position: 0 0, 0 0; } to { background-position: 0 0, 0 84px; } }

@media (max-width: 1300px) { .l-chip1 { right: -22px; } .l-chip2 { left: -26px; } }
@media (max-width: 980px) {
  .scene { max-width: 330px; perspective: 900px; }
  .l-back, .l-mid { display: none; }
  .l-chip1 { right: -10px; top: -22px; } .l-chip2 { left: -12px; bottom: -22px; }
  .fchip { font-size: 11.5px; padding: 8px 13px; }
}
@media (max-width: 420px) { .l-chip1, .l-chip2 { display: none; } }
/* Three planes at different depths. Driven from one rAF-throttled scroll
   handler in site.js writing a single custom property, so the browser only
   ever composites - no layout, no paint. */
.hero-plane { will-change: transform; }
.hero-copy { transform: translate3d(0, calc(var(--sy, 0) * -42px), 0); }
.hero-art   { transform: translate3d(0, calc(var(--sy, 0) * -84px), 0); }
.hero .strip { transform: translate3d(0, calc(var(--sy, 0) * -16px), 0); }

.strip { border-top: 1px solid var(--on-ink-line); margin-top: clamp(40px, 6vw, 68px); }
.strip-in { display: grid; grid-template-columns: repeat(4, 1fr); }
.strip-item { padding: 24px 22px 26px; border-left: 1px solid var(--on-ink-line); }
.strip-item:first-child { border-left: 0; padding-left: 0; }
.strip-item .k { display: flex; align-items: center; gap: 9px; font-size: 12px; font-weight: 800; letter-spacing: .16em; text-transform: uppercase; color: var(--gold); }
.strip-item .v { margin-top: 9px; font-size: 15.5px; color: var(--on-ink-body); }
@media (max-width: 980px) {
  .hero-grid { grid-template-columns: 1fr; }
  /* The headline comes first on a phone. The sample card used to be pulled above
     it, so the first thing a visitor met was a box of made-up numbers. */
  .hero-art { margin-top: 34px; justify-items: center; justify-content: center; padding: 0 28px; }
  .strip-in { grid-template-columns: repeat(2, 1fr); }
  .strip-item { border-left: 0; padding: 20px 0; border-top: 1px solid var(--on-ink-line); }
  .strip-item:nth-child(-n+2) { border-top: 0; }
  .strip-item:nth-child(even) { padding-left: 22px; border-left: 1px solid var(--on-ink-line); }
}

/* ── cards & grids ──────────────────────────────────────────────────────── */
/* A grid or flex item defaults to min-width:auto, so one stubborn child - a
   long label, a fixed-width mock - stops its whole column from shrinking and
   pushes the page sideways. Every track on this page is allowed to be narrower
   than its contents; anything that genuinely must not shrink says so itself. */
.grid > *, .contact-grid > *, .dash-lead > *, .chat-wrap > *, .hero-grid > * { min-width: 0; }
.grid { display: grid; gap: 18px; }
.g2 { grid-template-columns: repeat(2, 1fr); }
.g3 { grid-template-columns: repeat(3, 1fr); }
.g4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) { .g3, .g4 { grid-template-columns: repeat(2, 1fr); } }
/* Between 621 and 900 the three-up grids fall to two columns, and any odd card
   count then strands the last one beside an empty half - the single thing that
   most makes a tablet look thrown together. About has 3 cards and Services has
   9, so both did. The last card of an odd set takes the whole row instead. */
@media (min-width: 621px) and (max-width: 900px) {
  .g3 > :last-child:nth-child(odd), .g4 > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (max-width: 620px) { .g2, .g3, .g4 { grid-template-columns: 1fr; } }

.card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 24px 22px; box-shadow: var(--e2);
  transition: transform .22s cubic-bezier(.2,.7,.3,1), box-shadow .22s ease, border-color .22s ease;
}
/* Cards lift toward the reader. A light theme has no dark ground to fall back
   on, so without a real ramp everything sits at the same height and the page
   reads as flat print - which is exactly what "mara hua" meant. */
/* A card is an object on a surface, so it leans toward you. --rx/--ry come from
   one shared rAF in site.js; both default to 0, so a card with no pointer on it
   sits perfectly flat. */
.card-3d {
  transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateZ(0);
  transform-style: preserve-3d;
}
.card:hover { transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateY(-4px) translateZ(14px); box-shadow: var(--e4); border-color: var(--line-2); }
.card:active { transform: perspective(900px) translateY(-1px); box-shadow: var(--e2); }
/* On the darker band a shadow calibrated for paper loses most of its contrast,
   so those cards get the next step up. */
.sec-2 .card { box-shadow: var(--e3); }
.sec-2 .card:hover { box-shadow: var(--e4); }
.card .ic { color: var(--accent); margin-bottom: 14px; display: block; }
.card h3 { margin-bottom: 8px; }
.card p { font-size: 14.5px; color: var(--muted); line-height: 1.55; }
.sec-dark .card { background: rgba(255,255,255,.06); border-color: var(--on-ink-line); box-shadow: none; }
.sec-dark .card p { color: var(--on-ink-dim); }
.sec-dark .card .ic { color: var(--gold); }

.svc-card { position: relative; padding-top: 26px; }
.svc-card::before {
  content: ""; position: absolute; top: -1px; left: -1px; right: -1px; height: 3px;
  background: var(--orange); border-radius: var(--radius) var(--radius) 0 0;
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .6s cubic-bezier(.2,.7,.3,1); transition-delay: calc(var(--i, 0) * 65ms + 120ms);
}
.in .svc-card::before { transform: scaleX(1); }
.svc-card:nth-child(3n+2)::before { background: var(--c1); }
.svc-card:nth-child(3n)::before   { background: var(--c3); }

/* pillars (About) */
.pillar { display: flex; gap: 16px; align-items: flex-start; }
.pillar .ic { flex: none; width: 42px; height: 42px; display: grid; place-items: center; border: 1.5px solid var(--line); border-radius: 10px; color: var(--accent); background: var(--card); }
.pillar h3 { font-size: 17px; }
.pillar p { font-size: 14.5px; color: var(--muted); margin-top: 5px; line-height: 1.5; }

/* checklist (Research, Why) */
.checks { display: grid; gap: 14px; margin-top: 26px; }
.check { display: flex; gap: 13px; align-items: flex-start; }
.check .ic { flex: none; color: var(--accent); margin-top: 2px; }
.check b { display: block; font-size: 15.5px; font-weight: 700; }
.check span { font-size: 14.5px; color: var(--muted); line-height: 1.5; }
.sec-dark .check .ic { color: var(--gold); }
.sec-dark .check span { color: var(--on-ink-dim); }

.callout-band {
  display: flex; gap: 14px; align-items: flex-start;
  margin-top: 28px; padding: 18px 20px;
  border: 1px solid var(--line); border-left: 3px solid var(--gold);
  border-radius: 0 var(--radius) var(--radius) 0; background: var(--card);
}
.callout-band .ic { color: var(--gold); flex: none; }
.callout-band p { font-size: 15px; }

.outcome { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--line); font-family: "Space Grotesk", sans-serif; font-size: clamp(18px, 2.2vw, 22px); font-weight: 600; line-height: 1.35; }

/* sample-data label */
.sample-tag {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted); border: 1px solid var(--line); border-radius: 5px; padding: 3px 8px;
}
.sec-dark .hero .sample-tag, .on-ink .sample-tag { color: var(--on-ink-faint); border-color: var(--on-ink-line-2); }

/* ── research sample charts ─────────────────────────────────────────────── */
.chartset { display: grid; gap: 16px; }
.chart-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px 18px 16px; box-shadow: var(--e3); }
.chart-card .ct { font-size: 12.5px; font-weight: 700; letter-spacing: .04em; }
.chart-card .cs { font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.bar-row { display: flex; align-items: center; gap: 10px; font-size: 12.5px; margin-top: 9px; }
.bar-row .bl { width: clamp(52px, 22%, 74px); flex: none; color: var(--ink-2); font-weight: 600; }
.bar-row .bt { flex: 1; height: 8px; background: var(--track); border-radius: 4px; overflow: hidden; }
.bar-row .bt i { display: block; height: 100%; border-radius: 4px; transform-origin: 0 50%; transform: scaleX(0); transition: transform .9s cubic-bezier(.2,.7,.3,1); transition-delay: calc(var(--i, 0) * 90ms); }
.in .bar-row .bt i, .chartset.in .bar-row .bt i { transform: scaleX(1); }
.bar-row .bv { width: clamp(40px, 15%, 54px); flex: none; text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; }
.heat { display: grid; grid-template-columns: minmax(44px, 80px) repeat(4, minmax(0, 1fr)); gap: 4px; margin-top: 10px; font-size: 11px; }
.heat .hh { color: var(--muted); font-weight: 700; letter-spacing: .04em; text-align: center; padding-bottom: 2px; }
.heat .hl { color: var(--ink-2); font-weight: 600; display: flex; align-items: center; }
.heat .hc { height: 26px; border-radius: 4px; display: grid; place-items: center; font-weight: 700; color: #fff; opacity: 0; transform: scale(.88); transition: opacity .4s ease, transform .4s cubic-bezier(.2,.7,.3,1); transition-delay: calc(var(--i, 0) * 28ms); }
.in .heat .hc { opacity: 1; transform: none; }
/* One tier per step of the navy ramp, each carrying the text colour it can
   actually support. The old scheme put white on every tier and one of them
   measured 2.3:1. */
.heat .hc.t5 { background: var(--n5); color: #fff; }          /* 16.89:1 */
.heat .hc.t4 { background: var(--n4); color: #fff; }          /*  8.39:1 */
.heat .hc.t3 { background: var(--n3); color: #fff; }          /*  4.91:1 */
.heat .hc.t2 { background: var(--n2); color: var(--navy); }   /*  9.27:1 */
.heat .hc.t1 { background: var(--n1); color: var(--navy); }   /* 12.61:1 */
.heat .hc.t0 { background: var(--n0); color: var(--muted); }  /*  5.28:1 */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(58px, 1fr)); gap: 8px; margin-top: 10px; }
/* On the narrowest phones the fixed 80px label column plus four cells is wider
   than the card, and a grid cell will not shrink below its text. Give it less
   to hold on to. */
@media (max-width: 380px) {
  .heat { gap: 3px; font-size: 10px; }
  .heat .hc { height: 24px; }
  .chart-card { padding: 15px 14px 14px; }
}
.heat > * { min-width: 0; }
.tile { border: 1px solid var(--line); border-radius: 8px; padding: 10px 8px; text-align: center; }
.tile .tv { font-family: "Space Grotesk", sans-serif; font-size: 22px; font-weight: 650; line-height: 1; font-variant-numeric: tabular-nums; }
.tile { transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease; }
.tile:hover { transform: translateY(-2px); box-shadow: var(--e2); border-color: var(--line-2); }
.tile .tl { font-size: 10.5px; color: var(--muted); margin-top: 5px; letter-spacing: .04em; overflow-wrap: anywhere; }

/* ── intelligence demos ─────────────────────────────────────────────────── */
.demo-block { margin-top: clamp(32px, 5vw, 54px); }
.demo-head { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; margin-bottom: 18px; }
.demo-head h3 { font-family: "Space Grotesk", sans-serif; font-size: clamp(20px, 2.4vw, 26px); font-weight: 650; }

/* phone rail — scrolls sideways on small screens instead of squashing */
/* The phones are the one place a real 3D treatment is honest - they ARE
   objects. Perspective on the rail, a slight rotation on each, and they stand
   up as the section arrives instead of lying flat like three PNGs. */
/* Three phones either fit on one line or they scroll - they never wrap. Between
   1001 and 1180 the rail was 1px short of its 782px and dropped the third phone
   onto a second row, leaving a 590px hole beside a lonely handset. */
.phone-rail {
  display: flex; gap: 26px; flex-wrap: nowrap; min-width: 0;
  overflow-x: auto; overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch;
  /* vertical padding is not decoration: overflow-x:auto forces overflow-y to
     auto, so without it the hovered phone is clipped at the top and bottom */
  scroll-snap-type: x proximity; padding: 14px 0 18px; scrollbar-width: thin;
  perspective: 1700px; perspective-origin: 50% 40%;
}
.phone-rail > * { flex: none; scroll-snap-align: center; }
.phone-rail > * {
  transform: rotateY(var(--ry, 0deg)) rotateX(2deg) translateZ(var(--tz, 0px));
  transition: transform .7s cubic-bezier(.2,.7,.3,1), opacity .6s ease;
}
.phone-rail > :nth-child(1) { --ry: 8deg;  --tz: -14px; }
.phone-rail > :nth-child(2) { --ry: 0deg;  --tz: 14px; }
.phone-rail > :nth-child(3) { --ry: -8deg; --tz: -14px; }
.phone-rail > *:hover { --ry: 0deg; --tz: 30px; }
@media (max-width: 900px) { .phone-rail { perspective: none; } .phone-rail > * { --ry: 0deg; --tz: 0px; } }

/* The chat phone leans toward the pointer. Capped at 6 degrees so it reads as
   weight, not as a gimmick, and it is never required to use the demo. */
.tilt { transform: perspective(1100px) rotateX(var(--tx, 0deg)) rotateY(var(--ty, 0deg)); transition: transform .25s ease-out; will-change: transform; }
@media (max-width: 900px) {
  .phone-rail {
    flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x mandatory;
    padding-bottom: 12px; margin: 0 calc(var(--gutter) * -1); padding-left: var(--gutter); padding-right: var(--gutter);
    -webkit-overflow-scrolling: touch;
  }
  .phone-rail > * { scroll-snap-align: center; }
}
/* The hint appears when the rail can actually be scrolled, not at a width we
   guessed. site.js measures it. */
.rail-hint { display: none; font-size: 12px; color: var(--muted); margin-top: 6px; }
.phone-rail.scrolls + .rail-hint { display: block; }

/* On a tablet three handsets cannot fit, so the rail scrolls - but a phone that
   simply stops at the viewport edge reads as a clipped layout rather than as a
   rail with more in it. The edge the rail can still travel toward is faded, and
   only that edge, so the first phone is never veiled while the rail sits at its
   start. The mask lives on the scroll container, so it stays pinned while the
   phones move underneath it. */
@property --ml { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --mr { syntax: '<length>'; inherits: false; initial-value: 0px; }
.phone-rail.scrolls {
  perspective: none;
  --ml: 0px; --mr: 0px;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--ml), #000 calc(100% - var(--mr)), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 var(--ml), #000 calc(100% - var(--mr)), transparent 100%);
  transition: --ml .28s ease, --mr .28s ease;
}
.phone-rail.scrolls > * { --ry: 0deg; --tz: 0px; }
.phone-rail.more-left  { --ml: 44px; }
.phone-rail.more-right { --mr: 56px; }
@media (prefers-reduced-motion: reduce) { .phone-rail.scrolls { transition: none; } }



.dash-lead { display: grid; grid-template-columns: 300px 1fr; gap: 34px; align-items: start; }
/* Collapse the column BEFORE the rail gets squeezed, not after. */
@media (max-width: 1180px) { .dash-lead { grid-template-columns: minmax(0, 1fr); gap: 22px; } }
/* A grid item defaults to min-width:auto, so the three 246px phones inside the
   rail refused to let their column shrink and pushed the whole page sideways on
   a phone. The rail scrolls; the column must be allowed to be narrower than it. */
.dash-lead > *, .chat-wrap > * { min-width: 0; }
.phone-rail { min-width: 0; max-width: 100%; }
.feat { display: flex; gap: 12px; align-items: flex-start; margin-top: 18px; }
.feat .ic { width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center; flex: none; background: var(--n0); color: var(--c1); border: 1px solid var(--line); }
.feat b { display: block; font-size: 15px; }
.feat span { font-size: 13.5px; color: var(--muted); line-height: 1.4; }

/* dashboard phone (ported from components/dashboard-mockup.html) */
/* ── the handset ─────────────────────────────────────────────────────────────
   Built to the proportions of a current iPhone Pro Max rather than a generic
   rectangle: a 440x956pt screen at 0.5955 scale, a 55pt corner radius and the
   Dynamic Island where it actually sits. The thin bright line inside the frame
   is the polished rail; the screen content ends in a fade instead of a hard cut,
   because a real screen always has more below.
   ────────────────────────────────────────────────────────────────────────── */
/* ONE scale for the whole handset. The screen is laid out at full iPhone Pro Max
   size and then scaled as a single piece, so nothing inside it has to be
   re-tuned when the size changes - and the hover lift now happens inside the
   room the phone already occupies instead of pushing past the rail and being
   clipped top and bottom. (A rail with overflow-x:auto computes overflow-y as
   auto too, so a phone that grows on hover IS cut - Rohan, 1 Oct 2026.) */
.dphone {
  --ps: .85;
  width: calc(267px * var(--ps)); height: calc(574px * var(--ps));
  flex: none; position: relative;
  border-radius: calc(35px * var(--ps)); padding: calc(2.6px * var(--ps));
  background: linear-gradient(150deg, #3b4a66 0%, #1b2740 18%, #121c33 50%, #1b2740 82%, #44536f 100%);
  box-shadow: var(--e4), 0 0 0 1px rgba(0,0,0,.35);
}
/* the two side buttons, so the silhouette is a phone and not a card */
.dphone::before, .dphone::after {
  content: ""; position: absolute; width: calc(2.4px * var(--ps)); border-radius: 2px;
  background: linear-gradient(180deg, #4a5872, #27334c);
}
.dphone::before { left: calc(-2.2px * var(--ps)); top: calc(108px * var(--ps)); height: calc(30px * var(--ps));
  box-shadow: 0 calc(46px * var(--ps)) 0 0 #36425c, 0 calc(92px * var(--ps)) 0 0 #36425c; }
.dphone::after  { right: calc(-2.2px * var(--ps)); top: calc(132px * var(--ps)); height: calc(52px * var(--ps)); }
.dscr {
  position: relative;
  /* full-size layout, scaled down to the frame - origin 0 0 so it lands exactly
     in the padding box */
  width: calc(100% / var(--ps)); height: calc(100% / var(--ps));
  transform: scale(var(--ps)); transform-origin: 0 0;
  border-radius: 32.8px; overflow: hidden;
  background-color: #f7f9fd; background-image: linear-gradient(180deg,#f7f9fd,#eef2fa);
  font-family: Manrope, sans-serif; color: #101c33;
}
/* Dynamic Island */
.dscr::before {
  content: ""; position: absolute; z-index: 4; left: 50%; top: 6.5px;
  width: 74px; height: 22px; margin-left: -37px; border-radius: 11px; background: #05070d;
}
/* content runs under the tab bar rather than stopping dead */

.dstatus { height: 22px; display: flex; justify-content: space-between; align-items: center; padding: 0 16px; font-size: 9.5px; font-weight: 600; color: var(--neutral-ink); }
.dbody { padding: 4px 12px 60px; height: calc(100% - 34px); overflow: hidden; }
.dcard { background: #fff; border-radius: 14px; box-shadow: 0 2px 8px rgba(13,27,62,.08); padding: 10px 11px; margin-bottom: 8px; }
.dh { font-size: 12px; font-weight: 700; margin: 10px 2px 7px; }
.dtab { position: absolute; z-index: 3; left: 0; right: 0; bottom: 0; height: 52px; background: rgba(255,255,255,.94); backdrop-filter: blur(8px); border-top: 1px solid var(--track); display: flex; justify-content: space-around; align-items: center; padding-bottom: 8px; }
/* the home indicator */
.dtab::after { content: ""; position: absolute; left: 50%; bottom: 5px; width: 78px; height: 3.4px; margin-left: -39px; border-radius: 3px; background: #0f1a30; opacity: .55; }
.dtab div { display: flex; flex-direction: column; align-items: center; gap: 2px; font-size: 7.5px; color: #6b7694; font-weight: 600; }
.dtab div.on { color: var(--orange-ink); }
.dbar { height: 5px; border-radius: 3px; background: var(--track); overflow: hidden; margin-top: 4px; }
.dbar span { display: block; height: 100%; border-radius: 3px; }
.drow { display: flex; justify-content: space-between; align-items: center; }
.pill { font-size: 8px; font-weight: 700; padding: 2px 7px; border-radius: 10px; }
.pill.s { background: var(--ok-bg); color: var(--ok-ink); }
.pill.w { background: var(--hot-bg); color: var(--hot-ink); }
.livedot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--ok); margin-right: 4px; animation: blink 1.4s infinite; }
.flash { animation: flash .8s ease; }
@keyframes flash { 0% { color: var(--orange-ink); transform: scale(1.15); } 100% { color: inherit; transform: none; } }
@keyframes blink { 0%, 100% { opacity: .25 } 50% { opacity: 1 } }
.phone-cap { font-size: 11.5px; font-weight: 700; color: var(--muted); letter-spacing: .12em; text-align: center; margin-top: 10px; }

/* ROSHi chat demo (ported from components/roshi-chat-demo.html) */
.chat-wrap { display: grid; grid-template-columns: 300px 1fr; gap: clamp(26px, 5vw, 64px); align-items: center; }
@media (max-width: 980px) {
  .chat-wrap { grid-template-columns: minmax(0, 1fr); justify-items: center; }
  /* Stacked, the phone sat ABOVE the questions - so tapping one put the answer
     off the top of the screen and the demo looked broken. Read the prompt, tap,
     watch it answer just below. */
  .chat-wrap > :first-child { order: 2; }
  .chat-wrap > :last-child  { order: 1; width: 100%; }
  .chat-wrap .phone { height: 520px; }
  .chat-wrap .chat { padding-bottom: 8px; }
}
.phone {
  width: 291px; max-width: 100%; height: 626px; flex: none; position: relative;
  border-radius: 38px; padding: 2.8px;
  background: linear-gradient(150deg, #3b4a66 0%, #1b2740 18%, #121c33 50%, #1b2740 82%, #44536f 100%);
  box-shadow: var(--e4), 0 0 0 1px rgba(0,0,0,.35);
}
.phone::before, .phone::after {
  content: ""; position: absolute; width: 2.6px; border-radius: 2px;
  background: linear-gradient(180deg, #4a5872, #27334c);
}
.phone::before { left: -2.4px; top: 118px; height: 33px; box-shadow: 0 50px 0 0 #36425c, 0 100px 0 0 #36425c; }
.phone::after  { right: -2.4px; top: 144px; height: 57px; }
.screen { position: relative; width: 100%; height: 100%; border-radius: 35.5px; background: #f7f9fd; overflow: hidden; display: flex; flex-direction: column; color: var(--ink); }
/* Dynamic Island */
.notch { height: 36px; display: flex; justify-content: center; align-items: flex-start; padding-top: 7px; flex: none; }
.notch span { width: 80px; height: 24px; background: #05070d; border-radius: 12px; }
.apphead { display: flex; align-items: center; gap: 10px; padding: 10px 16px 12px; border-bottom: 1px solid var(--line); }
.avatar { width: 34px; height: 34px; border-radius: 50%; background: var(--navy); display: grid; place-items: center; color: var(--gold); font-family: "Space Grotesk", sans-serif; font-weight: 650; font-size: 15px; }
.apphead .nm { font-weight: 700; font-size: 14px; }
.apphead .st { font-size: 11px; color: var(--c3); }
.chat { flex: 1; overflow-y: auto; padding: 14px 12px; display: flex; flex-direction: column; gap: 10px; scrollbar-width: none; }
.chat::-webkit-scrollbar { display: none; }
.msg { max-width: 88%; font-size: 12.5px; line-height: 1.45; padding: 9px 12px; border-radius: 14px; animation: pop .3s ease; }
.msg.u { align-self: flex-end; background: var(--navy); color: #fff; border-bottom-right-radius: 4px; }
.msg.a { align-self: flex-start; background: #fff; border: 1px solid var(--line); border-bottom-left-radius: 4px; }
.msg.a b { color: var(--accent); }
.msg .mini { display: flex; height: 6px; border-radius: 3px; overflow: hidden; margin: 6px 0 2px; }
.typing { display: flex; gap: 4px; padding: 12px; }
.typing i { width: 6px; height: 6px; border-radius: 50%; background: #9aaac6; animation: blink 1s infinite; }
.typing i:nth-child(2) { animation-delay: .15s }
.typing i:nth-child(3) { animation-delay: .3s }
@keyframes pop { from { opacity: 0; transform: translateY(6px) } to { opacity: 1; transform: none } }
.inputbar { margin: 10px 12px 16px; border: 1px solid var(--line); background: #fff; border-radius: 22px; padding: 9px 14px; font-size: 12px; color: #6f7280; display: flex; justify-content: space-between; }
/* say what to do */
.try-line {
  display: inline-flex; align-items: center; gap: 9px; margin: 0 0 18px;
  font-size: 14px; font-weight: 600; color: var(--accent);
}
.chips { display: flex; flex-direction: column; gap: 11px; }
.chip {
  position: relative;
  background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.18); color: var(--on-ink-body);
  border-radius: 10px; padding: 13px 46px 13px 17px;
  font: 500 15px/1.35 Manrope, "Noto Sans Devanagari", sans-serif;
  text-align: left; cursor: pointer;
  transition: background .2s, border-color .2s, transform .2s, box-shadow .2s;
  display: flex; gap: 13px; align-items: center; min-height: 48px;
}
/* An arrow that slides on hover - the plainest way to say "this does something".
   A visitor could not tell these were buttons at all. */
.chip::after {
  content: ""; position: absolute; right: 16px; top: 50%; width: 15px; height: 15px; margin-top: -7.5px;
  background: currentColor; opacity: .55;
  transition: transform .2s ease, opacity .2s ease;
  -webkit-mask: no-repeat center/15px url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M5 12h13'/><path d='m12 6 6 6-6 6'/></svg>");
          mask: no-repeat center/15px url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M5 12h13'/><path d='m12 6 6 6-6 6'/></svg>");
}
.chip:hover { background: rgba(249,115,22,.14); border-color: var(--orange); transform: translateX(3px); }
.chip:hover::after { transform: translateX(4px); opacity: 1; }
.chip:active { transform: translateX(1px) scale(.995); }
.chip:focus-visible { outline: none; box-shadow: var(--ring); }
.chip.on { background: rgba(249,115,22,.16); border-color: var(--orange); box-shadow: inset 3px 0 0 var(--orange); }
.chip.on::after { opacity: 1; }
/* the first one keeps nudging until somebody has actually tried the demo */
.chips:not(.used) .chip:first-child { animation: nudgeChip 3s ease-in-out infinite; }
@keyframes nudgeChip {
  0%, 80%, 100% { transform: translateX(0); }
  86% { transform: translateX(6px); }
  93% { transform: translateX(0); }
}
/* the phone acknowledges the tap, so the two halves are obviously connected */
.phone { transition: box-shadow .3s ease; }
.phone.answering { box-shadow: var(--e4), 0 0 0 1px rgba(0,0,0,.35), 0 0 0 5px rgba(249,115,22,.28); }
.chip small { display: block; font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--orange-lite); margin-bottom: 3px; }
.chip svg { flex: none; }

.hl-line {
  margin-top: clamp(30px, 4vw, 46px); padding: 22px 26px;
  background: var(--card); border: 1px solid var(--line);
  border-left: 3px solid var(--orange); border-radius: 0 var(--radius) var(--radius) 0;
  box-shadow: var(--e2);
  font-family: "Space Grotesk", sans-serif; font-size: clamp(17px, 2.1vw, 21px); font-weight: 600; line-height: 1.35; color: var(--navy);
}

/* ── keeping the lower half alive ───────────────────────────────────────────
   Everything below the hero used to be a static document. These are small,
   cheap, compositor-only touches - nothing here competes with the content. */

/* Service cards: the icon lifts and turns a little when you reach for the card */
.svc-card .ic, .card .ic { transition: transform .3s cubic-bezier(.2,.7,.3,1), color .2s ease; }
.card:hover .ic { transform: translateY(-3px) rotate(-6deg) scale(1.08); color: var(--orange); }

/* The four hero strip items lift on hover too */
.strip-item { transition: background .25s ease; }
.strip-item:hover { background: rgba(255,255,255,.04); }

/* Research: the callout bar breathes */
.callout-band { position: relative; overflow: hidden; }
.callout-band::after {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--orange);
  animation: barPulse 3.4s ease-in-out infinite;
}
@keyframes barPulse { 0%, 100% { opacity: .55 } 50% { opacity: 1 } }

/* The "01 02 03 04" verbs count themselves in */
.verb { position: relative; overflow: hidden; }
.verb::after {
  content: ""; position: absolute; left: 0; right: 100%; bottom: -1px; height: 2px;
  background: var(--orange); transition: right .55s cubic-bezier(.2,.7,.3,1);
  transition-delay: calc(var(--i, 0) * 110ms);
}
.in .verb::after, .verb:hover::after { right: 0; }
.verb { transition: background .25s ease; }
.verb:hover { background: var(--card); }

/* How-it-works: the dashed connector draws itself left to right */
.step:not(:last-child)::after { transform-origin: 0 50%; transform: scaleX(0); transition: transform .7s cubic-bezier(.2,.7,.3,1); transition-delay: calc(var(--i, 0) * 160ms + 200ms); }
.in .step:not(:last-child)::after { transform: scaleX(1); }
.step .dot { transition: transform .25s cubic-bezier(.2,.7,.3,1), box-shadow .25s ease; }
.step:hover .dot { transform: scale(1.1); box-shadow: 0 0 0 6px rgba(249,115,22,.16); }

/* The PDF sheet's lines fill in, like a document being read */
.pdfdoc i { transform-origin: 0 50%; transform: scaleX(0); transition: transform .5s cubic-bezier(.2,.7,.3,1); transition-delay: calc(var(--i, 0) * 55ms); }
.in .pdfdoc i { transform: scaleX(1); }
/* and the arrow between the sheet and the grid keeps travelling */
.dgarrow svg { animation: arrowGo 2.4s ease-in-out infinite; }
@keyframes arrowGo { 0%, 100% { transform: translateX(-4px) } 50% { transform: translateX(4px) } }

/* The grid rows arrive one after another */
.gridmock tbody tr { opacity: 0; transform: translateX(-8px); transition: opacity .4s ease, transform .4s ease; transition-delay: calc(var(--i, 0) * 90ms + 300ms); }
.in .gridmock tbody tr { opacity: 1; transform: none; }

/* Before / With DataGrid: each line ticks in */
.compare li { transition: transform .2s ease, background .2s ease; }
.compare li:hover { background: rgba(13,27,62,.03); transform: translateX(3px); }

/* Contact details respond to a pointer */
.cinfo .row { transition: transform .2s ease; }
.cinfo .row:hover { transform: translateX(3px); }
.cinfo .row:hover .ic { color: var(--orange); }

/* Footer links and the whole footer get the same quiet lift */
.ftr h4 { position: relative; }
.ftr h4::after { content: ""; position: absolute; left: 0; bottom: -6px; width: 22px; height: 2px; background: var(--orange); }

/* ── DataGrid ───────────────────────────────────────────────────────────── */
.verbs { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; margin: 34px 0 0; border-top: 1px solid var(--line); }
@media (max-width: 720px) { .verbs { grid-template-columns: repeat(2, 1fr); } }
.verb { padding: 22px 18px 20px; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.verb:last-child { border-right: 0; }
@media (max-width: 720px) { .verb:nth-child(even) { border-right: 0; } }
.verb .n { font-family: "Space Grotesk", sans-serif; font-size: 13px; color: var(--accent); font-weight: 650; letter-spacing: .06em; }
.verb .t { font-family: "Space Grotesk", sans-serif; font-size: clamp(20px, 2.6vw, 27px); font-weight: 650; margin-top: 8px; }

.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-top: 34px; }
@media (max-width: 800px) { .steps { grid-template-columns: repeat(2, 1fr); } }
/* on the narrowest phones two columns leave 137px a step - one reads better */
@media (max-width: 380px) {
  .steps { grid-template-columns: 1fr; gap: 18px; }
  .step:not(:last-child)::after { display: none; }
  .verbs { grid-template-columns: 1fr; }
  .verb { border-right: 0; }
}
.step { position: relative; padding-right: 14px; }
.step .dot { width: 44px; height: 44px; border-radius: 50%; background: var(--navy); color: var(--on-ink); display: grid; place-items: center; font-family: "Space Grotesk", sans-serif; font-size: 16px; font-weight: 650; position: relative; z-index: 2; }
.step:not(:last-child)::after { content: ""; position: absolute; left: 46px; right: 0; top: 21px; height: 2px; background: repeating-linear-gradient(90deg, var(--line) 0 7px, transparent 7px 13px); }
@media (max-width: 800px) { .step:nth-child(even)::after { display: none; } }
.step h4 { font-family: "Space Grotesk", sans-serif; font-size: 16px; font-weight: 650; margin: 14px 0 0; }
.step p { font-size: 13.5px; color: var(--muted); margin-top: 5px; line-height: 1.45; }

.compare { display: grid; grid-template-columns: 1fr 1fr; gap: 0; margin-top: 34px; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--card); }
@media (max-width: 620px) {
  .compare { grid-template-columns: 1fr; }
  /* In one column the source order puts both headings first and both lists
     after, so "Before" sat on top of the DataGrid list. Pair each heading with
     its own list again. */
  .compare .ch.a { order: 1; } .compare ul.a { order: 2; }
  .compare .ch.b { order: 3; } .compare ul.b { order: 4; }
  .compare ul.a { padding-bottom: 10px; }
}
.compare .ch { padding: 14px 20px; font-size: 12px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; border-bottom: 1px solid var(--line); }
.compare .ch.a { color: var(--muted); background: var(--paper-2); }
.compare .ch.b { color: var(--ink); background: var(--n0); border-left: 1px solid var(--line); }
@media (max-width: 620px) { .compare .ch.b { border-left: 0; border-top: 1px solid var(--line); } }
.compare ul { margin: 0; padding: 8px 20px 18px; list-style: none; }
.compare ul.b { border-left: 1px solid var(--line); }
@media (max-width: 620px) { .compare ul.b { border-left: 0; } }
.compare li { display: flex; gap: 10px; align-items: flex-start; padding: 9px 0; font-size: 14.5px; border-bottom: 1px solid var(--line); }
.compare li:last-child { border-bottom: 0; }
.compare li .ic { flex: none; margin-top: 2px; }
.compare ul.a li { color: var(--muted); }
.compare ul.a li .ic { color: var(--c4-ink); }
.compare ul.b li .ic { color: var(--c3); }

/* the PDF → grid illustration */
.dgvis { display: grid; grid-template-columns: 150px 44px 1fr; gap: 14px; align-items: center; margin-top: 30px; }
@media (max-width: 720px) { .dgvis { grid-template-columns: 1fr; justify-items: center; gap: 10px; } }
.pdfdoc {
  width: 150px; height: 190px; background: #fff; border: 1px solid var(--line);
  border-radius: 7px; padding: 14px 13px; position: relative; overflow: hidden;
  /* a stack, not a sheet: the copy promises hundreds of documents */
  box-shadow: var(--e3), 6px 6px 0 -1px #fff, 6px 6px 0 0 var(--line), 12px 12px 0 -1px #fff, 12px 12px 0 0 var(--line);
}
.pdfdoc::before { content: "PDF"; position: absolute; right: 0; top: 0; background: var(--accent); color: #fff; font-size: 9px; font-weight: 800; letter-spacing: .1em; padding: 3px 7px; border-radius: 0 6px 0 6px; }
.pdfdoc i { display: block; height: 5px; background: var(--track); border-radius: 3px; margin-bottom: 7px; }
.dgarrow { display: grid; place-items: center; color: var(--accent); }
@media (max-width: 720px) { .dgarrow { transform: rotate(90deg); } }
.gridmock { background: #fff; border: 1px solid var(--line); border-radius: 8px; box-shadow: var(--e3); overflow: hidden; width: 100%; }
.gridmock table { width: 100%; border-collapse: collapse; font-size: 12.5px; font-variant-numeric: tabular-nums; }
.gridmock th { background: var(--paper-2); text-align: left; font-size: 10.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); padding: 9px 12px; border-bottom: 1px solid var(--line); white-space: nowrap; }
.gridmock td { padding: 9px 12px; border-bottom: 1px solid var(--line); white-space: nowrap; }
.gridmock tr:last-child td { border-bottom: 0; }
.gridmock .scroll { overflow-x: auto; }

.tagrow { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; }
/* Two eleven-line feature lists were pure grey text. Same facts, a quarter of
   the reading. */
.pillbox { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 22px; }
.pillbox span {
  font-size: 12.5px; font-weight: 600; color: var(--ink-2);
  background: var(--card); border: 1px solid var(--line-2); border-radius: 20px; padding: 6px 13px;
  box-shadow: var(--e1); transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.pillbox span:hover { transform: translateY(-2px); box-shadow: var(--e2); border-color: var(--orange); }
.tag { border: 1px solid var(--line-2); border-radius: 20px; padding: 7px 14px; font-size: 13px; color: var(--ink-2); background: var(--card); box-shadow: var(--e1); transition: transform .18s ease, box-shadow .18s ease; }
.tag:hover { transform: translateY(-2px); box-shadow: var(--e2); }

/* ── CTA band ───────────────────────────────────────────────────────────── */
/* A navy object resting ON the paper, not a full-bleed dark stripe. The depth
   Rohan asked for, made of elevation rather than glow. */
.cta-band { background: var(--paper); }
.cta-card {
  border-radius: 18px; text-align: center;
  padding: clamp(34px, 5vw, 58px) clamp(22px, 4vw, 54px);
  box-shadow: var(--e-ink);
  position: relative; overflow: hidden;
}
.cta-card::before {
  content: ""; position: absolute; inset: 40% -20% -60% -20%; pointer-events: none;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,.07) 0 1px, transparent 1px 74px),
    repeating-linear-gradient(0deg,  rgba(255,255,255,.07) 0 1px, transparent 1px 74px);
  transform: perspective(460px) rotateX(72deg); transform-origin: 50% 0;
  animation: floorRun 11s linear infinite;
  -webkit-mask-image: linear-gradient(to top, #000, transparent 85%);
          mask-image: linear-gradient(to top, #000, transparent 85%);
}
.cta-card > * { position: relative; z-index: 1; }
.cta-card h2 { color: var(--on-ink); }
.cta-card p { margin-top: 12px; color: var(--on-ink-dim); font-size: 17px; }
.cta-card .btn { margin-top: 26px; }

/* The one navy note left in the Intelligence section: a panel, not a band. */
.ink-panel { border-radius: 16px; padding: 20px 18px; box-shadow: var(--e-ink); }

/* ── contact ────────────────────────────────────────────────────────────── */
.contact-grid { display: grid; grid-template-columns: .85fr 1.15fr; gap: clamp(26px, 5vw, 56px); align-items: start; }
@media (max-width: 900px) { .contact-grid { grid-template-columns: 1fr; } }
.cinfo { display: grid; gap: 20px; margin-top: 26px; }
.cinfo .row { display: flex; gap: 13px; align-items: flex-start; }
.cinfo .ic { flex: none; color: var(--accent); margin-top: 2px; }
.cinfo .k { font-size: 11.5px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
.cinfo .v { font-size: 15.5px; margin-top: 3px; line-height: 1.45; }
.cinfo a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--line); }
.cinfo a:hover { border-bottom-color: var(--accent); color: var(--accent); }
.socials { display: flex; gap: 8px; margin-top: 8px; }
.socials a { width: 46px; height: 46px; border: 1px solid var(--line-2); border-radius: 10px; display: grid; place-items: center; color: var(--ink-2); background: var(--card); transition: border-color .18s, color .18s, transform .18s, box-shadow .18s; }
.socials a:hover { border-color: var(--gold); color: var(--accent); }

/* The conversion point should be the highest object on the page. */
/* the compact contact block that replaced the open form */
.contact-cta { text-align: left; padding: clamp(24px, 3vw, 32px); }
.contact-cta h3 { font-family: "Space Grotesk", sans-serif; font-size: clamp(20px, 2.4vw, 25px); font-weight: 650; }
.contact-cta p { font-size: 15px; color: var(--muted); margin-top: 8px; }
.contact-cta .btn { margin-top: 20px; }
.contact-or { display: block; margin-top: 14px; font-size: 13.5px; color: var(--muted); }
.contact-or a { color: var(--accent); font-weight: 700; text-decoration: none; border-bottom: 1px solid currentColor; }

/* the dialog the form now lives in */
.modal-wide { max-width: 560px; }
.modal-wide form.cform { background: transparent; border: 0; box-shadow: none; padding: 0; margin-top: 18px; }
.modal-box { max-height: calc(100dvh - 40px); overflow-y: auto; overscroll-behavior: contain; }

form.cform { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: clamp(20px, 3vw, 30px); box-shadow: var(--e4); }
.f2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 560px) { .f2 { grid-template-columns: 1fr; } }
.field { display: block; margin-bottom: 14px; }
.field > label, .field > span.lbl { display: block; font-size: 12.5px; font-weight: 700; letter-spacing: .04em; color: var(--ink-2); margin-bottom: 6px; }
.field .req { color: var(--accent); }
.field input, .field select, .field textarea {
  width: 100%; min-height: 46px; padding: 12px 13px;
  border: 1.5px solid var(--line-ui); border-radius: 8px; background: #fcfdff;
  box-shadow: inset 0 1px 2px rgba(13,27,62,.05);
  font: 400 15px/1.4 Manrope, "Noto Sans Devanagari", sans-serif; color: var(--ink);
  transition: border-color .16s ease, box-shadow .16s ease;
}
.field textarea { min-height: 104px; resize: vertical; }
.field select { appearance: none; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23566180' stroke-width='2' stroke-linecap='round'><path d='M6 9l6 6 6-6'/></svg>"); background-repeat: no-repeat; background-position: right 13px center; padding-right: 38px; }
.field input:focus, .field select:focus, .field textarea:focus { outline: none; border-color: var(--c1); box-shadow: var(--ring); }
.field.bad input, .field.bad select { border-color: var(--accent); }
.field .err { display: none; font-size: 12.5px; color: var(--accent); margin-top: 5px; font-weight: 600; }
.field.bad .err { display: block; }
.form-note { font-size: 12.5px; color: var(--muted); margin-top: 12px; line-height: 1.45; }
.form-ok {
  display: none; align-items: flex-start; gap: 12px;
  padding: 18px 20px; border: 1px solid var(--c3); border-left: 3px solid var(--c3);
  border-radius: 0 var(--radius) var(--radius) 0; background: var(--ok-bg); margin-bottom: 4px;
}
.form-ok.show { display: flex; }
.form-ok .ic { color: var(--c3); flex: none; margin-top: 1px; }
/* The other outcome. A form that says "thank you" when nothing was sent is
   worse than one that says it failed, because nobody calls back. */
.form-fail {
  display: none; align-items: flex-start; gap: 11px;
  padding: 14px 16px; border: 1px solid #f0c4bd; border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0; background: var(--hot-bg);
  font-size: 14px; color: var(--hot-ink); margin-bottom: 14px; line-height: 1.5;
}
.form-fail.show { display: flex; }
.form-fail .ic { flex: none; margin-top: 1px; }
.form-ok b { display: block; font-size: 15.5px; }
.form-ok span { font-size: 14px; color: var(--muted); }

/* ── footer ─────────────────────────────────────────────────────────────── */
.ftr { background: var(--navy); color: var(--on-ink-dim); padding: clamp(46px, 6vw, 70px) 0 26px; }
.ftr-grid { display: grid; grid-template-columns: 1.4fr 1fr 1.2fr; gap: 34px; }
@media (max-width: 860px) { .ftr-grid { grid-template-columns: 1fr; gap: 26px; } }
.ftr img.flogo { height: 30px; width: auto; }
.ftr p { font-size: 14.5px; line-height: 1.55; margin-top: 14px; max-width: 34ch; }
.ftr h4 { font-size: 11.5px; font-weight: 800; letter-spacing: .16em; text-transform: uppercase; color: var(--gold); margin: 0 0 14px; }
.ftr .flinks { display: grid; gap: 9px; }
.ftr a { color: var(--on-ink-dim); text-decoration: none; font-size: 14.5px; }
.ftr a { position: relative; }
.ftr a::after { content: ""; position: absolute; left: 0; right: 100%; bottom: -2px; height: 1px; background: var(--orange); transition: right .25s ease; }
.ftr a:hover, .ftr a:focus-visible { color: var(--on-ink); }
.ftr a:hover::after, .ftr a:focus-visible::after { right: 0; }
.ftr a:focus-visible { outline: none; }
.ftr .tagline { margin-top: 18px; color: var(--on-ink-body); font-size: 14.5px; }
.ftr .tagline .hi { color: var(--gold); }
.ftr-bot { margin-top: 34px; padding-top: 20px; border-top: 1px solid var(--on-ink-line); display: flex; flex-wrap: wrap; gap: 8px 18px; justify-content: space-between; font-size: 13px; }

/* ── the cursor leaves a mark ────────────────────────────────────────────────
   A soft light that follows the pointer across the dark surfaces, and a ring
   that trails a beat behind it. Pointer-only, so a phone never pays for it, and
   it sits under everything - nothing on the page depends on it. */
/* ── the cursor leaves a mark ────────────────────────────────────────────────
   A soft light that follows the pointer, and nothing else. The hard ring read
   as something stuck to the glass, and an orange wash read as a stain - so this
   is a neutral, barely-there lift, the kind a real light source would make.
   Pointer-only, sits under everything, nothing depends on it. */
.glow {
  position: fixed; left: 0; top: 0; z-index: 1; pointer-events: none;
  width: 520px; height: 520px; margin: -260px 0 0 -260px; border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,.085), rgba(255,255,255,.03) 45%, transparent 70%);
  opacity: 0; transition: opacity .35s ease; will-change: transform;
}
.glow.on { opacity: 1; }
/* on the light half of the page the same light has to be a shadow, not a flare */
.glow.light { background: radial-gradient(circle, rgba(13,27,62,.055), rgba(13,27,62,.02) 45%, transparent 70%); }


/* ── WhatsApp floating button ───────────────────────────────────────────── */
.wa {
  position: fixed; z-index: 70;
  right: max(18px, env(safe-area-inset-right));
  bottom: calc(18px + env(safe-area-inset-bottom));
  width: 56px; height: 56px; border-radius: 50%;
  /* the brand green puts a white glyph at 1.98:1 - the darker WhatsApp green
     carries the same icon at 4.14:1 */
  background: #128c7e; color: #fff; display: grid; place-items: center;
  box-shadow: 0 2px 5px rgba(0,0,0,.2), 0 12px 26px -8px rgba(0,0,0,.34); text-decoration: none;
  transition: transform .18s cubic-bezier(.22,.61,.36,1), box-shadow .18s ease;
}
.wa:hover { transform: scale(1.07); }
.wa:active { transform: scale(.97); }
.wa:focus-visible { outline: none; box-shadow: 0 0 0 4px rgba(37,211,102,.4); }

/* ── login modal ────────────────────────────────────────────────────────── */
.modal { position: fixed; inset: 0; z-index: 100; display: none; align-items: center; justify-content: center; padding: 20px; }
.modal.open { display: flex; }
.modal-bg { position: absolute; inset: 0; background: rgba(8,16,36,.58); }
@supports (backdrop-filter: blur(3px)) { .modal-bg { backdrop-filter: blur(3px); } }
.modal-box {
  position: relative; width: 100%; max-width: 410px;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  padding: 30px 28px 26px; box-shadow: 0 30px 70px rgba(0,0,0,.3);
  animation: rise .22s ease;
}
@keyframes rise { from { opacity: 0; transform: translateY(10px) } to { opacity: 1; transform: none } }
.modal-x { position: absolute; top: 12px; right: 12px; width: 36px; height: 36px; border: 0; background: transparent; border-radius: 8px; cursor: pointer; color: var(--muted); display: grid; place-items: center; }
.modal-x:hover { background: rgba(13,27,62,.07); color: var(--ink); }
.modal-box .mtitle { font-family: "Space Grotesk", sans-serif; font-size: 23px; font-weight: 650; }
.modal-box .msub { font-size: 13.5px; color: var(--muted); margin-top: 4px; }
.modal-box .lmark { width: 40px; height: 40px; border-radius: 10px; background: var(--navy); color: var(--gold); display: grid; place-items: center; font-family: "Space Grotesk", sans-serif; font-size: 19px; font-weight: 650; margin-bottom: 14px; }
.modal-box form { margin-top: 20px; }
.modal-err {
  display: none; gap: 9px; align-items: flex-start;
  background: var(--hot-bg); border: 1px solid #f0c4bd; border-radius: 8px;
  padding: 11px 13px; font-size: 13.5px; color: var(--hot-ink); margin-bottom: 14px;
}
.modal-err.show { display: flex; }
.modal-err .ic { flex: none; margin-top: 1px; }
.pw-wrap { position: relative; }
.pw-wrap input { padding-right: 46px; }
.pw-eye { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); width: 36px; height: 36px; border: 0; background: transparent; cursor: pointer; color: var(--muted); display: grid; place-items: center; border-radius: 7px; }
.pw-eye:hover { color: var(--ink); background: rgba(13,27,62,.06); }
.modal-foot { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); font-size: 12.5px; color: var(--muted); text-align: center; line-height: 1.5; }
.spinner { width: 15px; height: 15px; border: 2px solid rgba(255,253,249,.35); border-top-color: var(--on-ink); border-radius: 50%; animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg) } }

/* ── scroll reveal ────────────────────────────────────────────────────────
   Whole grids used to cross-fade as one 14px slab, so nine service cards
   arrived together and nothing looked composed. Now each child comes in on its
   own beat. --i is set by site.js. */
/* Opt-IN, never opt-out. `.rv { opacity: 0 }` covered every section below the
   hero and only site.js ever undid it - one blocked script and the page was a
   header, a hero and a footer. The hiding now requires JS to be alive. */
.rv { opacity: 1; transform: none; }
html.js .rv { opacity: 0; transform: translateY(22px);
  transition: opacity .65s cubic-bezier(.2,.7,.3,1), transform .65s cubic-bezier(.2,.7,.3,1); }
html.js .rv.in { opacity: 1; transform: none; }
html.js .rv-stagger > * { opacity: 0; transform: perspective(900px) translateY(26px) rotateX(8deg) scale(.985); transform-origin: 50% 100%; }
html.js .rv-stagger.in > * {
  opacity: 1; transform: none;
  transition: opacity .55s cubic-bezier(.2,.7,.3,1), transform .55s cubic-bezier(.2,.7,.3,1);
  transition-delay: calc(var(--i, 0) * 65ms);
}

/* ── nothing here is required to understand the page ──────────────────────
   Everything above is decoration on top of a document that already reads. */
@media (prefers-reduced-motion: reduce) {
  .rv, .rv-stagger > *, html.js .rv-stagger.in > * { opacity: 1 !important; transform: none !important; transition: none !important; }
  .livedot, .typing i, .flash, .modal-box, .msg { animation: none !important; }
  .card:hover, .btn:hover, .chip:hover { transform: none; }
  .hero-plane { transform: none !important; }
  .scene-rot, .layer, .hero-floor::before, .eyebrow::before,
  .cta-card::before, .card-3d, .count, .chips:not(.used) .chip:first-child,
  .ai-scan, .ai-mark i, .ai-live, .ai-msg, .ai-think i, .ai-bars span, .ai-caret,
  .callout-band::after, .dgarrow svg { animation: none !important; }
  .verb::after, .step:not(:last-child)::after, .pdfdoc i, .gridmock tbody tr {
    transform: none !important; opacity: 1 !important; transition: none !important; right: 0 !important;
  }
  html.js .rv .sec-head h2, html.js .sec-head.rv h2 { clip-path: none !important; transition: none !important; }
  .scene-tilt { transform: none !important; }
  .glow { display: none !important; }
  .tilt { transform: none !important; }
  .bar-row .bt i, .heat .hc, .tile .tv { transition: none !important; }
}

/* ── privacy / plain pages ──────────────────────────────────────────────── */
.doc { max-width: 46rem; }
.doc h2 { margin-top: 36px; font-size: clamp(21px, 2.6vw, 26px); }
.doc h1 + p { margin-top: 16px; }
.doc p, .doc li { font-size: 15.5px; color: var(--ink-2); line-height: 1.65; margin-top: 12px; }
.doc ul { padding-left: 20px; }
.doc .updated { font-size: 13px; color: var(--muted); margin-top: 8px; }
