/* ==========================================================================
   Kyla Joyner Portfolio — shared styles
   Sizes come from the Figma wireframes (1440 x 1024 frames).
   ========================================================================== */

/* ---------- Fonts ---------- */

@font-face {
  font-family: "Brunson";
  src: url("../assets/fonts/Brunson.woff2") format("woff2");
  font-display: swap;
}

@font-face {
  font-family: "Bebas Neue";
  src: url("../assets/fonts/BebasNeue-Regular.woff2") format("woff2");
  font-display: swap;
}

/* West End and Narkiss Yair come from the Adobe Fonts kit linked in each page's <head>. */

:root {
  --color-ink: #000;
  --color-paper: #fff;
  --color-thumb-border: rgba(0, 0, 0, 0.43);

  --font-accent: "west-end-decorate-shadow", "Brunson", serif; /* wordmark + page titles */
  --font-nav: "Bebas Neue", sans-serif;               /* nav + subheads */
  --font-header: "Brunson", serif;                    /* headers */
  --font-body: "narkiss-yair-variable", "Courier New", monospace; /* body copy */

  /* One Figma pixel, scaled so the 1440 x 1024 frame always fits the window
     without scrolling. Every desktop size below is a multiple of it. */
  --u: min(calc(100vw / 1440), calc(100vh / 1024));

  --header-height: calc(79 * var(--u));
  --ornament-width: calc(224.63 * var(--u));
  --ornament-height: calc(216.52 * var(--u));
}

/* ---------- Base ---------- */

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

body {
  margin: 0;
  background: var(--color-paper);
  color: var(--color-ink);
  font-family: var(--font-body);
}

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

a {
  color: inherit;
  text-decoration: none;
}

/* ---------- Header ---------- */

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--header-height);
  padding: 0 calc(44 * var(--u)) 0 calc(15 * var(--u));
  background: var(--color-paper);
}

.wordmark {
  font-family: var(--font-accent);
  font-weight: 400;
  font-synthesis: none;
  font-size: calc(37 * var(--u));
  letter-spacing: calc(4.8 * var(--u));
  white-space: nowrap;
}

.site-nav ul {
  display: flex;
  gap: calc(47 * var(--u));
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-nav a {
  font-family: var(--font-nav);
  font-size: calc(37.356 * var(--u));
  letter-spacing: calc(2.9885 * var(--u));
}

/* Faint underline: grows out from the middle on hover, stays under the section you're on */
.site-nav a {
  position: relative;
}

.site-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(-4 * var(--u));
  height: max(1px, calc(1.5 * var(--u)));
  background: rgba(0, 0, 0, 0.3);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.25s ease;
}

.site-nav a:hover::after,
.site-nav a:focus-visible::after,
.site-nav a[aria-current="page"]::after {
  transform: scaleX(1);
}

/* ---------- Page frame + corner ornaments ---------- */

.page {
  position: relative;
  height: calc(100vh - var(--header-height));
  overflow: hidden;
  overflow-x: clip; /* stays on even where a page lets content run long; ornaments hang off the edge */
  padding-top: calc(44 * var(--u));
}

.ornament {
  position: absolute;
  width: var(--ornament-width);
  height: var(--ornament-height);
  pointer-events: none;
}

/* The uploaded ornament points to the bottom-right corner; the others are flipped. */
.ornament--top-left     { top: calc(32 * var(--u)); left: calc(-11 * var(--u));  transform: rotate(180deg); }
.ornament--top-right    { top: calc(44 * var(--u)); right: calc(-14 * var(--u)); transform: scaleY(-1); }
.ornament--bottom-left  { bottom: calc(12 * var(--u)); left: calc(-11 * var(--u));  transform: scaleX(-1); }
.ornament--bottom-right { bottom: calc(12 * var(--u)); right: calc(-14 * var(--u)); }

/* ---------- Project page title ---------- */

.page-title {
  margin: 0;
  padding: 0 16px;
  font-family: var(--font-accent);
  font-size: calc(80.303 * var(--u));
  font-weight: 400;
  font-synthesis: none;
  letter-spacing: calc(10.4394 * var(--u));
  text-align: center;
}

/* ---------- Project pages ---------- */

/* Project pages can scroll if their content runs long. */
.page--project {
  height: auto;
  min-height: calc(100vh - var(--header-height));
  overflow-y: visible;
  display: flex;
  flex-direction: column;
  justify-content: center; /* title, intro and gallery sit centered in the space under the header */
  padding-top: calc(16 * var(--u));
  padding-bottom: calc(16 * var(--u));
}

.page--project > * {
  width: 100%;
}

.project-intro {
  max-width: calc(810 * var(--u));
  margin: calc(16 * var(--u)) auto 0;
  padding: 0 16px;
  font-family: var(--font-nav);
  font-size: calc(20.77 * var(--u));
  letter-spacing: calc(2.7 * var(--u));
  text-align: center;
}

.project-intro p {
  margin: 0 0 1.2em;
}

/* Project explainer: a red star, a Bebas label, then the copy in Narkiss.
   The labels share a column so every line of copy starts at the same edge. */
.explainer {
  --explainer-line: calc(34 * var(--u)); /* one shared line height so star, label and copy sit on the same center line */
  display: grid;
  grid-template-columns: auto auto 1fr;
  column-gap: calc(20 * var(--u));
  row-gap: calc(28 * var(--u));
  max-width: calc(1120 * var(--u)); /* same width as the work below, so they share a left edge */
  margin: calc(30 * var(--u)) auto 0;
  padding: 0 16px;
}

/* Match the narrower galleries so the left edges still line up */
.explainer:has(+ .project-gallery--portrait) { max-width: calc(860 * var(--u)); }
.explainer:has(+ .project-gallery--rows) { max-width: calc(1060 * var(--u)); }

.explainer__row {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: start;
}

.explainer__row::before {
  content: "\2605"; /* same red star as the Jukebox */
  display: flex;
  align-items: center;
  justify-content: center;
  height: calc(36 * 0.7 * var(--u)); /* as tall as the label's capitals, so the star centers on them */
  font-size: calc(32 * var(--u));
  line-height: 1;
  color: #c4263f;
}

/* Both the label and the copy are trimmed to the top of their capitals,
   so the first line of copy starts exactly level with "PROJECT:" / "ROLE:" */
.explainer__label {
  font-family: var(--font-nav);
  font-size: calc(36 * var(--u));
  letter-spacing: calc(2 * var(--u));
  line-height: 1;
  white-space: nowrap;
  text-box: trim-both cap alphabetic;
}

/* A label that carries its answer on the same line (Old Spice's client) */
.explainer__label--full {
  contain: inline-size; /* stays on one line without widening the column; spills into the gap instead */
  margin-bottom: 8px; /* no copy under it, so give the next row the usual breathing room */
}

/* A row without a star (UNC WBB's client): the header starts at the page's left edge */
.explainer__row--nostar::before { content: none; }
.explainer__row--nostar .explainer__label,
.page--project .explainer .explainer__row--nostar .explainer__copy { grid-column: 1 / -1; }

/* very narrow phones: shrink the one-line Client header just enough to fit */
@media (max-width: 350px) {
  .explainer .explainer__label--full { font-size: 23px; }
}

.explainer__copy {
  margin: 0;
  font-family: var(--font-body);
  font-size: calc(20 * var(--u));
  max-width: calc(720 * var(--u)); /* keeps lines a comfortable reading length */
  line-height: var(--explainer-line);
  text-box: trim-start cap alphabetic;
}

/* Browsers without text-box trimming (Firefox): close enough by hand */
@supports not (text-box: trim-both cap alphabetic) {
  .explainer__label { margin-top: -0.12em; margin-bottom: -0.18em; }
  .explainer__copy { margin-top: calc((var(--explainer-line) - 0.7em) / -2); }
}

.explainer__copy p {
  margin: 0 0 0.8em;
}

