/* ============================================================
   Resonant System v2 — the reading

   Everything shared by the two pages that render a daily reflection: the
   homepage and /dailyreflection. They were the same 553 lines of CSS inlined
   in each file, which meant every change had to be made twice and the two had
   already drifted apart in the one place it showed — the column width.

   The pages differ in two values, and they're custom properties rather than
   overridden rules, so the difference between the two pages is legible in one
   short block at the top of the homepage instead of scattered through a
   stylesheet:

     --page-top        the pause before the page starts
     --page-top-sm     the same, below 640px

   --reading-measure exists for the same purpose and nothing sets it: the
   homepage ran at 760px until the column widths across the site were
   unified. It's left in place because that's the knob to reach for if a
   page ever needs its own measure again.

   Unset, they fall back to what /dailyreflection uses.

   The masthead — headline, byline, opening line, and the rule under them —
   stays inline on the homepage. It's the only markup /dailyreflection doesn't
   have, and shipping rules for elements a page doesn't contain is what this
   file exists to stop.

   The class prefix is .hb-, and main carries .reading. Both are from /home-b/,
   where this page was built before it was promoted; the prefix is only a
   namespace, but main.home-b was a name that had stopped being true.
   ============================================================ */

/* .hb-sticky moved to nav.css — it positions the nav, and every page
   loads nav.css while only three load this file. */

/* The pause before the page starts is padding here, not an empty <div>.
   It was a spacer element — .hb-arrival — which is markup carrying no
   content, existing only to occupy vertical space that a padding value
   occupies just as well.

   Nothing at the bottom. The space under the share row is the footer's top
   inset, set to match the 16px above the row further down this file. */
main.reading {
  max-width: none;
  padding: var(--page-top, var(--space-5)) 3rem 0;
}
@media (max-width: 640px) { main.reading { padding: var(--page-top-sm, var(--space-3)) 1.5rem 0; } }

/* 760px, and the whole page sits on it — masthead and reflection alike.
   Wider than the site's --measure of 624px, which is the deliberate
   departure this page is testing.

   The cost is in the prose: 18px Source Serif 4 at 760px runs roughly 80
   characters a line, past the 75 usually given as the comfortable ceiling.
   That ceiling is about sustained reading — line after line, where the eye
   loses its place returning to the left margin. The teaser here is eight
   lines behind a fade, not an article, so it's a smaller cost than it
   would be on /dailyreflection, which stays at 624px.

   If it reads long, 720px is the middle: ~76 characters, still visibly
   wider than the rest of the site. */
.hb-col {
  max-width: var(--reading-measure, var(--measure));
  margin: 0 auto;
  text-align: center;
}

/* --- The reading -------------------------------------------- */
/* A chapter opening, in book proportions rather than web ones.

   The quote had been the largest thing in the reflection at 24–26px, above
   a body of 18px. That's backwards for what it is: an epigraph is a
   borrowed line standing at the door of the chapter, and in a book it's set
   *smaller* than the body precisely so the title can be the largest thing
   on the page. Every earlier attempt at this header had to squeeze in under
   an oversized quote, which is why it kept coming out as a label.

   So the order is title, then epigraph, then body — 30px, 19px, 18px —
   instead of the 22 / 24 / 18 it was. Nothing here is competing with
   anything now; each is plainly a different rank.

   Old-style figures are requested and appear not to arrive: Google's
   Source Serif 4 build doesn't seem to carry the feature, so the 3 sits on
   the baseline like any lining numeral. Left in place because it costs
   nothing and self-repairs if the font ever ships it; a real fix would mean
   self-hosting the full font.

   Asymmetric space, as a chapter has: the break comes before the header —
   104px of pause above it — and the header then sits close to what it
   introduces. */
.hb-stamp {
  margin: 0 0 var(--space-4);
}
/* Collapses when the loader leaves it empty, which is every normal read now
   that the quote is the heading. Without this the element still carries its
   40px of margin and opens a hole above the quote. It fills only for the
   archive wall, which writes "From the archive" into it. */
