/* Bullish Media — approach.
   1-to-1 replica of depoluxe.xyz/about. Every rule below is the reference's
   own, pulled from its compiled sheet and archived at
   docs/reference/2026-08-05/depo-about-rules.css; the figure geometry was
   re-derived from the measured rects in depo-about-chapters.json (captured
   live at 1600x1000). Spec:
   docs/superpowers/specs/2026-08-05-approach-page-design.md

   The page loads contact.css first and reuses its furniture wholesale — the
   Bullish/bull/Media lockup, the edge blur bands, the bottom meta line, and
   the off-white html paint. Only what is specific to this page lives here.

   PROGRESSIVE ENHANCEMENT LAW: nothing here hides content by default. Without
   JS this file renders a normal stacked document — fourteen full-height
   sections, natively scrollable, every word visible. approach.js adds
   `is-virtual` to <body> at mount, and only then does the wrap go fixed, the
   article start translating and the items start at opacity 0. */

body[data-page='approach'] {
  --page-bg: #efeeeb;
  /* html paints the page colour (contact.css) so the trail canvas at z -1 can
     sit between html and the body content. */
  background: transparent;
  color: var(--black);

  /* Default = ordinary document. The virtual state below takes it away. */
  overflow-y: auto;
  height: auto;
  min-height: 100%;
}

/* Same token steps the contact replica takes — the reference's own, measured
   in docs/reference/2026-08-05/depo.css. --font-size-l is what the chapter
   titles are set in (39.6px at 1600w, matching the measured h2). */
@media (min-width: 1400px) {
  body[data-page='approach'] { --font-size-l: 39.6px; --font-size-s: 14.3px; }
}
@media (min-width: 1650px) {
  body[data-page='approach'] { --font-size-l: 43.2px; --font-size-s: 15.6px; }
}
@media (min-width: 1900px) {
  body[data-page='approach'] { --font-size-l: 46.8px; --font-size-s: 16.9px; }
}

/* ------------------------------------------------------------ scroll wrap */

/* One fixed full-viewport window; inside it a 14-viewport article that the
   virtual scroll translates vertically. Native scrolling is never used in
   that state — body overflow goes hidden and the engine owns the wheel. */
.approach-wrap {
  position: relative;
  width: 100%;
}
.approach-article {
  position: relative;
  width: 100%;
  /* The roman numerals are pure CSS counters — see .counter below. */
  counter-reset: roman-counter;
}

body[data-page='approach'].is-virtual {
  overflow: hidden;
  height: 100%;
}
body[data-page='approach'].is-virtual .approach-wrap {
  position: fixed;
  inset: 0;
  z-index: 2;
  overflow: hidden;
}
body[data-page='approach'].is-virtual .approach-article {
  will-change: transform;
}

/* Trailing spacer: scrolling past the last section is what brings the fixed
   footer layer up. It is pure travel, so in the static document it collapses
   rather than opening an empty screen. */
.fake-footer {
  position: relative;
  width: 100%;
  height: 0;
  pointer-events: none;
}
body[data-page='approach'].is-virtual .fake-footer {
  height: 100vh;
  height: 100dvh;
}

/* ------------------------------------------------------------- text block */

.block-text {
  --body-width: 684px;
  --scroll-height: 200px;

  position: relative;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  padding: var(--padding);
  color: var(--black);
  font-family: var(--font-serif);
  font-size: var(--font-size);
  font-weight: 400;
  letter-spacing: -0.01em;
  line-height: var(--line-height);
}

/* The reference's own --body-width ladder. 786.6px at 1600w, which is what
   the measured text block probed at. */
@media (min-width: 1400px) { .block-text { --body-width: 786.6px; } }
@media (min-width: 1650px) { .block-text { --body-width: 855px; } }
@media (min-width: 1900px) { .block-text { --body-width: 923.4px; } }

.block-text p { margin: 0 0 1.375em; }
.block-text p:last-child { margin-bottom: 0; }

/* Intro: one centred column, no roman rail. */
.block-text:not(.--has-roman) {
  display: flex;
  align-items: center;
  justify-content: center;
}
.block-text:not(.--has-roman) .body {
  margin: 0 auto;
  max-width: var(--body-width);
  text-align: center;
}

