/* ==========================================================================
   Within — components
   --------------------------------------------------------------------------
   Every component either appears on the approved cover or solves a UX problem
   the cover does not have (reading order, spoilers, sign-up). Nothing here is
   decorative for its own sake.

   Components read layer-2 tokens ONLY (--bg, --text, --accent, --rule), never
   layer-1 palette names, so the same markup works on the dark trilogy site
   and the light blog with no override.
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. THE ORNAMENT
   --------------------------------------------------------------------------
   A hairline rule interrupted by a small gold diamond. It appears six times on
   the cover comp and it is the ONLY ornament in the whole system — base.yml
   is explicit that "nowhere does anything else decorate". Resist adding a
   second one.

   Built in CSS rather than as an image so it stretches to any width and
   inherits its colour from the ground it is sitting on. The one empty <span>
   is the diamond; the two rules are pseudo-elements.

       <div class="ornament" role="presentation"><span></span></div>
       <div class="ornament ornament--short ornament--center"><span></span></div>

   There is also assets/ornament/rule-diamond.svg for the places CSS cannot
   reach — an OG image, an email, a favicon.
   -------------------------------------------------------------------------- */

.ornament {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  margin: var(--sp-6) 0;
  color: var(--accent);
}

.ornament::before,
.ornament::after {
  content: "";
  flex: 1;
  height: 1px;
  background: currentColor;
  opacity: 0.55;
}

/* The diamond: a rotated square, small — about cap height on the comp. */
.ornament > span {
  flex: none;
  width: 7px;
  height: 7px;
  background: currentColor;
  transform: rotate(45deg);
}

.ornament--short  { max-width: 9rem; }
.ornament--tiny   { max-width: 5rem; margin-block: var(--sp-4); }
.ornament--center { margin-inline: auto; }


/* --------------------------------------------------------------------------
   2. HEADER / NAV
   -------------------------------------------------------------------------- */

.site-header {
  position: relative;
  z-index: 10;
  padding-block: var(--sp-5);
}
.site-header__inner {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-5);
  flex-wrap: wrap;
}

.wordmark {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--fs-lg);
  text-transform: uppercase;
  letter-spacing: var(--track-title);
  color: var(--text-strong);
}
/* The wordmark inside a hero sits on the night ground, not on the page
   ground, so it cannot take --text-strong from the ambient theme. */
.wordmark--onDark { color: var(--c-paper); }

.site-nav ul {
  display: flex; flex-wrap: wrap;
  gap: var(--sp-5);
  list-style: none; margin: 0; padding: 0;
}
.site-nav a {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--text);
  padding-block: var(--sp-2);
  border-bottom: 1px solid transparent;
}
.site-nav a:hover,
.site-nav a[aria-current="page"] {
  color: var(--accent);
  border-bottom-color: var(--rule);
}

/* Inside a hero the navbar sits on a photograph, where --text (a dark ink
   meant for paper) all but vanishes. Paper white plus a shadow the width of
   the stroke: legible over sky or over rock, without a bar behind it. */
.hero .site-nav a {
  color: var(--c-paper);
  font-size: var(--fs-sm);
  font-weight: 500;
  letter-spacing: 0.12em;
  /* A hairline of type over a sunset needs more than colour. Two shadows: a
     tight one that thickens the stroke, and a wide soft one that darkens the
     sky immediately around it. Cheaper than a bar behind the nav, and it does
     not cut a band across the photograph. */
  text-shadow: 0 1px 2px rgba(14, 26, 43, 0.85), 0 0 14px rgba(14, 26, 43, 0.65);
}
.hero .site-nav a:hover,
.hero .site-nav a[aria-current="page"] { color: var(--c-cream); border-bottom-color: var(--c-cream); }
.hero .wordmark {
  text-shadow: 0 1px 2px rgba(14, 26, 43, 0.85), 0 0 16px rgba(14, 26, 43, 0.6);
}


/* --------------------------------------------------------------------------
   3. HERO
   --------------------------------------------------------------------------
   A photograph bled to every edge with type floating in the sky, washed by a
   scrim rather than retouched. This is the cover's own method, and the scrim
   values in tokens.css are the cover's own numbers.

   The scrim is not optional. Measured on the cover, below about 0.64 alpha at
   the top the white title stops surviving a small-thumbnail legibility test
   against a bright sky — and a phone in sunlight is a harsher test than a
   store thumbnail.
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  min-height: min(88svh, 46rem);
  display: grid;
  align-items: end;
  overflow: hidden;
  background: var(--bg-deep);
}
.hero__media {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 45%;      /* keeps the sun and the trail in frame */
  z-index: 0;
}
.hero__scrim {
  position: absolute; inset: 0; z-index: 1;
  /* Two layers: the copy scrim (anchored to the type, top-left) over the
     photographic top ramp. Do NOT add --scrim-foot as well — three stacked
     washes leave no un-scrimmed photograph anywhere and the picture vanishes. */
  background: var(--scrim-copy), var(--scrim-top);
  pointer-events: none;
}
@media (max-width: 48rem) {
  .hero__scrim { background: var(--scrim-copy-narrow); }
}

/* --------------------------------------------------------------------------
   3b. TRAIL HERO  ← the landing page, until the cover reveal
   --------------------------------------------------------------------------
   A soft photograph needs a soft scrim and smaller type. The default hero is
   built for the canyon: heavy washes and --fs-hero, which at 7rem turns an
   eight-word line into four stacked rows and pushes the whole page down.
   -------------------------------------------------------------------------- */

/* 4:3 frame in a wide band. Pinned just above centre so the burning sky and
   the dog on the trail both stay in the crop - she is small, and pushing the
   crop down loses her before it loses anything else. Swap the picture at the
   cover reveal and this line is what needs revisiting.

   A new photograph gets a NEW FILENAME. Reusing one leaves every reader who
   has already visited looking at the old picture out of their browser cache,
   which is exactly what happened the first time this was swapped. */
.hero__media--trail { object-position: 50% 62%; }

/* Sized by Agnès: the title at this scale is the point of the page, and she
   would rather it be read than fitted. So this is a MINIMUM, never a fixed
   height - the type keeps its size and the hero grows if the sentence needs
   the room. Clamping the height instead shrank the type, and she rejected it.

   The minimum is the viewport itself. A 44rem cap was tried and on a taller
   laptop it ended the picture above the fold, leaving a band of page below
   the photograph. A hero that stops short of the screen looks like a mistake. */
.hero--trail { min-height: 100svh; }

/* A hero that sets a tone and then gets out of the way. Full-screen was right
   when the picture WAS the message; once the page's job became "introduce the
   writer", a whole screen of photograph only delayed her. Still a minimum,
   never a fixed height - the type keeps its size. */
/* Named "short" for the TYPE it carries, not for its height. The hero fills
   the screen so that a first look is the photograph and nothing else - half
   a headshot and three lines of bio peeking over the fold read as clutter,
   not as an invitation to scroll. The type inside stays at the smaller size
   Agnès chose; only the frame is tall. */
/* NOT the full screen. A whole viewport of photograph makes people leave
   before they reach the reason to stay, so the hero stops short and a band of
   the page below shows: a deliberate hint that there is more, rather than an
   accidental half of something.

   Raised 2026-09-02. At 80svh the band was deep enough to show the top of
   Agnès' headshot, which is the one thing that must not half-appear - a
   sliver of a face reads as a broken layout, not as an invitation.

   No rem ceiling any more. A fixed maximum meant that the taller the screen,
   the more of the bio came over the fold - exactly backwards. The height is
   now purely proportional, and the band below is cream: clearly more page,
   nothing cut in half. */
.hero--short { min-height: 92svh; }
/* And the section under it starts a further tenth of a screen down, so the
   fold always lands in that cream band rather than on the headshot - 92 + 9
   is more than 100 at every window height, which a fixed padding never is. */
.hero--short + .section { padding-top: max(var(--sp-8), 9svh); }

