/* =============================================================================
   ReLeaf: the homepage
   -----------------------------------------------------------------------------
   The page is one argument told in eight beats, in this order:

     1  first visual   Farmer Chen's farm, the photograph alone, with an
                       intro of its own and a drift into the map (18 Oct)
    (1b, the chapters dot rail in the right margin, was retired 18 Oct
                       at the owner's word; the nav card is the map)
     2  problem        01 the threat, 02 the gap, 03 the hour and the five
                       demands they earn, on white. home-problem.css holds
                       their shared frame, and each has its own sheet:
                       home-threat.css and
                       (with the reactor) home-reactor.css
     3  our answer     the reactor, the main character: one WebGL model on
                       ink with the same five demands around it; pointing at
                       a demand lights its parts (home-reactor.css)
     4  synbio         the inside of the reactor: a header row, one figure,
                       then the four modules as one run from light to protein
     5  iHP            the people who shaped the five demands, and the one
                       objection that became a design rule (home-ihp.css)
     6  big picture    one line of seven stations from the forecast to the
                       crop, with the work beside it (big-picture.css)
     7  vision         "Every farmer a biomanufacturer.": one farm becomes a
                       valley of them (home-vision.css)
     8  explore        where to read next: a few pages, one line each

   Rules that survived the redesign and should survive the next one:

   · NOTHING HERE IS A NUMBER, QUOTE, DATE OR RESULT that is not also on a
     sub-page with its evidence attached. The homepage is a door, not a source.
     The problem arc may cite outside literature, only through its numbered
     source list.
   · NO DISCLAIMERS ("still a plan", "design intent", "illustration", "nothing
     deployed"). Design is described as what the system does; an unmeasured
     result is never stated as a measurement.
   · THE PHOTOGRAPHS ARE ORDINARY on purpose. A cleanroom argues that you need
     a facility; a folding table argues that you do not.
   · ONE WebGL canvas, in #solution. Do not add a second one: the reactor is
     one packed bundle (hardware/bioreactor/models/_pack.*), parsed once.
   · EVERY SCROLL-DRIVEN EFFECT has a resting state that is correct with no
     JavaScript and no motion. Check with prefers-reduced-motion and with
     scripting off before shipping any change to the reactor, 03's figure or
     the vision.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; scroll-padding-top: calc(var(--nav-h) + 1rem); }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.68;
  color: var(--black);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img { display: block; max-width: 100%; }
a { color: var(--leaf-700); text-underline-offset: .18em; }
:focus-visible { outline: 2px solid var(--leaf-700); outline-offset: 3px; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.sitenav-spacer { height: var(--nav-h); }
/* nav.js draws the site bar; without scripting there is no bar to clear, so
   nothing sticks, pins or scrolls to a place 68px below the top edge */
@media (scripting: none) { :root { --nav-h: 0px; } .sitenav-spacer { display: none; } }

/* homepage-only tokens: the ink ground, and the one accent that is allowed
   to glow. --sig-green is the 520 nm the reactor actually runs on. */
:root {
  --ink:        #070b09;
  --sig-green:  #35e08a;
  --sig-dim:    #1b7f4d;   /* the 520 nm darkened for white grounds */
  /* The 520 nm, darkened for PAPER. #35e08a is 1.7:1 on white, which is not
     readable at any size, so anything on the white half of the page that has
     to mean "the green light" uses this instead: same hue, 5.4:1 on white,
     which passes AA for small text as well as large. The bright one stays
     for ink grounds, where it is 11.5:1, and for glows. */
  --sig-paper:  #0b7a46;
}

/* ---------------------------------------------------------------- bands --- */

.band { padding: var(--sp-8) 0; }
.band__inner { max-width: var(--max); margin: 0 auto; padding: 0 var(--sp-5); }
@media (min-width: 640px) { .band__inner { padding: 0 var(--sp-6); } }
/* THE SIDE GUTTER (the rail's, once: the chapters rail that lived in the
   right margin was retired 18 Oct). Every column on the page (.band__inner
   here, .pb-inner in home-problem.css, the reactor's --pad-x in
   home-reactor.css) still pads by this one value, so the sections keep one
   left edge: 64px from the window edge until the page's own margin is wider
   than that. */
