/* ---------- Fonts ---------- */
@font-face {
  font-family: 'PP Neue Montreal';
  src: url('fonts/PPNeueMontreal-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'PP Neue Montreal';
  src: url('fonts/PPNeueMontreal-Medium.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* ---------- Tokens ---------- */
:root {
  --bg-base: #ffffff;
  --text-primary: #1c1c1c;
  --text-muted: #52525b;
  --card-placeholder: #ececec;

  --margin-main: 20px;
  --column-gap: 10px;
  --card-gap: 6px;
  --wrapper-pad-bottom: 40px;

  --label-lg: 16px;
  --body-font: 'PP Neue Montreal', 'Helvetica Neue', Helvetica, Arial, sans-serif;

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  color-scheme: light;
}

:root[data-theme='dark'] {
  --bg-base: #191919;
  --text-primary: #f2f2f2;
  --text-muted: #a1a1aa;
  --card-placeholder: #2c2c30;
  color-scheme: dark;
}

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

html, body { margin: 0; padding: 0; }
[hidden] { display: none !important; }

body {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  background: var(--bg-base);
  color: var(--text-primary);
  font-family: var(--body-font);
  font-size: var(--label-lg);
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0.01em;
  /* Crisp type */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-kerning: normal;
  font-feature-settings: 'kern' 1, 'liga' 1;
  font-synthesis: none;
  -webkit-text-size-adjust: 100%;
  transition: background-color 0.4s ease, color 0.4s ease;
}

p { margin: 0; }
a { color: inherit; text-decoration: none; }
img { display: block; max-width: 100%; }

/* ---------- Header ---------- */
.site-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  padding: var(--margin-main);
  flex: 0 0 auto;
}

.brand { max-width: 243px; }
.brand__link { white-space: nowrap; }
/* Tagline alternates between two lines: a clipped one-line window with a sliding track (main.js) */
.brand__tagline { height: 1.4em; overflow: hidden; }
.brand__swap { display: block; }
.brand__swap > span { display: block; white-space: nowrap; }
.brand__name { font-weight: 500; color: var(--text-primary); }
.brand__tagline { color: var(--text-muted); }

.nav {
  display: flex;
  align-items: center;
  gap: 12px;
}

.nav__item {
  color: var(--text-primary);
  white-space: nowrap;
}

/* ---------- Rolling text links (brand + nav) ----------
   Two copies of the label stacked in a clipped box; on hover each letter slides up one
   line, staggered left → right, so the second copy rolls in. Letters are split by main.js. */
.roll {
  position: relative;
  display: inline-block;
  overflow: hidden;
  white-space: nowrap;
  vertical-align: top;
}
.roll__text { display: block; }
.roll__word { display: inline-block; white-space: nowrap; }
.roll__text--clone { position: absolute; left: 0; top: 100%; }
.roll {
  --roll-step: 16ms;   /* per-letter stagger */
  --roll-dur: 0.55s;
}
.roll .char {
  display: inline-block;
  white-space: pre;
  transition: transform var(--roll-dur) cubic-bezier(0.22, 1, 0.36, 1);
  transition-delay: calc(var(--i) * var(--roll-step));
}
/* "Kodu Studio" is short, so it uses the same per-letter stagger as the nav links */
.brand__link.roll { --roll-step: 16ms; --roll-dur: 0.45s; }
.roll:hover .char,
.roll:focus-visible .char { transform: translateY(-100%); }
@media (hover: none) { .roll .char { transition: none; } }

.theme-toggle {
  position: relative;
  width: 16px;
  height: 16px;
  padding: 0;
  margin: 0;
  border: 0;
  background: none;
  color: var(--text-primary);
  cursor: pointer;
  display: grid;
  place-items: center;
}
.theme-toggle__icon {
  grid-area: 1 / 1;
  width: 16px;
  height: 16px;
  transition: opacity 0.3s ease, transform 0.45s var(--ease-out);
}
.theme-toggle__icon--sun { opacity: 0; transform: rotate(-90deg) scale(0.6); }
:root[data-theme='dark'] .theme-toggle__icon--moon { opacity: 0; transform: rotate(90deg) scale(0.6); }
:root[data-theme='dark'] .theme-toggle__icon--sun { opacity: 1; transform: rotate(0deg) scale(1); }

/* ---------- Project cards ---------- */
.project-wrapper {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 var(--margin-main) var(--wrapper-pad-bottom);
}

.project-container {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--column-gap);
  width: 100%;
}

.project-card {
  flex: 1 0 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--card-gap);
}
/* Promote to a GPU layer only while the intro is animating; afterwards images rasterise at full crispness */
html:not(.intro-done) .project-card { will-change: transform; }

