/*
  BRAND STYLESHEET — first real design pass, 2026-09-15
  Replaces the earlier placeholder stylesheet now that a colour
  palette and typeface pairing exist (see
  05-visual-identity-and-architecture.md in the project root for the
  rationale behind every value below — don't change a colour or font
  here without updating that document too, so the two stay in sync).

  Palette source: kept cream + sage from Nerys's own Bluehost AI
  draft (the one visual element she'd already confirmed she likes),
  added a dusty slate blue and a muted brick red pulled from two of
  her five named reference sites, plus the warm gold label accent
  from her own draft. Five colours total, used narrowly — see the
  usage comment on each custom property below.

  Type: Noto Serif (headlines, pull-quotes, her name) + Noto Sans
  (body, nav, labels) — loaded via Google Fonts in baseof.html's
  <head>. Chosen for breadth/flexibility and free availability, per
  Chris's steer (2026-09-15) — corrected from "Nota" to "Noto," the
  actual Google Fonts family name.
*/

:root {
  /* --- Colour palette --- */
  --color-cream: #F6F1E7;        /* primary background */
  --color-ink: #2E2A24;          /* body text — warm charcoal, not pure black */
  --color-sage: #7C8B6E;         /* primary accent — buttons, dividers, small highlights */
  --color-sage-dark: #5F6C54;    /* sage darkened ~20% for hover states / accessible text-on-cream use */
  --color-blue: #5C7A8A;         /* secondary accent — cool counterweight to sage/cream warmth */
  --color-red: #A8503A;          /* tertiary accent — used sparingly: rules, quote marks, small badges only */
  --color-gold: #B8935A;         /* label accent — tiny all-caps supporting text only, never body copy or buttons */
  --color-cream-deep: #EFE7D6;   /* slightly deeper cream for card/section backgrounds that need to separate from the page background */

  /* --- Type --- */
  --font-serif: "Noto Serif", Georgia, "Times New Roman", serif;
  --font-sans: "Noto Sans", system-ui, -apple-system, sans-serif;

  /* --- Rhythm --- */
  --content-width: 42rem;
  --content-width-wide: 60rem;
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: var(--font-sans);
  line-height: 1.65;
  color: var(--color-ink);
  background: var(--color-cream);
}

/* Headings and anything meant to carry the literary/editorial voice
   use the serif; everything functional (nav, labels, body) stays
   sans, per the pairing rationale in the visual-identity doc. */
h1, h2, h3,
.hero-statement-lead,
.featured-title,
blockquote {
  font-family: var(--font-serif);
  color: var(--color-ink);
  line-height: 1.25;
}

h1 { font-size: 2.25rem; font-weight: 700; margin: 0 0 1rem; }
h2 { font-size: 1.5rem; font-weight: 600; margin: 2.5rem 0 1rem; }
h3 { font-size: 1.15rem; font-weight: 600; margin: 1.5rem 0 0.5rem; }

p { margin: 0 0 1rem; }

a {
  color: var(--color-sage-dark);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
}

/* LINKS, strengthened 2026-09-25. Chris: "perhaps the links could be
   a bit more apparent?" They were sage text with a hairline underline
   on a cream page, which at body size is close to invisible.
   Half a weight heavier, a 2px underline in a lightened sage so it
   reads as a rule rather than a scribble, and the offset kept so
   descenders are not struck through. */
a {
  font-weight: 500;
  text-decoration-thickness: 2px;
  text-decoration-color: color-mix(in srgb, var(--color-sage) 50%, transparent);
  transition: color 120ms ease, text-decoration-color 120ms ease;
}

/* Hover moved off blue on the same date, because blue now means the
   podcast in the featured pair and a colour should mean one thing.
   Red is the palette's sparing accent and a hover is momentary, which
   is exactly the budget red has. */
a:hover,
a:focus-visible {
  color: var(--color-red);
  text-decoration-color: currentColor;
}

/* Structural links are not body links: nav, buttons and whole-tile
   links set their own treatment and must not inherit the underline or
   the extra weight. */
.site-nav a,
.btn,
.portfolio-link,
.skip-link {
  font-weight: inherit;
  text-decoration-thickness: initial;
}

/* --- Header / nav --- */

/* The header is a full-width band; the inner wrapper holds the title and
   nav to the same measure as the page content. Splitting the two is what
   lets a rule or a tint span the viewport instead of stopping at 60rem
   and floating in the middle of the page.

   HEIGHT: 73px at desktop sizes, which is not an arbitrary number — it is
   exactly the distance from the top of the screen to the top of the
   photograph on the home page, and it is already identical on every page.
   The band was always this tall; until now there was simply nothing to
   see. If the vertical padding below changes, that relationship changes
   with it. */
.site-header {
  background: var(--color-cream);
}

.site-header-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.25rem 1.5rem;
  max-width: var(--content-width-wide);
  margin: 0 auto;
}

/* Treatment one: a hairline along the bottom edge.
   The rule is ink at low opacity rather than one of the palette colours.
   --color-cream-deep, the obvious candidate, is only a few values away
   from the page background and reads as a printing flaw at 1px; sage or
   gold at full strength read as decoration rather than structure. A faint
   ink line is the one that looks like a deliberate rule. */
.site-header--keyline {
  border-block-end: 1px solid rgba(46, 42, 36, 0.14);
}

/* Treatment two: a shift in tone, no rule. Separates by surface rather
   than by line, which is quieter on the home page where the band meets a
   photograph rather than a field of cream. */
.site-header--tone {
  background: var(--color-cream-deep);
}

.site-title {
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: 1.25rem;
  color: var(--color-ink);
  text-decoration: none;
}

/* The home page's h1 wraps the site title (see partials/header.html).
   It exists to give that page a top-level heading; it must not change
   how the header looks, so it inherits everything and carries no
   margin of its own. */
.site-title-heading {
  margin: 0;
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
}

.site-header nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  list-style: none;
  padding: 0;
  margin: 0;
  font-family: var(--font-sans);
  font-weight: 500;
  letter-spacing: 0.02em;
}

.site-header nav a {
  color: var(--color-ink);
  text-decoration: none;
  padding-bottom: 0.15rem;
  border-bottom: 2px solid transparent;
}

.site-header nav a:hover,
.site-header nav a:focus-visible {
  border-bottom-color: var(--color-sage);
  color: var(--color-ink);
}

/* --- Home page hero --- */
/* Design Option A from the reference-sites research: a single large,
   candid photo of Nerys as the entire hero, with her own words
   overlaid directly on it rather than a separate graphic. Photo choice
   (the wooden-door shot) is a first pass — swap freely once more
   photos or her own preference are in hand. */

.hero {
  position: relative;
  /* Clips the oversized wordmark below. This is the one legitimate use
     of overflow on this page: the wordmark is deliberately larger than
     the frame, so trimming it is the design, not a patch over a
     layout bug. */
  overflow: hidden;
  /* TIGHTER, 2026-10-05 (Chris): 640px down to 560. Two things happen at
     once and that is the point. The frame crops 80px higher off the
     bottom of the photograph, which is bench and paving rather than
     her. And because the wordmark is anchored to the bottom edge while
     the statement is centred in the frame, closing the frame by 80
     moves the wordmark up 80 and the statement up 40, so the gap
     between the subhead's last line and the top of the wordmark halves
     — which is the second half of what he asked for, with no second
     adjustment needed. Measured after: 72px becomes 32 at 1280. */
  min-height: min(72vh, 560px);
  display: flex;
  /* Was flex-end when the hero held her name; centred now that it
     holds the statement, so the text sits in the frame rather than
     hugging the bottom edge. */
  align-items: center;
  /* The photograph is an <img> since 2026-09-29 — see the note in
     layouts/index.html. What is left here is the frame it sits in. */
  margin-bottom: 3rem;
}

/* The photograph fills the frame and sits behind everything. Absolute
   rather than in flow, so the hero's height is still set by its
   min-height and its content, exactly as when this was a background. */
.hero-image {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  /* She sits lower in this frame than the figure in the old door shot.
     The mobile crop needs no equivalent: its framing is in the file. */
  object-position: center 38%;
}

