/* ==========================================================================
   FORMULA SPEED — compositional archetypes
   Section shapes that read differently from one another, so a page has a
   rhythm instead of one grid repeated. Loads after fs.css and fs-wow.css.
   ========================================================================== */

/* ---------- 1. PIN — a figure holds while the text steps past it ---------- */
.pin { position: relative; }
@media (min-width: 980px) {
  .pin-in { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(2rem, 5vw, 5rem); align-items: start; }
  .pin-fig { position: sticky; top: calc(var(--nav-h) + 6vh); height: min(76vh, 640px); }
  .pin-fig .frame { height: 100%; aspect-ratio: auto; }
  .pin-steps { display: grid; gap: clamp(4rem, 14vh, 11rem); padding-block: clamp(3rem, 12vh, 9rem); }
}
@media (max-width: 979px) {
  .pin-in { display: grid; gap: 2rem; }
  .pin-fig .frame { aspect-ratio: 4 / 3; }
  .pin-steps { display: grid; gap: 2.5rem; }
}
.pin-step { display: grid; gap: .9rem; align-content: start; }
.pin-step h3 { font-size: clamp(1.4rem, 2.8vw, 2.1rem); }
.pin-step p { color: var(--mist); }
.pin-step .mark-n {
  font-family: var(--ff-mono); font-size: .62rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--accent, var(--p3));
}
/* The pinned figure cross-fades between plates as the steps advance */
.pin-fig .frame { position: relative; }
.pin-fig .frame img { position: absolute; inset: 0; opacity: 0; transition: opacity 520ms var(--e-out); }
.pin-fig .frame img.live { opacity: 1; }

/* ---------- 2. RAIL — horizontal travel driven by vertical scroll ---------- */
.rail { position: relative; }
@media (min-width: 900px) {
  .rail-stick { position: sticky; top: 0; height: 100dvh; display: grid; align-content: center; overflow: hidden; }
  .rail-track { display: flex; gap: clamp(1rem, 2vw, 2rem); padding-inline: var(--gut); will-change: transform; }
  .rail-card { flex: 0 0 clamp(300px, 30vw, 460px); }
}
@media (max-width: 899px) {
  .rail-stick { padding-block: var(--bay); }
  .rail-track {
    display: flex; gap: 1rem; overflow-x: auto; padding-inline: var(--gut);
    scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
  }
  .rail-track::-webkit-scrollbar { height: 2px; }
  .rail-track::-webkit-scrollbar-thumb { background: var(--rule-2); }
  .rail-card { flex: 0 0 78vw; scroll-snap-align: start; }
}
.rail-card {
  background: var(--tunnel); border: 1px solid var(--rule);
  padding: clamp(1.4rem, 2.6vw, 2.2rem);
  display: flex; flex-direction: column; gap: .8rem;
  min-height: clamp(10rem, 18vh, 15rem);
  position: relative; overflow: hidden;
}
/* The link anchors to the foot, so the space below the copy reads as
   intentional rather than as a gap nobody filled. */
.rail-card .go { margin-top: auto; padding-top: .6rem; }
/* A card whose last child is body copy keeps its own height instead of being
   stretched by the min: the void was the min-height, not the content. */
.rail-card > p:last-child { margin-bottom: auto; }
.rail-card::before {
  content: ''; position: absolute; inset: auto 0 0 0; height: 2px;
  background: var(--accent, var(--p3)); transform: scaleX(0); transform-origin: left;
  transition: transform 600ms var(--e-out);
}
.rail-card:hover::before { transform: scaleX(1); }
/* Only pad when the head is NOT already inside a .wrap/.wrap-w, otherwise the
   gutter lands twice and the heading sits 48px off the cards below it. */
.rail-head { display: grid; gap: var(--sh-gap); margin-bottom: clamp(1.6rem, 4vw, 3rem); }
.rail-head:not(.wrap):not(.wrap-w) { padding-inline: var(--gut); }

/* ---------- 3. STAGGER — a grid that refuses to line up ---------- */
.stagger { display: grid; gap: clamp(1rem, 2.4vw, 2rem); }
@media (min-width: 900px) {
  .stagger { grid-template-columns: repeat(12, 1fr); align-items: start; }
  .stagger > *:nth-child(1) { grid-column: 1 / 6;  margin-top: 0; }
  .stagger > *:nth-child(2) { grid-column: 7 / 13; margin-top: clamp(3rem, 9vw, 8rem); }
  .stagger > *:nth-child(3) { grid-column: 2 / 7;  margin-top: clamp(1rem, 3vw, 3rem); }
  .stagger > *:nth-child(4) { grid-column: 8 / 12; margin-top: clamp(2rem, 5vw, 4rem); }
}