/* Chapter text: counter | body | label on one vertically-centred row. The
   1fr/auto/1fr rows are what centre it; the outer columns are the rails the
   numeral and the italic chapter name sit on. */
.block-text.--has-roman {
  display: grid;
  grid-template-columns: 1fr var(--body-width) 1fr;
  grid-template-rows: 1fr auto 1fr;
  align-items: center;
  justify-content: center;
}
.block-text .counter {
  grid-column: 1 / 2;
  grid-row: 2 / 3;
  text-align: left;
  color: var(--black);
  /* The numerals are never written in the markup: one counter, incremented
     per chapter, printed by the pseudo-element. */
  counter-increment: roman-counter;
}
.block-text .counter::after { content: counter(roman-counter, upper-roman); }
.block-text .body {
  grid-column: 2 / 3;
  grid-row: 2 / 3;
  max-width: var(--body-width);
  text-align: center;
}
.block-text .label {
  grid-column: 3 / 4;
  grid-row: 2 / 3;
  text-align: right;
  font-style: italic;
  color: var(--black);
}

/* -------------------------------------------------------- fake scrollbar */

/* Intro only. A 1px, 200px-tall rule at the bottom centre: a 0.3-alpha track
   that tweens in on show, and a black thumb scaled by --progress, which
   approach.js writes as 4x the whole-page progress (so it fills over the
   first quarter and then holds). Masked out toward the bottom. */
