/* ============================================================
   Jerod Wanner — portfolio landing
   Warm editorial system. Tokens driven by the Tweaks panel.
   ============================================================ */

:root {
  /* Defaults — overridden at runtime by the Tweaks panel */
  --bg:        oklch(0.945 0.014 90);
  --bg-deep:   oklch(0.915 0.018 88);
  --ink:       oklch(0.245 0.012 70);
  --ink-soft:  oklch(0.42 0.012 70);
  --ink-faint: oklch(0.58 0.010 70);
  --accent:    oklch(0.66 0.072 128);
  --hairline:  oklch(0.245 0.012 70 / 0.14);

  --font-display: "Spectral", Georgia, "Times New Roman", serif;
  --font-ui: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif;

  /* grid */
  --cols: 4;
  --gap: 28px;

  --maxw: 1280px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

* { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-ui);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100vh;
  position: relative;
  overflow-x: hidden;
  transition: background 0.5s var(--ease), color 0.5s var(--ease);
}

/* Subtle paper grain over everything */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9999;
  opacity: 0.5;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.045'/%3E%3C/svg%3E");
}

/* ---------------------------------------------------------- */
/* Shell                                                       */
/* ---------------------------------------------------------- */
.shell {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 clamp(22px, 4vw, 56px) 96px;
}

/* ---------------------------------------------------------- */
/* Top bar                                                     */
/* ---------------------------------------------------------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: clamp(16px, 2.2vw, 26px) 0 clamp(13px, 1.7vw, 18px);
  background: var(--bg);
  /* promote to its own layer so iOS doesn't repaint the sticky bar a frame
     late on momentum scroll (which briefly exposes content behind it) */
  transform: translateZ(0);
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  transition: background 0.5s var(--ease);
}
/* opaque backing that spans the FULL viewport width (not just the centered
   shell) and extends well above the bar — covers rubber-band overscroll and
   any repaint lag so nothing ever shows above or beside it */
.topbar::before {
  content: "";
  position: absolute;
  left: 50%;
  width: 100vw;
  margin-left: -50vw;
  top: -200px;
  bottom: 0;
  background: var(--bg);
  z-index: -1;
  pointer-events: none;
}
/* full-viewport-width hairline + drop shadow at the bar's bottom edge, so the
   shadow bleeds past the content edges instead of hard-cutting at the shell.
   Sits in the bar's stacking context (z-index:100) so it renders above the
   page content scrolling underneath. */
.topbar::after {
  content: "";
  position: absolute;
  left: 50%;
  width: 100vw;
  margin-left: -50vw;
  bottom: 0;
  height: 0;
  border-bottom: 1px solid transparent;
  pointer-events: none;
  transition: border-color 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
/* once the page is scrolled, separate the bar from the content beneath it */
.topbar.is-stuck::after {
  border-bottom-color: var(--hairline);
  box-shadow: 0 12px 30px -16px rgba(40, 32, 18, 0.5);
}

.brand-wrap {
  display: flex;
  align-items: center;
  gap: 0;
}

/* back chevron — hidden on the landing view, slides in beside the name
   once a project is open (replaces the old standalone "All work" link) */
.brand-back {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 0;
  margin-right: 0;
  padding: 0;
  border: none;
  background: none;
  color: var(--ink-soft);
  cursor: pointer;
  opacity: 0;
  overflow: hidden;
  transform: translateX(-4px);
  transition: width 0.32s var(--ease), opacity 0.28s var(--ease),
              transform 0.32s var(--ease), margin-right 0.32s var(--ease),
              color 0.2s var(--ease);
}
.brand-back svg { display: block; }
body.proj-open .brand-back {
  width: 22px;
  margin-right: 4px;
  opacity: 1;
  transform: none;
}
body.proj-open .brand-back:hover { color: var(--ink); transform: translateX(-2px); }
body.proj-open .brand { cursor: pointer; }
body.proj-open .brand-wrap:hover .brand { color: var(--accent); }
.brand-wrap .brand { transition: color 0.2s var(--ease); }

.brand {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 17px;
  letter-spacing: -0.01em;
  margin: 0;
  color: var(--ink);
  line-height: 1.1;
}

.nav {
  display: flex;
  align-items: center;
  gap: clamp(16px, 2vw, 26px);
}
.link-label { display: none; }

/* hamburger toggle — only shown on narrow viewports */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  width: 38px;
  height: 38px;
  margin: -4px -8px -4px 0;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  border-radius: 8px;
}
.nav-toggle span {
  display: block;
  width: 20px;
  height: 2px;
  background: var(--ink);
  border-radius: 2px;
  transition: transform 0.28s var(--ease), opacity 0.12s var(--ease);
}
.topbar.is-menu-open .nav-toggle span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.topbar.is-menu-open .nav-toggle span:nth-child(2) { opacity: 0; transform: scaleX(0); }
.topbar.is-menu-open .nav-toggle span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
.icon-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  color: var(--ink-soft);
  text-decoration: none;
  border-radius: 6px;
  transition: color 0.25s var(--ease), transform 0.25s var(--ease);
}
.icon-link svg { display: block; }
/* Bruce avatar — transparent dog-head photo used as a nav icon */
.bruce-avatar {
  display: block;
  width: 25px;
  height: 25px;
  object-fit: contain;
  object-position: center;
}
.icon-link.is-bruce:hover { transform: translateY(-2px); }
/* on hover: a quick left/right head wiggle that settles back to rest, then
   holds for ~2s before looping (the hold is the tail of the keyframes) */
