/* ===========================================================================
   thesalmankhan.com

   Every rule the page needs. There are no style attributes in the markup and
   no inline <style> block, which is what lets the CSP run without
   'unsafe-inline' — an injected style= simply does not apply.

   Sections follow the page order: tokens, base, layout primitives, then one
   block per section of the page.
   =========================================================================== */

:root {
  --paper:        #FAFAF8;
  --paper-2:      #F3F3EF;
  --paper-3:      #F0F0EC;
  --paper-4:      #EFEFEA;
  --paper-5:      #EDEDE8;
  --ink:          #14161A;
  --ink-2:        #34383E;
  --ink-3:        #45494F;
  --ink-4:        #565B62;
  --muted:        #6B7078;
  --muted-2:      #8A8F96;
  --muted-3:      #A9A9A2;
  --muted-4:      #C4C4BD;
  --line:         #E2E2DE;
  --line-2:       #E6E6E1;
  --accent:       #E8552D;

  --dark:         #14161A;
  --dark-2:       #1B1E24;
  --dark-line:    #2A2D33;
  --dark-line-2:  #2F3339;
  --dark-line-3:  #3A3E45;
  --dark-line-4:  #22252B;
  --dark-text:    #A9AAB0;
  --dark-text-2:  #9A9BA2;
  --dark-text-3:  #C9CACF;
  --dark-text-4:  #4C5158;

  --sans: Geist, "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --rail: 260px;
  --hdr-h: 68px;

  /* One size for every section heading, so About, AI and Selected work
     read as the same level rather than three competing ones. */
  --heading: clamp(26px, 2.6vw, 38px);
  --heading-lh: 1.16;
  --heading-ls: -.028em;
  --ease: cubic-bezier(.2, .7, .2, 1);
  --ease-out: cubic-bezier(.16, .84, .24, 1);
}

/* ------------------------------------------------------------------- base */

*, *::before, *::after { box-sizing: border-box; }
html {
  scroll-behavior: smooth;
  /* Belt and braces against a stray wide child. `clip` rather than `hidden`:
     overflow on the root propagates to the viewport, so sticky positioning is
     unaffected either way, but clip never creates a scroll container. */
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  text-wrap: pretty;
}