/* THE SCRIM. A background gradient stacked over a background image for
   free; an <img> needs a layer of its own. Over the photograph, under
   the text.

   Values unchanged, and chosen the same way: this frame is backlit,
   with a blown-out sky behind her that the cream statement was sitting
   on top of at a lighter setting. Raised until the lightest part of
   the picture still clears 4.5:1 against the text. Re-check if the
   photograph is ever swapped. */
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(rgba(46, 42, 36, 0.62) 0%, rgba(46, 42, 36, 0.78) 100%);
}

/* Above the photograph and the scrim. Without this the content is
   painted first and the scrim covers it — which is what happened to
   the wordmark on the first pass: it has z-index 0 of its own, so it
   sat under the new ::after layer and all but vanished. When the scrim
   was part of background-image it was painted below every child for
   free; as a pseudo-element it is not, and anything meant to be seen
   through it has to say so. */
.hero-inner { position: relative; z-index: 1; }

.hero-inner {
  max-width: var(--content-width-wide);
  margin: 0 auto;
  padding: 3rem 1.5rem;
  width: 100%;
}

/* The brand statement, overlaid on the hero photo (2026-09-21).
   Two tiers — large first sentence, smaller second — is Nerys's own
   specified treatment, not a design choice. The sizes below are the
   only thing enforcing it, so keep the ratio if you retune them.

   Both tiers use clamp() rather than breakpoints so the statement
   scales continuously with the viewport instead of jumping at
   arbitrary widths. The middle (vw) value does the work; the first
   and last stop it from becoming unreadably small on a phone or
   absurdly large on a desktop monitor. */

/* Oversized low-opacity wordmark behind the statement (2026-09-21).
   Anchored to the bottom-left of the hero rather than centred, so it
   never sits directly behind the statement's own text — cream letters
   under cream letters would cost legibility even at this opacity, and
   the statement has to stay the readable thing.

   Opacity is the whole brief ("there, but not overpowering"): 0.14 is
   visible as texture against the scrim without competing. It is the
   first value to retune if it reads too strong or too faint.

   pointer-events: none so it can never intercept a click or a text
   selection meant for the statement above it. */
.hero-wordmark {
  position: absolute;
  inset-inline-start: 0;
  inset-block-end: -0.12em;      /* Sink the descender below the frame. */
  /* Raised from 0 to 1 on 2026-09-29, when the scrim moved out of
     background-image and into .hero::after. As a background it was
     painted below every child for free; as a pseudo-element it is
     painted above anything that does not out-rank it, and at z-index 0
     the wordmark all but vanished under it. */
  z-index: 1;
  font-family: var(--font-serif);
  font-weight: 700;
  /* Sized by the frame, not by taste: at this weight "Nerys Parry" is
     about 6.06x its font-size wide, so the rendered text is roughly
     6.06 x 0.15 = 91% of the viewport. That leaves a 9% gutter at the
     right edge at every width — measured at 520, 768, 1024, 1280 and
     1600px, not guessed.
     Raised from 14vw on 2026-09-29 so the wordmark reads more clearly.
     16vw is where it stops working: that puts the text at 97% of the
     frame, close enough to the right edge to look like a mistake rather
     than a margin. Going bigger than that needs a decision to let it
     bleed off the edge deliberately.
     The rem cap stops it running away on very wide monitors. */
  font-size: clamp(4.5rem, 15vw, 13.5rem);
  line-height: 0.9;
  white-space: nowrap;
  color: #FBF8F1;
  /* 0.17, down from the 0.22 approved on 2026-09-29 — Chris, on the
     last pass before launch: "decrease the opacity of Nerys Parry in
     the hero banner." 0.22 was itself chosen from 0.14, 0.18 and 0.22
     compared over the actual photograph, so this sits just under the
     middle of that range: still legible as a name on the photograph's
     lighter passages, no longer competing with the statement set over
     it. This one line and its phone counterpart below are the whole
     control; nothing else depends on the value. */
  opacity: 0.17;
  pointer-events: none;
  user-select: none;
}

.hero-inner {
  /* Sits above the wordmark. Without this the statement would render
     underneath it in paint order, since both are children of .hero. */
  position: relative;
  z-index: 1;
}

.hero-statement {
  max-width: 34rem;
}

.hero-statement-lead {
  color: #FBF8F1;
  font-size: clamp(2rem, 5vw, 3.25rem);
  font-weight: 600;
  line-height: 1.15;
  margin: 0 0 1rem;
  /* Text sits on a photograph, so a soft shadow guarantees legibility
     over the lighter areas of the image even though the scrim above
     already darkens it. Belt and braces: the photo can be swapped at
     any time and the next one may be brighter. */
  text-shadow: 0 1px 12px rgba(20, 18, 15, 0.55);
}

.hero-statement-support {
  color: #FBF8F1;
  font-family: var(--font-sans);
  font-size: clamp(1rem, 1.8vw, 1.25rem);
  font-weight: 400;
  line-height: 1.5;
  margin: 0;
  text-shadow: 0 1px 10px rgba(20, 18, 15, 0.55);
}

/* --- Home page: who she is --- */
/* The descriptor line is the single change she asked for most
   directly. It is set larger than body copy and in the serif so it
   reads as a statement of fact about her rather than as the first
   line of a paragraph someone might skim past. */

/* Full-bleed tinted band. The section spans the viewport so the
   colour change is unmissable; the inner wrapper keeps the text on
   the same measure as everything else on the page. */
/* No background tint since 2026-10-05, when this moved from the foot of
   the page to directly under the hero. The tint existed to make a block
   at the bottom get noticed; up here, under a full-bleed photograph, a
   second full-width band of colour reads as another header. Plain text
   on the cream is quieter and does the job the position already does.

   The top padding is larger than the bottom so the line sits away from
   the photograph above it and close to the covers it introduces. */
/* THE STATEMENT, 2026-10-05.

   Three changes, all Chris's: it sets the page's left axis, it carries
   more weight as a piece of design, and it stands further off the
   covers beneath it.

   THE LEFT AXIS is the structural one. Before this, three different
   left edges ran down the page — the hero at 160px, the covers and
   quotes at 184, and this block at 304, because it was centred inside
   the narrow reading measure while everything else used the wide band.
   The odd one out was the first thing under the photograph, which is
   exactly where an axis gets established. It now uses the same wide
   container and the same 1.5rem gutter as .featured-panels, so its left
   edge and the left edge of the Haunted panel are the same line.

   The paragraph itself is held to a measure while the container sets
   the axis — see the note on max-width below for why that measure is
   44rem and not the 34 it started at. */
.home-about {
  margin: 0;
  /* Bottom padding does the separating Chris asked for. At 1.75rem the
     "More about me" link sat 44px off the covers and still read as
     attached to them; at 3.5rem it is 88px and the block closes.
     NO HORIZONTAL PADDING HERE: the gutter belongs inside the measured
     container below, exactly as .featured-panels does it. Putting it on
     this full-bleed element instead shifts the centred inner box and
     lands the text 24px to the LEFT of the covers — which is what the
     first attempt at this did. */
  padding: 3rem 0 3.5rem;
}

.home-about-inner {
  max-width: var(--content-width-wide);
  margin: 0 auto;
  padding: 0 1.5rem;
}

.home-descriptor {
  font-family: var(--font-serif);
  /* Raised from clamp(1.2rem, 2.2vw, 1.5rem). At the old size this read
     as a caption under the photograph rather than a statement in its
     own right, which is what it is. */
  font-size: clamp(1.4rem, 2.6vw, 1.85rem);
  /* ITALIC, 2026-10-05, Chris's suggestion and the right one. It marks
     the sentence as her voice rather than page furniture, and the site
     already sets Haunted's subtitle and every quote attribution in
     italic, so it is a tone the page knows. Delete this one line to go
     back to roman; nothing else depends on it. */
  font-style: italic;
  line-height: 1.35;
  /* 44rem rather than 34: measured, because the line count is what was
     being asked for and not the width. At 34, 36, 38, 40 and 42rem this
     sets as four lines; 44 is the first that gives three. The echo of
     .hero-statement's 34rem is lost, which is a real cost, but a
     statement that breaks cleanly in three beats an alignment nobody
     sees. */
  max-width: 44rem;
  /* text-wrap: balance evens the rag across three lines instead of
     leaving a short last one. Progressive: browsers without it wrap as
     before, which is merely less tidy. */
  text-wrap: balance;
  margin: 0 0 1.25rem;
}