.icon-link.is-bruce:hover .bruce-avatar {
  transform-origin: 50% 82%;
  animation: bruce-wiggle 3s var(--ease) infinite;
}
@keyframes bruce-wiggle {
  0%   { transform: rotate(0deg); }
  6%   { transform: rotate(-13deg); }
  12%  { transform: rotate(11deg); }
  18%  { transform: rotate(-8deg); }
  24%  { transform: rotate(6deg); }
  29%  { transform: rotate(-3deg); }
  34%  { transform: rotate(0deg); }
  100% { transform: rotate(0deg); }
}
.icon-link .emoji {
  font-size: 19px;
  line-height: 1;
  transform-origin: 70% 80%;
}
.icon-link:hover { color: var(--ink); transform: translateY(-2px) scale(1.12); }
.icon-link.is-linkedin:hover { color: #0A66C2; }
.icon-link[data-link="email"]:hover { transform: translateY(-2px); }
.icon-link[data-link="email"]:hover .emoji { animation: wave 0.9s var(--ease); }
.icon-link:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent);
}

@keyframes wave {
  0%, 100% { transform: rotate(0deg); }
  20% { transform: rotate(16deg); }
  40% { transform: rotate(-10deg); }
  60% { transform: rotate(14deg); }
  80% { transform: rotate(-6deg); }
}

/* resume icon: looping line-draw on the paper */
.icon-link[data-link="resume"] .doc-line {
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
}
.icon-link[data-link="resume"]:hover .doc-line {
  animation: doc-draw 1.5s var(--ease) infinite;
}
.icon-link[data-link="resume"]:hover .doc-line.l2 { animation-delay: 0.22s; }
@keyframes doc-draw {
  0%   { stroke-dashoffset: 1; }
  35%  { stroke-dashoffset: 0; }
  65%  { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: -1; }
}

/* --- mobile (no hover): auto-play each icon's animation once, hold ~1.5s,
   then loop. Motion lives in the first ~40% of a 2.5s cycle; the remainder
   holds at rest so the loop is seamless (start == end == resting state). --- */
