/* ===================================================================
   Hotel Insider — shared stylesheet
   Light mode only, white background — fixed theme, no dark variant.
   The logo (mark + wordmark) is reproduced from the real site: a
   navy gradient badge with "Hi" in Nunito, and "Hotel Insider" set in
   Nunito 700, real navy (#012970).
=================================================================== */

:root{
  --bg:#ffffff;
  --bg-alt:#ffffff;
  --surface:#ffffff;
  --surface-2:#f5f5f2;
  --text:#14181d;
  --text-muted:#5b6270;
  --stone:#5b6270;
  --line:rgba(20,24,29,0.10);
  --line-strong:rgba(20,24,29,0.20);
  --corner-radius:3px;

  --logo-text:#012970; /* real brand navy */

  
  --blue-text:#1749b0;
  --blue:var(--blue-text);
  --orange:#e2681c;
  --orange-text:#c4570f;
  --azure:#0ea5e9;
  --azure-text:#0369a1;
  --amber:#c8871f;
  --violet:#6d28d9;
  --violet-text:#5b21b6;

  /* --card-shadow:0 20px 40px -28px rgba(20,24,29,0.22); */
}
*{box-sizing:border-box;}
/* One shared corner radius across the site. The brand mark is intentionally
   excluded so the logo keeps its original 11% rounding. */
*:not(.brand-mark),
*:not(.brand-mark)::before,
*:not(.brand-mark)::after{border-radius:var(--corner-radius)!important;}
/* Preserve controls and indicators that were intentionally circular before
   the shared-radius rule. The active swipe indicator keeps its original pill. */
.ndf-play,
.chart-legend .dot,
.card-dot,
.mini-arrow,
.lp-arrow,
.ex-arrow,
.teaser-card .teaser-preview-video .play,
.shot-dot,
.avatar,
.testi-video .play,
.video-embed-play,
.wp11-dot,
.team-linkedin,
.team-add .plus{border-radius:50%!important;}
.card-dot.is-active{border-radius:5px!important;}
html{scroll-behavior:smooth;}
body{
  margin:0;
  background:var(--bg);
  color:var(--text);
  font-family:'Inter',sans-serif;
  font-size:16px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  transition:background-color .2s ease, color .2s ease;
}
h1,h2,h3,h4{
  font-family:'Fraunces',serif;
  font-weight:500;
  margin:0;
  letter-spacing:-0.01em;
}
em{font-style:italic;color:var(--blue-text);}
a{color:inherit;text-decoration:none;}
img{max-width:100%;display:block;}
.wrap{max-width:1180px;margin:0 auto;padding:0 32px;}
section{padding:80px 0;}

.eyebrow{
  font-family:'IBM Plex Mono',monospace;
  font-size:11.5px;letter-spacing:0.14em;text-transform:uppercase;
  display:flex;align-items:center;gap:10px;
}
.eyebrow::before{content:"";width:22px;height:1px;background:currentColor;display:inline-block;opacity:0.6;}
.eyebrow.teal{color:var(--blue-text);}
.eyebrow.coral{color:var(--orange-text);}
.eyebrow.violet{color:var(--azure-text);}