/* PHOTOGRAPH AS BACKGROUND. White type needs an empty, dark quarter of the
   frame to live in; this daylight picture has none, so the answer is not a
   heavier scrim - that greys the photograph and the type still fights it -
   but to stop asking the photograph to carry white type at all. The page's
   cream is laid over the picture and the type goes back to ink. */
/* .hero.hero--wash, not .hero--wash: the dark trail scrim is declared later
   in this file at equal specificity and was winning. The extra class is the
   cheapest way to say "this one is the deliberate override" without moving
   blocks around and breaking the section order. */
.hero.hero--wash .hero__scrim { background: var(--wash-foot), var(--wash-copy); }
.hero--wash .hero__media { filter: saturate(0.9); }
.hero--wash .hero__title,
.hero--wash .wordmark { color: var(--text-strong); }
.hero--wash .hero__tagline { color: var(--text); text-shadow: none; }
/* The navbar crosses onto the clear side of the wash, over snow, sky and
   grass. Small letterspaced caps in a light ink simply vanished there, so it
   gets three things at once: the strongest ink on the page, a heavier
   stroke, and a cream halo wide enough to hold its own patch of quiet.
   Letterspacing is pulled in too - tracking that reads as elegant on paper
   reads as faint over a photograph. */
.hero--wash .site-nav a,
.hero--wash .wordmark {
  text-shadow: 0 1px 2px rgba(251, 248, 242, 1), 0 0 10px rgba(251, 248, 242, 0.95),
               0 0 22px rgba(251, 248, 242, 0.85);
}
.hero--wash .site-nav a {
  color: var(--text-strong);
  font-weight: 500;
  letter-spacing: 0.12em;
}
.hero--wash .wordmark { font-weight: 400; }
.hero--wash .site-nav a:hover,
.hero--wash .site-nav a[aria-current="page"] {
  color: var(--accent);
  border-bottom-color: var(--rule);
}
@media (max-width: 48rem) {
  .hero.hero--wash .hero__scrim { background: var(--wash-copy-narrow); }
}
/* The type sits in the upper two-thirds, not against the bottom edge. Pinned
   to the foot it read as though it were falling out of the frame, and left
   nothing between the last line and the fold. */
.hero--short .hero__body--split {
  gap: var(--sp-6);
  /* Was a quarter of the viewport, which on a short laptop window pushed the
     hero past the fold - min-height is a floor, and tall content simply grows
     through it. Fixed space instead: the type still sits clear of the bottom
     edge, and the frame stays under the screen. */
  padding-bottom: var(--sp-7);
}
.hero--short .hero__title { font-size: clamp(1.7rem, 0.95rem + 2.3vw, 2.9rem); }
.hero--trail .hero__scrim { background: var(--scrim-sky); }
@media (max-width: 48rem) {
  .hero--trail .hero__scrim { background: var(--scrim-sky-narrow); }
}
/* A whole sentence, not a two-word book title - it needs a smaller ceiling
   and a measure, or it fills the frame and the photograph is decoration. */
.hero--trail .hero__title {
  font-size: clamp(2.1rem, 1.15rem + 3.2vw, 3.9rem);
  max-width: 20ch;
}
/* A claim is a sentence, not a two-word title. Sentence case, a smaller size
   and a wider measure, or fourteen words at display scale fill the screen and
   stop being readable as a sentence. */
/* .hero .hero__title--claim, not .hero__title--claim: the base .hero__title
   rule is declared LATER in this file and its uppercase was winning on equal
   specificity. A sentence of fourteen words set in caps is a wall. */
.hero .hero__title--claim {
  text-transform: none;
  letter-spacing: 0.01em;
  line-height: 1.16;
  font-style: italic;
}
.hero--short .hero--short .hero__title--claim,
.hero--short .hero__title--claim {
  /* Raised 2026-09-02. The claim IS the headline now, and at the old size it
     read as a caption - which left the bio peeking over the fold and made
     the first thing a stranger saw a half-portrait rather than a sentence.
     Bigger type also does the fold work: it fills the hero's foot, so what
     is below the fold stays below it. */
  font-size: clamp(1.75rem, 1.05rem + 2.3vw, 3.1rem);
  max-width: 24ch;
}
/* A fourteen-word claim needs fewer lines on a short window, or the hero
   grows through its own ceiling and pushes the fold off the screen. */
@media (max-height: 44rem) {
  .hero--short .hero__title--claim { font-size: clamp(1.2rem, 0.8rem + 1.2vw, 1.7rem); }
  .hero--short .hero__body--split { padding-bottom: var(--sp-5); }
  .hero__note a { padding: var(--sp-2) var(--sp-4); }
}
/* THE FOOT OF THE HERO: the claim and the book, side by side rather than
   stacked. The photograph's left third is ridge and figures; its right third
   is open pasture and haze - empty ground that was carrying nothing. Moving
   the book there gives the sentence the whole left column and puts the novel
   where the eye lands last. They share a baseline, so the two blocks read as
   one line of the picture rather than two floating labels. */
.hero__foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-6) var(--sp-7);
  flex-wrap: wrap;
}
.hero__foot .hero__title--claim { flex: 1 1 22ch; margin-bottom: 0; }
.hero__foot .hero__note { flex: 0 1 auto; }

/* The novel, beside the claim. Small, gold, uppercase - the only place on the
   landing page that names a book above the fold, and the only reason a
   stranger learns in two seconds that this is a novelist. */
.hero__note {
  font-size: var(--fs-xs, 0.8rem);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  margin: 0;
}
.hero__note a {
  display: inline-block;
  color: var(--accent-strong, var(--accent));
  font-weight: 500;
  border: 1px solid var(--accent);
  border-radius: 0;
  padding: var(--sp-3) var(--sp-4);
  text-align: right;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
/* Two lines, deliberately: the title, then what it is and when. One line put
   a novel's name and a date in the same breath and neither registered. */
.hero__note-title,
.hero__note-meta { display: block; }
.hero__note-meta {
  font-size: 0.86em;
  letter-spacing: 0.1em;
  opacity: 0.85;
  margin-top: 0.25em;
}
/* Stacked, "to the right" means nothing - there is one column. The note goes
   back under the claim and stops trying to hold an edge that isn't there. */
@media (max-width: 44rem) {
  .hero__foot { display: block; }
  .hero__foot .hero__note { margin-top: var(--sp-5); }
  .hero__note a { text-align: left; }
}
.hero__note a:hover { background: var(--accent); color: var(--c-night); }
.hero--wash .hero__note a {
  text-shadow: 0 1px 2px rgba(251, 248, 242, 1), 0 0 12px rgba(251, 248, 242, 0.9);
}

/* The tagline rides directly under the wordmark, in the scrim's darkest band,
   so it needs almost nothing of its own. It is a caption to her name, not a
   second headline - hence the small size and the ordinary sentence case. */
.hero__tagline {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--fs-lg);          /* the standfirst's size - it is a line to
                                       be read, not a credit line */
  color: var(--c-cream);
  margin: var(--sp-3) 0 0;
  /* Five nouns separated by dots read as one gesture; broken over two lines
     the last two look like an afterthought. Wide enough to stay on one line
     wherever there is room for it. */
  max-width: 52rem;
  text-shadow: 0 1px 3px rgba(14, 26, 43, 0.9), 0 0 18px rgba(14, 26, 43, 0.7);
}

/* Top block and foot block, pushed apart. The hero stops being type stacked
   in a corner over a picture and becomes a picture with type at both ends. */
.hero__body--split {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--sp-7);
  height: 100%;
  /* Sit the title as low as the scrub allows. The default hero pads sp-9 at
     the foot, which floats the type well clear of the dark band that makes it
     readable in the first place. */
  padding-bottom: var(--sp-5);
}
.hero--trail { align-items: stretch; }
/* In the scrub at the foot, below every ramp - white on near-black already,
   so the shadow is only insurance for a paler evening. */
