/* ============================================================================
   Case-study template. Loaded after css/ds.css, scoped to body.project.
   Swiss grid: one 12-column field per section, a sticky numbered rail on the
   left, flush-left type, hairlines everywhere, and accent blocks to break the
   run of dark. The legacy `.case-study` rules in style.css are untouched.
   ========================================================================== */

/* ============================================================================
   DISPLAY FACE
   Opt in per page with <body class="project" data-display="stack">.
   Right now that is every case study. The about page opts in through its
   .about class instead, because data-display="stack" would also switch on
   the panel stack, which About does not use. The face itself
   (Open Sauce Sans) is declared once, in ds.css, and shared with .home.

   TO CHANGE THE FACE  -> replace the file, then edit ds.css and the line
                          marked (1) below. Nothing else references it.
   TO REVERT THIS PAGE -> delete data-display="stack" from that page's <body>.
   TO APPLY ELSEWHERE  -> add the same attribute to that page's <body>.
   ========================================================================== */
/* ---------- Self-hosted Instrument Serif (uploaded files, SIL OFL 1.1) ----------
   Registered under its own family name so it can't be confused with the
   italic Google Fonts serves as 'Instrument Serif'.
   - Italic: About's serif accents, swapped in through --serif (trial).
     TO REVERT that part -> delete the .project.about main rule below. */
@font-face {
  font-family: 'Instrument Serif Local';
  src: url('/assets/fonts/InstrumentSerif-Italic.ttf') format('truetype');
  font-style: italic;
  font-weight: 400;
  font-display: swap;
}
.project.about main { --serif: 'Instrument Serif Local', 'Instrument Serif', Georgia, serif; }

/* Scoped to <main>: the page's headings and large bold text change, while the
   nav wordmark and footer stay on the shared face, so the site chrome still
   matches every other page. */
.project[data-display="stack"] main,
.project.about main {
  --font-display: 'Open Sauce Sans', 'Inter Tight', Inter, sans-serif;   /* (1) */
  font-synthesis-weight: none;
}

/* The nav's shared background is translucent + blurred, meant to show a soft
   hint of whatever scrolls under it. That reads fine normally, but this page
   has an opaque, high-contrast panel (with its own box-shadow) parked
   directly under the nav for a stretch during the stack effect above — the
   blur turns that into a smeared, discoloured strip. A plain opaque backing,
   painted before the nav's own text/links, hides the blur instead of the
   panel behind it. NOX only — every other page keeps the normal see-through
   nav. */
.project[data-display="stack"] .site-nav::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1; /* .wrap (brand + links) is a plain non-positioned box, which
                  paints ahead of a z-index:auto positioned one regardless of
                  DOM order — only a negative z-index reliably stays behind it */
  background: var(--card-bg);
  pointer-events: none;
}

/* ---------- The field ----------
   One 12-column field, declared once. Every block that subdivides the page
   uses it, so its internal rules land on the same lines as the section
   content instead of inventing their own tracks a few pixels off. */
.project .pj-field {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--col-gap);
}

/* The hairline is a border on the cell, so it lands exactly on the field's
   column line — no absolute positioning, no negative offset, no calc(), which
   is what WebKit was dropping. One gutter of air on each side of it: the grid
   gap before the rule, the cell's own padding after it. */
.project .pj-facts > div,
.project .pj-phase { position: relative; }
.project .pj-facts > div:not(:first-child) {
  border-left: 1px solid var(--rule);
  padding-left: var(--col-gap);
}
.project .pj-phase:not(:first-child) { padding-left: var(--col-gap); }

/* ---------- Strong rules ----------
   Text blocks carry no rules anywhere on the site: statements, quotes, lists
   and captions stand on type and space alone. What is left is structure
   (the facts strip, the next-project row, charts and tables) and the accent
   rule that opens stats, phases and, below the side rail, each section.
   The heavy white rule shares one treatment: solid across most of the
   measure, then dissolving into the background at the right-hand end.

   Drawn as a background rather than a border, because a border cannot carry a
   gradient without border-image — and border-image repaints every edge, which
   would also swallow the quiet hairline under the facts strip. The 1px dark
   hairlines are deliberately left alone: they are the quiet tier. */
.project {
  /* One size for every inset line inside a section: quotes, statements,
     the How Might We. */
  --insert-size: clamp(1.3rem, 2.3vw, 1.9rem);
  --rule-strong: linear-gradient(to right,
    var(--ink) 0%,
    var(--ink) 58%,
    rgba(243, 241, 236, 0.66) 78%,
    rgba(243, 241, 236, 0.22) 91%,
    rgba(243, 241, 236, 0) 100%);
}
.project .pj-facts {
  background-image: var(--rule-strong);
  background-repeat: no-repeat;
  background-size: 100% 2px;
  background-position: left top;
}

/* Cut-outs start their entrance scaled up and overflow visibly; at full
   width that would add a sideways scroll until they settle. clip, not
   hidden: it creates no scroll container, so the sticky panels still work. */
.project main { overflow-x: clip; }

/* ---------- Page header ---------- */

.project .pj-hero { position: relative; overflow: hidden; }
.project .pj-hero-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}
.project .pj-hero-bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 58%;
  opacity: 0.4;
}
.project .pj-hero-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, var(--bg) 0%, rgba(18, 17, 16, 0.72) 22%, rgba(18, 17, 16, 0.3) 58%, var(--bg) 100%),
    linear-gradient(to right, var(--bg) 0%, rgba(18, 17, 16, 0.6) 38%, rgba(18, 17, 16, 0.25) 100%);
}
.project .pj-head { position: relative; z-index: 1; }

.project .pj-head {
  padding-top: clamp(2rem, 5vh, 3.5rem);
  padding-bottom: clamp(2.5rem, 6vh, 4.5rem);
}

.project .pj-tags {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem 1.5rem;
  padding-bottom: 1rem;
}

/* Project facts, sitting above the title. Four facts on the field, three
   columns each, so the strip is a decision rather than a by-product of how
   many <div>s happen to be in it. */
.project .pj-facts {
  margin: 0 0 clamp(2.5rem, 6vw, 4.5rem);
  border-bottom: 1px solid var(--rule);
}
.project .pj-facts > div {
  grid-column: span 3;
  padding: 0.95rem 0 1.1rem;
}
/* The label names the field; the value is the thing you came to read, so the
   value carries the weight and the label recedes. */
.project .pj-facts dt {
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.project .pj-facts dd {
  margin: 0.45rem 0 0;
  font-family: var(--font-display);
  font-size: var(--fs-lead);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--ink);
}

/* ---------- Team roster ----------
   "4 people" opens the casefile's list of names: a panel that unrolls from
   the value's baseline (clip-path, top to bottom), opened by a 2px Kiln rule
   that draws across, then the names settle in one after another. It sits on
   Card Ground with a hairline edge, like every other raised surface: no
   shadow, no lift. Only built when a <dd data-team> lists two or more names
   (js/ui.js). */
.project .pj-team { z-index: 5; }
.project .pj-team dd { position: relative; }
.project .pj-team-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  cursor: pointer;
}
.project .pj-team-btn svg {
  flex: none;
  color: var(--ink-soft);
  transition: transform 0.5s var(--ease), color 0.35s var(--ease);
}
.project .pj-team.is-open .pj-team-btn svg { transform: rotate(180deg); color: var(--accent); }
.project .pj-team-btn:hover svg { color: var(--ink); }
/* Touch: the value is small, so the hit area grows to a finger's size. */
@media (pointer: coarse) {
  .project .pj-team-btn { position: relative; }
  .project .pj-team-btn::before { content: ""; position: absolute; inset: -12px -8px; }
}

.project .pj-team-panel {
  position: absolute;
  top: 100%;
  left: 0;
  width: max-content;
  min-width: 13.5rem;
  max-width: min(20rem, calc(100vw - 2.5rem));
  /* A bridge across the gap, so the pointer can travel from the value into
     the list without the hover dropping. */
  padding-top: 0.5rem;
  visibility: hidden;
  pointer-events: none;
  transition: visibility 0s linear 0.45s;
}
.project .pj-team-list {
  position: relative;
  list-style: none;
  margin: 0;
  padding: 0.35rem 1rem 0.45rem;
  background: var(--card-bg);
  border: 1px solid var(--rule-hi);
  clip-path: inset(0 0 100% 0);
  transition: clip-path 0.45s var(--ease-out);
}
/* The Kiln rule that opens the panel, drawn left to right. */
/* Frosted: the title and film behind stay faintly present through the
   panel. Browsers without backdrop-filter keep the solid Card Ground. */
