/* #7870: Single source of truth for blog section variant treatment AND (since the
   #7870 follow-up) the Left/Right side-by-side placement layout.
   Loaded render-blocking on the public surface via BlogLayout.razor's <HeadContent>
   (the public LiveEventBingo.Web App.razor link was retired in #8646 so it no longer
   render-blocks every route), and globally by the admin surface via
   MyEventBingo.Admin App.razor. So the BlogSectionVisual helper's CSS class output
   renders identically wherever it lands.

   Previously triple-duplicated across:
     - LiveEventBingo.Shared/Shared/DesktopBlogDetails.razor.css (scoped)
     - LiveEventBingo.Shared/Shared/MobileBlogDetails.razor.css (scoped)
     - MyEventBingo.Admin/Components/Pages/BlogManager.razor.css (scoped)
   Each kept drifting away from the others -- box-shadow and per-variant link
   colours were the most recent omission in the admin preview, caught by the
   2026-05-27 triad review on #7870. Centralising here.

   Design tokens (--meb-blog-*) remain the single source of truth for the
   actual colour values; this file only maps the CSS class output to those
   tokens. */

/* Base Default colour. The other variants override this with their on-section
   colour. Setting it here (rather than relying on inheritance from the page text)
   lets .section-copy use `color: inherit` and still render Default body as black
   — which it would not, otherwise, since the page text token is #2D2D2D. */
.article-section {
    color: var(--meb-blog-text-on-section-default);
}

/* CT-02 T6618 / Frozen Design Contract UI/UX v6 §2B -- shared chrome for all
   non-default variants: hard black border + 4px-offset shadow + 32px radius. */
.article-section--highlight,
.article-section--sky,
.article-section--mint,
.article-section--coral,
.article-section--ink {
    border: var(--meb-border-width-sm) solid var(--meb-blog-border-section);
    border-radius: var(--meb-blog-radius-section);
    box-shadow: var(--meb-blog-shadow-section);
    padding: var(--meb-space-stack-md) var(--meb-space-inline-20);
}

/* Mobile padding override -- tighter than desktop. Matches the prior
   MobileBlogDetails.razor.css scoped block (padding: --meb-space-stack-12
   --meb-space-inline-md). The variant set is identical so we lean on the
   shared selectors here rather than splitting by component. */
@media (max-width: 767px) {
    .article-section--highlight,
    .article-section--sky,
    .article-section--mint,
    .article-section--coral,
    .article-section--ink {
        padding: var(--meb-space-stack-12) var(--meb-space-inline-md);
    }
}

.article-section--highlight {
    background: var(--meb-blog-surface-section-highlight);
    color: var(--meb-blog-text-on-section-highlight);
}
.article-section--sky {
    background: var(--meb-blog-surface-section-sky);
    color: var(--meb-blog-text-on-section-sky);
}
.article-section--mint {
    background: var(--meb-blog-surface-section-mint);
    color: var(--meb-blog-text-on-section-mint);
}
.article-section--coral {
    background: var(--meb-blog-surface-section-coral);
    color: var(--meb-blog-text-on-section-coral);
}
.article-section--ink {
    background: var(--meb-blog-surface-section-ink);
    color: var(--meb-blog-text-on-section-ink);
}

/* CT-02 / Frozen Blog Detail UI/UX v1.2 §5 line 339-345 -- inline link colours
   per variant. Ensures links remain readable on every section background.
   Without this, the Ink (dark navy) variant renders inherited blue links on a
   dark surface, failing WCAG contrast -- exactly the case flagged in the
   triad review when the admin preview accidentally omitted these rules. */
.article-section--highlight a { color: var(--meb-blog-text-section-link-highlight); }
.article-section--sky       a { color: var(--meb-blog-text-section-link-sky); }
.article-section--mint      a { color: var(--meb-blog-text-section-link-mint); }
.article-section--coral     a { color: var(--meb-blog-text-section-link-coral); }
.article-section--ink       a { color: var(--meb-blog-text-section-link-ink); }

/* ── Per-post hero-strip colour (BlogPost.HeroStyle) ─────────────────────────
   Gives the blog-detail hero the SAME palette choices as a section's Visual style.
   Emitted by BlogSectionVisual.ResolveHeroContainerCss onto .article-hero-container.
   Each modifier REDEFINES the local --meb-blog-surface-hero variable on the container, so the
   scoped `.article-hero-container { background: var(--meb-blog-surface-hero) }` rule in
   Desktop/MobileBlogDetails.razor.css reads the override with no specificity fight.
   The four light variants keep the vetted dark hero text tokens: they stay readable on a light
   surface, and — critically — the affiliate/legal .disclaimer-note (which shares
   --meb-blog-text-back) is NOT recoloured. Only the dark Ink variant flips the hero text tokens to
   the on-section colour, so title/subtitle/back-link/disclaimer stay legible on the dark surface
   (the same lemon-on-ink pairing a section uses). The white date-pill keeps its black meta text
   either way. Default emits no modifier and keeps the legacy global hero colour. Reuses existing
   section tokens; no new tokens, no raw hex. */
