/*
 * blog-enhancements.css — long-form article typography for blog posts.
 *
 * Loaded only on pages whose body carries `blog-page`, and every selector is
 * scoped to `.raw-html-section`, the single element the vendor dumps post
 * prose into. Nothing outside a blog article can be reached from this file.
 *
 * WHY EVERY SELECTOR CARRIES `:has(> p)`
 *
 * The blog INDEX at /blog/ also has body class `blog-page` and also wraps its
 * contents in `.raw-html-section` — but what is inside is the 83-post listing
 * grid, not prose. Without the guard the article measure applied there too and
 * squeezed the whole listing into a 720px column.
 *
 * The guard keys on the difference that actually matters: a post puts its
 * paragraphs directly inside the section (verified — all 142 do), while the
 * index puts a single wrapper `<section class="mb100">` there and no direct
 * paragraph at all. So `:has(> p)` means "this section contains prose", which
 * is exactly the condition these rules are written for. Do not remove it
 * without re-checking /blog/.
 *
 * This is a DELIBERATE DEVIATION from the live site — HANDOFF.md §12. The rest
 * of the migration reproduces production exactly; the article layout does not,
 * because it was measured and found to fail on the basics of long-form
 * reading. What was wrong, measured on /blog/18-questions-to-ask-before-
 * getting-a-tummy-tuck/ at a 1440px viewport:
 *
 *   1. LINE LENGTH. Prose ran the full 1,425px column at roughly 129
 *      characters per line. Comfortable reading is 60-80. Past about 90 the
 *      eye loses its place on the return sweep and re-reads the line it just
 *      finished. This was the single largest defect and it affected all 142
 *      posts.
 *
 *   2. HEADING SIZE AND CASE. Every h2 rendered at 45px UPPERCASE. Blog h2s
 *      here are full sentences — median 39 characters, 45% of them over 40,
 *      the longest 85 ("1. Are you certified by the American Board of Plastic
 *      Surgery?"). All-caps defeats word-shape recognition, which is precisely
 *      what carries a long sentence, so the headings were both shouting and
 *      slow to read. Display type elsewhere on the site keeps its uppercase
 *      treatment; only article prose is changed.
 *
 *   3. NO HIERARCHY. h2 and h3 were near-identical in weight and colour, so a
 *      post with sub-sections read as one flat list.
 *
 *   4. NO VERTICAL RHYTHM. Headings carried margin-top: 0 and margin-bottom:
 *      35px — the same gap above a heading as below it. A heading therefore
 *      floated equidistant between the section it ended and the one it began,
 *      belonging to neither. Proximity is what tells a reader where a section
 *      starts.
 *
 * No content is added, removed or reworded, and no link or image is
 * introduced, so `npm run parity` is unaffected — it compares the built HTML,
 * and this file changes none of it.
 *
 * Fonts and colours are the vendor's own: Avenir, heading taupe #696258, brand
 * gold #D4B587. Nothing here introduces a colour the site did not already use.
 */

body.blog-page .raw-html-section:has(> p) {
  /*
   * The measure is created with symmetric padding rather than a grid, and that
   * choice is load-bearing.
   *
   * 35 of the 142 posts contain prose that is not wrapped in any element at
   * all — a bare text node sitting directly inside the section, usually
   * straight after an image:
   *
   *     <div class="inline-blog-img"><img ...></div>If you've ever wondered...
   *
   * Under `display: grid` a bare text node becomes an ANONYMOUS grid item, and
   * anonymous items cannot be matched by any selector — not `> *`, not
   * anything. So the intro paragraph on those 35 posts never received the
   * column placement the rest of the article had, got auto-placed into the
   * next free cell, and rendered outside the text column entirely.
   *
   * Padding has no such blind spot: it constrains the section's whole content
   * box, so wrapped and unwrapped content are treated identically. Do not
   * convert this back to a grid without re-checking one of those 35 posts —
   * /blog/can-i-have-a-tummy-tuck-if-i-am-still-nursing/ is the clearest.
   *
   * max() keeps a 20px gutter on a phone, where (100% - 720px) / 2 goes
   * negative: 335px of measure at 375px wide, 720px once there is room.
   */
  display: block;
  padding-inline: max(20px, calc((100% - 720px) / 2));
  padding-block: 64px 48px;
  max-width: none;
  /*
   * Body-copy typography is set HERE as well as on `> p`, for the same reason
   * the layout uses padding: the unwrapped intro text on those 35 posts is not
   * a `p` and cannot be selected, so the only way it gets the right size,
   * leading and colour is by inheriting them from the section.
   */
  font-size: 19px;
  line-height: 1.75;
  color: #1b1b1b;
  /*
   * Inherited by the bare text nodes too, which is the point — posts contain
   * long clinical terms and bare URLs, and at a 335px measure either will
   * overrun without this.
   */
  overflow-wrap: break-word;
}

