/* ==========================================================================
   GIFLIF v3 — site.css
   Hand-written semantic CSS. No build step (the Tailwind v4 CLI fails on this
   machine — see giflif-vanilla/build-css.sh for the exFAT bug write-up).
   css/tailwind.css is still loaded for the HERO markup only, which is reused
   verbatim from the live site. Everything else on the site uses these classes.
   Tokens are GIFLIF's own, lifted from the live site's CSS.
   ========================================================================== */

:root {
  --navy:        #0B1220;
  --navy-soft:   #111C33;
  --navy-line:   rgba(248, 242, 231, 0.12);
  --cream:       #F8F2E7;
  --cream-dim:   rgba(248, 242, 231, 0.72);
  --cream-faint: rgba(248, 242, 231, 0.48);

  --gold:        #B89B5E;
  --amber:       #E89B45;
  --magenta:     #EC4899;
  --lime:        #C6E85C;
  --electric:    #38BDF8;

  --display: "Cormorant Garamond", Georgia, serif;
  --sans:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono:    "IBM Plex Mono", ui-monospace, monospace;

  --wrap: 1180px;
  --gutter: clamp(1.25rem, 4vw, 4rem);
  --radius: 14px;

  /* ---------- MEASURE ----------------------------------------------------
     These used to be `ch` caps (88ch / 90ch / 92ch) and they did NOT do what
     they looked like they did. In Chromium `1ch` is the advance width of the
     glyph "0", which in Inter is ~0.73em — but the AVERAGE character in this
     site's English prose measures ~0.51em. So `88ch` rendered as roughly
     125 actual characters, and `92ch` on .answer computed to 1077px, which is
     WIDER than the 1065px content column, so it never bound at all.
     Measured before this change, at a 1440px viewport:
        .answer     101 chars/line average, 127 max   (target 60-75)
        .section p   84 average, 159 max
        .lede        82 average, 168 max
        .faq p       88 average, 120 max
        .ticks li    76 average, 149 max
     Set in rem instead, so the cap is the real rendered line length. Do not
     put these back into `ch` without re-measuring the rendered characters. */
  --measure:      38rem;   /* 608px — body prose at 1rem, ~72 chars/line   */
  --measure-lead: 42rem;   /* 672px — .answer at 1.16rem, ~72 chars/line   */
  --measure-wide: 46rem;   /* 736px — FAQ rows, where a summary is a title */

  /* ---------- VERTICAL SCALE ---------------------------------------------
     Every .section used to be `padding: clamp(1.5rem,3.2vw,2.5rem) 0`, so the
     gap between ANY two blocks was exactly 80px at 1440px (48px at 390px),
     whether they were arguing the same point or changing the subject. Ten
     identical gaps down /event-production/ is what reads as machine-made.
     Three steps now, and they are used by relationship, not by position. */
  --gap-major: clamp(2.5rem, 4.6vw, 3.75rem);  /* new subject            */
  --gap-minor: clamp(1.6rem, 2.6vw, 2.1rem);   /* back matter            */
  --gap-cont:  clamp(0.5rem, 1.1vw, 0.9rem);   /* continues the block above */
}

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

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

body {
  margin: 0;
  background: var(--navy);
  color: var(--cream);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; }
img { max-width: 100%; display: block; }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--cream); color: var(--navy);
  padding: .7rem 1.1rem; font-weight: 600; border-radius: 0 0 var(--radius) 0;
}
.skip-link:focus { left: 0; }

:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; }

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

/* ---------- masthead (inner pages) ---------- */
.masthead {
  position: sticky; top: 0; z-index: 60;
  background: rgba(11, 18, 32, 0.92);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--navy-line);
}
.masthead-in {
  max-width: var(--wrap); margin: 0 auto; padding: .85rem var(--gutter);
  display: flex; align-items: center; gap: 1.5rem;
}
.masthead-logo img { height: 34px; width: auto; }
.masthead-nav { margin-left: auto; display: flex; align-items: center; gap: 1.35rem; flex-wrap: wrap; }
.masthead-nav a {
  text-decoration: none; font-size: .82rem; letter-spacing: .02em;
  color: var(--cream-dim); transition: color .18s ease; white-space: nowrap;
}
.masthead-nav a:hover, .masthead-nav a[aria-current="page"] { color: var(--cream); }
.masthead-cta {
  border: 1px solid var(--navy-line); border-radius: 999px;
  padding: .42rem .95rem; color: var(--cream) !important;
}
.masthead-cta:hover { background: var(--cream); color: var(--navy) !important; border-color: var(--cream); }

@media (max-width: 900px) {
  .masthead-nav { gap: .9rem; }
  .masthead-nav a { font-size: .75rem; }
  .masthead-nav .hide-sm { display: none; }
}

/* ---------- colour sweep rule ---------- */
.color-sweep {
  height: 3px;
  background: linear-gradient(90deg, var(--magenta) 0%, #F59E0B 20%, var(--lime) 40%,
              var(--electric) 60%, var(--magenta) 80%, var(--lime) 100%);
  background-size: 200% 100%;
  animation: sweepShift 12s linear infinite;
}
@keyframes sweepShift { 0% { background-position: 0 0; } 100% { background-position: 200% 0; } }

/* ---------- page head ---------- */
.page-head { padding: clamp(1.6rem, 3.4vw, 2.9rem) 0 clamp(1rem, 2vw, 1.6rem); }
.eyebrow {
  font-family: var(--mono); font-size: .68rem; letter-spacing: .28em;
  text-transform: uppercase; color: var(--amber); margin: 0 0 .65rem;
}
.page-head h1 {
  font-family: var(--display); font-weight: 600;
  font-size: clamp(2.1rem, 5.4vw, 3.9rem); line-height: 1.04;
  letter-spacing: -0.02em; margin: 0 0 .75rem; max-width: 26ch;
}

/* THE ANSWER BLOCK — the AEO element. First thing in <main>, self-contained,
   40-60 words, names GIFLIF explicitly so it survives being quoted out of context. */
.answer {
  font-size: clamp(1rem, 1.45vw, 1.16rem); line-height: 1.6;
  color: var(--cream); max-width: var(--measure-lead); margin: 0 0 1.1rem;
}
/* The answer block used to be marked with a 3px amber border-left. That is the
   single most recognisable tell of a generated interface, and it also indented
   the most-read paragraph on every page away from the flush-left column
   everything else sits on. A short amber rule above the text does the same
   editorial job — marks the standfirst — without either problem. */
