/* ==========================================================================
   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;
}

/* ---------- 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: 92ch; 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: 88ch; 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 max-width:68ch at (0,1,1); this needs (0,2,0) to win. */
  max-width: none;
  font-size: clamp(0.98rem, 1.2vw, 1.12rem);
  line-height: 1.6;
}

/* ---------- sections ---------- */
.section { padding: clamp(1.5rem, 3.2vw, 2.5rem) 0; border-top: 1px solid var(--navy-line); }
.section:first-of-type { border-top: 0; }
.section > .wrap > h2, .section-title {
  font-family: var(--display); font-weight: 600;
  font-size: clamp(1.6rem, 3.4vw, 2.5rem); line-height: 1.12;
  letter-spacing: -0.015em; margin: 0 0 .8rem; max-width: 34ch;
}
.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: 90ch; 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. Never collapses to a
   single column — 2x2 is the intended phone layout. */
.grid-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1080px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) {
  .grid-4 { gap: .7rem; }
  .grid-4 .card { padding: 1rem .95rem; }
  .grid-4 .card h3 { font-size: 1.02rem; line-height: 1.25; }
  .grid-4 .card p { font-size: .84rem; }
  .grid-4 .card .kicker { font-size: .62rem; }
}

.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: .5rem; max-width: 88ch; }
.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: 92ch; }
.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: 88ch; }

/* ---------- 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); }

.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; }
@media (max-width: 560px) { .grid-4 .card .thumb { height: 84px; margin: -1rem -.95rem .7rem; } }

/* ---------- 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. */
@media (max-width: 560px) { .grid-4 .card p { font-size: .875rem; } }
.card .more    { font-size: .875rem; }
.ip-card .more { font-size: .875rem; }
.fact-label    { font-size: .875rem; }
.ip-video-title { font-size: .875rem; }
