/* ── Shibani Sumit · portfolio ─────────────────────────────
   Big type. Big air. Small doses of motion.
   Palette: near-black on White Lilac · Regal Blue accents · Pastel Blue hairlines
   Type: Quasimoda (drop woff2 into assets/fonts/) → Jost fallback

   Type scale — seven steps, nothing else:
     text-xs    13px            eyebrows, meta, footer
     text-sm    15px            nav, entry descriptions & links
     text-base  17px            body copy
     text-lg    18–22px fluid   highlights list
     display-3  24–40px fluid   entry titles, highlight numerals, contact line
     display-2  28–54px fluid   (unused — reserved)
     display-1  40–88px fluid   hero h1 only (the one deliberate outlier)
   Weights: 300 display · 400 body · 600 emphasis. No others.
─────────────────────────────────────────────────────────── */

@font-face {
  font-family: 'Quasimoda';
  src: url('assets/fonts/Quasimoda-Regular.woff2') format('woff2');
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: 'Quasimoda';
  src: url('assets/fonts/Quasimoda-Light.woff2') format('woff2');
  font-weight: 300; font-display: swap;
}
@font-face {
  font-family: 'Quasimoda';
  src: url('assets/fonts/Quasimoda-SemiBold.woff2') format('woff2');
  font-weight: 600; font-display: swap;
}

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

:root {
  --ink: #0A0A0A;
  --blue: #1E3765;
  --bg: #F8F9FC;
  --pastel: #B0C6D4;
  --quiet: #6B7280;

  --text-xs: 13px;
  --text-sm: 15px;
  --text-base: 17px;
  --text-lg: clamp(18px, 1.8vw, 22px);
  --display-3: clamp(24px, 3.2vw, 40px);
  --display-2: clamp(28px, 4.2vw, 54px);
  --display-1: clamp(40px, 7vw, 88px);

  --tracking-tight: -0.02em;
  --tracking-wide: 0.12em;

  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /* Vertical rhythm — four steps, ranked. Spacing encodes relationship,
     so the order matters as much as the values:
       hero-top   nav and headline are both "top of page" — keep them close
       section    the base beat between peer sections
       hero-out   hero → body is the one real mode change, so it gets the most
     Every gap on the page comes from exactly one of these. Never stack two. */
  --space-hero-top: clamp(48px, 7vh, 88px);
  --space-section:  clamp(72px, 11vh, 128px);
  --space-hero-out: clamp(88px, 13vh, 156px);
}

html { font-size: 16px; scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: 'Quasimoda', 'Jost', -apple-system, sans-serif;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

::selection { background: var(--pastel); }

a { color: inherit; text-decoration: none; }

.wrap { max-width: 1200px; margin: 0 auto; padding: 0 clamp(20px, 4vw, 56px); }

/* ── header ── */
.top {
  display: flex; justify-content: space-between; align-items: baseline; gap: 16px;
  padding-top: 32px;
  font-size: var(--text-sm);
}
.top .name { font-weight: 600; letter-spacing: 0.01em; transition: color 150ms var(--ease-out); }
.top .name:hover { color: var(--blue); }
.top nav { display: flex; gap: clamp(16px, 3vw, 36px); }
.top nav a {
  color: var(--quiet);
  transition: color 150ms var(--ease-out);
}
.top nav a:hover, .top nav a[aria-current] { color: var(--blue); }

/* ── hero ── */
/* Owns the full gap down to the first section; .orgs contributes nothing,
   so the two paddings can't compound the way they used to. */
.hero { padding: var(--space-hero-top) 0 var(--space-hero-out); }
.hero .hello {
  font-size: var(--text-base);
  color: var(--quiet);
  margin-bottom: 28px;
}
.hero h1 {
  font-weight: 300;
  font-size: var(--display-1);
  line-height: 1.05;
  letter-spacing: var(--tracking-tight);
}
.hero .sub {
  margin-top: 40px;
  max-width: 34em;
  font-size: var(--text-base);
}
.hero .sub + .sub { margin-top: 14px; }
.hero .go { margin-top: 40px; font-size: var(--text-base); display: flex; gap: 36px; flex-wrap: wrap; }

/* underlined text links with a drawn underline */
.tlink {
  position: relative;
  color: var(--blue);
  padding-bottom: 3px;
}
.tlink::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--blue);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 300ms var(--ease-out);
}
.tlink:hover::after { transform: scaleX(1); transform-origin: left; }
.tlink::before {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--pastel);
}

/* ── section scaffolding: the base beat ── */
section { padding: var(--space-section) 0 0; }
section.flush-top { padding-top: 0; }

/* accented word inside a display heading */
.accent { color: var(--blue); font-weight: 400; }
.sec {
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--quiet);
  margin-bottom: clamp(32px, 5vh, 56px);
}

/* ── organisations (static) & brands/campaigns (marquee) ── */
/* Zero, deliberately: the hero's bottom padding already owns this gap. */
.orgs { padding-top: 0; }