@media (hover: none) {
  .icon-link.is-bruce .bruce-avatar {
    transform-origin: 50% 82%;
    animation: bruce-auto 2.5s var(--ease) infinite;
  }
  .icon-link[data-link="resume"] .doc-line { animation: doc-auto 2.5s var(--ease) infinite; }
  .icon-link[data-link="resume"] .doc-line.l2 { animation-delay: 0.12s; }
  .icon-link[data-link="email"] .emoji { animation: wave-auto 2.5s var(--ease) infinite; }
  .icon-link.is-linkedin svg { transform-origin: center; animation: li-auto 2.5s var(--ease) infinite; }
}
@keyframes bruce-auto {
  0%   { transform: rotate(0deg); }
  5%   { transform: rotate(-13deg); }
  12%  { transform: rotate(11deg); }
  19%  { transform: rotate(-8deg); }
  26%  { transform: rotate(6deg); }
  32%  { transform: rotate(-3deg); }
  40%  { transform: rotate(0deg); }
  100% { transform: rotate(0deg); }
}
/* lines redraw, then hold visible (resting) through the pause */
@keyframes doc-auto {
  0%   { stroke-dashoffset: 0; }
  8%   { stroke-dashoffset: 1; }
  40%  { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: 0; }
}
@keyframes wave-auto {
  0%   { transform: rotate(0deg); }
  8%   { transform: rotate(16deg); }
  16%  { transform: rotate(-10deg); }
  24%  { transform: rotate(14deg); }
  32%  { transform: rotate(-6deg); }
  40%  { transform: rotate(0deg); }
  100% { transform: rotate(0deg); }
}
@keyframes li-auto {
  0%   { transform: scale(1); }
  12%  { transform: scale(1.18); }
  26%  { transform: scale(0.96); }
  40%  { transform: scale(1); }
  100% { transform: scale(1); }
}

/* ---------------------------------------------------------- */
/* Hero                                                        */
/* ---------------------------------------------------------- */
.hero {
  text-align: center;
  padding: clamp(64px, 11vw, 150px) 0 clamp(48px, 7vw, 96px);
}

.hero-eyebrow {
  font-family: var(--font-ui);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: clamp(22px, 3vw, 38px) 0 0;
  transition: opacity 0.9s var(--ease) 0.05s, transform 0.9s var(--ease) 0.05s;
}
html.js-anim:not(.ready) .hero-eyebrow { opacity: 0; transform: translateY(12px); }

.headline {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(38px, 6.6vw, 96px);
  line-height: 1.08;
  letter-spacing: -0.015em;
  margin: 0 auto;
  color: var(--ink);
}
.headline .line { display: block; }
.headline .u { position: relative; display: inline-block; }
.headline .word {
  display: inline-block;
  transition: opacity 0.95s var(--ease), transform 0.95s var(--ease);
}
html.js-anim:not(.ready) .headline .word { opacity: 0; transform: translateY(0.5em); }

/* painted underline beneath “through motion.” only — sits behind the type */
.paint {
  position: absolute;
  left: -3%;
  right: -3%;
  bottom: -0.02em;
  height: 0.26em;
  overflow: hidden;
  pointer-events: none;
  z-index: -1;
}
.paint svg {
  display: block;
  width: 100%;
  height: 100%;
  clip-path: inset(0 0 0 0);
  transition: clip-path 1.05s var(--ease) 0.95s;
}
html.js-anim:not(.ready) .paint svg { clip-path: inset(0 100% 0 0); }

/* ---------------------------------------------------------- */
/* Work grid                                                   */
/* ---------------------------------------------------------- */
.work {
  display: grid;
  grid-template-columns: repeat(var(--cols), 1fr);
  gap: var(--gap);
}

.tile {
  display: flex;
  flex-direction: column;
  gap: 12px;
  text-decoration: none;
  color: inherit;
  transition: opacity 0.75s var(--ease), transform 0.45s var(--ease);
}
html.js-anim:not(.ready) .tile { opacity: 0; }
.tile:hover { transition-delay: 0s, 0s; }

.tile-media {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: 4px;
  overflow: hidden;
  background: var(--bg-deep);
  box-shadow: 0 1px 0 0 var(--hairline);
  transition: transform 0.5s var(--ease), box-shadow 0.5s var(--ease), filter 0.5s var(--ease);
  will-change: transform;
}

/* swappable placeholder */
.placeholder {
  position: absolute;
  inset: 0;
  background:
    repeating-linear-gradient(
      -45deg,
      oklch(0.86 0.02 88) 0 11px,
      oklch(0.83 0.022 86) 11px 22px
    );
  display: flex;
  align-items: center;
  justify-content: center;
}
.placeholder span {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11px;
  letter-spacing: 0.06em;
  color: oklch(0.46 0.02 80);
  background: var(--bg);
  padding: 5px 9px;
  border-radius: 3px;
  text-transform: uppercase;
}