/* The flourish: a short gold rule above the statement. Gold is already
   the site's label colour — the small caps over each featured panel use
   it — so this marks the line as a piece of furniture in a vocabulary
   the page has, rather than introducing a fourth kind of decoration. A
   bordered box was rejected for that reason in September and still is.

   ::before on the paragraph rather than its own element, so there is
   nothing for a screen reader to announce. */
.home-descriptor::before {
  content: "";
  display: block;
  inline-size: 3rem;
  block-size: 2px;
  background: var(--color-gold);
  margin-block-end: 1.25rem;
}

.home-lede {
  font-size: 1.05rem;
  margin: 0 0 1.25rem;
  color: var(--color-ink);
}

.home-about-more a {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
}

/* --- Featured pair: Haunted and the novel, equal weight --- */
/* Her request, verbatim: "Haunted on the Left with a CTA to sign up
   for news, with the book on the right, with a CTA to buy, each given
   equal weight."

   auto-fit + minmax gives two equal 1fr columns whenever there is room
   for two ~20rem tracks, and drops to a single column when there is
   not — without a media query, so there is no invented breakpoint to
   get wrong. min(20rem, 100%) is the guard that stops the track's
   minimum from overflowing a viewport narrower than 20rem. */

/* RENAMED FROM .featured-pair 2026-10-05, when the pair became three:
   the blog, the podcast and the novel.

   THE TRACK MINIMUM DROPPED FROM 20rem TO 17rem on the same day, and
   the number is not arbitrary. The container is 60rem less two 1.5rem
   gutters, so 57rem of track; three columns need two 2.5rem gaps, which
   leaves 52rem, which is 17.33rem each. At the old 20rem minimum
   auto-fit could only place two and the third dropped to its own row,
   leaving a half-empty line across the widest part of the page.

   Nothing else changes with the count. auto-fit still collapses to two
   columns and then to one as the viewport narrows, and 1fr still makes
   every column exactly as wide as its neighbours, which is the "equal
   weight" Nerys asked for. min(17rem, 100%) is the guard that stops the
   track minimum overflowing a viewport narrower than 17rem. */
.featured-panels {
  max-width: var(--content-width-wide);
  margin: 0 auto 3.5rem;
  padding: 0 1.5rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
  gap: 2.5rem;
}

/* ONE PANEL ON ITS OWN, which is what the Work page shows. Left alone
   it would stretch a single blurb across the full 57rem and set it in
   lines nobody can track back to the start of. Capped at 28rem it keeps
   roughly the width it has when it stands beside its neighbours
   elsewhere, so the blog panel looks like the same object on all three
   pages rather than a different, larger one here. */
.featured-panels:has(> .featured-item:only-child) {
  grid-template-columns: minmax(0, 28rem);
}

/* TWO ROWS, NOT THREE, since 2026-10-05. The subgrid still aligns the
   pictures across a row; what it no longer does is align the buttons.

   It used to. Each item was image / body / actions, the body row took
   1fr, and every button was pushed to the bottom of the tallest panel
   so they all sat on one line. That read well with two panels of
   similar length and broke as soon as a short one joined them — the
   blog panel's button floated a long way below its own last line in
   order to keep station with the novel's. Chris: "need to have the link
   button directly underneath the text like in the Novel text where the
   button comes under the publisher's name and date." The alignment was
   between panels, and a panel is read down rather than across.

   So the body and the actions now share the second row inside
   .featured-stack, and panel bottoms end up ragged. "Equal weight",
   which is what Nerys asked for, still holds: the columns are exactly
   as wide as each other, the pictures line up, and no panel is dressed
   more prominently than another.

   The plain grid-template-rows line immediately before the subgrid one
   is a same-cascade fallback: a browser without subgrid support keeps
   the sensible stack and simply loses the picture alignment. */
.featured-panels { grid-auto-rows: auto; }

.featured-item {
  display: grid;
  grid-row: span 2;
  grid-template-rows: auto auto;
  grid-template-rows: subgrid;
  gap: 1rem;
}

/* The second subgrid row. align-content: start keeps the text and the
   button at the top of whatever height the row takes from the longest
   panel in it, rather than stretching to fill it — which would put the
   gap straight back. */
.featured-stack {
  display: grid;
  align-content: start;
  gap: 1rem;
}

/* ------------------------------------------------------------------
   THE INLINE VARIANT (2026-10-05) — the Work page.
   Chris: "make the NerVan-ah mention on the Work page similar to the
   services presented above it."

   On that page the panel is not a card beside other cards; it is the
   last block in a column of four services. In the default dress it sat
   in the 60rem band while the services sit in the 42rem measure, so the
   two had different left edges and the panel read as something imported
   from another page.

   THE WIDTH IS 42rem LESS 3rem, not 42rem. article.page is 42rem wide
   with 1.5rem of padding each side, so its text column is 39rem. This
   section carries no padding of its own and is 39rem, which lands its
   left edge and the keyline above it exactly on the services' own.
   ------------------------------------------------------------------ */
.featured-panels--inline {
  /* Both lines are needed. The max-width holds the block to the
     services' 39rem column on a wide screen; the width keeps it
     shrinking with the viewport the way article.page's own padding
     does, so the two stay on one axis at every width rather than only
     above 42rem. */
  width: calc(100% - 3rem);
  max-width: calc(var(--content-width) - 3rem);
  padding-inline: 0;
  /* The same rule the services use to separate one from the next, so
     this block is separated from the last of them in the same way. */
  border-block-start: 1px solid
    color-mix(in srgb, var(--color-sage) 40%, var(--color-cream-deep));
  padding-block-start: 2.25rem;
}

/* The single-panel cap is for a panel standing on its own in the wide
   band. Here the column IS the measure, so the panel fills it like
   every other block on the page. */
.featured-panels--inline:has(> .featured-item:only-child) {
  grid-template-columns: minmax(0, 1fr);
}

/* The coloured tick marks one card out from its neighbours. There are
   no neighbours here, and the services it now sits among carry nothing
   like it. */
.featured-panels--inline .featured-body::before {
  display: none;
}

/* The services' own heading size, so this reads as the next one of them
   rather than as a headline. */
.featured-panels--inline .featured-title {
  font-size: 1.3rem;
}

/* THE PICTURE GOES BESIDE THE TEXT, not above it (Chris, 2026-10-05):
   "put the photo to the right of the text so instead of 3 lines, the
   text runs 5-6 lines."

   Stacked, the blurb had the whole 39rem measure and set in three very
   long lines with a tall photograph above them — which is the shape of
   a card, not of the service blocks this now sits among. Beside it, the
   text column is 22rem (39 less the picture's 15 and a 2rem gutter), the
   blurb runs to five or six lines, and the block is about as tall as the
   picture instead of twice it.

   THE PICTURE IS SECOND IN THE MARKUP and placed in the second column
   explicitly, so the reading order a screen reader follows is unchanged
   from the stacked layout. align-self: start keeps it at the top of the
   row rather than stretching to the text's height.

   THE NUMBERS. The picture takes 20rem rather than the 15 it gets in a
   card, and a 2rem gutter leaves the text 17rem of the 39. That is what
   produces five or six lines: the blurb is 158 characters, it set four
   lines at 22rem, and 17rem is the width that lands it where Chris
   asked. The picture being larger is a bonus on a page where it is the
   only one.

   ONLY ABOVE 46rem. Below that the two columns do not fit, and the item
   falls back to the stacked layout every other panel uses. */
@media (min-width: 46rem) {
  .featured-panels--inline .featured-item {
    /* Out of the parent's subgrid: one row, two columns of its own. */
    grid-row: auto;
    grid-template-rows: auto;
    grid-template-columns: minmax(0, 1fr) 20rem;
    column-gap: 2rem;
  }

  .featured-panels--inline .featured-stack {
    grid-column: 1;
    grid-row: 1;
  }

  .featured-panels--inline .featured-image {
    grid-column: 2;
    grid-row: 1;
    max-inline-size: 20rem;
    align-self: start;
  }
}