.hero--trail .hero__title {
  text-shadow: 0 2px 10px rgba(14, 26, 43, 0.55);
  margin-bottom: 0;
}
.hero__body {
  position: relative; z-index: 2;
  padding-block: var(--sp-9);
  width: 100%;
}
/* --------------------------------------------------------------------------
   FULL-BLEED HERO  ← the landing page
   --------------------------------------------------------------------------
   One photograph across the whole screen, with the type on it. The earlier
   attempts at this failed for a specific reason worth writing down: they laid
   a scrim over the WHOLE frame. That greys the photograph everywhere - which
   is what made it look bland - and still leaves the letters sitting on
   clutter, because the middle of a daylight picture is busy wherever you put
   them.

   A poster does the opposite. It leaves the middle of the frame alone and
   pours the darkness into the two edges where the type actually is: the sky
   at the top, which holds no detail and loses nothing by going dark, and the
   scrub at the bottom, where white letters get real black underneath them.
   Lake, mountains, haze and the two walkers are untouched.
   -------------------------------------------------------------------------- */

.hero--full {
  position: relative;
  /* 88svh, and the number is not taste - it is what puts the tree line low
     enough in the crop for the name to clear it.

     The picture is 1200x900 and the hero is wide and short, so `cover` keeps
     the full width and takes a horizontal slice of the source: rows
     (900 - H) x 0.45 to that plus H. The pine tops are at source row 320. At
     70svh on a laptop that slice began at row 221, which put the trees only
     99px down the frame - right where the name was. At 88svh the slice begins
     nearer row 198 and the trees fall to about 122px, with open sky above
     them for the navigation and the name both. */
  min-height: 88svh;
  align-items: stretch;
}
/* The <picture> is a grid item like everything else, so it was opening a row
   of its own and pushing the type 93px down the frame - out of the top band.
   Taking it out of the flow leaves the body as the only item in the grid, so
   the body fills the hero and the corner button lands in the actual corner. */
.hero--full > picture {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.hero--full .hero__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* ONE BAND, over the sky, carrying two things. Everything below 46% of the
     frame is completely unfiltered - which is the whole difference between a
     poster and an open window. */
  background:
    linear-gradient(to bottom,
      rgba(17, 24, 30, 0.68) 0%,
      rgba(17, 24, 30, 0.60) 16%,
      rgba(17, 24, 30, 0.46) 30%,
      rgba(17, 24, 30, 0.28) 42%,
      rgba(17, 24, 30, 0.10) 52%,
      rgba(17, 24, 30, 0) 62%);
}
/* Its own colour, very slightly forward. Nothing is filtering the photograph
   down any more, so it can carry the daylight it was shot in. */
.hero--full .hero__media { filter: saturate(1.06) contrast(1.02); }
/* STATIC, deliberately. The base .hero__body is position:relative, which made
   it the containing block for anything absolute inside - so the five nouns,
   pinned to "50%", were taking 50% of the MASTHEAD's height (about 80px) and
   landing next to the name instead of halfway down the picture. The body is a
   grid item, so it keeps its z-index without being positioned. */
.hero--full .hero__body {
  position: static;
  z-index: 2;
  /* Everything hugs the top, because the top is where the sky is, and there
     is not a pixel to spare above the trees. The corner button needs no
     reserved space here: it is out of the flow at the right, the navigation
     is left-aligned and ends well short of it, so they share the first line
     without touching. */
  padding-block: var(--sp-4) var(--sp-6);
  align-self: start;
}
/* NAME LEFT, NAVIGATION RIGHT, ONE ROW. Stacked three deep - links, name,
   nouns - there was no size of name that fitted: this crop gives about 120px
   of sky above the pine tops and three rows spend it before the name has said
   anything. Sharing the row buys back a whole line, which is what lets the
   name be large again. flex-start, not baseline: the links then sit in the
   top of the band, its darkest part, where the smallest type on the
   photograph most needs to be. */
.hero--full .hero__masthead {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-5);
  flex-wrap: wrap;
}
/* BIGGER AGAIN, now that the links are beside it rather than above - but the
   ceiling here is the ROW, not the sky. At 1.85x the name measured 687px, the
   links need 412, and the page column is 1056: the row wrapped, the links
   dropped underneath, and that pushed the five nouns down into the trees. At
   1.55x the name is about 576px and the row holds with room to spare.

   Two limits, then, and both have been measured: 1.55x so the row does not
   wrap, and about 1.9x before the baseline reaches the pine tops. The row is
   the tighter of the two - do not raise this without checking the width. */
.hero--full .wordmark--big {
  font-size: min(calc(var(--fs-lg) * 1.55), 7.5vw);
}
.hero--full .site-nav { flex: 0 0 auto; }
.hero--full .site-nav ul { justify-content: flex-end; }

/* THE FIVE NOUNS, DIRECTLY UNDER THE NAME. They were out on the lake, pinned
   to half the frame's height; back under the name they read as the caption to
   it that they are. One line - a second would land in the trees. They sit on
   haze and distant shore, which have no detail to lose, and the halo does the
   rest. */
.hero--full .hero__nouns {
  margin: var(--sp-3) 0 0;
  /* The default paragraph measure is 38rem - a reading column - which broke
     the line in two and dropped the second half onto source row 344, twenty
     rows into the pines. It is a caption, not a paragraph: no measure. */
  max-width: none;
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--fs-lg);
  line-height: 1.35;
  color: #FFFDF8;
  text-shadow:
    0 1px 2px rgba(17, 24, 30, 0.95),
    0 0 10px rgba(17, 24, 30, 0.9),
    0 0 26px rgba(17, 24, 30, 0.72);
}
/* On a phone the links wrap under the name, so they lead from the left like
   everything else. */
@media (max-width: 40rem) {
  .hero--full .site-nav ul { justify-content: flex-start; }
}
/* THE HALO IS WHERE THE CONTRAST LIVES. Three shadows at three radii: a tight
   one that gives every stroke a hard edge, a middle one that fills the
   counters, and a wide soft one that darkens a hand's breadth of photograph
   around the words and nothing else. This is what lets the picture stay bright
   - the letters carry their own ground with them instead of asking the whole
   frame to go dark. */
.hero--full .wordmark,
.hero--full .hero__title {
  color: #FFFDF8;
  text-shadow:
    0 1px 2px rgba(17, 24, 30, 0.95),
    0 0 10px rgba(17, 24, 30, 0.85),
    0 0 34px rgba(17, 24, 30, 0.7);
}
.hero--full .hero__tagline,
.hero--full .site-nav a {
  color: #FFFDF8;
  text-shadow:
    0 1px 2px rgba(17, 24, 30, 0.95),
    0 0 9px rgba(17, 24, 30, 0.9),
    0 0 24px rgba(17, 24, 30, 0.7);
}
.hero--full .site-nav a:hover,
.hero--full .site-nav a[aria-current="page"] {
  color: var(--c-gold);
  border-bottom-color: rgba(201, 160, 92, 0.6);
}

/* DOWN IN THE GRASS, bottom right. It was in the top corner, which is the one
   part of the frame the masthead also wants; the far corner of the slope is
   the emptiest ground in the picture and the last place the eye lands.

   It carries its own dark plate, because there is no veil down there at all -
   gold on sunlit grass is gold on nothing. */
