/* Team, about and case-study pages. */
.figure__ph, .member__ph {
  display: grid; place-content: center; text-align: center;
  border: 2px dashed var(--surface-line); border-radius: var(--radius-lg);
  color: var(--text-lo); font-family: var(--font-mono); font-size: var(--fs-xs);
  padding: var(--s-8); min-height: 16rem; line-height: 1.6;
}
.member__ph { min-height: 0; aspect-ratio: 1; padding: var(--s-4); }

.team { display: grid; gap: var(--s-8); }
.member {
  display: grid; gap: var(--s-6); grid-template-columns: 1fr;
  padding-bottom: var(--s-8); border-bottom: 1px solid var(--surface-line);
}
@media (min-width: 48rem) { .member { grid-template-columns: 12rem 1fr; align-items: start; } }
/* The founder gets more room — hierarchy, not decoration. */
@media (min-width: 62rem) { .member--lead { grid-template-columns: 18rem 1fr; gap: var(--s-12); } }

.member__name { font-size: var(--fs-h3); margin-bottom: var(--s-1); }
.member--lead .member__name { font-size: var(--fs-h2); }
.member__role {
  font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--accent-ink); margin-bottom: var(--s-4);
}
.member__bio { color: var(--text-mid); }
.member__creds { display: grid; gap: var(--s-2); margin-top: var(--s-4); }
.member__creds li {
  font-size: var(--fs-sm); color: var(--text-mid);
  padding-left: var(--s-5); position: relative;
}
.member__creds li::before {
  content: ""; position: absolute; left: 0; top: 0.6em;
  width: 6px; height: 6px; border-radius: 50%; background: var(--y-yellow);
}
.team__note { margin-top: var(--s-8); color: var(--text-lo); font-size: var(--fs-sm); }

/* Case studies */
.case__meta { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-6); }
.case__body { max-width: 68ch; }
.case__body h2 { font-size: var(--fs-h3); margin-top: var(--s-12); }
.case__body p { color: var(--text-mid); }
.case__needs {
  display: inline-block; padding: 0.1em 0.5em; border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--y-red) 18%, transparent);
  color: var(--y-red-300); font-family: var(--font-mono); font-size: 0.85em;
}
.case__list { display: grid; gap: var(--s-3); margin: 0 0 var(--s-6); }
.case__list li { padding-left: var(--s-6); position: relative; color: var(--text-mid); }
.case__list li::before {
  content: ""; position: absolute; left: 0; top: 0.7em;
  width: 6px; height: 6px; border-radius: 50%; background: var(--y-yellow);
}

/* --- Case study list --------------------------------------------------- */
.caselist { display: grid; gap: 0; }
.caserow {
  display: block; padding: var(--s-8) 0;
  border-bottom: 1px solid var(--surface-line);
  text-decoration: none;
  transition: padding-left var(--dur) var(--ease-out);
}
.caserow:first-child { border-top: 1px solid var(--surface-line); }
.caserow:hover { padding-left: var(--s-4); }
.caserow__tag {
  font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--text-lo); margin-bottom: var(--s-3);
}
.caserow__title {
  font-size: var(--fs-h3); color: var(--text-hi);
  margin-bottom: var(--s-2); max-width: 24ch;
}
/* The flagship gets more type. Hierarchy in a list of six, not decoration. */
.caserow--lead .caserow__title { font-size: var(--fs-h2); }
.caserow__hook { color: var(--text-mid); max-width: 62ch; }
.caserow__go { font-size: var(--fs-sm); font-weight: 600; color: var(--accent-ink); }

/* --------------------------------------------------------------------------
   Case rows with artwork.

   The rows were text-only across the full width, so the right half of every
   one was empty. Each now carries the actual artefact — a live screenshot of
   the site we built, a frame from the film we made, the published YouTube
   still — which is the difference between a portfolio and a list of claims.
   -------------------------------------------------------------------------- */
.caserow {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr);
  gap: clamp(var(--s-5), 3vw, var(--s-10));
  align-items: center;
}
.caserow__copy { min-width: 0; }