.featured-image {
  inline-size: 100%;
  /* Cap the width rather than letting the image fill the whole column.
     At a 3:4 ratio a full-column image is roughly 490px tall on a
     desktop, which made the two empty placeholder panels the largest
     thing on the page — and will make the real covers oversized too.
     A book cover reads fine at this size and leaves the copy beneath
     it room to be the point. */
  max-inline-size: 15rem;
  block-size: auto;
  /* Reserve the space before the asset loads so nothing jumps. */
  aspect-ratio: 3 / 4;
  /* `contain`, not `cover`. Everything that goes in these slots is a
     cover or a screenshot, and cropping a book cover cuts the title
     off. Covers come in inconsistent proportions (the Queen's
     Quarterly one is nearer 2:3 than 3:4), so the deep-cream backdrop
     fills whatever the image does not, rather than the image being
     trimmed to fit the box. */
  object-fit: contain;
  background: var(--color-cream-deep);
  display: block;
  border-radius: 2px;
}

/* Placeholder panel shown where we do not have the artwork yet (the
   Haunted cover and the book cover, both outstanding). Dashed border
   and muted label so it reads unmistakably as "not done yet" rather
   than as a design element — Nerys is reviewing this page and should
   not have to ask which boxes are real. */
/* A DESIGNED PANEL, not a placeholder. Added 2026-09-25.

   The dashed boxes above mean "asset outstanding". This one means the
   opposite: there is no image and there never will be, because the tile
   points at a 2006 text article. Sharing the dashed treatment would
   leave a finished tile looking permanently unfinished, so this reads
   as a title page instead — solid ground, the publication set in the
   serif at a size that can actually be read at 12rem, and a short rule
   under it borrowed from the labels elsewhere on the site.

   It has to hold its own beside a magazine cover and a screenshot in
   the same row, which is why it is typographic rather than another
   bordered box: on a page already using rules and dashes, a fourth
   kind of border reads as clutter. */
/* DOUBLED CLASS ON PURPOSE. The base .portfolio-image rule is declared
   further down this file and sets display: block, so at equal
   specificity it was winning and the panel was never actually a grid —
   which silently killed the ::after rule below, since a pseudo-element
   is only blockified inside a grid or flex container. Naming both
   classes lets the modifier beat the base wherever either ends up in
   the file. */
.portfolio-image.portfolio-image--panel {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 0.75rem;
  padding: 1rem 0.9rem;
  text-align: center;
  background: var(--color-cream-deep);
  color: var(--color-ink);
  font-family: var(--font-serif);
  /* Fluid within the tile rather than fixed: these tracks range from
     10rem to 12rem, and a fixed size that suits one end looks wrong at
     the other. Container query units would be the natural tool, but
     that would mean making every tile a container for one panel. */
  font-size: clamp(0.95rem, 1.6vw, 1.15rem);
  line-height: 1.25;
  text-wrap: balance;
}

/* The rule sits on the panel rather than on the text, so it appears
   under a wordmark and under typeset text alike — the two treatments
   have to look like siblings when they end up in the same row. */
.portfolio-image.portfolio-image--panel::after {
  content: "";
  inline-size: 2rem;
  block-size: 2px;
  background: var(--color-gold);
}

/* A masthead is a wide, short thing dropped into a tall box, so it is
   held well short of the tile's full width — filling the width would
   leave a thin strip stranded in a lot of empty ground and read as a
   mistake. Capped in rem rather than a percentage so it stays the same
   physical size whether the track is 10rem or 12rem, which keeps it
   from growing conspicuously larger than the type it sits beside. */
.portfolio-panel-logo {
  inline-size: 100%;
  max-inline-size: 8.5rem;
  block-size: auto;
  display: block;
  /* Belt and braces: the grid centres it, and this centres it too if
     the panel ever falls back to a block container. */
  margin-inline: auto;
}

.featured-image--placeholder,
.portfolio-image--placeholder {
  display: grid;
  place-content: center;
  padding: 1rem;
  text-align: center;
  background: var(--color-cream-deep);
  border: 2px dashed var(--color-sage);
  color: var(--color-sage-dark);
  font-family: var(--font-sans);
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.featured-body { margin: 0; }

/* ACCENT RULE, 2026-09-25. A short coloured tick at the head of each
   panel's text — sage for the blog, blue for the podcast, gold for the
   novel. The panels are identical in dress and a reader could not tell
   a forthcoming broadcast from a published book from a running blog
   without reading all of them. The colour comes from a custom property
   set on the item in layouts/partials/featured-panels.html, which is
   why the third panel in 2026-10-05 was a line of data rather than a
   new rule here.

   ALL THREE ACCENTS ARE BELOW THE 4.5:1 that small text wants against
   this ground — gold measures 2.3:1, blue 4.1:1, sage 3.2:1. That is
   one decision about the whole set rather than three, and it is open:
   the tick itself is decoration and fine, but .featured-label borrows
   the same colour for 0.72rem type, which is where it bites. */
.featured-body::before {
  content: "";
  display: block;
  inline-size: 2.5rem;
  block-size: 3px;
  background: var(--accent, var(--color-gold));
  margin-block-end: 0.9rem;
}

.featured-label {
  font-family: var(--font-sans);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent, var(--color-gold));
  margin: 0 0 0.4rem;
}

.featured-title {
  font-size: clamp(1.5rem, 3vw, 2rem);
  margin: 0 0 0.6rem;
}

/* The Haunted hook line. Serif and italic so it reads as a line of
   promotional copy rather than as the first sentence of the
   description, which follows it immediately underneath. */
.featured-tagline {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 1.05rem;
  line-height: 1.4;
  color: var(--color-sage-dark);
  margin: 0 0 0.6rem;
}

.featured-blurb {
  margin: 0;
  font-size: 1.02rem;
}

/* Small status line under a blurb (currently the podcast air date).
   Muted and sans, so it reads as metadata rather than as more copy. */
.featured-meta {
  font-family: var(--font-sans);
  font-size: 0.88rem;
  color: var(--color-sage-dark);
  margin: 0.4rem 0 0;
}

.featured-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.25rem;
}

.featured-secondary {
  font-family: var(--font-sans);
  font-size: 0.9rem;
}

/* --- Buttons --- */
/* One button style, used by both calls to action, because "equal
   weight" means neither may look more clickable than the other. */

.btn {
  display: inline-block;
  padding: 0.7rem 1.4rem;
  background: var(--color-sage);
  color: #FBF8F1;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  text-decoration: none;
  border-radius: 0.25rem;
}

.btn:hover,
.btn:focus-visible {
  background: var(--color-sage-dark);
  color: #FBF8F1;
}

/* --- Portfolio grid (Work page) --- */
/* Outbound credential tiles. Same auto-fit approach as the featured
   pair, but with a smaller minimum so the row count adapts to however
   many tiles are live — which changes as Nerys sends missing links,
   so a fixed column count would need editing every time. */

/* TINTED BAND, 2026-09-25. This used to be a hairline rule on a cream
   page, separating the services list from the published-work row —
   two different claims, what she offers and who has published her.
   A hairline is the weakest available way to say that. A full-bleed
   change of ground says it without a rule, and gives the Work page a
   second beat instead of running as one unbroken sheet.

   Full-bleed outside, measure inside, the same shape as the home
   page's descriptor band. */
.portfolio {
  background: var(--color-cream-deep);
  margin-block: 3rem 0;
  padding-block: 0.5rem 3rem;
}

.portfolio-inner {
  max-width: var(--content-width-wide);
  margin-inline: auto;
  padding-inline: 1.5rem;
}

.portfolio h2 {
  margin-top: 0;
  padding-top: 2.5rem;
}

/* On the tinted ground the relationship inverts: panels and
   placeholders that were cream-deep cards on cream now have to be
   cream cards on cream-deep, or they vanish into the band. */
.portfolio .portfolio-image,
.portfolio .portfolio-image--placeholder,
.portfolio .portfolio-image.portfolio-image--panel {
  background: var(--color-cream);
}