.project-card__media {
  position: relative;
  width: 100%;
  aspect-ratio: 6 / 8;
  border-radius: 4px;
  overflow: hidden;
  background: var(--card-placeholder);
}
.project-card__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.7s var(--ease-out);
}
/* Card hover effects: pointer devices only. On touch screens :hover sticks after a tap,
   which left cards dimmed/zoomed, so none of this applies there. */
@media (hover: hover) and (pointer: fine) {
  .project-card:hover .project-card__media img { transform: scale(1.03); }

  /* Dim every other card (image + text) to 50%, keep the hovered one at 100%.
     Only enabled once the intro has finished so the transition doesn't fight GSAP. */
  .intro-done .project-card { transition: opacity 0.4s ease; }
  .intro-done .project-container:has(.project-card:hover) .project-card:not(:hover) { opacity: 0.5; }
}

.project-card--draft { cursor: default; }

.project-card__name { font-weight: 500; color: var(--text-primary); }
.project-card__info { color: var(--text-muted); }
.project-card__row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.project-card__index { display: none; font-weight: 500; color: var(--text-primary); }

/* ---------- Smooth scroll (Lenis) ---------- */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }

/* ---------- Project page ---------- */
.project-page {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--margin-main);
  align-content: start;
  padding: 0 var(--margin-main) var(--margin-main);
}

.project-image {
  position: relative;
  margin: 0; /* reset <figure> default */
  border-radius: 4px;
  overflow: hidden;
  background: var(--card-placeholder);
  grid-column: span 6;
}
.project-image img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;                                  /* fades in once the file has actually arrived */
  transition: opacity 0.5s ease;
}
.project-image img.is-loaded,
.project-image--hero img { opacity: 1; }   /* hero is handled by the card→hero transition, no fade */
.project-video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* Columns per row (aspect-ratio is set inline per image by main.js) */
.project-image--cols-1 { grid-column: span 6; }
.project-image--cols-2 { grid-column: span 3; }
.project-image--cols-3 { grid-column: span 2; }

/* .tall images: side by side at equal width, each at its own natural height (top-aligned,
   so a shorter neighbour simply leaves space below it). Nothing is cropped. */
.project-image { align-self: start; }

/* Mobile: every image full width, one per row */
@media (max-width: 699px) {
  .project-page { gap: 12px; padding-bottom: 12px; }
  .project-image--cols-2,
  .project-image--cols-3 { grid-column: span 6; }
}

/* ---------- About page ----------
   12-column grid (10px gutters, same as the homepage cards), anchored to the bottom.
   Portrait = cols 1–2 · eyebrows = cols 5–6 · text = cols 7–11 (as in the Figma grid). */
.about {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 40px var(--margin-main) 96px;
}
.about__grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  grid-template-rows: auto auto auto auto;
  column-gap: var(--column-gap);
  row-gap: 64px;
  align-items: start;
}

.about__portrait {
  grid-column: 1 / 3;
  grid-row: 1 / 5;
  aspect-ratio: 6 / 8;
  border-radius: 4px;
  overflow: hidden;
  background: var(--card-placeholder);
}
.about__portrait img { width: 100%; height: 100%; object-fit: cover; }

.about__eyebrow {
  grid-column: 5 / 7;
  font-weight: 500;
  font-size: 18px;
  line-height: 1.5;
  color: var(--text-primary);
}
.about__lead,
.about__list,
.about__links { grid-column: 7 / 12; }

.about__lead {
  max-width: 62ch;   /* keep measure comfortable on very wide screens */
  font-weight: 500;
  font-size: 18px;
  line-height: 1.5;
  color: var(--text-primary);
}

.about__list {
  list-style: none;
  margin: 0;
  padding: 0;
  font-weight: 500;
  font-size: 18px;
  line-height: 1.5;
  color: var(--text-primary);
}

/* Social links — label + Lucide arrow-up-right (20px, 5px gap) */
.about__links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  font-weight: 500;
  font-size: 18px;
  line-height: 1.5;
  color: var(--text-primary);
}
.about__link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.about__link-icon {
  width: 20px;
  height: 20px;
  flex: none;
  transition: transform 0.4s var(--ease-out);
}
.about__link:hover .about__link-icon { transform: translate(2px, -2px); }