@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .project .pj-team-list {
    background: rgba(26, 24, 22, 0.66);
    -webkit-backdrop-filter: blur(18px) saturate(1.2);
    backdrop-filter: blur(18px) saturate(1.2);
  }
}
.project .pj-team-list::before {
  content: "";
  position: absolute;
  left: -1px; right: -1px; top: -1px;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.6s var(--ease-out);
}
.project .pj-team-list li {
  display: flex;
  align-items: baseline;
  gap: 0.85rem;
  padding: 0.6rem 0;
  font-family: var(--font-body);
  font-size: var(--fs-note);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.35;
  color: var(--ink);
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}
.project .pj-team-list li + li { border-top: 1px solid var(--rule); }
.project .pj-team-no {
  flex: none;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.project .pj-team.is-open .pj-team-panel {
  visibility: visible;
  pointer-events: auto;
  transition-delay: 0s;
}
.project .pj-team.is-open .pj-team-list {
  clip-path: inset(0 0 0 0);
  transition-duration: 0.6s;
}
.project .pj-team.is-open .pj-team-list::before { transform: scaleX(1); transition-delay: 0.08s; }
.project .pj-team.is-open .pj-team-list li {
  opacity: 1;
  transform: none;
  transition-duration: 0.45s, 0.55s;
  transition-delay: calc(0.12s + var(--i, 0) * 0.05s);
}

@media (prefers-reduced-motion: reduce) {
  .project .pj-team-list,
  .project .pj-team-list::before,
  .project .pj-team-list li,
  .project .pj-team-btn svg { transition: none !important; }
  .project .pj-team-list li { transform: none; }
}

/* Title left, film right — a 6 | 6 split on the field, the same division the
   sections below use, instead of an arbitrary 6fr / 5.4fr. */
.project .pj-titlerow { row-gap: 2rem; }
.project .pj-titlerow > * { grid-column: 1 / -1; }
@media (min-width: 900px) {
  .project .pj-titlerow { align-items: start; }
  .project .pj-titlerow > :first-child { grid-column: span 6; }
  .project .pj-titlerow > :last-child { grid-column: 7 / span 6; }
}
.project .pj-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(2rem, 6.5vw, 5.75rem);
  line-height: 0.8;
  letter-spacing: -0.05em;
  margin: 0;
}
/* Subtitle under the page title: the same thin, wide Archivo caps as the
   "Ludovico Galassi" line on the home page. */
.project .pj-kicker {
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-weight: 100;
  font-size: clamp(1.05rem, 2vw, 1.6rem);
  line-height: 1.2;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
  margin: 1rem 0 0;
  max-width: 24ch;
}

/* About: the kicker splits into two tiers between the page title and the
   body, so the name reads as a step down from "About" and the role as a
   step down from the name. */
.project .ab-kicker { max-width: none; margin-top: 1.25rem; }
.project .ab-name {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.5rem, 3.6vw, 3.1rem);
  line-height: 1;
  letter-spacing: -0.035em;
  text-transform: none;
  font-stretch: normal;
  color: var(--ink);
}
.project .ab-role {
  display: block;
  margin-top: clamp(1.25rem, 2vw, 1.75rem);
  font-size: clamp(1rem, 1.7vw, 1.4rem);
}

/* Titles with a descender (the g of Lugh): the 0.8 line-height lets it hang
   below the line box, so the kicker is pushed clear by a share of the title
   size on top of a fixed base, never less than the usual 1rem gap. */
.project .pj-title--descender + .pj-kicker {
  margin-top: calc(0.6rem + clamp(2rem, 6.5vw, 5.75rem) * 0.2);
}

/* Two-word titles (Prime Couples): the longer word must fit the six-column
   half of the title row, so the face steps down from 6.5vw to 5.25vw. */
.project .pj-title--long { font-size: clamp(2rem, 5.25vw, 4.75rem); }
.project .pj-title--long.pj-title--descender + .pj-kicker {
  margin-top: calc(0.6rem + clamp(2rem, 5.25vw, 4.75rem) * 0.2);
}

/* Long titles that wrap onto several lines (Lifelong Learning Ecosystem):
   the 0.8 line-height lets a descender (the g) run into the capital on the
   line below, so these open up to 0.98. */
.project .pj-title--open { line-height: 0.98; }

/* A sentence for a title (Agosto, moglie mia non ti conosco): a step lower
   again, so it sets in two or three lines instead of five. */
.project .pj-title--longer { font-size: clamp(2rem, 3.3vw, 3.125rem); line-height: 0.95; }
.project .pj-title--longer.pj-title--descender + .pj-kicker {
  margin-top: calc(0.6rem + clamp(2rem, 3.3vw, 3.125rem) * 0.2);
}

/* Header media: every project's film or cover sits in the same 16:9 frame,
   whatever ratio its own poster has (Prime Couples' 1150/720, Weight of
   Words' 3024/1631…), so the header is the same height on every project.
   Posters crop to fill (object-fit: cover); a playing video letterboxes.
   The About page borrows this header for its portrait, so it is left out. */
.project:not(.about) .pj-titlerow .pj-video,
.project:not(.about) .pj-titlerow .pj-fig-media { aspect-ratio: 16 / 9; }
/* The note under it stays on one line (the longer caption truncates), so a
   caption that would wrap on narrower screens can't add a line either. */
.project:not(.about) .pj-titlerow .pj-video-note { flex-wrap: nowrap; }
.project:not(.about) .pj-titlerow .pj-video-note > * {
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.project:not(.about) .pj-titlerow .pj-video-note > :last-child { flex: none; }

/* ---------- Project pager ----------
   Previous / next arrows in the page gutter, left and right, vertically
   centred on the facts strip at the top of the header; hovering one turns
   it orange. The order wraps (01 ↔ 07). Below 900px the
   gutter is too narrow to hold them, and the "Next project" banner at the
   foot of the page carries the navigation instead. */
.project .pj-pager { display: none; }
.project .pj-facts-row { position: relative; }
@media (min-width: 900px) {
  .project .pj-pager { display: block; }
  .project .pj-pager-link {
    position: absolute;
    top: 50%;
    z-index: 2;
    display: flex;
    align-items: center;
    height: 36px;
    width: 36px;
    justify-content: center;
    border: 1px solid var(--rule-hi);
    border-radius: 999px;
    background: rgba(18, 17, 16, 0.72);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    color: var(--ink);
    text-decoration: none;
    transform: translateY(-50%);
    transition: border-color 0.35s var(--ease), background-color 0.35s var(--ease), color 0.35s var(--ease);
  }
  /* Pushed out of the content box into the gutter (3rem, 4rem from
     1400px), 6px in from its outer edge, so the 36px button never touches
     the strip. The facts' bottom margin collapses out of .pj-facts-row, so
     50% is the middle of the strip itself. */
  .project .pj-pager-prev { left: calc(-3rem + 6px); }
  .project .pj-pager-next { right: calc(-3rem + 6px); }
}
@media (min-width: 1400px) {
  .project .pj-pager-prev { left: calc(-4rem + 6px); }
  .project .pj-pager-next { right: calc(-4rem + 6px); }
}
@media (min-width: 900px) {
  .project .pj-pager-link svg { flex: none; transition: transform 0.35s var(--ease); }
  .project .pj-pager-link:hover,
  .project .pj-pager-link:focus-visible {
    border-color: var(--accent);
    background: var(--accent);
    color: var(--on-accent);
  }
  .project .pj-pager-prev:hover svg { transform: translateX(-2px); }
  .project .pj-pager-next:hover svg { transform: translateX(2px); }
}

/* ---------- Video facade ---------- */

.project .pj-video {
  margin: 0;
  position: relative;
  aspect-ratio: var(--video-ar, 16 / 9);
  overflow: hidden;
  background: var(--card-bg);
}
.project .pj-video::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--hairline);
  pointer-events: none;
  z-index: 3;
}
.project .pj-video-btn {
  position: absolute;
  inset: 0;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  color: inherit;
  font: inherit;
  display: block;
}
.project .pj-video-btn img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.9s var(--ease), opacity 0.6s var(--ease);
  opacity: 0.88;
}
.project .pj-video-btn:hover img { transform: scale(1.03); opacity: 1; }
.project .pj-play {
  position: absolute;
  left: 0; bottom: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.75rem 1.3rem;
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition: padding-right 0.4s var(--ease);
}
.project .pj-video-btn:hover .pj-play { padding-right: 2rem; }
.project .pj-play svg { width: 9px; height: 11px; fill: currentColor; }
.project .pj-video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; z-index: 2; }
.project .pj-video video { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 2; background: #000; object-fit: contain; }
.project .pj-video-note {
  margin: 0.7rem 0 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.35rem 1rem;
}

/* ---------- Section shell ---------- */

.project .pj-section {
  padding: clamp(4rem, 9vh, 7rem) 0;
}

@media (min-width: 1000px) {
  .project .pj-section {
    display: grid;
    grid-template-columns: minmax(0, 190px) minmax(0, 1fr);
    gap: clamp(2rem, 4vw, 4rem);
    align-items: start;
  }
  .project .pj-rail { position: sticky; top: calc(72px + 2.5rem); }
}

/* ---------- Panel stack (opt-in section overlap) ----------
   Every case study. Wrap a section in <div class="pj-panel-wrap"> and add
   "pj-panel" to the section itself: the panel sticks at the nav edge once
   scrolled to, and the next panel-wrap is pulled up early (negative margin)
   so it visibly climbs over the still-stuck panel instead of just following
   it. Desktop only — same breakpoint as the rail/grid above, which this
   nests inside; mobile keeps plain, ungimmicked scrolling.

   The wrap's extra scroll room comes from a ::after spacer, not
   padding-bottom: tested directly, Chrome's sticky implementation here
   ignores a containing block's own padding when computing how far a sticky
   child can travel — it needs an actual flow box (a real child, or a
   generated one) after the sticky element to get that room. */
@media (min-width: 1000px) {
  .project[data-display="stack"] .pj-panel-wrap { position: relative; }

  /* Each panel's pin distance (the scroll it stays put) and, on every wrap
     after the first, the lift that pulls it up over the panel before it. A
     wrap's dwell is cancelled by the next wrap's lift, so the effect adds no
     page height — sections keep their natural size, nothing is stretched. Both
     are measured in js/ui.js; at 0 (no JS) the page is a plain, correct
     scroll. */
  .project[data-display="stack"] .pj-panel-wrap::after {
    content: ""; display: block; height: var(--dwell, 0px);
  }
  .project[data-display="stack"] .pj-panel-wrap + .pj-panel-wrap {
    margin-top: calc(-1 * var(--lift, 0px));
  }

  /* The panel is a full-bleed, opaque card that sticks while the next climbs
     over it. --pin is 72px (under the nav) for panels that fit the viewport,
     and negative (bottom-pinned) for taller ones, so their lower content is
     read before they hold. The orange seam glow's alpha (--glow) is ramped
     from 0 in js/ui.js as the panel climbs over the one before it, so it fades
     in with the overlap instead of showing at rest. */
  .project[data-display="stack"] .pj-panel {
    position: sticky;
    top: var(--pin, 72px);
    background-color: var(--bg);
    box-shadow: 0 -70px 110px -40px rgba(226, 87, 46, var(--glow, 0));
    display: block;   /* the two-column grid lives on .wrap — NOX nests rail + content inside one */
  }
  .project[data-display="stack"] .pj-panel > .wrap {
    display: grid;
    grid-template-columns: minmax(0, 190px) minmax(0, 1fr);
    gap: clamp(2rem, 4vw, 4rem);
    align-items: start;
  }
}

/* Numbered rail. Bold enough to read as a running section index. */
.project .pj-rail {
  display: flex;
  align-items: baseline;
  gap: 0.8rem;
  margin-bottom: 2.25rem;
  padding-top: 0.15rem;
}
@media (min-width: 1000px) {
  .project .pj-rail { display: block; margin-bottom: 0; }
}
.project .pj-rail-no {
  display: block;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--accent);
}
.project .pj-rail h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.05rem, 1.5vw, 1.35rem);
  line-height: 1.1;
  letter-spacing: -0.025em;
  color: var(--ink);
  margin: 0;
}
.project .pj-rail-bar { display: none; }
@media (min-width: 1000px) {
  .project .pj-rail h2 { margin-top: 0.4rem; }
  .project .pj-rail-bar {
    display: block;
    height: 3px;
    width: 1.75rem;
    margin-top: 1.1rem;
    background: var(--rule-hi);
    transition: width 0.7s var(--ease), background-color 0.5s var(--ease);
  }
  .project .pj-section.is-current .pj-rail-bar { width: 100%; background: var(--accent); }
  .project .pj-section.is-current .pj-rail h2 { color: var(--ink); }
}

