/* ==========================================================================
   Vishal Verma — portfolio
   Palette, motion and layout inspired by dennissnellenberg.com:
   near-black canvas, oversized display type, numbered index rows,
   cursor-follow previews, scroll-reveal.
   ========================================================================== */

:root{
  --bg:        #0c0c0e;
  --bg-soft:   #141417;
  --card:      #16161a;
  --ink:       #f2f0ec;
  --dim:       #8c8a84;
  --faint:     #56544f;
  --line:      rgba(242,240,236,.13);
  --line-soft: rgba(242,240,236,.07);
  --accent:    #e8825a;
  --accent-dim:#a85a37;
  --ok:        #6ec38f;
  --shadow:    0 30px 80px rgba(0,0,0,.55);
}

:root[data-theme=light]{
  --bg:        #f6f4ef;
  --bg-soft:   #efece5;
  --card:      #ffffff;
  --ink:       #171614;
  --dim:       #67645e;
  --faint:     #a29e96;
  --line:      rgba(23,22,20,.14);
  --line-soft: rgba(23,22,20,.07);
  --accent:    #b8562f;
  --accent-dim:#8d3f20;
  --ok:        #2e7d4f;
  --shadow:    0 30px 70px rgba(60,50,40,.14);
}

*,*::before,*::after{box-sizing:border-box}

html{
  scroll-behavior:smooth;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}

body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font:400 16px/1.6 "Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;
  letter-spacing:-.005em;
  overflow-x:hidden;
  transition:background .4s ease,color .4s ease;
}

::selection{background:var(--accent);color:#fff}

a{color:inherit;text-decoration:none}
h1,h2,h3,h4{margin:0;font-weight:500;letter-spacing:-.035em;line-height:1.02}
p{margin:0}

.serif{font-family:"Instrument Serif",Georgia,"Times New Roman",serif;font-style:italic;font-weight:400;letter-spacing:-.02em}

/* Side padding only. A `padding` shorthand here would beat `section`'s vertical
   padding (class > element) and flatten the gaps between sections. */
.wrap{max-width:1240px;margin:0 auto;padding-left:40px;padding-right:40px}
@media(max-width:760px){.wrap{padding-left:22px;padding-right:22px}}

/* ---------------------------------------------------------------- preloader */
#pre{
  position:fixed;inset:0;z-index:999;background:var(--bg);
  display:flex;align-items:flex-end;justify-content:space-between;
  padding:0 40px 40px;
  transition:transform .9s cubic-bezier(.76,0,.24,1);
}
#pre.gone{transform:translateY(-101%)}
#pre .pname{font-size:clamp(34px,7vw,86px);letter-spacing:-.045em;line-height:1}
#pre .pnum{font:500 clamp(34px,7vw,86px)/1 "Inter",sans-serif;letter-spacing:-.05em;color:var(--faint);
  font-variant-numeric:tabular-nums}
#pre .pbar{position:absolute;left:0;bottom:0;height:2px;width:0;background:var(--accent)}
@media(max-width:760px){#pre{padding:0 22px 26px}}

/* --------------------------------------------------------------------- nav */
nav{
  position:fixed;top:0;left:0;right:0;z-index:400;
  display:flex;align-items:center;justify-content:space-between;
  padding:26px 40px;mix-blend-mode:normal;
  transition:transform .45s cubic-bezier(.76,0,.24,1),background .35s,padding .35s;
}
nav.hid{transform:translateY(-120%)}
nav.solid{background:color-mix(in srgb,var(--bg) 88%,transparent);backdrop-filter:blur(14px);
  padding:16px 40px;border-bottom:1px solid var(--line-soft)}
.logo{font-size:17px;font-weight:600;letter-spacing:-.03em;display:flex;align-items:center;gap:9px;
  white-space:nowrap;flex:none}
.logo i{width:7px;height:7px;border-radius:50%;background:var(--accent);display:block;font-style:normal;
  flex:none}
.logo .abbr{display:none}
.nlinks{display:flex;align-items:center;gap:30px;font-size:14px;color:var(--dim)}
.nlinks a{position:relative;padding:2px 0;transition:color .25s}
.nlinks a::after{content:"";position:absolute;left:0;bottom:-1px;width:0;height:1px;background:var(--accent);
  transition:width .3s cubic-bezier(.76,0,.24,1)}
.nlinks a:hover,.nlinks a.on{color:var(--ink)}
.nlinks a:hover::after,.nlinks a.on::after{width:100%}
#theme{background:none;border:1px solid var(--line);color:var(--dim);border-radius:99px;
  width:34px;height:34px;font:inherit;font-size:13px;cursor:pointer;transition:.25s}
