/* Blog-article typography: Karla (body) / Exo 2 (headings), per explicit
   request (2026-09-24) -- matching the manuals (see wdocs/css/manual.css).

   Scoped to .blog-post specifically, NOT applied to .prose directly:
   .prose is shared by ~170 other pages sitewide (KB articles, product
   pages, ...) that this migration doesn't touch, so overriding it
   directly would be a de-facto sitewide font change smuggled in through
   one class. .blog-post is a wrapper this migration's own template adds
   (see tools/blog/render_post.py) -- nothing else on the site uses it.

   Font values come from the shared css/fonts.css, loaded before this file
   (see render_post.py's own <link> order) -- not redefined here, same
   reasoning as wdocs/css/manual.css's own note on this.
*/
.blog-post h1, .blog-post h2, .blog-post h3, .blog-post h4, .blog-post h5, .blog-post h6 {
  font-family: var(--f-heading);
}
.blog-post,
.blog-post p, .blog-post li, .blog-post a, .blog-post blockquote {
  font-family: var(--f-body);
}

/* Real in-body headings (h2/h3 mainly, occasionally h1/h4 -- confirmed
   on real samples: cloudwatcher-vs-tess-w's own Google-Docs-pasted
   <h1>, remote-observatory-hosting-australia's own <h2>/<h3>/<h4> FAQ
   answers) had NOTHING beyond font-family set here -- font-size and
   margin both fell back to the bare browser default, reported by the
   user two ways: a heading with no WYSIWYG size of its own read "like
   normal text" (no size step up from body copy at all), and real
   headings in general needed "more breathing space, over and under
   them" (the browser default's own small auto margins). Matches
   .prose's own h2/h3 convention (color/weight/letter-spacing), extended
   down to h1 and h4-h6 which .prose itself never needed. */
.blog-post h1 {
  font-size: clamp(1.8rem, 3.6vw, 2.5rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--navy);
  line-height: 1.2;
  margin: 2.25rem 0 1.5rem;
}
.blog-post h2 {
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--navy);
  margin: 2.25rem 0 1.5rem;
  /* 1.5rem, up from an earlier 1rem -- confirmed still too tight on a
     real sample (remote-observatory-hosting-australia's own "Remote
     Observatory Hosting in Australia" <h2>), reported again after the
     first margin pass. */
}
.blog-post h3 {
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--navy);
  margin: 2rem 0 1.1rem;
}
.blog-post h4 {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--navy);
  margin: 1.75rem 0 1rem;
}
.blog-post h5, .blog-post h6 {
  font-size: 1rem;
  font-weight: 700;
  color: var(--navy);
  margin: 1.5rem 0 0.9rem;
}
.blog-post h1:first-child, .blog-post h2:first-child, .blog-post h3:first-child,
.blog-post h4:first-child, .blog-post h5:first-child, .blog-post h6:first-child {
  margin-top: 0;
}

/* A real quote (confirmed on a real sample, cloudwatcher-k-factor-
   optimisation-tool's own <blockquote>, reported by the user as
   "formatted as normal text" -- no CSS here gave it any visual
   distinction from a plain paragraph at all): the same gold accent
   border-left already used sitewide for a callout/pull-quote box
   (style.css's own .quote-card/.comp-card), not a new invention.
   margin:1.5rem 2rem (real left/right inset, not just 0) -- confirmed
   on a real sample (dragonfly-home-assistant's own testimonial quote,
   reported as "slightly indented" in the original but not here): no
   explicit indent in the source at all, just the plain browser default
   <blockquote> margin (~40px each side) that this rule's own earlier
   `margin:1.5rem 0` was overriding away entirely. */
.blog-post blockquote {
  border-left: 3px solid var(--gold);
  padding: 0.25rem 0 0.25rem 1.25rem;
  margin: 1.5rem 2rem;
  font-style: italic;
  color: #4a5872;
}
.blog-post blockquote p:last-child {
  margin-bottom: 0;
}

/* A real list (.prose ul's own bullet-to-text gap, padding-left:1.15rem
   on the LI, is unrelated to this) sat flush with the body text's own
   left edge -- no visible indent of the LIST ITSELF at all, since
   .prose's own `ul{padding:0}` starts the bullet at that same edge --
   confirmed on two real samples (calling-all-astrophotographers,
   combining-the-dragonfly...'s own real <ul>s, not a WYSIWYG fake-
   bullet paragraph) and reported as "missing the indents". A real,
   explicit WYSIWYG indent (a kept `padding-left` inline style, see
   clean_elementor_post.py's strip_presentational) still wins over this
   default -- inline style always outranks a class rule regardless of
   specificity, so a list with its own real deeper indent (lunatico-and-
   the-environment's own 120px one) is unaffected either way. */
