/* ==========================================================================
   Oyoun Media (projects/oyoun.html)

   The case is told in the final mockups (assets/images/oyoun/final): the
   laptop and the phone take turns, and the page always ends on a laptop.

   Every mockup is a cut-out PNG shown whole, at its own shape. Nothing frames
   it, nothing crops it, and no words sit on it: no borders, no radius, no
   object-fit, no veil. The device itself is the frame.

   The opening follows the One Pinch opening (styles/salt.css): the work fills
   the screen and the words sit at the bottom left. Below it, six layouts take
   turns so the run of devices never settles into one beat:
     side     words beside one laptop (flips sides)
     pair     two laptops, a line each, the second a step lower
     combo    a laptop and a phone standing side by side
     wide     one laptop on its own, for the big moments
     phone    words beside a tall phone (flips sides)
     chapter  the words that open a run
   ========================================================================== */
.oy { --oy-orange: #f2532c; }

.oy img { display: block; max-width: 100%; height: auto; background: none; border: 0; border-radius: 0; box-shadow: none; }
/* Only the figures inside a layout lose their margin; the combo and wide
   figures are layouts themselves and keep margin-inline: auto to centre */
.oy-fig { margin: 0; }
/* The picture wrappers only choose a file; the img stays the layout item */
.oy picture { display: block; }
/* some browsers (Safari) let the <source> tags take grid cells once the
   picture is display: contents, so hide them outright */
.oy picture source { display: none; }

/* The mockups sit in front of the page grain (.wb-grain, z 70) and the
   contour lines (.field, z 65), so the sites inside them read clean, but
   behind the bar (z 80). Nothing around them may start a stacking context,
   or they would be trapped under the grain again. */
.oy-hero__mac, .oy-hero__phone, .oy-dev { position: relative; z-index: 75; }
.oy figcaption {
  margin-top: 14px;
  color: var(--wb-muted);
  font-size: 15px;
  line-height: 1.5;
}

/* ---------- The opening ---------- */
.oy-hero {
  position: relative;
  display: flex;
  align-items: flex-end;
  /* only as tall as the devices need under the bar, never more than a screen,
     so there is no empty band between the bar and the laptop */
  --oy-floor: 164px;
  min-height: min(100svh, calc(var(--oy-dev-w) * 2057 / 3200 + var(--oy-floor) + 128px));
  padding: 128px var(--wb-pad) 64px;
  overflow: hidden;
  /* how wide the devices are; the words take what is left beside them */
  --oy-dev-w: min(60vw, calc((100svh - var(--oy-floor) - 128px) * 3200 / 2057), 1240px);
}
/* A low orange light behind the devices, where One Pinch has its film */
.oy-hero::before {
  content: "";
  position: absolute;
  z-index: 0;
  right: -10%;
  top: 0;
  width: 80%;
  height: 90%;
  background: radial-gradient(closest-side, rgb(242 83 44 / 0.16), rgb(242 83 44 / 0.04) 60%, transparent);
  pointer-events: none;
}
/* The devices take the top right; the words take the bottom left. Sized by
   both width and height, so they never meet and nothing leaves the screen. */
.oy-hero__devices {
  position: absolute;
  /* sits low, level with the words: on most screens the laptop ends at the
     line above the buttons, so the buttons pass under its left edge */
  bottom: var(--oy-floor);
  right: calc(var(--wb-pad) + 2%);
  width: var(--oy-dev-w);
}
.oy-hero__mac { width: 100%; }
.oy-hero__phone {
  position: absolute;
  right: -6%;
  bottom: -2%;
  width: 19.5%;
}
.oy-hero__say {
  position: relative;
  z-index: 1;
  display: grid;
  justify-items: start;
  gap: 18px;
  max-width: min(34ch, calc(100vw - var(--oy-dev-w) - var(--wb-pad) * 2 - 2vw - 56px));
}
.oy-kicker {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  color: var(--portfolio-accent-text, #c6f432);
  font-size: 13px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.oy-hero__title {
  margin: 0;
  font-size: clamp(52px, 7vw, 112px);
  line-height: 0.94;
  letter-spacing: -0.03em;
}
.oy-hero__line {
  margin: 0;
  max-width: 26ch;
  color: var(--wb-muted);
  font-size: clamp(18px, 1.7vw, 23px);
  line-height: 1.45;
}
/* The two ways on: into the case, or out to the live site */
.oy-hero__ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 14px;
  /* side by side: the row may run wider than the words above it (the laptop
     ends well above it), and only wraps when the screen is too narrow */
  width: max-content;
  max-width: calc(100vw - var(--wb-pad) * 2);
}
.oy-hero__ctas .cta { margin-top: 0; }

/* ---------- One line on its own ---------- */
.oy-say {
  padding: clamp(96px, 14vh, 160px) var(--wb-pad) clamp(16px, 3vh, 32px);
}
.oy-say h2 {
  width: min(100%, var(--wb-max));
  margin: 0 auto;
  font-size: clamp(32px, 4.6vw, 64px);
  line-height: 1.04;
  letter-spacing: -0.02em;
}

/* ---------- Shared: the width every layout sits in, and the words ---------- */
.oy-side, .oy-pair, .oy-combo, .oy-wide, .oy-phone, .oy-chapter {
  width: min(100%, var(--wb-max));
  margin-inline: auto;
  padding: clamp(48px, 9vh, 112px) var(--wb-pad);
}
.oy-words h2, .oy-chapter h2 {
  margin: 0;
  font-size: clamp(30px, 3.6vw, 52px);
  line-height: 1.04;
  letter-spacing: -0.02em;
}
.oy-words h3 {
  margin: 0;
  font-size: clamp(26px, 3vw, 40px);
  line-height: 1.08;
  letter-spacing: -0.02em;
}
.oy-words p, .oy-chapter p {
  max-width: 44ch;
  margin: 20px 0 0;
  color: var(--wb-muted);
  font-size: 18px;
  line-height: 1.6;
}
.oy-chapter { padding-bottom: 0; }

/* side: words beside one laptop */
.oy-side { display: grid; gap: clamp(32px, 5vw, 80px); align-items: center; }

/* pair: two laptops, a line each */
.oy-pair { display: grid; gap: clamp(32px, 4vw, 56px); align-items: start; }

/* combo: a laptop and a phone standing side by side, centred on each other.
   The phone is sized so it stands about as tall as the laptop's screen. */
.oy-combo__devices {
  /* a grid that fills the row exactly, so the pair is centred on the page */
  display: grid;
  grid-template-columns: minmax(0, 74fr) minmax(0, 20fr);
  align-items: center;
  gap: clamp(16px, 3vw, 48px);
}
.oy-combo__devices > * { width: 100%; }
.oy-combo--flip .oy-combo__devices { grid-template-columns: minmax(0, 20fr) minmax(0, 74fr); }
.oy-combo--flip .oy-dev--ph { order: -1; }
.oy-combo figcaption { max-width: 60ch; margin-inline: auto; text-align: center; }

/* wide: one laptop on its own */
.oy-wide { display: grid; justify-items: center; }
.oy-wide .oy-dev--mac { width: min(100%, 1080px); }
.oy-wide figcaption { text-align: center; }

/* phone: words beside a tall phone */
.oy-phone { display: grid; gap: clamp(32px, 6vw, 96px); align-items: center; }
.oy-phone .oy-dev--ph {
  /* height-led, so the whole phone fits on screen; width follows the PNG */
  width: min(100%, calc(min(78svh, 760px) * 1187 / 2399));
  justify-self: center;
}

/* ---------- The end ---------- */
.oy-outcome__title { margin: 0 0 32px; font-size: clamp(32px, 5vw, 64px); line-height: 1.04; letter-spacing: -0.02em; }
.oy-outcome__line { margin: 20px 0 32px; color: rgba(237, 234, 227, 0.72); font-size: 18px; }

@media (min-width: 900px) {
  .oy-side { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
  .oy-side--flip { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
  .oy-side--flip .oy-words { order: 2; }
  .oy-pair { grid-template-columns: 1fr 1fr; }
  /* the second of a pair sits lower, so the two read as a step, not a grid */
  .oy-pair .oy-fig:nth-child(2) { margin-top: clamp(48px, 8vw, 120px); }
  .oy-phone { grid-template-columns: 1fr 1fr; }
  .oy-phone--flip .oy-words { order: 2; }
  .oy-phone--flip .oy-dev--ph { order: 1; }
}

/* Wide screens have room beside the buttons, so the devices stand on the
   same floor as them */
@media (min-width: 1840px) {
  .oy-hero { --oy-floor: 72px; }
}

/* Narrower screens: the opening stacks, devices first, words under them */
@media (max-width: 1099px) {
  .oy-hero { flex-direction: column; align-items: stretch; min-height: 0; padding-top: 112px; }
  .oy-hero__devices { position: relative; top: auto; bottom: auto; right: auto; width: 90%; margin: 0 0 56px; }
  .oy-hero__say { max-width: 40ch; }
}
@media (max-width: 899px) {
  .oy-hero, .oy-side, .oy-pair, .oy-combo, .oy-wide, .oy-phone, .oy-chapter, .oy-say { padding-inline: 16px; }
  .oy-hero__devices { width: 88%; }
  .oy-combo__devices { gap: 10px; }
  .oy-phone .oy-dev--ph { width: min(72%, calc(72svh * 1187 / 2399)); }
}

/* ---------- Reveal ----------
   The devices rise into place as they scroll in, a touch smaller than they
   land, so each one arrives rather than appears. Only the whole mockup moves;
   nothing is masked or clipped on the way in. woodberg.js adds .is-visible. */
.js .oy-side.wb-reveal, .js .oy-pair.wb-reveal, .js .oy-combo.wb-reveal,
.js .oy-wide.wb-reveal, .js .oy-phone.wb-reveal { opacity: 1; transform: none; transition: none; }

.js .wb-reveal .oy-dev--mac {
  opacity: 0;
  transform: translateY(80px) scale(0.93);
  transition: opacity 900ms ease var(--d, 0ms), transform 1300ms var(--wb-ease) var(--d, 0ms);
}
.js .wb-reveal .oy-dev--ph {
  opacity: 0;
  transform: translateY(110px) rotate(3deg) scale(0.94);
  transition: opacity 900ms ease var(--d, 120ms), transform 1400ms var(--wb-ease) var(--d, 120ms);
}
.js .wb-reveal .oy-words,
.js .wb-reveal figcaption {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 800ms ease var(--d, 200ms), transform 1000ms var(--wb-ease) var(--d, 200ms);
}
/* the second laptop of a pair, and the phone of a combo, follow a beat later */
.oy-pair .oy-fig:nth-child(2) { --d: 180ms; }
.oy-pair figcaption { --d: 380ms; }
.oy-combo .oy-dev--ph { --d: 220ms; }
.oy-combo figcaption { --d: 420ms; }
.oy-side--flip .oy-words, .oy-phone--flip .oy-words { --d: 160ms; }

.js .wb-reveal.is-visible .oy-dev--mac,
.js .wb-reveal.is-visible .oy-dev--ph,
.js .wb-reveal.is-visible .oy-words,
.js .wb-reveal.is-visible figcaption { opacity: 1; transform: none; }

/* The opening plays once, on load: the devices rise, then the words */
@keyframes oy-rise {
  from { opacity: 0; transform: translateY(var(--oy-rise, 28px)) scale(var(--oy-scale, 1)); }
  to { opacity: 1; transform: none; }
}
.js .oy-hero__mac { --oy-rise: 90px; --oy-scale: 0.94; animation: oy-rise 1400ms var(--wb-ease) 80ms both; }
.js .oy-hero__phone { --oy-rise: 160px; --oy-scale: 0.9; animation: oy-rise 1400ms var(--wb-ease) 300ms both; }
.js .oy-hero__say > * { animation: oy-rise 1000ms var(--wb-ease) both; }
.js .oy-hero__say > :nth-child(1) { animation-delay: 420ms; }
.js .oy-hero__say > :nth-child(2) { animation-delay: 500ms; }
.js .oy-hero__say > :nth-child(3) { animation-delay: 600ms; }
.js .oy-hero__say > :nth-child(4) { animation-delay: 700ms; }

@media (prefers-reduced-motion: reduce) {
  .js .wb-reveal .oy-dev--mac, .js .wb-reveal .oy-dev--ph,
  .js .wb-reveal .oy-words, .js .wb-reveal figcaption { transform: none; }
  .js .oy-hero__mac, .js .oy-hero__phone, .js .oy-hero__say > * { --oy-rise: 0px; --oy-scale: 1; }
}

/* ==========================================================================
   The rebuild: five interactions, each shown moving
   ========================================================================== */

/* A device that can play its own screen. The mockup is the still; the clip
   (assets/video/oyoun/<name>.mp4) lies exactly over the page area under the
   browser bar and fades in once it has a frame. No clip, no change. */
.oy-shot { position: relative; display: block; }
.oy-shot img { width: 100%; }
.oy-clip {
  position: absolute;
  z-index: 1;
  object-fit: cover;
  opacity: 0;
  transition: opacity 700ms ease;
  pointer-events: none;
  background: transparent;
}
.oy-clip.is-ready { opacity: 1; }
/* measured on the 3200 x 2057 laptop and the 1187 x 2399 phone */
.oy-shot--mac .oy-clip { left: 9.69%; top: 8.95%; width: 80.56%; height: 73.07%; }
/* the phone frame leans 0.68deg, so the clip leans with it */
.oy-shot--ph .oy-clip { left: 5.9%; top: 13.55%; width: 88.54%; height: 75.91%; transform: rotate(-0.68deg); }
/* phones caught with Safari's bar collapsed: the page runs from just under
   the small address line down into the rounded corners */
.oy-shot--full .oy-clip { top: 10.5%; height: 87.04%; border-radius: 0 0 14.3% 14.3% / 0 0 7.2% 7.2%; }

/* ---------- Contents: the five interactions at a glance ---------- */
.oy-index { padding: clamp(24px, 4vh, 48px) var(--wb-pad) clamp(40px, 7vh, 80px); }
/* one row of six screens, on the same left edge as the line above */
.oy-index ol {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: clamp(12px, 1.4vw, 20px);
  width: min(100%, var(--wb-max));
  margin: 0 auto;
  padding: 0;
  list-style: none;
}
.oy-index a {
  display: grid;
  gap: 10px;
  color: inherit;
  text-decoration: none;
}
/* the screen only, cut from the laptop still: page area 310,184 to 2888,1687 */
.oy-index__thumb {
  display: block;
  overflow: hidden;
  aspect-ratio: 2578 / 1503;
  border-radius: 6px;
  background: #222;
  outline: 1px solid rgb(237 234 227 / 0.1);
  transition: transform 500ms var(--wb-ease), outline-color 300ms ease;
}
.oy-index__thumb img {
  display: block;
  width: 124.13%;
  max-width: none;
  margin: -7.14% 0 0 -12.02%;
}
.oy-index__meta { font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; }
.oy-index__k { color: var(--wb-muted); }
.oy-index__t { font-size: 15px; line-height: 1.3; transition: color 300ms ease; }
.oy-index a:hover .oy-index__thumb, .oy-index a:focus-visible .oy-index__thumb { transform: translateY(-6px); outline-color: var(--portfolio-accent-text, #c6f432); }
.oy-index a:hover .oy-index__t, .oy-index a:focus-visible .oy-index__t { color: var(--portfolio-accent-text, #c6f432); }

/* narrower: the row scrolls sideways instead of shrinking */
@media (max-width: 1099px) {
  .oy-index { padding-inline: 0; }
  .oy-index ol {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: clamp(150px, 42vw, 220px);
    width: 100%;
    padding: 0 var(--wb-pad) 6px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--wb-pad);
    scrollbar-width: none;
  }
  .oy-index ol::-webkit-scrollbar { display: none; }
  .oy-index li { scroll-snap-align: start; }
}
@media (max-width: 899px) {
  .oy-index ol { padding-inline: 16px; scroll-padding-inline: 16px; }
}

/* ---------- One interaction ---------- */
.oy-ix { scroll-margin-top: 96px; padding-top: clamp(64px, 12vh, 140px); }
.oy-ix__head {
  display: grid;
  gap: 20px;
  width: min(100%, var(--wb-max));
  margin: 0 auto;
  padding: 0 var(--wb-pad);
}
.oy-ix__head h2 {
  margin: 0;
  font-size: clamp(36px, 5.2vw, 80px);
  line-height: 1;
  letter-spacing: -0.03em;
}
.oy-ix__body { max-width: 40ch; margin: 0; color: var(--wb-muted); font-size: clamp(18px, 1.5vw, 21px); line-height: 1.5; }
.oy-ix figcaption b { color: var(--wb-page-text, #edeae3); font-weight: 600; }

/* 40 -> 5 -> 1, the services in one line */
.oy-count {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: clamp(12px, 3vw, 56px);
  width: min(100%, var(--wb-max));
  margin: clamp(48px, 9vh, 112px) auto 0;
  padding: 0 var(--wb-pad);
  font-size: clamp(88px, 17vw, 280px);
  line-height: 0.85;
  letter-spacing: -0.05em;
}
.oy-count i { font-style: normal; font-size: 0.32em; color: var(--wb-muted); }
.oy-count span:last-child { color: var(--oy-orange); }
.oy-count__key {
  margin: 18px 0 0;
  color: var(--wb-muted);
  font-size: 13px;
  letter-spacing: 0.1em;
  text-align: center;
  text-transform: uppercase;
}

/* ---------- The rest of the system, sideways ---------- */
.oy-strip { position: relative; margin-top: clamp(64px, 12vh, 140px); }
.oy-strip__stick {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(24px, 5vh, 56px);
  min-height: 100svh;
  padding: 96px 0 48px;
  overflow: hidden;
}
.oy-strip__head { width: min(100%, var(--wb-max)); margin: 0 auto; padding: 0 var(--wb-pad); }
.oy-strip__head h2 { margin: 0; font-size: clamp(32px, 4.6vw, 64px); line-height: 1.04; letter-spacing: -0.02em; }
.oy-strip__head p { max-width: 46ch; margin: 14px 0 0; color: var(--wb-muted); font-size: 18px; line-height: 1.6; }
.oy-strip__track {
  --oy-row: clamp(220px, 46svh, 540px);
  display: flex;
  align-items: flex-end;
  gap: clamp(24px, 4vw, 64px);
  padding: 0 var(--wb-pad);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
}
.oy-strip__track::-webkit-scrollbar { display: none; }
.oy-strip__item { flex: none; margin: 0; scroll-snap-align: start; }
/* sized by height, so each device is whole: width follows its own shape */
.oy-strip__item .oy-shot { width: calc(var(--oy-row) * 3200 / 2057); }
.oy-strip__item--ph .oy-shot { width: calc(var(--oy-row) * 1187 / 2399); }
.oy-strip__item figcaption { max-width: 34ch; }
/* With scripts/oyoun.js the section grows tall and the row is moved across
   as you scroll down; the row itself no longer scrolls */
.oy-strip.is-driven .oy-strip__stick { position: sticky; top: 0; height: 100svh; }
.oy-strip.is-driven .oy-strip__track { overflow: visible; scroll-snap-type: none; will-change: transform; }

@media (max-width: 899px) {
  .oy-ix__head, .oy-count, .oy-strip__head, .oy-strip__track { padding-inline: 16px; }
  .oy-ix__head h2 br, .oy-say h2 br { display: none; }
  .oy-strip__track { --oy-row: clamp(170px, 28svh, 260px); }
}

@media (prefers-reduced-motion: reduce) {
  .oy-clip { display: none; }
}

/* ---------- The fold: 40 -> 5 -> 1, played by scrolling ----------
   scripts/oyoun.js adds .is-driven: the section grows tall, the stage sticks,
   and forty dots gather into five pillars, then into one eye that follows
   the cursor. Without it, the plain count stays. */
.oy-fold { position: relative; }
.oy-fold__stick { display: none; }
.oy-fold.is-driven { height: 320svh; }
.oy-fold.is-driven .oy-count, .oy-fold.is-driven .oy-count__key { display: none; }
.oy-fold.is-driven .oy-fold__stick {
  position: sticky;
  top: 0;
  display: grid;
  grid-template-rows: 1fr auto;
  justify-items: center;
  height: 100svh;
  padding: 96px var(--wb-pad) clamp(40px, 8vh, 88px);
  overflow: hidden;
}
.oy-fold__stage { width: min(100%, 1100px); height: 100%; min-height: 0; overflow: visible; }
.oy-fold__dots circle { fill: var(--wb-page-text, #edeae3); }
.oy-fold__dots circle.is-lit { fill: var(--oy-orange); }
.oy-fold__white { fill: var(--oy-orange); }
.oy-fold__pupil { fill: #151513; }
.oy-fold__eye { opacity: 0; transform: scale(0.2); transform-box: fill-box; transform-origin: center; }
.oy-fold__read {
  display: flex;
  align-items: baseline;
  gap: clamp(14px, 2vw, 28px);
  margin: 0;
}
.oy-fold__num {
  min-width: 2ch;
  font-size: clamp(72px, 11vw, 168px);
  line-height: 0.85;
  letter-spacing: -0.05em;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.oy-fold__num.is-one { color: var(--oy-orange); }
.oy-fold__key { color: var(--wb-muted); font-size: 13px; letter-spacing: 0.1em; text-transform: uppercase; }

/* ---------- Phones read the phone first ----------
   A laptop shrunk to a phone's width is unreadable, so below 900px each pair
   stacks: the phone recording leads at a size you can read, the laptop
   follows across the full width. */
@media (max-width: 899px) {
  .oy-combo__devices,
  .oy-combo--flip .oy-combo__devices { grid-template-columns: minmax(0, 1fr); justify-items: center; gap: 40px; }
  .oy-combo .oy-dev--ph { order: -1; width: min(70%, calc(64svh * 1187 / 2399)); }
  .oy-combo .oy-dev--mac { width: 100%; }
  .oy-combo .oy-dev--ph { --d: 0ms; }
  .oy-combo .oy-dev--mac { --d: 180ms; }

  /* tighter rhythm: one chapter flows into the next */
  .oy-ix { padding-top: 72px; }
  .oy-ix__head { gap: 16px; }
  .oy-side, .oy-pair, .oy-combo, .oy-wide, .oy-phone { padding-block: 40px; }
  .oy-pair { gap: 40px; }
  .oy-fold.is-driven { height: 260svh; }
  .oy-fold.is-driven .oy-fold__stick { padding: 88px 16px 128px; }
  .oy-fold__read { flex-direction: column; align-items: center; gap: 10px; }
  .oy-fold__num { text-align: center; }
}
.oy-fold__links line { stroke: var(--wb-muted); stroke-width: 1.5; stroke-dasharray: 1; stroke-dashoffset: 1; opacity: 0.55; }
.oy-fold__glint { fill: #edeae3; opacity: 0.85; }

/* Process: the steps are one line each here, so the cells hug their words
   instead of standing 290px tall (woodberg.css keeps that for other cases) */
.oy .wb-phases li { min-height: 0; }