.tile-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.4s var(--ease);
}
/* video sits on top of the static poster and fades in only while playing,
   so pausing/resetting falls back to the first-frame poster image */
.tile.has-video .placeholder { opacity: 0; }
.tile.is-playing .tile-video { opacity: 1; }

/* static poster + hover Vimeo embed (silent background loop) */
.tile-poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.tile-embed {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.9s cubic-bezier(0.4, 0, 0.2, 1);
  background: #fff;
}
.tile-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.tile.embed-on .tile-embed { opacity: 1; }

/* media inner zoom layer */
.tile-media .zoom {
  position: absolute;
  inset: 0;
  transition: transform 0.7s var(--ease);
}

/* playhead + timecode overlay */
.tile-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s var(--ease);
}
.tile-overlay .scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(20,16,8,0.55), rgba(20,16,8,0) 46%);
}
.timecode {
  position: absolute;
  top: 10px; left: 11px;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: rgba(255,255,255,0.92);
  background: rgba(20,16,8,0.4);
  backdrop-filter: blur(2px);
  padding: 3px 6px;
  border-radius: 3px;
}
.playhead {
  position: absolute;
  left: 11px; right: 11px; bottom: 11px;
  height: 2px;
  background: rgba(255,255,255,0.28);
  border-radius: 2px;
  overflow: hidden;
}
.playhead::after {
  content: "";
  position: absolute;
  inset: 0;
  width: 0%;
  background: var(--accent);
  border-radius: 2px;
}

/* moving sheen on placeholder while "playing" */
.tile-media .sheen {
  position: absolute;
  top: 0; bottom: 0;
  width: 40%;
  left: -50%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,0.22), transparent);
  opacity: 0;
}

.tile-meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 0 1px;
  opacity: 0;
  transform: translateY(-4px);
  /* keep the caption above the mat's hover drop shadow (the scaled .tile-media
     lifts into its own layer, so without this its shadow would wash over the
     words below) */
  position: relative;
  z-index: 1;
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
}
.tile:hover .tile-meta,
.tile:focus-visible .tile-meta { opacity: 1; transform: none; }
@media (hover: none) {
  .tile-meta { opacity: 1; transform: none; }
}
.tile-title {
  font-family: var(--font-ui);
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--ink);
}
.tile-role {
  font-family: var(--font-ui);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--ink-faint);
  text-align: right;
  white-space: nowrap;
}
.tile-index {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 10.5px;
  color: var(--ink-faint);
  margin-right: 2px;
}

/* ============================================================
   HOVER BEHAVIORS (toggled via [data-hover] on .work)
   ============================================================ */

/* shared: while hovering, run the play sim */
.tile:hover .tile-overlay { opacity: 1; }
.tile:hover .playhead::after { animation: playline 5.5s linear forwards; }
.tile:hover .sheen { animation: sweep 1.6s var(--ease) infinite; }

@keyframes playline { from { width: 0%; } to { width: 100%; } }
@keyframes sweep {
  0%   { left: -50%; opacity: 0; }
  20%  { opacity: 1; }
  100% { left: 110%; opacity: 0; }
}

/* --- play (default): the whole tile (mat + caption) scales up as one unit,
   so the type grows with the thumbnail. The mat carries a subtle drop shadow;
   the caption sits above it (z-index) with its own text-shadow, so the mat's
   shadow never tints the type. --- */
.work[data-hover="play"] .tile:hover,
.work[data-hover="play"] .tile.is-playing {
  transform: scale(1.025);
}
.work[data-hover="play"] .tile:hover .tile-media,
.work[data-hover="play"] .tile.is-playing .tile-media {
  box-shadow: 0 1px 0 0 var(--hairline), 0 12px 22px -20px rgba(40, 32, 18, 0.32);
}
.work[data-hover="play"] .tile:hover .tile-title,
.work[data-hover="play"] .tile.is-playing .tile-title { color: var(--accent); }

