/* Claudia Conte — the chosen composition, in two states of one page.

   One document, one set of words, and a width that decides which drawing they
   are set in.

   BRANCH (the default, and everything a phone or a narrow window ever sees):
   a single hairline runs down the page and every section hangs off it at a
   blossom node. The painting is a small mark in the masthead and a print at
   the foot of the practical section. Nothing moves but the branch drawing
   itself, once, on arrival.

   FIELD (from the width named in `data-wide` on <html>): the tree is the
   field. It stands the height of the opening, the words sit low on its left
   on the ground it grows out of, blossoms fall through the whole opening and
   a pointer sweep lets a gust of wind cross it. The sections below return to
   a centred axis.

   The two are not two pages: the words, the calls to action and the facts are
   written once in the markup and are the same in both. What changes is the
   room they stand in — and when the width crosses, the room is rebuilt in
   front of the reader rather than swapped under them; see "the crossing".

   Loads on top of shared/base.css. */

/* The branch state must never be able to scroll sideways, and neither may the
   half-second in which the field's tree is on its way out of the room. */
body { overflow-x: clip; }

/* ---------- the identity mark: a wash, not a tile ----------
   boom.jpg's painted ground is a flat #FBD9D8 over most of its width, so the
   mark stands on a wash of exactly that colour and only the wash has to meet
   the paper. `darken` hands every pixel of the ground that is lighter than
   the wash — the pale band down the left of the painting — over to the wash,
   which leaves the tree's own ink as the whole of the mark. Two offset
   ellipses rather than one keep the wash from reading as a disc; the opaque
   core is sized to contain the whole 56 x 48 picture, corners included, or
   the JPEG's corners would surface again. */

.brand-mark {
  position: relative;
  display: grid;
  place-items: center;
  flex: none;
  width: 150px;
  height: 130px;
  margin-inline: -34px -22px;
  margin-block: -22px;
}
.brand-mark::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(closest-side at 48% 46%,
      var(--wash) 0 51%,
      rgba(251, 217, 216, 0.76) 64%,
      rgba(251, 217, 216, 0.32) 82%,
      rgba(251, 217, 216, 0) 100%),
    radial-gradient(closest-side at 62% 63%,
      rgba(251, 217, 216, 0.46) 0 34%,
      rgba(251, 217, 216, 0) 100%);
}
.brand-mark img {
  position: relative;
  width: 56px;
  height: auto;
  mix-blend-mode: darken;
}

/* The masthead keeps its own plane above the opening. While the field is
   closing, the tree travels up through the space the opening is giving back,
   and the brand must not be underneath it for those few hundred milliseconds. */
.shell-top { position: relative; z-index: 3; }

/* ---------- the branch: spine and blossom nodes ---------- */

.spine { position: relative; padding-left: var(--spine-gap); --spine-gap: clamp(1.35rem, 3.2vw, 2.75rem); }
.spine::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 1px;
  transform-origin: top;
  background: linear-gradient(to bottom, var(--sage) 0%, var(--sage) 82%, rgba(158, 173, 156, 0) 100%);
}

.section { position: relative; padding-block: clamp(3rem, 7vw, 5.5rem) 0; }
.section:last-child { padding-bottom: clamp(3rem, 7vw, 5rem); }
.section + .section { border-top: 1px solid var(--hairline-soft); }

.node {
  position: absolute;
  left: calc(var(--spine-gap) * -1);
  top: calc(0.86em - 8px);
  transform: translateX(-50%);
  color: var(--rose);
  line-height: 0;
}
.section h2, .hero-title { position: relative; }
.hero .node { top: calc(0.53em - 8px); }

/* The mobile branch needs no horizontal rule across its opening. */
@media (max-width: 79.999rem) {
  .masthead { border-bottom: 0; }
  .hero { padding-bottom: 1.5rem; }
}
.node svg { display: block; }

/* ---------- the opening ---------- */

.air {
  position: relative;
  isolation: isolate;
  padding-top: clamp(2.5rem, 6vw, 4rem);
}

.hero-title {
  font-size: clamp(2.3rem, 1.35rem + 3.9vw, 4.1rem);
  font-weight: 300;
  line-height: 1.06;
  letter-spacing: -0.025em;
  max-width: 15ch;
  margin-bottom: clamp(1.25rem, 2.5vw, 1.75rem);
}