a { color: var(--accent); text-decoration: none; }
::selection { background: var(--accent); color: #fff; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: #C9C9C3; }

/* An inline `display:` would beat the UA's [hidden] rule; there are none left
   in the markup, but this keeps hidden authoritative regardless. */
[hidden] { display: none !important; }

img { max-width: 100%; }

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

@keyframes rise    { from { opacity: 0; transform: translateY(28px); } to { opacity: 1; transform: none; } }
@keyframes wipe    { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes marq    { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes fade    { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop     { from { opacity: 0; transform: translateY(24px) scale(.985); } to { opacity: 1; transform: none; } }
@keyframes slidein { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* -------------------------------------------------------------- primitives */

.mono {
  font-family: var(--mono);
  text-transform: uppercase;
  letter-spacing: .14em;
  font-size: 10px;
}

.shell {
  max-width: 1560px;
  margin: 0 auto;
  /* `clip`, not `hidden`. overflow-x:hidden computes overflow-y:auto, which
     makes this element a scroll container — and a sticky descendant then
     sticks to *its* scrollport instead of the viewport, so the header just
     scrolls away. `clip` trims the same overflow without that side effect. */
  overflow-x: clip;
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
  background: var(--paper);
}

/* The label / content split used by most sections. */
.rail {
  display: grid;
  grid-template-columns: var(--rail) 1fr;
  border-bottom: 1px solid var(--line);
}
.rail__label {
  padding: 56px 28px;
  border-right: 1px solid var(--line);
}
.rail__label--dark { border-right-color: var(--dark-line); }

.rail__index {
  position: sticky;
  top: calc(var(--hdr-h) + 32px);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
}
.rail__index--accent { color: var(--accent); }

.rail__sub {
  margin-top: 12px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .1em;
  color: var(--muted-3);
}

.section-heading {
  margin: 0 0 28px;
  font-size: var(--heading);
  line-height: var(--heading-lh);
  letter-spacing: var(--heading-ls);
  font-weight: 500;
  max-width: 30ch;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 13px 20px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  border: none;
  cursor: pointer;
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.btn--accent  { background: var(--accent); color: #fff; }
.btn--outline { background: transparent; border: 1px solid var(--ink); color: var(--ink); }
.btn--solid   { background: var(--ink); color: var(--paper); }

.btn--accent:hover,
.btn--outline:hover { background: var(--ink); color: var(--paper); }
.btn--solid:hover   { background: var(--accent); color: #fff; }

.progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 0;
  background: var(--accent);
  z-index: 120;
  will-change: width;
}

/* ----------------------------------------------------------------- header */

.hdr {
  position: sticky;
  top: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 0 28px;
  height: var(--hdr-h);
  background: rgba(250, 250, 248, .88);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}

.hdr__brand { display: flex; align-items: center; gap: 12px; color: var(--ink); }

.hdr__mark {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  background: var(--ink);
  color: var(--paper);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .02em;
}
.hdr__mark--invert { background: var(--paper); color: var(--ink); }

.hdr__name {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}

.hdr__nav { display: flex; align-items: center; gap: 4px; }

.hdr__link {
  padding: 8px 12px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
  transition: color .2s ease, background .2s ease;
}
.hdr__link:hover { color: var(--ink); background: var(--paper-3); }
.hdr__link[aria-current="true"] { color: var(--ink); background: var(--paper-3); }

.hdr__cta {
  margin-left: 10px;
  padding: 9px 16px;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  transition: background .2s ease, color .2s ease;
}
.hdr__cta:hover { background: var(--accent); color: #fff; }

.burger {
  display: none;
  align-items: center;
  gap: 10px;
  padding: 10px 14px 10px 12px;
  background: var(--ink);
  border: none;
  cursor: pointer;
  color: var(--paper);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.burger__bars { display: grid; gap: 3px; width: 15px; }
.burger__bars span { display: block; height: 1.5px; background: var(--paper); }

/* ------------------------------------------------------------------- hero */

.hero {
  display: grid;
  grid-template-columns: 1.35fr .65fr;
  align-items: end;
  border-bottom: 1px solid var(--line);
}

.hero__body { padding: 84px 28px 44px; min-width: 0; }

.hero__kicker {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 40px;
  animation: rise .7s var(--ease) both;
}
.hero__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
.hero__kicker-text {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
}

.hero__title {
  margin: 0;
  font-size: clamp(52px, 7.4vw, 118px);
  line-height: .92;
  letter-spacing: -.045em;
  font-weight: 600;
}
.hero__line { display: block; animation: rise .8s var(--ease) both; }
.hero__name { animation-delay: .06s; }

/* The role sits under the name at a much smaller size: it is a subtitle, and
   at the h1's own scale it competed with the name and ran to two lines.
   Sized to hold "Software Engineer & IT Manager" on one line at desktop. */
.hero__role {
  animation-delay: .18s;
  font-size: clamp(18px, 2.6vw, 38px);
  line-height: 1.2;
  letter-spacing: -.02em;
  margin-top: .34em;
}

/* The two copies share an identical box so they overlay exactly: same padding,
   same wrapping, same line breaks. */
.hero__role-text { position: relative; display: inline-block; min-height: 1.2em; }

/* Present for screen readers, absent from the page. The rotating copy is
   aria-hidden — a heading whose words change every few seconds is hostile
   to read aloud — so the full role is exposed here instead. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.hero__role-base,
.hero__role-fill {
  padding: 0 .12em .06em;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* Block, not inline: an inline box sits on a baseline with leading above it,
   so it would never line up with an absolutely positioned overlay. */
.hero__role-base {
  display: block;
  color: var(--ink);
}

.hero__role-fill {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  color: #fff;
  background: var(--accent);
  /* Empty until JS goes live; without JS the static rule below shows it. */
  clip-path: inset(0 100% 0 0);
}

/* Once JavaScript is driving, the band is simply on. Both copies hold only
   the characters written so far, so the band hugs them: writing fills it and
   erasing empties it. There is no second animation to keep in step with the
   letters, which is what made the earlier sweep drift out of sync. */
.hero__role-text.is-live .hero__role-fill { clip-path: inset(0); }

/* No JS, or reduced motion: the band simply sits there, filled. */
.no-sweep .hero__role-fill { clip-path: inset(0 0 0 0); }

/* The caret blinks the whole time the line is live — while writing, while the
   phrase is held, and while it is erased — because a cursor that appears only
   during typing reads as a glitch rather than as a prompt.
 *
 * It is drawn on BOTH copies. The base one is never seen (the band covers it)
 * but it has to be there: it is what reserves the caret's width, and the two
 * boxes must stay identical or the overlay stops lining up. currentColor then
 * gives each copy the right colour on its own — ink below, white in the band. */
.hero__role-text.is-live .hero__role-base::after,
.hero__role-text.is-live .hero__role-fill::after {
  content: '';
  display: inline-block;
  width: .06em;
  height: .78em;
  margin-left: .04em;
  background: currentColor;
  vertical-align: baseline;
  animation: caret 1s steps(1) infinite;
}

@keyframes caret { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }

.hero__rule {
  height: 1px;
  background: var(--ink);
  margin: 40px 0 28px;
  transform-origin: left;
  animation: wipe .9s var(--ease) .4s both;
}

.hero__text {
  display: grid;
  grid-template-columns: 1.1fr .9fr;
  gap: 40px;
  animation: rise .8s var(--ease) .5s both;
}
.hero__lede { margin: 0; font-size: 19px; line-height: 1.55; max-width: 54ch; color: var(--ink-2); }
.hero__actions { display: flex; flex-direction: column; gap: 14px; align-items: flex-start; }

.hero__media {
  position: relative;
  border-left: 1px solid var(--line);
  align-self: stretch;
  min-height: 420px;
  overflow: hidden;
  background: var(--paper-3);
}
.hero__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 22%;
  filter: grayscale(1) contrast(1.06);
  animation: fade 1.2s ease .3s both;
}
.hero__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(250, 250, 248, .35), rgba(250, 250, 248, 0) 42%);
}
.hero__bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px;
  background: rgba(20, 22, 26, .86);
  backdrop-filter: blur(6px);
}
.hero__bar .mono { color: var(--paper); }
.hero__bar .mono--accent { color: var(--accent); }

/* ------------------------------------------------------------------ stats */

.stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-bottom: 1px solid var(--line);
}
.stats__cell { padding: 34px 28px; border-right: 1px solid var(--line); }
.stats__n {
  font-size: clamp(38px, 4vw, 62px);
  line-height: 1;
  letter-spacing: -.04em;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.stats__label {
  margin-top: 12px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ------------------------------------------------------------------ about */

.about { display: grid; grid-template-columns: 1fr 360px; }
.about__prose { padding: 56px 44px; }
.about__copy {
  display: grid;
  gap: 20px;
  max-width: 62ch;
  font-size: 17px;
  line-height: 1.62;
  color: var(--ink-2);
}
.about__copy p { margin: 0; }

.about__aside {
  border-left: 1px solid var(--line);
  padding: 56px 28px;
  display: flex;
  flex-direction: column;
  gap: 26px;
}
.about__portrait { aspect-ratio: 4 / 5; overflow: hidden; background: var(--paper-3); }
.about__portrait img { width: 100%; height: 100%; object-fit: cover; filter: grayscale(1); }

.facts { display: grid; gap: 14px; }
.facts__row {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}
.facts__k {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--muted);
}
.facts__v { font-size: 13px; font-weight: 500; text-align: right; }

/* --------------------------------------------------------------------- ai */

.ai { background: var(--dark); color: var(--paper); border-bottom: 1px solid var(--dark); }
.ai .rail { border-bottom: none; }
.ai__body { padding: 56px 44px; }

.ai__heading {
  margin: 0 0 24px;
  font-size: var(--heading);
  line-height: var(--heading-lh);
  letter-spacing: var(--heading-ls);
  font-weight: 500;
  max-width: 34ch;
}
.ai__lede { margin: 0 0 48px; max-width: 62ch; font-size: 17px; line-height: 1.62; color: var(--dark-text); }

.ai__cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  background: var(--dark-line);
  border: 1px solid var(--dark-line);
}
.ai__card { background: var(--dark); padding: 32px 30px 34px; transition: background .3s ease; }
.ai__card:hover { background: var(--dark-2); }
.ai__no { font-family: var(--mono); font-size: 10px; letter-spacing: .14em; color: var(--accent); margin-bottom: 20px; }
.ai__title { margin: 0 0 12px; font-size: 21px; letter-spacing: -.02em; font-weight: 500; }
.ai__text { margin: 0 0 18px; font-size: 15px; line-height: 1.6; color: var(--dark-text-2); }

.tags { display: flex; flex-wrap: wrap; gap: 6px; }
.tag {
  padding: 5px 9px;
  border: 1px solid var(--dark-line-2);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .08em;
  color: var(--dark-text-3);
}

.marquee { border-top: 1px solid var(--dark-line); overflow: hidden; padding: 16px 0; }
.marquee__track { display: flex; width: max-content; animation: marq 34s linear infinite; }
.marquee__group { display: flex; gap: 44px; padding-right: 44px; }
.marquee__item {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--dark-text-4);
  white-space: nowrap;
}

/* --------------------------------------------------------------- services */

.srv {
  display: grid;
  grid-template-columns: 72px 1fr 1.15fr;
  gap: 32px;
  align-items: start;
  padding: 30px 44px;
  border-bottom: 1px solid var(--line);
  transition: background .3s ease;
}
.srv:hover { background: var(--paper-2); }
.srv__no { font-family: var(--mono); font-size: 11px; letter-spacing: .1em; color: var(--muted-3); padding-top: 6px; }
.srv__title { margin: 0; font-size: 24px; letter-spacing: -.025em; font-weight: 500; line-height: 1.2; }
.srv__text { margin: 0; font-size: 15px; line-height: 1.6; color: var(--ink-4); max-width: 56ch; }

/* ------------------------------------------------------------- experience */

.exp {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 40px;
  padding: 40px 44px;
  border-bottom: 1px solid var(--line);
  transition: background .3s ease;
}
.exp:hover { background: var(--paper-2); }

/* The rows stack as you scroll: each one pins and the next slides up over the
   top of it, like a deck being dealt.
 *
 * All seven share one parent, so a pinned row stays pinned until the parent
 * runs out — which is what lets the following rows pile on top of it. Order in
 * the document is the paint order, so a later row covers an earlier one with
 * no z-index needed; the background is what makes the cover opaque, and
 * without it you would read two rows through each other.
 *
 * Where a row stops is measured per row by JS, because it depends on whether
 * the row is shorter than the screen. --stick-top falls back to the header
 * height, which is the answer for every row that fits.
 *
 * The rows reveal with a plain fade, not the usual travel: a transform on a
 * sticky element moves where it pins, so a 26px entrance translate left every
 * pinned row hanging 26px below the header with a strip of page in the gap. */
.exp--stack {
  position: sticky;
  top: var(--stick-top, var(--hdr-h));
  background: var(--paper);
}

/* Sticky rows overlap, so the row above needs a hard edge against the one
   sliding over it — the shared 1px border is on the wrong side for that. */
.exp--stack + .exp--stack { box-shadow: 0 -1px 0 var(--line); }

.exp__logo-wrap { height: 34px; display: flex; align-items: center; margin-bottom: 16px; }
.exp__logo {
  width: 140px;
  height: 34px;
  object-fit: contain;
  object-position: left center;
  /* Full colour by default — a client's mark is part of the credential, and
     desaturating it made the darker logos read as placeholders. */
}
.exp__range { font-family: var(--mono); font-size: 11px; letter-spacing: .1em; color: var(--muted); }
.exp__duration { margin-top: 6px; font-family: var(--mono); font-size: 10px; letter-spacing: .1em; color: var(--muted-3); }
.exp__title { margin: 0 0 4px; font-size: 25px; letter-spacing: -.028em; font-weight: 500; }
.exp__company { font-size: 15px; color: var(--accent); margin-bottom: 20px; font-weight: 500; }

.bullets { margin: 0; padding: 0; list-style: none; display: grid; gap: 10px; }
.bullets li {
  display: grid;
  grid-template-columns: 16px 1fr;
  gap: 10px;
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink-3);
}
.bullets__dash { color: var(--muted-4); font-family: var(--mono); font-size: 12px; padding-top: 3px; }

/* ------------------------------------------------------------------- work */

.work { border-bottom: 1px solid var(--line); }
.work .rail { border-bottom: none; }
.work__head { padding: 56px 44px 28px; }
.work__heading {
  margin: 0 0 28px;
  font-size: var(--heading);
  line-height: var(--heading-lh);
  letter-spacing: var(--heading-ls);
  font-weight: 500;
  max-width: 44ch;
}

.chips { display: flex; flex-wrap: wrap; gap: 6px; padding-bottom: 4px; }
.chip {
  padding: 9px 14px;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  transition: background .2s ease, color .2s ease, border-color .2s ease;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--line);
}
.chip:hover { border-color: var(--ink); }
.chip[aria-pressed="true"] { background: var(--ink); color: var(--paper); border-color: var(--ink); }

.grid3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--line);
  border-top: 1px solid var(--line);
  transition: opacity .2s ease;
}
.grid3[aria-busy="true"] { opacity: .45; }