.hero--full .utility {
  position: absolute;
  top: auto;
  bottom: var(--sp-6);
  right: var(--sp-5);
  z-index: 3;
  margin: 0;
}
.hero--full .chat-open {
  background: rgba(17, 24, 30, 0.74);
  border-color: rgba(201, 160, 92, 0.85);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
/* min-height is a floor, so on a short laptop window the type grew through it
   and took the fold with it. Everything steps down together. */
@media (max-height: 46rem) {
  /* No reserved strip for the corner button on a short window either - it is
     out of the flow at the right and the navigation is left-aligned. This rule
     was costing 54px at the very top of the frame, which is 54px of the only
     sky the name has. */
  .hero--full .hero__body { padding-block: var(--sp-4) var(--sp-6); }
}
/* Close under the picture: the headline is the next thing and it should be
   arriving as the photograph ends, not after a field of cream. */
.hero--full + .section { padding-top: var(--sp-7); }

/* HER NAME, TWICE THE SIZE. It is the first thing on the site and it had been
   set at the size of a section heading. The vw ceiling is only there so it
   cannot outgrow a phone. */
.wordmark--big {
  display: block;
  font-size: min(calc(var(--fs-lg) * 2), 9.5vw);
  line-height: 1.04;
}

/* --------------------------------------------------------------------------
   THE OPENING  ← the headline and the book, on the cream
   --------------------------------------------------------------------------
   Everything a stranger has to READ, in the page's own ink at full contrast,
   with no photograph underneath and therefore no scrim, no halo and no
   compromise on size. This is where the landing page actually speaks.
   -------------------------------------------------------------------------- */

.opening { margin-block: 0 var(--sp-7); }
/* The five nouns, moved off the photograph. They are a caption to her name,
   so they lead the opening rather than competing with the claim. */
/* Five nouns separated by dots read as one gesture; broken over two lines the
   last two look like an afterthought. The default paragraph measure is a
   reading column and cut it in half, so it gets its own. */
.opening__nouns {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--fs-lg);
  color: var(--text);
  max-width: 46rem;
  margin: 0 0 var(--sp-4);
}
.opening__claim {
  font-family: var(--font-display);
  font-weight: 300;
  font-style: italic;
  font-size: clamp(2.1rem, 1.2rem + 3.1vw, 3.9rem);
  line-height: 1.12;
  letter-spacing: 0.005em;
  color: var(--text-strong);
  max-width: 46rem;
  margin: 0;
  text-wrap: pretty;
}
.opening__book { margin: var(--sp-6) 0 0; }

/* THE BOOK, as a filled button. Outlined gold on a photograph was a whisper;
   gold ground with the night ink on it is the loudest thing on the page after
   the headline, which is right - it is the only reason the launch exists. */
.booknote {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.2em;
  background: var(--accent);
  border-color: var(--accent);
  /* Stated, not --bg: on the cream ground --bg IS the cream, which would put
     pale text on a gold button. */
  color: var(--c-night);
  padding: var(--sp-4) var(--sp-6);
}
.booknote:hover {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
  color: var(--c-night);
}
.booknote__title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  letter-spacing: var(--track-title);
  line-height: 1.1;
}
.booknote__meta {
  font-size: var(--fs-xs);
  letter-spacing: var(--track-label);
  opacity: 0.82;
}

/* PARKED. .hero--split below is the two-column version - a night panel of type
   beside an undimmed photograph. No page uses it; it is kept because it solved
   the readability problem outright and may be wanted again. */

/* --------------------------------------------------------------------------
   SPLIT HERO  ← the landing page
   --------------------------------------------------------------------------
   Type on its own ground, photograph on its own. Every earlier version put
   white letters over a daylight photograph and then tried to rescue them: a
   dark scrim greyed the picture, a cream wash made the picture bland, and the
   tagline sat over the trees where nothing can be read at any opacity. The
   frame simply has no empty quarter for type to live in.

   Two columns solve all of it at once. The panel is near-black, so contrast
   is a non-question and the claim can be as large as it deserves; the
   photograph keeps its own colour and never carries a word.
   -------------------------------------------------------------------------- */

.hero--split {
  position: relative;
  display: grid;
  /* The type side is the wider one. Equal halves read as a comparison of two
     things; a 1.15 : 1 split reads as a page with a picture on it. */
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  align-items: stretch;
  min-height: 92svh;
  background: var(--c-night);
}
.hero--split .hero__panel { display: flex; background: var(--c-night); }
.hero--split .hero__panel-inner {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--sp-7);
  width: 100%;
  /* The left padding is the PAGE's own gutter, computed the same way .page
     computes it. That puts the wordmark directly above the author's name in
     the section below, which is what makes the two halves of the screen read
     as one page rather than as two panes. */
  padding: var(--sp-5) var(--sp-7) var(--sp-8)
           max(var(--sp-6), calc((100vw - var(--page-max)) / 2));
}
.hero--split .hero__frame { position: relative; overflow: hidden; }
/* No filter, no scrim, no wash. It carries no type, so it has nothing to
   apologise for. */
.hero--split .hero__frame .hero__media { object-position: 50% 45%; }

/* The panel is night whatever the ground, so its type is stated here rather
   than inherited - the page below can be in light mode. */
.hero--split .hero__panel { color: var(--c-shell); }
.hero--split .wordmark,
.hero--split .hero__title { color: var(--c-shell); text-shadow: none; }
.hero--split .hero__tagline { color: rgba(251, 248, 242, 0.72); text-shadow: none; }
.hero--split .site-nav a { color: rgba(251, 248, 242, 0.82); text-shadow: none; }
.hero--split .site-nav a:hover,
.hero--split .site-nav a[aria-current="page"] {
  color: var(--c-gold);
  border-bottom-color: rgba(201, 160, 92, 0.5);
}
/* THE CLAIM, at last at headline size. On its own ground there is no reason
   to keep it small, and it is the sentence the whole page is built on. */
.hero--split .hero__title--claim {
  text-transform: none;
  letter-spacing: 0.01em;
  line-height: 1.14;
  font-style: italic;
  font-size: clamp(1.9rem, 1.1rem + 2.4vw, 3.35rem);
  /* No ch measure at all. 17ch was a column narrower than the panel it sits
     in - five lines of four words, which reads as a poem rather than a claim -
     and raising the number chased a moving target, because ch is measured on
     the digit zero and this display italic has an unusually narrow one (30ch
     came out at 326px, not the 600 it looks like). The panel is already the
     right measure: it is about 580px at every screen width, because its left
     padding is the page gutter and grows with the window. */
  max-width: 100%;
  margin: 0;
}
/* The button goes to the actual top-right corner of the page, over the sky in
   the photograph, rather than to the right edge of the panel - which is the
   middle of the screen and reads as nothing in particular. It needs its own
   dark ground there: gold on sky is gold on nothing. */
