/* ==========================================================================
   Elephant Room - site.css
   The redesign stylesheet. All five pages are on it.

   It replaces css/main.css, which has been removed - nothing referenced it any
   more. main.css carried assumptions this file deliberately drops: a fixed nav
   with a hardcoded body offset, background-size:contain on the hero, pastel
   gradient result boxes, and no focus styles at all.

   Concept: "The Waterline." The hero photograph is elephants at a waterhole,
   mirrored in still water; the mirror axis measures 51% of image height. That
   line organises the page, and the same hairline recurs as the section rule.
   ========================================================================== */

/* ------------------------------------------------------------------ tokens */
:root{
  /* Unchanged from the old palette - same hues, different jobs. */
  --accent:      #a30069;
  --accent-deep: #5e2c7f;

  /* The neutrals that let the magenta read as an accent instead of a wash. */
  --ink:     #170d14;
  --ink-2:   #45343e;
  --ink-3:   #6f5c67;
  --paper:   #f7f2ee;
  --paper-2: #ede2da;
  --surface: #fffcfa;   /* lifted panel on the warm ground */
  --recess:  #f4ebe3;   /* one step down from the panel, for result blocks */
  --rule:    #d8c9c0;

  /* Measured from the photograph, not estimated. See docs/UX-ASSESSMENT.md. */
  --waterline: 51%;
  --subject:   65.7%;   /* densest silhouette - the tusker */

  /* The site's existing typeface. One family, weight does the work. */
  --display: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --body:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  --measure: 34rem;
  --figmax:  46rem;   /* shared cap so figures line up despite mixed sources */
  --gutter:  clamp(1.25rem, 5vw, 5rem);
  --shell:   72rem;
  --ease:    cubic-bezier(.22,.61,.36,1);
}

/* -------------------------------------------------------------------- base */
*,*::before,*::after{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; }

body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--body);
  font-size:1.0625rem;
  line-height:1.65;
  font-synthesis-weight:none;
  -webkit-font-smoothing:antialiased;
}

img{ max-width:100%; display:block; }

/* main.css defines no :focus rule anywhere on the site. This is that fix. */
:focus-visible{
  outline:2px solid var(--accent);
  outline-offset:3px;
  border-radius:2px;
}

.shell{ width:min(var(--shell), 100% - var(--gutter)*2); margin-inline:auto; }

/* Visible only to screen readers, and to anyone who tabs into it. */
.skip{
  position:absolute; left:var(--gutter); top:0; z-index:200;
  transform:translateY(-120%);
  background:var(--ink); color:var(--paper);
  padding:.75rem 1.25rem; text-decoration:none;
  font-size:.875rem; font-weight:600;
  transition:transform .2s var(--ease);
}
.skip:focus{ transform:translateY(0); }

/* ---------------------------------------------------------------- progress */
.progress{
  position:fixed; inset:0 0 auto 0; height:2px; z-index:100;
  background:var(--accent);
  transform:scaleX(var(--p,0)); transform-origin:0 50%;
}

/* --------------------------------------------------------------------- nav */
.nav{
  position:fixed; inset:0 0 auto 0; z-index:90;
  background:color-mix(in srgb, var(--paper) 86%, transparent);
  backdrop-filter:saturate(150%) blur(12px);
  border-bottom:1px solid transparent;
  transition:border-color .3s var(--ease);
}
.nav[data-stuck="true"]{ border-bottom-color:var(--rule); }

.nav__in{
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  width:min(var(--shell), 100% - var(--gutter)*2); margin-inline:auto;
  min-height:64px;
}

.brand{
  display:flex; align-items:center; gap:.6rem;
  min-height:44px; padding-right:.5rem;   /* stays a 44px target when the
                                             wordmark is hidden on mobile */
  font-family:var(--display); font-weight:600; font-size:1.05rem;
  letter-spacing:-.01em; color:var(--ink); text-decoration:none;
  white-space:nowrap;   /* "Elephant in the Room" never breaks mid-name */
}
.brand svg,
.brand img{ width:30px; height:30px; flex:none; border-radius:50%; object-fit:cover; }