.caserow__art {
  margin: 0;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--surface-line);
  background: var(--surface-1);
  aspect-ratio: 16 / 10;
}
.caserow__art img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  /* Screenshots are top-weighted — the header and hero are the recognisable
     part — so the crop holds the top rather than centring on body content. */
  object-position: 50% 12%;
  /* Muted at rest so six plates down a page do not shout over the headings;
     colour returns on the row being read. */
  filter: saturate(0.72) brightness(0.82);
  transform: scale(1.02);
  transition: filter var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
}
.caserow:hover .caserow__art img { filter: none; transform: scale(1.06); }

/* The lead row gets a larger plate — it is the flagship and reads as one. */
.caserow--lead { grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr); }

/* Below ~54rem the plate would be a letterbox strip beside squeezed type, so
   it stacks above the copy where it still does its job. */
@media (max-width: 54rem) {
  .caserow { grid-template-columns: 1fr; }
  .caserow--lead { grid-template-columns: 1fr; }
  .caserow__art { order: -1; aspect-ratio: 16 / 9; }
}

/* ==========================================================================
   CASE STUDY — media-first.
   The prose version ran ~900 words per study. These pages now lead with the
   artefacts and carry the argument in captions; the grid is deliberately
   irregular so it reads as a wall of work rather than a product listing.
   ========================================================================== */

/* --- stat band — NOT CURRENTLY RENDERED ---
   Removed from every case study in includes/work.php; the rules are kept so
   restoring the band is uncommenting one block there, not rebuilding a layout.
   If it is still unused when this file is next touched, delete it. */
.casestat__band { padding-block: clamp(var(--s-6), 3vw, var(--s-10)); }
.casestat {
  display: grid; gap: var(--s-6);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
}
.casestat__item { border-top: 2px solid var(--y-yellow); padding-top: var(--s-4); }
.casestat__n {
  font-family: var(--font-display); font-size: clamp(2rem, 1.2rem + 2.6vw, 3.25rem);
  line-height: 1; letter-spacing: -0.03em; color: var(--text-hi); margin: 0 0 var(--s-2);
  font-variant-numeric: tabular-nums;
}
.casestat__l { color: var(--text-mid); font-size: var(--fs-sm); margin: 0; }

/* --- the grid --- */
/* Uniform tiles, three across.
   The first pass ran every third card full width for rhythm, but at these
   image sizes a full-width card was ~600px tall and the page turned into one
   enormous picture per screen. Same size for everything reads as a contact
   sheet of the work, which is what a portfolio grid should be. */
.casegrid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(var(--s-4), 2vw, var(--s-6));
}
.casecard { margin: 0; min-width: 0; }

@media (max-width: 60rem) { .casegrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 34rem) { .casegrid { grid-template-columns: 1fr; } }

.casecard__frame {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--surface-line);
  background: var(--surface-1);
  transform: perspective(1000px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg));
  transition: transform var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out),
              box-shadow var(--dur) var(--ease-out);
}
/* One ratio for every tile, so the grid lines up on every row regardless of
   whether the source is a 16:9 screenshot or a 9:16 reel. */
.casecard__frame { max-height: 15rem; }
.casecard:hover .casecard__frame {
  border-color: rgb(240 198 74 / 0.5);
  box-shadow: var(--glow-yellow);
}
.casecard__m {
  width: 100%; height: 100%; object-fit: cover; display: block;
  /* Screenshots and scene frames are both top-weighted — the header of a site
     and the subject of a shot both sit above centre. */
  object-position: 50% 18%;
  transition: transform var(--dur-slow) var(--ease-out);
}
.casecard:hover .casecard__m { transform: scale(1.04); }

.casecard__sheen {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 50%),
              rgb(255 255 255 / 0.14), transparent 62%);
  opacity: 0; transition: opacity var(--dur) var(--ease-out);
}
.casecard:hover .casecard__sheen { opacity: 1; }

/* Video cards get a play mark so a still frame is not mistaken for a photo. */
/* The sound toggle. Sits where the play triangle used to, because that is the
   corner a visitor already looks at on a clip — but it is a real <button>
   rather than the decorative span the triangle was, since this one does
   something. */