.pcard {
  background: var(--paper);
  cursor: pointer;
  padding: 14px 14px 26px;
  transition: transform .5s var(--ease-out), background .3s ease;
}
/* No lift. Raising the card by 4px moved its bottom edge out from under a
   pointer resting near it, which dropped the hover, which lowered the card
   back on to the pointer — a loop that flickered the image scale on and off.
   The background shift and the zoom carry the hover on their own. */
.pcard:hover { background: var(--paper-2); }

.pcard__media { position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: var(--paper-5); }
/* Two classes, not one, and deliberately so: .media-fade below also sets a
   transition on this element, and as a single class declared later it won —
   which left the hover zoom with a transition on opacity and none at all on
   transform. The scale had nothing to interpolate, so it snapped. This rule
   therefore has to carry BOTH the fade and the zoom. */
.pcard__media .pcard__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  /* Scaled in 3D on a promoted layer, so the browser interpolates the zoom by
     compositing rather than re-rasterising the image at every step. */
  transform: scale3d(1, 1, 1);
  will-change: transform;
  backface-visibility: hidden;
  transition:
    opacity   .55s ease,
    transform .85s cubic-bezier(.22, .61, .36, 1);
}
.pcard:hover .pcard__img { transform: scale3d(1.045, 1.045, 1); }