.answer::before {
  content: ""; display: block; width: 3.25rem; height: 2px;
  background: var(--amber); border-radius: 1px; margin: 0 0 .85rem;
}

/* Blocks awaiting Karan's own commercial copy. Deliberately reads as unfinished
   rather than as a designed pull-quote, so nothing placeholder ships unnoticed. */
.todo {
  border: 1px dashed rgba(232, 155, 69, .5); border-radius: 6px;
  padding: .9rem 1.05rem; background: rgba(232, 155, 69, .045);
}

.lede { font-size: 1.02rem; color: var(--cream-dim); max-width: var(--measure); margin: 0 0 .95rem; }

/* Wide variant — used for the homepage statement directly under the hero.
   The default .answer is capped at 62ch for readability, which on a 1000px+
   row leaves the right half empty and reads as a floating column. Here the
   line runs the full measure and the size drops so it lands in ~2 lines. */
.answer.answer-wide {
  /* .section p sets the body measure at (0,1,1); this needs (0,2,0) to win.
     It used to be `none`, which let this paragraph run the full 1065px column
     at 120 characters per line — the longest measure on the site. It is still
     the widest thing on the page, but it is now bounded. */
  max-width: var(--measure-wide);
  font-size: clamp(0.98rem, 1.2vw, 1.12rem);
  line-height: 1.6;
}

/* ---------- sections ---------- */
.section { padding: var(--gap-major) 0; border-top: 1px solid var(--navy-line); }
.section:first-of-type { border-top: 0; }

/* A block that CONTINUES the one above it — a fact strip under the argument
   it quantifies, a logo wall under the claim it evidences. It carries no
   heading of its own, so it must not be fenced off by a rule and a full
   major gap; that is exactly what made unrelated and related blocks read
   identically. Set by gen_site.py, never by hand. */
.section--cont { padding-top: var(--gap-cont); border-top: 0; }

/* Back matter — FAQ, related reading, Beyond India, the closing CTA. Real
   sections, but not the argument, so they sit on a tighter rhythm and their
   headings drop a whole tier (see below). */
.section--minor { padding: var(--gap-minor) 0; }

.section > .wrap > h2, .section-title {
  font-family: var(--display); font-weight: 600;
  font-size: clamp(1.75rem, 3.7vw, 2.75rem); line-height: 1.1;
  letter-spacing: -0.015em; margin: 0 0 .8rem;
  max-width: 22ch;              /* headings wrap EARLIER than body, on purpose */
  text-wrap: balance;
}

/* The ladder, measured at 1440px: h1 62px -> section title 44px -> back-matter
   title 26px -> card h3 20px -> body 16px. Before this pass 44 of the site's
   47 h2s rendered at exactly 40px, so "Related reading" shouted as loudly as
   "Four ways to work with us" and nothing on the page was actually dominant. */
.section--minor > .wrap > h2,
.section--minor .section-title,
.section--minor .reach-title {
  font-size: clamp(1.4rem, 2.1vw, 1.625rem);
  line-height: 1.18; max-width: 30ch;
}
.section h3 {
  font-family: var(--display); font-weight: 600;
  font-size: clamp(1.15rem, 2vw, 1.5rem); margin: 0 0 .5rem; letter-spacing: -0.01em;
}
.section p { max-width: var(--measure); color: var(--cream-dim); }
.section p strong { color: var(--cream); font-weight: 600; }

/* ---------- fact strip ---------- */
.facts {
  display: grid; gap: 1px; background: var(--navy-line);
  border: 1px solid var(--navy-line); border-radius: var(--radius); overflow: hidden;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.fact { background: var(--navy); padding: 1.15rem 1.25rem; }
.fact-num {
  /* Sans, not the display serif. Cormorant Garamond ships OLD-STYLE figures, so
     "2015" and "80M+" rendered with descending, uneven digits — fine for prose,
     wrong for a stat you want read at a glance. Inter with lining tabular figures
     gives even, aligned numerals. */
  font-family: var(--sans); font-size: clamp(1.45rem, 2.8vw, 2rem);
  font-weight: 700; letter-spacing: -0.02em;
  font-variant-numeric: lining-nums tabular-nums;
  font-feature-settings: "lnum" 1, "tnum" 1;
  color: var(--amber); line-height: 1.05; display: block; margin-bottom: .3rem;
}
.fact-label { font-size: .82rem; color: var(--cream-dim); line-height: 1.45; }

/* ---------- cards ---------- */
.grid { display: grid; gap: 1.15rem; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(265px, 1fr)); }

/* The four offers must read as ONE row on desktop and 2x2 on phones
   (Karan, 26 Aug). auto-fit was wrapping them 3+1, so the track count is
   explicit here rather than derived from a min width. */
.grid-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1080px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } }

/* PHONES. 18 Sep — Karan: "the text formatting for mobile version is not
   correct." Measured at 390px: the 2x2 grid leaves each card ~137px wide, and
   the body paragraph was running at 13-18 CHARACTERS PER LINE ("Audience
   Intelligence" wrapped at 10). The previous fix here shrank the copy to
   13.4px, which made it smaller, not readable.

   Two of Karan's instructions collide on a phone: 2x2 (26 Aug) and readable
   copy (18 Sep). No paragraph is legible in a 137px column, so the phone card
   becomes a TILE: photo, kicker, title, and the one-line tagline. The pitch
   paragraph stays in the DOM (crawlers, screen readers) but is not drawn; the
   full pitch is one tap away on the offer's own page.

   To flip to a readable single column instead, replace the first rule below
   with:  .grid-4 { grid-template-columns: 1fr; }  and delete the `p` rule. */
@media (max-width: 560px) {
  .grid-4 { gap: .7rem; }
  .grid-4 .card { padding: .9rem .9rem 1rem; }
  .grid-4 .card .thumb { height: 96px; margin: -.9rem -.9rem .7rem; }
  .grid-4 .card .kicker { font-size: .6rem; }
  .grid-4 .card h3 { font-size: 1.05rem; line-height: 1.2; margin: 0 0 .35rem; text-wrap: balance; }
  .grid-4 .card p { display: none; }
  .grid-4 .card .more { font-size: .78rem; line-height: 1.35; }
}