.explainer__copy p:last-child {
  margin-bottom: 0;
}

.explainer__tbd {
  opacity: 0.45;
}

/* Desktop: the explainer becomes a column on the left that stays in view
   while the work scrolls past on the right. Phones keep it stacked on top. */
@media (min-width: 901px) {
  .page--project:has(> .explainer, > .project-aside) {
    display: grid;
    grid-template-columns: calc(420 * var(--u)) minmax(0, 1fr);
    column-gap: calc(64 * var(--u));
    align-content: center;
    padding-left: calc(80 * var(--u));
    padding-right: calc(80 * var(--u));
  }

  .page--project:has(> .explainer, > .project-aside) > * {
    grid-column: 2;
  }

  .page--project > .explainer,
  .page--project > .project-aside {
    grid-column: 1;
    grid-row: 1 / span 10;
    align-self: start;
    position: sticky;
    top: calc(40 * var(--u));
    margin: calc(28 * var(--u)) 0 0;
  }

  .page--project > .explainer,
  .project-aside > .explainer {
    grid-template-columns: auto 1fr;
    row-gap: calc(40 * var(--u));
    max-width: none;
    padding: 0;
  }

  .project-aside > .explainer { margin: 0; }

  /* View full project sits under Role, lined up with the copy */
  .page--project > .project-aside > .project-link {
    margin: calc(40 * var(--u)) 0 0 calc(39.3 * var(--u));
  }

  /* star and label on one line, copy underneath, lined up with the label */
  .page--project .explainer .explainer__copy {
    grid-column: 2;
    margin-top: calc(18 * var(--u));
    font-size: calc(19 * var(--u));
    line-height: 1.6;
  }

  .page--project:has(> .explainer, > .project-aside) .project-gallery,
  .page--project:has(> .explainer, > .project-aside) .project-video {
    padding: 0;
  }

  .page--project:has(> .explainer, > .project-aside) > .project-link {
    justify-self: center;
  }
}

/* Two on top, two on bottom, sized so the whole brief fits the first screen */
.project-gallery {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(24 * var(--u));
  max-width: calc(1120 * var(--u));
  margin: calc(28 * var(--u)) auto 0;
  padding: 0 16px;
}

.project-gallery img {
  width: 100%;
  height: auto;
  cursor: zoom-in;
  transition: opacity 0.2s ease;
}

.project-gallery img:hover {
  opacity: 0.85;
}

/* Tall brand book pages: two rows of four */
.project-gallery--portrait {
  grid-template-columns: repeat(4, 1fr);
  gap: calc(20 * var(--u));
  max-width: calc(860 * var(--u));
}

/* Old Spice: the Pure Sport stick as a 3D model you can drag to spin */
.explainer:has(+ .product-3d) { max-width: calc(860 * var(--u)); }

.product-3d {
  position: relative;
  max-width: calc(860 * var(--u));
  height: min(calc(620 * var(--u)), 70vh);
  margin: calc(28 * var(--u)) auto 0;
  padding: 0 16px;
}

.product-3d__canvas {
  display: block;
  width: 100%;
  height: 100%;
  cursor: grab;
  touch-action: pan-y; /* sideways drags spin it, vertical swipes still scroll the page */
}

.product-3d.is-dragging .product-3d__canvas { cursor: grabbing; }

.product-3d__hint {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 10px); /* just under the model, clear of the stick */
  margin: 0;
  text-align: center;
  font-family: var(--font-nav);
  font-size: calc(18 * var(--u));
  letter-spacing: 2px;
  opacity: 0.5;
  transition: opacity 0.4s ease;
  pointer-events: none;
}

.product-3d.has-spun .product-3d__hint { opacity: 0; }

/* the awards line sits under the "Drag to spin" hint */
.product-3d + .project-note { margin-top: calc(48 * var(--u)); }

/* Old Spice: the badge's three parts in a row under the model, each with its story */
.logo-parts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: calc(40 * var(--u));
  max-width: calc(860 * var(--u));
  margin: calc(48 * var(--u)) auto 0;
  padding: 0 16px;
  list-style: none;
}

/* more room between the badge story and the page nav */
.logo-parts + .project-nav { margin-top: calc(80 * var(--u)); }

.logo-parts__item img {
  display: block;
  width: 100%;
  height: auto;
}

.logo-parts__title {
  margin: calc(16 * var(--u)) 0 0;
  font-family: var(--font-nav);
  font-size: calc(32 * var(--u));
  font-weight: normal;
  letter-spacing: calc(2 * var(--u));
  line-height: 1;
}

.logo-parts__copy {
  margin: calc(10 * var(--u)) 0 0;
  font-family: var(--font-body);
  font-size: calc(17 * var(--u));
  line-height: 1.6;
}

/* One tall page on its own (Old Spice Ad Campaign): as tall as the screen allows */
.project-gallery--single {
  grid-template-columns: 1fr;
  justify-items: center;
}

.project-gallery--single img {
  width: auto;
  max-width: 100%;
  max-height: calc(100vh - var(--header-height) - 140px);
}

/* Mixed shapes in rows: images in a row share a height, and each one's width
   follows its aspect ratio (--ar), so nothing gets cropped */
.project-gallery--rows {
  display: flex;
  flex-direction: column;
  gap: calc(20 * var(--u));
  max-width: calc(1060 * var(--u));
}

.gallery-row {
  display: flex;
  gap: calc(20 * var(--u));
}

.gallery-row img {
  flex: var(--ar) 1 0;
  min-width: 0;
}

/* Main video on a project page, 16:9 like the film */
.project-video {
  max-width: calc(1120 * var(--u));
  margin: calc(28 * var(--u)) auto 0;
  padding: 0 16px;
}

.project-video iframe {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
}

/* Small link under the video to the full story elsewhere (opens in a new tab); underlined on hover */
.project-link {
  align-self: center;
  width: auto !important;
  margin-top: calc(14 * var(--u));
  font-family: var(--font-nav);
  font-size: calc(20 * var(--u));
  letter-spacing: calc(2 * var(--u));
  position: relative;
}

/* same grow-from-the-middle underline as the nav and Back to Work */
.project-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(-3 * var(--u));
  height: max(1px, calc(1.5 * var(--u)));
  background: rgba(0, 0, 0, 0.3);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.25s ease;
}

.project-link:hover::after,
.project-link:focus-visible::after {
  transform: scaleX(1);
}

/* explainer plus View full project, kept together (stacked on phones, left column on desktop) */
.project-aside > .project-link {
  display: inline-block;
  margin: 24px 16px 0;
}

/* Small line of project details, e.g. awards */
.project-note {
  margin: calc(10 * var(--u)) 0 0;
  padding: 0 16px;
  font-family: var(--font-nav);
  font-size: calc(18 * var(--u));
  letter-spacing: calc(1.8 * var(--u));
  text-align: center;
  color: rgba(0, 0, 0, 0.7);
}

/* Photo story under the video. A shared 16:9 frame keeps the rows even
   (a couple of stills are a hair taller); the slideshow shows them uncropped. */
.project-gallery--story {
  margin-top: calc(48 * var(--u));
}

.project-gallery--story img {
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

/* Back to Work link under the gallery, same grow-from-center underline as the nav */
.back-link {
  position: relative;
  align-self: center;
  width: auto !important;
  margin-top: calc(28 * var(--u));
  font-family: var(--font-nav);
  font-size: calc(26 * var(--u));
  letter-spacing: calc(2.5 * var(--u));
}

.back-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(-4 * var(--u));
  height: max(1px, calc(1.5 * var(--u)));
  background: rgba(0, 0, 0, 0.3);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.25s ease;
}

.back-link:hover::after,
.back-link:focus-visible::after {
  transform: scaleX(1);
}

/* Back to All Work and More Work sit side by side at the bottom of each project */
.project-nav {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: calc(16 * var(--u)) calc(72 * var(--u));
  margin-top: calc(28 * var(--u));
}