/* The arrow says "this opens": it belongs to the hover, not to the resting
   card. Sitting there permanently on nine tiles at once, it read as part of
   the artwork rather than as a control. */
.pcard__badge {
  position: absolute;
  right: 12px;
  top: 12px;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  background: rgba(20, 22, 26, .82);
  color: var(--paper);
  font-size: 13px;
  transition: opacity .28s var(--ease-out), transform .28s var(--ease-out);
}

/* Only where there is a pointer to hover with. On touch there is no hover
   state to reveal it, so hiding it would hide it for good. */
@media (hover: hover) {
  .pcard__badge {
    opacity: 0;
    transform: translate(4px, -4px) scale(.9);
  }

  /* Keyboard too: the card is a role="button", so it can be reached and
     opened without a pointer ever touching it. */
  .pcard:hover .pcard__badge,
  .pcard:focus-visible .pcard__badge {
    opacity: 1;
    transform: none;
  }
}
.pcard__body { padding: 20px 12px 0; }
.pcard__title { margin: 0 0 6px; font-size: 19px; letter-spacing: -.022em; font-weight: 500; }
.pcard__link { color: inherit; text-decoration: none; }
.pcard__link:hover { color: var(--accent); }
.pcard__client {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted-2);
  margin-bottom: 14px;
}
.pcard__desc { margin: 0 0 16px; font-size: 14px; line-height: 1.5; color: var(--ink-4); max-width: 44ch; }

