/* ==========================================================================
   /blog — page 3114, "Benely Insights"

   Reference design: prototypes/blog.html
   Spec: docs/superpowers/specs/2026-09-02-blog-recompose-design.md

   MOST OF THIS PAGE IS NOT IN THIS FILE. The Pro Posts widget has a real
   Style panel, so title/meta/excerpt type and colour, thumbnail size,
   columns, gaps, card fill, border, radius and padding all live in
   _elementor_data as controls. That is the Rule 1 outcome the [bloglist]
   shortcode on /resources could not give, and it is worth protecting: do
   not move a colour or a font size in here for convenience.

   What lives here is only what no control expresses:
     - the hero ground and the kicker's hairline pseudo-element
     - THE ORDER SWAP that moves the date into the eyebrow slot
     - the 3-line and 2-line clamps
     - the cover's bottom hairline and its mist loading ground
     - the card's internal padding and its hover states
     - pagination and the sidebar

   FOUR BLOCKS IN THE PROTOTYPE ARE DELIBERATELY ABSENT, because each has a
   counterpart the Elementor build provides and porting it would be dead CSS
   or would shadow a control:
     - `:root{--e-global-color-*}` and `.wrap`  — the site provides both.
     - `.bnly-blog__layout{display:grid}` and its 1024/860 breakpoints —
       there is no such element. The two columns are Elementor columns
       sized by _inline_size 72/28 (65/35 tablet). A wrapper rule would
       match nothing.
     - `.elementor-posts-container{display:grid;grid-template-columns:
       repeat(2,1fr);gap:…}` and its 600px step — Elementor already emits
       exactly this from cards_columns / cards_column_gap / cards_row_gap.
       Declaring it here would make the columns control inert.
     - `.elementor-post__thumbnail{aspect-ratio:16/9}` and the `img`
       `object-fit:cover` — Elementor owns the cover. `cards_item_ratio`
       writes `padding-bottom: calc(SIZE * 100%)` on the thumbnail and the
       plugin absolutely positions the image inside it
       (`.elementor-has-item-ratio .elementor-fit-height img{height:100%}`).
       The widget also already sets `overflow:hidden` there. Only the
       hairline and the mist ground below are ours.

   THE SIDEBAR IS A DOCUMENTED RULE 1 EXCEPTION, and a legitimate one: it is
   a WordPress core widget (wp-widget-categories), not an Elementor widget,
   so it has NO Style panel and there is no panel here for a stylesheet to
   contradict - the same case as the mega-menu. Colour still binds to
   --e-global-color-*, so a palette change still reaches it.

   TOKEN NAMES ARE THE KIT'S, NOT THE PROTOTYPE'S. prototypes/blog.html
   declares its own :root with friendly names - `navy`, `brand` - that the
   live kit does not emit. The kit has SYSTEM colours primary/secondary/
   text/accent and CUSTOM colours ink/raised/amber/cyan/mist/deep/edge/...
   There is no `navy` and no `brand`. Navy is `secondary`, brand is `primary`.

   Porting `var( --e-global-color-navy )` verbatim fails silently and takes
   the WHOLE declaration with it: an unresolvable var() is invalid at
   computed-value time, so `outline: 2px solid var(--…-navy)` computes to the
   INITIAL outline - style none, width medium (3px), colour currentColor. That
   is not "the colour is wrong", it is "there is no outline at all". It cost
   three focus rings and turned every sidebar hover browser-default black.

   Elementor emits `var( --e-global-color-x )` WITH SPACES inside the parens.
   A regex like `var\(--e-global` matches nothing.

   SCOPING. Card-internal rules compound on .elementor-post__card so they sit
   at (0,0,3,0) and clear Elementor's own skin CSS at (0,0,2,0) on
   specificity rather than on load order - the editor reverses that tie, so a
   tie is not a win. They stay below the per-element control output at
   (0,0,4,0), so every Style-panel control still wins, which is the point.

   Never scope on .elementor-location-* (front-end only, invisible in the
   editor) and never compound with .elementor-section (the class may land on
   a column).
   ========================================================================== */

/* ==========================================================================
   MIST HERO — a lighter sibling of the /resources ink hero.

   Deliberately not ink: /blog sits one click behind /resources, and two
   identical ink heroes in a row read as repetition. This page's job is
   browsing, not arriving.

   The kicker, page title and lede carry every colour and type value as
   widget controls. Only the ground and the kicker's hairline are here.
   ========================================================================== */