#theme:hover{color:var(--ink);border-color:var(--ink)}
/* Over the full-bleed hero photo the nav has to be light in both themes.
   Scoped to the home page — elsewhere the nav sits on the page background. */
body.home nav:not(.solid) .logo{color:#fff}
body.home nav:not(.solid) .nlinks{color:rgba(255,255,255,.72)}
body.home nav:not(.solid) .nlinks a:hover,
body.home nav:not(.solid) .nlinks a.on{color:#fff}
body.home nav:not(.solid) #theme{color:rgba(255,255,255,.8);border-color:rgba(255,255,255,.32)}
body.home nav:not(.solid) #theme:hover{color:#fff;border-color:#fff}
@media(max-width:760px){
  nav,nav.solid{padding:18px 22px}
  .nlinks{gap:18px;font-size:13px}
}
/* Below this the full name + four links + toggle no longer fit on one line,
   so the wordmark drops to initials rather than wrapping into the links. */
@media(max-width:600px){
  .logo .full{display:none}
  .logo .abbr{display:inline}
  .nlinks{gap:14px;font-size:12.5px}
  #theme{width:30px;height:30px;font-size:12px}
}

/* -------------------------------------------------------------------- hero
   Full-bleed portrait, oversized name bleeding past both edges over the
   bottom of it, pill left / tagline right. Everything on the photo is light,
   regardless of theme, because the photo's ground is black. */
.hero{position:relative;height:100svh;min-height:560px;overflow:hidden;
  background:#0c0c0e;isolation:isolate}
.hero-bg{position:absolute;inset:0;z-index:0;margin:0;background:#0c0c0e}
/* Anchored to the top of the frame: the source has generous headroom above the
   head, and any downward offset combined with the settle-zoom crops into the
   hair. Keep the zoom small for the same reason. */
.hero-bg img{display:block;width:100%;height:100%;object-fit:cover;object-position:50% 0%;
  will-change:transform,opacity;transform:scale(1.06) translateY(var(--par,0px));
  transition:opacity 1.2s ease,transform 1.7s cubic-bezier(.22,1,.36,1)}
.js .hero-bg img{opacity:0;transform:scale(1.15)}
.js .hero-bg.in img{opacity:1;transform:scale(1.06) translateY(var(--par,0px))}

/* Legibility scrims: one under the nav, one under the name. */
.hero::before,.hero::after{content:"";position:absolute;left:0;right:0;z-index:1;pointer-events:none}
.hero::before{top:0;height:210px;background:linear-gradient(to bottom,rgba(0,0,0,.55),transparent)}
.hero::after{bottom:0;height:66%;
  background:linear-gradient(to top,rgba(0,0,0,.86),rgba(0,0,0,.4) 40%,transparent)}

.hero-fg{position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);z-index:2;
  display:flex;justify-content:space-between;align-items:center;gap:32px}
.hero .pill{color:rgba(255,255,255,.9);border-color:rgba(255,255,255,.3);
  background:rgba(0,0,0,.3);backdrop-filter:blur(8px);margin:0}
.pill{display:inline-flex;align-items:center;gap:9px;font-size:13px;color:var(--dim);
  border:1px solid var(--line);border-radius:99px;padding:8px 16px;width:max-content}
.pill i{width:7px;height:7px;border-radius:50%;background:var(--ok);display:block;
  animation:pulse 2.2s infinite}
@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.35;transform:scale(.75)}}

/* The shirt is cream, so white type over it needs its own shadow rather than
   relying on the scrims, which only cover the top and bottom bands. */
.hero-fg{text-shadow:0 2px 26px rgba(0,0,0,.8),0 1px 4px rgba(0,0,0,.55)}
.hero-tag{text-align:right;color:#fff}
.hero-tag .arr{display:block;font-size:21px;margin-bottom:16px;opacity:.8;
  animation:nudge 2.4s ease-in-out infinite}
@keyframes nudge{0%,100%{transform:translate(0,0)}50%{transform:translate(4px,4px)}}
.hero-tag p{font-size:clamp(19px,2.4vw,31px);letter-spacing:-.03em;line-height:1.22}
.hero-tag p b{display:block;font-weight:400;font-size:.52em;letter-spacing:.14em;
  text-transform:uppercase;color:rgba(255,255,255,.8);margin-top:12px}

/* The name: deliberately wider than the viewport, drifting sideways. */
.hero-name{position:absolute;left:0;right:0;bottom:2.5vh;z-index:2;margin:0;
  overflow:hidden;white-space:nowrap;color:#fff;
  font-size:clamp(74px,15.5vw,236px);letter-spacing:-.055em;line-height:.92;font-weight:500}
.hero-name .tk{display:inline-block;animation:namescroll 30s linear infinite}
.hero-name .tk span{padding-right:.28em}
@keyframes namescroll{to{transform:translateX(-50%)}}

@media(max-width:760px){
  .hero-fg{flex-direction:column;align-items:flex-start;gap:22px;top:auto;bottom:27vh;
    transform:none}
  .hero-tag{text-align:left}
  .hero-name{bottom:4vh}
  .hero .pill{background:rgba(0,0,0,.5)}
  /* On a tall viewport `cover` scales by height, so the full frame is visible
     and only the sides are cropped. A light zoom anchored near the face trims
     the dead headroom without inflating the head. */
  .hero-bg img,
  .js .hero-bg.in img{transform:scale(1.12) translateY(var(--par,0px));
    transform-origin:50% 10%}
  .js .hero-bg img{transform:scale(1.22)}
}

/* ------------------------------------------------------- page hero (no photo)
   Used by pages without a full-bleed portrait. Per-side padding again, so it
   doesn't clobber .wrap's gutters. */
.phero{position:relative;padding-top:190px;padding-bottom:56px}
.phero .pill{margin-bottom:34px}
.phero h1{font-size:clamp(48px,11vw,168px);letter-spacing:-.055em;line-height:.88;font-weight:500}
.phero h1 .l2{display:block;color:var(--dim)}
.phero-meta{display:flex;justify-content:space-between;align-items:flex-end;gap:40px;
  margin-top:44px;padding-top:26px;border-top:1px solid var(--line);flex-wrap:wrap}
.phero-meta p{max-width:46ch;font-size:16px;color:var(--dim);line-height:1.65}
.phero-meta p b{color:var(--ink);font-weight:500}
.phero-role{font-size:13px;text-transform:uppercase;letter-spacing:.16em;color:var(--faint);
  white-space:nowrap}
@media(max-width:760px){.phero{padding-top:132px}}

/* -------------------------------------------------------------------- intro */
.intro{padding-top:104px;padding-bottom:44px}
.intro p{font-size:clamp(21px,2.7vw,34px);line-height:1.34;letter-spacing:-.03em;
  max-width:26ch;color:var(--dim);font-weight:400}
.intro p b{color:var(--ink);font-weight:500}
.scroll-cue{display:flex;align-items:center;gap:10px;font-size:12px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--faint);margin-top:44px}
.scroll-cue span{display:block;width:34px;height:1px;background:var(--faint);
  animation:cue 1.9s cubic-bezier(.76,0,.24,1) infinite}
@keyframes cue{0%{transform:scaleX(0);transform-origin:left}
  50%{transform:scaleX(1);transform-origin:left}
  51%{transform:scaleX(1);transform-origin:right}
  100%{transform:scaleX(0);transform-origin:right}}

/* ---------------------------------------------------------------- portrait
   The studio shot is on a black ground, so every frame keeps a dark fill in
   both themes — it reads as a deliberate photograph rather than a cut-out. */
/* The source is nearly square, so a square `object-fit: cover` crop shows almost
   the entire frame and the face ends up tiny. These use a zoomed background
   crop instead, framed on the head. */
.face{background-color:#0c0c0e;background-image:url(../img/vishal.jpg);
  background-repeat:no-repeat;background-position:50% 13%;background-size:300%;
  border-radius:50%;border:1px solid var(--line)}

/* A round portrait dropped inline into a sentence. */
.av{display:inline-block;width:.9em;height:.9em;vertical-align:-.08em;margin:0 .14em;
  transition:transform .7s cubic-bezier(.34,1.56,.64,1) .35s}
.js .av{transform:scale(0)}
.js .rv.in .av{transform:scale(1)}

.foot-shot{width:92px;height:92px;flex:none;margin:0 0 26px}

/* ----------------------------------------------------------------- marquee */
.marq{border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  padding:18px 0;overflow:hidden;white-space:nowrap;background:var(--bg-soft)}
.marq div{display:inline-flex;gap:44px;padding-right:44px;animation:slide 34s linear infinite}
.marq span{font-size:14px;letter-spacing:.05em;color:var(--dim);display:flex;align-items:center;gap:44px}
.marq span::after{content:"";width:5px;height:5px;border-radius:50%;background:var(--accent);opacity:.65}
@keyframes slide{to{transform:translateX(-100%)}}

/* --------------------------------------------------------------- sections */
section{padding-top:140px;padding-bottom:110px}
/* Clears the fixed nav (67px when scrolled) on an in-page anchor jump. */
section[id],footer[id]{scroll-margin-top:80px}
.shead{display:flex;align-items:baseline;gap:16px;margin-bottom:14px}
.snum{font:500 12px/1 "Inter",sans-serif;letter-spacing:.14em;color:var(--accent);
  border:1px solid var(--line);border-radius:99px;padding:6px 11px;flex:none}
.slab{font-size:12px;letter-spacing:.18em;text-transform:uppercase;color:var(--faint)}
.stitle{font-size:clamp(34px,5.6vw,72px);letter-spacing:-.045em;margin-bottom:16px;max-width:18ch}
.sintro{color:var(--dim);max-width:58ch;font-size:16.5px;line-height:1.7;margin-bottom:56px}
.sintro a,.about-copy a,.track-note a,.job a{color:var(--accent);
  border-bottom:1px solid transparent;transition:border-color .25s}
.sintro a:hover,.about-copy a:hover,.track-note a:hover,.job a:hover{border-color:var(--accent)}

/* --------------------------------------------------------- index rows */
.rows{border-top:1px solid var(--line)}
.row{display:grid;grid-template-columns:66px 1fr auto;align-items:center;gap:26px;
  padding:30px 4px;border-bottom:1px solid var(--line);position:relative;
  transition:padding-left .45s cubic-bezier(.76,0,.24,1),border-color .3s}
.row::before{content:"";position:absolute;left:0;top:0;bottom:0;width:0;background:var(--bg-soft);
  z-index:-1;transition:width .45s cubic-bezier(.76,0,.24,1)}
.row:hover{padding-left:22px;border-color:var(--accent)}
.row:hover::before{width:100%}
.row .n{font:500 13px/1 "Inter",sans-serif;color:var(--faint);letter-spacing:.06em;
  font-variant-numeric:tabular-nums;transition:color .3s}
.row:hover .n{color:var(--accent)}
.row h3{font-size:clamp(22px,3.1vw,38px);letter-spacing:-.035em;font-weight:500;transition:color .3s}
.row .sub{display:block;font-size:14px;color:var(--dim);margin-top:7px;line-height:1.55;max-width:62ch}
.row .sub b{color:var(--ink);font-weight:500}
.row .sub code{font:inherit;font-family:ui-monospace,Menlo,monospace;font-size:12.8px;
  background:var(--bg-soft);border:1px solid var(--line-soft);border-radius:5px;padding:1px 5px}
.row .tags{display:flex;gap:7px;flex-wrap:wrap;margin-top:12px}
.row .tags b{font:500 11px/1 "Inter",sans-serif;letter-spacing:.05em;color:var(--dim);
  border:1px solid var(--line);border-radius:99px;padding:5px 9px}
.row .go{font-size:13px;color:var(--faint);display:flex;align-items:center;gap:9px;white-space:nowrap;
  transition:color .3s,transform .35s cubic-bezier(.76,0,.24,1)}
.row:hover .go{color:var(--accent);transform:translateX(6px)}
@media(max-width:760px){
  .row{grid-template-columns:38px 1fr;gap:14px;padding:24px 2px}
  .row .go{grid-column:2;justify-content:flex-start;margin-top:10px}
  .row:hover{padding-left:8px}
}

/* ------------------------------------------------------------------ about */
.statement{font-size:clamp(26px,4.1vw,54px);line-height:1.16;letter-spacing:-.038em;
  max-width:20ch;font-weight:500}
.statement em{color:var(--accent);font-style:normal}
.about-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:70px;align-items:start}
.about-copy p{color:var(--dim);font-size:16.5px;line-height:1.72;margin-bottom:20px}
.about-copy p b{color:var(--ink);font-weight:500}
.stats{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:14px;overflow:hidden;margin-top:44px}
.stat{background:var(--bg);padding:26px 22px}
.stat b{display:block;font-size:clamp(30px,4.4vw,48px);letter-spacing:-.045em;font-weight:500;
  line-height:1;margin-bottom:9px}