/* Line-reveal masks (spans are injected by main.js, removed again after the intro) */
.about .line,
.project-text .line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.08em;   /* room for descenders inside the mask */
  margin-bottom: -0.08em;
}
.about .line > span,
.project-text .line > span { display: block; }

/* Pre-animation: hide until JS is ready (JS removes this) */
.is-loading .about__portrait,
.is-loading .about__eyebrow,
.is-loading .about__lead,
.is-loading .about__list li,
.is-loading .about__links li { opacity: 0; }

@media (max-width: 1199px) {
  .about__portrait { grid-column: 1 / 4; }
  .about__eyebrow  { grid-column: 5 / 7; }
  .about__lead, .about__list, .about__links { grid-column: 7 / 13; }
}

@media (max-width: 899px) {
  .about { justify-content: flex-start; padding-top: 3rem; padding-bottom: 40px; }   /* 3rem from the nav */
  .about__grid { row-gap: 12px; }
  .about__portrait { grid-column: 1 / 7; grid-row: auto; margin-bottom: 36px; }        /* half the screen width */
  .about__eyebrow, .about__lead, .about__list, .about__links { grid-column: 1 / 13; }
  .about__list { margin-bottom: 0; }
  .about__eyebrow { margin-top: 36px; }                 /* same gap between every section… */
  .about__portrait + .about__eyebrow { margin-top: 0; } /* …except the first, which sits under the portrait */
}

/* ---------- Project copy block (Overview / My Role / The Team / Live Site) ----------
   Same 12-col grid + type as the About page: eyebrows in cols 5–6, text in cols 7–11. */
.project-text {
  grid-column: span 6;
  /* 4rem at ≤600px → 11rem at ≥2200px (minus the grid's 20px so the visual gap matches) */
  padding: calc(clamp(4rem, 1.375rem + 7vw, 11rem) - var(--margin-main)) 0;
}
.project-text__grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--column-gap);
  row-gap: 2.5rem;
  align-items: start;
}
.project-text__eyebrow { grid-column: 5 / 7; }
.project-text__lead,
.project-text__list,
.project-text__link { grid-column: 7 / 12; }
.project-text__eyebrow,
.project-text__lead,
.project-text__list,
.project-text__link {
  font-weight: 500;
  font-size: 18px;
  line-height: 1.5;
  color: var(--text-primary);
}
.project-text__lead { max-width: 62ch; }
.project-text__list { list-style: none; margin: 0; padding: 0; }
/* Hidden until the reveal has measured its lines (JS adds is-revealed) */
.project-text:not(.is-revealed) .project-text__eyebrow,
.project-text:not(.is-revealed) .project-text__lead,
.project-text:not(.is-revealed) .project-text__list li,
.project-text:not(.is-revealed) .project-text__link { opacity: 0; }

/* External link: label + Lucide arrow-up-right (20px, 5px gap) — shared with the About page */
.ext-link { display: inline-flex; align-items: center; gap: 5px; }
.ext-link__icon { width: 20px; height: 20px; flex: none; transition: transform 0.4s var(--ease-out); }
.ext-link:hover .ext-link__icon { transform: translate(2px, -2px); }

@media (max-width: 1199px) {
  .project-text__eyebrow { grid-column: 5 / 7; }
  .project-text__lead, .project-text__list, .project-text__link { grid-column: 7 / 13; }
}
@media (max-width: 899px) {
  .project-text__grid { row-gap: 12px; }
  .project-text__eyebrow, .project-text__lead, .project-text__list, .project-text__link { grid-column: 1 / 13; font-size: 16px; }
  .project-text__eyebrow { margin-top: 28px; }
  .project-text__eyebrow:first-child { margin-top: 0; }
  .project-text__link { margin-top: 28px; }
}

/* =====================================================================================
   NEXT PROJECT SECTION (bottom of every project page)
   To remove: set NEXT_PROJECT = false in main.js. This CSS block is then unused and can go.
   ===================================================================================== */