.article-hero-container--highlight { --meb-blog-surface-hero: var(--meb-blog-surface-section-highlight); }
.article-hero-container--sky       { --meb-blog-surface-hero: var(--meb-blog-surface-section-sky); }
.article-hero-container--mint      { --meb-blog-surface-hero: var(--meb-blog-surface-section-mint); }
.article-hero-container--coral     { --meb-blog-surface-hero: var(--meb-blog-surface-section-coral); }
.article-hero-container--ink {
    --meb-blog-surface-hero: var(--meb-blog-surface-section-ink);
    --meb-blog-text-title: var(--meb-blog-text-on-section-ink);
    --meb-blog-text-subtitle: var(--meb-blog-text-on-section-ink);
    --meb-blog-text-back: var(--meb-blog-text-on-section-ink);
}

/* CT-02 T6617 / Frozen Design Contract UI/UX v6 §1B -- Image side-by-side placement.
   #7870 follow-up: moved here from DesktopBlogDetails.razor.css (scoped ::deep) so the
   admin BlogManager preview renders Left/Right side-by-side IDENTICALLY to the public
   surface. The variant treatment (colour/border/shadow) was centralised in #7870, but
   the placement *layout* was the one piece left behind in the public-only scoped file --
   which is why the admin preview used to stack image-above-text for Left/Right.

   Section becomes a flexbox row when the modifier class is present; the figure sits on
   the side dictated by the modifier via `order`. Mobile never emits these modifier
   classes (MobileBlogDetails passes includePlacementModifier:false), so the rules match
   nothing on the mobile surface and no mobile collapse is needed here. The admin preview
   is desktop-only and now passes includePlacementModifier:true. */
.article-section--image-left,
.article-section--image-right {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: var(--meb-space-inline-20);
}

/* Two-slot side-by-side layout: figure + text-block as direct children. ADO #7982:
   SectionFigure always renders <figure class="section-figure"> as the outer element, so
   the direct child here is always .section-figure regardless of PictureHref. */
.article-section--image-left > .section-figure {
    order: 0;
    flex: 0 0 auto;
    max-width: 40%;
}
.article-section--image-left > .section-text {
    order: 1;
    flex: 1 1 auto;
    min-width: 0; /* allow text-block to shrink under tight widths */
}
.article-section--image-right > .section-figure {
    order: 1;
    flex: 0 0 auto;
    max-width: 40%;
}
.article-section--image-right > .section-text {
    order: 0;
    flex: 1 1 auto;
    min-width: 0;
}

/* ADO #9576: cap the section image to its figure — the image analogue of the video rule
   below, which already carries the same `width:auto + max-width:100%` lesson.

   `.section-figure img` in the scoped DesktopBlogDetails.razor.css sets `width: auto` with
   NO max-width, so an asset wider than its figure lays out at intrinsic width and the
   figure's `overflow: hidden` silently clips the excess. Measured on prod post 1 at 1440
   before the content workaround: a 731px img inside a 367px Left figure (364px lost, the
   headline cut mid-word) and 497px inside the same 367px Right figure. Side placements bind
   first because of the max-width:40% above, but the cap is deliberately UNCONDITIONAL — the
   full-width placements escaped only because the ~900px column happens to exceed the current
   assets' intrinsic width, and a wider asset clips there too. Matches `.article-hero img`,
   which has always been capped this way.

   Lives HERE rather than in the scoped file for the same reason as the placement layout
   above: the admin BlogManager preview loads this sheet, and an author must see the same
   clipping the public surface would produce. Mobile already sets `width: 100%`, so this is
   a no-op there. Only §4.1-allowed raw props (max-width, height). */
.section-figure img {
    max-width: 100%;
    height: auto; /* hold aspect when max-width binds */
}