@media (min-width: 1180px) {
  :root { --rail-gutter: max(var(--sp-6), calc(64px - max(0px, (100vw - var(--max)) / 2))); }
  .band__inner { padding-inline: var(--rail-gutter); }
}
/* TWO GROUNDS ONLY: white and ink. The "tint" bands used to be pale leaf with a
   leaf hairline top and bottom; they are plain white now, like every other light
   band. The class stays so the markup does not have to change. */
.band--tint { background: var(--white); }
.band--dark { background: var(--ink); color: var(--leaf-100); }
.band--dark a { color: var(--leaf-200); }

.kicker {
  margin: 0 0 var(--sp-4);
  font-size: .6875rem; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--leaf-700);
}
.band--dark .kicker { color: var(--sig-green); }

h2.band__title {
  margin: 0 0 var(--sp-5);
  font-family: var(--font-display);
  font-size: var(--text-h2);
  font-weight: 700; line-height: 1.14; letter-spacing: -.018em;
  color: var(--leaf-900);
  max-width: 26ch;
}

.lede { max-width: 62ch; font-size: var(--text-lede); line-height: 1.55; color: var(--gray-600); }
.band--dark .lede { color: var(--leaf-200); }

/* a small utility: fade-and-rise once, on entry (home.js piece 1). Visible
   by default: only home.js hides it (.is-armed), and only for an element that
   is still below the screen, so with scripting off, or a script that never
   runs, it is simply there. */
.rise { transition: opacity .7s ease, transform .7s ease; }
.rise.is-armed:not(.in) { opacity: 0; transform: translateY(18px); }
@media (prefers-reduced-motion: reduce) { .rise { transition: none; } }
/* printed before the reader scrolled to it, an armed element is still there */
@media print { .rise.is-armed { opacity: 1 !important; transform: none !important; transition: none !important; } }

/* ============================================================= 1  HERO ==== */
/* Farmer Chen's field, full screen, and nothing else (18 Oct: the light and
   the machine under it are gone).

   THE LAYERS, bottom to top:
     · .hero__frame--farm  the photograph and its wash.
     · .hero__veil         white, at nothing until the reader scrolls on:
                           the field fades into the map's white ground.
     · .hero__inner        the title and Farmer Chen's words.

   THE INTRO (home-hero.css) is classes on .hero: .is-pre is its first frame,
   .is-on plays it. Both are set by the hero's own script in index.html,
   which sets neither with reduced motion, so the defaults here are the
   finished hero. THE DRIFT on the way out is home.js piece 0, transform and
   opacity only. */

.hero {
  position: relative; isolation: isolate;
  background: var(--ink); color: var(--white);
  min-height: calc(100vh - var(--nav-h, 68px));
  min-height: calc(100svh - var(--nav-h, 68px));
  display: grid;
}
.hero__frames { position: absolute; inset: 0; container-type: size; overflow: hidden; }
.hero__frame { position: absolute; inset: 0; overflow: hidden; }
.hero__frame img { width: 100%; height: 100%; object-fit: cover; }

.hero__frame--farm { z-index: 1; }
.hero__frame--farm img { object-position: 50% 42%; }

/* The photograph's stand-in: the same picture 48 px wide (half a kilobyte),
   blurred. With script (html.hl, set in <head>) the photograph waits at
   nothing until it is decoded and then fades in over it, so a slow line sees
   the field come into focus instead of a picture drawn in from the top.
   Without script the photograph simply loads over it. */
.hero__frame--farm::before {
  content: ""; position: absolute; inset: -8%; z-index: -1;
  background: url("../img/home/hero-team-lqip.webp") 50% 42% / cover no-repeat;
  filter: blur(26px);
}
html.hl .hero__frame--farm img { opacity: 0; transition: opacity .9s ease; }
html.hl .hero__frame--farm img.is-in { opacity: 1; }

/* The wash: a corner shadow for the title, a foot shadow for the quote, an
   edge vignette on the right. Light, so the field keeps its daylight. */