.hb-stamp:empty { display: none; }
.hb-stamp .eyebrow-tag {
  display: block;
  font-family: 'Source Serif 4', serif;
  /* Capitals, because that's what letterspacing is for. Lowercase
     letterforms carry their spacing in the drawing; opening them up breaks
     word shapes and reads as a mistake — the old line about letterspacing
     lowercase and stealing sheep. Capitals are inscriptional forms and want
     the air, which is why letterspaced caps are the classical title-page
     and chapter-opening treatment.

     Weight drops to 400 with the change. Caps carry more visual mass than
     mixed case at the same size, so 500 would read as shouting where the
     intent is ceremony. */
  font-size: clamp(1.4rem, 3vw, 1.625rem);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  line-height: 1.25;
  color: var(--heading);
}
.hb-stamp .eyebrow-date {
  display: block;
  font-family: 'Source Serif 4', serif;
  /* 18px against the title's 26px, where it was 15 against 30. The two are
     a pair now rather than a heading and a footnote — same case, same
     tracking, separated by size and colour alone. */
  font-size: 1.125rem;
  font-weight: 400;
  font-style: normal;
  font-variant-numeric: oldstyle-nums;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted-strong);
  margin-top: var(--space-2);
}

/* An epigraph: smaller than the body it stands in front of, italic, and
   narrower than the measure so it reads as set apart rather than as the
   first paragraph. */
.hb-quote {
  font-family: 'Source Serif 4', serif;
  /* 28px — the mantra's size exactly, and with the mantra's italic, weight and
     colour already matched here, the two are now typographically the same
     thing. That is deliberate: the quote and the mantra bookend the reading,
     someone else's words opening it and Jim's closing it, in one voice at one
     size with the prose sitting between them at 18.4px.

     It was 19px until today, which is six tenths of a pixel over that prose —
     so the epigraph was carried entirely by italic, weight and colour. That
     held only while the date sat between the heading and the quote: an 18px
     line there made the 19px quote read as a step up. Taking the date off
     removed the step, the quote butted against the 26px caps, and it read as
     shrinking.

     Note it now runs larger than the DAILY REFLECTION label above it. The
     label is a label; the quote is the first thing worth reading. */
  font-size: 1.75rem;
  font-style: italic;
  /* --heading and weight 500, where the prose below is --body at 400.

     Compensation rather than emphasis. Italic strokes are thinner than upright
     ones, so at matching colour and weight the quote reads paler than the
     paragraphs under it — and it's the first thing a reader meets. Colour
     alone barely moved it, because #364548 and #1A2426 are both close to black
     and the strokes are too fine to carry the difference. Weight is the lever
     that addresses the actual cause, and it matches the mantra's. */
  color: var(--heading);
  font-weight: 500;
  line-height: 1.6;
  letter-spacing: 0;
  max-width: 34em;
  margin: 0 auto var(--space-2);
}

/* Serif rather than Inter now, and small. It's the epigraph's source line,
   so it belongs to the epigraph's voice — a sans attribution under a serif
   quote read as metadata attached to a display element. */
.hb-attr {
  font-family: 'Source Serif 4', serif;
  font-size: 0.9rem;
  font-style: normal;
  color: var(--muted-strong);
  /* 40px, matching the gap above the quote. It was 64 — the largest space on
     the upper page, larger than the one separating the date stamp from the
     quote, which made the epigraph look stranded between two blocks rather
     than sitting in front of one.

     24 now that a rule stands below it. A hairline separates in one pixel, so
     the space either side of it no longer has to do the separating on its
     own — and the 16 above this line still binds the attribution to the
     quote as a single unit. */
  margin: 0 0 var(--space-3);
}

/* The mark between the epigraph and the essay, tighter than the 40px below
   the one before the mantra. That one ends a long stretch of prose; this one
   sits between two short blocks and would look stranded with the same air.
   typography.css sets 0 and 40 for .section-mark. */