/* ---------- The 12-column field ---------- */

.project .pj-content {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(2rem, 3.5vw, 3rem) var(--col-gap);
}
.project .pj-content > * {
  grid-column: var(--start, auto) / span var(--span, 12);
  align-self: var(--align, start);
  margin-top: var(--push, 0);
}
@media (max-width: 759px) {
  .project .pj-content { grid-template-columns: minmax(0, 1fr); gap: 1.75rem; }
  .project .pj-content > * { grid-column: 1 / -1; margin-top: 0; }
}

/* ---------- Type ---------- */

.project .pj-display {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.6rem, 3.1vw, 2.65rem);
  line-height: 1.07;
  letter-spacing: -0.035em;
  margin: 0;
  text-wrap: balance;
}
.project .pj-display em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.005em;
}
.project .pj-p {
  margin: 0;
  color: var(--ink-soft);
  font-size: var(--fs-body);
  line-height: 1.66;
}
/* Only stacked paragraphs; as grid siblings they must keep their row top. */
.project :not(.pj-content) > .pj-p + .pj-p { margin-top: 1rem; }
.project .pj-p b, .project .pj-p strong {
  color: var(--ink);
  font-weight: 500;
  box-shadow: inset 0 -0.42em 0 var(--mark);
}

/* A quote that sits in the grid. */
.project .pj-quote {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--insert-size);
  line-height: 1.2;
  letter-spacing: -0.03em;
  /* Not the margin shorthand: .pj-content > * sets margin-top from --push. */
  margin-right: 0; margin-bottom: 0; margin-left: 0;
  color: var(--ink);
}
.project .pj-quote em { font-family: var(--serif); font-style: italic; font-weight: 400; }
.project :not(.pj-content) > .pj-quote { margin-top: 0; }
/* Words picked out in the accent inside a line (How might we…). */
.project .pj-accent { color: var(--accent); }
/* How Might We: the one shared treatment on every case study — a bright
   label, then the question as a quiet insert (no rule, insert size), flush
   left under it, its opening "How might we" in accent. Span 9. */
.project .pj-hmw .ds-label { margin: 0 0 0.9rem; }

/* Statements: inset lines at the shared --insert-size. The
   emphasis comes from splitting the sentence between ink and accent. */
.project .pj-statement {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--insert-size);
  line-height: 1.15;
  letter-spacing: -0.04em;
  color: var(--ink);
  margin: 0;
  text-wrap: balance;
}
.project .pj-statement em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.01em;
  color: var(--accent);
}
.project .pj-statement b { color: var(--accent); font-weight: inherit; }
.project .pj-statement .pj-statement-note.pj-statement-note--ink { color: var(--ink); }
/* Quieter variant: set in the lighter .pj-quote weight. */
.project .pj-statement--quiet {
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.03em;
}
.project .pj-statement .pj-statement-note {
  display: block;
  margin-top: 1.1rem;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
}

/* ---------- Accent band ---------- */

.project .ds-band .pj-band-inner {
  display: grid;
  gap: 1.5rem;
}
@media (min-width: 900px) {
  .project .ds-band .pj-band-inner {
    grid-template-columns: minmax(0, 190px) minmax(0, 1fr);
    gap: clamp(2rem, 4vw, 4rem);
    align-items: start;
  }
}
.project .ds-band p.pj-band-text {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.4rem, 2.7vw, 2.35rem);
  line-height: 1.12;
  letter-spacing: -0.035em;
  margin: 0;
  max-width: 30ch;
}
.project .ds-band p.pj-band-text em { font-family: var(--serif); font-style: italic; font-weight: 400; }

/* ---------- Figures ---------- */

/* margin-top must survive: .pj-content > * sets it from --push, and a
   `margin: 0` shorthand here would silently win and kill every offset. */
.project .pj-fig { margin-right: 0; margin-bottom: 0; margin-left: 0; }
/* Nested in a wrapper (a stack, a strip, a grid) nothing sets it, so the
   browser's 1em default would drop the figure below its neighbours. */
.project :not(.pj-content) > .pj-fig { margin-top: 0; }
.project .pj-fig-media {
  position: relative;
  display: block;
  aspect-ratio: var(--ar, 3 / 2);
  overflow: hidden;
  background: var(--card-bg);
}
.project .pj-fig-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--pos, center);
  display: block;
  transition: transform 0.8s var(--ease), filter 0.6s var(--ease);
}
.project .pj-fig-media::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--hairline);
  pointer-events: none;
}
.project .pj-fig:hover .pj-fig-media img { transform: scale(1.035); }

.project .pj-fig figcaption {
  margin-top: 0.7rem;
  display: flex;
  gap: 0.7rem;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--ink-dim);
  position: relative;
}
.project .pj-fig figcaption b { color: var(--accent); font-weight: 700; flex: none; }

/* A strip of small process shots, all cropped to one ratio. */
/* Same four-up rhythm as the phase strip, on the same field lines. */
.project .pj-strip {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.9rem var(--col-gap);
}
@media (max-width: 639px) {
  .project .pj-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.project .pj-strip .pj-fig-media { aspect-ratio: 4 / 5; }
.project .pj-strip-note { grid-column: 1 / -1; margin: 0.35rem 0 0; }

/* ---------- Phase strip ---------- */

/* Four phases, three field columns each: the internal rules land on the same
   lines as the section content instead of 7-22px off them. */
.project .pj-phases {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  /* No gap between cells: the air is padding inside each cell instead, so
     the accent rule on top and the hairline underneath run unbroken from
     edge to edge and the table reads as closed. */
  column-gap: 0;
}
.project .pj-phase {
  padding: 1.1rem var(--col-gap) 1.5rem 0;
  position: relative;
}
.project .pj-phase::before {
  content: "";
  position: absolute;
  left: 0; top: -2px;
  width: calc(100% + 1px);
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.8s var(--ease-out), height 0.3s var(--ease);
  transition-delay: calc(var(--i, 0) * 120ms), 0s;
}
/* Each accent runs 1px past its cell, over the next cell's divider, so the
   segments meet without a grey notch; the last one stops at the edge. */
.project .pj-phases.is-visible .pj-phase::before { transform: scaleX(1); }
.project .pj-phase:last-child::before { width: 100%; }
.project .pj-phase:hover::before { height: 6px; }
.project .pj-phase:hover b { color: var(--accent); }
.project .pj-phase:hover span:not(.ds-label) { color: var(--ink); }
/* Three tiers, clearly separated: index, name, consequence. */
.project .pj-phase .ds-label { font-weight: 500; color: var(--ink-dim); }
.project .pj-phase b {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.15rem, 1.6vw, 1.45rem);
  line-height: 1.12;
  letter-spacing: -0.03em;
  margin: 0.65rem 0 0.45rem;
  text-wrap: balance;
  transition: color 0.4s var(--ease);
}
.project .pj-phase span:not(.ds-label) {
  display: block;
  color: var(--ink-soft);
  font-size: var(--fs-small);
  line-height: 1.5;
  max-width: 22ch;
  transition: color 0.4s var(--ease);
}