.casecard__sound {
  position: absolute; right: var(--s-3); bottom: var(--s-3); z-index: 2;
  display: grid; place-items: center;
  width: 2.5rem; height: 2.5rem; padding: 0; border-radius: 50%;
  background: rgb(13 13 15 / 0.7); border: 1px solid rgb(255 255 255 / 0.25);
  backdrop-filter: blur(8px); color: var(--y-white); cursor: pointer;
  transition: border-color var(--dur) var(--ease-out), background-color var(--dur) var(--ease-out);
}
.casecard__sound svg { width: 1.1rem; height: 1.1rem; display: block; }
.casecard__sound:hover, .casecard__sound:focus-visible {
  border-color: var(--y-yellow); background: rgb(13 13 15 / 0.88);
}
/* Unmuted is a state worth seeing at a glance — on a grid of clips it is the
   only way to tell which one is making the noise. */
.casecard__sound[aria-pressed="true"] {
  background: var(--y-yellow); border-color: transparent; color: var(--y-black);
}
/* The card is tilted by data-tilt; the button has to stay clickable on top. */
.casecard__frame { position: relative; }

.casecard__cap { display: grid; gap: 2px; padding-top: var(--s-3); }
.casecard__tag {
  font-size: var(--fs-xs); letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase; color: var(--accent-ink);
}
.casecard__note { color: var(--text-mid); font-size: var(--fs-sm); line-height: var(--lh-snug); }

/* --- handover note --- */
.caseadmin {
  margin: clamp(var(--s-8), 4vw, var(--s-12)) 0 0;
  padding: var(--s-5) var(--s-6);
  border-radius: var(--radius);
  border: 1px solid rgb(240 198 74 / 0.32);
  background: rgb(240 198 74 / 0.05);
  color: var(--text-mid); max-width: none;
  display: grid; gap: var(--s-2);
}
.caseadmin__k {
  font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--y-yellow);
}

/* --- portrait grid (all-reel case studies) --------------------------------
   Sikha and Ge'sha are entirely 9:16 source — reels at 576×1024 and stills up
   to 1000×1968. The shared 16:10 tile centre-cropped every one of them into a
   letterbox, cutting the top of the head off a talking-head reel. These pages
   opt in via `orient` in case_media() and get true 9:16 tiles.

   Deliberately placed AFTER the .casegrid media queries above: those carry the
   same specificity, so anything declared earlier would lose to them on source
   order and the portrait grid would silently revert to 2-up on tablets.

   `--cols` comes from PHP so the last row is not ragged. The max-width caps a
   tile at ~17rem; without it a 3-column portrait grid on a wide screen makes
   each tile ~400px wide and 710px tall, which is a poster, not a contact
   sheet. */
.casegrid--portrait {
  /* minmax(0, 21rem) caps a tile at phone width so a 3-column grid does not
     grow 400px-wide, 710px-tall posters on a large screen, while still letting
     columns shrink below the cap when --cols is 4 and they cannot all fit.
     `justify-content: start` keeps the grid's left edge on the section heading;
     centring it inside a left-aligned section reads as a layout bug. */
  grid-template-columns: repeat(var(--cols, 4), minmax(0, 21rem));
  justify-content: start;
}
.casegrid--portrait .casecard__frame {
  aspect-ratio: 9 / 16;
  max-height: none;
}
/* The reels are exactly 9:16 so they sit uncropped. The stills vary from 4:5
   to roughly 1:2, so some crop is unavoidable — bias upward, because the face
   is above centre in every one of them. */
.casegrid--portrait .casecard__m { object-position: 50% 22%; }