/* --- lift: whole tile rises, stronger shadow --- */
.work[data-hover="lift"] .tile:hover { transform: translateY(-8px); }
.work[data-hover="lift"] .tile:hover .tile-media { box-shadow: 0 1px 0 0 var(--hairline), 0 34px 50px -24px rgba(40,32,18,0.62); }
.work[data-hover="lift"] .tile:hover .zoom { transform: scale(1.03); }

/* --- spotlight: siblings dim & desaturate, hovered pops --- */
.work[data-hover="spotlight"]:hover .tile { filter: saturate(0.5) brightness(0.94); opacity: 0.5; }
.work[data-hover="spotlight"]:hover .tile:hover { filter: none; opacity: 1; }
.work[data-hover="spotlight"] .tile:hover .tile-media { box-shadow: 0 1px 0 0 var(--hairline), 0 26px 46px -26px rgba(40,32,18,0.6); }
.work[data-hover="spotlight"] .tile:hover .zoom { transform: scale(1.05); }
.work[data-hover="spotlight"]:hover .tile { transition: filter 0.4s var(--ease), opacity 0.4s var(--ease), transform 0.45s var(--ease); }

/* keyboard focus mirrors hover for accessibility */
.tile:focus-visible { outline: none; }
.tile:focus-visible .tile-media { box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent); }

/* reduced motion */
@media (prefers-reduced-motion: reduce) {
  html.js-anim:not(.ready) .hero-eyebrow,
  html.js-anim:not(.ready) .headline .word,
  html.js-anim:not(.ready) .tile { opacity: 1 !important; transform: none !important; }
  html.js-anim:not(.ready) .paint svg { clip-path: inset(0 0 0 0) !important; }
  .tile:hover .playhead::after, .tile:hover .sheen { animation: none !important; }
}

/* ============================================================
   VIEW TRANSITION + PROJECT PAGE
   ============================================================ */

/* landing exit choreography */
#landingView.leaving .hero {
  opacity: 0;
  transform: translateY(-30px);
  transition: opacity 0.45s var(--ease), transform 0.45s var(--ease);
}

.project { display: block; }
.project[hidden] { display: none; }

/* scroll-triggered reveal (armed by JS when a project opens) */
[data-reveal].is-armed {
  opacity: 0;
  transform: translateY(32px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}
[data-reveal].is-armed.is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal].is-armed { opacity: 1 !important; transform: none !important; }
}

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: none;
  border: none;
  cursor: pointer;
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--ink-soft);
  padding: 6px 0;
  margin: 4px 0 clamp(28px, 4vw, 44px);
  transition: color 0.25s var(--ease), gap 0.25s var(--ease);
}
.back-link svg { transition: transform 0.25s var(--ease); }
.back-link:hover { color: var(--ink); gap: 11px; }
.back-link:hover svg { transform: translateX(-2px); }

/* head: title + meta */
.proj-head {
  margin-top: clamp(26px, 3.4vw, 46px);
  margin-bottom: clamp(40px, 5.5vw, 72px);
}
.proj-title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(28px, 3.8vw, 50px);
  line-height: 1.12;
  letter-spacing: -0.012em;
  color: var(--ink);
  margin: 0;
}
.proj-years { color: var(--ink-faint); font-weight: 400; font-size: 0.5em; letter-spacing: 0; }
.proj-intro {
  font-family: var(--font-ui);
  font-size: clamp(15px, 1.1vw, 17.5px);
  line-height: 1.62;
  color: var(--ink-soft);
  margin: clamp(18px, 2vw, 26px) 0 0;
  text-wrap: pretty;
}
/* meta footer: pillar / role / agency at the very bottom of the page */
.proj-meta-foot {
  display: flex;
  flex-flow: row wrap;
  gap: 28px 64px;
  margin-top: clamp(52px, 7vw, 96px);
  padding-top: clamp(24px, 3vw, 34px);
  border-top: 1px solid var(--hairline);
}
.meta-label {
  display: block;
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 4px;
}
.meta-val {
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.4;
  color: var(--ink);
}