/* The light the tree stands in, and the ground it grows out of: the painting's
   own colours, read off the file — palest at the top, the flat wash through
   the middle, and giving out into paper toward the foot so the field has no
   lower edge. It belongs to the field alone, so the branch keeps it at zero. */
.air::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  opacity: 0;
  background: linear-gradient(to bottom,
    var(--wash-pale) 0,
    var(--wash-mid) 18%,
    var(--wash) 42%,
    var(--wash) 72%,
    rgba(251, 217, 216, 0.55) 86%,
    rgba(251, 217, 216, 0) 100%);
}

/* ---------- the tree and the fall ----------
   Both are drawn out of the flow at every width, and both are held at zero
   while the branch is the composition. Their geometry does not depend on the
   state, so the width can cross in either direction without the picture
   jumping to a different size before it fades. */

.air-tree {
  /* the original is vector: it may be as large as the composition wants — as
     wide as 78 % of the screen, and never taller than the field it stands in
     (82 % of the viewport's height, at 513.04 : 427.11) */
  --tree-w: clamp(30rem, min(78vw, 98.52vh), 74rem);

  position: absolute;
  z-index: 0;
  right: clamp(-9vw, -4vw, 0px);
  bottom: clamp(1.5rem, 4vh, 3rem);
  width: var(--tree-w);
  max-width: none;
  margin: 0;
  pointer-events: none;
}
.air-tree img {
  width: 100%;
  height: auto;
  display: block;
}
.air-tree canvas {
  position: absolute;
  left: 0;
  top: 0;
  visibility: hidden;
}
.air-tree[data-yielding] canvas { visibility: visible; }
.air-tree[data-yielding] img { visibility: hidden; }

.drift {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: clip;
  pointer-events: none;
}
.still { position: absolute; inset: 0; }

.air-tree, .drift { opacity: 0; visibility: hidden; }