.portfolio-grid {
  list-style: none;
  padding: 0;
  margin: 1.5rem 0 0;
  display: grid;
  /* Tracks are bounded at BOTH ends — min 10rem, max 14rem — rather
     than the usual `1fr` maximum. With `1fr` the four current tiles
     stretched to fill the full 60rem width, producing three enormous
     tiles on one row and a lonely fourth on the next. Capping the
     track keeps tiles at a sane thumbnail size and lets four sit in a
     row, and the count will re-flow on its own as Nerys sends the
     three missing links. */
  grid-template-columns: repeat(auto-fit, minmax(min(10rem, 100%), 12rem));
  /* Without this the bounded tracks would be centred in the leftover
     space; tiles should start at the left edge, aligned with the
     heading above them. */
  justify-content: start;
  gap: 1.75rem;
}

/* THREE ROWS: the picture, the context label, then the title and the
   publication line together.

   WHAT THE SUBGRID ALIGNS across a row is the pictures, the labels and
   the point where every title starts. What it deliberately does NOT
   align, since 2026-10-05, is the publication lines: aligning those
   forced a one-line title to sit a long way from its own meta so that
   it could line up with a three-line title two tiles over. That
   alignment is between tiles, and a tile is read down rather than
   across. So the title and its meta share the last row and tile
   bottoms end up ragged, which is the right trade.

   THE LABEL EARNED A ROW OF ITS OWN for the opposite reason: it is one
   line on most tiles and two on "Employee Magazine Production", and
   inside the text block that second line would have pushed one tile's
   title below its neighbours'. In its own row the extra line grows the
   row for everyone and the titles stay in step. */
.portfolio-tile {
  display: grid;
  grid-row: span 3;
  grid-template-rows: auto auto auto;
  grid-template-rows: subgrid;
}

/* Two wrappers, one layout. A tile is an <a> when it has somewhere to
   go and a <div> when it does not (see portfolio-grid.html). They share
   every layout rule here; what they do NOT share is the hover and focus
   treatment further down, which stays on .portfolio-link alone. A plate
   that lit up under the cursor would be promising a click it cannot
   honour. */
.portfolio-link,
.portfolio-plate {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
  gap: 0.5rem;
  text-decoration: none;
  color: var(--color-ink);
}

.portfolio-image {
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: 3 / 4;
  /* Same reasoning as .featured-image above — never crop a cover. */
  object-fit: contain;
  background: var(--color-cream-deep);
  display: block;
  border-radius: 2px;
  /* Transition is on the image, not the whole tile, so the text never
     shifts on hover — movement under the cursor makes a link feel
     unstable and hurts anyone with a tremor or a trackpad. */
  transition: opacity 150ms ease;
}

.portfolio-link:hover .portfolio-image,
.portfolio-link:focus-visible .portfolio-image {
  opacity: 0.82;
}

/* Photographs fill the tile instead of letterboxing. Opt-in per tile
   (fit: "cover" in data/portfolio.yaml) because the default has to
   stay `contain` for covers, which must never be cropped. */
.portfolio-image--cover {
  object-fit: cover;
  background: none;
}

/* THE EYEBROW, 2026-10-05. The same shape as .featured-label on the
   home page - sans, semibold, small, tracked, set in capitals - but
   NOT the same colour.

   .featured-label is gold, and gold measures 2.3:1 against this band's
   cream-deep ground. Small text needs 4.5:1. One label on the home
   page is a question for another day; nine of them at once is not the
   place to repeat it. Sage-dark measures 4.5:1 and is already the
   palette's answer for supporting text on cream. If the gold is wanted
   back for the match with the home page, it is this one line.

   The capitals and the tracking are what separate the label from the
   publication line below it, which shares the colour. */
.portfolio-context {
  font-family: var(--font-sans);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  line-height: 1.35;
  text-transform: uppercase;
  color: var(--color-sage-dark);
}

/* The last subgrid row. align-content: start keeps the pair at the
   top of whatever height the row takes from the tallest title in it,
   rather than stretching to fill it — which would reintroduce the gap
   this change exists to remove. */
.portfolio-text {
  display: grid;
  align-content: start;
  gap: 0.35rem;
}

.portfolio-title {
  font-family: var(--font-serif);
  font-size: 1.05rem;
  line-height: 1.3;
}

.portfolio-link:hover .portfolio-title,
.portfolio-link:focus-visible .portfolio-title {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.portfolio-meta {
  font-family: var(--font-sans);
  font-size: 0.85rem;
  color: var(--color-sage-dark);
}

/* --- Service blocks (Work page) --- */
/* Her services arrived as a heading, a paragraph and a list of
   sub-offerings each, which is a richer structure than the single bold
   line the page carried before. These rules give each service room to
   read as its own block rather than as four paragraphs in a row.

   Scoped to h3 because the Work page is the only page using that level:
   About and Privacy stop at h2. If another page ever introduces an h3
   this will need a page-scoped class instead. */

article.page h3 {
  font-size: 1.3rem;
  margin-block-start: 2.75rem;
}

/* ------------------------------------------------------------------
   PORTFOLIO VIDEO BADGE (2026-10-05)
   Marks the three tiles that play rather than read, so a reader knows
   before clicking. See the note in partials/portfolio-tile-body.html
   for why a glyph and not the word.
   ------------------------------------------------------------------ */

/* The positioning context. Wraps the image or the panel in every tile,
   not only the video ones, so the two cases cannot drift apart. */
.portfolio-media {
  position: relative;
  display: block;
}

.portfolio-badge {
  position: absolute;
  /* Bottom-left rather than centred: centred reads as "press here to
     play", which is wrong — the tile opens YouTube in a new tab, it
     does not play in place. A corner badge labels; a centre button
     promises. */
  inset-block-end: 0.4rem;
  inset-inline-start: 0.4rem;
  display: block;
  line-height: 0;
  /* The disc is light and some stills are light too, so a soft dark
     halo keeps the badge legible on any frame without a hard outline. */
  filter: drop-shadow(0 1px 2px rgba(46, 42, 36, 0.55));
}

.portfolio-badge-disc {
  fill: rgba(246, 241, 231, 0.94);
}

.portfolio-badge-arrow {
  fill: var(--color-ink);
}

/* A hairline above every service except the first, so the four read as
   separate offerings rather than one continuous run of text.

   DARKENED 2026-10-05 (Chris). At plain --color-cream-deep the line was
   barely a tint against the cream page and did not do the dividing it
   was there for. Mixing sage into it keeps the line inside the palette
   — a grey rule would be the first neutral on the site — while making
   it something a reader actually sees. */
article.page h3 ~ h3 {
  border-block-start: 1px solid
    color-mix(in srgb, var(--color-sage) 40%, var(--color-cream-deep));
  padding-block-start: 2.25rem;
}

/* ------------------------------------------------------------------
   WORK PAGE (2026-10-05)
   ------------------------------------------------------------------ */

/* The line under the photograph is the page's opening sentence, and it
   was setting as ordinary body copy directly beneath a large image,
   where it read as neither caption nor lede. Chris asked for italics;
   it gets the hook-line treatment the site already has — serif italic
   in the muted sage, the same as the podcast's line on the About page
   and Haunted's on the home page — so the three pages introduce
   themselves in one voice rather than three.

   For plain italic body copy instead, drop everything here but
   font-style. */
article.page--work .page-photos + p {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 1.05rem;
  line-height: 1.4;
  color: var(--color-sage-dark);
}

/* Services is the only h2 on this page and it introduces the four
   offerings rather than heading a block of prose, so it behaves like a
   section title: larger, and sitting close to the first service rather
   than floating between them. The gap after it goes from 0.6rem to
   0.1rem — "significantly reduce" was the ask — and the first h3 below
   it has its own 2.75rem top margin, which is what the negative-looking
   closeness is actually made of. */
article.page--work h2 {
  font-size: clamp(1.75rem, 3.2vw, 2.15rem);
  margin-block-end: 0.1rem;
}

article.page--work h2 + h3 {
  margin-block-start: 1.25rem;
}

article.page h3 + p {
  margin-block-start: 0.5rem;
}

/* The sub-offering lists. Tighter than default so a five-item list
   reads as a set of related things rather than a long scroll. */
article.page ul {
  margin: 0.9rem 0 1rem;
  padding-inline-start: 1.15rem;
}

article.page ul li {
  margin-block-end: 0.25rem;
}

/* --- Page photos (Work, Contact) --- */
/* A row of one or two photographs, set from each page's own front
   matter. Same auto-fit pattern as the featured pair: two side by side
   when there is room, stacked when there is not, and no invented
   breakpoint either way. Both files are normalised to 4:3 when they
   are generated, so a landscape and a portrait original still sit as
   equal tiles here rather than one being half the height of the other. */

/* NO max-width and NO horizontal padding here, deliberately.
   FIXED 2026-09-25 — Chris: "Shouldn't the left and right edges of the
   photo line up with the text margins?" They should, and they did not.

   This row sits INSIDE article.page, which already applies both the
   42rem measure and 1.5rem of side padding. Repeating them here meant
   the max-width never bound (the parent's content box is narrower than
   it anyway) while the padding applied twice, insetting every photo
   1.5rem further than the paragraph above it on each side. The row now
   simply fills its parent's content box, so an image's edges land on
   the same line as the text.

   The corollary: a single photo is now exactly the width of the prose
   and needs no special case, which is why .page-photos--single is gone.

   Tracks: 14rem minimum with a 1fr maximum. One photo takes the full
   column; two share it at about 19rem each. The old comment here said
   18rem tracks could not fit — that was true only while the double
   padding was eating 3rem of the row. */
.page-photos {
  margin-block: 2.5rem 1rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
  gap: 1.25rem;
}

.page-photos img {
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
  border-radius: 2px;
}

/* --- Click-to-load video embeds --- */
/* Nothing from YouTube is fetched until the button is pressed — see
   layouts/shortcodes/youtube.html. These rules style the poster, the
   play control, and the iframe that replaces them. */

.video-embed {
  max-width: var(--content-width);
  margin: 2rem auto;
  padding: 0;
}

/* The home page's trailer, held to the reading measure rather than the
   wide one: a full-bleed video directly under the featured pair would
   outweigh both panels above it. */
/* CENTRED, and deliberately the one thing on this page that is.
   Briefly left-aligned to the page axis on 2026-10-05 when the
   statement above was, and Chris put it back the same day. He is
   right: the axis is set by text, and a 16:9 block of picture is not
   text. Pinned to the left it reads as a panel that failed to reach
   the right-hand edge; centred under the pair it reads as a full
   stop. Do not "fix" this to match the others. */
.home-trailer {
  max-width: var(--content-width);
  margin: 0 auto 3.5rem;
  padding: 0 1.5rem;
}

/* A DESIGNED POSTER PANEL, for a video whose own thumbnail is not fit
   to publish. Same reasoning as the portfolio panel: the alternative
   was either a blurry frame or a dashed "coming soon" box on a page
   that is otherwise finished, and neither is what a book trailer
   deserves. Replace it with a still the moment there is a good one —
   passing `poster` to the partial takes precedence over this. */
/* DOUBLED CLASS, same trap as the portfolio panel: the base
   .video-embed-poster rule is declared further down and sets display,
   so at equal specificity it won and this panel was never a grid — the
   label and the title ran together on one line with the play control
   sitting on top of them. Naming both classes lets the modifier beat
   the base wherever either ends up in the file. */
.video-embed-poster.video-embed-poster--panel {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 0.6rem;
  aspect-ratio: 16 / 9;
  padding: 1.5rem;
  text-align: center;
  background: var(--color-cream-deep);
}

.video-embed-poster-label {
  font-family: var(--font-sans);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-gold);
}