.blog-post ul, .blog-post ol {
  padding-left: 1.25rem;
}

/* WordPress core's own image-alignment convention (alignleft/alignright/
   aligncenter/alignnone) -- real intended layout from the source, kept as
   real classes rather than dropped (see clean_elementor_post.py's
   download_images), matched here with the same float treatment the
   manuals give their own wrapped images (manual.css's .img-float-left/
   -right), not a new invention. */
.blog-post img.alignleft {
  float: left;
  margin: 0.3rem 1.5rem 1rem 0;
}
.blog-post img.alignright {
  float: right;
  margin: 0.3rem 0 1rem 1.5rem;
}
.blog-post img.aligncenter {
  display: block;
  margin: 1.25rem auto;
}

/* Hero: matches the MANUALS' own hero band (wdocs/css/manual.css's
   .manual-hero/.manual-title/.device-tag), per explicit request -- same
   solid navy, same Exo 2 display title, same rotated gold label, not
   just the same font. Reuses the site's OWN --navy/--gold tokens
   (style.css) directly rather than manual.css's parallel --manual-navy/
   --manual-gold copies of the exact same values -- one real source, not
   a second set of tokens for blog to depend on manual.css for.
   Scoped to .blog-post-hero (the template's own dedicated class) so the
   other 215 .page-hero pages keep their existing dark-gradient look. */
.blog-post-hero {
  background: var(--navy);
  padding: 2.25rem 0;
}
.blog-post-hero::before {
  content: none; /* kill .page-hero's own radial-gradient overlay */
}
.blog-post-hero h1 {
  font-family: var(--f-heading);
  font-weight: 700;
  font-size: clamp(1.5rem, 3.4vw, 2.2rem);
  line-height: 1.1;
  margin-bottom: 0.7rem;
  max-width: none; /* .page-hero's own 28ch cap is for a longer marketing headline, not a title */
}

/* Category label -- same chip as the manuals' own device-tag (gold,
   rotated, mono, uppercase), just with the post's real category as its
   text (from blog.html's own listing, see render_post.py's
   find_category) instead of a product name. */
.blog-post-hero .device-tag {
  display: inline-flex;
  align-items: center;
  font-family: var(--f-mono);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #12233f;
  background: var(--gold);
  border-radius: 3px;
  padding: 0.3rem 0.7rem;
  transform: rotate(-2deg);
  box-shadow: 0 4px 10px -4px rgba(0, 0, 0, 0.4);
}

/* A real multi-column source section (see clean_elementor_post.py's
   render_section) -- e.g. Hive's own "Calendar" box sitting beside its
   main article text on staging -- becomes a real 2-column CSS grid, not
   a float: the aside is the LAST node after column 0's own content, so
   a float has nothing left after it to wrap around and just renders
   below everything instead of beside it (confirmed on the real Hive
   sample). A grid has no such ordering requirement -- both columns lay
   out side by side regardless of which one is taller. A float WAS tried
   for a second real shape (several short paired sections in sequence,
   "combining-the-dragonfly...") to let a later step's text wrap up
   around a still-tall earlier photo instead of leaving blank space --
   but confirmed WRONG directly against the real staging page: a float
   doesn't stop at its own row, so a LATER row's own short text was
   wrapping up around an EARLIER row's still-tall image instead of
   starting fresh below it, misaligning every row after the first. Grid
   is correct for both real shapes -- each row keeps its own independent
   height, matching how Elementor's own real column layout actually
   behaves (a flex row per section, not a page-wide float). */
.blog-post .blog-row {
  display: grid;
  grid-template-columns: 1fr 280px;
  gap: 2rem;
  margin: 1.5rem 0;
  /* No align-items override -- grid's own default (stretch) is what's
     wanted here, confirmed on a real sample (remote-observatory-
     hosting-australia's own image + "the figures are..." box row,
     reported by the user as the box sitting too high, "I believe it's
     bottom aligned with the image"): an earlier version of this rule
     set align-items:start, which left the SHORTER column (the boxed
     aside here) flush at the row's TOP with nothing below it -- no box,
     just blank page background -- instead of the box's own background
     reaching all the way down to match the taller column, which is
     what makes its bottom edge read as aligned with the image's own
     bottom. Stretch doesn't change anything for a bare image aside (an
     <img> has no background to visibly stretch) or for Hive's own
     Calendar box (already close to the main column's own height), so
     neither real sample regresses. */
}
/* Two or more further columns in the same row (e.g. a 3-column
   text+image+image section -- confirmed on a real sample, "combining-
   the-dragonfly...": Steps 1-2's text sits beside TWO separate photos)
   need a wider slot than the single-aside default -- each stays its own
   box, grouped side by side in .blog-aside-row rather than merged into
   one taller box. */