/* ADO #8903 (T3): self-hosted video sizing + the CLS reservation. This rule lives HERE — in the
   render-blocking blog-route CSS (BlogLayout HeadContent), NOT in the deferred scoped .razor.css
   bundle — so the aspect-ratio box holds geometry BEFORE first paint (the #8593/#8632 cold-load CLS
   class). The per-clip ratio is the inline `--clip-aspect` custom property CdnVideo sets from the
   CHOSEN device slot's derived dims (mobile → portrait, desktop → landscape, exactly); `16/9` is the
   fallback only for legacy / failed-derive / fallback-served slots. `object-fit: contain` fits both
   portrait (9:16 mobile gameplay) and landscape (16:9) within the reserved box; `max-height: 60vh`
   (M11) keeps a portrait clip usable without blowing past the fold (in Left/Right the figure's
   max-width:40% binds first, so the cap mostly governs the full-width Above/Below + all-mobile case).

   WIDTH must be `auto` (+ `max-width:100%`), NOT `100%`. With `width:100%` a PORTRAIT clip in a
   full-width Above/Below figure pins the box to the whole column (~900px on desktop) while
   `max-height:60vh` caps the height -- so `object-fit:contain` letterboxes the skinny clip in a sea
   of empty side space (measured ~337px of dead space each side on a 1080x2316 clip). `width:auto`
   lets the aspect-ratio + max-height drive the width instead, so the box hugs the clip (box shrinks
   to ~252px); `max-width:100%` still caps a LANDSCAPE clip to the column, and `margin-inline:auto`
   centres the hugged box. Left/Right (max-width:40%) already hugged, so it is unchanged. Verified
   against prod content (posts 1035/1038) at 1440x900 + 390x844, CLS-neutral (aspect-ratio reserves
   the box pre-paint either way; the <video> is not a layout-shift source). ADO #8903 T5 (#8915).
   Only §4.1-allowed raw props (aspect-ratio, object-fit, overflow, display, width, max-width,
   max-height, margin). */
.section-figure.section-video video {
    display: block;
    width: auto;
    max-width: 100%;
    height: auto;
    aspect-ratio: var(--clip-aspect, 16 / 9);
    max-height: 60vh;
    object-fit: contain;
    margin-inline: auto;
}

/* ADO #8903 follow-up (#8915 CLS): reserve the flex-item WIDTH before the clip's metadata loads.
   Image-left/right places the figure as a SHRINK-TO-FIT flex item (flex:0 0 auto; max-width:40%), so its
   width comes from its content's natural size. But the `width:auto` above (needed to hug a portrait clip)
   means a poster-less <video> contributes ZERO width until readyState>=1 -- so the figure collapsed to 0
   and the clip VANISHED during load, then reappeared, and flickered again on every Blazor hydration
   node-rebuild (the fresh <video> resets to readyState 0). The earlier claim that "Left/Right already
   hugged, so it is unchanged" held only for the STABLE (loaded) state, not the pre-metadata window.
   Deriving a definite basis from the chosen-slot aspect (--clip-aspect, set on the FIGURE by SectionVideo)
   times the 60vh height cap gives the figure a real width pre-load; min(40%, ...) keeps the column cap so a
   landscape clip is bounded exactly as before. The full-width Above/Below case is a normal block that seeds
   its box from max-height:60vh and never collapsed -- so it is untouched. Verified on prod content (post
   1037, image-left) at 1440x900: box holds ~322x572 at readyState 0 (was 0x0), zero shift once loaded.
   Only §4.1-allowed raw props (flex-basis; flex is already used by the .article-section--image-* rules). */
.article-section--image-left > .section-figure.section-video,
.article-section--image-right > .section-figure.section-video {
    flex-basis: min(40%, calc(60vh * var(--clip-aspect, 16 / 9)));
}

/* #11059: hide the SEO nav from the render-blocking sheet. This rule used to live in BlogLayout's inline
   <style> after the article (~87K into the document), so the nav painted as a 24px row and then vanished (CLS).
   The sheet is a static render-blocking link in all three shells, so the hide applies before first paint.
   Keep it out of BlogLayout.razor. */
.seo-primary-nav {
    position: absolute !important;
    left: -9999px !important;
    top: auto !important;
    width: 1px !important;
    height: 1px !important;
    overflow: hidden !important;
    white-space: nowrap !important;
}

/* #11050: the blog shell and heading font-family rules moved here from BlogLayout's inline <style> after the
   article, so the first (SSR) paint uses the heading font (Poppins) whenever the preloaded face has arrived
   (font-display:swap; best-effort) and the later circuit-start rebuild of the h1 is not a larger, later LCP
   candidate. Same declarations and selectors as the old inline block. These rules now load before app.css and
   the scoped bundle, so a later unscoped rule of equal specificity (0,1,1) would win. Only the latin subset
   of Poppins 800 is preloaded (App.razor); latin-ext titles fall back until the face arrives.
   #7855-A: blog typography is token-driven per Frozen Detail v1.2 section 5; headings and meta opt in to their
   roles via --meb-blog-font-family-heading (Poppins) / --meb-blog-font-family-body. */
.blog-standalone-layout {
    /* The body Stack is Align="center", so without a definite width .main-body shrink-wraps to its content
       (see MainLayout.razor.css .main-body). Required so the blog column's contain: inline-size cannot
       collapse the article column. */
    width: 100%;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    font-family: var(--meb-blog-font-family-body);
}

.blog-standalone-layout h1,
.blog-standalone-layout h2,
.blog-standalone-layout h3,
.blog-standalone-layout h4,
.blog-standalone-layout h5,
.blog-standalone-layout h6,
.blog-standalone-layout .title,
.blog-standalone-layout .article-title,
.blog-standalone-layout .section-title {
    font-family: var(--meb-blog-font-family-heading);
}
