/* TCR Engineering base stylesheet.
   MOBILE FIRST. Every media query below is min-width. There is not one max-width
   query in this file and there must never be one. The narrow viewport is the base
   case; wider viewports are progressive enhancement.

   Fluid layout only: containers carry max-width, percentages, min(), clamp(),
   Flexbox and Grid. A fixed `width` in pixels on a layout container is a defect. */

/* ---------- Fonts: two families, site-wide, self-hosted ----------
   Rohit's ruling, 2026-07-10. Inter carries everything readable; JetBrains Mono carries
   numbers. No serif, no display face. Both are variable, subsetted to Latin, and served
   from our own origin with an immutable cache header. Inter is preloaded in the head of
   every page; JetBrains Mono is not, because no number is ever the LCP element. */

@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/inter-var-subset.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2074,
                 U+20B9, U+2122, U+2212, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("/assets/fonts/jetbrains-mono-var-subset.woff2") format("woff2-variations");
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+2000-206F, U+20B9, U+2212;
}

/* ---------- Reset ---------- */

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body,
h1, h2, h3, h4, p, figure, blockquote, dl, dd, ul, ol { margin: 0; padding: 0; }

ul[class], ol[class] { list-style: none; }

img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
  height: auto;
}

input, button, textarea, select { font: inherit; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ---------- Document ---------- */

body {
  background: var(--tcr-cream);
  color: var(--tcr-ink);
  font-family: var(--font-ui);
  font-size: var(--step-0);
  line-height: 1.6;
  text-rendering: optimizeLegibility;
  min-height: 100vh;
}

h1, h2, h3, h4 {
  color: var(--tcr-primary);
  font-weight: 600;
  line-height: 1.15;
  text-wrap: balance;
}

h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); margin-block-start: var(--space-l); }
h3 { font-size: var(--step-2); margin-block-start: var(--space-m); }
h4 { font-size: var(--step-1); margin-block-start: var(--space-m); }

p, li { max-width: 68ch; }
p + p { margin-block-start: var(--space-s); }

a { color: var(--tcr-primary); text-underline-offset: 0.2em; }
a:focus-visible,
button:focus-visible {
  outline: 3px solid var(--tcr-accent-light);
  outline-offset: 2px;
}

.skip-link {
  position: absolute;
  left: -9999px;
}
.skip-link:focus {
  left: var(--gutter);
  top: var(--space-xs);
  z-index: 10;
  background: var(--tcr-dark);
  color: var(--tcr-cream);
  padding: var(--space-xs) var(--space-s);
}

/* ---------- Layout primitives ---------- */

.wrap {
  width: 100%;
  max-width: var(--wrap-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.wrap--narrow { max-width: var(--wrap-narrow); }

section { padding-block: var(--space-xl); }

/* Fluid card grid. One column on a phone, then as many columns as fit,
   with no breakpoint doing the work. */
.grid {
  display: grid;
  gap: var(--space-m);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
}

.cluster {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  align-items: center;
}

/* ---------- Header and navigation ---------- */

.site-header {
  background: var(--tcr-dark);
  color: var(--tcr-cream);
  position: sticky;
  top: 0;
  z-index: 5;
}

.site-header .wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-s);
  padding-block: var(--space-xs);
}

.site-nav ul {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  list-style: none;
}

.site-nav a { color: var(--tcr-cream); text-decoration: none; }
.site-nav a:hover { color: var(--tcr-accent-dark); text-decoration: underline; }

/* Collapsed by default on the phone, opened by the toggle button. */
.site-nav[data-open="false"] { display: none; }
.nav-toggle { background: none; border: 1px solid var(--tcr-cream); color: inherit; padding: var(--space-2xs) var(--space-xs); }

@media (min-width: 48em) {
  .nav-toggle { display: none; }
  .site-nav[data-open="false"] { display: block; }
  .site-nav ul { flex-direction: row; gap: var(--space-m); }
}

/* ---------- Hero. The LCP element. ---------- */

.hero {
  position: relative;
  padding-block: 0;
}

.hero__media {
  width: 100%;
  aspect-ratio: 4 / 5;              /* phone crop */
  object-fit: cover;
}

@media (min-width: 48em) {
  .hero__media { aspect-ratio: 21 / 9; }
}

.hero__copy {
  padding: var(--space-l) var(--gutter);
  background: var(--tcr-dark);
  color: var(--tcr-cream);
}

.hero__copy h1 { color: var(--tcr-cream); }
.hero__copy .accent { color: var(--tcr-accent-dark); }

/* On the wide viewport the copy sits over the dark left third of the frame,
   which is where the image brief reserves negative space. */
@media (min-width: 64em) {
  .hero { display: grid; }
  .hero__media, .hero__copy { grid-area: 1 / 1; }
  .hero__copy {
    background: linear-gradient(90deg, rgba(49, 56, 65, 0.94) 0%, rgba(49, 56, 65, 0.86) 55%, rgba(49, 56, 65, 0.55) 82%, rgba(49, 56, 65, 0) 100%); /* 2026-07-16: same fade extension as the v4 navy block below */
    align-self: center;
    max-width: min(52ch, 55%);
    padding-inline: max(var(--gutter), calc((100vw - var(--wrap-max)) / 2 + var(--gutter)));
  }
}

/* ---------- The answer-first block (the GEO golden rule) ---------- */

.answer-first {
  font-size: var(--step-prose);  /* 2026-07-31 (Rohit): one prose size. was --step-1. see scripts/normalise_prose_size.py */
  line-height: 1.5;
  max-width: 68ch;
}

.answer-first + ul,
.answer-first + ol,
.answer-first + .table-wrap {
  margin-block-start: var(--space-m);
}

/* ---------- Data ---------- */

.table-wrap { overflow-x: auto; }   /* the only horizontal scroll permitted */

table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--step--1);
}

caption { text-align: start; color: var(--tcr-muted); padding-block-end: var(--space-xs); }
th, td { border-bottom: 1px solid var(--tcr-hairline); padding: var(--space-xs) var(--space-s); text-align: start; vertical-align: top; }
thead th { background: var(--tcr-primary); color: var(--tcr-white); }
tbody tr:nth-child(even) { background: var(--tcr-cream-warmer); }

td.num, .stat__value { font-family: var(--font-data); font-variant-numeric: tabular-nums; }
td.num { text-align: end; }

.stat__value { font-size: var(--step-3); color: var(--tcr-primary); }
.stat__label { color: var(--tcr-muted); font-size: var(--step--1); }

/* ---------- Cards ---------- */

.card {
  background: var(--tcr-cream-warm);
  border: 1px solid var(--tcr-hairline);
  padding: var(--space-m);
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.card h3 { margin-block-start: 0; }

/* ---------- Call to action. One verb site-wide. ---------- */

.cta {
  display: inline-block;
  background: var(--tcr-accent-light);
  color: var(--tcr-ink);
  font-weight: 600;
  text-decoration: none;
  padding: var(--space-xs) var(--space-m);
  min-height: 44px;               /* touch target */
  line-height: 2;
}

.cta--on-dark { background: var(--tcr-accent-dark); }

/* ---------- Footer ---------- */

.site-footer {
  background: var(--tcr-dark);
  color: var(--tcr-cream);
  padding-block: var(--space-xl);
}

.site-footer a { color: var(--tcr-cream); }
.site-footer .tagline .initial { color: var(--tcr-accent-dark); font-weight: 700; }

/* ---------- Editorial pages ----------
   Rohit's ruling 2026-07-10: no serif ships on the web. Editorial pages are set in
   Inter at a wider measure and looser leading, which is where a serif was earning its
   keep anyway. If a serif is ever proposed again, it loads on that route alone and only
   if the measured LCP delta on a Pages preview is under 100 ms. */

.tcre-editorial p,
.tcre-editorial li {
  font-size: var(--step-prose);  /* 2026-07-31 (Rohit): was --step-1 (24px), which left all 315 posts a step above the main site. One prose size across every page family. */
  line-height: 1.75;
  max-width: 64ch;
}

.tcre-editorial h2 { margin-block-start: var(--space-xl); }

/* The About-page centrepiece was specified in Playfair Display 36pt. It renders as
   inline SVG outlines instead: pixel-identical, roughly 3 KB, zero font requests, and
   it cannot flash unstyled. Style hook only; the glyphs live in the markup. */
.centrepiece svg { width: 100%; height: auto; fill: var(--tcr-dark); }

/* ============================================================================
   Batch-1 components (appended 2026-07-12, additive only; nothing above this
   line was modified). Mobile-first; every media query below is min-width.
   ========================================================================= */

/* ---------- Shared ---------- */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The hero image ships as an art-directed <picture> (AVIF + WebP, 4:5 phone /
   21:9 desktop). The <picture> is the grid item; the <img> keeps .hero__media. */
.hero > picture { width: 100%; }
@media (min-width: 64em) {
  .hero > picture { grid-area: 1 / 1; }
}

.eyebrow {
  display: block;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--tcr-accent-light);
  margin-block-end: var(--space-xs);
}

.band--dark { background: var(--tcr-dark); color: var(--tcr-cream); }
.band--dark h2, .band--dark h3 { color: var(--tcr-cream); }
.band--dark a { color: var(--tcr-cream); }
.band--dark .eyebrow { color: var(--tcr-accent-dark); }

.section-lede { color: var(--tcr-muted); max-width: 68ch; }

/* Scroll reveal: elements start visible; the JS adds .reveal only when
   IntersectionObserver exists and reduced motion is not requested. */
.reveal { opacity: 0; transform: translateY(20px); transition: opacity 200ms ease-out, transform 200ms ease-out; }
.reveal.is-visible { opacity: 1; transform: none; }

/* ---------- Stat band (locked composition rule) ---------- */

.stat-band { background: var(--tcr-dark); color: var(--tcr-cream); }
.stat-band .wrap {
  display: grid;
  gap: var(--space-m);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
  text-align: center;
}
.stat-band .stat__value {
  display: block;
  color: var(--tcr-accent-light);
  font-size: var(--step-4);
  font-weight: 700;
}
.stat-band .stat__label { color: var(--tcr-muted); display: block; }

/* ---------- Solution Finder ---------- */

.finder { background: var(--tcr-cream-warm); border: 1px solid var(--tcr-hairline); padding: var(--space-m); }
.finder form {
  display: grid;
  gap: var(--space-s);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  align-items: end;
}
.finder label { display: block; font-size: var(--step--1); font-weight: 600; margin-block-end: var(--space-2xs); }
.finder select {
  width: 100%;
  padding: var(--space-xs);
  border: 1px solid var(--tcr-hairline);
  background: var(--tcr-white);
  color: var(--tcr-ink);
}
.finder button.cta { border: 0; cursor: pointer; width: 100%; }

/* ---------- Bento matrix ---------- */

.bento {
  display: grid;
  gap: var(--space-m);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
}
@media (min-width: 64em) {
  .bento { grid-template-columns: repeat(3, 1fr); }
  .bento > .tile--wide { grid-column: 1 / -1; }
}

.tile {
  position: relative;
  background: var(--tcr-cream-warm);
  border: 1px solid var(--tcr-hairline);
  padding: var(--space-m);
  overflow: hidden;
}
.tile h3 { margin-block-start: 0; font-size: var(--step-1); }
.tile .tile__no { font-family: var(--font-data); color: var(--tcr-muted); font-size: var(--step--1); }
.tile a { font-weight: 600; }
.tile:hover { box-shadow: 0 6px 18px rgba(49, 56, 65, 0.15); transition: box-shadow 200ms ease-out; }

/* Cursor-follow spotlight: --mx / --my set by one pointermove listener.
   No effect on touch or reduced-motion (the JS never attaches). */
.tile[data-spotlight]::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 200ms ease-out;
  background: radial-gradient(24rem circle at var(--mx, 50%) var(--my, 50%), rgba(255, 140, 0, 0.10), transparent 45%);
}
.tile[data-spotlight]:hover::after { opacity: 1; }

/* ---------- Client-impact cards ---------- */

.impact-card { background: var(--tcr-white); border: 1px solid var(--tcr-hairline); padding: var(--space-m); }
.impact-card .impact__value {
  display: block;
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--step-3);
  font-weight: 700;
  color: var(--tcr-accent-light);
}
.impact-card h3 { font-size: var(--step-1); }

/* ---------- Accreditation ribbon ---------- */

.ribbon ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs) var(--space-m);
  list-style: none;
  font-size: var(--step--1);
  color: var(--tcr-muted);
}
.ribbon li { border: 1px solid var(--tcr-hairline); padding: var(--space-2xs) var(--space-xs); background: var(--tcr-white); }

/* ---------- Testimonial / quote band ---------- */

.quote-band blockquote {
  border-inline-start: 3px solid var(--tcr-accent-light);
  padding-inline-start: var(--space-m);
  font-size: var(--step-1);
  max-width: 60ch;
}
.quote-band cite { display: block; margin-block-start: var(--space-xs); color: var(--tcr-muted); font-style: normal; }

/* ---------- Video facade (click-to-load; no autoloaded iframe) ---------- */

.video-facade {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--tcr-dark);
  border: 0;
  color: var(--tcr-cream);
  cursor: pointer;
  display: grid;
  place-items: center;
  gap: var(--space-s);
  padding: var(--space-m);
}
.video-facade .play {
  width: 4rem;
  height: 4rem;
  border-radius: 50%;
  background: var(--tcr-accent-light);
  display: grid;
  place-items: center;
}
.video-facade .play::before {
  content: "";
  border-style: solid;
  border-width: 0.7rem 0 0.7rem 1.2rem;
  border-color: transparent transparent transparent var(--tcr-ink);
  margin-inline-start: 0.2rem;
}
.video-frame { width: 100%; aspect-ratio: 16 / 9; }
.video-frame iframe { width: 100%; height: 100%; border: 0; }

/* ---------- Insight cards ---------- */

.insight-card { background: var(--tcr-white); border: 1px solid var(--tcr-hairline); padding: var(--space-m); display: flex; flex-direction: column; gap: var(--space-2xs); }
.insight-card .insight__meta { font-size: var(--step--1); color: var(--tcr-muted); }
.insight-card h3 { font-size: var(--step-0); margin-block-start: 0; }
.insight-card p { font-size: var(--step--1); color: var(--tcr-muted); }

/* ---------- Standards marquee (pause on hover; static under reduced motion
   or when JS marks no-motion) ---------- */

.marquee { overflow: hidden; border-block: 1px solid var(--tcr-hairline); padding-block: var(--space-s); }
.marquee ul {
  display: flex;
  flex-wrap: wrap;              /* static, readable base case */
  gap: var(--space-s) var(--space-m);
  list-style: none;
  font-family: var(--font-data);
  font-size: var(--step--1);
  color: var(--tcr-muted);
  width: max-content;
  max-width: 100%;
}
@media (prefers-reduced-motion: no-preference) {
  .marquee[data-animate="true"] ul {
    flex-wrap: nowrap;
    max-width: none;
    animation: marquee-scroll 60s linear infinite;
  }
  .marquee[data-animate="true"]:hover ul { animation-play-state: paused; }
}
@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* ---------- Sticky in-page subnav with scroll progress ---------- */

.subnav {
  position: sticky;
  top: 3.4rem;                   /* clears the site header */
  z-index: 4;
  background: var(--tcr-cream);
  border-block-end: 1px solid var(--tcr-hairline);
}
.subnav ul {
  display: flex;
  gap: var(--space-m);
  list-style: none;
  overflow-x: auto;
  padding-block: var(--space-xs);
  font-size: var(--step--1);
}
.subnav a { text-decoration: none; white-space: nowrap; }
.subnav .progress {
  display: block;
  height: 3px;
  width: 100%;
  transform-origin: left;
  transform: scaleX(var(--scroll-progress, 0));
  background: var(--tcr-accent-light);
}