@media (max-width: 60rem) {
  .casegrid--portrait { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 40rem) {
  .casegrid--portrait { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (hover: none) { .casecard__frame { transform: none; } .casecard__sheen { display: none; } }

/* --- live site embed ------------------------------------------------------
   A frame of the site actually serving traffic, not a screenshot. Only
   rendered where the client's server permits framing; see case_live_site(). */
.livesite {
  margin-top: clamp(var(--s-8), 4vw, var(--s-12));
  border: 1px solid var(--surface-line);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-1);
}
.livesite__head {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--surface-line);
  font-size: var(--fs-sm);
}
.livesite__dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--y-green);
  animation: live-pulse 2s var(--ease-inout) infinite; flex: none;
}
@keyframes live-pulse { 50% { opacity: .3; } }
.livesite__label { color: var(--text-mid); }
.livesite__open { margin-left: auto; color: var(--accent-ink); white-space: nowrap; }
.livesite__frame { position: relative; aspect-ratio: 16 / 10; background: var(--surface-2); }
.livesite__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

@media (prefers-reduced-motion: reduce) { .livesite__dot { animation: none; } }

/* ── CASE-STUDY HERO THUMBNAIL ─────────────────────────────────────────────
   The artefact from the /work/ row, carried onto the page that row opens.
   Same work_art() source for both, so the picture a visitor clicked is the
   one that greets them. */
.case__head { align-items: center; }

/* NOT RENDERED ON A PHONE. `display: none` would still download the file —
   the browser fetches a src it has decided not to paint — so the whole
   <figure> is dropped from the layout AND the image is given no work to do.
   Below 62rem the headline alone owns the hero, which is what it was doing
   before this existed. */
.case__thumb { display: none; margin: 0; }

@media (min-width: 62rem) {
  .case__thumb {
    display: block; justify-self: center;
    border-radius: var(--radius-lg); overflow: hidden;
    border: 1px solid var(--surface-line); box-shadow: var(--shadow-card);
  }
  /* SIZED BY ITS OWN ASPECT, NOT CROPPED TO A FIXED ONE.
     These six artefacts are not one shape: three are landscape screenshots
     (1400x790), one a 16:9 film frame, and two are tall portraits — the
     academy still is 1000x1500 and the jewellery model 1000x1777. Forcing
     16/10 with object-fit:cover took the top off a head on one and cut the
     model in half on the other. Capping both axes and letting the image pick
     its own box means every orientation arrives whole; the figure shrinks to
     whatever it is showing. */
  .case__thumb img {
    display: block; margin-inline: auto;
    max-width: 100%; max-height: 26rem;
    width: auto; height: auto;
  }
  /* A case with no artefact keeps the old single-column hero rather than
     leaving a 5fr column of nothing beside the headline. */
  .case__head--bare { grid-template-columns: 1fr; }
}

/* Closing line under the case list. A <p>, so the measure cap has to be
   released or a centred line sits inside a narrow left-aligned box — the
   trap this stylesheet has now hit five times. */
.caselist__more {
  max-width: none; margin: var(--s-10) 0 0;
  text-align: center; font-size: var(--fs-body-lg); color: var(--text-mid);
}
/* Orphaned 2026-09-22 with the NDA clause it styled. Kept, not deleted: the
   paragraph is still here and a second line may well go back into it. */
.caselist__more span { display: block; margin-top: var(--s-2); font-size: var(--fs-sm); color: var(--text-lo); }

/* ── CORNER-MARK CROP ──────────────────────────────────────────────────────
   Some footage from the avatar shoots carries the generator's mark burned into
   the bottom-right corner. Rather than repair every asset, the tile zooms in
   until that corner sits outside the frame.

   THE BOTTOM IS THE CHEAP CROP, AND THE FIGURE IS MEASURED, NOT GUESSED.
   Sampled from the assets themselves: the mark's top edge lands at 87.9% of
   frame height on the 608x1080 clips and their posters, and at 90.9% on
   studio-1.webp (1000x1968). Pushing that past the frame bottom through
   `object-fit: cover` needs scale > 1/0.879 = 1.138 in the worst case (a frame
   no wider, proportionally, than the media -- when it IS wider, cover already
   crops the bottom and the requirement relaxes). 1.14 therefore cleared it by
   a fraction of a pixel. 1.2 clears it by ~5% of the frame height with the
   faint diffusion rim included, at a cost of 17% off the bottom -- which on
   these knees-up portraits is chair and floor.

   Clearing it sideways instead would cost 21% of the width, which on a
   portrait talking-head starts cutting into the subject.

   `scale`, not `transform`: the card carries data-tilt and GSAP writes
   `transform` on its own targets. These are separate properties and compose,
   which is the rule this codebase has already paid to learn twice. */