.next-project {
  grid-column: span 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  /* top padding: 5rem on a phone → 12.75rem (204px) at 1512px, fluid in between */
  padding: clamp(5rem, 13.6vw - 0.1rem, 12.75rem) 0 0;
  margin: 0 calc(-1 * var(--margin-main));           /* full-bleed so the clipped image meets the edges cleanly */
  height: 756px;                                      /* fixed height = the image gets cut off (~345px of it showing) */
  overflow: hidden;
  color: var(--text-primary);
}
.next-project__eyebrow {
  font-weight: 500;
  font-size: 18px;
  line-height: 1.5;
  text-transform: uppercase;
}
.next-project__name {
  margin: 24px 0 0;
  font-weight: 500;
  font-size: 56px;
  line-height: 1.5;
  letter-spacing: -0.01em;
}
.next-project__window {
  margin-top: 72px;
  width: min(900px, calc(100vw - 2 * var(--margin-main)));
  border-radius: 4px 4px 0 0;
  overflow: hidden;
  background: var(--card-placeholder);
}
.next-project__media {
  aspect-ratio: 16 / 9;
  position: relative;
}
.next-project__media img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.9s var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .next-project:hover .next-project__media img { transform: scale(1.03); }
}
@media (max-width: 899px) {
  .next-project { height: auto; }
  .next-project__name { font-size: 32px; }
  .next-project__window { margin-top: 40px; }
  .next-project__media { aspect-ratio: 16 / 9; }
  .next-project__window {
    /* window is (100vw - 88px) wide → 16:9 image is 0.5625× that tall; show 80% of it */
    height: calc((100vw - 2 * var(--margin-main) - 3rem) * 0.45);
    width: calc(100vw - 2 * var(--margin-main) - 3rem);                 /* 1.5rem narrower each side than the page images */
  }
}
.project-page:has(.next-project) { padding-bottom: 0; }   /* teaser runs to the page edge */
/* END NEXT PROJECT SECTION */

/* =====================================================================================
   CUSTOM CURSOR (pointer devices only)
   A small white dot in difference blend mode, so it inverts whatever is under it and reads
   in both themes. Grows on project cards and links. To remove: delete this block and the
   CUSTOM CURSOR section in main.js.
   ===================================================================================== */
@media (hover: hover) and (pointer: fine) {
  html.has-cursor,
  html.has-cursor a,
  html.has-cursor button,
  html.has-cursor .project-card { cursor: none; }

  .cursor-dot {
    position: fixed;
    top: 0;
    left: 0;
    width: 16px;
    height: 16px;
    margin: -8px 0 0 -8px;              /* centred on the pointer */
    border-radius: 50%;
    background: #fff;
    mix-blend-mode: difference;
    pointer-events: none;
    z-index: 100;
    opacity: 0;                          /* fades in on first move */
    will-change: transform;
  }
}
/* END CUSTOM CURSOR */

/* ---------- Page transition helpers ---------- */
/* The floating image that travels between the card and the project hero */
.flip-clone {
  position: fixed;
  z-index: 50;
  border-radius: 4px;
  overflow: hidden;
  pointer-events: none;
  will-change: top, left, width, height;
}
.flip-clone img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  backface-visibility: hidden;
}
/* While a transition runs, hand opacity control to GSAP */
.is-transitioning .project-card { transition: none; }
.is-transitioning .project-container:has(.project-card:hover) .project-card:not(:hover) { opacity: 1; }

/* Pre-animation state: hide until JS positions the cards (JS removes this) */
.is-loading .brand > *,
.is-loading .nav > *,
.is-loading .project-card { opacity: 0; }

/* Homepage only: cards start below the viewport during the intro — stop that creating a scrollbar */
html.lock-scroll { overflow: hidden; }

/* ---------- Responsive: 2-col grid below 1200px ---------- */
@media (max-width: 1199px) {
  .project-wrapper {
    justify-content: flex-start;
    padding-top: 0;
  }
  .project-container {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    row-gap: 24px;
    align-items: start;
  }
  .project-card { flex: none; }
}

/* =====================================================================================
   MOBILE CAROUSEL (< 700px)
   One swipeable row: first card centred, next card peeking in from the right, with an
   "01." index above each card. To go back to the stacked 2-column grid on mobile, delete
   this whole block (down to the closing "END MOBILE CAROUSEL" line). Nothing else depends on it.
   ===================================================================================== */