/* ---------- Case files ---------- */

.case-file { background: var(--tcr-white); border: 1px solid var(--tcr-hairline); padding: var(--space-m); }
.case-file .case__meta { font-family: var(--font-data); font-size: var(--step--1); color: var(--tcr-muted); }
.case-file h3 { font-size: var(--step-1); }

/* ---------- FAQ (native disclosure, no JS) ---------- */

.faq details { border-block-end: 1px solid var(--tcr-hairline); padding-block: var(--space-s); }
.faq summary { font-weight: 600; cursor: pointer; color: var(--tcr-primary); }
.faq details p { margin-block-start: var(--space-xs); }

/* ---------- Expert card ---------- */

.expert-card { background: var(--tcr-cream-warm); border: 1px solid var(--tcr-hairline); padding: var(--space-m); max-width: 32rem; }
.expert-card .expert__role { color: var(--tcr-muted); font-size: var(--step--1); }

/* ---------- Closing CTA band ---------- */

.cta-band { background: var(--tcr-dark); color: var(--tcr-cream); text-align: center; }
.cta-band h2 { color: var(--tcr-cream); }
.cta-band p { margin-inline: auto; }

/* ---------- Footer columns ---------- */

.footer-cols {
  display: grid;
  gap: var(--space-l);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  margin-block: var(--space-l);
}
.footer-cols h2 { font-size: var(--step-0); color: var(--tcr-cream); margin-block-start: 0; }
.footer-cols ul { list-style: none; display: flex; flex-direction: column; gap: var(--space-2xs); font-size: var(--step--1); }
.site-footer .credline { color: var(--tcr-muted); font-size: var(--step--1); }

/* ============================================================================
   V4 DESIGN LANGUAGE (appended 2026-07-12). Ports the approved wireframe
   02_Draft_HTML/TCR-Website_Homepage-Draft_v4.html into the shipped site.
   Additive: nothing above this line was modified; later rules win the cascade.
   Every media query remains min-width (the wireframe's max-width queries are
   converted: narrow viewport is the base case).
   ========================================================================= */

/* ---------- Global re-grounding to the v4 palette ---------- */

h1, h2, h3, h4 { color: var(--tcr-navy); }

.eyebrow {
  font-size: 13px;
  letter-spacing: 0.14em;
  color: var(--tcr-primary);   /* Steel Blue on light grounds (v4) */
}
.on-dark .eyebrow, .band--dark .eyebrow { color: var(--tcr-accent-light); }

.sec-h2 { margin-block-start: var(--space-xs); font-size: clamp(26px, 3.4vw, 34px); }

/* Buttons: v4 primary is Orange with white text, 2px radius. Overrides .cta. */
.cta, .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background: var(--tcr-accent-light);
  color: var(--tcr-white);
  font-weight: 600;
  text-decoration: none;
  padding: 14px 26px;
  min-height: 48px;
  border-radius: 2px;
  border: none;
  cursor: pointer;
  line-height: 1.2;
  transition: background 0.18s ease;
}
.cta:hover, .btn:hover { background: var(--tcr-orange-hover); }
.cta--on-dark { background: var(--tcr-accent-light); color: var(--tcr-white); }
.btn-ghost { background: transparent; color: var(--tcr-white); border: 1px solid rgba(255, 255, 255, 0.45); }
.btn-ghost:hover { background: transparent; border-color: var(--tcr-accent-light); color: var(--tcr-accent-light); }

.band--dark { background: var(--tcr-navy); }
.cta-band { background: var(--tcr-navy); }
.cta-band h2 { color: var(--tcr-white); }
.cta-band p { color: var(--tcr-white-90); }

/* ---------- Utility bar ---------- */

.utility { background: var(--tcr-navy-deep); color: var(--tcr-white-65); font-size: 13px; }
.utility .wrap {
  display: flex;
  justify-content: space-between;
  align-items: center;
  min-height: 38px;
  padding-block: 6px;
  flex-wrap: wrap;
  gap: 6px 16px;
}
.utility a { color: var(--tcr-white-65); text-decoration: none; }
.utility a:hover { color: var(--tcr-white); }
.utility .entities { display: none; }
.utility .entities .sep { margin: 0 5px; opacity: 0.35; }
@media (min-width: 48em) {
  .utility .entities { display: block; }
}

/* ---------- Site header (v4 nav): translucent navy, sticky, blur ---------- */

.site-header {
  background: rgba(0, 31, 63, 0.86);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.site-header .wrap { min-height: 72px; gap: 28px; flex-wrap: nowrap; }
.site-header img { height: 34px; width: auto; }

.site-nav ul { gap: 24px; }
.site-nav a {
  color: var(--tcr-white-90);
  font-size: 15px;
  font-weight: 500;
  padding: 6px 0;
  position: relative;
  display: block;
}
.site-nav a:hover { color: var(--tcr-white); text-decoration: none; }
.site-nav a:not(.cta):hover::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 2px;
  background: var(--tcr-accent-light);
}
.site-nav .cta { padding: 10px 18px; min-height: 42px; }

/* Desktop nav hidden on the phone; the drawer takes over (v4 pattern). */
.site-nav { display: none; }
.nav-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-left: auto;
  color: var(--tcr-white);
  background: none;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 2px;
  width: 46px;
  height: 46px;
  font-size: 22px;
  cursor: pointer;
}
@media (min-width: 64em) {
  .nav-toggle { display: none; }
  .site-nav, .site-nav[data-open="false"] { display: block; }
}

/* Scroll progress bar inside the header */
.site-header .progress {
  position: absolute;
  left: 0; top: 0;
  height: 2px;
  width: 0;
  background: var(--tcr-accent-light);
  z-index: 61;
}
.site-header { position: sticky; }

/* ---------- Mobile drawer ---------- */

.drawer { display: none; position: fixed; inset: 0; z-index: 70; background: var(--tcr-navy); padding: 24px; overflow-y: auto; }
.drawer.open { display: block; }
.drawer .dtop { display: flex; justify-content: space-between; align-items: center; margin-block-end: 28px; }
.drawer .dtop img { height: 34px; width: auto; }
.drawer .dclose { background: none; border: 1px solid rgba(255, 255, 255, 0.3); color: var(--tcr-white); width: 46px; height: 46px; font-size: 22px; border-radius: 2px; cursor: pointer; }
.drawer ul { list-style: none; display: flex; flex-direction: column; gap: 2px; margin-block-end: 24px; }
.drawer ul a { color: var(--tcr-white); font-size: 19px; font-weight: 600; padding: 16px 0; display: block; border-bottom: 1px solid rgba(255, 255, 255, 0.1); text-decoration: none; }
.drawer .dsub { color: var(--tcr-white-65); font-size: 14px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; margin: 28px 0 10px; }
.drawer .dutil { display: flex; flex-direction: column; gap: 12px; color: var(--tcr-white-65); font-size: 15px; }
.drawer .dutil a { color: var(--tcr-white-65); text-decoration: none; }
.drawer .btn, .drawer .cta { width: 100%; margin-block-start: 8px; }

/* ---------- V4 hero: layered CSS ground (blueprint grid + glow + scan) ---------- */

.hero--v4 {
  position: relative;
  background: linear-gradient(180deg, #001A35 0%, var(--tcr-navy) 100%);
  color: var(--tcr-white);
  padding-block: clamp(56px, 9vw, 104px) 0;
  overflow: hidden;
}
.hero--v4::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* 2026-07-31 (Rohit): "above the india's oldest i see dotted lines...can you
     remove it". This was a 56px grid of 1px white lines at 5% opacity, masked
     at 30% 0% so it was at FULL strength across the top of the hero, exactly
     where the eyebrow sits, and broke up over the photograph into what read as
     dotted rules. Switched off site-wide (.hero--v4 is the shared hero). The
     rule is kept, not deleted, so the stacking context is unchanged and the
     overlay can be restored by uncommenting the four lines below.
       background-image:
         linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px),
         linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
       background-size: 56px 56px;
       mask-image: radial-gradient(ellipse 95% 85% at 30% 0%, #000 30%, transparent 78%);
     The .scan sweep, the three .aur aurora layers and the .wave SVG are
     untouched. */
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 56px 56px;
  -webkit-mask-image: radial-gradient(ellipse 95% 85% at 30% 0%, #000 30%, transparent 78%);
          mask-image: radial-gradient(ellipse 95% 85% at 30% 0%, #000 30%, transparent 78%);
}
.hero--v4::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 60% 50% at 78% 16%, rgba(255, 140, 0, 0.13), transparent 65%);
}
.hero--v4 .scan {
  position: absolute;
  top: 0; bottom: 0; left: -240px;
  width: 240px;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(255, 140, 0, 0.07), transparent);
  animation: scan 9s linear infinite;
}
@keyframes scan { to { transform: translateX(calc(100vw + 480px)); } }
.hero--v4 .hero-inner { position: relative; z-index: 1; }
.hero--v4 .eyebrow { margin-block-end: 20px; color: var(--tcr-accent-light); }
.hero--v4 h1 { color: var(--tcr-white); font-size: clamp(30px, 5vw, 58px); font-weight: 600; max-width: 17ch; letter-spacing: -0.01em; }
.hero--v4 h1 .w { display: inline-block; opacity: 0; transform: translateY(16px); animation: rise 0.55s cubic-bezier(0.2, 0.6, 0.2, 1) forwards; animation-delay: calc(var(--i) * 60ms); }
@keyframes rise { to { opacity: 1; transform: none; } }
.hero--v4 .sub { margin-block-start: 22px; font-size: clamp(16px, 2vw, 19px); color: var(--tcr-white-90); font-weight: 500; max-width: none; }
.hero--v4 .stats { margin-block-start: 34px; display: flex; flex-wrap: wrap; gap: 16px 28px; }
@media (min-width: 48em) { .hero--v4 .stats { gap: 16px 44px; } }
.stat-chip .num { display: block; font-family: var(--font-data); font-size: clamp(26px, 3vw, 36px); font-weight: 700; color: var(--tcr-accent-light); letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.stat-chip .lab { display: block; margin-block-start: 4px; font-size: 12.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--tcr-white-65); }
.hero--v4 .cta-row { margin-block-start: 38px; display: flex; gap: 16px; flex-wrap: wrap; }
.hero--v4 .wave { display: block; width: 100%; height: 52px; margin-block-start: 44px; opacity: 0.5; }
.hero--v4 .wave path { fill: none; stroke: var(--tcr-accent-light); stroke-width: 1.6; stroke-dasharray: 2400; stroke-dashoffset: 2400; animation: draw 2.4s 0.4s ease-out forwards; }
@keyframes draw { to { stroke-dashoffset: 0; } }
.credential-ribbon {
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  padding: 22px 0 40px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 22px;
  align-items: center;
  font-size: 14px;
  color: var(--tcr-white-65);
}
.credential-ribbon .cr-label { font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--tcr-muted-light); }
.credential-ribbon .dot { color: var(--tcr-accent-light); }

/* Photo heroes (T2/T4) re-grounded to v4 navy */
.hero__copy { background: var(--tcr-navy); }
@media (min-width: 64em) {
  .hero__copy {
    background: linear-gradient(90deg, rgba(0, 31, 63, 0.94) 0%, rgba(0, 31, 63, 0.86) 55%, rgba(0, 31, 63, 0.55) 82%, rgba(0, 31, 63, 0) 100%); /* 2026-07-16: fade extended to cover the full copy width; was 0 at 62% and white copy drowned on light hero images */
    text-shadow: 0 1px 12px rgba(0, 21, 44, 0.55);
  }
}
.hero__copy .eyebrow { color: var(--tcr-accent-light); }

/* ---------- Answer-first band (v4) ---------- */

.answer-band { background: var(--tcr-cream); padding-block: 34px; border-bottom: 1px solid var(--tcr-hairline); }
.answer-band .answer-first { border-inline-start: 0; padding-inline-start: 0; font-size: var(--step-prose); max-width: 80ch; }  /* 2026-07-31 (Rohit): one prose size. was a hard-coded 16.5px, the only hard-coded prose size on the site. see scripts/normalise_prose_size.py */

/* ---------- Proof / impact cards (v4: orange top rule, hover lift) ---------- */

.impact-card {
  border-top: 3px solid var(--tcr-accent-light);
  padding: 30px 24px;
  transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.impact-card:hover { box-shadow: 0 14px 34px rgba(0, 31, 63, 0.10); transform: translateY(-3px); }
.impact-card .impact__value { color: var(--tcr-navy); font-size: clamp(28px, 3vw, 38px); letter-spacing: -0.02em; overflow-wrap: anywhere; }
.impact-card .eyebrow { font-size: 12px; letter-spacing: 0.12em; margin: 16px 0 8px; color: var(--tcr-primary); }
.impact-card .more { margin-block-start: 16px; display: inline-block; color: var(--tcr-accent-light); font-weight: 600; font-size: 14px; text-decoration: none; }
/* Client marks in the impact cards (2026-07-30, Rohit; optical pass the same day).
   The SVGs carry a viewBox and no width/height, so without a rule they had no
   intrinsic size at all. Heights are per mark because the marks carry very
   different padding inside their own viewBox, measured with cairosvg: Adani's
   artwork fills 100 percent of its box, PDO's fills 16 percent of the height.
   A single height therefore rendered Adani large and Aramco, Reliance and PDO
   small. BIS, Indian Oil and GAIL are held at 64px, the size Rohit confirmed
   reads correctly, and the rest are calibrated so every ink box lands in one
   band. The slot height is fixed so the value line still aligns across a row.
   Mobile-first; the only query is min-width. */
.impact-card__logos {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-s);
  margin: 0 0 var(--space-s);
  min-height: 99px;
}
.impact-card__logos img {
  height: 48px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
}
/* 2026-07-31b (Rohit): Adani height pin REMOVED. It existed because Adani was the
   only mark whose artwork filled its viewBox while the others wasted 60-70% of
   theirs on empty margin. Aramco, Reliance, PDO and GAIL have all since been
   cropped to their ink, so the pin was the only thing still making Adani small.
   It now inherits height:100% like Aramco, Reliance and BIS. */
.impact-card__logos img[src$="saudi-aramco.svg"] { height: 72px; }
.impact-card__logos img[src$="reliance-industries.svg"] { height: 99px; }
.impact-card__logos img[src$="petroleum-development-oman.svg"] { height: 75px; }
/* 2026-07-31b (Rohit): GAIL capped. Cropping it to its ink this morning took it
   from 47% to 100% ink, so it overpowered Indian Oil (still 67% ink) in the shared
   pipelines card. 72px of GAIL ink against ~64px of Indian Oil ink. Indian Oil is
   deliberately NOT touched: Rohit says every other mark is correct. */
.impact-card__logos img[src$="gail-india-v2.svg"] { height: 54px; }
@media (min-width: 48em) {
  .impact-card__logos { min-height: 132px; }
  .impact-card__logos img { height: 64px; }
  /* 2026-07-31b: Adani desktop pin removed, see the note above. */
  .impact-card__logos img[src$="saudi-aramco.svg"] { height: 96px; }
  .impact-card__logos img[src$="reliance-industries.svg"] { height: 132px; }
  .impact-card__logos img[src$="petroleum-development-oman.svg"] { height: 100px; }
  .impact-card__logos img[src$="gail-india-v2.svg"] { height: 72px; }
}
.impact-card__logos img {
  height: 48px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
}
@media (min-width: 48em) {
  .impact-card__logos { min-height: 64px; }
  .impact-card__logos img { height: 64px; }
}