.nav__links{ display:flex; gap:.35rem; list-style:none; margin:0; padding:0; }
.nav__links a{
  display:block; padding:.85rem .8rem; min-height:44px;   /* 44px tap target */
  font-size:.8125rem; font-weight:600; letter-spacing:.09em;
  text-transform:uppercase; text-decoration:none; color:var(--ink-2);
  white-space:nowrap;
  position:relative; transition:color .2s var(--ease);
}
.nav__links a::after{
  content:""; position:absolute; left:.8rem; right:.8rem; bottom:.55rem;
  height:1.5px; background:var(--accent);
  transform:scaleX(0); transform-origin:0 50%;
  transition:transform .32s var(--ease);
}
.nav__links a:hover{ color:var(--ink); }
.nav__links a:hover::after,
.nav__links a[aria-current="page"]::after{ transform:scaleX(1); }
.nav__links a[aria-current="page"]{ color:var(--ink); }

.menu-btn{
  display:none; align-items:center; gap:.6rem;
  min-height:44px; padding:.6rem .25rem;
  background:none; border:0; cursor:pointer; color:var(--ink);
  font-family:var(--body); font-size:.75rem; font-weight:600;
  letter-spacing:.14em; text-transform:uppercase;
}
.menu-btn i{ display:block; width:22px; height:9px; position:relative; }
.menu-btn i::before, .menu-btn i::after{
  content:""; position:absolute; left:0; right:0; height:1.5px;
  background:currentColor; transition:transform .34s var(--ease);
}
.menu-btn i::before{ top:0; }
.menu-btn i::after{ bottom:0; }
.nav[data-open="true"] .menu-btn i::before{ transform:translateY(3.75px) rotate(45deg); }
.nav[data-open="true"] .menu-btn i::after{ transform:translateY(-3.75px) rotate(-45deg); }

/* ======================================================================
   HERO

   Rebuilt after three rounds of "the top of the image is cropped". The old
   version stacked an overscanned base layer and a clipped reflection layer and
   tuned object-position to compensate; the framing was then an emergent
   property of four interacting values and it kept coming out wrong.

   This version makes the framing impossible to get wrong on desktop: the box
   takes the PHOTOGRAPH'S OWN ASPECT RATIO, so `cover` has nothing to crop and
   the entire frame is on screen. Height follows width.

   Mobile is the exception and must stay different: at 390px a 1.77:1 frame is
   only 220px tall, which is not a hero. There the image is left wider than the
   viewport and panned horizontally, so you travel the herd instead of seeing a
   slice of one animal.
   ====================================================================== */

.hero{
  position:relative; isolation:isolate; overflow:hidden;
  background:var(--ink);
  width:100%;
  /* Starts BELOW the fixed nav. It used to run underneath it, and the nav hid
     the top 64px of the photo, which is exactly where the tusker's raised
     trunk is: the frame is tight at the top (I-06, reopened 2026-09-18). */
  margin-top:64px;
  aspect-ratio:1732 / 980;      /* the photo's exact ratio (right-edge line trimmed) */
  /* A whole frame fits on a normal laptop (1440x900: 876px incl. nav). Only a
     short window caps it, and then the crop comes off the BOTTOM - the
     reflection - never the top (see object-position below). */
  max-height:calc(100svh - 64px);
  display:grid; align-items:end;
}
.hero__media{ position:absolute; inset:0; z-index:-2; }
.hero__img{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover; object-position:center top;
}

/* Legibility. The headline sits over the reflection, which is the quiet half
   of the picture, with a bottom-up scrim rather than text-shadow alone. */
.hero__scrim{
  position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:linear-gradient(to top,
    rgba(23,13,20,.82) 0%, rgba(23,13,20,.45) 30%, rgba(23,13,20,0) 62%);
}

.hero__in{ position:relative; padding-block:0 clamp(2rem,5vw,4rem); }

.hero h1{
  font-family:var(--display);
  font-weight:800; font-size:clamp(2.25rem, 5.6vw, 4.5rem);
  line-height:1.02; letter-spacing:-.028em;
  color:#fff; margin:0; max-width:16ch; text-wrap:balance;
}
.hero h1 em{ font-style:italic; font-weight:700; color:#ffd9ec; }

.hero__sub{
  margin:1.25rem 0 0; max-width:30rem;
  color:rgba(255,255,255,.9);
  font-size:clamp(1rem, 1.6vw, 1.1875rem); line-height:1.6;
}

}

.rise{ display:inline-block; overflow:hidden; vertical-align:bottom; }
.rise > span{
  display:inline-block;
  animation:rise .95s var(--ease) both;
  animation-delay:calc(var(--i,0) * 70ms + 150ms);
}
@keyframes rise{ from{ transform:translateY(105%) } to{ transform:translateY(0) } }

/* ------------------------------------------------------------- structure */
.rule{ border:0; height:1px; background:var(--rule); margin:0; }