/* ---------- 4. PROCESS — a line draws itself down a numbered rail --------- */
.proc { position: relative; display: grid; gap: clamp(2rem, 5vh, 3.6rem); padding-left: clamp(2.2rem, 5vw, 4rem); }
.proc::before {
  content: ''; position: absolute; left: clamp(.55rem, 1.4vw, 1.1rem); top: .4rem; bottom: .4rem;
  width: 1px; background: var(--rule);
}
/* Drawn with a scale, never a height: animating height relayouts the whole
   rail on every scroll frame. --drawn is a 0..1 number set by the engine. */
.proc::after {
  content: ''; position: absolute; left: clamp(.55rem, 1.4vw, 1.1rem); top: .4rem; bottom: .4rem;
  width: 1px;
  background: linear-gradient(180deg, var(--p3), var(--p5), var(--p7));
  transform: scaleY(var(--drawn, 0));
  transform-origin: top;
  transition: transform 240ms linear;
}
.proc-item { position: relative; display: grid; gap: .6rem; }
.proc-item::before {
  content: ''; position: absolute;
  left: calc(clamp(2.2rem, 5vw, 4rem) * -1 + clamp(.55rem, 1.4vw, 1.1rem) - 4px);
  top: .55rem; width: 9px; height: 9px; border-radius: 50%;
  background: var(--void); border: 1px solid var(--rule-2);
  transition: background 420ms var(--e-out), border-color 420ms var(--e-out);
}
.proc-item.rise-on::before { background: var(--accent, var(--p7)); border-color: var(--accent, var(--p7)); }
.proc-item h3 { font-size: clamp(1.15rem, 2.2vw, 1.6rem); }
.proc-item p { color: var(--mist); font-size: .95rem; }

/* ---------- 5. TAKEOVER — one sentence owns the viewport ---------- */
.takeover {
  min-height: 78vh; display: grid; align-items: center;
  position: relative; overflow: hidden;
  border-block: 1px solid var(--rule);
}
.takeover q {
  quotes: none;
  font-family: var(--ff-display);
  font-variation-settings: 'wdth' 110, 'wght' 800;
  font-size: clamp(2rem, 6.2vw, 5rem);
  line-height: .98; letter-spacing: -.045em;
  max-width: 17ch; display: block; text-wrap: balance;
}
.takeover q em { font-style: normal; color: var(--p7); }
.takeover cite { display: block; margin-top: 1.6rem; font-style: normal; }

/* ---------- 6. DUO — editorial text beside a tall parallaxed figure ------- */
.duo { display: grid; gap: clamp(2rem, 5vw, 4rem); align-items: center; }
@media (min-width: 940px) {
  .duo { grid-template-columns: 1fr 1.15fr; }
  .duo.rev > *:first-child { order: 2; }
  .duo .frame { aspect-ratio: 3 / 4; }
}
.duo .frame img { will-change: transform; }

/* ---------- 7. INDEX — big rows that open on hover ---------- */
.index { border-top: 1px solid var(--rule); }
.irow {
  display: grid; gap: .4rem 1.5rem; align-items: baseline;
  padding-block: clamp(1.3rem, 2.6vw, 2.1rem);
  border-bottom: 1px solid var(--rule);
  position: relative; overflow: hidden;
}
@media (min-width: 820px) {
  .irow { grid-template-columns: 13ch 1fr auto; }
}
/* The row's content slides, not its padding: a padding transition relayouts
   the whole list on every hover. */
.irow > * { transition: transform 420ms var(--e-out), color 300ms var(--e-out); }
.irow:hover > * { transform: translateX(clamp(.5rem, 1.4vw, 1.2rem)); }
.irow::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--accent, var(--p7));
  transform: scaleY(0); transform-origin: bottom;
  transition: transform 420ms var(--e-out);
}
.irow:hover::before { transform: scaleY(1); transform-origin: top; }
.irow .k {
  font-family: var(--ff-mono); font-size: .6rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--vapour);
}
.irow h3 {
  font-size: clamp(1.15rem, 2.4vw, 1.85rem);
  transition: color 300ms var(--e-out);
}
.irow:hover h3 { color: var(--chalk); }
.irow .go { white-space: nowrap; }

/* ---------- 8. MOSAIC — figures at deliberately unequal sizes ---------- */
.mosaic { display: grid; gap: clamp(.6rem, 1.4vw, 1.1rem); }
@media (min-width: 900px) {
  .mosaic { grid-template-columns: repeat(6, 1fr); grid-auto-rows: clamp(90px, 11vw, 150px); }
  .mosaic > *:nth-child(1) { grid-column: span 4; grid-row: span 3; }
  .mosaic > *:nth-child(2) { grid-column: span 2; grid-row: span 2; }
  .mosaic > *:nth-child(3) { grid-column: span 2; grid-row: span 1; }
  .mosaic > *:nth-child(4) { grid-column: span 3; grid-row: span 2; }
  .mosaic > *:nth-child(5) { grid-column: span 3; grid-row: span 2; }
}
.mosaic .frame { aspect-ratio: auto; height: 100%; }