.casecard__frame--crop > .casecard__m {
  scale: 1.2;
  transform-origin: 50% 0;   /* anchor the top, push the bottom out */
}

/* ── WHY US GRID ───────────────────────────────────────────────────────────
   Six reassurance cards under the case list. Three across, then two, then one.

   TWO TRAPS THIS CODEBASE HAS PAID FOR ALREADY, BOTH AVOIDED HERE:

   1. THE MEASURE CAP. site.css sets `p { max-width: var(--measure) }`. Both
      paragraphs in this card are <p>, so without `max-width: none` they stop
      at the prose measure and leave a ragged gutter inside a box that is
      already narrower than the measure. That is the single most repeated bug
      on this site.

   2. FLEX, NOT GRID ROWS, to pin the proof pill to the foot. The homepage
      services grid tried `grid-template-rows: … 1fr auto` for the same job and
      it does not work: these cards are stretched by the outer grid to the
      tallest in their row, and a stretched grid container hands the leftover
      to its AUTO tracks, not to the `1fr` one. The pill drifted. `flex: 1` on
      the body absorbs the slack instead and the pill lands on the floor every
      time. */
.whyx {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: clamp(var(--s-3), 1.4vw, var(--s-5));
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
@media (max-width: 68rem) { .whyx { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 40rem) { .whyx { grid-template-columns: 1fr; } }

.whyx__card {
  display: flex; flex-direction: column; gap: var(--s-3);
  min-width: 0;
  padding: clamp(var(--s-5), 2vw, var(--s-7));
  border: 1px solid var(--surface-line);
  border-radius: var(--radius-lg);
  background: linear-gradient(160deg, var(--surface-1), var(--surface-0));
  transition: border-color var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-out),
              box-shadow var(--dur) var(--ease-out);
}
.whyx__card:hover {
  border-color: rgb(240 198 74 / 0.45);
  transform: translateY(-3px);
  box-shadow: 0 22px 50px -28px rgb(0 0 0 / 0.85);
}
@media (hover: none) { .whyx__card:hover { transform: none; } }

/* The icon sits in its own tinted disc so six line drawings of different
   visual weight still read as one set. */
.whyx__badge {
  display: grid; place-items: center;
  width: 2.9rem; height: 2.9rem; border-radius: 50%;
  border: 1px solid rgb(240 198 74 / 0.3);
  background: rgb(240 198 74 / 0.1);
  color: var(--y-yellow);
  transition: background var(--dur) var(--ease-out), transform var(--dur) var(--ease-out);
}
.whyx__card:hover .whyx__badge { background: rgb(240 198 74 / 0.2); transform: scale(1.06); }
.whyx__icon { width: 1.4rem; height: 1.4rem; display: block; }

.whyx__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 0.95rem + 0.4vw, 1.25rem);
  line-height: var(--lh-snug); letter-spacing: -0.015em;
  color: var(--text-hi);
}
/* flex: 1 — takes the slack so the pill below reaches the foot of the card. */
.whyx__body {
  margin: 0; flex: 1 1 auto; max-width: none;
  color: var(--text-mid); font-size: var(--fs-sm); line-height: var(--lh-relaxed);
}
.whyx__proof { margin: 0; max-width: none; }
.whyx__proof span {
  display: inline-block;
  padding: 0.3rem 0.7rem; border-radius: 999px;
  border: 1px solid rgb(240 198 74 / 0.28);
  background: rgb(240 198 74 / 0.08);
  color: var(--accent-ink);
  font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: 0.04em;
  /* The ISO certificate number is long and has no spaces to break on. Let it
     wrap inside the pill rather than push the card wider than its track. */
  overflow-wrap: anywhere;
}
@media (prefers-reduced-motion: reduce) {
  .whyx__card, .whyx__badge { transition: none; }
  .whyx__card:hover { transform: none; }
}
