/* ==========================================================================
   Single Blog Post
   Templates : single.php + template-parts/blog/*
   Prefixes  : uq-blog-page, uq-blog-breadcrumbs, uq-blog-header,
               uq-blog-main, uq-blog-toc, uq-blog-ai,
               uq-blog-share, uq-blog-share-bar, uq-blog-related
   ==========================================================================

   ITS OWN STYLESHEET, ON PURPOSE. style.css is 396KB and loads on every page of
   the site, so keeping the Blog out of it is the strongest guarantee that
   Projects, Services, Locations and Pages are byte-for-byte unchanged -- and
   the whole Blog design can be retired later by deleting one file.

   Loaded only on a single Blog Post that has blog_modules rows, with style.css
   ('html5blank') as its dependency so it prints after it and wins ties on
   source order. See uq_blog_assets() in inc/blog.php.

   ---------------------------------------------------------------------------
   PROJECT DETAILS IS THE DESIGN REFERENCE
   ---------------------------------------------------------------------------
   Per the client: the Blog must read as the Blog version of the Project
   Details page, not as a second website. Every value below that could have been
   an invention is instead taken from .uq-project-details / .uq-related-projects
   in style.css. The ones worth naming, because they are what makes the two
   pages feel like one site:

     grid          1fr + 372px aside, 48px gap, 1200px container, 5vw gutters
     cards         24px padding, 1px --uq-theme-border, 10px radius,
                   24px stack gap, no shadow
     sticky        top: 148px, above 992px only
     H1            --uq-theme-primary BLUE, Roobert 500, 38/34/30/27,
                   line-height 1.14, tracking -0.025em, 20px below
     in-copy       h2/h3/h4 at 26/21/18, blue, Roobert 500, 36px/14px margins
     body copy     16px --uq-module-description-size, --uq-theme-text
     eyebrow chip  amber pill, 4px 12px, 999px radius, Inter 14px/600,
                   tracking -0.01em, black text, brightness(0.96) on hover
     FAQ           question 17 / number 19 / answer 15 at 1.6, header left at
                   the column edge, 28px to the first row, title 30/28/26/24
     cards row     3.15 cards visible, 24px gap, 16/9 media at 12px radius with
                   a 1px border and NO card border, title Roobert 22/500/1.2 at
                   #111 clamped to two lines, meta 13px #767676
     arrows        44px circle, --uq-theme-primary ground, white glyph, 10px gap
     CTA           the shared .uq-article-end component, untouched

   Three components are rendered entirely by their own CSS in style.css and are
   only ever passed variables from here, never new declarations:

     .uq-faq             the FAQ accordion (with js/faq.js)
     .uq-article-end     the CTA Footer
     .breadcrumbs        the site breadcrumb trail

   ONE DELIBERATE DEVIATION, and it is the only one: body copy runs at a 1.62
   line-height where Project Details uses 1.4. Project copy is a few paragraphs
   of intro; a Blog article is two thousand words in the same column, and 1.4
   sets it too tight to read at length. Size, colour, family and the whole
   heading ladder are identical. It is one token -- --uq-blog-body-line -- if
   the client would rather match exactly.

   Quo (the client's reference) informed only three things, all layout rather
   than looks: that the contents list belongs in the sidebar, the composition of
   the "Summarize article with" row, and roughly three cards across for the
   related row.

   OVERFLOW DISCIPLINE. Both grid tracks are minmax(0, ...) and the article body
   caps images, tables, pre and iframes, so a long word, a wide table or a
   pasted embed cannot push the page sideways at any tested width (1440, 1024,
   768, 500, 375). The carousel scrolls inside its own clipped viewport, never
   the page. */

/* ==========================================
   Page reset
   ========================================== */

/* The theme has a global `main { float: right; width: 74% }` and a
   `main { margin: 0 0 40px }` inside a max-width block, both left over from the
   old sidebar layout. Projects and Services each answer it with their own
   `main.uq-*-flex-page` rule; this is the Blog's. (0,1,1) beats the bare `main`
   selector, and this sheet also loads after style.css, so no !important is
   needed. */
main.uq-blog-flex-page {
    display: block;
    float: none;
    clear: both;
    width: 100%;
    max-width: none;
    margin: 0;
    /* NOT overflow: hidden. A sticky sidebar inside an overflow-hidden ancestor
       never sticks -- which is why css/flexible-content.css, whose .uq-flex-page
       rule does set it, is not loaded on this template. */
    overflow: visible;
}

.uq-blog-page,
.uq-blog-page *,
.uq-blog-page *::before,
.uq-blog-page *::after {
    box-sizing: border-box;
}