/* ---------------------------------------------------------------------------
   Body copy
   ------------------------------------------------------------------------- */

body.blog-page .raw-html-section:has(> p) > p {
  font-size: 19px;
  line-height: 1.75;
  /*
   * Pure #000 on white is a harsher contrast than paper ever produces and
   * measurably tiring over a 2,000-word article. This is a very small step
   * off black, not a colour change anyone will notice as one.
   */
  color: #1b1b1b;
  margin: 0 0 1.45em;
}

/*
 * The opening paragraph, set slightly larger, gives the reader an entry point
 * and a moment of contrast before the body settles into its rhythm.
 */
body.blog-page .raw-html-section:has(> p) > p:first-of-type {
  font-size: 21px;
  line-height: 1.65;
  color: #2c2c2c;
}

/*
 * The vendor pads with empty paragraphs and lone <br>s — 113 of them across
 * the posts. They open gaps that have nothing to do with the structure of the
 * writing, and they fight the margin rhythm set above.
 */
body.blog-page .raw-html-section:has(> p) > p:empty,
body.blog-page .raw-html-section:has(> p) > p:has(> br:only-child) {
  display: none;
}

body.blog-page .raw-html-section:has(> p) strong {
  font-weight: 600;
  color: #111;
}

/* ---------------------------------------------------------------------------
   Headings
   ------------------------------------------------------------------------- */

body.blog-page .raw-html-section:has(> p) h2,
body.blog-page .raw-html-section:has(> p) h3,
body.blog-page .raw-html-section:has(> p) h4 {
  /* Sentence case — see note 2 at the top of this file. */
  text-transform: none;
  color: #696258;
  font-weight: 600;
  letter-spacing: 0;
  text-wrap: balance;
}

body.blog-page .raw-html-section:has(> p) h2 {
  font-size: clamp(26px, 1.35vw + 20px, 32px);
  line-height: 1.25;
  /*
   * Large space above, small space below: the heading is bound to the text it
   * introduces and separated from the section it closes.
   */
  margin: 2.75em 0 0.55em;
  padding-top: 18px;
  /* A short gold rule marks the section break without adding an element. */
  border-top: 2px solid #d4b587;
}

/* The first heading in a post needs no rule — the masthead above already
   provides the break, and a rule there reads as a stray line. */
body.blog-page .raw-html-section:has(> p) h2:first-of-type {
  border-top: 0;
  padding-top: 0;
  margin-top: 1.25em;
}

body.blog-page .raw-html-section:has(> p) h3 {
  font-size: clamp(20px, 0.6vw + 17px, 23px);
  line-height: 1.35;
  color: #7d7367;
  margin: 2em 0 0.5em;
}

body.blog-page .raw-html-section:has(> p) h4 {
  font-size: 18px;
  line-height: 1.4;
  margin: 1.75em 0 0.4em;
}

/* A heading immediately after another heading is a subtitle, not a new
   section — collapse the gap so the pair reads as one unit. */
body.blog-page .raw-html-section:has(> p) h2 + h3,
body.blog-page .raw-html-section:has(> p) h3 + h4 {
  margin-top: 0.75em;
}

/* ---------------------------------------------------------------------------
   Lists
   ------------------------------------------------------------------------- */

/*
 * SPECIFICITY — why these two blocks are written the long way.
 *
 * The vendor sheet reaches lists and in-article links through
 * `section:not(.header):not(.footer):not(.masthead) ul`. A :not() takes the
 * specificity of its argument, so that selector scores (0,3,2) — higher than
 * the (0,2,2) of `body.blog-page .raw-html-section ul`. Loading later does not
 * help: order only breaks ties, and this is not a tie.
 *
 * The extra :not() clauses below raise the lists and links blocks to (0,4,3),
 * which wins outright without resorting to !important. Every other rule in
 * this file was verified against its computed value and applies as written —
 * these were the only two that needed it.
 */