.blog-post .blog-row.blog-row-wide {
  grid-template-columns: 1fr 380px;
}
/* Real shared heights are set directly on each <img> (inline style, see
   clean_elementor_post.py's apply_gallery_heights) whenever the source's
   own real width/height data made that possible -- these rules are just
   the fallback for whenever it wasn't (a box holding something other
   than one plain image). */
.blog-post .blog-aside-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: flex-start;
}
.blog-post .blog-aside-row .blog-aside {
  flex: 1 1 160px;
  width: auto;
}
/* Boxed/tinted treatment (mirrors the site's own existing card
   conventions -- style.css's .office-card/.pi-card, not a new
   invention) is for a REAL sidebar note with its own content (a
   heading, real text -- Hive's "Calendar" box). A column that's nothing
   but image(s) gets NO box -- confirmed wrong on a real sample
   ("combining-the-dragonfly..."): a bare pair of photos next to a
   couple of steps has no real sidebar content to set apart, so a
   border/background around it was pure decoration with nothing behind
   it to justify it. */
/* width:100% -- NOT a fixed px value -- so the aside always fills
   whatever width its OWN grid cell actually got: .blog-row's default
   280px column (Hive's own boxed sidebar, unaffected either way, since
   that track itself is already 280px) or a real computed percentage
   split (see clean_elementor_post.py's render_section) when the source
   had real column-width data. A hardcoded width here was overriding
   that computed split entirely -- confirmed wrong on a real sample
   (neaf-2025-lunatico-astro, a real 50/50 text+image row): the aside
   stayed pinned to 280px regardless of its real 50% share, leaving the
   main column far wider than intended and the image column far
   narrower. */