.hero--split .utility {
  position: absolute;
  top: var(--sp-4);
  right: var(--sp-5);
  z-index: 3;
  margin: 0;
}
.hero--split .chat-open {
  background: rgba(17, 24, 30, 0.66);
  border-color: rgba(201, 160, 92, 0.75);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
.hero--split .chat-open:hover,
.hero--split .chat-open:focus-visible { background: var(--c-gold); }

/* A SHORT WINDOW. min-height is a floor, so on a laptop window turned short
   the type simply grew through it and the hero ran off the bottom of the
   screen - taking the fold with it. Everything steps down together. */
@media (max-height: 46rem) {
  .hero--split .hero__panel-inner {
    gap: var(--sp-5);
    padding-top: var(--sp-6);
    padding-bottom: var(--sp-6);
  }
  .hero--split .hero__title--claim { font-size: clamp(1.5rem, 1rem + 1.5vw, 2.15rem); }
  .hero--split .hero__note { margin-top: var(--sp-5); }
  .hero--split .hero__tagline { font-size: var(--fs-base, 1rem); }
}
.hero--split .hero__note { margin-top: var(--sp-6); }

@media (max-width: 60rem) {
  /* Stacked: the panel first, because the navigation belongs at the top of a
     page, then the photograph as a band under it. */
  .hero--split {
    grid-template-columns: 1fr;
    min-height: 0;
  }
  .hero--split .hero__panel-inner {
    gap: var(--sp-6);
    padding: var(--sp-5) var(--sp-6) var(--sp-7);
  }
  .hero--split .hero__frame { height: 42svh; min-height: 14rem; }
  .hero--split .hero__title--claim { max-width: 26rem; }
}
/* The page under it starts a tenth of a screen down, so on a tall window the
   fold lands in cream rather than on the top of the headshot. */
.hero--split + .section { padding-top: max(var(--sp-8), 8svh); }

/* --------------------------------------------------------------------------
   LEDE  ← the heading on /blog/ and /books/
   --------------------------------------------------------------------------
   /blog/ only. Books went back to its display-size word and its ornament on
   2026-09-02; this stayed, because on /blog/ the sentence says what the three
   strands ARE, which the word "Blog" under a nav bar already marking Blog as
   the current page never did.
   -------------------------------------------------------------------------- */

.blog-lede {
  font-family: var(--font-display);
  font-weight: 300;
  font-style: italic;
  font-size: clamp(1.2rem, 0.9rem + 0.95vw, 1.7rem);
  line-height: var(--lh-snug);
  letter-spacing: 0.01em;
  color: var(--text-strong);
  max-width: var(--measure-wide);
  margin: var(--sp-4) 0 0;
  text-wrap: pretty;
}
/* The second sentence is the gloss on the first, so it steps back a shade
   rather than starting a new paragraph and costing another line of space. */
.blog-lede span { color: var(--text); }

/* --------------------------------------------------------------------------
   UTILITY ROW  ← "Ask me anything", above the navigation
   --------------------------------------------------------------------------
   The chat widget's own launcher is a 380px bar pinned to the bottom-right
   corner of the screen, which is where a SaaS support chat lives. On an
   author's site it sat on top of the writing. This is the same thing in the
   place a reader looks for a way to talk to someone.
   -------------------------------------------------------------------------- */

.utility {
  display: flex;
  justify-content: flex-end;
  margin-bottom: var(--sp-3);
}
.chat-open {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  /* Gold on both grounds, so one rule serves the night panel and the cream
     Blog masthead without a second set of colours. */
  color: var(--c-gold);
  background: transparent;
  border: 1px solid rgba(201, 160, 92, 0.55);
  border-radius: 999px;
  padding: var(--sp-2) var(--sp-4);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.chat-open:hover,
.chat-open:focus-visible {
  background: var(--c-gold);
  border-color: var(--c-gold);
  color: var(--c-night);
}

/* Title-in-the-sky: content at the TOP, like the cover, where the photograph
   is emptiest. This is the default hero for a book or series page. */
.hero--sky { align-items: start; }
.hero--sky .hero__body { padding-top: var(--sp-8); }

/* A hero with NO photograph. The full-height hero is sized for a picture, so
   without one it is a void, and a void reads as something that failed to load
   rather than as a decision. Books is in that state until the cover reveal:
   its hero image WAS the cover photograph and had to come out.

   So: a masthead. It hugs its own type, the trilogy starts near the top of
   the screen, and the page looks finished. At the reveal, drop this class and
   the full-height hero returns with the cover in it - the page visibly
   changes on the day, which is worth more than a picture standing in now. */
.hero--compact {
  min-height: 0;
  align-items: start;
  /* .hero paints --bg-deep for a photograph to sit on. With no photograph and
     no height, that leaves a slightly different navy from the page ground and
     a visible seam across the screen. Let the page ground show through. */
  background: transparent;
}
.hero--compact .hero__body { padding-block: var(--sp-5) var(--sp-5); }
.hero--compact .hero__title { font-size: clamp(2.4rem, 1.4rem + 3vw, 4rem); }

/* With no photograph underneath, the type takes the GROUND's own ink instead
   of paper white. That one substitution lets the same masthead serve the dark
   Books page and the light Blog page, so the two read as siblings without a
   second set of markup. */
.hero--compact .hero__title,
.hero--compact .wordmark { color: var(--text-strong); text-shadow: none; }
.hero--compact .site-nav a { color: var(--text); text-shadow: none; }
.hero--compact .site-nav a:hover,
.hero--compact .site-nav a[aria-current="page"] {
  color: var(--accent);
  border-bottom-color: var(--rule);
}
.hero--compact .hero__sub { color: var(--text); text-shadow: none; }
/* .section pads sp-9 at the top, which is right under a full-height hero and
   far too much under a masthead - it reopens the very gap the masthead was
   closing. */
.hero--compact + main.section { padding-top: var(--sp-4); }
/* A washed hero already ends in the page's own cream, so the section under it
   needs no separating space either. */
/* Enough cream under a washed hero that whatever shows above the fold is
   space, not the top third of a photograph. */
.hero--wash + main.section { padding-top: var(--sp-8); }

/* Type at the foot instead — for an interior page over a busier picture. */
.hero--foot .hero__scrim { background: var(--scrim-foot); }

.hero__title {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--fs-hero);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-title);
  text-transform: uppercase;
  color: var(--c-paper);
  margin: 0 0 var(--sp-4);
  hyphens: none;
  /* The cover has no text-shadow; the scrim does that work. A shadow here
     would muddy the hairline serifs. */
}
.hero__sub {
  font-style: italic;
  font-size: var(--fs-lg);
  color: var(--c-cream);
  max-width: 30rem;
  margin: 0;
}


/* --------------------------------------------------------------------------
   4. SERIES STRIP  ← the most important component on the trilogy site
   --------------------------------------------------------------------------
   A reader arriving from a search on "The Canyon Within" has no idea it is
   Book Two. This strip goes at the top of EVERY book page and every book
   excerpt, and it is the whole fix: three numbered books, in order, current
   one marked, unwritten ones visibly unwritten.

   Marked up as an ordered list so the reading order is real to a screen
   reader and not just a visual arrangement.

       <nav class="series-strip" aria-label="The Within Trilogy, in order">
         <ol>
           <li><a href="...">     <span class="label">Book One</span> The Chaos Within</a></li>
           <li aria-current="page"><span class="label">Book Two</span> The Canyon Within</li>
           <li class="is-unwritten"><span class="label">Book Three</span> The Creation Within</li>
         </ol>
       </nav>
   -------------------------------------------------------------------------- */

.series-strip {
  border-block: 1px solid var(--rule-quiet);
  padding-block: var(--sp-4);
  margin-block: var(--sp-6);
}
.series-strip ol {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-5);
  list-style: none; margin: 0; padding: 0;
  counter-reset: book;
}
.series-strip li {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  line-height: var(--lh-snug);
  color: var(--text-soft);
  padding-top: var(--sp-3);
  border-top: 2px solid transparent;
}
.series-strip a { color: var(--text); display: block; }
.series-strip a:hover { color: var(--accent-strong); }

.series-strip [aria-current="page"] {
  color: var(--text-strong);
  border-top-color: var(--accent);
}
.series-strip .is-unwritten {
  opacity: 0.5;
  font-style: italic;
}

@media (max-width: 46rem) {
  .series-strip ol { grid-template-columns: 1fr; gap: var(--sp-3); }
  .series-strip li { border-top: 0; border-left: 2px solid transparent;
                     padding: var(--sp-1) 0 var(--sp-1) var(--sp-4); }
  .series-strip [aria-current="page"] { border-left-color: var(--accent); }
}


/* --------------------------------------------------------------------------
   5. BOOK CARD + STATUS
   --------------------------------------------------------------------------
   NOT a Material card: no elevation, no shadow, no filled surface. A cover, a
   rule, and type. The cover image IS the visual weight; a box around it just
   competes.
   -------------------------------------------------------------------------- */

.book-card {
  display: grid;
  grid-template-columns: minmax(0, 18rem) 1fr;   /* 12rem + 50%, at Agnès' request */
  gap: var(--sp-6);
  align-items: start;
  padding-block: var(--sp-7);
  border-top: 1px solid var(--rule-quiet);
}
.book-card__cover img {
  width: 100%;
  /* The only shadow in the system, and it exists because a book is a
     physical object sitting on a page, not a rectangle printed on it. */
  box-shadow: 0 2px 6px rgba(0,0,0,.32), 0 12px 32px rgba(0,0,0,.28);
}
.book-card__title {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-strong);
  margin: 0 0 var(--sp-2);
}
.book-card__blurb { color: var(--text); }

/* The chronology, demoted. It used to be a numbered strip at the top of every
   book page, which with one book published announced a Book One nobody could
   buy. As a footnote it still answers "what order did this happen in" for the
   reader who wants to know, without framing the shelf around a gap. */
.chronology {
  font-size: var(--fs-sm);
  color: var(--text-soft);
  max-width: var(--measure-wide);
  margin: var(--sp-7) 0 0;
  padding-top: var(--sp-5);
  border-top: 1px solid var(--rule-quiet);
}
.chronology .label { display: block; margin-bottom: var(--sp-2); }