/* sections */
.proj-section {
  display: flex;
  flex-direction: column;
  gap: clamp(16px, 1.6vw, 22px);
  margin-bottom: clamp(48px, 7vw, 96px);
}
.proj-h {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(19px, 1.8vw, 26px);
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 0;
}
.proj-h-years {
  color: var(--ink-faint);
  font-weight: 400;
  font-size: 0.62em;
  letter-spacing: 0;
  margin-left: 0.12em;
}
.proj-p {
  font-family: var(--font-ui);
  font-size: clamp(15px, 1.1vw, 17px);
  line-height: 1.66;
  color: var(--ink-soft);
  max-width: 66ch;
  margin: 0;
  text-wrap: pretty;
}

/* media */
.media {
  position: relative;
  border-radius: 4px;
  overflow: hidden;
  background: var(--bg-deep);
  box-shadow: 0 1px 0 0 var(--hairline), 0 12px 28px -22px rgba(40,32,18,0.5);
}
.media.ratio-wide   { aspect-ratio: 16 / 9; }
.media.ratio-still  { aspect-ratio: 4 / 3; }
.media.ratio-panel  { aspect-ratio: 3 / 2; }
.media.ratio-vert   { aspect-ratio: 9 / 16; }
.media.ratio-square { aspect-ratio: 1 / 1; }
.media.ratio-portrait { aspect-ratio: 4 / 5; }
.media.ratio-tall   { aspect-ratio: 3 / 4; }
.media.ratio-banner { aspect-ratio: 2 / 1; }
.media.ratio-reel   { aspect-ratio: 886 / 1920; }

/* dark video slot (logo marks, product on black, etc.) */
.media.is-dark { background: oklch(0.16 0.01 280); }
.placeholder.dark {
  background:
    repeating-linear-gradient(
      -45deg,
      oklch(0.225 0.012 280) 0 11px,
      oklch(0.185 0.012 280) 11px 22px
    );
}
.placeholder.dark span {
  color: oklch(0.72 0.018 280);
  background: oklch(0.135 0.012 280);
}

.media > .placeholder { transition: opacity 0.4s var(--ease); }
.proj-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* contain (not cover) so the full video frame is always visible at its
     native resolution — no cropping of the icon/logo animation content.
     Extra gap between tiles (below) gives the frames room to breathe. */
  object-fit: contain;
  opacity: 0;
  transition: opacity 0.45s var(--ease);
}
.media.has-video > .placeholder { opacity: 0; }
.media.has-video .proj-video { opacity: 1; }

/* Vimeo embeds fill the media frame (background mode crops to cover) */
.proj-embed {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

/* figure = media slot + caption below.
   margin:0 resets the UA <figure> default (1em 40px) so media sits flush
   with the copy + topbar edges instead of inset 40px on each side. */
.fig { display: flex; flex-direction: column; gap: 10px; min-width: 0; margin: 0; }
.fig-cap {
  font-family: var(--font-display);
  font-size: 14px;
  line-height: 1.4;
  letter-spacing: 0.002em;
  color: var(--ink-soft);
  text-wrap: pretty;
}

.media-row {
  display: grid;
  gap: clamp(22px, 3vw, 48px);
  align-items: start;
}
.media-row.cols-2 { grid-template-columns: repeat(2, 1fr); }
.media-row.cols-3 { grid-template-columns: repeat(3, 1fr); }
.media-row.cols-4 { grid-template-columns: repeat(4, 1fr); }
.media-row.cols-5 { grid-template-columns: repeat(5, 1fr); }

/* top-level rhythm between project blocks */
#projContent > .proj-block { margin-bottom: clamp(48px, 7vw, 96px); }
/* hero media sits first now — give it breathing room under the sticky topbar */
#projContent > .proj-block:first-child { margin-top: clamp(16px, 2.2vw, 28px); }
.proj-head + .proj-block { margin-top: clamp(-8px, 0vw, 0px); }

/* composite: 1x1 over banner on the left, full-height vertical on the right */
.split-stack {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: clamp(14px, 1.6vw, 26px);
  align-items: stretch;
}
.split-left {
  display: flex;
  flex-direction: column;
  /* square pinned to the top, banner pinned to the bottom — the gap between
     them grows to fill the column so the banner's bottom edge lines up with
     the bottom of the tall vertical video on the right */
  justify-content: space-between;
  gap: clamp(14px, 1.6vw, 26px);
  min-width: 0;
}
.split-right { height: 100%; gap: 0; align-items: stretch; }
/* pin the vertical slot to the video's exact pixel aspect (1260×2736) so the
   Vimeo embed fills it edge-to-edge with no letterboxing (was height-filled,
   which left the slot off-ratio and let the player pillarbox/letterbox) */
.split-right .media { aspect-ratio: 1260 / 2736; height: auto; align-self: start; width: 100%; }
@media (max-width: 700px) {
  .split-stack { grid-template-columns: 1fr; }
  .split-right { height: auto; max-width: 340px; }
  .split-right .media { aspect-ratio: 1260 / 2736; height: auto; }
}

/* media nested inside a text section uses the section's own gap */
.section-media { margin-top: clamp(4px, 0.8vw, 10px); }

/* credits */
.credits-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 22px 28px;
  margin: 4px 0 0;
  border-top: 1px solid var(--hairline);
  padding-top: 26px;
}
.credit dt {
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 6px;
}
.credit dd {
  font-family: var(--font-ui);
  font-size: 14.5px;
  color: var(--ink);
  margin: 0;
}