.block-text .scrollbar-fake {
  --progress: 0;
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 1px;
  height: var(--scroll-height);
  mask-image: linear-gradient(180deg, #000 30%, transparent 80%);
  -webkit-mask-image: linear-gradient(180deg, #000 30%, transparent 80%);
}
.block-text .scrollbar-fake > div {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 100%;
  transform-origin: 0 0;
}
.block-text .scrollbar-fake .track {
  background-color: rgba(0, 0, 0, 0.3);
  transform: scaleY(1);
  /* --ease-in-quad, the reference's own curve for this tween. */
  transition: transform 1.2s cubic-bezier(0.55, 0.085, 0.68, 0.53);
}
.block-text .scrollbar-fake .thumb {
  background-color: #000;
  transform: scaleY(var(--progress));
}

/* ------------------------------------------------------------ title block */

.block-title {
  --img-size: 4rem;
  --img-height: 4rem;

  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  padding: var(--padding);
  color: var(--black);
  text-align: center;
}

/* Fullscreen media field behind the title. */
.block-title .media {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
.block-title .media > figure {
  margin: 0;
  overflow: hidden;
}
.block-title .media > figure img,
.block-title .media > figure video {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Crossfading stills (Bullish addition, not in the reference). Every still
   figure carries a small pool on data-pool; approach.js stacks a second <img>
   over the markup one and swaps which is on top — hold ~1s, fade 0.6s, phase
   staggered per figure, running only while the section is shown. This is the
   only transition on these elements; the fade band drives the FIGURE's
   opacity, never the layers'. */
.block-title .media > figure img { transition: opacity 0.6s ease-in-out; }

.block-title h2 {
  position: relative;
  z-index: 1;
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--font-size-l);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.01em;
  line-height: var(--line-height);
}

/* Scroll drift. Every driven figure carries --dx/--dy, written per frame by
   approach.js from the section's viewport top (see the DRIFT table there).
   Unset — no JS, reduced motion — they resolve to 0 and the layout is the
   rest pose. type_2 and type_4 are measured as undriven, so they keep no
   transform of their own. */

/* type_1 — four 8rem squares flush to the four corners of the field
   (142.2px at 1600w; the live sweep reads 142). */
.block-title.--type_1 { --img-size: 8rem; --img-height: 8rem; }
.block-title.--type_1 .media > figure {
  position: absolute;
  width: var(--img-size);
  height: var(--img-size);
  transform: translate3d(var(--dx, 0px), var(--dy, 0px), 0);
}
.block-title.--type_1 .media-1 { left: 0; top: 0; }
.block-title.--type_1 .media-2 { right: 0; top: 0; }
.block-title.--type_1 .media-3 { right: 0; bottom: 0; }
.block-title.--type_1 .media-4 { left: 0; bottom: 0; }

/* type_2 — a 12x12 grid over the whole field. (The reference ships
   `reapeat(12,1fr)`, a typo that leaves its own grid implicit; written
   correctly here, which is what its measured rects actually describe.) */
.block-title.--type_2 .media {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-template-rows: repeat(12, 1fr);
}
.block-title.--type_2 .media > figure { position: relative; }
.block-title.--type_2 .media .media-1 { grid-column: 1 / 3;  grid-row: 1 / 10; }
.block-title.--type_2 .media .media-2 { grid-column: 1 / 5;  grid-row: 10 / 13; }
.block-title.--type_2 .media .media-3 { grid-column: 8 / 13; grid-row: 1 / 4; }
.block-title.--type_2 .media .media-4 { grid-column: 11 / 13; grid-row: 4 / 13; }

/* type_3 / type_5 — a centred flex row; figures 2 and 3 carry an extra margin
   that opens the hole the title sits in.

   type_3 is PORTRAIT — 6.875rem x 15rem windows (122x267 at 1600w) with a
   12.5rem gap and margin, all three solved from the live sweep: subtract each
   figure's drift (+-0.4T / +-0.2T) from its rect at top +68 and the row lands
   at x 0 / 344.3 / 1133.7 / 1477.3, i.e. exactly edge to edge across the
   1600px viewport with gap == margin == 222.2px. (The first build's 7.5rem
   squares at a 6.25rem gap came from the static hidden-pose capture, which
   reads different tokens.)

   type_5 keeps its 1.25rem x full-height slivers at a 10rem gap. */
.block-title.--type_3 { --img-size: 6.875rem; --img-height: 15rem; --gap: 12.5rem; }
.block-title.--type_5 { --img-size: 1.25rem; --img-height: 100%; --gap: 10rem; }

.block-title.--type_3 .media,
.block-title.--type_5 .media {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--gap);
}
.block-title.--type_3 .media > figure,
.block-title.--type_5 .media > figure {
  position: relative;
  flex: 0 0 auto;
  width: var(--img-size);
  height: var(--img-height);
  transform: translate3d(var(--dx, 0px), var(--dy, 0px), 0);
}
.block-title.--type_3 .media > figure:nth-child(2),
.block-title.--type_5 .media > figure:nth-child(2) { margin-right: var(--gap); }
.block-title.--type_3 .media > figure:nth-child(3),
.block-title.--type_5 .media > figure:nth-child(3) { margin-left: var(--gap); }

/* type_4 — the filmstrip geometry, carrying our own websites. Four 26.5rem
   windows offset to centres -2.2h / -1h / +1h / +2.2h; the +-1h pair opens the
   hole the title sits in, and the outer pair sweeps through as the section
   enters and leaves.

   Each window is now a STILL showing one site screenshot and crossfading
   through its own pool — so the reference's strip-sampling inner offsets are
   gone on purpose: there is no continuous film to sample, and leaving them
   would also land on the second <img> layer the crossfade engine inserts.
   Screenshots are anchored to their top edge (nav / hero) rather than centred.

   The windows carry the screenshots' own 16:10 aspect (753.75 x 471 at 1600w),
   so a 1280x800 capture cover-fills with nothing cropped off either edge — a
   square window showed only ~62% of the page width. Window CENTRES are
   unchanged: the ladder is built from --img-height. */
.block-title.--type_4 {
  --img-height: 26.5rem;
  --img-size: calc(var(--img-height) * 1.6);
}
.block-title.--type_4 .media > figure {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--img-size);
  height: var(--img-height);
  transform: translate(-50%, calc(-50% + var(--offset)));
}
.block-title.--type_4 .media > figure img { object-position: center top; }
.block-title.--type_4 .media > .media-1 { --offset: calc(var(--img-height) * -2.2); }
.block-title.--type_4 .media > .media-2 { --offset: calc(var(--img-height) * -1); }
.block-title.--type_4 .media > .media-3 { --offset: calc(var(--img-height) * 1); }
.block-title.--type_4 .media > .media-4 { --offset: calc(var(--img-height) * 2.2); }

/* type_6 — two big columns, each holding TWO separate windows at different
   heights, and each window cover-filled with its own medium.

   The -0.8h / +0.5h / -0.5h / +0.8h ladder is the WINDOW offset from the
   section centre, not an inner crop: reference frames
   scratchpad/depo-about/sweep-01-s11-top-190.jpg and -02-s11-top215.jpg show
   four distinct full frames, the pair in each column 1.3h apart with a ~144px
   gap between them, which is exactly what this ladder gives. The inner media
   keeps the generic rule — height 100%, top 0, cover — so nothing is sampled
   out of a shared strip. */
.block-title.--type_6 { --img-size: 30vw; --img-height: 30vw; }
.block-title.--type_6 .media > figure {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--img-size);
  height: var(--img-height);
  /* The drift composes with the centring translate — the two columns
     counter-scroll at +-1.1T, this chapter's signature move. */
  transform: translate(-50%, calc(-50% + var(--offset)))
             translate3d(var(--dx, 0px), var(--dy, 0px), 0);
}
.block-title.--type_6 .media > .media-1 { left: 25%; --offset: calc(var(--img-height) * -0.8); }
.block-title.--type_6 .media > .media-2 { left: 25%; --offset: calc(var(--img-height) * 0.5); }
.block-title.--type_6 .media > .media-3 { left: 75%; --offset: calc(var(--img-height) * -0.5); }
.block-title.--type_6 .media > .media-4 { left: 75%; --offset: calc(var(--img-height) * 0.8); }