.blog-post .blog-aside {
  width: 100%;
  padding: 1.5rem;
  background: var(--mist, #f4f6fa);
  border: 1px solid rgba(27, 58, 107, 0.1);
  border-radius: 8px;
  box-sizing: border-box;
}
.blog-post .blog-aside.blog-aside-plain {
  padding: 0;
  background: none;
  border: none;
  border-radius: 0;
}
.blog-post .blog-aside h2 {
  font-size: 1.1rem;
  text-align: center;
  margin-bottom: 0.75rem;
}
/* 1.05rem, up from an earlier 0.95rem -- confirmed too close to the
   0.9rem body text below it (barely a 5.5% step) to read as a real
   title/body size hierarchy at all, reported by the user as "the
   relation between the size of the month titles and their items hasn't
   been maintained"; the plugin's own CSS never set an explicit size for
   either (it relies on the theme's own default h4-vs-p relationship, no
   fixed ratio to copy), so this is a normal, clearly-stepped heading
   size instead, not a measured original ratio. */
.blog-post .blog-aside h4 {
  font-family: var(--f-heading);
  font-size: 1.05rem;
  margin: 0.9rem 0 1.1rem;
}
.blog-post .blog-aside h4:first-child {
  margin-top: 0;
}
/* Real content -- confirmed on Hive's own source: several checklist
   lines under one month sit inside a SINGLE <p>, separated by a real
   <br><br> (a genuine double line break, not two separate paragraphs).
   A tighter line-height doesn't touch that real structure, just shrinks
   how much vertical space each line (including the blank one from
   <br><br>) takes up -- confirmed too loose at the default 1.55 for a
   compact checklist read, and (reported on the real Hive page once its
   aside got its own real, much wider column -- see .blog-aside below)
   still too loose at 1.3, then at 1.15 (reported again, "a bit more"):
   the gap between two checklist lines under the same month read bigger
   than the gap from a month's own title down to its first line, the
   reverse of the intended hierarchy. 1.0 (normal single-line height,
   the tightest a <br><br> blank line can get without starting to crowd
   a single long line's own wrap) shrinks that blank line further
   without touching how a single long line itself wraps; the month
   title's own margin-bottom above (1.1rem) is what actually sets the
   two apart. Scoped to .blog-timeline-content specifically, NOT every
   .blog-aside p -- confirmed wrong applied generally on a real sample
   (lunatico-and-the-environment's own real caption-like reaction text
   under its "Welcome to Sodom" photo, a genuine multi-line WRAPPED
   paragraph, not a <br><br> checklist at all): line-height:1 crammed
   its wrapped lines together "very close", reported by the user as
   needing "the same spacing as normal text" -- a real sentence wrapping
   onto several lines needs real line spacing, this tight value is only
   correct for the <br><br> blank-line case above. */
.blog-post .blog-aside p {
  font-size: 0.9rem;
  line-height: 1.5;
  margin-bottom: 0.5rem;
}
/* max-width, NOT a forced width:100% (an earlier version of this rule) --
   confirmed wrong on a real sample (Hive's own "Calendar" box, reported
   by the user as "extremely big now"): once the aside legitimately got
   its own real, much wider column (see .blog-aside below), width:100%
   force-stretched every image inside it up to that FULL width even when
   the image's own real, native size was much smaller (Hive's cover photo
   is natively 212px wide, stretched here to ~550px, pixelated and nearly
   2.5x too tall) -- the exact opposite of the sitewide default
   (style.css's own `img{max-width:100%}`) every other image on the site
   already gets, which caps oversized images down but never stretches an
   undersized one up. A real, large photo (confirmed on neaf-2025-
   lunatico-astro's own real 50/50 photo row, natively 1024px+) still
   fills the column exactly the same either way, since max-width only
   ever caps a LARGER image down to the container -- nothing here
   regresses that case. */
.blog-post .blog-aside img {
  max-width: 100%;
  height: auto;
  border-radius: 4px;
  margin: 0.5rem 0 1rem;
  /* margin-bottom 1rem, up from a flat 0.5rem both sides -- confirmed
     too tight on a real sample (lunatico-and-the-environment's own
     "Welcome to Sodom" photo + its one-line reaction text right below
     it, in the same boxed aside): reported by the user as "image
     footers don't get enough space to separate them from their image",
     the gap between an image and real caption-like text right after it
     specifically, not the image's own top margin above it. */
}
/* A real WordPress aligncenter image (Hive's own cover photo, lunatico-
   and-the-environment's own "Welcome to Sodom" photo) was losing its
   real centering once INSIDE an aside specifically -- confirmed a real
   specificity collision: the sitewide `.blog-post img.aligncenter{margin:
   1.25rem auto}` (the rule that actually centers it, via auto left/right
   margins) and the rule right above this one both have the exact same
   specificity, and the aside rule comes LATER in this file, so its own
   flat `margin:0.5rem 0 1rem` (not auto) silently won and cancelled the
   centering -- reported by the user two ways: Hive's cover image "not
   centre aligned", and lunatico-and-the-environment's own photo
   "horizontal alignment with respect to its footer a bit off". The
   extra ".aligncenter" in this selector outranks both equally-specific
   rules, restoring the real centering without touching the vertical
   margins right above. */
.blog-post .blog-aside img.aligncenter {
  margin-left: auto;
  margin-right: auto;
}
.blog-post .blog-aside.blog-aside-plain img {
  margin: 0 0 1rem;
  border-radius: 0; /* rounded corners are part of the boxed/card look above; a bare image (no box) keeps its real, square-cornered original */
}
.blog-post .blog-aside.blog-aside-plain img:last-child {
  margin-bottom: 0;
}
.blog-post .blog-aside .section-divider {
  border-top: 1px solid rgba(27, 58, 107, 0.12);
  margin: 0.9rem 0;
}

/* A real vertical timeline (icon circle + connecting line per item) --
   the real source's own visual shape for an eael-feature-list widget
   (confirmed on Hive's own "Calendar" box: a FontAwesome icon circle
   connected by a line, per month -- see clean_elementor_post.py's
   clean_feature_list), reported missing by the user ("is there nothing
   we can do to emulate the line with circles... the calendar sidebar
   has?"). Self-contained here (not the sitewide .flow/.flow-dot/
   .flow-step the main site already uses for a similar shape, e.g.
   cw-watchdog.html) -- deliberately not reused as-is: .flow-step itself
   has no display:flex rule of its own in style.css, so .flow-left and
   .flow-content would stack vertically rather than side by side,
   unconfirmed/unverified sitewide behavior this migration shouldn't
   risk depending on or silently fixing (a shared, non-blog stylesheet,
   out of scope here) -- a fresh, scoped-to-.blog-post version sidesteps
   that risk entirely. The dot holds a real inline checkmark SVG (not
   the original's own FontAwesome "forumbee" icon -- a generic brand
   logo with no real connection to "a completed checklist item" anyway,
   and would need a whole new icon-font dependency this migration
   doesn't otherwise add anywhere; a real vector checkmark matches the
   user's own request for "an icon" rather than a plain text character,
   in the same inline-SVG style already used sitewide, e.g. the FAQ's
   own chevron above). Gold (var(--gold)), not navy -- per explicit
   request, matching the gold already used elsewhere (the hero's own
   category chip, CTA buttons), with a dark icon on top of it (var(--
   void)), the same gold+dark-icon convention already used sitewide
   (style.css's own .device-tag/.btn-cta) rather than the white-on-navy
   this started with. */
.blog-post .blog-timeline {
  margin: 0.5rem 0;
}
.blog-post .blog-timeline-step {
  display: flex;
  gap: 0.6rem;
}
.blog-post .blog-timeline-left {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex-shrink: 0;
  width: 26px;
}
.blog-post .blog-timeline-dot {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--gold);
  color: var(--void);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.blog-post .blog-timeline-dot svg {
  width: 14px;
  height: 14px;
}
.blog-post .blog-timeline-line {
  width: 2px;
  background: rgba(27, 58, 107, 0.15);
  flex: 1;
  margin: 2px auto 0;
}
.blog-post .blog-timeline-step:last-child .blog-timeline-line {
  display: none;
}
.blog-post .blog-timeline-content {
  padding-bottom: 0.75rem;
}
.blog-post .blog-timeline-content h4 {
  margin: 0 0 0.3rem;
}
.blog-post .blog-timeline-content p {
  margin-bottom: 0;
  line-height: 1;
}

@media (max-width: 700px) {
  .blog-post .blog-row,
  .blog-post .blog-row.blog-row-wide {
    grid-template-columns: 1fr;
  }
}

/* A real Elementor "gallery" widget (see clean_elementor_post.py's
   clean_gallery) -- confirmed on a real sample (neaf-2025-lunatico-
   astro): 6 separate galleries, 59 real photos, the source's own layout
   a real masonry grid (data-settings: "gallery_layout":"masonry").
   A fixed-height grid with object-fit:cover (an earlier version of this
   rule) cropped every photo to a uniform box, discarding each one's own
   real framing/aspect ratio -- confirmed wrong: portrait and landscape
   shots alike got the same square-ish crop. CSS multi-column is the
   standard no-JS way to get a real masonry effect: each image keeps
   its own natural aspect ratio (width:100%, height:auto), and
   break-inside:avoid stops one photo being split across two columns. */
.blog-post .blog-gallery {
  column-count: 3;
  column-gap: 1rem;
  margin: 1.5rem 0;
}
.blog-post .blog-gallery img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 6px;
  margin: 0 0 1rem;
  break-inside: avoid;
}
@media (max-width: 700px) {
  .blog-post .blog-gallery {
    column-count: 2;
  }
}