/* An author statement rather than a description of one book - it stands
   above the shelf and stays true as the shelf grows. Display italic, wide
   measure, no quotation marks: it is a claim, not a pull-quote. */
/* --------------------------------------------------------------------------
   4b. LATEST  ← three newest posts, on the landing page
   --------------------------------------------------------------------------
   A fixed hero photograph says nothing about whether anything is new. This
   row is the only thing on the landing page that changes by itself: publish a
   post and it appears here, so a returning reader can see at a glance that
   the site is alive. Three, deliberately - enough to prove movement, few
   enough that the page stays a front door rather than becoming an index.
   -------------------------------------------------------------------------- */

.latest {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: var(--sp-6);
  margin: var(--sp-6) 0 0;
  padding: 0;
  list-style: none;
}
.latest__link { display: block; color: var(--text); text-decoration: none; }
.latest__link:hover .latest__title { color: var(--accent); }
.latest__thumb {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: var(--radius-photo);
  margin-bottom: var(--sp-3);
}
/* One essay has no photograph. Without a stand-in its card floats to the top
   of the row while its neighbours start below their images, and three cards
   stop looking like a set. A ruled empty frame keeps the grid honest. */
.latest__thumb--none {
  background: transparent;
  border: 1px solid var(--rule-quiet);
}
.latest__title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  line-height: var(--lh-snug);
  color: var(--text-strong);
  margin: var(--sp-2) 0 var(--sp-2);
  transition: color var(--dur) var(--ease);
}
.latest__meta { font-size: var(--fs-xs); color: var(--text-soft); margin: 0; }


/* Where a reader decides what to do next: the END of the essay, not the
   margin beside it. Reuses .latest - same three-up shape, so a reader meets
   one pattern for "here is more to read" wherever they are. */
.more { margin-top: var(--sp-8); }
.more__title {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  margin: 0;
}


/* --------------------------------------------------------------------------
   5a. STRAND  ← the three blog categories on /blog/
   --------------------------------------------------------------------------
   A category introduced in Agnès' own words, not a card and not a teaser. The
   rule above each one does the separating, so three of these read as three
   doors rather than three adverts. /blog/ deliberately shows no combined post
   feed: mixing the categories is the thing this page exists to undo.
   -------------------------------------------------------------------------- */

/* ONE UNDER ANOTHER. They were three abreast for a day so that all three were
   visible at once; Agnès wanted the wide rows back. Three columns forced every
   introduction into the same clamped seven lines, which turns three different
   welcomes into three cards of equal weight - a directory rather than three
   doors. A wide row gives each strand a real photograph and all of her words. */
.strand {
  display: grid;
  grid-template-columns: minmax(0, 22rem) 1fr;
  gap: var(--sp-7);
  align-items: start;
  border-top: 1px solid var(--rule-quiet);
  padding-block: var(--sp-7);
  /* No max-width. This block was capped at --measure-wide, which is a MEASURE
     for a single column of prose - put a 18rem photograph beside it and the
     text was squeezed into a ribbon. The photograph and the text each get
     their own width instead: the picture a real size, the paragraphs the
     reading measure they need, and the page carries both. */
}
/* A photograph of Agnès' own, one per strand - the picture says what the
   category is faster than the paragraph does. Fixed 4:3 so three unequal
   source frames still line up down the page. */
.strand__media { display: block; }
.strand__media img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-photo);
}

@media (max-width: 44rem) {
  .strand { grid-template-columns: 1fr; gap: var(--sp-5); }
}

.strand__name {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--fs-xl);
  text-transform: uppercase;
  letter-spacing: var(--track-title);
  margin: 0 0 var(--sp-4);
}
.strand__name a { color: var(--text-strong); text-decoration: none; }
.strand__name a:hover { color: var(--accent); }
.strand__body { min-width: 0; }
/* A short list of what a strand actually contains. Not a feature grid - it is
   Agnès' own voice, so it stays plain type with the label in the body face. */
.strand__bullets {
  list-style: none;
  margin: var(--sp-5) 0 0;
  padding: 0;
  max-width: var(--measure);
}
.strand__bullets li {
  padding-left: var(--sp-5);
  position: relative;
  margin-bottom: var(--sp-3);
  color: var(--text);
}
.strand__bullets li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.6em;
  width: 0.35rem; height: 0.35rem;
  background: var(--accent);
  transform: rotate(45deg);
}
.strand__bullets strong { color: var(--text-strong); font-weight: 500; }
/* CLAMPED, not truncated in Liquid. Agnès' three welcomes run to wildly
   different lengths - Soul & Self's is a single sentence - so three columns
   showed three different depths and the Read buttons landed on three
   different lines. A fixed number of lines gives every strand the same
   weight on the page; the full introduction is on the strand's own page.
   The old -webkit- properties are the only ones any browser implements, and
   every browser implements them, including Firefox. */
/* No clamp. In a wide row there is nothing to equalise against, so Agnès'
   introduction runs in full - which is the whole point of the page. */
.strand__intro { color: var(--text); max-width: var(--measure); }
.strand__foot {
  display: flex; align-items: baseline; flex-wrap: wrap;
  gap: var(--sp-4);
  margin: var(--sp-5) 0 0;
}
.strand__count,
.strand__latest {
  font-size: var(--fs-sm);
  color: var(--text-soft);
}
.strand__latest { margin: var(--sp-3) 0 0; }
.strand__latest time { margin-left: var(--sp-2); }


/* --------------------------------------------------------------------------
   5c. TASTE  ← a paragraph of the actual writing, on the landing page
   --------------------------------------------------------------------------
   The one thing an author's front page must not omit. A visitor can read a
   real paragraph of Agnès' prose before being asked for anything - no bio, no
   blurb, no description OF the writing, the writing itself.
   -------------------------------------------------------------------------- */

.taste { margin-block: var(--sp-7); max-width: var(--measure-wide); }
.taste__title {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  line-height: var(--lh-snug);
  margin: var(--sp-2) 0 var(--sp-4);
}
.taste__title a { color: var(--text-strong); }
.taste__title a:hover { color: var(--accent-strong); }
.taste__text {
  font-size: var(--fs-lg);
  line-height: 1.5;
  color: var(--text);
  max-width: var(--measure);
}


/* --------------------------------------------------------------------------
   5b. LAUNCH PANEL
   --------------------------------------------------------------------------
   One book, one date, on the landing page only. It is bordered rather than
   filled: a filled block would read as an advertisement dropped onto the
   page, and this is the page's own news. No cover art here before the
   reveal - see rule 7 in README.md.
   -------------------------------------------------------------------------- */

.launch {
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
  padding: var(--sp-6) var(--sp-6) var(--sp-7);
  margin-block: var(--sp-7);
  max-width: var(--measure-wide);
}
.launch__date {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--accent);
  margin: 0 0 var(--sp-3);
}
.launch__title {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--fs-xl);
  text-transform: uppercase;
  letter-spacing: var(--track-title);
  line-height: var(--lh-tight);
  color: var(--text-strong);
  margin: 0 0 var(--sp-3);
}
.launch__line {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--fs-lg);
  color: var(--text-accent);
  margin: 0 0 var(--sp-4);
}
.launch__blurb { color: var(--text); margin: 0 0 var(--sp-5); }
.launch__actions {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  margin: 0;
}

.credo {
  font-family: var(--font-display);
  font-weight: 300;
  font-style: italic;
  font-size: var(--fs-lg);
  line-height: var(--lh-tight);
  color: var(--text-strong);
  max-width: 34rem;
  margin: var(--sp-3) 0 0;
}

/* Editions. The same book in three languages is one book, so the language
   choice sits under the cover as a quiet row of equals - not three separate
   entries in the list, and not a dropdown. Each link goes to that edition's
   own Amazon page, where the translated cover and description already live. */
