:root{
  --wall: #fffde9;
  --wall-shadow: #f0efec;
  --ink: #1c1a17;
  --ink-soft: #6b6660;
  --line: #e4e1db;
  --frame-wood: #2b2521;
  --frame-wood-light: #4a3f37;
  --mat: #fbfaf7;
  --accent: #f0805f; /* the orange actually used sitewide — doodles, scribbles, .dot-a */
  --accent2: #2f8f7f;
  --accent3: #f5c518;
  --rail: #c9c4ba;
}

@font-face{
  font-family: 'Liberation Sans';
  src: url('fonts/LiberationSans-Regular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face{
  font-family: 'Liberation Sans';
  src: url('fonts/LiberationSans-Bold.ttf') format('truetype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face{
  font-family: 'Liberation Sans';
  src: url('fonts/LiberationSans-Italic.ttf') format('truetype');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face{
  font-family: 'Liberation Sans';
  src: url('fonts/LiberationSans-BoldItalic.ttf') format('truetype');
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}
@font-face{
  font-family: 'Bagnard';
  src: url('fonts/Bagnard.otf') format('opentype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face{
  font-family: 'Sentient';
  src: url('fonts/Sentient-Bold.woff2') format('woff2'),
       url('fonts/Sentient-Bold.otf') format('opentype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face{
  font-family: 'Satoshi';
  src: url('fonts/Satoshi-Regular.woff2') format('woff2'),
       url('fonts/Satoshi-Regular.otf') format('opentype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face{
  font-family: 'Satoshi';
  src: url('fonts/Satoshi-Black.woff2') format('woff2'),
       url('fonts/Satoshi-Black.otf') format('opentype');
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}

*{ box-sizing: border-box; }

html, body{
  margin: 0;
  padding: 0;
  background: var(--wall);
  color: var(--ink);
  font-family: 'M PLUS 1', 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}

/* ScrollSmoother manages its own wrapper/content sizing via JS at runtime —
   these just need to be free to grow to whatever height the pinned scroll
   distance requires, so no fixed height here. */
.page{
  position: relative;
  background: var(--wall);
}

/* ===================== persistent site logo / home button ===================== */
/* Hidden while the landing screen is in view; slides in from the left, at a
   fixed tilt, once the user has fully scrolled past it (see script.js). */

.site-logo{
  position: fixed;
  top: 28px;
  left: 28px;
  width: 60px;
  height: 60px;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  z-index: 40;
  opacity: 0;
  pointer-events: none;
  transform: translateX(-160px) rotate(-360deg);
  transition: transform 0.9s ease-out, opacity 0.4s ease;
}
.site-logo img{
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.site-logo.visible{
  opacity: 1;
  pointer-events: auto;
  transform: translateX(0) rotate(0deg);
}

/* ---- top-right nav — plain "Connect" label + social icons, no card ---- */
/* height matches .site-logo (60px) so both drop-in elements share a baseline */

.top-nav{
  position: fixed;
  top: 28px;
  right: 32px;
  height: 60px;
  display: flex;
  align-items: center;
  gap: 14px;
  z-index: 40;
  pointer-events: none;
  transform: translateY(-160px);
  transition: transform 0.6s ease-out;
}
.top-nav.visible{
  pointer-events: auto;
  transform: translateY(0);
}

.top-nav-connect{
  font-family: 'M PLUS 1', 'Inter', sans-serif;
  font-size: 1.1rem;
  letter-spacing: 0.05em;
  color: var(--ink);
}

.top-nav-socials{
  display: flex;
  align-items: center;
  gap: 10px;
}
.top-nav-socials img{ width: 28px; height: 28px; display: block; }
.top-nav-socials a{ line-height: 0; }

/* ---- mobile-only "Connect" footer — hidden entirely on desktop, .top-nav
   already covers that case there. See the mobile breakpoint for the actual
   look: a plain block at the bottom-left of the page. ---- */
.mobile-connect-footer{ display: none; }

/* ---- "Ask me about" easter eggs: pre-2018 Kanye (own widget, below) and
   the plain topic-trigger buttons (each pops a one-liner into .about-message,
   under the About Me photos) share this reset. Kanye stays permanently
   underlined as the one "obvious" easter egg; the topic buttons are plain
   text until hovered/focused, when the underline draws itself in. ---- */
.kanye-trigger,
.topic-trigger{
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
}
.kanye-trigger,
.topic-trigger{
  text-decoration: underline solid;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
}
.kanye-trigger{ text-decoration-color: var(--accent); }
.kanye-trigger:hover{ color: var(--accent); }

/* Same underline as Kanye's — same color, thickness, offset — just invisible
   until hovered/focused instead of permanent, animated in via the one part
   of a text-decoration that transitions smoothly across browsers. Text color
   deliberately stays put here (unlike Kanye's own hover) — just the
   underline, not a color highlight over the whole word. */
.topic-trigger{
  text-decoration-color: transparent;
  transition: text-decoration-color 0.2s ease;
}
.topic-trigger:hover,
.topic-trigger:focus-visible{
  text-decoration-color: var(--accent);
}

/* Now-playing widget lives inside .top-nav (fixed, already outside
   #smooth-content — see the comment above .site-logo), so it appears to the
   left of "Connect" and rides along with the nav's own show/hide-on-scroll. */
.kanye-nowplaying{
  display: flex;
  align-items: center;
  gap: 6px;
  margin-right: 10px; /* extra breathing room before "Connect", beyond .top-nav's own gap */
}
.kanye-nowplaying[hidden]{ display: none; }

/* .kanye-vinyl-wrap is the hover/focus target and tooltip's positioning
   context — it does NOT clip, unlike .kanye-vinyl inside it, so the tooltip
   (which needs to render outside the circle, to its left) isn't cut off. */
.kanye-vinyl-wrap{
  position: relative;
  flex-shrink: 0;
}

.kanye-vinyl{
  position: relative;
  width: 46px; /* a bit smaller than .site-logo's 60px — this widget stays compact */
  height: 46px;
  border-radius: 50%;
  overflow: hidden; /* clips .kanye-vinyl-art to a circle */
  box-shadow: 0 2px 6px rgba(0,0,0,0.35);
  animation: kanye-spin 3s linear infinite;
  animation-play-state: paused;
}
.kanye-vinyl.is-spinning{ animation-play-state: running; }
.kanye-vinyl-art{
  /* Oversized + centered rather than a plain object-fit:cover: some of these
     YouTube thumbnails (e.g. the "Audio" uploads) have a decorative border
     baked around a smaller centered cover image, which a plain cover-crop
     doesn't remove. Zooming in like this crops that border away for those,
     at the cost of slightly tighter framing on thumbnails that were already
     full-bleed. */
  position: absolute;
  top: 50%; left: 50%;
  width: 150%;
  height: 150%;
  object-fit: cover;
  transform: translate(-50%, -50%);
}

@keyframes kanye-spin{ to{ transform: rotate(360deg); } }

.kanye-vinyl-tooltip{
  position: absolute;
  top: 50%;
  right: 100%;
  margin-right: 10px;
  transform: translateY(-50%);
  background: var(--wall);
  border: 2px solid #000;
  border-radius: 6px;
  padding: 4px 10px;
  font-family: 'M PLUS 1', 'Inter', sans-serif;
  font-size: 0.8rem;
  color: var(--ink);
  white-space: nowrap;
  box-shadow: 0 4px 10px rgba(0,0,0,0.15);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
}
.kanye-vinyl-wrap:hover .kanye-vinyl-tooltip,
.kanye-vinyl-wrap:focus-visible .kanye-vinyl-tooltip{
  opacity: 1;
}

.kanye-close{
  width: 16px;
  height: 16px;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  color: var(--accent);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.kanye-close svg{ width: 12px; height: 12px; }
.kanye-close:hover{ filter: brightness(0.85); }

.kanye-playpause,
.kanye-volume{
  width: 30px;
  height: 30px;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  color: var(--accent);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.kanye-playpause svg,
.kanye-volume svg{ width: 24px; height: 24px; }
.kanye-playpause:hover,
.kanye-volume:hover{ filter: brightness(0.85); }

.kanye-pause-icon{ display: inline; }
.kanye-play-icon{ display: none; }
.kanye-playpause.is-paused .kanye-pause-icon{ display: none; }
.kanye-playpause.is-paused .kanye-play-icon{ display: inline; }

.kanye-vol-slash{ display: none; }
.kanye-volume.is-muted .kanye-vol-wave{ display: none; }
.kanye-volume.is-muted .kanye-vol-slash{ display: inline; }

/* Off-screen host for the real YouTube IFrame player — kept tiny and
   positioned outside the viewport rather than display:none, since some
   browsers pause playback on a display:none video. */
.kanye-yt-host{
  position: fixed;
  left: -9999px;
  top: -9999px;
  width: 2px;
  height: 2px;
  overflow: hidden;
}

/* ===================== GALLERY ===================== */
/* Desktop: pinned by ScrollTrigger, .track is translated on the x-axis by a
   scrubbed GSAP tween (see script.js) — no native scrolling happens here at
   all, GSAP owns the motion. Mobile: falls back to a plain vertical stack,
   see the media query at the bottom of this file. */

.gallery{
  position: relative;
  height: 100vh;
  width: 100vw;
  overflow: hidden;
  background: var(--wall);
}

.track{
  position: relative;
  display: flex;
  align-items: center;
  height: 100%;
  width: max-content;
  padding: 0 6vw;
  gap: 6vw;
  will-change: transform;
}

/* ---- landing screen — reference: Figma "Sanjeev Varma Portfolio Page" ---- */
.landing{
  position: relative;
  flex-shrink: 0;
  width: 100vw;
  height: 100%;
  margin-left: -6vw; /* cancels .track's left padding so this first screen is edge-to-edge */
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Keeps the composition below at the Figma canvas's 1440:900 ratio, letterboxed
   to fit whatever the viewport's actual ratio is, so .landing can center it —
   without this, a viewport taller or wider than 1440:900 left the vh/vw-pinned
   content stuck near the top instead of centered. Children below are positioned
   in cqw/cqh (percent of THIS element), which is what the original vw/vh values
   already meant when the viewport itself was assumed to be exactly 1440x900. */
.landing-canvas{
  container-type: size;
  position: relative;
  width: min(100%, 160vh);
  aspect-ratio: 1440 / 900;
}

.landing-name{
  position: absolute;
  left: 8.9cqw;
  top: 8.2cqh;
  margin: 0;
  font-family: 'Satoshi', 'Inter', 'Liberation Sans', sans-serif;
  font-weight: 800;
  font-size: clamp(2.2rem, 8.3cqw, 7.5rem);
  line-height: 1.05;
  letter-spacing: 0.08em;
  color: var(--ink);
  white-space: nowrap;
}

.landing-bio{
  position: absolute;
  left: 8.9cqw;
  top: 52.6cqh;
  width: clamp(200px, 21cqw, 320px);
  margin: 0;
  font-family: 'M PLUS 1', 'Inter', sans-serif;
  font-size: clamp(0.95rem, 1.95cqw, 1.2rem);
  line-height: 1.5;
  letter-spacing: 0.05em;
  color: var(--ink);
}

.landing-sun{
  position: absolute;
  left: 32.1cqw;
  top: 32.7cqh;
  width: 37.1cqw;
  max-width: 534px;
  min-width: 220px;
  height: auto;
  pointer-events: none;
  animation: sun-spin 65s linear infinite;
}

@keyframes sun-spin{
  from{ transform: rotate(0deg); }
  to{ transform: rotate(360deg); }
}

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

.landing-cta{
  position: absolute;
  left: 74.4cqw;
  top: 57.4cqh;
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font-family: 'M PLUS 1', 'Inter', sans-serif;
  font-size: clamp(1rem, 1.74cqw, 1.4rem);
  letter-spacing: 0.05em;
  line-height: 1.1;
  color: var(--ink);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}

.landing-cta-arrow-wrap{ display: contents; } /* no-op on desktop — see the mobile override */
.landing-cta-arrow{
  height: 0.9em; /* scales with the button's own text size */
  width: auto;
}

/* On a narrow *desktop* window (still fine-pointer, so still horizontally
   pinned — see the matchMedia guard in script.js) the bio's original spot
   beside the sun runs into the sun's left edge. Push the title up and let
   the bio sit in the space that frees up above the sun instead, widening it
   so it wraps to fewer lines and clears the sun's top edge. Sun/cta are left
   alone — they aren't part of the overlap. */
@container (max-width: 800px){
  .landing-name{ top: 5cqh; }
  .landing-bio{ top: 18cqh; width: min(60cqw, 420px); }
}

/* ===================== about me — reference: Figma "Sanjeev Varma
   Portfolio Page", Page 3, node 41:153 ===================== */
/* Same full-screen-slide + letterboxed-canvas pattern as .landing (see its
   comment above) — keeps the rotated photo collage centered and correctly
   proportioned at any viewport instead of pinned to raw vw/vh. Unlike
   .landing this isn't the track's first child, so it doesn't need the
   negative-margin edge-to-edge trick: the track's own gap on either side is
   invisible against the shared cream background. */
.about-panel{
  position: relative;
  flex-shrink: 0;
  width: 100vw;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.about-canvas{
  container-type: size;
  position: relative;
  width: min(100%, 160vh);
  aspect-ratio: 1440 / 900;
}

/* ---- photo + doodle collage — the user's own Figma Smart Animate export,
   inlined verbatim in index.html (see the comment there). Covers the 5
   photos AND all 18 doodle accents AND the "Sanjeev" scribble as one unit,
   so this single box replaces what used to be ~24 separately-positioned
   elements. Sized/centred to the tight bounding box of that original
   combined layout (Figma "Group 9", node 46:264 — computed, not eyeballed):
   x=79.326,y=98,w=563.111,h=704.094 at the 1440x900 reference. The SVG's own
   viewBox is a 512x512 square, so it's sized by width with aspect-ratio:1 —
   its rendered height comes out a bit shorter than the original portrait
   region rather than distorting or cropping the square source. Playback
   (pause on load, replay on scroll-into-view) is handled by the inline
   <script> + script.js via the SVG DOM's pauseAnimations()/
   unpauseAnimations() — only possible because it's inlined, not
   <img src="...">, which is why it lives directly in the markup. */
.about-photo-cluster{
  position: absolute;
  left: 25.062cqw;
  top: 50.006cqh;
  width: 39.105cqw;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.about-photo-cluster svg{
  display: block;
  width: 100%;
  height: 100%;
}

/* ---- "Ask me about" topic messages — one shared line, centered under the
   photo cluster, swapped in each time a topic button is clicked. */
.about-message{
  position: absolute;
  left: 25.062cqw; /* same horizontal center as .about-photo-cluster */
  top: 80cqh;
  transform: translateX(-50%);
  width: 42cqw;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  font-family: 'M PLUS 1', 'Inter', sans-serif;
  font-weight: 600;
  font-size: clamp(0.6rem, 1.1cqw, 0.95rem);
  line-height: 1.3;
  color: var(--accent);
  text-align: center;
}
.about-message[hidden]{ display: none; }
/* The LeBron gif sits noticeably taller than a line of text, so it gets its
   own (higher) position — otherwise it either overlaps the photo cluster
   above at the text's top, or sits with an oddly large gap below it. */
.about-message.has-photo{ top: 74cqh; }
.about-message-photo{
  /* .about-canvas keeps a locked 1440:900 ratio, so cqw and cqh always scale
     together — the earlier min(cqw,cqh) here didn't actually add anything.
     The real bug: .about-message sits at top:84cqh, so anything sized past
     16cqh tall pushes below 100cqh — i.e. off the bottom of the panel —
     no matter the window's size or aspect ratio. 13cqh leaves a margin. */
  width: clamp(70px, 13cqh, 180px);
  height: clamp(70px, 13cqh, 180px);
  object-fit: cover;
  border-radius: 8px;
  flex-shrink: 0;
}
.about-message-photo[hidden],
.about-message-text[hidden]{ display: none; }
.about-message-text a{
  color: inherit;
  text-decoration: underline solid;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
}

.about-copy{
  position: absolute;
  left: 51.6cqw;
  top: 39.33cqh;
  width: 42.2cqw;
}

.about-title-scribble{
  display: block;
  width: 38.85%; /* 236px of the copy block's 608px reference width */
  aspect-ratio: 5.351; /* the cropped viewBox's own ratio — see the comment in index.html */
  margin: 0 0 1.4cqh;
}
.about-title-scribble svg{
  display: block;
  width: 100%;
  height: 100%;
}

.about-copy p{
  margin: 0 0 0.6cqh;
  font-family: 'M PLUS 1', 'Inter', sans-serif;
  font-size: clamp(0.85rem, 1.15cqw, 1.0625rem);
  line-height: 1.6;
  letter-spacing: 0.02em;
  color: var(--ink);
}
.about-copy p:last-child{ margin-bottom: 0; }
.usf-logo-inline{
  height: 1.5em; /* matches the surrounding text's letter height at any viewport, scaled up */
  width: auto; /* preserves the PNG's own aspect ratio */
  vertical-align: middle;
  margin-left: 0.35em;
}
.about-copy strong{ font-weight: 700; }

/* ---- outro — reference: Figma "Sanjeev Varma Portfolio Page", Page 4,
   node 57:30. Starburst frame sits at 904,116 (736x736) and the text box at
   1040,357, both on the same 1440:900 canvas used by .landing/.about-panel. ---- */
.outro-panel{
  position: relative;
  flex-shrink: 0;
  width: 100vw;
  height: 100%;
  /* The burst doesn't start until 66.778cqw into its own canvas, so the plain
     6vw track gap leaves a long blank run of shared cream after the last card.
     Pulling the panel left (like .landing cancels the track's leading padding)
     closes that dead run without moving the burst within its own canvas. This
     margin is bigger than the natural gap, so the panel's own (blank) leading
     edge overlaps the previous card's box — pointer-events:none lets clicks
     fall through that dead region to the card underneath, since nothing in
     .outro-panel itself is ever interactive. */
  margin-left: -42vw;
  margin-right: -6vw; /* cancels .track's right padding, mirroring .landing on the left */
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden; /* the starburst is meant to run off the right edge, not shrink to fit */
  pointer-events: none;
}

.outro-canvas{
  container-type: size;
  position: relative;
  width: min(100%, 160vh);
  aspect-ratio: 1440 / 900;
}

.outro-burst{
  position: absolute;
  left: 66.778cqw;
  top: 12.889cqh;
  width: 51.111cqw;
  height: 81.778cqh;
}

.outro-thanks{
  position: absolute;
  left: 76.222cqw;
  top: 39.667cqh;
  margin: 0;
  font-family: 'Satoshi', 'Inter', 'Liberation Sans', sans-serif; /* same face as .landing-name */
  font-weight: 400; /* .landing-name is 800 — same face, not bold */
  font-size: clamp(1.5rem, 3.764cqw, 3.4rem);
  line-height: 1.15;
  color: var(--ink);
}

/* ---- each painting — reference: Figma "Sanjeev Varma Portfolio Page",
   Page 2, node 29:136 (card 36:144). Card is 601x319 at 1440 wide, so its
   width/text scale tracks that ~41.8vw ratio; text is left-aligned to the
   image, not centered. ---- */
.frame-wrap{
  position: relative;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 41.8vw;
  min-width: 340px;
  max-width: 620px;
  padding-top: 4.5rem;
}

/* Wraps the image + title + description in one link, per the Figma card —
   the meta line below (year/type + dot) is a sibling, outside this link,
   and stays plain, non-interactive text. */
.frame-card-link{
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

/* The thin mat border behind the image, per node 36:144 — matches the
   page's cream background (var(--wall)) instead of Figma's gray so the
   card sits flush with the rest of the site. */
.frame{
  width: 100%;
  background: var(--wall);
  padding: 7px;
  border-radius: 15px;
}

.canvas{
  width: 100%;
  aspect-ratio: 587 / 308;
  border-radius: 15px;
  overflow: hidden;
}

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

.plaque{
  margin-top: 1.4rem;
  text-align: left;
}

.plaque h2{
  font-family: 'M PLUS 1', 'Inter', sans-serif;
  font-weight: 400;
  font-size: 1.375rem;
  color: var(--ink);
  margin: 0 0 0.4rem;
}

.plaque-desc{
  font-size: 0.9375rem;
  line-height: 1.4;
  color: #6a6a6a;
  margin: 0;
}

/* Sits outside .frame-card-link — stays plain, non-clickable text even
   though everything above it (image, title, description) is a link. */
.plaque-meta{
  font-size: 0.9375rem;
  color: #6a6a6a;
  margin: 1rem 0 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.dot{
  display: inline-block;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  flex-shrink: 0;
}
.dot-a{ background: #f0805f; }
.dot-b{ background: var(--accent2); }
.dot-c{ background: var(--accent3); }

/* ===================== RESPONSIVE ===================== */

@media (max-width: 820px) and (pointer: coarse){
  /* No pin, no GSAP transform here (see the ScrollTrigger.matchMedia guard
     in script.js) — just a plain vertical stack, letting the page scroll
     natively. Horizontal scroll-jacking is a bad fit for touch input.
     Gated on (pointer: coarse) too, not just width, so a narrow *desktop*
     window (mouse/trackpad) keeps the horizontal pin instead of falling
     back to this — only an actual touch device drops into vertical stacking. */
  .gallery{ height: auto; overflow: visible; }
  .track{
    display: flex;
    flex-direction: column;
    align-items: center;
    height: auto;
    width: 100%;
    padding: 3rem 0;
    gap: 3.5rem;
  }

  .site-logo{ display: none; } /* no roll-in on mobile — see .mobile-connect-footer for the equivalent */

  /* .top-nav itself stays up (not display:none) so the Kanye now-playing
     widget can still show at the top when triggered from About Me — only
     the desktop-only Connect label + socials (moved to .mobile-connect-footer)
     are dropped here. */
  .top-nav-connect,
  .top-nav-socials{ display: none; }

  .mobile-connect-footer{
    display: flex;
    align-items: center;
    align-self: flex-start;
    gap: 16px;
    padding: 0 6vw;
    font-family: 'M PLUS 1', 'Inter', sans-serif;
    font-size: 1rem;
    letter-spacing: 0.05em;
    color: var(--ink);
  }
  .mobile-connect-footer-socials{ display: flex; align-items: center; gap: 16px; }
  .mobile-connect-footer-socials img{ width: 28px; height: 28px; display: block; }
  .mobile-connect-footer-socials a{ line-height: 0; }

  .kanye-player{
    right: 0;
    bottom: 0;
    width: 100%;
    border-width: 2px 0 0;
    border-radius: 12px 12px 0 0;
  }

  .landing{
    width: 92vw;
    height: auto;
    margin-left: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1.2rem;
    padding: 2.4rem 0 3rem;
  }
  /* Unwraps the canvas so its children stack directly in .landing's flex
     column below, instead of being constrained to the 1440:900 box. */
  .landing-canvas{
    display: contents;
    container-type: normal;
    width: auto;
    aspect-ratio: auto;
  }
  .landing-name,
  .landing-bio,
  .landing-sun,
  .landing-cta{
    position: static;
    left: auto; right: auto; top: auto; bottom: auto;
  }
  .landing-name{ font-size: 2.6rem; white-space: normal; }
  .landing-bio{ width: 100%; max-width: none; }
  .landing-sun{
    width: 55vw;
    max-width: 300px;
    align-self: center;
    margin: 0.5rem 0;
  }
  /* Mobile scrolls vertically (the horizontal-pin gallery is desktop-only —
     see script.js's isDesktop() check), so the arrow drops below the label
     and points down instead of sitting beside it pointing right. */
  .landing-cta{
    white-space: normal;
    flex-direction: column;
    align-items: center;
    align-self: center; /* .landing's column is left-aligned otherwise */
    text-align: center;
  }
  /* rotate() doesn't resize the layout box, so rotating the image directly
     left it reserving its pre-rotation (short, wide) footprint — almost no
     vertical space — and the now-visually-tall arrow overflowed upward into
     the label above it. The wrap gets the correctly-sized (tall) box for
     flex/gap purposes; the image inside keeps its normal undistorted
     dimensions and just rotates freely within that space. */
  .landing-cta-arrow-wrap{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 0.9em;
    height: 3.4em; /* image is ~178:47, so its rotated height is ~3.4x its width */
  }
  .landing-cta-arrow{ transform: rotate(90deg); }

  .frame-wrap{ width: 86vw; min-width: 0; }

  /* Outro: the canvas stops being a query container here, so every cqw/cqh
     value above has to be restated — centre the text over the burst instead. */
  .outro-panel{ width: 86vw; height: auto; margin-left: 0; margin-right: 0; padding: 2rem 0; }
  .outro-canvas{
    container-type: normal;
    width: 100%;
    aspect-ratio: 1 / 1;
  }
  .outro-burst{
    left: 50%; top: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    height: auto;
  }
  .outro-thanks{
    left: 50%; top: 50%;
    transform: translate(-50%, -50%);
    width: max-content;
    font-size: 2rem;
    text-align: center;
  }

  /* About me: shrink the animated collage (now one SVG covering photos +
     doodles + scribble) into a centered square above the stacked copy,
     rather than the desktop's absolutely-positioned canvas. */
  .about-panel{ width: 92vw; height: auto; padding: 1rem 0 2.5rem; }
  .about-canvas{
    display: flex;
    flex-direction: column;
    align-items: center;
    container-type: normal;
    width: 100%;
    aspect-ratio: auto;
    gap: 1.1rem;
  }
  .about-photo-cluster{
    position: relative;
    /* Reset the desktop rule's left/top (25.062cqw/50.006cqh) — cqw/cqh
       don't resolve in this container-type:normal breakpoint, so browsers
       fall back to resolving them against the viewport instead of treating
       them as inert, and position:relative (needed below for .about-bubble's
       containing block) actually applies that leftover offset, shoving the
       whole cluster ~400px down into the copy text below it. */
    top: 0;
    left: 0;
    transform: none;
    width: 80vw;
    max-width: 340px;
    aspect-ratio: 1;
  }
  /* .about-canvas is a flex column here, so .about-message just becomes the
     next item in that stack — right under the photo cluster — instead of
     needing its own cqw/cqh-based placement (which is container-type:normal
     here anyway, so wouldn't resolve). */
  .about-message{
    position: static;
    transform: none;
    width: 90%;
    font-size: 0.85rem;
  }
  /* cqw doesn't resolve here (container-type:normal) — use vw instead so
     this still scales with the window rather than sitting at a fixed size. */
  .about-message-photo{
    width: clamp(120px, 45vw, 220px);
    height: clamp(120px, 45vw, 220px);
  }
  .about-copy{
    position: static;
    width: 100%;
    margin-top: 0.5rem;
  }
  .about-title-scribble{ width: 160px; }
  .about-copy p{ font-size: 0.95rem; }
}