/* NO PADDING HERE. The band's rhythm is the section's own padding control -
   88/72/56 - and that is deliberate.

   A `padding-block` here was DEAD CSS. Elementor emits
   `.elementor-3114 .elementor-element.elementor-element-47f62a9d{padding:…}`
   at (0,0,2,0) and `.bnly-bloghero` is (0,0,1,0), so the control wins on
   specificity and load order cannot save it. Computed padding was 0px top and
   bottom, and the ~400px the hero appeared to have was not design at all: the
   section carried a leftover `height:"min-height"` with no `custom_height`,
   so Elementor's 400px DEFAULT was holding it open, plus a stray
   `custom_height_mobile:300`. Both are now cleared.

   This is the third time in this redesign that splitting padding between a
   control and a stylesheet has ended with the control silently winning. Put
   the whole property in one system, and prefer the control. */
.bnly-bloghero{
  background:var( --e-global-color-mist );
}

/* The kicker's RULE is a pseudo-element, which no control expresses. Its
   11.5px/.22em/lh 1.2 type is the site's settled eyebrow - identical to the
   CTA band's and every footer column head - and lives on the widget. */
.bnly-bloghero__kicker{
  display:flex;align-items:center;gap:14px;
}
.bnly-bloghero__kicker::after{
  content:"";height:1px;flex:1;max-width:96px;
  background:rgba(21,68,120,.30);
}
/* Measure caps. A 20ch headline and a 56ch lede are line-length limits, not
   colour or type, and there is no control for either.

   THEY GO ON THE TEXT ELEMENT, NOT THE WIDGET WRAPPER. `ch` resolves against
   the element's OWN font, and the wrapper inherits the page's -apple-system
   20px while the heading is Newsreader 48px. Measured: `20ch` on the wrapper
   computed to 249.7px and broke "Benely Insights" - fifteen characters -
   across two lines. On the heading itself it resolves against 48px Newsreader,
   which is what 20ch was meant to mean. */
.bnly-bloghero__title .elementor-heading-title{ max-width:20ch }
.bnly-bloghero__lede p{ max-width:56ch }

/* A measure cap CENTRES the box unless something says otherwise, and here
   something did: redesign.css carries a site-wide
   `.elementor-widget-text-editor .elementor-widget-container > p{margin-left:auto}`
   at (0,0,2,1). The rule above sets only max-width, so the auto margin won
   uncontested and the lede's 56ch box was centred in the 1200 rail - it
   started at 339.6 against an h1 at 120, and at 191.7 against 40 at 1024.
   It looked deliberate, and at 390 it aligned perfectly, because there the
   text is narrower than the cap and there is no free space to split.

   The site-wide rule is CORRECT and stays: the CTA band's "See what our
   clients say about us." is text-align:center and genuinely wants a centred
   box. This hero is the only place on the site where a text-align:start
   paragraph sits in one. Overriding it needs (0,0,3,1) - a tie would only
   win by load order, and the editor reverses that. */
.bnly-bloghero .bnly-bloghero__lede .elementor-widget-container > p{
  margin-inline:0;
}

/* The lede's line-height control is defeated, and this restores it rather than
   restating it. Elementor writes `line-height:1.6` on the widget WRAPPER, but
   `style.css` carries a bare `p{line-height:var(--wp--typography--line-height…)}`
   that matches the <p> directly - and a rule that matches always beats an
   inherited value, whatever the specificity. Measured: the panel said 30.4px
   and the paragraph rendered 32.3px. Inheriting re-points it at the control,
   so the panel and the canvas agree again. */
.bnly-bloghero__lede p{ line-height:inherit }

/* ==========================================================================
   THE BODY — posts + sidebar

   NO PADDING HERE, for the same reason as the hero fifty lines up, and this
   was the FOURTH time in this redesign that splitting padding between a
   control and a stylesheet ended with the control silently winning.

   `.bnly-blog{padding-block:…}` was dead. Elementor emits
   `.elementor-3114 .elementor-element.elementor-element-3920321{padding:0px}`
   at (0,0,3,0) - in all three media queries - and `.bnly-blog` is (0,0,1,0).
   Computed padding was 0px top and bottom, so the sidebar's CATEGORIES head
   sat flush against the hero's bottom edge (0px) and the pagination cleared
   the ink CTA band by 10px, which is Elementor's default widget-wrap padding
   rather than anything designed. For scale, /resources leaves 96/72/56 before
   the same band.

   The rhythm is now the section's padding control at 80/56/48. One system per
   property, and prefer the control - it is what an editor reaches for, and it
   outranks the stylesheet anyway.
   ========================================================================== */