.video-embed-poster-title {
  font-family: var(--font-serif);
  font-size: clamp(1.15rem, 2.6vw, 1.7rem);
  line-height: 1.2;
  color: var(--color-ink);
  text-wrap: balance;
  /* Room for the play control, which is centred over the whole panel —
     without this the title sits behind it. */
  margin-block-end: 3.25rem;
}

.video-embed-trigger {
  /* The whole poster is the button, so it is sized by its contents and
     carries no default button chrome. */
  display: block;
  position: relative;
  inline-size: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  /* Reserve the shape before the poster loads so nothing jumps, and so
     the iframe that replaces it lands in exactly the same box. */
  aspect-ratio: 16 / 9;
  border-radius: 2px;
  overflow: hidden;
}

.video-embed-poster {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.video-embed-poster--placeholder {
  display: grid;
  place-content: center;
  background: var(--color-cream-deep);
  border: 2px dashed var(--color-sage);
  color: var(--color-sage-dark);
  font-family: var(--font-sans);
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* WHEN THE POSTER IS A DESIGNED PANEL rather than a photograph, the
   play control moves out of the middle and the scrim comes off. Over a
   still, a centred control on a dark scrim is right — it has to stay
   legible over an image nobody has tuned it for. Over our own panel
   there is no image to sit on and nothing to darken, and a centred
   control simply lands on top of the title. Below the text, on the
   panel's own ground, is both legible and out of the way.

   :has() rather than a class on the trigger, so the partial does not
   have to know which poster state it rendered in order to set one. */
.video-embed-trigger:has(.video-embed-poster--panel) .video-embed-play {
  background: none;
  align-content: end;
  padding-block-end: 2.25rem;
}

/* The bottom margin that had been reserving room for a centred control
   is no longer needed now that the control sits below the text. */
.video-embed-poster-title { margin-block-end: 0; }

.video-embed-play {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  /* A light scrim so the play control stays visible over any still,
     bright or dark, without having to tune it per video. */
  background: rgba(46, 42, 36, 0.25);
  transition: background 150ms ease;
}

.video-embed-play-disc {
  fill: rgba(246, 241, 231, 0.92);
}

.video-embed-play-arrow {
  fill: var(--color-sage-dark);
}

.video-embed-trigger:hover .video-embed-play,
.video-embed-trigger:focus-visible .video-embed-play {
  background: rgba(46, 42, 36, 0.12);
}

/* The focus ring goes on the trigger rather than inside it, since the
   button is the full poster. */
.video-embed-trigger:focus-visible {
  outline: 3px solid var(--color-sage-dark);
  outline-offset: 3px;
}

.video-embed-frame {
  display: block;
  inline-size: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  border-radius: 2px;
}

.video-embed-fallback {
  display: inline-block;
  margin-block-start: 0.75rem;
  font-family: var(--font-sans);
  font-size: 0.95rem;
}

/* ITALIC, 2026-10-05 (Chris, asking whether it should be: it should).
   The site has two vocabularies for small supporting text and this
   line was in the wrong one. Sans and sage is what facts are set in
   here — the imprint note, a tile's publication line, a date. Serif
   italic and sage is what a caption is set in, which is what the
   photograph caption on the Work page became earlier today. This is a
   caption under a piece of media, so it matches that one exactly,
   size included.

   THE TITLE INSIDE IT GOES ROMAN. An italic book title inside an
   italic caption is invisible, so emphasis in this one line inverts —
   standard practice, and the reason the caption is markdownified in
   partials/video-embed.html rather than printed raw. */
.video-embed-caption {
  margin-block-start: 0.6rem;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 1.05rem;
  line-height: 1.4;
  color: var(--color-sage-dark);
}

.video-embed-caption em {
  font-style: normal;
}

/* --- Utilities --- */
/* Visually hidden but still announced by screen readers. Used for the
   "(opens in a new tab)" notes on external links — every outbound link
   on this site opens a new tab at Nerys's request, and that should be
   announced rather than just happening. Clip-path plus a 1px box is
   the technique that survives both text zoom and forced-colours mode;
   display:none and visibility:hidden would remove it from the
   accessibility tree entirely, which defeats the purpose. */

.visually-hidden {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- Type hierarchy for supporting text, 2026-09-25 --- */
/* Chris: "all the type has the same importance and some of the text is
   less important, like note content." Markdown gives every paragraph
   the same weight, so these two classes are what a page uses to say
   otherwise. Both are set through shortcodes rather than raw HTML —
   see layouts/shortcodes/credit.html and note.html. */

/* The smallest type on the site: a line that has to be on the record
   but must not compete. Uppercase and tracked so it reads as a caption
   rather than a sentence, and in sage rather than ink so it recedes
   even before the size registers. */
.credit {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-sage-dark);
  margin-block: 1.75rem 0;
}

/* Quieter than body copy, louder than a credit: bibliographic or
   parenthetical detail a reader may want and should not trip over.
   Deliberately NOT uppercase — these lines are read, not scanned. */
.note {
  font-family: var(--font-sans);
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--color-sage-dark);
  margin-block: 0 0.9rem;
}

/* --- Home page pull-quotes --- */
/* Added 2026-09-17: Options B/D from the reference-sites research —
   lead with third-party credibility before the bio. Quotes render as
   real <blockquote>/<footer> markup (see layouts/index.html), which
   is what lets the attribution line below be styled separately from
   the quote text itself — the plain-paragraph quotes on the About
   page can't do this yet (see the blockquote comment further down),
   so this section's markup is the more correct version of the same
   idea and worth carrying back to About once that page is restructured. */

.home-quotes {
  max-width: var(--content-width-wide);
  margin: 0 auto 3rem;
  padding: 0 1.5rem;
  display: grid;
  gap: 1.5rem;
}

/* --- Press quotes, shared by both pages, 2026-09-25 --- */
/* Chris: "we have lots of quotes ... could we not use them a bit more
   graphically?" The stylesheet has carried a note since September
   saying a proper pull-quote treatment needed real blockquote markup
   first; layouts/partials/quotes.html is that markup, and this is the
   treatment it was waiting for.

   The device is a large red opening mark set in the serif, sitting in
   its own column so the quote text aligns against it rather than
   flowing around it. Red is the palette's most energetic colour and
   had been used exactly once, as a 3px line. A pull-quote on an
   author's site is the one place a flourish is expected. */

.quote {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 0.7rem;
  align-items: start;
  /* Overrides the generic blockquote rule further down, which draws a
     left rule these do not want — the mark replaces it. */
  border-left: 0;
  padding-left: 0;
  font-style: normal;
}

.quote::before {
  content: "\201C";
  grid-row: 1 / span 2;
  font-family: var(--font-serif);
  font-size: 2.9rem;
  line-height: 0.78;
  color: var(--color-red);
  /* Optically aligned: a quotation mark hangs high in its box, so
     nudging it down lands it on the first line of text rather than
     above it. */
  translate: 0 0.06em;
}

.quote-text {
  margin: 0;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: clamp(1.02rem, 1.5vw, 1.15rem);
  line-height: 1.38;
  text-wrap: pretty;
}

.quote-source {
  grid-column: 2;
  margin-top: 0.45rem;
  font-family: var(--font-sans);
  font-style: normal;
  font-size: 0.82rem;
  letter-spacing: 0.02em;
  color: var(--color-sage-dark);
}

.quote-source em { font-style: italic; }

/* Home: one per row, full measure, room to breathe. */
.quotes--stack {
  display: grid;
  gap: 1.9rem;
}

/* About: a set rather than a list. Cards on the deeper cream so five
   quotes read as a block of praise you can take in at a glance,
   instead of five paragraphs to wade through. */
.quotes--grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  gap: 1.1rem;
  margin-block: 1.5rem 2.25rem;
}