/* prev / next */
/* patent seal — small, right-aligned, non-intrusive */
.proj-patent {
  display: flex;
  justify-content: flex-end;
  gap: clamp(12px, 1.4vw, 20px);
  margin-top: clamp(4px, 0.8vw, 10px);
}
/* sits between the last video and the meta footer — keep that gap tight */
.proj-patent + .proj-meta-foot { margin-top: clamp(26px, 3.4vw, 44px); }
.patent-link {
  display: inline-flex;
  transform-origin: center;
  transition: transform 0.25s var(--ease);
}
.patent-link:hover,
.patent-link:focus-visible { transform: scale(1.14); }
.patent-link img { width: 34px; height: 34px; display: block; }

/* prev / next */
.proj-nav {
  display: flex;
  justify-content: space-between;
  gap: 24px;
  border-top: 1px solid var(--hairline);
  padding-top: 28px;
  margin-top: clamp(20px, 3vw, 40px);
}
.proj-nav-link {
  display: flex;
  flex-direction: column;
  gap: 5px;
  text-decoration: none;
  transition: transform 0.3s var(--ease);
}
.proj-nav-link.next { text-align: right; align-items: flex-end; }
.pn-label {
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.pn-title {
  font-family: var(--font-display);
  font-size: clamp(20px, 2.4vw, 30px);
  font-weight: 500;
  color: var(--ink);
  transition: color 0.25s var(--ease);
}
.proj-nav-link.prev:hover { transform: translateX(-4px); }
.proj-nav-link.next:hover { transform: translateX(4px); }
.proj-nav-link:hover .pn-title { color: var(--accent); }

@media (max-width: 860px) {
  .proj-meta-foot { gap: 22px 40px; }
  .credits-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 860px) {
  .media-row.cols-4 { grid-template-columns: repeat(3, 1fr); }
  .media-row.cols-5 { grid-template-columns: repeat(3, 1fr); }
}
/* stack-mobile grids collapse to a single column once we hit phone width,
   instead of going 2-up — used by the Meta Accounts top vert videos */
@media (max-width: 640px) {
  .media-row.cols-3.stack-mobile,
  .media-row.cols-2.stack-mobile { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .media-row.cols-3 { grid-template-columns: 1fr 1fr; }
  .media-row.cols-4 { grid-template-columns: 1fr 1fr; }
  .media-row.cols-5 { grid-template-columns: 1fr 1fr; }
  /* keep prev/next on one row: previous stays left, next stays right */
  .proj-nav { gap: 18px; }
  .proj-nav-link { flex: 1 1 0; min-width: 0; }
  .proj-nav-link.next { text-align: right; align-items: flex-end; }
  .pn-title { font-size: clamp(16px, 4.4vw, 24px); }
}

/* ---------------------------------------------------------- */
/* Responsive                                                  */
/* ---------------------------------------------------------- */
@media (max-width: 980px) {
  .work { --cols: 2 !important; }
}

/* hamburger nav — collapse the three icon links into a dropdown menu */
@media (max-width: 640px) {
  .nav-toggle { display: flex; }
  .nav {
    position: absolute;
    top: calc(100% + 12px);
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    min-width: 188px;
    padding: 8px;
    background: var(--bg);
    border: 1px solid var(--hairline);
    border-radius: 12px;
    box-shadow: 0 18px 40px -16px rgba(40,32,18,0.42);
    z-index: 60;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px) scale(0.98);
    transform-origin: top right;
    transition: opacity 0.24s var(--ease), transform 0.24s var(--ease), visibility 0.24s;
  }
  .topbar.is-menu-open .nav { opacity: 1; visibility: visible; transform: none; }
  .nav .icon-link {
    width: 100%;
    height: auto;
    justify-content: flex-start;
    gap: 13px;
    padding: 11px 12px;
    border-radius: 8px;
    color: var(--ink);
  }
  .nav .icon-link:hover { transform: none; background: var(--bg-deep); color: var(--ink); }
  .nav .icon-link.is-linkedin:hover { color: var(--ink); }
  .nav .icon-link svg,
  .nav .icon-link .bruce-avatar,
  .nav .icon-link .emoji { width: 21px; flex: none; }
  .link-label {
    display: inline;
    font-family: var(--font-ui);
    font-size: 14.5px;
    font-weight: 600;
    letter-spacing: -0.005em;
  }
}

@media (max-width: 560px) {
  .work { --cols: 1 !important; }
}

/* ============ THANKS — hand-drawn sign-off ============ */
.thanks {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: clamp(32px, 5vw, 64px) 16px clamp(48px, 7vw, 84px);
  margin-top: clamp(12px, 3vw, 32px);
}
.thanks-defs { position: absolute; }

.thanks-art {
  position: relative;
  display: inline-block;
  /* the boil: rough brush edge driven by #thxBrush (seed cycled in JS) */
  filter: url(#thxBrush);
}

.thanks-mark {
  display: block;
  font-family: "Caveat", cursive;
  font-weight: 700;
  font-size: clamp(40px, 6vw, 66px);
  line-height: 0.9;
  letter-spacing: 0.01em;
  padding: 0 0.32em;
  color: var(--accent);
  /* write-on wipe, left → right */
  clip-path: inset(0 100% 0 0);
}
.thanks-rule {
  display: block;
  width: clamp(96px, 14vw, 150px);
  height: auto;
  margin: -5px auto 0;
}
.thanks-rule path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}
.thanks-sub {
  font-family: "Caveat", cursive;
  font-weight: 600;
  font-size: clamp(16px, 1.8vw, 21px);
  white-space: nowrap;
  color: var(--ink-soft);
  margin: clamp(2px, 0.5vw, 5px) 0 0;
  opacity: 0;
  transform: translateY(8px) rotate(-1.2deg);
}

/* reveal sequence once scrolled into view */
.thanks.is-in .thanks-mark {
  animation: thxWrite 0.62s cubic-bezier(0.22, 0.61, 0.36, 1) 0.05s forwards;
}
.thanks.is-in .thanks-rule path {
  animation: thxDraw 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.6s forwards;
}
.thanks.is-in .thanks-sub {
  animation: thxFade 0.6s var(--ease) 0.92s forwards;
}

@keyframes thxWrite { to { clip-path: inset(0 0 0 0); } }
@keyframes thxDraw  { to { stroke-dashoffset: 0; } }
@keyframes thxFade  { to { opacity: 1; transform: translateY(0) rotate(-1.2deg); } }

@media (prefers-reduced-motion: reduce) {
  .thanks-art { filter: none; }
  .thanks-mark { clip-path: none; }
  .thanks-rule path { stroke-dashoffset: 0; }
  .thanks-sub { opacity: 1; transform: rotate(-1.2deg); }
}

