/* ===== Colors & basics =====
   Change --accent to recolor buttons and links across the whole site. */
:root {
  --bg: #ffffff;
  --surface: #f6f6f4;
  --text: #1a1a1a;
  --muted: #6b6b6b;
  --border: #e4e4e0;
  --accent: #2f5bea;
  --accent-text: #ffffff;
  --radius: 10px;
  --max-width: 1040px;
  --font-sans: "Geist", system-ui, -apple-system, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Resume page background (from the "Blank Resume" Figma frame) */
  --resume-gradient-start: #f2f2f7;
  --resume-gradient-end: #e0e0e5;

  /* Resume colors (from the resume Figma design) */
  --resume-paper: #f9f9fa;
  --resume-paper-border: #d0d0d7;
  --resume-heading: #19191a;
  --resume-text: #323234;
  --resume-body: #616165;
  --resume-label: #7a7a7f;

  /* The site is light mode only */
  color-scheme: light;
}

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

html {
  scroll-behavior: smooth;
  scroll-padding-top: 80px;
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.65;
  color: var(--text);
  background: var(--bg);
}

/* ===== Grain =====
   A fixed layer of SVG noise over the whole page. The noise is turned into
   black specks of varying transparency (feColorMatrix), which darkens the page
   like the old "multiply" blend did, but without a blend mode, which made the
   browser re-blend the whole screen on every scroll frame.
   Adjust opacity for strength, and baseFrequency (in the SVG) for how fine the grain is. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 240px;
  opacity: 0.15;
}

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

a {
  color: var(--accent);
}

h1, h2, h3 {
  line-height: 1.2;
  margin: 0 0 0.5em;
}

.container {
  width: 100%;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 24px;
}

/* ===== Header ===== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 64px;
}

.logo {
  font-weight: 700;
  color: var(--text);
  text-decoration: none;
}

.nav-links {
  display: flex;
  gap: 24px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-links a {
  color: var(--muted);
  text-decoration: none;
  font-size: 15px;
}

.nav-links a:hover,
.nav-links a[aria-current="page"] {
  color: var(--text);
}

/* ===== Extra pages (e.g. resume.html) ===== */
.page {
  min-height: 60vh;
  border-top: none;
}

/* Gradient background used on resume.html */
.page-resume {
  min-height: 100%;
  background: linear-gradient(162deg, var(--resume-gradient-start) 0%, var(--resume-gradient-end) 101%);
}

.page-resume body {
  background: transparent;
}

.page-resume .site-header {
  background: color-mix(in srgb, var(--resume-gradient-start) 85%, transparent);
}

.page-resume .site-footer {
  border-top: none;
}

/* Resume page: the copyright sits just under the card's bottom-left corner */
.site-footer.resume-footer {
  max-width: 902px;
  margin: 0 auto;
  padding: 16px 0 0 8px;
}

.resume-footer p {
  margin: 0;
}

/* Keep the page content above the dot grid */
.page-resume main,
.page-resume .site-footer {
  position: relative;
  z-index: 1;
}

/* ===== Page stats (bottom-left corner of the resume page) ===== */
/* Bottom-left: the stats pills */
.floating-dock {
  position: fixed;
  left: 20px;
  bottom: 40px;
  z-index: 6;
}

/* Bottom-right: the quick action menu (and its "Contact" pill when collapsed) */
.quick-dock {
  position: fixed;
  right: 20px;
  bottom: 40px;
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}

/* On page load, the pills and the action menu fade in, slide up 16px with a
   little bounce and come into focus from a blur, like the popovers. The menu
   follows the pills by a beat. ("backwards" only holds the start state during
   the delay, so nothing lingers once the animation is done.) */
.floating-dock,
.quick-dock {
  animation: dock-in 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) 0.5s backwards;
}

.quick-dock {
  animation-delay: 0.65s;
}