/* ---------- Scroll-linked motion helpers ---------- */
[data-par] { will-change: transform; }

/* A figure that grows very slightly as it enters, so stills feel alive */
.frame.zoom img { transform: scale(1.12); transition: transform 1400ms var(--e-out); }
.frame.zoom.rise-on img,
.rise-on .frame.zoom img { transform: scale(1); }

@media (prefers-reduced-motion: reduce) {
  .pin-fig { position: static; height: auto; }
  .rail-stick { position: static; height: auto; }
  .rail-track { transform: none; overflow-x: auto; }
  .frame.zoom img { transform: none; }
  .proc::after { height: 100%; }
  [data-par] { transform: none; }
}

/* ---------- 9. EDITORIAL — an article hero, not a campaign hero ---------- */
/* An article title is a sentence, not a slogan. The four-to-six word headlines
   elsewhere on the site sit comfortably in .d1 at its 6rem ceiling inside the
   17ch cap; a 74-character title does not — it runs to five lines of 96px type
   and pushes the lede and the first paragraph off the first screen. The
   editorial hero keeps the .d1 element and its semantics and drops it to a
   reading size with a real measure, so the page opens like an article. */
.phero.editorial .d1 {
  font-size: clamp(1.95rem, 4.2vw, 3.3rem);
  font-variation-settings: 'wdth' 108, 'wght' 790;
  line-height: 1.0;
  letter-spacing: -0.032em;
  max-width: min(26ch, 100%);
}
.phero.editorial .lede {
  margin-top: 1.5rem;
  max-width: min(60ch, 100%);
}
/* An editorial hero is shorter than a display one and the header sits over it
   all the same; it needs the clearance whether or not it carries a figure. */
.phero.editorial { padding-top: calc(var(--nav-h) + clamp(3rem, 7vh, 5rem)); }

/* A closing band that offers two routes puts them on one row. .band-in is a
   grid with justify-items:start, so two loose buttons stack into a ragged
   left-hand column; the row keeps them side by side and drops its own
   margin-top, which would otherwise double up with the band's grid gap. */
.band-in .phero-cta,
.band-in .hero-cta { margin-top: 0; }

/* ==========================================================================
   SECTION HERO — every interior page opens on a real image, not a flat ground
   ========================================================================== */
.phero { position: relative; overflow: hidden; isolation: isolate; }

.phero-fig {
  position: absolute;
  inset: 0;
  z-index: -2;
  margin: 0;
  overflow: hidden;
}
.phero-fig img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--pos, center);
  transform: scale(1.06);
  will-change: transform;
  /* A slight pull on the luminance does more for legibility than another
     layer of black gloss: every detail of the photograph survives, the
     average brightness comes down, and white type holds on it.
     The blur belongs in the same declaration, not in a second rule: filter is
     one property, so a later rule naming it replaces the whole list. It was
     declared in fs-wow.css and this rule was quietly eating it. The sources
     top out near 1000px and are shown at ~1500, and the defocus reads as
     depth of field while keeping the type over it crisp. */
  filter: blur(1.5px) brightness(.74) contrast(1.04) saturate(1.06);
}
/* The scrim is a veil now, not a lid. It does exactly three jobs and stops:
   darken the top band so the transparent header's links stay readable, hold a
   pool under the bottom-left copy, and dissolve into the page ground at the
   foot. Everywhere else the photograph is simply the photograph. */
.phero-fig::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    /* A pool in the bottom-left corner, where the copy actually sits. A pool
       is what keeps this transparent: darkening a corner costs the picture
       nothing, darkening the whole frame costs it everything. */
    radial-gradient(88% 74% at 0% 100%,
      rgba(4,6,10,.94) 0%, rgba(4,6,10,.78) 26%, rgba(4,6,10,.44) 52%,
      rgba(4,6,10,.14) 72%, rgba(4,6,10,0) 88%),
    /* A short band under the header, so its links keep a ground */
    linear-gradient(180deg, rgba(4,6,10,.52) 0%, rgba(4,6,10,.14) 20%, rgba(4,6,10,0) 38%),
    /* The foot dissolves into the page ground rather than cutting against it */
    linear-gradient(180deg, rgba(4,6,10,0) 70%, rgba(4,6,10,.38) 88%, var(--void) 100%);
}
/* The figure is inset:0 on the section, and the section's top padding now
   carries the header height — so the photograph begins at y=0 of the page and
   passes behind the transparent header instead of starting below it. */
