@charset "UTF-8";
/* ===========================================================================
   ROOT — the rootscape
   ---------------------------------------------------------------------------
   One photograph behind the whole of the home page below the hero, panned from
   the crown of the tree to the tip of its roots as the visitor scrolls. Every
   block of the page — stories, chapters, tours, promises, leaders, journal —
   sits on top of it.

   Two mechanics, and that is the whole sheet:

     1  The picture is a sticky layer with `margin-bottom: -100svh`. It takes up
        no room in the flow, so the content scrolls over a pinned image. This is
        used instead of `background-attachment: fixed`, which iOS ignores
        outright and Android repaints the full viewport for.

     2  /static/js/home-rootscape.js writes one custom property on the section,
        --rs-p, running 0 at the crown to 1 at the deepest root, and sets the
        image's object-position from it. Nothing else is written per frame.

   The second half of the sheet re-dresses the site's ordinary light components
   for a dark, photographic background. Those rules are scoped under .rootscape
   so /tours, /leaders and every other page keep the parchment cards untouched.

   Every colour is a token from style.css; this sheet adds no new palette.
   =========================================================================== */

.rootscape {
  position: relative;
  isolation: isolate;
  background: var(--bark-950);
  color: var(--bone-100);
  /* How far back the photograph is pushed. Kept deliberately light: the type
     that has to survive over it carries its own local scrim (see
     .rootscape-say below) and every card is smoked glass, so legibility does
     not depend on flattening the picture. One number, one edit. */
  --rs-veil: .5;
  /* How much of that veil is given back by the time the pan reaches the roots.
     .5 - .42 leaves .08 at the bottom, where the photograph is nearly black on
     its own and needs no help. */
  --rs-veil-fade: .42;
  --rs-p: 0;
  /* How much wider the picture is drawn than fitting the frame's height would
     give. 1 is exactly `contain` — the whole tree, nothing cropped. Above that
     it gains width and loses the same proportion off the top and bottom, which
     is affordable because both ends are inside the fade (see .rootscape-veil
     and the mask on .rootscape-img): the crown and the finest root hairs
     dissolve into bark rather than ending on a cut. One number, one edit. */
  --rs-zoom: 1.28;
}

/* == The picture ===========================================================
   The outer layer is absolutely positioned, so it occupies no space at all and
   the content column starts at the very top of the section. The inner frame is
   what sticks.

   Do not put `overflow` on .rootscape-bg — an overflow other than `visible`
   makes it a scroll container, and a sticky child sticks to its nearest
   scrolling ancestor, so the frame would stop following the viewport. */
.rootscape-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.rootscape-frame {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  /* The picture is letterboxed (see .rootscape-img), so the frame's own colour
     is what fills the margins beside it. Bark, not black, so the bands read as
     the page rather than as a video player. */
  background: var(--bark-950);
}