.card {
  background: rgba(248, 242, 231, 0.035);
  border: 1px solid var(--navy-line); border-radius: var(--radius);
  padding: 1.4rem 1.45rem; text-decoration: none; color: inherit;
  display: flex; flex-direction: column; gap: .55rem;
  transition: border-color .2s ease, transform .2s ease, background .2s ease;
}
a.card:hover { border-color: var(--amber); transform: translateY(-3px); background: rgba(248, 242, 231, 0.06); }
.card .kicker {
  font-family: var(--mono); font-size: .64rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--amber);
}
.card p { margin: 0; font-size: .92rem; color: var(--cream-dim); }
.card .more { margin-top: auto; padding-top: .5rem; font-size: .84rem; color: var(--cream); font-weight: 500; }

/* offer cards get an accent edge so the four offers read as siblings */
.card[data-accent="ip"]       { border-top: 3px solid var(--magenta); }
.card[data-accent="prod"]     { border-top: 3px solid var(--amber); }
.card[data-accent="audience"] { border-top: 3px solid var(--electric); }
.card[data-accent="youtube"]  { border-top: 3px solid var(--lime); }

/* ---------- list ---------- */
.ticks {
  list-style: none; padding: 0; margin: 0 0 .9rem; display: grid; gap: .6rem;
  /* +1.6rem for the hanging em-dash, so the TEXT column is the real measure. */
  max-width: calc(var(--measure) + 1.6rem);
}
.ticks li { position: relative; padding-left: 1.6rem; color: var(--cream-dim); }
.ticks li::before { content: "—"; position: absolute; left: 0; color: var(--amber); }
.ticks li strong { color: var(--cream); }

/* ---------- FAQ (AEO) ---------- */
.faq { display: grid; gap: 0; border-top: 1px solid var(--navy-line); max-width: var(--measure-wide); }
.faq details { border-bottom: 1px solid var(--navy-line); }
.faq summary {
  cursor: pointer; list-style: none; padding: 1.1rem 2rem 1.1rem 0; position: relative;
  font-weight: 600; font-size: 1.02rem; color: var(--cream);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+"; position: absolute; right: .25rem; top: 50%; transform: translateY(-50%);
  color: var(--amber); font-size: 1.3rem; font-weight: 400;
}
.faq details[open] summary::after { content: "–"; }
.faq details > p { margin: 0 0 .9rem; color: var(--cream-dim); max-width: var(--measure); }

/* ---------- CTA ---------- */
.cta-band {
  border: 1px solid var(--navy-line); border-radius: var(--radius);
  padding: clamp(1.6rem, 4vw, 2.6rem); background: rgba(248, 242, 231, 0.035);
}
.cta-band h2 { font-family: var(--display); font-size: clamp(1.5rem, 3.2vw, 2.2rem); margin: 0 0 .6rem; }
.cta-band p { margin: 0 0 1.3rem; color: var(--cream-dim); max-width: var(--measure); }

.btn {
  display: inline-block; text-decoration: none; border-radius: 999px;
  padding: .78rem 1.6rem; font-weight: 600; font-size: .93rem;
  background: var(--cream); color: var(--navy);
  border: 1px solid var(--cream); transition: opacity .18s ease;
}
.btn:hover { opacity: .87; }
.btn-ghost { background: transparent; color: var(--cream); border-color: var(--navy-line); }
.btn-ghost:hover { border-color: var(--cream); opacity: 1; }
.btn-row { display: flex; gap: .75rem; flex-wrap: wrap; }

/* ---------- back control + breadcrumb ---------- */
/* .page-nav is the row that carries both. Desktop: the back pill sits BESIDE
   the crumb trail. Phone: it stacks ABOVE it, so neither can collide with the
   other or with a sticky masthead. Markup comes from back_link() /
   crumbs_html() in _build/gen_site.py — do not hand-edit the built HTML. */
.page-nav {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: .5rem .9rem; padding-top: 1rem;
}
.page-nav .crumbs { padding-top: 0; }

/* A quiet mono pill, same family as .masthead-cta and .rel-link. The amber is
   on the arrow glyph only — no coloured slab, no thick side border. */
.back-link {
  display: inline-flex; align-items: center; gap: .45rem;
  font-family: var(--mono); font-size: .66rem;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--cream-dim); text-decoration: none; white-space: nowrap;
  padding: .34rem .85rem .34rem .68rem;
  border: 1px solid var(--navy-line); border-radius: 999px;
  transition: color .18s ease, border-color .18s ease, background-color .18s ease;
}
.back-link:hover {
  color: var(--cream); border-color: var(--amber);
  background: rgba(248, 242, 231, 0.05);
}
/* The global :focus-visible ring already applies; this only lifts the pill's
   own colours so the focused state reads as clearly as the hover state. */
.back-link:focus-visible { color: var(--cream); border-color: var(--amber); }
.back-link-arrow {
  color: var(--amber); font-size: .8rem; line-height: 1;
  transition: transform .18s ease;
}
.back-link:hover .back-link-arrow { transform: translateX(-2px); }
@media (prefers-reduced-motion: reduce) {
  .back-link-arrow, .back-link:hover .back-link-arrow { transform: none; }
}
@media (max-width: 560px) {
  .page-nav { flex-direction: column; align-items: flex-start; gap: .5rem; }
  .back-link { font-size: .62rem; letter-spacing: .12em; }
}

.crumbs { font-size: .78rem; color: var(--cream-faint); padding-top: 1rem; }
.crumbs a { text-decoration: none; }
.crumbs a:hover { color: var(--cream); }
.crumbs span { margin: 0 .45rem; }

/* ---------- logo wall: one line, scrolls itself AND takes a swipe ---------- */
/* Files are pre-normalised to white-on-transparent (or baked onto a light chip
   for two-colour lockups) by _build/build_client_logos.py, so there is NO css
   filter here. The old `brightness(0) invert(1)` only worked because all nine
   original logos happened to be dark marks on transparency; over a white-
   background JPEG it produces a solid white rectangle.

   The drift is driven by scrollLeft in js/site.js, NOT a transform animation —
   a transform cannot be grabbed, and Karan wants to swipe the row with a finger.
   A real scroll container gives native touch/trackpad momentum for free. */