.hero__frame--farm::after {
  content: ""; position: absolute; inset: 0; z-index: 2;
  background:
    radial-gradient(125% 80% at 0% 0%,
      rgb(7 11 9 / .78) 0%, rgb(7 11 9 / .42) 30%, rgb(7 11 9 / .1) 54%, transparent 72%),
    linear-gradient(180deg,
      rgb(7 11 9 / .24) 0%, rgb(7 11 9 / .02) 36%, rgb(7 11 9 / .2) 72%, rgb(7 11 9 / .7) 100%),
    linear-gradient(90deg, rgb(7 11 9 / .16) 0%, rgb(7 11 9 / .02) 52%, rgb(7 11 9 / .18) 74%, rgb(7 11 9 / .62) 100%);
}

/* white over the field, raised by the scroll (home.js piece 0) */
.hero__veil { position: absolute; inset: 0; z-index: 2; background: var(--white); opacity: 0; pointer-events: none; }

/* One column: the title top left, the foot bottom right, a spring between. */
.hero__inner {
  position: relative; z-index: 3;
  width: 100%; max-width: var(--max); margin: 0 auto;
  padding: clamp(3.5rem, 2rem + 6vh, 6.5rem) var(--sp-5) clamp(1.75rem, 1rem + 3vh, 3rem);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto 1fr auto;
}
@media (min-width: 640px) { .hero__inner { padding-left: var(--sp-6); padding-right: var(--sp-6); } }
/* 18 Oct (Jacquelyn): the title and its line sit at the screen's left
   margin, not the content column's, on wide screens too */
@media (min-width: 1100px) { .hero__inner { max-width: none; padding-left: clamp(2rem, 4vw, 4.5rem); padding-right: clamp(2rem, 4vw, 4.5rem); } }

.hero__head { grid-row: 1; justify-self: start; }
.hero__claim {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 750; color: var(--white);
  text-wrap: balance;
}

.hero__foot { grid-row: 3; align-self: end; display: flex; justify-content: flex-end; }
.hero__note { margin: 0; }
.hero__note p { margin: 0; font-style: italic; text-wrap: pretty; }
.hero__note p::before { content: "\201C"; }
.hero__note p::after  { content: "\201D"; }

@media (max-width: 800px) {
  .hero__frame--farm img { object-position: 45% 50%; }
  .hero__frame--farm::after {
    background:
      linear-gradient(180deg,
        rgb(7 11 9 / .72) 0%, rgb(7 11 9 / .22) 30%, rgb(7 11 9 / .48) 62%, rgb(7 11 9 / .93) 100%);
  }
}
/* a phone held upright gets the portrait files (index.html) */
@media (max-aspect-ratio: 2/3) {
  .hero__frame--farm img { object-position: 50% 50%; }
  .hero__frame--farm::before { background-image: url("../img/home/hero-team-portrait-lqip.webp"); background-position: 50% 50%; }
}

/* ========================================================== 4  SYNBIO ===== */
/* One header column, then the circuit figure and the four modules under it, on one line, each with a numbered disc in the colour of
   its box in the figure. One numbering (1 to 4), one type family, and the
   modules close the card: there is no caption (owner, 29 Sep), so the row
   takes a little more room below than above and the card ends on it. */

.sb__head { max-width: 46rem; margin-bottom: var(--sp-6); }
.sb__head .kicker { margin-bottom: var(--sp-3); }
/* 7 Oct: no lede under this title; the title carries the fact, so it keeps
   the whole gap to the figure (.sb__lede and its rule went with it) */
.sb__head .band__title { margin-bottom: 0; max-width: 26ch; }

/* 1 Oct (Jacquelyn: the outline round it read as generated). No box: the
   figure and the four modules sit straight on the white, and the modules'
   own rail is the only line. */
.sb-card { margin: 0; background: var(--white); }

/* the figure: its own width reserved by the <img>'s attributes. Narrower
   than 42rem it scrolls sideways (60rem on a phone, so the labels stay
   readable); the frame is a keyboard scroll container with a focus ring. */