.section{ padding-block:clamp(4rem, 9vw, 8rem); }
.section--band{ background:var(--paper-2); padding-block:clamp(3rem,6vw,5rem); }
.section--tight{ padding-block:clamp(3rem, 6vw, 5rem); }

.eyebrow{
  display:flex; align-items:center; gap:.85rem;
  font-size:.75rem; font-weight:600; letter-spacing:.16em;
  text-transform:uppercase; color:var(--accent); margin:0 0 1.75rem;
}
.eyebrow::before{ content:""; width:2rem; height:1px; background:var(--accent); flex:none; }

/* --------------------------------------------------------------- opening */
.opening p{
  font-family:var(--display); font-optical-sizing:auto;
  font-weight:600; font-size:clamp(1.5rem, 3.4vw, 2.5rem);
  line-height:1.24; letter-spacing:-.02em;
  max-width:24ch; margin:0; color:var(--ink); text-wrap:pretty;
}
.opening strong{ font-weight:600; color:var(--accent); }
.opening .note{
  font-family:var(--body); font-weight:400; font-size:1rem; line-height:1.7;
  letter-spacing:0; color:var(--ink-2); max-width:var(--measure); margin-top:2rem;
}

/* ------------------------------------------------------------- practices */
/* Three equal centred cards become three asymmetric rows. Body copy is
   left-aligned - centred paragraphs are a readability tax. */
.practice{
  display:grid; gap:clamp(1rem, 3vw, 3rem);
  grid-template-columns:minmax(0,7rem) minmax(0,1fr) minmax(0,1.15fr);
  align-items:start;
  padding-block:clamp(2.25rem, 4.5vw, 3.5rem);
  border-bottom:1px solid var(--rule);
}
.practice:first-of-type{ border-top:1px solid var(--rule); }
.practice__n{
  font-family:var(--display); font-size:.875rem; font-weight:600;
  letter-spacing:.1em; color:var(--accent); padding-top:.55rem;
  font-variant-numeric:tabular-nums;
}
.practice h2{
  font-family:var(--display); font-optical-sizing:auto;
  font-weight:700; font-size:clamp(1.5rem, 2.8vw, 2.125rem);
  line-height:1.12; letter-spacing:-.025em; margin:0; text-wrap:balance;
}
.practice__body{ padding-top:.25rem; }
.practice p{ margin:0 0 1.5rem; color:var(--ink-2); max-width:var(--measure); }

/* --------------------------------------------------------------- link -- */
.arrow{
  display:inline-flex; align-items:center; gap:.55rem; min-height:44px;
  font-size:.8125rem; font-weight:600; letter-spacing:.1em;
  text-transform:uppercase; text-decoration:none; color:var(--ink);
  position:relative;
}
.arrow span{ position:relative; }
.arrow span::after{
  content:""; position:absolute; left:0; right:0; bottom:-3px; height:1px;
  background:currentColor; transform:scaleX(1); transform-origin:100% 50%;
  transition:transform .34s var(--ease);
}
.arrow:hover span::after{ transform:scaleX(0); }
.arrow svg{ width:1.15rem; height:1.15rem; transition:transform .34s var(--ease); }
.arrow:hover{ color:var(--accent); }
.arrow:hover svg{ transform:translateX(5px); }

/* ------------------------------------------------------------- casework */
/* The proof, visible without a click. Figures carry their evidence in the
   caption as prose - no stat tiles, no big-number rows. */
.case{
  display:grid; gap:clamp(1.5rem, 4vw, 3.5rem);
  grid-template-columns:minmax(0,1fr) minmax(0,1.05fr); align-items:center;
}
.case__fig{ margin:0; position:relative; }
/* No forced aspect-ratio. The archive images are small - the Tanker Free BC
   collage exists only at 496x257 - so cropping them to a fixed box would
   upscale and clip them. The figure takes the image's own shape instead, and
   is capped so it never blows up much past native. Replace the source assets
   at 2x and this cap can go. */
.case__fig img{
  width:100%; height:auto; max-width:38rem;
  filter:saturate(.92) contrast(1.03); background:var(--paper-2);
}
.case__fig figcaption{
  margin-top:.75rem; font-size:.8125rem; color:var(--ink-3);
}
.case h2{
  font-family:var(--display); font-optical-sizing:auto;
  font-weight:700; font-size:clamp(1.75rem, 3.4vw, 2.75rem);
  line-height:1.08; letter-spacing:-.028em; margin:.5rem 0 1.25rem;
  text-wrap:balance;
}
.case p{ color:var(--ink-2); max-width:var(--measure); margin:0 0 1.25rem; }