.logo-marquee {
  overflow-x: auto; overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none; -ms-overflow-style: none;
  cursor: grab;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.logo-marquee::-webkit-scrollbar { display: none; }
.logo-marquee.is-grabbing { cursor: grabbing; }
.logo-track {
  display: flex; align-items: center; width: max-content;
  gap: clamp(2rem, 4vw, 3.4rem);
}
.logo-track img {
  height: calc(38px * var(--s, 1)); width: auto; flex: 0 0 auto;
  opacity: .92; transition: opacity .2s ease;
  -webkit-user-drag: none; user-select: none; pointer-events: auto;
}
.logo-track img:hover { opacity: 1; }
@media (max-width: 700px) { .logo-track img { height: calc(30px * var(--s, 1)); } }


/* ---------- proof strip: real shows, named ---------- */
/* Reuses .logo-marquee for the scroll/swipe behaviour (see js/site.js) so there is
   one scrolling mechanism on the site, not two. Only the cells differ. */
.ps { cursor: grab; }
.ps-track { display: flex; align-items: stretch; width: max-content; gap: .85rem; padding: 2px 0 4px; }
.ps-cell { flex: 0 0 clamp(240px, 27vw, 330px); margin: 0; }
.ps-cell img {
  width: 100%; height: 190px; object-fit: cover; object-position: 50% 35%; display: block;
  border-radius: var(--radius); border: 1px solid var(--navy-line); background: #0d1220;
}
.ps-cell figcaption { margin-top: .5rem; display: block; }
.ps-cell figcaption strong {
  display: block; color: var(--cream); font-weight: 600; font-size: .92rem; line-height: 1.25;
}
.ps-cell figcaption span {
  display: block; margin-top: .15rem; font-size: .76rem; line-height: 1.35;
  color: rgba(248, 242, 231, 0.55);
}
/* Shorts thumbnails are 9:16 — show them at their real shape rather than
   cropping a vertical card into a landscape slot. */
.ps-vertical .ps-cell { flex: 0 0 clamp(150px, 15vw, 190px); }
.ps-vertical .ps-cell img { height: auto; aspect-ratio: 9 / 16; object-fit: cover; }

@media (max-width: 700px) {
  /* vw, NOT %. The track is `width: max-content`, so a percentage basis resolves
     against the track's own content width rather than the viewport — at 375px
     that made every cell 1258px wide against a 205px height, a 6:1 letterbox
     slice. Harmless while these strips sat ~1400px down the page; the moment
     the gallery became the hero it was the first thing a phone user saw. */
  .ps-vertical .ps-cell { flex: 0 0 44vw; }
  .ps-cell { flex: 0 0 78vw; }
  .ps-cell img { height: 160px; }
}

/* ---------- numbered process steps ---------- */
.steps {
  list-style: none; margin: 1.4rem 0 0; padding: 0;
  display: grid; gap: .9rem; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  counter-reset: step;
}
.step {
  position: relative; padding: 1.15rem 1.2rem 1.2rem;
  border: 1px solid var(--navy-line); border-radius: var(--radius);
  background: rgba(248, 242, 231, 0.025);
}
.step-n {
  display: block; font-family: var(--mono); font-size: .72rem; letter-spacing: .18em;
  color: var(--amber); margin-bottom: .55rem;
  font-variant-numeric: lining-nums tabular-nums;
}
.step h3 {
  font-family: var(--sans); font-size: 1rem; font-weight: 600;
  margin: 0 0 .4rem; color: var(--cream); line-height: 1.3;
}
.step p { margin: 0; font-size: .88rem; line-height: 1.55; color: var(--cream-dim); }

/* ---------- thumbnails that open their video ----------
   A cover we tied to a real video on the GIFLIF Fest channel is wrapped in a
   link (see VIDEO_LINKS in _build/gen_site.py). The wrapper must not change the
   layout — the image rules are `.ps-cell img` / `.cc-cell img` descendants, so
   they still apply — it only has to carry the affordance and a focus ring. */
.yt-thumb-link { display: block; border-radius: var(--radius); text-decoration: none; }
.yt-thumb-link img { transition: opacity .18s ease, border-color .18s ease; }
.yt-thumb-link:hover img { opacity: .88; border-color: var(--amber); }
.yt-thumb-link:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; }
.vp-link { color: inherit; text-decoration: none; }
.vp-link:hover { color: var(--amber); text-decoration: underline; }
.vp-link:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

/* ---------- video proof rows ---------- */
.vp-list { display: grid; gap: .9rem; margin-top: 1.4rem; }
.vp-row {
  display: grid; grid-template-columns: 260px 1fr; gap: 1.15rem; align-items: start;
  padding: .95rem; border: 1px solid var(--navy-line); border-radius: var(--radius);
  background: rgba(248, 242, 231, 0.025);
}
.vp-thumb {
  width: 100%; aspect-ratio: 16 / 9; object-fit: cover;
  border-radius: 10px; border: 1px solid var(--navy-line); display: block;
}
.vp-views {
  display: inline-block; font-family: var(--mono); font-size: .7rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--amber); margin-bottom: .4rem;
  font-variant-numeric: lining-nums tabular-nums;
}
.vp-title {
  font-family: var(--sans); font-size: .97rem; font-weight: 600; line-height: 1.35;
  margin: 0 0 .45rem; color: var(--cream);
}
.vp-note { margin: 0; font-size: .87rem; line-height: 1.55; color: var(--cream-dim); max-width: 70ch; }
@media (max-width: 700px) { .vp-row { grid-template-columns: 1fr; gap: .8rem; } }

/* ---------- related links ---------- */
.rel-row { display: grid; gap: .7rem; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
.rel-link {
  display: block; padding: .9rem 1.05rem; border: 1px solid var(--navy-line);
  border-radius: var(--radius); text-decoration: none; color: var(--cream);
  font-size: .95rem; line-height: 1.35; transition: border-color .2s ease, background .2s ease;
}
.rel-link:hover { border-color: var(--amber); background: rgba(248, 242, 231, 0.05); }
.rel-link span {
  display: block; font-family: var(--mono); font-size: .62rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--amber); margin-bottom: .35rem;
}

/* ---------- prose blocks for case studies ---------- */
.prose p { margin: 0 0 1.05rem; }
.pill {
  display: inline-block; font-family: var(--mono); font-size: .64rem;
  letter-spacing: .16em; text-transform: uppercase;
  padding: .3rem .7rem; border-radius: 999px; border: 1px solid var(--navy-line);
  color: var(--cream-dim); margin: 0 .4rem .4rem 0;
}