@media (max-width: 1150px) {
  .project .pj-phases { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Two up: only the right-hand cells take the gutter. */
  .project .pj-phase:nth-child(odd) { border-left: 0; padding-left: 0; }
  .project .pj-phase:nth-child(even) { padding-left: var(--col-gap); }
}

/* Below 480px a two-up track is narrower than the longest phase name, which
   is a single unbreakable word. One column instead: the four phases are a
   sequence, so reading them top to bottom suits the arc anyway — and the
   strip stops depending on how wide the display face happens to be. */
@media (max-width: 479px) {
  .project .pj-phases { grid-template-columns: minmax(0, 1fr); }
  .project .pj-phase,
  .project .pj-phase:nth-child(even),
  .project .pj-phase:nth-child(odd) {
    padding-left: 0;
    padding-right: 0;
  }
}

/* ---------- Lists ---------- */

.project .pj-list { margin: 0; padding: 0; list-style: none; }
.project .pj-list li {
  padding: 0.75rem 0;
  font-size: var(--fs-note);
  color: var(--ink-soft);
  display: flex;
  gap: 1rem;
  transition: padding-left 0.4s var(--ease), color 0.4s var(--ease);
}
.project .pj-list li:hover { padding-left: 0.6rem; color: var(--ink); }
.project .pj-list li i {
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-style: normal;
  font-weight: 700;
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  color: var(--accent);
  padding-top: 0.3rem;
  flex: none;
}
.project .pj-questions {
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1.1rem, 1.7vw, 1.45rem);
  line-height: 1.32;
  color: var(--ink);
}
.project .pj-questions li {
  padding: 0.65rem 0;
  transition: color 0.4s var(--ease);
}
.project .pj-questions li:hover { color: var(--accent); }

/* ---------- The ritual ---------- */

.project .pj-steps {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.75rem, 3.5vw, 2.75rem) var(--col-gap);
}
@media (max-width: 639px) { .project .pj-steps { grid-template-columns: minmax(0, 1fr); } }
.project .pj-step { margin: 0; }
.project .pj-step-head {
  display: flex;
  align-items: baseline;
  gap: 0.8rem;
  padding: 0 0 0.9rem;
  margin-bottom: 0.9rem;
  position: relative;
}
.project .pj-step-head i {
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-style: normal;
  font-weight: 700;
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  color: var(--accent);
  flex: none;
}
.project .pj-step-head b {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1rem, 1.35vw, 1.2rem);
  letter-spacing: -0.025em;
}
.project .pj-step .pj-fig-media { overflow: hidden; }
.project .pj-step .pj-fig-media img { transition: transform 0.8s var(--ease), filter 0.6s var(--ease); filter: brightness(0.92); }
.project .pj-step:hover .pj-fig-media img { transform: scale(1.04); filter: brightness(1.05); }
.project .pj-step p {
  margin: 0.8rem 0 0;
  color: var(--ink-soft);
  font-size: var(--fs-small);
  line-height: 1.55;
  max-width: 40ch;
}

/* ---------- Lugh additions ----------
   Components the NOX template didn't need, built from the same parts: field
   lines, hairlines, the strong rule on top, the accent index. */

/* Square marks (agent icon, logo) are small source files and graphic, not
   photographs: on one column they stop at about half the width. */
@media (max-width: 759px) {
  .project .pj-content > .pj-fig--mark { width: min(100%, 15rem); }
}

/* Big figures. Three across on the field, four columns each, so the rules
   land where the section content does. */
.project .pj-stats {
  container-type: inline-size;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* No gap between cells (see .pj-phases): the accent rule and the bottom
     hairline run unbroken, the air is each cell's own padding. */
  column-gap: 0;
}
.project .pj-stat {
  padding: 1.25rem var(--col-gap) 1.4rem 0;
  position: relative;
}
.project .pj-stat:not(:first-child) { padding-left: var(--col-gap); }
.project .pj-stat::before {
  content: "";
  position: absolute;
  left: 0; top: 0;
  width: calc(100% + 1px); height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.8s var(--ease-out);
  transition-delay: calc(var(--i, 0) * 120ms);
}
.project .pj-stats.is-visible .pj-stat::before { transform: scaleX(1); }
.project .pj-stat:last-child::before { width: 100%; }
.project .pj-stat b {
  display: block;
  font-family: var(--font-display);
  font-weight: 800;
  /* Sized by the row, not the viewport, so every figure in a row matches
     and a six-digit one ("500,000", ~3.8em wide) still fits its third of
     it. The clamp is the fallback for browsers without container units. */
  font-size: clamp(2.4rem, 5.2vw, 5.25rem);
  font-size: min(5.25rem, 7cqi);
  line-height: 0.9;
  letter-spacing: -0.05em;
  color: var(--ink);
  margin-bottom: 0.9rem;
  font-variant-numeric: tabular-nums;   /* the count-up doesn't jitter sideways */
  transition: color 0.4s var(--ease);
}
.project .pj-stat:hover b { color: var(--accent); }
.project .pj-stats--2 .pj-stat b { font-size: min(5.25rem, 11cqi); }
@media (max-width: 759px) {
  .project .pj-stats .pj-stat b { font-size: min(5.25rem, 22cqi); }
  .project .pj-stats { grid-template-columns: minmax(0, 1fr); }
  .project .pj-stat,
  .project .pj-stat:not(:first-child) { padding-left: 0; padding-right: 0; }
  .project .pj-stat::before { width: 100%; }
}

/* Three-up phase table (system layers, testing rounds). Longer copy than the
   NOX phases, so the consequence line runs the full cell. */
.project .pj-phases--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.project .pj-phases--3 .pj-phase span:not(.ds-label) { max-width: 38ch; }
@media (max-width: 1150px) {
  .project .pj-phases--3 .pj-phase:nth-child(n) { padding-left: var(--col-gap); }
  .project .pj-phases--3 .pj-phase:first-child { padding-left: 0; }
}
@media (max-width: 759px) {
  .project .pj-phases--3 { grid-template-columns: minmax(0, 1fr); }
  .project .pj-phases--3 .pj-phase:nth-child(n) { padding-left: 0; }
}

/* Four states in a row: small illustrations, read as a sequence. */
.project .pj-steps--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 999px) { .project .pj-steps--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.project .pj-steps--4 .pj-step .pj-fig-media { aspect-ratio: var(--ar, 6 / 5); }
.project .pj-steps--4 .pj-step .pj-fig-media img { filter: none; }
/* The dock-state illustrations are drawn with rounded corners on white, so
   the frame is rounded to match and the white corner is clipped away. */
.project .pj-steps--4 .pj-step .pj-fig-media { border-radius: 8px; }
.project .pj-steps--4 .pj-step .pj-fig-media::after { border-radius: inherit; }

/* Palette: the chip is the colour, the label says where it comes from. */
.project .pj-swatches {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0 var(--col-gap);
}
.project .pj-swatch { display: flex; flex-direction: column; gap: 0.35rem; }
.project .pj-swatch-chip {
  display: block;
  aspect-ratio: 4 / 5;
  background: var(--c);
  margin-bottom: 0.6rem;
  box-shadow: inset 0 0 0 1px var(--hairline);
  transition: transform 0.6s var(--ease);
  transform-origin: bottom;
}
.project .pj-swatch:hover .pj-swatch-chip { transform: scaleY(1.04); }
.project .pj-swatch b {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1rem, 1.35vw, 1.2rem);
  letter-spacing: -0.025em;
}
.project .pj-swatch span:not(.ds-label):not(.pj-swatch-chip) {
  color: var(--ink-soft);
  font-size: var(--fs-small);
  line-height: 1.45;
}

/* ---------- Prime Couples additions ---------- */

/* Cutouts (transparent PNGs: phones, paper, a person at a desk) sit straight
   on the page. No card, no frame, never cropped. */
.project .pj-fig--cutout .pj-fig-media { background: none; overflow: visible; }
.project .pj-fig--cutout .pj-fig-media::after { display: none; }
.project .pj-fig--cutout .pj-fig-media img { object-fit: contain; }
/* Figures that should hold still on hover (no zoom). */
.project .pj-fig--still:hover .pj-fig-media img { transform: none; }
/* --fit shrinks a cut-out inside its frame (1 = fills it), so objects of
   different real sizes can read at one scale beside each other. The frame
   is square, so a percentage padding insets it evenly on all sides. */
.project .pj-fig--cutout .pj-fig-media img {
  box-sizing: border-box;
  padding: calc((1 - var(--fit, 1)) * 50%);
  /* --nx / --ny nudge a piece inside its frame. The standalone translate
     property, so it adds to the hover zoom (transform) instead of replacing it. */
  translate: var(--nx, 0) var(--ny, 0);
}

/* Portrait phones: on one column they would run 700px tall each. */
@media (max-width: 759px) {
  .project .pj-content > .pj-fig--phone { width: min(100%, 14rem); }
}

/* Technical drawings on white: shown whole on a white sheet, so a row of
   drawings with different proportions still shares one frame. */