.quotes--grid .quote {
  background: var(--color-cream-deep);
  padding: 1.15rem 1.25rem 1.3rem;
  border-radius: 2px;
}

.quotes--grid .quote::before { font-size: 2.4rem; }
.quotes--grid .quote-text { font-size: 1rem; }

/* --- Generic page (About, Work, Contact, Privacy) --- */

main {
  padding-bottom: 2rem;
}

article.page {
  max-width: var(--content-width);
  margin: 0 auto;
  padding: 2rem 1.5rem;
}

/* ------------------------------------------------------------------
   VERTICAL RHYTHM (2026-10-05, Chris: "make the text more grouped and
   less one space after each line").

   The page was setting almost everything at one interval — 16px
   between a heading and its first line, 16 between paragraphs, 40
   before the next heading. At those values a section does not read as
   a block, it reads as a list of paragraphs that happens to have
   headings in it.

   Three intervals now, and the difference between them is the point:

     10px   a heading and the line it introduces — they belong together,
            so the gap is smaller than the one between paragraphs
     14px   paragraphs inside the same section
     56px   before the next heading, which is what makes a section end

   Scoped to article.page so it governs the body pages — About, Work,
   Contact, Privacy — and leaves the home page's composed blocks alone.
   ------------------------------------------------------------------ */
article.page h2 {
  margin-block: 3.5rem 0.6rem;
}

/* The first heading has the page title above it already; the full
   section gap there pushes the page open for no reason. */
article.page > h2:first-of-type {
  margin-block-start: 2.5rem;
}

article.page p {
  margin-block: 0 0.9rem;
}

/* A hook line belongs to the heading above it, not to the prose below:
   tight to the title, normal gap to the paragraph that follows. */
/* The novel's bibliographic block — credit, imprint, availability,
   out-of-print — is four short lines about one object. They set as one
   group, close enough to scan in a glance, with the ordinary paragraph
   gap kept for the prose on either side. */
article.page .credit {
  margin-block: 0.35rem 0;
}

/* A note always belongs to the line above it — the imprint to the
   title, "out of print" to the availability line — so it tucks under
   whatever precedes it and the full paragraph gap goes after. Without
   the `p + .note` rule the out-of-print aside floated midway between
   the buy link and the summary, belonging to neither. */
article.page .credit + .note,
article.page .note + .note,
article.page p + .note {
  margin-block-start: 0.2rem;
}

/* Adjacent vertical margins collapse to the LARGER of the two, so the
   0.2rem above loses to the preceding paragraph's 0.9rem and the note
   sits a full gap away regardless. The paragraph's own bottom margin
   has to come down to match, which is what :has() is for. Without this
   the "Out of print" line floated midway between the buy link and the
   summary, belonging to neither — the rule above looked correct and
   did nothing. */
article.page p:has(+ .note) {
  margin-block-end: 0.2rem;
}

article.page .note {
  margin-block-end: 0;
}

article.page .note + p {
  margin-block-start: 0.9rem;
}

/* --- About page photo treatments (2026-09-21) ---
   Three options, switched by params.aboutPhotoStyle — see
   layouts/_default/single.html for which is which and why. */

/* The original: a 144px circle. Kept for comparison only. */
.about-headshot--avatar {
  display: block;
  width: 9rem;
  height: 9rem;
  border-radius: 50%;
  object-fit: cover;
  object-position: center 25%;
  margin: 0 0 1.5rem;
  border: 3px solid var(--color-cream-deep);
}

/* A portrait alongside the biography, text flowing around it.
   Stacked by default and floated only when the column is wide enough to
   take it — a float in a narrow column would squeeze the text into a
   gutter two or three words wide. */
.about-headshot--beside {
  display: block;
  inline-size: 100%;
  max-inline-size: 15rem;
  block-size: auto;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  margin: 0 0 1.5rem;
  border-radius: 2px;
}

/* A container query, not a viewport media query: what decides whether
   the float works is the width of THIS column, which is capped at the
   reading measure and so is not the same thing as the width of the
   window. Asking the container directly keeps the rule true if the page
   is ever placed in a narrower layout. */
.page--portrait {
  container-type: inline-size;
}

@container (min-width: 30rem) {
  .about-headshot--beside {
    float: inline-start;
    margin-inline-end: 1.75rem;
    margin-block-end: 1rem;
    max-inline-size: 13rem;
  }

  /* Do NOT clear headings here. An earlier version did, on the theory
     that a heading in the narrow strip beside a portrait looks broken;
     in practice it pushed the entire body below the photo and nothing
     wrapped at all, which is the one thing this treatment exists to do.
     The biography runs well past the bottom of the portrait, so every
     heading after it lands at full width on its own anyway.

     The first heading does need its top margin removed, though —
     h2's 2.5rem would otherwise open a gap between the portrait's top
     edge and the first line of text beside it. */
  .page--portrait .about-headshot--beside + h2 {
    margin-block-start: 0;
  }
}