/* ---------- footer ---------- */
.site-foot {
  border-top: 1px solid var(--navy-line); margin-top: clamp(3rem, 7vw, 5rem);
  padding: clamp(2.5rem, 5vw, 3.5rem) 0 2.5rem; font-size: .88rem;
}
.foot-grid { display: grid; gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.foot-grid h4 {
  font-family: var(--mono); font-size: .64rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--amber); margin: 0 0 .85rem; font-weight: 500;
}
.foot-grid ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.foot-grid a { text-decoration: none; color: var(--cream-dim); }
.foot-grid a:hover { color: var(--cream); }
.foot-base {
  margin-top: 2.5rem; padding-top: 1.4rem; border-top: 1px solid var(--navy-line);
  display: flex; gap: 1rem; flex-wrap: wrap; justify-content: space-between;
  color: var(--cream-faint); font-size: .8rem;
}

/* ---------- draft banner (local build only) ---------- */
.draft-flag {
  background: repeating-linear-gradient(45deg, #7C2D12, #7C2D12 12px, #9A3412 12px, #9A3412 24px);
  color: #FFF7ED; text-align: center; padding: .5rem 1rem;
  font-family: var(--mono); font-size: .7rem; letter-spacing: .12em; text-transform: uppercase;
}

/* ==========================================================================
   IMAGE-LED BLOCKS — added 2026-08-19 after Karan: "too bland and boring".
   The site had type and rules but almost no photography. These blocks put
   the real festival imagery to work.
   ========================================================================== */

/* ---------- IP showcase: the two owned festivals, big and visual ---------- */
.ip-showcase { display: grid; gap: 1.15rem; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); }

.ip-card {
  position: relative; display: flex; flex-direction: column; justify-content: flex-end;
  min-height: clamp(340px, 42vw, 460px); border-radius: var(--radius); overflow: hidden;
  text-decoration: none; color: var(--cream);
  border: 1px solid var(--navy-line); isolation: isolate;
}
.ip-card img.bg {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  z-index: -2; transition: transform .7s cubic-bezier(.2,.7,.3,1);
}
.ip-card::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to top, rgba(11,18,32,.94) 0%, rgba(11,18,32,.62) 42%, rgba(11,18,32,.18) 100%);
}
.ip-card:hover img.bg { transform: scale(1.05); }
.ip-card:hover { border-color: var(--amber); }
.ip-card-body { padding: clamp(1.3rem, 3vw, 2rem); }
.ip-card .ip-logo { height: 40px; width: auto; margin-bottom: .9rem; opacity: .95; }
.ip-card h3 {
  font-family: var(--display); font-size: clamp(1.5rem, 3vw, 2.1rem);
  margin: 0 0 .45rem; letter-spacing: -0.01em;
}
.ip-card p { margin: 0 0 .7rem; color: rgba(248,242,231,.86); font-size: .93rem; max-width: 46ch; }
.ip-card .names {
  font-family: var(--mono); font-size: .66rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--amber); line-height: 1.8;
}
.ip-card .more { font-size: .86rem; font-weight: 600; margin-top: .8rem; }

/* ---------- photo strip / marquee ---------- */
.strip-wrap { overflow: hidden; border-block: 1px solid var(--navy-line); padding: 1.15rem 0; }
.strip { display: flex; gap: .8rem; width: max-content; animation: stripScroll 60s linear infinite; }
.strip:hover { animation-play-state: paused; }
.strip figure { margin: 0; width: 210px; flex: 0 0 auto; }
.strip img {
  width: 100%; height: 132px; object-fit: cover; border-radius: 8px;
  filter: saturate(.9) contrast(1.05); opacity: .9;
}
.strip figcaption {
  font-family: var(--mono); font-size: .6rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--cream-faint); margin-top: .45rem;
}
@keyframes stripScroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
  .strip { animation: none; width: 100%; overflow-x: auto; }
}

/* ---------- media card: card with a real image on top ---------- */
.card .thumb {
  margin: -1.4rem -1.45rem .95rem; height: 168px; overflow: hidden;
  border-radius: var(--radius) var(--radius) 0 0;
}
/* Faces sit in the UPPER part of a performance photo, so a centred cover-crop
   slices them — Gurdas Maan lost his whole face above the mouth in a card. Bias
   every cover crop upward. Images whose subject sits low override this inline
   (see FOCUS in gen_site.py). */
.card .thumb img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 35%;
  transition: transform .55s ease;
}
a.card:hover .thumb img { transform: scale(1.06); }


/* Offer cards carry a photo now — shorter than the case-card thumb because the
   four-up grid is narrow and the point is a glance, not a gallery. */
.grid-4 .card .thumb { height: 118px; margin: -1.4rem -1.45rem .85rem; }
/* (phone thumb height now set with the rest of the phone tile rules, above) */

/* ---------- feature band: full-width image with copy over it ---------- */
.feature {
  position: relative; border-radius: var(--radius); overflow: hidden;
  border: 1px solid var(--navy-line); isolation: isolate;
  display: flex; align-items: flex-end; min-height: clamp(280px, 34vw, 400px);
}
.feature img.bg {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2;
}
.feature::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(100deg, rgba(11,18,32,.94) 0%, rgba(11,18,32,.80) 38%, rgba(11,18,32,.30) 66%, rgba(11,18,32,.08) 100%);
}
.feature-body { padding: clamp(1.1rem, 3vw, 2rem); max-width: 72ch; }
.feature-body h2 {
  font-family: var(--display); font-size: clamp(1.5rem, 3.4vw, 2.4rem);
  margin: 0 0 .6rem; letter-spacing: -0.015em;
}
.feature-body p { color: rgba(248,242,231,.88); margin: 0 0 1rem; }

/* ---------- split: image beside copy ---------- */
.split { display: grid; gap: clamp(1.2rem, 3vw, 2.5rem); align-items: center;
         grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.split img { width: 100%; border-radius: var(--radius); border: 1px solid var(--navy-line); }
.split-copy h2 { font-family: var(--display); font-size: clamp(1.4rem, 3vw, 2.1rem); margin: 0 0 .8rem; }

/* ---------- page-head with an image behind it (inner pages) ---------- */
.page-head.has-media { position: relative; isolation: isolate; }
.page-head.has-media img.bg {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2; opacity: .5;
}
.page-head.has-media::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to bottom, rgba(11,18,32,.8) 0%, rgba(11,18,32,.9) 60%, var(--navy) 100%);
}

/* ---------- artist portrait tiles ---------- */
.card img.portrait {
  width: 100%; aspect-ratio: 4/3; object-fit: cover;
  border-radius: 10px; margin-bottom: .75rem;
}