/* ---------- buttons ---------- */
.btn{
  font-family:'IBM Plex Mono',monospace;font-size:12.5px;letter-spacing:0.06em;text-transform:uppercase;
  padding:13px 24px;border-radius:3px;display:inline-flex;align-items:center;gap:8px;
  transition:all .22s ease;border:1px solid transparent;cursor:pointer;white-space:nowrap;
}
.btn-teal{background:var(--blue);color:#fff;}
.btn-teal:hover{filter:brightness(1.08);transform:translateY(-1px);}
.btn-line{border-color:var(--line-strong);color:var(--text);}
.btn-line:hover{border-color:var(--blue);color:var(--blue-text);}

/* ---------- header / nav (adapts with the page) ---------- */
header{
  position:fixed;top:0;left:0;right:0;z-index:60;
  background:var(--bg);
  border-bottom:1px solid var(--line);
}
nav.wrap{display:flex;align-items:center;justify-content:space-between;height:76px;}

/* ---- real logo: navy gradient badge ("Hi") + Nunito wordmark ---- */
.brand{display:flex;align-items:center;font-family:'Nunito',sans-serif;font-weight:700;font-size:18px;color:var(--logo-text);}
.brand-mark{
  width:30px;height:30px;border-radius:11%;
  background:linear-gradient(135deg,#001f3f 0%,#0055aa 80%);
  color:#fff;
  display:flex;align-items:center;justify-content:center;
  font-family:'Nunito',sans-serif;font-weight:700;font-size:21px;
  flex-shrink:0;
}
.brand-word{margin-left:15px;}

.navlinks{display:flex;gap:30px;font-size:14px;color:var(--text-muted);}
.navlinks a{transition:color .2s;padding:4px 0;border-bottom:1px solid transparent;}
.navlinks a:hover{color:var(--text);}
.navlinks a.active{color:var(--text);border-bottom-color:var(--blue);}
.navactions{display:flex;align-items:center;gap:20px;}
.navtoggle{display:none;background:none;border:none;color:var(--text);cursor:pointer;padding:6px;}
.navtoggle svg{width:22px;height:22px;}
.mobile-panel{display:none;}
@media(max-width:920px){
  .navlinks{display:none;}
  .navtoggle{display:block;}
  .mobile-panel{
    display:flex;flex-direction:column;gap:2px;
    background:var(--surface);border-top:1px solid var(--line);
    max-height:0;overflow:hidden;transition:max-height .3s ease;
  }
  .mobile-panel.open{max-height:520px;}
  .mobile-panel a{padding:16px 32px;font-size:15px;color:var(--text);border-bottom:1px solid var(--line);}
}

/* ---------- nav flyout menus (Resources / About) ---------- */
.navdrop{position:relative;}
.navdrop-trigger{
  display:inline-flex;align-items:center;gap:6px;
  background:none;border:none;padding:4px 0;margin:0;
  font:inherit;font-size:14px;color:inherit;cursor:pointer;
  border-bottom:1px solid transparent;transition:color .2s;
}
.navdrop-trigger .chev{width:9px;height:9px;flex-shrink:0;opacity:0.6;transition:transform .2s ease;}
.navdrop-trigger:hover{color:var(--text);}
.navdrop:hover .navdrop-trigger .chev,
.navdrop.open .navdrop-trigger .chev{transform:rotate(180deg);}
.navdrop.active .navdrop-trigger{color:var(--text);border-bottom-color:var(--blue);}

.navdrop-panel{
  position:absolute;top:calc(100% + 24px);left:-22px;
  width:460px;background:var(--surface);border:1px solid var(--line);border-radius:10px;
  /* box-shadow:var(--card-shadow); */overflow:hidden;
  display:grid;grid-template-columns:1.05fr 0.95fr;
  opacity:0;visibility:hidden;transform:translateY(6px);
  transition:opacity .18s ease, transform .18s ease, visibility .18s;
  z-index:80;
}
.navdrop-panel::before{content:"";position:absolute;top:-24px;left:0;right:0;height:24px;}
.navdrop:hover .navdrop-panel,
.navdrop.open .navdrop-panel,
.navdrop.hover-open .navdrop-panel,
.navdrop:focus-within .navdrop-panel{opacity:1;visibility:visible;transform:translateY(0);}
.navdrop.hover-open .navdrop-trigger .chev{transform:rotate(180deg);}

.navdrop-links{padding:1px;display:flex;flex-direction:column;justify-content:center;gap:2px;}
/* Scoped to .navdrop-panel (0,2,0) rather than the bare class (0,1,0):
   ".navlinks a{padding:4px 0}" is (0,1,1) and was silently winning over
   plain ".navdrop-link"/".navdrop-feature", collapsing their real padding
   down to 4px top/bottom and 0 left/right regardless of what's set here. */
.navdrop-panel .navdrop-link{display:block;padding:11px 12px;border-radius:6px;transition:background .15s;}
.navdrop-link:hover{background:var(--bg-alt);}
.navdrop-link .ndl-title{display:block;font-size:14px;color:var(--text);font-weight:500;}
.navdrop-link .ndl-desc{display:block;font-size:12px;color:var(--text-muted);margin-top:3px;line-height:1.4;}
/* Hovering anywhere in a submenu row (title or description) colors that
   row's title, matching the footer link hover treatment. Same on the
   top-level Product/Resources/About labels. */
.navdrop-link:hover .ndl-title{color:var(--blue-text);}
.navdrop-trigger:hover{color:var(--blue-text);}

.navdrop-panel .navdrop-feature{display:flex;flex-direction:column;background:var(--bg-alt);padding:11px 11px 11px 11px;border-left:1px solid var(--line);}
.ndf-art{border-radius:6px;overflow:hidden;aspect-ratio:16/11;margin-bottom:12px;position:relative;}
.ndf-play{position:absolute;inset:0;margin:auto;width:34px;height:34px;border-radius:50%;background:rgba(255,255,255,0.94);display:flex;align-items:center;justify-content:center;transition:transform .2s;}
.ndf-play svg{width:13px;height:13px;fill:#0a0e13;}
.navdrop-feature .ndf-tag{font-family:'IBM Plex Mono',monospace;font-size:10px;text-transform:uppercase;letter-spacing:0.07em;color:var(--orange-text);}
.navdrop-feature .ndf-title{display:block;font-family:'Inter',sans-serif;font-size:12px;font-weight:400;color:var(--text-muted);line-height:1.4;margin-top:7px;}
.navdrop-feature .ndf-go{display:inline-block;margin-top:12px;font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--blue-text);}
.navdrop-feature:hover .ndf-go{text-decoration:underline;}
@media(max-width:920px){
  .navdrop-panel{display:none;}
}

/* ---------- page hero (interior pages) ---------- */
.page-hero{padding:180px 0 90px;position:relative;overflow:hidden;}
.page-hero::before{
  content:"";position:absolute;inset:0;
  background:radial-gradient(ellipse 800px 420px at 85% 0%, rgba(29,95,214,0.14), transparent 60%),
             radial-gradient(ellipse 600px 420px at 5% 70%, rgba(14,165,233,0.10), transparent 60%);
  pointer-events:none;
}
.page-hero h1{font-size:clamp(36px,4.6vw,58px);line-height:1.06;margin-top:18px;max-width:820px;position:relative;}
.page-hero p.lede{font-size:17px;color:var(--text-muted);max-width:560px;margin-top:22px;position:relative;}
.filter-row{display:flex;gap:10px;flex-wrap:wrap;margin-top:34px;position:relative;}
.filter-btn{font-family:'IBM Plex Mono',monospace;font-size:12px;text-transform:uppercase;letter-spacing:0.05em;padding:9px 16px;border-radius:20px;border:1px solid var(--line-strong);color:var(--text-muted);cursor:pointer;background:transparent;transition:all .2s;}
.filter-btn:hover{border-color:var(--blue);color:var(--blue-text);}
.filter-btn.active{background:var(--text);border-color:var(--text);color:var(--bg);}

/* ---------- hero (home) ---------- */
.hero{padding:186px 0 100px;position:relative;overflow:hidden;z-index:0;}
.hero::before{
  content:"";position:absolute;inset:0;
  background:radial-gradient(ellipse 900px 500px at 82% 8%, rgba(29,95,214,0.16), transparent 60%),
             radial-gradient(ellipse 700px 500px at -10% 60%, rgba(226,104,28,0.10), transparent 60%);
  pointer-events:none;
}
.hero.hero-patterned::before{
  background:linear-gradient(120deg, rgba(29,95,214,0.07), rgba(14,165,233,0.055) 45%, rgba(226,104,28,0.05));
}
.hero-ornament{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden;}
.hero-ornament svg{display:block;width:100%;height:100%;}
.hero-grid{display:grid;grid-template-columns:1.1fr 0.9fr;gap:64px;align-items:center;position:relative;z-index:1;}
.hero-patterned .btn-line{background:var(--bg);}
.hero h1{font-size:clamp(40px,5.4vw,68px);line-height:1.03;margin-top:20px;}
.hero p.lede{font-size:18px;color:var(--text-muted);max-width:460px;margin-top:26px;}
.hero-cta{display:flex;gap:16px;margin-top:38px;align-items:center;flex-wrap:wrap;}
.hero-note{font-size:13px;color:var(--text-muted);margin-top:34px;font-family:'IBM Plex Mono',monospace;}

/* ---------- hero color themes (index_new_bg_1..10.html only) ----------
   Each theme is a bold, saturated wash on .hero::before (replacing the
   default subtle tint) plus matching light text, scoped entirely under
   .hero-bg-N so no other page — including index.html/index_new.html — is
   touched. The ornament's own gradient colors are set separately per page
   via data-color-a/-b on .hero-ornament (read by script.js). */
.hero-bg-1,.hero-bg-2,.hero-bg-3,.hero-bg-4,.hero-bg-5,
.hero-bg-6,.hero-bg-7,.hero-bg-8,.hero-bg-9,.hero-bg-10{color:#fff;}
.hero-bg-1 h1,.hero-bg-2 h1,.hero-bg-3 h1,.hero-bg-4 h1,.hero-bg-5 h1,
.hero-bg-6 h1,.hero-bg-7 h1,.hero-bg-8 h1,.hero-bg-9 h1,.hero-bg-10 h1{color:#fff;}
.hero-bg-1 em,.hero-bg-2 em,.hero-bg-3 em,.hero-bg-4 em,.hero-bg-5 em,
.hero-bg-6 em,.hero-bg-7 em,.hero-bg-8 em,.hero-bg-9 em,.hero-bg-10 em{color:#fff;}
.hero-bg-1 p.lede,.hero-bg-2 p.lede,.hero-bg-3 p.lede,.hero-bg-4 p.lede,.hero-bg-5 p.lede,
.hero-bg-6 p.lede,.hero-bg-7 p.lede,.hero-bg-8 p.lede,.hero-bg-9 p.lede,.hero-bg-10 p.lede{color:rgba(255,255,255,0.82);}
.hero-bg-1 .hero-note,.hero-bg-2 .hero-note,.hero-bg-3 .hero-note,.hero-bg-4 .hero-note,.hero-bg-5 .hero-note,
.hero-bg-6 .hero-note,.hero-bg-7 .hero-note,.hero-bg-8 .hero-note,.hero-bg-9 .hero-note,.hero-bg-10 .hero-note{color:rgba(255,255,255,0.6);}
.hero-bg-1 .btn-line,.hero-bg-2 .btn-line,.hero-bg-3 .btn-line,.hero-bg-4 .btn-line,.hero-bg-5 .btn-line,
.hero-bg-6 .btn-line,.hero-bg-7 .btn-line,.hero-bg-8 .btn-line,.hero-bg-9 .btn-line,.hero-bg-10 .btn-line{
  background:transparent;border-color:rgba(255,255,255,0.5);color:#fff;
}
.hero-bg-1 .btn-line:hover,.hero-bg-2 .btn-line:hover,.hero-bg-3 .btn-line:hover,.hero-bg-4 .btn-line:hover,.hero-bg-5 .btn-line:hover,
.hero-bg-6 .btn-line:hover,.hero-bg-7 .btn-line:hover,.hero-bg-8 .btn-line:hover,.hero-bg-9 .btn-line:hover,.hero-bg-10 .btn-line:hover{
  background:rgba(255,255,255,0.14);border-color:#fff;color:#fff;
}

/* .hero.hero-patterned.hero-bg-N (3 classes) rather than bare .hero-bg-N:
   ".hero.hero-patterned::before" above is 2 classes + a pseudo-element,
   which otherwise wins over a 1-class override regardless of source order
   — the exact bug class documented earlier for .navlinks a / .navdrop-link. */
/* 1 — Navy (reference image) */
.hero.hero-patterned.hero-bg-1::before{background:linear-gradient(120deg, #082259 0%, #1a3a75 45%, #1d4b9f 100%);}
.hero-bg-1 .eyebrow{color:rgba(255,255,255,0.82);}
/* 2 — Teal */
.hero.hero-patterned.hero-bg-2::before{background:linear-gradient(120deg, #052e2b 0%, #0b5c56 45%, #0ea5a0 100%);}
.hero-bg-2 .eyebrow{color:#7dead9;}
/* 3 — Violet */
.hero.hero-patterned.hero-bg-3::before{background:linear-gradient(120deg, #1b0b33 0%, #3b1370 45%, #6d28d9 100%);}
.hero-bg-3 .eyebrow{color:#d6bbfb;}
/* 4 — Emerald */
.hero.hero-patterned.hero-bg-4::before{background:linear-gradient(120deg, #052e1a 0%, #0b5c33 45%, #10a95e 100%);}
.hero-bg-4 .eyebrow{color:#86efac;}
/* 5 — Amber */
.hero.hero-patterned.hero-bg-5::before{background:linear-gradient(120deg, #2b1a05 0%, #6b3e0a 45%, #c8871f 100%);}
.hero-bg-5 .eyebrow{color:#ffdd94;}
/* 6 — Crimson */
.hero.hero-patterned.hero-bg-6::before{background:linear-gradient(120deg, #2e0808 0%, #6b1414 45%, #c22a2a 100%);}
.hero-bg-6 .eyebrow{color:#ffb3b3;}
/* 7 — Rose */
.hero.hero-patterned.hero-bg-7::before{background:linear-gradient(120deg, #33081f 0%, #7a1245 45%, #d6336c 100%);}
.hero-bg-7 .eyebrow{color:#ffb3d6;}
/* 8 — Slate */
.hero.hero-patterned.hero-bg-8::before{background:linear-gradient(120deg, #0d1117 0%, #1c232e 45%, #2d3848 100%);}
.hero-bg-8 .eyebrow{color:#93c5fd;}
/* 9 — Indigo */
.hero.hero-patterned.hero-bg-9::before{background:linear-gradient(120deg, #0c1033 0%, #201a6b 45%, #3730a3 100%);}
.hero-bg-9 .eyebrow{color:#c7d2fe;}
/* 10 — Ocean */
.hero.hero-patterned.hero-bg-10::before{background:linear-gradient(120deg, #04202e 0%, #0a4a63 45%, #0e7fa3 100%);}
.hero-bg-10 .eyebrow{color:#a5f3fc;}

/* ---------- hero-bg-1-N: 10 all-blue sub-variants of theme 1 (Navy) ----------
   index_new_bg_1_1..10.html. Same white-text/button treatment as the
   hero-bg-N themes above, reused via a shared selector list; only the
   ::before gradient (colors AND angle/direction — "sides" — vary per
   famous blue palette) and eyebrow tint differ per variant. */
.hero-bg-1-1,.hero-bg-1-2,.hero-bg-1-3,.hero-bg-1-4,.hero-bg-1-5,
.hero-bg-1-6,.hero-bg-1-7,.hero-bg-1-8,.hero-bg-1-9,.hero-bg-1-10{color:#fff;}
.hero-bg-1-1 h1,.hero-bg-1-2 h1,.hero-bg-1-3 h1,.hero-bg-1-4 h1,.hero-bg-1-5 h1,
.hero-bg-1-6 h1,.hero-bg-1-7 h1,.hero-bg-1-8 h1,.hero-bg-1-9 h1,.hero-bg-1-10 h1{color:#fff;}
.hero-bg-1-1 em,.hero-bg-1-2 em,.hero-bg-1-3 em,.hero-bg-1-4 em,.hero-bg-1-5 em,
.hero-bg-1-6 em,.hero-bg-1-7 em,.hero-bg-1-8 em,.hero-bg-1-9 em,.hero-bg-1-10 em{color:#fff;}
.hero-bg-1-1 p.lede,.hero-bg-1-2 p.lede,.hero-bg-1-3 p.lede,.hero-bg-1-4 p.lede,.hero-bg-1-5 p.lede,
.hero-bg-1-6 p.lede,.hero-bg-1-7 p.lede,.hero-bg-1-8 p.lede,.hero-bg-1-9 p.lede,.hero-bg-1-10 p.lede{color:rgba(255,255,255,0.82);}
.hero-bg-1-1 .hero-note,.hero-bg-1-2 .hero-note,.hero-bg-1-3 .hero-note,.hero-bg-1-4 .hero-note,.hero-bg-1-5 .hero-note,
.hero-bg-1-6 .hero-note,.hero-bg-1-7 .hero-note,.hero-bg-1-8 .hero-note,.hero-bg-1-9 .hero-note,.hero-bg-1-10 .hero-note{color:rgba(255,255,255,0.6);}
.hero-bg-1-1 .btn-line,.hero-bg-1-2 .btn-line,.hero-bg-1-3 .btn-line,.hero-bg-1-4 .btn-line,.hero-bg-1-5 .btn-line,
.hero-bg-1-6 .btn-line,.hero-bg-1-7 .btn-line,.hero-bg-1-8 .btn-line,.hero-bg-1-9 .btn-line,.hero-bg-1-10 .btn-line{
  background:transparent;border-color:rgba(255,255,255,0.5);color:#fff;
}
.hero-bg-1-1 .btn-line:hover,.hero-bg-1-2 .btn-line:hover,.hero-bg-1-3 .btn-line:hover,.hero-bg-1-4 .btn-line:hover,.hero-bg-1-5 .btn-line:hover,
.hero-bg-1-6 .btn-line:hover,.hero-bg-1-7 .btn-line:hover,.hero-bg-1-8 .btn-line:hover,.hero-bg-1-9 .btn-line:hover,.hero-bg-1-10 .btn-line:hover{
  background:rgba(255,255,255,0.14);border-color:#fff;color:#fff;
}

/* 1-1 — Facebook (120deg, dark navy → FB blue) */
.hero.hero-patterned.hero-bg-1-1::before{background:linear-gradient(120deg, #050e2e 0%, #0d3b8c 50%, #1877f2 100%);}
.hero-bg-1-1 .eyebrow{color:#7db4ff;}
/* 1-2 — Twitter/X (120deg, deep teal-navy → sky blue) */
.hero.hero-patterned.hero-bg-1-2::before{background:linear-gradient(120deg, #031c2e 0%, #0c6fa8 50%, #1da1f2 100%);}
.hero-bg-1-2 .eyebrow{color:#7fd1ff;}
/* 1-3 — LinkedIn (160deg, near-horizontal, navy → LinkedIn blue) */
.hero.hero-patterned.hero-bg-1-3::before{background:linear-gradient(160deg, #001428 0%, #004182 50%, #0a66c2 100%);}
.hero-bg-1-3 .eyebrow{color:#86b8ea;}
/* 1-4 — Stripe (135deg, navy → indigo → cyan — Stripe's signature duo) */
.hero.hero-patterned.hero-bg-1-4::before{background:linear-gradient(135deg, #0a2540 0%, #4b3fd6 50%, #00d4ff 100%);}
.hero-bg-1-4 .eyebrow{color:#9fe8ff;}
/* 1-5 — Discord blurple (100deg, near-vertical, ink → blurple) */
.hero.hero-patterned.hero-bg-1-5::before{background:linear-gradient(100deg, #171a34 0%, #3c46c8 50%, #5865f2 100%);}
.hero-bg-1-5 .eyebrow{color:#b7bdff;}
/* 1-6 — Dropbox (120deg, navy → Dropbox blue) */
.hero.hero-patterned.hero-bg-1-6::before{background:linear-gradient(120deg, #001235 0%, #0040dd 55%, #2a8dff 100%);}
.hero-bg-1-6 .eyebrow{color:#8ec4ff;}
/* 1-7 — "Deep Space" (135deg, the famous uigradients slate-blue trio) */
.hero.hero-patterned.hero-bg-1-7::before{background:linear-gradient(135deg, #0f2027 0%, #203a43 50%, #2c5364 100%);}
.hero-bg-1-7 .eyebrow{color:#9fd6e8;}
/* 1-8 — IBM blue (120deg, near-black → IBM blue) */
.hero.hero-patterned.hero-bg-1-8::before{background:linear-gradient(120deg, #00082e 0%, #054ada 55%, #0f62fe 100%);}
.hero-bg-1-8 .eyebrow{color:#8fb3ff;}
/* 1-9 — "Bluelagoo" (90deg, horizontal — the famous uigradients 3-stop) */
.hero.hero-patterned.hero-bg-1-9::before{background:linear-gradient(90deg, #002a7a 0%, #0052d4 35%, #4364f7 70%, #6fb1fc 100%);}
.hero-bg-1-9 .eyebrow{color:#bcd9ff;}
/* 1-10 — Microsoft Azure, REVERSED (45deg, light side leads, dark trails —
   the "other side" of the gradient vs. every variant above) */
.hero.hero-patterned.hero-bg-1-10::before{background:linear-gradient(45deg, #00a4ef 0%, #0078d7 50%, #002050 100%);}
.hero-bg-1-10 .eyebrow{color:#7fd1ff;}

.chart-card{background:var(--surface);border:1px solid var(--line);border-radius:8px;padding:26px 24px 20px;/* box-shadow:var(--card-shadow); */}
.chart-card .cc-head{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:14px;}
.chart-card .cc-head .t{font-family:'IBM Plex Mono',monospace;font-size:12px;color:var(--text-muted);text-transform:uppercase;}
.chart-card .cc-head .p{font-family:'Fraunces',serif;font-size:22px;color:var(--blue-text);}
svg.chart{width:100%;height:auto;overflow:visible;}
.chart-legend{display:flex;gap:20px;margin-top:14px;font-size:12px;color:var(--text-muted);font-family:'IBM Plex Mono',monospace;flex-wrap:wrap;}
.chart-legend .dot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px;}

/* ---------- marquee ---------- */
.marquee-section{cursor:grab;user-select:none;-webkit-user-select:none;position:relative;padding:52px 0;border-top:1px solid var(--line);border-bottom:1px solid var(--line);overflow:hidden;}
.marquee-label{font-size:12px;color:var(--text-muted);font-family:'IBM Plex Mono',monospace;letter-spacing:0.1em;text-transform:uppercase;text-align:center;margin-bottom:32px;}
.marquee-placeholder{display:none;position:absolute;left:0;right:0;bottom:52px;height:36px;padding:0 32px;grid-template-columns:repeat(6,minmax(0,1fr));gap:clamp(20px,5vw,70px);pointer-events:none;}
.marquee-placeholder span{height:36px;background:var(--line);border-radius:3px;opacity:.5;}
.marquee-section.is-loading .marquee-placeholder{display:grid;}
.marquee-section.is-loading .marquee-track{visibility:hidden;}
.marquee-section.is-revealing .marquee-track{visibility:visible;pointer-events:none;}
@media(max-width:600px){
  .marquee-placeholder{padding:0 20px;grid-template-columns:repeat(4,minmax(0,1fr));}
  .marquee-placeholder span:nth-child(n+5){display:none;}
}
.marquee-track{min-height:36px;display:flex;gap:70px;width:max-content;align-items:center;cursor:grab;user-select:none;-webkit-user-select:none;}
.marquee-track.dragging{cursor:grabbing;}
.marquee-track img{height:36px;width:auto;filter:grayscale(1) opacity(0.55);transition:opacity .25s, filter .25s;-webkit-user-drag:none;}
.marquee-track:not(.hover-managed) img:hover,.marquee-track img.is-hovered{filter:grayscale(0) opacity(1);}
.marquee-tooltip{position:absolute;z-index:2;max-width:calc(100% - 16px);padding:4px 8px;border:1px solid var(--line);border-radius:3px;background:var(--logo-text);color:#fff;font-size:11px;line-height:1.4;text-align:center;pointer-events:none;}

/* ---------- latest posts (LinkedIn case studies) ---------- */
/* ---------- shared: carousel pagination dots ----------
   One dot per real card, built by script.js and appended under whichever
   row it belongs to (.ex-row, .lp-row, and the mobile .w1-grid). The
   active dot stretches into a pill rather than just changing color, so
   position is readable at a glance without relying on hue alone. Buttons,
   not spans — each one is a real click target that scrolls to its card. */
.card-dots{display:flex;gap:7px;justify-content:center;align-items:center;margin-top:18px;}
.card-dot{
  width:8px;height:8px;padding:0;border:none;border-radius:50%;
  background:var(--line-strong);cursor:pointer;
  transition:width .25s ease, background .25s ease, border-radius .25s ease;
}
.card-dot:hover{background:var(--text-muted);}
.card-dot.is-active{width:22px;border-radius:5px;background:var(--blue);}
.card-dot:focus-visible{outline:2px solid var(--blue);outline-offset:2px;}
.lp-row .card-dots{flex-wrap:wrap;}
.lp-row .card-dot{flex-shrink:0;}
@media(prefers-reduced-motion:reduce){.card-dot{transition:none;}}

/* ---------- homepage: Explore rows (3 cards visible, looping) ----------
   One row per content type (Product / Testimonials / Market Monitor),
   replacing the old 3-across .teaser-grid where each cell was its own
   mini-carousel. Same native scroll-snap + 3x-clone loop as .lp-row
   below, just sized to 3 cards per view instead of 4, and reusing the
   existing .teaser-card visuals rather than restyling them. */
.ex-row{position:relative;margin-top:16px;}
.ex-viewport{width:100%;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;-ms-overflow-style:none;cursor:grab;}
.ex-viewport.dragging{cursor:grabbing;scroll-snap-type:none;}
.ex-viewport.dragging,.ex-viewport.dragging *{user-select:none;}
.ex-viewport::-webkit-scrollbar{display:none;}
.ex-track{display:flex;gap:24px;align-items:stretch;}
/* 3 across, sharing two 24px gaps. Cards keep .teaser-card's own border,
   radius and padding — only the sizing and snap behaviour live here. */
.ex-card{flex:0 0 calc((100% - 48px)/3);scroll-snap-align:start;display:flex;flex-direction:column;}
/* .teaser-card's tag color was keyed to :nth-child(1|2|3), which assumed
   exactly three cards in a grid. In a flat looping row that no longer maps
   to anything, so the accent is declared once per row instead. */
.ex-row[data-accent="blue"] .teaser-card .tag{color:var(--blue-text);}
.ex-row[data-accent="orange"] .teaser-card .tag{color:var(--orange-text);}
.ex-row[data-accent="azure"] .teaser-card .tag{color:var(--azure-text);}
@media(max-width:860px){
  .ex-track{gap:16px;}
  .ex-card{flex:0 0 100%;}
}

/* .lp-row is the positioning context for the arrows below — .lp-viewport
   is full width (matching the Explore section's card row above) since the
   arrows no longer take up flex space from it. margin-top matches the
   eyebrow-to-content gap used everywhere else (e.g. .about-grid h2). */
.lp-row{position:relative;margin-top:16px;}
.lp-viewport{width:100%;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;-ms-overflow-style:none;cursor:grab;}
.lp-viewport.dragging{cursor:grabbing;scroll-snap-type:none;}
.lp-viewport::-webkit-scrollbar{display:none;}
.lp-track{display:flex;gap:16px;}
.lp-card{
  flex:0 0 calc(25% - 12px);scroll-snap-align:start;position:relative;
  aspect-ratio:3/5;border-radius:10px;overflow:hidden;
  text-decoration:none;display:flex;flex-direction:column;
  background:var(--surface);border:1px solid var(--line);
}
/* Three stacked sections, each with its own background/text color instead
   of overlaying text on the image: the image (fixed flex-basis — same
   size on every card, regardless of title length, per feedback that a
   flex:1 image was coming out a different height on every card), then
   .lp-card-body (plain white, the site's usual text color — same
   var(--text) as e.g. .testi-quote — holding the title; description was
   cut per earlier feedback), then .lp-card-foot (Victor Matsas + the
   LinkedIn badge). .lp-card-body is flex:1 and .lp-card-foot has
   margin-top:auto, so the title sits right under the image and the footer
   is pinned to the card's bottom edge — any slack between them (a 1-line
   vs. 2-line title) becomes one flexible gap in the middle, not a change
   in image size. */
.lp-card-img{flex:0 0 65%;overflow:hidden;}
.lp-card-img img{width:100%;height:100%;object-fit:cover;display:block;}
.lp-card-body{flex:1;min-height:0;background:var(--surface);display:flex;flex-direction:column;}
.lp-card-title{padding:12px 14px 10px;margin:0;font-size:14.5px;font-weight:400;line-height:1.3;color:var(--text);overflow-wrap:break-word;}
/* Foot is now the same white background + usual text colors as the title
   above it — the only thing still blue anywhere on the card is the
   LinkedIn badge itself (swapped to a solid-blue chip with a white glyph,
   the standard LinkedIn button look, instead of the previous white
   chip/blue glyph). */
.lp-card-foot{margin-top:auto;flex:0 0 auto;background:var(--surface);display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 14px 14px;}
.lp-card-meta{display:flex;flex-direction:column;line-height:1.3;min-width:0;}
.lp-card-name{font-size:12px;font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.lp-card-time{font-size:10.5px;color:var(--text-muted);}
.lp-card-linkedin{width:26px;height:26px;border-radius:6px;background:var(--blue);color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.lp-card-linkedin svg{width:14px;height:14px;}
/* Visual style (size/background/border/icon/hover/mobile bump) is shared
   with .mini-arrow in the Explore section below — see that rule for the
   actual declarations. Only what's genuinely different about this one
   lives here: it's always visible (Latest Posts loops indefinitely, so
   there's no single-slide case to hide it for) and vertically centered via
   a fixed top:50% rather than .mini-arrow's JS-computed seam position
   (kept as .lp-row children rather than .lp-viewport children so they stay
   fixed in place instead of scrolling away with .lp-track). */
.lp-arrow{position:absolute;top:50%;display:flex;}
/* Mobile-only: match .teaser-card/.teaser-body's exact padding and font
   sizes (the Explore mini-carousel cards, e.g. "Rate Calendar") rather than
   the desktop .lp-card sizing scaled up — title at .teaser-card h3's 19px,
   28px side padding like .teaser-body, name/role sized like .testi-who
   .name/.role. Desktop is untouched; this only applies at the same
   860px breakpoint everything else here folds to one-card-per-view at. */
@media(max-width:860px){
  .lp-card{flex:0 0 100%;}
  .lp-card-title{font-size:19px;font-weight:400;padding:24px 28px 10px;}
  .lp-card-foot{padding:0 28px 24px;}
  .lp-card-name{font-size:14px;}
  .lp-card-time{font-size:12.5px;}
  .lp-card-linkedin{width:30px;height:30px;}
  .lp-card-linkedin svg{width:16px;height:16px;}
}
.cs-scroll-title{font-size:13.5px;color:var(--text);padding:12px 14px 4px;line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
.cs-scroll-byline{font-size:11.5px;color:var(--text-muted);padding:0 14px 14px;font-family:'IBM Plex Mono',monospace;}

/* ---------- about / stats ---------- */
.about-section{padding:112px 0 116px;}
.about-grid{display:grid;grid-template-columns:minmax(0,0.9fr) minmax(0,1.1fr);gap:clamp(64px,8vw,108px);align-items:start;}
.about-grid h2{font-size:clamp(32px,3.25vw,44px);font-weight:400;line-height:1.08;margin-top:24px;max-width:520px;}
.about-copy p{color:var(--text-muted);font-size:14px;line-height:1.72;max-width:620px;margin:0;}
/* Used on the About page's "Our approach" section — full-width single
   column instead of the narrow 480px cap meant for the old 2-column
   .about-grid split; the .reveal wrapper itself already caps overall
   width to a readable 720px, so the paragraphs can just fill it. */
.about-copy-wide p{max-width:none;}
.stat-list{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(24px,3.5vw,48px);margin-top:28px;}
.stat-row{position:relative;padding:40px 0 0;}
.stat-row::before{content:"";position:absolute;top:-1px;left:0;width:34px;height:2px;background:var(--blue-text);}
.stat-row:nth-child(2)::before{background:var(--orange-text);}
.stat-row:nth-child(3)::before{background:var(--azure-text);}
.stat-row .desc{font-size:14px;line-height:1.55;color:var(--text-muted);font-weight:400;}
@media(max-width:860px){
  .about-section{padding:72px 0 76px;}
  .about-grid{gap:36px;}
}
@media(max-width:640px){
  .stat-list{grid-template-columns:1fr;gap:24px;margin-top:24px;}
  .stat-row{padding-top:24px;}
}

/* ---------- teaser grid ---------- */
.teaser-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:16px;}
.teaser-card{border:1px solid var(--line);border-radius:8px;padding:32px 28px;background:var(--surface);transition:border-color .2s, transform .2s;/* box-shadow transition: box-shadow .2s; */}
.teaser-card:hover{border-color:var(--line-strong);/* box-shadow:var(--card-shadow); */}
.teaser-card .tag{font-family:'IBM Plex Mono',monospace;font-size:11px;text-transform:uppercase;letter-spacing:0.06em;}
.teaser-card:nth-child(1) .tag{color:var(--blue-text);}
.teaser-card:nth-child(2) .tag{color:var(--orange-text);}
.teaser-card:nth-child(3) .tag{color:var(--azure-text);}
.teaser-card h3{font-size:19px;margin-top:14px;}
.teaser-card p{font-size:14px;color:var(--text-muted);margin-top:10px;}
/* Safety cap for the mini-carousel specifically: CSS Grid stretches every
   card in the 3-up row to match whichever slide's natural content is
   tallest, so one long paragraph (any slide, any card) would otherwise
   force empty space under the other two. Clamping keeps the body height in
   the same range as the fixed 16:10 .teaser-preview image above it. */
.mini-carousel .teaser-body p{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;}
/* .go is a separate <a> from the card's own link now (see mini-carousel
   note below) — it carries its own side/bottom padding to match where
   .teaser-body's used to end, since it's no longer nested inside it. */
.teaser-card .go{font-family:'IBM Plex Mono',monospace;font-size:12px;margin-top:auto;padding:20px 28px 28px;display:inline-block;color:var(--text);opacity:0.6;}
.teaser-card:hover .go{opacity:1;}

/* ---------- teaser-card mini-carousel ----------
   Per-card carousel (not a row-level one): each .mini-carousel card holds N
   full .teaser-slide entries (image + tag + title + text + link), laid out
   side by side in .teaser-slide-track inside the fixed-size, overflow:hidden
   .teaser-slide-viewport "window" — the card's own footprint/position in the
   outer 3-up grid never changes. JS moves the track with a real transform:
   translateX, updated live during a drag/swipe so the card visibly follows
   the pointer (not just an instant flip), then eases to the nearest slide on
   release; a plain click on an arrow animates the same way. Arrows are only
   shown by JS when a card actually has more than one slide (see script.js)
   — a single-slide card renders with no arrows at all. */
/* display:flex chain (card → viewport → track → slide → body) so a grid row
   with taller neighboring cards stretches all the way down to each slide;
   combined with .go{margin-top:auto} below, that keeps the "→" link sitting
   on the same baseline in every card regardless of how much content (a full
   title+paragraph vs. just a short avatar block) sits above it. */
.teaser-card.mini-carousel{position:relative;user-select:none;-webkit-user-select:none;display:flex;flex-direction:column;}
/* viewport/track stay plain block boxes (not flex containers themselves) —
   .flex:1 + height:100% stretch them to fill the card's full grid-row
   height, without turning .teaser-slide-track into a flex *item* of
   viewport, which would make its own width (5 slides wide, meant to
   overflow) ambiguous against viewport's 1-slide-wide box. */
/* pan-y: claim horizontal gestures for our own JS drag/swipe handling,
   while still letting the browser's native vertical page-scroll through
   untouched — same fix already used on .marquee-track elsewhere. Without
   this, a touch-drag that isn't perfectly horizontal can get reinterpreted
   by the browser as "the user wants to scroll the page", which cancels our
   pointer sequence (fires pointercancel) before it ever reaches the commit
   threshold — the card visibly starts to follow the finger but the gesture
   never completes, so only the arrow buttons ever actually change slides. */
.teaser-slide-viewport{overflow:hidden;position:relative;flex:1;touch-action:pan-y;}
.teaser-slide-track{display:flex;cursor:grab;height:100%;}
.teaser-slide-track.dragging{cursor:grabbing;}
.teaser-slide{flex:0 0 100%;min-width:0;display:flex;flex-direction:column;}
/* The "card" part of a slide (image + tag/title/text) is now its own <a>,
   separate from .go below it — so a slide can send the two to different
   places (e.g. Product: card jumps to that tool's own anchor on the Product
   page, .go always goes to the Product page in general). .teaser-slide-link
   fills all the vertical space .go doesn't need, which is what keeps .go
   pinned to the bottom without requiring it to be nested inside .teaser-body
   anymore. */
.teaser-slide-link{display:flex;flex-direction:column;flex:1;color:inherit;text-decoration:none;}
/* Shared nav-arrow style for both per-card carousels: Explore's .mini-arrow
   and Latest Posts' .lp-arrow (see that rule for what's different about
   it). Darkened from the original near-invisible light-glass look
   (rgba(255,255,255,0.2) background, barely visible over light chart
   backgrounds like the one in the bug report) to a dark, semi-opaque
   circle that reads reliably over any image brightness — white icon to
   match, instead of the old var(--text) dark icon that assumed a light
   glassy circle. */
.mini-arrow, .lp-arrow, .ex-arrow{
  left:10px;
  width:35px;height:35px;border-radius:50%;flex-shrink:0;
  background:rgba(10,14,19,0.35);border:1px solid rgba(155,155,155,0.3);
  align-items:center;justify-content:center;cursor:pointer;
  z-index:5;transform:translateY(-50%);backdrop-filter:blur(2px);
  transition:background .2s, opacity .2s;
}
.mini-arrow{position:absolute;display:none;}
.mini-arrow.is-visible{display:flex;}
.mini-arrow:hover, .lp-arrow:hover, .ex-arrow:hover{background:rgba(10,14,19,0.75);}
.mini-arrow svg, .lp-arrow svg, .ex-arrow svg{width:14px;height:14px;color:#fff;}
.mini-next, .lp-next, .ex-next{left:auto;right:10px;}
/* .ex-arrow's `top` is set by script.js to the preview image's lower edge,
   the same seam .mini-arrow uses — the cards are tall (image + copy), so a
   plain top:50% would drop the arrows into the body text. */
.ex-arrow{position:absolute;display:flex;}
/* 1.5× on mobile (860px matches where .teaser-grid drops to one card per
   view) — a bigger, easier-to-hit touch target now that arrows are the
   only sure way to advance a slide from a stationary tap. */
@media(max-width:860px){
  .mini-arrow, .lp-arrow, .ex-arrow{width:52.5px;height:52.5px;}
  .mini-arrow svg, .lp-arrow svg, .ex-arrow svg{width:21px;height:21px;}
}

/* Image variant — additive only (index_explicit.html); a plain .teaser-card
   with no .has-preview / .teaser-preview / .teaser-body is unaffected. */
.teaser-card.has-preview{padding:0;overflow:hidden;}
.teaser-card .teaser-preview{aspect-ratio:16/10;flex-shrink:0;background:var(--bg-alt);overflow:hidden;position:relative;border-bottom:1px solid var(--line);}
.teaser-card .teaser-preview img{width:100%;height:100%;object-fit:cover;object-position:top;display:block;-webkit-user-drag:none;}
.teaser-card .teaser-preview-chart{padding:16px 18px 0;}
.teaser-card .teaser-preview-chart svg{width:100%;height:100%;display:block;}
.teaser-card .teaser-preview-tag{position:absolute;top:14px;right:16px;font-family:'IBM Plex Mono',monospace;font-size:10px;text-transform:uppercase;letter-spacing:0.06em;color:var(--blue-text);}
.teaser-card .teaser-preview-video{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;background:linear-gradient(135deg, rgba(29,95,214,0.16), rgba(226,104,28,0.14));}
.teaser-card .teaser-preview-video .play{width:42px;height:42px;border-radius:50%;background:rgba(10,14,19,0.6);display:flex;align-items:center;justify-content:center;transition:transform .2s;}
.teaser-card .teaser-preview-video .play svg{width:15px;height:15px;}
.teaser-card .teaser-preview-video .vlabel{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--text-muted);}
/* .has-img — real thumbnail (index_new.html only); index.html's version has
   no <img> and no .has-img, so it keeps the plain gradient+centered-label
   look above, untouched. */
.teaser-card .teaser-preview-video.has-img{position:relative;}
.teaser-card .teaser-preview-video.has-img img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0;}
.teaser-card .teaser-preview-video.has-img::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg, rgba(10,14,19,0) 45%, rgba(10,14,19,0.6) 100%);z-index:1;}
.teaser-card .teaser-preview-video.has-img .play{position:relative;z-index:2;background:rgba(255,255,255,0.94);}
.teaser-card .teaser-preview-video.has-img .play svg{fill:#0a0e13;}
.teaser-card .teaser-preview-video.has-img .vlabel{position:absolute;z-index:2;bottom:14px;left:16px;color:rgba(238,241,244,0.9);}
/* Quote-style preview — for mini-carousel slides with no photo (e.g. text
   testimonials reused from the Testimonials page). Keeps the same box as a
   real .teaser-preview (aspect-ratio, border-bottom — both classes are
   applied together in the markup) but centers italic quote text in it
   instead of an image, clamped to fit the fixed-height box gracefully
   regardless of quote length. */
.teaser-card .teaser-preview-quote{
  display:flex;align-items:center;justify-content:center;
  padding:22px 24px;text-align:center;background:var(--surface-2);
}
.teaser-card .teaser-preview-quote .quote-text{
  font-family:'Fraunces',serif;font-style:italic;font-size:14.5px;line-height:1.45;color:var(--text);
  display:-webkit-box;-webkit-line-clamp:6;-webkit-box-orient:vertical;overflow:hidden;
}
.teaser-card .teaser-body{padding:24px 28px 0;display:flex;flex-direction:column;flex:1;}

/* Homepage testimonials: original images, plain person details, rich quotes. */
.home-testimonials .ex-viewport,.home-testimonials .ex-viewport.dragging{cursor:default;}
.home-testimonials a[href],.home-testimonials button{cursor:pointer;}
.home-testimonials .teaser-preview{aspect-ratio:16/10;min-height:200px;flex:0 0 auto;text-decoration:none;}
.home-testimonials .teaser-preview-quote{padding:20px 18px;background:linear-gradient(125deg,var(--quote-start),var(--quote-end));}
.home-testimonials .teaser-preview-quote.quote-blue,.testimonial-detail-quote.quote-blue{--quote-start:#174bb8;--quote-end:#2166d5;}
.home-testimonials .teaser-preview-quote.quote-orange,.testimonial-detail-quote.quote-orange{--quote-start:#a6401b;--quote-end:#bd5528;}
.home-testimonials .teaser-preview-quote.quote-azure,.testimonial-detail-quote.quote-azure{--quote-start:#075e68;--quote-end:#087782;}
.home-testimonials .teaser-preview-quote.quote-violet,.testimonial-detail-quote.quote-violet{--quote-start:#423299;--quote-end:#5743b4;}
/* Adjust this font-size to try different homepage quote sizes. */
.home-testimonials .teaser-preview-quote .quote-text{display:block;width:100%;overflow:visible;color:#fff;font-family:'Inter',sans-serif;font-size:15.5px;font-weight:400;font-style:italic;line-height:1.45;text-align:center;text-align-last:center;hyphens:none;overflow-wrap:break-word;}
/* Leave room for italic glyphs that extend past their text advance. */
.home-testimonials .quote-excerpt{display:-webkit-box;padding-inline:.2em;-webkit-line-clamp:7;-webkit-box-orient:vertical;overflow:hidden;}
.home-testimonials .has-full-quote .quote-excerpt{-webkit-line-clamp:5;}
.testi-grid .testi-quote{font-size:19px;font-style:italic;text-align:center;}
.testi-read-more{display:block;margin-top:1.45em;text-align:right;text-align-last:right;color:inherit;font-style:italic;text-decoration:underline;text-underline-offset:3px;white-space:nowrap;}
.home-testimonials .teaser-body{padding:28px 22px 0;flex:0 0 auto;}
.home-testimonials .testi-who{min-height:84px;margin-top:0;gap:14px;}
.home-testimonials .testi-person{min-width:0;overflow-wrap:break-word;}
.home-testimonials .testi-who .name{font-size:14px;font-weight:600;line-height:1.4;}
.home-testimonials .testi-who .role{font-size:13px;font-weight:400;line-height:1.5;margin-top:3px;color:var(--text-muted);}
.home-testimonials .teaser-card .go{font-family:'Inter',sans-serif;font-size:13px;color:var(--text-muted);opacity:1;padding:40px 22px 24px;}
.home-testimonials .teaser-card .go:hover{color:var(--blue-text);}
.home-testimonials .avatar:focus-visible{outline:2px solid var(--blue);outline-offset:3px;}
.home-testimonials .teaser-preview:focus-visible{outline:2px solid var(--blue);outline-offset:-3px;}
.home-testimonials .teaser-preview-video.has-img .vlabel{bottom:28px;}

/* ---------- features / fig grid ---------- */
.fig-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--line);margin-top:60px;border:1px solid var(--line);}
.fig-card{background:var(--surface);padding:36px 32px;min-height:300px;display:flex;flex-direction:column;}
.fig-card .fig-num{font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.08em;}
.fig-card:nth-child(1) .fig-num{color:var(--blue-text);}
.fig-card:nth-child(2) .fig-num{color:var(--orange-text);}
.fig-card:nth-child(3) .fig-num{color:var(--azure-text);}
.fig-card h3{font-size:21px;margin-top:15px;color:var(--text);}
.fig-card p{font-size:14.5px;color:var(--text-muted);margin-top:11px;flex:1;}
.fig-card .fig-img{margin-top:18px;border:1px solid var(--line);border-radius:4px;overflow:hidden;}
.fig-wide{grid-column:1/-1;background:var(--surface);padding:42px;border-top:1px solid var(--line);}
.fig-wide .fig-num{color:var(--azure-text);font-family:'IBM Plex Mono',monospace;font-size:12px;}
.fig-wide h3{font-size:23px;color:var(--text);margin-top:6px;}
.fig-wide p{font-size:14.5px;color:var(--text-muted);max-width:540px;margin-top:10px;}
.fig-sub-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:28px;}
.fig-sub{border:1px solid var(--line);border-radius:2px;overflow:hidden;background:var(--surface-2);}
.fig-sub .fs-label{padding:12px 16px;font-family:'IBM Plex Mono',monospace;font-size:11px;text-transform:uppercase;letter-spacing:0.06em;color:var(--blue-text);border-top:1px solid var(--line);}

/* ---------- product: chaos-to-clarity compare banner ---------- */
.compare-card{position:relative;aspect-ratio:1/1;border-radius:2px;overflow:hidden;border:1px solid var(--line);/* box-shadow:var(--card-shadow); */background:var(--surface);}
.compare-placeholder{display:none;position:absolute;inset:0;z-index:1;background:rgba(255,255,255,.06);pointer-events:none;}
.compare-card.is-loading{background:transparent;border-color:rgba(255,255,255,.08);}
.compare-card.is-loading .compare-placeholder{display:block;}
.compare-card.is-loading img-comparison-slider{visibility:hidden;}
.compare-card.is-revealing img-comparison-slider{visibility:visible;pointer-events:none;}
.compare-card img-comparison-slider{display:block;width:100%;height:100%;--divider-width:2px;}
.compare-card img-comparison-slider [slot]{position:relative;display:block;width:100%;height:100%;background-size:cover;background-position:center center;background-repeat:no-repeat;}
/* [slot] img — for slots that use a real <img> instead of a background-image
   div (index_new.html); harmless elsewhere since those slots have no <img>. */
.compare-card img-comparison-slider [slot] img{width:100%;height:100%;object-fit:cover;object-position:center center;display:block;pointer-events:none;}
.compare-label{position:absolute;top:16px;z-index:2;font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:var(--text);background:rgba(255,255,255,0.88);backdrop-filter:blur(2px);border:1px solid var(--line-strong);border-radius:20px;padding:6px 13px;}
.compare-label.left{left:16px;}
.compare-label.right{right:16px;}

/* index_new.html only — narrower compare banner, more room for the copy.
   aspect-ratio is the before/after images' own real ratio (1716/912) rather
   than the 1/1 above. A CSS aspect-ratio computed from the container's own
   *measured* width, combined with the slider's internal ResizeObserver, was
   causing a measure → resize → re-measure loop that left the divider in the
   wrong place — matching the ratio the images actually are removes the
   mismatch that loop was fighting over. Using "auto" instead (sized purely
   from the library's own JS measurement) fixed that but broke the page's
   reveal-on-scroll: the card has no height at all until the library's JS
   runs, so the IntersectionObserver's first check sees zero area and never
   fires again once a real height appears. A concrete ratio sizes the card
   immediately from CSS alone, sidestepping both problems. */
.hero-grid-narrow{grid-template-columns:1fr 1.5fr;}
.compare-card-narrow{width:100%;max-width:700px;margin-left:auto;aspect-ratio:1716/912;}
@media(max-width:920px){
  .hero-grid-narrow{grid-template-columns:1fr;}
  .compare-card-narrow{margin-left:0;}
  /* hero-grid-narrow stacks at 920px, ahead of the plain .hero-grid's own
     860px breakpoint — only the headline centers here; everything else
     (eyebrow, lede, hero-note) stays left-aligned. */
  .hero-grid-narrow > div:first-child h1{text-align:center;}
}

/* ---------- product: benefits row ---------- */
.benefits-row{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--line);border:1px solid var(--line);margin-top:44px;}
.benefit-tile{background:var(--surface);padding:26px 24px;}
.benefit-tile .bt-label{font-family:'IBM Plex Mono',monospace;font-size:11px;text-transform:uppercase;letter-spacing:0.06em;color:var(--orange-text);}
.benefit-tile p{font-size:14px;color:var(--text-muted);margin-top:10px;line-height:1.55;}
@media(max-width:860px){.benefits-row{grid-template-columns:1fr;}}

/* ---------- product: alternating feature rows ---------- */
.feature-row{display:grid;grid-template-columns:1fr 1fr;gap:64px;align-items:center;padding:64px 0;border-bottom:1px solid var(--line);}
.feature-row.reverse .feature-media{order:2;}
.feature-row.reverse .feature-copy{order:1;}
.feature-copy .fig-num{font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.08em;color:var(--blue-text);}
.feature-copy h3{font-size:26px;margin-top:14px;line-height:1.2;}
.feature-copy p{font-size:15.5px;color:var(--text-muted);margin-top:14px;max-width:460px;}
.feature-media{border:1px solid var(--line);border-radius:8px;overflow:hidden;/* box-shadow:var(--card-shadow); */}
.feature-media img{width:100%;display:block;}
.feature-subrow{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:8px;padding-bottom:64px;}
.feature-sub{border:1px solid var(--line);border-radius:6px;overflow:hidden;background:var(--surface-2);}
.feature-sub img{width:100%;display:block;}
.feature-sub .fs-label{padding:12px 16px;font-family:'IBM Plex Mono',monospace;font-size:10.5px;text-transform:uppercase;letter-spacing:0.05em;color:var(--blue-text);border-top:1px solid var(--line);}
@media(max-width:860px){
  .feature-row{grid-template-columns:1fr;gap:28px;padding:44px 0;}
  .feature-row.reverse .feature-media,.feature-row.reverse .feature-copy{order:initial;}
  .feature-subrow{grid-template-columns:1fr;padding-bottom:44px;}
}

/* ---------- product: framed screenshot mockup (hero) ---------- */
.product-shot{border:1px solid var(--line);border-radius:8px;overflow:hidden;/* box-shadow:var(--card-shadow); */background:var(--surface);}
.shot-bar{display:flex;align-items:center;gap:6px;padding:12px 14px;background:var(--bg-alt);border-bottom:1px solid var(--line);}
.shot-dot{width:9px;height:9px;border-radius:50%;background:var(--line-strong);display:inline-block;}
.shot-url{margin-left:8px;font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--text-muted);}
.product-shot img{width:100%;display:block;}

/* ---------- product: tabbed tool switcher ---------- */
/* Mobile gets a swipeable-card version instead of the tab switcher (same
   .mini-carousel component as the Explore section — drag/swipe, arrows,
   infinite loop, all already handled by the existing JS, no new code).
   .tool-switcher-mobile is hidden by default and shown only at the same
   860px breakpoint the tab switcher itself folds to a single column at;
   .tool-switcher does the reverse, so exactly one of the two is ever
   visible for a given viewport width. */
.tool-switcher-mobile{display:none;}
@media(max-width:860px){
  .tool-switcher{display:none;}
  .tool-switcher-mobile{display:block;margin-top:24px;}
  .tool-switcher-mobile .teaser-body{padding-bottom:24px;}
  .tool-switcher-mobile .teaser-body p{display:block;-webkit-line-clamp:unset;overflow:visible;}
}
.tool-switcher{margin-top:44px;border:1px solid var(--line);border-radius:10px;overflow:hidden;background:var(--surface);}
.tool-tabs{display:flex;flex-wrap:wrap;border-bottom:1px solid var(--line);background:var(--bg-alt);}
.tool-tab{flex:1;min-width:140px;display:flex;flex-direction:column;gap:4px;align-items:flex-start;padding:16px 18px;background:none;border:none;border-right:1px solid var(--line);cursor:pointer;text-align:left;transition:background .15s;font-family:inherit;}
.tool-tab:last-child{border-right:none;}
.tool-tab:hover{background:rgba(29,95,214,0.06);}
.tool-tab .tt-num{font-family:'IBM Plex Mono',monospace;font-size:10.5px;color:var(--text-muted);letter-spacing:0.06em;}
.tool-tab .tt-name{font-size:13.5px;color:var(--text);font-weight:500;}
.tool-tab.active{background:linear-gradient(120deg,var(--blue),#1b50b8);box-shadow:none;border-radius:0!important;}
.tool-tab.active .tt-num,.tool-tab.active .tt-name{color:#fff;}
.tool-tab.active .tt-name{font-weight:400;}
.tool-tab:focus-visible{outline:2px solid var(--blue);outline-offset:-5px;}
.tool-tab.active:focus-visible{outline-color:#fff;}
.tool-panel{display:none;grid-template-columns:0.85fr 1.15fr;gap:40px;padding:40px;align-items:center;}
.tool-panel.active{display:grid;}
.tool-copy h3{font-size:23px;line-height:1.25;}
.tool-copy p{font-size:15px;color:var(--text-muted);margin-top:14px;}
.product-page .tool-details{font-size:15px;font-weight:400;color:var(--text-muted);margin-top:14px;padding-left:11px;list-style:none;}
.product-page .tool-details li{position:relative;}
.product-page .tool-details li::before{content:"";position:absolute;left:-10px;top:0.45em;top:calc((1lh - 1cap)/2);width:3px;height:0.72em;height:1cap;background:var(--blue);border-radius:0!important;}
.product-page .tool-details li + li{margin-top:10px;}
.product-page .tool-switcher-mobile .tool-details{font-size:14px;margin-top:10px;}
.tool-media{border:1px solid var(--line);border-radius:6px;overflow:hidden;}
.tool-media img{width:100%;display:block;}
.tool-panel .feature-subrow{grid-column:1/-1;margin-top:4px;padding-bottom:0;}
@media(max-width:860px){
  .tool-tabs{flex-direction:column;}
  .tool-tab{border-right:none;border-bottom:1px solid var(--line);}
  .tool-tab:last-child{border-bottom:none;}
  .tool-panel{grid-template-columns:1fr;padding:24px;gap:20px;}
  .tool-panel .feature-subrow{grid-template-columns:1fr;}
}

/* ---------- index: patterned stripe band (marquee variant) ---------- */
.marquee-section.patterned{position:relative;background:linear-gradient(120deg, rgba(29,95,214,0.07), rgba(14,165,233,0.055) 45%, rgba(226,104,28,0.05));overflow:hidden;}
.marquee-section.patterned::before{
  content:"";position:absolute;inset:0;pointer-events:none;opacity:0.8;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='56' viewBox='0 0 56 56'%3E%3Cg fill='none' stroke='%231d5fd6' stroke-opacity='0.16'%3E%3Cpath d='M28 3 L53 28 L28 53 L3 28 Z'/%3E%3C/g%3E%3C/svg%3E");
  background-size:56px 56px;
}
.marquee-section.patterned .marquee-label,
.marquee-section.patterned .marquee-track{position:relative;z-index:1;}

/* ---------- pricing ---------- */
.plan-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;margin-top:56px;}
.plan{border:1px solid var(--line);border-radius:8px;padding:36px 28px;background:var(--surface);position:relative;display:flex;flex-direction:column;}
.plan.popular{border-color:var(--orange);/* box-shadow:var(--card-shadow); */}
.plan .badge{position:absolute;top:-13px;right:26px;background:var(--orange);color:#fff;font-family:'IBM Plex Mono',monospace;font-size:10.5px;letter-spacing:0.08em;text-transform:uppercase;padding:5px 12px;border-radius:3px;}
.plan .tier{font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.1em;text-transform:uppercase;color:var(--text-muted);}
.plan .price{font-family:'Fraunces',serif;font-size:42px;margin-top:12px;color:var(--text);}
.plan .price span{font-size:14px;color:var(--text-muted);font-family:'Inter',sans-serif;}
.plan ul{list-style:none;padding:0;margin:26px 0 28px;display:flex;flex-direction:column;gap:12px;}
.plan li{font-size:14px;color:var(--text-muted);display:flex;gap:10px;align-items:flex-start;}
.plan li::before{content:"—";color:var(--blue-text);flex-shrink:0;}
.pricing-page .plan li::before{content:"✓";}
.pricing-page .plan li.unavailable span{text-decoration:line-through;}
.pricing-page .plan li.unavailable::before{content:"×";color:var(--text-muted);}
.plan .btn{margin-top:auto;justify-content:center;}

/* ---------- FAQ ---------- */
.faq{margin-top:70px;max-width:760px;}
.faq details{border-bottom:1px solid var(--line);padding:22px 0;}
.faq summary{cursor:pointer;font-family:'Fraunces',serif;font-size:18px;list-style:none;display:flex;justify-content:space-between;align-items:center;gap:20px;color:var(--text);}
.faq summary::-webkit-details-marker{display:none;}
.faq summary::after{content:"+";font-family:'IBM Plex Mono',monospace;font-size:20px;color:var(--blue-text);transition:transform .2s;}
.faq details[open] summary::after{transform:rotate(45deg);}
.faq p{color:var(--text-muted);font-size:14.5px;margin-top:14px;max-width:600px;}

/* ---------- legal / long-form content (privacy-policy.html) ---------- */
.legal-content{max-width:720px;}
.legal-content h2{font-size:22px;margin-top:52px;}
.legal-content h2:first-child{margin-top:0;}
.legal-content h3{font-size:16px;margin-top:26px;color:var(--text);}
.legal-content p{color:var(--text-muted);font-size:15.5px;line-height:1.7;margin-top:12px;}
.legal-content ul{color:var(--text-muted);font-size:15.5px;line-height:1.7;margin-top:12px;padding-left:20px;}
.legal-content li{margin-top:6px;}
.legal-content li strong{color:var(--text);}
.legal-content a{color:var(--blue-text);text-decoration:underline;}

/* ---------- testimonials ---------- */
.testi-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:56px;}
/* .testi-card is now sometimes an <a> (the 4 text quotes link to their own
   detail page) and sometimes still a plain block — color/text-decoration
   reset makes the anchor look identical to the old <div>. Split into a
   pastel-tinted .testi-card-top (the quote) and a plain-white
   .testi-card-body (the avatar/name/role) — same shape as .testi-video's
   colored .thumb + white .body, so the tint reads as a "preview" area
   rather than coloring the whole card. */
.testi-card{border:1px solid var(--line);border-radius:8px;overflow:hidden;background:var(--surface);display:flex;flex-direction:column;color:inherit;text-decoration:none;transition:border-color .2s, transform .2s;/* box-shadow transition: box-shadow .2s; */}
a.testi-card:hover{border-color:var(--line-strong);/* box-shadow:var(--card-shadow); */}
.testi-card-top{flex:1;display:flex;align-items:center;padding:30px 26px;}
.testi-card-body{padding:20px 26px 26px;background:var(--surface);}
.testi-card-body .testi-who{margin-top:0;}
.stars{color:var(--amber);font-size:13px;letter-spacing:2px;margin-bottom:16px;}
.testi-quote{font-family:'Fraunces',serif;font-size:18px;line-height:1.45;flex:1;color:var(--text);}
/* Full testimonial: pale card colors and separate, right-aligned attribution. */
.testimonial-story{padding-top:180px;}
.testimonial-story-label{margin:0 0 24px;}
.testimonial-story-name{font-size:clamp(36px,4.6vw,58px);line-height:1.06;margin:0 0 32px;overflow-wrap:break-word;}
.testimonial-detail-quote{margin:0;padding:clamp(24px,5vw,48px) clamp(20px,4vw,44px);border-radius:3px;font-size:24px;color:#000;overflow-wrap:break-word;background:linear-gradient(125deg,color-mix(in srgb,var(--quote-start) 8%,white),color-mix(in srgb,var(--quote-end) 4%,white));}
.testimonial-attribution .testi-who{justify-content:flex-end;text-align:right;margin-top:24px;}
.testimonial-attribution .testi-name-row{justify-content:flex-end;}
.testimonial-attribution .testi-person{min-width:0;overflow-wrap:break-word;}
@media(max-width:600px){.testimonial-detail-quote{font-size:21px;}}
.testi-who{display:flex;align-items:center;gap:12px;margin-top:24px;cursor:default;}
.avatar{width:61px;height:61px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-family:'IBM Plex Mono',monospace;font-size:13px;font-weight:500;flex-shrink:0;overflow:hidden;}
/* Template placeholder photos (rm1-rm6.png) — not real client photos, see
   the comment on each template's avatar for context. Cover the circle;
   the inline background-color set per instance is now just a loading-state
   fallback behind the image. */
.avatar img{width:100%;height:100%;object-fit:cover;display:block;}
.avatar svg{width:52%;height:52%;}
.testi-card:nth-child(3n+1) .avatar{background:rgba(29,95,214,0.12);color:var(--blue-text);}
.testi-card:nth-child(3n+2) .avatar{background:rgba(226,104,28,0.12);color:var(--orange-text);}
.testi-card:nth-child(3n+3) .avatar{background:rgba(14,165,233,0.12);color:var(--azure-text);}
.testi-who .name{font-size:14px;color:var(--text);}
.testi-who .testi-name-row{display:flex;align-items:center;gap:6px;}
.testi-who .testi-person-link{color:inherit;text-decoration:none;cursor:pointer;transition:color .2s;}
.testi-who .testi-person-link:hover,.testi-who .testi-person-link:focus-visible{color:var(--blue-text);}
.testi-who .testi-person-link:focus-visible{outline:2px solid var(--blue);outline-offset:3px;border-radius:3px;}
.testi-who .testi-linkedin{position:relative;z-index:3;display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;flex:0 0 20px;color:#0a66c2;text-decoration:none;cursor:pointer;}
.testi-linkedin svg{display:block;width:14px;height:14px;}
.testi-linkedin:hover{color:var(--blue-text);}
.testi-linkedin:focus-visible{outline:2px solid var(--blue);outline-offset:2px;border-radius:2px;}
.testi-grid .testi-card{position:relative;}
.testi-grid .testi-detail-link{color:inherit;text-decoration:none;}
.testi-grid .testi-card:has(a.testi-detail-link):hover{border-color:var(--line-strong);}
.testi-who .role{font-size:12.5px;color:var(--text-muted);margin-top:2px;}
.testi-video{position:relative;border-radius:8px;overflow:hidden;border:1px solid var(--line);background:var(--surface);}
.testi-video .thumb{aspect-ratio:16/10;background:linear-gradient(135deg,#132420,#1a1530);position:relative;display:flex;align-items:center;justify-content:center;}
.testi-video .play{width:56px;height:56px;border-radius:50%;background:rgba(255,255,255,0.94);display:flex;align-items:center;justify-content:center;transition:transform .2s;}
.testi-video .play svg{width:18px;height:18px;margin-left:3px;}
.testi-video .vlabel{position:absolute;bottom:14px;left:16px;font-family:'IBM Plex Mono',monospace;font-size:11px;text-transform:uppercase;letter-spacing:0.06em;color:rgba(238,241,244,0.8);}
.testi-video .thumb.has-img img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0;}
.testi-video .thumb.has-img::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg, rgba(10,14,19,0) 45%, rgba(10,14,19,0.6) 100%);z-index:1;}
.testi-video .thumb.has-img .play{position:relative;z-index:2;}
.testi-video .thumb.has-img .vlabel{z-index:2;}

/* ---------- responsive video embed (testimonial / report detail pages) ---------- */
.video-embed{position:relative;aspect-ratio:16/9;border-radius:8px;overflow:hidden;background:#0a0e13;border:1px solid var(--line);/* box-shadow:var(--card-shadow); */}
.video-embed iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block;}
/* Link-out variant — some videos restrict which domains may iframe-embed
   them (YouTube error 153), so this opens the real YouTube page instead of
   embedding a player that may fail to load. */
.video-embed-link{display:block;}
.video-embed-link img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}
.video-embed-link::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg, rgba(10,14,19,0.05) 40%, rgba(10,14,19,0.65) 100%);}
.video-embed-play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:64px;height:64px;border-radius:50%;background:rgba(255,255,255,0.94);display:flex;align-items:center;justify-content:center;z-index:2;transition:transform .2s;}
.video-embed-play svg{width:22px;height:22px;fill:#0a0e13;margin-left:3px;}
.video-embed-link:hover .video-embed-play{transform:translate(-50%,-50%) scale(1.08);}
.video-embed-label{position:absolute;bottom:16px;left:18px;z-index:2;font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.04em;color:#fff;}

/* ---------- report detail pages (Market Monitor) ---------- */
.report-byline{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;font-family:'IBM Plex Mono',monospace;font-size:12.5px;color:var(--text-muted);margin-top:18px;}
.report-byline .btn{padding:8px 16px;font-size:11.5px;}
.report-body h2{font-size:24px;margin-top:56px;margin-bottom:16px;}
.report-body h2:first-child{margin-top:0;}
.report-body p{color:var(--text-muted);font-size:15.5px;line-height:1.7;max-width:760px;}
.district-list{display:grid;grid-template-columns:1fr 1fr;gap:16px 32px;margin-top:20px;}
.district-list div{padding:14px 0;border-top:1px solid var(--line);}
.district-list .dn{font-family:'Fraunces',serif;font-size:15px;color:var(--text);margin-bottom:4px;}
.district-list .dd{font-size:13.5px;color:var(--text-muted);line-height:1.5;}
.insight-box{background:var(--bg-alt);border-left:3px solid var(--blue);padding:16px 20px;border-radius:4px;font-size:14px;color:var(--text-muted);margin-top:20px;max-width:760px;}
.insight-box b{color:var(--text);}
.rsp-list{margin-top:24px;max-width:760px;}
.rsp-row{padding:14px 0;border-top:1px solid var(--line);}
.rsp-row:last-child{border-bottom:1px solid var(--line);}
.rsp-head{display:flex;justify-content:space-between;align-items:baseline;gap:12px;font-size:14.5px;}
.rsp-head .n{color:var(--text);font-weight:500;}
.rsp-head .s{font-family:'IBM Plex Mono',monospace;font-size:12.5px;color:var(--blue-text);flex-shrink:0;}
.rsp-bar{height:5px;border-radius:3px;background:var(--line);margin-top:8px;overflow:hidden;}
.rsp-bar span{display:block;height:100%;background:var(--blue);border-radius:3px;}
.rsp-desc{font-size:13px;color:var(--text-muted);margin-top:6px;}
.report-source{margin-top:40px;padding-top:24px;border-top:1px solid var(--line);font-size:13px;color:var(--text-muted);}
.report-source a{color:var(--blue-text);text-decoration:underline;}
.testi-video .body{padding:22px 24px;background:var(--surface);}
@media(max-width:900px){.testi-grid{grid-template-columns:1fr 1fr;}}
@media(max-width:640px){.testi-grid{grid-template-columns:1fr;}}

/* ---------- homepage: hotel type card (glyph rail + panes) ----------
   Ported from templates/public/build/index_hotel_type_1_1_1.html. That
   file's .ht1-section{padding:100px 0} is deliberately not carried over —
   the section uses this page's standard 80px `section` padding instead,
   same call made for the other ported build modules.

   Panes swap by toggling .active (display none/block) rather than sliding
   a track, so the swipe handler in script.js commits on release instead of
   following the finger 1:1; the .ht1-enter-* keyframes below supply the
   directional motion that makes the change read as a swipe. */
/* Full width of .wrap, matching every other module on the page — the source
   file capped this at 940px and centred it, which left it visibly narrower
   than the rows above and below. */
.ht1{display:grid;grid-template-columns:66px 1fr;margin:44px 0 0;border-radius:3px;overflow:hidden;
  background:radial-gradient(circle at 18% -10%, #2c74d6, #10306f 72%);color:#fff;
  /* box-shadow:0 50px 90px -50px rgba(20,24,29,0.55); */}
/* Contents rail is marks only — no names, no numbers. The glyphs inherit
   currentColor so they can sit at full white weight next to the copy. */
.ht1-rail{border-right:1px solid rgba(255,255,255,0.14);padding:11px 0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;}
.ht1-row{display:flex;align-items:center;justify-content:center;width:44px;height:44px;border-radius:3px;
  background:none;border:0;cursor:pointer;font-family:inherit;color:#fff;
  transition:background .22s ease;}
.ht1-ico{width:26px;height:26px;display:block;}
.ht1-ico svg{width:100%;height:100%;display:block;}
.ht1-row:hover{color:#fff;background:rgba(255,255,255,0.07);}
.ht1-row.active{color:#fff;background:rgba(255,255,255,0.15);/* box-shadow:inset 0 0 0 1px rgba(255,255,255,0.32); */}
/* touch-action:pan-y hands horizontal gestures to the swipe handler while
   leaving vertical page scrolling native — correct here because the pane
   is not a scroll container, so no native horizontal behaviour is lost. */
/* Padding moved off the pane and onto .ht1-copy so the photo can run flush
   to the card's right edge and full bleed top to bottom. */
/* Desktop gains one 44px contents-button height above and below the original
   301px module. The rail and copy stay vertically centered in the result. */
.ht1-pane{position:relative;height:389px;overflow:hidden;touch-action:pan-y;cursor:grab;}
.ht1-pane.dragging{cursor:grabbing;}
.ht1-pane.dragging,.ht1-pane.dragging *{user-select:none;}
.ht1-panel{display:none;width:100%;height:100%;min-height:0;}
/* Copy left, photo right. Panels without a photo yet (Management companies,
   Hotel groups) simply omit .has-shot and their copy spans the full width,
   rather than leaving a hole where the image would go. */
.ht1-panel.active{display:grid;grid-template-columns:1fr;}
.ht1-panel.has-shot.active{grid-template-columns:1fr 44%;}
.ht1-copy{position:relative;z-index:1;padding:38px 42px;display:flex;flex-direction:column;justify-content:center;}
.ht1-panel h3{font-family:'Fraunces',serif;font-weight:500;font-size:29px;line-height:1.12;color:#fff;}
.ht1-blurb{margin-top:12px;font-size:14px;line-height:1.62;color:rgba(255,255,255,0.72);max-width:420px;}
/* Title, blurb and tags all stack down the left now, so the chips are a
   wrapped row under the copy instead of the old column pinned to the right. */
.ht1-chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:22px;}
.ht1-chips span{font-size:11.5px;font-weight:600;padding:6px 11px;border-radius:3px;background:#fff;
  color:#123a86;white-space:nowrap;/* box-shadow:0 3px 10px -2px rgba(10,14,19,0.28); */}
/* The photo fills its whole half — object-fit:cover crops rather than
   letterboxes, so differently-proportioned source images all sit flush.
   NOTE: the Independent hotels file is literally named
   "IndependantHote;.png" (misspelt, with a trailing semicolon). It's
   referenced with the semicolon percent-encoded as %3B. Renaming the file
   would be the tidier fix — say the word and I'll update the reference. */
.ht1-shot{position:relative;min-height:0;overflow:hidden;}
.ht1-shot img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center center;display:block;}
/* Direction-aware entrance: the incoming pane slides in from the side the
   swipe came from, so a forward swipe and a backward swipe don't look
   identical. */
@keyframes ht1-in-right{from{opacity:0;transform:translateX(30px);}to{opacity:1;transform:none;}}
@keyframes ht1-in-left{from{opacity:0;transform:translateX(-30px);}to{opacity:1;transform:none;}}
.ht1-panel.enter-right{animation:ht1-in-right .3s cubic-bezier(.22,.61,.36,1);}
.ht1-panel.enter-left{animation:ht1-in-left .3s cubic-bezier(.22,.61,.36,1);}
/* While a finger is down the panel is moved by inline transform with no
   transition, so it tracks the pointer exactly. This class is added only
   for the spring back home when a swipe doesn't reach the commit
   threshold — without it the panel would snap back instantly. */
.ht1-panel.settling{transition:transform .3s cubic-bezier(.22,.61,.36,1), opacity .3s ease;}
@media(prefers-reduced-motion:reduce){
  .ht1-panel.enter-right,.ht1-panel.enter-left{animation:none;}
  .ht1-panel.settling{transition:none;}
}
@media(max-width:860px){
  .ht1{grid-template-columns:1fr;grid-template-rows:auto auto;height:auto;}
  .ht1-rail{flex-direction:row;justify-content:flex-start;overflow-x:auto;gap:3px;padding:8px;
    border-right:none;border-bottom:1px solid rgba(255,255,255,0.14);}
  .ht1-rail::-webkit-scrollbar{display:none;}
  .ht1-row{flex:0 0 auto;}
  .ht1-pane{height:auto;min-height:0;}
  .ht1-panel{height:auto;min-height:0;grid-template-rows:auto 345px;}
  /* One column here: the photo drops below the copy rather than shrinking
     to a sliver beside it. */
  .ht1-panel.has-shot.active{grid-template-columns:1fr;}
  .ht1-copy{padding:26px 20px 28px;}
  .ht1-panel h3{font-size:24px;}
  .ht1-blurb{max-width:none;}
  .ht1-chips{gap:6px;margin-top:16px;}
  /* The former flexible image row was about 517px tall in the 799px
     mobile card. 345px is one-and-a-half times shorter, while switching
     the surrounding rows to auto keeps the blue rail and copy unchanged. */
  .ht1-shot{height:345px;min-height:0;}
}

/* ---------- homepage: "Who it's for" bold bento grid ---------- */
/* Ported from templates/public/build_new_modules/index.html (source:
   index_w_1.html). Section padding is deliberately NOT overridden here —
   it uses the same plain 80px `section` padding as every other homepage
   module, instead of that build file's own 110px. .w1-grid's margin-top
   is 44px to match this codebase's existing eyebrow-only-then-grid gap
   (.case-grid, .benefits-row below) rather than that file's 52px. */
.w1-grid{--w1-gap:20px;position:relative;display:grid;grid-template-columns:repeat(2,1fr);gap:var(--w1-gap);margin-top:44px;}
.w1-grid::after{content:"";position:absolute;inset:0;background:radial-gradient(circle at 50% -20%, rgba(255,255,255,0.22), transparent 55%);pointer-events:none;}
/* Static cards — the hover lift is disabled. These aren't links (there's
   no "who it's for" detail page to send them to), so a card that rose and
   cast a shadow under the cursor was implying a click target that doesn't
   exist. The transition is commented out alongside the :hover rule it
   existed for; restore both together if the cards ever become clickable. */
.w1-card{position:relative;border-radius:3px;padding:26px 24px;overflow:hidden;color:#fff;display:flex;flex-direction:column;/* transition:transform .35s cubic-bezier(.22,.61,.36,1), box-shadow .35s ease; */}
/* .w1-card:hover{transform:translateY(-6px);box-shadow:0 40px 70px -28px rgba(20,24,29,0.45);} */
/* One radial gradient shared by the whole group, light at its centre and
   fading to navy at the edges. Each card shows only its own tile of it:
   background-size spans the full grid (2 columns x 3 rows), and each
   card's background-position picks its tile, so the light centre lands on
   the seam between the two middle cards by construction — no hand-matched
   hex values, and it stays aligned if the palette changes.
   Sized to the 6-card / 3-row layout (was 2 rows when this held 4 cards);
   the vertical positions are the thirds 0% / 50% / 100%, which put the
   gradient's midpoint exactly on the row-2 boundary — i.e. the seam
   between the two middle cards.

   The gaps are added into background-size on purpose. A plain
   `200% 300%` counts only the cards' own widths and heights and ignores
   the grid gaps between them, so each row's slice came out shifted by one
   gap from the row above — the six tiles no longer agreed on where the
   centre was (measured: 20px of drift per row) and the "single shared
   gradient" stopped being continuous. Including the gaps makes the image
   exactly the size of the whole grid, so the percentage positions line
   every tile up against its true place in it. */
.w1-card{
  background-image:radial-gradient(circle, #2367c3 0%, #123a86 100%);
  background-size:calc(200% + var(--w1-gap)) calc(300% + var(--w1-gap) * 2);
}
.w1-card:nth-child(1){background-position:0% 0%;}
.w1-card:nth-child(2){background-position:100% 0%;}
.w1-card:nth-child(3){background-position:0% 50%;}
.w1-card:nth-child(4){background-position:100% 50%;}
.w1-card:nth-child(5){background-position:0% 100%;}
.w1-card:nth-child(6){background-position:100% 100%;}
/* Line-art ornament, one motif per card, taken from
   templates/public/ornament/build/index.html (with its .w1-art rule from
   that build's styles.css). Anchored flush to the card's bottom-right
   corner and deliberately taller than the card, so .w1-card's own
   overflow:hidden crops it — that crop is the intended framing. Sits at
   z-index 0, behind the card's content, which already carries z-index 1
   on .w1-num / .w1-head / .w1-chips. The source's
   `.w1-card:hover .w1-art{opacity:.78}` is deliberately not carried over:
   these cards were made static earlier, and a motif that brightened under
   the cursor would reintroduce the hover reaction that was removed. */
.w1-art{position:absolute;right:0;bottom:0;width:40%;aspect-ratio:5/4;z-index:0;pointer-events:none;opacity:0.5;}
.w1-art svg{width:100%;height:100%;display:block;}
@media(max-width:860px){.w1-art{width:42%;opacity:0.34;}}
.w1-num{position:absolute;z-index:1;top:22px;right:24px;font-family:'IBM Plex Mono',monospace;font-size:12px;color:rgba(255,255,255,0.6);}
.w1-head{position:relative;z-index:1;display:flex;align-items:center;gap:14px;}
.w1-icon{flex-shrink:0;width:44px;height:44px;border-radius:3px;background:rgba(255,255,255,0.16);backdrop-filter:blur(6px);display:flex;align-items:center;justify-content:center;}
.w1-icon svg{width:22px;height:22px;color:#fff;}
.w1-tag{font-family:'Fraunces',serif;font-weight:500;font-size:25px;line-height:1.25;color:#fff;}
.w1-chips{position:relative;z-index:1;display:flex;flex-wrap:wrap;gap:8px;margin-top:20px;}
.w1-chips span{font-family:'Inter',sans-serif;font-weight:600;font-size:12px;padding:7px 14px;border-radius:3px;background:#fff;color:#123a86;/* box-shadow:0 3px 10px -2px rgba(10,14,19,0.28); */letter-spacing:-0.01em;}
/* Below the breakpoint the six cards become a one-at-a-time swipe
   carousel (script.js appends the dots underneath) rather than a tall
   stack, so the grid turns into a horizontal scroll-snap track. The
   shared gradient follows: it's sliced into 6 side-by-side columns
   instead of the desktop 2x3, which keeps the light centre on the
   boundary between cards 3 and 4 — the same two cards it sits between on
   desktop, just measured along the other axis. */
@media(max-width:860px){
  .w1-grid{
    display:flex;flex-wrap:nowrap;grid-template-columns:none;
    overflow-x:auto;scroll-snap-type:x mandatory;
    scrollbar-width:none;-ms-overflow-style:none;cursor:grab;
  }
  .w1-grid::-webkit-scrollbar{display:none;}
  .w1-grid.dragging{cursor:grabbing;scroll-snap-type:none;}
  .w1-grid.dragging,.w1-grid.dragging *{user-select:none;}
  .w1-card{flex:0 0 100%;scroll-snap-align:start;background-size:calc(600% + var(--w1-gap) * 5) 100%;}
  .w1-card:nth-child(1){background-position:0% 0%;}
  .w1-card:nth-child(2){background-position:20% 0%;}
  .w1-card:nth-child(3){background-position:40% 0%;}
  .w1-card:nth-child(4){background-position:60% 0%;}
  .w1-card:nth-child(5){background-position:80% 0%;}
  .w1-card:nth-child(6){background-position:100% 0%;}
}
/* All six cards are visible at once in the desktop grid, so there is
   nothing for dots to page through — they only earn their place once the
   grid collapses to one card per view. */
@media(min-width:861px){
  .w1-grid + .card-dots{display:none;}
}

/* ---------- homepage: "Ways of practice" interactive stepper ---------- */
/* Ported from templates/public/build_new_modules/index.html. Section
   padding uses the plain 80px `section` default (not that build file's
   100px). .wp11-stepper's margin-top is 44px, matching this page's other
   eyebrow-only-then-content gaps (.w1-grid, .case-grid, .benefits-row)
   instead of that file's 56px. The panel below is joined directly to the
   ribbon so both pieces read as one connected module. */
.wp11-stepper{position:relative;margin-top:44px;width:100vw;margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw);overflow:hidden;isolation:isolate;}
.wp11-bg{position:absolute;inset:0;opacity:0;transition:opacity .5s ease;z-index:0;}
.wp11-bg.active{opacity:1;}
/* Draggable on desktop: the row scrolls the card track below it 1:1 (see
   attachDragScroll in script.js). touch-action:pan-y hands horizontal
   gestures to that script while leaving vertical page scrolling native —
   correct here precisely because, unlike .wp11-viewport, this row is not
   a scroll container on desktop, so there's no native horizontal
   behaviour being overridden. The mobile media query below turns it into
   a real scroll container, and resets touch-action so that native
   scrolling works instead. */
.wp11-stepper-inner{display:flex;align-items:flex-start;position:relative;z-index:1;max-width:1180px;margin:0 auto;padding:36px 32px;cursor:grab;touch-action:pan-y;}
.wp11-stepper-inner.dragging{cursor:grabbing;}
.wp11-stepper-inner.dragging,.wp11-stepper-inner.dragging *{user-select:none;}
.wp11-step{flex:1;text-align:center;position:relative;background:none;border:none;cursor:pointer;padding:0 6px;font-family:inherit;z-index:1;}
/* Connector line as two segments per step, stopping exactly at the dot's
   own edge (half its 40px width) on each side — instead of one continuous
   line running underneath every dot, which showed through their
   translucent fill. First/last step skip the outer stub. */
.wp11-step::before,.wp11-step::after{content:"";position:absolute;top:20px;height:1px;background:rgba(255,255,255,0.35);z-index:0;}
.wp11-step::before{left:0;right:calc(50% + 20px);}
.wp11-step::after{left:calc(50% + 20px);right:0;}
.wp11-step:first-child::before{display:none;}
.wp11-step:last-child::after{display:none;}
.wp11-dot{width:40px;height:40px;border-radius:50%;background:rgba(255,255,255,0.14);border:1.5px solid rgba(255,255,255,0.45);display:flex;align-items:center;justify-content:center;margin:0 auto;color:rgba(255,255,255,0.85);transition:all .3s cubic-bezier(.22,.61,.36,1);}
.wp11-dot svg{width:19px;height:19px;}
/* Active dot's pulsing halo disabled (companion to the ribbon-background
   pulse commented out in script.js). The ring holds at the keyframes' own
   0%/100% value — 5px of var(--ring) — which is exactly the resting look
   it already had between pulses, so nothing about the color or size at
   rest changes; only the 5px -> 10px breathing stops. Restore by
   uncommenting; the keyframes and the reduced-motion override below are
   deliberately left in place, inert, for that. */
.wp11-step.active .wp11-dot{background:#fff;border-color:#fff;color:var(--c);transform:scale(1.1);/* box-shadow:0 0 0 5px var(--ring), 0 10px 22px -10px rgba(10,14,19,0.45); *//* animation:wp11-pulse 1.7s ease-in-out infinite; */}
@keyframes wp11-pulse{
  0%,100%{/* box-shadow:0 0 0 5px var(--ring), 0 10px 22px -10px rgba(10,14,19,0.45); */}
  50%{/* box-shadow:0 0 0 10px var(--ring), 0 10px 22px -10px rgba(10,14,19,0.45); */}
}
@media(prefers-reduced-motion:reduce){.wp11-step.active .wp11-dot{animation:none;}}
.wp11-label{display:block;margin-top:13px;font-family:'IBM Plex Mono',monospace;font-size:10.5px;text-transform:uppercase;letter-spacing:0.03em;color:rgba(255,255,255,0.7);}
.wp11-step.active .wp11-label{color:#fff;font-weight:600;}

/* The mobile ribbon is cloned to [copy][real][copy] for infinite swiping.
   If the page loads below 760px and is then widened, those clones remain
   in the DOM. Keep them available for a later resize back to mobile, but
   never let the aria-hidden copies participate in the desktop flex row. */
@media(min-width:761px){
  .wp11-step[aria-hidden="true"]{display:none;}
}

/* .wp11-panels is the lower card chrome, joined flush to the ribbon above;
   its top edge and top corner radii are removed so the two pieces read as
   one module. The actual
   swipe/scroll mechanics live one level in, on .wp11-viewport/.wp11-track
   — same structure and technique as the homepage's Latest Posts row
   (.lp-row/.lp-viewport/.lp-track): a native overflow-x:auto scroll-snap
   track, cloned to 3x for an infinite loop (script.js), plus live 1:1
   mouse-drag-to-scroll. This replaced an earlier hand-rolled "measure a
   pointerup/pointercancel's release coordinates and decide a direction"
   approach that kept breaking on real touch devices — pointercancel's
   coordinates aren't reliable, so that approach had no good fallback.
   Native scroll-snap has no equivalent failure mode: scrollLeft is
   applied live on every pointermove, and the browser's own snap physics
   settle the final panel after release regardless of which event ends
   the gesture. */
.wp11-panels{margin-top:0;position:relative;border:1px solid var(--line);border-top:0;border-radius:0 0 var(--corner-radius) var(--corner-radius)!important;background:var(--surface);/* box-shadow:var(--card-shadow); */overflow:hidden;}
.wp11-viewport{width:100%;overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none;-ms-overflow-style:none;cursor:grab;}
.wp11-viewport.dragging{cursor:grabbing;scroll-snap-type:none;}
.wp11-viewport.dragging,.wp11-viewport.dragging *{user-select:none;}
.wp11-viewport::-webkit-scrollbar{display:none;}
.wp11-track{display:flex;}
.wp11-panel{flex:0 0 100%;scroll-snap-align:start;display:grid;grid-template-columns:1.05fr 0.95fr;}
.wp11-panel-copy{padding:44px;display:flex;flex-direction:column;justify-content:center;}
.wp11-panel-copy h3{font-family:'Fraunces',serif;font-weight:500;font-size:24px;line-height:1.25;max-width:420px;}
.wp11-panel-copy p{font-size:14.5px;color:var(--text-muted);margin-top:14px;max-width:420px;line-height:1.65;}
.wp11-panel-shot{background:var(--bg-alt);}
.wp11-panel-shot img,.wp11-panel-shot svg{width:100%;height:100%;object-fit:cover;display:block;}
@media(max-width:760px){
  .wp11-panel{grid-template-columns:1fr;}
  /* Balance the image with the compact mobile ribbon below so the complete
     Ways of Practice module matches the hotel-type module's total height. */
  .wp11-panel-shot{height:214px;aspect-ratio:auto;}
}
@media(max-width:480px){
  /* Offset the extra line wrapping on narrow phones so the two complete
     modules remain visually equal in height. */
  .wp11-panel-shot{height:208px;}
}

/* Mobile: the label row becomes a swipe carousel showing two steps at a
   time (current + next), connected by the same white line as desktop.
   Each step is exactly half the viewport, so native scroll-snap naturally
   lands on adjacent pairs. */
@media(max-width:760px){
  .wp11-stepper-inner{
    display:flex;flex-wrap:nowrap;padding:14px 0;
    /* Scrollable, but positioned by script (syncRibbon) rather than by the
       user or the browser: its offset is derived from the card track's, so
       the two move as one. Hence scroll-snap and smooth scrolling are both
       off — either would fight the continuous per-frame scrollLeft writes —
       and touch-action:pan-y keeps horizontal gestures going to the drag
       handler while vertical page scrolling stays native. The steps are
       cloned 3x in script.js so this loops the same way the cards do. */
    overflow-x:auto;-webkit-overflow-scrolling:touch;
    scroll-snap-type:none;scroll-behavior:auto;
    touch-action:pan-y;
  }
  .wp11-stepper-inner::-webkit-scrollbar{display:none;}
  .wp11-step{flex:0 0 50%;}
}

/* ---------- case studies ---------- */
.case-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:32px 26px;margin-top:44px;}
.case-card{display:block;}
.case-img{aspect-ratio:4/3;overflow:hidden;border-radius:4px;background:var(--bg-alt);}
.case-img img{width:100%;height:100%;object-fit:cover;transition:transform .5s ease;}
.case-card .cc-eyebrow{font-family:'IBM Plex Mono',monospace;font-size:11px;text-transform:uppercase;letter-spacing:0.06em;margin-top:16px;}
.case-card:nth-child(3n+1) .cc-eyebrow{color:var(--blue-text);}
.case-card:nth-child(3n+2) .cc-eyebrow{color:var(--orange-text);}
.case-card:nth-child(3n+3) .cc-eyebrow{color:var(--azure-text);}
.case-card h4{font-size:18px;margin-top:8px;line-height:1.3;color:var(--text);font-weight:500;}
.case-card .case-desc{font-size:13.5px;color:var(--text-muted);margin-top:8px;line-height:1.5;}
.case-card .byline{font-size:13px;color:var(--text-muted);margin-top:8px;}
@media(max-width:860px){.case-grid{grid-template-columns:1fr 1fr;}}
@media(max-width:600px){.case-grid{grid-template-columns:1fr;}}

/* ---------- team ---------- */
.team-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:22px;margin-top:56px;}
.team-card{border:1px solid var(--line);border-radius:8px;overflow:hidden;background:var(--surface);}
.team-photo{aspect-ratio:1;display:flex;align-items:center;justify-content:center;font-family:'Fraunces',serif;font-size:34px;}
.team-card:nth-child(4n+1) .team-photo{background:linear-gradient(135deg,rgba(29,95,214,0.22),rgba(29,95,214,0.04));color:var(--blue-text);}
.team-card:nth-child(4n+2) .team-photo{background:linear-gradient(135deg,rgba(226,104,28,0.22),rgba(226,104,28,0.04));color:var(--orange-text);}
.team-card:nth-child(4n+3) .team-photo{background:linear-gradient(135deg,rgba(14,165,233,0.22),rgba(14,165,233,0.04));color:var(--azure-text);}
.team-card:nth-child(4n+4) .team-photo{background:linear-gradient(135deg,rgba(200,135,31,0.22),rgba(200,135,31,0.04));color:var(--amber);}
.team-body{padding:11px 10px 22px;}
.team-body .name{font-size:15.5px;font-family:'Fraunces',serif;color:var(--text);}
/* Copy protection for names, paired with the copy/cut handlers in script.js:
   user-select:none stops a selection from ever forming here in the first
   place, which is what actually blocks Ctrl+C / right-click-Copy in
   practice — the event handlers are a fallback for the rare case something
   still ends up selected (e.g. selecting an ancestor element). */
.js-name{user-select:none;-webkit-user-select:none;-moz-user-select:none;}
.team-body .role{font-size:12.5px;color:var(--text-muted);margin-top:5px;font-family:'IBM Plex Mono',monospace;letter-spacing:0.02em;}
.team-name-row{display:flex;align-items:center;gap:6px;}
.team-linkedin{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;flex:0 0 20px;color:#0a66c2;text-decoration:none;cursor:pointer;}
.team-linkedin:hover{color:var(--blue-text);}
.team-linkedin:focus-visible{outline:2px solid var(--blue);outline-offset:2px;border-radius:2px;}
.team-linkedin svg{display:block;width:14px;height:14px;}
.team-add{border:1px dashed var(--line-strong);border-radius:8px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;color:var(--text-muted);min-height:100%;padding:40px 20px;}
.team-add .plus{width:34px;height:34px;border-radius:50%;border:1px solid var(--line-strong);display:flex;align-items:center;justify-content:center;font-size:18px;}
.team-add span{font-family:'IBM Plex Mono',monospace;font-size:11.5px;text-transform:uppercase;letter-spacing:0.05em;}
@media(max-width:900px){.team-grid{grid-template-columns:repeat(2,1fr);}}

/* ---------- contact ---------- */
.contact-grid{display:grid;grid-template-columns:0.8fr 1.2fr;gap:70px;margin-top:20px;}
.contact-block{padding:22px 0;border-bottom:1px solid var(--line);}
.contact-block .l{font-family:'IBM Plex Mono',monospace;font-size:11.5px;text-transform:uppercase;letter-spacing:0.06em;color:var(--text-muted);}
.contact-block .v{font-family:'Fraunces',serif;font-size:19px;margin-top:8px;color:var(--text);}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin-bottom:18px;}
.field{display:flex;flex-direction:column;gap:8px;}
.field.full{grid-column:1/-1;}
.field label{font-family:'IBM Plex Mono',monospace;font-size:11.5px;text-transform:uppercase;letter-spacing:0.05em;color:var(--text-muted);}
.field input,.field textarea,.field select{
  background:var(--surface);border:1px solid var(--line-strong);border-radius:4px;padding:13px 14px;
  color:var(--text);font-family:'Inter',sans-serif;font-size:14.5px;outline:none;transition:border-color .2s;
}
.field input:focus,.field textarea:focus,.field select:focus{border-color:var(--blue);}
.field textarea{resize:vertical;min-height:120px;}

/* ---------- cta band ---------- */
.cta-band{padding:140px 0;text-align:center;position:relative;overflow:hidden;}
.cta-band::before{content:"";position:absolute;inset:0;background:radial-gradient(ellipse 600px 300px at 50% 40%, rgba(29,95,214,0.14), transparent 65%);}
.cta-band h2{font-size:clamp(32px,4.6vw,54px);position:relative;max-width:800px;margin:0 auto;line-height:1.1;}
.cta-band p{color:var(--text-muted);margin-top:20px;font-size:16px;position:relative;}
.cta-band .hero-cta{justify-content:center;margin-top:34px;position:relative;}

/* ---------- footer ---------- */
footer{border-top:1px solid var(--line);padding:74px 0 40px;background:var(--bg);}

.foot-grid{display:grid;grid-template-columns:1.4fr 1fr 1fr 1.2fr;gap:48px;}
/* Grid/flex items default to min-width:auto (their content's intrinsic
   minimum), and text/email <input> elements have a large one — without
   this, the newsletter input refuses to shrink below that floor, forcing
   its grid column (and everything downstream: .wrap, footer, the whole
   page) wider than the viewport. This is the real cause of the mobile
   horizontal-scroll bug. */
.foot-grid > div{min-width:0;}
/* Replaces the site's own logo in the footer — this now goes straight to
   the company's LinkedIn page (see the .foot-brand a href), so it's styled
   as a LinkedIn link instead: the same solid-blue badge + white glyph as
   .lp-card-linkedin on the Latest Posts cards, plus a label so it reads as
   "this goes to our LinkedIn", not as the site's own wordmark. */
.foot-linkedin{display:flex;align-items:center;gap:10px;margin-bottom:14px;text-decoration:none;}
.foot-linkedin-badge{width:32px;height:32px;border-radius:7px;background:var(--blue);color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.foot-linkedin-badge svg{width:17px;height:17px;}
.foot-linkedin-label{font-family:'Nunito',sans-serif;font-weight:700;font-size:14.5px;color:var(--logo-text);}
/* The real address never sits in the page's HTML as plain text — same
   .js-email obfuscation technique as the Contact/Privacy Policy pages,
   filled in by script.js once the page has loaded. */
.foot-email{display:inline-block;font-size:13.5px;color:var(--text-muted);text-decoration:none;}
.foot-email:hover{color:var(--blue-text);}
/* margin-top:0 wasn't needed before — every footer column used to start
   with this same <h5>, so its ~19px browser-default top margin was
   invisible (all four columns were equally offset from the grid's true
   top). Now that .foot-brand starts with .foot-linkedin instead (a div,
   no default margin), that same 19px shows up as a real misalignment
   between the LinkedIn row and the other three "SITE"/"COMPANY"/
   "NEWSLETTER" column headers — reset it so all four start flush. */
footer h5{font-family:'IBM Plex Mono',monospace;font-size:11.5px;letter-spacing:0.08em;text-transform:uppercase;color:var(--text-muted);margin-top:0;margin-bottom:16px;}
footer ul{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:11px;}
footer ul a{font-size:14px;color:var(--text);opacity:0.85;}
footer ul a:hover{opacity:1;color:var(--blue-text);}
/* Was an inline style attribute on the <p> in base.html. Moved into CSS so
   the gradient footer below can restyle it — an inline colour can only be
   beaten with !important, and the muted grey is unreadable on the blue. */
.foot-note{color:var(--stone);font-size:13.5px;margin-bottom:14px;}
.foot-form{display:flex;border:1px solid var(--line-strong);border-radius:3px;overflow:hidden;margin-top:6px;background:var(--surface);}
.foot-form input{flex:1;min-width:0;background:transparent;border:none;padding:12px 14px;color:var(--text);font-family:'Inter',sans-serif;font-size:13.5px;outline:none;}
.foot-form button{background:var(--blue);border:none;color:#fff;padding:0 18px;font-family:'IBM Plex Mono',monospace;font-size:12px;cursor:pointer;text-transform:uppercase;}
.foot-bottom{display:flex;justify-content:space-between;margin-top:64px;padding-top:24px;border-top:1px solid var(--line);font-size:12.5px;color:var(--text-muted);flex-wrap:wrap;gap:12px;}
.cookie-settings-link{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;}
.cookie-settings-link:hover{color:var(--blue-text);}

/* ---------- footer: solid blue, deepening downward ----------
   Deliberately placed after every rule above: these override the footer's
   default colours, and those defaults are declared at the same specificity
   further up, so anything written earlier would simply lose the cascade.

   No white-to-blue fade: the blue starts at full strength on the footer's
   very first pixel, so the top edge is a clean line against the white band
   above it. From there it deepens to navy at the bottom. Everything in the
   footer therefore sits on blue or darker, which is what lets all of its
   text be white. */
footer{
  background:linear-gradient(to bottom, var(--blue) 0%, #01102e 100%);
  /* The colour change alone draws the edge — a border on top of it just
     reads as a second, darker line. */
  border-top:none;
}
/* Every element in the footer now sits on blue, so all of it goes white.
   The defaults are greys and navies chosen against a white page — left
   alone they range from low-contrast to invisible. */
footer h5{color:rgba(255,255,255,0.72);}
footer ul a{color:#fff;opacity:0.88;}
footer ul a:hover{opacity:1;color:#fff;}
.foot-linkedin-label{color:#fff;}
.foot-email{color:rgba(255,255,255,0.82);}
.foot-email:hover{color:#fff;}
.foot-note{color:rgba(255,255,255,0.75);}
.foot-bottom{color:rgba(255,255,255,0.82);border-top-color:rgba(255,255,255,0.22);}
.cookie-settings-link:hover{color:#fff;}
/* The newsletter field stays a white pill — its input text is dark, so it
   has to — but its hairline and the LinkedIn badge were drawn for a white
   page: on blue the badge would sink into the background and the border
   would read as a dark smudge. */
.foot-form{border-color:rgba(255,255,255,0.28);}
.foot-linkedin-badge{background:#fff;color:var(--blue);}

/* ---------- cookie consent banner ---------- */
.cookie-banner{
  position:fixed;left:0;right:0;bottom:0;z-index:100;
  background:var(--surface);border-top:1px solid var(--line-strong);
  /* box-shadow:0 -20px 40px -28px rgba(20,24,29,0.28); */
  padding:22px 0;
  transform:translateY(110%);
  transition:transform .45s cubic-bezier(.22,.61,.36,1);
}
.cookie-banner.show{transform:translateY(0);}
.cookie-banner-inner{
  max-width:1180px;margin:0 auto;padding:0 32px;
  display:flex;align-items:center;justify-content:space-between;gap:32px;flex-wrap:wrap;
}
.cookie-banner p{font-size:13.5px;line-height:1.55;color:var(--text-muted);max-width:640px;margin:0;}
.cookie-banner p a{color:var(--blue-text);text-decoration:underline;}
.cookie-actions{display:flex;gap:12px;flex-shrink:0;}
.cookie-actions .btn{padding:11px 22px;font-size:12px;}
@media(max-width:640px){
  .cookie-banner-inner{flex-direction:column;align-items:stretch;}
  .cookie-actions{justify-content:flex-end;}
}

/* ---------- reveal / responsive ---------- */
.reveal{opacity:0;transform:translateY(18px);transition:opacity .7s ease, transform .7s ease;}
.reveal.in{opacity:1;transform:translateY(0);}
@media(max-width:860px){
  .hero-grid,.about-grid,.contact-grid{grid-template-columns:1fr;}
  .fig-grid,.teaser-grid,.plan-grid,.testi-grid{grid-template-columns:1fr;}
  .fig-sub-grid{grid-template-columns:1fr;}
  .form-row{grid-template-columns:1fr;}
  section{padding:80px 0;}
  .foot-grid{grid-template-columns:1fr 1fr;}
  /* Once the hero stacks to one column, only the headline centers —
     eyebrow, lede, and hero-note stay left-aligned. */
  .hero-grid > div:first-child h1{text-align:center;}
}
@media(max-width:600px){
  /* Tighter side margins on phone widths — more content fits per line. */
  .wrap{padding:0 20px;}
}
@media (prefers-reduced-motion: reduce){
  .reveal{opacity:1;transform:none;transition:none;}
  /* Autoplay speed is zeroed in JS (matchMedia check); dragging still works. */
  html{scroll-behavior:auto;}
}