.stat span{font-size:13px;color:var(--dim);line-height:1.45;display:block}
.skills{margin-top:0}
.skill{padding:18px 0;border-bottom:1px solid var(--line-soft);display:grid;
  grid-template-columns:150px 1fr;gap:20px;align-items:baseline}
.skill:first-child{border-top:1px solid var(--line)}
.skill b{font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--faint);font-weight:500}
.skill span{font-size:15px;color:var(--dim);line-height:1.6}
@media(max-width:900px){
  .about-grid{grid-template-columns:1fr;gap:44px}
  .skill{grid-template-columns:1fr;gap:7px}
}

/* --------------------------------------------------------------- timeline */
.job{display:grid;grid-template-columns:200px 1fr;gap:34px;padding:34px 0;
  border-bottom:1px solid var(--line)}
.job:first-child{border-top:1px solid var(--line)}
.job .when{font-size:13px;color:var(--faint);letter-spacing:.05em;padding-top:6px}
.job .when b{display:block;color:var(--accent);font-weight:500;margin-bottom:5px}
.job h3{font-size:clamp(20px,2.6vw,29px);letter-spacing:-.03em;margin-bottom:5px}
.job .org{font-size:14px;color:var(--dim);margin-bottom:16px}
.job ul{margin:0;padding-left:17px;color:var(--dim);font-size:15px;line-height:1.68}
.job li{margin-bottom:8px}
.job li b{color:var(--ink);font-weight:500}
.job li::marker{color:var(--accent)}
@media(max-width:760px){.job{grid-template-columns:1fr;gap:12px}}

