/* =========================================================================
   PORTFOLIO — RADICAL MINIMALISM
   -------------------------------------------------------------------------
   Pure white. Plain black. One typeface (Inter). Lots of breathing room.
   No gradients, no 3D, no decoration. The content is the design.

   HOW THIS FILE IS ORGANISED
   1.  Design tokens (colours, type sizes, spacing)  <-- edit these to retune
   2.  Reset & base
   3.  Layout helpers (container, sections)
   4.  Header / navigation
   5.  Buttons & links
   6.  Media / image placeholders   <-- the grey [LABEL] boxes
   7.  Home / hero
   8.  Selected work grid
   9.  About
   10. Stories (photo gallery)
   11. Footer
   12. Case study page
   13. Scroll reveal animation
   14. Responsive (tablet / mobile)
   15. Reduced motion + page transitions

   TIP: Almost every colour, size and gap is a variable in section 1.
   Change one value there and it updates everywhere.
   ========================================================================= */


/* =========================================================================
   1. DESIGN TOKENS
   ========================================================================= */
:root {

  /* ---- Colour ---------------------------------------------------------- */
  --bg:               #ffffff;   /* page background — pure white            */
  --text:             #000000;   /* all real content text — plain black     */
  --muted:            #8a8a8a;   /* small secondary text (labels, captions) */
  --line:             #e6e6e6;   /* hairline dividers / borders             */
  --placeholder-bg:   #ededed;   /* the grey image-placeholder fill         */
  --placeholder-bg-2: #e5e5e5;   /* placeholder on hover                    */
  --placeholder-text: #9a9a9a;   /* the [LABEL] text inside a placeholder   */
  --placeholder-hint: #b9b9b9;   /* the small "REPLACE · 4:3" hint          */

  /* ---- Typeface -------------------------------------------------------- */
  /* Inter is loaded from Google Fonts in each HTML <head>.                 */
  /* If it ever fails to load, the system font stack below is used instead. */
  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          Helvetica, Arial, sans-serif;

  /* ---- Type scale (fluid: shrinks on phones, grows on big screens) ----- */
  --fs-hero:   clamp(2.25rem, 6vw, 4.5rem);   /* the home name              */
  --fs-display:clamp(1.75rem, 4vw, 3rem);     /* big page titles            */
  --fs-h2:     clamp(1.35rem, 1rem + 1.5vw, 1.9rem); /* section headings    */
  --fs-lead:   clamp(1rem, 0.95rem + 0.3vw, 1.2rem); /* taglines / intros   */
  --fs-body:   1rem;                           /* normal paragraph text      */
  --fs-small:  0.8125rem;                      /* fine print                 */
  --fs-label:  0.75rem;                        /* uppercase tracked labels   */

  /* ---- Spacing & widths ------------------------------------------------ */
  --space-section: clamp(5rem, 9vw, 8rem); /* vertical gap per section */
  --gutter:        clamp(1.5rem, 5vw, 5rem);   /* left/right page padding    */
  --maxw:          1440px;                      /* overall content max width  */
  --maxw-text:     68ch;                        /* comfy reading line length  */

  /* ---- Motion ---------------------------------------------------------- */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);      /* soft, natural easing       */
  --dur:  0.7s;                                 /* reveal duration            */
}


/* =========================================================================
   2. RESET & BASE
   ========================================================================= */
*, *::before, *::after { box-sizing: border-box; }

* { margin: 0; }

html {
  scroll-behavior: smooth;        /* smooth in-page jumps to #sections      */
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

img, picture, video, canvas { display: block; max-width: 100%; }

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

h1, h2, h3 { font-weight: 500; line-height: 1.1; }

/* A confident little detail: black text selection */
::selection { background: #000; color: #fff; }

/* Keyboard focus ring (only shows for keyboard users) */
a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 4px;
  border-radius: 1px;
}

/* Skip link for accessibility — hidden until focused with Tab */
.skip-link {
  position: absolute;
  left: 1rem;
  top: -100px;
  z-index: 100;
  background: #000;
  color: #fff;
  padding: 0.6rem 1rem;
  font-size: var(--fs-small);
  transition: top 0.2s ease;
}
.skip-link:focus { top: 1rem; }

/* Tiny shared "eyebrow" label — uppercase, tracked, muted */
.eyebrow {
  display: inline-block;
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
  font-weight: 500;
}


/* =========================================================================
   3. LAYOUT HELPERS
   ========================================================================= */
.container {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* A major section of the page with generous vertical breathing room */
.section { padding-block: var(--space-section); }

/* Anchor targets sit clear of the sticky header when jumped to */
[id] { scroll-margin-top: 6rem; }

/* Standard heading row for a section: title on the left, meta on the right */
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: clamp(1.1rem, 2.5vw, 1.75rem);
}
.section-head__title {
  font-size: var(--fs-h2);
  letter-spacing: -0.02em;
}
.section-head__meta {
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  white-space: nowrap;
}

/* A quiet, on-brand call-to-action (used instead of a heavy button).
   Small tracked label, goes black on hover, with a little arrow nudge. */
.section-head__link {
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  white-space: nowrap;
  transition: color 0.25s ease;
}
.section-head__link:hover { color: var(--text); }
.section-head__link span {
  display: inline-block;
  transition: transform 0.25s var(--ease);
}
.section-head__link:hover span { transform: translateX(4px); }


/* =========================================================================
   4. HEADER / NAVIGATION
   Quiet, sticky top bar. A hairline appears only once you start scrolling
   so the home screen stays as clean as possible.
   ========================================================================= */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--bg);
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s ease;
}
.site-header.is-scrolled { border-bottom-color: var(--line); }

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding-block: 1.15rem;
}

/* The wordmark (your name) on the left */
.site-header__name {
  font-weight: 500;
  font-size: 0.95rem;
  letter-spacing: -0.01em;
}