/* ------------------------------------------------------- dark choreography */

/* The page turns black under the chapter slides and back to off-white under
   the text blocks. approach.js tweens html's background-color through the
   grays and flips this class at the crossover; everything here is what has to
   invert with it. Text blocks always sit on light ground, so the counter,
   body and label stay black — only the chapter titles and the wash bands
   change. No-JS and reduced motion never get the class: the page stays light,
   because the flip is scroll choreography, not content. */
html.is-dark .block-title h2 { color: #f9f4eb; }
html.is-dark .edge-blur > div { background: rgb(249 244 235 / var(--opacity)); }

/* ---------------------------------------------------------------- footer */

/* The lockup + meta line live UNDER the article (z 1 against the wrap's 2),
   revealed as the last section scrolls off. In the static document the layer
   is simply the last screen of the page. */
.approach-footer {
  position: relative;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  pointer-events: none;
}
body[data-page='approach'].is-virtual .approach-footer {
  position: fixed;
  inset: 0;
  z-index: 1;
  height: 100vh;
  height: 100dvh;
}
/* contact.css pins the lockup itself; inside this layer it is just the
   centred square. */
body[data-page='approach'] .approach-footer .contact-mark {
  position: absolute;
  inset: 0;
  z-index: auto;
}

/* ------------------------------------------------- small viewports */

/* The reference's own small-breakpoint figure sizes (below 1000px), including
   the tighter type_3/type_5 gap and its 7x margin. */
@media (max-width: 999px) {
  .block-title.--type_1 { --img-size: 4rem; --img-height: 4rem; }
  /* Portrait ratio kept at phone scale. */
  .block-title.--type_3 { --img-size: 3.4rem; --img-height: 7.5rem; --gap: 0.625rem; }
  /* Same 16:10 law at phone scale — 254.4 x 159. */
  .block-title.--type_4 { --img-height: 13.25rem; --img-size: calc(var(--img-height) * 1.6); }
  .block-title.--type_5 { --img-size: 1.25rem; --img-height: 100%; --gap: 0.625rem; }
  .block-title.--type_6 { --img-size: 40vw; --img-height: 40vw; }
  .block-title.--type_3 .media > figure:nth-child(2) { margin-right: calc(var(--gap) * 7); }
  .block-title.--type_3 .media > figure:nth-child(3) { margin-left: calc(var(--gap) * 7); }
}

@media (max-width: 900px) {
  /* The roman rail cannot survive a phone width: the row becomes three
     stacked rows — numeral above, body in the middle, chapter name below. */
  .block-text { --body-width: 300px; --scroll-height: 100px; }
  .block-text.--has-roman {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: 1fr auto 1fr;
    justify-items: center;
  }
  .block-text .counter { grid-column: 1 / 2; grid-row: 1 / 2; text-align: center; }
  .block-text .body    { grid-column: 1 / 2; grid-row: 2 / 3; }
  .block-text .label   { grid-column: 1 / 2; grid-row: 3 / 4; text-align: center; }
}