.rootscape-img {
  /* Sized off the frame's height rather than by object-fit, so --rs-zoom above
     is a plain multiplier on the result. Centred absolutely: `left`/`top` are
     physical, so the picture sits in the middle of the frame in both reading
     directions without a second rule.

     `min(100%, ...)` is what stops it on a phone, where the viewport is taller
     than the picture's own ratio and the width term would overflow the screen.
     There it fills the width and nothing is cropped at all. */
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: block;
  width: min(100%, calc(100svh * (941 / 1672) * var(--rs-zoom)));
  height: auto;
  max-width: none;
  user-select: none;
  -webkit-user-drag: none;

  /* The photograph came desaturated — a grey-green canopy over near-black soil.
     Lifting the exposure alone made it paler rather than richer, so the
     saturation carries the colour and the contrast puts the bite back. The
     figures are held down deliberately: the type over this has to stay legible,
     and past about 1.6 on the saturation the grass turns synthetic. */
  filter: brightness(1.18) saturate(1.45) contrast(1.06);

  /* The left and right edges dissolve into the bark instead of ending on a
     seam. The mask is on the image itself rather than on an overlay above it,
     so it is measured against the picture's own box and stays correct at every
     --rs-zoom — an overlay would have to repeat the width calculation and
     would drift the moment either number changed.

     Vertical fading is the veil's job, below: it has to cover the letterbox
     bands as well as the picture, so it cannot live on this element. */
  -webkit-mask-image: linear-gradient(to right,
    transparent 0%, #000 16%, #000 84%, transparent 100%);
  mask-image: linear-gradient(to right,
    transparent 0%, #000 16%, #000 84%, transparent 100%);
}

/* On a phone the picture already fills the width, so a 16% fade would eat the
   trunk. Just enough to take the hard edge off. */
@media (max-aspect-ratio: 941 / 1672) {
  .rootscape-img {
    -webkit-mask-image: linear-gradient(to right,
      transparent 0%, #000 6%, #000 94%, transparent 100%);
    mask-image: linear-gradient(to right,
      transparent 0%, #000 6%, #000 94%, transparent 100%);
  }
}

/* The veil is what makes bone-coloured type legible over a photograph that is
   near-white at the top and near-black at the bottom. A flat wash does the
   constant work; the gradient only weights the two ends, where the section has
   to hand over to the hero above and the footer below. */
.rootscape-veil {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* The flat layer thins out as the pan descends, for the same reason the
     exposure is lifted: near the crown the picture is bright and the type
     needs protecting from it, near the roots the picture is dark and any
     further veil is just deleting the photograph. */
  --rs-veil-now: calc(var(--rs-veil) - var(--rs-p) * var(--rs-veil-fade));
  background:
    linear-gradient(to bottom,
      var(--bark-950) 0%,
      rgba(16, 18, 8, .16) 12%,
      rgba(16, 18, 8, .16) 88%,
      var(--bark-950) 100%),
    linear-gradient(rgba(16, 18, 8, var(--rs-veil-now)), rgba(16, 18, 8, var(--rs-veil-now)));
}

/* == The content =========================================================== */
.rootscape-flow {
  position: relative;
  z-index: 1;
  padding-block: clamp(3rem, 7vw, 7rem);
}

.rootscape-block { padding-block: clamp(2.5rem, 5vw, 4.5rem); }

/* == The manifesto =========================================================
   Five stanzas set between the content blocks. Centred, wide margins, nothing
   beside them — while one is on screen the picture is doing the work and the
   type is only a caption to it. */
.rootscape-say {
  position: relative;
  padding-block: clamp(6rem, 16vh, 12rem);
  padding-inline: 6vw;
  text-align: center;
}
/* A local band of shade under each chapter, so the copy is legible whether the
   pan has it over the near-white sky or the near-black soil. Without it the
   only way to protect the type is to flatten the whole photograph, which is
   what the global veil used to be doing.

   Full-bleed and feathered on the vertical axis only. A radial pool was the
   obvious shape and was wrong: strong enough to carry the copy over the sky, a
   radial reads as a distinct dark oval pasted on the picture, because the sky
   in this photograph is a flat gradient with no texture to hide an edge in. A
   horizontal band has no edge to notice — it passes for the same haze that is
   already in the frame.

   Sized against the worst case rather than the average one: sweeping the pan
   with the copy parked centre-screen, the backdrop is hardest at the very top,
   where the sky measures 0.18 relative luminance; from a quarter of the way
   down it is under 0.03 everywhere. These stops are what carry that one case
   over the 4.5:1 floor, so the first chapter reads as well as the last. */
.rootscape-say::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(to bottom,
    transparent 0%,
    rgba(16, 18, 8, .5) 20%,
    rgba(16, 18, 8, .82) 46%,
    rgba(16, 18, 8, .82) 58%,
    rgba(16, 18, 8, .5) 82%,
    transparent 100%);
}
/* The stanza itself. One size for every line — the source is a poem, not a
   headline with a deck under it, and stepping the first line up to display
   size would invent an emphasis the writing does not have.

   Sized to sit between the section headings (1.4rem) and the hero (6rem):
   large enough to hold the screen on its own, small enough that a three-line
   stanza does not need scrolling to finish. The leading is wide because
   Persian sets tall and these lines are read slowly. */
.rootscape-say-lines {
  margin: 0 auto;
  /* Wide enough that the written line breaks are the ones that show. At 34ch
     five of the eleven lines wrapped, which turns a deliberate break into an
     accident of column width — the whole reason each line is its own element.
     `ch` is measured on the digit zero and badly underestimates Persian, hence
     the generous figure; the vw term is what actually binds on small screens,
     where wrapping is unavoidable and fine. */
  max-width: min(92vw, 64ch);
  font-family: var(--font-display);
  font-size: clamp(1.15rem, .82rem + 1.15vw, 1.95rem);
  font-weight: 300;
  line-height: 2;
  color: var(--bone-100);
  text-shadow: 0 2px 34px rgba(16, 18, 8, .9);
  text-wrap: pretty;
}
body.rtl .rootscape-say-lines { font-weight: 400; line-height: 2.1; }

/* Block, so each line of the poem holds its own row. A line long enough to
   wrap still wraps — the break is a floor, not a ceiling. */
.rootscape-line { display: block; }

/* == The shape of a stanza =================================================
   Every stanza on this page is a couplet: a line that sets something up and a
   line that answers it. Set at one size they read as a single wrapped
   sentence and the turn between the two is lost — which is the whole point of
   the writing.

   So the stanza is given a shape. The setup line steps down and back: smaller,
   dimmer, lighter, so it reads as spoken under the breath. The closing line
   keeps the display size and the full bone, and carries a hairline ember tick
   above it — a mark, not a rule; it is 2.4em wide and centred, so it reads as
   punctuation rather than as a divider across the page.

   `:last-child` rather than `:nth-child(2)`, so a stanza written as three lines
   still resolves correctly: everything before the last one is setup.

   A one-line stanza is all payoff and gets no tick — there is nothing for it to
   turn away from. */
.rootscape-line:not(:last-child) {
  font-size: .74em;
  font-weight: 300;
  line-height: 1.85;
  color: rgba(227, 213, 189, .68);
  margin-block-end: .5em;
}
body.rtl .rootscape-line:not(:last-child) { font-weight: 400; }

.rootscape-line:last-child:not(:first-child) {
  position: relative;
  padding-block-start: 1.5em;
}
.rootscape-line:last-child:not(:first-child)::before {
  content: '';
  position: absolute;
  inset-block-start: .55em;
  inset-inline-start: 50%;
  transform: translateX(50%);
  width: 2.4em;
  height: 1px;
  background: linear-gradient(to left, transparent, var(--ember-400), transparent);
  opacity: .75;
}
body.ltr .rootscape-line:last-child:not(:first-child)::before {
  transform: translateX(-50%);
}

/* The lines rise in sequence rather than as one block. app.js puts .is-visible
   on the [data-reveal] wrapper the first time it enters the viewport; the
   delay is the line's own index, so a stanza arrives the way it is read.

   Under prefers-reduced-motion style.css collapses every transition to .001ms
   and app.js marks everything visible immediately, so this resolves at once
   rather than needing its own override. */
.rootscape-line {
  opacity: 0;
  transform: translateY(.45em);
  transition:
    opacity .7s var(--ease) calc(var(--i) * .11s),
    transform .7s var(--ease) calc(var(--i) * .11s);
}
[data-reveal].is-visible .rootscape-line {
  opacity: 1;
  transform: none;
}

/* == The mark ==============================================================
   The glyph and the word "Root", set as one lockup under the stanza that names
   it. Forced to left-to-right in both locales: "Root" is a Latin proper noun
   and is not translated, so the glyph stays on the left and the word on the
   right whether the page around it runs rtl or ltr. Without this the pair
   silently mirrors under dir="rtl" and the lockup reads backwards. */
.rootscape-mark {
  direction: ltr;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(.7rem, 1.6vw, 1.35rem);
  margin: clamp(2.2rem, 5vh, 3.6rem) 0 0;

  /* Arrives after the stanza it belongs to has finished settling, so it lands
     as the closing beat of the block rather than as a sixth line of the poem. */
  opacity: 0;
  transform: translateY(.5em);
  transition:
    opacity .8s var(--ease) .34s,
    transform .8s var(--ease) .34s;
}
[data-reveal].is-visible .rootscape-mark {
  opacity: 1;
  transform: none;
}

.rootscape-mark img {
  width: clamp(44px, 5.6vw, 76px);
  height: auto;
  opacity: .92;
  filter: drop-shadow(0 2px 24px rgba(16, 18, 8, .9));
}
/* Tracked out, because a four-letter word at display size with none of it
   reads as a logo rather than as a piece of running text. */
.rootscape-mark span {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, .95rem + 1.9vw, 2.9rem);
  font-weight: 300;
  letter-spacing: .16em;
  line-height: 1;
  color: var(--bone-100);
  text-shadow: 0 2px 34px rgba(16, 18, 8, .9);
}


/* == Promises ==============================================================
   Deliberately not cards. This block lands where the trunk fills the frame,
   which is the most legible part of the whole picture — covering it with three
   opaque panels would waste it. */
.rootscape-promise {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.rootscape-promise-item h3 {
  margin: .7rem 0 .5rem;
  font-size: 1.12rem;
  color: var(--bone-100);
}
.rootscape-promise-item p {
  margin: 0;
  font-size: .92rem;
  line-height: 1.85;
  color: rgba(227, 213, 189, .76);
}
.rootscape-promise-num {
  display: block;
  font-family: var(--font-display);
  font-size: 2.1rem;
  font-weight: 300;
  line-height: 1;
  color: var(--ember-400);
  font-variant-numeric: tabular-nums;
}


/* ===========================================================================
   Dark dress for the site's ordinary components
   ---------------------------------------------------------------------------
   Everything below re-skins shared classes for this section only. The selectors
   are all descendants of .rootscape, so no other page is touched.
   =========================================================================== */

/* -- Headings and section heads ------------------------------------------- */
.rootscape h2,
.rootscape h3 { color: var(--bone-100); }

.rootscape .eyebrow { color: var(--ember-400); }

.rootscape .section-head { border-color: rgba(227, 213, 189, .18); }

.rootscape .section-head > a,
.rootscape .stories-head > a { color: var(--bone-300); }
.rootscape .section-head > a:hover,
.rootscape .stories-head > a:hover { color: var(--ember-400); }

.rootscape .muted { color: rgba(227, 213, 189, .62); }

/* -- Cards ----------------------------------------------------------------
   Smoked glass rather than solid panels: the photograph stays visible through
   every card, so the section reads as one continuous image with information
   laid on it instead of a dark page with pictures pasted behind it.

   `backdrop-filter` is the whole effect, and it is also the expensive part, so
   the blur is kept small and no card animates it. */
.rootscape .card {
  background: rgba(26, 29, 16, .52);
  border-color: rgba(227, 213, 189, .16);
  -webkit-backdrop-filter: blur(12px) saturate(1.1);
  backdrop-filter: blur(12px) saturate(1.1);
  box-shadow: 0 18px 50px -28px rgba(0, 0, 0, .9);
}
.rootscape .card:hover {
  border-color: rgba(212, 136, 79, .5);
  box-shadow: 0 22px 60px -26px rgba(0, 0, 0, .95);
}
/* Browsers without backdrop-filter get an opaque panel instead of an
   unreadable transparent one. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .rootscape .card { background: rgba(26, 29, 16, .92); }
}

.rootscape .card-body h3 a { color: var(--bone-100); }
.rootscape .card-body h3 a:hover { color: var(--ember-400); }
.rootscape .card-meta { color: var(--ember-400); }
.rootscape .card-facts { color: rgba(227, 213, 189, .72); }
.rootscape .card-facts strong { color: var(--bone-100); }
.rootscape .card-footer { border-top-color: rgba(227, 213, 189, .14); }
.rootscape .price { color: var(--ember-400); }
.rootscape .card-media,
.rootscape .card-placeholder { background: rgba(16, 18, 8, .6); }

.rootscape .leader-card .avatar { background: rgba(247, 243, 234, .08); }

/* -- Buttons --------------------------------------------------------------- */
.rootscape .btn-primary {
  background: var(--ember-600);
  color: var(--bone-100);
}
.rootscape .btn-primary:hover { background: var(--ember-500); }

/* -- Stories rail ----------------------------------------------------------
   The ring's inner border is cut out of the page background so the photograph
   does not show as a hairline between the ring and the thumbnail. */
/* No rule under the rail here. On the site's light pages that hairline is what
   separates the stories from the page beneath them; over the photograph it is a
   hard edge drawn across the picture, and the change in content is separation
   enough. */
.rootscape .stories { border-bottom: 0; }
.rootscape .story-ring { background: rgba(227, 213, 189, .28); }
.rootscape .story-ring-inner {
  border-color: rgba(16, 18, 8, .85);
  background: rgba(16, 18, 8, .6);
}
.rootscape .story-badge { border-color: rgba(16, 18, 8, .85); }
.rootscape .story-name { color: rgba(227, 213, 189, .82); }


/* == Reduced motion ========================================================
   The pan is the only thing that stops. The picture unpins and stands as a
   single tall still behind the top of the section, the veil goes with it, and
   every block below reads on flat bark. */
@media (prefers-reduced-motion: reduce) {
  /* The pan is gone, so the picture no longer moves in any mode. All that is
     left to stop is the pinning itself: the frame stands as one still at the
     top of the section and the content scrolls past it onto flat bark.

     `relative`, not `static` — .rootscape-img is absolutely positioned and
     needs the frame to stay its containing block. Made static, the image would
     resolve against .rootscape-bg instead and centre itself in the whole
     section, which is several screens tall. */
  .rootscape-frame { position: relative; }
}


/* == Cards arriving =========================================================
   The tours, the leaders and the journal all sit in a `.grid` inside a
   [data-reveal] section, so the first time that section reaches the viewport
   app.js puts .is-visible on it and every card in it slides in — up and in from
   the reading-start edge, one after the next rather than all together.

   The stagger index comes from :nth-child rather than from a `--i` written by
   the template, because the tour card is a shared partial: /tours renders the
   same file and must not inherit a home-page animation. Nine steps is two full
   rows of the widest grid on the page plus a spare; anything past that falls
   back to --i: 0 and simply arrives with the first of its row, which is
   invisible in practice because nothing on this page renders that many.

   The slide is along the inline axis, so it reads as "in from the margin" in
   both directions: from the right in Farsi, from the left in English.
   `transform` cannot take a logical value, hence the two body rules. */
.rootscape [data-reveal] .card {
  --i: 0;
  opacity: 0;
  transform: translate3d(var(--rs-slide, 0), 30px, 0);
  transition:
    opacity .72s var(--ease) calc(var(--i) * .085s),
    transform .72s var(--ease) calc(var(--i) * .085s);
  /* The cards carry backdrop-filter; promoting them for the duration of the
     slide keeps that from being recomposited on every frame. */
  will-change: transform, opacity;
}
.rootscape [data-reveal].is-visible .card {
  opacity: 1;
  transform: none;
  will-change: auto;
}

body.rtl .rootscape { --rs-slide: 46px; }
body.ltr .rootscape { --rs-slide: -46px; }

.rootscape [data-reveal] .grid > *:nth-child(2) .card,
.rootscape [data-reveal] .grid > .card:nth-child(2) { --i: 1; }
.rootscape [data-reveal] .grid > *:nth-child(3) .card,
.rootscape [data-reveal] .grid > .card:nth-child(3) { --i: 2; }
.rootscape [data-reveal] .grid > *:nth-child(4) .card,
.rootscape [data-reveal] .grid > .card:nth-child(4) { --i: 3; }
.rootscape [data-reveal] .grid > *:nth-child(5) .card,
.rootscape [data-reveal] .grid > .card:nth-child(5) { --i: 4; }
.rootscape [data-reveal] .grid > *:nth-child(6) .card,
.rootscape [data-reveal] .grid > .card:nth-child(6) { --i: 5; }
.rootscape [data-reveal] .grid > *:nth-child(7) .card,
.rootscape [data-reveal] .grid > .card:nth-child(7) { --i: 6; }
.rootscape [data-reveal] .grid > *:nth-child(8) .card,
.rootscape [data-reveal] .grid > .card:nth-child(8) { --i: 7; }
.rootscape [data-reveal] .grid > *:nth-child(9) .card,
.rootscape [data-reveal] .grid > .card:nth-child(9) { --i: 8; }

/* The heading above each grid leads the cards in by a beat, so the block
   assembles top-down instead of the title sitting there waiting. */
.rootscape [data-reveal] .section-head {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .6s var(--ease), transform .6s var(--ease);
}
.rootscape [data-reveal].is-visible .section-head {
  opacity: 1;
  transform: none;
}

/* Nothing above may leave content invisible if the visitor asked for stillness.
   style.css already collapses transitions to .001ms under reduced motion and
   app.js marks every [data-reveal] visible up front, but the initial opacity is
   a plain declaration, not a transition, so it needs saying explicitly. */
@media (prefers-reduced-motion: reduce) {
  .rootscape [data-reveal] .card,
  .rootscape [data-reveal] .section-head {
    opacity: 1;
    transform: none;
  }
}


/* == The seam with the footer ==============================================
   .site-footer carries `margin-top: 4rem` for the site's ordinary light pages,
   where it is the breathing room under a parchment page. Here the page above it
   is dark and full-bleed, so that margin renders as a band of bare --paper
   between the rootscape and the footer. This sheet only loads on the home page,
   so closing it up here touches nothing else. */
.site-footer { margin-top: 0; }


/* == Narrow screens ========================================================
   Under about 600px the picture is taller than the viewport by a much larger
   factor, so the same scroll distance covers far more of it. Nothing needs to
   change for the pan — it is proportional — but the chapter copy needs to stop
   eating whole screens on its own. */
@media (max-width: 600px) {
  /* On a phone the same spacing that gives a stanza room on a desktop leaves
     a screen-and-a-half of empty picture between every block: the stories rail
     ended a third of the way down and the next line of the poem did not start
     until the one after it. The bands come in far enough that each block sits
     against the next, which is the difference between scrolling through the
     page and scrolling past it. The shade behind a stanza is a gradient over
     the block, so it tightens with the padding and keeps covering the type. */
  .rootscape-flow { padding-block: clamp(1.5rem, 4vw, 2.5rem); }
  .rootscape-say { padding-block: clamp(1.75rem, 4.5vh, 3rem); }
  .rootscape-block { padding-block: clamp(1.25rem, 3vw, 2rem); }
  .rootscape .stories { padding-block: clamp(1.25rem, 3vw, 2rem); }
  .rootscape { --rs-veil: .64; }
}