.project .pj-fig--sheet .pj-fig-media { background: #fff; }
.project .pj-fig--sheet .pj-fig-media img { object-fit: contain; padding: clamp(0.75rem, 1.5vw, 1.25rem); box-sizing: border-box; }
.project .pj-fig--sheet:hover .pj-fig-media img { transform: none; }
/* A small mark on white: a wider sheet margin so it floats in the frame. */
.project .pj-fig--sheet.pj-fig--inset .pj-fig-media img { padding: var(--inset, clamp(1.75rem, 5vw, 4.5rem)); }
/* A cut-out on white placed by hand: sized (--iw) and set from the left
   (--ix) as shares of the frame's width, centred vertically, so the subject
   sits in the middle while an arm can still run off the right edge. */
.project .pj-fig--placed .pj-fig-media { background: #fff; }
.project .pj-fig--placed .pj-fig-media img {
  position: absolute;
  top: 0; bottom: 0;
  left: var(--ix, 0%);
  width: var(--iw, 100%);
  max-width: none;
  height: auto;
  margin: auto 0;
}

/* Two figures only: two columns of six on the field. */
.project .pj-stats--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* Platform logos: five small tiles, one row, the same field gutters. */
.project .pj-logos {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--col-gap);
  margin: 0;
}
.project .pj-logos img {
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  display: block;
  border-radius: 18%;
  transition: transform 0.5s var(--ease);
}
.project .pj-logos img:hover { transform: translateY(-4px); }
.project .pj-logos figcaption { grid-column: 1 / -1; }
@media (max-width: 759px) { .project .pj-logos { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 0.6rem; } }

/* App mark with its store badges underneath. */
.project .pj-appmark { display: flex; flex-direction: column; align-items: flex-start; gap: 1rem; }
.project .pj-appmark > img { width: min(100%, 9.5rem); height: auto; border-radius: 22%; }
.project .pj-appmark-badges { display: flex; flex-wrap: wrap; gap: 0.5rem; max-width: 100%; }
.project .pj-appmark-badges img { height: 2rem; width: auto; max-width: 100%; }
/* Centred variant: icon and badges share one axis, the block sits level
   with the paragraph beside it. */
.project .pj-appmark--center { align-items: center; text-align: center; }
.project .pj-appmark--center .pj-appmark-badges { justify-content: center; }

/* Eight-colour palette as one strip: chip over hex, no names. */
.project .pj-swatches--strip { grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 0 0.5rem; }
.project .pj-swatches--strip .pj-swatch-chip { aspect-ratio: 3 / 4; margin-bottom: 0.4rem; }
@media (max-width: 759px) { .project .pj-swatches--strip { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.9rem 0.5rem; } }

/* The user flow as a numbered sequence, arrows between the steps. */
.project .pj-flow { margin: 0; padding: 0; list-style: none; }
.project .pj-flow li {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 1rem 0 1.1rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.15rem, 1.7vw, 1.5rem);
  letter-spacing: -0.03em;
  line-height: 1.12;
  transition: color 0.4s var(--ease), padding-left 0.4s var(--ease);
}
.project .pj-flow li:hover { color: var(--accent); padding-left: 0.6rem; }
.project .pj-flow li i {
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-style: normal;
  font-weight: 700;
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  color: var(--accent);
  flex: none;
}
.project .pj-flow li:not(:last-child)::after {
  content: "↓";
  margin-left: auto;
  font-family: var(--micro);
  font-size: var(--fs-small);
  color: var(--ink-dim);
}
/* Two-by-two variant: plain cells, no arrows. */
.project .pj-flow--grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--col-gap); }
.project .pj-flow.pj-flow--grid li:not(:last-child)::after { content: none; }
@media (max-width: 599px) {
  .project .pj-flow--grid { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- Dper additions ---------- */

/* Long website captures in a fixed window that scrolls on its own, so a
   6000px page reads as a page, not as a sliver. The label tells you it
   moves; the scrollbar is kept thin and on-brand. */
.project .pj-shot .pj-fig-media {
  aspect-ratio: var(--ar, 3 / 4);
  overflow-y: auto;
  /* Let the page take over once the capture hits its end (see js/ui.js). */
  overscroll-behavior: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--accent) transparent;
  background: #fff;
}
.project .pj-shot .pj-fig-media img { height: auto; object-fit: initial; }
.project .pj-shot:hover .pj-fig-media img { transform: none; }
/* The frame hairline would scroll away with the content, so it moves to an
   outline, which stays put on the scroll box. */
.project .pj-shot .pj-fig-media::after { display: none; }
.project .pj-shot .pj-fig-media { outline: 1px solid var(--hairline); outline-offset: -1px; }
.project .pj-shot-name {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 0.8rem 0 0.9rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1rem, 1.35vw, 1.2rem);
  letter-spacing: -0.025em;
  transition: border-color 0.4s var(--ease);
}
.project .pj-shot-name .ds-label { color: var(--ink-dim); }

/* One column: every window gets the same readable height. */
@media (max-width: 999px) {
  .project .pj-shot .pj-fig-media { aspect-ratio: 3 / 4; }
}

/* Two-cell phase table, six columns each. */
.project .pj-phases--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.project .pj-phases--2 .pj-phase:nth-child(2) { padding-left: var(--col-gap); }
.project .pj-phases--2 .pj-phase span:not(.ds-label) { max-width: 44ch; }
@media (max-width: 759px) {
  .project .pj-phases--2 { grid-template-columns: minmax(0, 1fr); }
  .project .pj-phases--2 .pj-phase:nth-child(2) { padding-left: 0; }
}

/* Archetypes: a small portrait beside name, role and their own words. */
.project .pj-personas {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem) var(--col-gap);
}
.project .pj-persona {
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr);
  gap: 0 1rem;
  align-items: start;
}
.project .pj-persona img { width: 100%; height: auto; aspect-ratio: 272 / 412; object-fit: cover; display: block; filter: grayscale(0.15); }
.project .pj-persona b {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.15rem, 1.6vw, 1.45rem);
  letter-spacing: -0.03em;
  line-height: 1.1;
}
.project .pj-persona .ds-label { display: block; margin: 0.35rem 0 0.8rem; color: var(--accent); }
.project .pj-persona q {
  display: block;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1rem, 1.3vw, 1.15rem);
  line-height: 1.3;
  color: var(--ink);
}
@media (max-width: 999px) { .project .pj-personas { grid-template-columns: minmax(0, 1fr); } }

/* ---------- Weight of Words additions ---------- */

/* A sentence under a big figure, when the label alone would lose the fact. */
.project .pj-stat .pj-stat-note {
  display: block;
  margin-top: 0.7rem;
  max-width: 34ch;
  color: var(--ink-soft);
  font-size: var(--fs-small);
  line-height: 1.5;
}

/* Outbound call to action: the same orange block as "Watch the video". */
.project .pj-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.85rem 1.4rem;
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  transition: padding-right 0.4s var(--ease);
}
.project .pj-cta:hover { padding-right: 2rem; }
.project .pj-content > .pj-cta { justify-self: start; }

/* ---------- Agosto additions ---------- */

/* Five-up grid (colour references, the fifteen final plates): five across
   the field on desktop, three on tablet, two on a phone. */
.project .pj-grid5 {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem) var(--col-gap);
  align-items: end;
}
.project .pj-grid5 .pj-fig figcaption { font-size: var(--fs-micro); }
@media (max-width: 999px) { .project .pj-grid5 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 559px) { .project .pj-grid5 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---------- About additions ---------- */

.project .pj-list .ab-strong { color: var(--ink); font-weight: 500; }
/* About: level lists (tools, languages) give their labels one fixed width
   so the values align. */
.project .ab-levels li i { min-width: 6.4rem; text-transform: uppercase; }
.project .pj-list a {
  color: inherit;
  text-decoration: none;
}
.project .pj-list li:hover a { color: var(--ink); }
/* Contact: the same accent band that closes the home page. Everything on it
   is on-kiln at full strength (5:1); bone ink only on the display-size lead
   (3.3:1 passes as large text). The Kiln marks used elsewhere (rail number,
   active bar, focus ring, selection) would vanish on the orange, so each one
   switches to on-kiln here. */
.project .ab-contact {
  background: var(--accent);
  color: var(--on-accent);
  margin-top: clamp(2rem, 5vh, 4rem);
}
@media (min-width: 1000px) {
  .project .ab-contact { display: block; }
  .project .ab-contact > .wrap {
    display: grid;
    grid-template-columns: minmax(0, 190px) minmax(0, 1fr);
    gap: clamp(2rem, 4vw, 4rem);
    align-items: start;
  }
}
.project .ab-contact .pj-rail-no,
.project .ab-contact .pj-rail h2,
.project .ab-contact.is-current .pj-rail h2 { color: var(--on-accent); }
.project .ab-contact .pj-rail-bar { background: rgba(27, 15, 8, 0.3); }
.project .ab-contact.is-current .pj-rail-bar { background: var(--on-accent); }
@media (max-width: 999px) {
  .project .ab-contact .pj-rail { border-top-color: var(--on-accent); }
}
.project .ab-contact :focus-visible { outline-color: var(--on-accent); }
.project .ab-contact ::selection { background: var(--on-accent); color: var(--accent); }

.project .ab-contact-lead {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.75rem, 4.2vw, 3.4rem);
  line-height: 1.06;
  letter-spacing: -0.035em;
  color: var(--ink);
  margin: 0;
  max-width: 17ch;
}
.project .ab-contact-lead em { font-family: var(--serif); font-style: italic; font-weight: 400; }

.project .ab-mail-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 1.1rem 1.75rem;
}
.project .ab-mail {
  display: inline-flex;
  align-items: center;
  gap: 0.9rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.05rem, 2.2vw, 1.75rem);
  letter-spacing: -0.02em;
  color: var(--on-accent);
  text-decoration: none;
  padding-bottom: 0.45rem;
  border-bottom: 1px solid rgba(27, 15, 8, 0.35);
  transition: border-color 0.4s var(--ease);
  overflow-wrap: anywhere;
}
.project .ab-mail:hover { border-bottom-color: var(--on-accent); }
.project .ab-mail svg { width: 14px; height: 14px; flex: none; transition: transform 0.45s var(--ease); }
.project .ab-mail:hover svg { transform: translate(3px, -3px); }
.project .ab-contact .ds-copy,
.project .ab-contact .ds-copy:hover,
.project .ab-contact .ds-copy.is-done { color: var(--on-accent); }