/* row 1: fits one viewport, so it sits still */
.logorow {
  border-top: 1px solid var(--pastel);
  border-bottom: 1px solid var(--pastel);
  padding: clamp(34px, 5vh, 52px) 0;
}
.logorow .row {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(28px, 5vw, 64px);
  flex-wrap: wrap;
}
.logorow .cell { display: flex; align-items: center; justify-content: center; }
.logorow .cell img {
  display: block;
  opacity: 0.82;
  transition: opacity 200ms var(--ease-out);
}
.logorow .boxed img { border-radius: 5px; }
@media (hover: hover) and (pointer: fine) {
  .logorow .cell img:hover { opacity: 1; }
}
@media (max-width: 700px) {
  .logorow .row { justify-content: center; row-gap: 36px; }
}
.sec-gap { margin-top: clamp(56px, 8vh, 96px); }

.marquee {
  display: flex;
  overflow: hidden;
  padding: clamp(28px, 4vh, 44px) 0;
  border-top: 1px solid var(--pastel);
  border-bottom: 1px solid var(--pastel);
  /* fade the edges so logos enter and leave rather than getting clipped */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}
.marquee .track {
  list-style: none;
  display: flex;
  align-items: center;
  flex-shrink: 0;
  gap: clamp(44px, 6vw, 88px);
  padding-right: clamp(44px, 6vw, 88px);
  animation: marquee 52s linear infinite;
  will-change: transform;
}
.marquee.rev .track { animation-direction: reverse; }
.marquee:hover .track,
.marquee:focus-within .track { animation-play-state: paused; }

/* campaign artwork is taller than the brand wordmarks, so the band gets more room */
.m-work { padding: clamp(34px, 5vh, 52px) 0; }
.m-work .track { animation-duration: 46s; }

.marquee .cell { display: flex; align-items: center; justify-content: center; }
.marquee .cell img {
  display: block;
  opacity: 0.82;
  transition: opacity 200ms var(--ease-out);
}
.marquee .boxed img { border-radius: 5px; }
@media (hover: hover) and (pointer: fine) {
  .marquee .cell img:hover { opacity: 1; }
}
@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-100%); }
}


/* ── proud list ── */
.proud { counter-reset: n; list-style: none; }
.proud li {
  counter-increment: n;
  display: grid;
  grid-template-columns: clamp(64px, 10vw, 140px) 1fr;
  gap: 24px;
  padding: clamp(28px, 4vh, 44px) 0;
  border-bottom: 1px solid var(--pastel);
  align-items: start;
}
.proud li:first-child { border-top: 1px solid var(--pastel); }
.proud li::before {
  content: "0" counter(n);
  font-size: var(--display-3);
  font-weight: 300;
  line-height: 1.1;
  color: var(--pastel);
  transition: color 250ms var(--ease-out);
  font-variant-numeric: tabular-nums;
}
.proud li:hover::before { color: var(--blue); }
.proud li p {
  max-width: 44em;
  font-size: var(--text-lg);
  line-height: 1.5;
  font-weight: 300;
}
.proud li p strong { font-weight: 600; }

/* ── work filters (chips) ──
   Type is the .sec eyebrow treatment at chip scale; the 4px radius matches
   the skip link and the boxed logo tiles, so no new corner value enters the
   system. Selected state is pastel fill + blue, not solid blue — the page
   already spends its one solid-blue moment on the contact block. */
.filters { margin-bottom: clamp(24px, 4vh, 40px); }
.f-row { display: flex; flex-wrap: wrap; gap: 8px; }
.f {
  font: inherit;
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--quiet);
  background: none;
  /* --quiet, not --pastel: a pastel hairline sits at 1.68:1 against the page,
     under the 3:1 WCAG 1.4.11 floor for a control boundary. This is the one
     place the chips are louder than the rest of the hairlines, on purpose. */
  border: 1px solid var(--quiet);
  border-radius: 4px;
  padding: 7px 14px;
  cursor: pointer;
  /* colour lands before the fill does — transitioning both over the same
     160ms leaves the label muddy against a half-changed background */
  transition: color 100ms var(--ease-out), border-color 160ms var(--ease-out),
              background 160ms var(--ease-out), transform 140ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .f:hover { color: var(--blue); border-color: var(--blue); }
}
.f:active { transform: scale(0.97); }
.f[aria-pressed="true"] {
  color: var(--bg);
  border-color: var(--blue);
  background: var(--blue);
}
/* "All" is the resting state, not a filter. It still marks itself selected —
   blue label and border — but takes no fill, so a page nobody has touched yet
   has no solid block competing with the headline. The absence of a filled
   chip is what "showing everything" looks like. */
.f[data-filter="all"][aria-pressed="true"] {
  color: var(--blue);
  background: none;
}

