/* ------------------------------------------------------------------
   Joyce Shen — shenjoyce.com
   Single static page. No build step, no dependencies, no JavaScript.
   ------------------------------------------------------------------ */

:root {
  --bg: #ffffff;
  --fg: #101010;
  --dim: #85857f;
  --rule: #e4e2dd;
  --shell: 28px;   /* horizontal page padding */
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 400 15px/1.55 "Helvetica Neue", Helvetica, Inter, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: inherit; text-decoration: none; }
a:hover { color: var(--dim); }
a:focus-visible { outline: 2px solid var(--fg); outline-offset: 3px; }

h1, h2, p { margin: 0; }

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

/* Visible only once tabbed to */
.skip {
  position: absolute; left: -9999px;
  padding: 10px 14px; background: var(--fg); color: #fff; z-index: 10;
}
.skip:focus { left: 12px; top: 12px; }

/* Small uppercase label used for nav, section heads, captions, footer */
.micro {
  font-size: 10.5px;
  font-weight: 400;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--dim);
}
.tab { font-variant-numeric: tabular-nums; }

/* ------------------------------ Hero ------------------------------ */

.hero {
  position: relative;
  height: 84vh;
  min-height: 430px;
  overflow: hidden;
}
/* Takes either an <img> or a <video>. The background colour shows through
   while the file loads, and stands in for it if the file is missing. */
.hero-media {
  position: absolute; inset: 0;
  background-color: #45443f;
  display: flex; align-items: center; justify-content: center;
  color: #7e7c75;
  font-size: 9px; letter-spacing: .16em; text-transform: uppercase;
}
.hero-media:empty::after { content: "Image"; }

.hero-media > img,
.hero-media > video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;

  /* The muted grade is baked into the file rather than applied here, since
     filtering a video costs work on every frame. Uncomment to try a grade
     before committing to it:
     filter: saturate(.45) contrast(1.05); */
}

/* Anyone who has asked for less motion gets the poster frame instead */
@media (prefers-reduced-motion: reduce) {
  .hero-media > video { display: none; }
}

.scrim {
  position: absolute; inset: 0;
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, .34) 0 18%,
    rgba(0, 0, 0, 0) 46%,
    rgba(0, 0, 0, .44) 100%
  );
}

.hero-nav {
  position: absolute; top: 0; left: 0; right: 0;
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 16px;
  padding: 20px var(--shell);
}
.hero-nav .micro,
.hero-caption .micro { color: rgba(255, 255, 255, .84); }
.hero-nav a:hover { color: #fff; }
.hero-nav .links { display: flex; gap: 20px; }

.hero-caption {
  position: absolute; bottom: 26px; left: var(--shell); right: var(--shell);
  display: flex; justify-content: space-between; align-items: flex-end; gap: 20px;
  color: #fff;
}
.hero-caption h1 {
  font-size: clamp(2.1rem, 5.4vw, 4.4rem);
  line-height: .95;
  letter-spacing: -.035em;
  font-weight: 600;
}
.hero-caption h1 span {
  display: block;
  max-width: 26rem;
  padding-top: .7rem;
  font-size: 32%;
  font-weight: 400;
  letter-spacing: .01em;
}

/* ---------------------------- Content ---------------------------- */

.wrap {
  max-width: 1180px;
  margin: 0 auto;
  padding: 58px var(--shell) 84px;
}

.intro {
  display: grid;
  grid-template-columns: 1fr 1.3fr;
  gap: 40px;
  padding-bottom: 48px;
  border-bottom: 1px solid var(--rule);
}
.big {
  font-size: 1.4rem;
  line-height: 1.35;
  letter-spacing: -.015em;
  max-width: 26rem;
}
.intro .side { color: var(--dim); max-width: 34rem; }

section { padding-top: 44px; }

.head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 16px;
  padding-bottom: 14px;
}

/* Experience rows */
.row {
  display: grid;
  grid-template-columns: 4.5rem 1.1fr 1.4fr;
  gap: 20px;
  align-items: baseline;
  padding: 15px 0;
  border-top: 1px solid var(--rule);
}
.row:last-child { border-bottom: 1px solid var(--rule); }
.row .yr { color: var(--dim); }
.row .role { font-weight: 500; }
.row .org { display: block; font-weight: 400; color: var(--dim); }
.row .desc { color: var(--dim); }

/* Media — justified rows.
   Giving each figure a flex-grow equal to its aspect ratio makes every figure
   in a row settle on the same height, so landscape and portrait shots can sit
   side by side without being cropped to a common shape. */
.photo-rows { display: flex; flex-direction: column; gap: 14px; }
.photo-row { display: flex; gap: 14px; }

.photo-rows figure { margin: 0; }
.photo-row figure { flex: var(--ar) 1 0; min-width: 0; }

.photo-rows img {
  width: 100%;
  height: auto;
  aspect-ratio: var(--ar);
  object-fit: cover;
}

.photo-rows figcaption {
  display: flex; justify-content: space-between; gap: 12px;
  padding-top: 7px;
}

/* One image spanning the full content width, to break the rhythm of the rows.
   Height is capped so it stays a wide band rather than a second hero on tall
   screens — past the cap the image crops instead of growing. */
.photo-wide img { max-height: 62vh; }

/* Contact */
.contact {
  display: grid; grid-template-columns: 1fr auto;
  gap: 30px; align-items: end;
  padding-top: 8px;
}
.contact .big {
  font-size: clamp(1.6rem, 4.2vw, 3rem);
  line-height: 1.04;
  letter-spacing: -.03em;
  font-weight: 500;
  max-width: none;
}
.contact .list { display: grid; gap: 5px; text-align: right; }

footer {
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px;
  margin-top: 56px;
  padding-top: 16px;
  border-top: 1px solid var(--fg);
}

/* ----------------------------- Mobile ----------------------------- */

@media (max-width: 780px) {
  :root { --shell: 18px; }

  .hero { height: 74vh; }

  /* If the hero ever goes back to video, this shows phones the still poster
     instead. It reliably stops playback, though whether the file is still
     fetched is up to the browser — drop the <video> to be certain:
     .hero-media > video { display: none; } */

  .hero-nav { flex-wrap: wrap; }
  .hero-nav .name { display: none; }
  .hero-nav .links { gap: 16px; }
  .hero-caption {
    bottom: 18px;
    flex-direction: column; align-items: flex-start; gap: 12px;
  }

  .wrap { padding-top: 38px; padding-bottom: 56px; }

  .intro { grid-template-columns: 1fr; gap: 20px; padding-bottom: 32px; }
  .big { font-size: 1.2rem; }

  .row { grid-template-columns: 3.4rem 1fr; gap: 3px 14px; }
  .row .desc { grid-column: 2; }

  /* One photograph per row, uncropped. Pairing orientations at this width
     leaves either an awkward gap or a very tall portrait. */
  .photo-rows { gap: 22px; }
  .photo-row { flex-direction: column; gap: 22px; }

  .contact { grid-template-columns: 1fr; gap: 18px; }
  .contact .list { text-align: left; }
}