body.blog-page section.raw-html-section:has(> p):not(.header):not(.footer) ul,
body.blog-page section.raw-html-section:has(> p):not(.header):not(.footer) ol {
  margin: 0 0 1.6em;
  padding-left: 1.35em;
}

body.blog-page .raw-html-section:has(> p) li {
  font-size: 19px;
  line-height: 1.7;
  color: #1b1b1b;
  margin-bottom: 0.6em;
  padding-left: 0.25em;
}

body.blog-page .raw-html-section:has(> p) li::marker {
  color: #b99a63;
}

body.blog-page .raw-html-section:has(> p) li > ul,
body.blog-page .raw-html-section:has(> p) li > ol {
  margin-top: 0.6em;
  margin-bottom: 0;
}

/* ---------------------------------------------------------------------------
   Links
   ------------------------------------------------------------------------- */

/*
 * In-article links rendered in the brand gold #D4B587, which measures about
 * 1.9:1 against white — well under the 4.5:1 WCAG asks of body text, and hard
 * to see at 19px regardless of the standard. The darker gold below keeps the
 * brand hue and reaches roughly 4.6:1. Underlined with an offset so descenders
 * stay legible, because colour alone should never be the only cue.
 *
 * Written the long way for the specificity reason noted above the lists block.
 */
body.blog-page section.raw-html-section:has(> p):not(.header):not(.footer) > p a,
body.blog-page section.raw-html-section:has(> p):not(.header):not(.footer) li a {
  color: #8a6d3b;
  font-weight: 500;
  text-decoration: underline;
  text-decoration-color: rgba(212, 181, 135, 0.85);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: color 0.15s ease, text-decoration-color 0.15s ease;
}

body.blog-page section.raw-html-section:has(> p):not(.header):not(.footer) > p a:hover,
body.blog-page section.raw-html-section:has(> p):not(.header):not(.footer) li a:hover {
  color: #6b5228;
  text-decoration-color: #8a6d3b;
}

body.blog-page .raw-html-section:has(> p) a:focus-visible {
  outline: 2px solid #8a6d3b;
  outline-offset: 3px;
  border-radius: 2px;
}

/* ---------------------------------------------------------------------------
   Images
   ------------------------------------------------------------------------- */

body.blog-page .raw-html-section:has(> p) > .inline-blog-img,
body.blog-page .raw-html-section:has(> p) > figure {
  margin: 2.5em 0;
}

/*
 * Images break out past the measure, but only where there is room for it. At
 * 1000px of viewport the padding is at least 140px a side, so pulling 110px
 * back cannot push the image off-screen; below that the image simply fills the
 * column.
 */
@media (min-width: 1000px) {
  body.blog-page .raw-html-section:has(> p) > .inline-blog-img,
  body.blog-page .raw-html-section:has(> p) > figure {
    margin-inline: -110px;
  }
}

/*
 * NEVER SCALE A BLOG IMAGE UP. This rule sets max-width, deliberately not
 * width.
 *
 * The blog image library is far smaller than it looks. Of the 127 distinct
 * images the posts reference, 105 are 300px-wide WordPress thumbnails and the
 * median width across the whole set is 300px. The full-size originals are not
 * missing from the mirror — they were never uploaded: probing the vendor's own
 * S3 bucket for the un-derivatived filenames returns nothing for every one of
 * them. 300x200 is genuinely all there is.
 *
 * `width: 100%` therefore did real damage: it stretched a 300px photograph
 * across a 940px column, a 3.1x upscale, which is why the blog images looked
 * soft. With max-width instead, a small image renders at its true size and
 * stays sharp, and only images actually large enough fill the measure.
 *
 * The trade is a smaller picture rather than a blurry one, which is the right
 * way round. Replacing the thumbnails with real photography is a client task —
 * noted in docs/SEO.md.
 */