/* --- the card -----------------------------------------------------------
   Background, border, radius, shadow and padding are all CONTROLS on the
   widget and are not repeated here. What is here is the flex column the
   order swap needs, the corner clip the radius control needs, and the
   hover, which the widget has no control for. */
:is(.bnly-blog,.bnly-related) .elementor-post__card{
  display:flex;flex-direction:column;height:100%;overflow:hidden;
  transition:border-color .25s cubic-bezier(.22,1,.36,1),
             transform .25s cubic-bezier(.22,1,.36,1);
}
/* Hover border only: brand is 3.46 on white and may never carry small text
   (colour law 2). There is no hover-state control on this widget, so this
   colour is here by necessity, not convenience. */
:is(.bnly-blog,.bnly-related) .elementor-post__card:hover{
  border-color:var( --e-global-color-primary );
  transform:translateY(-2px);
}

/* THE ORDER SWAP. The cards skin renders thumbnail -> text -> meta, so the
   date lands at the BOTTOM. The card is flex/column with exactly three
   direct children, so this is all it takes to lift the meta into the eyebrow
   position and match the /resources card. Note it puts DOM order (title
   first) at odds with visual order (date first) - deliberate, and the better
   way round: a screen reader meets the meaningful link before the date. */
:is(.bnly-blog,.bnly-related) .elementor-post__card .elementor-post__thumbnail__link{ order:1 }
:is(.bnly-blog,.bnly-related) .elementor-post__card .elementor-post__meta-data{ order:2 }
:is(.bnly-blog,.bnly-related) .elementor-post__card .elementor-post__text{ order:3 }

/* Cover. Its own hairline for the same measured reason as /resources: the
   featured images are white-ground title cards, 67-77% near-white, so
   without this line the cover's edge dissolves into the card. The mist is
   the ground the box shows while the image loads. The 16/9 itself is the
   cards_item_ratio control - see the header. */
:is(.bnly-blog,.bnly-related) .elementor-post__card .elementor-post__thumbnail{
  border-bottom:1px solid rgba(124,136,148,.22);
  background:var( --e-global-color-mist );
}

/* !important is required, and it is the only place in this file that earns it.
   The header says cards_item_ratio owns the cover, and it does own the BOX -
   measured 408x231, ratio 1.770 against 16/9's 1.778. But the IMAGE inside it
   was still not filling, at 412x130, and no Elementor control can fix that:

   the PARENT THEME stamps an inline style on every attachment image.
   twentytwentyone/inc/template-functions.php filters
   wp_get_attachment_image_attributes unconditionally and prepends
   `width:100%;height:56.28%;max-width:1672px`. An inline style beats any
   stylesheet rule lacking !important - including Elementor's own
   `.elementor-has-item-ratio .elementor-fit-height img{height:100%}` - and
   56.28% of the box is not 100% of it.

   This is the same trap resources.css:139 documents, and it is why /resources
   passes. CLAUDE.md files it under Elementor's image widget; it is not
   specific to that widget at all - it hits get_the_post_thumbnail() and the
   Posts widget identically, because it is a filter on the attachment itself.

   Verify with getComputedStyle(img).height, never by reading the rule back. */
:is(.bnly-blog,.bnly-related) .elementor-post__card .elementor-post__thumbnail img{
  display:block;
  width:100% !important;
  height:100% !important;
  max-width:none !important;
  object-fit:cover;
}

/* Date, as the eyebrow. Its type and colour are meta controls.

   HORIZONTAL padding is the `card_padding` CONTROL, holding the clamp
   verbatim on the `custom` unit. It used to be the shorthand below, and it
   was DEAD for its whole life: the control was set to 0, which emits
   `padding: 0 0` from `{{WRAPPER}} .elementor-post__text` at (0,0,4,0) -
   `.elementor-<post> .elementor-element.elementor-element-<id>` is three
   classes before the target, not two - and this file's (0,0,3,0) rule lost.
   The cards rendered with their title, date and excerpt flush against the
   card edge while the stylesheet said otherwise.

   VERTICAL padding stays here for a reason a control cannot express: the
   skin hardcodes `padding: 10px {{SIZE}}` on the meta, so its 10px is not
   reachable from any panel, and `card_vertical_padding` writes to
   `.elementor-post__card` itself - which holds the FULL-BLEED cover, so
   using it would inset the image from the card's top edge. Left at 0.

   These must outrank the control's own (0,0,4,0), so they compound
   `.elementor-element.elementor-widget` to reach (0,0,5,0). A tie would
   only win by load order, and the editor reverses that. */