.phero.has-fig { padding-block: calc(var(--nav-h) + clamp(4rem, 10vh, 7.5rem)) clamp(4.5rem, 11vh, 8rem); }
.phero.has-fig .d1 { text-wrap: balance; }

/* Narrow screens have no room to the right of the copy, so the horizontal
   pass is dropped and the vertical one carries a little more weight. */
/* Narrow screens have no room beside the copy, so the corner pool becomes a
   full-width one and the vertical pass carries a little more weight. */
@media (max-width: 720px) {
  .phero-fig::after {
    background:
      radial-gradient(150% 66% at 0% 100%,
        rgba(4,6,10,.94) 0%, rgba(4,6,10,.76) 34%, rgba(4,6,10,.34) 66%, rgba(4,6,10,0) 92%),
      linear-gradient(180deg, rgba(4,6,10,.60) 0%, rgba(4,6,10,.16) 26%, rgba(4,6,10,0) 44%),
      linear-gradient(180deg, rgba(4,6,10,0) 68%, rgba(4,6,10,.44) 88%, var(--void) 100%);
  }
}
@media (prefers-reduced-motion: reduce) {
  .phero-fig img { transform: none; }
}

/* ==========================================================================
   GAMMA — the finish range for a base, switched by colour chip
   ========================================================================== */
.gamma { display: grid; gap: clamp(1.2rem, 2.6vw, 2rem); }
@media (min-width: 940px) { .gamma { grid-template-columns: 1.6fr 1fr; align-items: center; } }

.gamma-stage {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--tunnel);
  border: 1px solid var(--rule);
  overflow: hidden;
}
.gamma-stage img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 420ms var(--e-out);
}
.gamma-stage img.live { opacity: 1; }

.gamma-side { display: grid; gap: 1rem; align-content: center; }
.gamma-name {
  font-family: var(--ff-display);
  font-variation-settings: 'wdth' 112, 'wght' 800;
  font-size: clamp(1.2rem, 2.2vw, 1.7rem);
  letter-spacing: -.035em; line-height: 1.18;
}
.gamma-side p { font-size: .92rem; color: var(--mist); }

.chips { display: flex; flex-wrap: wrap; gap: .6rem; }
.chip {
  position: relative;
  width: 38px; height: 38px;
  border: 1px solid var(--rule-2);
  background: var(--sw, #888);
  cursor: pointer;
  padding: 0;
  transition: transform var(--t-quick) var(--e-out), border-color var(--t-quick) var(--e-out);
}
.chip:hover { transform: translateY(-2px); border-color: var(--rule-2); }
.chip[aria-pressed="true"] { border-color: var(--chalk); }
.chip[aria-pressed="true"]::after {
  content: '';
  position: absolute; inset: -5px;
  border: 1px solid var(--p7);
}
.chip:focus-visible { outline: 2px solid var(--p3); outline-offset: 3px; }

/* Real measured figures for a base */
.spex { display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); }
@media (min-width: 620px) { .spex { grid-template-columns: repeat(3, 1fr); } }
.spex div { background: var(--tunnel); padding: clamp(1rem, 2.2vw, 1.5rem); display: grid; gap: .3rem; }
.spex dt, .spex .k {
  font-family: var(--ff-mono); font-size: .58rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--vapour);
}
.spex dd, .spex .v {
  margin: 0;
  font-family: var(--ff-display);
  font-variation-settings: 'wdth' 114, 'wght' 820;
  font-size: clamp(1.15rem, 2.2vw, 1.6rem);
  letter-spacing: -.035em;
  font-feature-settings: 'tnum' 1;
  color: var(--chalk);
}
.spex .v small { font-size: .5em; font-variation-settings: 'wght' 600; color: var(--mist); margin-left: .25em; }

@media (prefers-reduced-motion: reduce) {
  .gamma-stage img { transition: none; }
}

/* A section hero may carry a looping video instead of a still. Same scrim,
   same framing rules; the poster covers the load and reduced-motion. */
.phero-fig video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--pos, center);
  transform: scale(1.04);
}
@media (prefers-reduced-motion: reduce) {
  .phero-fig video { display: none; }
  .phero-fig .poster { display: block; }
}
.phero-fig .poster { display: none; width: 100%; height: 100%; object-fit: cover; }

/* ==========================================================================
   FIGURE PROPORTION — a figure beside a text block must not dwarf it.
   On a wide column a 3/4 ratio produced 900px of image next to 230px of
   copy (3.4x). The cap is on height, so the ratio still governs narrow
   columns while wide ones stop growing.
   ========================================================================== */
