/* =========================================================================
   CHAPTER PAGES — rails of cards, and the card popup.

   The chapters used to be one long scroll-driven scene. They are now what
   apple.com does on its front page: a titled row of cards you push sideways.
   A card is a headline and a picture; everything else waits behind a tap, so
   the page stays quiet and nothing scroll-jacks the reader.
   ========================================================================= */
body.chapter { background:#f5f5f7; color:var(--black); }
/* the chapter switcher is pinned to the bottom of the window, so the page has
   to end above it rather than under it */
body.chapter main { padding-bottom:calc(var(--pfoot-h, 3.6rem) + 2rem); }

/* ---- the opening, built like the brochure covers ----
   One rounded card with the headline and its pills, and the chapter's own
   photograph breaking out over its edge. The overlap is the whole point: a
   panel with everything tidily inside it reads as a slide. */
.chero {
  position:relative;
  width:min(76rem,92vw); margin:0 auto;
  padding:clamp(1.6rem,4vw,3rem) 0 clamp(3rem,7vw,5.5rem);
}
.chero__card {
  position:relative; z-index:1;
  width:min(100%, 70%);
  border-radius:clamp(24px,3vw,36px);
  padding:clamp(1.8rem,4vw,3.2rem);
  background:
    radial-gradient(120% 130% at 8% 4%, #ffffff 0%, #eef1f6 52%, #e4e9f2 100%);
  box-shadow:0 40px 80px -44px rgba(16,32,64,0.55), 0 2px 10px -6px rgba(16,32,64,0.3);
}
.chero__logo { position:absolute; top:clamp(1.4rem,3vw,2.2rem); right:clamp(1.4rem,3vw,2.2rem); height:2.4rem; }

/* the pills, straight off the brochure covers */
.chero__pills { list-style:none; display:flex; flex-wrap:wrap; gap:0.5rem; margin:1.1rem 0 0; }
/* A pill keeps its text on one line — until the line is longer than the phone.
   "First second-generation graduate (with Dr. Abel)" is 344px of nowrap on a
   320px screen, and a flex row cannot wrap what refuses to break, so it hung
   65px off the edge and let the whole page pan sideways. */
.chero__pills li { max-width:100%; }
@media (max-width:640px) { .chero__pills li { white-space:normal; } }
.chero__pills li {
  padding:0.42rem 1rem; border-radius:999px;
  border:1.5px solid rgba(16,42,90,0.22); background:rgba(255,255,255,0.72);
  font-size:0.82rem; font-weight:600; color:#1a2b47; white-space:nowrap;
}

/* the photograph, hung off the card's right edge */
.chero__pop {
  position:absolute; z-index:2; margin:0;
  right:0; bottom:0; width:min(44%, 27rem); aspect-ratio:4/5;
  border-radius:clamp(18px,2.4vw,28px); overflow:hidden;
  box-shadow:0 50px 90px -40px rgba(16,32,64,0.75), 0 0 0 8px rgba(255,255,255,0.85);
  transform:rotate(-1.4deg);
}
.chero__pop img { width:100%; height:100%; object-fit:cover; display:block; }

.chero__kicker {
  font-size:0.78rem; font-weight:700; letter-spacing:0.14em; text-transform:uppercase;
  color:var(--blue); margin-bottom:0.7rem;
}
.chero__h {
  font-size:clamp(2rem,4.6vw,3.4rem); line-height:1.06; letter-spacing:-0.02em;
  font-weight:700;
}
.chero__h em { font-style:normal; color:#6e6e73; }
/* the copy stops short of where the photograph overlaps the card */
.chero__card > * { max-width:min(100%, 30rem); }
.chero__lead {
  font-size:clamp(1rem,1.5vw,1.2rem); line-height:1.5; color:#3a3a3e;
  margin-top:0.9rem;
}
.chero__meta {
  display:flex; flex-wrap:wrap; gap:0.4rem 2rem; margin-top:1.4rem;
  font-size:0.82rem; color:#6e6e73;
}
.chero__meta span { display:grid; }
.chero__meta b {
  color:var(--black); font-size:0.72rem; letter-spacing:0.08em; text-transform:uppercase;
}

/* ---- a rail ---- */
.crail { width:100%; padding:clamp(1.4rem,3.5vw,2.6rem) 0; }
.rail__head {
  display:flex; align-items:flex-end; gap:1rem;
  width:min(76rem,92vw); margin:0 auto 1rem;
}
.rail__title {
  font-size:clamp(1.3rem,2.4vw,1.9rem); font-weight:700; letter-spacing:-0.02em;
  line-height:1.2; margin-right:auto; max-width:52rem;
}
.rail__title span { color:#86868b; font-weight:600; }
.rail__nav { display:flex; gap:0.5rem; flex:none; }
.rail__arrow {
  width:2.3rem; height:2.3rem; border-radius:50%; border:0; cursor:pointer;
  background:rgba(0,0,0,0.06); color:#1d1d1f; font-size:1.3rem; line-height:1;
  display:grid; place-items:center;
  transition:background 0.18s ease, opacity 0.18s ease;
}
.rail__arrow:hover { background:rgba(0,0,0,0.12); }
.rail__arrow:disabled { opacity:0.25; cursor:default; }
.crail:not(.is-scrollable) .rail__nav { display:none; }

.rail__track {
  list-style:none; display:flex; gap:1.25rem;
  overflow-x:auto; overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory;
  scroll-padding-left:max(4vw, calc((100vw - 76rem) / 2));
  /* Room above the cards for the lift. overflow-x:auto makes overflow-y auto
     too, so a card that rises has to rise into padding or it is clipped —
     which the hover lift was already just barely getting away with. */
  padding:1.4rem max(4vw, calc((100vw - 76rem) / 2)) 1.6rem;
  scrollbar-width:none;
}
.rail__track::-webkit-scrollbar { display:none; }
.rail__track.is-dragging { scroll-snap-type:none; cursor:grabbing; }
.rail__item { flex:none; scroll-snap-align:start; width:clamp(16rem,25vw,22rem); }

/* ---- a card ---- */
.acard {
  display:flex; flex-direction:column; width:100%; aspect-ratio:3/4;
  border:0; padding:0; cursor:pointer; text-align:left; overflow:hidden;
  border-radius:22px; background:var(--white); color:var(--black);
  box-shadow:0 2px 10px -4px rgba(0,0,0,0.16);
  transition:transform 0.28s cubic-bezier(0.2,0.9,0.3,1.1), box-shadow 0.28s ease;
}
.acard:hover, .acard:focus-visible {
  transform:translateY(-6px);
  box-shadow:0 26px 48px -22px rgba(0,0,0,0.45);
}
.acard:focus-visible { outline:3px solid var(--blue); outline-offset:3px; }
.acard--dark { background:#111114; color:var(--white); }

.acard__body { display:block; padding:1.5rem 1.5rem 0.6rem; }
.acard__kicker {
  display:block; font-size:0.7rem; font-weight:700; letter-spacing:0.1em;
  text-transform:uppercase; color:#bf5a11; margin-bottom:0.55rem;
}
.acard--dark .acard__kicker { color:#ff9f4a; }
.acard__kicker.is-live { color:#0e8b51; }
.acard--dark .acard__kicker.is-live { color:#3ddc97; }
.acard__title {
  display:block; font-size:clamp(1.15rem,1.7vw,1.45rem); font-weight:700;
  line-height:1.18; letter-spacing:-0.015em;
}
.acard__sub { display:block; font-size:0.85rem; color:#6e6e73; margin-top:0.4rem; }
.acard--dark .acard__sub { color:#a1a1a6; }
.acard__big {
  display:block; font-size:clamp(2.2rem,4vw,3rem); font-weight:700; letter-spacing:-0.03em;
  color:var(--blue); margin:0 0 0.35rem; line-height:1;
}
.acard--dark .acard__big { color:#5cb2ff; }
.acard__media { display:block; flex:1; min-height:0; margin-top:0.8rem; }
.acard__media img { width:100%; height:100%; object-fit:cover; display:block; }

/* ---- the closing band ---- */
.cband {
  width:min(76rem,92vw); margin:clamp(1.5rem,4vw,3rem) auto 0;
  background:var(--black); color:var(--white); border-radius:26px;
  padding:clamp(2rem,5vw,3.4rem); text-align:center;
}
.cband h2 { font-size:clamp(1.5rem,3vw,2.3rem); font-weight:700; letter-spacing:-0.02em; }
.cband h2 em { font-style:normal; color:#8ec5ff; }
.cband p { color:#a1a1a6; margin:0.7rem auto 1.4rem; max-width:38rem; }

@media (max-width:900px) {
  /* nothing hangs off anything on a phone — the picture simply sits under the
     card, still overlapping it a little so the pair still reads as one thing */
  .chero__card { width:100%; padding-bottom:clamp(4rem,18vw,7rem); }
  .chero__pop {
    position:relative; right:auto; bottom:auto; width:min(20rem,62vw);
    aspect-ratio:4/3; margin:-3.5rem 0 0 auto; transform:rotate(-1.4deg);
  }
  .chero__logo { height:1.9rem; }
  .rail__track { scroll-padding-left:4vw; padding-left:4vw; padding-right:4vw; }
  .rail__head { width:92vw; }
  .rail__item { width:min(17rem,74vw); }
}

/* =========================================================================
   THE CARD POPUP
   Portrait panel: pictures on top, then the words, which scroll on their own
   when there are a lot of them. Two ways out and no others — the round X, or
   anywhere outside the panel.
   ========================================================================= */
.pop {
  position:fixed; inset:0; z-index:200; display:grid; place-items:center;
  padding:clamp(0.8rem,3vw,2rem); opacity:0; transition:opacity 0.24s ease;
}
.pop.is-open { opacity:1; }
.pop[hidden] { display:none; }
.pop__scrim {
  position:absolute; inset:0; cursor:pointer;
  background:color-mix(in srgb, var(--black) 55%, transparent); backdrop-filter:blur(14px);
}
.pop__panel {
  position:relative; width:min(30rem,94vw); max-height:min(88vh,52rem);
  display:flex; flex-direction:column; overflow:hidden;
  background:var(--white); color:var(--black); border-radius:26px;
  box-shadow:0 50px 110px -30px rgba(0,0,0,0.7);
  transform:scale(0.94) translateY(12px);
  transition:transform 0.3s cubic-bezier(0.2,0.9,0.3,1.2);
}
.pop.is-open .pop__panel { transform:none; }

.pop__x {
  position:absolute; top:0.85rem; right:0.85rem; z-index:3;
  width:2.1rem; height:2.1rem; border-radius:50%; border:0; cursor:pointer;
  background:color-mix(in srgb, var(--black) 45%, transparent); color:var(--white);
  font-size:1.25rem; line-height:1; display:grid; place-items:center;
  backdrop-filter:blur(6px);
  transition:background 0.18s ease, transform 0.18s ease;
}
.pop__x:hover { background:var(--black); transform:scale(1.08); }

/* the pictures */
.pop__media { position:relative; flex:none; aspect-ratio:4/3; overflow:hidden; background:#101018; }
.pop__media[hidden] { display:none; }
.pop__slides { display:flex; height:100%; transition:transform 0.5s cubic-bezier(0.3,0.9,0.3,1); }
.pop__slide { flex:none; width:100%; height:100%; margin:0; }
/* THE WHOLE PICTURE, NOT A CROP OF IT.
   `cover` filled the box by cutting the picture, which is right for a card on
   a ring — the card is a thumbnail and a crop of a photograph still reads.
   It is wrong HERE. This panel is where somebody has pressed BECAUSE they
   wanted to see the picture, and half of what they open is a logo, a goal
   badge or a screen grab with words on it. Cropping those takes the words
   off: the SDG badges opened with their own numbers cut in half.
   `contain` on a neutral ground shows all of it, always. A photograph gets a
   little air at the sides, which reads as deliberate; a badge stays a badge. */
.pop__slide img { width:100%; height:100%; object-fit:contain; display:block; }
.pop__dots {
  position:absolute; left:50%; bottom:0.7rem; transform:translateX(-50%);
  display:flex; gap:0.4rem; padding:0.35rem 0.6rem; border-radius:999px;
  background:color-mix(in srgb, var(--black) 38%, transparent); backdrop-filter:blur(6px);
}
.pop__dots[hidden] { display:none; }
.pop__dots i {
  width:0.42rem; height:0.42rem; border-radius:50%; cursor:pointer;
  background:rgba(255,255,255,0.45); transition:background 0.2s ease, transform 0.2s ease;
}
.pop__dots i.is-on { background:var(--white); transform:scale(1.25); }

/* The picture above is cropped to a 4:3 box. This opens the whole one, at its
   own size, in a tab of its own. Bottom right, so it clears the round X above
   it and the dots in the middle. */
.pop__view {
  position:absolute; right:0.7rem; bottom:0.7rem; z-index:3;
  padding:0.35rem 0.7rem; border-radius:999px;
  font-size:0.72rem; font-weight:700; letter-spacing:0.02em; line-height:1;
  color:var(--white); text-decoration:none; white-space:nowrap;
  background:color-mix(in srgb, var(--black) 45%, transparent);
  backdrop-filter:blur(6px);
  /* the band is clipped to the pill */
  overflow:hidden;
  transition:background 0.18s ease, transform 0.18s ease;
  /* a slow breath of light around it, so it is findable on a busy photograph
     even in the four seconds between sweeps */
  animation:pop-view-glow 3.4s ease-in-out infinite;
}
.pop__view[hidden] { display:none; }
.pop__view:hover { background:var(--black); transform:translateY(-1px); }
.pop__view:focus-visible { outline:2px solid var(--white); outline-offset:2px; }

/* THE SWEEP. Same idiom as the cards on the rest of the site — a narrow
   diagonal band, moving for about a second of a three-and-a-bit second cycle,
   so most of the time nothing is moving and it never becomes noise.
   Its own keyframes rather than shine.css's, because this button lives inside
   a panel that is display:none until it is opened, and the script that hands
   out the site's shine measures where things sit on the page. It cannot
   measure something that is not there yet. */
/* MEASURED IN PIXELS, ON A BOX THAT FILLS THE PILL.
   Two earlier attempts failed the same way and both looked right in the
   computed styles. One animated background-position against a gradient sized
   240% of the box; the other positioned a skewed bar with percentage offsets.
   In each the bright part sat outside the pill for the whole sweep and
   nothing ever appeared on screen.
   What settled it was painting the pseudo-element solid red: it filled the
   pill, so it was never a question of whether it drew — only of where the
   light was. So: a box that covers the pill exactly, a 70-pixel band inside
   it, and a position in PIXELS, which cannot be misread. */
.pop__view::after {
  content:''; position:absolute; inset:0; border-radius:inherit;
  pointer-events:none;
  background-image:linear-gradient(100deg,
    rgba(255,255,255,0) 0%,
    rgba(255,255,255,0.18) 35%,
    rgba(255,255,255,0.68) 50%,
    rgba(255,255,255,0.18) 65%,
    rgba(255,255,255,0) 100%);
  background-repeat:no-repeat;
  background-size:58px 100%;
  background-position-x:-80px;
  animation:pop-view-shine 3.4s ease-in-out infinite;
}
/* It travels for about a second of the three and a bit, then waits — most of
   the time nothing is moving, which is what keeps it from being noise. */
@keyframes pop-view-shine {
  0%, 8%     { background-position-x:-80px; }
  34%, 100%  { background-position-x:230px; }
}
@keyframes pop-view-glow {
  0%, 100% { box-shadow:0 0 0 0 rgba(255,255,255,0); }
  30%      { box-shadow:0 0 14px 1px rgba(255,255,255,0.5); }
}
/* once it has been found it stops asking to be found */
.pop__view:hover, .pop__view:focus-visible { animation:none; }
.pop__view:hover::after, .pop__view:focus-visible::after { animation:none; opacity:0; }

/* the words — this is the part that scrolls */
.pop__scroll { overflow-y:auto; padding:1.4rem 1.5rem 1.6rem; -webkit-overflow-scrolling:touch; }
.pop__kicker {
  font-size:0.7rem; font-weight:700; letter-spacing:0.1em; text-transform:uppercase;
  color:var(--blue); margin-bottom:0.4rem;
}
.pop__title { font-size:1.4rem; font-weight:700; letter-spacing:-0.02em; line-height:1.2; }
.pop__sub { font-size:0.95rem; color:#3a3a3e; margin-top:0.35rem; }
.pop__meta { font-size:0.78rem; color:#86868b; margin-top:0.5rem; }
.pop__text { margin-top:0.9rem; }
.pop__text p { font-size:0.94rem; line-height:1.6; color:#3a3a3e; }
.pop__text p + p { margin-top:0.8rem; }
/* an address inside a story. It has to break, or one long one pushes the
   panel wider than the phone it is being read on */
.pop__link {
  color:var(--blue); font-weight:600; text-decoration:underline;
  text-underline-offset:2px; overflow-wrap:anywhere;
}
.pop__link:hover { color:var(--black); }
.pop__go {
  display:inline-block; margin-top:1.1rem; font-size:0.9rem; font-weight:700;
  color:var(--blue); text-decoration:none;
}
.pop__go:hover { text-decoration:underline; }

@media (prefers-reduced-motion:reduce) {
  .pop, .pop__panel, .pop__slides, .acard { transition:none; }
  /* Somebody who has asked their computer for less movement has asked for
     this too. The button is still there and still says what it does. */
  .pop__view { animation:none; }
  .pop__view::after { animation:none; opacity:0; }
}

/* a box that has not been published yet — only ever seen on the preview link */
.acard--draft { outline: 3px dashed #ffb020; outline-offset: -3px; }
.acard__draft {
  position: absolute; top: 0.8rem; right: 0.8rem; z-index: 2;
  background: #ffb020; color: #3a2600; font-size: 0.62rem; font-weight: 800;
  letter-spacing: 0.08em; text-transform: uppercase;
  padding: 0.2rem 0.55rem; border-radius: 999px;
}
.acard { position: relative; }

/* =========================================================================
   THE USHER
   A salesperson does not hand a stranger a brochure and walk away. They point
   at one thing, say what it is, then point at the next. This is that, in a
   row of cards: each one is scanned, lifts, and settles, left to right, and
   then the row rests before going round again.

   Only ONE row on the page does it at a time — whichever is nearest the middle
   of the screen. Eight rows all pointing at once is not a guide, it is a
   fairground.

   It stops the moment somebody touches the row. They have taken over, and
   being led by the elbow after that is annoying rather than helpful.
   ========================================================================= */
.acard.is-usher {
  z-index: 3;
  animation: usher-lift 900ms cubic-bezier(0.22, 1.3, 0.34, 1);
}

@keyframes usher-lift {
  0%   { transform: none; }
  26%  { transform: translateY(-9px) scale(1.032); }
  52%  { transform: translateY(-2px) scale(1.006); }
  74%  { transform: translateY(-6px) scale(1.020); }
  100% { transform: none; }
}

/* the scan passing over it. ::after belongs to the shine that every card
   already carries, so this is ::before. */
.acard::before {
  content: '';
  position: absolute; inset: 0; z-index: 4;
  pointer-events: none; border-radius: inherit;
  opacity: 0;
}
.acard.is-usher::before {
  /* A NARROW band, and a see-through one. The first version ran from 38% to
     62% of an image two and a half times the card's width — well over half the
     card lit at once, in near-solid blue, which did not read as light passing
     over the card so much as paint being poured on it. You could not read the
     card underneath. */
  background: linear-gradient(
    100deg,
    transparent 45%,
    color-mix(in srgb, var(--blue) 18%, transparent) 48.5%,
    color-mix(in srgb, #dbeeff 62%, transparent) 50%,
    color-mix(in srgb, var(--blue) 18%, transparent) 51.5%,
    transparent 55%);
  background-size: 200% 100%;
  background-repeat: no-repeat;
  animation: usher-scan 900ms ease-out;
}
@keyframes usher-scan {
  0%   { opacity: 0;   background-position: 100% 0; }
  14%  { opacity: 0.9; }
  78%  { opacity: 0.9; }
  100% { opacity: 0;   background-position: 0% 0; }
}

/* and a ring, so the card is picked out of the row even where the scan has
   already passed */
.acard.is-usher {
  box-shadow:
    0 0 0 2px color-mix(in srgb, var(--blue) 70%, transparent),
    0 26px 52px -20px color-mix(in srgb, var(--blue) 45%, transparent),
    0 18px 40px -22px rgba(0, 0, 0, 0.5);
}

/* A card being pointed at should not also be swept by the ambient shine —
   two lights on the same object at once reads as a glitch. */
.acard.is-usher.shine::after { animation-play-state: paused; opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  .acard.is-usher, .acard.is-usher::before { animation: none; }
  .acard.is-usher { box-shadow: 0 0 0 2px var(--blue); }
}