:is(.bnly-blog,.bnly-related) .elementor-post__card .elementor-post__meta-data{
  margin:0;
  border:0;                                    /* the cards skin draws a
     meta border by default; it belonged to a footer position */
}
:is(.bnly-blog,.bnly-related) .elementor-element.elementor-widget
  .elementor-post__card .elementor-post__meta-data{
  padding-top:clamp(16px,1.6vw,22px);
  padding-bottom:0;
}
:is(.bnly-blog,.bnly-related) .elementor-post__card .elementor-post__text{
  display:flex;flex-direction:column;gap:8px;
}
:is(.bnly-blog,.bnly-related) .elementor-element.elementor-widget
  .elementor-post__card .elementor-post__text{
  padding-top:10px;
  padding-bottom:clamp(16px,1.6vw,22px);
}

/* Three lines keeps every card's text block the same height without a fixed
   height that a longer headline would overflow. */
:is(.bnly-blog,.bnly-related) .elementor-post__card .elementor-post__title{
  margin:0;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
  overflow:hidden;
}
/* Parent-relative: no control can express "recolour on the card's hover". */
:is(.bnly-blog,.bnly-related) .elementor-post__card:hover .elementor-post__title a{
  color:var( --e-global-color-secondary );
}
/* The card title is the primary link on this page and had no focus ring -
   the thumbnail link carries tabindex="-1", so this is the only tab stop
   per card. Navy on white is 9.86. The outline follows the line boxes on a
   wrapped inline link, which is correct behaviour, not a defect. */
:is(.bnly-blog,.bnly-related) .elementor-post__card .elementor-post__title a:focus-visible{
  outline:2px solid var( --e-global-color-secondary );
  outline-offset:3px;
}
/* The excerpt is why these cards are wider than /resources'. Two lines of
   context is the difference between an index and a browse page. */
:is(.bnly-blog,.bnly-related) .elementor-post__card .elementor-post__excerpt p{
  margin:0;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;
}

/* --- pagination ---------------------------------------------------------
   The default is bare WordPress link soup. The widget's pagination controls
   reach colour and typography only - there is no control for the chip's
   size, border, radius or the filled current state, so the geometry and the
   colours that belong to it are here. Numbers get a real target size and the
   current page is a filled ink chip. */
.bnly-blog .elementor-pagination{
  margin-top:clamp(32px,4vw,48px);
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:6px;
  font:400 14px/1 'Poppins',system-ui,sans-serif;
}
.bnly-blog .elementor-pagination .page-numbers{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:40px;height:40px;padding:0 12px;
  border-radius:var(--benely-radius,8px);
  border:1px solid rgba(124,136,148,.28);
  color:var( --e-global-color-secondary );          /* 9.86 on white */
  text-decoration:none;
  transition:border-color .25s cubic-bezier(.22,1,.36,1),
             background .25s cubic-bezier(.22,1,.36,1);
}
.bnly-blog .elementor-pagination .page-numbers:hover{
  border-color:var( --e-global-color-secondary );
  background:var( --e-global-color-mist );
}
.bnly-blog .elementor-pagination .page-numbers.current{
  background:var( --e-global-color-ink );
  border-color:var( --e-global-color-ink );
  color:var( --e-global-color-surface );       /* 17.04 on ink */
}
.bnly-blog .elementor-pagination .page-numbers.dots{
  border-color:transparent;min-width:24px;padding:0;
  color:var( --e-global-color-deep );
}
.bnly-blog .elementor-pagination .page-numbers:focus-visible{
  outline:2px solid var( --e-global-color-secondary );outline-offset:3px;
}