.frame { max-height: min(58vh, 520px); }
.duo .frame { aspect-ratio: 4 / 5; }
/* These manage their own height and must not be clipped by the cap */
.mosaic .frame,
.pin-fig .frame,
.bleed .frame { max-height: none; }

/* ==========================================================================
   CUTOUTS — the client's product shots are studio cutouts on white. Dropped
   straight onto a black page they read as pasted in from another project.
   Given their own pale plate they read as catalogue pages, which is what
   they are. Never mix a .cut and a dark-ground figure in the same mosaic.
   ========================================================================== */
.frame.cut {
  background: #E9ECF0;
  border-color: rgba(150, 180, 214, .28);
  display: grid;
  place-items: center;
  padding: clamp(.8rem, 2vw, 1.6rem);
}
.frame.cut img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  mix-blend-mode: multiply;   /* drops the white so the plate shows through */
}
.frame.cut figcaption {
  background: linear-gradient(0deg, rgba(233, 236, 240, .96), transparent);
  color: #33404F;
}
.frame.cut.zoom img { transform: none; }

/* A row of cutouts reads as a spec sheet rather than a gallery */
.cuts { display: grid; gap: clamp(.6rem, 1.4vw, 1rem); }
@media (min-width: 720px) { .cuts.c3 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 900px) { .cuts.c4 { grid-template-columns: repeat(4, 1fr); } }
.cuts .frame { aspect-ratio: 4 / 3; max-height: none; }

/* ==========================================================================
   TIMELINE — five decades read top to bottom.

   It ran left to right before, five columns across one horizontal axis. That
   forced every decade into a fifth of the page: the eras became five equal
   labels and the sentence under each one had nowhere to go. Read vertically a
   decade gets the full measure, the drawing sits beside its own paragraph at
   a size that answers the text, and the axis does what an axis of years is
   supposed to do — descend.

   The axis is drawn per step, not once for the whole block, so each era owns
   its own segment of the pressure ramp and the segments join into one
   continuous line. No script measures anything; the geometry below is closed.
   ========================================================================== */
.tl {
  --tl-yr: 8.5rem;   /* year gutter */
  --tl-ax: 46px;     /* axis column: holds the 22px marker with air around it */
  position: relative;
  display: grid;
  gap: 0;
}
@media (max-width: 899px) { .tl { --tl-yr: 0rem; --tl-ax: 34px; } }

.tl-step {
  position: relative;
  display: grid;
  grid-template-columns: var(--tl-yr) var(--tl-ax) minmax(0, 1fr) minmax(0, 15rem);
  align-items: start;
  column-gap: clamp(1rem, 2.2vw, 2rem);
  padding-block: 0 clamp(2.4rem, 5vw, 4rem);
}
@media (max-width: 899px) {
  .tl-step {
    grid-template-columns: var(--tl-ax) minmax(0, 1fr);
    padding-block: 0 clamp(2rem, 5vw, 2.8rem);
  }
}

/* The axis segment. Each step draws its own, floor to ceiling of its own row,
   so consecutive steps meet with no seam. The colour travels from this era to
   the next, which is why the ramp is unbroken across the whole descent. */
.tl-step::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--tl-yr) + clamp(1rem, 2.2vw, 2rem) + (var(--tl-ax) - 2px) / 2);
  width: 2px;
  background: linear-gradient(180deg, var(--c, var(--p4)), var(--c2, var(--p4)));
  opacity: .55;
}
@media (max-width: 899px) {
  .tl-step::before { left: calc((var(--tl-ax) - 2px) / 2); }
}
/* The line stops at the last marker instead of running into the whitespace
   under the final paragraph. */
.tl-step:last-child::before {
  bottom: auto;
  height: 100%;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 42%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0%, #000 42%, transparent 100%);
}

/* Year, right against the axis so the eye reads date-then-marker-then-name */
.tl-yrs {
  grid-column: 1;
  grid-row: 1;
  justify-self: end;
  padding-top: .1rem;
  font-family: var(--ff-mono);
  font-size: clamp(.68rem, 1.1vw, .8rem);
  letter-spacing: .06em;
  color: var(--c, var(--accent));
  font-feature-settings: 'tnum' 1;
  white-space: nowrap;
}
@media (max-width: 899px) {
  .tl-yrs { grid-column: 2; grid-row: 1; justify-self: start; padding-top: 0; margin-bottom: .3rem; }
}