/* ── featured work index (home) + work page index ── */
.index { border-top: 1px solid var(--pastel); }
.entry.is-hidden { display: none; }
.entry {
  display: block;
  border-bottom: 1px solid var(--pastel);
  padding: clamp(24px, 4vh, 40px) 0;
  position: relative;
}
.entry .e-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 24px;
}
.entry h3 {
  font-size: var(--display-3);
  font-weight: 300;
  letter-spacing: var(--tracking-tight);
  line-height: 1.15;
  transition: color 200ms var(--ease-out), transform 300ms var(--ease-out);
}
.entry .e-meta {
  font-size: var(--text-xs);
  color: var(--quiet);
  white-space: nowrap;
  transition: color 200ms var(--ease-out);
}
.entry .e-desc {
  max-width: 40em;
  margin-top: 10px;
  font-size: var(--text-sm);
  color: var(--quiet);
}
.entry .e-links { margin-top: 14px; font-size: var(--text-sm); display: flex; gap: 28px; flex-wrap: wrap; }
a.entry:hover h3, .entry:hover .e-meta { color: var(--blue); }
a.entry h3::after {
  content: "↗";
  display: inline-block;
  font-size: 0.5em;
  margin-left: 0.6em;
  opacity: 0;
  transform: translate(-6px, 4px);
  transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out);
}
a.entry:hover h3::after { opacity: 1; transform: translate(0, 0); }

.after-index { margin-top: clamp(28px, 5vh, 48px); font-size: var(--text-base); }

/* ── contact: full-bleed blue ── */
/* margin = the gap before the blue starts; padding = air inside it.
   Both ride the same scale so the block doesn't invent its own rhythm. */
.contact {
  margin-top: var(--space-section);
  background: var(--blue);
  color: var(--bg);
  padding: var(--space-section) 0 0;
}
.contact .sec { color: var(--pastel); }
.contact .sec sup { color: var(--bg); }
/* One sentence, both links inside it. display-3, not display-2: this is the
   last thing on the page rather than a second headline, and at 54px an email
   address wraps and starts shouting. Nothing here needs "making consistent"
   because it is literally one sentence at one size. */
.contact .big-line {
  font-weight: 300;
  font-size: var(--display-3);
  letter-spacing: var(--tracking-tight);
  line-height: 1.4;
  max-width: 20em;
}
.contact .big-line a {
  color: var(--bg);
  border-bottom: 1px solid rgba(176, 198, 212, 0.55);
  padding-bottom: 2px;
  transition: border-color 200ms var(--ease-out);
}
.contact .big-line a:hover { border-color: var(--bg); }
.contact footer {
  margin-top: clamp(56px, 9vh, 96px);
  border-top: 1px solid rgba(176, 198, 212, 0.35);
  padding: 24px 0 32px;
  display: flex;
  justify-content: space-between;
  gap: 16px;
  font-size: var(--text-xs);
  color: var(--pastel);
}
/* Tight enough that the email and the CV read as one pair of links rather
   than two separate statements. */

/* ── focus & skip link ── */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
:where(a, button, summary, details, [tabindex]):focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
  border-radius: 2px;
}
.contact :where(a, button):focus-visible { outline-color: var(--pastel); }
.skip {
  position: absolute; left: 50%; top: 8px;
  transform: translate(-50%, -160%);
  z-index: 20;
  background: var(--blue); color: var(--bg);
  padding: 10px 18px; border-radius: 4px;
  font-size: var(--text-sm);
  transition: transform 180ms var(--ease-out);
}
.skip:focus { transform: translate(-50%, 0); }

/* ── scroll reveal ──
   280ms, not 600. A recruiter scans fast; anything slower means content is
   still assembling itself under the cursor. Travel drops 20px → 8px for the
   same reason — the movement is a hint that something arrived, not a journey. */
.reveal {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 280ms var(--ease-out), transform 280ms var(--ease-out);
}
.reveal.in { opacity: 1; transform: translateY(0); }

/* Stagger is scoped to actual lists. The old rule keyed off :nth-child of any
   sibling, so section eyebrows picked up delays they shouldn't have had and
   list items 5–6 got none at all. */
.proud li.reveal:nth-child(2), .index .entry.reveal:nth-child(2) { transition-delay: 45ms; }
.proud li.reveal:nth-child(3), .index .entry.reveal:nth-child(3) { transition-delay: 90ms; }
.proud li.reveal:nth-child(4), .index .entry.reveal:nth-child(4) { transition-delay: 135ms; }
.proud li.reveal:nth-child(5) { transition-delay: 180ms; }

/* ── small screens ── */
@media (max-width: 600px) {
  .top { flex-wrap: wrap; }
  .proud li { grid-template-columns: 48px 1fr; gap: 14px; }
  .entry .e-row { flex-direction: column; gap: 6px; }
}

/* ── reduced motion ── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .marquee .track { animation: none; }
  .marquee { flex-wrap: wrap; -webkit-mask-image: none; mask-image: none; }
  .marquee .track + .track { display: none; }
  .marquee .track { flex-wrap: wrap; justify-content: center; row-gap: 32px; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .f:active { transform: none; }   /* colour still responds; movement doesn't */
}
