/* ═══════════════════════════════════════════════════════════════════════════
   Vignesh — video editor. One page.

   THE GROUND IS PAPER, NOT BLACK, AND THAT IS THE WHOLE IDEA. Every video
   portfolio on the internet is a dark page with bright thumbnails, which
   means the thumbnails are competing with a background doing the same thing.
   Invert it: a warm paper ground, ink type, and the films are then the only
   dark saturated rectangles anywhere on the page. Hierarchy falls out for
   free — the work is loudest because nothing else is.

   THE PALETTE COMES OUT OF THE PORTRAIT. The blue is the polo he is wearing
   in DSC00146 and the clay is the wall behind him, sampled rather than
   picked. That is why the photograph sits in the page instead of on it.

   SPENDING THE BOLDNESS IN ONE PLACE. The signature is the scrub: drag your
   cursor across a tile and the footage moves with it, with a live timecode
   under the frame. It is the one gesture that belongs to this subject and
   nobody else's — it is what hovering a clip in an edit bin does. Everything
   around it is deliberately quiet: no gradients, no grain, no glass, one
   accent colour, two type sizes doing most of the work.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  --paper:    #E9E7E2;
  --paper-2:  #DFDCD5;
  --rule:     #CFCBC2;
  --ink:      #17191C;
  --ink-soft: #3B3E43;
  --mute:     #6E7075;
  --blue:     #23407A;   /* the polo */
  --blue-lit: #33589E;
  --clay:     #C0958A;   /* the wall */

  /* SATOSHI, ONE FAMILY, FOUR WEIGHTS. This ran on Bricolage Grotesque over
     Instrument Sans, and the quirks in Bricolage's letterforms read as fussy
     rather than as character. Satoshi is the geometric register Poppins is
     reaching for and misses: closed apertures, a real 900, and tight enough
     at display size to carry a name at 7vw without looking inflated. One
     family across display and body, with the mono kept only for timecode and
     metadata, where a tabular figure is doing an actual job. */
  --display: 'Satoshi', 'Segoe UI', system-ui, sans-serif;
  --body:    'Satoshi', system-ui, -apple-system, sans-serif;
  --mono:    'JetBrains Mono', ui-monospace, Consolas, monospace;

  --rail: clamp(1.15rem, 5vw, 3.25rem);
  --max:  1180px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* One slow curve and one duration, used by every reveal on the page, so the
     whole site moves at a single tempo instead of each section having its own
     idea of what "slow" means. */
  --slow: 1.25s;
  --glide: cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, video { display: block; max-width: 100%; }

a { color: var(--blue); text-decoration-thickness: 1px; text-underline-offset: 3px; }

:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
  border-radius: 1px;
}

.mono { font-family: var(--mono); }

/* Small caps-height utility label. Used for every piece of metadata on the
   page — eyebrows, counts, runtimes, filenames — so that measured facts all
   speak in one voice and prose speaks in another. */
.eyebrow,
.slug {
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mute);
}

/* ─────────────────────────────────────────────────────────────── the bar ── */

.bar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem var(--rail);
  background: color-mix(in srgb, var(--paper) 86%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--rule);
}

.bar__name {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.05rem;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
}

.bar__links {
  display: flex;
  gap: 1.35rem;
  font-family: var(--mono);
  font-size: 0.74rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.bar__links a {
  color: var(--ink-soft);
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s var(--ease), color 0.3s var(--ease);
}

.bar__links a:hover { color: var(--blue); border-bottom-color: var(--blue); }

/* ────────────────────────────────────────────────────────────────── hero ── */

.hero {
  max-width: var(--max);
  margin: 0 auto;
  padding: clamp(2.5rem, 7vw, 5.5rem) var(--rail) clamp(3rem, 8vw, 6rem);
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}

@media (min-width: 880px) {
  .hero { grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr); }
}

.hero__shot { margin: 0; }

/* On a phone the claim has to be the first thing read, so the photograph
   moves below the call to action and does the work of a section break
   instead. On desktop there is room for both at once and it leads. */
@media (max-width: 879px) {
  .hero__shot { order: 2; }
  .hero__say  { order: 1; }
}

.hero__shot img {
  width: 100%;
  height: auto;
  background: var(--paper-2);
  /* A print-like edge rather than a card: thin ink hairline, no radius, no
     drop shadow. The photograph is a photograph, not a UI surface. */
  border: 1px solid var(--rule);
}

.hero__shot figcaption {
  margin-top: 0.85rem;
  font-size: 0.86rem;
  line-height: 1.55;
  color: var(--mute);
  max-width: 34ch;
}

.hero__shot .slug { display: block; margin-bottom: 0.3rem; }

/* The name is the headline now, so it gets the whole size budget. 900 rather
   than the old 800: at this size Satoshi's black weight is the difference
   between a name and a label. */
.hero h1 {
  margin: 0;
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(3.4rem, 11vw, 9.2rem);
  line-height: 0.88;
  letter-spacing: -0.05em;
}