/* ---------- legal line — every page, below the footer columns ---------- */
.foot-legal {
  margin-top: 1rem; padding-top: 1rem;
  border-top: 1px solid var(--navy-line);
  font-size: .76rem; color: var(--cream-faint); letter-spacing: .01em;
}

/* ── Case-study carousel ───────────────────────────────────────────────────
   Case-study pages were 100% text. These prove the job was delivered.
   Scroll-snap rather than a JS library: real swipe on a phone, and if the
   arrow script never runs it is still a usable scrollable strip.        */
.cc { position: relative; margin-top: .3rem; }
.cc-track {
  display: flex; gap: .8rem; overflow-x: auto; scroll-snap-type: x mandatory;
  scroll-behavior: smooth; padding-bottom: .6rem;
  scrollbar-width: thin; scrollbar-color: rgba(248,242,231,.25) transparent;
}
.cc-track::-webkit-scrollbar { height: 6px; }
.cc-track::-webkit-scrollbar-thumb { background: rgba(248,242,231,.22); border-radius: 3px; }
.cc-cell {
  flex: 0 0 clamp(230px, 30%, 330px); margin: 0; scroll-snap-align: start;
}
.cc-cell img {
  width: 100%; height: 215px; border-radius: var(--radius);
  border: 1px solid var(--navy-line); display: block; background: #0d1220;
}
/* Shorts thumbnails are 9:16 — give them their real shape instead of
   letterboxing a vertical card into a landscape slot. */
.cc-cell.cc-vshort { flex: 0 0 clamp(140px, 15vw, 180px); }
.cc-cell.cc-vshort img { height: auto; aspect-ratio: 9 / 16; object-fit: cover; }

/* photos may be cropped; posters must NOT be — they carry the partner branding */
.cc-photo img  { object-fit: cover; object-position: 50% 35%; }
.cc-poster img { object-fit: contain; padding: 4px; }
/* the clips are vertical 9:16 — contain, like posters, so nothing is cropped off */
.cc-cell video {
  width: 100%; height: 215px; object-fit: contain;
  border-radius: var(--radius); border: 1px solid var(--navy-line);
  background: #0d1220; display: block;
}
.cc-cell figcaption {
  margin-top: .45rem; font-size: .78rem; line-height: 1.35;
  color: rgba(248, 242, 231, 0.6);
}
.cc-nav {
  position: absolute; top: 92px; z-index: 2; width: 34px; height: 34px;
  border-radius: 50%; border: 1px solid var(--navy-line);
  background: rgba(11, 18, 32, 0.82); color: var(--cream);
  font-size: 1.15rem; line-height: 1; cursor: pointer; display: none;
}
.cc-nav:hover { background: rgba(232, 155, 69, 0.9); color: #0B1220; }
.cc-prev { left: -14px; } .cc-next { right: -14px; }
.cc[data-ready] .cc-nav { display: block; }
.cc-note { margin-top: .9rem; font-size: .82rem; color: rgba(248, 242, 231, 0.5); }
@media (max-width: 700px) {
  .cc-cell { flex: 0 0 86%; }
  .cc-nav { display: none !important; }
}

/* ── Artist gallery — the hero ─────────────────────────────────────────────
   Karan, 31 Aug: "the images are coming too low, the images should come up
   ... one can select what kind of artist they want ... gallery has to be the
   hero everywhere across the website."

   So the roster leads the page and the prose follows it, and the tile is built
   around the photograph rather than around a paragraph. Denser than .card
   (which is a reading unit) because this is a scanning unit — you are looking
   for a face you recognise, not reading 64 bios. */
.gal-filter {
  display: flex; flex-wrap: wrap; gap: .5rem; margin: 0 0 1.35rem;
  padding: 0; list-style: none;
}
.gal-chip {
  font-family: var(--mono); font-size: .68rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--cream-dim);
  background: transparent; border: 1px solid var(--navy-line);
  border-radius: 999px; padding: .5rem .9rem; cursor: pointer;
  transition: color .18s ease, border-color .18s ease, background .18s ease;
}
.gal-chip:hover { color: var(--cream); border-color: var(--cream-faint); }
.gal-chip:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; }
.gal-chip[aria-pressed="true"] {
  color: var(--ink); background: var(--amber); border-color: var(--amber);
}
.gal-chip .n { opacity: .6; margin-left: .45rem; }

.gal {
  display: grid; gap: .95rem;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
}
@media (max-width: 560px) { .gal { grid-template-columns: repeat(2, 1fr); gap: .7rem; } }

.gal-item {
  display: flex; flex-direction: column; gap: .45rem;
  text-decoration: none; color: inherit;
}
.gal-item .shot {
  position: relative; aspect-ratio: 4/3; overflow: hidden;
  border-radius: 10px; background: rgba(248, 242, 231, 0.05);
  border: 1px solid var(--navy-line);
}
.gal-item .shot img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 32%;
  transition: transform .5s ease;
}
a.gal-item:hover .shot img { transform: scale(1.05); }
a.gal-item:hover .shot { border-color: var(--amber); }
/* No photograph yet: initials, never a stand-in face. */
.gal-item .shot[data-initials]::after {
  content: attr(data-initials);
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--display); font-size: 1.5rem; color: var(--cream-faint);
}
.gal-item h3 {
  font-family: var(--sans); font-size: .88rem; font-weight: 600;
  line-height: 1.25; margin: 0; color: var(--cream);
}
.gal-item .cat {
  font-family: var(--mono); font-size: .58rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--amber);
}
.gal-item[hidden] { display: none; }
.gal-empty { color: var(--cream-dim); font-size: .92rem; }