/* A real embedded YouTube video (see clean_elementor_post.py's
   clean_video) -- the standard responsive-iframe pattern. Shorts are
   vertical (9:16); a normal embed is landscape (16:9) -- detected from
   the source URL itself so a portrait video isn't letterboxed. */
.blog-post .blog-video {
  position: relative;
  width: 100%;
  max-width: 640px;
  aspect-ratio: 16 / 9;
  margin: 1.5rem auto;
}
.blog-post .blog-video.blog-video-vertical {
  max-width: 360px;
  aspect-ratio: 9 / 16;
}
.blog-post .blog-video iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 6px;
}

/* A real FAQ accordion (see clean_elementor_post.py's clean_toggle),
   overriding style.css's own sitewide .faq/.faq-item/.faq-body (a
   plain white box with no padding on the closed <summary> state at
   all) per explicit request: a light grey box (the same var(--mist)
   tint already used for .blog-aside, not a new color), real padding on
   every side of the closed state, and a real chevron instead of the
   browser's own default disclosure triangle (see make_faq_chevron) --
   rotating on [open], the same pattern already used sitewide for a
   disclosure triangle (style.css's own .manual-toc/.toc-chapter
   details), just a real chevron shape instead of a CSS-generated
   character. */
.blog-post .faq-item {
  background: var(--mist, #f4f6fa);
}
.blog-post .faq-item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 1rem 1.25rem;
  cursor: pointer;
  list-style: none;
  font-weight: 700;
  color: var(--navy);
}
.blog-post .faq-item summary::-webkit-details-marker {
  display: none;
}
.blog-post .faq-item .collapse-arrow {
  flex-shrink: 0;
  transform: rotate(-180deg);
  transition: transform 0.2s ease;
}
.blog-post .faq-item[open] .collapse-arrow {
  transform: rotate(0deg);
}
.blog-post .faq-body {
  background: var(--mist, #f4f6fa);
}