.pull{
  margin:2rem 0 0; padding:1.5rem 0 0; border-top:1px solid var(--rule);
  max-width:none;   /* the rule matched a 36ch measure while every other rule
                       in the card ran the full width - four right edges */
  font-family:var(--display); font-style:italic; font-weight:400;
  font-size:1.1875rem; line-height:1.5; color:var(--ink);
}
.pull p, .pull{ text-wrap:pretty; }
.pull cite{
  display:block; margin-top:.9rem; font-family:var(--body); font-style:normal;
  font-size:.8125rem; letter-spacing:.08em; text-transform:uppercase;
  color:var(--ink-3);
}

/* -------------------------------------------------------------------- cta */
.cta{ background:var(--paper-2); }
.cta__in{ display:grid; gap:2rem; justify-items:start; }
.cta h2{
  font-family:var(--display); font-optical-sizing:auto;
  font-weight:700; font-size:clamp(2rem, 5vw, 3.5rem); line-height:1.04;
  letter-spacing:-.03em; margin:0; max-width:16ch; text-wrap:balance;
}
.cta p{ color:var(--ink-2); max-width:var(--measure); margin:0; }

/* The booking calendar (I-16). Hidden until "Start a Conversation" is
   clicked, then it opens in place under the button: the section grows rather
   than sending people off to a new tab. Calendly draws its own white card
   (about 25rem wide, wider once a day is picked), so there is no frame here,
   and the width is capped so the card does not float in a wide empty box. */
.book{
  justify-self:stretch;
  width:100%; max-width:var(--figmax);
  height:700px;                      /* Calendly's own suggested height */
  margin-top:-.5rem;
  opacity:0; transform:translateY(12px);
  transition:opacity .45s var(--ease), transform .45s var(--ease);
}
/* The footer's "Book a call" scrolls here; keep the button clear of the nav. */
.cta [data-book]{ scroll-margin-top:88px; }
.book[data-open="true"]{ opacity:1; transform:none; }
.book .calendly-inline-widget{ height:100%; min-width:320px; }
.book__wait{
  margin:0; padding:2rem; font-size:.9375rem; color:var(--ink-3);
}
/* Phones: Calendly stacks the date and time pickers, so it needs more room. */
@media (max-width:46rem){ .book{ height:880px; } }
@media (prefers-reduced-motion:reduce){ .book{ transition:none; transform:none; } }

.btn{
  display:inline-flex; align-items:center; gap:.75rem;
  padding:1.05rem 1.9rem; min-height:52px;
  background:var(--ink); color:var(--paper); text-decoration:none;
  font-size:.875rem; font-weight:600; letter-spacing:.08em; text-transform:uppercase;
  position:relative; overflow:hidden; isolation:isolate;
}
.btn::before{
  content:""; position:absolute; inset:0; z-index:-1; background:var(--accent);
  transform:translateY(101%); transition:transform .4s var(--ease);
}
.btn:hover::before{ transform:translateY(0); }
.btn svg{ width:1.1rem; height:1.1rem; transition:transform .4s var(--ease); }
.btn:hover svg{ transform:translateX(4px); }