/* ══════════════════════════════════════════════════════════════════════════
   MOBILE TAP TARGETS — 44px minimum
   ─────────────────────────────────────────────────────────────────────────
   Measured at 375px: .gal-chip was 79x32, .back-link 114x29, breadcrumb
   links 35x15 and footer links 73x17 — all under the 44px minimum for a
   fingertip. Every fix here grows the *box* (min-height + centring) and
   leaves type size, colour and copy untouched, so nothing re-flows
   horizontally and nothing overlaps: the elements sit in single columns or
   in already-wrapping rows, so extra height only adds vertical pitch.
   Scoped to phones/small tablets — desktop pointer targets are unchanged.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 767px) {

  /* Filter chips (artist gallery). Padding-inline is kept so the pill keeps
     its shape; only the vertical box grows 32px -> 44px. .gal-filter already
     wraps, so the extra height just makes the rows taller. */
  .gal-chip {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 44px; padding-block: 0;
  }

  /* Back pill. Same pill, taller box — the border-radius is 999px so it
     stays a capsule rather than becoming a rectangle. */
  .back-link { min-height: 44px; }

  /* Breadcrumbs. inline-flex + vertical-align keeps them on one baseline row
     next to their "/" separators while each link gets a 44px hit box. The
     separators keep them horizontally apart, so no two boxes touch. */
  .crumbs a { display: inline-flex; align-items: center; min-height: 44px; vertical-align: middle; }
  .crumbs span { vertical-align: middle; }

  /* Footer link columns. The list gap is dropped to 0 because each link now
     carries its own 44px of height — keeping the old .5rem gap on top would
     have made the footer needlessly long. Pitch is exactly 44px: adjacent
     links touch but never overlap. width:100% makes the whole row tappable. */
  .foot-grid ul { gap: 0; }
  .foot-grid li { display: flex; }
  .foot-grid a { display: flex; align-items: center; min-height: 44px; width: 100%; }

  /* Footer base row (Instagram / YouTube / email). Already a wrapping flex
     row, so taller links only add row height. */
  .foot-base a { display: inline-flex; align-items: center; min-height: 44px; }
}


/* ══════════════════════════════════════════════════════════════════════════
   MOBILE OVERFLOW & GEOMETRY SWEEP
   ─────────────────────────────────────────────────────────────────────────
   Companion to the tap-target block above. Horizontal overflow was already
   clean on all 31 pages at 375/390/414/768 (documentElement.scrollWidth never
   exceeded innerWidth, and neither html nor body carries an overflow-x:hidden
   that could be hiding one). What follows are the geometry and legibility
   faults that measuring turned up instead. Additive only — every rule is an
   override at the end of the file, nothing above is restructured.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 1. Feature band: the scrim runs the wrong way on a phone ──────────────
   .feature::after is a 100deg (left-to-right) scrim: 94% opaque navy at the
   left, 8% at the right. That is correct for the shape the band has on a
   desktop — a 2.5:1 letterbox where .feature-body occupies the left third and
   the photograph is allowed to breathe on the right.

   On a phone the band flips to PORTRAIT (measured 335x432 on the homepage:
   the height is set by the stacked copy, not by min-height), and .feature-body
   then spans the full width — max-width:72ch stops binding below ~640px. So
   the right half of every paragraph lands on the 30%->8% tail of the scrim,
   i.e. on bare artwork. On /: the body copy sat directly on top of the words
   "80 MILLION+ VIEWS" and "3.5 LAKH SUBSCRIBERS" baked into
   eighty-million.webp — two competing texts in the same pixels.

   Rotating the scrim to vertical matches the axis the band actually stacks on
   below 700px: artwork still reads at the top, copy gets an even ground. */
@media (max-width: 700px) {
  .feature::after {
    background: linear-gradient(to bottom,
      rgba(11, 18, 32, 0.45) 0%,
      rgba(11, 18, 32, 0.88) 26%,
      rgba(11, 18, 32, 0.96) 100%);
  }
}

/* ── 2. Proof strips: the edge fade was eating real words ──────────────────
   .ps reuses .logo-marquee for its scroll/swipe behaviour, and inherits that
   class's edge mask: transparent -> #000 at 6%, #000 -> transparent at 94%.
   That fade exists to hide the wrap seam of the CLIENT WALL, which is an
   infinite doubled marquee — it is never at rest, so no logo ever sits under
   the fade for longer than a frame.

   A proof strip is the opposite: [data-proof] is finite and never drifts (see
   js/site.js), so it sits at scrollLeft 0 with .ps-track flush to x=0 and its
   first cell permanently under the fade. Because the mask length is a
   PERCENTAGE of the viewport, at 375px it is 22.5px — measured: the "S" of
   "Seedhe Maut" and the "F" of "For Skillbox" were rendered at near-zero
   alpha on /what-we-do/. The same happened to the last cell at the right end.

   Fix is two halves that have to agree: pin the fade to a fixed length, and
   inset the track by that same length so no cell can rest underneath it. The
   strip still bleeds edge-to-edge while scrolling, which is the point of it. */