@keyframes dock-in {
  from {
    opacity: 0;
    transform: translateY(16px);
    filter: blur(8px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
    filter: blur(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .floating-dock,
  .quick-dock {
    animation-name: dock-fade-in;
    animation-timing-function: ease;
  }

  @keyframes dock-fade-in {
    from { opacity: 0; }
    to { opacity: 1; }
  }
}

/* 1508px and wider: the pills (left) and the open menu (right) are each
   centered in the gap between the resume and the window edge, until they're
   72px from the resume; on wider screens they hold 72px from it.
   How: each dock spans its whole gap (the card is 902px wide and centered, so
   each gap is 50% - 451px wide) and has two flexible spacers around its
   content. The spacers share the leftover space equally (centered), but the
   one next to the resume can't grow past 72px. This works whatever the
   pills' or menu's width is. Below 1508px the menu would be under 19px from
   the resume, so it collapses behind the "Contact" pill instead (see below). */
@media (min-width: 1508px) {
  .floating-dock,
  .quick-dock {
    display: flex;
    flex-direction: row;
    align-items: flex-end;
    width: calc(50% - 451px);
    pointer-events: none;
  }

  .floating-dock {
    left: 0;
  }

  .quick-dock {
    left: auto;
    right: 0;
  }

  .floating-dock::before,
  .floating-dock::after,
  .quick-dock::before,
  .quick-dock::after {
    content: "";
    flex: 1;
  }

  /* The spacer next to the resume */
  .floating-dock::after,
  .quick-dock::before {
    max-width: 72px;
  }

  .page-stats,
  .quick-inner {
    flex-shrink: 0;
    pointer-events: auto;
  }
}

.page-stats {
  display: flex;
  gap: 10px;
}

.stat-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 36px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  /* Lightens toward white as the page is scrolled (--progress, 0 to 1, set on
     .page-stats by the reading progress script), so the pills stay visible
     against the darker bottom of the page */
  background: color-mix(in srgb,
    color-mix(in srgb, #fff calc(var(--progress, 0) * 85%), #dedee3) 85%, transparent);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  font: inherit;
  font-size: 15px;
  font-weight: 500;
  color: var(--resume-text);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.stat-pill svg {
  flex-shrink: 0;
  color: var(--resume-label);
}

/* Like button */
.stat-like {
  position: relative;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.stat-like:hover {
  background: color-mix(in srgb, #d4d4da 90%, transparent);
}

.stat-like:focus-visible {
  outline: 2px solid var(--resume-label);
  outline-offset: 2px;
}

.stat-heart path {
  fill: #9a9aa0;
  transition: fill 0.25s ease;
}

.stat-like.is-liked .stat-heart path {
  fill: #ff3b5c;
}

/* A soft red ring bursts out from the heart when it's liked */
.stat-like::after {
  content: "";
  position: absolute;
  left: 23px;
  top: 50%;
  width: 18px;
  height: 18px;
  margin: -9px 0 0 -9px;
  border: 2px solid #ff3b5c;
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
}

.stat-like.is-bouncing {
  animation: pill-bounce 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.stat-like.is-popping .stat-heart {
  animation: heart-pop 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.stat-like.is-popping::after {
  animation: heart-ring 0.6s ease-out;
}

@keyframes pill-bounce {
  0% { transform: scale(1); }
  30% { transform: scale(0.9); }
  65% { transform: scale(1.06); }
  100% { transform: scale(1); }
}

@keyframes heart-pop {
  0% { transform: scale(1); }
  25% { transform: scale(0.6); }
  60% { transform: scale(1.4) rotate(-8deg); }
  100% { transform: scale(1) rotate(0); }
}

@keyframes heart-ring {
  0% { opacity: 0.7; transform: scale(0.6); }
  100% { opacity: 0; transform: scale(2.4); }
}

@media (prefers-reduced-motion: reduce) {
  .stat-like.is-bouncing,
  .stat-like.is-popping .stat-heart,
  .stat-like.is-popping::after {
    animation: none;
  }
}

@media (max-width: 720px) {
  .floating-dock {
    left: 12px;
    bottom: 12px;
  }

  .page-stats {
    gap: 6px;
  }

  .stat-pill {
    height: 32px;
    padding: 0 11px;
    font-size: 13px;
  }
}

/* ===== Quick action menu (from the "Quick Action Menu" Figma component) ===== */
.quick-menu {
  display: flex;
  flex-direction: column;
  gap: 16px; /* 32px in the design, minus the items' 8px hover padding above and below */
  /* As wide as the longest row: its value, 16px of space, then the icon */
  width: max-content;
  padding: 16px 10px;
  line-height: normal;
  background: #f4f4f6;
  border: 0.5px solid #d0d0d7;
  border-radius: 6px;
  box-shadow:
    0 12px 40px 0 rgba(0, 0, 0, 0.05),
    0 16px 32px 0 rgba(12, 12, 13, 0.05),
    112px 76px 100px 0 rgba(0, 0, 0, 0.02);
}

/* Each row is clickable; the 8px / 10px padding gives the hover background
   room around the text while keeping the text where the design puts it */
.quick-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 16px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  font: inherit;
  text-align: left;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.quick-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.quick-label {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--resume-label);
}

.quick-value {
  font-size: 14px;
  font-weight: 500;
  color: var(--resume-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Sits at the bottom of the item, level with the value line */
.quick-icon {
  display: grid;
  flex-shrink: 0;
  align-self: flex-end;
  margin-left: auto;
  color: var(--resume-label);
  transition: color 0.2s ease, transform 0.2s ease;
}

.quick-icon svg {
  grid-area: 1 / 1;
  transition: opacity 0.2s ease, transform 0.25s ease;
}

/* Hover / keyboard focus: a soft background, and the icon darkens and nudges */
.quick-item:hover,
.quick-item:focus-visible {
  background: rgba(120, 120, 128, 0.1);
}

.quick-item:hover .quick-icon,
.quick-item:focus-visible .quick-icon {
  color: var(--resume-text);
}

.quick-item[target="_blank"]:hover .quick-icon {
  transform: translate(1px, -1px);
}

.quick-item[download]:hover .quick-icon {
  transform: translateY(1px);
}

.quick-item:focus-visible {
  outline: 2px solid var(--resume-label);
  outline-offset: -2px;
}

.quick-item:active {
  background: rgba(120, 120, 128, 0.16);
}

/* The "Contact" pill that opens the menu is hidden unless the menu is collapsed.
   It's styled as a button: white with a thin gray border and a soft shadow,
   like the popovers */
.quick-toggle {
  display: none;
  border: 0.5px solid #d0d0d7;
  background: #fff;
  box-shadow:
    0 1px 2px rgba(12, 12, 13, 0.04),
    0 4px 12px rgba(12, 12, 13, 0.06);
  cursor: pointer;
  transition: background-color 0.2s ease, box-shadow 0.2s ease;
}

.quick-toggle:hover,
.quick-dock.menu-open .quick-toggle {
  background: #f4f4f6;
  box-shadow:
    0 1px 2px rgba(12, 12, 13, 0.04),
    0 2px 6px rgba(12, 12, 13, 0.05);
}

.quick-toggle:focus-visible {
  outline: 2px solid var(--resume-label);
  outline-offset: 2px;
}

.quick-inner {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}

/* Screens up to 1507px: there isn't room for the open menu beside the resume,
   so it collapses behind the "Contact" pill and opens above it,
   sliding up and un-blurring like the popovers.
   The pill follows the same rule as the wide-screen docks: centered in the gap
   between the resume and the window edge, but never more than 72px from the
   resume. The spacer on the edge side is at least 20px, and min-width keeps
   the dock at least as wide as the pill plus that spacer, so when the gap is
   too narrow the pill sits 20px from the window edge. */
@media (max-width: 1507px) {
  .quick-dock {
    right: 0;
    flex-direction: row;
    align-items: flex-end;
    width: calc(50% - 451px);
    min-width: max-content;
    pointer-events: none;
  }

  .quick-dock::before,
  .quick-dock::after {
    content: "";
    flex: 1;
  }

  /* The spacer next to the resume */
  .quick-dock::before {
    max-width: 72px;
  }

  /* The spacer next to the window edge */
  .quick-dock::after {
    min-width: 20px;
  }

  .quick-inner {
    flex-shrink: 0;
    pointer-events: auto;
  }

  .quick-toggle {
    display: inline-flex;
  }

  .quick-menu {
    position: absolute;
    right: 0;
    bottom: calc(100% + 10px);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(12px);
    filter: blur(6px);
    transition: opacity 0.2s ease, transform 0.25s ease, filter 0.25s ease, visibility 0s linear 0.25s;
  }

  .quick-dock.menu-open .quick-menu {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateY(0);
    filter: blur(0);
    transition:
      opacity 0.25s ease,
      transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1),
      filter 0.35s ease-out,
      visibility 0s;
  }
}

@media (max-width: 1507px) and (prefers-reduced-motion: reduce) {
  .quick-menu,
  .quick-dock.menu-open .quick-menu {
    transform: none;
  }
}

/* Phones: the Contact pill sits in the bottom-right corner, lined up with
   the stats pills, and the open menu stays inside the screen */
@media (max-width: 720px) {
  .quick-dock {
    bottom: 12px;
  }

  .quick-dock::after {
    min-width: 12px;
  }

  .quick-menu {
    max-width: calc(100vw - 24px);
  }
}

/* ===== Reading progress (resume page) =====
   A thin line across the top of the window in the headline's gradient colors.
   The full gradient always spans the window; the script in resume.html sets
   --progress (0 to 1) and only that much of the line is revealed. */
.reading-progress {
  --progress: 0;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 6;
  height: 5px;
  background: linear-gradient(90deg, #e5883c 0%, #e9a592 35%, #e48ec8 65%, #b19adc 100%);
  clip-path: inset(0 calc((1 - var(--progress)) * 100%) 0 0);
  pointer-events: none;
}

/* ===== Top blur (resume page) =====
   A band at the top of the window where the page gets progressively blurrier toward the
   top, so the resume softly blurs out as it scrolls up. Four stacked layers
   each blur more and only show in their slice of the band (via masks); a soft
   tint on top helps the content fade into the background. */
.top-blur {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 5;
  height: 112px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s ease;
}

.top-blur.is-visible {
  opacity: 1;
}

.top-blur > div {
  position: absolute;
  inset: 0;
}

.top-blur > div:nth-child(1) {
  -webkit-backdrop-filter: blur(1px);
  backdrop-filter: blur(1px);
  -webkit-mask-image: linear-gradient(to top, transparent 0%, #000 25%);
  mask-image: linear-gradient(to top, transparent 0%, #000 25%);
}

.top-blur > div:nth-child(2) {
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  -webkit-mask-image: linear-gradient(to top, transparent 25%, #000 50%);
  mask-image: linear-gradient(to top, transparent 25%, #000 50%);
}

.top-blur > div:nth-child(3) {
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  -webkit-mask-image: linear-gradient(to top, transparent 50%, #000 75%);
  mask-image: linear-gradient(to top, transparent 50%, #000 75%);
}

.top-blur > div:nth-child(4) {
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  -webkit-mask-image: linear-gradient(to top, transparent 75%, #000 100%);
  mask-image: linear-gradient(to top, transparent 75%, #000 100%);
}

.top-blur::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom,
    color-mix(in srgb, var(--resume-gradient-start) 70%, transparent) 40%,
    transparent 100%);
}

/* ===== Dot grid (resume page background) =====
   2px dots every 24px. A second, darker copy of the grid shows only
   in a soft circle around the mouse (--x / --y are set by the script in resume.html). */
.dot-grid {
  --dot-spacing: 24px;
  --shift-x: 0px;
  --shift-y: 0px;
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Crect x='11' y='11' width='2' height='2' rx='1' fill='%23CDCDD5'/%3E%3C/svg%3E");
  background-size: var(--dot-spacing) var(--dot-spacing);
  background-position: var(--shift-x) var(--shift-y);
}

.dot-grid::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Crect x='11' y='11' width='2' height='2' rx='1' fill='%23A4A4AD'/%3E%3C/svg%3E");
  background-size: inherit;
  background-position: inherit;
  -webkit-mask-image: radial-gradient(circle 160px at var(--x, -999px) var(--y, -999px), #000 0%, transparent 100%);
  mask-image: radial-gradient(circle 160px at var(--x, -999px) var(--y, -999px), #000 0%, transparent 100%);
  opacity: 0;
  transition: opacity 0.4s ease;
}

.dot-grid.is-active::after {
  opacity: 1;
}

/* The fold sizes are registered so they can animate (the fold lifts on hover) */
@property --fold-top { syntax: "<length>"; inherits: true; initial-value: 0px; }
@property --fold-side { syntax: "<length>"; inherits: true; initial-value: 0px; }
@property --fold-tip-x { syntax: "<length>"; inherits: true; initial-value: 0px; }
@property --fold-tip-y { syntax: "<length>"; inherits: true; initial-value: 0px; }

/* ===== Resume (built from the resume Figma design) ===== */
/* Bottom padding: room for the floating pills (40px from the bottom + 36px
   tall) plus a 48px gap above them, so the copyright never sits on them */
.resume-wrap {
  padding: 92px 24px 124px;
}

/* The frame holds the card and draws its shadow. The fold sizes live here so
   both the card and its shadow can use them.
   Fold size: the crease runs from --fold-top along the top edge
   to --fold-side down the right edge. --fold-tip-x / -y is where the folded
   corner lands (the corner mirrored across the crease). */
.resume-frame {
  --fold-top: 200px;
  --fold-side: 183.3px;
  --fold-tip-x: 17.4px;
  --fold-tip-y: 199.3px;
  position: relative;
  max-width: 902px;
  margin: 0 auto;
  transition:
    --fold-top 0.5s cubic-bezier(0.34, 1.3, 0.64, 1),
    --fold-side 0.5s cubic-bezier(0.34, 1.3, 0.64, 1),
    --fold-tip-x 0.5s cubic-bezier(0.34, 1.3, 0.64, 1),
    --fold-tip-y 0.5s cubic-bezier(0.34, 1.3, 0.64, 1);
}

/* The card's shadow follows the real paper shape, folded corner included.
   It's cast by an empty copy of the card's shape (::before) behind the card.
   Because that copy has nothing animated inside it, the browser draws the
   shadow once and reuses it while scrolling. (A filter on the card itself had
   to be redrawn every frame because of the animated headline, and a trimmed
   box-shadow left a hard line next to the fold.) */
.resume-shadow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  filter:
    drop-shadow(0 10px 16px rgba(0, 0, 0, 0.05))
    drop-shadow(0 8px 10px rgba(12, 12, 13, 0.04))
    drop-shadow(90px 61px 40px rgba(0, 0, 0, 0.02));
}

.resume-shadow::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 6px;
  background: var(--resume-paper);
  clip-path: polygon(0 0, calc(100% - var(--fold-top)) 0, 100% var(--fold-side), 100% 100%, 0 100%);
}

.resume {
  position: relative;
  padding: 80px 74px 92px;
  background: var(--resume-paper);
  border: 0.5px solid var(--resume-paper-border);
  border-radius: 6px;
  color: var(--resume-text);
  line-height: normal;
  /* Cut off the top-right corner where the paper is folded down */
  clip-path: polygon(0 0, calc(100% - var(--fold-top)) 0, 100% var(--fold-side), 100% 100%, 0 100%);
}

/* Hovering the corner lifts the fold: it peels back further, the crease starts
   farther left so the flap's left side grows longer than its bottom, and its
   shadow drops lower and softer */
.resume-frame:has(.fold-hotspot:hover, .stamp:hover, .stamp:focus-visible) {
  --fold-top: 250px;
  --fold-side: 216.4px;
  --fold-tip-x: 35.9px;
  --fold-tip-y: 247.3px;
}

/* The fold's hover area: a box over the corner, outside the (trimmed) card.
   It's sized from the fold values, so while hovered it grows with the lifted
   fold and the cursor can't slip out of it mid-animation. */
.fold-hotspot {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 3;
  width: var(--fold-top);
  height: var(--fold-tip-y);
}

/* ===== Loading screen (resume page) =====
   While <html> has .is-loading (set in the page's <head>), the page is hidden
   and the loader shows: the stamp sways in 3D with a shine passing over it,
   the bar fills in the reading progress colors over 2s, and "Loading" sits
   below. Then .is-revealing fades and blurs the loader out while the resume
   comes in from a blur. */
.loader {
  display: none;
}

.is-loading .loader,
.is-revealing .loader {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.is-revealing .loader {
  animation: loader-out 0.5s ease forwards;
}

@keyframes loader-out {
  to {
    opacity: 0;
    filter: blur(10px);
    transform: scale(1.04);
  }
}

.loader-stamp {
  position: relative;
  width: 200px;
  animation:
    loader-stamp-in 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) backwards,
    loader-stamp-sway 2.4s ease-in-out infinite alternate;
}

.loader-stamp img {
  display: block;
  width: 100%;
  height: auto;
  filter:
    drop-shadow(0 2px 4px rgba(12, 12, 13, 0.08))
    drop-shadow(0 16px 28px rgba(12, 12, 13, 0.12));
}

@keyframes loader-stamp-in {
  from {
    opacity: 0;
    filter: blur(8px);
    translate: 0 16px;
  }
}

@keyframes loader-stamp-sway {
  from { transform: perspective(700px) rotateY(-16deg) rotateX(6deg) rotateZ(-2deg); }
  to   { transform: perspective(700px) rotateY(16deg) rotateX(-4deg) rotateZ(2deg); }
}

/* A band of light that sweeps across, cut to the stamp's shape */
.loader-shine {
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg,
    rgba(255, 255, 255, 0) 35%, rgba(255, 255, 255, 0.45) 50%, rgba(255, 255, 255, 0) 65%)
    0 0 / 300% 100% no-repeat;
  -webkit-mask: url("images/stamp.webp") center / 100% 100% no-repeat;
  mask: url("images/stamp.webp") center / 100% 100% no-repeat;
  animation: loader-shine 1.6s ease-in-out 0.3s infinite;
}

@keyframes loader-shine {
  from { background-position: 100% 0; }
  to   { background-position: 0 0; }
}

/* The bar: the full gradient, revealed left to right over 2s */
.loader-bar {
  width: 160px;
  height: 3px;
  margin-top: 40px;
  border-radius: 3px;
  background: rgba(50, 50, 52, 0.08);
  overflow: hidden;
}

.loader-bar span {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, #e5883c 0%, #e9a592 35%, #e48ec8 65%, #b19adc 100%);
  animation: loader-fill 1.9s cubic-bezier(0.45, 0, 0.25, 1) forwards;
}

@keyframes loader-fill {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

.loader-text {
  margin: 14px 0 0;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--resume-label);
}

/* The page stays hidden while loading. The pills and menu have no load
   animation yet, so theirs plays (from the start) once the page is revealed. */
.is-loading .resume-wrap,
.is-loading .floating-dock,
.is-loading .quick-dock {
  opacity: 0;
  animation: none;
}

/* Once the loader has faded out (0.5s), the resume comes into focus from a
   blur as it rises into place with a little bounce, and the pills and menu
   follow it in */
.is-revealing .resume-wrap {
  animation: page-in 0.7s cubic-bezier(0.34, 1.56, 0.64, 1) 0.5s backwards;
}

.is-revealing .floating-dock {
  animation-delay: 1s;
}

.is-revealing .quick-dock {
  animation-delay: 1.15s;
}

@keyframes page-in {
  from {
    opacity: 0;
    filter: blur(14px);
    transform: translateY(24px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .loader-stamp,
  .loader-shine {
    animation: none;
  }

  @keyframes page-in {
    from { opacity: 0; }
  }

  @keyframes loader-out {
    to { opacity: 0; }
  }
}

/* ===== Stamp (tucked under the folded corner) =====
   .stamp-pocket is the same box as .fold, just below it, so the flap hides the
   stamp. The stamp's spot comes from the fold values: it sits in the flap's
   corner, tilted like the flap's edge, and moves with the fold as it lifts.
   When the fold is hovered it slides out from under the flap. */
.stamp-pocket {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 1;
  width: var(--fold-top);
  height: var(--fold-tip-y);
  pointer-events: none;
}

.stamp {
  position: absolute;
  left: calc(var(--fold-tip-x) + var(--fold-top) * 0.07);
  top: calc(var(--fold-tip-y) - var(--fold-top) * 0.08);
  width: calc(var(--fold-top) * 0.4);
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  pointer-events: auto;
  transform-origin: 0 100%;
  transform: translateY(-100%) rotate(-5deg);
  transition: transform 0.5s cubic-bezier(0.34, 1.3, 0.64, 1);
}

.stamp img {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 1px 1.5px rgba(24, 24, 32, 0.18));
}

.resume-frame:has(.fold-hotspot:hover, .stamp:hover, .stamp:focus-visible) .stamp {
  transform: translate(calc(var(--fold-top) * -0.2), calc(var(--fold-top) * 0.2)) translateY(-100%) rotate(-12deg);
}

.stamp:focus-visible {
  outline: 2px solid var(--resume-label);
  outline-offset: 3px;
}

/* The fold's hover area opens the stamp too */
.fold-hotspot {
  cursor: pointer;
}

/* ===== Stamp lightbox =====
   Blurs and fades the page so only the stamp is in view. The stamp comes in
   like the popovers (slides up with a bounce, clearing from a blur) and tilts
   in 3D toward the cursor (--rx / --ry, set by the script in resume.html),
   with a soft glare that follows the cursor (--gx / --gy). */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  padding: 32px 24px;
  background: rgba(228, 228, 233, 0.6);
  -webkit-backdrop-filter: blur(0);
  backdrop-filter: blur(0);
  cursor: zoom-out;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, backdrop-filter 0.4s ease, -webkit-backdrop-filter 0.4s ease, visibility 0s linear 0.4s;
}

.lightbox.is-open {
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
  opacity: 1;
  visibility: visible;
  transition: opacity 0.3s ease, backdrop-filter 0.4s ease, -webkit-backdrop-filter 0.4s ease, visibility 0s;
}

.lightbox-stage {
  width: min(760px, 100%);
  filter: blur(10px);
  opacity: 0;
  transform: translateY(24px) scale(0.94);
  transition: opacity 0.2s ease, transform 0.3s ease, filter 0.3s ease;
}

/* filter: none (not blur(0)) once open, so nothing flattens the 3D tilt */
.lightbox.is-open .lightbox-stage {
  filter: none;
  opacity: 1;
  transform: none;
  transition:
    opacity 0.3s ease 0.05s,
    transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) 0.05s,
    filter 0.45s ease-out 0.05s;
}

.lightbox-tilt {
  --rx: 0deg;
  --ry: 0deg;
  --gx: 50%;
  --gy: 50%;
  --lift: 1;
  position: relative;
  /* The perspective is part of the stamp's own transform rather than set on
     its parent, so it still works in Safari (which flattens 3D under a filter) */
  transform: perspective(900px) rotateX(var(--rx)) rotateY(var(--ry));
  scale: var(--lift);
  transition: transform 0.6s cubic-bezier(0.34, 1.3, 0.64, 1), scale 0.4s ease;
  /* Keeps the stamp on its own layer so Safari doesn't redraw it mid-tilt */
  will-change: transform;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

/* While the cursor is over it, the script eases the tilt each frame,
   so only the lift animates here */
.lightbox.is-tilting .lightbox-tilt {
  --lift: 1.03;
  transition: scale 0.4s ease;
}

.lightbox-tilt img {
  display: block;
  width: 100%;
  height: auto;
  filter:
    drop-shadow(0 4px 8px rgba(12, 12, 13, 0.08))
    drop-shadow(0 28px 48px rgba(12, 12, 13, 0.16));
}

/* Glare, cut to the stamp's shape (perforations included) */
.lightbox-glare {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(circle at var(--gx) var(--gy), rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0) 55%);
  -webkit-mask: url("images/stamp.webp") center / 100% 100% no-repeat;
  mask: url("images/stamp.webp") center / 100% 100% no-repeat;
  opacity: 0;
  transition: opacity 0.4s ease;
}

.lightbox.is-tilting .lightbox-glare {
  opacity: 1;
}

.lightbox-close {
  position: absolute;
  top: 20px;
  right: 20px;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.7);
  color: var(--resume-text);
  cursor: pointer;
  transition: background 0.2s ease;
}

.lightbox-close:hover {
  background: #fff;
}

.lightbox-close:focus-visible {
  outline: 2px solid var(--resume-label);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .stamp,
  .lightbox-stage,
  .lightbox.is-open .lightbox-stage {
    transition: opacity 0.2s ease;
  }

  .lightbox-stage {
    transform: none;
  }
}

/* ===== Folded corner =====
   .fold-flap is the folded-over flap (the back of the paper). Its outline is
   built from the --fold-* values, so it keeps its gentle curl while it reshapes.
   .fold casts the flap's shadow onto the card. */
.fold {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
  width: var(--fold-top);
  height: var(--fold-tip-y);
  pointer-events: none;
  filter: drop-shadow(-5px 8px 12px rgba(24, 24, 32, 0.28));
  transition: filter 0.5s ease;
}

.resume-frame:has(.fold-hotspot:hover, .stamp:hover, .stamp:focus-visible) .fold {
  filter: drop-shadow(-9px 14px 18px rgba(24, 24, 32, 0.3));
}

.fold-flap {
  position: absolute;
  inset: 0;
  /* A faint shadow at the crease, a soft highlight just past it,
     then darker toward the tip, lifting a touch at the very edge */
  background: linear-gradient(222.5deg,
    #f0f0f3 48%, #fdfdfe 51.4%, #ececf0 67.2%, #d7d7dd 89.3%, #e1e1e6 96%);
  clip-path: polygon(
      0 0,
      calc(var(--fold-top) * 1.0) calc(var(--fold-side) * 1.0),
      calc(var(--fold-top) * 0.8403 + var(--fold-tip-x) * 0.1507) calc(var(--fold-side) * 0.8403 + var(--fold-tip-y) * 0.1507),
      calc(var(--fold-top) * 0.6837 + var(--fold-tip-x) * 0.3015) calc(var(--fold-side) * 0.6837 + var(--fold-tip-y) * 0.3015),
      calc(var(--fold-top) * 0.5302 + var(--fold-tip-x) * 0.4524) calc(var(--fold-side) * 0.5302 + var(--fold-tip-y) * 0.4524),
      calc(var(--fold-top) * 0.3797 + var(--fold-tip-x) * 0.6034) calc(var(--fold-side) * 0.3797 + var(--fold-tip-y) * 0.6034),
      calc(var(--fold-top) * 0.2323 + var(--fold-tip-x) * 0.7545) calc(var(--fold-side) * 0.2323 + var(--fold-tip-y) * 0.7545),
      calc(var(--fold-top) * 0.088 + var(--fold-tip-x) * 0.9058) calc(var(--fold-side) * 0.088 + var(--fold-tip-y) * 0.9058),
      calc(var(--fold-top) * 0.0414 + var(--fold-tip-x) * 0.9476) calc(var(--fold-side) * 0.0414 + var(--fold-tip-y) * 0.9476),
      calc(var(--fold-top) * 0.0136 + var(--fold-tip-x) * 0.9532) calc(var(--fold-side) * 0.0136 + var(--fold-tip-y) * 0.9532),
      calc(var(--fold-top) * 0.0046 + var(--fold-tip-x) * 0.9226) calc(var(--fold-side) * 0.0046 + var(--fold-tip-y) * 0.9226),
      calc(var(--fold-top) * 0.0121 + var(--fold-tip-x) * 0.7602) calc(var(--fold-side) * 0.0121 + var(--fold-tip-y) * 0.7602),
      calc(var(--fold-top) * 0.0163 + var(--fold-tip-x) * 0.6013) calc(var(--fold-side) * 0.0163 + var(--fold-tip-y) * 0.6013),
      calc(var(--fold-top) * 0.0172 + var(--fold-tip-x) * 0.4459) calc(var(--fold-side) * 0.0172 + var(--fold-tip-y) * 0.4459),
      calc(var(--fold-top) * 0.0148 + var(--fold-tip-x) * 0.2938) calc(var(--fold-side) * 0.0148 + var(--fold-tip-y) * 0.2938),
      calc(var(--fold-top) * 0.009 + var(--fold-tip-x) * 0.1452) calc(var(--fold-side) * 0.009 + var(--fold-tip-y) * 0.1452)
    );
}

.resume :where(h1, h2, h3, h4, p) {
  margin: 0;
  line-height: normal;
}

.resume-intro {
  display: flex;
  flex-direction: column;
}

.resume-signature {
  display: grid;
  width: 366px;
  margin-bottom: 2px;
  /* Offset to sit over the name (exact centering would be -59px) */
  margin-left: -31px;
}

/* All copies sit on top of each other */
.resume-signature img {
  grid-area: 1 / 1;
  width: 100%;
  height: auto;
}

/* Sharp copy: fully visible in the top half, fading out below it */
.resume-signature img:first-child {
  -webkit-mask-image: linear-gradient(to bottom, #000 50%, transparent 67%);
  mask-image: linear-gradient(to bottom, #000 50%, transparent 67%);
}

/* Blurrier copies take over band by band toward the bottom */
.resume-signature .blur-1 {
  filter: blur(1px);
  -webkit-mask-image: linear-gradient(to bottom, transparent 50%, #000 67%, transparent 83%);
  mask-image: linear-gradient(to bottom, transparent 50%, #000 67%, transparent 83%);
}

.resume-signature .blur-2 {
  filter: blur(2px);
  -webkit-mask-image: linear-gradient(to bottom, transparent 67%, #000 83%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 67%, #000 83%, transparent 100%);
}

.resume-signature .blur-3 {
  filter: blur(3px);
  -webkit-mask-image: linear-gradient(to bottom, transparent 83%, #000 100%);
  mask-image: linear-gradient(to bottom, transparent 83%, #000 100%);
}

.resume-name {
  font-size: 29px;
  font-weight: 500;
  letter-spacing: normal;
  color: var(--resume-heading);
}

.resume-title,
.resume-label,
.company-years,
.role-years {
  font-family: var(--font-mono);
  font-weight: 400;
  color: var(--resume-label);
}

.resume-title {
  margin-top: 6px;
  font-size: 19px;
}

.resume-statement {
  /* Wide enough that the headline wraps into three even lines (no single word
     left on a fourth), plus room for the hover letters, which lose a little kerning */
  max-width: 712px;
  margin-top: 93px;
  font-size: 32px;
  font-weight: 500;
}

.resume-statement .soft {
  color: var(--resume-body);
}

/* ===== Flowing gradient text =====
   A band of orange, peach, pink and lavender (colors sampled from the
   reference video) slides continuously through the letters, so every color
   passes across the whole phrase. The band repeats seamlessly. */
.gradient-text {
  --cycle: linear-gradient(90deg,
    #e5883c 0%, #e7943f 10%, #e9a592 24%, #e48ec8 40%,
    #b19adc 55%, #e48ec8 70%, #e9a592 84%, #e5883c 100%);
  background-image: var(--cycle);
  background-size: 200% 100%;
  background-repeat: repeat-x;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: gradient-cycle 7s linear infinite;
}

@keyframes gradient-cycle {
  from {
    background-position: 200% 0;
  }

  to {
    background-position: 0% 0;
  }
}

/* When the script splits the phrase into letters, each letter shows its own
   slice of the same band (--w = phrase width, --x = letter's offset), so the
   colors still flow as one piece while letters move independently on hover. */
.gradient-text.is-split {
  background: none;
  animation: none;
}

.gradient-text .letter {
  display: inline-block;
  background-image: var(--cycle);
  background-size: calc(var(--w) * 2) 100%;
  background-repeat: repeat-x;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: letter-cycle 7s linear infinite;
  transition: transform 0.7s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* While the cursor is over the phrase, letters follow it quickly;
   on leave they spring back with a little bounce (the transition above) */
.gradient-text.is-hovering .letter {
  transition-duration: 0.18s;
  transition-timing-function: ease-out;
}

@keyframes letter-cycle {
  from {
    background-position: calc(0px - var(--x)) 0;
  }

  to {
    background-position: calc(var(--w) * 2 - var(--x)) 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .gradient-text,
  .gradient-text .letter {
    animation: none;
  }

  .resume-frame,
  .fold {
    transition: none;
  }
}

/* Blinking text cursor at the end of the headline */
.text-cursor {
  display: inline-block;
  width: 0.1em;
  height: 1em;
  margin-left: 0.12em;
  vertical-align: -0.12em;
  background: var(--resume-label);
  animation: cursor-blink 1.8s steps(1, end) infinite;
}

@keyframes cursor-blink {
  50% {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .text-cursor {
    animation: none;
  }
}

.resume-label {
  font-size: 16px;
}

/* A short note under the headline, set like the labels */
.resume-note {
  margin-top: 24px;
  font-family: var(--font-mono);
  font-size: 16px;
  color: var(--resume-label);
}

.resume-note + .resume-label {
  margin-top: 112px;
}

.resume-divider {
  display: block;
  max-width: 100%;
  margin: 38px 0 63px;
}

.company + .resume-divider {
  margin-top: 74px;
  margin-bottom: 74px;
}

.company + .resume-divider + .expertise {
  margin-top: -3px;
}

.company {
  display: flex;
  flex-direction: column;
  gap: 62px;
  padding-left: 18px;
}

.company-header {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.company-header.with-avatar {
  flex-direction: row;
  align-items: center;
  gap: 16px;
}

.company-heading {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.company .avatar {
  --avatar-size: 56px;
}

.company-name {
  font-size: 22px;
  font-weight: 500;
  color: var(--resume-text);
}

.company-years {
  font-size: 16px;
}

.roles {
  display: flex;
  flex-direction: column;
  gap: 75px;
}

.role {
  display: grid;
  grid-template-columns: 106px minmax(0, 489px);
  column-gap: 74px;
  align-items: start;
}

.role-years {
  font-size: 16px;
  white-space: nowrap;
}

.role-body {
  display: flex;
  flex-direction: column;
  gap: 26px;
}

.role-title {
  font-size: 19px;
  font-weight: 500;
  color: var(--resume-text);
}

.highlights {
  display: flex;
  flex-direction: column;
  gap: 32px;
  margin: 0;
  padding: 0 0 0 24px;
  font-size: 16px;
  line-height: 29px;
  color: var(--resume-body);
}

.highlights li::marker {
  color: #323234;
}

.highlights strong {
  display: block;
  font-weight: 500;
  color: var(--resume-text);
}

.highlights .narrow {
  max-width: 452px;
  line-height: 30px;
}

.expertise {
  display: flex;
  flex-direction: column;
  gap: 32px;
  max-width: 741px;
}

.expertise p {
  font-size: 16px;
  font-weight: 400;
  line-height: 29px;
  color: #616165;
}

/* ===== Avatar (from the "Neo Avatar" Figma component) =====
   A dark rounded tile with a logo centered inside.
   Change --avatar-size to resize it; everything inside scales with it. */
.avatar {
  --avatar-size: 70px;
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: var(--avatar-size);
  height: var(--avatar-size);
  overflow: hidden;
  border: 0.5px solid #cecece;
  border-radius: calc(var(--avatar-size) * 0.2);
  background: linear-gradient(136deg, #232323 6.09%, #161616 52.69%, #2b2b2b 97.54%);
  box-shadow: 0 calc(var(--avatar-size) * 0.08) calc(var(--avatar-size) * 0.16) calc(var(--avatar-size) * -0.04) rgba(12, 12, 13, 0.4);
}

.avatar img {
  display: block;
  width: calc(var(--avatar-size) * 0.74);
  height: auto;
}

/* Orange version (from the "Skip Avatar" Figma component) */
.avatar-skip {
  border-color: #ffbb75;
  background: linear-gradient(135deg, #ffa142 0%, #ff8000 50.48%, #ff9121 100%);
  box-shadow: 0 calc(var(--avatar-size) * 0.086) calc(var(--avatar-size) * 0.171) 0 rgba(153, 77, 0, 0.35);
}

/* ===== Popover trigger (a company name with a dotted underline and an arrow) ===== */
.popover-trigger {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

/* Dotted underline in the reading progress bar's gradient. Two background
   layers: a row of round "holes" in the card's colour on top, over the
   gradient, so the gradient only shows through as dots. On hover the dots
   drift slowly sideways. box-decoration-break repeats it on wrapped lines. */
.popover-trigger-text {
  --dot-gap: 5px;
  padding-bottom: 1px;
  background:
    radial-gradient(circle at center, transparent 0.9px, var(--resume-paper) 1.3px) 0 100% / var(--dot-gap) 2px repeat-x,
    linear-gradient(90deg, #e5883c 0%, #e9a592 35%, #e48ec8 65%, #b19adc 100%) 0 100% / 100% 2px no-repeat;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

.popover-trigger:hover .popover-trigger-text,
.popover-trigger:focus-visible .popover-trigger-text {
  animation: dots-drift 0.9s linear infinite;
}

@keyframes dots-drift {
  to { background-position: var(--dot-gap) 100%, 0 100%; }
}

.popover-trigger svg {
  flex-shrink: 0;
  color: var(--resume-label);
  transition: transform 0.25s ease, color 0.2s ease;
}

.popover-trigger:hover svg,
.popover-trigger:focus-visible svg {
  color: var(--resume-text);
  transform: translateX(2px);
}

.popover-trigger:focus-visible {
  outline: 2px solid var(--resume-label);
  outline-offset: 4px;
  border-radius: 4px;
}

/* ===== Popover (from the "Popover" Figma component) =====
   Positioned by the script in resume.html: above its trigger with the tail
   pointing down at it, or below (.is-below) when there isn't room above.
   --tail-x is the tail's center, measured from the popover's left edge. */
.popover {
  --tail-x: 61px;
  display: block;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 50;
  width: 350px;
  max-width: calc(100vw - 24px);
  padding: 20px 20px 24px;
  background: #fff;
  border-radius: 6px;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  /* Starts blurred and clears as it appears. Drop-shadows (not box-shadow)
     so the tail gets the shadow too */
  filter:
    blur(8px)
    drop-shadow(0 20px 32px rgba(12, 12, 13, 0.05))
    drop-shadow(0 49px 40px rgba(0, 0, 0, 0.05))
    drop-shadow(112px 76px 100px rgba(0, 0, 0, 0.02));
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  /* Starts 16px lower and slides up with a little bounce as it appears */
  transform: translateY(16px);
  transition: opacity 0.2s ease, transform 0.25s ease, filter 0.25s ease, visibility 0s linear 0.25s;
}

.popover.is-open {
  filter:
    blur(0)
    drop-shadow(0 20px 32px rgba(12, 12, 13, 0.05))
    drop-shadow(0 49px 40px rgba(0, 0, 0, 0.05))
    drop-shadow(112px 76px 100px rgba(0, 0, 0, 0.02));
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: translateY(0);
  transition:
    opacity 0.25s ease,
    transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1),
    filter 0.4s ease-out,
    visibility 0s;
}

/* Image area at the top, full bleed: it runs to the popover's top, left and
   right edges (the negative margins cancel the popover's padding) */
.popover-media {
  aspect-ratio: 310 / 169;
  margin: -20px -20px 20px;
  border-radius: 6px 6px 0 0;
  overflow: hidden;
}

.popover-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* When the popover opens below its trigger, the tail is at the top, right
   above the photo. The photo then grows upward by the tail's height (23px)
   and is clipped to the shape of "photo + tail", so one continuous image
   fills the tail too. --tail-x lines the tail part up with the real tail. */
.popover.is-below .popover-media:has(img) {
  position: relative;
  box-sizing: content-box;
  padding-top: 23px;
  margin-top: -43px;
  border-radius: 0;
  overflow: visible;
  clip-path: polygon(
      0 100%,
      0.00px 29.00px,
      0.80px 26.00px,
      3.00px 23.80px,
      6.00px 23.00px,
      calc(var(--tail-x) - 21.25px + 0.00px) 23.00px,
      calc(var(--tail-x) - 21.25px + 1.59px) 22.98px,
      calc(var(--tail-x) - 21.25px + 2.62px) 22.84px,
      calc(var(--tail-x) - 21.25px + 3.39px) 22.56px,
      calc(var(--tail-x) - 21.25px + 4.06px) 22.16px,
      calc(var(--tail-x) - 21.25px + 4.73px) 21.49px,
      calc(var(--tail-x) - 21.25px + 5.54px) 20.37px,
      calc(var(--tail-x) - 21.25px + 19.00px) 1.23px,
      calc(var(--tail-x) - 21.25px + 19.75px) 0.62px,
      calc(var(--tail-x) - 21.25px + 20.73px) 0.41px,
      calc(var(--tail-x) - 21.25px + 21.70px) 0.62px,
      calc(var(--tail-x) - 21.25px + 22.46px) 1.23px,
      calc(var(--tail-x) - 21.25px + 35.91px) 20.37px,
      calc(var(--tail-x) - 21.25px + 36.73px) 21.49px,
      calc(var(--tail-x) - 21.25px + 37.39px) 22.16px,
      calc(var(--tail-x) - 21.25px + 38.07px) 22.56px,
      calc(var(--tail-x) - 21.25px + 38.83px) 22.84px,
      calc(var(--tail-x) - 21.25px + 39.86px) 22.98px,
      calc(var(--tail-x) - 21.25px + 41.45px) 23.00px,
      calc(100% - 6.00px) 23.00px,
      calc(100% - 3.00px) 23.80px,
      calc(100% - 0.80px) 26.00px,
      calc(100% - 0.00px) 29.00px,
      100% 100%
    );
}

.popover.is-below .popover-media:has(img) img {
  position: absolute;
  inset: 0;
}

/* ...and the tail's own fill steps aside so the photo shows through it */
.popover.is-below:has(.popover-media img) .popover-tail-fill {
  fill: transparent;
}

.popover p {
  margin: 0;
  font-size: 15px;
  line-height: 25px;
  color: var(--resume-body);
}

.popover strong {
  font-weight: 500;
  color: var(--resume-text);
}

/* The tail hangs from the popover's bottom edge. Its fill overlaps the box
   slightly, so there's no seam between them. */
.popover-tail {
  position: absolute;
  top: 100%;
  left: calc(var(--tail-x) - 20.75px);
  overflow: visible;
}

.popover-tail-fill {
  fill: #fff;
}

/* No border on the popover, so no outline on the tail either */
.popover-tail-edge {
  display: none;
}

/* Below the trigger: the tail moves to the top and points up */
.popover.is-below .popover-tail {
  top: auto;
  bottom: 100%;
  transform: scaleY(-1);
}

/* Video popover: just the video (6px corners, soft shadow), no card or tail.
   It keeps the popover's slide, bounce and blur-in, but the blur is the only
   filter: a drop-shadow filter would be redrawn on every video frame, so the
   shadow is a box-shadow on the video instead. */
.popover-video,
.popover-video.is-open {
  width: 480px;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 6px;
  cursor: default;
}

.popover-video {
  filter: blur(8px);
}

.popover-video.is-open {
  filter: none;
}

.popover-video video {
  display: block;
  width: 100%;
  height: auto;
  border: 0.5px solid #fff;
  border-radius: 6px;
  background: #fff;
  box-shadow:
    0 2px 4px rgba(12, 12, 13, 0.04),
    0 12px 24px rgba(12, 12, 13, 0.06),
    0 32px 56px rgba(0, 0, 0, 0.06);
}

@media (prefers-reduced-motion: reduce) {
  .popover,
  .popover.is-open {
    transform: none;
  }

  .popover-trigger-text {
    animation: none !important;
  }
}

/* Resume on tablets and phones */
@media (max-width: 1000px) {
  .resume {
    padding: 120px 48px 80px;
  }

  .resume-statement {
    margin-top: 72px;
    font-size: 32px;
  }

  .resume-note + .resume-label {
    margin-top: 80px;
  }

  .company {
    padding-left: 0;
  }

  .role {
    grid-template-columns: 1fr;
    row-gap: 16px;
  }
}

@media (max-width: 720px) {
  /* Bottom: room for the pills (12px from the bottom + 32px tall) plus 48px */
  .resume-wrap {
    padding: 32px 12px 92px;
  }

  .resume-frame {
    --fold-top: 126px;
    --fold-side: 115.2px;
    --fold-tip-x: 11.3px;
    --fold-tip-y: 125.5px;
  }

  .resume {
    padding: 56px 24px 56px;
  }

  .resume-frame:has(.fold-hotspot:hover, .stamp:hover, .stamp:focus-visible) {
    --fold-top: 157.2px;
    --fold-side: 136px;
    --fold-tip-x: 22.7px;
    --fold-tip-y: 155.5px;
  }

  .resume-name {
    font-size: 28px;
  }

  .resume-signature {
    width: 160px;
    margin-bottom: 6px;
    margin-left: 0;
  }

  .resume-title {
    font-size: 18px;
  }

  .resume-label {
    font-size: 16px;
  }

  .resume-statement {
    margin-top: 48px;
    font-size: 26px;
  }

  .resume-note {
    margin-top: 16px;
  }

  .resume-note + .resume-label {
    margin-top: 52px;
  }

  .resume-divider,
  .company + .resume-divider {
    margin: 32px 0 48px;
  }

  .company {
    gap: 48px;
  }

  .roles {
    gap: 64px;
  }

  .company-name {
    font-size: 24px;
  }

  .company .avatar {
    --avatar-size: 48px;
  }

  .company-header.with-avatar {
    gap: 14px;
  }

  .role-title {
    font-size: 21px;
  }

  .company-years,
  .role-years {
    font-size: 16px;
  }

  .highlights,
  .expertise p {
    font-size: 17px;
    line-height: 30px;
  }

  .highlights {
    gap: 28px;
    padding-left: 22px;
  }

  .highlights .narrow {
    line-height: inherit;
  }
}

.page h1 {
  font-size: clamp(2.2rem, 5vw, 3rem);
  letter-spacing: -0.03em;
}

/* ===== Hero ===== */
.hero {
  padding-top: 120px;
  padding-bottom: 100px;
}

.eyebrow {
  color: var(--accent);
  font-weight: 600;
  margin: 0 0 8px;
}

.hero h1 {
  font-size: clamp(2.6rem, 7vw, 4.5rem);
  letter-spacing: -0.03em;
}

.lead {
  font-size: 1.2rem;
  color: var(--muted);
  max-width: 600px;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 32px;
}

/* ===== Buttons ===== */
.button {
  display: inline-block;
  padding: 12px 22px;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-text);
  font: inherit;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: opacity 0.15s;
}

.button:hover {
  opacity: 0.85;
}

.button-ghost {
  background: transparent;
  color: var(--accent);
}

/* ===== Sections ===== */
.section {
  padding-top: 80px;
  padding-bottom: 80px;
  border-top: 1px solid var(--border);
}

.section h2 {
  font-size: 1.9rem;
  letter-spacing: -0.02em;
  margin-bottom: 24px;
}

.section-intro {
  color: var(--muted);
  margin-top: -12px;
}

/* ===== About ===== */
.about-grid {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 48px;
}

.about-grid p {
  margin-top: 0;
}

.skills {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 8px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.skills li {
  padding: 6px 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 14px;
}

/* ===== Projects ===== */
.project-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 24px;
}

.project {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg);
  transition: transform 0.15s, box-shadow 0.15s;
}

.project:hover {
  transform: translateY(-3px);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
}

.project-image {
  aspect-ratio: 16 / 10;
  object-fit: cover;
  width: 100%;
}

.placeholder {
  display: grid;
  place-items: center;
  background: var(--surface);
  color: var(--muted);
  font-size: 14px;
}

.project-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 20px;
}

.project-body h3 {
  font-size: 1.15rem;
}

.project-body p {
  margin: 0 0 16px;
  color: var(--muted);
  font-size: 15px;
}

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
}

.tags li {
  padding: 2px 10px;
  background: var(--surface);
  border-radius: 6px;
  font-size: 13px;
  color: var(--muted);
}

.project-links {
  margin-top: auto;
}

.project-links a {
  font-weight: 600;
  font-size: 15px;
  text-decoration: none;
}

/* ===== Contact ===== */
.contact-form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  max-width: 640px;
  margin-top: 24px;
}

.contact-form label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 14px;
  font-weight: 500;
}

.contact-form .full {
  grid-column: 1 / -1;
}

.contact-form input,
.contact-form textarea {
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font: inherit;
}

.contact-form input:focus,
.contact-form textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.contact-form button {
  justify-self: start;
}

.social {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  list-style: none;
  margin: 40px 0 0;
  padding: 0;
}

.social a {
  font-weight: 500;
}

/* ===== Footer ===== */
.site-footer {
  padding-top: 32px;
  padding-bottom: 48px;
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: 14px;
}

/* ===== Phones & small screens ===== */
@media (max-width: 720px) {
  .container {
    padding: 0 16px;
  }

  .nav {
    flex-wrap: wrap;
    height: auto;
    padding-top: 12px;
    padding-bottom: 12px;
    row-gap: 4px;
  }

  .logo {
    white-space: nowrap;
  }

  .nav-links {
    gap: 14px;
  }

  .nav-links a {
    font-size: 14px;
  }

  .hero {
    padding-top: 72px;
    padding-bottom: 64px;
  }

  .section {
    padding-top: 56px;
    padding-bottom: 56px;
  }

  .about-grid,
  .contact-form {
    grid-template-columns: 1fr;
  }
}
