/* ─── SECTION RAIL ─────────────────────────────────
   Fixed index of the case study, tracking scroll. Reads as frame marks
   down the edge of a strip: each entry has a tick that lights when its
   section is in view, matching the hero light-meter idiom. */
/* Sticky, not fixed: it starts level with the title and rides down with
   the page. 88px clears the 64px navbar plus a 24px gap. The 38px top
   margin matches the title's own offset so the two line up on load. */
.rail { position: sticky; top: 88px; align-self: start; margin-top: 8px; z-index: 60; display: flex; flex-direction: column; gap: 16px; }
/* Back home sits above the index with the space one more link would take.
   The rail already puts 16px between its children, so 21px more gives 37px
   total—an 8px list gap, a 21px line box, and another 8px gap. */
.rail-link.rail-home { display: block; margin-bottom: 21px; }
/* Sits in the same 16px gutter the section arrows use, so every label in
   the rail starts on one edge. Hidden until hover—the section arrows mark
   the active entry, this one answers a pointer, so the two never show for
   the same reason at the same time. It points the other way. */
.rail-back { position: absolute; left: 0; top: 50%; display: flex; align-items: center; justify-content: center; width: 11px; height: 11px; margin-top: -5.5px; opacity: 0; transform: translateX(4px); transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.23, 1, 0.32, 1); }
.rail-link.rail-home:hover .rail-back { opacity: 1; transform: translateX(0); }
.rail-back svg { display: block; width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; transition: transform 0.22s cubic-bezier(0.23, 1, 0.32, 1); }
.rail-link.rail-home:hover .rail-back svg { transform: translateX(-3px); }
@media (prefers-reduced-motion: reduce) { .rail-link.rail-home:hover .rail-back svg { transform: none; } }
.rail-list { display: flex; flex-direction: column; gap: 8px; }
.rail-link { position: relative; display: block; padding-left: 16px; white-space: nowrap; font-family: 'Figtree', sans-serif; font-size: 14px; font-weight: 400; letter-spacing: 0; line-height: 1.5; color: var(--ink-soft); text-decoration: none; transition: color 0.2s ease; }
/* Hover previews the active state: the ink goes the whole way and the
   gutter arrow comes up at half strength, so a pointer shows you where a
   click lands without pretending you are already there. :not(.active)
   keeps it off the entry that is already lit — same specificity as the
   active rule, so order alone would not settle it. */
.rail-link:hover { color: var(--ink); }
.rail-link:not(.active):hover .rail-arrow { opacity: 0.45; transform: translateX(0); }
    .rail-link.active { color: var(--ink); font-weight: 500; }