/* ============================================================================
   ALIGNMENT PASS, 2026-07-31c (Rohit). Additive; nothing above this line moved.
   Written after a 16-page browser sweep for containers whose children break onto
   a second row with exactly one item stranded on it. See
   scripts/fix_alignment_pass.py for the full findings table, including the three
   cases deliberately NOT changed (newsroom remainder, gc-links text flow, and
   the materials-testing marquee, which overflows into an overflow-x:hidden
   parent by design).
   ========================================================================= */

/* 1. Adani: matched to Reliance by WIDTH, not height. Reliance renders 137x96;
      Adani's artwork is ratio 1.58, so 137 / 1.58 = 87px of height renders it
      137 wide, the same visual size. */
.impact-card__logos img[src$="adani-power.svg"] { height: 87px; }

/* 2. Solution Finder: four children in a three-track grid stranded the button.
      Scoped to .finder-band so the /contact/ and /service-request/ forms, which
      are .finder but not .finder-band, keep their auto-fit multi-row layout. */
@media (min-width: 48em) {
  .finder-band .finder form { grid-template-columns: repeat(3, 1fr) auto; }
  .finder-band .finder form > p:last-child { align-self: end; }
  /* `align-items: end` aligns MARGIN boxes, not visible boxes. The select
     wrappers carry margin-block-end: 24px and the button wrapper carries
     margin-block-start: 16px, so the four margin edges lined up while the
     visible bottoms sat 24px apart and the button still read as "lower".
     Measured in Chrome: the delta is now 0px, all four children bottom out at
     the same y. The grid `gap` supplies the spacing these margins provided. */
  .finder-band .finder form > p { margin-block: 0; }
}

/* 3. Hero proof ribbon: four chips total ~900px against an 818px container, so
      flex-wrap broke them 3 + 1. Two-by-two until they genuinely fit, then one
      row. There is no width at which 3 + 1 can now occur. */
.hero--v4 .proof-ribbon {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, auto));
  justify-content: start;
}
@media (min-width: 68em) {
  .hero--v4 .proof-ribbon { grid-template-columns: repeat(4, minmax(0, auto)); }
}

/* 4. /about/ group grid: exactly four cards, and four 19rem tracks would need
      1276px against a 1216px maximum wrap, so auto-fit always resolved to three
      and stranded the fourth. Two columns gives a balanced 2 x 2. */
@media (min-width: 48em) {
  .group-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---------- Solution Finder (v4: navy band, navy-card panel) ---------- */

.finder-band { background: var(--tcr-navy); color: var(--tcr-white); }
.finder-band h2 { color: var(--tcr-white); }
.finder-band .answer-first { color: var(--tcr-white-90); border-color: var(--tcr-accent-light); }
.finder-band .finder { background: var(--tcr-navy-card); border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 4px; padding: 24px; }
.finder-band .finder label { font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--tcr-muted-light); }
.finder-band .finder select {
  background: var(--tcr-navy-select);
  color: var(--tcr-white);
  border: 1px solid rgba(255, 255, 255, 0.2);
  padding: 13px 14px;
  min-height: 48px;
  border-radius: 2px;
}

/* ---------- Matrix bento (v4: navy entry cards + white pillar tiles) ---------- */

.matrix-card {
  background: var(--tcr-navy);
  color: var(--tcr-white);
  padding: 44px 36px;
  border-radius: 4px;
  min-height: 220px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 20px;
  text-decoration: none;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.matrix-card:hover { transform: translateY(-4px); box-shadow: 0 20px 44px rgba(0, 31, 63, 0.22); }
.matrix-card h3 { color: var(--tcr-white); font-size: clamp(24px, 2.6vw, 30px); margin-block-start: 14px; }
.matrix-card .count { font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--tcr-accent-light); font-weight: 600; }
.matrix-card .desc { color: var(--tcr-white-90); margin-block-start: 12px; font-size: 16px; }
.matrix-card .arrow { color: var(--tcr-accent-light); font-weight: 600; }

.tile {
  background: var(--tcr-white);
  transition: box-shadow 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
}
.tile:hover { box-shadow: 0 14px 34px rgba(0, 31, 63, 0.10); transform: translateY(-3px); border-color: var(--tcr-accent-light); }
.tile .tile__no { font-size: 12.5px; color: var(--tcr-accent-light); font-weight: 700; }
.tile h3 { font-size: 19px; }
.tile p { font-size: 14px; color: var(--tcr-muted); }
.tile a { color: var(--tcr-accent-light); font-weight: 600; font-size: 13.5px; text-decoration: none; }

.bento { grid-template-columns: 1fr; }
@media (min-width: 48em) {
  .bento { grid-template-columns: 1fr 1fr; }
  .bento > .matrix-card, .bento > .tile, .bento > .tile--wide { grid-column: span 1; }
  .bento > .tile--wide { grid-column: 1 / -1; }
}
@media (min-width: 64em) {
  .bento { grid-template-columns: repeat(6, 1fr); gap: 18px; }
  .bento > .matrix-card { grid-column: span 3; }
  .bento > .tile { grid-column: span 2; }
  .bento > .tile--wide { grid-column: 1 / -1; }
}

/* ---------- Stat band (v4 chips on navy) ---------- */

.stat-band { background: var(--tcr-navy); }
.stat-band .stat__value { color: var(--tcr-accent-light); font-family: var(--font-data); font-size: clamp(26px, 3vw, 36px); letter-spacing: -0.02em; }
.stat-band .stat__label { color: var(--tcr-white-65); font-size: 12.5px; letter-spacing: 0.1em; text-transform: uppercase; }

/* ---------- Video band (v4) ---------- */

.video-band { background: var(--tcr-navy); color: var(--tcr-white); text-align: center; }
.video-band h2 { color: var(--tcr-white); }
.video-band .answer-first { color: var(--tcr-white-90); margin-inline: auto; text-align: center; border-inline-start: 0; padding-inline-start: 0; }
.video-band .video-facade,
.video-band .video-frame { margin: 38px auto 0; max-width: 840px; }
.video-facade {
  border-radius: 6px;
  background: radial-gradient(circle at 50% 42%, #123A63 0%, #04223F 70%);
  border: 1px solid rgba(255, 255, 255, 0.12);
}
.video-facade .play { width: 72px; height: 72px; transition: transform 0.2s ease; }
.video-facade:hover .play { transform: scale(1.08); }
.video-facade .play::before { border-color: transparent transparent transparent var(--tcr-white); }

/* ---------- Insight cards (v4) ---------- */

.insight-card { padding: 24px; transition: box-shadow 0.2s ease, transform 0.2s ease; }
.insight-card:hover { box-shadow: 0 14px 34px rgba(0, 31, 63, 0.10); transform: translateY(-3px); }
.insight-card .insight__meta { font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--tcr-primary); font-weight: 600; }
.insight-card .insight__meta .type { color: var(--tcr-accent-light); }
.insight-card h3 { font-size: 18.5px; margin-block-start: 14px; line-height: 1.3; }
.insight-card h3 a { color: var(--tcr-navy); text-decoration: none; }
.insight-card h3 a:hover { color: var(--tcr-accent-light); }
.head-row { display: flex; justify-content: space-between; align-items: flex-end; flex-wrap: wrap; gap: 12px; }
.head-row .all-link { color: var(--tcr-accent-light); font-weight: 600; text-decoration: none; }

/* ---------- Newsroom band (v4) ---------- */

.newsroom-band { background: var(--tcr-cream-warm); }
.news-card { background: var(--tcr-white); border: 1px solid var(--tcr-hairline); border-left: 3px solid var(--tcr-primary); padding: 24px; display: block; text-decoration: none; color: inherit; }
.news-card .outlet { font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--tcr-primary); font-weight: 700; }
.news-card .date { font-size: 12.5px; color: var(--tcr-muted); margin-block-start: 4px; }
.news-card h3 { font-size: 17.5px; margin-block-start: 12px; line-height: 1.35; }
.news-card .link { margin-block-start: 14px; display: inline-block; color: var(--tcr-accent-light); font-weight: 600; font-size: 14px; }

/* ---------- Approvals moat (v4: cert cards on deep navy) ---------- */

.moat { background: var(--tcr-navy-deep); color: var(--tcr-white); }
.moat h2 { color: var(--tcr-white); }
.moat .answer-first { color: var(--tcr-white-90); }
.cert-card { background: var(--tcr-navy-card); border: 1px solid rgba(255, 255, 255, 0.14); border-radius: 3px; padding: 24px; display: flex; flex-direction: column; text-decoration: none; color: inherit; }
.cert-card .issuer { font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--tcr-accent-light); font-weight: 700; }
.cert-card .refno { font-family: var(--font-data); font-size: 19px; color: var(--tcr-white); margin-block-start: 10px; font-weight: 700; overflow-wrap: anywhere; }
.cert-card .scope { font-size: 14px; color: var(--tcr-white-65); margin-block-start: 10px; flex: 1; }
.cert-card .validity { font-size: 12.5px; color: var(--tcr-muted-light); margin-block-start: 14px; }
.moat .moat-cta { color: var(--tcr-accent-light); font-weight: 600; text-decoration: none; }

/* ---------- Client strip (typography only, v4) ---------- */

.clients { text-align: center; }
.clients .names { display: flex; flex-wrap: wrap; justify-content: center; gap: 14px 36px; font-size: clamp(16px, 2vw, 19px); font-weight: 600; color: #5B6470; list-style: none; }
.clients .note { margin-block-start: 22px; font-size: 12.5px; color: var(--tcr-muted-light); margin-inline: auto; }

/* ---------- Testimonial / quote band (v4) ---------- */

.quote-band { background: var(--tcr-cream-warm); }
.quote-band blockquote { border-inline-start: 4px solid var(--tcr-accent-light); padding-inline-start: 24px; font-size: clamp(19px, 2.4vw, 24px); font-weight: 500; color: var(--tcr-navy); line-height: 1.4; }
.quote-band cite { margin-block-start: 22px; font-size: 15px; }

/* ---------- FAQ (v4: plus / minus marker) ---------- */

.faq details { padding-block: 0; }
.faq summary { list-style: none; padding: 22px 44px 22px 0; font-size: 18px; color: var(--tcr-navy); position: relative; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; position: absolute; right: 8px; top: 18px; font-size: 26px; color: var(--tcr-accent-light); font-weight: 400; line-height: 1; }
.faq details[open] summary::after { content: "\2013"; }
.faq details p { padding-block-end: 24px; margin-block-start: 0; max-width: 78ch; }

/* ---------- Careers strip (v4) ---------- */

.careers-strip { border-block: 1px solid var(--tcr-hairline); padding-block: 52px; }
.careers-strip .wrap { display: flex; justify-content: space-between; align-items: center; gap: 20px; flex-wrap: wrap; }
.careers-strip p { font-size: clamp(17px, 2vw, 19px); color: var(--tcr-navy); font-weight: 500; max-width: 60ch; }

/* ---------- Footer (v4: #00152C, four columns, entity row, bottom bar) ---------- */

.site-footer { background: var(--tcr-navy-footer); color: var(--tcr-white-65); font-size: 14.5px; padding-block: 64px 0; }
.site-footer a { color: var(--tcr-white-65); text-decoration: none; }
.site-footer a:hover { color: var(--tcr-white); }
.footer-cols { grid-template-columns: 1fr; gap: 32px; margin-block: 0 0; }
@media (min-width: 48em) { .footer-cols { grid-template-columns: 1fr 1fr; } }
@media (min-width: 64em) { .footer-cols { grid-template-columns: 1.4fr 1fr 1fr 1fr; } }
.footer-cols h2 { color: var(--tcr-white); font-size: 13px; letter-spacing: 0.1em; text-transform: uppercase; margin-block-end: 16px; font-weight: 600; }
.footer-cols ul { gap: 10px; font-size: 14.5px; }
.site-footer .flogo { height: 32px; width: auto; margin-block-end: 18px; }
.site-footer .about { max-width: 34ch; font-size: 14px; line-height: 1.7; }
.site-footer .entity-row { margin-block-start: 44px; border-top: 1px solid rgba(255, 255, 255, 0.1); padding-block-start: 22px; display: flex; flex-wrap: wrap; gap: 10px 20px; font-size: 13px; }
.site-footer .entity-row .ext::after { content: " \2197"; color: var(--tcr-accent-light); }
.site-footer .bottom { margin-block-start: 22px; border-top: 1px solid rgba(255, 255, 255, 0.1); padding: 20px 0 30px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px; font-size: 12.5px; }
.site-footer .tagline { font-weight: 600; color: var(--tcr-white-90); font-size: inherit; }
.site-footer .tagline .initial { color: var(--tcr-accent-light); font-weight: 700; }
.site-footer .credline { color: var(--tcr-muted-light); font-size: 12.5px; margin-block-start: 22px; }

/* ---------- Reduced motion for the v4 layers ---------- */

@media (prefers-reduced-motion: reduce) {
  .hero--v4 .scan { display: none; }
  .hero--v4 h1 .w { opacity: 1; transform: none; animation: none; }
  .hero--v4 .wave path { stroke-dashoffset: 0; animation: none; }
}

/* ============================================================================
   CORRECTION PASS (2026-07-12, Rohit's review of the v4 batch). Additive.
   ========================================================================= */

/* Full-width running text. Rohit's ruling (2026-07-12, extended same day):
   ALL paragraphs and ALL list items on tcreng.com run across the full page
   width. No character-measure cap anywhere in page content. This overrides
   the 68ch cap in the frozen base rules above. */
main p, main li { max-width: none; }
.answer-first { max-width: none; margin-block-end: var(--space-m); }
.faq details p { max-width: none; }
.site-footer .credline { max-width: none; }
.answer-band .answer-first { max-width: none; }

/* Breathing room after section headings and head rows (one line of space). */
.sec-h2 { margin-block-end: var(--space-m); }
.head-row { margin-block-end: var(--space-m); }
h2 + .grid, h2 + .bento, h2 + .table-wrap { margin-block-start: var(--space-m); }

/* Client-impact cards: compact (Rohit: the boxes were too big). */
.impact-card { padding: 20px 18px; }
.impact-card .impact__value { font-size: clamp(20px, 2.2vw, 28px); }
.impact-card p { font-size: 14px; }
.impact-card .eyebrow { margin: 10px 0 6px; }

/* Photo heroes: the copy overlay was too narrow and taller than the image.
   The image now fills the hero cell; the copy gets a wider measure. */
@media (min-width: 64em) {
  .hero { min-height: 34rem; }
  .hero > picture { height: 100%; }
  .hero__media { height: 100%; aspect-ratio: auto; }
  .hero__copy { max-width: min(64ch, 62%); }
}

/* v4 hero with a photographic ground (T1 Home): image behind the copy,
   navy shade for legibility, no blueprint grid over a photograph. */
.hero--photo::before { content: none; }
.hero--photo .hero-bg { position: absolute; inset: 0; }
.hero--photo .hero-bg picture, .hero--photo .hero-bg img { width: 100%; height: 100%; }
.hero--photo .hero-bg img { object-fit: cover; }
.hero--photo .shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(0, 26, 53, 0.95) 0%, rgba(0, 31, 63, 0.85) 42%, rgba(0, 31, 63, 0.55) 100%);
}

/* Utility bar: Investors and Client Login (v4 wireframe, pages now exist). */
.utility .investors { color: var(--tcr-accent-light); font-weight: 600; }
.utility .login { color: var(--tcr-white); font-weight: 600; border: 1px solid rgba(255, 255, 255, 0.3); padding: 3px 10px; border-radius: 2px; }
.utility .login:hover { border-color: var(--tcr-accent-light); color: var(--tcr-accent-light); }