.techs { display: flex; flex-wrap: wrap; gap: 5px; }
.tech {
  padding: 4px 8px;
  background: var(--paper-4);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .06em;
  color: var(--ink-4);
}

.work__empty {
  grid-column: 1 / -1;
  background: var(--paper);
  padding: 56px 44px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted-2);
}

.work__more { display: flex; justify-content: center; padding: 34px; border-top: 1px solid var(--line); }
.work__more .btn { padding: 14px 26px; }

/* ----------------------------------------------------------------- skills */

.cols2 { display: grid; grid-template-columns: 1fr 1fr; }
.skills__col { padding: 56px 44px; }
.skills__col--bordered { border-right: 1px solid var(--line); }
.skills__heading,
.knowledge__heading {
  margin: 0 0 30px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}
.skills__list { display: grid; gap: 24px; }
.skill__row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 10px; }
.skill__name { font-size: 17px; font-weight: 500; letter-spacing: -.015em; }
.skill__pct { font-family: var(--mono); font-size: 11px; color: var(--muted-2); }
.skill__track { height: 3px; background: var(--line-2); }
.skill__bar { height: 3px; background: var(--accent); transition: width 1.1s var(--ease); }

.knowledge { padding: 44px; border-top: 1px solid var(--line); }
.knowledge__heading { margin-bottom: 22px; }
.knowledge__list { display: flex; flex-wrap: wrap; gap: 8px; }
.ktag {
  padding: 9px 14px;
  border: 1px solid var(--line);
  font-size: 14px;
  color: var(--ink-2);
  transition: border-color .2s ease, background .2s ease;
}
.ktag:hover { border-color: var(--ink); background: var(--paper-2); }

/* ------------------------------------------------------------------ legal */

.legal__col { padding: 48px 44px; }
.legal__col--bordered { border-right: 1px solid var(--line); }
.legal__title { margin: 0 0 16px; font-size: 22px; letter-spacing: -.022em; font-weight: 500; }
.legal__copy { display: grid; gap: 12px; font-size: 14px; line-height: 1.62; color: var(--ink-3); }
.legal__copy p { margin: 0; }
.legal__pair {
  padding: 48px 44px;
  border-top: 1px solid var(--line);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 44px;
}

.policy__stack { display: grid; }
.policy__block { padding: 48px 44px; }
.policy__block--bordered { border-top: 1px solid var(--line); }
.policy__switch {
  padding: 28px 44px;
  border-top: 1px solid var(--line);
  background: var(--paper-2);
}

/* ----------------------------------------------------------- case study */

.case__body { min-width: 0; }
.case__head { padding: 56px 44px 44px; border-bottom: 1px solid var(--line); }
.case__back {
  display: inline-block;
  margin-bottom: 24px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
  transition: color .2s ease;
}
.case__back:hover { color: var(--accent); }
.case__grid { display: grid; grid-template-columns: 1fr 340px; }
.case__meta {
  padding: 44px 36px;
  border-left: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 30px;
}
.case__gallery {
  padding: 44px;
  display: grid;
  gap: 28px;
  background: var(--paper-2);
}
.case__figure {
  margin: 0;
  background: var(--paper-5);
  border: 1px solid var(--line);
  overflow: hidden;
}
.case__img {
  display: block;
  width: 100%;
  height: auto;
}

/* ---------------------------------------------------------------- contact */

.contact { background: var(--dark); color: var(--paper); }
.contact .rail { border-bottom: none; }
.contact__body { padding: 72px 44px; }
.contact__heading {
  margin: 0 0 20px;
  font-size: clamp(38px, 5.6vw, 88px);
  line-height: .98;
  letter-spacing: -.045em;
  font-weight: 500;
  max-width: 18ch;
}
.contact__lede { margin: 0 0 48px; max-width: 52ch; font-size: 17px; line-height: 1.6; color: var(--dark-text); }
.contact__actions { display: flex; flex-wrap: wrap; gap: 10px; }

.cbtn {
  padding: 15px 24px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.cbtn--accent  { background: var(--accent); color: #fff; }
.cbtn--outline { border: 1px solid var(--dark-line-3); color: var(--paper); }
.cbtn--accent:hover  { background: var(--paper); color: var(--ink); }
.cbtn--outline:hover { background: var(--paper); color: var(--ink); border-color: var(--paper); }

.footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 22px 28px;
  border-top: 1px solid var(--dark-line);
}
.footer .mono { color: var(--muted); }
.footer__nav { display: flex; gap: 20px; align-items: center; }
.footer__link {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted-2);
  transition: color .2s ease;
}
.footer__link:hover { color: var(--paper); }

/* ------------------------------------------------------------ mobile menu */