/* Full-width band above the page. Height is capped so it cannot become
   a second hero: the home page owns the one big photographic moment,
   and if every page opens with a large picture of her the site loses
   its rhythm. */
.about-band {
  inline-size: 100%;
  /* 320px cut her off at the jaw. The arithmetic is unforgiving: at
     full width this photograph scales to ~914px tall, and her head
     occupies roughly 480 of those, so any band shorter than that
     slices her face. 500px is the smallest height that holds a whole
     head — which is itself the argument against this treatment, since
     a 500px band is most of the screen and starts competing with the
     home page's hero. */
  block-size: min(56vh, 500px);
  overflow: hidden;
  margin-block-end: 2rem;
  background: var(--color-cream-deep);
}

.about-band img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  /* She sits right of centre in the frame (about 59% across) with her
     eyes ~40% down, so a centred crop would put her at the edge. */
  object-position: 59% 27%;
  display: block;
}

/* The generic blockquote, for any quotation in page copy that is not
   one of the press quotes. Scoped with :not(.quote) since 2026-09-25 —
   the press quotes draw their own mark and must not also carry this
   left rule. */
blockquote:not(.quote) {
  border-left: 3px solid var(--color-red);
  padding-left: 1rem;
  margin: 1.5rem 0;
  font-size: 1.1rem;
  font-style: italic;
}

/* --- Footer --- */

.site-footer {
  padding: 2rem 1.5rem;
  text-align: center;
  font-size: 0.9rem;
  color: var(--color-sage-dark);
  border-top: 1px solid var(--color-cream-deep);
}

.site-footer a {
  color: var(--color-sage-dark);
}

/* --- Cookie banner --- */

.cookie-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: var(--color-cream-deep);
  border-top: 1px solid var(--color-sage);
  padding: 1rem 1.5rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  font-size: 0.9rem;
}

.cookie-banner button {
  cursor: pointer;
  font-family: var(--font-sans);
  font-weight: 600;
  border: none;
  border-radius: 0.25rem;
  padding: 0.5rem 1rem;
  background: var(--color-sage);
  color: #FBF8F1;
}

.cookie-banner button:hover,
.cookie-banner button:focus-visible {
  background: var(--color-sage-dark);
}

/* --- Small screens --- */

@media (max-width: 32rem) {
  .site-header {
    flex-direction: column;
    align-items: flex-start;
  }

  .hero {
    /* Was 60vh, which on a phone showed the photograph's entire
       vertical extent — metres of door above her head and the full
       length of her skirt below. Capped in absolute pixels as well as
       vh so a tall phone cannot stretch it back out. */
    min-height: min(52vh, 380px);

    /* A width breakpoint is genuinely the right tool here: this is a
       framing decision about one specific photograph, not a layout
       that can resolve itself intrinsically. */

    /* The wordmark has to come down with the hero, or it fills a
       380px-tall frame on its own. */
    font-size: 1rem;
  }

  /* 300px of Turnstile will not sit beside a two-line question on a
     phone, so the pair stacks and the widget goes back to the left. */
  .contact-form__gate {
    display: block;
  }

  .contact-form__gate .cf-turnstile {
    margin-inline-start: 0;
    margin-block-start: 1rem;
  }

  .hero-wordmark {
    /* 18vw overflowed a 390px phone and rendered as "Nerys Parr".
       Raised 12vw -> 14vw on 2026-09-29 alongside the desktop size. On a
       390px phone that is 331px of text in a 390px frame; 15vw was 355px,
       which crowded the edge on the narrowest phones still in use. */
    font-size: clamp(2.5rem, 14vw, 4.5rem);
    /* Kept two points above the desktop value, as it has been
       throughout: the wordmark is physically smaller here and sits over
       a busier crop, so it needs the extra to read the same. Moved with
       the desktop value on 2026-10-06, 0.24 to 0.19. */
    opacity: 0.19;
  }
}

/* ------------------------------------------------------------------
   CONTACT FORM (added 2026-09-24) - layouts/shortcodes/contact-form.html
   Kept plain and calm: cream fields on the cream page, ink text, sage
   focus ring to match the button. Labels sit above the fields (easier
   to read and tap on phones than side-by-side).
   ------------------------------------------------------------------ */
.contact-form {
  max-width: var(--content-width);
  margin: 1.5rem 0 2.5rem;
}

.contact-form__field {
  /* Tightened 2026-10-05: the fields were a full paragraph gap apart,
     which on a three-field form reads as three separate questions
     rather than one form to fill in. */
  margin: 0 0 0.9rem;
}

.contact-form__field label {
  display: block;
  /* Smaller, 2026-10-05 (Chris). At body size these labels carried the
     same weight as the sentences above the form, so the eye met
     "Name" as a statement rather than as the tag on a box. Sans at
     0.85rem keeps them legible and puts them a clear step below the
     copy. */
  font-size: 0.85rem;
  font-family: var(--font-sans);
  font-weight: 600;
  letter-spacing: 0.01em;
  margin-bottom: 0.25rem;
}

.contact-form input,
.contact-form textarea {
  width: 100%;
  font: inherit;
  color: var(--color-ink);
  background: #fff;
  border: 1px solid var(--color-cream-deep);
  border-radius: 4px;
  padding: 0.6rem 0.75rem;
}

.contact-form textarea {
  resize: vertical;   /* let people make it taller, never wider than the column */
}

/* Visible keyboard focus in the brand's accessible sage. */
.contact-form input:focus-visible,
.contact-form textarea:focus-visible {
  outline: 2px solid var(--color-sage-dark);
  outline-offset: 1px;
  border-color: var(--color-sage-dark);
}

/* ------------------------------------------------------------------
   MAILING LIST CONSENT (added 2026-09-29)
   The yes/no question inside the contact form. A fieldset, so the two
   options read as one question rather than two stray inputs.

   Fieldsets arrive with a border, padding and margins no two browsers
   agree on, so all of that is reset and the spacing rebuilt to match
   the fields above it. The legend is styled to look like the field
   labels, because to a visitor it is one.
   ------------------------------------------------------------------ */
/* The consent question and the human check, side by side. The widget is
   pushed to the form's right edge; see the note in the shortcode for
   why it belongs there rather than beside the question. align-items:
   end lines the two up on their bottoms, which is the only edge they
   share — the question is two lines of text, the widget a fixed box. */
.contact-form__gate {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  justify-content: space-between;
  gap: 1rem 1.5rem;
  margin: 0 0 1.25rem;
}

.contact-form__gate .cf-turnstile {
  /* Flush right even when the row wraps and the widget is alone on its
     line; without this it would sit left on the wrapped line. */
  margin-inline-start: auto;
}

.contact-form__consent {
  border: 0;
  margin: 0;
  padding: 0;
  /* min-inline-size: 0 stops a fieldset refusing to shrink below its
     content's intrinsic width, which is a fieldset-only quirk and the
     usual cause of a form overflowing on a phone. */
  min-inline-size: 0;
}

.contact-form__consent legend {
  /* padding: 0 removes the gap browsers leave either side of a legend
     where the border used to pass through it. */
  padding: 0;
  font-weight: 600;
  margin-bottom: 0.4rem;
}

.contact-form__choice {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin: 0 0 0.3rem;
}

/* The input rule above sets width:100% for the text fields. A radio
   must not inherit that, or it stretches into a grey bar. The
   attribute selector out-ranks the bare .contact-form input rule, and
   sits after it, so this holds either way. */
.contact-form__choice input[type="radio"] {
  width: auto;
  margin: 0;
  /* accent-color tints the native control rather than replacing it
     with a div, so it keeps the platform's own keyboard behaviour,
     focus ring and high-contrast handling for free. */
  accent-color: var(--color-sage-dark);
  /* The control sits slightly low against a baseline-aligned label;
     this brings it back onto the text's optical line. */
  transform: translateY(0.15em);
}

.contact-form__choice label {
  font-weight: 400;
  /* The whole label is a click target via `for`, so make it look it. */
  cursor: pointer;
}

/* Honeypot: moved off-screen rather than display:none, because some
   bots skip fields they can tell are display:none. */
.contact-form__trap {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.contact-form .cf-turnstile {
  margin: 0.5rem 0 1rem;
}