.project-nav .back-link {
  margin-top: 0;
}

@media (max-width: 900px) {
  .project-nav { gap: 12px 32px; }
  .project-nav .back-link { font-size: 18px; letter-spacing: 1.5px; }
}

/* More Work flips through the projects like a slideshow: the page slides out left, the next slides in from the right */
.page--project.is-leaving {
  opacity: 0;
  transform: translateX(-60px);
  transition: opacity 0.35s ease, transform 0.35s ease;
}

.slide-in .page--project {
  animation: slide-in 0.45s ease backwards;
}

@keyframes slide-in {
  from { opacity: 0; transform: translateX(60px); }
}

@media (prefers-reduced-motion: reduce) {
  .page--project.is-leaving { transition: none; transform: none; }
  .slide-in .page--project { animation: none; }
}

/* ---------- Lightbox (full-screen image viewer) ---------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.97);
}

.lightbox[hidden] {
  display: none;
}

.lightbox-open {
  overflow: hidden;
}

.lightbox__image {
  max-width: calc(100vw - 160px);
  max-height: calc(100vh - 120px);
  width: auto;
  height: auto;
  box-shadow: 0 6px 30px rgba(0, 0, 0, 0.15);
}

.lightbox button {
  border: 0;
  background: none;
  color: var(--color-ink);
  font-family: var(--font-nav);
  cursor: pointer;
}

.lightbox__close {
  position: absolute;
  top: 20px;
  right: 32px;
  font-size: 28px;
  letter-spacing: 2px;
}

.lightbox button:focus-visible {
  outline: 1px solid var(--color-ink);
  outline-offset: 4px;
}

.lightbox__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  padding: 0 16px;
  font-size: 72px;
  line-height: 1;
}

.lightbox__arrow--prev { left: 12px; }
.lightbox__arrow--next { right: 12px; }

.lightbox__count {
  position: absolute;
  bottom: 18px;
  left: 0;
  right: 0;
  margin: 0;
  font-family: var(--font-nav);
  font-size: 22px;
  letter-spacing: 2px;
  text-align: center;
  pointer-events: none; /* never blocks the arrows beside it */
}

/* ---------- About: old TV turning on ---------- */

.page--about {
  height: auto;
  overflow-y: visible;
  padding-top: 0;
}

/* First screen: just the TV, centred under the header */
.about-hero {
  height: calc(100vh - var(--header-height));
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Second screen: headshot and bio, framed by the corner ornaments */
.about-me {
  position: relative;
  min-height: calc(100vh - var(--header-height));
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(120 * var(--u)) 16px;
}

/* The ornaments hug the corners of the headshot */
.about-me__frame {
  position: relative;
  flex: 0 0 auto;
  padding: calc(84 * var(--u)); /* far enough out that the ornaments never touch the photo */
}

.about-me__frame .ornament {
  width: calc(150 * var(--u));
  height: calc(145 * var(--u));
}

.about-me__frame .ornament--top-left     { top: 0;    left: 0; }
.about-me__frame .ornament--top-right    { top: 0;    right: 0; }
.about-me__frame .ornament--bottom-left  { bottom: 0; left: 0; }
.about-me__frame .ornament--bottom-right { bottom: 0; right: 0; }

.about-me__inner {
  display: flex;
  align-items: center;
  gap: calc(110 * var(--u));
  max-width: calc(1260 * var(--u));
}

.about-me__photo {
  display: block;
  width: calc(480 * var(--u));
  height: auto;
}

.about-me__heading {
  margin: 0 0 calc(16 * var(--u));
  font-family: var(--font-nav);
  font-size: calc(64 * var(--u));
  font-weight: 400;
  letter-spacing: calc(3 * var(--u));
  line-height: 1;
}

/* Social and email links, with the same grow-from-the-middle underline as the nav */
.about-me__links {
  display: flex;
  flex-wrap: wrap;
  gap: calc(14 * var(--u)) calc(28 * var(--u));
  margin: calc(32 * var(--u)) 0 0;
  padding: 0;
  list-style: none;
}

.about-me__links a {
  position: relative;
  font-family: var(--font-body);
  font-size: calc(24 * var(--u));
  color: inherit;
  text-decoration: none;
}

.about-me__links a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(-4 * var(--u));
  height: max(1px, calc(1.5 * var(--u)));
  background: currentColor;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.25s ease;
}

.about-me__links a:hover::after,
.about-me__links a:focus-visible::after {
  transform: scaleX(1);
}

/* Résumé: dark pill under the social links, red underline under the word */
.resume-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: calc(36 * var(--u));
  padding: calc(13 * var(--u)) calc(48 * var(--u)) calc(11 * var(--u));
  border-radius: calc(14 * var(--u));
  background: #231f20;
  color: #fff;
  font-family: var(--font-nav);
  font-size: calc(32 * var(--u));
  letter-spacing: calc(1 * var(--u));
  line-height: 1;
  text-decoration: none;
  transition: transform 0.25s ease, background-color 0.25s ease;
}

.resume-btn:hover,
.resume-btn:focus-visible {
  background: #000;
  transform: translateY(calc(-3 * var(--u)));
}

.about-me__copy {
  margin: 0;
  font-family: var(--font-body);
  font-size: calc(30 * var(--u));
  line-height: 1.6;
}

/* Kyla's TV art sits on top; the screen glows through its cut-out */
.tv {
  position: relative;
  width: calc(1100 * var(--u));
  max-width: calc(100vw - 32px);
  aspect-ratio: 2350 / 1782;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.tv:focus-visible {
  outline: 2px solid #000;
  outline-offset: 6px;
}

/* Click the TV: the picture tears, splits colour and the snow spikes for a moment */
.tv.is-glitching .tv__content {
  animation: tv-glitch 0.6s steps(1) both;
}

.tv.is-glitching .tv__title,
.tv.is-glitching .tv__roles {
  text-shadow: -0.8cqw 0 rgba(255, 40, 80, 0.8), 0.8cqw 0 rgba(40, 220, 255, 0.8);
}

.tv.is-glitching .tv__static {
  opacity: 0.75 !important;
}

.tv.is-glitching .tv__scanlines {
  animation: tv-roll 0.6s linear both;
}

@keyframes tv-glitch {
  0%   { transform: translate(0, 0); clip-path: inset(0 0 0 0); }
  10%  { transform: translate(-3cqw, 0) skewX(12deg); clip-path: inset(10% 0 55% 0); }
  20%  { transform: translate(2cqw, 1cqw); clip-path: inset(45% 0 20% 0); }
  30%  { transform: translate(0, -2cqw) scaleY(1.1); clip-path: inset(0 0 0 0); }
  40%  { transform: translate(4cqw, 0) skewX(-18deg); clip-path: inset(65% 0 5% 0); }
  50%  { transform: translate(-2cqw, 3cqw); clip-path: inset(25% 0 40% 0); }
  60%  { transform: translate(1cqw, 0); clip-path: inset(0 0 0 0); opacity: 0.4; }
  75%  { transform: translate(-1cqw, -1cqw) skewX(6deg); clip-path: inset(5% 0 70% 0); opacity: 1; }
  90%  { transform: translate(0.5cqw, 0); clip-path: inset(0 0 0 0); }
  100% { transform: none; clip-path: none; }
}

@keyframes tv-roll {
  from { transform: translateY(-30%); }
  to   { transform: translateY(0); }
}

.tv__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 2;
  pointer-events: none;
  filter: drop-shadow(0 calc(10 * var(--u)) calc(14 * var(--u)) rgba(0, 0, 0, 0.28));
}

/* Soft contact shadow on the "floor" under the legs */
.tv::after {
  content: "";
  position: absolute;
  left: 6%;
  right: 6%;
  bottom: -2.5%;
  height: 6%;
  z-index: 0;
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.12) 45%, transparent 72%);
  pointer-events: none;
}