.menu {
  position: fixed;
  inset: 0;
  z-index: 300;
  background: var(--dark);
  display: flex;
  flex-direction: column;
  animation: fade .22s ease both;
}
.menu__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 16px;
  border-bottom: 1px solid var(--dark-line);
  flex: none;
}
.menu__brand { display: flex; align-items: center; gap: 12px; }
.menu__name {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted-2);
}
.menu__close {
  width: 40px;
  height: 40px;
  background: transparent;
  border: 1px solid var(--dark-line-3);
  color: var(--paper);
  font-size: 16px;
  cursor: pointer;
}
.menu__nav { flex: 1; overflow-y: auto; display: flex; flex-direction: column; }
.menu__inner { margin: auto 0; display: flex; flex-direction: column; flex: none; }

.menu__link {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 15px 20px;
  color: var(--paper);
  border-bottom: 1px solid var(--dark-line-4);
  animation: slidein .45s var(--ease-out) both;
}
/* Staggered entrance — one class per position, because the delay cannot be an
   inline style under this CSP. */
.menu__link--1 { animation-delay: .040s; }
.menu__link--2 { animation-delay: .085s; }
.menu__link--3 { animation-delay: .130s; }
.menu__link--4 { animation-delay: .175s; }
.menu__link--5 { animation-delay: .220s; }
.menu__link--6 { animation-delay: .265s; }
.menu__link--7 { animation-delay: .310s; }

.menu__no { font-family: var(--mono); font-size: 10px; letter-spacing: .12em; color: var(--accent); width: 26px; }
.menu__label { font-size: 27px; letter-spacing: -.03em; font-weight: 500; }

.menu__foot {
  flex: none;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--dark-line);
  border-top: 1px solid var(--dark-line);
}
.menu__cta {
  padding: 18px 16px;
  text-align: center;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.menu__cta--accent { background: var(--accent); color: #fff; }
.menu__cta--dark   { background: var(--dark); color: var(--paper); }

/* ------------------------------------------------------------------ modal */

.modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(20, 22, 26, .78);
  backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 3vh 2vw;
  animation: fade .25s ease both;
}
.modal__dialog {
  width: min(1600px, 92vw);
  height: 88vh;
  background: var(--paper);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: pop .4s var(--ease) both;
}
.modal__head {
  flex: none;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  padding: 24px 30px;
  border-bottom: 1px solid var(--line);
}
.modal__title { margin: 0 0 6px; font-size: 27px; letter-spacing: -.032em; font-weight: 500; }
.modal__client {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted-2);
}
.modal__head-right { flex: none; display: flex; align-items: center; gap: 12px; }
.modal__counter { font-family: var(--mono); font-size: 10px; letter-spacing: .12em; color: var(--muted-3); }
.modal__close {
  width: 38px;
  height: 38px;
  background: var(--ink);
  color: var(--paper);
  border: none;
  font-size: 16px;
  cursor: pointer;
  transition: background .2s ease;
}
.modal__close:hover { background: var(--accent); }

.modal__body { flex: 1; min-height: 0; display: grid; grid-template-columns: 1fr 320px; }
.modal__gallery { min-width: 0; min-height: 0; display: flex; flex-direction: column; border-right: 1px solid var(--line); }
.modal__stage {
  position: relative;
  flex: 1;
  min-height: 0;
  background: var(--paper-5);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 18px;
}
.modal__img { width: 100%; height: 100%; min-height: 280px; object-fit: contain; }

.modal__arrows {
  position: absolute;
  left: 14px;
  right: 14px;
  top: 50%;
  display: flex;
  justify-content: space-between;
  pointer-events: none;
}
.modal__arrow {
  pointer-events: auto;
  width: 36px;
  height: 36px;
  background: rgba(20, 22, 26, .78);
  color: var(--paper);
  border: none;
  cursor: pointer;
  font-size: 14px;
  transition: background .2s ease;
}
.modal__arrow:hover { background: var(--accent); }

.thumbs {
  flex: none;
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 12px 14px;
  border-top: 1px solid var(--line);
  background: var(--paper-2);
  scrollbar-width: thin;
}
.thumbs::-webkit-scrollbar { height: 6px; }

.thumb {
  flex: none;
  width: 96px;
  height: 62px;
  padding: 0;
  cursor: pointer;
  overflow: hidden;
  background: none;
  border: 2px solid transparent;
  opacity: .62;
  transition: border-color .2s ease, opacity .2s ease;
}
.thumb img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }
.thumb[aria-current="true"] { border-color: var(--accent); opacity: 1; }

.modal__meta {
  min-height: 0;
  overflow-y: auto;
  padding: 26px 26px 34px;
  display: flex;
  flex-direction: column;
  gap: 26px;
}
.modal__label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--muted-2);
  margin-bottom: 12px;
}
.modal__scope { margin: 0; font-size: 14px; line-height: 1.55; color: var(--ink-2); }
.modal__links { display: grid; gap: 6px; }
.modal__link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 11px 13px;
  border: 1px solid var(--ink);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  transition: background .2s ease, color .2s ease;
}
.modal__link:hover { background: var(--ink); color: var(--paper); }

/* -------------------------------------------------------------------- ads */

.ad { background: var(--paper-2); }
.ad__label-cell { padding: 22px 28px; border-right: 1px solid var(--line); }
.ad__label { font-family: var(--mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted-3); }
/* The ad script sizes its own container, and a mis-sized unit would otherwise
   widen the page. Clipping here keeps a third-party iframe from deciding the
   site's layout. */