/* The marker, centred in the axis column and therefore on the line */
.tl-dot {
  grid-column: 2;
  grid-row: 1;
  justify-self: center;
  width: 22px; height: 22px;
  border-radius: 50%;
  border: 2px solid var(--c, var(--accent));
  background: var(--void);
  display: grid; place-items: center;
  flex-shrink: 0;
}
.tl-dot i { width: 7px; height: 7px; border-radius: 50%; background: var(--c, var(--accent)); display: block; }
@media (max-width: 899px) {
  .tl-dot { grid-column: 1; grid-row: 1; width: 18px; height: 18px; }
  .tl-dot i { width: 6px; height: 6px; }
}

/* The body of the era */
.tl-body { grid-column: 3; display: grid; gap: .55rem; }
@media (max-width: 899px) {
  .tl-body { grid-column: 2; grid-row: 2; padding-top: .4rem; }
}
.tl-name {
  font-family: var(--ff-display);
  font-variation-settings: 'wdth' 114, 'wght' 820;
  font-size: clamp(1.45rem, 3vw, 2.35rem);
  letter-spacing: -.04em;
  line-height: 1.06;
  color: var(--chalk);
}
.tl-txt { font-size: clamp(.9rem, 1.2vw, .98rem); color: var(--mist); max-width: 46ch; }

/* A fourth column for the drawing keeps it beside its own words rather than
   stacked above them, and caps it so it never outweighs the paragraph. */
.tl-fig { grid-column: 4; grid-row: 1; margin: 0; }
@media (max-width: 899px) {
  .tl-fig { grid-column: 2; grid-row: 3; margin-top: .9rem; max-width: min(300px, 74%); }
}

.tl-car { width: 100%; height: auto; aspect-ratio: 200 / 74; }
.tl-car .body   { fill: none; stroke: var(--c, var(--accent)); stroke-width: 2.4; stroke-linejoin: round; stroke-linecap: round; }
.tl-car .wing   { fill: none; stroke: var(--c, var(--accent)); stroke-width: 2.4; stroke-linecap: round; }
.tl-car .tyre   { fill: #0A0E14; stroke: var(--chalk); stroke-width: 2; opacity: .5; }
.tl-car .detail { fill: none; stroke: var(--c, var(--accent)); stroke-width: 1.4; opacity: .7; stroke-linecap: round; }
.tl-car .air    { stroke: var(--rule-2); stroke-width: 1; stroke-dasharray: 3 5; opacity: .7; }

/* ==========================================================================
   PLACEHOLDER — an image slot the client has not filled yet.

   A grey box says "broken". This says "reserved": the plate is the page's own
   material, the frame is a register mark off a technical drawing, and the
   label states in plain Italian what photograph belongs here and at what
   ratio. It is a brief printed in the layout, not a gap in it.
   ========================================================================== */
.ph {
  position: relative;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: .7rem;
  aspect-ratio: var(--ar, 4 / 3);
  margin: 0;
  padding: clamp(1.2rem, 3vw, 2.2rem);
  overflow: hidden;
  text-align: center;
  border: 1px solid var(--rule-2);
  border-radius: 2px;
  background:
    repeating-linear-gradient(135deg,
      rgba(120, 160, 210, .045) 0 2px, transparent 2px 9px),
    linear-gradient(162deg, rgba(20, 30, 44, .92), rgba(8, 12, 18, .94));
}
/* The register frame: an inset dashed rule, deliberately not the border, so
   the plate reads as a marked-up area rather than a framed picture. */
.ph::before {
  content: '';
  position: absolute;
  inset: clamp(.55rem, 1.4vw, .95rem);
  border: 1px dashed rgba(150, 180, 214, .26);
  border-radius: 1px;
  pointer-events: none;
}
/* Corner ticks, drawn once and mirrored by background-position */
.ph::after {
  content: '';
  position: absolute;
  inset: clamp(.55rem, 1.4vw, .95rem);
  pointer-events: none;
  background-image:
    linear-gradient(var(--p3), var(--p3)), linear-gradient(var(--p3), var(--p3)),
    linear-gradient(var(--p3), var(--p3)), linear-gradient(var(--p3), var(--p3));
  background-repeat: no-repeat;
  background-size: 14px 2px, 2px 14px, 14px 2px, 2px 14px;
  background-position: left top, left top, right bottom, right bottom;
  opacity: .5;
}

.ph-ico { width: clamp(28px, 5vw, 40px); height: auto; color: var(--p3); opacity: .72; }
.ph-ico path, .ph-ico circle, .ph-ico rect {
  fill: none; stroke: currentColor; stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round;
}
.ph-lab {
  font-family: var(--ff-mono);
  font-size: clamp(.52rem, .9vw, .6rem);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--p3);
}
.ph-note {
  font-size: clamp(.78rem, 1.1vw, .88rem);
  color: var(--mist);
  max-width: 34ch;
  line-height: 1.4;
}
.ph-ar {
  position: absolute;
  right: clamp(1rem, 2.2vw, 1.5rem);
  top: clamp(1rem, 2.2vw, 1.5rem);
  font-family: var(--ff-mono);
  font-size: .5rem;
  letter-spacing: .1em;
  color: var(--vapour);
  font-feature-settings: 'tnum' 1;
}
/* A placeholder standing in for a full-bleed hero fills its parent instead of
   holding a ratio of its own — and it must get out of the way. Centred, its
   brief lands exactly where the headline is and the two print over each other.
   In a hero the plate is just a field; the brief retires to the bottom-right
   corner, opposite the copy, at a size that reads as a production note. */