.uq-blog-page {
    /* Geometry — Project Details' own values. */
    --uq-blog-gap: 48px;
    --uq-blog-aside-width: 372px;
    --uq-blog-card-radius: 10px;
    --uq-blog-media-radius: 12px;
    --uq-blog-border: var(--uq-theme-border, #e5e5e5);
    /* Clears the fixed .header.stuck (blue bar + nav) plus breathing room. The
       same figure .uq-project-details--sticky uses, and the same one
       js/blog.js falls back to, so a sticky column, a TOC jump and a plain
       #anchor landing all agree. */
    --uq-blog-sticky-top: 148px;

    /* Colour — the theme's real token set. */
    --uq-blog-primary: var(--uq-theme-primary, #104E8B);
    --uq-blog-primary-dark: #0d3f71;
    --uq-blog-accent: var(--uq-theme-accent, #FDBB2F);
    --uq-blog-muted: var(--uq-theme-text, #3F4B58);
    --uq-blog-ink: #000000;
    --uq-blog-tint: #f7f6f5;

    /* ---- Type: the page title ----
       NO TOKENS HERE. The four --uq-blog-title-size* values that used to sit at
       this point are removed, and so is the 56px ladder that briefly replaced
       them: pinning the Blog Default to the .uq-heading-h1 scale made Default
       and an explicit "H1" choice render identically, which is not a heading
       system -- it is one hardcoded size with an unused control beside it.

       The Blog Header title is now a member of the site's shared section-title
       rule in style.css, alongside .uq-service-feature__title,
       .uq-process__section-title, .uq-related-projects__title and the rest, so:

         Default            --uq-module-title-*   clamp(40px, 3.4vw, 48px)
                                                  / 40 / 36 / 32
         H1..H6 / Display   .uq-heading-*         the global site scale

       Both pages resolve through exactly the same two rules, and there is no
       Blog-specific title scale left in this file to drift from it. */
    /* The FAQ heading stays below the H1, exactly as it does on a Project. */
    --uq-blog-faq-title-size: 30px;
    --uq-blog-faq-title-size-lg: 28px;
    --uq-blog-faq-title-size-md: 26px;
    --uq-blog-faq-title-size-sm: 24px;
    --uq-blog-body-size: var(--uq-module-description-size, 16px);
    /* The one deviation from Project Details — see the header comment. */
    --uq-blog-body-line: 1.62;

    font-family: var(--uq-site-font-body, Arial, sans-serif);
    color: var(--uq-blog-ink);
    background: #ffffff;
}

/* One inner box for every Blog section: the site's 1200px container. */
.uq-blog-breadcrumbs__container,
.uq-blog-header__container,
.uq-blog-main__container,
.uq-blog-share-bar__container,
.uq-blog-related__container {
    width: 100%;
    max-width: 1200px;
    margin: 0 auto;
}

/* The article column's own measure, expressed from the grid tokens so it can
   never drift from the grid: used by the Share bar, which is a separate
   full-width section that has to line up under the copy. */
.uq-blog-share-bar__row {
    max-width: calc(100% - var(--uq-blog-aside-width) - var(--uq-blog-gap));
}

/* ==========================================
   Breadcrumbs
   ==========================================
   .breadcrumbs itself is styled by style.css -- it is the site's single
   breadcrumb markup, and it reads identically here to every other page. Only
   its container and spacing are set, matching .uq-project-breadcrumbs. */
.uq-blog-breadcrumbs {
    width: 100%;
    padding: 0 5vw 4px;
    background: #ffffff;
}

.uq-blog-breadcrumbs .breadcrumbs {
    margin: 0;
    /* A long trail wraps inside the container instead of widening the page. */
    overflow-wrap: anywhere;
}

/* ==========================================
   Blog Header
   Layout: blog_header
   ========================================== */
.uq-blog-header {
    --uq-bh-space-top: 32px;
    --uq-bh-space-bottom: 48px;
    display: block;
    width: 100%;
    padding: var(--uq-bh-space-top) 5vw var(--uq-bh-space-bottom);
    background: #ffffff;
}

/* Inside the header the section padding already provides the offset. */
.uq-blog-header .uq-blog-breadcrumbs {
    padding: 0 0 16px;
}

.uq-blog-header__text {
    /* A measured column rather than the full 1200px: a 1200px-wide H1 and a
       1200px-wide standfirst read as a banner, not as an article opening. 780px
       is the width the article column itself resolves to at desktop
       (1200 - 372 - 48), so the header and the copy share one measure.

       NOT named __intro, and that is not cosmetic. style.css carries a shared
       rule for inline links inside Flexible Content copy:

         .uq-flex-page [class*="description"] a,
         .uq-flex-page [class*="lead"] a,
         .uq-flex-page [class*="intro"] a,
         .uq-flex-page [class*="subtitle"] a,
         .uq-flex-page [class*="answer"] a { text-decoration: underline; ... }

       single.php puts .uq-flex-page on <main> deliberately (it is what gives
       the Blog the shared CTA typography), so any container whose class merely
       CONTAINS one of those five words underlines every link inside it at
       (0,2,1) -- which no (0,1,0) rule here can undo. As __intro this wrapper
       underlined the category chip and reset its colour and font. Renamed
       rather than fought with a deeper selector: the shared rule is right, and
       a pill-shaped label is not body copy. .uq-blog-header__description keeps
       its name on purpose -- it IS copy, and an inline link in it should get
       exactly that treatment. */
    width: 100%;
    /* 960px, not 780px.
     *
       780px was the article column's own measure (1200 - 372 aside - 48 gap),
       chosen so the header shared one measure with the body copy. That is the
       right measure for a 16px paragraph and the wrong one for a 48px heading:
       at 780px a normal article title -- "How to Know When Your Roof Needs
       Repair" -- broke to a second line while roughly 420px of the 1200px
       container sat empty to its right, and the 1200px hero directly beneath it
       made that gap read as a mistake rather than a margin.
     *
       960px is 80% of the container. It holds a normal title on one line at
       desktop, still gives a long one a natural break, and stays clearly inside
       the container so the header does not become a full-bleed banner. No fixed
       width and no <br>: width:100% above still caps it to the container at
       every narrower viewport, so this only ever applies where the space
       genuinely exists. */
    max-width: 960px;
}

/* 16px, the gap .uq-project-details__meta holds above its own H1, so the chip
   sits the same distance off the title on both pages. */
.uq-blog-header__eyebrow {
    margin: 0 0 16px;
}

/* The Project category chip, to the value: amber pill, Inter 14px/600, black,
   no uppercase, -0.01em. Not a Blog invention. */
.uq-blog-header__category {
    display: inline-flex;
    align-items: center;
    max-width: 100%;
    padding: 4px 12px;
    border-radius: 999px;
    background: var(--uq-blog-accent);
    color: #000000;
    font-family: var(--uq-site-font-body, Arial, sans-serif);
    font-size: 14px;
    font-weight: 600;
    line-height: 1.35;
    letter-spacing: -0.01em;
    text-decoration: none;
    overflow-wrap: anywhere;
    transition: filter 0.2s ease, box-shadow 0.2s ease;
}

a.uq-blog-header__category:hover,
a.uq-blog-header__category:focus-visible {
    filter: brightness(0.96);
    box-shadow: 0 2px 10px -2px rgba(16, 78, 139, 0.28);
    color: #000000;
}

a.uq-blog-header__category:focus-visible {
    outline: 2px solid var(--uq-blog-primary);
    outline-offset: 2px;
}

/* The Project H1, to the value -- including the brand blue. On a Project page
   the H1, the section titles, the in-copy headings and the FAQ heading are all
   --uq-theme-primary; a near-black Blog H1 was the single biggest reason the
   page read as a different site. */
.uq-blog-header .uq-blog-header__title {
    margin: 0 0 20px;
    padding: 0;
    color: var(--uq-blog-primary);
    font-family: var(--uq-site-font-heading, Arial, sans-serif);
    text-align: left;
    text-transform: none;
    text-wrap: balance;
}

/* Default only -- Display/H1-H6 fall through to the shared uq-heading-* classes.
 *
   NO font-size. It comes from the shared section-title rule in style.css, which
   this selector is now listed in; declaring one here would beat that rule (this
   sheet loads after style.css) and re-create the private Blog scale that was
   just removed.
 *
   1.08 / -0.035em are .uq-process__section-title's Default values -- the same
   pair .uq-project-details__title now carries -- so a Default Blog title and a
   Default Project title are the same size AND the same shape. */
.uq-blog-header__title:not([class*="uq-heading-"]) {
    font-weight: 500;
    line-height: 1.08;
    letter-spacing: -0.035em;
}

/* The standfirst. One step above the 16px body copy, on the body face and the
   body colour, so it reads as the article's opening sentence rather than as a
   second heading. 860px inside the title's 960px keeps the conventional
   standfirst shape -- a slightly shorter line than the heading above it -- while
   still using the width the header now has; the 1.55 line-height is the
   long-form step, matching the article body rather than the 1.4 the site's
   short module descriptions use. */
.uq-blog-header__description {
    margin: 0;
    max-width: 860px;
    color: var(--uq-blog-muted);
    font-size: 18px;
    font-weight: 400;
    line-height: 1.55;
}

.uq-blog-header__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 16px;
    margin: 20px 0 0;
    color: var(--uq-blog-muted);
    /* The Project card's meta step. */
    font-size: 13px;
    line-height: 1.4;
}

/* gap is load-bearing, not decoration: a flex container drops whitespace-only
   text nodes between its items, so the space between the word "Updated" and
   its <time> would disappear and the line would read "UpdatedApril 18, 2026". */
.uq-blog-header__meta-item {
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

/* A dot between items rather than a border, so a wrapped row never leaves a
   dangling separator at the end of a line. */
.uq-blog-header__meta-item + .uq-blog-header__meta-item::before {
    content: "";
    display: inline-block;
    width: 4px;
    height: 4px;
    margin-right: 11px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.45;
}

.uq-blog-header__author {
    color: var(--uq-blog-ink);
    font-weight: 600;
}

/* The byline links to the native author archive (author.php -> the shared hub).
   Everything is inherited from .uq-blog-header__author, so the link is the same
   size, weight and colour as the word "By" beside it and the date before it --
   the ONLY thing declared here is what the theme's global `a { color: #FDBB2F;
   font-weight: 600 }` would otherwise impose. Without it the author's name
   would render yellow in the middle of a grey meta line.

   (0,2,0) beats the (0,0,1) element selector, so no !important is needed. */
.uq-blog-header__meta .uq-blog-header__author-link {
    color: inherit;
    font-family: inherit;
    font-size: inherit;
    font-weight: inherit;
    line-height: inherit;
    text-decoration: none;
    transition: color 0.2s ease;
}

.uq-blog-header__meta .uq-blog-header__author-link:hover {
    color: var(--uq-blog-primary);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.uq-blog-header__meta .uq-blog-header__author-link:focus-visible {
    outline: 2px solid var(--uq-blog-primary);
    outline-offset: 2px;
    color: var(--uq-blog-primary);
}

/* Media treatment matched to the Project card: 1px border, 12px radius, a
   cinematic band and the same #eef1f4 placeholder ground, so the lead image and
   the related cards are visibly the same component family. aspect-ratio rather
   than a height, so the space is reserved before the image arrives and nothing
   shifts. */
.uq-blog-header__media {
    display: block;
    width: 100%;
    margin: 36px 0 0;
    overflow: hidden;
    border: 1px solid var(--uq-blog-border);
    border-radius: var(--uq-blog-media-radius);
    background: #eef1f4;
}

/* HEIGHT IS THE RATIO, AND ONLY THE RATIO. The client asked for a more compact
   header, so this band went from 16/9 to 2/1 -- measured on a real post, 674px
   tall at 1440 becomes 599px, and every width scales by the same 11%:

       1440   674 -> 599        992   493 -> 438
       1200   598 -> 532        768   379 -> 337

   A 21/9 band was tried first and came back as too short -- the brief was "the
   height smaller", not a cinematic strip -- so 2/1 is the deliberate moderate
   step: obviously shorter than 16/9, still clearly a lead photograph rather than
   a letterbox.

   NOTHING ELSE MOVES. The width is still 100% of the column, object-fit stays
   `cover` with a centred origin, so the photograph is re-cropped rather than
   squashed and no image is distorted. The border, the 12px radius, the #eef1f4
   placeholder ground and the 36px top margin are untouched, and because the size
   is still expressed as an aspect-ratio the space is reserved before the image
   loads -- the header does not shift as it arrives. */
.uq-blog-header__image {
    display: block;
    width: 100%;
    height: 100%;
    aspect-ratio: 2 / 1;
    object-fit: cover;
    object-position: center;
}

/* ==========================================
   Blog Main Content
   Layout: blog_main
   ========================================== */
.uq-blog-main {
    --uq-bm-space-top: 24px;
    --uq-bm-space-bottom: 80px;
    display: block;
    width: 100%;
    padding: var(--uq-bm-space-top) 5vw var(--uq-bm-space-bottom);
    background: #ffffff;
}

/* 1fr + a fixed 372px aside, 48px gap -- the Project Details grid.
   minmax(0, ...) on BOTH tracks is what stops a long word, a wide table or a
   pasted embed in the WYSIWYG from pushing the page into horizontal overflow:
   a 1fr track's implicit minimum is auto, which is the content's own width. */
.uq-blog-main__layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, var(--uq-blog-aside-width));
    align-items: start;
    gap: var(--uq-blog-gap);
    width: 100%;
}

.uq-blog-main--single .uq-blog-main__layout {
    grid-template-columns: minmax(0, 1fr);
}

.uq-blog-main__content,
.uq-blog-main__aside {
    min-width: 0;
}

/* ---------- Article body ---------- */
/* No max-width at desktop: the grid already resolves this column to 780px,
   exactly as it does on a Project. The cap below 992px is the one addition --
   stacked, the column becomes the full container, and 16px prose at 1100px is
   too long a line to read. */
.uq-blog-main__article {
    color: var(--uq-blog-muted);
    font-size: var(--uq-blog-body-size);
    font-weight: var(--uq-module-description-weight, 400);
    line-height: var(--uq-blog-body-line);
}

.uq-blog-main__article > :first-child {
    margin-top: 0;
}

.uq-blog-main__article > :last-child {
    margin-bottom: 0;
}

.uq-blog-main__article p,
.uq-blog-main__article ul,
.uq-blog-main__article ol {
    margin: 0 0 20px;
    font-size: inherit;
    line-height: inherit;
}

/* The Project in-copy heading ladder, to the value: 26/21/18, brand blue,
   Roobert 500, 36px above and 14px below. */
.uq-blog-main .uq-blog-main__article h2,
.uq-blog-main .uq-blog-main__article h3,
.uq-blog-main .uq-blog-main__article h4 {
    margin: 36px 0 14px;
    padding: 0;
    color: var(--uq-blog-primary);
    font-family: var(--uq-site-font-heading, Arial, sans-serif);
    font-weight: 500;
    text-transform: none;
    /* Anchor landing offset, so a #fragment -- from the TOC, a shared link or a
       search result -- lands below the stuck site header. */
    scroll-margin-top: var(--uq-blog-sticky-top);
}

.uq-blog-main .uq-blog-main__article h2 {
    font-size: 26px;
    line-height: 1.15;
    letter-spacing: -0.02em;
}

.uq-blog-main .uq-blog-main__article h3 {
    font-size: 21px;
    line-height: 1.25;
    letter-spacing: -0.01em;
}

.uq-blog-main .uq-blog-main__article h4 {
    font-size: 18px;
    line-height: 1.3;
    letter-spacing: -0.01em;
}

.uq-blog-main__article h2:first-child,
.uq-blog-main__article h3:first-child,
.uq-blog-main__article h4:first-child {
    margin-top: 0;
}

/* Headings are not the only thing an editor can link to: any id in the copy
   gets the same landing offset. */
.uq-blog-main__article [id] {
    scroll-margin-top: var(--uq-blog-sticky-top);
}

.uq-blog-main__article ul,
.uq-blog-main__article ol {
    padding-left: 22px;
}

.uq-blog-main__article li {
    margin: 0 0 8px;
    font-size: inherit;
    line-height: inherit;
}

.uq-blog-main__article li:last-child {
    margin-bottom: 0;
}

.uq-blog-main__article strong,
.uq-blog-main__article b {
    color: #000000;
    font-weight: 600;
}

/* Blue and underlined, exactly as .uq-project-details__content a. `font:
   inherit` is load-bearing: style.css sets a global `a { font-weight: 600 }`,
   which otherwise leaves every inline link heavier than its sentence. */
.uq-blog-main__article a {
    color: var(--uq-blog-primary);
    font: inherit;
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
    transition: color 0.2s ease;
}

.uq-blog-main__article a:hover,
.uq-blog-main__article a:focus-visible {
    color: var(--uq-blog-primary-dark);
}

.uq-blog-main__article img {
    max-width: 100%;
    height: auto;
    border-radius: var(--uq-blog-card-radius);
}

.uq-blog-main__article figure {
    margin: 28px 0;
}

.uq-blog-main__article figcaption {
    margin-top: 10px;
    color: var(--uq-blog-muted);
    font-size: 13px;
    line-height: 1.5;
}

.uq-blog-main__article blockquote {
    margin: 28px 0;
    padding: 4px 0 4px 22px;
    border-left: 3px solid var(--uq-blog-accent);
    color: var(--uq-blog-ink);
    font-size: 18px;
    line-height: 1.5;
}

.uq-blog-main__article blockquote p:last-child {
    margin-bottom: 0;
}

/* A wide table, a long code block or a pasted embed must scroll inside itself,
   not widen the page. */
.uq-blog-main__article table {
    display: block;
    width: 100%;
    max-width: 100%;
    overflow-x: auto;
    border-collapse: collapse;
    font-size: 15px;
}

.uq-blog-main__article th,
.uq-blog-main__article td {
    padding: 10px 12px;
    border: 1px solid var(--uq-blog-border);
    text-align: left;
}

.uq-blog-main__article pre {
    max-width: 100%;
    overflow-x: auto;
    padding: 16px;
    border-radius: var(--uq-blog-card-radius);
    background: var(--uq-blog-tint);
    font-size: 14px;
}

.uq-blog-main__article iframe,
.uq-blog-main__article video,
.uq-blog-main__article embed,
.uq-blog-main__article object {
    max-width: 100%;
}

/* ---------- FAQ block ---------- */
.uq-blog-main__faq-block {
    margin-top: 56px;
}

/* The FAQ component's own rules in style.css do the rendering. Everything here
   is either geometry that makes a full-bleed section sit inside a column, or a
   VALUE for one of the component's own tokens -- and every value is the one
   Project Details uses, so the two FAQs are the same FAQ. Not one font,
   colour, border, divider, arrow, hover, focus, answer or header rule is
   redeclared, and js/faq.js drives the accordion unchanged.

   .uq-faq is authored as a full-bleed section, so three things have to go: its
   5vw gutters (the inline --uq-faq-container:100% only removes the max-width,
   not the padding), its vertical section padding (zeroed by the inline
   --uq-faq-space-* the template sets), and its overflow clip, which would cut
   the focus ring off a trigger on the column edge. */
.uq-blog-main__faq {
    --uq-faq-container: 100%;
    --uq-faq-space-top: 0;
    --uq-faq-space-bottom: 0;
    width: 100%;
    padding-right: 0;
    padding-left: 0;
    overflow: visible;
}

/* Project Details' own FAQ scale and header composition. The number COLUMN
   follows the glyph via the component's own base-to-26px ratio, so a 62px
   gutter sized for a 26px "Q1." does not leave a hole beside a 19px one; the
   template still supplies --uq-faq-number-base (62/80/96 for 1-9/10-99/100+). */
.uq-blog-main .uq-faq {
    --uq-faq-question-size: 17px;
    --uq-faq-number-size: 19px;
    --uq-faq-answer-size: 15px;
    --uq-faq-answer-line-height: 1.6;
    --uq-faq-header-align: left;
    --uq-faq-header-inline: 0;
    --uq-faq-header-width: 100%;
    --uq-faq-header-gap: 28px;
    --uq-faq-number-width: calc(var(--uq-faq-number-base, 62) / 26 * var(--uq-faq-number-size));
}

/* The FAQ heading. One class deeper than the shared section-title rule
   `.uq-faq__title:not([class*="uq-heading-"])` (0,2,0 -> 0,3,0), which is what
   it takes to win without !important. The :not() is carried over verbatim so an
   explicit ACF Heading Style choice still overrides through the shared
   uq-heading-* classes. Size only -- the Roobert face, the 500 weight, the
   brand blue, the balance and the left alignment all come from the component
   and the header tokens above. Same 30/28/26/24 ladder as a Project. */
.uq-blog-main .uq-faq__title:not([class*="uq-heading-"]) {
    font-size: var(--uq-blog-faq-title-size);
}

/* ==========================================
   Sidebar cards
   ==========================================
   The Project Details sidebar card, to the value: 24px padding, 1px
   --uq-theme-border, 10px radius, white ground. The map card and the contact
   card on a Project carry exactly this, so the Blog's three cards read as the
   same pair of components.

   NO DROP SHADOW. The card used to carry the site's card lift as well --
   `box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05)` -- and the client's note is
   that the fade around the Table of Contents, the AI Summary and the Social
   card has to go. One rule draws all three, so the shadow comes off here and
   all three lose it together; the --uq-blog-card-shadow token that fed it was
   read by nothing else and is gone with it.

   The 1px border, the 10px radius, the 24px padding and the 24px stack gap are
   deliberately untouched: the card still reads as a card, it just does not
   float any more. */
.uq-blog-main__aside-inner {
    display: flex;
    flex-direction: column;
    gap: 24px;
    width: 100%;
}

.uq-blog-main__card {
    padding: 24px;
    border: 1px solid var(--uq-blog-border);
    border-radius: var(--uq-blog-card-radius);
    background: #ffffff;
}

/* One label treatment for all three cards. Project Details' sidebar cards
   carry no headings at all, so there is no value to copy -- these take the
   site's heading language instead: Roobert 500 in brand blue, at the step
   below the in-copy H4. Deliberately not uppercase, matching the Project
   chips and the reference's own quiet label. */
.uq-blog-toc__title,
.uq-blog-ai__title,
.uq-blog-main__social-title {
    margin: 0;
    padding: 0;
    color: var(--uq-blog-primary);
    font-family: var(--uq-site-font-heading, Arial, sans-serif);
    /* 17px, the step below the in-copy H4 (18px) and above the 16px body --
       the same relationship the Project card's own labels hold. 16px sat level
       with the body copy beside it and read as a paragraph, not a label. */
    font-size: 17px;
    font-weight: 500;
    line-height: 1.3;
    letter-spacing: -0.01em;
    text-transform: none;
}

/* One internal rhythm for all three cards. Each list previously opened at a
   different distance below its own label -- 16px, 12px and 14px -- which is
   what stopped the sidebar reading as one system: three cards in the same frame
   with three different internal measures. The per-list rules further down now
   all state this same 14px. */

/* ---------- Table of Contents ---------- */
.uq-blog-toc__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

/* Mobile only. display:none above the breakpoint also takes it out of the tab
   order, which is why js/blog.js can leave aria-expanded="true" there. */
.uq-blog-toc__toggle {
    display: none;
}

.uq-blog-toc__list {
    display: block;
    margin: 14px 0 0;
    padding: 0;
    list-style: none;
}

.uq-blog-toc__item {
    margin: 0;
    padding: 0;
    list-style: none;
}

/* The theme draws `article ul li::before { content: '-' }`. Nothing here is a
   bulleted list, and a stray dash on a contents row or a carousel card is
   exactly the kind of unexplained mark this pass is removing. */
.uq-blog-toc__item::before,
.uq-blog-toc__item::after {
    display: none;
    content: none;
}

/* H3 rows are a level, not a smaller copy of the same level: the indent does
   the work, so the type only drops half a step rather than a full one. */
.uq-blog-toc__item--h3 {
    padding-left: 14px;
}

.uq-blog-toc__link {
    position: relative;
    display: block;
    padding: 8px 8px 8px 14px;
    /* The rail the active marker rides on. Continuous, because the rows have no
       vertical gap between them. */
    border-left: 2px solid var(--uq-blog-border);
    border-radius: 0 6px 6px 0;
    /* 14.5px, not 14: this is the one piece of navigation on the page and it
       sat a step under the smallest body copy on the site. */
    color: var(--uq-blog-muted);
    font-size: 14.5px;
    font-weight: 400;
    line-height: 1.45;
    text-decoration: none;
    transition: color 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;
}

.uq-blog-toc__item--h3 .uq-blog-toc__link {
    font-size: 14px;
}

.uq-blog-toc__link:hover {
    color: var(--uq-blog-ink);
    border-left-color: var(--uq-blog-muted);
    background: rgba(16, 78, 139, 0.04);
}

.uq-blog-toc__link:focus-visible {
    outline: 2px solid var(--uq-blog-primary);
    outline-offset: 2px;
    border-radius: 2px;
}

/* Set by js/blog.js. Three quiet signals rather than one loud one: the rail
   goes brand blue and thickens to 3px, the label goes blue at 500, and a 6%
   tint fills the row. Weight moves 400 -> 500, not 400 -> 600 -- a full two
   steps made the row visibly wider than its neighbours and the list twitched
   sideways as the reader scrolled. */
.uq-blog-toc__link.is-active {
    border-left-color: var(--uq-blog-primary);
    /* Drawn as an inset shadow rather than a wider border, so the text does not
       shift 1px left when a row becomes active. */
    box-shadow: inset 1px 0 0 0 var(--uq-blog-primary);
    background: rgba(16, 78, 139, 0.06);
    color: var(--uq-blog-primary);
    font-weight: 500;
}

/* ==========================================
   Summarize article with
   Rendered by template-parts/blog/summarize-links.php
   ==========================================
   Five plain outbound links -- no buttons, no tint, no nested card. The rows
   are text links with a small mark, which is the composition of the client's
   reference; the type, the colours and the focus treatment are the site's. */
.uq-blog-ai__list {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 14px 0 0;
    padding: 0;
    list-style: none;
}

.uq-blog-ai__item {
    margin: 0;
    padding: 0;
    list-style: none;
}

.uq-blog-ai__item::before,
.uq-blog-ai__item::after {
    display: none;
    content: none;
}

.uq-blog-ai__link {
    display: flex;
    align-items: center;
    gap: 10px;
    /* Negative inline margin so the hover tint bleeds to the card's padding
       edge while the text stays on the card's own left edge, in line with the
       label above it. */
    margin: 0 -8px;
    padding: 8px;
    border-radius: 6px;
    color: var(--uq-blog-muted);
    font-family: var(--uq-site-font-body, Arial, sans-serif);
    /* 15px, level with the TOC rows and the FAQ answers, so the two link lists
       in the sidebar are the same size instead of 14.5 against 14. */
    font-size: 15px;
    /* Overrides the global `a { font-weight: 600 }` -- these are text links in
       a list, not emphasis. */
    font-weight: 500;
    line-height: 1.35;
    text-decoration: none;
    transition: color 0.2s ease, background-color 0.2s ease;
}

.uq-blog-ai__link:hover {
    background: rgba(16, 78, 139, 0.06);
    color: var(--uq-blog-primary);
}

/* Already blue at rest, so hover deepens rather than colours in -- the same
   two-step the in-copy links use (primary -> primary-dark). Subtle on purpose:
   the row's own background tint is doing the main work. */
.uq-blog-ai__link:hover .uq-blog-ai__icon,
.uq-blog-ai__link:focus-visible .uq-blog-ai__icon {
    color: var(--uq-blog-primary-dark);
}

.uq-blog-ai__link:focus-visible {
    outline: 2px solid var(--uq-blog-primary);
    outline-offset: 1px;
    color: var(--uq-blog-primary);
}

/* A fixed 20px slot, centred: the five service marks are different shapes and
   different intrinsic widths, so without a fixed box the five names started on
   five different x-positions. This is the alignment fix.
 *
   Site blue at rest, not muted grey. These are real brand marks now rather than
   the abstract strokes that were here before, and the blue is what makes the
   row read as a deliberate, branded control instead of five grey smudges. It is
   also the one colour treatment shared with the share discs below, which is
   what makes the two icon groups read as one system. */
.uq-blog-ai__icon {
    display: inline-flex;
    flex: 0 0 20px;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    color: var(--uq-blog-primary);
    transition: color 0.2s ease;
}

/* 18px against the share discs' 16px, and that is an OPTICAL match rather than
   a mismatch: these marks are drawn on a 24-unit grid with their own internal
   padding, while the Bootstrap social marks fill a 16-unit box edge to edge.
   Rendered at the same pixel size the social ones look a size larger. */
.uq-blog-ai__icon svg {
    display: block;
    width: 18px;
    height: 18px;
}

.uq-blog-ai__name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ==========================================
   Article tags
   Rendered by template-parts/blog/tags.php, at the end of the article column
   ==========================================
   Native WordPress `post_tag` terms as small outline links. Deliberately light:
   they are a navigation footnote under a long article, not a call to action, so
   there is no fill, no shadow, no weight above 500 and nothing here is the size
   of a button. The client's own note was "do NOT make them look like large
   buttons".

   The outline pill is the site's existing quiet-link shape -- the same 1px
   #e5e5e5 / 999px treatment the Share control uses -- rather than a new one.
   Colour, border and type are all theme tokens.
   ========================================== */
.uq-blog-tags {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px 12px;
    /* Separated from the copy above by a hairline, the way the article's own
       sections are, so the row reads as an endnote rather than as more body. */
    margin: 40px 0 0;
    padding: 20px 0 0;
    border-top: 1px solid var(--uq-blog-border, #e5e5e5);
}

.uq-blog-tags__label {
    flex: 0 0 auto;
    margin: 0;
    padding: 2px 0;
    color: var(--uq-blog-muted, #3F4B58);
    font-family: var(--uq-site-font-body, Arial, sans-serif);
    /* The Blog Header meta step. */
    font-size: 13px;
    font-weight: 600;
    line-height: 1.4;
}

.uq-blog-tags__list {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    min-width: 0;
    margin: 0;
    padding: 0;
    list-style: none;
}

.uq-blog-tags__item {
    margin: 0;
    padding: 0;
    list-style: none;
}

/* The theme draws `article ul li::before { content: '-' }`, and the article
   column is exactly where that rule lives. */
.uq-blog-tags__item::before,
.uq-blog-tags__item::after {
    display: none;
    content: none;
}

.uq-blog-tags__link {
    display: inline-flex;
    align-items: center;
    max-width: 100%;
    padding: 4px 12px;
    border: 1px solid var(--uq-blog-border, #e5e5e5);
    border-radius: 999px;
    background: transparent;
    color: var(--uq-blog-muted, #3F4B58);
    font-family: var(--uq-site-font-body, Arial, sans-serif);
    font-size: 13px;
    /* Overrides the global `a { font-weight: 600 }` -- a tag is not emphasis. */
    font-weight: 500;
    line-height: 1.4;
    text-decoration: none;
    overflow-wrap: anywhere;
    transition: border-color 0.2s ease, color 0.2s ease;
}

.uq-blog-tags__link:hover {
    border-color: var(--uq-blog-primary, #104E8B);
    color: var(--uq-blog-primary, #104E8B);
}

.uq-blog-tags__link:focus-visible {
    outline: 2px solid var(--uq-blog-primary, #104E8B);
    outline-offset: 2px;
    border-color: var(--uq-blog-primary, #104E8B);
    color: var(--uq-blog-primary, #104E8B);
}

@media screen and (max-width: 767px) {
    .uq-blog-tags {
        margin-top: 32px;
        padding-top: 16px;
    }
}

/* ==========================================
   Share -- one component, two variants
   Rendered by template-parts/blog/share-links.php
   ========================================== */
.uq-blog-main__social-title {
    margin-bottom: 14px;
}

.uq-blog-share__list {
    display: flex;
    margin: 0;
    padding: 0;
    list-style: none;
}

.uq-blog-share__item {
    margin: 0;
    padding: 0;
    list-style: none;
}

.uq-blog-share__item::before,
.uq-blog-share__item::after {
    display: none;
    content: none;
}

.uq-blog-share__link {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
    transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

.uq-blog-share__link:focus-visible {
    outline: 2px solid var(--uq-blog-primary);
    outline-offset: 2px;
}

.uq-blog-share__icon {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
}

.uq-blog-share__icon svg {
    display: block;
    width: 16px;
    height: 16px;
}

/* ---------- sidebar variant: icon row ---------- */
.uq-blog-share--sidebar .uq-blog-share__list {
    flex-wrap: wrap;
    gap: 8px;
}

/* 38px discs on an 8px gap: five of them plus the copy control fit one row of
   the 372px card at desktop and stay on one row at 340px, which is what stopped
   the row wrapping into a ragged 4+2 block. */
.uq-blog-share--sidebar .uq-blog-share__link {
    width: 38px;
    height: 38px;
    justify-content: center;
    border: 1px solid var(--uq-blog-border);
    border-radius: 50%;
    /* Site blue at rest, the same value the Summarize marks above now carry. */
    color: var(--uq-blog-primary);
    transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

/* The site's blue on hover, and the amber only as the focus ring -- the same
   two-colour split the Project chips use, where blue is the action and amber is
   the marker. */
.uq-blog-share--sidebar .uq-blog-share__link:hover {
    border-color: var(--uq-blog-primary);
    background: var(--uq-blog-primary);
    color: #ffffff;
    transform: translateY(-1px);
}

.uq-blog-share--sidebar .uq-blog-share__link:focus-visible {
    border-color: var(--uq-blog-primary);
    box-shadow: 0 0 0 3px var(--uq-blog-accent);
    outline-offset: 3px;
}

/* The label stays in the DOM for the accessible name -- visually hidden, not
   display:none, so it is still announced. */
.uq-blog-share--sidebar .uq-blog-share__label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* ---------- panel variant: labelled rows ---------- */
.uq-blog-share--panel .uq-blog-share__list {
    flex-direction: column;
    gap: 2px;
    min-width: 210px;
}

.uq-blog-share--panel .uq-blog-share__link {
    gap: 12px;
    width: 100%;
    padding: 10px 12px;
    border-radius: 6px;
    color: var(--uq-blog-muted);
    font-size: 14.5px;
    font-weight: 500;
    line-height: 1.3;
}

.uq-blog-share--panel .uq-blog-share__link:hover {
    background: rgba(16, 78, 139, 0.06);
    color: var(--uq-blog-primary);
}

/* Blue mark, muted label -- exactly the pairing the Summarize rows use, so the
   Share panel and the Summarize card are the same row treatment with different
   contents rather than two different lists. */
.uq-blog-share--panel .uq-blog-share__icon {
    color: var(--uq-blog-primary);
}

/* Copy Link confirmation. Announced through the aria-live status line as well,
   so this is reinforcement rather than the only feedback. */
.uq-blog-share.is-copied .uq-blog-share__link--copy {
    border-color: var(--uq-blog-primary);
    color: var(--uq-blog-primary);
}

.uq-blog-share__status {
    margin: 10px 0 0;
    color: var(--uq-blog-muted);
    font-size: 13px;
    line-height: 1.4;
}

.uq-blog-share__status:empty {
    display: none;
}

/* ==========================================
   Share bar
   Layout: blog_share
   ========================================== */
.uq-blog-share-bar {
    --uq-sh-space-top: 8px;
    --uq-sh-space-bottom: 48px;
    display: block;
    width: 100%;
    padding: var(--uq-sh-space-top) 5vw var(--uq-sh-space-bottom);
    background: #ffffff;
}

/* ---------- Adjacent-section spacing ---------- */
/* THE ONE REAL DEAD ZONE ON THE PAGE, and why this is expressed with :has()
   rather than by changing a default.
 *
 * Every Blog section owns its own top and bottom spacing, set per row by the
 * editor, so between two sections the two values ADD. That is the same
 * arrangement Project Details uses and it is right almost everywhere -- but the
 * Share module is not a section, it is a utility row, and it lands in the middle
 * of a gap sized for two full sections:
 *
 *     FAQ ends  -> blog_main bottom 80 + blog_share top 8   = 88px
 *     Share row -> blog_share bottom 48 + related top 64    = 112px
 *
 * so a 60px-tall row sat alone in ~200px of white and read as something that
 * had come loose.
 *
 * :has(+ ...) fires ONLY on the adjacency that causes it -- an article
 * immediately followed by a Share module, a Share module immediately followed by
 * Related Articles. A Blog built without a Share row is untouched, and so is a
 * Share row that is not between those two.
 *
 * min() is deliberate: this only ever REDUCES. An editor who sets 24px still
 * gets 24px; only the oversized default is brought in. And a browser without
 * :has() simply keeps today's spacing, so there is no broken state. */
.uq-blog-main:has(+ .uq-blog-share-bar) {
    padding-bottom: min(var(--uq-bm-space-bottom, 80px), 48px);
}

.uq-blog-share-bar:has(+ .uq-blog-related) {
    padding-bottom: min(var(--uq-sh-space-bottom, 48px), 40px);
}

/* An end-of-article rule, not a floating strip. The row was a hairline with a
   title and a button hanging off it in open white space, 88px below the FAQ and
   112px above the carousel -- so it read as a section that had lost its
   section. It is now a bounded band: a divider above AND below, 22px of
   controlled padding inside, and the pair vertically centred between them. The
   two rules give the block edges, which is what makes it look deliberate at the
   same spacing it already had. */
.uq-blog-share-bar__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: 22px 0;
    border-top: 1px solid var(--uq-blog-border);
    border-bottom: 1px solid var(--uq-blog-border);
}

.uq-blog-share-bar__title {
    margin: 0;
    color: var(--uq-blog-primary);
    font-family: var(--uq-site-font-heading, Arial, sans-serif);
    /* 17px, the sidebar card label step. This is a label on a utility row, not
       a section heading, and at 18px it competed with the 21px in-copy H3
       directly above it. */
    font-size: 17px;
    font-weight: 500;
    line-height: 1.3;
    letter-spacing: -0.01em;
}

.uq-blog-share-bar__control {
    position: relative;
    flex: 0 0 auto;
}

/* The site's own outline control: brand blue, a pill, and it fills on hover --
   the same behaviour the Project chips and the CTA button have. */
.uq-blog-share-bar__button {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    padding: 10px 20px;
    border: 1px solid var(--uq-blog-primary);
    border-radius: 999px;
    background: transparent;
    color: var(--uq-blog-primary);
    font-size: 14px;
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease;
}

.uq-blog-share-bar__button:hover,
.uq-blog-share-bar__control .uq-blog-share-bar__button[aria-expanded="true"] {
    background: var(--uq-blog-primary);
    color: #ffffff;
}

.uq-blog-share-bar__button:focus-visible {
    outline: 2px solid var(--uq-blog-primary);
    outline-offset: 2px;
}

.uq-blog-share-bar__button-icon svg {
    display: block;
    width: 16px;
    height: 16px;
}

.uq-blog-share-bar__panel {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    z-index: 20;
    padding: 8px;
    border: 1px solid var(--uq-blog-border);
    border-radius: var(--uq-blog-card-radius);
    background: #ffffff;
    /* The site's raised-panel shadow, tinted with the brand blue rather than
       neutral black -- the same language .uq-reviews__platform-panel and the
       Project popover use. */
    box-shadow: 0 1px 2px rgba(16, 78, 139, 0.06), 0 16px 36px -8px rgba(16, 78, 139, 0.20);
}

/* The panel declares no display of its own, so normalize's [hidden] already
   hides it -- stated explicitly so a later `display` on this class cannot
   silently unhide the closed panel. */
.uq-blog-share-bar__panel[hidden] {
    display: none;
}

/* ==========================================
   Related Articles
   Layout: related_articles
   Rendered by template-parts/blog/related-articles.php
   ==========================================
   A TEXT-FIRST THREE-UP GRID, following the reference the client supplied: a
   title, a short excerpt and a quiet metadata line on a very light panel. No
   image, no card shadow, no radius, no arrows.

   SCOPED TO THIS MODULE ONLY. Every selector below is under .uq-blog-related,
   which exists on a single Blog Post and nowhere else. The Blog Hub, the Post
   archives, the Projects Hub and the Related Projects carousel draw
   .uq-hub-card from css/hub-card.css and share not one rule with this file.

   The panel tint is derived from the site's own brand blue rather than
   introduced: #f5f8fc is --uq-theme-primary at a few percent over white, so the
   row reads as Roofer On Demand rather than as a grey box. Type, spacing and
   the border colour are all existing theme tokens.

   WHAT WENT, AND WHY. This module used to be a transform carousel -- 3.15 cards
   visible with the next one peeking, two round arrows and an aria-live status
   line. The client's brief specifies the responsive behaviour as 3 / 2 / 1
   COLUMNS, which is a grid, so the track, the viewport, the peek, the arrows
   and their rules are gone. Removed selectors, for the record:

     .uq-blog-related__nav            .uq-blog-related__viewport
     .uq-blog-related__arrow          .uq-blog-related__track
     .uq-blog-related__media          .uq-blog-related__image
     .uq-blog-related__body           .uq-blog-related__footer
     .uq-blog-related__tag            .uq-blog-related__term
     .uq-blog-related__status         .uq-blog-related.is-static
     --uq-ra-visible  --uq-ra-media-ratio  --uq-ra-arrow-bg  --uq-ra-arrow-icon
*/
.uq-blog-related {
    /* Column gap and row gap. 24 / 32 keeps two rows of three compact rather
       than airy, which is the reference's own rhythm. */
    --uq-ra-gap: 24px;
    --uq-ra-row-gap: 32px;
    --uq-ra-columns: 3;

    /* Client feedback: "Related blogs cards should have rounded corners."
     *
     * 10px, which is the site's card radius rather than a number chosen for this
     * module: --uq-ms-card-radius (Service Cards), --uq-pd-card-radius (the
     * Project and Service sidebar cards), --uq-hc-radius (the hub media) and the
     * Blog Hub panel in css/hub-card.css are all 10px -- that panel having been
     * rounded for this same direction, "Blog cards rounded corners like the
     * rest". The Related card and the Hub card are one card language, so they
     * now agree again.
     *
     * It replaces the 0 an earlier pass set when the brief was square corners.
     *
     * The token reaches exactly two rules -- the card's own border-radius below,
     * and --uq-rp-radius in the carousel block at the foot of this file, which is
     * the focus ring on the slider viewport. Both should be rounded together, so
     * one number still does it. Nothing outside .uq-blog-related reads it: the
     * Blog Hub card has its own --uq-hc-radius and its own literal. */
    --uq-ra-radius: 10px;
    --uq-ra-pad: 24px;

    /* THE THEME SETTINGS COLOURS, AND THE ORDER IS THE WHOLE POINT.
     *
     * Related Blog Card Background/Border Color are printed to :root as
     * --uq-related-blog-card-bg / --uq-related-blog-card-border, and the main
     * Blog pair as --uq-blog-card-bg / --uq-blog-card-border -- each only when
     * that field holds a real colour. See uq_blog_card_color_vars() in
     * inc/hub.php.
     *
     * So the chain below reads: THIS card's own setting, else the main Blog card
     * setting, else the literal. That is the client's rule -- "if the Related
     * Blog colors are empty, fall back to the main Blog card colors" -- and
     * expressing it as nested var() rather than resolving it in PHP is what
     * makes each PROPERTY fall back on its own: set only a Related border and
     * you get the main background with the new border, no special case.
     *
     * IT RUNS ONE WAY ONLY. .uq-hub-card--blog in css/hub-card.css reads the
     * main pair and nothing else, so a Related colour can never reach the Blog
     * Hub grid. This card is template-parts/blog/related-article-card.php; that
     * one is template-parts/hub/blog-card.php. Two partials, two classes, two
     * settings.
     *
     * The literals stay last, and they are the same #f5f8fc / #e6edf5 the Hub
     * card falls back to, so with every field empty both cards render exactly
     * what they rendered before -- to the byte.
     *
     * The brand blue, thinned almost to white. Not a new colour: a tint.
     *
     * THE HOVER PAIR IS NOW WIRED TOO, to its own two settings -- Related Blog
     * Card Hover Background/Border Color -- so a card whose resting colour has
     * been changed can be told what to hover to.
     *
     * NOTE THE DIFFERENT CHAIN LENGTH, which is deliberate and is the client's
     * rule rather than an inconsistency: a RESTING colour falls back
     * related -> main -> literal, but a HOVER colour falls back
     * related-hover -> literal, with NO step through the main card's hover.
     * "If a hover option is empty, preserve the current default hover styling"
     * -- the default being the #eef3f9 / #dbe6f2 this card already carried, not
     * whatever the Blog Hub hovers to. So setting a Hub hover colour cannot move
     * this card, in either direction.
     *
     * --uq-ra-card-border-hover is new only as a NAME. The value it holds was
     * previously a literal typed inline in the :hover rule below; promoting it
     * to a token beside its three siblings is what lets it be overridden at all,
     * and it resolves to the same #dbe6f2 when the setting is empty. */
    --uq-ra-card-bg: var(--uq-related-blog-card-bg, var(--uq-blog-card-bg, #f5f8fc));
    --uq-ra-card-bg-hover: var(--uq-related-blog-card-bg-hover, #eef3f9);
    --uq-ra-card-border: var(--uq-related-blog-card-border, var(--uq-blog-card-border, #e6edf5));
    --uq-ra-card-border-hover: var(--uq-related-blog-card-border-hover, #dbe6f2);

    /* 20px -> 24px, matching the Blog Hub card exactly. These two are the same
       card by design -- same tint, same hairline, same 600 / 1.28 / -0.015em
       title, same 15px summary clamped to the same three lines -- and the hub's
       title has been raised twice for emphasis, so this one follows rather than
       being left a size behind its twin.

       It is a FLAT value now, not the top of a ladder. The 19px steps that used
       to sit in the 1200 and 767 blocks below are gone, because the hub card
       does not step its title down either: one size everywhere, and a single
       23px step on phones. Those blocks still carry their own gap and padding
       changes -- only the title line was removed from each. */
    --uq-ra-title-size: 24px;
    --uq-ra-title-color: #111111;
    --uq-ra-summary-size: 15px;
    --uq-ra-meta-size: 13px;
    /* #767676 rather than #808080: 4.54:1 on white, so the smallest text on the
       card clears WCAG AA instead of landing just under it. */
    --uq-ra-meta-color: #767676;

    --uq-ra-space-top: 64px;
    --uq-ra-space-bottom: 64px;

    display: block;
    width: 100%;
    max-width: 100%;
    padding: var(--uq-ra-space-top) 5vw var(--uq-ra-space-bottom);
    background: #ffffff;
}

/* Just the heading now -- the arrows it used to sit opposite are gone. */
.uq-blog-related__header {
    display: block;
    margin: 0 0 32px;
}

/* Brand blue, Roobert, left, on the shared section-title scale -- identical to
   .uq-related-projects__title. */
.uq-blog-related .uq-blog-related__title {
    margin: 0;
    min-width: 0;
    padding: 0;
    /* THE FALLBACK CHAIN IS LOAD-BEARING, and its absence was a real bug.
     *
     * --uq-blog-primary is declared on .uq-blog-page, which single.php puts on
     * <main>. A Flexible Page does not carry that class -- its <main> is just
     * .uq-flex-page -- so on a Page this variable is UNDEFINED, `color:
     * var(--uq-blog-primary)` was invalid at computed-value time, and the
     * heading fell back to INHERITED body colour instead of brand blue. The
     * same Related Articles module therefore rendered blue on an article and
     * dark slate on a Page, beside a Related Projects heading that was blue in
     * both places.
     *
     * --uq-theme-primary is declared at :root in style.css, so it resolves
     * everywhere; the literal is the last resort. On a single Post
     * --uq-blog-primary is defined and wins, so an article is unchanged to the
     * byte -- both tokens resolve to #104E8B anyway.
     *
     * Every other --uq-blog-* reference in this module already carried a hard
     * fallback for exactly this reason. These two were the ones that did not. */
    color: var(--uq-blog-primary, var(--uq-theme-primary, #104E8B));
    font-family: var(--uq-site-font-heading, Arial, sans-serif);
    text-align: left;
    text-transform: none;
    text-wrap: balance;
}

/* 1.1 / -0.02em, which is what .uq-related-projects__title states and what
   .uq-heading-h2 states. 1.06 / -0.035em is the FAQ section-title treatment,
   tuned for a centred display heading -- against the Related carousel's
   left-aligned 48px it set the two identical headings on the two pages at
   visibly different tracking. */
.uq-blog-related__title:not([class*="uq-heading-"]) {
    font-size: var(--uq-module-title-size, clamp(40px, 3.4vw, 48px));
    font-weight: 500;
    line-height: 1.1;
    letter-spacing: -0.02em;
}

/* ---------- Section description (SEO copy under the title) ----------
   Client addition: `section_description`, an optional WYSIWYG on the
   related_articles layout, printed inside the header directly under the title
   and above the grid.

   THE TREATMENT IS THE SHARED MODULE DESCRIPTION, not this sheet's standfirst.
   Client feedback (#4): this copy read a step larger than every other module
   description on the site. It used to be .uq-blog-header__description to the
   value -- 18px / 400 / 1.55, stepping to 17px at 991 -- which is the scale for
   copy under the ARTICLE'S OWN H1, not under a module H2. The three type lines
   now point at --uq-module-description-* instead: 16px / 400 / 1.4, stepping to
   15px under 767px. Those are the tokens the fifteen-selector shared rule in
   style.css resolves every other section description to, and the ones
   --uq-blog-body-size at the top of this sheet already tracks for body copy.
   .uq-related-projects__description in style.css took the identical change in
   the same pass, so the two Related modules still read alike.

   NOTHING ELSE MOVES. The 860px measure, --uq-blog-muted and every margin are
   the values they were; only the three type declarations change.

   The one difference in KIND is that this is a WYSIWYG <div> rather than a
   single <p>, so its children carry the global `p { margin: 0 0 20px }`; the
   two child resets below are what stop that margin adding a 20px hole above the
   grid. .uq-related-projects__description in style.css carries the same pair for
   the same reason.

   Inline links inside it are handled by the shared
   `.uq-flex-page [class*="description"] a` rule in style.css -- single.php and
   template-flexible-content.php both put .uq-flex-page on <main>, so it reaches
   this module on an article and on a Page alike. That is why the element is
   named __description.

   A row with the field empty emits nothing at all, so nothing below can change
   an existing article. */
.uq-blog-related__description {
    max-width: 860px;
    margin: 16px 0 0;
    /* Same fallback chain, same reason as the title above: --uq-blog-muted is
       declared on .uq-blog-page, which a Flexible Page does not carry, so
       without this the SEO copy inherited its colour instead of taking the
       muted one. An article is unchanged -- the token is defined there. */
    color: var(--uq-blog-muted, var(--uq-theme-text, #3F4B58));
    font-size: var(--uq-module-description-size, 16px);
    font-weight: var(--uq-module-description-weight, 400);
    line-height: var(--uq-module-description-line-height, 1.4);
}

.uq-blog-related__description > :first-child {
    margin-top: 0;
}

.uq-blog-related__description > :last-child {
    margin-bottom: 0;
}

@media screen and (max-width: 991px) {
    .uq-blog-related__description {
        margin-top: 14px;
    }
}

/* The size step moved out of the 991 block above and down to 767, which is
   where --uq-module-description-size-mobile drops and therefore where every
   other module description on the page steps. 991 keeps the margin, which is
   this module's own spacing and not part of the shared scale. */
@media screen and (max-width: 767px) {
    .uq-blog-related__description {
        font-size: var(--uq-module-description-size-mobile, 15px);
    }
}

/* ---------- The grid ---------- */
.uq-blog-related__grid {
    display: grid;
    /* minmax(0, 1fr) is what stops a long unbroken word in a title from
       widening its column past its share and pushing the row into overflow. */
    grid-template-columns: repeat(var(--uq-ra-columns), minmax(0, 1fr));
    gap: var(--uq-ra-row-gap) var(--uq-ra-gap);
    width: 100%;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* One or two related articles must not each become a third of the row with a
   hole beside them. Same rule the old track applied, same class name. */
.uq-blog-related--few .uq-blog-related__grid {
    --uq-ra-columns: 2;
}

.uq-blog-related__item {
    display: flex;
    min-width: 0;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* The theme draws `article ul li::before { content: '-' }`, and this row sits
   inside the article. A dash at the left of every card is exactly the stray
   mark this design cannot have. */
.uq-blog-related__item::before,
.uq-blog-related__item::after {
    display: none;
    content: none;
}

/* ---------- The card ---------- */
.uq-blog-related__card {
    /* The anchor for the stretched link below. */
    position: relative;
    display: flex;
    width: 100%;
    /* Fills its grid cell, so every card in a row is the same height and the
       metadata lines up -- the brief's "equal card heights on desktop". */
    height: 100%;
    min-width: 0;
    flex-direction: column;
    gap: 12px;
    padding: var(--uq-ra-pad);
    border: 1px solid var(--uq-ra-card-border);
    border-radius: var(--uq-ra-radius);
    background: var(--uq-ra-card-bg);
    /* The card's own background and border are clipped by border-radius for
       free; overflow: hidden is what makes any CHILD respect the same corners --
       today the stretched-link overlay that covers the card edge to edge, and
       tomorrow an image or a coloured block if one is ever added to this card.
       Without it a square-cornered child would poke out of the rounded corner.
     *
       Safe here because nothing in this card is meant to escape it: the only
       absolutely positioned thing is that overlay, which is inset to 0, and the
       focus ring is drawn on the CARD (or, in the no-:has() fallback, on a link
       sitting well inside the 24px padding) so neither is clipped. */
    overflow: hidden;
    /* No shadow. The panel and its hairline are the whole of the container. */
    box-shadow: none;
    transition: background-color 0.2s ease, border-color 0.2s ease;
}

.uq-blog-related__card:hover {
    background: var(--uq-ra-card-bg-hover);
    /* Was the literal #dbe6f2. Same value when the setting is empty -- the token
       declared above carries it as its var() fallback -- so this is a rename,
       not a restyle. */
    border-color: var(--uq-ra-card-border-hover);
}

/* Client feedback (#8): these titles read as a different typeface from every
   other card title on the site, and they measured that way. Whitelisted in the
   shared card-title rule in style.css, .uq-multi-services__card-title,
   .uq-filterable-cards__card-title, .uq-how-it-works__card-title,
   .uq-service-feature__card-title, .uq-footer-cta__card-title and
   .uq-manufacturers__name ALL render Roobert / 500 / 1.35 / -0.015em. Only the
   SIZE varies by context -- 18, 19, 22, 24 -- which is why the size below stays
   on this component's own token and is the one property not touched here.

   THREE of the four constant properties were out of step:

       family  the visible text is inside the <a>, and :root's
               `body, p, a, li, ... { font-family: var(--uq-site-font-body)
               !important }` beat the `font: inherit` on the link -- so the
               heading face declared on the heading never reached the words. The
               link rule below now restates it with the same !important
               .uq-multi-services__tab and .uq-footer-cta__card-title need for
               exactly this reason.
       weight  600 -- the SemiBold band this system reserves for buttons. Every
               card title on the site is Medium.
       lh      1.28 against the shared 1.35.

   letter-spacing was already -0.015em; it is said through the token now so the
   four move together in future.

   Colour, margins, padding, the stretched ::after hit area, the hover and the
   focus ring are all untouched. */
.uq-blog-related__card-title {
    margin: 0;
    padding: 0;
    /* An <h3>, so the :root `h1..h6 { font-family: ... !important }` rule
       already puts it on Roobert -- declared anyway so the card does not depend
       on a global !important staying where it is. The <a> inside is the one that
       needed help; see .uq-blog-related__link below. */
    font-family: var(--uq-site-font-heading, Arial, sans-serif);
    font-size: var(--uq-ra-title-size);
    font-weight: var(--uq-module-card-title-weight, 500);
    line-height: var(--uq-module-card-title-line-height, 1.35);
    letter-spacing: var(--uq-module-card-title-letter-spacing, -0.015em);
    color: var(--uq-ra-title-color);
    text-transform: none;
    overflow-wrap: anywhere;
}

.uq-blog-related__card-title::before,
.uq-blog-related__card-title::after {
    display: none;
    content: none;
}

/* The one link on the card. Colour and weight are inherited from the heading so
   the theme's global `a { color: #FDBB2F; font-weight: 600 }` cannot reach it. */
.uq-blog-related__link {
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
    /* `font: inherit` above asks for the heading's Roobert and does not get it:
       :root's `body, p, a, li, ... { font-family: ... !important }` reaches this
       <a> as an element selector, and !important beats a plain shorthand however
       specific. Restating it !important at (0,1,0) is what actually lands the
       face on the words -- same fix, same reason, as
       .uq-hub-card__heading-link in css/hub-card.css. */
    font-family: var(--uq-site-font-heading, Arial, sans-serif) !important;
    text-decoration: none;
}

/* STRETCHED: the whole card is clickable, without a second <a> and without
   wrapping the card in one. */
.uq-blog-related__link::after {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1;
    content: "";
}

.uq-blog-related__card:hover .uq-blog-related__link {
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* BRAND BLUE ON HOVER, NEVER THE SITE'S YELLOW.

   Same fix, same reason, as .uq-hub-card__heading-link in css/hub-card.css --
   the two cards share this pattern and now share this behaviour. style.css
   carries a global `a:hover { color: #FDBB2F }`, and that selector at (0,1,1)
   OUTRANKS the `color: inherit` above at (0,1,0), so the card title turned
   yellow on hover. Putting the class in the state selector takes it to (0,2,0),
   which wins without !important and without touching the global rule.

   :hover fires from anywhere on the card, because the link is stretched over it
   by ::after; the descendant selector covers the card's own hover state; :focus
   and :active close the remaining interactive states.

   The DEFAULT title colour is unchanged -- still --uq-ra-title-color (#111111)
   through `color: inherit`. Typography, spacing, the underline and the card
   design are all exactly as they were. */
.uq-blog-related__link:hover,
.uq-blog-related__link:focus,
.uq-blog-related__link:active,
.uq-blog-related__card:hover .uq-blog-related__link {
    /* WITH THE HEX FALLBACK, and it is not decoration. --uq-blog-primary is
       declared on .uq-blog-page -- the <main> of a single Post -- not on this
       module, so it reaches here by inheritance from an ancestor OUTSIDE the
       component. If this row is ever rendered anywhere that wrapper is absent,
       a bare var() would be invalid at computed-value time and `color` would
       silently fall back to the INHERITED #111111 rather than to blue: the fix
       would look like it simply had not been applied. The neighbouring
       :focus-visible rule already hedges the same way. */
    color: var(--uq-blog-primary, #104E8B);
}

/* FOCUS, IN TWO LAYERS, AND THE ORDER MATTERS.

   The link is stretched over the whole card, so a ring drawn on the <a> itself
   traces the title text and not the thing the reader is actually about to
   activate. The ring therefore belongs on the CARD -- but only where the
   browser can express that, which needs :has().

   So the link keeps a real ring by default, and it is moved to the card ONLY
   inside @supports. A browser with :focus-visible but without :has() would
   otherwise get the suppression and none of the replacement, which is a
   keyboard user left with no visible focus at all. */
.uq-blog-related__link:focus-visible {
    outline: 2px solid var(--uq-blog-primary, #104E8B);
    outline-offset: 2px;
}

@supports selector(:has(a)) {
    .uq-blog-related__card:has(.uq-blog-related__link:focus-visible) {
        outline: 2px solid var(--uq-blog-primary, #104E8B);
        outline-offset: 2px;
    }

    .uq-blog-related__link:focus-visible {
        outline: none;
    }
}

.uq-blog-related__summary {
    /* Three lines, so a long summary cannot make one card twice the height of
       its neighbour before the grid equalises them. */
    display: -webkit-box;
    overflow: hidden;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    margin: 0;
    padding: 0;
    /* The site's shared card-description colour, not this sheet's --uq-blog-muted.
       These cards and the Blog Hub's are deliberately the same card -- same
       tint, same hairline, same 15px/1.55 summary clamped to the same three
       lines -- and measured on the live pages the ONLY thing that differed
       between them was this colour: #3F4B58 here against rgba(0,0,0,0.7) on the
       hub. The hub's is the site's, shared with Service Cards, How It Works,
       Filterable Cards, Service Feature and Feature Showcase, so this is the
       side that moves.

       The declaration changes, not the token: --uq-blog-muted is read by a
       dozen other rules in this sheet -- article body copy, section
       descriptions, meta rows -- and those are section copy, not card
       descriptions. Repointing the variable would drag all of them along.
       style.css makes the same distinction where it defines this token. */
    color: var(--uq-module-card-description-color, rgba(0, 0, 0, 0.7));
    font-family: var(--uq-site-font-body, Arial, sans-serif);
    font-size: var(--uq-ra-summary-size);
    font-weight: 400;
    line-height: 1.55;
}

/* ---------- The metadata line ---------- */
.uq-blog-related__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    /* margin-top: auto pins the row to the bottom edge whatever the title and
       summary lengths are. */
    margin: auto 0 0;
    padding: 0;
    gap: 2px 6px;
    color: var(--uq-ra-meta-color);
    font-family: var(--uq-site-font-body, Arial, sans-serif);
    font-size: var(--uq-ra-meta-size);
    font-weight: 400;
    line-height: 1.45;
}

.uq-blog-related__meta-item {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    min-width: 0;
}

/* The middot TRAILS the item it follows rather than leading the next one, and
   that is the difference between a tidy row and a broken-looking one. The row
   wraps on a narrow card, and a leading separator puts a stray middot at the
   START of the second line; a trailing one stays attached to the end of the
   first, which reads as a continued list.

   :not(:last-child) rather than a + sibling rule, so an article with no
   category or no author still ends on its date and never on a divider. */
.uq-blog-related__meta-item:not(:last-child)::after {
    content: "\00B7";
    opacity: 0.7;
}

/* Client feedback: "Blog cards category and author should be bold."
 *
 * 600 is the theme's bold step, so the row reads as emphasised rather than as a
 * new weight introduced for it. (It was also both blog card TITLES' weight when
 * this was written; feedback #8 has since put them on the shared card title's
 * 500, and the client asked for the row's weight to stay as it is, so the two no
 * longer match and that is deliberate.) Nothing else moves: the 13px size, the
 * baseline alignment, the 2px/6px gap and the row's position are all untouched,
 * and so are the reading time and the date -- which is why the two spans carry
 * their own modifier. .uq-hub-card--blog gets the same treatment in
 * css/hub-card.css; no other card component reads either selector. */
.uq-blog-related__meta-item--category,
.uq-blog-related__meta-item--author {
    font-weight: 600;
    /* Client feedback (#10): Category and Author take the CARD TITLE's colour
       rather than the meta grey. --uq-ra-title-color, not a literal #111111, so
       the two keep matching if the title colour is ever re-pointed -- which it
       can be: the Theme Settings note further up this file exists because that
       token is overridable. The row keeps --uq-ra-meta-color on
       .uq-blog-related__meta, which is what leaves the reading time and the date
       grey -- the same reason these two spans carry a modifier at all. Only the
       colour moves. */
    color: var(--uq-ra-title-color, #111111);
}

/* The middot is an ::after on the item, so it would inherit the bold and, now,
   the title colour -- sitting heavier and darker than the ones after the reading
   time. Pinned back to the row's own weight and its own grey so every separator
   in the line matches. An inherited value loses to any declared one, so this
   needs no extra specificity. */
.uq-blog-related__meta-item--category::after,
.uq-blog-related__meta-item--author::after {
    font-weight: 400;
    color: var(--uq-ra-meta-color, #767676);
}

/* ==========================================
   Sticky right column
   ==========================================
   Only while the layout is actually two columns, and only above the stacking
   breakpoint -- the same condition .uq-project-details--sticky applies.
   `align-items: start` on the grid is what lets the column be shorter than the
   article; without it the track would stretch and sticky would have nothing to
   travel inside.

   NO INTERNAL SCROLLBAR. This block used to cap the sticky inner wrapper with
   `max-height: calc(100vh - top - 24px)` plus `overflow-y: auto`, which gave the
   sidebar a scrollbar of its own inside the page's scrollbar. The client asked
   for that removed and for the cards to flow naturally, so the cap, the
   overflow, the `overscroll-behavior: contain` that went with it and the 2px
   gutter that was reserving room for the bar are all gone.

   WHAT THAT TRADES. The cap was a safety valve: with it, a sidebar taller than
   the viewport could still be read by scrolling inside the column. Without it a
   sticky element simply pins at `top` and anything below the fold stays below
   the fold. Measured on the live posts the column runs ~600-700px against a
   ~730px budget at a 900px viewport, so it fits today and the valve was never
   doing visible work -- but a post with a very long Table of Contents, read on a
   short window, can now have the bottom of the Share card out of reach. That is
   the client's explicit call, and it is the only thing the removal costs.

   Sticky itself is kept: `position: sticky` and `top` stay exactly as they
   were, so the column still travels with the article above 992px. */
@media screen and (min-width: 992px) {
    /* THE FIX. `position: sticky` was computing correctly and still did nothing,
       because a sticky element can only travel inside its CONTAINING BLOCK --
       here .uq-blog-main__aside, the grid item it sits in.
     *
       .uq-blog-main__layout carries `align-items: start`, which sizes every grid
       item to its own content rather than to the row. Measured on the live
       markup at 1440 before this rule existed:
     *
           .uq-blog-main__content      1547px
           .uq-blog-main__aside         717px
           .uq-blog-main__aside-inner   717px   <- identical to its parent
           travel                         0px
     *
       The sticky element exactly filled its containing block, so there was no
       distance to stick over and the sidebar simply scrolled away with the page.
       Nothing else was wrong: every ancestor up to <body> computes
       overflow: visible, and there is no transform, filter or contain anywhere
       in the chain -- all seven were checked.
     *
       align-self: stretch puts the aside track back to the row's full height
       (1547px), which is the article's height, leaving 830px of travel. It is
       set on the ASIDE only, so `align-items: start` still governs the rest of
       the grid and the article column is untouched.
     *
       Scoped to the --sticky modifier and to >=992px, so a row with Sticky
       Sidebar off, and every width below the stacking breakpoint, keep a plain
       static column. No position: fixed anywhere. */
    .uq-blog-main--sticky .uq-blog-main__aside {
        align-self: stretch;
    }

    .uq-blog-main--sticky .uq-blog-main__aside-inner {
        position: sticky;
        top: var(--uq-blog-sticky-top);
    }
}

/* ==========================================
   Responsive
   ==========================================
   The breakpoints are Project Details' own -- 1200 / 991 / 767 / 479 -- so the
   two pages change shape at the same widths. */
@media screen and (max-width: 1200px) {
    .uq-blog-page {
        --uq-blog-gap: 40px;
        --uq-blog-aside-width: 340px;
    }

    /* Still THREE columns: the brief calls 992-1200px desktop, and the
       reference keeps three there. The gap, the padding and the title step down
       instead, which is what keeps three cards readable in the narrower
       container. */
    .uq-blog-related {
        --uq-ra-gap: 20px;
        --uq-ra-row-gap: 28px;
        --uq-ra-pad: 20px;
    }
}

/* One column: article, FAQs, then the sidebar cards -- the DOM order already.
   The sidebar stops being sticky here, as specified. */
@media screen and (max-width: 991px) {
    .uq-blog-page {
        --uq-blog-faq-title-size: var(--uq-blog-faq-title-size-lg);
    }

    .uq-blog-main__layout {
        grid-template-columns: minmax(0, 1fr);
        gap: 48px;
    }

    /* Stacked, the column is the full container. The article keeps the measure
       it had at desktop rather than running to 1100px, which is the one thing
       Project Details does not need to solve because its copy is short. */
    .uq-blog-main__article,
    .uq-blog-main__faq,
    .uq-blog-share-bar__row {
        max-width: 780px;
    }

    .uq-blog-main__aside-inner {
        gap: 20px;
    }

    /* Stacked, the cards are the full container width, so a single-column
       contents list would be very tall and very narrow. Two columns keeps it a
       block rather than a page. */
    .uq-blog-toc__list {
        columns: 2;
        column-gap: 24px;
    }

    .uq-blog-toc__item {
        break-inside: avoid;
    }

    /* The toggle appears with the breakpoint, which is also where js/blog.js
       starts collapsing the list. */
    .uq-blog-toc__toggle {
        display: inline-flex;
        align-items: center;
        gap: 8px;
        padding: 6px 12px;
        border: 1px solid var(--uq-blog-border);
        border-radius: 999px;
        background: transparent;
        color: var(--uq-blog-primary);
        font-size: 13px;
        font-weight: 600;
        line-height: 1.2;
        cursor: pointer;
    }

    .uq-blog-toc__toggle:focus-visible {
        outline: 2px solid var(--uq-blog-primary);
        outline-offset: 2px;
    }

    .uq-blog-toc__toggle-icon svg {
        display: block;
        width: 12px;
        height: 8px;
        transition: transform 0.2s ease;
    }

    .uq-blog-toc__toggle[aria-expanded="true"] .uq-blog-toc__toggle-icon svg {
        transform: rotate(180deg);
    }

    .uq-blog-toc__list[data-collapsed="true"] {
        display: none;
    }

    /* The Summarize rows sit two-up when the card is the full container width,
       so the card does not become a tall column of five short links. */
    .uq-blog-ai__list {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
        gap: 2px 8px;
    }

    /* Tablet: two columns. */
    .uq-blog-related {
        --uq-ra-columns: 2;
    }

    .uq-blog-related__header {
        margin-bottom: 24px;
    }
}

@media screen and (max-width: 767px) {
    .uq-blog-page {
        --uq-blog-faq-title-size: var(--uq-blog-faq-title-size-md);
    }

    .uq-blog-breadcrumbs {
        padding-bottom: 0;
    }

    .uq-blog-header {
        padding-bottom: 32px;
    }

    .uq-blog-header__description {
        font-size: 17px;
    }

    .uq-blog-header__media {
        margin-top: 28px;
    }

    /* One notch shorter than it was: 4/3 -> 16/9. On a real post 516px becomes
       387px at 766 and 252px becomes 189px at 375.

       WHY THE PHONE BAND IS STILL TALLER THAN THE DESKTOP ONE, as it was before:
       the column is narrow here, so the same ratio would read as a strip rather
       than a photograph. Keeping the phone one notch taller is the existing
       design's own relationship, preserved rather than invented.

       LEFT AT 16/9 ON PURPOSE when the desktop band was eased back from 21/9 to
       2/1: checked at 390px, where this renders 349x196, the image still reads
       as a proper lead photograph and not a letterbox, so it did not need the
       same correction.

       Note the asymmetry that leaves, in case it ever wants revisiting: desktop
       is now 11% shorter than the original design and the phone is 25% shorter.
       Matching the phone to desktop's 11% would be 3/2 here (224px at 375), one
       value on this line.

       IT ALSO SMOOTHS THIS BREAKPOINT. The image has always grown taller crossing
       below 767 -- measured on the original design, 379px at 768 against 516px at
       766 -- because the ratio changes faster than the column narrows. That step
       is now 337px -> 387px, the smallest it has been. Removing it altogether
       would mean a third breakpoint, which is a layout change rather than a
       height one. */
    .uq-blog-header__image {
        aspect-ratio: 16 / 9;
    }

    .uq-blog-main {
        padding-bottom: 56px;
    }

    .uq-blog-main .uq-blog-main__article h2 {
        font-size: 24px;
    }

    .uq-blog-main .uq-blog-main__article h3 {
        font-size: 20px;
    }

    .uq-blog-main__faq-block {
        margin-top: 44px;
    }

    .uq-blog-toc__list {
        columns: 1;
    }

    /* Phone: one column. A stacked card is full width, so it can afford the
       desktop padding back and a slightly tighter row gap. */
    .uq-blog-related {
        --uq-ra-columns: 1;
        --uq-ra-gap: 16px;
        --uq-ra-row-gap: 16px;
        --uq-ra-pad: 20px;
        padding-top: 48px;
        padding-bottom: 48px;
    }

    /* --few must not force two columns onto a phone. */
    .uq-blog-related--few .uq-blog-related__grid {
        --uq-ra-columns: 1;
    }

    .uq-blog-share-bar {
        padding-bottom: 36px;
    }

    .uq-blog-share-bar__row {
        flex-direction: column;
        align-items: flex-start;
        gap: 14px;
    }

    /* Anchored to the left edge of the control on a narrow screen, so the panel
       cannot hang off the viewport and create horizontal scroll. */
    .uq-blog-share-bar__panel {
        right: auto;
        left: 0;
    }
}

@media screen and (max-width: 479px) {
    .uq-blog-page {
        --uq-blog-faq-title-size: var(--uq-blog-faq-title-size-sm);
    }

    .uq-blog-main__card {
        padding: 20px;
    }

    .uq-blog-ai__list {
        grid-template-columns: minmax(0, 1fr);
    }

    .uq-blog-related {
        --uq-ra-pad: 18px;
        /* The phone step, 1px under the desktop size -- the same shape the Blog
           Hub card's ladder takes at this breakpoint. */
        --uq-ra-title-size: 23px;
        --uq-ra-summary-size: 14px;
        --uq-ra-meta-size: 12px;
    }
}

/* ==========================================
   Reduced motion
   ==========================================
   A `.uq-blog-ticker__track { animation-play-state: paused }` rule used to lead
   this block -- the page's two marquees were its only continuous motion. Both
   strips were removed at the client's request, so the pause has nothing left to
   pause and goes with them; the transition guard below still applies to
   everything on the page. */
@media (prefers-reduced-motion: reduce) {
    .uq-blog-page *,
    .uq-blog-page *::before,
    .uq-blog-page *::after {
        transition-duration: 0.01ms !important;
    }
}

/* ==========================================
   Related Articles -- the slider (4+ cards)
   ==========================================
   Client feedback: "Related blogs should have a slider."

   THERE IS NO CAROUSEL CSS HERE, and that is the point. At four cards or more
   template-parts/blog/related-articles.php emits the RELATED PROJECTS chrome --
   .uq-related-projects__viewport / __track / __item / __nav / __arrow /
   __status -- so the clipping viewport, the transform track and its easing, the
   fractional peek, the round 44px arrows and their disabled state all come from
   style.css, already written and already tested. js/related-projects.js drives
   it unchanged.

   Every one of those rules reads its numbers from five --uq-rp-* custom
   properties that style.css declares on .uq-related-projects, a class this
   section does not carry. Declaring the same five here is the whole of the
   integration: the component follows, and there is one carousel on the site
   rather than two.

   THE GAP IS THE BLOG'S OWN, not Related Projects'. --uq-ra-gap is already
   24px stepping to 16px on a phone, so pointing --uq-rp-gap at it keeps the
   slider on this module's rhythm and means one number to change, not two.

   THE PEEK IS RELATED PROJECTS' EXACTLY -- 3.15 / 2.2 / 1.35 / 1.12 at the same
   four widths -- because "consistent with Related Projects" is the brief and
   the fraction is what makes the next card show. The media queries below mirror
   that ladder; they are needed because style.css sets it on
   .uq-related-projects, which this section is not.

   THREE CARDS OR FEWER MATCH NONE OF THIS: the section has no --carousel class,
   the <ul> is still .uq-blog-related__grid, and the grid rules above are
   untouched. */
.uq-blog-related--carousel {
    --uq-rp-gap: var(--uq-ra-gap);
    --uq-rp-visible: 3.15;
    --uq-rp-radius: var(--uq-ra-radius);
    --uq-rp-arrow-bg: var(--uq-blog-primary, var(--uq-theme-primary, #104E8B));
    --uq-rp-arrow-icon: #ffffff;
}

/* The header becomes a row so the arrows sit opposite the copy, which is where
   Related Projects puts them. __heading is the wrapper the partial emits in this
   mode only; in grid mode the header is still `display: block` with the title
   and description as its two lines.

   Client feedback (#6): the arrows sat too high. `align-items: flex-start` put
   the 44px pair at the TOP of a block that carries a title AND a description --
   65.6px above the bottom of that copy at 1440. Every other slider on the site
   ends the arrows with the copy instead: .uq-reviews__header and
   .uq-manufacturers__header both say `align-items: flex-end`, and the arrows
   come to rest on the last line of the section description. This header now says
   the same thing, and because __heading is the taller item it is the one that
   sets the row height -- so the title and the description do not move at all,
   only the arrows do.

   The `margin-top: 4px` that used to sit on .uq-related-projects__nav below went
   with it: it existed only to nudge the pair down off a flex-start edge, and at
   flex-end it is inert -- a top margin cannot move an item that is aligned by
   its bottom. */
.uq-blog-related--carousel .uq-blog-related__header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 24px;
}

.uq-blog-related--carousel .uq-blog-related__heading {
    min-width: 0;
}

@media screen and (max-width: 991px) {
    .uq-blog-related--carousel {
        --uq-rp-visible: 2.2;
    }
}

@media screen and (max-width: 767px) {
    .uq-blog-related--carousel {
        --uq-rp-visible: 1.35;
    }

    /* The arrows stay on the title's row -- they are the only way to page on a
       device with no hover, and they are already a 44px touch target.

       THE PHONE KEEPS flex-start, which is why it is restated here. The base
       rule above moved to flex-end for feedback #6, and on a phone that would
       have dropped the pair to the last line of a copy block three lines deep,
       leaving a hole beside the title. .uq-related-projects__header carries the
       same flex-start override at this breakpoint, for the same reason, so the
       two Related modules still agree with each other on a phone. The 4px nudge
       is the one the base nav rule used to carry: at flex-start it is what keeps
       the pair off the title's cap line, and it is scoped here now because
       flex-end above has no use for it. */
    .uq-blog-related--carousel .uq-blog-related__header {
        gap: 16px;
        align-items: flex-start;
    }

    .uq-blog-related--carousel .uq-related-projects__nav {
        margin-top: 4px;
    }
}

@media screen and (max-width: 479px) {
    .uq-blog-related--carousel {
        --uq-rp-visible: 1.12;
    }
}