.editions { margin-top: var(--sp-4); }
.editions .label { display: block; margin-bottom: var(--sp-2); }
.editions__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0;
}
.editions__row .btn { font-size: var(--fs-xs); padding: var(--sp-1) var(--sp-3); }

/* A photograph belonging to a series rather than to one book — the shelf, the
   table at a signing. Deliberately half the width of a hero: it is a snapshot,
   not a statement. */
.series-photo {
  display: block;
  width: 100%;
  max-width: 23rem;
  height: auto;
  border-radius: var(--radius-photo);
  margin: var(--sp-6) 0;
}

@media (max-width: 40rem) {
  .book-card { grid-template-columns: 1fr; gap: var(--sp-5); }
  .book-card__cover { max-width: 11rem; }
}

/* Status. Every book carries one, always, so an unwritten book never looks
   like a broken link. Three states and no others. */
.status {
  display: inline-block;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  padding: var(--sp-1) var(--sp-3);
  border: 1px solid var(--rule);
  color: var(--accent);
  margin-bottom: var(--sp-3);
}
.status--writing  { color: var(--text-soft); border-color: var(--rule-quiet); }
.status--soon     { color: var(--accent); }
.status--out      { color: var(--bg); background: var(--accent);
                    border-color: var(--accent); }


/* --------------------------------------------------------------------------
   6. BUTTONS
   --------------------------------------------------------------------------
   ONE primary button per page. On an unpublished trilogy the primary action
   is the email list, not a shop link — there is nothing to buy yet, and the
   list is the only asset the site is actually building.
   -------------------------------------------------------------------------- */

.btn {
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  padding: var(--sp-3) var(--sp-6);
  border: 1px solid var(--accent);
  color: var(--accent);
  background: transparent;
  cursor: pointer;
  transition: background var(--dur) var(--ease),
              color var(--dur) var(--ease);
}
.btn:hover { background: var(--accent); color: var(--bg); }

.btn--primary { background: var(--accent); color: var(--bg); }
.btn--primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); }

.btn--quiet { border-color: var(--rule-quiet); color: var(--text); }
.btn--quiet:hover { border-color: var(--accent); background: transparent;
                    color: var(--accent); }


/* --------------------------------------------------------------------------
   7. SPOILER DISCLOSURE
   --------------------------------------------------------------------------
   Book Two's real blurb spoils Book One's ending. The page shows a
   spoiler-safe framing by default and puts the full description behind a
   disclosure the reader opens deliberately.

   <details> and <summary> — no JavaScript, works with the page half-loaded,
   and screen readers announce the expanded state for free.
   -------------------------------------------------------------------------- */

.spoiler {
  border: 1px solid var(--rule-quiet);
  padding: var(--sp-4) var(--sp-5);
  margin: var(--sp-6) 0;
  max-width: var(--measure);
}
.spoiler > summary {
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--accent);
  cursor: pointer;
  list-style: none;
}
.spoiler > summary::-webkit-details-marker { display: none; }
.spoiler > summary::before {
  content: "＋";
  margin-right: var(--sp-3);
  font-size: 0.9em;
}
.spoiler[open] > summary::before { content: "−"; }
.spoiler[open] > summary { margin-bottom: var(--sp-4); }
.spoiler > *:last-child { margin-bottom: 0; }

/* A quieter disclosure, for a books index where several bordered boxes down
   one page read as a stack of crates. Same behaviour, no frame, and it sits
   at the end of the visible text rather than announcing itself. */
.spoiler--quiet { border: 0; padding: 0; margin: var(--sp-3) 0 0; max-width: var(--measure); }
.spoiler--quiet > summary { font-size: var(--fs-xs); }
.spoiler--quiet[open] > summary { margin-bottom: var(--sp-3); }

/* The buy button belongs under the artwork, not adrift at the foot of the
   description — the cover is what the eye lands on and what gets clicked. */
.book-card__cover .btn { display: block; margin-top: var(--sp-4); text-align: center; }

/* A series introduction: the words lead, the photograph sits beside them
   rather than interrupting the column between the intro and the first book. */
.series-intro {
  display: grid;
  grid-template-columns: 1fr minmax(0, 17rem);
  gap: var(--sp-6);
  align-items: start;
  margin: var(--sp-5) 0 var(--sp-6);
}
.series-intro .series-photo { margin: 0; max-width: 100%; }
@media (max-width: 40rem) {
  .series-intro { grid-template-columns: 1fr; }
}


/* --------------------------------------------------------------------------
   8. SIGN-UP
   -------------------------------------------------------------------------- */

.signup {
  border-block: 1px solid var(--rule);
  padding-block: var(--sp-8);
  margin-block: var(--sp-9);
}
.signup__form {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  max-width: 30rem; margin-top: var(--sp-5);
}
.signup input[type="email"] {
  flex: 1 1 16rem;
  font-family: var(--font-body);
  font-size: var(--fs-md);
  padding: var(--sp-3) var(--sp-4);
  background: transparent;
  border: 1px solid var(--rule);
  color: var(--text);
}
.signup input[type="email"]::placeholder { color: var(--text-soft); }
.signup input[type="email"]:focus-visible { border-color: var(--accent); }
.signup__note {
  font-size: var(--fs-xs);
  color: var(--text-soft);
  margin: var(--sp-3) 0 0;
}

/* Substack and Medium live here and nowhere louder. They are directions to
   the same author, not destinations competing with the page you are on. */
/* The site's own line, closing every page. Italic display type so it reads as
   a signature rather than as another navigation item. */
.site-footer__line a {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--fs-md);
  color: var(--text);
}
.site-footer__line a:hover { color: var(--accent-strong); }

.site-footer__elsewhere a { color: var(--text-soft); }
.site-footer__elsewhere a:hover { color: var(--accent); }


/* --------------------------------------------------------------------------
   9. PULL QUOTE — for excerpts and blog posts
   -------------------------------------------------------------------------- */

.pull {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-style: italic;
  line-height: 1.34;
  color: var(--text-accent);
  max-width: var(--measure-wide);
  margin: var(--sp-8) 0;
  padding: 0;
  border: 0;
}


/* --------------------------------------------------------------------------
   10. POST LIST — the blog's index
   -------------------------------------------------------------------------- */

.post-list { list-style: none; margin: 0; padding: 0; }
.post-list > li {
  padding-block: var(--sp-6);
  border-top: 1px solid var(--rule-quiet);
  max-width: none;
}
.post-list h2 {
  font-size: var(--fs-xl);
  margin: var(--sp-2) 0;
}
.post-list h2 a { color: var(--text-strong); }
.post-list h2 a:hover { color: var(--accent); }
.post-list__meta {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--text-soft);
}
.post-list__excerpt { color: var(--text); margin: var(--sp-3) 0 0; }


/* --------------------------------------------------------------------------
   11b. AUTHOR BLOCK
   -------------------------------------------------------------------------- */

.author-grid {
  display: grid;
  grid-template-columns: minmax(0, 9.5rem) 1fr;
  gap: var(--sp-6);
  align-items: start;
}
.author-grid > img { width: 100%; height: auto; }
/* The portrait stays beside the text at every width - it is small enough
   that stacking it would only add scroll. */
@media (max-width: 40rem) {
  .author-grid { grid-template-columns: minmax(0, 7rem) 1fr; gap: var(--sp-5); }
}


/* --------------------------------------------------------------------------
   11. FOOTER
   -------------------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--rule-quiet);
  margin-top: var(--sp-9);
  padding-block: var(--sp-7) var(--sp-8);
  font-size: var(--fs-sm);
  color: var(--text-soft);
}
.site-footer a { color: var(--text); }
.site-footer__cols {
  display: flex; flex-wrap: wrap; gap: var(--sp-7);
  justify-content: space-between;
}


/* --------------------------------------------------------------------------
   12. CHAT WIDGET (Demeterics)
   --------------------------------------------------------------------------
   Third-party embed. It is a guest on the page, so it is styled down to the
   system rather than left on its vendor default — a bright rounded bubble in
   the corner of this site looks like an advert someone else bought.

   These are the widget's documented custom properties. Everything else about
   it is out of our control, which is the trade for not building a chat UI.
   -------------------------------------------------------------------------- */

