/* Featured mockups — marquee spotlight showcase (rendered by featured.js).
   Three rows of preview thumbnails drift horizontally inside a dark stage;
   featured.js periodically FLIPs one card out of its row to center stage,
   zoomed up with its meta and links, then returns it to the flow. Scoped
   under .featured / .frow / .mcard / .fspot so it never collides with the
   page styles.

   Fonts: PP Neue Montreal + PP Mondwest are licensed Pangram Pangram cuts and
   are not committed. Drop the woff2 files into site/fonts/ with these names;
   until then every stack degrades cleanly to system fonts. */

@font-face {
  font-family: 'PP Neue Montreal';
  src: url('/fonts/PPNeueMontreal-Book.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'PP Neue Montreal';
  src: url('/fonts/PPNeueMontreal-Medium.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'PP Neue Montreal';
  src: url('/fonts/PPNeueMontreal-SemiBold.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'PP Mondwest';
  src: url('/fonts/PPMondwest-Regular.woff2') format('woff2');
  /* single cut; the range stops the browser faux-bolding the 600 titles */
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
}

.featured {
  --f-ink: #051A24;
  --f-ink-2: #0D212C;
  --f-muted: #273C46;
  --f-body: 'PP Neue Montreal', 'Helvetica Neue', system-ui, -apple-system, sans-serif;
  --f-serif: 'PP Mondwest', Georgia, 'Times New Roman', serif;
  --f-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  /* shared rhythm for rows + track gaps so the loop math stays consistent */
  --f-gap: clamp(14px, 2vw, 24px);
  /* the whole section is the stage: the marquee reads as its background */
  background: var(--f-ink);
  color: #F2F6F8;
  font-family: var(--f-body);
  padding: 0; /* the inner wrapper owns spacing; overrides the page section rule */
}
.featured__inner {
  max-width: 1200px;
  margin-inline: auto;
  padding-block: 96px;
  padding-inline: 24px;
}

/* Header — title block on the left, "View all" CTA pinned to the right end.
   Wraps to a stacked layout on narrow screens. */
.featured__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px 32px;
  flex-wrap: wrap;
  margin-bottom: clamp(40px, 6vw, 64px);
}
.featured__head-text { min-width: 0; }
.featured__eyebrow {
  font-family: var(--f-mono);
  font-size: 12px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: rgba(242, 246, 248, 0.55);
}
.featured__title {
  font-family: var(--f-body);
  font-weight: 600;
  font-size: clamp(32px, 5vw, 44px);
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: #fff;
  margin-top: 14px;
}
.featured__serif { font-family: var(--f-serif); font-weight: 400; }

/* "View all" CTA — sits at the right end of the header row (see .featured__head) */
.featured__cta {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 1px solid rgba(255, 255, 255, 0.4);
  color: #fff;
  border-radius: 999px;
  padding: 12px 28px;
  font-size: 14px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  transition: transform 0.3s ease-out, background 0.2s ease;
}
.featured__cta:hover { transform: translateY(-2px); background: rgba(255, 255, 255, 0.1); }

/* Stage — no panel, no border: the rows are the section's background, bleeding
   edge-to-edge across the viewport while the header keeps the content width. */
.featured__stage {
  position: relative;
  overflow: clip;
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  padding-block: clamp(8px, 1.5vw, 20px);
}

.featured__rows {
  display: grid;
  gap: var(--f-gap);
}

/* One marquee row. The track inside it is twice the card set wide and is
   translated by featured.js via WAAPI; the mask fades the loop's edges. */
.frow {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.frow__track {
  display: flex;
  gap: var(--f-gap);
  width: max-content;
  will-change: transform;
}

/* Marquee card — a preview.png thumbnail with a tint-colored edge glow.
   It's a <button>: clicking spotlights the mockup. */
.mcard {
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid oklch(from var(--tint, #89AACC) l c h / 0.35);
  padding: 0;
  font: inherit;
  flex: 0 0 auto;
  width: clamp(180px, 22vw, 300px);
  aspect-ratio: 16 / 10;
  border-radius: 14px;
  overflow: hidden;
  background: var(--f-ink-2);
  box-shadow: 0 0 24px oklch(from var(--tint, #89AACC) l c h / 0.12);
  cursor: pointer;
  transition: transform 0.3s ease, box-shadow 0.3s ease, opacity 0.3s ease;
}
.mcard:hover,
.mcard:focus-visible {
  transform: translateY(-3px);
  box-shadow: 0 0 34px oklch(from var(--tint, #89AACC) l c h / 0.3);
}
.mcard:focus-visible {
  outline: 2px solid oklch(from var(--tint, #89AACC) l c h / 0.8);
  outline-offset: 2px;
}
.mcard__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Slot keeper while its card is on the spotlight stage — invisible but still
   occupying its place in the flow so the loop geometry never changes. */
.mcard.is-ghost {
  opacity: 0;
  pointer-events: none;
  transform: none;
}

/* Veil — dims and desaturates the drifting rows behind the spotlight. */
.featured__veil {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: rgba(5, 26, 36, 0.72);
  -webkit-backdrop-filter: saturate(0.4);
  backdrop-filter: saturate(0.4);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s ease;
}
.featured__stage.is-spotlighting .featured__veil { opacity: 1; }

/* Flight clone — featured.js positions it with inline top/left/width/height
   and animates only its transform. Lives on <body>, hence position: fixed. */
.fspot-clone {
  position: fixed;
  z-index: 60;
  margin: 0;
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid oklch(from var(--tint, #89AACC) l c h / 0.5);
  box-shadow: 0 24px 64px rgba(2, 12, 18, 0.55), 0 0 44px oklch(from var(--tint, #89AACC) l c h / 0.28);
  background: var(--f-ink-2);
  pointer-events: none;
  will-change: transform;
  transform-origin: top left;
}
.fspot-clone img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Spotlight layer — centered figure + meta panel over the dimmed rows. */
.fspot {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(14px, 2vw, 22px);
  padding: clamp(20px, 3vw, 40px);
  pointer-events: none;
}
.fspot {
  /* the stage card is ALWAYS exactly 16:10 — the same framing as preview.png
     and the marquee cards, so the flight lands with zero crop-jump and a
     uniform scale. featured.js overrides --spot-w with the exact largest
     16:10 that fits the stage; this is only the pre-measure fallback. */
  --spot-w: min(62vw, 780px, 92%);
}
.fspot__figure {
  display: block;
  flex: none; /* never let the centered column squash the 16:10 box */
  width: var(--spot-w);
  aspect-ratio: 16 / 10;
  border-radius: clamp(14px, 1.6vw, 20px);
  overflow: hidden;
  border: 1px solid oklch(from var(--tint, #89AACC) l c h / 0.5);
  box-shadow: 0 24px 64px rgba(2, 12, 18, 0.55), 0 0 44px oklch(from var(--tint, #89AACC) l c h / 0.28);
  background: var(--f-ink-2);
  opacity: 0;
}
.fspot__figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.fspot.is-open .fspot__figure { opacity: 1; }
.fspot.is-open { pointer-events: auto; }

/* Meta — index numeral, then a two-row caption: the eyebrow and title own the
   full stage width on top, the client and links sit on the row beneath. The
   title never shares its row with the buttons, which is what used to crush it
   into a one-word-per-line column. Fades and rises a beat after the card lands. */
.fspot__meta {
  display: flex;
  flex: none;
  align-items: center;
  gap: clamp(14px, 2.5vw, 28px);
  /* Normally the caption lines up with the figure's edges. On a short or narrow
     stage the figure is sized down to fit, and matching that width would squeeze
     the title into a column again — so the caption keeps a 34rem floor (capped
     at the stage) and simply runs wider than the picture. */
  width: min(100%, max(var(--spot-w), 34rem));
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.5s ease 0.25s, transform 0.5s ease 0.25s;
}
.fspot.is-open .fspot__meta {
  opacity: 1;
  transform: translateY(0);
}
.fspot__num {
  flex: none;
  font-family: var(--f-serif);
  font-weight: 400;
  line-height: 0.9;
  font-size: clamp(2rem, 4.5vw, 58px);
  color: var(--tint, #89AACC);
}
/* the caption's two rows; everything to the right of the numeral */
.fspot__body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(10px, 1.4vw, 16px);
}
.fspot__text { min-width: 0; }
.fspot__type {
  display: block;
  font-family: var(--f-mono);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--tint, #9FB3BD);
}
.fspot__name {
  font-family: var(--f-serif);
  font-weight: 600;
  line-height: 1.12;
  /* Sized so even the longest name in the registry ("Setia Air-Cond &
     Electrical — Sticky Building Hero (v2)", 55 chars) holds one line at the
     780px stage — a uniform cap rather than per-item shrinking, because this
     slot re-renders every few seconds and jittering type would show. The vw
     term tracks the stage as it narrows; balance catches any rare wrap. */
  font-size: clamp(1.1rem, 1.9vw, 1.5rem);
  text-wrap: balance;
  color: #fff;
  margin-top: 6px;
}
/* second row — client on the left, the two links pinned to the right end */
.fspot__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px 18px;
  flex-wrap: wrap;
}
.fspot__client {
  min-width: 0;
  font-size: 13px;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.65);
}
.fspot__links {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  flex: none;
}
.fspot__link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: 999px;
  padding: 10px 20px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #fff;
  white-space: nowrap;
  transition: background 0.2s ease;
}
.fspot__link:hover { background: rgba(255, 255, 255, 0.1); }
.fspot__link svg { width: 13px; height: 13px; }

@media (max-width: 720px) {
  .featured__inner { padding-block: 72px; }
  .fspot { --spot-w: min(92vw, 480px, 100%); }
  .fspot__meta { gap: 12px; }
  .fspot__body { gap: 10px; }
  .fspot__link { padding: 9px 16px; }
}

@media (max-width: 560px) {
  /* below this the two pills can no longer share a row with the client name,
     so give them the whole width rather than hyphenating the company */
  .fspot__links { flex-basis: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .mcard,
  .fspot__link,
  .featured__cta { transition: none; }
  .mcard:hover,
  .mcard:focus-visible { transform: none; }
  /* the crossfade fallback still eases opacity — that's the one motion kept */
  .fspot__figure { transition: opacity 0.4s ease; }
  .fspot__meta { transition: opacity 0.4s ease 0.1s; transform: none; }
}