.project .ab-links {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 2rem;
}
.project .ab-links a {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-weight: 600;
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--on-accent);
  text-decoration: none;
  text-underline-offset: 4px;
}
.project .ab-links a:hover { text-decoration: underline; text-decoration-thickness: 1px; }
.project .ab-links a svg { width: 9px; height: 9px; transition: transform 0.4s var(--ease); }
.project .ab-links a:hover svg:not(.ds-link-i) { transform: translate(2px, -2px); }
.project .ab-links a .ds-link-i { width: 16px; height: 16px; flex: none; margin-right: 0.15rem; }
@media (pointer: coarse) {
  .project .ab-links { gap: 1.5rem 2rem; }
  .project :is(.ab-links a, .ab-contact .ds-copy) { position: relative; }
  .project :is(.ab-links a, .ab-contact .ds-copy)::before { content: ""; position: absolute; inset: -12px -8px; }
  .project .ab-mail { padding-block: 0.6rem; }
}

/* ---------- Diagrams (Lugh system) ----------
   Built in HTML + SVG on the figure's own card-bg frame instead of a
   light-grey image: nodes placed by percentage on a fixed 5:4 box, links
   drawn in ink-dim with accent arrowheads, notes in the body face. Marks
   keep their own colours; dark wordmarks ship recoloured to ink (Vosk's
   "osk", ElevenLabs, n8n's wordmark). Sizes follow the frame (cqi),
   so the diagram scales as one picture from phone to desktop. */
.project .pj-fig--dia .pj-fig-media { container-type: inline-size; }
.project .pj-fig--dia:hover .pj-fig-media img { transform: none; }
.project .pj-dia { position: absolute; inset: 0; display: block; }
.project .pj-dia-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  fill: none;
  stroke: var(--ink-dim);
  stroke-width: 1.2;
  color: var(--accent);
  overflow: visible;
}
.project .pj-dia-lines marker path { stroke: var(--accent); }
.project .pj-dia-node {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: 36%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2.4cqi;
  text-align: center;
}
.project .pj-dia .pj-dia-logo {
  width: auto;
  height: var(--h, 10cqi);
  max-width: 100%;
  object-fit: contain;
}
.project .pj-dia-note {
  font-size: clamp(0.72rem, 2.6cqi, 0.95rem);
  line-height: 1.4;
  color: var(--ink-soft);
  text-wrap: balance;
}
.project .pj-dia .ds-label { font-size: clamp(var(--fs-micro), 2.1cqi, var(--fs-label)); line-height: 1.3; }
/* Below ~520px the labels sit on their 11px floor while the nodes keep
   closing in, so the wide cut steps down to normal width to keep neighbours
   (Google Calendar / Google Drive) apart instead of shrinking the text. */
@container (max-width: 520px) {
  .project .pj-dia .ds-label { font-stretch: 100%; letter-spacing: 0.02em; }
}
/* The hub: the Claude mark itself sits on the loop's centre (level with the
   midpoint of its arrows); its label hangs below without shifting it. */
.project .pj-dia-hub { width: auto; }
.project .pj-dia-hub .ds-label {
  position: absolute;
  top: calc(100% + 1.6cqi);
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;   /* absolutely placed under a narrow mark: never wrap per letter */
  color: var(--accent);
}
.project .pj-dia-n8n { width: 36cqi; height: auto; color: var(--ink); }

/* ---------- Information architecture (Lugh dashboard) ----------
   From the Claude Design "Voice Agent Dashboard Map". A centred head (label,
   title, the shell's parts), an accent stem, then one column per navigation
   section: accent-ruled header with its index, and beneath it a tree line in
   rule-hi carrying each page as an accent square, numbered 1.1, 1.2… Columns
   wrap on their own (250px minimum), so four across on desktop and fewer on
   narrower screens with no breakpoints. */
.project .pj-ia { margin: 0; }
.project .pj-ia-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
}
.project .pj-ia-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 800;
  /* The section's display size, so it doesn't outrank the section opener. */
  font-size: clamp(1.6rem, 3.1vw, 2.65rem);
  line-height: 1;
  letter-spacing: -0.035em;
  color: var(--ink);
  text-wrap: balance;
}
.project .pj-ia-sub {
  margin: 0;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.project .pj-ia-stem { width: 1px; height: 56px; margin: 28px auto 0; background: var(--accent); }
.project .pj-ia-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  row-gap: 56px;
}
.project .pj-ia-col { display: flex; flex-direction: column; min-width: 0; }
.project .pj-ia-col header {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 18px 24px 20px 0;
  border-top: 2px solid var(--accent);
  border-bottom: 1px solid var(--rule);
}
.project .pj-ia-no {
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--accent);
}
.project .pj-ia-col h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.15rem, 1.6vw, 1.45rem);
  line-height: 1.12;
  letter-spacing: -0.03em;
  color: var(--ink);
}
/* The tree: one rule-hi line down the column, each page hung on it. */
.project .pj-ia-nodes {
  list-style: none;
  margin: 28px 32px 0 3px;
  padding: 0 0 4px;
  border-left: 1px solid var(--rule-hi);
  display: flex;
  flex-direction: column;
  gap: 30px;
}
.project .pj-ia-nodes > li {
  position: relative;
  padding-left: 22px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  transition: color 0.3s var(--ease);
}
.project .pj-ia-nodes > li::before {
  content: "";
  position: absolute;
  left: -4px;
  top: 6px;
  width: 7px;
  height: 7px;
  background: var(--accent);
}
.project .pj-ia-node-head { display: flex; gap: 10px; align-items: baseline; }
.project .pj-ia-node-no {
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.045em;
  color: var(--ink-dim);
}
.project .pj-ia h4 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-lead);
  line-height: 1.25;
  letter-spacing: -0.02em;
  color: var(--ink);
  transition: color 0.3s var(--ease);
}
.project .pj-ia-nodes > li:hover h4 { color: var(--accent); }
.project .pj-ia-nodes p,
.project .pj-ia-nodes ul li {
  margin: 0;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--ink-soft);
  text-wrap: pretty;
}
.project .pj-ia-nodes ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.project .pj-ia-nodes ul li { display: flex; gap: 8px; }
.project .pj-ia-nodes ul li::before { content: "·"; color: var(--rule-hi); }
.project .pj-ia figcaption {
  margin-top: 72px;
  display: flex;
  justify-content: center;
  gap: 0.7rem;
  text-align: center;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 500;
  line-height: 1.6;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.project .pj-ia figcaption b { color: var(--accent); font-weight: 700; flex: none; }

/* ---------- User persona (Prime Couples) ----------
   From the Claude Design "User Persona". A label over the whole card; an
   aside (portrait, name, facts strip) beside the main column (the quote,
   level with the portrait, then six numbered blocks in two columns). Both sides wrap: the aside stacks above the main
   column on narrow screens, the two block columns become one. */
.project .pj-pc {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 28px clamp(2rem, 4vw, 64px);
  align-items: flex-start;
}
/* The label heads the whole card, so the portrait and the quote start on
   the same line beneath it. */
.project .pj-pc-label { flex-basis: 100%; }
.project .pj-pc-side { flex: 1 1 260px; max-width: 360px; display: flex; flex-direction: column; gap: 28px; }
.project .pj-pc-photo {
  position: relative;
  display: block;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--card-bg);
}
.project .pj-pc-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.project .pj-pc-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--hairline);
  pointer-events: none;
}
.project .pj-pc-name {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(2.4rem, 4.6vw, 4.25rem);
  line-height: 0.9;
  letter-spacing: -0.05em;
  color: var(--ink);
  text-wrap: balance;
}
.project .pj-pc-facts {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-bottom: 1px solid var(--rule);
  background-image: var(--rule-strong);
  background-repeat: no-repeat;
  background-size: 100% 2px;
}
.project .pj-pc-facts > div { padding: 0.95rem 24px 1.1rem 0; }
.project .pj-pc-facts > div:nth-child(2) { padding: 0.95rem 0 1.1rem 24px; border-left: 1px solid var(--rule); }
.project .pj-pc-facts .pj-pc-wide { grid-column: 1 / -1; padding-right: 0; border-top: 1px solid var(--rule); }
.project .pj-pc-facts dt {
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.project .pj-pc-facts dd {
  margin: 0.45rem 0 0;
  font-family: var(--font-display);
  font-size: var(--fs-lead);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.3;
  color: var(--ink);
}
.project .pj-pc-facts .pj-pc-wide dd {
  font-family: var(--font-body);
  font-size: var(--fs-note);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.65;
  color: var(--ink-soft);
}
.project .pj-pc-facts .pj-pc-wide dd b { color: var(--ink); font-weight: 500; }
.project .pj-pc-main {
  flex: 3 1 520px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(2.5rem, 5vw, 64px);
  container-type: inline-size;
}
.project .pj-pc-quote {
  margin: 0;
  max-width: 34ch;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--insert-size);
  line-height: 1.2;
  letter-spacing: -0.03em;
  color: var(--ink);
  text-wrap: balance;
}
.project .pj-pc-quote em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.005em;
  color: var(--accent);
}
/* Six blocks: 01–03 down the left, 04–06 down the right, on shared rows so
   each pair's accent rules line up. One column when the main side is narrow. */