/* Footer social icons (v4 wireframe; URLs from facts.json contact.social). */
.site-footer .social { margin-block-start: 24px; display: flex; gap: 12px; }
.site-footer .social a {
  width: 40px;
  height: 40px;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 2px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.2s ease;
}
.site-footer .social a:hover { border-color: var(--tcr-accent-light); }
.site-footer .social svg { width: 18px; height: 18px; fill: none; stroke: var(--tcr-white); stroke-width: 1.5; }

/* Form fields on the RFQ form (T8 Contact), styled like the finder selects. */
.finder .input {
  width: 100%;
  padding: 13px 14px;
  min-height: 48px;
  border: 1px solid var(--tcr-hairline);
  background: var(--tcr-white);
  color: var(--tcr-ink);
  border-radius: 2px;
}
.finder-band .finder .input {
  background: var(--tcr-navy-select);
  color: var(--tcr-white);
  border-color: rgba(255, 255, 255, 0.2);
}
.finder textarea.input { min-height: 220px; }  /* 2026-07-31 (Rohit): was 96px. The scope description is now the form's main field, since industry, service and standard were removed. */

/* A-Z service index */
.az-group { border-top: 1px solid var(--tcr-hairline); padding-block: var(--space-m); }
.az-group h2 { font-family: var(--font-data); color: var(--tcr-accent-light); font-size: var(--step-2); margin-block: 0 var(--space-s); }
.az-group ul { list-style: none; display: grid; gap: var(--space-2xs) var(--space-m); grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); }

/* ==================================================================
   FIX PASS (2026-07-12, Rohit's deep-check rulings). Additive.
   ================================================================== */

/* 1. Tablet-band hero clamp (Rohit's ruling on the deep-check flag).
   Below 48em the stacked hero keeps the 4:5 phone crop at full width, which
   at 500-767px runs to ~960px tall and pushes the H1 a full viewport down.
   Clamp the media height in the stacked layout; object-fit: cover (already
   on .hero__media) crops gracefully. Released again at 48em where the 21:9
   crop takes over. The 4:5 master crop itself is unchanged. */
.hero__media { max-height: min(65vh, 30rem); }
@media (min-width: 48em) {
  .hero__media { max-height: none; }
}

/* 2. Stat rows: neutralise the global `p + p` prose-rhythm margin inside
   flex/grid stat components. In flow it is invisible; in a flex or grid row
   margins do not collapse, so every stat except the first rode 16px lower
   (the "53" chip on the home hero, and the first .stat on every stat-band).
   Class-wide fix, both components. Verified by live injection: all tops
   equalise. Row spacing when the row wraps is carried by the gap, not the
   margin, so nothing else moves. */
.hero--v4 .stats .stat-chip,
.stat-band .stat { margin-block-start: 0; }


/* ============================================================================
   CORRECTION PASS 2 (2026-07-13, Rohit's design review). Additive.
   The 2026-07-12 full-width rule covered main p / main li only; class-scoped
   measures kept capping text (.tcre-editorial 64ch on every blog post,
   .section-lede 68ch, .quote-band blockquote 60ch, dd/figcaption uncovered).
   Rule: no character-measure cap on any running content, anywhere.
   ========================================================================= */
main :is(p, li, dd, dt, figcaption, blockquote),
.tcre-editorial p,
.tcre-editorial li,
.section-lede,
.quote-band blockquote { max-width: none; }


/* ============================================================================
   MEGA MENU (2026-07-13, Rohit's design review). Additive. Desktop-only
   dropdown panels under Industries and Services; the drawer serves narrow
   viewports. Opens on hover and :focus-within (keyboard), plus [data-open]
   set by site.js for coarse pointers. Escape closes (site.js).
   ========================================================================= */
.site-nav .has-mega { position: static; }
.site-nav .has-mega > a { display: inline-flex; align-items: center; gap: 6px; }
.site-nav .chev { width: 7px; height: 7px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg) translateY(-1px); transition: transform 160ms ease-out; }
.site-nav .has-mega:hover .chev, .site-nav .has-mega:focus-within .chev { transform: rotate(225deg) translateY(-1px); }
.site-nav .mega {
  position: absolute; left: 0; right: 0; top: 100%;
  background: var(--tcr-dark);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  border-bottom: 2px solid var(--tcr-accent-dark);
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.35);
  opacity: 0; visibility: hidden; transform: translateY(8px); pointer-events: none;
  transition: opacity 160ms ease-out, transform 160ms ease-out, visibility 0s linear 160ms;
  z-index: 60;
}
.site-nav .has-mega:hover .mega,
.site-nav .has-mega:focus-within .mega,
.site-nav .has-mega[data-open="true"] .mega {
  opacity: 1; visibility: visible; transform: none; pointer-events: auto; transition-delay: 0s;
}
.mega-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr)); gap: 8px 28px; padding-block: 26px 20px; }
.mega-h { font-size: 12px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--tcr-accent-light); margin-block-end: 8px; }
.mega-h a { color: inherit; font: inherit; letter-spacing: inherit; }
.site-nav .mega a { display: block; padding: 5px 0; font-size: 14.5px; font-weight: 400; color: var(--tcr-cream); text-decoration: none; }
.site-nav .mega .mega-h a { display: inline; padding: 0; font-weight: 600; font-size: inherit; color: var(--tcr-accent-light); }
.site-nav .mega a:hover { color: var(--tcr-accent-light); text-decoration: none; }
.site-nav .mega a:not(.cta):hover::after { content: none; }
.mega-foot { grid-column: 1 / -1; border-top: 1px solid rgba(255, 255, 255, 0.08); padding-block-start: 12px; margin-block-start: 8px; }
.site-nav .mega .mega-foot a { display: inline-block; font-weight: 600; color: var(--tcr-accent-light); margin-inline-end: 28px; }
@media (prefers-reduced-motion: reduce) {
  .site-nav .mega, .site-nav .chev { transition: none; }
  .site-nav .mega { transform: none; }
}