/* ------------------------------------------------------------ learn teaser */
.teaser{border:1px solid var(--line);border-radius:18px;padding:46px;background:var(--bg-soft);
  display:grid;grid-template-columns:1fr auto;gap:40px;align-items:center;
  transition:border-color .35s,transform .45s cubic-bezier(.76,0,.24,1)}
.teaser:hover{border-color:var(--accent);transform:translateY(-4px)}
.teaser h3{font-size:clamp(26px,3.6vw,42px);letter-spacing:-.04em;margin-bottom:12px}
.teaser p{color:var(--dim);max-width:52ch;line-height:1.7}
.teaser .arrow{width:74px;height:74px;border-radius:50%;border:1px solid var(--line);flex:none;
  display:grid;place-items:center;font-size:22px;transition:.35s}
.teaser:hover .arrow{background:var(--accent);border-color:var(--accent);color:#fff;transform:rotate(45deg)}
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:22px}
.chips b{font:500 12px/1 "Inter",sans-serif;color:var(--dim);border:1px solid var(--line);
  border-radius:99px;padding:7px 12px}
@media(max-width:760px){.teaser{grid-template-columns:1fr;padding:30px;gap:26px}}

/* ------------------------------------------------------------- learn page */
.track{padding-top:124px;padding-bottom:0}
/* Sticks below the fixed nav, not underneath it — the scrolled nav is 67px. */
.track-head{position:sticky;top:68px;z-index:5;background:var(--bg);padding:22px 0 18px;
  border-bottom:1px solid var(--line);margin-bottom:6px}