.role {
  margin: 0.7rem 0 0;
  font-size: clamp(1.05rem, 2vw, 1.35rem);
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--ink-soft);
}

/* The proof. Six names, no sentence around them — a list reads as a client
   roster, and a sentence containing the same six names reads as boasting. */
.brands {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.15rem;
  margin: 1.9rem 0 0;
  padding: 1.35rem 0 0;
  border-top: 1px solid var(--rule);
  /* Wide enough that six names fall into two even lines. At 38ch the last one
     wrapped alone onto a third, which reads as an afterthought rather than as
     part of the roster. */
  max-width: 52ch;
  font-family: var(--mono);
  font-size: 0.73rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mute);
}

.brands li { white-space: nowrap; }

/* Six words at the top of the work, in the metadata voice, so it reads as an
   instrument label rather than as more copy. No leading rule: a short
   horizontal line sitting in front of a line of text reads as a dash, which is
   the thing being taken off this page. */
.scrubnote {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--rail) clamp(1.5rem, 4vw, 2.5rem);
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--mute);
}

.cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  margin-top: 2rem;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 0 1.7rem;
  border: 1px solid var(--ink);
  font-family: var(--mono);
  font-size: 0.76rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  background: transparent;
  transition: background-color 0.35s var(--ease), color 0.35s var(--ease), border-color 0.35s var(--ease);
}

.btn:hover { background: var(--ink); color: var(--paper); }

.btn--solid {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

.btn--solid:hover { background: var(--blue); border-color: var(--blue); color: #fff; }

/* ────────────────────────────────────────────────────────────────── bins ── */

.bin {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--rail) clamp(2.75rem, 6vw, 4.5rem);
}

.bin__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  padding-bottom: 0.7rem;
  border-bottom: 1px solid var(--ink);
}

.bin__title {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.3rem, 2.9vw, 1.95rem);
  letter-spacing: -0.032em;
  line-height: 1.1;
}

/* Count and runtime, not "01 / 02 / 03". These sections are kinds of work,
   not a sequence, so a number would be decoration — how many pieces and how
   many minutes is the fact a person hiring actually wants. */
.bin__meta {
  flex-shrink: 0;
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.09em;
  color: var(--mute);
  white-space: nowrap;
}

.bin__note {
  margin: 0.85rem 0 0;
  max-width: 52ch;
  font-size: 0.95rem;
  color: var(--mute);
}

.bin__grid {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(0.75rem, 2vw, 1.4rem);
  margin: clamp(1.4rem, 3vw, 2.2rem) 0 0;
  padding: 0;
}

@media (min-width: 760px) {
  .bin__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ───────────────────────────────────────────────────────────────── tiles ── */

.card {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

/* display:block is load-bearing, not tidiness. This is a <span> so that it can
   live inside the <button> without nesting interactive elements, and an inline
   box ignores aspect-ratio outright — without this the tile collapses to
   nothing and the grid renders as captions with no film above them. */
.tile {
  display: block;
  position: relative;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  background: var(--ink);
}

.tile img,
.tile video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.tile video {
  opacity: 0;
  transition: opacity 0.25s linear;
}

.tile.is-scrubbing video { opacity: 1; }

/* The scrub track. Sits on the frame rather than under it so the cursor and
   the readout are in the same place your eye already is.

   THE PLAYHEAD IS PAPER-COLOURED, NOT THE ACCENT BLUE. It was blue first, on
   a translucent white track, which put a mid-blue bar on top of a lighter
   grey one over black video — the fill read as DARKER than its own track and
   the whole thing vanished. The accent earns its keep everywhere else on this
   page; over footage the only colour with guaranteed contrast is the page's
   own light, so the bar is paper on a dark track. */
.tile__track {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 4px;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity 0.2s linear;
}

.tile.is-scrubbing .tile__track { opacity: 1; }

.tile__fill {
  height: 100%;
  width: 0;
  background: var(--paper);
}

.tile__tc {
  position: absolute;
  left: 0.55rem;
  bottom: 0.6rem;
  padding: 0.15rem 0.4rem;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.04em;
  color: #fff;
  background: rgba(23, 25, 28, 0.72);
  opacity: 0;
  transition: opacity 0.2s linear;
  font-variant-numeric: tabular-nums;
}

.tile.is-scrubbing .tile__tc { opacity: 1; }

/* Touch devices get a play affordance instead, since there is no hover to
   discover the scrub with. */
.tile__play {
  position: absolute;
  right: 0.55rem;
  bottom: 0.6rem;
  width: 30px;
  height: 30px;
  display: none;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: 50%;
  background: rgba(23, 25, 28, 0.5);
}

.tile__play svg { width: 9px; fill: #fff; margin-left: 2px; }

body.no-hover .tile__play { display: flex; }

.card__meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: 0.6rem;
}

.card__client {
  font-size: 0.9rem;
  font-weight: 500;
  line-height: 1.35;
}

.card__craft {
  display: block;
  margin-top: 0.1rem;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--mute);
}

.card__dur {
  flex-shrink: 0;
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--mute);
  font-variant-numeric: tabular-nums;
}