.project .pj-pc-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 48px 32px; }
@container (min-width: 600px) {
  .project .pj-pc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .project .pj-pc-block:nth-child(-n+3) { grid-column: 1; }
  .project .pj-pc-block:nth-child(n+4) { grid-column: 2; }
  .project .pj-pc-block:nth-child(1), .project .pj-pc-block:nth-child(4) { grid-row: 1; }
  .project .pj-pc-block:nth-child(2), .project .pj-pc-block:nth-child(5) { grid-row: 2; }
  .project .pj-pc-block:nth-child(3), .project .pj-pc-block:nth-child(6) { grid-row: 3; }
}
.project .pj-pc-block { display: flex; flex-direction: column; gap: 18px; }
.project .pj-pc-block header {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding-top: 0.9rem;
  border-top: 2px solid var(--accent);
}
.project .pj-pc-block header span {
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--accent);
}
.project .pj-pc-block h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.05rem, 1.5vw, 1.35rem);
  line-height: 1.1;
  letter-spacing: -0.025em;
  color: var(--ink);
}
.project .pj-pc-block p,
.project .pj-pc-block ul {
  margin: 0;
  font-size: var(--fs-note);
  line-height: 1.65;
  color: var(--ink-soft);
  text-wrap: pretty;
}
.project .pj-pc-block ul { padding: 0; list-style: none; display: flex; flex-direction: column; gap: 10px; }
.project .pj-pc-block li { position: relative; padding-left: 17px; }
.project .pj-pc-block li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.7em;
  width: 5px;
  height: 5px;
  border-radius: 999px;
  background: var(--accent);
}
.project .pj-pc-block b { color: var(--ink); font-weight: 500; }
.project .pj-pc-block p b { box-shadow: inset 0 -0.42em 0 var(--mark); }
.project .pj-pc figcaption {
  flex-basis: 100%;
  display: flex;
  gap: 0.7rem;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.project .pj-pc figcaption b { color: var(--accent); font-weight: 700; flex: none; }

/* ---------- Emotional journey map (Prime Couples) ----------
   From the Claude Design "Emotional Journey Map": an emotion curve over six
   stages (white line, accent area, dashed baseline, accent rings on the
   moments that matter), then a table of feeling / thinking / doing per
   stage, on the site's rules. Needs ~980px to read, so below that it
   scrolls sideways inside its own box instead of squeezing. */
.project .pj-jm { margin: 0; }
/* The scroll box clips on both axes, so it leaves room for what sits on the
   chart's edges: the quotes above the curve, the last dot at the far right. */
.project .pj-jm-scroll { overflow-x: auto; padding: 32px 10px 0 0; margin-right: -10px; }
.project .pj-jm-grid {
  min-width: 980px;
  display: grid;
  grid-template-columns: 52px repeat(6, minmax(0, 1fr));
}
.project .pj-jm-chart { grid-column: 2 / -1; position: relative; height: 400px; }
.project .pj-jm-chart svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.project .pj-jm-area { fill: var(--mark); }
.project .pj-jm-base { stroke: var(--ink-dim); stroke-width: 1; stroke-dasharray: 8 7; vector-effect: non-scaling-stroke; }
.project .pj-jm-div { stroke: var(--rule); stroke-width: 1; vector-effect: non-scaling-stroke; }
.project .pj-jm-line { fill: none; stroke: var(--ink); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.project .pj-jm-tick {
  position: absolute;
  top: 3%;
  width: 7px;
  height: 7px;
  margin: -3.5px 0 0 -3.5px;
  border-radius: 999px;
  background: var(--rule-hi);
}
.project .pj-jm-baselabel { position: absolute; left: 26px; transform: translateY(calc(-100% - 8px)); }
.project .pj-jm-pt { position: absolute; width: 0; height: 0; }
.project .pj-jm-dot {
  position: absolute;
  left: -7px;
  top: -7px;
  width: 14px;
  height: 14px;
  border-radius: 999px;
  background: var(--ink);
  box-shadow: 0 0 0 3px var(--bg);
}
.project .pj-jm-pt.is-key .pj-jm-dot { background: var(--accent); }
.project .pj-jm-ring {
  position: absolute;
  left: -17px;
  top: -17px;
  width: 34px;
  height: 34px;
  box-sizing: border-box;
  border-radius: 999px;
  border: 1px dashed var(--accent);
}
.project .pj-jm-quote {
  position: absolute;
  left: 0;
  bottom: 30px;
  transform: translateX(-50%);
  width: max-content;
  max-width: 190px;
  text-align: center;
  line-height: 1.4;
  text-wrap: balance;
}
.project .pj-jm-rule { grid-column: 1 / -1; height: 2px; background: var(--accent); }
.project .pj-jm-corner { border-bottom: 1px solid var(--rule); }
.project .pj-jm-stage {
  padding: 20px 20px 18px;
  border-left: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  display: flex;
  gap: 8px;
  align-items: baseline;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
}
.project .pj-jm-stage b { color: var(--accent); font-weight: 700; }
.project .pj-jm-rowlabel {
  border-bottom: 1px solid var(--rule);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 22px 0;
}
.project .pj-jm-rowlabel span {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.project .pj-jm-cell {
  margin: 0;
  padding: 20px 20px 28px;
  border-left: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  font-size: var(--fs-small);
  line-height: 1.55;
  color: var(--ink-soft);
  text-wrap: pretty;
}
.project .pj-jm figcaption {
  margin-top: 0.7rem;
  display: flex;
  gap: 0.7rem;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.project .pj-jm figcaption b { color: var(--accent); font-weight: 700; flex: none; }

/* ---------- Collage (Prime Couples prototyping) ----------
   Three cut-outs layered into one picture inside a framed panel: the
   pointed-at wireframe at the back, the stack of sheets over it, the person
   testing on the laptop in front. Positions are percentages of a 780 x 721
   composition whose edges are the images' own outer edges, so the frame
   sits flush on them and the collage scales as one image. The frame's top
   sits level with the paragraph beside it. */
.project .pj-collage { margin: 0; }
.project .pj-collage-frame {
  position: relative;
  display: block;
  background: var(--card-bg);
  overflow: hidden;
}
.project .pj-collage-frame::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--hairline);
  pointer-events: none;
}
.project .pj-collage-stage { position: relative; display: block; aspect-ratio: 780 / 721; }
.project .pj-collage-stage img { position: absolute; height: auto; display: block; }
.project .pj-collage figcaption {
  margin-top: 0.7rem;
  display: flex;
  gap: 0.7rem;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.project .pj-collage figcaption b { color: var(--accent); font-weight: 700; flex: none; }

/* ---------- Phone trio (Prime Couples) ----------
   The three app screens side by side, the middle one set a little lower, on
   a fixed composition (percentages of a 1423 x 861 box) so they keep their
   spacing at every width. No hover zoom here. */
.project .pj-trio { margin: 0; }
.project .pj-trio-stage { position: relative; display: block; aspect-ratio: 1423 / 861; }
.project .pj-trio-stage img { position: absolute; height: auto; display: block; }
.project .pj-trio figcaption {
  margin-top: 0.7rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 0.4rem 1.5rem;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.project .pj-trio figcaption b { color: var(--accent); font-weight: 700; margin-right: 0.5rem; }

/* ---------- User flow board (Prime Couples) ----------
   From the Claude Design "User Flow v2": every screen placed where it sits
   in the flow on a fixed 1076 x 1630 board, numbered captions under each,
   and accent arrows (a tap ring where the gesture starts, a head where the
   next screen begins) drawn over the top in one SVG with the same
   viewBox, so screens and arrows always line up. Captions size with the
   board (cqw). Below ~760px the board keeps a readable width and scrolls
   sideways in its own box. */
.project .pj-uf { margin: 0; display: flex; flex-direction: column; gap: 32px; }
.project .pj-uf-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  flex-wrap: wrap;
  padding-bottom: 18px;
  background-image: var(--rule-strong);
  background-repeat: no-repeat;
  background-size: 100% 2px;
  background-position: left bottom;
}
.project .pj-uf-legend { display: flex; gap: 28px; align-items: center; }
.project .pj-uf-legend > span {
  display: flex;
  gap: 10px;
  align-items: center;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.project .pj-uf-tap {
  position: relative;
  width: 16px;
  height: 16px;
  border-radius: 999px;
  border: 1.2px solid var(--accent);
  background: rgba(226, 87, 46, 0.18);
  box-sizing: border-box;
}
.project .pj-uf-tap::after {
  content: "";
  position: absolute;
  inset: 3.3px;
  border-radius: 999px;
  background: var(--accent);
}
.project .pj-uf-arrow { position: relative; width: 29px; height: 8px; }
.project .pj-uf-arrow::before {
  content: "";
  position: absolute;
  left: 0;
  top: 3.3px;
  width: 22px;
  height: 1.4px;
  background: var(--accent);
}
.project .pj-uf-arrow::after {
  content: "";
  position: absolute;
  right: 0;
  top: 0;
  border-left: 7px solid var(--accent);
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
}
.project .pj-uf-scroll { overflow-x: auto; }
.project .pj-uf-board {
  position: relative;
  width: 100%;
  min-width: 720px;
  aspect-ratio: 1076 / 1630;
  container-type: inline-size;
}
.project .pj-uf-board img {
  position: absolute;
  object-fit: cover;
  display: block;
  background: var(--card-bg);
  outline: 1px solid var(--hairline);
  outline-offset: -1px;
}
.project .pj-uf-board img.is-key { outline-color: var(--ink); }
.project .pj-uf-board p {
  position: absolute;
  margin: 0;
  display: flex;
  gap: 0.7em;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: max(0.92cqw, 9px);
  font-weight: 500;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--ink-soft);
  line-height: 1.4;
  text-wrap: pretty;
}
.project .pj-uf-board p b { color: var(--accent); font-weight: 700; flex: none; }
.project .pj-uf-board svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.project .pj-uf-board svg polyline { fill: none; stroke: var(--accent); stroke-width: 1.4; stroke-linejoin: round; }
.project .pj-uf-board svg polygon { fill: var(--accent); }
.project .pj-uf-board svg .tap { fill: rgba(226, 87, 46, 0.22); stroke: var(--accent); stroke-width: 1.2; }
.project .pj-uf-board svg .tapdot { fill: var(--accent); }
.project .pj-uf figcaption {
  display: flex;
  gap: 0.7rem;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.project .pj-uf figcaption b { color: var(--accent); font-weight: 700; flex: none; }

/* ---------- Workflow table (Lugh) ----------
   From the Claude Design "Workflow Table": a closed table on the site's
   rules — accent rule on top, hairline rows and dividers, no gaps. Two
   groups: the n8n workflows, then (after a strong white rule) the ones
   reached through Claude's own MCP connectors, whose route reads dimmer.
   Scrolls sideways inside its own box below 640px instead of squeezing. */
.project .pj-wf { margin: 0; }
.project .pj-wf-scroll { overflow-x: auto; }
.project .pj-wf table {
  width: 100%;
  min-width: 640px;
  border-collapse: collapse;
  table-layout: fixed;
  border-top: 2px solid var(--accent);
}
/* Column widths (25% / 15% / rest) come from the <colgroup>. */
.project .pj-wf tr { border-bottom: 1px solid var(--rule); }
.project .pj-wf :is(th, td) {
  text-align: left;
  vertical-align: top;
  padding: 20px 32px 22px;
}
.project .pj-wf tr > :first-child { padding-left: 0; }
.project .pj-wf tr > :not(:first-child) { border-left: 1px solid var(--rule); }
/* Column heads and the route column: small caps. */
.project .pj-wf thead th,
.project .pj-wf .pj-wf-route {
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.4;
  color: var(--ink);
}
.project .pj-wf thead th { padding-top: 16px; padding-bottom: 16px; }
.project .pj-wf .pj-wf-route { padding-top: 24px; }
.project .pj-wf tbody th {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.05rem, 1.4vw, 1.25rem);
  line-height: 1.15;
  letter-spacing: -0.03em;
  color: var(--ink);
  text-wrap: balance;
}
.project .pj-wf tbody td:last-child {
  font-size: var(--fs-body);
  line-height: 1.66;
  color: var(--ink-soft);
  text-wrap: pretty;
}
/* The MCP group: the dissolving white rule above it (a row of its own, so
   the gradient spans the whole table), its route in ink-dim. */
.project .pj-wf .pj-wf-rule { border-bottom: 0; }
.project .pj-wf .pj-wf-rule td {
  padding: 0;
  height: 2px;
  border-left: 0;
  background: var(--rule-strong);
}
.project .pj-wf .pj-wf-mcp .pj-wf-route { color: var(--ink-dim); }
.project .pj-wf figcaption {
  margin-top: 0.7rem;
  display: flex;
  gap: 0.7rem;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.project .pj-wf figcaption b { color: var(--accent); font-weight: 700; flex: none; }

/* ---------- Next project ---------- */

.project .pj-next {
  display: block;
  text-decoration: none;
  padding: clamp(2.5rem, 6vh, 4rem) 0 clamp(2.5rem, 6vh, 4rem);
  position: relative;
  transition: padding-left 0.55s var(--ease);
}
.project .pj-next:hover { padding-left: 1.25rem; }
.project .pj-next-row { border-bottom: 1px solid var(--rule); padding-bottom: 1.35rem; }
.project .pj-next::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.7s var(--ease);
}
.project .pj-next:hover::after { transform: scaleX(1); }
.project .pj-next-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 1.5rem;
  margin-top: 1.1rem;
}
.project .pj-next h2 {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(2rem, 6vw, 4.5rem);
  line-height: 1;
  letter-spacing: -0.045em;
  margin: 0;
  transition: color 0.4s var(--ease);
}
.project .pj-next:hover h2 { color: var(--accent); }
.project .pj-next-thumb {
  width: clamp(88px, 14vw, 180px);
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--card-bg);
  flex: none;
}
.project .pj-next-thumb img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.7s var(--ease); }
.project .pj-next:hover .pj-next-thumb img { transform: scale(1.07); }
.project .pj-next-meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.4rem 1rem;
  margin-top: 1.35rem;
}