.track-head .in{display:flex;align-items:baseline;gap:16px;flex-wrap:wrap}
.track-head h2{font-size:clamp(26px,4vw,44px);letter-spacing:-.04em}
.track-head .count{font-size:13px;color:var(--faint);margin-left:auto;letter-spacing:.05em}
.track-note{color:var(--dim);font-size:15.5px;line-height:1.7;max-width:62ch;margin:20px 0 30px}
.bar{height:3px;background:var(--line);border-radius:99px;overflow:hidden;margin-top:14px}
.bar i{display:block;height:100%;background:var(--accent);width:0;transition:width 1.1s cubic-bezier(.76,0,.24,1)}
.parts{display:flex;flex-wrap:wrap;gap:7px;margin:26px 0 8px}
.parts b{font:400 12.5px/1 "Inter",sans-serif;color:var(--dim);border:1px solid var(--line);
  border-radius:7px;padding:8px 11px;transition:.25s}
.parts b.done{color:var(--ink);border-color:var(--accent-dim)}
.parts b.done::before{content:"● ";color:var(--accent);font-size:9px;vertical-align:middle}

/* ----------------------------------------------------------------- footer */
footer{border-top:1px solid var(--line);padding:110px 0 44px;background:var(--bg-soft)}
.cta{font-size:clamp(42px,10vw,150px);letter-spacing:-.055em;line-height:.92;font-weight:500;
  display:block;transition:color .35s}
