/* ===================================================================
   projects.css — the home page's work section.

   A pinned rail hijacks vertical scroll: you had to travel sideways
   through every screen of a project before the page would move on.
   This does the opposite. The meta column is `position: sticky`, which
   is pure CSS and costs the scroll nothing, while the screens flow
   past it as an ordinary vertical column. Scroll behaves the way the
   reader expects, and the project's context stays on screen the whole
   time they are looking at its work.
   =================================================================== */

.pj {
  position: relative;
  border-top: 1px solid var(--m-border);
}

.pj__grid {
  max-width: var(--m-wide-max);
  margin: 0 auto;
  padding: clamp(4rem, 10vh, 8rem) var(--m-gutter);
  display: grid;
  grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: start;
}

/* ---- left: the column that stays ---- */

.pj__meta {
  position: sticky;
  top: clamp(4rem, 16vh, 9rem);
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.pj__kicker {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .6rem;
  margin: 0;
  font-size: .6875rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--m-fg-subtle);
}
.pj__kicker i {
  font-style: normal;
  width: 3px; height: 3px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

.pj__title {
  margin: 0;
  font-size: clamp(1.6rem, 2.4vw, 2.35rem);
  line-height: 1.08;
  letter-spacing: -.033em;
  font-weight: 300;
  color: var(--m-fg);
  text-wrap: balance;
}

.pj__outcome {
  margin: 0;
  font-size: .9375rem;
  line-height: 1.65;
  font-weight: 300;
  color: var(--m-fg-muted);
  text-wrap: pretty;
}

/* Stats used to sit side by side in equal columns. Inside a 20rem sticky
   column three of them are 90px each, so "10.5% → 3.5%" wrapped under its
   own arrow and the labels broke onto three ragged lines. Stacking is the
   only layout that survives any value length and any number of stats, and
   it buys the label a full column — enough room to say what the number
   means instead of shouting two cramped uppercase words. */
.pj__stats {
  display: grid;
  gap: .9rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--m-border);
}
.pj__stat {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: .15rem;
}
.pj__stat b {
  font-weight: 400;
  letter-spacing: -.02em;
  line-height: 1.1;
  color: var(--m-fg);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  /* surface.css sets 1.5rem. "10.5% → 3.5%" is the longest value on the page
     and at 1.5rem it fills the 20rem column edge to edge, so any narrower
     column pushes it out. 1.375rem leaves it room and nothing else changes. */
  font-size: 1.375rem;
}
.pj__stat span {
  font-size: .8125rem;
  letter-spacing: 0;
  font-weight: 300;
  color: var(--m-fg-muted);
  line-height: 1.45;
}

.pj__cta {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  align-self: flex-start;
  font-size: .875rem;
  color: var(--m-fg);
  text-decoration: none;
  padding-bottom: .3rem;
  border-bottom: 1px solid var(--m-border-strong);
  transition: border-color .3s var(--m-ease), gap .3s var(--m-ease);
}
.pj__cta:hover { border-bottom-color: var(--m-fg); gap: .85rem; }
.pj__cta svg { width: .8em; height: .8em; }

/* ---- right: the stream ---- */

.pj__stream {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(1.5rem, 3vw, 2.75rem) clamp(1rem, 2vw, 1.75rem);
  align-items: start;
}

.pj__shot { margin: 0; min-width: 0; }

/* Widths and offsets vary so the column reads as a composition rather
   than a stack. Set per item in the markup via data-span / data-offset. */
.pj__shot { grid-column: span 12; }
.pj__shot[data-span="7"]  { grid-column: span 7; }
.pj__shot[data-span="8"]  { grid-column: span 8; }
.pj__shot[data-span="5"]  { grid-column: span 5; }
.pj__shot[data-span="6"]  { grid-column: span 6; }
.pj__shot[data-offset="1"] { margin-left: 8%; }
.pj__shot[data-offset="2"] { margin-top: clamp(1.5rem, 5vw, 4rem); }

.pj__frame {
  position: relative;
  border-radius: 14px;
  border: 1px solid var(--m-border);
  background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.015));
  padding: .5rem;
  overflow: hidden;
  transition: border-color .5s var(--m-ease);
}
.pj__shot:hover .pj__frame { border-color: var(--m-border-strong); }