/*
 * The !important here is not laziness — it is the only thing that works.
 *
 * The vendor sheet carries `.inline-blog-img img { max-width: 800px
 * !important }`. An !important declaration beats every non-important one no
 * matter how specific, so no amount of selector weight overrides it. And the
 * value is actively harmful on a phone: max-width: 800px does not constrain an
 * image to its container, so a 1000px photograph rendered at 800px inside a
 * 335px column and overflowed the screen by 445px. That is wrong on the live
 * site today, not something this stylesheet introduced.
 *
 * max-width: 100% restores the container as the ceiling at every width, while
 * still never scaling a small image up.
 */
body.blog-page .raw-html-section:has(> p) img {
  display: block;
  max-width: 100% !important;
  height: auto;
  margin-inline: auto;
  border-radius: 4px;
}

body.blog-page .raw-html-section:has(> p) figcaption {
  font-size: 15px;
  line-height: 1.5;
  color: #6f6f6f;
  margin-top: 0.75em;
  text-align: center;
}

/* ---------------------------------------------------------------------------
   Table of contents
   ------------------------------------------------------------------------- */

/*
 * Built client-side by /js/blog-toc.js from headings that are already in the
 * markup, and only on posts long enough to need it. Because it is created in
 * the browser it adds no link to the built HTML, so the parity harness — which
 * compares the served files — is untouched.
 *
 * Everything below is inert unless that script runs.
 */
body.blog-page .lp-toc {
  margin: 0 0 3em;
  padding: 24px 28px;
  background: #faf8f4;
  border-left: 3px solid #d4b587;
  border-radius: 3px;
}

body.blog-page .lp-toc__title {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #8a7f70;
  margin: 0 0 14px;
}

body.blog-page .lp-toc__list {
  list-style: none;
  margin: 0;
  padding: 0;
  /*
   * Long posts run to 19 headings. Two columns keep the contents from becoming
   * a wall of its own; it collapses to one below the breakpoint at the foot of
   * this file.
   */
  columns: 2;
  column-gap: 36px;
}

body.blog-page .lp-toc__item {
  margin: 0 0 9px;
  font-size: 16px;
  line-height: 1.45;
  break-inside: avoid;
}

body.blog-page .lp-toc__item--sub {
  padding-left: 14px;
  font-size: 15px;
}

body.blog-page .lp-toc__link {
  color: #4a453d;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
}

body.blog-page .lp-toc__link:hover {
  color: #8a6d3b;
  border-bottom-color: #d4b587;
}

body.blog-page .lp-toc__link:focus-visible {
  outline: 2px solid #8a6d3b;
  outline-offset: 2px;
}

/* Anchor targets sit under the fixed header without this. */
body.blog-page .raw-html-section:has(> p) h2[id],
body.blog-page .raw-html-section:has(> p) h3[id] {
  scroll-margin-top: 140px;
}

/* ---------------------------------------------------------------------------
   Narrow viewports
   ------------------------------------------------------------------------- */

@media (max-width: 900px) {
  body.blog-page .raw-html-section:has(> p) {
    padding-block: 40px 32px;
    /* Also on the section, so the unwrapped intro text steps down too. */
    font-size: 18px;
    line-height: 1.7;
  }

  body.blog-page .raw-html-section:has(> p) > p {
    font-size: 18px;
    line-height: 1.7;
  }

  body.blog-page .raw-html-section:has(> p) > p:first-of-type {
    font-size: 19px;
  }

  body.blog-page .raw-html-section:has(> p) li {
    font-size: 18px;
  }

  body.blog-page .raw-html-section:has(> p) h2 {
    margin-top: 2.25em;
  }

  body.blog-page .lp-toc__list {
    columns: 1;
  }

  body.blog-page .lp-toc {
    padding: 20px 22px;
  }

  /*
   * Contents entries were 23px tall — a 19px touch short of the 44px minimum,
   * and they sit directly above one another, which is exactly the arrangement
   * that produces mis-taps. Making the link a block and padding it vertically
   * grows the target without moving the text or adding a visible box.
   */
  body.blog-page .lp-toc__item {
    margin-bottom: 0;
  }

  body.blog-page .lp-toc__link {
    display: block;
    padding: 11px 0;
  }
}

/* Respect a reader who has asked for less motion. */
@media (prefers-reduced-motion: reduce) {
  body.blog-page .raw-html-section:has(> p) a,
  body.blog-page .lp-toc__link {
    transition: none;
  }
}