.cta:hover{color:var(--accent)}
.cta .serif{color:var(--accent)}
.fmeta{display:flex;justify-content:space-between;gap:40px;flex-wrap:wrap;
  margin-top:70px;padding-top:28px;border-top:1px solid var(--line)}
.fcol b{display:block;font-size:12px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--faint);margin-bottom:12px;font-weight:500}
.fcol a,.fcol span{display:block;font-size:15px;color:var(--dim);margin-bottom:7px;transition:color .25s}
.fcol a:hover{color:var(--accent)}
.fbot{margin-top:56px;display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;
  font-size:13px;color:var(--faint)}

/* ------------------------------------------------------------ scroll reveal
   Hidden states are gated behind `.js` (set by an inline script in <head>), so
   if the script never loads the page renders fully instead of staying blank. */
.rv{transition:opacity .8s cubic-bezier(.22,1,.36,1),transform .8s cubic-bezier(.22,1,.36,1)}
.js .rv{opacity:0;transform:translateY(26px)}
.js .rv.in{opacity:1;transform:none}
.rv.d1{transition-delay:.07s}.rv.d2{transition-delay:.14s}.rv.d3{transition-delay:.21s}

@media(prefers-reduced-motion:reduce){
  *{animation:none!important;transition-duration:.01ms!important;scroll-behavior:auto!important}
  .js .rv,.rv{opacity:1;transform:none}
  .js .av,.av{transform:none}
  .js .hero-bg img,.js .hero-bg.in img{opacity:1;transform:scale(1.06)}
  .hero-name .tk{animation:none}
  #pre{display:none}
}