/* Drawer accordions (mobile grouped nav, same pass). */
.drawer li > details { border-block-end: 1px solid rgba(255, 255, 255, 0.12); }
.drawer summary { cursor: pointer; padding: 12px 0; font-size: 18px; font-weight: 600; color: var(--tcr-white, #fff); list-style: none; display: flex; align-items: center; justify-content: space-between; }
.drawer summary::-webkit-details-marker { display: none; }
.drawer summary::after { content: "+"; font-weight: 400; font-size: 20px; color: var(--tcr-accent-light); }
.drawer details[open] summary::after { content: "\2212"; }
.drawer details a { display: block; padding: 7px 0 7px 14px; font-size: 15.5px; color: var(--tcr-cream); text-decoration: none; }
.drawer details a:hover { color: var(--tcr-accent-light); }


/* ============================================================================
   HOME WOW PASS (2026-07-13). Additive. Home opening screen: campaign hero
   (staggered line reveal, credential chip row, proof ribbon) and the services
   bento mosaic (gold keyline cards, one 2x2 feature cell). All entrance
   motion sits inside (prefers-reduced-motion: no-preference) and animates
   with fill-mode: both from the keyframe, so every element is fully visible
   by default: with JS off, with animations disabled, and under reduced
   motion. The full reveal completes within 0.8 s. No new image requests.
   ========================================================================= */

/* Hero campaign type stack */
.hero--v4 h1 .hl { display: block; }
.hero--v4 h1 .hl--accent { color: var(--tcr-accent-light); }
.hero--v4 .sub--range { margin-block-start: 14px; font-size: 15px; font-weight: 400; color: var(--tcr-white-65); }

/* Credential chip row (facts.json credentials block). Keeps NADCAP AC7101
   on the opening screen; the 2026 chip carries the accent. */
.cred-chips { list-style: none; margin: 18px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px 10px; }
.cred-chips li {
  font-family: var(--font-data);
  font-size: 12.5px;
  letter-spacing: 0.02em;
  color: var(--tcr-white-90);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 999px;
  padding: 5px 13px;
  background: rgba(255, 255, 255, 0.04);
}
.cred-chips .chip--hot { border-color: var(--tcr-accent-light); color: var(--tcr-accent-light); font-weight: 600; }

/* Proof ribbon: the four hero counters as a thin, hairline-bounded strip.
   Count-up is the existing [data-count] behaviour in site.js; markup and
   final values stay server-rendered and unchanged. */
.hero--v4 .proof-ribbon { margin-block-start: 38px; border-block: 1px solid rgba(255, 255, 255, 0.14); padding-block: 16px; gap: 12px 36px; }
@media (min-width: 48em) { .hero--v4 .proof-ribbon { gap: 12px 54px; } }
.hero--v4 .proof-ribbon .stat-chip { display: flex; align-items: baseline; gap: 10px; }
.hero--v4 .proof-ribbon .num { font-size: clamp(22px, 2.4vw, 30px); }
.hero--v4 .proof-ribbon .lab { margin-block-start: 0; }

/* Hero entrance: pure CSS, staggered by --l (60 ms steps, 0.4 s each; the
   last element lands at 0.76 s). Scoped to the home photo hero. fill-mode
   "both" means the hidden state exists only while the animation runs; with
   animations disabled the static state is fully visible. */
@media (prefers-reduced-motion: no-preference) {
  .hero--v4.hero--photo .hero-inner > .eyebrow,
  .hero--v4.hero--photo h1 .hl,
  .hero--v4.hero--photo .hero-inner > .sub,
  .hero--v4.hero--photo .cred-chips,
  .hero--v4.hero--photo .hero-inner > .cta-row {
    animation: wow-rise 0.4s cubic-bezier(0.2, 0.6, 0.2, 1) both;
    animation-delay: calc(var(--l, 0) * 60ms);
  }
  @keyframes wow-rise {
    from { opacity: 0; transform: translateY(18px); }
  }
}

/* Services bento mosaic: gold keyline cards; Materials Testing is the 2x2
   feature cell. Scoped to .bento--services (home page only). The cursor
   spotlight is the existing .tile[data-spotlight] behaviour, hover-only. */
.bento--services > .tile {
  border: 1px solid transparent;
  border-radius: 4px;
  background:
    linear-gradient(var(--tcr-white), var(--tcr-white)) padding-box,
    linear-gradient(135deg, var(--tcr-accent-light), var(--tcr-hairline) 55%) border-box;
}
.bento--services > .tile--feature {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 16px;
  background:
    linear-gradient(160deg, var(--tcr-navy) 0%, var(--tcr-navy-select) 100%) padding-box,
    linear-gradient(135deg, var(--tcr-accent-light), rgba(255, 140, 0, 0.25) 60%) border-box;
}
.bento--services > .tile--feature h3 { color: var(--tcr-white); font-size: clamp(24px, 2.4vw, 30px); }
.bento--services > .tile--feature p { color: var(--tcr-white-90); font-size: 16px; }
.bento--services > .tile--feature .tile__no { color: var(--tcr-accent-light); }
.bento--services > .tile--feature a { color: var(--tcr-accent-light); font-size: 15px; }
@media (min-width: 48em) {
  /* 2026-07-17: converted from a 48-64em range query (build rule: min-width only) */
  .bento--services > .tile--feature { grid-column: 1 / -1; }
  .bento--services > .tile:last-of-type { grid-column: 1 / -1; }
}
@media (min-width: 64em) {
  .bento--services > .tile--feature { grid-column: span 4; grid-row: span 2; }
  .bento--services > .tile:last-of-type { grid-column: auto; }
}

/* Blog post figures (2026-07-13, image-display pass). Additive. */
.tcre-editorial .post-figure { margin-block: var(--space-l); }
.tcre-editorial .post-figure img { width: auto; max-width: 100%; height: auto; }
.tcre-editorial .post-figure--featured { margin-block: var(--space-m) var(--space-l); }
.tcre-editorial .post-figure figcaption { font-size: var(--step-0); color: var(--tcr-muted); margin-block-start: var(--space-xs); }

/* ===== INSIGHT CARD THUMBNAILS (2026-07-14, additive) ===== */
.insight-card__thumb { display: block; aspect-ratio: 16 / 9; overflow: hidden; background: var(--tcr-navy); }
.insight-card__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ===== INSIGHTS FACET PANEL (2026-07-14, additive; JS-ruling amendment of 2026-07-14) ===== */
.facet-panel { border: 1px solid var(--tcr-hairline); background: var(--tcr-white); padding: var(--space-m); margin-block-end: var(--space-m); display: grid; gap: var(--space-s); grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); }
.facet-panel fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
.facet-panel legend { font-weight: 600; font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.06em; margin-block-end: 0.5rem; }
.facet-panel label { display: flex; align-items: baseline; gap: 0.45rem; font-size: var(--step--1); padding-block: 0.12rem; }
.facet-panel .fct-n { color: var(--tcr-muted); font-size: 0.85em; margin-inline-start: auto; }
.facet-panel .facet-row { grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between; gap: var(--space-s); margin: 0; border-block-start: 1px solid var(--tcr-hairline); padding-block-start: var(--space-2xs); }
.facet-panel #facet-clear { background: none; border: 1px solid var(--tcr-hairline); padding: 0.3rem 0.8rem; cursor: pointer; font: inherit; font-size: var(--step--1); }
.facet-panel #facet-clear:hover { border-color: var(--tcr-navy); }

/* ===== KEY TAKEAWAYS BOX (2026-07-14, additive) ===== */
.key-takeaways .wrap { border: 1px solid var(--tcr-hairline); border-inline-start: 4px solid var(--tcr-accent, #E8C833); background: var(--tcr-white); padding: var(--space-m); }
.key-takeaways h2 { margin-block-start: 0; }
.key-takeaways ul { margin-block-end: 0; }
.key-takeaways li { margin-block-end: 0.4rem; }

/* ===== GUIDE CTA (top-guide posts, 2026-07-14, additive) ===== */
.guide-cta { border: 1px solid var(--tcr-hairline); border-inline-start: 4px solid var(--tcr-accent, #E8C833); background: var(--tcr-white); padding: var(--space-m); margin-block-start: var(--space-m); }
.guide-cta p:last-child { margin-block-end: 0; }

/* ===== INSIGHTS PAGINATION (2026-07-15, additive) ===== */
.pagination { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--space-s); margin-block-start: var(--space-l); padding-block-start: var(--space-m); border-block-start: 1px solid var(--tcr-hairline); }
.pagination__pages { display: flex; flex-wrap: wrap; gap: var(--space-2xs); }
.pagination__page { display: inline-flex; align-items: center; justify-content: center; min-width: 2.25rem; min-height: 2.25rem; padding-inline: 0.4rem; border: 1px solid var(--tcr-hairline); color: var(--tcr-navy); text-decoration: none; font-size: var(--step--1); }
.pagination__page:hover { border-color: var(--tcr-navy); background: var(--tcr-accent-20); }
.pagination__page--current { background: var(--tcr-navy); color: var(--tcr-white); border-color: var(--tcr-navy); font-weight: 600; }
.pagination__prev, .pagination__next { font-size: var(--step--1); color: var(--tcr-navy); text-decoration: none; white-space: nowrap; }
.pagination__prev:hover, .pagination__next:hover { text-decoration: underline; }
.pagination__prev--disabled, .pagination__next--disabled { color: var(--tcr-muted); }


/* ============================================================================
   MEGA MENU HOVER-GAP FIX (2026-07-15, additive). Bug: mouse enters "Industries"
   or "Services", then moving down toward a submenu item makes the panel vanish
   before the click lands.

   Root cause: .site-header .wrap uses align-items:center (line ~150), so the
   <nav>/<ul>/<li class="has-mega"> chain is only as tall as its own text
   content and sits vertically centred inside the 72px header row, not
   stretched to fill it. .mega is position:absolute against .site-header
   (top:100%, the only positioned ancestor in the chain — .has-mega itself is
   position:static), so .mega's top edge sits at the header's true bottom
   edge, roughly 20px below where .has-mega's actual hoverable box ends. That
   20px is a dead zone: moving the pointer from the trigger link down into
   the panel crosses it, :hover/:focus-within stops matching .has-mega before
   the pointer reaches .mega, .mega's pointer-events snaps to none instantly
   (it is not in the transition list), and the panel is still visibly fading
   out for 160ms while already unclickable. That is the "menu disappears"
   symptom.

   Fix: stretch .site-nav and the <li> chain to the full row height at the
   same 64em breakpoint where the desktop nav becomes visible, so
   .has-mega's hoverable box touches .mega with zero gap. .has-mega > a keeps
   its own inline-flex centring, so the visible link position is unchanged;
   only the invisible hit-testing box grows to fill the row.
   ========================================================================= */
@media (min-width: 64em) {
  .site-header .wrap { align-items: stretch; }
  .site-header .wrap > a { display: flex; align-items: center; }
  .site-nav { display: flex; align-items: stretch; }
  .site-nav ul { align-items: stretch; }
  .site-nav li { display: flex; align-items: stretch; }
  .site-nav .has-mega { align-self: stretch; }
  .site-nav .has-mega > a { height: 100%; }
}

/* ============================================================================
   MEGA MENU: nav-item height parity + residual hover-gap bridge (2026-07-16,
   additive). Two defects reported after the 2026-07-15 fix above went live.

   Defect 1: Industries/Services/Who We Are text sits visibly lower than
   Insights/Newsroom/Careers/Downloads. Cause: the 07-15 fix set
   .has-mega > a { height: 100% } and .has-mega > a already had
   display:inline-flex; align-items:center (line ~1136), so its text centres
   in the full 56px stretched row. Plain .site-nav a is display:block with
   padding:6px 0 (line ~678) and never received the same treatment, so its
   text still sits near the top of its own (also-stretched) 56px box instead
   of centred. Result: two different vertical text positions on one row.

   Fix: give every desktop nav link display:flex; align-items:center, not
   just .has-mega's. .site-nav .has-mega > a (line 1136) is a more specific
   selector (two classes vs one class + child combinator) and still wins for
   the three mega items, so this only changes the plain items and the
   Request a Quote button to match.

   Defect 2: clicking into a mega panel (reported on Who We Are) still loses
   the panel. Measured live (2026-07-16): even with the has-mega row stretched
   to the header's content-box height, the row's own bottom edge sits at
   .site-header's padding-bottom (8px) short of the header's true bottom,
   and .mega opens flush with the header's true bottom. That leaves an
   ~8px strip, directly below each has-mega trigger, that belongs to
   neither the trigger's box nor the (visibility:hidden-while-closed, so
   not hoverable) panel. The pointer crosses it in transit, :hover on
   .has-mega goes false for that instant, and .mega's pointer-events snaps
   to none immediately (not in its transition list) while it is still
   visibly fading out. Confirmed identical (16px .mega-to-li gap) on all
   three has-mega items, not unique to Who We Are.

   Fix: an invisible ::before bridge anchored to .has-mega > a (not to
   .has-mega itself, which would become .mega's positioning ancestor and
   collapse the panel to the trigger's own width). position:relative is
   set on the <a>, not the <li>, for that reason. ::before (not ::after,
   which .site-nav a:not(.cta):hover::after already uses for the underline)
   spans the trigger's own width, sits immediately below it, and is a
   genuine descendant of .has-mega, so it keeps :hover/:focus-within
   continuous across the dead zone. 14px covers the measured ~8px gap with
   margin; it carries no visible content and .mega's z-index:60 keeps the
   open panel clickable above it once the pointer arrives.
   ========================================================================= */
@media (min-width: 64em) {
  .site-nav li > a { display: flex; align-items: center; }
  .site-nav .has-mega > a { position: relative; }
  .site-nav .has-mega > a::before {
    content: "";
    position: absolute;
    left: 0; right: 0; top: 100%;
    height: 14px;
  }
}

/* ============================================================================
   GROUP COMPANY PAGES (added 2026-07-16, Rohit's instruction: dedicated pages
   for TCR Advanced, TCR Arabia and Evolve by TCR, each with a prominent link
   to the entity's own website, plus the About-page group grid).
   Mobile-first; min-width queries only; no fixed container widths.
   ========================================================================= */

/* The portal band: a full-bleed panel carrying one very large outbound link */
.portal-band {
  background: linear-gradient(135deg, var(--tcr-navy, #001F3F) 0%, #00172F 100%);
  color: #fff;
  padding: clamp(2.5rem, 7vw, 5rem) 0;
  position: relative;
  overflow: hidden;
}
.portal-band::before {
  content: '';
  position: absolute; inset: 0;
  background:
    radial-gradient(60rem 30rem at 110% -20%, rgba(232, 200, 51, 0.10), transparent 60%),
    radial-gradient(40rem 22rem at -10% 120%, rgba(232, 200, 51, 0.06), transparent 60%);
  pointer-events: none;
}
.portal-band .wrap { position: relative; }
.portal-band .portal-kicker {
  font-size: 0.78rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--tcr-accent-dark, #E8C833); margin: 0 0 0.75rem;
}
.portal-band .portal-name {
  font-size: clamp(2rem, 6vw, 3.75rem);
  font-weight: 800; line-height: 1.05; letter-spacing: -0.02em;
  margin: 0 0 1rem; color: #fff;
}
.portal-band .portal-desc { max-width: none; margin: 0 0 1.75rem; color: rgba(255,255,255,0.85); }
.portal-link {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  border: 1px solid rgba(232, 200, 51, 0.55);
  border-radius: 6px;
  padding: clamp(1.1rem, 3vw, 1.75rem) clamp(1.25rem, 4vw, 2.25rem);
  text-decoration: none;
  background: rgba(255,255,255,0.03);
  transition: background 160ms ease, border-color 160ms ease, transform 160ms ease;
}
.portal-link:hover, .portal-link:focus-visible {
  background: rgba(232, 200, 51, 0.10);
  border-color: var(--tcr-accent-dark, #E8C833);
  transform: translateY(-2px);
}
.portal-link .portal-url {
  font-family: var(--font-data, "JetBrains Mono", monospace);
  font-size: clamp(1.05rem, 3.5vw, 1.75rem);
  font-weight: 600; color: #fff; word-break: break-all;
}
.portal-link .portal-action {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 0.5rem;
  color: var(--tcr-accent-dark, #E8C833); font-weight: 700; white-space: nowrap;
}
.portal-link .portal-action .arrow { transition: transform 160ms ease; display: inline-block; }
.portal-link:hover .portal-action .arrow { transform: translateX(6px); }
@media (prefers-reduced-motion: reduce) {
  .portal-link, .portal-link .portal-action .arrow { transition: none; }
  .portal-link:hover { transform: none; }
  .portal-link:hover .portal-action .arrow { transform: none; }
}

/* About-page group grid: one card per operating entity */
.group-grid {
  display: grid; gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
  margin-top: 1.5rem;
}
.group-card {
  display: flex; flex-direction: column;
  border: 1px solid var(--tcr-hairline, #E0E0E0);
  border-top: 3px solid var(--tcr-accent-light, #FF8C00);
  border-radius: 6px;
  padding: 1.5rem;
  background: #fff;
}
.group-card .gc-entity { font-size: 1.25rem; font-weight: 800; margin: 0 0 0.25rem; color: var(--tcr-navy, #001F3F); }
.group-card .gc-role {
  font-size: 0.78rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--tcr-muted, #5A6672); margin: 0 0 0.75rem;
}
.group-card p { margin: 0 0 1rem; }
.group-card .gc-links { margin-top: auto; display: flex; flex-wrap: wrap; gap: 0.75rem 1.25rem; }
.group-card .gc-links a { font-weight: 700; text-decoration: none; }
.group-card .gc-links a:hover { text-decoration: underline; }
.group-card .gc-links .gc-ext { color: var(--tcr-muted, #5A6672); }

/* Entity masthead: logo + semantic address cards on the group-company pages
   (added 2026-07-16, Rohit's instruction: entity logos from the brand skills
   plus complete postal addresses from the contact page). */
.entity-masthead .entity-logo {
  height: clamp(44px, 6vw, 64px);
  width: auto;
  display: block;
  margin-bottom: 1.25rem;
}
.office-grid {
  display: grid; gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  margin-top: 1rem;
}
.office-grid address {
  font-style: normal;
  border: 1px solid var(--tcr-hairline, #D4D2CC);
  border-radius: 6px;
  padding: 1.25rem 1.5rem;
  line-height: 1.75;
  background: #fff;
}
.office-grid address strong { color: var(--tcr-navy, #001F3F); display: inline-block; margin-bottom: 0.25rem; }

/* ---------- CTA trust signal (Phase 2, 2026-07-17, facts.json-sourced) ---------- */
.cta-band .cta-trust { margin-block-start: 0.875rem; font-size: var(--step--1); color: var(--tcr-white-65); }

/* ---------- Downloads document grid (Phase 4, 2026-07-17) ---------- */
.doc-filter { margin-block: var(--space-s) var(--space-m); }
.doc-filter__count { font-size: var(--step--1); color: var(--tcr-muted); margin-block-start: 0.375rem; }
.doc-grid { list-style: none; padding: 0; display: grid; gap: var(--space-s); grid-template-columns: repeat(auto-fill, minmax(min(100%, 21rem), 1fr)); margin-block: var(--space-s) var(--space-l); }
.doc-card { display: flex; gap: 0.875rem; align-items: flex-start; background: #fff; border: 1px solid rgba(0, 31, 63, 0.12); padding: 0.875rem; }
.doc-card__thumb img { width: 4.5rem; height: auto; display: block; border: 1px solid rgba(0, 31, 63, 0.15); }
.doc-card__title { margin: 0; font-weight: 600; }
.doc-card__title a { text-decoration: none; }
.doc-card__meta { margin: 0.25rem 0 0; font-size: var(--step--1); color: var(--tcr-muted); }

/* ---------- Comparison slider (Phase 5, 2026-07-17). No-JS: two stacked captioned figures. ---------- */
.compare { margin-block: var(--space-m); }
.compare__item { margin: 0 0 var(--space-s); }
.compare__item img { width: 100%; height: auto; display: block; }
.compare figcaption { font-size: var(--step--1); color: var(--tcr-muted); margin-block-start: 0.25rem; }
.compare.is-active { position: relative; overflow: hidden; --split: 50%; }
.compare.is-active .compare__item { position: absolute; inset: 0; margin: 0; }
.compare.is-active .compare__item img { height: 100%; object-fit: cover; }
.compare.is-active .compare__item--b { clip-path: inset(0 0 0 var(--split)); }
.compare.is-active figcaption { position: absolute; bottom: 0.5rem; margin: 0; padding: 0.125rem 0.5rem; background: rgba(0, 31, 63, 0.82); color: #fff; }
.compare.is-active .compare__item--a figcaption { left: 0.5rem; }
.compare.is-active .compare__item--b figcaption { right: 0.5rem; }
.compare__handle { position: absolute; top: 0; bottom: 0; left: var(--split); width: 2px; background: var(--tcr-accent, #E8C833); pointer-events: none; }
.compare__handle::after { content: "\2194"; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: var(--tcr-accent, #E8C833); color: var(--tcr-navy, #001F3F); width: 1.75rem; height: 1.75rem; border-radius: 50%; display: grid; place-items: center; font-size: 0.9rem; }
.compare__range { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: ew-resize; margin: 0; }

/* ---------- Accreditation marks strip (2026-07-17). NABL rule: certificate number below the symbol. ---------- */
.accred-marks { display: flex; gap: var(--space-l); align-items: flex-end; flex-wrap: wrap; margin-block: var(--space-s) var(--space-m); }
.accred-mark { margin: 0; }
.accred-mark img { display: block; height: 7.5rem; width: auto; }
.accred-mark figcaption { font-size: var(--step--1); color: var(--tcr-muted); margin-block-start: 0.375rem; font-weight: 600; }
.cred-chips a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }

/* RESTORED 2026-07-19: the entire block below (approved 2026-07-16 over ~11
   review passes with Rohit, deployed to all 314 posts) was lost from this
   file by a later edit pass built on a pre-2026-07-16 copy (the same
   OneDrive torn-write/stale-base failure in LESSONS.md). Source of truth
   for the restoration: the design-session preview copy, byte-identical to
   the approved state. Do not remove; the post hero layout on every
   /post/ page depends on it. */
/* ============================================================================
   Insight post hero: headline image, square, right of the title (2026-07-16,
   Rohit's instruction). PROTOTYPE — applied to one post only pending review
   before the generator (build_insight_pages.py) and the full 314-post rebuild.

   .hero--post is the reset the campaign hero (.hero--v4) never needed: a blog
   headline is prose, not a marketing line, and must not be clipped to the
   17ch campaign measure (.hero--v4 h1 { max-width: 17ch }, appended block
   above). .hero--post-image adds the square figure only when a post actually
   ships a featured_image; a post with none keeps the single-column reset and
   the title runs the full row width, per Rohit's "otherwise" instruction. */
.hero--v4.hero--post .hero-inner { max-width: none; }
.hero--v4.hero--post h1 { max-width: none; }

/* Second correction, 2026-07-16: the campaign hero's top padding
   (clamp(56px, 9vw, 104px), appended block above) was written for a
   marketing hero with stats/CTA rows underneath it, not a byline. Combined
   with a 220-280px square image against a three-line text column, the
   navy block ran far taller than the content needed, leaving open navy
   below the date and the image both. The post hero gets its own, shorter
   top clamp; bottom stays 0 as in the base rule. */
/* Eleventh pass, 2026-07-16 (Rohit): tighter top — the gap above the
   image/title drops from 32-52px to 20-28px — and a deliberate sliver of
   navy below the image (10-16px) instead of the flush bleed, so the image
   reads as framed inside the band. */
.hero--v4.hero--post { padding-block: clamp(20px, 3vw, 28px) clamp(10px, 1.5vw, 16px); }

/* Row layout is the mobile-first default (not a min-width add-on): the image
   sits right of the title at every viewport, including narrow phones, per
   Rohit's first correction 2026-07-16 (the original pass used a 48em row
   breakpoint, which stacked the image below the title on any viewport or
   preview pane narrower than 768px). The thumbnail scales down with
   clamp() instead of dropping to a second row, and is vertically centred
   against the text column, not top-aligned.

   Fifth pass, 2026-07-16 (Rohit: "maximum format, retain the layout"). The
   failed fourth pass proved the constraint: a bigger image plus symmetric
   padding opens navy above AND below the image and the band balloons. The
   fix is to let the image own the band's bottom edge. Hero bottom padding
   is 0 (base rule above), so once the figure is taller than the text
   column it becomes the row's tallest item and its bottom edge lands
   flush on the navy/white boundary — a full bleed. Every added pixel of
   image size now extends the image to that edge instead of opening empty
   navy under the byline, and the title column stays vertically centred
   against it. On phones the width clamp keeps the figure below the text
   height, so narrow viewports keep the compact centred row unchanged. */
.hero--v4.hero--post-image .hero-inner {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: clamp(16px, 4vw, 32px);
}
.hero--v4.hero--post-image .hero-copy {
  flex: 1 1 auto;
  min-width: 0;
  /* Breathing room under the byline when the flush-bottom image governs
     the row height; inert on phones where the text governs. */
  padding-block: clamp(8px, 1.5vw, 20px);
}
/* Seventh pass, 2026-07-16 (Rohit: eyebrow/title/date sit too low — move
   them up level with the image). From 48em up, where the flush-bottom
   image governs the row height, the text column top-aligns with the
   image's top edge instead of centring against its midpoint: centring
   was dropping the text toward the lower half of the band and, on long
   two-line titles, letting the text column outgrow the image and stretch
   the band. Top-aligned, the eyebrow starts level with the image's top
   edge and the whole column reads as one line with it. Phones keep the
   approved centred row (there the image is smaller than the text and
   centring is what looks right). The copy's top padding is zeroed at
   this breakpoint so the eyebrow's cap height truly sits at the image
   edge; bottom padding stays as the text's guard against the boundary. */
@media (min-width: 48em) {
  .hero--v4.hero--post-image .hero-inner { align-items: flex-start; }
  .hero--v4.hero--post-image .hero-copy { padding-block: 0 clamp(8px, 1.5vw, 20px); }
}
/* Tenth pass, 2026-07-16 (Rohit's ruling from the straddle screenshot):
   the featured image renders at its NATURAL aspect ratio — no square
   crop, no object-fit distortion — and sits entirely inside the navy
   band, as part of the headline. This retires the square aspect-ratio
   figure (fifth/sixth pass), the boundary straddle with its negative
   margins, float spacer and paint-order overrides (eighth pass), and
   the absolute-fill fix that patched the square (ninth pass). The
   figure now shrink-wraps the image; the img keeps its intrinsic ratio
   under twin caps (max-width for narrow viewports, max-height so the
   band stays in proportion). The band's bottom edge still lands flush
   on the image's bottom when the image is the tallest item (hero
   padding-bottom stays 0), so no navy opens beneath the image. */
.post-hero-clear { display: none; }  /* retired straddle spacer, inert */
.hero--v4.hero--post-image .hero-figure {
  flex: 0 0 auto;
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.16);
  box-shadow: 0 14px 34px rgba(0, 10, 25, 0.35);
}
.hero--v4.hero--post-image .hero-figure picture { display: block; }
.hero--v4.hero--post-image .hero-figure img {
  display: block;
  width: auto;
  height: auto;
  max-width: min(38vw, 420px);
  max-height: clamp(120px, 24vw, 240px);
}

/* Third correction, 2026-07-16: the generic `section { padding-block:
   var(--space-xl); }` rule (line ~120) gives every <section>, including
   .tcre-editorial (the article body, all 314 posts), up to 96px of top
   AND bottom padding around its content. With the h2 above the <article>
   set to .visually-hidden (zero rendered height), the top half of that
   padding was the entire gap between the hero and the first line of body
   text; the bottom half stacked with .cta-band's own top padding (also
   var(--space-xl)) to leave up to ~192px of dead space after the last
   paragraph before the CTA band. Scoped to .tcre-editorial only (verified:
   this class appears on all 314 post pages and nowhere else in the built
   site), trimmed to a small but present breathing gap on both edges. */
.tcre-editorial { padding-block: var(--space-s) var(--space-m); }

/* why-tcr restructure pass, 2026-07-19 (Rohit's UX brief): alternating canvas
   panels and generic accordions, brand tokens only. Additive; used on
   /why-tcr/ only for now, safe site-wide. */
.band--white { background: var(--tcr-white); }
.accordion { margin-block: var(--space-m); }
.accordion details { border: 1px solid var(--tcr-hairline); background: var(--tcr-cream-warmer); padding: var(--space-xs) var(--space-s); margin-block-start: var(--space-xs); }
.accordion summary { cursor: pointer; font-weight: 600; }
.accordion details > p, .accordion details > ul { margin-block-start: var(--space-xs); }


/* 2026-07-21 (Rohit): home refinements. Additive. */
/* Video facade shows the corporate video poster; click-to-load behaviour unchanged. */
.video-facade__poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.video-facade::after { content: ""; position: absolute; inset: 0; background: rgba(20, 24, 28, 0.45); z-index: 1; }
.video-facade .play, .video-facade > span { position: relative; z-index: 2; }
/* Service pillars: equal visual weight (Materials Testing no longer a 2x2 feature cell). */
.bento--services > .tile:last-of-type { grid-row: auto; }
@media (min-width: 48em) { .bento--services > .tile:last-of-type { grid-column: span 1; } }
@media (min-width: 64em) { .bento--services > .tile:last-of-type { grid-column: span 2; } }


/* 2026-07-21 (Rohit): NACE award — description left, certificate thumbnail right, links to PDF. */
.award { display: flex; flex-wrap: wrap; gap: var(--space-l); align-items: center; }
.award__body { flex: 1 1 22rem; }
.award__body blockquote { margin: 0; }
.award__link { font-weight: 600; }
.award__thumb { flex: 0 0 auto; display: block; width: 100%; max-width: 220px; }
.award__thumb img { width: 100%; height: auto; border: 1px solid var(--tcr-hairline); border-radius: 4px; box-shadow: 0 6px 18px rgba(49, 56, 65, 0.12); }


/* 2026-07-21 (Rohit): press masthead logos on newsroom cards. */
.news-card__logo { display: block; margin-block-end: 14px; }
.news-card__logo, .news-card__logo img { height: 30px; width: auto; }
.news-card__logo img { display: block; }


/* 2026-07-21 (Rohit, standing rule for every page): the orange accent rule is
   an emphasis device, not a paragraph style. It marks ONE passage per section,
   the GEO answer-first passage, and nothing after it. Every subsequent
   .answer-first inside the same container renders as plain prose. Do not add
   a border-inline-start to any new component without checking this rule. */
.answer-first ~ .answer-first {
  border-inline-start: 0;
  padding-inline-start: 0;
}

/* 2026-07-21 (Rohit): related-insights rail footer link, used by the industry
   rails and the per-industry insight index pages. Additive, brand tokens only. */
.rail-more { margin-block-start: var(--space-m); font-weight: 600; }
.rail-more a { margin-inline-end: var(--space-m); }

/* ============================================================================
   2026-07-26 (Rohit). Three additive blocks. Nothing above this line changed.
   ========================================================================= */

/* ---------- 1. Full service mega panel ----------
   The Services panel now carries all 58 child pages, not 4 per pillar. Asset
   Integrity is 17 items and Materials Testing 14, so the panel is taller than
   the four-item version it replaces. Two consequences handled here, both
   scoped to .mega-grid--services so the Industries and Who We Are panels are
   untouched:
   (a) six fixed columns on a wide viewport, one per pillar, so a pillar's
       children never split across a column break and read as two pillars;
   (b) a height ceiling with internal scroll, so the panel can never exceed the
       viewport on a 768px laptop and strand its own footer link. */
.site-nav .mega { max-height: min(80vh, 42rem); overflow-y: auto; overscroll-behavior: contain; }
.mega-grid--services { align-items: start; }
.mega-grid--services .mega-col { min-width: 0; }
.mega-grid--services .mega-h { position: sticky; top: 0; background: var(--tcr-dark); padding-block-end: 6px; z-index: 1; }
@media (min-width: 64em) {
  .mega-grid--services { grid-template-columns: repeat(6, minmax(0, 1fr)); column-gap: 22px; }
}
/* The panel is dense at 58 links; tighten the row rhythm so it stays scannable. */
.site-nav .mega-grid--services a { padding: 4px 0; line-height: 1.35; }

/* ---------- 2. Nested pillar accordions in the mobile drawer ----------
   58 links behind one accordion is a 58-item scroll on a phone. Each pillar now
   gets its own <details> inside the Services accordion. Second level only; the
   markers and indents step in one level from the first. */
.drawer details .drawer-sub { border-block-end: 0; border-block-start: 1px solid rgba(255, 255, 255, 0.08); margin-inline-start: 14px; }
.drawer .drawer-sub > summary { padding: 9px 0; font-size: 15.5px; font-weight: 600; color: var(--tcr-cream); }
.drawer .drawer-sub > summary::after { font-size: 17px; }
.drawer .drawer-sub a { padding-inline-start: 14px; font-size: 15px; }

/* ---------- 3. Prose lists match the prose they belong to ----------
   Rohit, 2026-07-26: "every time there is a bullet point, those are being
   handled with a different font, and that should not be correct."

   Diagnosis, measured. `.answer-first` sets font-size: var(--step-1)
   (1.20rem to 1.50rem fluid). A bare <li> inherits the body at var(--step-0)
   (1.00rem to 1.13rem). On the cleaned industry pages every body paragraph
   carries .answer-first, so every bullet list under one renders about 25 per
   cent smaller than the sentence that introduced it. It reads as a different
   typeface. It is the same typeface, two steps down the scale.

   Fix. A content wrap that sets its prose at the answer-first scale sets its
   bare lists to the same scale. :has() ties the two together structurally, so
   the rule is correct on a cleaned page and inert on a page that has no
   answer-first passage, rather than guessing from adjacency (a list is often
   separated from its answer by an intervening paragraph or table).

   Scope. Bare <ul>/<ol> only. `ul[class]`/`ol[class]` opted out of default list
   styling at line 43 and are excluded here by the same logic, so cards, chips,
   doc grids, ribbons, the marquee, the A-Z index and the footer keep their own
   type. Browser support: :has() is available in every browser in the support
   matrix; where it is not, nothing changes and the page renders as it does
   today. */
main .wrap:has(> .answer-first) > ul,
main .wrap:has(> .answer-first) > ol,
main section:has(> .wrap > .answer-first) .wrap > ul,
main section:has(> .wrap > .answer-first) .wrap > ol {
  font-size: var(--step-prose);  /* 2026-07-31 (Rohit): one prose size. was --step-1. see scripts/normalise_prose_size.py */
  line-height: 1.5;
}
main .wrap:has(> .answer-first) > ul > li,
main .wrap:has(> .answer-first) > ol > li,
main section:has(> .wrap > .answer-first) .wrap > ul > li,
main section:has(> .wrap > .answer-first) .wrap > ol > li {
  font-size: inherit;
  line-height: inherit;
  margin-block-end: 0.35em;
}
/* A nested list is a sub-point: it steps back one rung of the scale. */
main .wrap:has(> .answer-first) > ul ul,
main .wrap:has(> .answer-first) > ul ol,
main .wrap:has(> .answer-first) > ol ul,
main .wrap:has(> .answer-first) > ol ol {
  font-size: var(--step-prose);  /* 2026-07-31 (Rohit): one prose size. was --step-0. see scripts/normalise_prose_size.py */
  line-height: 1.6;
}
/* Belt and braces for the direct-adjacency case, which is the GEO golden rule's
   own shape: the answer passage, then the same information as an extractable
   list immediately after it. */
.answer-first + ul,
.answer-first + ol {
  font-size: var(--step-prose);  /* 2026-07-31 (Rohit): one prose size. was --step-1. see scripts/normalise_prose_size.py */
  line-height: 1.5;
}

/* ---------- 4. Leadership hub: the card grid (2026-07-26) ----------
   /about/leadership/ was one 111 KB page carrying 27 biographies as flat prose.
   It is now a hub of 29 cards, 27 of them linking to a page of their own with
   Person JSON-LD. Brand tokens only; no new colour. */
.leader-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: var(--space-s);
  margin-block-start: var(--space-m);
  list-style: none;
  padding: 0;
}
.leader-card {
  background: var(--tcr-cream-warm);
  border-inline-start: 3px solid var(--tcr-accent-light);
  padding: var(--space-s) var(--space-s) calc(var(--space-s) - 2px);
}
.leader-card h3 {
  font-size: var(--step-1);
  margin-block: 0 4px;
  line-height: 1.25;
}
.leader-card h3 a { color: var(--tcr-primary); text-decoration: none; }
.leader-card h3 a:hover { color: var(--tcr-accent-dark); text-decoration: underline; }
.leader-card__role {
  font-size: var(--step--1);
  line-height: 1.45;
  color: var(--tcr-ink);
  margin-block: 0 6px;
  max-width: none;
}
.leader-card__entity {
  font-family: var(--font-data);
  font-size: 12.5px;
  letter-spacing: 0.02em;
  color: var(--tcr-muted);
  margin-block: 0;
  max-width: none;
}
/* A leader with no biography yet is carried, not dropped, and reads as a name on
   the bench rather than a broken link. Flagged for Rohit on the build report. */
.leader-card--nobio { border-inline-start-color: var(--tcr-hairline); background: var(--tcr-grey-light); }
.leader-card__video {
  display: inline-block;
  margin-inline-start: 8px;
  padding: 1px 7px;
  border: 1px solid var(--tcr-hairline);
  border-radius: 2px;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tcr-accent-dark);
  background: var(--tcr-white);
}
/* The same roster as a plain list, ahead of the cards. The GEO golden rule: the
   engines lift a list far more reliably than a grid of articles, and this one
   carries every name, role and entity in one extractable block. Visually
   suppressed on wide screens where the cards do the work; always in the markup,
   always readable to a crawler and a screen reader. */
.leader-index { margin-block: var(--space-s) 0; padding-inline-start: 1.15rem; }
.leader-index li { margin-block-end: 0.3em; max-width: none; }
@media (min-width: 48em) {
  .leader-index { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}

/* ---------- 5. Video grid (2026-07-26, Rohit's instruction) ----------
   TCR's own YouTube films now sit on the pages that discuss the work. The
   component is the existing .video-facade: a <button data-video-id> that
   site.js replaces with a youtube-nocookie iframe on click, so nothing is
   requested from Google until the visitor presses play. Posters are local
   files under /assets/img/06-video/; no page hotlinks i.ytimg.com. Where a
   poster has not been downloaded yet the facade renders on brand tokens and
   the page is still correct. Brand tokens only; no new colour. */
.video-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
  gap: var(--space-s);
  margin-block-start: var(--space-m);
}
.video-item { margin: 0; }
.video-grid .video-facade {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 16 / 9;
  padding: 0;
  border: 1px solid var(--tcr-hairline);
  background: var(--tcr-dark);
  cursor: pointer;
  overflow: hidden;
}
.video-grid .video-facade .play { width: 54px; height: 54px; }
.video-item figcaption {
  font-size: var(--step--1);
  line-height: 1.45;
  color: var(--tcr-ink);
  padding-block-start: var(--space-xs);
  max-width: none;
}
/* The same films as a plain list, ahead of the grid. A <button> facade carries
   no href, so a crawler and an answer engine would otherwise see no link to the
   video at all. This list is the extractable form the GEO rule asks for; it is
   visually suppressed on wide screens where the grid does the work, and always
   present in the markup and to a screen reader. */
.video-index { margin-block: var(--space-s) 0; padding-inline-start: 1.15rem; }
.video-index li { margin-block-end: 0.3em; max-width: none; }
@media (min-width: 48em) {
  .video-index { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}

/* ---------- 6. Entity site card (2026-07-26, Rohit's instruction) ----------
   TCR Advanced, TCR Kuwait and TCR Qatar run their own domains. Each of those
   pages carries a large screenshot of the site, hyperlinked through. The
   screenshot is a local asset like every other image on this site. */
/* Capped at 40rem (640px) on Rohit's ruling of 2026-07-30: at full container
   width the screenshot took more screen than the page it illustrates. The
   16:10 ratio is unchanged, so the card renders at most 640 x 400 and the
   placeholder panel caps with it. */
.site-card { display: block; max-width: 40rem; margin-block: var(--space-m); text-decoration: none; }
.site-card__shot {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--tcr-hairline);
  background: var(--tcr-grey-light);
}
.site-card:hover .site-card__shot { border-color: var(--tcr-accent-light); }
.site-card__cap {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs) var(--space-s);
  align-items: baseline;
  padding-block-start: var(--space-xs);
  font-size: var(--step--1);
  color: var(--tcr-muted);
}
.site-card__cap strong { color: var(--tcr-primary); font-size: var(--step-0); }
.site-card__url { font-family: var(--font-data); font-size: 12.5px; letter-spacing: 0.02em; }
/* Placeholder until the screenshot is captured: a labelled panel at the real
   aspect ratio, so the layout does not shift when the image lands. */
.site-card__pending {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 16 / 10;
  border: 1px dashed var(--tcr-hairline);
  background: var(--tcr-grey-light);
  color: var(--tcr-muted);
  font-family: var(--font-data);
  font-size: 13px;
  text-align: center;
  padding: var(--space-s);
}

/* ---------- 7. Leadership portraits (2026-07-27, Rohit's instruction) ----------
   Cut-out portraits, background removed, blended into the navy hero. The image
   files carry their own alpha and a baked bottom fade (scripts/build_headshots.py),
   so the blend does not depend on a CSS mask and survives if the mask property is
   unsupported. Brand tokens only. */

/* --- the hero --- */
.hero--portrait .hero-inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-m);
  align-items: end;
}
.hero--portrait .hero-portrait {
  position: relative;
  justify-self: center;
  /* Rohit's ruling 2026-07-27: the portrait sits FULLY inside the band. It used
     to hang below it, which ate into the section beneath on a short laptop
     viewport.
     Amended the same day, second report ("a lot of space above the image which
     makes the hero very big"): the figure is now sized by WIDTH alone. Every
     hero asset is emitted on ONE canvas by scripts/build_headshots_v2.py, with
     the top of the hair pinned at 3 per cent and the figure running to the
     bottom edge, so width fixes height exactly and the box can never be a
     different shape from the picture inside it. The former max-height cap is
     what produced the dead band: a capped box plus object-fit:contain
     letterboxes, and with object-position:bottom the letterbox lands above the
     head.
     Amended again the same day, fourth report (shoulders cut off at the sides):
     the canvas widened from 1100 x 1250 to 1200 x 1250, which ships at
     1100 x 1146. Nothing here depends on the exact ratio: the generator writes
     the real width and height onto the <img> by reading them off the file, so
     this rule needs no edit when the canvas moves again. */
  width: min(100%, 18rem);
  margin-block-end: 0;
}
.hero--portrait .hero-portrait img {
  display: block;
  width: 100%;
  height: auto;
  /* No object-fit. The asset and the box are the same shape, so there is
     nothing to letterbox and nothing to crop. Cropping would be worse than
     letterboxing here: the bottom of every asset is the alpha ramp that
     dissolves the shoulders into the band, and cutting it re-introduces a hard
     horizontal edge. */
  /* No mask either. There used to be a second CSS ramp here, from 78 per cent to
     transparent, as a safety net for tightly cropped sources. It was doing real
     damage: the asset already fades over its own last 10 per cent, measured, so
     the CSS ramp dissolved a further 12 per cent of shoulder on top of it. On a
     29.5rem portrait that is about 100 px of figure turned into empty band, and
     it is part of what Rohit reported as "space at the bottom" on 2026-07-27.
     The asset owns the fade. */
}
@media (min-width: 48em) {
  .hero--portrait .hero-inner {
    /* copy left, face right: the portraits are mirrored where needed so the
       subject looks INTO the copy rather than off the edge of the page */
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    gap: var(--space-l);
    align-items: end;
  }
  .hero--portrait .hero-portrait {
    justify-self: end;
    /* 26rem wide is 27.1rem tall on the shipped 1100 x 1146 asset, close to the
       height the old max-height cap was aiming at. Setting it on the width
       instead means the box and the asset stay the same shape. */
    width: min(100%, 26rem);
    margin-block-end: 0;
    /* Rohit, 2026-07-27, third report: "very little space on the top and the
       bottom of the image should be aligned to the bottom of the hero section
       with no spacing."
       The remaining top space was never the asset. It is the band's own
       padding-block-start, up to 104px, which pushes the portrait down along
       with the copy. Cancelling it on the portrait column alone lets the figure
       start at the top edge of the band while the copy keeps its breathing
       room. Desktop only: below 48em the portrait sits UNDER the copy, and a
       negative margin there would drive it into the CTA. */
    margin-block-start: calc(-1 * clamp(56px, 9vw, 104px));
  }
  .hero--portrait h1 { max-width: 14ch; }
  .hero--portrait .hero-copy { padding-block-end: clamp(24px, 4vw, 56px); }
}
@media (min-width: 75em) {
  .hero--portrait .hero-portrait { width: min(100%, 29rem); }
}
/* Bottom: flush, no gap. This rule used to add up to 40px of padding, from the
   era when the portrait hung BELOW the band and the section had to keep it. It
   no longer hangs: build_headshots_v2.py runs the figure to 0.990 of its own
   canvas, so the picture's bottom edge and the band's bottom edge are the same
   line and any padding here is visible dead space. */
.hero--portrait { padding-block-end: 0; }

/* --- the Insights overflow list on a leader page ---
   The first twelve posts that name a leader get picture cards. The rest are
   plain links: forty-one cards is a wall, and a data-reveal grid that tall never
   satisfies the IntersectionObserver threshold in site.js, so it renders at
   opacity 0 and the content is simply gone. See mentions_section() in
   scripts/build_leadership_pages.py. Deliberately carries NO data-reveal. */
.mentions-more-h {
  margin-block-start: var(--space-l);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tcr-muted);
}
.mentions-more {
  margin-block-start: var(--space-s);
  padding-inline-start: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  gap: 2px var(--space-l);
}
.mentions-more li {
  padding-block: 10px;
  border-block-end: 1px solid var(--tcr-hairline);
}
.mentions-more a { font-weight: 600; }
.mentions-more .insight__meta {
  display: block;
  margin-block-start: 2px;
}

/* --- the hub grid thumbnail --- */
.leader-card { display: grid; grid-template-columns: 64px 1fr; gap: var(--space-s); align-items: start; }
.leader-card__photo {
  grid-row: span 3;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--tcr-dark);
  border: 1px solid var(--tcr-hairline);
}
.leader-card__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* A leader with no photograph yet gets their initials, not a broken frame or a
   grey silhouette. Nothing on this grid should look like a missing asset. */
.leader-card__initials {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  font-family: var(--font-data);
  font-size: 19px;
  letter-spacing: 0.04em;
  color: var(--tcr-accent-dark);
  background: var(--tcr-dark);
}
.leader-card > h3, .leader-card > p { grid-column: 2; }
@media (min-width: 48em) {
  .leader-card { grid-template-columns: 76px 1fr; }
  .leader-card__photo { width: 76px; height: 76px; }
}

/* ---------- 8. Person row (2026-07-27) ----------
   A named individual placed in the body of a page rather than in the leadership
   grid: Syed Ameen Hassan on /global/tcr-arabia/. Photo left, text right, stacking
   on a narrow viewport. Brand tokens only. */
.person-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-s);
  align-items: start;
  margin-block-start: var(--space-m);
}
.person-row__photo {
  margin: 0;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--tcr-dark);
  border: 1px solid var(--tcr-hairline);
}
.person-row__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.person-row__body h3 { margin-block: 0 2px; font-size: var(--step-1); }
.person-row__role {
  font-family: var(--font-data);
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--tcr-muted);
  margin-block: 0 var(--space-xs);
  max-width: none;
}
@media (min-width: 40em) {
  .person-row { grid-template-columns: 150px minmax(0, 1fr); gap: var(--space-m); }
  .person-row__photo { width: 150px; height: 150px; }
}

/* Portrait variant of .person-row. Added 2026-07-27 on Rohit's instruction, so
   the full cut-out portrait carries the body of the text rather than a 150 px
   disc. The ground is --tcr-navy and not --tcr-dark on purpose: the headshot
   assets are composed with an alpha ramp across their bottom tenth so the
   shoulders dissolve into #001F3F, which is the colour the leader-page hero
   band ends on. On any other ground that ramp is visible as a soft edge. The
   aspect ratio is the asset's own 1200 x 1250, so the panel cannot letterbox.
   Mobile first: the panel is full width in the narrow viewport and becomes a
   column beside the prose at 40em, per the project's min-width-only rule. */
.person-row--portrait .person-row__photo {
  width: min(100%, 17rem);
  height: auto;
  aspect-ratio: 1200 / 1250;
  border-radius: 3px;
  background: var(--tcr-navy);
}
/* The image keeps the base rule's width:100%; height:100%; object-fit:cover.
   Only the anchor changes, to the top of the frame, so a ratio that ever drifts
   from the asset's own crops the shoulders rather than the face. Measured
   2026-07-27: asset 1100x1146 = 0.9599, panel 1200/1250 = 0.9600, so nothing is
   cropped today. */
.person-row--portrait .person-row__photo img { object-position: 50% 0; }
@media (min-width: 40em) {
  .person-row--portrait { grid-template-columns: min(36%, 17rem) minmax(0, 1fr); }
  .person-row--portrait .person-row__photo { width: 100%; height: auto; }
}

/* ---------- Leader hero: the name and the role are one unit (2026-07-28, Rohit) ----------
   Reported: "the name, a huge space, their title, the call to action." The
   portrait hero inherited `.hero--v4 .sub { margin-block-start: 22px }` from the
   campaign hero, where the sub-line is a separate claim under a headline, while
   `.cta` carries no top margin at all. On a leader page the role IS the name's
   second line, so the 22px belonged in the wrong place: it split the identity
   and then jammed the button against the role.
   Rohit's instruction: name, then title, then a space, then the call to action.
   Scoped to .hero--portrait so the campaign hero on the homepage and the pillar
   hubs is untouched. */
.hero--portrait .hero-copy .sub { margin-block-start: 6px; }
.hero--portrait .hero-copy .cta { margin-block-start: clamp(22px, 3.2vw, 34px); }

/* ---------- Photo bands: TCR's own photographs on the page (2026-07-28, Rohit) ----------
   The company picture library (Mahape and Vadodara buildings, the laboratories
   and their equipment, the group shots, the Dammam bench, the TCR Qatar
   signing, and the two anniversary marks) now sits on the pages that discuss
   the work. Emitted by scripts/build_company_photos.py from
   data/company-photos.json; never hand-edited in built HTML.

   Fluid by construction, per the mobile-first rule: the grid is auto-fit with a
   min() floor, so one figure fills the column on a phone and two or three sit
   side by side on a desktop with no media query and no fixed pixel width.
   Brand tokens only. */
/* .photo-band carries no rule of its own by design: it is a semantic hook so the
   applier can find and replace its own section, and the band takes the page's
   default cream ground and the shared <section> spacing. Give the section
   band--white in the emitted markup if a page needs the alternation. */
.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: var(--space-m);
  margin-block-start: var(--space-m);
}
.photo-card { margin: 0; }
.photo-card picture { display: block; }
.photo-card img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 3px;
  background: var(--tcr-grey-light);
}
.photo-card figcaption {
  margin-block-start: 10px;
  font-size: var(--step--1);
  line-height: 1.45;
  color: var(--tcr-muted);
  max-width: none;
}
/* An anniversary mark is line art on white, not a photograph. It gets a white
   panel so the mark's own white ground does not read as a torn edge against the
   cream body, it is capped in width so it reads as a mark rather than a hero,
   and it is centred. */
.photo-card--mark img {
  background: var(--tcr-white);
  border: 1px solid var(--tcr-hairline);
  padding: var(--space-s);
  max-width: 26rem;
  margin-inline: auto;
}
.photo-card--mark figcaption { text-align: center; }

/* Certificate thumbnail on a homepage accreditation card (2026-07-28, Rohit's
   instruction). The card now opens the certificate itself rather than the
   /quality/ index, so it shows the first page of the document it opens. Small
   on purpose: it is a proof token, not an illustration, and the reference
   number and validity window remain the card's content. */
.cert-card__thumb {
  display: block;
  width: 64px;
  margin-block-end: 16px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 2px;
  overflow: hidden;
  background: var(--tcr-white);
}
.cert-card__thumb img { display: block; width: 100%; height: auto; }

/* ---------- Newsroom: document cards and the press-clipping list (2026-07-28) ----------
   Rohit's instruction: every PDF the site links to shows a thumbnail of the
   document alongside. The six original 'In the news' cards link to the live
   article on the outlet's own site and keep their outlet logo; the six added
   below link to a PDF held on this domain and show its first page instead. */
.news-card__doc {
  display: block;
  width: 72px;
  margin-block-end: 14px;
  border: 1px solid var(--tcr-hairline);
  border-radius: 2px;
  overflow: hidden;
  background: var(--tcr-white);
}
.news-card__doc img { display: block; width: 100%; height: auto; }

/* The press-clipping list. A list, not a grid: it is nineteen documents in
   reverse date order and an engine lifts a list far more reliably. The
   thumbnail is a column beside the link, and the row is fluid, so on a phone
   the thumbnail sits at 56 px and the title wraps beside it. */
.doc-list { list-style: none; padding-inline-start: 0; margin-block-start: var(--space-s); }
.doc-list li {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr);
  gap: var(--space-s);
  align-items: start;
  padding-block: 14px;
  border-block-end: 1px solid var(--tcr-hairline);
  max-width: none;
}
.doc-list li:last-child { border-block-end: 0; }
.doc-list__thumb {
  display: block;
  border: 1px solid var(--tcr-hairline);
  border-radius: 2px;
  overflow: hidden;
  background: var(--tcr-white);
}
.doc-list__thumb img { display: block; width: 100%; height: auto; }
@media (min-width: 48em) {
  .doc-list li { grid-template-columns: 72px minmax(0, 1fr); }
}

/* Light ground for a body portrait (2026-07-28, Rohit's instruction).
   Reported on Syed Ameen Hassan: "you need not have it in blue background as
   it is no longer part of the hero, it is part of the body text."
   Measured before changing anything: the shipped asset
   /assets/img/08-people/syed-ameen/hero-1100w.webp is RGBA with a real alpha
   channel, transparent at all four corners and dissolving to alpha 0 across
   its bottom edge. The blue was never in the file. It was
   `.person-row--portrait .person-row__photo { background: var(--tcr-navy) }`,
   which is correct on a leader page where the panel continues the navy hero
   band and wrong in the body of an entity page. So the fix is the ground, not
   a re-cut: the same transparent cut-out now dissolves into warm cream, and no
   new bytes ship for a change that was one declaration deep. */
.person-row--light .person-row__photo { background: var(--tcr-cream-warm); }

/* ---------- Photographs scattered inline, with a CSS-only lightbox ----------
   Rohit's second ruling on this component, 2026-07-28: "I actually wanted these
   images to be scattered around the page, not clubbed all together in one
   section... use smaller images or images in line with the text. Text can move
   around the image, and if a user wants to enlarge the image they can click it
   and it opens full size."

   So the .photo-band / .photo-grid block above is RETIRED. It is retained, not
   deleted, because /downloads/ and any future gallery may want a grid, and
   because deleting CSS that nothing currently emits buys nothing. Nothing on
   the site emits .photo-band any more.

   Mobile first: the figure is a full-width block in the narrow viewport, where
   a 22rem float beside 92vw of prose would leave a two-word column. It becomes
   a float at 48em, alternating side down the page. */
.photo-figure {
  margin: 0 0 var(--space-m);
}
.photo-figure__zoom { display: block; text-decoration: none; }
.photo-figure img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 3px;
  background: var(--tcr-grey-light);
}
.photo-figure__zoom:focus-visible img { outline: 3px solid var(--tcr-accent-dark); outline-offset: 2px; }
.photo-figure figcaption {
  margin-block-start: 8px;
  font-size: var(--step--1);
  line-height: 1.4;
  color: var(--tcr-muted);
  max-width: none;
}
/* The affordance. Without it a photograph that opens full size looks exactly
   like one that does not, and nobody clicks it. */
.photo-figure figcaption::after {
  content: " Click to enlarge.";
  color: var(--tcr-accent-dark);
  font-weight: 600;
}
.photo-figure--mark img {
  background: var(--tcr-white);
  border: 1px solid var(--tcr-hairline);
  padding: var(--space-s);
}
@media (min-width: 48em) {
  .photo-figure { width: min(38%, 22rem); }
  .photo-figure--right { float: right; margin-inline-start: var(--space-m); }
  .photo-figure--left  { float: left;  margin-inline-end: var(--space-m); }
}
/* Contain the float inside its own section. flow-root establishes a block
   formatting context, which is the modern clearfix and costs one declaration.
   Scoped to .photo-host so .wrap is untouched on the other 460 pages. */
.photo-host .wrap { display: flow-root; }
/* A table or a figure must not try to wrap around a float: .table-wrap scrolls
   horizontally, so beside a 22rem float it would become a scrollbar with a
   sliver of table in it. Clear instead. */
.photo-host .table-wrap,
.photo-host .grid,
.photo-host .video-grid { clear: both; }

/* --- the lightbox: :target, no JavaScript ---
   The overlay is an <aside> that is display:none until the URL fragment matches
   its id. Clicking the figure sets the fragment; the scrim and the Close link
   set it back to the figure's own id, which also returns focus to where the
   reader was. Consequences of having no script, stated rather than discovered:
   the browser Back button closes the overlay because it is a history entry, and
   Escape does not close it, which is why the scrim and Close are both real
   links and Close is visible rather than a bare glyph. */
.lightbox { display: none; }
.lightbox:target {
  display: grid;
  position: fixed;
  inset: 0;
  z-index: 200;
  place-items: center;
  padding: clamp(12px, 4vw, 48px);
  background: rgba(0, 31, 63, 0.94);
  overflow: auto;
}
.lightbox__scrim { position: absolute; inset: 0; cursor: zoom-out; }
.lightbox__inner {
  position: relative;
  margin: 0;
  max-width: min(96vw, 68rem);
}
.lightbox__inner img { display: block; width: 100%; height: auto; border-radius: 3px; }
.lightbox__inner figcaption {
  margin-block-start: 12px;
  color: var(--tcr-white-90);
  font-size: var(--step--1);
  line-height: 1.45;
  max-width: none;
}
.lightbox__close {
  position: relative;
  justify-self: end;
  align-self: start;
  grid-area: 1 / 1;
  margin: 0;
  padding: 8px 16px;
  min-height: 44px;
  line-height: 28px;
  background: var(--tcr-accent-light);
  color: var(--tcr-ink);
  font-weight: 600;
  text-decoration: none;
  border-radius: 3px;
}
.lightbox__inner { grid-area: 1 / 1; }

/* ---------- List markers (2026-07-28, Rohit's instruction) ----------
   "Make sure the bullet points are being showcased properly on all the pages."

   The base reset at the top of this file zeroes padding on ul and ol, which is
   the right call for the twenty-odd list-based components on the site (nav,
   drawer, chips, doc grids, footer columns) because every one of them supplies
   its own layout. It is the wrong call for a plain content list: with
   list-style-position defaulting to outside and padding-inline-start at 0, the
   marker renders OUTSIDE the list's content box, sitting in the wrapper's
   gutter, and on a narrow viewport it is clipped against it.

   So the indent comes back, scoped to a content list, which is exactly the set
   the reset's own `ul[class]` selector excludes: a list with no class. Every
   component keeps its zero padding because every component is classed.
   Marker colour is the accent, so a list reads as TCR's rather than the
   browser's. */
main ul:not([class]),
main ol:not([class]) { padding-inline-start: 1.35rem; }
main ul:not([class]) > li,
main ol:not([class]) > li { margin-block-end: 0.4em; padding-inline-start: 0.2rem; }
main ul:not([class]) > li::marker { color: var(--tcr-accent-dark); }
main ol:not([class]) > li::marker { color: var(--tcr-muted); font-family: var(--font-data); }
/* A nested list steps in once more and drops to a hollow marker, so two levels
   are distinguishable without a second colour. */
main ul:not([class]) ul { list-style-type: circle; margin-block-start: 0.4em; }


/* ---------- Closing CTA band: space above the button (2026-07-28, Rohit) ----------
   Reported as "it is touching the words". Measured before changing anything, on
   /why-tcr/ in Chrome: the gap between the closing <h2>'s box and the "Request a
   Quote" button's box was exactly 0 px. Two rules combined to produce it. The
   reset at the top of this file zeroes every h2 margin, and .cta-band h2 is a
   plain h2 (not .sec-h2, which does carry margin-block-end), so the heading has
   no bottom margin. And .cta / .btn is display:inline-flex with no top margin of
   its own, so the button's border box began on the heading's border box.

   The space is put on the following element rather than on the heading, because
   the band's second element is a <p> on some pages and the button on others, and
   an inline-level box's top margin does not collapse with the previous sibling's
   bottom margin, so setting both would double it.

   .cta-trust keeps its own 0.875rem (two-class selector, higher specificity);
   the credline is struck on new pages but still present on the older ones and
   this must not change how those read. */
.cta-band p { margin-block-start: var(--space-s); }
.cta-band .cta,
.cta-band .btn { margin-block-start: var(--space-m); }


/* ---------- A referenced PDF, shown as its own first page (2026-07-28, Rohit) ----------
   "Make the letter PDF file available to download and show it as a thumbnail in
   the blog article too." The single-document case, as a <figure>; the several-
   document case is .doc-list above and is unchanged. The thumbnail is 226 x 320
   at source and is capped here rather than re-encoded, so no new bytes ship and
   the immutable-cache rule is not touched. */
/* A document figure is the same component as any other blog image: the frame is
   the figure's own width, the thumbnail fills it, the caption sits under it at
   the same width. Sizing and float live in the .post-figure--inline block above,
   which this shares, so the two can never drift apart. Only the frame treatment
   is different: a document gets a drop shadow, because a scan of a page needs to
   read as a physical object rather than as a photograph. */
.doc-figure__thumb {
  display: block;
  width: 100%;
  border: 1px solid var(--tcr-hairline);
  border-radius: 2px;
  overflow: hidden;
  background: var(--tcr-white);
  padding: 6px;
  box-shadow: 0 6px 18px rgba(49, 56, 65, 0.12);
}
.doc-figure__thumb img { display: block; width: 100%; height: auto; }
.tcre-editorial .post-figure--doc figcaption a { font-weight: 600; }


/* ---------- The named quote on an Insights post (2026-07-28, Rohit's ruling) ----------
   "We must always have a blog quote." A quote with nobody's name on it is an
   assertion, so the attribution is part of the component, not a loose paragraph
   below it. Reuses the .quote-band rule weight already on the site so the two
   read as one family; scoped to the article body so nothing else moves. */
.tcre-editorial .post-quote { margin-block: var(--space-l); }
.tcre-editorial .post-quote blockquote {
  border-inline-start: 4px solid var(--tcr-accent-light);
  padding-inline-start: 24px;
  font-size: clamp(19px, 2.4vw, 24px);
  font-weight: 500;
  color: var(--tcr-navy);
  line-height: 1.45;
  max-width: none;
}
.tcre-editorial .post-quote figcaption {
  margin-block-start: 12px;
  padding-inline-start: 28px;
  font-size: var(--step--1);
  color: var(--tcr-muted);
  max-width: none;
}


/* ---------- Blog body images: inline with the text, bordered, captioned ----------
   Rohit's standing rule, 2026-07-28: "whenever you place any image in the blog
   it should be inline with the text, with a border around the image and the
   caption." Same treatment .photo-figure gives an in-page photograph, so the
   two read as one family, and the same mobile-first reasoning: a 22rem float
   beside 92vw of prose leaves a two-word column, so the figure is a full-width
   block in the narrow viewport and becomes a float at 48em, alternating side
   down the article. */
/* Amended 2026-07-28 (second pass, Rohit): "the image is sitting in a content
   box which is way too wide ... the caption should take the identical width of
   the image, there should be just a minor space around the image, the image
   should be aligned in the centre of the frame, and the frame must not be so
   wide."

   The fix is to stop sizing the frame and the image independently. The FIGURE
   carries the width; the image is width:100% of it and the caption is the same
   box, so frame width, image width and caption width are one number by
   construction and cannot drift. 18rem at desktop, which is about a third of
   the 76rem measure. The border sits 6px off the image, which is the "minor
   space", and the image is centred inside it because it fills it exactly.

   Default side is LEFT, per the same instruction. --right remains available for
   a second figure in the same section so a run of images alternates instead of
   stacking down one edge. */
.tcre-editorial .post-figure--inline,
.tcre-editorial .post-figure--doc {
  margin: 0 0 var(--space-m);
  width: 100%;
  max-width: 22rem;
}
.tcre-editorial .post-figure--inline img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--tcr-hairline);
  border-radius: 3px;
  background: var(--tcr-white);
  padding: 6px;
}
.tcre-editorial .post-figure--inline figcaption,
.tcre-editorial .post-figure--doc figcaption {
  width: 100%;
  margin-block-start: 8px;
  font-size: var(--step--1);
  line-height: 1.4;
  color: var(--tcr-muted);
  max-width: none;
}
@media (min-width: 48em) {
  .tcre-editorial .post-figure--inline,
  .tcre-editorial .post-figure--doc { width: min(34%, 18rem); }
  .tcre-editorial .post-figure--left,
  .tcre-editorial .post-figure--doc { float: left;  margin-inline-end: var(--space-m); }
  .tcre-editorial .post-figure--right { float: right; margin-inline-start: var(--space-m); margin-inline-end: 0; }
}
/* A float has to be contained by the article, and a table or a grid must clear
   it rather than try to wrap: .table-wrap scrolls horizontally, so beside a
   24rem float it becomes a scrollbar with a sliver of table in it. */
.tcre-editorial article { display: flow-root; }
.tcre-editorial .table-wrap,
.tcre-editorial .post-quote,
.tcre-editorial .faq { clear: both; }


/* ---------- Insights hub: browse by topic (2026-07-28, Rohit's pagination ruling) ----------
   Replaces the JS checkbox facet panel. With 21 cards a page a client-side
   filter over the current page would search 21 of 315 posts and report
   "showing 1 of 21", which is worse than no filter. These are links to the
   per-tag index pages, which already carry every post for that tag, newest
   first, and the counts are corpus-wide from data/blog-taxonomy-index.json.
   It also works with JavaScript off, which the checkbox panel did not. */
.browse-panel {
  display: grid;
  gap: var(--space-l);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  margin-block: var(--space-m) var(--space-l);
  padding-block: var(--space-m);
  border-block: 1px solid var(--tcr-hairline);
}
.browse-h {
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--tcr-muted);
  margin-block-end: var(--space-xs);
}
.browse-list {
  list-style: none;
  padding-inline-start: 0;
  display: grid;
  gap: 2px 18px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
}
.browse-list li { display: flex; align-items: baseline; gap: 0.4rem; max-width: none; font-size: var(--step--1); }
.browse-list a { color: var(--tcr-navy); text-decoration: none; }
.browse-list a:hover { text-decoration: underline; }
.browse-list .fct-n { color: var(--tcr-muted); font-family: var(--font-data); font-size: 0.85em; }


/* ---------- A card grid does not stretch one card across the page (2026-07-28, Rohit) ----------
   Reported on /about/leadership/ajay-essampally/: "the blog post being shown is
   too big and covers the entire page and looks different from the other blog
   posts." Ajay is named in one article, and `.grid` uses
   repeat(auto-fit, minmax(min(100%, 18rem), 1fr)). auto-FIT collapses the empty
   tracks and lets the surviving card span the whole 76rem measure, so one card
   renders four times the size of one of twelve.

   auto-FILL keeps the tracks. One card is then exactly the size of one of
   twelve, which is what "identical blog post sizes" means. Scoped with :has()
   to grids that actually hold insight cards, so no other grid on the site
   changes, and it reaches all 485 built pages without regenerating any of them.
   The only other visible effect is that a partly-filled LAST row no longer
   stretches, which is the same consistency argument. */
.grid:has(> .insight-card) {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr));
}


/* ---------- Body images: one ship size, click to enlarge (2026-07-28, Rohit) ----------
   Measured before the change: 596 in-body images, 273.2 MB on disk, 405 over
   the 100 KB budget, because the Wix-era originals were migrated byte-for-byte
   and never re-encoded. scripts/fit_body_images.py now ships every one at
   760 px and links a 1600 px enlargement, so the page carries the reading size
   and the reader fetches the detail only if they ask for it.

   The affordance matters as much as the link: an image that opens full size
   looks exactly like one that does not, and nobody clicks it. The caption says
   so, in the accent colour, exactly as .photo-figure does. */
.figure-zoom { display: block; text-decoration: none; cursor: zoom-in; }
.figure-zoom:focus-visible img { outline: 3px solid var(--tcr-accent-dark); outline-offset: 2px; }
.tcre-editorial .post-figure:has(> .figure-zoom) figcaption::after {
  content: " Click to enlarge.";
  color: var(--tcr-accent-dark);
  font-weight: 600;
}
.tcre-editorial .post-figure .figure-zoom img {
  border: 1px solid var(--tcr-hairline);
  border-radius: 3px;
  background: var(--tcr-white);
  padding: 6px;
}

/* ============================================================================
   PROSE SIZING (appended 2026-07-30, Rohit's ruling). Additive: nothing above
   this line was modified, and NO page was edited to achieve it.

   The problem. `.answer-first` is the GEO class for the single 40 to 60 word
   direct answer at the top of a section, and it sets --step-1 (19.2 to 24 px).
   It had been applied to 3,490 paragraphs across 176 pages, as a way of getting
   a readable body size, because the inherited --step-0 (16 to 18.1 px) read too
   small. The effect was that every paragraph was a lead paragraph, and body copy
   ran at 24 px on a wide monitor.

   The fix, in two rules and no page edits.

   1. The general sibling combinator does the work that no page rewrite would
      otherwise have avoided. The FIRST .answer-first inside a parent has no
      .answer-first before it, so it does not match `~` and keeps --step-1: it is
      the genuine answer paragraph. Every LATER .answer-first in the same parent
      is ordinary body copy and drops to --step-prose.
      (`:first-of-type` was tried and rejected: measured across 94 sections on
      eight representative pages, the first <p> in a section carries
      .answer-first only 71 per cent of the time, so it would have missed the
      lead on nearly a third of sections.)

   2. Unclassed paragraphs and unclassed lists inside a .wrap move from --step-0
      to --step-prose, so a paragraph reads the same whether or not somebody
      remembered to put the class on it. Classed containers set their own sizes
      and win on specificity, so cards, chips and captions are untouched.
   ========================================================================= */

.answer-first ~ .answer-first { font-size: var(--step-prose); }  /* 2026-07-31: now a no-op, .answer-first is itself --step-prose. Retained, not deleted. */

main .wrap > p:not([class]),
main .wrap > ul:not([class]) > li,
main .wrap > ol:not([class]) > li { font-size: var(--step-prose); }

/* ============================================================================
   .case-file__more  (added 2026-07-31, Rohit's instruction)
   The "read the note" affordance on the /insights/case-studies/ engagement
   cards. It sits at the end of the card paragraph, so it needs to read as a
   next step rather than as one more inline link in a sentence full of
   certificate numbers. Block display, one step down, the orange accent, and a
   hairline it earns on hover; no new colour, no new font, no new token.
   ========================================================================= */

.case-file__more {
  display: block;
  margin-top: var(--space-xs);
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--tcr-accent-light);
  text-decoration: none;
}

.case-file__more:hover,
.case-file__more:focus-visible {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}