.hb-col .section-mark { margin: 0 auto var(--space-3); }

/* The whole reading, not a taste of it. The teaser clipped the loader's
   output to three paragraphs behind a fade and put a button under it; the
   loader was fetching the entire interpretation either way, so showing all
   of it costs nothing and removes a click from between a visitor and the
   thing they came for.

   Left-aligned inside a centred column — the prose is the one thing on the
   page that's read line after line, and centred body text has no spine to
   return to. Everything above it stays centred.

   No section mark between the attribution and the prose. On the live page
   a 96px rule marks the handoff from Steinbeck's words to Jim's; here the
   64px gap is the only separator, since a rule is another object and the
   page is trying to hold as few as possible. Watch for whether the two
   voices blur. */
#interpretation-section { text-align: left; }
.interpretation { line-height: 1.75; }
/* 19.2px on a phone against 18.4 elsewhere. A held phone is closer to the eye
   than a laptop but the type is smaller in absolute terms, and this is the one
   page people read at length. */
@media (max-width: 640px) {
  .interpretation { font-size: 1.2rem; }
}


/* --- The mantra --------------------------------------------- */
/* The line meant to be carried out of the reading, set a breath after it
   and given room below.

   It gets no treatment of its own. Several versions did give it one — a
   full screen to itself, a sticky hold at the centre, veils that deepened
   as it arrived — and each of them made the page behave differently at that
   one moment than at every other. It's the same page throughout now: the
   edges recede, wherever you are.

   dvh, not vh: mobile browsers change viewport height as their toolbars
   come and go.

   Conditional on the mantra actually being there. reflection-loader.js sets
   display:block inline when a reflection has one; without the :has() test a
   reflection without a mantra would leave an empty screen mid-page that
   reads as a broken layout. */
.hb-mantra-panel:has(> #mantra-section:not(.is-hidden)) {
  /* The mantra sits at the top of the panel, a breath after the last line
     of the reading — not centred in it. Centring was what put the gap
     there: a 40dvh panel with the mantra in the middle means 20dvh above
     it, and that half is visible while the prose is still on screen.

     There's no minimum height any more either. The 40dvh was travel room
     for a hold that no longer exists, and with the veils constant it was
     simply empty page below the mantra. */
  /* No padding of its own. The reading's last paragraph carries 48px and
     that's the space above the rule; the 16px that used to sit here went
     to paying for the rule, which costs room no matter how thin it is.
     The mantra still reads as belonging to the reading rather than as the
     next section — the rule is a change of voice, not a section break.

     No margin below it either, and that's the point. This declared one and
     .rs-share declared another, the two collapsed to whichever was larger,
     and so three separate reductions to the smaller one changed nothing at
     all on screen. One gap, one owner: whatever follows the mantra states
     its own distance from it, in its own file. */
  /* No scroll snapping. It was added to stop the last paragraph and half a
     viewport of emptiness being visible at once — but that was a symptom of
     the panel being full height, and it isn't any more. What survived was
     the grab: a scroller that takes over near the end of a reading is the
     opposite of what this page is for. Scrolling here is the reader's. */
}

/* The rule divides rather than leans: 40px beneath it against the 48px the
   last paragraph puts above it. typography.css sets 8px and 28px, which is
   right where the mark belongs to what follows it — here it separates two
   things and wants to sit between them. */
.hb-mantra-panel .mantra-mark { margin: 0 auto var(--space-4); }

/* The mantra closes the reading, and then the footer. It had a passage of
   its own for a while — a clone on a fixed layer that took the screen while
   the page receded around it, and came back. It worked, and the reason it's
   gone is the space it cost: a scroll-driven hold has to be paid for in
   scroll, and with nothing beneath the mantra to spend, the payment was an
   empty half-screen the reader met on the way to the footer. See
   89f02c1 if it's wanted back.

   What's left is the same treatment the rest of the page gets — whatever is
   near an edge recedes — which is what singles the mantra out anyway when
   it's the only thing in the middle of the screen. */