/* ----------------------------------------------------------------- footer */
.foot{ background:var(--ink); color:rgba(247,242,238,.75); }
.foot__in{
  display:grid; gap:2.5rem;
  grid-template-columns:repeat(auto-fit, minmax(12rem,1fr));
  padding-block:4rem 2rem;
}
.foot h2{
  font-family:var(--body); font-size:.75rem; letter-spacing:.14em;
  text-transform:uppercase; color:rgba(247,242,238,.5);
  margin:0 0 1rem; font-weight:600;
}
.foot ul{ list-style:none; margin:0; padding:0; }
.foot a{
  color:var(--paper); text-decoration:none; font-size:.9375rem;
  display:inline-flex; align-items:center; padding:.6rem 0; min-height:44px;
  transition:color .2s var(--ease);
}
.foot a:hover{ color:#ff8ec8; }
.foot__base{
  display:flex; flex-wrap:wrap; gap:1rem; justify-content:space-between;
  padding-block:1.5rem 2.5rem; border-top:1px solid rgba(247,242,238,.15);
  font-size:.8125rem; color:rgba(247,242,238,.55);
}

/* ----------------------------------------------------------------- reveal */
/* Content is visible by default and only ARMED into its hidden state by the
   inline head script - so no-JS readers, print, Reader mode and link-preview
   crawlers always get a full page. The arming happens before first paint, so
   there is no flash. A failsafe in the page script un-arms everything after
   2s in case IntersectionObserver never fires. Nothing here is load-bearing:
   if all of it fails, the page is simply static. */
.js .reveal{ opacity:0; transform:translateY(1.5rem); }
.js .reveal.in{
  opacity:1; transform:none;
  transition:opacity .8s var(--ease), transform .8s var(--ease);
  transition-delay:var(--d, 0ms);
}

/* ============================================================== breakpoints */
@media (max-width:56rem){
  /* The full name plus five links stops fitting below ~900px, and wrapped
     it into two lines. Logo only from here down, as on phones. */
  .brand span{ display:none; }

  .practice{ grid-template-columns:minmax(0,3rem) minmax(0,1fr); row-gap:.75rem; }
  .practice__body{ grid-column:2; }   /* small row-gap: a big one left every
                                         heading floating away from its own
                                         paragraph once the grid stacked */
  .case{ grid-template-columns:1fr; }
  .case__fig{ order:-1; }
}

@media (max-width:46rem){
  .nav__in{ min-height:56px; }
  .menu-btn{ display:inline-flex; }

  .nav__links{
    position:fixed; inset:56px 0 auto 0;
    flex-direction:column; gap:0;
    background:var(--paper); border-bottom:1px solid var(--rule);
    padding:.5rem var(--gutter) 1.5rem;
    transform:translateY(-101%); visibility:hidden;
    transition:transform .42s var(--ease), visibility .42s;
  }
  .nav[data-open="true"] .nav__links{ transform:translateY(0); visibility:visible; }
  .nav__links a{
    padding:1rem 0; font-size:1.5rem; letter-spacing:-.02em;
    text-transform:none; font-family:var(--display); font-weight:500;
    border-bottom:1px solid var(--rule);
  }
  .nav__links li:last-child a{ border-bottom:0; }
  .nav__links a::after{ left:0; right:auto; width:1.75rem; bottom:.7rem; }

  .brand span{ display:none; }

  /* ---- the panning hero ------------------------------------------------
     Height is deliberately NOT full-bleed here. The visible fraction of the
     photo is viewportWidth / (heroHeight * 1.774), so a SHORTER hero shows
     MORE of the image width - which is what lets a whole elephant fit. At
     ~72svh the tusker and its reflection sit in frame with room to spare. */
  .hero{
    margin-top:56px;              /* the nav is 56px tall here */
    aspect-ratio:auto; max-height:none;
    height:clamp(26rem, 72svh, 34rem);
    align-items:end;
  }
  .hero__media{ inset:0; }

  /* One layer, full height, wider than the viewport, translated on X. */
  .hero__img{
    inset:0; height:100%; width:auto; max-width:none;
    object-fit:cover; object-position:left center;
    transform:translate3d(var(--x, 0px), 0, 0);
  }

  .hero__in{ padding-block:0 2.25rem; justify-content:flex-end; }
  .hero h1{ font-size:clamp(2.25rem, 10vw, 3rem); max-width:12ch; }
  .hero__sub{ margin-top:1rem; font-size:1rem; }
}

/* Every motion on this page is decorative; none of it is load-bearing. */
@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
  .rise > span{ transform:none; }
  .reveal{ opacity:1; transform:none; }
  .hero__img{ transform:none !important; }
}

/* ==========================================================================
   INTERIOR PAGES
   Added for engagement.html. Shares every token above; adds only the layout
   the case-study pages need. The old .exp-card / .results / .challenge rules
   in main.css are NOT used here - the pastel gradient result boxes they draw
   were the main source of the "twelve different accent colours" problem.
   ========================================================================== */

/* --------------------------------------------------------------- pagehead */
/* Interior pages open on type, not on a photograph. The homepage hero is the
   site's one big visual moment; repeating it here would flatten it. */
/* I-15: the header used to sit on the same paper as the body, and read as
   floating. It is now a band in the pastel of the hero photograph's sky:
   blush at the top, lavender towards the horizon, a warmer pink glow where
   the sun has just gone down. The band ends on the waterline hairline.
   Everything is CSS, with no markup change, so the copy gate cannot be
   affected. (Tried and dropped: a dark plum band, then a faint elephant
   silhouette inside the band. The client wants colour only.) */