.ad__slot { padding: 22px 44px; min-width: 0; overflow: hidden; }
.ad__slot ins { display: block; width: 100%; max-width: 100%; }

/* A slot stays invisible until Google actually fills it: no empty grey band,
   no orphaned "Advertisement" label. app.js flips these classes. */
.ad--pending { background: transparent; border-bottom: none; }
.ad--pending .ad__label { opacity: 0; }
.ad--empty { display: none; }

/* ------------------------------------------------------- skill bar widths */

/* The bar width comes from the CMS and cannot be an inline style under this
   CSP, so it is expressed as one utility class per whole percent. */
.pw-0{width:0%}.pw-1{width:1%}.pw-2{width:2%}.pw-3{width:3%}.pw-4{width:4%}
.pw-5{width:5%}.pw-6{width:6%}.pw-7{width:7%}.pw-8{width:8%}.pw-9{width:9%}
.pw-10{width:10%}.pw-11{width:11%}.pw-12{width:12%}.pw-13{width:13%}.pw-14{width:14%}
.pw-15{width:15%}.pw-16{width:16%}.pw-17{width:17%}.pw-18{width:18%}.pw-19{width:19%}
.pw-20{width:20%}.pw-21{width:21%}.pw-22{width:22%}.pw-23{width:23%}.pw-24{width:24%}
.pw-25{width:25%}.pw-26{width:26%}.pw-27{width:27%}.pw-28{width:28%}.pw-29{width:29%}
.pw-30{width:30%}.pw-31{width:31%}.pw-32{width:32%}.pw-33{width:33%}.pw-34{width:34%}
.pw-35{width:35%}.pw-36{width:36%}.pw-37{width:37%}.pw-38{width:38%}.pw-39{width:39%}
.pw-40{width:40%}.pw-41{width:41%}.pw-42{width:42%}.pw-43{width:43%}.pw-44{width:44%}
.pw-45{width:45%}.pw-46{width:46%}.pw-47{width:47%}.pw-48{width:48%}.pw-49{width:49%}
.pw-50{width:50%}.pw-51{width:51%}.pw-52{width:52%}.pw-53{width:53%}.pw-54{width:54%}
.pw-55{width:55%}.pw-56{width:56%}.pw-57{width:57%}.pw-58{width:58%}.pw-59{width:59%}
.pw-60{width:60%}.pw-61{width:61%}.pw-62{width:62%}.pw-63{width:63%}.pw-64{width:64%}
.pw-65{width:65%}.pw-66{width:66%}.pw-67{width:67%}.pw-68{width:68%}.pw-69{width:69%}
.pw-70{width:70%}.pw-71{width:71%}.pw-72{width:72%}.pw-73{width:73%}.pw-74{width:74%}
.pw-75{width:75%}.pw-76{width:76%}.pw-77{width:77%}.pw-78{width:78%}.pw-79{width:79%}
.pw-80{width:80%}.pw-81{width:81%}.pw-82{width:82%}.pw-83{width:83%}.pw-84{width:84%}
.pw-85{width:85%}.pw-86{width:86%}.pw-87{width:87%}.pw-88{width:88%}.pw-89{width:89%}
.pw-90{width:90%}.pw-91{width:91%}.pw-92{width:92%}.pw-93{width:93%}.pw-94{width:94%}
.pw-95{width:95%}.pw-96{width:96%}.pw-97{width:97%}.pw-98{width:98%}.pw-99{width:99%}
.pw-100{width:100%}

/* --------------------------------------------------------- anchor targets */

/* The header is sticky, so a jump to #about would otherwise land the heading
   underneath it. scroll-margin-top reserves the header's height (plus a little
   breathing room) at every anchor target. */
section[id],
[id="privacy"],
[id="cookies"],
[id="terms"] {
  scroll-margin-top: calc(var(--hdr-h) + 16px);
}

/* ------------------------------------------------------- deferred sections */

/* Below-the-fold sections are skipped entirely by layout and paint until they
   approach the viewport. contain-intrinsic-size reserves roughly the right
   height in the meantime so the scrollbar stays honest and nothing jumps when
   a section is finally rendered.

   This is a rendering optimisation only: the markup is in the document from
   the first byte, so crawlers and find-in-page still see everything. */
.defer {
  content-visibility: auto;
  contain-intrinsic-size: auto 900px;
}
.defer-800  { contain-intrinsic-size: auto 800px; }
.defer-900  { contain-intrinsic-size: auto 900px; }
.defer-1200 { contain-intrinsic-size: auto 1200px; }
.defer-1600 { contain-intrinsic-size: auto 1600px; }

/* --------------------------------------------------------------- reveal fx */

/* Content is visible by default. Without JavaScript none of these classes are
   ever applied, so the page can never end up with invisible sections — the
   animation is added by app.js and removed again on intersection. */
.reveal-init {
  opacity: 0;
  will-change: opacity, transform;
  transition:
    opacity   .7s var(--ease-out),
    transform .8s var(--ease-out);
}
.reveal-in {
  opacity: 1;
  transform: none;
}