.sb-fig__frame { overflow-x: auto; }
.sb-fig__frame:focus-visible { outline: 2px solid var(--leaf-700); outline-offset: -3px; }
.sb-card img { display: block; min-width: 42rem; width: 100%; height: auto; }
.sb-fig__swipe { display: none; }
@media (max-width: 740px) {
  .sb-fig__swipe {
    display: block; margin: 0; padding: var(--sp-2) var(--sp-5);
    font-size: var(--text-xs); line-height: 1.5; color: var(--gray-500);
  }
  .sb-fig__plate { position: relative; }
  .sb-fig__plate::after {
    content: ""; position: absolute; top: 0; right: 0; bottom: 0; width: 3rem;
    pointer-events: none;
    background: linear-gradient(90deg, rgb(255 255 255 / 0), rgb(255 255 255 / .92));
  }
  .sb-card img { min-width: 60rem; }
}

/* the four modules: numbered discs on one rail, under the figure */
.sb-seq {
  list-style: none; margin: 0; padding: var(--sp-6) 0 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: var(--sp-5);
  position: relative;
}
.sb-step { position: relative; }
/* the rail: from each disc to the next one */
.sb-step:not(:last-child)::after {
  content: ""; position: absolute; top: .8rem; left: 1.6rem; right: calc(-1 * var(--sp-5));
  height: 1px; background: var(--gray-300);
}
/* --sb is the colour of that module's box in the BioRender figure, darkened
   until white text on it clears 4.5:1 */