.pagehead{
  --sky-hi: #f9e6ef;      /* blush, the upper sky */
  --sky-lo: #ece2f2;      /* lavender, the sky at the horizon */
  --glow:   #f5c3dc;      /* the afterglow */
  background:
    /* wide and gentle, so it reads as warmth, not a spot (a tighter glow banded) */
    radial-gradient(90% 140% at 100% var(--glow-y, 30%), color-mix(in srgb, var(--glow) 55%, transparent), transparent 70%),
    linear-gradient(180deg, var(--sky-hi) 0%, var(--sky-lo) 100%);
  padding-block:calc(64px + clamp(3rem,7vw,5.5rem)) clamp(3rem,6vw,4.75rem);
  border-bottom:1px solid color-mix(in srgb, var(--accent) 45%, transparent);  /* the waterline */
}

.pagehead h1{
  font-family:var(--display); font-optical-sizing:auto;
  font-weight:800; font-size:clamp(2.5rem,6.5vw,4.5rem);
  line-height:1.0; letter-spacing:-.028em; margin:0;
  max-width:14ch; text-wrap:balance;
}
/* The lede runs the full width of the band. It was capped at 42ch, which on
   desktop stopped it at the middle of the screen and left the band's right
   half empty (client, 2026-09-18). It is large text and only two or three
   lines, so the longer line reads fine. */
.pagehead .lede{
  margin:1.75rem 0 0; max-width:none;
  font-family:var(--display); font-weight:400;
  font-size:clamp(1.125rem,2.3vw,1.5rem); line-height:1.4;
  letter-spacing:-.015em; color:var(--ink-2); text-wrap:pretty;
}
.pagehead .lede strong{ font-weight:500; color:var(--ink); }

/* A full-bleed strip rather than a full hero - enough image to set the
   subject, not so much that it competes with the homepage. */
/* Replaces the old fixed-height full-bleed band, which cropped 72-79% off the
   two images actually used with it (both portrait or near-square). A page
   image now keeps its own shape and its own resolution. */
.pagefig{ margin:0 0 clamp(1rem,3vw,2rem); }
/* About Us opens straight onto a photo. Give it air below the band. */
.pagehead + .shell > .pagefig:first-child{ margin-top:clamp(2.5rem,6vw,4.5rem); }
.pagefig img{
  width:auto; max-width:min(100%, var(--w, 100%), var(--figmax)); height:auto;
  background:var(--paper-2);
}
.pagefig figcaption{
  margin-top:.75rem; font-size:.8125rem; color:var(--ink-3); max-width:48ch;
}

/* -------------------------------------------------------------- narrative */
.narrative{ max-width:38rem; margin-inline:0; }   /* flush left, not centred */
.narrative p{ margin:0 0 1.35rem; color:var(--ink-2); font-size:1.0625rem; }
.narrative p:last-child{ margin-bottom:0; }
.narrative .lead{
  font-family:var(--display); font-weight:700;
  font-size:clamp(1.25rem,2.4vw,1.625rem); line-height:1.36;
  letter-spacing:-.018em; color:var(--ink); margin-bottom:1.75rem;
}
.narrative em{ font-style:normal; color:var(--accent); font-weight:500; }

/* -------------------------------------------------------------- chronicle */
/* Open. Always. main.css puts four of these five behind a closed <details>,
   which hides the only real evidence the page has. */
/* Each case study sits on its own panel. On a single flat ground the sections
   read as floating; a surface with a real edge anchors them. */
.chronicle{
  background:var(--surface);
  border:1px solid var(--rule);
  border-radius:3px;
  padding:clamp(1.75rem,4vw,3rem);
  margin-bottom:clamp(1.25rem,3vw,2rem);
  max-width:calc(var(--figmax) + clamp(1.75rem,4vw,3rem) * 2);
}
.chronicle__head{ margin-bottom:2rem; }
/* The prefix is styled inside the heading, not split out of it, so the title
   remains the single string the client wrote. */
.chronicle__n{
  display:block; margin-bottom:.5rem;
  font-size:.8125rem; font-weight:600; letter-spacing:.12em;
  text-transform:uppercase; color:var(--accent);
  font-variant-numeric:tabular-nums;
}
.chronicle__kicker{ display:none; }
.chronicle__head h2{
  margin:0; font-family:var(--display); font-optical-sizing:auto;
  font-weight:700; font-size:clamp(1.625rem,3.2vw,2.5rem);
  line-height:1.1; letter-spacing:-.026em; text-wrap:balance;
}
/* The figure occupies the full card measure so every card has ONE right edge,
   but the image inside is still never upscaled - the three archive assets that
   are narrower than the cap (496, 648, 720px) sit centred on the panel instead
   of being stretched to fill it. */
.chronicle__fig{
  margin:0 0 2.5rem; max-width:var(--figmax);
  background:var(--paper-2);
  display:grid; justify-items:center;
}
/* An image is never stretched past its own pixels. These archive assets range
   from 496px to 1200px wide; forcing them all to fill a 1152px column upscaled
   the small ones by up to 2.3x, which is what made the pages look soft and
   uneven. --w is the natural width, set per image in the markup. */