.phero-fig .ph {
  position: absolute;
  inset: 0;
  aspect-ratio: auto;
  border: 0;
  border-radius: 0;
  align-content: end;
  justify-items: end;
  text-align: right;
  gap: .35rem;
  padding: clamp(1.6rem, 4vw, 3rem);
}
.phero-fig .ph::before,
.phero-fig .ph::after { inset: clamp(1rem, 2.4vw, 1.8rem); }
.phero-fig .ph .ph-ico { width: 22px; opacity: .5; }
.phero-fig .ph .ph-note { font-size: .74rem; max-width: 26ch; opacity: .8; }
.phero-fig .ph .ph-ar { right: clamp(1.7rem, 3.4vw, 2.6rem); top: clamp(1.7rem, 3.4vw, 2.6rem); }
@media (max-width: 720px) {
  .phero-fig .ph .ph-note { display: none; }
}
.ph.tall  { --ar: 4 / 5; }
.ph.wide  { --ar: 16 / 9; }
.ph.panel { --ar: auto; height: 100%; }
@media (max-width: 560px) {
  .ph-note { display: none; }
}

/* ==========================================================================
   TRIPTYCH — three doors, not three cards.

   The segments were a row of bordered cards on a horizontal rail: the same
   box three times, which is the one thing three genuinely different audiences
   should not look like. This is three full-height photographic panels butted
   edge to edge across the whole viewport, each opening on its own picture and
   its own pressure colour, read as a choice of doors. No card, no border, no
   rail — the image is the surface and the type stands on it.
   ========================================================================== */
.trip { display: grid; gap: 2px; }
@media (min-width: 880px) { .trip { grid-template-columns: repeat(3, 1fr); } }

.trip-panel {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: grid;
  align-content: end;
  gap: .7rem;
  min-height: clamp(26rem, 72vh, 40rem);
  padding: clamp(1.6rem, 3.4vw, 2.8rem);
  color: var(--chalk);
}
@media (max-width: 879px) { .trip-panel { min-height: clamp(21rem, 56vh, 27rem); } }

.trip-panel img,
.trip-panel .ph {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%; height: 100%;
  object-fit: cover;
  border: 0; border-radius: 0; aspect-ratio: auto;
  transform: scale(1.03);
  transition: transform 900ms var(--e-out);
}
/* The panel's own pressure wash over the photograph: its accent at the foot,
   the page ground at the head, so three panels read as three temperatures. */
.trip-panel::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Plain first, tinted second. color-mix() is not universal, and an
     unsupported function invalidates its whole declaration — without the
     first pass a browser that lacks it would drop the scrim entirely and
     leave near-white type on a bright photograph. */
  background:
    linear-gradient(180deg, rgba(4,6,10,.70) 0%, rgba(4,6,10,.20) 34%,
                            rgba(4,6,10,.72) 72%, rgba(4,6,10,.94) 100%);
  background:
    linear-gradient(180deg, rgba(4,6,10,.70) 0%, rgba(4,6,10,.20) 34%,
                            rgba(4,6,10,.72) 72%, rgba(4,6,10,.94) 100%),
    linear-gradient(180deg, transparent 45%, color-mix(in srgb, var(--accent) 34%, transparent) 100%);
  transition: opacity var(--t-base) var(--e-soft);
}
/* The accent bar along the head of the panel, drawn short and swept to full
   width on approach. scaleX, so nothing reflows. */
.trip-panel::after {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--accent);
  transform: scaleX(.16);
  transform-origin: left center;
  transition: transform 620ms var(--e-out);
}
@media (hover: hover) {
  .trip-panel:hover img { transform: scale(1.09); }
  .trip-panel:hover::after { transform: scaleX(1); }
  .trip-panel:hover .go { color: var(--accent); }
}
.trip-panel:focus-visible { outline: 2px solid var(--p3); outline-offset: -6px; }