.card:hover .card__client { color: var(--blue); }

/* ───────────────────────────────────────────────────────────────── close ── */

.close {
  max-width: var(--max);
  margin: 0 auto;
  padding: clamp(3rem, 8vw, 6rem) var(--rail) clamp(2.5rem, 6vw, 4rem);
  border-top: 1px solid var(--ink);
}

.close h2 {
  margin: 0;
  max-width: 16ch;
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(2rem, 5.6vw, 3.6rem);
  line-height: 0.98;
  letter-spacing: -0.042em;
  text-wrap: balance;
}

.close > p {
  margin: 1.35rem 0 0;
  max-width: 48ch;
  font-size: 1.02rem;
  color: var(--ink-soft);
  text-wrap: pretty;
}

.credits {
  margin: clamp(2rem, 4vw, 3rem) 0 0;
  display: grid;
  gap: 0;
  max-width: 640px;
}

.credits > div {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 1fr);
  gap: 1rem;
  padding: 0.8rem 0;
  border-top: 1px solid var(--rule);
}

.credits dt {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--mute);
  padding-top: 0.15rem;
}

.credits dd {
  margin: 0;
  font-size: 0.96rem;
  line-height: 1.5;
}

.foot {
  max-width: var(--max);
  margin: 0 auto;
  padding: 1.5rem var(--rail) 2.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mute);
}

.foot a { color: var(--mute); text-decoration: none; border-bottom: 1px solid var(--rule); }
.foot a:hover { color: var(--blue); border-bottom-color: var(--blue); }

/* ──────────────────────────────────────────────────────────────── player ── */

.player {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(20, 22, 25, 0.95);
  backdrop-filter: blur(6px);
}

.player[hidden] { display: none; }

.player__stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  max-width: 100%;
}

.player__stage video {
  max-width: min(94vw, 1200px);
  max-height: 78vh;
  width: auto;
  height: auto;
  background: #000;
}

.player__cap {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 0.35rem 0.85rem;
  text-align: center;
  color: rgba(233, 231, 226, 0.92);
  font-size: 0.92rem;
}

.player__cap span {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: rgba(233, 231, 226, 0.55);
}

.player__close {
  position: absolute;
  top: clamp(0.85rem, 2.5vw, 1.5rem);
  right: clamp(0.85rem, 2.5vw, 1.5rem);
  min-height: 44px;
  padding: 0 1.1rem;
  border: 1px solid rgba(233, 231, 226, 0.35);
  background: transparent;
  color: var(--paper);
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 0.3s var(--ease), color 0.3s var(--ease);
}

.player__close:hover { background: var(--paper); color: var(--ink); }

/* ───────────────────────────────────────────────────────────────  motion ── */

/* EVERY PART OF THE PAGE ARRIVES THE SAME WAY: out of focus, slightly low,
   and slowly. One rule, one curve, one duration — the stagger between items is
   the only thing that varies, so the page reads as a single considered motion
   rather than as a collection of effects.

   The blur is the point. A plain fade is a change in opacity; a defocus
   resolving into focus is the language of the thing this page is about, and at
   1.25s it is slow enough to be felt rather than just noticed.

   will-change is set only while an element is still waiting, and dropped the
   moment it lands — leaving it on all fifteen tiles permanently keeps every
   one of them on its own compositor layer for the life of the page. */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  filter: blur(14px);
  will-change: opacity, transform, filter;
  transition:
    opacity var(--slow) var(--glide),
    transform var(--slow) var(--glide),
    filter var(--slow) var(--glide);
}

.reveal.in {
  opacity: 1;
  transform: none;
  filter: blur(0);
  will-change: auto;
}

/* Tiles get a touch more travel and a slow settle out of scale, because a
   rectangle of footage can carry motion that a line of type cannot. */
.bin__grid .reveal {
  transform: translateY(30px) scale(0.985);
  transition-duration: 1.45s;
}

.bin__grid .reveal.in { transform: none; }

/* The photograph is the slowest thing on the page. It is also the largest, and
   large elements moving at the same speed as small ones read as fast. */
.hero__shot.reveal {
  transform: translateY(26px) scale(0.99);
  filter: blur(18px);
  transition-duration: 1.7s;
}

.hero__shot.reveal.in { transform: none; filter: blur(0); }

/* The opening sequence, in the order it should be read: name, then what he
   does, then who for, then how to reach him — with the photograph coming up
   just behind the name rather than racing it. Written here rather than
   computed in script.js because it is choreography, not logic. */
.hero__shot        { transition-delay: 0.12s; }
.hero__say h1      { transition-delay: 0.06s; }
.hero__say .role   { transition-delay: 0.20s; }
.hero__say .brands { transition-delay: 0.34s; }
.hero__say .cta    { transition-delay: 0.48s; }

.bin__note { transition-delay: 0.09s; }

.close > p       { transition-delay: 0.10s; }
.close .credits  { transition-delay: 0.20s; }
.close .cta      { transition-delay: 0.30s; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}