@media (max-width: 699px) {
  .project-wrapper {
    justify-content: flex-start;
    padding: 2rem var(--margin-main);   /* 2rem safe zone above and below the row */
  }
  .project-container {
    display: flex;                      /* override the 2-col grid */
    justify-content: flex-start;        /* NOT center: centring an overflowing row hides its start */
    gap: var(--column-gap);
    align-items: flex-start;
    align-self: stretch;                /* fill the wrapper's width (it centres children by default) */
    width: auto;
    min-width: 0;
    margin: auto calc(-1 * var(--margin-main));         /* auto = vertically centred, but never overflows the safe zone */
    padding: 0 calc((100vw - var(--card-w)) / 2);       /* centres the first (and last) card */
    --card-w: calc(90vw - 6px);         /* neighbours peek in by ~12px on a 375px phone */
    overflow-x: auto;
    overflow-y: visible;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .project-container::-webkit-scrollbar { display: none; }
  .project-card {
    flex: 0 0 var(--card-w);
    scroll-snap-align: center;
  }
  .project-card__media { aspect-ratio: 4 / 5; }
  .project-card__index { display: block; }

  /* During the intro the cards fly in from below the viewport — let them show outside the row */
  html:not(.intro-done) .project-container { overflow: visible; }
}
/* END MOBILE CAROUSEL */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* =====================================================================================
   CONTACT PANEL
   Slides in from the right when "Contact" is clicked; the page behind it dims and blurs.
   Colours are inverted against the page theme (dark panel in light mode, light panel in
   dark mode). To remove: delete this block and the CONTACT PANEL section in main.js.
   ===================================================================================== */
.contact-scrim {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(10, 10, 10, 0.45);
  -webkit-backdrop-filter: blur(7px);
  backdrop-filter: blur(7px);
  opacity: 0;
  visibility: hidden;
}
:root[data-theme='dark'] .contact-scrim { background: rgba(0, 0, 0, 0.55); }

.contact-panel {
  /* Inverted against the page theme */
  --panel-bg: #141414;
  --panel-text: #f2f2f2;
  --panel-muted: rgba(242, 242, 242, 0.55);
  --panel-line: rgba(242, 242, 242, 0.16);

  position: fixed;
  top: 0;
  right: 0;
  z-index: 90;
  width: min(680px, 50vw);
  height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 3rem;
  padding: var(--margin-main);
  background: var(--panel-bg);
  color: var(--panel-text);
  overflow-y: auto;
  overscroll-behavior: contain;
  transform: translateX(100%);
  visibility: hidden;
}
:root[data-theme='dark'] .contact-panel {
  --panel-bg: #ffffff;
  --panel-text: #1c1c1c;
  --panel-muted: rgba(28, 28, 28, 0.55);
  --panel-line: rgba(28, 28, 28, 0.16);
}

.contact-panel__top { display: block; }

.contact-panel__bar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: var(--label-lg);
}
.contact-panel__close {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  cursor: pointer;
}

.contact-panel__body {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 2rem;
  margin-top: 2.5rem;
}
.contact-panel__lead {
  max-width: 34ch;
  font-size: clamp(1.125rem, 1.6vw, 1.5rem);
  line-height: 1.35;
}
.contact-panel__lead span { color: var(--panel-muted); }

.contact-panel__portrait {
  flex: 0 0 auto;
  width: clamp(110px, 12vw, 160px);
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border-radius: 2px;
}
.contact-panel__portrait img { width: 100%; height: 100%; object-fit: cover; }

.contact-panel__links { padding-bottom: 2.5rem; }
.contact-panel__label {
  color: var(--panel-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 1rem;
}
.contact-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: clamp(0.9rem, 1.6vw, 1.4rem) 0;
  border-top: 1px solid var(--panel-line);
  font-size: clamp(1.5rem, 3vw, 2.5rem);
  line-height: 1.1;
}
.contact-link:last-of-type { border-bottom: 1px solid var(--panel-line); }
.contact-link svg {
  flex: 0 0 auto;
  width: 2rem;
  height: 2rem;
  transition: transform 0.45s var(--ease-out);
}
/* Hovering anywhere on the row rolls the label, not just the text itself */
.contact-link:hover .roll .char { transform: translateY(-100%); }
.contact-link:hover svg { transform: translateX(6px); }
.contact-link--ext:hover svg { transform: translate(4px, -4px); }
.contact-link .roll { --roll-step: 10ms; }

@media (max-width: 899px) {
  .contact-panel {
    width: 100%;
    gap: 2rem;
  }
  .contact-panel__body { margin-top: 1.5rem; }
  .contact-panel__links { padding-bottom: 1rem; }
  .contact-panel__portrait { width: clamp(96px, 26vw, 140px); }
}
/* END CONTACT PANEL */