/* ==========================================================================
   THE SIDEBAR.

   RULE 1 EXCEPTION, and a legitimate one: this is a WordPress core widget
   (`wp-widget-categories`), not an Elementor widget. It has NO Style panel
   at all, so there is no panel here for a stylesheet to contradict - the
   same documented case as the mega-menu. Colour still binds to
   --e-global-color-*, so a palette change still reaches it.

   The list is emitted as <h5>Categories</h5> + <nav><ul><li.cat-item>.
   Counts are NOT emitted until the widget's "Show post counts" option is
   enabled.
   ========================================================================== */
/* The site header is `position:fixed` and 120px tall at EVERY width (measured
   1440 down to 390), so it is not in flow and a sticky offset measured from
   the viewport parks the list underneath it. `top:24px` put the "Categories"
   heading 96px behind the nav. The offset has to clear the header first. */
.bnly-blog{ --benely-headerh:120px }
.bnly-blog__side{
  position:sticky;
  top:calc(var(--benely-headerh) + 24px);
}

/* The two pages nest this differently, so sticky cannot live at one level.

   ARCHIVE is a CONTAINER build whose parent sets align-items:flex-start, so
   .bnly-blog__side is content-height (581px) inside a 2827px inner container.
   It has room to travel and the rule above is enough.

   /blog is a COLUMN build, and Elementor stretches BOTH the column and its
   .elementor-widget-wrap to the row's full height - measured 1528px each
   against the same 581px list. A sticky box with zero room to move is inert,
   which is why the sidebar here had never actually stuck. The widget inside
   the wrap is the first content-height ancestor, so that is where it goes. */
.bnly-blog__side > .elementor-widget-wrap > .elementor-widget{
  position:sticky;
  top:calc(var(--benely-headerh) + 24px);
}

.bnly-blog__side h5{
  margin:0 0 14px;
  font:700 11.5px/1.2 'Poppins',system-ui,sans-serif;
  letter-spacing:.22em;text-transform:uppercase;
  color:var( --e-global-color-secondary );          /* 9.86 on white */
}
.bnly-blog__side ul{ list-style:none;margin:0;padding:0 }
.bnly-blog__side li:last-child{ border-bottom:1px solid rgba(124,136,148,.22) }

/* THE COUNT IS A BARE TEXT NODE, and that decides this whole block.
   WordPress core emits it after the </a> with no wrapper at all:

       <li class="cat-item cat-item-11"><a href="…">Health Insurance</a> (107)

   The prototype assumed a `<span class="cat-count">` inside the <a> and this
   file carried a `.cat-count` rule to match. That rule was dead - CSS cannot
   target a text node.

   So the LI carries the count's appearance and the anchor overrides it for
   the label. The li is the flex row, which also puts the count at the right
   without needing an element to push against. Deep, not muted: muted #A9ADB5
   is 2.4 on white and would fail; deep is 8.86. */
.bnly-blog__side li{
  border-top:1px solid rgba(124,136,148,.22);
  display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding:11px 2px;
  font:400 12px/1.3 'Poppins',system-ui,sans-serif;
  color:var( --e-global-color-deep );          /* the count - 8.86 on white */
  font-variant-numeric:tabular-nums;
}
.bnly-blog__side li a{
  font:400 15px/1.3 'Poppins',system-ui,sans-serif;
  color:var( --e-global-color-ink );           /* the label - 17.04 on white */
  text-decoration:none;
  transition:color .2s cubic-bezier(.22,1,.36,1);
}
.bnly-blog__side li a:hover{ color:var( --e-global-color-secondary ) }
.bnly-blog__side li a:focus-visible{
  outline:2px solid var( --e-global-color-secondary );outline-offset:2px;
}

/* --- breakpoints --------------------------------------------------------
   Every breakpoint named here must be measured, not assumed.

   767, NOT the prototype's 860. The prototype stacked a CSS grid it owned;
   here the stack is Elementor's, and Elementor collapses columns at its
   MOBILE breakpoint (767) by default. Un-sticking the sidebar and splitting
   its list into two columns at 860 would do it while the sidebar is still a
   35% column beside the posts, which is where it is between 768 and 1024. */
@media (max-width:767px){
  /* Sidebar drops below the posts. It is a secondary index, and a narrow
     column beside a single card column is not worth the width. */
  .bnly-blog__side,
  .bnly-blog__side > .elementor-widget-wrap > .elementor-widget{ position:static }
  .bnly-blog__side ul{
    display:grid;grid-template-columns:repeat(2,1fr);column-gap:24px;
  }
}
@media (max-width:600px){
  .bnly-blog__side ul{ grid-template-columns:1fr }
}