.trip-n {
  position: absolute;
  top: clamp(1.4rem, 3vw, 2.4rem);
  left: clamp(1.6rem, 3.4vw, 2.8rem);
  font-family: var(--ff-display);
  font-variation-settings: 'wdth' 118, 'wght' 860;
  font-size: clamp(3.4rem, 7vw, 5.6rem);
  line-height: .8;
  letter-spacing: -.05em;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--accent);
  -webkit-text-stroke: 1.5px color-mix(in srgb, var(--accent) 70%, transparent);
  font-feature-settings: 'tnum' 1;
  pointer-events: none;
}
.trip-lab {
  font-family: var(--ff-mono);
  font-size: .58rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}
.trip-panel h3 {
  font-family: var(--ff-display);
  font-variation-settings: 'wdth' 110, 'wght' 800;
  font-size: clamp(1.35rem, 2.3vw, 1.85rem);
  letter-spacing: -.03em;
  max-width: 20ch;
}
.trip-panel p { font-size: .9rem; color: var(--mist); max-width: 34ch; }
.trip-panel .go { margin-top: .5rem; }

@media (prefers-reduced-motion: reduce) {
  .trip-panel img { transform: none; transition: none; }
  .trip-panel::after { transform: scaleX(1); transition: none; }
}

/* A placeholder standing inside an existing framed slot inherits the slot's
   ratio and chrome instead of imposing its own, so swapping a photograph for
   a placeholder never disturbs the layout around it. */
.frame > .ph {
  position: absolute;
  inset: 0;
  aspect-ratio: auto;
  border: 0;
  border-radius: 0;
}

/* A framed slot whose photograph has not been supplied has nothing inside it
   with an intrinsic height — the placeholder is absolutely positioned — so any
   context that sizes figures from their content collapses it to the border.
   That is exactly what the single-column mosaic does on a phone. The slot
   therefore carries its own ratio, declared on the figure so the value also
   reaches the placeholder inside it. Declared after .mosaic .frame, which it
   has to override at equal specificity. */
.frame.ph-slot {
  aspect-ratio: var(--ar, 4 / 3);
  height: auto;
  max-height: none;
}

/* ==========================================================================
   COMPONENTI — the page that sends do-it-yourself builders to the store.
   ========================================================================== */
/* A section label above the pressure rule, in the measured-value voice */
.kicker { color: var(--p3); margin-bottom: .2rem; }

/* Two short paragraphs, read as one statement: the lede carries the claim,
   the second line narrows it. Kept to the reading measure. */
.diy-text { display: grid; gap: 1rem; max-width: 62ch; }
.diy-text p:not(.lede) { color: var(--mist); }

/* A part is a catalogue plate with its own caption, line and way out. The
   plates are the pale .frame.cut used for the studio cutouts elsewhere; the
   text sits on the page ground under each one, so three of them read as a
   spec sheet rather than three boxes. */
.parts { display: grid; gap: clamp(1.6rem, 3.4vw, 2.6rem); }
@media (min-width: 860px) { .parts { grid-template-columns: repeat(3, 1fr); } }
.part { display: grid; gap: .7rem; align-content: start; }
.part .frame.cut { aspect-ratio: 4 / 3; max-height: none; margin-bottom: .4rem; }
.part h3 { font-size: clamp(1.25rem, 2.1vw, 1.6rem); }
.part p { color: var(--mist); font-size: .95rem; max-width: 40ch; }
.part .go {
  justify-self: start;
  display: inline-flex; align-items: center; gap: .5em;
  margin-top: .2rem;
  font-size: .82rem; font-variation-settings: 'wght' 650;
  color: var(--chalk);
  border-bottom: 1px solid var(--accent);
  padding-bottom: .2rem;
  transition: color var(--t-quick) var(--e-out);
}
.part .go .arw { transition: transform var(--t-base) var(--e-out); }
.part .go:hover { color: var(--accent); }
.part .go:hover .arw { transform: translate(3px, -3px); }

/* A link inside running text: underlined, never only colour */
a.inline { color: var(--chalk); text-decoration: underline; text-underline-offset: .18em; text-decoration-color: var(--p3); }
a.inline:hover { color: var(--p3); }

/* A one-line pointer to another path, set between sections */
.aside-link { display: flex; flex-wrap: wrap; gap: .4rem 1rem; align-items: baseline; color: var(--mist); }
.aside-link .go { display: inline-flex; align-items: center; gap: .5em; color: var(--chalk); font-variation-settings: 'wght' 650; border-bottom: 1px solid var(--p3); padding-bottom: .15rem; }
.aside-link .go:hover { color: var(--p3); }
.aside-link .go .arw { transition: transform var(--t-base) var(--e-out); }
.aside-link .go:hover .arw { transform: translateX(4px); }

/* The closing band's microcopy under a single button */
.band-in > .meas { color: var(--vapour); }