.rail-arrow { position: absolute; left: 0; top: 50%; display: flex; align-items: center; justify-content: center; width: 11px; height: 11px; margin-top: -5.5px; opacity: 0; transform: translateX(-4px); transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.23, 1, 0.32, 1); }
.rail-link.active .rail-arrow { opacity: 1; transform: translateX(0); }
.rail-arrow svg { display: block; width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
/* Back to top closes the rail the way Back home opens it—same 37px of air
   (16px rail gap + 21px), same gutter arrow on hover, pointing up instead
   of back. Only present once the page has bottomed out. */
.rail-link.rail-top { display: block; margin-top: 21px; opacity: 0; pointer-events: none; transition: opacity 0.3s ease; }
body.at-bottom .rail-link.rail-top { opacity: 1; pointer-events: auto; }
.rail-up { position: absolute; left: 0; top: 50%; display: flex; align-items: center; justify-content: center; width: 11px; height: 11px; margin-top: -5.5px; opacity: 0; transform: translateY(4px); transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.23, 1, 0.32, 1); }
.rail-link.rail-top:hover .rail-up { opacity: 1; transform: translateY(0); }
.rail-up svg { display: block; width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
@media (prefers-reduced-motion: reduce) { .rail-arrow, .rail-back, .rail-up { transition: opacity 0.2s ease; transform: none; } .rail-link.active .rail-arrow, .rail-link.rail-home:hover .rail-back, .rail-link.rail-top:hover .rail-up { transform: none; } }

/* ─── CASE STUDY SHELL ─────────────────────────── */
/* One grid for the whole case study. The rail is the left column; the
   right column holds the title, credits, cover and every section, and
   carries the divider—so the rule runs the full height of the page
   rather than stopping where the sticky rail ends. 119 + 729 = 848; the
   809 is 1px rule + 48px air + 760px of text, and the rail is sized so the
   longest label also clears the rule by 48px—equal on both sides. */
.layout { max-width: 1040px; margin: 104px auto 0; padding: 0 48px; display: grid; grid-template-columns: 151px 809px; gap: 0; justify-content: center; }
/* The divider belongs to the reading column, not the rail: the rail is
   sticky and only as tall as its own links, so a border there would stop
   partway down the page. 1px border + 48px padding inside a 729px column
   leaves the text at 680px. */
.page { position: relative; min-width: 0; padding-left: 48px; }
/* The rule is a pseudo-element, not a border: a border would run the
   column's whole height, including the 112px tail, and butt into the
   footer. Starting at 0 puts it level with the title; the 112px bottom
   inset is exactly the tail, so it ends with the last section. */
.page::before { content: ''; position: absolute; left: 0; top: 0; bottom: 112px; width: 1px; background: var(--rule); }


/* cover frame. Lighter shadow than the Home hero (0.16)—everything
   else on the site was flattened toward ~0.05. */
/* Masthead, cover and the rail+text grid all share one 848px band, which is
   exactly rail(120) + gap(48) + text(680). No vw units anywhere: those
   include the scrollbar and would push a horizontal scroll onto the page. */
.cover { margin-top: 48px; aspect-ratio: 16 / 7; border-radius: var(--r-media); overflow: hidden; background: var(--rule); display: flex; align-items: center; justify-content: center; }

/* Project name above the case study title, matching the section labels — 14px Regular at label ink. It is a label for what follows, not a
   headline, so it takes the same treatment as Overview: or My Impact:. */
.project-name { font-size: 14px; font-weight: 400; letter-spacing: 0; line-height: 1.5; color: var(--ink-faint); margin-bottom: 16px; }
.title { font-size: 36px; font-weight: 500; letter-spacing: -0.024em; line-height: 1.15; color: var(--ink); }
.meta-item { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.meta-label { font-family: 'Figtree', sans-serif; font-size: 14px; font-weight: 500; letter-spacing: 0; line-height: 1.5; color: var(--ink-faint); }
.meta-value { font-size: 14px; line-height: 1.5; color: var(--ink); }

/* section rhythm—eyebrow, statement, explanation, evidence */
/* 72px between sections against 48px between beats—the gap has to be
   bigger than the one inside a section or the page reads as one flat
   list of blocks rather than five sections with contents. */
.section { padding-top: 72px; scroll-margin-top: 88px; }
.kicker { font-family: 'Figtree', sans-serif; font-size: 14px; font-weight: 400; letter-spacing: 0; line-height: 1.5; color: var(--ink-faint); margin-bottom: 16px; }
.statement { font-size: 24px; font-weight: 500; letter-spacing: -0.018em; line-height: 1.25; color: var(--ink); }
.prose { margin-top: 16px; }
.prose p { font-size: 16px; line-height: 1.5; color: var(--ink-soft); }
.prose p + p { margin-top: 16px; }
.prose strong { font-weight: 500; color: var(--ink); }

/* how it works—heading, paragraph, evidence */
.beat { margin-top: 48px; }
/* A beat straight after the section label sits on the label's own 16px
   gap. Sibling selector, not :first-of-type—that keys on element type,
   and the first div in the section is the kicker. */
.kicker + .beat { margin-top: 0; }
.beat h3 { font-size: 24px; font-weight: 500; letter-spacing: -0.018em; line-height: 1.25; color: var(--ink); }
.beat p { font-size: 16px; line-height: 1.5; color: var(--ink-soft); margin-top: 16px; }

/* empty media frames—a fill and a mono slug naming what
   belongs here. Swap the frame for the real asset when it lands. */
.shots { margin-top: 16px; display: grid; gap: 16px; }
.shots.two { grid-template-columns: 1fr 1fr; }
.shots.four { grid-template-columns: repeat(4, 1fr); gap: 16px; }
.figure { display: flex; flex-direction: column; gap: 12px; }
.frame { background: var(--rule); border-radius: var(--r-media); display: flex; align-items: center; justify-content: center; overflow: hidden; }
.frame.wide { aspect-ratio: 16 / 9; }
.frame.tall { aspect-ratio: 4 / 5; }
.frame-slug { font-family: 'DM Mono', monospace; font-size: 9.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-faint); text-align: center; padding: 0 16px; word-break: break-word; }
.shots.four .frame-slug { font-size: 8px; padding: 0 10px; }

/* reflection */

/* Contributions list—part of the same block as the paragraph above it,
   no rule between them. The bullet is a pseudo-element so a wrapped line
   hangs on the indent instead of running back under the marker. */
.contrib { margin-top: 16px; }
.contrib .contrib-label + ul { margin-top: 0; }
.contrib-label { font-family: 'Figtree', sans-serif; font-size: 16px; font-weight: 500; line-height: 1.5; color: var(--ink); margin-bottom: 16px; }
.contrib ul { list-style: none; display: flex; flex-direction: column; gap: 16px; }
.contrib li { position: relative; padding-left: 20px; font-size: 16px; line-height: 1.5; color: var(--ink-soft); }
.contrib li::before { content: '\2022'; position: absolute; left: 0; top: 0; color: var(--ink-faint); }

.tail { height: 112px; }

/* scroll reveal. Fixed 80px inset, never a percentage—a percentage
   scales with viewport height and mistimes on tall screens. */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity 0.7s ease, transform 0.7s cubic-bezier(0.23, 1, 0.32, 1); }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; transform: none; transition: none; } }