/* Equal air above and below the share row.

   The gap above it is 16px, stated by .rs-share in share.css. The gap below
   it isn't the reading's at all — it's the footer's own top inset, 64px on a
   desktop and 24 on a phone, sitting between the row and the hairline the
   footer draws. So no amount of adjustment inside the reading could ever
   match the two.

   Overridden here rather than in footer.css because it's true of these pages
   only: About and the legal pages end on prose and want the footer's usual
   distance. Higher specificity than the shorthand in footer.css, including
   its mobile one, so it holds at every width.

   Deliberately less than the 24px above the row, not equal to it. The row
   belongs to the reading it follows, and unequal spacing is what says so —
   equal spacing would leave it floating between the mantra and the footer,
   which is the arrangement we started with. */
main.reading + footer { padding-top: 20px; }

/* Nothing below the reading until the reading is there. Without this the
   ask and the footer render against the loading state, sit near the top of
   the screen for a moment, and are shoved down when the reflection lands. */
#reflection-content.is-hidden ~ .hb-end { visibility: hidden; }
main:has(#reflection-content.is-hidden) + footer { visibility: hidden; }

/* --- The end of the reading ---------------------------------- */
/* The two pills that used to sit here — a solid Subscribe and a ghost Share —
   are gone. Share is its own control now, in share.css, and subscribe isn't on
   a page that carries a reflection at all: it lives in the nav, so the end of
   a reading has exactly one thing on it.

   The pill rules went with them rather than being left for later. They
   described markup that no page contains. */

.loading, .error-state { text-align: center; padding: var(--space-4) 0; }

/* --- Top-of-screen fade ------------------------------------- */
/* Whatever reaches the top of the viewport dims, wherever you are on the
   page — so attention sits on what's in front of you rather than on the
   line you've just left behind.

   One fixed gradient over the top edge does it, rather than fading elements
   individually. It's the page's own ground painted over the content and
   falling away to nothing, so text doesn't grey out — it goes under the
   paper. Nothing needs to know its own scroll position, and it works the
   same for the masthead, the quote, the prose and the mantra.

   Stated as explicit rgba stops rather than `transparent`: some engines
   interpolate the keyword through rgba(0,0,0,0), which pulls a grey haze
   through the middle of the gradient.

   z-index 40 — over the reading and under the nav, which fades on the same
   --scrim value so the two stay in step. The dialogs (100) open above it.
   pointer-events:none so it never eats a click or a text selection. */
body::before {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /* Derived from the nav rather than a number that happens to match it.
     --scrim-fade is how far the veil takes to clear once past the nav. */
  height: calc(var(--nav-h) + var(--scrim-fade, 110px));
  z-index: 40;
  pointer-events: none;
  /* Absent at the top of the page and coming up over the first 120px of
     scroll. Without the ramp the scrim would wash out the nav before the
     reader had moved at all. Defaults to 0, so if the script never runs the
     page renders unveiled rather than permanently hazed. */
  opacity: var(--scrim, 0);
  transition: opacity 0.2s linear;
  /* Opaque for the nav's whole height, then falling away.
     It used to reach 0.92 at 35% and fade from there, which on a phone put the
     nav's lower edge at around 40% — so as the nav faded out on scroll, the
     date stamp passing behind it showed straight through the wordmark. The
     veil has to be solid everywhere the nav is, or the nav withdrawing reveals
     the reading instead of hiding it. --nav-h is 90px; 45% of 200px is 90. */
  background: linear-gradient(
    to bottom,
    rgba(250, 250, 248, 1) 0,
    rgba(250, 250, 248, 1) var(--nav-h),
    rgba(250, 250, 248, 0) calc(var(--nav-h) + var(--scrim-fade, 110px))
  );
}

/* On a phone the fade was the problem. 90px of nav plus 110px of fade is 200px
   of a ~750px screen — a quarter of the view hazed, and the haze landing over
   the top of the reading rather than over the nav it exists to cover. The nav
   still needs covering; the long soft tail does not.

   Stated as a variable so the two numbers that matter — where the nav ends and
   how far the veil takes to clear — are both readable in one place. */
@media (max-width: 768px) {
  :root { --scrim-fade: 44px; }
}
/* And the same at the bottom edge, so the clear part of the screen is the
   middle. Whatever is centred is what's in focus — which is how the mantra
   ends up alone without anything being dimmed on its account. The earlier
   version of this faded the prose and the ask individually, on the mantra's
   position; two gradients replace all of it and apply everywhere on the
   page rather than at one moment in it.

   It ramps out at the foot of the document, mirroring the way the top one
   ramps in at the head — otherwise the footer would sit permanently under
   a veil it could never scroll out of. */
body::after {
  content: '';
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 200px;
  z-index: 40;
  pointer-events: none;
  opacity: var(--scrim-bottom, 0);
  transition: opacity 0.2s linear;
  background: linear-gradient(
    to top,
    rgba(250, 250, 248, 1) 0%,
    rgba(250, 250, 248, 0.85) 30%,
    rgba(250, 250, 248, 0) 100%
  );
}
/* The same band everywhere on the page. It used to deepen and solidify as
   the mantra reached the centre of the screen, which singled the mantra out
   — the page behaved differently at one moment than at every other. One
   treatment, applied consistently: whatever is near an edge recedes,
   wherever you are. */
@media (max-width: 640px) {
  /* The top veil keeps its height on a phone — the nav is 90px there as well,
     and a 140px veil can't be opaque across it and still fade. Only the bottom
     one shrinks. */
  body::after { height: 140px; }
}

/* No dialogs. There were two — a subscribe form and a share confirmation —
   and neither has anything left to open it. Subscribe isn't on a page that
   carries a reflection, and the share control reports what it did in the line
   you were already looking at rather than over the page. */

/* ============================================================
   TEMPORARY — the closing line is hidden while its copy is undecided. Delete
   this block to bring it back. Do not remove it for any other reason: it has
   been reinstated twice by accident and asked for three times.

   Half of what this block used to hide is now resolved: the share pill became
   the control in share.css, and the subscribe pill is gone from the reading
   pages entirely. The line above them is what's left. */
.hb-close { display: none; }


/* ============================================================
   The homepage teaser
   ------------------------------------------------------------
   Only the homepage carries #interpretation-snippet, so these rules are inert
   on the two pages that show the reading in full.

   The fade is the same device the archive wall uses: the text doesn't stop, it
   recedes. A hard cut reads as truncation — something taken away — where a fade
   reads as more of it being there. Which is the honest description in both
   places.
   ============================================================ */
.hb-teaser {
  position: relative;
  max-height: 13em;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 55%, transparent 100%);
}
.hb-teaser .interpretation { margin-bottom: 0; }

/* Sits close under the fade rather than in the middle of the gap — the fade is
   the end of the reading and this is the door out of it, and a door belongs at
   the edge of a room.

   The generous space is BELOW, not above: it separates the one thing this page
   exists to produce from the pair of secondary controls under it. Without that
   gap, read / share / subscribe read as three options of equal rank rather than
   an action and two afterthoughts. */
.hb-more {
  margin: var(--space-2) 0 var(--space-5);
  text-align: center;
}
/* Larger than the prose it follows, not smaller. It had been set at 1.05rem,
   the same weight as the muted attribution — the quietest thing on a page whose
   whole job is to produce this click. */
.hb-more a {
  font-family: 'Source Serif 4', serif;
  font-size: 1.25rem;
  font-weight: 500;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid rgba(42, 90, 107, 0.28);
  padding-bottom: 2px;
  transition: border-color .12s, color .12s;
}
.hb-more a:hover {
  color: var(--accent-hover);
  border-bottom-color: var(--accent-hover);
}