/* The nav links on the right */
.site-nav {
  display: flex;
  gap: clamp(1rem, 3vw, 2.5rem);
}
.site-nav a {
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text);
  transition: color 0.25s ease;
}
.site-nav a:hover { color: var(--muted); }


/* =========================================================================
   5. LINKS (inline text link style, used sparingly)
   ========================================================================= */
.link-underline {
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: color 0.25s ease;
}
.link-underline:hover { color: var(--muted); }


/* =========================================================================
   6. MEDIA / IMAGE PLACEHOLDERS
   -------------------------------------------------------------------------
   A ".media" box keeps a fixed shape (aspect ratio) whether it holds a
   grey placeholder or a real photo.

   PLACEHOLDER:   <div class="media media--4x3"> ...label spans... </div>
   REAL IMAGE:    <div class="media media--4x3"><img src="..." alt="..."></div>
                  (just drop an <img> inside; you can delete the label spans)
   ========================================================================= */
.media {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  text-align: center;
  width: 100%;
  aspect-ratio: 4 / 3;          /* default shape; override with a modifier  */
  background: var(--placeholder-bg);
  overflow: hidden;             /* clips the gentle hover zoom              */
  transition: background-color 0.4s ease;
}

/* The aspect-ratio options */
.media--16x9 { aspect-ratio: 16 / 9; }
.media--2x1  { aspect-ratio: 2 / 1; }    /* wide + short — fits one screen */
.media--3x2  { aspect-ratio: 3 / 2; }
.media--4x3  { aspect-ratio: 4 / 3; }
.media--1x1  { aspect-ratio: 1 / 1; }
.media--3x4  { aspect-ratio: 3 / 4; }   /* portrait */
.media--4x5  { aspect-ratio: 4 / 5; }   /* portrait */

/* A real image dropped inside fills the box edge-to-edge */
.media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.6s var(--ease);
}

/* ---- Skeleton shimmer -------------------------------------------------
   While a real image is still loading, its box shows an animated grey
   shimmer (a "skeleton"). The moment the image finishes loading, JS adds
   .is-loaded and the shimmer fades away to reveal the photo. Only boxes
   that actually contain an <img> shimmer (placeholders are left alone). */
.media:has(img)::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  background-color: #e9e9ec;
  background-image: linear-gradient(
    100deg,
    rgba(255, 255, 255, 0) 20%,
    rgba(255, 255, 255, 0.6) 50%,
    rgba(255, 255, 255, 0) 80%
  );
  background-size: 220% 100%;
  background-repeat: no-repeat;
  animation: media-shimmer 1.25s ease-in-out infinite;
  transition: opacity 0.5s ease;
  pointer-events: none;
}
.media.is-loaded::after {
  opacity: 0;
  animation: none;
}
@keyframes media-shimmer {
  from { background-position: 180% 0; }
  to   { background-position: -80% 0; }
}

/* The [LABEL] text shown while it's still a placeholder */
.media__label {
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-weight: 500;
  color: var(--placeholder-text);
  padding-inline: 1rem;
}
.media__hint {
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--placeholder-hint);
}


/* =========================================================================
   7. HOME / HERO
   Full screen. Just your name and one tagline. Nothing else.
   ========================================================================= */
.hero {
  aspect-ratio: 16 / 9;          /* 16:9 instead of full screen             */
  min-height: 480px;             /* don't collapse on small / narrow screens */
  display: flex;
  align-items: center;           /* vertically centred                      */
  position: relative;
}
/* On screens narrower than the 16:9 break-even point, the min-height would
   otherwise make aspect-ratio drive the WIDTH (480 × 16/9 = 853px) and push
   the page wider than the phone, clipping the tagline. Drop the ratio there
   and let height follow content instead. */
@media (max-width: 900px) {
  /* Full-screen hero: only the name + one-line intro show above the fold.
     "Selected Work" stays below, so the first screen is calm and blank.
     svh = small viewport height, so it fits exactly under the mobile
     address bar without the next section peeking in. */
  .hero {
    aspect-ratio: auto;
    min-height: 100vh;
    min-height: 100svh;
  }
}
.hero__scroll-hint {
  position: fixed;
  bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
  left: 50%;
  transform: translateX(-50%);
  color: var(--ink);
  opacity: 0.65;
  transition: none;
  z-index: 10;
}
.hero__scroll-hint:hover { opacity: 1; }
.hero__scroll-hint.is-hidden { opacity: 0 !important; pointer-events: none; }
/* Gently bounce the chevron down and back so it reads as "scroll down".
   Animating the inner SVG keeps the anchor's translateX(-50%) centering. */
.hero__scroll-hint svg {
  animation: chevron-bounce 1.8s ease-in-out infinite;
}
@keyframes chevron-bounce {
  0%, 100% { transform: translateY(0);   opacity: 1;   }
  50%      { transform: translateY(7px); opacity: 0.45; }
}
.hero__name {
  font-size: var(--fs-hero);
  font-weight: 500;
  line-height: 0.95;
  letter-spacing: -0.04em;
  max-width: 18ch;
}
.hero__tagline {
  margin-top: clamp(1.25rem, 3vw, 2rem);
  font-size: var(--fs-lead);
  line-height: 1.4;
  color: var(--muted);
  max-width: 46ch;
}


/* =========================================================================
   8. SELECTED WORK GRID  (like a clean product grid)
   ========================================================================= */
.work-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(1.5rem, 3vw, 2.25rem) clamp(1.25rem, 3vw, 2rem); /* row col */
  container-type: inline-size;   /* lets a card's height be measured against the FULL grid width */
}

.card { display: block; color: inherit; }