/* Three constraints at once: never wider than the column, never wider than the
   image's own pixels (--w), and never wider than a shared cap. The cap is what
   makes the column of figures read as regular - without it the natural widths
   range from 496px to 1200px and the page looks ragged. */
.chronicle__fig img{
  width:auto; max-width:100%; height:auto;
  filter:saturate(.94) contrast(1.02);
}
.chronicle__fig figcaption{
  justify-self:start; padding:.75rem .9rem 0;
  margin-top:0; font-size:.8125rem; color:var(--ink-3); max-width:48ch;
}

/* Two columns of movements: challenge on the left, what we did on the right,
   outcome spanning underneath. Collapses to one column under 56rem. */
.chronicle__body{
  display:grid; gap:clamp(2rem,4.5vw,3.25rem);   /* was ~1.25-2rem: the result
                                                    block read as more prose
                                                    rather than a conclusion */
  grid-template-columns:minmax(0,1fr);
  max-width:var(--figmax);       /* same width as the figure above it, so the
                                    rules, the copy and the picture all share
                                    one right edge */
}
.movement{ min-width:0; }
.movement--full{ grid-column:1 / -1; }
.movement--outcome{
  background:var(--recess);
  padding:clamp(1.25rem,3vw,1.75rem) clamp(1.25rem,3vw,1.75rem) clamp(1.1rem,2.5vw,1.5rem);
  border-radius:2px;
}
.movement--outcome h3{ border-bottom-color:var(--rule); }
.movement--outcome .outcomes li::before{ background:var(--accent); }
.movement p, .movement > ul{ max-width:none; }
.movement h3{
  margin:0 0 1rem; font-family:var(--body);
  font-size:.75rem; font-weight:600; letter-spacing:.16em;
  text-transform:uppercase; color:var(--ink-3);
  padding-bottom:.75rem; border-bottom:1px solid var(--rule);
}
.movement p{ margin:0 0 1.1rem; color:var(--ink-2); }
.movement p:last-child{ margin-bottom:0; }
.movement > ul:not(.outcomes){
  margin:0; padding:0; list-style:none;
  display:flex; flex-direction:column; gap:.7rem;
}
.movement > ul:not(.outcomes) li{
  position:relative; padding-left:1.15rem; color:var(--ink-2);
  font-size:1rem; line-height:1.6;
}
.movement > ul:not(.outcomes) li::before{
  content:""; position:absolute; left:0; top:.68em;
  width:.45rem; height:1px; background:var(--accent);
}

/* Outcomes read as prose, one sentence per line, at body size. A grid of
   large figures is the single most recognisable tell of a generated site, so
   the numbers stay inside the sentences that give them meaning - the way the
   existing site writes them. */
.outcomes{
  margin:0; padding:0; list-style:none;
  display:flex; flex-direction:column; gap:.85rem;
}
.outcomes li{
  position:relative; padding:0 0 0 1.15rem;
  color:var(--ink-2); font-size:1rem; line-height:1.6;
}
.outcomes li::before{
  content:""; position:absolute; left:0; top:.68em;
  width:.45rem; height:1px; background:var(--accent);
}
.outcomes b{ font-weight:600; color:var(--ink); }
/* Sub-clauses run on in the same sentence rather than sitting under it. */
.outcomes span{ display:inline; color:inherit; }
.outcomes span::before{ content:" - "; }

/* --------------------------------------------------------------- closing */
.closing{ background:var(--paper-2); }
.closing .narrative{ margin-bottom:0; }
.closing .thread{
  font-family:var(--display); font-weight:600;
  font-size:clamp(1.375rem,3vw,2rem); line-height:1.28;
  letter-spacing:-.022em; color:var(--ink); max-width:26ch; margin:0;
  text-wrap:pretty;
}

.principles{
  margin:0; padding:0; list-style:none; max-width:var(--figmax);
  display:grid; grid-template-columns:minmax(0,1fr); row-gap:0;
  border-top:1px solid var(--rule);
}
.principles li{
  padding:1rem 0; border-bottom:1px solid var(--rule);
  font-family:var(--display); font-size:1.0625rem; font-weight:600;
  letter-spacing:-.012em; color:var(--ink);
}


@media (max-width:56rem){
  .chronicle__head{ grid-template-columns:1fr; gap:.4rem; }
  .chronicle__body{ grid-template-columns:1fr; }
  .outcomes li{ padding-right:0; }
}