/* Lines up with the screen hole in tv.webp, a little oversized so the bezel hides the edge */
.tv__screen {
  position: absolute;
  left: 7%;
  top: 9.3%;
  width: 67.2%;
  height: 70.8%;
  overflow: hidden;
  border-radius: 9% / 12%;
  background: #0c0c0c;
  container-type: inline-size;
  isolation: isolate; /* keeps the star layering inside the screen */
}

/* The picture tube warming up: a dot, then a line, then the full screen */
.tv__beam {
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at center, #f4f1ea 0%, #cfcac0 55%, #6d6a64 100%);
  transform: scale(0, 0);
  animation: tv-on 1.6s cubic-bezier(0.2, 0.7, 0.3, 1) 0.4s forwards;
}

@keyframes tv-on {
  0%   { transform: scale(0, 0);         filter: brightness(3); }
  20%  { transform: scale(0.02, 0.004);  filter: brightness(3); }
  45%  { transform: scale(1, 0.004);     filter: brightness(3); }
  70%  { transform: scale(1, 1);         filter: brightness(2); }
  100% { transform: scale(1, 1);         filter: brightness(0.25); }
}

/* Name, rotating roles and the orbiting stars share one layer so stars can pass in front of and behind the text */
.tv__content {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3cqw;
  filter: url(#crt-warp); /* slight barrel bulge, like the picture sits on curved glass */
}

.tv__title {
  position: relative;
  z-index: 2;
  margin: 0;
  font-family: var(--font-accent);
  font-weight: 400;
  font-synthesis: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  font-size: 13cqw;
  letter-spacing: 0.6cqw;
  line-height: 0.9;
  color: #f4f1ea;
  text-shadow: 0 0 2cqw rgba(255, 255, 255, 0.55);
  opacity: 0;
  animation: tv-title 1.2s ease-out 1.9s forwards, tv-flicker 4s steps(1) 3.1s infinite;
}

@keyframes tv-title {
  0%   { opacity: 0;   filter: blur(6px); }
  30%  { opacity: 0.8; filter: blur(2px); }
  40%  { opacity: 0.2; }
  60%  { opacity: 1;   filter: blur(0); }
  100% { opacity: 1;   filter: blur(0); }
}

/* An occasional faint flicker once the picture is up */
@keyframes tv-flicker {
  0%, 100% { opacity: 1; }
  47%      { opacity: 0.85; }
  48%      { opacity: 1; }
  82%      { opacity: 0.9; }
  83%      { opacity: 1; }
}

/* Name and roles tilt together so the roles stay centred under Joyner */
.tv__name {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2.4cqw;
  transform: rotate(-6deg);
}

/* One role at a time, flipping over like a sign */
.tv__roles {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 4.2cqw;
  margin: 0;
  perspective: 40cqw;
  font-family: var(--font-nav);
  font-size: 3.6cqw;
  letter-spacing: 0.5cqw;
  color: #f4f1ea;
  text-shadow: 0 0 1.2cqw rgba(255, 255, 255, 0.45);
  opacity: 0;
  animation: tv-title 1.2s ease-out 2.4s forwards;
}

.tv__roles span {
  position: absolute;
  inset: 0;
  text-align: center;
  white-space: nowrap; /* longer roles like Country Music Defender stay on one line */
  opacity: 0;
  transform: rotateX(-90deg);
  transform-origin: 50% 50% -2cqw;
  transition: transform 0.5s ease, opacity 0.5s ease;
}

.tv__roles span.is-in {
  opacity: 1;
  transform: rotateX(0);
}

.tv__roles span.is-out {
  opacity: 0;
  transform: rotateX(90deg);
}

.tv__star {
  position: absolute;
  left: 0;
  top: 0;
  width: 7cqw;
  height: auto;
  /* stacked shadows give the flat star some thickness */
  filter: drop-shadow(0.2cqw 0.25cqw 0 #8a2238) drop-shadow(0.2cqw 0.25cqw 0 #5c1424) drop-shadow(0 0 1cqw rgba(255, 210, 220, 0.3));
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
}

/* Moving TV static (snow) that stays on once the picture is up */
.tv__static {
  position: absolute;
  z-index: 4;
  inset: -50%;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  3 0 0 0 -1.1'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 240px 240px;
  opacity: 0;
  animation: tv-static-in 0.6s ease-out 1.2s forwards, tv-static 0.4s steps(1) infinite;
}

@keyframes tv-static-in {
  to { opacity: 0.3; }
}

/* Jump the noise around every frame so it reads as moving snow */
@keyframes tv-static {
  0%   { transform: translate(0, 0); }
  12%  { transform: translate(-6%, 4%); }
  25%  { transform: translate(5%, -7%); }
  37%  { transform: translate(-8%, -3%); }
  50%  { transform: translate(3%, 8%); }
  62%  { transform: translate(-4%, -9%); }
  75%  { transform: translate(9%, 2%); }
  87%  { transform: translate(-2%, 6%); }
}

.tv__scanlines {
  position: absolute;
  z-index: 5;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.18) 0,
    rgba(0, 0, 0, 0.18) 1px,
    transparent 1px,
    transparent 3px
  );
  box-shadow: inset 0 0 8cqw rgba(0, 0, 0, 0.85); /* dark edges like curved glass */
}

/* Soft glare on the glass */
.tv__screen::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  background: radial-gradient(ellipse 70% 55% at 28% 18%, rgba(255, 255, 255, 0.12), transparent 70%);
}

/* Power button: an invisible hit area over the button drawn on the TV */
.tv__power {
  position: absolute;
  left: 81.3%;
  top: 42.2%;
  width: 5.8%;
  height: 4.2%;
  z-index: 3;
  padding: 0;
  border: 0;
  border-radius: 12%;
  background: transparent;
  cursor: pointer;
}

.tv__power:active {
  background: rgba(0, 0, 0, 0.25); /* reads as the button pushing in */
}

.tv__power:focus-visible {
  outline: 2px solid #f4f1ea;
  outline-offset: 2px;
}

/* Channel buttons 1-6: hit areas over the rocker buttons drawn on the set */
.tv__channels {
  position: absolute;
  left: 81.2%;
  top: 49.4%;
  width: 12.8%;
  height: 7.2%;
  z-index: 3;
}

.tv__channel {
  position: absolute;
  top: 0;
  left: calc(var(--i) * 16.625%); /* button pitch on the art */
  width: 15.6%;
  height: 100%;
  padding: 0;
  border: 0;
  border-radius: 10%;
  background: transparent;
  cursor: pointer;
}

/* the chosen channel's button looks pushed in */
.tv__channel[aria-pressed="true"],
.tv__channel:active {
  background: rgba(0, 0, 0, 0.28);
}

.tv__channel:focus-visible {
  outline: 2px solid #f4f1ea;
  outline-offset: 2px;
}

/* Channel 2: "dark mode", a bright screen with the name and roles in black */
.tv__light {
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at center, #f4f1ea 0%, #e4dfd4 60%, #b9b4aa 100%);
  opacity: 0;
  transition: opacity 0.2s;
}

.tv[data-channel="2"] .tv__light { opacity: 1; }

.tv[data-channel="2"] .tv__title,
.tv[data-channel="2"] .tv__roles {
  color: #111;
  text-shadow: none;
}

/* Channel 3: the landscape film with the name written out in red script */
.tv__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  filter: url(#crt-warp); /* same barrel bulge as the name, so the footage sits on the curved glass */
}

.tv[data-channel="3"] .tv__video { opacity: 1; }
.tv[data-channel="3"] .tv__name,
.tv[data-channel="3"] .tv__star { visibility: hidden; }

/* Channel 3: a red star spins in 3D over the footage, the name sits still in its middle */
.tv__spin {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-items: center;
  perspective: 90cqw;
  visibility: hidden;
}

.tv[data-channel="3"] .tv__spin { visibility: visible; }