/* Each project is a clean Apple-style tile: a soft grey frame (sharp corners,
   on-brand) with the full device mockup shown inside — its breathing room on
   top is kept for the text. The grey matches the mockup images' own background
   (#f5f4f7), so image and frame blend into one seamless tile. */
.card .media {
  margin-bottom: 0;
  background: #f5f4f7;
}
/* Show the whole mockup — never crop — so the gap on top stays intact */
.card .media img { object-fit: contain; transition: none; }

/* Work tiles share ONE shape at every width (desktop, tablet, phone) so the
   layout reads identically everywhere — no more text jumping up or down between
   breakpoints. The shape is a SQUARE (1:1): in the 2-column grid a card is half
   the grid wide, and a case-study hero is the full grid wide at 2:1 — so a
   square card stands exactly as tall as a case-study hero image, by design.
   The mockup is anchored to the BOTTOM, and the caption sits in the open space
   above it, vertically centred — midway between the top of the card and the
   top of the image. */
.work-grid .card .media {
  /* Match the case-study banner's on-screen height EXACTLY. The banner is the
     full content width at 2:1, so its height = gridWidth / 2. With the grid set
     as a query container above, 50cqw === gridWidth / 2 === that banner height. */
  aspect-ratio: auto;
  height: 50cqw;
  display: flex;
  flex-direction: column;
  border-radius: 4px;
}
.work-grid .card__caption {
  position: absolute;           /* overlaid on the full-card image */
  top: clamp(2rem, 11%, 5rem);   /* sit near the top, nudged down a little over the empty upper area */
  left: 0;
  right: 0;
  z-index: 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0 clamp(1rem, 4%, 2rem);
  gap: 0.5rem;
}
.work-grid .card .media img {
  position: absolute;           /* image fills the WHOLE card */
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;   /* device rests on the bottom edge */
  padding: 0;
  z-index: 0;
}
/* Caption type — sized to sit comfortably, not shout. */
.work-grid .card__title   { font-size: clamp(1.4rem, 1.1rem + 1.1vw, 1.75rem); line-height: 1.08; }
.work-grid .card__tagline { font-size: clamp(0.9rem, 0.85rem + 0.28vw, 1.05rem); max-width: 30ch; }
.work-grid .card__cta {
  margin-top: 0.5rem;
  /* Apple-style compact black pill */
  padding: 0.38rem 1rem;
  font-size: clamp(0.78rem, 0.75rem + 0.15vw, 0.9rem);
  font-weight: 400;
  background: #000;
  color: #fff;
  transition: background-color 0.2s ease;
}
.work-grid .card:hover .card__cta:not(.card__cta--ongoing) { background: #1d1d1f; }
/* Ongoing status badge: quiet grey outline, NOT a filled button (keep text grey, not white) */
.work-grid .card__cta--ongoing { background: transparent; color: #6e6e73; }

/* Apple-style caption: name + one-line tagline + single pill CTA.
   Sits in the breathing room at the top of each tile. Kept compact. */
.card__caption {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: clamp(2.5rem, 7%, 4.5rem) 1.25rem 0;
  gap: 0.25rem;
}
.card__title {
  font-size: clamp(1.15rem, 0.9rem + 1vw, 1.65rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.05;
  color: #1d1d1f;
}
.card__tagline {
  font-size: clamp(0.72rem, 0.68rem + 0.3vw, 0.875rem);
  font-weight: 400;
  line-height: 1.3;
  color: #6e6e73;
  max-width: 28ch;
}
.card__cta {
  display: inline-block;
  margin-top: 0.4rem;
  padding: 0.35rem 0.95rem;
  border-radius: 980px;
  background: #000;
  color: #fff;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.01em;
}

/* Ongoing project: the card isn't a link yet, and its pill reads as a quiet
   status badge (outlined, muted) rather than a black "tap me" button. */
.card--ongoing { cursor: default; }
.card__cta--ongoing {
  background: transparent;
  color: #6e6e73;
  border: 1px solid #c7c7cc;
}

.card__footer {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}
.card__name {
  font-size: 1.0625rem;
  font-weight: 500;
  letter-spacing: -0.01em;
}
.card__category {
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  white-space: nowrap;
}

/* Gentle hover: image eases in, name underlines */
.card:hover .media { background: var(--placeholder-bg-2); }
/* No zoom on real-image tiles — contain fit means scale reveals grey edges */
.card:hover .media:has(img) { background: #f5f4f7; }
.card:hover .card__name {
  text-decoration: underline;
  text-underline-offset: 3px;
}


/* =========================================================================
   8B. TESTIMONIALS  —  infinite horizontal marquee
   Cards scroll left in a seamless loop. Edges fade out via CSS mask.
   Hover anywhere on the track to pause.
   ========================================================================= */
.tml-overflow {
  overflow: hidden;
  cursor: grab;
  /* fade the left and right edges to white */
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 7%, #000 93%, transparent 100%);
  mask-image:         linear-gradient(to right, transparent 0%, #000 7%, #000 93%, transparent 100%);
}
.tml-overflow.is-dragging {
  cursor: grabbing;
  user-select: none;
}
.tml-track {
  display: flex;
  gap: 1.25rem;
  width: max-content;
  animation: tml-scroll 120s linear infinite;
}
@keyframes tml-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* The invisible anchor covers the whole card so the entire tile is clickable */
.tml__link {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.tml {
  position: relative;
  flex: 0 0 270px;
  height: 260px;
  display: flex;
  flex-direction: column;
  padding: 1.25rem 1.4rem;
  border: 1px solid var(--line);
  background: var(--bg);
}

/* Top row: where it's from (left) + stars / upvotes / role (right) */
.tml__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.9rem;
}
.tml__source {
  display: flex;
  align-items: center;
  color: var(--muted);
  line-height: 1;
}
.tml__source svg { display: block; }
.tml__stars {                          /* ★ rating — kept black, it's content */
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  color: var(--text);
  white-space: nowrap;
}
.tml__meta {                           /* upvotes / subreddit / role          */
  font-size: var(--fs-small);
  color: var(--muted);
  white-space: nowrap;
}

/* The review itself */
.tml__quote {
  font-size: 0.875rem;
  line-height: 1.55;
  letter-spacing: -0.005em;
  margin: 0;
  flex: 1;                      /* fills available space above the name */
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
}

/* Who wrote it — always pinned to the bottom of the card, one line */
.tml__by {
  margin-top: 0.9rem;
  flex-shrink: 0;
  font-size: var(--fs-small);
  color: var(--muted);
  font-style: normal;
  border-top: 1px solid var(--line);
  padding-top: 0.65rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tml__name { color: var(--text); font-weight: 500; }

/* ---- Brand colour on hover (per platform) -------------------------------
   On hover the border turns the platform's brand colour, and the source
   icon + author name match it. No glow, no animation — just a clean tint. */
.tml[data-platform="apple"]  { --brand: #0071e3; }    /* Apple   blue   */
.tml[data-platform="play"]   { --brand: #34a853; }    /* Play    green  */
.tml[data-platform="reddit"] { --brand: #ff4500; }    /* Reddit  orange */

.tml {
  transition: border-color .25s ease;
}
.tml:hover {
  border-color: var(--brand);
}
.tml:hover .tml__source,
.tml:hover .tml__name {
  color: var(--brand);
  transition: color .25s ease;
}
/* Stars turn golden on hover */
.tml__stars { transition: color .25s ease; }
.tml:hover .tml__stars { color: #f5b301; }


/* =========================================================================
   9. ABOUT
   ========================================================================= */
#about { padding-bottom: clamp(8rem, 14vw, 12rem); }

.about__grid {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: start;
}
/* Keep the profile photo a controlled height so About fits the screen */
.about__media .media {
  aspect-ratio: auto;
  height: clamp(240px, 46vh, 420px);
}
.about__lead {
  font-size: var(--fs-lead);
  line-height: 1.35;
  letter-spacing: -0.01em;
  margin-bottom: 1rem;
}
.about__body p {
  max-width: var(--maxw-text);
  line-height: 1.55;
  margin-bottom: 0.75rem;
}
.about__body p:last-child { margin-bottom: 0; }

/* Small facts list (Based in / Focus / Availability …) */
.about__facts {
  margin-top: 1.5rem;
  display: grid;
  gap: 0.5rem;
}
.about__fact {
  display: flex;
  gap: 1rem;
  align-items: baseline;
  padding-top: 0.6rem;
  border-top: 1px solid var(--line);
}
.about__fact dt {
  flex: 0 0 9rem;
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
}
.about__fact dd { font-size: var(--fs-body); }


/* =========================================================================
   10. STORIES (personal photo gallery)
   A scattered, masonry-style collage: each photo keeps its own shape so the
   grid feels organic. Four tight columns keep the tiles small and compact.
   ========================================================================= */
.stories__grid {
  columns: 4;
  column-gap: clamp(0.5rem, 1.4vw, 0.9rem);
}
.stories__item {
  break-inside: avoid;                 /* don't split a photo across columns  */
  margin-bottom: clamp(0.5rem, 1.4vw, 0.9rem);
}

/* Gentle hover zoom for a little life */
.stories__item .media img { transition: transform 0.6s var(--ease); }
.stories__item:hover .media { background: var(--placeholder-bg-2); }
.stories__item:hover .media img { transform: scale(1.04); }


/* =========================================================================
   11. FOOTER
   ========================================================================= */
.site-footer {
  border-top: 1px solid var(--line);
  padding-block: var(--space-section);
}
.site-footer__cta { margin-bottom: clamp(3rem, 6vw, 5rem); }
.site-footer__email {
  display: inline-block;
  margin-top: 1rem;
  font-size: clamp(1rem, 2.5vw, 2rem);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.1;
  max-width: 100%;
  overflow-wrap: anywhere;   /* never let the long email widen the page */
}
.site-footer__email:hover { text-decoration: underline; text-underline-offset: 4px; }

.site-footer__row {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 1.5rem 2rem;
}
.site-footer__socials {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1rem, 3vw, 2rem);
}
.site-footer__socials a {
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  transition: color 0.25s ease;
}
.site-footer__socials a:hover { color: var(--muted); }
.site-footer__fine {
  font-size: var(--fs-small);
  color: var(--muted);
}

/* A quiet last word — inspired by Kanye West.
   One lowercase line, alone in space, as the page's final breath. */
.site-footer__okay {
  margin-top: clamp(4rem, 9vw, 7rem);
  text-align: center;
  font-size: var(--fs-small);
  letter-spacing: 0.04em;
  color: var(--muted);
}


/* =========================================================================
   12. CASE STUDY PAGE
   ========================================================================= */
.case { padding-top: clamp(2rem, 6vw, 4rem); }

/* "← Selected Work" back link */
.case-back { margin-bottom: clamp(2.5rem, 6vw, 4rem); }
.case-back a {
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  transition: color 0.25s ease;
}
.case-back a:hover { color: var(--text); }

.case-hero { margin-bottom: clamp(3rem, 8vw, 6rem); }
.case-hero__logo {
  display: block;
  width: clamp(72px, 8vw, 96px);
  height: clamp(72px, 8vw, 96px);
  border-radius: 0;                   /* square corners, no rounding */
  margin-bottom: 1.5rem;
  object-fit: cover;
}
.case-hero__title {
  font-size: var(--fs-display);
  letter-spacing: -0.03em;
  margin-top: 0.75rem;
  max-width: 20ch;
}

/* App-store style action buttons */
.case-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 2rem;
}
.case-btn {
  display: inline-flex;
  align-items: center;
  padding: 0.6rem 1.4rem;
  border: 1px solid var(--text);
  border-radius: 999px;
  font-size: var(--fs-label);
  letter-spacing: 0.02em;
  transition: background 0.2s ease, color 0.2s ease;
}
.case-btn:first-child {                /* primary, filled */
  background: var(--text);
  color: var(--bg);
}
.case-btn:hover {
  background: var(--bg);
  color: var(--text);
}
.case-btn:not(:first-child):hover {
  background: var(--text);
  color: var(--bg);
}

/* Project facts (Role / Year / Platform …) */
.case-meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 1.5rem 2rem;
  margin-top: clamp(2.5rem, 5vw, 4rem);
  padding-top: 2rem;
  border-top: 1px solid var(--line);
}
.case-meta dt {
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  margin-bottom: 0.5rem;
}
.case-meta dd { font-size: var(--fs-body); }
/* Platform links: plain black, always underlined */
.case-meta dd a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;   /* a little breathing room under the text */
}

/* Star rating shown in the project facts (set the score with --rating) */
.case-rating {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;          /* let the count drop to its own line, never mid-word */
  gap: 0.2rem 0.5rem;
}
.case-rating__stars {
  --rating: 0;            /* 0 to 5 — set inline on the element */
  position: relative;
  display: inline-block;
  font-size: 1em;
  line-height: 1;
  letter-spacing: 2px;
  white-space: nowrap;      /* all five stars stay on one line */
  font-family: Arial, sans-serif; /* consistent star glyph */
}
.case-rating__stars::before {
  content: "★★★★★";
  background: linear-gradient(
    90deg,
    var(--text) calc(var(--rating) / 5 * 100%),
    #c9c9c9 calc(var(--rating) / 5 * 100%)   /* visible grey for the empty part */
  );
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
.case-rating__count {
  color: var(--muted);
  white-space: nowrap;      /* keep "App Store" together, never "App" / "Store" */
}

/* ---- Medium-style reading layout (case studies) ----------------------
   The article body reads like a Medium post: a serif reading face, a
   narrow centred column, generous type, and sans-serif bold headings.
   Scoped to .prose / .case-figure so the rest of the site is untouched. */
.prose {
  max-width: 42rem;                 /* ~672px — Medium's reading measure */
  margin-inline: auto;              /* centre the column */
  font-family: Georgia, Charter, Cambria, "Times New Roman", serif;
  font-size: clamp(1.12rem, 1.02rem + 0.42vw, 1.3125rem);  /* ~18–21px */
  line-height: 1.65;
  color: #242424;                   /* Medium's warm near-black */
}
.prose h2 {
  font-family: var(--font);         /* headings stay sans-serif + bold */
  font-weight: 600;
  font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2rem);
  letter-spacing: -0.02em;
  line-height: 1.25;
  color: #242424;
  margin-top: 2.5rem;
  margin-bottom: 0.9rem;
}
.prose p { line-height: 1.65; margin-bottom: 1.6rem; }
.prose p:last-child { margin-bottom: 0; }
.prose a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}

/* Spacing around each text block and full-width figure */
.case-block  { margin-block: clamp(2.5rem, 6vw, 4rem); }
.case-figure {
  margin-block: clamp(2.5rem, 6vw, 4rem);
  max-width: 46rem;                 /* Medium-style centred image column */
  margin-inline: auto;
}
.case-figure figcaption {
  margin-top: 0.75rem;
  font-size: var(--fs-small);
  color: var(--muted);
  text-align: center;               /* Medium centres captions */
  font-style: italic;
}

/* Two image placeholders side by side */
.case-figure-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1.25rem, 3vw, 2rem);
  margin-block: clamp(3.5rem, 9vw, 7rem);
}

/* Four vertical user-testing videos — equal widths, height ≈ the 2:1 sections */
.case-videos {
  display: flex;
  justify-content: center;
  gap: clamp(0.6rem, 1.5vw, 1.2rem);
  margin-block: clamp(3.5rem, 9vw, 7rem);
}
.case-videos video {
  flex: 1 1 0;
  min-width: 0;
  aspect-ratio: 9 / 16;
  object-fit: cover;
  border-radius: 12px;
  background: var(--placeholder-bg);
}

/* Captioned user-testing clips */
.case-vid {
  flex: 1 1 0;
  min-width: 0;
  margin: 0;
}
.case-vid video {
  width: 100%;
  flex: none;
}
.case-vid figcaption {
  margin-top: 0.75rem;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--muted, #888);
}
.case-vid figcaption strong {
  display: block;
  color: var(--ink, #111);
  font-weight: 600;
  font-size: 0.9rem;
  margin-bottom: 0.2rem;
}

@media (max-width: 760px) {
  .case-videos { flex-wrap: wrap; }
  .case-vid { flex: 1 1 40%; }
}

/* Outcome — phone screen with floating Google Play review cards (Snatchfy-style) */
/* This composition needs the SAME width as other figures,
   so we apply the same 46rem limit. */
.case-figure.case-outcome { max-width: 46rem; }
.case-outcome__stage { 
  position: relative;
  padding-bottom: clamp(4rem, 10vw, 8rem); /* Give bottom cards room so they don't break out */
}
/* The track is a no-op wrapper on desktop (display:contents lets the cards
   float absolutely against the stage exactly as before). It only becomes a
   real flex row — a left-scrolling marquee — on mobile (see media query). */
.greview-track { display: contents; }
.greview--clone { display: none; }
.case-outcome__shot {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 0;
}
.greview {
  position: absolute;
  width: 23%;
  max-width: 240px;
  background: #fff;
  border-radius: 0;
  padding: 0.35rem 0.55rem;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.07);
  font-size: 0.64rem;
}
.greview__head { display: flex; align-items: center; gap: 0.3rem; margin-bottom: 0.15rem; }
.greview__title { font-weight: 600; font-size: 0.7rem; color: #1d1d1f; line-height: 1.1; margin-bottom: 0.1rem; }
.greview__store {
  display: flex; align-items: center; gap: 0.2rem;
  margin-top: 0.3rem; font-size: 0.55rem; font-weight: 500; color: #86868b;
}
.greview__store-ic { width: 0.7rem; height: 0.7rem; flex-shrink: 0; }
.greview--app .greview__stars { color: #f5a623; }
.greview__avatar {
  width: 1.2rem; height: 1.2rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 0.6rem; font-weight: 600; flex-shrink: 0;
}
.greview__name { font-weight: 600; font-size: 0.7rem; color: #1d1d1f; }
.greview__stars { color: #00a884; font-size: 0.6rem; letter-spacing: 0.06em; margin-bottom: 0.15rem; }
.greview__text { color: #3a3a3c; line-height: 1.25; margin: 0; font-size: 0.64rem; }

/* Three cards per side, aligned straight and pushed to the edges with much larger vertical gaps */
.greview--l1 { top: 2%;  left: 2%; }
.greview--l2 { top: 40%; left: 2%; }
.greview--l3 { top: 78%; left: 2%; }
.greview--r1 { top: 2%;  right: 2%; }
.greview--r2 { top: 40%; right: 2%; }
.greview--r3 { top: 78%; right: 2%; }

/* Reddit-style card (Snatchfy outcome): a "Reddit + upvotes" header and a
   "u/name · Snatchfy" footer. Scoped to .greview--reddit so the Bhaiji cards
   (avatar + name + stars) are untouched. Compact + roomy type to stay legible
   while three cards per side sit clear of each other (no clutter). */
.greview--reddit {
  border-radius: 0;
  width: 22%;
  max-width: 230px;
  padding: 0.75rem 0.85rem;
}
/* Three cards per side, evenly spaced so they never overlap */
.greview--reddit.greview--l1 { top: 2%;  left: 2%; }
.greview--reddit.greview--l2 { top: 40%; left: 2%; }
.greview--reddit.greview--l3 { top: 78%; left: 2%; }
.greview--reddit.greview--r1 { top: 2%;  right: 2%; }
.greview--reddit.greview--r2 { top: 40%; right: 2%; }
.greview--reddit.greview--r3 { top: 78%; right: 2%; }
.greview__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.45rem;
}
.greview__brand {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-weight: 600;
  font-size: 0.8rem;
  color: #1d1d1f;
}
.greview__brand .greview__store-ic { width: 0.95rem; height: 0.95rem; }
.greview__votes {
  font-size: 0.75rem;
  font-weight: 600;
  color: #ff4500;
  letter-spacing: 0.02em;
}
.greview--reddit .greview__text {
  font-size: 0.85rem;
  line-height: 1.35;
  color: #1d1d1f;
  margin: 0 0 0.5rem;
}
.greview__by {
  font-size: 0.7rem;
  font-weight: 600;
  color: #6b6b70;
}
.greview__sub { color: #b0b0b5; font-weight: 500; }

@media (max-width: 860px) {
  .case-outcome__stage {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.5rem;
    overflow: hidden;            /* clip the marquee at the screen edges */
  }
  .case-outcome__shot { max-width: 360px; }

  /* Reviews now read as a single row that drifts right-to-left on a loop,
     the same feel as the homepage Testimonials. The cloned set (added by JS)
     makes the loop seamless. Pauses while a finger is held down (.is-paused). */
  .greview-track {
    display: flex;
    gap: 0.85rem;
    width: max-content;
    animation: tml-scroll 42s linear infinite;
  }
  .greview-track.is-paused { animation-play-state: paused; }
  .greview--clone { display: flex; }
  .greview {
    position: static;
    flex: 0 0 16rem;
    width: 16rem;
    max-width: none;
    height: auto;
    flex-direction: column;
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.08);
  }
}

/* Outcome stats row */
.case-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: 2rem;
  margin-top: 2.5rem;
  max-width: 46rem;
  margin-inline: auto;
}
.case-stat__num {
  font-size: clamp(1.4rem, 3.5vw, 2.25rem);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1;
}
.case-stat__label {
  margin-top: 0.75rem;
  font-size: var(--fs-small);
  color: var(--muted);
}

/* "Next project →" footer of a case study */
.case-next {
  border-top: 1px solid var(--line);
  padding-block: clamp(3rem, 6vw, 5rem);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}
.case-next a {
  font-size: clamp(1.2rem, 0.7rem + 2vw, 2.5rem);
  font-weight: 500;
  letter-spacing: -0.02em;
  white-space: nowrap;          /* keep "Farmers Near Me →" on one line */
}
.case-next a:hover { text-decoration: underline; text-underline-offset: 4px; }

/* Optional wrapper: stacks the big link with a small note (e.g. an external
   project that opens on Behance) right under it, aligned to the link. */
.case-next__link {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.3rem;
}
.case-next__ext {
  font-size: clamp(0.72rem, 0.66rem + 0.3vw, 0.85rem);
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--muted);
  white-space: nowrap;
}

/* On phones the flex row squeezes the link into a narrow column and the
   arrow drops to a second line. Stack the label above the link so it gets
   the full width and stays on one clean line. */
@media (max-width: 600px) {
  .case-next {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
  }
  .case-next__link { align-items: flex-start; }
}


/* =========================================================================
   13. SCROLL REVEAL ANIMATION
   Elements with class "reveal" start slightly down and transparent, then
   gently fade + rise into place when scrolled into view. Driven by JS,
   which adds the "is-visible" class. The "html.js" guard means that if
   JavaScript is off, nothing is ever hidden.
   ========================================================================= */
html.js .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--dur) var(--ease),
              transform var(--dur) var(--ease);
  transition-delay: var(--d, 0s);   /* optional stagger via style="--d:.1s" */
}
html.js .reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* Safety net: if JS loads but the observer never runs for any reason,
   force everything visible after 3s so content is never stuck hidden. */
html.js .reveal {
  animation: reveal-fallback 0.01s linear 3s forwards;
}
@keyframes reveal-fallback { to { opacity: 1; transform: none; } }


/* =========================================================================
   14. RESPONSIVE
   ========================================================================= */

/* ---- Tablet ----------------------------------------------------------- */
@media (max-width: 900px) {
  .stories__grid { columns: 3; }

  /* Apple-style 2-up tablet tiles: give each tile a tall (portrait) frame,
     anchor the device mockup to the BOTTOM, and let the caption sit a bit
     lower so it stays close to the device. The extra height + scaled top
     padding stops the CTA pill ("View case study" / "View on Behance") from
     landing on the device screen even when the tagline wraps to two lines.
     The ≤600 rules below override this for phones (single column). */
  .card .media { aspect-ratio: 4 / 5; }
  .card .media img {
    object-position: center bottom;
    padding: 0 0.85rem 1rem;
  }
  .card__caption {
    padding-top: clamp(3.25rem, 9vw, 6rem);
    gap: 0.25rem;
  }
  .card__title {
    font-size: clamp(1.5rem, 3.2vw, 1.95rem);
    line-height: 1.1;
  }
  .card__tagline { font-size: 0.95rem; line-height: 1.35; }
  .card__cta {
    margin-top: 0.45rem;
    padding: 0.4rem 1rem;
    font-size: 0.8rem;
  }

  /* iPad / tablet work tiles: smaller, tighter caption (these out-specify the
     .card__* rules above, which is why the desktop sizes were leaking through).
     Layout is unchanged — still a full-image tile with the caption overlaid. */
  .work-grid .card__caption {
    top: clamp(1.5rem, 8%, 3.5rem);
    gap: 0.3rem;
    padding: 0 clamp(0.85rem, 4%, 1.5rem);
  }
  .work-grid .card__title {
    font-size: clamp(1.05rem, 2.4vw, 1.35rem);
    line-height: 1.1;
  }
  .work-grid .card__tagline {
    font-size: clamp(0.78rem, 1.5vw, 0.9rem);
    line-height: 1.3;
  }
  .work-grid .card__cta {
    margin-top: 0.4rem;
    padding: 0.3rem 0.8rem;
    font-size: clamp(0.7rem, 1.4vw, 0.78rem);
  }
}

/* ---- Small tablet / large phone --------------------------------------- */
@media (max-width: 760px) {
  .about__grid { grid-template-columns: 1fr; gap: 2.5rem; }
  .case-figure-pair { grid-template-columns: 1fr; }

}

/* ---- Phone ------------------------------------------------------------ */
@media (max-width: 600px) {
  .work-grid {
    grid-template-columns: 1fr;
    gap: 0.75rem;                 /* breathing room between stacked cards */
    margin-inline: calc(-1 * var(--gutter)); /* bleed to screen edges */
  }
  /* Single column: a full-width 2:1 strip would be too short for the mockup +
     caption, so fall back to the square shape here. */
  .work-grid .card .media {
    height: auto;
    aspect-ratio: 1 / 1;
    border-radius: 0;             /* sharp edges, Apple edge-to-edge style */
  }
  .stories__grid { columns: 2; }

  /* Stacked, uncluttered header: name on its own line, nav evenly below */
  .site-header__inner {
    flex-direction: column;
    align-items: center;
    gap: 1.1rem;                  /* breathing room between name and nav */
    padding-block: 1rem;
  }
  .site-header__name {
    font-size: 0.95rem;
    white-space: nowrap;          /* keep "Aryan Shinde" on one line */
  }
  .site-nav {
    gap: clamp(0.9rem, 5vw, 1.6rem);
  }
  .site-nav a { font-size: 0.72rem; letter-spacing: 0.07em; }

  .about__fact { flex-direction: column; gap: 0.25rem; }
  .about__fact dt { flex-basis: auto; }

  /* Apple-style mobile tiles: on a full-width single column each project
     becomes a tall, generous block (like apple.com's promo tiles). The
     title gets real breathing room at the top, and the device mockup is
     anchored to the BOTTOM so it fills the lower half and never collides
     with the text. This is what keeps it clean once it stacks. */
  .card .media {
    aspect-ratio: 4 / 5;                 /* taller, Apple promo proportions */
  }
  .card .media img {
    object-position: center bottom;      /* device sits at the bottom edge */
    padding: 0 1rem 1.25rem;             /* small inset, not edge-to-edge */
  }
  /* Top padding SCALES with width. On a narrow tall phone (e.g. Galaxy Z
     Fold, ~344px) this resolves to ~3.5rem and the device sits right under
     the caption. On a wider single-column "tab" layout (~480–600px) the
     tile gets much taller, so the caption is pushed proportionally further
     down to stay close to the device instead of leaving a big gap. */
  .card__caption {
    padding-top: clamp(3.5rem, 110vw - 24rem, 17rem);
    gap: 0.4rem;
  }
  .card__title,
  .work-grid .card__title {
    font-size: clamp(1.55rem, 6.2vw, 1.95rem);
    line-height: 1.08;
  }
  .card__tagline,
  .work-grid .card__tagline {
    font-size: clamp(0.88rem, 3.4vw, 1.1rem);
    line-height: 1.3;
  }
  .card__cta,
  .work-grid .card__cta {
    margin-top: 0.4rem;                      /* tighter gap below the tagline */
    padding: 0.45rem 1.1rem;                 /* smaller pill */
    font-size: clamp(0.72rem, 2.6vw, 0.85rem);
  }
}


/* =========================================================================
   15. REDUCED MOTION + PAGE TRANSITIONS
   ========================================================================= */

/* Smooth cross-page fade in supporting browsers (Chrome/Edge). Harmless
   everywhere else — pages just load normally. */
@view-transition { navigation: auto; }

/* Respect users who prefer no motion: turn everything off and show all
   content immediately. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  html.js .reveal { opacity: 1 !important; transform: none !important; }
}


/* =========================================================================
   16. IMAGE LIGHTBOX  (gallery-style full-screen viewer)
   Click a case-study image and it opens here, alone, on black — zoomable.
   The markup is created by main.js; these styles drive the look + feel.
   ========================================================================= */

/* Hint that case-study images can be opened */
.is-zoomable { cursor: zoom-in; }

/* Faint "expand" badge in the top-right of every zoomable case-study image,
   so it's obvious the image can be opened full-screen. It stays quietly
   visible by default (good on touch, where there's no hover) and brightens
   when the figure is hovered. pointer-events:none lets the click fall
   through to the image, which already triggers the lightbox. */
.case-figure, .case-outcome__stage { position: relative; }
.zoom-badge {
  position: absolute;
  top: clamp(0.6rem, 1.5vw, 1rem);
  right: clamp(0.6rem, 1.5vw, 1rem);
  z-index: 4;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 9px;
  background: rgba(255, 255, 255, 0.72);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: #1d1d1f;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.14);
  opacity: 0.55;                 /* faint, but always visible */
  transition: opacity 0.25s ease, transform 0.25s ease;
  pointer-events: none;          /* click passes through to the image */
}
.case-figure:hover .zoom-badge,
.case-outcome__stage:hover .zoom-badge {
  opacity: 1;
  transform: scale(1.06);
}
.zoom-badge svg { width: 1rem; height: 1rem; display: block; }

/* The user-testing clips can be opened in a big player — invite the click. */
.case-vid { position: relative; }
.case-vid video.is-playable { cursor: pointer; }

/* The big video in the lightbox: centred, fit to the screen. Leaves room at
   the bottom for the custom control bar. */
.lightbox__video {
  max-width: 92dvw;
  max-height: 82dvh;
  width: auto;
  height: auto;
  object-fit: contain;
  background: #000;
  border-radius: 6px;
  cursor: pointer;
}

/* Custom, always-visible control bar (play/pause + progress + time).
   Pinned to the bottom of the viewer so the scrubber never auto-hides. */
.vctrl {
  position: absolute;
  left: 50%;
  bottom: max(1.25rem, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 0.85rem;
  width: min(92dvw, 720px);
  padding: 0.7rem 1rem;
  border-radius: 999px;
  background: rgba(20, 20, 22, 0.6);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  color: #fff;
}
.vctrl__play {
  flex: 0 0 auto;
  width: 2.1rem;
  height: 2.1rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  cursor: pointer;
  transition: background-color 0.2s ease;
}
.vctrl__play:hover { background: rgba(255, 255, 255, 0.26); }
.vctrl__play svg { width: 1.1rem; height: 1.1rem; display: block; }

/* The track is the full-width bar; the fill is the "shrinking" progress that
   grows as the video plays. Click or drag anywhere on the track to seek. */
.vctrl__track {
  position: relative;
  flex: 1 1 auto;
  height: 5px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.25);
  cursor: pointer;
  touch-action: none;
}
.vctrl__track::after {
  /* a bigger invisible hit-area so it's easy to grab on touch */
  content: "";
  position: absolute;
  inset: -10px 0;
}
.vctrl__fill {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: 0%;
  border-radius: 999px;
  background: #fff;
}
.vctrl__time {
  flex: 0 0 auto;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  color: rgba(255, 255, 255, 0.85);
  white-space: nowrap;
}

/* Lock the page behind the viewer */
body.lightbox-open { overflow: hidden; }

.lightbox {
  position: fixed;
  inset: 0;
  /* Use the DYNAMIC viewport so the overlay matches what's actually visible
     on mobile. Without this, iOS Safari sizes `inset:0` / `vh` to the larger
     toolbar-hidden viewport, which pushes the centred image down off-centre. */
  height: 100dvh;
  width: 100dvw;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;                 /* the image stands alone on black */
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.28s var(--ease), visibility 0.28s var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.lightbox.is-open {
  opacity: 1;
  visibility: visible;
}

/* The stage fills the screen; the image is centred and fit inside it */
.lightbox__stage {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.lightbox__img {
  max-width: 92dvw;
  max-height: 90dvh;
  object-fit: contain;
  cursor: zoom-in;
  user-select: none;
  -webkit-user-drag: none;
  touch-action: none;               /* we handle pan / pinch ourselves */
  transform-origin: center center;
  transition: transform 0.18s ease-out;
  will-change: transform;
}
/* While zoomed, the cursor invites zooming back out / panning */
.lightbox.is-zoomed .lightbox__img { cursor: grab; }
.lightbox.is-zoomed .lightbox__img:active { cursor: grabbing; }
/* Don't animate transform mid-drag/pinch — only on the click-to-zoom step.
   (The drag/pinch updates are continuous, so a transition would lag.) */
.lightbox.is-zoomed .lightbox__img { transition: none; }

.lightbox__close {
  position: absolute;
  top: max(1rem, env(safe-area-inset-top));
  right: max(1rem, env(safe-area-inset-right));
  z-index: 2;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.25rem;
  line-height: 1;
  color: #fff;
  background: rgba(255, 255, 255, 0.12);
  border: none;
  border-radius: 50%;
  cursor: pointer;
  transition: background-color 0.2s ease, transform 0.2s ease;
}
.lightbox__close:hover {
  background: rgba(255, 255, 255, 0.24);
  transform: scale(1.06);
}
.lightbox__close:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}