/* Entrance variants. app.js picks one per element from a data attribute, so
   the page does not scroll past twenty identical fades.

   None of them move an element sideways. A horizontal translate pushes content
   outside the viewport while it waits its turn, and the page clips overflow
   rather than scrolling it — so the first characters of a line were being cut
   off instead of animating. Vertical travel has no such edge to fall off. */
.reveal-up    { transform: translateY(26px); }
.reveal-rise  { transform: translateY(44px); }
.reveal-scale { transform: scale(.965); }
.reveal-fade  { transform: none; }
.reveal-blur  { transform: translateY(18px); filter: blur(6px); }

/* The settled state, declared AFTER the variants and with two classes so it
   beats them on both specificity and source order.

   It was previously a single class declared before them, so a variant such as
   .reveal-up won the cascade and its translateY was never removed: every
   revealed element sat 26px below where it belonged, and section borders hung
   past the bottom of their own section. That is what made the stats dividers
   appear to run on into the section underneath. */
.reveal-init.reveal-in {
  opacity: 1;
  transform: none;
  filter: none;
}

/* Stagger within a group: each child comes in just behind the one before it. */
.reveal-d1 { transition-delay: .00s; }
.reveal-d2 { transition-delay: .07s; }
.reveal-d3 { transition-delay: .14s; }
.reveal-d4 { transition-delay: .21s; }
.reveal-d5 { transition-delay: .28s; }
.reveal-d6 { transition-delay: .35s; }

/* A section's heading rule draws itself as the section arrives. */
.reveal-init .hero__rule { transform: scaleX(0); }

.media-fade { opacity: 0; transition: opacity .55s ease; }
.media-in { opacity: 1; }

/* Images keep their box before they load, so a lazy image arriving mid-scroll
   never pushes the content under it. */
.pcard__media img,
.about__portrait img { display: block; }

/* ------------------------------------------------------------ breakpoints */

@media (max-width: 1080px) {
  .hdr__nav { display: none; }
  .burger { display: flex; }

  .rail { grid-template-columns: 1fr; }
  .rail__label { border-right: none; padding-bottom: 0; }
  .rail__index { position: static; }

  .hero { grid-template-columns: 1fr; }
  .hero__media { border-left: none; border-top: 1px solid var(--line); min-height: 58vw; }
  .hero__text { grid-template-columns: 1fr; gap: 26px; }

  .about, .ai__cards, .modal__body, .exp, .cols2, .legal__pair, .case__grid { grid-template-columns: 1fr; }
  .about__aside { border-left: none; border-top: 1px solid var(--line); }
  .case__meta { border-left: none; border-top: 1px solid var(--line); }

  .grid3 { grid-template-columns: repeat(2, 1fr); }
  .srv { grid-template-columns: 1fr; gap: 8px; }
  .exp { gap: 20px; }

  .cols2 > .skills__col--bordered,
  .cols2 > .legal__col--bordered { border-right: none; }
  .cols2 > .skills__col + .skills__col,
  .cols2 > .legal__col + .legal__col { border-top: 1px solid var(--line); }

  .modal__gallery { border-right: none; border-bottom: 1px solid var(--line); }
  .modal__dialog { height: 92vh; }
}

@media (max-width: 860px) {
  .stats { grid-template-columns: repeat(2, 1fr); }
  .stats__cell:nth-child(-n + 2) { border-bottom: 1px solid var(--line); }

  .grid3 { grid-template-columns: 1fr; }

  .hdr { padding-left: 16px; padding-right: 16px; }
  .hero__body { padding: 44px 20px 30px; }
  .hero__rule { margin: 20px 0 18px; }

  .stats__cell { padding: 20px; }
  .stats__n { font-size: 38px; }
  .stats__label { margin-top: 8px; }

  .rail__label { padding: 22px 20px 0; }
  .about__prose, .ai__body, .skills__col, .legal__col, .legal__pair, .contact__body, .policy__block, .policy__switch, .case__head, .case__gallery, .case__meta { padding: 28px 20px; }
  .about__aside { padding: 28px 20px; }
  .contact__body { padding: 38px 20px; }
  .knowledge { padding: 26px 20px; }
  .work__head { padding: 28px 20px 16px; }
  .srv { padding: 20px; }
  .exp { padding: 26px 20px; }
  .ai__card { padding: 22px 18px 26px; }
  .pcard { padding: 12px 12px 22px; }
  .pcard__body { padding: 16px 6px 0; }
  .ad__label-cell, .ad__slot { padding: 14px 20px; }
  .footer { flex-wrap: wrap; }
  .modal__head { padding-left: 16px; padding-right: 16px; }
}

@media (max-width: 460px) {
  .stats__n { font-size: 32px; }
  .stats__label { font-size: 9px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  /* No caret, no typing cursor. */
  .hero__role-text .hero__role-base::after,
  .hero__role-text .hero__role-fill::after { display: none; }

  /* No entrance transforms at all — content simply is where it belongs. */
  .reveal-init,
  .reveal-up, .reveal-rise, .reveal-scale, .reveal-fade, .reveal-blur {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
}