.petal {
  position: absolute;
  left: calc(var(--x) * 100%);
  top: calc(var(--y) * 100%);
  width: calc(var(--s) * 1px);
  height: calc(var(--s) * 1.3333px);
  margin-left: calc(var(--s) * -0.5px);
  margin-top: calc(var(--s) * -0.6667px);
  transform: rotate(calc(var(--r) * 1deg));
  opacity: var(--a);
  fill: var(--rose);
  overflow: visible;
}
.petal:nth-of-type(3n)   { fill: #D898B0; }
.petal:nth-of-type(4n+1) { fill: #E8B8C8; }

.drift canvas { position: absolute; inset: 0; }
.air[data-breeze="on"] .still { display: none; }

/* The illustrated wind stays inside the opening. The shared engine appends
   this canvas to `.air` because the markup sets `data-wind-scope="air"`;
   clipping at the field edge keeps a gust from following the reader down into
   the informational sections. */
.air > .wind {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* the words, which belong to both states */
.air-text { position: relative; z-index: 2; }

/* A light behind the words so the canopy never competes with them. It is a
   paper light with no edge, not a card: the same paper the page is made of,
   brightest under the heading and gone well before the trunk. The branch has
   no canopy to hold off, so there it is not drawn at all. */
.air-text::before {
  content: "";
  position: absolute;
  z-index: -1;
  /* It reaches well past the words in the field, where it has a canopy to
     hold off. On the branch it is not drawn, and it must not be laid out
     past the words either: an invisible light hanging five rem off the right
     of the column is still five rem of page to scroll sideways through. */
  inset: 0;
  opacity: 0;
  background: radial-gradient(ellipse at 42% 50%,
    rgba(250, 247, 242, 0.94) 0,
    rgba(250, 247, 242, 0.82) 38%,
    rgba(250, 247, 242, 0.4) 62%,
    rgba(250, 247, 242, 0) 80%);
}

/* ---------- who I help ---------- */

#voor-wie h2 { margin-bottom: 0.55rem; }
#voor-wie > .lead {
  font-size: 1.1875rem;
  color: var(--ink-soft);
}

.support-groups {
  display: grid;
  gap: 2.5rem;
  margin-top: clamp(1.75rem, 4vw, 2.75rem);
  padding-bottom: 1.5rem;
}
.support-group { min-width: 0; }
.support-group h2 {
  margin: 0 0 1.1rem;
  padding-bottom: 0.8rem;
  border-bottom: 1px solid var(--hairline);
  color: var(--accent);
  font-size: clamp(1.3rem, 1.15rem + 0.4vw, 1.5rem);
  font-weight: 400;
  font-style: italic;
  line-height: 1.3;
  text-wrap: balance;
}
.support-topics {
  display: grid;
  gap: 0.85rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.support-topics li {
  display: grid;
  grid-template-columns: 0.875rem minmax(0, 1fr);
  align-items: start;
  column-gap: 0.8rem;
  line-height: 1.5;
}
.topic-blossom {
  display: block;
  color: var(--rose);
  margin-top: 0.35em;
}

@media (min-width: 46rem) {
  .support-groups {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: clamp(2rem, 5vw, 4.5rem);
  }
}

@media (min-width: 80rem) and (min-height: 32rem) {
  #voor-wie { max-width: 52rem; }
  #voor-wie .support-groups { padding-bottom: 0; }
}

/* ---------- how I work ---------- */

.approach-copy {
  margin: clamp(2.5rem, 5vw, 4rem) auto 0;
  padding-bottom: 1.5rem;
}
.approach-copy h2 {
  margin: 0 0 1rem;
  color: var(--accent);
  font-size: clamp(1.3rem, 1.15rem + 0.4vw, 1.5rem);
  font-weight: 400;
  font-style: italic;
  line-height: 1.3;
}

/* ---------- practical ---------- */

.map-place { white-space: nowrap; }

.map-pin {
  display: inline-block;
  width: 1em;
  height: 1em;
  margin-right: 0.3em;
  vertical-align: -0.125em;
}

@media (min-width: 46rem) {
  .practical { grid-template-columns: minmax(0, 1fr) minmax(0, 14rem); }
}

.artwork {
  border-radius: var(--petal);
  box-shadow: 0 14px 30px -24px rgba(75, 57, 64, 0.85);
  width: 100%;
  max-width: var(--tree-w);
}

/* ---------- the colophon sits inside the shell here ---------- */

.colophon { margin-top: 0; }

/* ================= the field =================
   From here on, the wide state. The query is written once in the markup, on
   <html data-wide>, and repeated here and in crossing.js; the three must say
   the same thing. Width alone is not the condition: the tree needs the height
   of a window as well as its width, so a wide, shallow window keeps the
   branch rather than standing a tree it has no room for. */

@media (min-width: 80rem) and (min-height: 32rem) {

  /* the opening leaves the reading column and takes the whole width */
  .shell-main { max-width: none; padding-inline: 0; }

  .spine { padding-left: 0; }
  .spine::before { transform: scaleY(0); opacity: 0; }
  .node { opacity: 0; }
  .brand-mark { display: none; }
  .masthead { border-bottom: 0; }
  .hero { padding-bottom: 1.5rem; }
  .section + .section { border-top: 0; }
  .artwork { display: none; }

  .air {
    --text-w: 34rem;

    overflow: clip;
    min-height: clamp(38rem, 92vh, 60rem);
    display: grid;
    align-items: end;
    padding-block: clamp(3rem, 6vw, 5rem) clamp(3.5rem, 7vw, 5.5rem);
  }
  .air::before { opacity: 1; }
  .air-tree, .drift { opacity: 1; visibility: visible; }

  .air-text {
    width: min(100% - 2rem, var(--text-w));
    margin-inline: clamp(1rem, 8vw, 10rem) auto;
    text-align: left;
  }
  .air-text::before {
    /* Meet the viewport edge so the paper light cannot expose a clipped,
       straight seam where the left margin grows beyond the old 6rem inset. */
    inset: -3.5rem -5rem -3rem calc(-1 * clamp(1rem, 8vw, 10rem));
    opacity: 1;
  }

  .air-title {
    font-size: clamp(2.3rem, 1.5rem + 3.2vw, 3.9rem);
    line-height: 1.06;
    letter-spacing: -0.028em;
    max-width: none;
    margin-bottom: clamp(1.1rem, 2.4vw, 1.6rem);
  }

  .air .lead { max-width: 30rem; }
  .air .cta-quiet { border-color: rgba(75, 57, 64, 0.26); }

  /* the page below the field returns to a centred axis. The opening is a
     section too, so every rule here names the ones that follow it: the field
     itself keeps the whole width. */
  .air ~ .section {
    max-width: 42rem;
    margin-inline: auto;
    padding-block: clamp(3.25rem, 8vw, 5.5rem) 0;
  }

  /* The print of the painting belongs to the branch: here the tree has just
     stood the height of the opening. Its column goes with it, or the facts
     would keep reading against a fourteen-rem hole and break their own lines
     two words at a time. */
  .practical { grid-template-columns: minmax(0, 1fr); }
  .facts-column { max-width: 34rem; }
  .air ~ .section:last-of-type { padding-bottom: clamp(2rem, 4vw, 3rem); }
  /* A content page has no field above it, so it takes the same axis itself. */
  .page-body {
    max-width: calc(var(--measure) + 2rem);
    margin-inline: auto;
    padding-inline: 1rem;
    padding-bottom: clamp(2rem, 4vw, 3rem);
  }
  .air ~ .section h2 { text-align: center; }
  .air ~ .section .support-group h2 { text-align: left; }
  .air ~ .section .lead { text-align: center; margin-inline: auto; }
  /* Centred under the heading, and larger than the branch shows it — the
     portrait was sized for a 34rem column and read smaller here than on a
     phone, which is the wrong way round when there is this much room. 18rem
     is as large as the supplied 400 px file goes without being enlarged. */
  .portrait-layout { justify-items: center; grid-template-columns: minmax(0, 1fr); }
  .portrait { max-width: 18rem; }
  .notes, .facts-column { margin-inline: auto; }

  /* Content remains visible without JavaScript. reveal.js adds `.reveal-ready`
     only when IntersectionObserver is available, then each section settles in
     once and remains in place. */
  @media (prefers-reduced-motion: no-preference) {
    .reveal-ready [data-reveal]:not([data-revealed]) {
      opacity: 0;
      transform: translateY(1.25rem);
    }
    .reveal-ready [data-reveal] {
      transition:
        opacity 700ms cubic-bezier(0.16, 1, 0.3, 1),
        transform 800ms cubic-bezier(0.16, 1, 0.3, 1);
    }
  }
}

/* ================= arriving =================
   One authored moment per state, on load: the branch draws itself down the
   page and the opening settles under it; the field's tree is already standing
   and only the words settle onto its ground. */

@media (prefers-reduced-motion: no-preference) {
  .spine::before { animation: branch-grow 1100ms cubic-bezier(0.16, 1, 0.3, 1) both; }
  .hero .node { animation: blossom-open 700ms cubic-bezier(0.16, 1, 0.3, 1) 700ms both; }
  .air-text > * { animation: settle 800ms cubic-bezier(0.16, 1, 0.3, 1) both; }
  .air-title { animation-delay: 120ms; }
  .air .lead { animation-delay: 260ms; }
  .air .actions { animation-delay: 380ms; }
  .air .glance { animation-delay: 480ms; }
  @media (min-width: 80rem) and (min-height: 32rem) {
    .spine::before, .hero .node { animation: none; }
  }
}

@keyframes branch-grow { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes settle {
  from { opacity: 0; transform: translateY(0.6rem); filter: blur(5px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes blossom-open {
  from { opacity: 0; transform: translateX(-50%) scale(0.55); }
  to   { opacity: 1; transform: translateX(-50%) scale(1); }
}

/* ================= the crossing =================
   The width can change while someone is looking at the page — a window
   dragged wider, a laptop docked to a monitor, a tablet turned. The layout
   switches on a media query, which is instantaneous and would read as a
   glitch, so crossing.js marks the document for the length of one move and
   the change is performed instead of applied.

   Going wide, the room is built: the ground lights, the tree rises into it
   out of its own foot, the fall arrives behind the words, and the hairline
   that was carrying the page withdraws upward, its nodes closing.

   Going narrow, the tree leaves the way a picture is taken down — faster than
   it arrived, exits always are — and the branch draws itself back down the
   page with its blossoms opening after it.

   Nothing here runs at any other moment: the marker is on the document for
   about a second, once per crossing. Under prefers-reduced-motion crossing.js
   never sets it, and the two states simply exchange. */

@media (prefers-reduced-motion: no-preference) {

  /* --- into the field --- */
  html[data-crossing="field"] .air::before { animation: ground-light 700ms cubic-bezier(0.16, 1, 0.3, 1) both; }
  html[data-crossing="field"] .air-tree { animation: tree-rise 950ms cubic-bezier(0.16, 1, 0.3, 1) both; }
  html[data-crossing="field"] .drift { animation: fall-arrive 900ms cubic-bezier(0.16, 1, 0.3, 1) 260ms both; }
  html[data-crossing="field"] .air-text::before { animation: paper-light 800ms cubic-bezier(0.16, 1, 0.3, 1) 220ms both; }
  html[data-crossing="field"] .spine::before { animation: branch-withdraw 520ms cubic-bezier(0.16, 1, 0.3, 1) both; }
  html[data-crossing="field"] .node { animation: blossom-close 320ms cubic-bezier(0.16, 1, 0.3, 1) both; }

  /* --- back to the branch --- */
  html[data-crossing="branch"] .air-tree { animation: tree-leave 420ms cubic-bezier(0.4, 0, 1, 1) both; }
  html[data-crossing="branch"] .drift { animation: fall-leave 320ms cubic-bezier(0.4, 0, 1, 1) both; }
  html[data-crossing="branch"] .air::before,
  html[data-crossing="branch"] .air-text::before { animation: light-out 400ms ease-out both; }
  html[data-crossing="branch"] .spine::before { animation: branch-grow 900ms cubic-bezier(0.16, 1, 0.3, 1) 180ms both; }
  html[data-crossing="branch"] .node { animation: blossom-open 600ms cubic-bezier(0.16, 1, 0.3, 1) 620ms both; }

  /* The words themselves are never taken away: they exist in both states and
     say the same thing in both, so crossing.js carries them from the position
     one state leaves them in to the position the other gives them. What is
     drawn here is only the room around them.

     The sections below the opening move from one axis to the other under a
     single short dissolve, so the whole page changes as one thing rather than
     as a list of parts. They never go further than half out; a reader with
     their eye on a phone number does not lose it mid-drag. */
  html[data-crossing] .air ~ .section[data-revealed] { animation: axis-shift 560ms cubic-bezier(0.16, 1, 0.3, 1) both; }

  /* A section that has not been scrolled to yet is waiting at zero for its own
     reveal; the dissolve must not bring it up and then drop it again. */
}

@keyframes tree-rise {
  from { opacity: 0; visibility: visible; transform: translateY(2rem) scale(0.975); filter: blur(7px); }
  to   { opacity: 1; visibility: visible; transform: none; filter: blur(0); }
}
@keyframes tree-leave {
  from { opacity: 1; visibility: visible; transform: none; filter: blur(0); }
  99%  { opacity: 0; visibility: visible; transform: translateY(1.25rem) scale(0.985); filter: blur(5px); }
  to   { opacity: 0; visibility: hidden; transform: translateY(1.25rem) scale(0.985); filter: blur(5px); }
}
@keyframes fall-arrive {
  from { opacity: 0; visibility: visible; }
  to   { opacity: 1; visibility: visible; }
}
@keyframes fall-leave {
  from { opacity: 1; visibility: visible; }
  99%  { opacity: 0; visibility: visible; }
  to   { opacity: 0; visibility: hidden; }
}
@keyframes ground-light { from { opacity: 0; } to { opacity: 1; } }
@keyframes paper-light { from { opacity: 0; } to { opacity: 1; } }
@keyframes light-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes branch-withdraw {
  from { transform: scaleY(1); opacity: 1; }
  to   { transform: scaleY(0); opacity: 0; }
}
@keyframes blossom-close {
  from { opacity: 1; transform: translateX(-50%) scale(1); }
  to   { opacity: 0; transform: translateX(-50%) scale(0.5); }
}
@keyframes axis-shift {
  from { opacity: 0.5; }
  to   { opacity: 1; }
}

/* Native rich text inherits the approved section typography and rhythm. */
.editorial-body > :first-child { margin-top: 0; }
.editorial-body > :last-child { margin-bottom: 0; }
.topic-copy p { margin: 0; }
.topic-copy p + p { margin-top: .5em; }
.topic-copy { min-width: 0; overflow-wrap: anywhere; }

.prose > p + .pending { margin-top: 1.1rem; }
.editorial-body p + p { margin-top: 1.1rem; }
.row-note { margin-top: .6rem; }
.facts dt, .facts dd { min-width: 0; overflow-wrap: anywhere; }

#over-mij .portrait-layout:has(> .portrait:only-child) { grid-template-columns: minmax(0, 1fr); }