dem-agent {
  --dem-primary-color: #C9A05C;   /* the system gold — the launcher           */
  --dem-accent-color:  #0E1A2B;   /* dusk, so the panel matches the ground    */
  --dem-bottom: 20px;
  --dem-right:  20px;
}


/* --------------------------------------------------------------------------
   13. PAGER — previous / next essay
   --------------------------------------------------------------------------
   The one component the trilogy site never needed. Same hairline vocabulary
   as .post-list so a reader arriving from an essay sees no seam.
   -------------------------------------------------------------------------- */

.pager {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-6);
  margin-top: var(--sp-7);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--rule-quiet);
  max-width: var(--measure-wide);
}
.pager__link {
  display: block;
  color: var(--text);
  text-decoration: none;
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}
.pager__link .label { display: block; margin-bottom: var(--sp-2); }
.pager__link:hover { color: var(--accent); }
.pager__link--next { text-align: right; grid-column: 2; }

@media (max-width: 34rem) {
  .pager { grid-template-columns: 1fr; }
  .pager__link--next { text-align: left; grid-column: 1; }
}


/* --------------------------------------------------------------------------
   14. TITLE COVER — a book whose artwork is not on show yet
   --------------------------------------------------------------------------
   Same proportion as a real trade paperback (5.5 x 8.5) so the card layout
   does not shift when real artwork replaces it.
   -------------------------------------------------------------------------- */

.title-cover {
  aspect-ratio: 5.5 / 8.5;
  background: var(--c-night);
  border: 1px solid var(--rule);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  padding: var(--sp-5) var(--sp-4);
  text-align: center;
}
.title-cover__series {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--c-gold);
}
.title-cover__title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  line-height: var(--lh-tight);
  text-transform: uppercase;
  letter-spacing: var(--track-title);
  color: var(--c-paper);
  text-wrap: balance;
}
.title-cover__status {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--c-bone);
  opacity: 0.7;
}


/* --------------------------------------------------------------------------
   15. FEATURED IMAGE — the picture that belongs to an essay
   --------------------------------------------------------------------------
   WordPress calls it a "featured image": one photograph per post, shown at the
   head of the piece and as a thumbnail in any listing. The blog had one for 28
   of 29 essays and they carry a lot of the warmth, so the list is not allowed
   to become a wall of text again.
   -------------------------------------------------------------------------- */

.featured {
  display: block;
  width: 100%;
  max-width: var(--measure);      /* the text column, not wider than it */
  aspect-ratio: 3 / 2;            /* every essay opens the same shape, whatever
                                     proportion the photograph arrived in */
  object-fit: cover;
  object-position: 50% 45%;
  height: auto;
  margin: var(--sp-5) 0 var(--sp-6);
  border-radius: var(--radius-photo);
  background: var(--bg-deep);
}

/* Listing rows become two columns once there is room for a thumbnail. */
.post-list > li.has-thumb {
  display: grid;
  grid-template-columns: 12.75rem 1fr;   /* 8.5rem + 50%, at Agnès' request */
  gap: var(--sp-5);
  align-items: start;
}
.post-list__thumb {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-photo);
  background: var(--bg-deep);
}
.post-list__thumb:hover { opacity: 0.88; }

/* The image column carries the date beneath it, so the text column can start
   flush with the title. Without the margin reset the title sits a few pixels
   below the top of the photograph and the row looks accidentally ragged. */
.post-list__media { display: flex; flex-direction: column; gap: var(--sp-2); }
.post-list__media .post-list__meta { margin: 0; }
.post-list > li.has-thumb h2 { margin-top: 0; }

.post-list__excerpt { color: var(--text); margin: var(--sp-2) 0 var(--sp-3); }

.read-more {
  display: inline-block;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  padding-bottom: 2px;
}
.read-more:hover { color: var(--accent-strong); border-bottom-color: currentColor; }

@media (max-width: 34rem) {
  .post-list > li.has-thumb { grid-template-columns: 1fr; gap: var(--sp-3); }
  .post-list__thumb { aspect-ratio: 16 / 9; }
}

/* --------------------------------------------------------------------------
   16. DOOR — the big category choices on the landing page
   -------------------------------------------------------------------------- */

.doors {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--sp-5);
  margin: var(--sp-7) 0;
  padding: 0;
  list-style: none;
}
.door {
  display: block;
  padding: var(--sp-5);
  border: 1px solid var(--rule);
  color: var(--text);
  text-decoration: none;
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.door:hover { background: var(--bg-deep); transform: translateY(-2px); color: var(--text); }
.door__name {
  font-family: var(--font-display);
  font-size: var(--fs-xl);          /* a door should read as a destination,
                                       not as a caption */
  line-height: var(--lh-snug);
  color: var(--text-strong);
  display: block;
  margin-bottom: var(--sp-2);
}
.door__blurb { font-size: var(--fs-md); color: var(--text); margin: 0; }
.door--books { border-color: var(--accent); }

/* An arrow costs nothing and says "this goes somewhere" without a word. It
   slides on hover, which is the only motion on the page. */
.door__go {
  display: inline-block;
  margin-top: var(--sp-4);
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--accent);
}
.door:hover .door__go { color: var(--accent-strong); }
.door__go::after {
  content: " \2192";
  display: inline-block;
  transition: transform var(--dur) var(--ease);
}
.door:hover .door__go::after { transform: translateX(0.25em); }

/* ONE current thing under each door: the newest essay, the coming book. The
   door is the destination; this is the reason to go through it now. Replaced
   a three-item list, which was a directory - useful, but it said nothing was
   happening. */
.door__latest {
  padding: var(--sp-5) var(--sp-5) 0;
}
.door__latest .label { display: block; margin-bottom: var(--sp-3); }
.door__latest-img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: var(--radius-photo);
  margin-bottom: var(--sp-4);
}
.door__latest-title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  line-height: var(--lh-snug);
  margin: 0 0 var(--sp-3);
}
.door__latest-title a { color: var(--text-strong); }
.door__latest-title a:hover { color: var(--accent-strong); }
.door__latest-text { color: var(--text); }

/* The older three-up list, kept for any page that still wants a directory. */
.door__list {
  list-style: none;
  margin: var(--sp-4) 0 0;
  padding: 0 var(--sp-5);
}
.door__list li + li { margin-top: var(--sp-4); padding-top: var(--sp-4);
                      border-top: 1px solid var(--rule-quiet); }
/* Picture first, then the name. A thumbnail is the fastest way to say what a
   thing is, and it is what makes these clickable rather than merely listed. */
.door__list a {
  display: grid;
  grid-template-columns: minmax(0, 4.5rem) 1fr;
  gap: var(--sp-4);
  align-items: center;
  font-family: var(--font-display);
  font-size: var(--fs-md);
  line-height: var(--lh-snug);
  color: var(--text);
}
.door__list a:hover { color: var(--accent-strong); }
.door__thumb {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-photo);
  display: block;
}
/* Trade paperback proportion, so a cover is a cover and not a crop. */
.door__thumb--book {
  aspect-ratio: 5.5 / 8.5;
  border-radius: 0;
  box-shadow: 0 1px 3px rgba(0,0,0,.30), 0 6px 14px rgba(0,0,0,.22);
}
/* The trilogy has no artwork to show before the reveal. A night tile with the
   ornament on it, NOT a grey box: a grey box reads as a broken image. */
.door__thumb--none {
  background: var(--c-night);
  border: 1px solid var(--rule);
  box-shadow: none;
  display: grid;
  place-items: center;
}
.door__thumb--none img { width: 40%; opacity: 0.8; }
.door__date { display: block; font-size: var(--fs-xs); color: var(--text-soft);
              font-family: var(--font-body); margin-top: var(--sp-1); }

/* Two deep columns, not a row of small cards. */
.doors--deep { grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); }
.doors--deep > li { display: flex; flex-direction: column; }