.pj__frame::before {
  content: "";
  position: absolute;
  top: .5rem; left: .5rem; right: .5rem;
  height: 1.5rem;
  border-radius: 9px 9px 0 0;
  background:
    radial-gradient(circle at .75rem 50%, rgba(255,255,255,.22) 2.5px, transparent 3px),
    radial-gradient(circle at 1.45rem 50%, rgba(255,255,255,.22) 2.5px, transparent 3px),
    radial-gradient(circle at 2.15rem 50%, rgba(255,255,255,.22) 2.5px, transparent 3px),
    rgba(255,255,255,.05);
  z-index: 1;
  pointer-events: none;
}

.pj__frame img {
  display: block;
  width: 100%;
  height: auto;
  padding-top: 1.5rem;
  box-sizing: border-box;
  border-radius: 9px;
  background: var(--m-surface);
}

/* ---- phones ----
   A phone screen is nearly 2.2 times taller than it is wide, so at the width
   of a grid column it stands taller than the window it is being read in and
   the reader only ever sees its top third. Here the height is the constraint
   and the width follows from it, so a whole screen is always on screen at
   once, and the pair is centred in the stream rather than left in columns
   that are now much wider than the phones sitting in them. */
.pj__stream:has(.pj__shot--phone) {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: clamp(1.25rem, 3vw, 2.5rem);
}
/* The phone's width comes from its height cap and the capture's ratio
   (662x1432 and 590x1280, both 0.462 wide for tall), so the figure is given
   that width outright. Without it the figure is as wide as its caption wants
   to be, and the caption then runs past the side of the phone it describes. */
.pj__shot--phone { flex: 0 1 auto; min-width: 0; max-width: calc(min(62vh, 620px) * 0.462); }

.pj__shot--phone .pj__frame {
  border: none;
  background: none;
  padding: 0;
  border-radius: 0;
  overflow: visible;
  display: flex;
  justify-content: center;
}
.pj__shot--phone .pj__frame::before { display: none; }

/* The captures are screen content with no device chrome of their own, so the
   bezel is drawn here — the same one every case page uses, so a screen looks
   identical on the home and inside the study. */
.pj__shot--phone .pj__frame img,
.pj__shot--phone .pj__frame video {
  display: block;
  padding-top: 0;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: min(62vh, 620px);
  border: 5px solid #0B0B0D;
  border-radius: 26px;
  background: #0B0B0D;
  box-sizing: border-box;
  filter: drop-shadow(0 24px 48px rgba(0, 0, 0, .55));
}
.pj__shot--phone .pj__cap { max-width: none; margin-inline: auto; }


.pj__cap {
  text-align: left;
  margin-top: .85rem;
  font-size: .8125rem;
  line-height: 1.5;
  font-weight: 300;
  color: var(--m-fg-subtle);
  max-width: none;
}
.pj__cap b {
  display: block;
  font-weight: 400;
  color: var(--m-fg-muted);
  margin-bottom: .2rem;
}

/* ---- narrow ---- */

@media (max-width: 900px) {
  .pj__grid {
    grid-template-columns: 1fr;
    gap: 2.5rem;
    padding-top: clamp(3rem, 8vh, 4.5rem);
    padding-bottom: clamp(3rem, 8vh, 4.5rem);
  }
  /* Sticky in a single column would pin the meta over its own screens. */
  .pj__meta { position: static; }
  .pj__stream { display: flex; flex-direction: column; gap: 2rem; }
  .pj__shot,
  .pj__shot[data-offset="1"],
  .pj__shot[data-offset="2"] { margin: 0; }
  .pj__stream:has(.pj__shot--phone) { display: flex; flex-direction: column; align-items: center; }
  .pj__shot--phone { align-self: center; max-width: 17rem; }
  .pj__shot--phone .pj__frame img,
  .pj__shot--phone .pj__frame video { max-height: none; width: 100%; }
  .pj__shot--phone .pj__cap { text-align: left; max-width: none; }
}