.sb-step:nth-child(1) { --sb: #456f3c; }   /* module 1, green  */
.sb-step:nth-child(2) { --sb: #2d6f80; }   /* module 2, blue   */
.sb-step:nth-child(3) { --sb: #42639f; }   /* module 3, indigo */
.sb-step:nth-child(4) { --sb: #7d5512; }   /* module 4, amber  */
.sb-step__n {
  position: relative;
  display: grid; place-items: center;
  width: 1.6rem; height: 1.6rem; border-radius: 50%;
  background: var(--sb); color: var(--white);
  font-size: .8rem; font-weight: 700; font-variant-numeric: tabular-nums;
  box-shadow: 0 0 0 4px var(--white);
}
.sb-step__t {
  margin: var(--sp-3) 0 var(--sp-2);
  font-family: var(--font-display); font-size: var(--text-base);
  font-weight: 700; line-height: 1.25; color: var(--leaf-900);
}
.sb-step__p { margin: 0; font-size: var(--text-sm); line-height: 1.55; color: var(--gray-600); text-wrap: pretty; }

@media (max-width: 899px) {
  .sb-seq { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: var(--sp-5); }
  .sb-step::after { display: none; }
}
@media (max-width: 559px) {
  .sb-seq { grid-template-columns: 1fr; }
  .sb-step { display: grid; grid-template-columns: 1.6rem minmax(0, 1fr); column-gap: var(--sp-3); }
  .sb-step__n { grid-row: 1 / span 2; }
  .sb-step__t { margin-top: .1rem; }
}

/* ========================================================= 8  EXPLORE ===== */
/* Five pages as picture cards. The menu reaches every page, so this only
   names where to start: two wide cards on the first row (Description,
   Results), then the three pages the team is nominated for (Hardware,
   Measurement, Integrated Human Practices).

   NO CAPTIONS, AND THE NAME SITS ON THE PICTURE (owner, 7 Oct). The band
   under the photograph that this section had for an afternoon is gone. What
   carries the white type instead is a shade in the bottom third of the card
   only: it is written as seven stops of a smoothstep rather than two of a
   linear ramp, so it has no visible edge and no band of grey across the
   middle of the photograph, and it stops well short of the top, where the
   subject of every one of these five pictures is. Nothing is drawn into the
   image files themselves.

   Hover and focus move the photograph and the arrow, never the name.
   ========================================================================== */
.xp .lede { margin-bottom: var(--sp-6); }
.xp-cards {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: clamp(var(--sp-4), 1.4vw, var(--sp-5));
  grid-template-columns: repeat(6, minmax(0, 1fr));
}
.xp-card { grid-column: span 2; }
.xp-card--big { grid-column: span 3; }
.xp-card a {
  position: relative; display: block; height: 100%;
  border-radius: 1rem; overflow: hidden;
  background: var(--ink);
  color: var(--white); text-decoration: none;
  transition: box-shadow .3s ease, transform .3s ease;
}
.xp-card img {
  display: block; width: 100%; aspect-ratio: 16 / 9; height: auto; object-fit: cover;
  transition: transform .6s cubic-bezier(.2, .7, .2, 1);
}
.xp-card--big img { aspect-ratio: 21 / 9; }

/* the shade: the bottom third, eased, so it has no edge anywhere */
.xp-card a::before {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(to top,
    rgb(7 11 9 / .78) 0%,
    rgb(7 11 9 / .74) 5%,
    rgb(7 11 9 / .62) 11%,
    rgb(7 11 9 / .44) 18%,
    rgb(7 11 9 / .26) 25%,
    rgb(7 11 9 / .12) 32%,
    rgb(7 11 9 / .03) 39%,
    transparent 46%);
  transition: opacity .3s ease;
}
/* a hairline inside the corner radius, so a pale photograph still reads as
   a card on the band's pale ground */
.xp-card a::after {
  content: ""; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgb(7 11 9 / .08);
}
.xp-card__name {
  position: absolute; z-index: 2; left: 0; right: 0; bottom: 0;
  margin: 0; padding: clamp(1rem, .6rem + 1vw, 1.6rem) clamp(1.1rem, .7rem + 1vw, 1.75rem);
  font-family: var(--font-display);
  font-size: clamp(1.375rem, .95rem + 1.2vw, 2rem);
  font-weight: 750; line-height: 1.1; letter-spacing: -.028em;
  color: var(--white);
  text-shadow: 0 1px 2px rgb(7 11 9 / .45), 0 2px 22px rgb(7 11 9 / .55);
  text-wrap: balance;
}
.xp-card--big .xp-card__name { font-size: clamp(1.625rem, 1.05rem + 1.6vw, 2.5rem); }
/* the arrow stays in the text flow, so on a name that takes two lines it
   follows the last word; the no-break space keeps it off a line of its own */
.xp-card__name::after {
  content: "\00a0\2192";
  display: inline-block; font-weight: 600; color: var(--sig-green);
  text-shadow: 0 1px 10px rgb(7 11 9 / .5);
  transition: transform .3s cubic-bezier(.2, .7, .2, 1);
}
.xp-card a:hover { box-shadow: 0 16px 44px rgb(7 11 9 / .2); transform: translateY(-3px); }
.xp-card a:hover img { transform: scale(1.04); }
.xp-card a:hover::before { opacity: .88; }
.xp-card a:hover .xp-card__name::after { transform: translateX(.32em); }
.xp-card a:focus-visible { outline: 2px solid var(--leaf-700); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .xp-card a, .xp-card img, .xp-card__name::after, .xp-card a::before { transition: none; }
  .xp-card a:hover { transform: none; }
  .xp-card a:hover img { transform: none; }
  .xp-card a:hover .xp-card__name::after { transform: none; }
}

/* two up, then one up: the wide cards keep their 21:9, the rest 16:9 */
@media (max-width: 899px) {
  .xp-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .xp-card, .xp-card--big { grid-column: span 1; }
  .xp-card--big img { aspect-ratio: 16 / 9; }
  .xp-card__name, .xp-card--big .xp-card__name { font-size: clamp(1.1875rem, .85rem + 1.1vw, 1.625rem); }
}
@media (max-width: 559px) {
  .xp-cards { grid-template-columns: 1fr; }
  .xp-card img, .xp-card--big img { aspect-ratio: 2 / 1; }
  .xp-card__name, .xp-card--big .xp-card__name { font-size: 1.5rem; }
}
/* with scripting off there is no menu at the top: drop the sentence about it */
@media (scripting: none) { .xp-menu { display: none; } }

/* ============================================================== FOOTER ==== */
/* footer2 comes from page.css; the homepage loads it for that alone.
   page.css paints it grey-50 for every page on the wiki; the homepage keeps to
   white and ink, so it is overridden here and nowhere else. */
.footer2 { background: var(--white); }

/* 1 Oct (students: "... with a / protein"). The synbio title runs to one
   line where it fits and breaks into two even lines where it does not. */
.sb__head .band__title { max-width: 36ch; text-wrap: balance; }