/* ---------- Next project banner ----------
   The next project's image fills the block edge to edge, dimmed, under a
   diagonal fade: solid page colour in the bottom-left corner, where the
   title and meta sit, clearing towards the top-right so the image shows
   there. Hover lifts the image a little, like the thumbnail it replaces. */
.project .pj-next-banner {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.project .pj-next-bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}
.project .pj-next-bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 40%;
  opacity: 0.5;
  transition: opacity 0.7s var(--ease), transform 1.2s var(--ease);
}
.project .pj-next-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Diagonal: solid only in the bottom-left corner behind the text, clearing
     early so most of the block shows the image. First layer: a short fade
     at the bottom, so the image never ends on a hard line above the
     "All work" link. */
  background:
    linear-gradient(to top, var(--bg) 0%, rgba(18, 17, 16, 0) 22%),
    linear-gradient(to top right,
      var(--bg) 0%,
      var(--bg) 16%,
      rgba(18, 17, 16, 0.8) 32%,
      rgba(18, 17, 16, 0.3) 56%,
      rgba(18, 17, 16, 0) 80%);
}
.project .pj-next-banner:hover .pj-next-bg img { opacity: 0.62; transform: scale(1.03); }

/* ---------- Back link ---------- */
.project .pj-back {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  margin: 1.75rem 0 3rem;
  font-family: var(--micro);
  font-stretch: var(--micro-wide);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-dim);
  text-decoration: none;
  transition: color 0.35s var(--ease), gap 0.35s var(--ease);
}
.project .pj-back:hover { color: var(--accent); gap: 0.9rem; }

/* ---------- Tablet: 760-999px ----------
   The rail collapses at 1000px but the field used to hold 12 columns down to
   760, which left `--span:4` paragraphs at ~29 characters. One column for
   prose, with the multi-up strips halved. */
@media (min-width: 760px) and (max-width: 999px) {
  .project .pj-content { grid-template-columns: minmax(0, 1fr); gap: 2.25rem; }
  .project .pj-content > * { grid-column: 1 / -1; margin-top: 0; align-self: start; }
  .project .pj-p, .project .pj-questions { max-width: 62ch; }
  .project .pj-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Below the side rail, each section opens on one accent rule over its title. */
@media (max-width: 999px) {
  .project .pj-rail { border-top: 2px solid var(--accent); padding-top: 0.9rem; }
}

/* ---------- Narrow viewports ---------- */
@media (max-width: 759px) {
  /* Two up, two down: four facts divide cleanly, with no orphan row and no
     half-width hairline under it. */
  .project .pj-facts > div { grid-column: span 6; }
  .project .pj-facts > div:nth-child(-n+2) { border-bottom: 1px solid var(--rule); }
  /* Two up: only the right-hand cells sit after a rule. */
  .project .pj-facts > div:nth-child(odd) { border-left: 0; padding-left: 0; }
  .project .pj-facts > div:nth-child(even) { border-left: 1px solid var(--rule); padding-left: var(--col-gap); }
  .project .pj-phase span:not(.ds-label) { max-width: none; }
  .project .pj-rail-no { align-self: baseline; }
  .project .ds-band .pj-band-inner { gap: 1rem; }
  .project .pj-video-note { font-size: 0.9em; }
}

/* A figure that sits beside two stacked blocks, level with the first. */
@media (min-width: 760px) {
  .project .pj-content > .pj-rows-2 { grid-row: span 2; }
}
/* A figure that takes the height of the column beside it: the frame drops
   its ratio and stretches, the photo crops to fill (cover). Side by side
   only; stacked, it keeps its --ar. */
@media (min-width: 760px) {
  .project .pj-content > .pj-fig--fill { align-self: stretch; display: flex; flex-direction: column; }
  .project .pj-fig--fill .pj-fig-media { flex: 1 1 auto; aspect-ratio: auto; min-height: 0; }
  .project .pj-fig--fill .pj-fig-media img { position: absolute; inset: 0; }
}

/* ---------- Sideways diagrams on narrow screens (js/ui.js) ---------- */
.project .pj-swipe-hint { margin: 0 0 0.8rem; color: var(--ink-dim); }
.project .pj-swipe-hint[hidden] { display: none; }
.project .is-scrollable:not(.is-end) {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 3.5rem), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 3.5rem), transparent);
}
.project .is-scrollable:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
/* On a phone the flow board scrolls anyway: give it more width so its
   labels (sized off the board) and screens stay legible, about 10.5px. */
@media (max-width: 759px) {
  .project .pj-uf-board { min-width: 1150px; }
}

/* Reduced motion: hovering an image no longer zooms it. Scroll reveals,
   panels and counters are already switched off in js/ui.js. */
@media (prefers-reduced-motion: reduce) {
  .project .pj-fig-media img,
  .project .pj-next-thumb img,
  .project .pj-next-bg img,
  .project .pj-video-btn img,
  .project .pj-swatch-chip { transform: none !important; }
}