.logo-marquee[data-proof] {
  --ps-fade: 20px;
  -webkit-mask-image: linear-gradient(90deg, transparent 0,
    #000 var(--ps-fade), #000 calc(100% - var(--ps-fade)), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0,
    #000 var(--ps-fade), #000 calc(100% - var(--ps-fade)), transparent 100%);
}
.logo-marquee[data-proof] .ps-track { padding-inline: 20px; }

/* ── 3. Horizontal scrollers must not chain to the page ────────────────────
   .ip-marquee and .artists-marquee-wrap (hero.css) both already set
   overscroll-behavior-x: contain. .logo-marquee — the client wall AND every
   proof strip — did not, so a swipe carried past either end of a finite strip
   chains outward: on iOS that is the back-navigation gesture, which sends the
   visitor off the page while they are trying to look at photographs.
   overflow-y is already hidden here, so vertical page scroll is unaffected. */
.logo-marquee { overscroll-behavior-x: contain; }
/* .cc-track is a real scroll-snap carousel; same reasoning, same fix. */
.cc-track { overscroll-behavior-x: contain; }

/* ── 4. Body text below the 14px floor ─────────────────────────────────────
   Measured at 375px. Each of these carries sentences a visitor is meant to
   read, not a label or a caption, so each is lifted to exactly 0.875rem/14px
   — the smallest value that clears the floor, chosen so the reflow is under
   a pixel per line and no card changes its column count.
     .grid-4 .card p    .84rem  13.44px  offer-card body (phones only)
     .card .more        .84rem  13.44px  card call-to-action
     .ip-card .more     .86rem  13.76px  IP-card call-to-action
     .fact-label        .82rem  13.12px  the sentence under each big number
     .ip-video-title    .85rem  13.60px  homepage video-card titles (hero.css;
                                         site.css loads after it, so this wins)
   Deliberately NOT touched, and reported instead: .foot-legal (.76rem) and the
   figcaption spans under photographs (.76rem) are fine print and captions, a
   tier where sub-14px is conventional, and lifting them would re-flow every
   photo strip and footer on the site. That is Karan's call, not mine. */
/* (phone offer-card paragraph is hidden; see the phone tile rules) */
.card .more    { font-size: .875rem; }
.ip-card .more { font-size: .875rem; }
.fact-label    { font-size: .875rem; }
.ip-video-title { font-size: .875rem; }

/* --- Beyond India ---------------------------------------------------------
   Karan, 7 Sep: the site said nothing about work outside India, while the
   whole of /what-we-do/ read as Madhya-Pradesh-only. Text-only by necessity:
   the only images on file are travel snapshots from the old White Walls site
   (a Thai cultural show the team attended, Tashkent airport arrivals) and a
   2012 dealer-trip aftermovie branded to another production company. None of
   it shows an exhibition or conference being executed, so none of it can
   honestly illustrate this claim. */
.reach { border-top: 1px solid rgba(248,242,231,.14); }
.reach-title {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: clamp(1.6rem, 3.4vw, 2.3rem);
  line-height: 1.1; margin: 0 0 .6rem;
}
.reach-lede { max-width: var(--measure); margin: 0 0 1.5rem; line-height: 1.65; opacity: .88; }
.reach-places {
  display: flex; flex-wrap: wrap; gap: .6rem; list-style: none; padding: 0; margin: 0;
}
.reach-place {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: .74rem; letter-spacing: .14em; text-transform: uppercase;
  padding: .55rem 1.05rem; border-radius: 999px;
  border: 1px solid rgba(228,185,91,.42);
  color: #E4B95B;
  white-space: nowrap;
}
@media (max-width: 480px) {
  .reach-place { font-size: .68rem; padding: .5rem .85rem; }
}


/* ==========================================================================
   TYPOGRAPHY, RHYTHM & TARGET PASS — 2026-09-16
   Appended deliberately: several rules here must beat declarations set
   earlier in this file (.card h3 size, .card .more, .crumbs a).
   Every number below was measured in headless Chromium at 1440x900 and
   390x844 against the built pages, not estimated.
   ========================================================================== */

/* --- 1. Heading balance ---------------------------------------------------
   Nothing in this stylesheet set text-wrap before this pass. Measured at
   390px, seven pages carried a two-line h2 whose second line was less than
   60% of the first ("Where we have produced, / across India" — 29 chars then
   12). `balance` evens the lines; `pretty` only stops single-word last lines,
   which is what body copy needs. */
h1, h2, h3, h4,
.section-title, .reach-title, .cta-band h2, .card h3, .step h3, .ip-card h3 {
  text-wrap: balance;
}
p, li, .answer, .lede, .faq summary, figcaption {
  text-wrap: pretty;
}

/* --- 2. Card heading tier -------------------------------------------------
   .section h3 set card titles at clamp(1.15rem,2vw,1.5rem) = 24px at 1440px.
   A 24px serif title over 14.7px body inside a 342px card put card headings
   only 16px below the page's section titles — part of why every level read
   as equally important. 20px restores a real step (44 -> 26 -> 20). */
.card h3, .grid .card h3 {
  font-size: clamp(1.05rem, 1.35vw, 1.25rem);
  line-height: 1.22;
}

/* --- 3. Card grids: no orphan rows ---------------------------------------
   .grid-3 is repeat(auto-fit, minmax(265px,1fr)), which resolves to exactly
   3 columns at every desktop width. Measured item counts in the built pages:
     /work/                          7 cards  -> 3 + 3 + 1  (lone orphan)
     /guides/                        4 cards  -> 3 + 1      (lone orphan)
     /ips/                           5 cards  -> 3 + 2      (acceptable)
     /guides/film-festivals-in-india/ 6 cards -> 3 + 3      (fine)
   Quantity queries fix the two orphan cases without touching the content, so
   a page that gains or loses a card re-lays itself correctly.
   :has() is Chrome 105+ / Safari 15.4+ / Firefox 121+; browsers without it
   keep the current 3-column behaviour, which is the existing appearance. */
@media (min-width: 880px) {
  /* 4 items read as a 2x2 block, not a row of three with a straggler. */
  .grid-3:has(> :last-child:nth-child(4)) { grid-template-columns: repeat(2, 1fr); }
  /* 7 items go to four columns: 4 + 3. */
  .grid-3:has(> :last-child:nth-child(7)) { grid-template-columns: repeat(4, 1fr); }
}

/* --- 4. Mobile tap targets (>= 44x44) -------------------------------------
   Measured at 390px across all 13 pages. Four controls failed; the counts are
   instances across the whole site.
     .crumbs a            35 x 44   x15   below on width
     .card .more a       151 x 17    x2   standalone CTA inside a non-link card
     .hero-nav a          29 x 12    x5   /consultants/ only
   Inline links inside .ticks running text (20px tall) are NOT padded out:
   WCAG 2.5.8 exempts links in a sentence, and boxing them would break the
   line rhythm of the prose they sit in. Reported, not changed. */
.crumbs a {
  display: inline-flex; align-items: center;
  min-height: 44px; min-width: 44px; justify-content: center;
  padding-inline: .35rem;
}
.card .more a,
a.card .more {
  display: inline-flex; align-items: center; min-height: 44px;
}
/* .hero-nav lives in hero.css, which the root index.html and /journey/ also
   load — but they do NOT load site.css, so scoping the fix here reaches
   /consultants/ (the only site.css page with a hero) and cannot collide with
   the journey workstream. */
.hero-nav a {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px; padding-inline: .3rem;
}

/* --- 5. Page head -> first section --------------------------------------
   .page-head ended with 25.6px of padding and the first .section opened with
   40px, so the standfirst sat 65.6px from the first section — near-identical
   to the 80px between two unrelated sections. The head and the block that
   answers it now read as one unit. */
.page-head + .section,
.page-head + .section--cont { padding-top: var(--gap-minor); border-top: 0; }


/* --- phone heading ladder --------------------------------------------------
   At 390px the h1 floor (2.1rem = 33.6px) sat only 1.2x above the section h2
   (28px), so nothing on the page was clearly the title. 2.3rem = 36.8px gives
   h1 37 / h2 28 / back-matter h2 22 / card h3 17 / body 16. Desktop untouched. */
@media (max-width: 560px) {
  .page-head h1 { font-size: 2.3rem; line-height: 1.06; }
  /* Mono eyebrows are .68rem = 10.9px. Fine for "What we do"; not for the
     43-character "The Great Indian Film & Literature Festival" on /ips/giflif-fest/,
     which wrapped to two lines below the 12px legibility floor. */
  .eyebrow, .page-head .eyebrow, .kicker { font-size: .74rem; letter-spacing: .22em; }
  .section--minor > .wrap > h2,
  .section--minor .section-title,
  .section--minor .reach-title { font-size: 1.35rem; }
}