/* ------------------------------------------------------------------ bios */
/* about-us.html. Two people, introduced by each other - so the attribution
   is the point, not a footnote. */
.bios{
  display:grid; gap:clamp(2rem,5vw,4rem);
  grid-template-columns:repeat(auto-fit,minmax(18rem,1fr));
  border-top:1px solid var(--rule); padding-top:clamp(2rem,4vw,3rem);
}
.bio__portrait{
  width:clamp(7rem,14vw,9.5rem);
  height:clamp(7rem,14vw,9.5rem);   /* MUST be explicit: the HTML height
                                       attribute is a presentational hint that
                                       maps to CSS height, so aspect-ratio
                                       alone is silently ignored here. */
  object-fit:cover; object-position:var(--pos, center);
  border-radius:50%; margin-bottom:1.5rem; background:var(--paper-2);
}
/* Keep the two bios' text baselines aligned regardless of portrait shape. */
.bio{ display:flex; flex-direction:column; }
.bio h2{
  margin:0 0 1rem; font-family:var(--display); font-optical-sizing:auto;
  font-weight:700; font-size:clamp(1.5rem,2.6vw,2rem);
  line-height:1.1; letter-spacing:-.025em;
}
.bio p{ margin:0 0 1.1rem; color:var(--ink-2); max-width:var(--measure); }
.bio__by{
  margin-top:1.25rem; font-size:.75rem; font-weight:600; letter-spacing:.14em;
  text-transform:uppercase; color:var(--accent);
}

/* ==========================================================================
   INDEX RAIL
   Engagement only for now, pending a look.

   The interior pages run 8,000-12,000px with five or six case studies and no
   way to see what is on the page or reach one directly. The rail lists them in
   the left margin - which was empty anyway, since the copy is capped at a
   readable measure inside a much wider frame.

   It is a table of contents, not a widget: hairlines, the page's own numbering,
   and the accent only to mark position.
   ========================================================================== */
.caselist{
  display:grid; gap:clamp(2rem,5vw,4rem);
  grid-template-columns:minmax(0,14rem) minmax(0,1fr);
  align-items:start;
}
.caselist__items{ min-width:0; }

.rail{
  position:sticky; top:calc(64px + 1.5rem);   /* clears the fixed nav */
  align-self:start;
}
.rail__title{
  margin:0 0 1rem; font-size:.6875rem; font-weight:600; letter-spacing:.16em;
  text-transform:uppercase; color:var(--ink-3);
  padding-bottom:.75rem; border-bottom:1px solid var(--rule);
}
.rail__list{ list-style:none; margin:0; padding:0; counter-reset:none; }
.rail__list li + li{ border-top:1px solid var(--rule); }

.rail__list a{
  display:grid; grid-template-columns:1.5rem 1fr; gap:.15rem;
  align-items:baseline;
  padding:.7rem 0; min-height:44px;
  font-size:.875rem; line-height:1.35; letter-spacing:-.005em;
  color:var(--ink-2); text-decoration:none;
  transition:color .2s var(--ease);
}
.rail__n{
  font-variant-numeric:tabular-nums; font-weight:600; font-size:.75rem;
  color:var(--ink-3); transition:color .2s var(--ease);
}
.rail__list a:hover{ color:var(--ink); }
.rail__list a:hover .rail__n{ color:var(--accent); }

/* Position marker. A left bar rather than a colour swap, so the list stays
   quiet and only one thing moves as you scroll. */
.rail__list a{ position:relative; padding-left:.85rem; }
.rail__list a::before{
  content:""; position:absolute; left:0; top:.7rem; bottom:.7rem;
  width:2px; background:var(--accent);
  transform:scaleY(0); transform-origin:50% 0;
  transition:transform .28s var(--ease);
}
.rail__list a[aria-current="true"]{ color:var(--ink); font-weight:600; }
.rail__list a[aria-current="true"]::before{ transform:scaleY(1); }
.rail__list a[aria-current="true"] .rail__n{ color:var(--accent); }

/* Anchored jumps must clear the fixed nav. */
.chronicle{ scroll-margin-top:calc(64px + 1.5rem); }

@media (max-width:64rem){
  /* Below this the rail would squeeze the cards, and a sticky column on a
     short viewport is worse than none. The pages still read top to bottom. */
  .caselist{ grid-template-columns:minmax(0,1fr); }
  .rail{ display:none; }
}
@media (prefers-reduced-motion:reduce){
  .rail__list a::before{ transition:none; }
}