.tv__spin-star {
  grid-area: 1 / 1;
  position: relative;
  width: 66cqw;
  aspect-ratio: 1 / 0.95;
  transform-style: preserve-3d;
  animation: tv-spin 5s linear infinite;
}

/* front and back faces, plus ten side walls along the star's edges, so it reads as one solid piece at every angle */
.tv__spin-star i {
  position: absolute;
  inset: 0;
  background: linear-gradient(160deg, #f27a93, #e44e6c 55%, #c73c5a);
  clip-path: polygon(50% 0%, 61.2% 34.5%, 97.6% 34.5%, 68.2% 55.9%, 79.4% 90.5%, 50% 69.1%, 20.6% 90.5%, 31.8% 55.9%, 2.4% 34.5%, 38.8% 34.5%);
  transform: translateZ(2.5cqw);
}

.tv__spin-star i + i { transform: rotateY(180deg) translateZ(2.5cqw); }

.tv__spin-star b {
  position: absolute;
  height: 5cqw;
  background: #b8334f;
}

@keyframes tv-spin {
  to { transform: rotateY(360deg); }
}

.tv__spin-name {
  grid-area: 1 / 1;
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 6.5cqw 0 0; /* the star's visual middle sits a little below its box centre */
  font-family: var(--font-accent);
  font-weight: 400;
  font-synthesis: none;
  font-size: 10cqw;
  letter-spacing: 0.4cqw;
  line-height: 0.9;
  color: #fff;
  text-shadow: 0 0.4cqw 1.2cqw rgba(0, 0, 0, 0.45);
  transform: rotate(-6deg);
}

/* Channel 3 click: the footage tears and splits colour with the rest of the picture */
.tv.is-glitching .tv__video {
  animation: tv-glitch 0.6s steps(1) both, tv-glitch-color 0.6s steps(1) both;
}

@keyframes tv-glitch-color {
  0%   { filter: url(#crt-warp); }
  10%  { filter: url(#crt-warp) hue-rotate(90deg) saturate(3) contrast(1.4); }
  30%  { filter: url(#crt-warp) invert(0.15) saturate(2); }
  45%  { filter: url(#crt-warp) hue-rotate(-120deg) contrast(1.6); }
  60%  { filter: url(#crt-warp) brightness(1.6) saturate(0.3); }
  80%  { filter: url(#crt-warp) hue-rotate(40deg) saturate(2.5); }
  100% { filter: url(#crt-warp); }
}

/* Switching off: the picture squeezes into a bright line, then a dot, then black */
.tv.is-off .tv__beam,
.tv.is-off .tv__light,
.tv.is-off .tv__video,
.tv.is-off .tv__content,
.tv.is-off .tv__static,
.tv.is-off .tv__scanlines {
  animation: tv-off 0.55s ease-in forwards;
}

@keyframes tv-off {
  0%   { transform: scale(1, 1);        filter: brightness(1); opacity: 1; }
  45%  { transform: scale(1, 0.006);    filter: brightness(4); opacity: 1; }
  80%  { transform: scale(0.015, 0.006); filter: brightness(5); opacity: 1; }
  100% { transform: scale(0, 0);        filter: brightness(5); opacity: 0; }
}

/* Switching back on replays the warm-up, and the picture fades up once the tube is lit */
.tv.is-waking .tv__beam {
  animation: tv-on 1.6s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
}

.tv.is-waking .tv__content {
  animation: tv-wake 1.6s ease-out both;
}

@keyframes tv-wake {
  0%, 55% { opacity: 0; }
  100%    { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .tv__beam {
    animation: none;
    transform: none;
    filter: brightness(0.25);
  }

  .tv__title {
    animation: none;
    opacity: 1;
  }

  .tv__static {
    animation: none;
    opacity: 0.15;
  }

  .tv__roles {
    animation: none;
    opacity: 1;
  }

  .tv__roles span {
    transition: none;
  }

  .tv.is-glitching .tv__content,
  .tv.is-glitching .tv__video,
  .tv.is-glitching .tv__scanlines {
    animation: none;
  }

  .tv.is-off .tv__beam,
  .tv.is-off .tv__light,
  .tv.is-off .tv__video,
  .tv.is-off .tv__content,
  .tv.is-off .tv__static,
  .tv.is-off .tv__scanlines {
    animation: none;
    opacity: 0;
  }

  .tv.is-waking .tv__beam,
  .tv.is-waking .tv__content {
    animation: none;
  }

  .tv__spin-star { animation: none; }
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---------- What's Kyla Spinning (radio) ---------- */

.radio {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: calc(40 * var(--u)) 16px calc(160 * var(--u));
}

.radio__title {
  margin: 0 0 calc(40 * var(--u));
  font-family: var(--font-nav);
  font-weight: 400;
  font-synthesis: none;
  font-size: calc(72 * var(--u));
  letter-spacing: calc(4 * var(--u));
  text-align: center;
}

.radio__set {
  position: relative;
  width: calc(1100 * var(--u));
  max-width: 100%;
}

.radio__img {
  display: block;
  width: 100%;
  height: auto;
}

/* Sits exactly over the white cassette label in radio.jpg */
.radio__display {
  position: absolute;
  left: 31.2%;
  top: 41.3%;
  width: 37.5%;
  height: 26.4%;
  overflow: hidden;
  display: flex;
  align-items: center;
  background: #f6f4ef;
  box-shadow: inset 0 calc(4 * var(--u)) calc(6 * var(--u)) rgba(0, 0, 0, 0.18);
  container-type: inline-size;
}

/* Red stripe from the original label, kept as a nod to it */
.radio__display::after {
  content: "";
  position: absolute;
  left: 2%;
  right: 4%;
  bottom: 16%;
  height: 2px;
  background: #c4263f;
}

.radio__track {
  display: flex;
  flex: none;
  white-space: nowrap;
  font-family: var(--font-nav);
  font-size: 11cqw;
  letter-spacing: 0.6cqw;
  color: #1a1a1a;
  animation: radio-scroll var(--marquee-time, 30s) linear infinite;
}

.radio__track span {
  padding-right: 6cqw;
}

.radio__track span::after {
  content: "\2605"; /* star between songs */
  padding-left: 6cqw;
  font-size: 0.6em;
  vertical-align: 0.25em;
  color: #c4263f;
}

/* Radio off (after EJECT): the label goes blank */
.radio__display.is-off .radio__track,
.radio__display.is-off::after {
  opacity: 0;
}

.radio__track,
.radio__display::after {
  transition: opacity 0.3s ease;
}

/* Invisible hit areas laid over the knob and buttons in the photo */
.radio__btn {
  position: absolute;
  z-index: 1;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
  transition: background-color 0.1s ease;
}

.radio__btn.is-held,
.radio__btn:active {
  background: rgba(0, 0, 0, 0.18); /* reads as the button being pushed in */
}

.radio__btn:focus-visible {
  outline: 2px solid #000;
  outline-offset: 3px;
}

.radio__btn--tune  { left: 81.7%; top: 22.5%; width: 16%;   height: 58.3%; border-radius: 50%; }
.radio__btn--ffwd  { left: 61.1%; top: 78.2%; width: 14%;   height: 10.4%; border-radius: 2px; }
.radio__btn--vol   { left: 2.9%;  top: 25.5%; width: 15.25%; height: 53.4%; border-radius: 50%; }
.radio__btn--eject { left: 24.9%; top: 78.4%; width: 14.1%; height: 10.7%; border-radius: 2px; }

@keyframes radio-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

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

/* ---------- Lost partner (bottom of About) ---------- */

.lost {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(40 * var(--u));
  position: relative;
  z-index: 1;
  padding: calc(80 * var(--u)) 16px calc(80 * var(--u));
}

/* Kyla's pixel cowboy leaning on a cactus: six frames, he takes a drag and blows a smoke ring */
.lost__cowboy {
  flex: none;
  width: calc(260 * var(--u));
  aspect-ratio: 250 / 233;
  background: url("../assets/images/lost-cowboy.png") 0 0 / 600% 100% no-repeat;
  image-rendering: pixelated;
  animation: lost-smoke 6.5s steps(1) infinite;
}

@keyframes lost-smoke {
  0%     { background-position-x: 0; }
  25%    { background-position-x: 20%; }
  37.5%  { background-position-x: 40%; }
  50%    { background-position-x: 60%; }
  62.5%  { background-position-x: 80%; }
  75%    { background-position-x: 100%; }
}

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

/* Pixel western landscape footer with a rolling tumbleweed */
.landscape {
  --h: max(120px, 15vw);
  position: relative;
  height: var(--h);
  background: url("../assets/images/about/landscape.svg") center bottom / auto 100% repeat-x;
  image-rendering: pixelated;
  overflow: hidden;
  margin-top: calc(var(--h) * -28 / 36); /* the cowboy sits right on the ground line */
}

.landscape__tumbleweed {
  position: absolute;
  left: 0;
  bottom: calc(var(--h) * 7.6 / 36); /* rolls along the ground line */
  width: calc(var(--h) * 7 / 36);
  height: auto;
  image-rendering: pixelated;
  animation: tumble-across 14s linear infinite;
}

@keyframes tumble-across {
  0%   { transform: translateX(110vw) translateY(0) rotate(0deg); }
  10%  { transform: translateX(99vw) translateY(-40%) rotate(-90deg); }
  20%  { transform: translateX(88vw) translateY(0) rotate(-180deg); }
  30%  { transform: translateX(77vw) translateY(-25%) rotate(-270deg); }
  40%  { transform: translateX(66vw) translateY(0) rotate(-360deg); }
  50%  { transform: translateX(55vw) translateY(-45%) rotate(-450deg); }
  60%  { transform: translateX(44vw) translateY(0) rotate(-540deg); }
  70%  { transform: translateX(33vw) translateY(-30%) rotate(-630deg); }
  80%  { transform: translateX(22vw) translateY(0) rotate(-720deg); }
  90%  { transform: translateX(11vw) translateY(-35%) rotate(-810deg); }
  100% { transform: translateX(-12vw) translateY(0) rotate(-900deg); }
}

@media (prefers-reduced-motion: reduce) {
  .landscape__tumbleweed { animation: none; transform: translateX(70vw); }
}

/* Plain text beside the cowboy: three loading dots, then the line and a link back up */
.lost__bubble {
  position: relative;
  flex: none;
  width: calc(320 * var(--u)); /* fixed so the cowboy doesn't shift when the dots turn into words */
  font-family: var(--font-body);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.lost.is-talking .lost__bubble {
  opacity: 1;
}

.lost__dots {
  display: flex;
  gap: calc(10 * var(--u));
  padding: calc(12 * var(--u)) 0;
}

.lost__dots i {
  width: calc(10 * var(--u));
  height: calc(10 * var(--u));
  background: #1c1c1c;
  animation: lost-dot 0.9s steps(1) infinite;
}

.lost__dots i:nth-child(2) { animation-delay: 0.3s; }
.lost__dots i:nth-child(3) { animation-delay: 0.6s; }

@keyframes lost-dot {
  0%, 100% { opacity: 0.2; }
  33%      { opacity: 1; }
}

.lost__text,
.lost__links {
  display: none;
  margin: 0;
}

.lost.has-spoken .lost__dots { display: none; }
.lost.has-spoken .lost__text { display: block; animation: lost-in 0.3s ease both; }
.lost.has-links .lost__links { display: flex; animation: lost-in 0.3s ease both; }

.lost__text {
  font-size: calc(24 * var(--u));
  line-height: 1.3;
  white-space: nowrap;
}

.lost__links {
  gap: calc(32 * var(--u));
  margin-top: calc(16 * var(--u));
}

.lost__links a {
  position: relative;
  font-family: var(--font-nav);
  font-size: calc(24 * var(--u));
  letter-spacing: calc(2 * var(--u));
  color: inherit;
  text-decoration: none;
}

.lost__links a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(-3 * var(--u));
  height: max(1px, calc(1.5 * var(--u)));
  background: rgba(0, 0, 0, 0.3); /* same grow-from-the-middle underline as the nav and Back to All Work */
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.25s ease;
}

.lost__links a:hover::after,
.lost__links a:focus-visible::after {
  transform: scaleX(1);
}

@keyframes lost-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .lost__bubble { transition: none; }
  .lost__dots i { animation: none; opacity: 1; }
}

/* ---------- Work grid ---------- */

.work-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: calc(44 * var(--u)) calc(41 * var(--u));
  max-width: calc((380 * 3 + 41 * 2) * var(--u));
  /* centered top to bottom in the first screen, under the header
     (730u = three rows of tiles plus two gaps; 44u = the page's top padding) */
  margin: max(calc(24 * var(--u)), calc((100vh - var(--header-height) - 730 * var(--u)) / 2 - 44 * var(--u))) auto 0;
  padding: 0;
  list-style: none;
}

.work-card {
  position: relative;
  display: block;
  width: calc(380 * var(--u));
  aspect-ratio: 380 / 214;
  overflow: hidden;
  border: 0.5px solid var(--color-thumb-border);
}

.work-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: filter 0.3s ease, transform 0.3s ease;
}

/* Slight blur on hover. The tiny scale hides the soft edge blur leaves at the card border. */
.work-card:hover img,
.work-card:focus-visible img {
  filter: blur(6px);
  transform: scale(1.06);
}

/* Project name that fades in over the blurred thumbnail */
.work-card__label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 calc(16 * var(--u));
  font-family: var(--font-nav);
  font-size: calc(34 * var(--u));
  letter-spacing: calc(2.5 * var(--u));
  text-align: center;
  color: var(--color-ink);
  background: rgba(255, 255, 255, 0.45); /* soft wash so the name reads on any thumbnail */
  opacity: 0;
  transition: opacity 0.3s ease;
}

.work-card:hover .work-card__label,
.work-card:focus-visible .work-card__label {
  opacity: 1;
}

/* Crops match the Figma thumbnails */
.work-card img[src*="old-spice"] {
  object-position: center 44%;
}

.work-card--logo img {
  object-fit: contain;
}

.work-card--wordmark img {
  object-fit: contain;
  padding: 0 8%;
}

/* ---------- Smaller screens ---------- */

@media (max-width: 900px) {
  /* Phones and small tablets use fixed sizes and scroll normally. */
  :root {
    --u: 1px;
    --header-height: 79px;
  }

  .page {
    height: auto;
    min-height: calc(100vh - var(--header-height));
    overflow-y: visible;
    padding-bottom: 120px;
  }

  .site-header {
    gap: 16px;
    padding: 0 16px;
  }

  .wordmark {
    font-size: 24px;
    letter-spacing: 2.6px;
  }

  .site-nav ul {
    gap: 20px;
  }

  .site-nav a {
    font-size: 24px;
    letter-spacing: 2px;
  }

  .page-title {
    font-size: 44px;
    letter-spacing: 5px;
  }

  .project-gallery {
    grid-template-columns: 1fr; /* stack on phones so each page stays readable */
  }

  .project-gallery--portrait {
    grid-template-columns: 1fr 1fr;
  }

  .product-3d {
    height: 70vh;
  }

  .logo-parts {
    grid-template-columns: 1fr;
    gap: 40px;
    max-width: 420px;
    margin-top: 40px;
  }

  .logo-parts__item img {
    width: 200px;
  }

  .logo-parts + .project-nav { margin-top: 56px; }

  .logo-parts__title {
    margin-top: 12px;
    font-size: 28px;
  }

  .logo-parts__copy {
    font-size: 16px;
  }

  .product-3d__hint {
    font-size: 16px;
  }

  .gallery-row {
    flex-direction: column;
  }

  .lightbox__image {
    max-width: 100vw;
  }

  .lightbox__arrow {
    top: auto;
    bottom: 4px;
    transform: none;
    font-size: 48px;
  }

  .project-intro {
    font-size: 17px;
    letter-spacing: 1.5px;
  }

  /* Phones: star and label on one line, copy underneath */
  .explainer {
    grid-template-columns: auto 1fr;
    column-gap: 10px;
    row-gap: 22px;
    margin-top: 12px;
  }

  .explainer__row::before { height: calc(26px * 0.7); font-size: 22px; }
  .explainer__label { font-size: 26px; letter-spacing: 1.2px; }
  .explainer__copy { grid-column: 1 / -1; margin-top: 14px; font-size: 16px; line-height: 1.6; }

  .ornament {
    width: 110px;
    height: 106px;
  }

  .page--about {
    padding-bottom: 0;
  }

  .about-hero {
    height: auto;
    padding: 120px 0 40px;
  }

  .about-me {
    padding: 60px 16px 80px;
  }

  .about-me__inner {
    flex-direction: column;
    gap: 28px;
  }

  .about-me__frame {
    padding: 50px;
  }

  .about-me__frame .ornament {
    width: 80px;
    height: 77px;
  }

  .about-me__photo {
    width: min(270px, calc(100vw - 132px));
  }

  .about-me__copy {
    font-size: 17px;
  }

  .about-me__heading {
    font-size: 26px;
  }

  .about-me__links a {
    font-size: 16px;
  }

  .resume-btn {
    margin-top: 24px;
    padding: 9px 32px 7px;
    border-radius: 10px;
    font-size: 21px;
  }

  .radio__title {
    font-size: 30px;
  }

  .lost {
    flex-direction: column;
    gap: 36px;
  }

  .lost__cowboy { width: 180px; }

  .lost { padding-bottom: 40px; }
  .landscape { margin-top: 0; }

  .lost__bubble { width: auto; text-align: center; }
  .lost__dots { justify-content: center; }
  .lost__links { justify-content: center; }

  .lost__text { font-size: 18px; }
  .lost__links a { font-size: 20px; }
  .lost__dots i { width: 8px; height: 8px; }


  .work-grid {
    margin-top: 100px; /* clears the smaller corner ornaments */
    padding: 0 16px;
  }

  .work-grid li,
  .work-card {
    width: 100%;
    max-width: 380px;
  }
}

@media (max-width: 480px) {
  .wordmark {
    font-size: 17px;
    letter-spacing: 1.3px;
  }

  .site-nav ul {
    gap: 12px;
  }

  .site-nav a {
    font-size: 18px;
    letter-spacing: 1px;
  }
}

/* ---------- Rodeo: wrangling animation + gallery ---------- */

.page--rodeo {
  height: auto;
  overflow-y: visible;
  padding: calc(46 * var(--u)) 0 calc(260 * var(--u)); /* lane top lines up with the ornament tops */
}

.rodeo-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(56 * var(--u));
}

/* lane fenced by the two top ornaments: its sides sit on the ornaments' inner
   edges and its top on their tops, so the rider appears out of the left one
   and vanishes into the right one without ever drawing over them */
.wrangle-track {
  align-self: stretch;
  margin: 0 calc(167 * var(--u)) 0 calc(170 * var(--u));
  overflow: hidden;
  container-type: inline-size;
  /* soft edges: he fades in from the left ornament and out into the right one */
  -webkit-mask-image: linear-gradient(to right, transparent 0%, rgba(0,0,0,.08) 6%, rgba(0,0,0,.3) 13%, rgba(0,0,0,.65) 21%, #000 30%, #000 70%, rgba(0,0,0,.65) 79%, rgba(0,0,0,.3) 87%, rgba(0,0,0,.08) 94%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0%, rgba(0,0,0,.08) 6%, rgba(0,0,0,.3) 13%, rgba(0,0,0,.65) 21%, #000 30%, #000 70%, rgba(0,0,0,.65) 79%, rgba(0,0,0,.3) 87%, rgba(0,0,0,.08) 94%, transparent 100%);
}

.page--rodeo .ornament {
  z-index: 2;
}

/* wrangle.png is eight 114 x 44 pixel frames side by side: four galloping with the
   lasso overhead, two throwing it, and two catching the horse (only on click).
   The rider rides on .wrangle; the frames play on its ::before so a click can swap
   the frames without restarting the ride. */
.wrangle {
  width: min(calc(570 * var(--u)), 70vw);
  aspect-ratio: 114 / 44;
  cursor: pointer;
  animation: ride 9s linear infinite;
}

.wrangle::before {
  content: "";
  display: block;
  width: 100%;
  height: 100%;
  background: url("../assets/images/rodeo/wrangle.png") 0 0 / 800% 100% no-repeat;
  image-rendering: pixelated;
  animation: wrangle 9s step-end infinite;
  animation-delay: var(--wrangle-sync, 0s); /* set by the click code so the frames rejoin the ride in step */
}

/* Clicked: throw, the loop lands on the horse, then the rope pulls tight for about a second */
.wrangle.is-catching::before {
  animation: wrangle-catch 1.65s step-end forwards;
}

@keyframes wrangle-catch {
  0%   { background-position-x: 57.143%; }
  12%  { background-position-x: 71.429%; }
  24%  { background-position-x: 85.714%; }
  39%  { background-position-x: 100.000%; }
  100% { background-position-x: 100.000%; }
}

@keyframes ride {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100cqw); }
}

/* one 9s pass, in step with the ride: frames 0-3 gallop with the lasso
   swinging overhead, then near the right ornament he throws it (frames 4-5)
   as he fades out; the rope never lands on the horse unless you click him */
@keyframes wrangle {
  0.000% { background-position-x: 0.000%; }
  1.562% { background-position-x: 14.286%; }
  3.125% { background-position-x: 28.571%; }
  4.688% { background-position-x: 42.857%; }
  6.250% { background-position-x: 0.000%; }
  7.812% { background-position-x: 14.286%; }
  9.375% { background-position-x: 28.571%; }
  10.938% { background-position-x: 42.857%; }
  12.500% { background-position-x: 0.000%; }
  14.062% { background-position-x: 14.286%; }
  15.625% { background-position-x: 28.571%; }
  17.188% { background-position-x: 42.857%; }
  18.750% { background-position-x: 0.000%; }
  20.312% { background-position-x: 14.286%; }
  21.875% { background-position-x: 28.571%; }
  23.438% { background-position-x: 42.857%; }
  25.000% { background-position-x: 0.000%; }
  26.562% { background-position-x: 14.286%; }
  28.125% { background-position-x: 28.571%; }
  29.688% { background-position-x: 42.857%; }
  31.250% { background-position-x: 0.000%; }
  32.812% { background-position-x: 14.286%; }
  34.375% { background-position-x: 28.571%; }
  35.938% { background-position-x: 42.857%; }
  37.500% { background-position-x: 0.000%; }
  39.062% { background-position-x: 14.286%; }
  40.625% { background-position-x: 28.571%; }
  42.188% { background-position-x: 42.857%; }
  43.750% { background-position-x: 0.000%; }
  45.312% { background-position-x: 14.286%; }
  46.875% { background-position-x: 28.571%; }
  48.438% { background-position-x: 42.857%; }
  50.000% { background-position-x: 0.000%; }
  51.562% { background-position-x: 14.286%; }
  53.125% { background-position-x: 28.571%; }
  54.688% { background-position-x: 42.857%; }
  56.250% { background-position-x: 0.000%; }
  57.812% { background-position-x: 14.286%; }
  59.375% { background-position-x: 28.571%; }
  60.938% { background-position-x: 42.857%; }
  62.500% { background-position-x: 0.000%; }
  64.062% { background-position-x: 14.286%; }
  65.625% { background-position-x: 28.571%; }
  67.188% { background-position-x: 42.857%; }
  68.750% { background-position-x: 0.000%; }
  70.312% { background-position-x: 14.286%; }
  71.875% { background-position-x: 28.571%; }
  73.438% { background-position-x: 42.857%; }
  75.000% { background-position-x: 0.000%; }
  76.562% { background-position-x: 14.286%; }
  78.125% { background-position-x: 28.571%; }
  79.688% { background-position-x: 42.857%; }
  81.250% { background-position-x: 0.000%; }
  82.812% { background-position-x: 14.286%; }
  84.375% { background-position-x: 57.143%; }
  85.938% { background-position-x: 71.429%; }
  87.500% { background-position-x: 57.143%; }
  89.062% { background-position-x: 71.429%; }
  90.625% { background-position-x: 57.143%; }
  92.188% { background-position-x: 71.429%; }
  93.750% { background-position-x: 57.143%; }
  95.312% { background-position-x: 71.429%; }
  96.875% { background-position-x: 57.143%; }
  98.438% { background-position-x: 71.429%; }
}

.rodeo-title {
  margin: 0;
  padding: 0 16px;
  font-family: var(--font-nav);
  font-weight: 400;
  font-size: calc(64 * var(--u));
  letter-spacing: calc(3 * var(--u));
  text-align: center;
}

.rodeo-intro {
  margin: calc(-36 * var(--u)) 0 0; /* sits close under the headline */
  padding: 0 16px;
  font-family: var(--font-body);
  font-size: calc(26 * var(--u));
  line-height: 1.5;
  text-align: center;
}

.rodeo-gallery {
  max-width: calc(1260 * var(--u));
  margin: calc(90 * var(--u)) auto 0;
  padding: 0 16px;
}

/* masonry-style columns so posters and landscape pieces keep their shapes */
.rodeo-gallery__grid {
  columns: 3;
  column-gap: calc(28 * var(--u));
  margin: 0;
  padding: 0;
  list-style: none;
}

.rodeo-gallery__item {
  break-inside: avoid;
  margin-bottom: calc(28 * var(--u));
}

.rodeo-gallery__item img {
  width: 100%;
  height: auto;
}

@media (prefers-reduced-motion: reduce) {
  .wrangle { animation: none; margin: 0 auto; cursor: default; }
  .wrangle::before, .wrangle.is-catching::before { animation: none; background-position-x: 0; }
}

@media (max-width: 900px) {
  .page--rodeo { padding: 37px 0 80px; }
  .wrangle-track { margin: 0 75px 0 78px; }
  .wrangle { width: 50vw; }
  .rodeo-hero { gap: 28px; }
  .rodeo-title { font-size: 30px; letter-spacing: 1.5px; }
  .rodeo-intro { margin-top: -16px; font-size: 16px; }
  .rodeo-gallery { margin-top: 40px; }
  .rodeo-gallery__grid { columns: 2; column-gap: 12px; }
  .rodeo-gallery__item { margin-bottom: 12px; }
}

@media (max-width: 480px) {
  .rodeo-gallery__grid, .rodeo-gallery__grid--big { columns: 1; }
}

.rodeo-gallery__item img {
  cursor: zoom-in;
}

/* pieces pop up slightly on hover */
.rodeo-gallery__item > img,
.sizzle {
  display: block;
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .rodeo-gallery__item > img:hover,
  .sizzle:hover {
    transform: translateY(-6px) scale(1.02);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.18);
  }
}

/* Swing ride and Red Dead infographic run across the whole gallery */
.rodeo-gallery__item--feature {
  column-span: all;
}

/* Red Dead infographic shares a row with a photo; each flex value is the image's width / height,
   so both come out the same height and the row fills the full width */
.rodeo-gallery__row {
  display: flex;
  gap: calc(28 * var(--u));
}

.rodeo-gallery__row > img {
  min-width: 0;
  width: 100%;
}

@media (max-width: 900px) {
  .rodeo-gallery__row { gap: 12px; }
}

/* Videos scattered through the gallery: a YouTube embed and two of Kyla's own clips */
.rodeo-gallery__item--video iframe,
.rodeo-gallery__item--video video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  background: #000;
}

/* packed layout (js/main.js): photos fill in around videos that span two columns */
.rodeo-gallery__grid.is-packed {
  position: relative;
  columns: auto;
}

.rodeo-gallery__grid.is-packed > .rodeo-gallery__item {
  position: absolute;
  margin: 0;
}

/* video thumbnails: a short muted sizzle plays on its own, click plays the full video */
.sizzle {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  padding: 0;
  border: 0;
  background: #000;
  cursor: pointer;
  overflow: hidden;
}

.sizzle img,
.sizzle__preview,
.sizzle__preview iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover; /* crops the letterbox off YouTube's 4:3 thumbnails */
  border: 0;
}

.sizzle__preview {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.sizzle__preview.is-playing {
  opacity: 1;
}

.sizzle__preview iframe {
  /* overscan so YouTube's title bar and logo sit outside the frame */
  inset: -60px 0;
  height: calc(100% + 120px);
}

/* the featured pieces sit two to a row, so they show larger than the rest */
.rodeo-gallery__grid--big {
  columns: 2;
}

/* ---------- Growing vine ornaments (js/vines.js) ---------- */
/* At rest the vine is the regular ornament. Hovering a corner regrows it from
   its corner, the buds popping open as the vine reaches them. */
.vine-ornament {
  display: block;
  pointer-events: auto; /* needed for the hover */
}

.vine {
  display: block;
  width: 100%;
  height: 100%;
  fill: var(--color-ink);
  overflow: visible;
}

.vine__bud {
  transform-box: fill-box;
  transform-origin: center;
}

.vine-ornament.is-growing .vine {
  animation: vine-grow 1.6s ease-out both;
}

.vine-ornament.is-growing .vine__bud {
  animation: vine-bud 0.45s ease-out both;
  animation-delay: calc(var(--at) * 1.4s); /* blooms once the vine reaches it */
}

@keyframes vine-grow {
  from { clip-path: circle(9% at 88.9% 90.1%); }
  to   { clip-path: circle(85% at 88.9% 90.1%); }
}

@keyframes vine-bud {
  0%   { transform: scale(0); }
  65%  { transform: scale(1.15); }
  100% { transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .vine-ornament.is-growing .vine,
  .vine-ornament.is-growing .vine__bud { animation: none; }
}

/* Copyright line at the very bottom of every page */
/* Footer on every page: contact links over the copyright line */
.site-footer__links {
  display: flex;
  justify-content: center;
  gap: calc(48 * var(--u));
  padding-top: calc(32 * var(--u));
}

.site-footer__links a {
  position: relative;
  font-family: var(--font-nav);
  font-size: calc(24 * var(--u));
  letter-spacing: calc(2 * var(--u));
  color: inherit;
  text-decoration: none;
}

.site-footer__links a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(-3 * var(--u));
  height: max(1px, calc(1.5 * var(--u)));
  background: rgba(0, 0, 0, 0.3); /* same grow-from-the-middle underline as the nav */
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.25s ease;
}

.site-footer__links a:hover::after,
.site-footer__links a:focus-visible::after {
  transform: scaleX(1);
}

/* Project pages: the links line up with the Project / Role copy instead of centring */
.page--project ~ .site-footer .site-footer__links {
  justify-content: flex-start;
  padding-left: calc(119.3 * var(--u)); /* page gutter + star column: same edge as the Project / Role copy */
}

@media (max-width: 900px) {
  .page--project ~ .site-footer .site-footer__links { padding-left: 16px; } /* phones: copy runs full width from the gutter */
}

.copyright {
  margin: 0;
  padding: calc(16 * var(--u)) 16px calc(28 * var(--u));
  font-family: var(--font-body);
  font-size: calc(14 * var(--u));
  text-align: center;
  color: rgba(0, 0, 0, 0.55);
}

@media (max-width: 900px) {
  .copyright { font-size: 12px; padding: 12px 16px 24px; }
  .site-footer__links { gap: 32px; padding-top: 24px; }
  .site-footer__links a { font-size: 18px; }
}
