
.csh-industry-slider-wrap{position:relative}
.csh-industry-slider{display:flex!important;grid-template-columns:none!important;gap:24px;overflow-x:auto;scroll-snap-type:x mandatory;scroll-padding-inline:4px;-webkit-overflow-scrolling:touch;padding:8px 4px 20px;scrollbar-width:thin}
.csh-industry-slider>.card{flex:0 0 calc((100% - 72px)/4)!important;min-width:260px;scroll-snap-align:start}
.csh-industry-slider::-webkit-scrollbar{height:8px}
.csh-industry-slider::-webkit-scrollbar-thumb{background:#cf3949;border-radius:99px}
.csh-slider-controls{display:flex;justify-content:flex-end;gap:10px;margin:0 0 14px}
.csh-slider-btn{width:42px;height:42px;border:1px solid #d8e1eb;border-radius:50%;background:#fff;color:#0f2d49;font-size:24px;line-height:1;cursor:pointer;box-shadow:0 4px 14px rgba(15,45,73,.1)}
.csh-slider-btn:hover{background:#cf3949;color:#fff;border-color:#cf3949}
@media(max-width:1024px){.csh-industry-slider>.card{flex-basis:calc((100% - 24px)/2)!important}}
@media(max-width:640px){.csh-industry-slider>.card{flex-basis:85%!important;min-width:0}}

/* ============================================================
   Batch 9 — Services page (532) density pass
   Added 2026-10-02 by the design pass (task #12).
   LAYOUT ONLY: spacing, grouping, hierarchy, column counts.
   No copy is set in this block.
   Every selector is prefixed `div.cshp`. The class `.cshp` is defined
   only inside page 532's own markup, so no rule below can match any
   other page on the site.
   Rollback: restore this field from custom-css-before.txt (SHA-256
   806abe99a9059363097978e0445753aa5a2d03238c0e26b1ac12c76c0a9067ac).
   ============================================================ */

/* 1 — Rendering artefact. The live render injects empty <p></p> elements
       ahead of real paragraphs; each one carries a 13px top margin from
       `.cshp .service p`. They hold no content, so they are removed from
       layout. This targets rendered output only — no stored content. */
div.cshp p:empty{display:none}

/* 2 — Vertical rhythm. A clear gap between one section and the next,
       a tight one between a heading and what it introduces. Previously
       a flat 64px / 26px pair repeated across every section. */
div.cshp{padding:52px 22px 64px}
div.cshp .intro{margin-bottom:28px}
div.cshp .section-head{margin:0 0 18px}
div.cshp .services,div.cshp .steps,div.cshp .plans,div.cshp .fee-wrap{margin-bottom:52px}
div.cshp .cta{margin-top:52px}

/* 3 — "Why work with us": four claims of 8-12 words each were rendering as a
       second two-column white-card grid directly above the service grid, in
       the same treatment. Four across reads as one strip and removes the
       repeat. Applies to the grid that follows the head without an id, which
       is the only 4-card .services section. */
div.cshp .section-head:not([id]) + .services{grid-template-columns:repeat(4,1fr);gap:14px}

/* 4 — Six delivery steps in 3x2: a complete block with no half-empty row,
       and it rhymes with the three-column packages grid above it. */
div.cshp .steps{grid-template-columns:repeat(3,1fr);gap:16px}

/* 5 — The services grid is two columns and closes cleanly at eight cards,
       so no card spans. The parity rule that used to span the last card while
       the count was odd (grid-column:1/-1 on article:last-child:nth-child(odd))
       was REMOVED on 2026-10-02: inert at eight cards, and at nine it would
       have changed the layout silently rather than by intent. If the service
       count ever becomes odd, add the span deliberately, with the new count
       in hand. Two columns is kept over one: a single column costs roughly
       600px of scroll for no readability gain. */

/* 6 — Card interiors, where the height actually is. Each service card holds
       four paragraphs, each previously carrying a 13px top margin at 1.65
       leading. */
div.cshp .service{padding:20px}
div.cshp .service p{margin:7px 0 0;line-height:1.45}
div.cshp .num{width:30px;height:30px}
div.cshp .btn{min-height:44px;padding:10px 18px}

/* 7 — Package cards. One long price line on the third card sets the height of
       all three, because the grid stretches them to match. */
div.cshp .plan{padding:26px}
div.cshp .price-line{font-size:14px;line-height:1.4;padding:11px 0}
div.cshp .plan ul{margin:16px 0 20px}
div.cshp .plan li{padding:5px 0 5px 25px}

/* 8 — "Quoted separately": seven short items read better across two columns
       than as one stack down a full-width card. */
div.cshp .cost-title{padding:20px 26px}
div.cshp .cost-body{padding:18px 26px}
div.cshp .cost-body ul{columns:2;column-gap:44px;line-height:1.7}
div.cshp .note{padding:14px 26px}

/* 9 — FAQ rows and step cards. */
div.cshp details{padding:15px 4px}
div.cshp .step{padding:18px}

/* 10 — Tablet. */
@media(max-width:900px){
div.cshp .section-head:not([id]) + .services{grid-template-columns:repeat(2,1fr)}
div.cshp .steps{grid-template-columns:repeat(3,1fr)}
div.cshp .cost-body ul{columns:1}
}

/* 11 — Mobile. Steps and the four claims stay two-up rather than collapsing
        to a single column; padding and section rhythm tighten. */
@media(max-width:600px){
div.cshp{padding:34px 14px 44px}
div.cshp .section-head{margin:0 0 16px}
div.cshp .services,div.cshp .steps,div.cshp .plans,div.cshp .fee-wrap{margin-bottom:38px}
div.cshp .section-head:not([id]) + .services{grid-template-columns:repeat(2,1fr);gap:12px}
div.cshp .steps{grid-template-columns:repeat(2,1fr);gap:12px}
div.cshp .service{padding:18px}
div.cshp .step{padding:16px}
div.cshp .plan{padding:22px}
div.cshp .cta{padding:32px 20px}
div.cshp .cost-body ul{columns:1}
}

/* ============================================================
   Batch 16 — service card motion + palette depth
   Page 532 (.cshp) only. Added 2026-10-02 (task #19).

   COLOUR SOURCE. Every colour below is either a variable already
   defined by this page's own .cshp palette block —
     --red    #cf3e4e   (accent: eyebrows, badges, solid buttons)
     --navy   #102a43   (primary dark)
     --navy2  #183b56
     --line   #dde5ed
     --soft   #f5f8fb
     #ffffff             (card and section surfaces)
   — or a color-mix of one of those with #ffffff. No new hue family
   is introduced. The shadow value reuses the exact
   rgba(16,42,67,…) form already used by this page's .plan cards,
   i.e. --navy at low alpha.

   MOTION. Nothing here animates a layout property. Only transform,
   opacity and paint-only properties (background, border-colour,
   box-shadow, colour) transition. The accent rule is an absolutely
   positioned pseudo-element, so it occupies no space. Therefore:
   no card can move a neighbour, page height cannot change, and the
   CTA row alignment cannot reopen.

   ROLLBACK: restore this field from custom-css-before-batch16.txt.
   ============================================================ */

/* 1 — Left accent rule at rest. Painted by an absolutely positioned
       pseudo-element so it takes no space at all: the card keeps its exact
       padding box and no line of text can re-wrap. */
div.cshp .service{position:relative;transition:transform .18s ease,border-color .18s ease,background-color .18s ease,box-shadow .18s ease}
div.cshp .service::before{content:"";position:absolute;left:0;top:14px;bottom:14px;width:3px;border-radius:0 3px 3px 0;background:color-mix(in srgb,var(--red) 30%,#fff);transition:background-color .18s ease,transform .18s ease}

/* 2 — Hover, and keyboard parity. A service card is an <article> and cannot
       receive focus itself, so :has(:focus-visible) is what lifts the card
       when a keyboard user focuses the button inside it. */
div.cshp .service:hover,
div.cshp .service:has(:focus-visible){transform:translateY(-3px);border-color:color-mix(in srgb,var(--red) 40%,#fff);box-shadow:0 14px 30px rgba(16,42,67,.10)}
div.cshp .service:hover::before,
div.cshp .service:has(:focus-visible)::before{background:var(--red);transform:scaleY(1.06)}

/* 3 — The number badge fills with the accent. */
div.cshp .num{transition:background-color .18s ease,color .18s ease,transform .18s ease}
div.cshp .service:hover .num,
div.cshp .service:has(:focus-visible) .num{background:var(--red);color:#fff;transform:scale(1.06)}

/* 4 — The outline CTA becomes this page's solid CTA: the same red fill and
       white label already used by the packages card and the closing call to
       action, so the page gains no second button language. */
div.cshp .service .btn{transition:background-color .18s ease,border-color .18s ease,color .18s ease,transform .18s ease}
div.cshp .service .btn:hover,
div.cshp .service .btn:focus-visible,
div.cshp .service:hover .btn{background:var(--red);border-color:var(--red);color:#fff!important;transform:translateY(-1px)}

/* 5 — A focus ring in the theme accent, for anyone tabbing through. */
div.cshp a:focus-visible{outline:2px solid var(--red);outline-offset:2px}

/* 6 — Motion off on request. The state changes still happen; the movement
       and the transitions do not. */
@media(prefers-reduced-motion:reduce){
div.cshp .service,
div.cshp .service::before,
div.cshp .num,
div.cshp .service .btn{transition:none}
div.cshp .service:hover,
div.cshp .service:has(:focus-visible),
div.cshp .service:hover::before,
div.cshp .service:has(:focus-visible)::before,
div.cshp .num,
div.cshp .service:hover .num,
div.cshp .service:has(:focus-visible) .num,
div.cshp .service .btn:hover,
div.cshp .service .btn:focus-visible,
div.cshp .service:hover .btn{transform:none}
}

/* ============================================================
   Batch 19 — extending the card language to the packages, process
   and additional-costs blocks. Page 532 (.cshp) only.
   Added 2026-10-02 (task #22).

   COLOUR SOURCE — unchanged from Batch 16. No new palette entry:
     var(--red)  #cf3e4e · var(--navy) #102a43 · var(--soft) #f5f8fb
     #ffffff, and color-mix() of those with each other.
     Shadows reuse the rgba(16,42,67,…) / rgba(207,62,78,…) forms
     this page already uses, i.e. --navy and --red at low alpha.

   THE INTERACTIVITY DECISION, applied consistently below:
     INTERACTIVE blocks — a card that CONTAINS a button — lift and
     change colour. Movement and elevation are the cues that read as
     "this does something", and every one of those blocks really does
     have a button inside it.
     NON-INTERACTIVE blocks — no button inside — change colour only.
     No transform, no shadow. A block that visibly lifts but does
     nothing when clicked is a broken promise; a block whose colours
     deepen reads as "you are looking here", which is all it can
     honestly mean.
     The process tiles and the additional-costs card are therefore
     colour-only. The package cards are not: all three carry a button.

   MOTION — transform, opacity and paint-only properties only
   (background, border-colour, box-shadow, colour). No layout
   property is animated, so height and the 0/0/0/0 service-CTA row
   alignment cannot move.

   ROLLBACK: restore this field from custom-css-before-batch19.txt.
   ============================================================ */

/* 1 — Resting accent rule, same geometry as the service cards, for the blocks
       that did not have it. Absolutely positioned, so it occupies no space and
       cannot re-wrap any text. The promoted package card is deliberately
       excluded: it already carries a 2px red border as its accent, and a second
       red bar beside it would thicken the edge rather than enrich it. */
div.cshp .plan,
div.cshp .step,
div.cshp .cost-card{position:relative}
div.cshp .plan:not(.primary)::before,
div.cshp .step::before,
div.cshp .cost-card::before{content:"";position:absolute;left:0;top:16px;bottom:16px;width:3px;border-radius:0 3px 3px 0;background:color-mix(in srgb,var(--red) 30%,#fff);transition:background-color .18s ease}

/* 2 — Package cards are interactive — each carries a button — so they get the
       same lift as the service cards. :not(.primary) keeps the promoted card's
       red border untouched, because that border is what marks it out. */
div.cshp .plan{transition:transform .18s ease,box-shadow .18s ease,border-color .18s ease}
div.cshp .plan:not(.primary):hover,
div.cshp .plan:not(.primary):has(:focus-visible){transform:translateY(-3px);border-color:color-mix(in srgb,var(--red) 40%,#fff);box-shadow:0 18px 40px rgba(16,42,67,.13)}
div.cshp .plan:not(.primary):hover::before,
div.cshp .plan:not(.primary):has(:focus-visible)::before{background:var(--red)}

/* 3 — The promoted card lifts on its own terms: the red border and the red
       shadow stay red, and the red shadow deepens. A uniform treatment would
       flatten the hierarchy that the border and the badge exist to create. */
div.cshp .plan.primary:hover,
div.cshp .plan.primary:has(:focus-visible){transform:translateY(-3px);box-shadow:0 22px 46px rgba(207,62,78,.20)}

/* 4 — Buttons in the packages row. The outline ones become this page's solid
       button, exactly as the service CTAs do. The already-solid one keeps its
       hue and gains elevation instead, so it stays recognisably the same
       button rather than turning into a different one. */
div.cshp .plan .btn{transition:background-color .18s ease,border-color .18s ease,color .18s ease,transform .18s ease,box-shadow .18s ease}
div.cshp .plan .btn-outline:hover,
div.cshp .plan .btn-outline:focus-visible,
div.cshp .plan:hover .btn-outline,
div.cshp .plan:has(:focus-visible) .btn-outline{background:var(--red);border-color:var(--red);color:#fff!important;transform:translateY(-1px)}
div.cshp .plan .btn-solid:hover,
div.cshp .plan .btn-solid:focus-visible,
div.cshp .plan:hover .btn-solid,
div.cshp .plan:has(:focus-visible) .btn-solid{transform:translateY(-1px);box-shadow:0 8px 18px rgba(207,62,78,.28)}

/* 5 — Process tiles: informational, no button inside. Colour only — the accent
       rule goes full strength and the tile surface warms. No transform and no
       shadow, for the reason set out at the top of this block. */
div.cshp .step{transition:background-color .18s ease}
div.cshp .step:hover{background:color-mix(in srgb,var(--red) 7%,var(--soft))}
div.cshp .step:hover::before{background:var(--red)}

/* 6 — The additional-costs card: likewise informational, no button. Same
       restrained treatment, same reason. */
div.cshp .cost-card{transition:background-color .18s ease}
div.cshp .cost-card:hover{background:color-mix(in srgb,var(--red) 5%,#fff)}
div.cshp .cost-card:hover::before{background:var(--red)}

/* 7 — The closing panel's button, so the button language is uniform page-wide. */
div.cshp .cta .btn{transition:transform .18s ease,box-shadow .18s ease}
div.cshp .cta .btn:hover,
div.cshp .cta .btn:focus-visible{transform:translateY(-1px);box-shadow:0 10px 24px rgba(207,62,78,.30)}

/* 8 — Motion off on request. The state changes still happen; the movement and
       the transitions do not. */
@media(prefers-reduced-motion:reduce){
div.cshp .plan,div.cshp .plan::before,div.cshp .step,div.cshp .step::before,
div.cshp .cost-card,div.cshp .cost-card::before,div.cshp .plan .btn,div.cshp .cta .btn{transition:none}
div.cshp .plan:not(.primary):hover,div.cshp .plan:not(.primary):has(:focus-visible),
div.cshp .plan.primary:hover,div.cshp .plan.primary:has(:focus-visible),
div.cshp .plan .btn-outline:hover,div.cshp .plan .btn-outline:focus-visible,
div.cshp .plan:hover .btn-outline,div.cshp .plan:has(:focus-visible) .btn-outline,
div.cshp .plan .btn-solid:hover,div.cshp .plan .btn-solid:focus-visible,
div.cshp .plan:hover .btn-solid,div.cshp .plan:has(:focus-visible) .btn-solid,
div.cshp .cta .btn:hover,div.cshp .cta .btn:focus-visible{transform:none}
}

/* ============================================================
   Batch 19b — correction. Page 532 (.cshp) only. 2026-10-02 (task #22).

   Batch 16 gave EVERY .service card the hover lift. The four cards in
   the "Why work with us" strip are .service cards — they simply are not
   in the interactive set: they contain no button.

   Under the rule stated at the top of Batch 19 — a block that visibly
   lifts but does nothing when clicked is a broken promise — those four
   must not lift. They keep the colour response (the accent rule going to
   full strength, and the number badge filling with the accent) and lose
   the transform and the shadow, so they now behave exactly like the six
   process tiles and the additional-costs card.

   This makes the interactivity rule true across the whole page rather
   than only on the blocks it was written for.

   Rollback: restore the field from custom-css-before-batch19b.txt.
   ============================================================ */
div.cshp .section-head:not([id]) + .services > .service:hover,
div.cshp .section-head:not([id]) + .services > .service:has(:focus-visible){transform:none;box-shadow:none}

/* ============================================================
   Batch 20 — package pricing labels. Page 532 (.cshp) only.
   Added 2026-10-03 (task #23).

   Each package card gains a short pricing label in the header slot
   that was empty beside its eyebrow. Wording is a literal
   contiguous substring of THAT SAME CARD'S own fee line — no new
   wording, no invented price points, no percentages, no figures.

   SEPARATION FROM THE RECOMMENDATION BADGE.
   The two carry different classes of message, so they share
   neither fill nor position:
     .badge     — recommendation: accent-FILLED, white text,
                  curved pill, positioned OUTSIDE the card's top
                  edge at right:20px, hanging over the border.
     .plan-tag  — pricing class: NEUTRAL outline chip, dark text,
                  positioned INSIDE the header on the content grid
                  at right:26px, level with the eyebrow.
   Because the badge is the only accent-filled element in the row,
   filling the two empty slots does not dilute it.

   The label is absolutely positioned, so it is out of flow: it
   cannot change any card's height, cannot reflow, and cannot move
   a neighbouring card.

   ROLLBACK: restore the field from custom-css-before-batch20.txt
   and the page content from 532-content-before-batch20.txt.
   ============================================================ */
div.cshp .plan-tag{position:absolute;top:26px;right:26px;display:inline-block;background:var(--soft);border:1px solid var(--line);border-radius:20px;padding:3px 9px;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;color:var(--navy);line-height:1.3;white-space:nowrap;transition:background-color .18s ease,border-color .18s ease,color .18s ease}
div.cshp .plan:hover .plan-tag,
div.cshp .plan:has(:focus-visible) .plan-tag{border-color:color-mix(in srgb,var(--red) 40%,#fff);color:var(--red)}
div.cshp .plan.primary .plan-tag{border-color:color-mix(in srgb,var(--red) 30%,#fff)}
@media(prefers-reduced-motion:reduce){div.cshp .plan-tag{transition:none}}

/* ============================================================
   Batch 20b — bottom-align the three package buttons.
   Page 532 (.cshp) only. Added 2026-10-03 (task #23).

   CAUSE — diagnosed from the live DOM, not guessed:
   wpautop wraps each bare <a class="btn"> in a <p>. So the element
   that is actually a flex item inside .plan is that wrapper <p>,
   not the <a>. The page stylesheet declares margin-top:auto on
   .cshp .btn, but that lands on the <a>, which is not a flex item,
   where `auto` computes to 0. Nothing therefore pushes the button
   down: the grid stretches all three cards to 496px and the slack
   collects below the button, so each button sits wherever that
   card's own content happens to end — 377.9 / 367.9 / 418.1.

   FIX — put the auto margin on the element that IS the flex item.

   Scoped to .plan only. The service-coverage row is already at a
   0/0/0/0 CTA spread and its buttons carry an inline margin-top;
   it is deliberately not touched.

   No height change is possible: each card's height comes from the
   grid row, not from its own content, so moving a button down
   inside a card moves nothing else.

   ROLLBACK: restore the field from custom-css-before-batch20b.txt.
   ============================================================ */
div.cshp .plan > p:last-child{margin-top:auto}

/* ============================================================
   Batch 27 — product surfaces styled in the site's card language.
   Added 2026-10-04 (task #30). Applies only to WooCommerce
   surfaces (`.woocommerce` exists only there) and to the
   industry-page product section, which the catalogue mu-plugin
   emits with the same wrapper class.

   PALETTE — no new hue family. Every value below is already used
   on this site:
     #102a43  navy — the site's h2/h3 colour AND the services card
              heading colour, so it is shared by both systems
     #cf3e4e  accent red — the services card language (eyebrow,
              badge, solid button, left accent rule)
     #dde5ed  card border on the services cards
     #f5f8fb  tile surface on the services cards
     #60758b  muted body text on the services cards
     #243b53  the site's body text colour
     #ffffff  card surface
   Shadows reuse the rgba(16,42,67,…) / rgba(207,62,78,…) forms the
   services page already uses — i.e. navy and accent red at low alpha.

   MOTION — matches the services page: transform, opacity and
   paint-only properties only. Nothing here animates a layout
   property, so no card can move a neighbour.
   ============================================================ */

:root{
  --cshp74-navy:#102a43;
  --cshp74-red:#cf3e4e;
  --cshp74-line:#dde5ed;
  --cshp74-soft:#f5f8fb;
  --cshp74-muted:#60758b;
  --cshp74-ink:#243b53;
}

/* ---------- 1. The listing grid ---------- */
.woocommerce ul.products{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin:0 0 52px;padding:0;list-style:none}
.woocommerce ul.products::before,.woocommerce ul.products::after{display:none;content:none}
.woocommerce ul.products.columns-3{grid-template-columns:repeat(3,1fr)}

/* ---------- 2. The product card ---------- */
.woocommerce ul.products li.product{position:relative;display:flex;flex-direction:column;width:auto!important;max-width:none!important;float:none!important;clear:none!important;justify-self:stretch;margin:0!important;padding:18px;background:#fff;border:1px solid var(--cshp74-line);border-radius:12px;box-shadow:none;transition:transform .18s ease,box-shadow .18s ease,border-color .18s ease}
.woocommerce ul.products li.product::before{content:"";position:absolute;left:0;top:14px;bottom:14px;width:3px;border-radius:0 3px 3px 0;background:color-mix(in srgb,var(--cshp74-red) 30%,#fff);transition:background-color .18s ease}
.woocommerce ul.products li.product:hover,
.woocommerce ul.products li.product:has(:focus-visible){transform:translateY(-3px);border-color:color-mix(in srgb,var(--cshp74-red) 40%,#fff);box-shadow:0 14px 30px rgba(16,42,67,.1)}
.woocommerce ul.products li.product:hover::before,
.woocommerce ul.products li.product:has(:focus-visible)::before{background:var(--cshp74-red)}

/* ---------- 3. Image, title, price ---------- */
.woocommerce ul.products li.product a{text-decoration:none}
.woocommerce ul.products li.product a img{display:block;width:100%;height:180px;object-fit:cover;margin:0 0 14px;border-radius:9px}
.woocommerce ul.products li.product .woocommerce-loop-product__title{margin:0;padding:0;font-size:17px;line-height:1.3;font-weight:700;color:var(--cshp74-navy)}
.woocommerce ul.products li.product .price{margin:8px 0 0;font-size:16px;font-weight:700;color:var(--cshp74-navy)}
.woocommerce ul.products li.product .price del{color:var(--cshp74-muted);font-weight:400}
.woocommerce ul.products li.product .price ins{text-decoration:none}
.woocommerce ul.products li.product .price .woocommerce-Price-currencySymbol{font-weight:700}

/* ---------- 4. The sample action — same weight as "Request this service" ---------- */
.woocommerce .csh-sample-button,
.woocommerce ul.products li.product .button{display:inline-flex;align-items:center;justify-content:center;min-height:44px;margin-top:auto;padding:10px 18px;border:1.5px solid var(--cshp74-navy)!important;border-radius:8px;background:transparent!important;color:var(--cshp74-navy)!important;font-size:14px;font-weight:700;line-height:1;text-decoration:none;box-shadow:none;transition:background-color .18s ease,border-color .18s ease,color .18s ease,transform .18s ease}
.woocommerce ul.products li.product .price + .button{margin-top:14px}
.woocommerce .csh-sample-button:hover,
.woocommerce .csh-sample-button:focus-visible,
.woocommerce ul.products li.product:hover .button,
.woocommerce ul.products li.product:has(:focus-visible) .button{background:var(--cshp74-red)!important;border-color:var(--cshp74-red)!important;color:#fff!important;transform:translateY(-1px)}

/* ---------- 5. Single product ---------- */
.woocommerce div.product{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:44px;margin:0 0 52px}
.woocommerce div.product .woocommerce-product-gallery{float:none!important;width:auto!important;margin:0}
.woocommerce div.product .woocommerce-product-gallery img{border-radius:12px;border:1px solid var(--cshp74-line)}
.woocommerce div.product .summary{float:none!important;width:auto!important;margin:0}
.woocommerce div.product .product_title{font-size:30px;line-height:1.15;font-weight:700;margin:0 0 12px;color:var(--cshp74-navy)}
.woocommerce div.product p.price{font-size:24px;font-weight:700;margin:0 0 16px;color:var(--cshp74-navy)}
.woocommerce div.product p.price del{color:var(--cshp74-muted);font-weight:400;font-size:18px}
.woocommerce div.product .woocommerce-product-details__short-description{font-size:16px;line-height:1.65;color:var(--cshp74-ink)}
.woocommerce div.product .csh-sample-wrap{margin:20px 0 0}
.woocommerce div.product .csh-sample-wrap .csh-sample-button{width:100%}
.woocommerce div.product .product_meta{margin:18px 0 0;padding-top:14px;border-top:1px solid var(--cshp74-line);font-size:13px;color:var(--cshp74-muted)}
.woocommerce div.product .product_meta a{color:var(--cshp74-navy);text-decoration:none}
.woocommerce div.product .stock{color:var(--cshp74-red);font-weight:700;font-size:14px}

/* ---------- 6. Tabs, upsells, related ---------- */
.woocommerce div.product .woocommerce-tabs{margin:0 0 52px;clear:both}
.woocommerce div.product .woocommerce-tabs ul.tabs{margin:0 0 20px;padding:0;border-bottom:1px solid var(--cshp74-line)}
.woocommerce div.product .woocommerce-tabs ul.tabs::before{display:none;content:none}
.woocommerce div.product .woocommerce-tabs ul.tabs li{margin:0 24px 0 0;padding:0;background:transparent;border:0;border-radius:0}
.woocommerce div.product .woocommerce-tabs ul.tabs li::before,
.woocommerce div.product .woocommerce-tabs ul.tabs li::after{display:none;content:none}
.woocommerce div.product .woocommerce-tabs ul.tabs li a{padding:10px 0;font-size:14px;font-weight:700;color:var(--cshp74-muted);text-decoration:none}
.woocommerce div.product .woocommerce-tabs ul.tabs li.active a{color:var(--cshp74-navy);box-shadow:inset 0 -2px 0 var(--cshp74-red)}
.woocommerce section.related.products,
.woocommerce section.upsells.products{margin:0 0 52px;clear:both}
.woocommerce section.related.products > h2,
.woocommerce section.upsells.products > h2{margin:0 0 18px;font-size:24px;color:var(--cshp74-navy)}

/* ---------- 7. Empty state (markup emitted by the catalogue mu-plugin) ---------- */
.woocommerce.csh-shop-empty{margin:0 0 52px;padding:40px 26px;background:var(--cshp74-soft);border:1px solid var(--cshp74-line);border-radius:12px;text-align:left}
.woocommerce.csh-shop-empty h2{margin:0 0 10px;font-size:24px;color:var(--cshp74-navy)}
.woocommerce.csh-shop-empty p{margin:0 0 12px;font-size:16px;line-height:1.65;color:var(--cshp74-ink);max-width:720px}
.woocommerce.csh-shop-empty p:last-child{margin-bottom:0}

/* ---------- 8. The industry-page product section ---------- */
.woocommerce.csh-industry-products{margin:48px 0 0;padding:36px 0 0;border-top:1px solid var(--cshp74-line)}
.woocommerce.csh-industry-products > h2{margin:0 0 8px;font-size:26px;font-weight:700;color:var(--cshp74-navy)}
.woocommerce.csh-industry-products .csh-ip-intro{margin:0 0 22px;font-size:15px;color:var(--cshp74-muted);max-width:720px}
.woocommerce.csh-industry-products ul.products{grid-template-columns:repeat(3,1fr);margin-bottom:22px}
.woocommerce.csh-industry-products .csh-ip-more{margin:0}
.woocommerce.csh-industry-products .csh-ip-more .csh-sample-button{width:auto}

/* ---------- 9. Motion off on request ---------- */
@media(prefers-reduced-motion:reduce){
.woocommerce ul.products li.product,
.woocommerce ul.products li.product::before,
.woocommerce .csh-sample-button,
.woocommerce ul.products li.product .button{transition:none}
.woocommerce ul.products li.product:hover,
.woocommerce ul.products li.product:has(:focus-visible),
.woocommerce .csh-sample-button:hover,
.woocommerce .csh-sample-button:focus-visible,
.woocommerce ul.products li.product:hover .button,
.woocommerce ul.products li.product:has(:focus-visible) .button{transform:none}
}

/* ---------- 10. Responsive ---------- */
@media(max-width:1100px){
.woocommerce ul.products{grid-template-columns:repeat(3,1fr)}
.woocommerce.csh-industry-products ul.products{grid-template-columns:repeat(3,1fr)}
}
@media(max-width:900px){
.woocommerce ul.products,
.woocommerce.csh-industry-products ul.products{grid-template-columns:repeat(2,1fr);gap:14px}
.woocommerce div.product{grid-template-columns:1fr;gap:28px}
}
@media(max-width:600px){
.woocommerce ul.products,
.woocommerce.csh-industry-products ul.products{grid-template-columns:1fr}
.woocommerce ul.products li.product{padding:16px}
.woocommerce ul.products li.product a img{height:200px}
.woocommerce.csh-shop-empty{padding:28px 18px}
.woocommerce.csh-industry-products{padding-top:28px;margin-top:36px}
}

/* ---------- 11. Focus ring, matching the services page ---------- */
.woocommerce a:focus-visible{outline:2px solid var(--cshp74-red);outline-offset:2px}

/* ============================================================
   Batch 27b — the WooCommerce chrome around the products.
   Page 532's field, but these rules touch only WooCommerce
   surfaces (`.woocommerce` exists only there).
   Added 2026-10-04 (task #30).

   WHY THIS EXISTS. With no theme WooCommerce support, everything
   WooCommerce prints around the loop arrives unstyled: the result
   count, the sort dropdown, pagination, the sale badge and the
   notice bars all render as browser defaults. The card and the
   button were fixed in Batch 27; this is the rest of what a
   visitor sees on a product page.

   PALETTE — the same existing values as Batch 27. No new hue.
   MOTION — none here; these are static controls.
   ROLLBACK — restore the field from custom-css-before-batch27c.txt.
   ============================================================ */

/* Result count + sort dropdown */
.woocommerce .woocommerce-result-count{margin:0 0 20px;font-size:14px;color:var(--cshp74-muted)}
.woocommerce .woocommerce-ordering{float:none;margin:0 0 20px}
.woocommerce .woocommerce-ordering select{min-height:42px;padding:9px 14px;border:1.5px solid var(--cshp74-line);border-radius:8px;background:#fff;color:var(--cshp74-navy);font-size:14px;font-weight:600}
.woocommerce .woocommerce-ordering select:focus-visible{outline:2px solid var(--cshp74-red);outline-offset:2px}

/* Pagination */
.woocommerce nav.woocommerce-pagination ul{display:flex;gap:6px;justify-content:center;margin:0;padding:0;border:0}
.woocommerce nav.woocommerce-pagination ul li{margin:0;border:0;overflow:visible}
.woocommerce nav.woocommerce-pagination ul li a,
.woocommerce nav.woocommerce-pagination ul li span{display:inline-flex;align-items:center;justify-content:center;min-width:40px;min-height:40px;padding:0 10px;border:1px solid var(--cshp74-line);border-radius:8px;color:var(--cshp74-navy);font-size:14px;font-weight:700;text-decoration:none}
.woocommerce nav.woocommerce-pagination ul li a:hover,
.woocommerce nav.woocommerce-pagination ul li a:focus-visible{border-color:var(--cshp74-navy)}
.woocommerce nav.woocommerce-pagination ul li span.current{background:var(--cshp74-navy);border-color:var(--cshp74-navy);color:#fff}

/* Sale badge — the page's accent, same treatment as the package badge */
.woocommerce span.onsale{min-height:0;min-width:0;padding:5px 12px;border-radius:20px;background:var(--cshp74-red);color:#fff;font-size:11px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;line-height:1.5}

/* Notice bars */
.woocommerce .woocommerce-message,
.woocommerce .woocommerce-info,
.woocommerce .woocommerce-error{margin:0 0 26px;padding:14px 18px;border:0;border-left:3px solid var(--cshp74-red);border-radius:8px;background:var(--cshp74-soft);color:var(--cshp74-ink);font-size:15px}
.woocommerce .woocommerce-message::before,
.woocommerce .woocommerce-info::before,
.woocommerce .woocommerce-error::before{color:var(--cshp74-red)}

/* Quantity input and any remaining default WC form control */
.woocommerce .quantity input.qty{min-height:44px;padding:8px 12px;border:1.5px solid var(--cshp74-line);border-radius:8px;color:var(--cshp74-navy);font-size:15px;font-weight:600}

/* Product meta and category links */
.woocommerce div.product .product_meta a:hover{color:var(--cshp74-red)}
.woocommerce .posted_in a,
.woocommerce .tagged_as a{color:var(--cshp74-navy)}

/* The skip link and screen-reader text WooCommerce prints, left alone but
   kept invisible as intended rather than accidentally styled */
.woocommerce .screen-reader-text{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(1px,1px,1px,1px);white-space:nowrap}

@media(max-width:600px){
.woocommerce .woocommerce-result-count{margin-bottom:12px}
.woocommerce .woocommerce-ordering{margin-bottom:16px}
.woocommerce nav.woocommerce-pagination ul li a,
.woocommerce nav.woocommerce-pagination ul li span{min-width:36px;min-height:36px}
}

/* ============================================================
   Batch 38 — the de-identified manufacturer card.
   Added 2026-10-05 (task #39). Appended to cnsourcehub-styles.css.

   WHAT THIS IS. One card = one factory we have physically audited,
   described completely and NOT named. The card publishes the
   capability and withholds the identity.

   CLASS PREFIX. Every rule is `.cshm-*`. The theme's own `.card`,
   `.card-title` and `.card-image` classes are used by the industry
   cards on the same page, so restyling those would break them —
   this card uses its own namespace and touches nothing of theirs.

   PALETTE. The same existing values as the service and product
   cards. No new hue family:
     --cshp74-navy #102a43 · --cshp74-red #cf3e4e
     --cshp74-line #dde5ed · --cshp74-soft #f5f8fb
     --cshp74-muted #60758b · --cshp74-ink #243b53 · #fff

   MOTION. transform, opacity and paint-only properties only, on
   hover and :focus-visible equally. Nothing reflows.

   OUTCOME STATES. Three, distinguished by fill + border + mark,
   and none reads as an error:
     Verified             navy fill, white label — authoritative
     Verified with conds  white fill, navy border, navy label
     Not recommended      soft fill, muted border, muted label
   The "Not recommended" state is a CREDIBILITY ASSET: if the audit
   cannot say no, the "Verified" badge means nothing. It is styled
   as a classification, never as a warning, and it deliberately
   carries no quote CTA — a card that says "not recommended" must
   not also say "request a quote for this". Its single action is a
   link to the verified alternatives instead.
   ============================================================ */

/* ---------- The list ---------- */
.cshm-list{display:grid;grid-template-columns:1fr;gap:22px;margin:0 0 52px;padding:0;list-style:none}

/* ---------- The card ---------- */
.cshm-card{position:relative;display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:26px;padding:22px;background:#fff;border:1px solid var(--cshp74-line);border-radius:12px;box-shadow:0 12px 32px rgba(16,42,67,.06);transition:transform .18s ease,box-shadow .18s ease,border-color .18s ease}
.cshm-card::before{content:"";position:absolute;left:0;top:18px;bottom:18px;width:3px;border-radius:0 3px 3px 0;background:color-mix(in srgb,var(--cshp74-red) 30%,#fff);transition:background-color .18s ease}
.cshm-card:hover,
.cshm-card:has(:focus-visible){transform:translateY(-3px);border-color:color-mix(in srgb,var(--cshp74-red) 40%,#fff);box-shadow:0 18px 40px rgba(16,42,67,.12)}
.cshm-card:hover::before,
.cshm-card:has(:focus-visible)::before{background:var(--cshp74-red)}

/* ---------- Media column: one feature frame plus a thumbnail strip ---------- */
.cshm-media{display:flex;flex-direction:column;gap:10px;min-width:0}
.cshm-frame{position:relative;display:flex;align-items:center;justify-content:center;flex:1 1 auto;min-height:220px;aspect-ratio:16/10;border:1px solid var(--cshp74-line);border-radius:9px;background:var(--cshp74-soft);overflow:hidden}
.cshm-frame img{display:block;width:100%;height:100%;object-fit:cover}
.cshm-slot{margin:0;padding:0 14px;font-size:12px;font-weight:700;line-height:1.5;letter-spacing:.02em;color:var(--cshp74-muted);text-align:center}
.cshm-thumbs{display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin:0;padding:0;list-style:none}
.cshm-thumb{position:relative;display:flex;align-items:center;justify-content:center;aspect-ratio:1/1;border:1px solid var(--cshp74-line);border-radius:7px;background:var(--cshp74-soft);overflow:hidden}
.cshm-thumb img{display:block;width:100%;height:100%;object-fit:cover}
.cshm-thumb--count{font-size:12px;font-weight:800;color:var(--cshp74-navy)}
/* Thumbnail-linked video: a photo, not an embed. No autoplay, no page weight.
   The play mark is drawn in CSS so no icon font or image is loaded. */
.cshm-thumb--video::after{content:"";position:absolute;left:50%;top:50%;width:0;height:0;margin:-7px 0 0 -4px;border-left:10px solid #fff;border-top:7px solid transparent;border-bottom:7px solid transparent;filter:drop-shadow(0 1px 3px rgba(16,42,67,.55))}

/* ---------- Body ---------- */
.cshm-body{display:flex;flex-direction:column;min-width:0}
.cshm-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}
.cshm-ref{margin:0;font-size:12px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--cshp74-red)}

/* ---------- Outcome badge: fill + border + mark, three ways ---------- */
.cshm-outcome{display:inline-flex;align-items:center;gap:7px;padding:6px 12px;border:1px solid transparent;border-radius:20px;font-size:11px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;line-height:1.5;white-space:nowrap}
.cshm-outcome::before{content:"";flex:0 0 auto;width:6px;height:6px;border-radius:50%;background:currentColor}
.cshm-outcome--verified{background:var(--cshp74-navy);border-color:var(--cshp74-navy);color:#fff}
.cshm-outcome--conditions{background:#fff;border-color:var(--cshp74-navy);color:var(--cshp74-navy)}
.cshm-outcome--not{background:var(--cshp74-soft);border-color:var(--cshp74-line);color:var(--cshp74-muted)}

.cshm-title{margin:10px 0 0;font-size:21px;line-height:1.25;font-weight:700;color:var(--cshp74-navy)}
.cshm-loc{margin:6px 0 0;font-size:14px;line-height:1.5;color:var(--cshp74-muted)}

/* ---------- Facts and audit, both as definition lists ---------- */
.cshm-facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px 24px;margin:18px 0 0;padding:16px 0 0;border-top:1px solid var(--cshp74-line)}
.cshm-fact{min-width:0}
.cshm-facts dt,.cshm-audit dt{margin:0;font-size:11px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--cshp74-muted)}
.cshm-facts dd,.cshm-audit dd{margin:4px 0 0;font-size:14px;line-height:1.55;color:var(--cshp74-ink)}

.cshm-audit{margin:18px 0 0;padding:16px 18px;border-left:3px solid var(--cshp74-navy);border-radius:9px;background:var(--cshp74-soft)}
.cshm-audit-h{margin:0 0 12px;font-size:11px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--cshp74-navy)}
.cshm-audit dl{margin:0}
.cshm-audit dd+dt{margin-top:10px}

/* ---------- The gate: an exclusivity statement, not a disclaimer ---------- */
.cshm-gate{margin:18px 0 0;padding:16px 18px;border:1px solid color-mix(in srgb,var(--cshp74-navy) 22%,#fff);border-radius:9px;background:color-mix(in srgb,var(--cshp74-navy) 4%,#fff)}
.cshm-gate-h{margin:0 0 6px;font-size:11px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--cshp74-navy)}
.cshm-gate p{margin:0;font-size:14px;line-height:1.6;color:var(--cshp74-ink)}

/* ---------- The note carries the reason for a non-verified outcome ---------- */
.cshm-note{margin:14px 0 0;padding-left:12px;border-left:2px solid var(--cshp74-line);font-size:13px;line-height:1.6;color:var(--cshp74-muted)}

/* ---------- One action, pushed to the foot of the card.
       The auto margin sits on the WRAPPER, not on the anchor: wpautop wraps a
       bare <a> in a <p>, so an auto margin on the anchor would be inert. ---------- */
.cshm-foot{display:flex;align-items:center;justify-content:space-between;gap:16px;margin:auto 0 0;padding:18px 0 0}
.cshm-cta{display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding:10px 18px;border:1.5px solid var(--cshp74-navy);border-radius:8px;background:transparent;color:var(--cshp74-navy)!important;font-size:14px;font-weight:700;line-height:1;text-decoration:none;transition:background-color .18s ease,border-color .18s ease,color .18s ease,transform .18s ease}
.cshm-cta:hover,
.cshm-cta:focus-visible{background:var(--cshp74-red);border-color:var(--cshp74-red);color:#fff!important;transform:translateY(-1px)}
.cshm-cta--alt{border-color:var(--cshp74-line);color:var(--cshp74-navy)!important}
.cshm-cert{flex:0 0 auto;font-size:12px;font-weight:700;letter-spacing:.02em;color:var(--cshp74-muted)}

.cshm-card a:focus-visible{outline:2px solid var(--cshp74-red);outline-offset:2px}

/* ---------- Responsive: the card must not collapse at 390px ---------- */
@media(max-width:900px){
.cshm-card{grid-template-columns:1fr;gap:18px}
.cshm-media{gap:8px}
}
@media(max-width:600px){
.cshm-card{padding:16px}
.cshm-card::before{top:14px;bottom:14px}
.cshm-head{flex-direction:column;gap:10px}
.cshm-outcome{align-self:flex-start}
.cshm-title{font-size:19px}
.cshm-facts{grid-template-columns:1fr;gap:12px}
.cshm-audit,.cshm-gate{padding:14px}
.cshm-foot{flex-direction:column;align-items:stretch;gap:12px}
.cshm-cta{width:100%}
.cshm-cert{text-align:center}
.cshm-thumbs{grid-template-columns:repeat(4,1fr)}
}

/* ---------- Motion off on request ---------- */
@media(prefers-reduced-motion:reduce){
.cshm-card,
.cshm-card::before,
.cshm-cta{transition:none}
.cshm-card:hover,
.cshm-card:has(:focus-visible),
.cshm-cta:hover,
.cshm-cta:focus-visible{transform:none}
}

/* ============================================================
   Batch 41 - the industry-hub row image box, made uniform.
   Added 2026-10-05 (task #41). Appended to cnsourcehub-styles.css.

   WHY. The nine .industry-card rows on /industries/ rendered at three
   different widths - 300 / 360 / 331 px - because each source ratio
   drove the used width. The owning rule is the THEME's own
   .industry-card-image { flex:0 0 300px; height:240px } in
   themes/haozhuti-vip-cnsh/assets/styles/main.css: it sets a height
   and a flex basis but no width, so a 3:2 source stretched the box to
   360px and a 500x363 source to 331px. This mu-plugin sheet loads
   AFTER the theme, so the override below wins without touching it.

   FIX. Pin the desktop box to a fixed 300x240 with object-fit:cover.
   DESKTOP ONLY - the theme already stacks and sizes the image at
   width:100%; height:200px inside its max-width:768px block, so this
   rule is scoped to min-width:769px and changes nothing at mobile
   width. No colour, no font, no other selector. One box, one size.
   ============================================================ */
@media (min-width: 769px){
.industry-card-image{width:300px;height:240px;flex:0 0 300px;min-width:0;max-width:300px;object-fit:cover}
}
/* ==== Batch 43 (2026-10-11) - Resources page (ID 28) card-foot alignment ==== */
/* SCOPE. Every rule is prefixed body.page-id-28 as requested. IMPORTANT: that prefix
   is INERT on this site - the theme never calls body_class(), so <body> ships with no
   classes (verified: document.body.className === " customize-support"; a fetch of this
   page returns the bare tag <body>). The site's own page CSS therefore also carries a
   working duplicate using body:has(.menu-item-40.current-menu-item). menu-item-40 is
   the Resources nav item and is .current-menu-item ONLY on /resources/ (blog/faq get
   current-menu-ancestor, not -item), so the :has() form matches this page and nothing
   else. Both forms are listed on each rule. */
body.page-id-28 .card,
body:has(.menu-item-40.current-menu-item) .card{display:flex;flex-direction:column}
body.page-id-28 .card-body,
body:has(.menu-item-40.current-menu-item) .card-body{display:flex;flex-direction:column;flex:1 1 auto}
body.page-id-28 .card-link,
body:has(.menu-item-40.current-menu-item) .card-link{margin-top:auto;align-self:flex-start;padding-top:14px;display:inline-flex;align-items:center;gap:6px}
@media(max-width:1024px){body.page-id-28 .cards-grid-3,body:has(.menu-item-40.current-menu-item) .cards-grid-3{grid-template-columns:1fr}}
/* ==== Batch 44 (2026-10-11) - Resources page (ID 28) hero frame swap ==== */
/* Replaces the BRANDED frame still painted on the /resources/ hero: attachment 520
   (.../2026/09/2026090400301302883.jpg, the CONTROLWAY / ZTL110-120 / WARNING frame that
   was removed from the industries Beauty row) with an unbranded 2026-10-05 frame:
   attachment 624 (.../2026/10/202610050738492de05-scaled.jpg). The OTHER hero frame
   (attachment 519 = .../2026/09/202609040030123d5ee.jpg) is left untouched, so the
   slider keeps two distinct frames.
   WHICH PSEUDO. On page 28 the live rules are the Customizer's
   body:has(.menu-item-40.current-menu-item) .hero-dark::before / ::after block. Verified
   in the live DOM: ::before carries 2026090400301302883.jpg (the CONTROLWAY frame) and
   ::after carries 202609040030123d5ee.jpg. So the new image is set on ::before. (The
   parallel body.page-id-28 ... forms are inert here - this theme never calls body_class().)
   SPECIFICITY. The leading html type selector lifts the target from (0,3,2) to (0,3,3),
   above the original rule, so the override wins regardless of stylesheet order. No theme
   file, template, plugin file or content is touched. Rollback: truncate this file to the
   first 45722 bytes. */
html body:has(.menu-item-40.current-menu-item) .hero-dark::before,
html body.page-id-28 .hero-dark::before{background-image:linear-gradient(rgba(8,29,58,.80),rgba(8,29,58,.80)),url('https://cnsourcehub.com/wp-content/uploads/2026/10/202610050738492de05-scaled.jpg')}
/* ==== Batch 44c (2026-10-11) - Blog page (ID 15) card-foot alignment ==== */
/* SCOPE. Mirrors the Batch 43 Resources block (page-id-28 / menu-item-40) exactly,
   re-scoped to the Blog nav item menu-item-41. Verified live on the DOM: on /blog/ the
   nav item carrying .current-menu-item is "page-item-15 current_page_item menu-item-41";
   on /resources/ it is menu-item-40. So body:has(.menu-item-41.current-menu-item) matches
   /blog/ and nothing else. The body.page-id-15 twin is INERT (this theme never calls
   body_class()) and is listed only for symmetry with the Batch 43 block. Bottom-anchors the
   Read More link so every card footer lines up in a row. NO excerpt clamp is re-applied.
   Rollback: truncate this file to the first 47247 bytes. */
body.page-id-15 .card,
body:has(.menu-item-41.current-menu-item) .card{display:flex;flex-direction:column}
body.page-id-15 .card-body,
body:has(.menu-item-41.current-menu-item) .card-body{display:flex;flex-direction:column;flex:1 1 auto}
body.page-id-15 .card-link,
body:has(.menu-item-41.current-menu-item) .card-link{margin-top:auto;align-self:flex-start;padding-top:14px;display:inline-flex;align-items:center;gap:6px}

/* ==== Batch 46 (2026-10-11) - Blog page (ID 15) <=1024px single-column collapse ==== */
/* DEFECT (recorded R64/R67): at <=1024px the theme stacks .cards-grid-3 to TWO columns,
   so on /blog/ the cards render ~158px wide at 390 (the same narrow-card defect flagged
   on Resources). Batch 43 fixed this for Resources (page-id-28 / menu-item-40) with the
   rule at line 753, but no equivalent rule was ever added for the Blog. This is that one
   missing rule.
   SCOPE: scoped to the Blog nav item only. Verified live on the DOM: on /blog/ the nav
   item carrying .current-menu-item is "page-item-15 current_page_item menu-item-41"; on
   /resources/ it is menu-item-40, so body:has(.menu-item-41.current-menu-item) matches
   /blog/ and nothing else. Every other rule in this file is untouched; the
   body.page-id-15 twin is inert (this theme never calls body_class()).
   BREAKPOINT: max-width:1024px, identical to the Resources fix.
   Rollback: truncate this file to the first 48431 bytes. */
@media(max-width:1024px){body.page-id-15 .cards-grid-3,body:has(.menu-item-41.current-menu-item) .cards-grid-3{grid-template-columns:1fr}}

/* ==========================================================================
   CN Source Hub — "Reference Library" design system
   Batch 61 (2026-10-11) · task #64 · for /blog/ and /resources/ ONLY
   --------------------------------------------------------------------------
   SCOPE. Every rule below is scoped under .cnsh-page, a wrapper class that
   exists only in the two templates this batch ships. Nothing else on the site
   can be reached, so no !important is needed anywhere.
   HOME. Appended to wp-content/mu-plugins/cnsourcehub-styles.css, which is
   enqueued site-wide and survives BOTH a theme update and a theme switch.
   ROLLBACK: truncate the file back to its pre-Batch-61 length (see changelog).
   ========================================================================== */

/* ------------------------------------------------------------------ 1. TOKENS
   Hierarchy comes from tonal steps of the EXISTING navy/red families plus the
   already-defined gold. No new hue family is introduced. --cshp74-* is left
   untouched (legacy, batch-numbered); new work uses the stable --cnsh- prefix. */
.cnsh-page{
  --cnsh-ink:#0A1A2F;        /* deepest: text + darkest band */
  --cnsh-navy:#102A43;       /* brand band (existing --navy) */
  --cnsh-navy-600:#1C3D5A;   /* tonal step: secondary dark surface, image scrim */
  --cnsh-slate:#486581;      /* dek / body-secondary text */
  --cnsh-mist:#7C97AC;       /* tertiary meta */
  --cnsh-line:#DFE7EE;       /* hairlines (existing --border) */
  --cnsh-paper:#F6F8FA;      /* page ground (existing --light-bg) */
  --cnsh-card:#FFFFFF;
  --cnsh-red:#C83E4D;        /* topic accent + primary action (existing) */
  --cnsh-red-700:#A82E3B;    /* tonal step: hover/pressed + focus ring */
  --cnsh-gold:#C9952E;       /* editorial rule + kicker (already defined, unused here) */

  --cnsh-sans:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  --cnsh-serif:Fraunces,"Iowan Old Style","Palatino Linotype",Georgia,serif;

  --cnsh-wrap:1280px;
  --cnsh-gutter:24px;
  --cnsh-radius:14px;
  --cnsh-ease:cubic-bezier(.2,.7,.3,1);

  background:var(--cnsh-paper);
  color:var(--cnsh-ink);
  font-family:var(--cnsh-sans);
  font-size:16px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
.cnsh-page *,.cnsh-page *::before,.cnsh-page *::after{box-sizing:border-box}
.cnsh-page img{max-width:100%;display:block}
.cnsh-page a{color:var(--cnsh-navy)}

/* ------------------------------------------------------- 2. LAYOUT PRIMITIVES */
.cnsh-wrap{width:100%;max-width:var(--cnsh-wrap);margin:0 auto;padding:0 var(--cnsh-gutter)}
.cnsh-band{padding:64px 0}
.cnsh-band--paper{background:var(--cnsh-paper)}
.cnsh-band--white{background:var(--cnsh-card)}
.cnsh-band--navy{background:var(--cnsh-navy);color:#fff}
.cnsh-band--tight{padding:48px 0}
.cnsh-band--roomy{padding:88px 0}
.cnsh-rule{border:0;border-top:1px solid var(--cnsh-line);margin:0}

/* Deliberate rhythm: section openings vary by weight instead of one uniform pad. */
.cnsh-head{max-width:62ch;margin-bottom:36px}
.cnsh-head--centre{margin-left:auto;margin-right:auto;text-align:center}
.cnsh-kicker{
  display:inline-flex;align-items:center;gap:10px;
  font-size:.75rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--cnsh-slate);margin:0 0 12px;
}
.cnsh-kicker::before{content:"";width:28px;height:2px;background:var(--cnsh-gold);flex:0 0 auto}
.cnsh-head--centre .cnsh-kicker{justify-content:center}
.cnsh-title{
  font-family:var(--cnsh-serif);font-weight:600;color:var(--cnsh-ink);
  font-size:clamp(1.75rem,1.2rem + 1.6vw,2.5rem);line-height:1.16;margin:0 0 12px;
  letter-spacing:-.01em;
}
.cnsh-sub{margin:0;color:var(--cnsh-slate);font-size:1.0625rem;line-height:1.65}

/* --------------------------------------------------------- 3. LINK & BUTTON
   The important action must never be distinguishable by colour alone. */
.cnsh-btn{
  display:inline-flex;align-items:center;gap:10px;
  padding:14px 24px;border-radius:999px;border:2px solid transparent;
  background:var(--cnsh-red);color:#fff;font-weight:600;font-size:1rem;line-height:1;
  text-decoration:none;cursor:pointer;
  transition:background .18s var(--cnsh-ease),transform .18s var(--cnsh-ease);
}
.cnsh-btn:hover{background:var(--cnsh-red-700)}
.cnsh-btn:focus-visible{outline:3px solid var(--cnsh-red-700);outline-offset:3px}
.cnsh-btn--ghost{background:transparent;color:#fff;border-color:rgba(255,255,255,.45)}
.cnsh-btn--ghost:hover{background:rgba(255,255,255,.12);border-color:#fff}
.cnsh-btn--light{background:#fff;color:var(--cnsh-navy)}
.cnsh-btn--light:hover{background:#EDF2F7}
.cnsh-btn__arrow{transition:transform .18s var(--cnsh-ease)}
.cnsh-btn:hover .cnsh-btn__arrow{transform:translateX(3px)}

/* Text links carry a persistent underline — colour alone is not a signal. */
.cnsh-link{
  color:var(--cnsh-navy);text-decoration:underline;
  text-decoration-thickness:1px;text-underline-offset:3px;
}
.cnsh-link:hover{color:var(--cnsh-red-700);text-decoration-thickness:2px}
.cnsh-link:focus-visible{outline:3px solid var(--cnsh-red-700);outline-offset:2px;border-radius:2px}

/* -------------------------------------------------------------- 4. META ROWS */
.cnsh-meta{display:flex;align-items:center;flex-wrap:wrap;gap:10px;font-size:.8125rem;color:var(--cnsh-mist)}
.cnsh-tag{
  display:inline-block;padding:3px 10px;border-radius:999px;
  background:rgba(200,62,77,.10);color:var(--cnsh-red);
  font-weight:700;font-size:.6875rem;letter-spacing:.10em;text-transform:uppercase;
}
.cnsh-dot{width:3px;height:3px;border-radius:50%;background:var(--cnsh-line)}
.cnsh-time::before{content:"◦";margin-right:5px;color:var(--cnsh-mist)}

/* ------------------------------------------------------- 5. THE IMAGE TREATMENT
   ONE crop ratio (3:2) everywhere article imagery appears, plus one grading rule,
   so six source photographs read as a single set. The library's real ratios run
   1.404–1.778 (plus one 0.667 portrait); 3:2 crops the least from the majority.
   No new image is added. */
.cnsh-media{position:relative;overflow:hidden;background:var(--cnsh-navy-600);aspect-ratio:3/2}
.cnsh-media img{width:100%;height:100%;object-fit:cover;filter:saturate(.92) contrast(1.04);
  transition:transform .45s var(--cnsh-ease)}
.cnsh-media::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(16,42,67,0) 42%,rgba(16,42,67,.58) 100%);
}
.cnsh-media--plain::after{display:none}
/* The featured-image library is only 400px wide — see the report. Panels that
   would upscale are capped instead of stretched. */
.cnsh-media--capped{max-width:400px}

/* ============================================================ 6. THE CARDS
   Frozen fields only: image · topic · read time · title · dek · date.
   Cards are interactive, so hover AND keyboard focus both belong here. */
.cnsh-card{
  position:relative;display:flex;flex-direction:column;
  background:var(--cnsh-card);border:1px solid var(--cnsh-line);border-radius:var(--cnsh-radius);
  overflow:hidden;height:100%;
  transition:transform .2s var(--cnsh-ease),box-shadow .2s var(--cnsh-ease),border-color .2s var(--cnsh-ease);
}
.cnsh-card:hover{transform:translateY(-3px);box-shadow:0 14px 34px rgba(10,26,47,.13);border-color:#C9D6E2}
/* Focus lives on the card's one real link, so a keyboard user gets one stop per card. */
.cnsh-card__link{display:flex;flex-direction:column;height:100%;text-decoration:none;color:inherit}
.cnsh-card__link:focus-visible{outline:3px solid var(--cnsh-red-700);outline-offset:-3px;border-radius:var(--cnsh-radius)}
.cnsh-card__body{padding:20px 22px 22px;display:flex;flex-direction:column;gap:10px;flex:1}
.cnsh-card__title{
  font-family:var(--cnsh-serif);font-weight:600;font-size:1.1875rem;line-height:1.28;
  color:var(--cnsh-ink);margin:0;
}
.cnsh-card__dek{margin:0;color:var(--cnsh-slate);font-size:.9375rem;line-height:1.58}
.cnsh-card__foot{margin-top:auto;padding-top:14px;display:flex;align-items:center;justify-content:space-between;gap:12px}
.cnsh-card__more{
  font-weight:600;font-size:.875rem;color:var(--cnsh-navy);
  text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px;
}
.cnsh-card:hover .cnsh-card__more{color:var(--cnsh-red-700);text-decoration-thickness:2px}
.cnsh-card__date{font-size:.8125rem;color:var(--cnsh-mist)}
.cnsh-card:hover .cnsh-media img{transform:scale(1.03)}

.cnsh-grid{display:grid;gap:26px;grid-template-columns:repeat(3,1fr)}
.cnsh-grid--2{grid-template-columns:repeat(2,1fr)}

/* ================================================== 7. /blog/ — THE LIBRARY */

/* 7.1 HERO. Replaces the theme's hero-dark band. The 72px top margin is not decoration:
   the site's navbar is fixed, and the theme clears it on its own bands with exactly this
   value — without it the nav sits on top of the hero. */
.cnsh-hero{position:relative;background:var(--cnsh-navy);color:#fff;margin-top:72px;padding:76px 0 60px;overflow:hidden}
.cnsh-hero::before{
  content:"";position:absolute;inset:0;opacity:.5;
  background:linear-gradient(135deg,var(--cnsh-ink) 0%,var(--cnsh-navy-600) 55%,var(--cnsh-navy) 100%);
}
.cnsh-hero__inner{position:relative}
.cnsh-hero__title{
  font-family:var(--cnsh-serif);font-weight:600;letter-spacing:-.015em;
  font-size:clamp(2rem,1.3rem + 2.6vw,3.25rem);line-height:1.08;margin:0 0 14px;color:#fff;
}
.cnsh-hero__promise{margin:0 0 26px;font-size:1.125rem;line-height:1.6;color:#C6D4E1;max-width:56ch}
.cnsh-hero__toolbar{display:flex;flex-wrap:wrap;gap:14px;align-items:center}
.cnsh-search{display:flex;flex:1 1 320px;max-width:440px;background:#fff;border-radius:999px;padding:6px 6px 6px 20px}
.cnsh-search input{
  flex:1;border:0;background:transparent;font:inherit;color:var(--cnsh-ink);min-width:0;outline:none;
}
.cnsh-search input::placeholder{color:var(--cnsh-mist)}
.cnsh-search:focus-within{box-shadow:0 0 0 3px rgba(201,149,46,.55)}
.cnsh-topics{display:flex;flex-wrap:wrap;gap:8px 16px;margin-top:24px;padding-top:22px;border-top:1px solid rgba(255,255,255,.16)}
.cnsh-topics__label{font-size:.75rem;font-weight:600;letter-spacing:.13em;text-transform:uppercase;color:#93A9BC;align-self:center}
.cnsh-topics a{
  color:#fff;text-decoration:none;font-size:.875rem;font-weight:500;
  padding:4px 2px;border-bottom:2px solid transparent;
  transition:border-color .16s var(--cnsh-ease),color .16s var(--cnsh-ease);
}
.cnsh-topics a:hover{border-bottom-color:var(--cnsh-gold);color:#fff}
.cnsh-topics a:focus-visible{outline:2px solid var(--cnsh-gold);outline-offset:3px}
.cnsh-topics__count{color:#93A9BC;font-size:.8125rem}

/* 7.2 LEAD ARTICLE — a split feature. This is deliberately NOT a card: a 2-column
   composition the grid does not have, and the image panel is bounded because the
   source images are 400px wide. */
.cnsh-lead{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:0;
  background:var(--cnsh-card);border:1px solid var(--cnsh-line);border-radius:var(--cnsh-radius);overflow:hidden}
.cnsh-lead__media{position:relative;order:2}
.cnsh-lead__body{order:1;padding:44px;display:flex;flex-direction:column;justify-content:center;gap:14px}
.cnsh-lead__title{
  font-family:var(--cnsh-serif);font-weight:600;font-size:clamp(1.5rem,1.1rem + 1.2vw,2.125rem);
  line-height:1.16;letter-spacing:-.01em;margin:0;color:var(--cnsh-ink);
}
.cnsh-lead__jak{margin:0;color:var(--cnsh-slate);font-size:1.0625rem;line-height:1.6}
.cnsh-lead__actions{display:flex;align-items:center;gap:18px;flex-wrap:wrap;margin-top:6px}

/* 7.3 TOPIC RAIL — a horizontal set of entries with counts, not a grid. */
.cnsh-rail{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:0;
  border-top:1px solid var(--cnsh-line);border-left:1px solid var(--cnsh-line)}
.cnsh-rail__item{
  border-right:1px solid var(--cnsh-line);border-bottom:1px solid var(--cnsh-line);
  padding:20px 22px;text-decoration:none;color:inherit;display:flex;flex-direction:column;gap:6px;
  transition:background .16s var(--cnsh-ease);
}
.cnsh-rail__item:hover{background:var(--cnsh-card)}
.cnsh-rail__item:focus-visible{outline:3px solid var(--cnsh-red-700);outline-offset:-3px}
.cnsh-rail__n{font-size:.8125rem;font-weight:700;color:var(--cnsh-gold);letter-spacing:.06em}
.cnsh-rail__name{font-weight:600;font-size:.9375rem;color:var(--cnsh-ink);text-transform:uppercase;letter-spacing:.05em}
.cnsh-rail__count{font-size:.8125rem;color:var(--cnsh-mist)}

/* 7.4 "START HERE" — an editorial numbered list, not a third card grid. */
.cnsh-start{display:grid;grid-template-columns:minmax(0,300px) minmax(0,1fr);gap:40px;align-items:start}
.cnsh-start__list{margin:0;padding:0;list-style:none;counter-reset:cnshstart}
.cnsh-start__item{counter-increment:cnshstart;display:grid;grid-template-columns:52px minmax(0,1fr);gap:18px;
  padding:20px 0;border-top:1px solid var(--cnsh-line)}
.cnsh-start__item:last-child{border-bottom:1px solid var(--cnsh-line)}
.cnsh-start__item::before{
  content:counter(cnshstart,decimal-leading-zero);
  font-family:var(--cnsh-serif);font-weight:600;font-size:1.375rem;color:var(--cnsh-gold);line-height:1.2;
}
.cnsh-start__title{display:block;font-weight:600;font-size:1.0625rem;color:var(--cnsh-ink);
  text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px;margin-bottom:4px}
.cnsh-start__item a:hover .cnsh-start__title{color:var(--cnsh-red-700);text-decoration-thickness:2px}
.cnsh-start__item a:focus-visible{outline:3px solid var(--cnsh-red-700);outline-offset:3px;border-radius:3px;display:block}
.cnsh-start__dek{margin:0;color:var(--cnsh-slate);font-size:.9375rem;line-height:1.55}

/* 7.5 CLOSING BAND. The action is a button AND the link is underlined. */
.cnsh-close{background:var(--cnsh-ink);color:#fff}
.cnsh-close__inner{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(0,1fr);gap:40px;align-items:center}
.cnsh-close__title{font-family:var(--cnsh-serif);font-weight:600;font-size:clamp(1.5rem,1.1rem + 1.2vw,2rem);
  line-height:1.18;margin:0 0 10px;color:#fff}
.cnsh-close__text{margin:0;color:#B9C8D6;font-size:1.0625rem;line-height:1.6}
.cnsh-close__text a{color:#fff;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px}
.cnsh-close__actions{display:flex;flex-wrap:wrap;gap:14px;justify-content:flex-end}

/* ============================================== 8. /resources/ — THE SHOP WINDOW */

/* 8.1 EDITOR'S PICK — full-width feature, bigger than anything else on the page. */
.cnsh-pick{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);gap:0;
  background:var(--cnsh-navy);color:#fff;border-radius:var(--cnsh-radius);overflow:hidden}
.cnsh-pick__media{order:2}
.cnsh-pick__body{order:1;padding:48px;display:flex;flex-direction:column;justify-content:center;gap:14px}
.cnsh-pick__title{font-family:var(--cnsh-serif);font-weight:600;font-size:clamp(1.625rem,1.2rem + 1.4vw,2.375rem);
  line-height:1.14;margin:0;color:#fff}
.cnsh-pick__dek{margin:0;color:#C6D4E1;font-size:1.0625rem;line-height:1.62}
.cnsh-pick__meta{display:flex;gap:12px;align-items:center;font-size:.8125rem;color:#93A9BC}
.cnsh-pick .cnsh-media::after{display:none}
.cnsh-pick__flag{
  display:inline-flex;align-items:center;gap:8px;font-size:.6875rem;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--cnsh-gold);
}
.cnsh-pick__flag::before{content:"";width:20px;height:2px;background:var(--cnsh-gold)}

/* 8.2 COLLECTIONS — each an editorial row: heading + promise in a left rail,
   cards to the right. Asymmetric, so it never reads as another 3-up grid.
   Driven by the page's existing m1 repeater (tit / desc / count). */
.cnsh-coll{display:grid;grid-template-columns:minmax(0,300px) minmax(0,1fr);gap:40px;align-items:start}
.cnsh-coll + .cnsh-coll{margin-top:56px}
.cnsh-coll__rail{position:sticky;top:88px}
.cnsh-coll__title{font-family:var(--cnsh-serif);font-weight:600;font-size:1.5rem;line-height:1.2;
  margin:0 0 10px;color:var(--cnsh-ink)}
.cnsh-coll__promise{margin:0;color:var(--cnsh-slate);font-size:.9375rem;line-height:1.6}
.cnsh-coll__all{display:inline-block;margin-top:14px;font-size:.875rem;font-weight:600}

/* 8.3 TOOLS & DOWNLOADS — given real presence: a distinct band, a file-type badge,
   and the file's real metadata instead of a bare button. */
.cnsh-tools{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:26px}
.cnsh-tool{
  display:flex;flex-direction:column;gap:14px;padding:26px 26px 24px;
  background:var(--cnsh-card);border:1px solid var(--cnsh-line);border-radius:var(--cnsh-radius);
  border-top:3px solid var(--cnsh-gold);height:100%;
  transition:transform .2s var(--cnsh-ease),box-shadow .2s var(--cnsh-ease);
}
.cnsh-tool:hover{transform:translateY(-3px);box-shadow:0 14px 34px rgba(10,26,47,.12)}
.cnsh-tool__badge{
  align-self:flex-start;display:inline-flex;align-items:center;gap:7px;
  font-size:.6875rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--cnsh-red);background:rgba(200,62,77,.09);border-radius:999px;padding:4px 11px;
}
.cnsh-tool__title{font-family:var(--cnsh-serif);font-weight:600;font-size:1.1875rem;
  line-height:1.26;margin:0;color:var(--cnsh-ink)}
.cnsh-tool__dek{margin:0;color:var(--cnsh-slate);font-size:.9375rem;line-height:1.58}
.cnsh-tool__foot{margin-top:auto;padding-top:8px}

/* 8.4 WHY US — one tightened row with hairline dividers, not four floating boxes. */
.cnsh-why{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--cnsh-line)}
.cnsh-why__item{padding:28px 26px 4px;border-right:1px solid var(--cnsh-line)}
.cnsh-why__item:last-child{border-right:0}
.cnsh-why__icon{color:var(--cnsh-navy);margin-bottom:12px;display:block}
.cnsh-why__title{font-family:var(--cnsh-serif);font-weight:600;font-size:1.0625rem;color:var(--cnsh-ink);margin-bottom:6px}
.cnsh-why__desc{color:var(--cnsh-slate);font-size:.9375rem;line-height:1.55}

/* ============================================================ 9. RESPONSIVE */
@media (max-width:1024px){
  .cnsh-grid{grid-template-columns:repeat(2,1fr)}
  .cnsh-lead,.cnsh-pick{grid-template-columns:1fr}
  .cnsh-lead__media,.cnsh-pick__media{order:1}
  .cnsh-lead__body,.cnsh-pick__body{order:2;padding:34px}
  .cnsh-coll,.cnsh-start{grid-template-columns:1fr;gap:26px}
  .cnsh-coll__rail{position:static}
  .cnsh-close__inner{grid-template-columns:1fr;gap:24px}
  .cnsh-close__actions{justify-content:flex-start}
  .cnsh-why{grid-template-columns:repeat(2,1fr)}
  .cnsh-why__item{border-right:0;border-bottom:1px solid var(--cnsh-line);padding:24px 20px}
  .cnsh-media--capped{max-width:none}
}
@media (max-width:640px){
  .cnsh-band{padding:44px 0}
  .cnsh-band--roomy{padding:56px 0}
  .cnsh-grid,.cnsh-grid--2,.cnsh-why{grid-template-columns:1fr}
  .cnsh-hero{padding:48px 0 40px}
  .cnsh-lead__body,.cnsh-pick__body{padding:26px 22px 28px}
  .cnsh-start__item{grid-template-columns:40px minmax(0,1fr);gap:14px}
  .cnsh-search{padding:6px 6px 6px 16px}
  .cnsh-btn{width:100%;justify-content:center}
  .cnsh-close__actions .cnsh-btn{width:auto}
}

/* ------------------------------------------------- 10. MOTION, RESPECTED (R43) */
@media (prefers-reduced-motion:reduce){
  .cnsh-page *,.cnsh-page *::before,.cnsh-page *::after{
    animation-duration:.001ms !important;animation-iteration-count:1 !important;
    transition-duration:.001ms !important;scroll-behavior:auto !important;
  }
  .cnsh-card:hover,.cnsh-tool:hover{transform:none}
  .cnsh-card:hover .cnsh-media img{transform:none}
  .cnsh-btn:hover .cnsh-btn__arrow{transform:none}
}

/* ==== Batch 64 (2026-10-11) - finishing pass (task #68) ==== */
/* Appended to mu-plugins/cnsourcehub-styles.css. Scoped under .cnsh-page like everything
   else, so it can only reach the two redesigned pages.
   ROLLBACK: truncate the stylesheet back to 69,190 bytes. */

/* F6 - THE 390px SEARCH FIELD, a real bug.
   The mobile rule `.cnsh-btn{width:100%;justify-content:center}` was written for the closing
   band's stacked buttons, but the hero's search form contains a .cnsh-btn too - the Search
   button. At 390 that button took the entire row and squeezed the input to width 0: an
   invisible text field beside an empty Search button, on the first screen of the library
   page on a phone. Measured before: input 0px, button 323px.
   The button inside the search form is now exempt, and the input keeps a floor so it can
   never be reduced to nothing again. */
.cnsh-search{flex-wrap:nowrap}
.cnsh-search input{flex:1 1 auto;min-width:7rem}
.cnsh-search .cnsh-btn{width:auto;flex:0 0 auto;padding:14px 18px}

/* The closing band's copy now renders, so the band's two halves are no longer a button
   beside an empty box. Keeps the text column from running the full width of a wide band. */
.cnsh-close__text{max-width:62ch}

/* ==========================================================================
   Batch 69 (task #73) + Batch 70 (task #74)
   Appended to mu-plugins/cnsourcehub-styles.css. Scoped under .cnsh-page plus the
   article-only `body:has(.post > p)` scope, so nothing here can reach another page.
   ROLLBACK: truncate the stylesheet to 70,430 bytes.

   NOTE ON THE SPLIT: §1 is COLOUR ONLY (task #73). §2 onwards is COMPOSITION ONLY
   (task #74). They are appended together because one owner holds both, and are kept in
   separate blocks so either can be rolled back without the other.
   ========================================================================== */

/* ==========================================================================
   §1 — COLOUR IDENTITY (task #73). No colour that the site does not already render.
   --------------------------------------------------------------------------
   THE RULE APPLIED: a colour counts as identity only if a page OUTSIDE this redesign
   renders it. Those are, measured off home / pricing / industries / manufacturers /
   contact: #102A43 (navy band), #0B172A (footer + deep ink), #243B53 (heading text),
   #627D98 (secondary text), #829AB1 (tertiary text), #D9E2EC (hairlines), #F5F8FA
   (page ground), #FFFFFF (surfaces), #C83E4D (the single accent: tags and CTA).
   WHITE AND THE PALETTE VALUES AT REDUCED OPACITY ARE NOT NEW COLOURS — they are the
   palette at alpha, and that is how the muted tones on the dark bands are done here.

   The fix is mostly a re-pointing of the tokens rather than a rewrite, because every
   off-palette value in the design system was reached through a token. The gold was
   used ONLY through --cnsh-gold, so re-pointing it removes it everywhere at once.
   ========================================================================== */
.cnsh-page{
  /* #C9952E gold — OFF PALETTE, REMOVED. The site has one accent (the red), so the
     editorial rules and flags that carried the gold now carry that red. */
  --cnsh-gold:#C83E4D;
  /* #0A1A2F "one step past the navy" — a value nothing else on the site renders.
     The site's deepest navy is the footer's #0B172A, so that is the ink now. */
  --cnsh-ink:#0B172A;
  /* #1C3D5A — a navy step nothing renders. Collapsed onto the rendered band navy. */
  --cnsh-navy-600:#102A43;
  /* #486581 / #7C97AC — custom slates; the site renders #627D98 and #829AB1. */
  --cnsh-slate:#627D98;
  --cnsh-mist:#829AB1;
  /* #DFE7EE / #F6F8FA — near-misses of the rendered #D9E2EC and #F5F8FA. */
  --cnsh-line:#D9E2EC;
  --cnsh-paper:#F5F8FA;
  /* #A82E3B — a red step nothing renders. One red, one state: the accent itself. */
  --cnsh-red-700:#C83E4D;
}
/* The numerals that carried the gold drop to the site's tertiary slate, so the red
   stays an accent rather than becoming a second voice on every list. */
.cnsh-rail__n,.cnsh-start__item::before{color:#829AB1}

/* The few values the design system wrote as literals rather than through a token. */
.cnsh-page .cnsh-card:hover{border-color:#D9E2EC}
.cnsh-page .cnsh-btn--light{background:#FFFFFF;color:#102A43}
.cnsh-page .cnsh-btn--light:hover{background:#D9E2EC}
.cnsh-hero__promise,.cnsh-pick__dek{color:rgba(255,255,255,.78)}
.cnsh-pick__meta,.cnsh-topics__label,.cnsh-topics__count{color:rgba(255,255,255,.62)}
.cnsh-close__text{color:rgba(255,255,255,.72)}

/* ==========================================================================
   §2 — COMPOSITION (task #74). Compact: fewer wasted vertical pixels, same measure,
   same type sizes. NOT shorter articles, NOT smaller text.
   ========================================================================== */

/* 2.1 A TIGHTER RHYTHM. The band rhythm was set for a page with less in it; every
   section drops by a step and the section headers sit closer to what follows. */
.cnsh-band{padding:48px 0}
.cnsh-band--roomy{padding:64px 0}
.cnsh-band--tight{padding:36px 0}
.cnsh-hero{padding:52px 0 40px}
.cnsh-head{margin-bottom:26px}
.cnsh-grid{gap:22px}
.cnsh-card__body{padding:18px 20px 20px}
.cnsh-card__title{font-size:1.125rem}
.cnsh-coll + .cnsh-coll{margin-top:40px}

/* 2.2 THE TOPIC RAIL, RETIRED AS A SECTION. Five topics holding two articles each
   cannot carry a band of their own — it cost height on a page that wants to be
   shorter, and it advertised how little sat behind each topic. The topics survive as
   a slim filter on the grid: same data, no boast, no numbered strip, no counts. */
.cnsh-filter{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 18px;
  padding:14px 0 0;margin:0 0 22px;border-top:1px solid #D9E2EC;
}
.cnsh-filter__label{
  font-size:.75rem;font-weight:600;letter-spacing:.13em;text-transform:uppercase;
  color:#829AB1;
}
.cnsh-filter a{
  font-size:.9375rem;font-weight:500;color:#102A43;text-decoration:none;
  padding:2px 0;border-bottom:2px solid transparent;
}
.cnsh-filter a:hover{border-bottom-color:#C83E4D}
.cnsh-filter a:focus-visible{outline:3px solid #C83E4D;outline-offset:2px;border-radius:2px}

/* ==========================================================================
   §3 — THE ARTICLE'S COLUMNS GET A JOB (task #74, item 1)
   --------------------------------------------------------------------------
   The measure stays 544px. The columns either side were empty; the left one now
   carries an in-page contents rail built from the article's own H2/H3 headings, which
   is what long-form pages normally do with that space.
   REJECTED, and why: (a) widening the measure — the user asked for the centring that
   created these columns, and 67 characters is right; (b) a related-guides rail — the
   articles already appear again on /blog/ and /resources/, so it would repeat rather
   than add; (c) a second enquiry card — the closing band already ends the page with
   one, and two would compete. A rail that merely repeated the headings beside it would
   be worse than the empty space, which is why this one is sticky and linked.
   --------------------------------------------------------------------------
   MOBILE IS DROPPED, DELIBERATELY: below 1240px there is no gutter to put it in, so it
   is removed rather than allowed to break. */
.cnsh-toc{display:none}
@media (min-width:1240px){
  .cnsh-toc{
    display:block;position:sticky;top:88px;
    margin:0 0 26px -288px;width:240px;
    max-width:240px;
    padding:16px 18px;border-left:2px solid #D9E2EC;
    font-size:.875rem;line-height:1.5;
  }
  .cnsh-toc__title{
    margin:0 0 10px;font-size:.75rem;font-weight:600;letter-spacing:.13em;
    text-transform:uppercase;color:#829AB1;
  }
  .cnsh-toc ol{margin:0;padding:0;list-style:none;counter-reset:cnshtoc}
  .cnsh-toc li{counter-increment:cnshtoc;margin:0 0 7px}
  .cnsh-toc li::before{
    content:counter(cnshtoc,decimal-leading-zero);
    color:#829AB1;font-size:.75rem;margin-right:8px;
  }
  .cnsh-toc a{color:#243B53;text-decoration:none}
  .cnsh-toc a:hover{color:#C83E4D;text-decoration:underline;text-underline-offset:3px}
  .cnsh-toc a:focus-visible{outline:3px solid #C83E4D;outline-offset:2px;border-radius:2px}
  /* If the rail would run past the end of the article, sticky releases it naturally —
     no measured clamp is needed, and none is applied. */
}

/* 3.2 THE ARTICLE HEADER, COMPACTED. The band was built for a tall hero; on a single
   post it holds a title, a breadcrumb and nothing else, so it loses its extra height.
   Scoped with `body:has(.post > p)` — the article discriminator established in Batch 57
   — which matches single posts and NOT the Services page, whose `.post` has no direct
   paragraph child. */
@media (min-width:641px){
  body:has(.post > p) .hero-dark{padding-top:34px;padding-bottom:26px}
}
body:has(.post > p) .hero-dark h1.page-header-title{margin-bottom:8px}

/* ==========================================================================
   Batch 71 (task #76) — centre the READING UNIT, not the text column
   --------------------------------------------------------------------------
   MEASURED BEFORE, at 1440: the rail sits 153 → 393 (240 wide), the reading column
   441 → 985 (544 wide). So the UNIT spans 153 → 985 = 832px of a 1425px viewport:
   **296px of air on the right, 153px on the left.** The column itself was already
   centred — the rail is what made the unit left-heavy. That is the user's complaint in
   a smaller shape: 799px of dead space down one side became 440px down one side.

   ⚠️ THE TRADE-OFF, ON THE RECORD: the text column and the reading unit CANNOT both be
   centred. The unit is centred, because even margins are what was asked for — which
   necessarily moves the text column off the page centre.

   ARITHMETIC. Unit width = 240 rail + 48 gutter + 544 column = 832. Centring it in
   1425px gives 296.5px on each side. The container's content box holds 1232px, so the
   column's left margin becomes `50% - 128px`: 1232/2 - 128 = 488, putting the column at
   488 → 1032 inside the container, its centre 144px right of the page centre, and the
   unit's centre exactly ON it (rail at 488-288 = 200, unit right edge at 1032 → the unit
   spans 200 → 1032 within the container, symmetric about 616 = its centre ✓).

   ⇒ The text column's centre moves from **0 → +144px** off the page centre. Reported.

   Applied only at ≥1240px, where the rail exists; below that the column stays centred and
   there is no rail. `max-width` is NOT touched, so the measure stays 544px, and no
   transform is used — a transform on an ancestor would give the sticky rail a transformed
   containing block, and this change must not disturb the rail's behaviour.
   ========================================================================== */
@media (min-width:1240px){
  body:has(.post > p) .post{margin-left:calc(50% - 128px);margin-right:auto}
}

/* ==========================================================================
   Batch 71b (task #76, item 1) — THE TYPE IDENTITY
   --------------------------------------------------------------------------
   AUDIT RESULT. Across home · /pricing-service-packages/ · /industries/ ·
   /manufacturers/ · /contact-us/, EVERY h1, h2, paragraph, button and nav link computes
   to **Inter** — the site's only design face; everything else that appears is WordPress,
   plugin or browser chrome, not design type. **Fraunces appeared on `/blog/` and
   `/resources/` and nowhere else.** It was as foreign to the type identity as the gold was
   to the colour identity, and the audit test that removed the gold applies to a typeface
   unchanged.

   ⇒ ALIGNED. `--cnsh-serif` now points at the site's own stack, so every heading on these
   two pages renders in the same face as the rest of the site. **The display hierarchy is
   kept through size, weight and the kicker rules rather than through a second face** —
   Inter 700 at 2.5rem is a heading, and it was never the face that gave the pages their
   structure.

   ⚠️ REVERTIBLE IN ONE LINE if the serif is wanted after all: point `--cnsh-serif` back at
   Fraunces and restore the enqueue in `cnsourcehub-design.php`. **Recorded as the
   alternative, not taken** — and note the article page was 100% Inter either way, so the
   face never reached the reading surface.

   No colour is set here. No size, spacing or measure is changed.
   ========================================================================== */
.cnsh-page{--cnsh-serif:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
.cnsh-page .cnsh-hero__title,
.cnsh-page .cnsh-title,
.cnsh-page .cnsh-card__title,
.cnsh-page .cnsh-lead__title,
.cnsh-page .cnsh-pick__title,
.cnsh-page .cnsh-coll__title,
.cnsh-page .cnsh-tool__title,
.cnsh-page .cnsh-why__title,
.cnsh-page .cnsh-close__title,
.cnsh-page .cnsh-start__item::before{font-weight:700}
.cnsh-page .cnsh-title,.cnsh-page .cnsh-hero__title{letter-spacing:-.02em}
.cnsh-page .cnsh-card__title,.cnsh-page .cnsh-tool__title,.cnsh-page .cnsh-coll__title{letter-spacing:-.005em}

/* ==========================================================================
   Batch 72 (task #77) — the contents rail becomes a rail: BESIDE the text, not above it
   --------------------------------------------------------------------------
   THE FAULT, measured at scrollY = 0 on article 203:

       hero band ends ................ 430
       nav.cnsh-toc, IN FLOW ......... 510 → 1274   (764px tall)
       article's first paragraph ..... 1301        (775px below its own top)

   The rail was 240px wide and pulled into the gutter with a negative margin, so it LOOKED
   like a sidebar — but it never left the vertical flow, so it also occupied 764px of it.
   A reader got the hero band, then ~870px of contents with the entire right side empty, and
   only then the first sentence. **That is the empty-white-space complaint made worse, on the
   page the rail was added to fix.** Two rounds missed it because both asked whether the rail
   WORKED (ten anchors, pins, clears the footer, dropped at 390 — all true) and neither asked
   whether the text begins BESIDE it or BELOW it.

   THE FIX: the rail gets its own floated wrapper (added by the `the_content` filter — the
   rail is ours, the article is not). A float is out of the vertical flow, so the prose starts
   beside it at the top of the column, and the wrapper carries `position:sticky`, which a
   float supports. All the rail's own measurements stay true.

   ⚠️ WHY NOT A TWO-COLUMN GRID ON THE ARTICLE WRAPPER: that needs the body wrapped in a
   column, and wrapping it would break every `.post > p` / `.post > h2` rule the reading layer
   is built on — CSS selectors follow the DOM, not the box, so `display:contents` does not
   rescue them either, and without it every paragraph becomes its own grid cell.
   ========================================================================== */

/* Below 1240px there is no gutter, so the wrapper is hidden with the rail inside it. */
.cnsh-tocwrap{display:none}

@media (min-width:1240px){
  .cnsh-tocwrap{
    display:block;
    float:left;
    position:sticky;
    top:88px;
    width:240px;
    max-width:240px;
    margin:0 0 10px -288px;   /* 240 rail + 48 gutter, into the left gutter */
  }
  /* The rail's own box returns to static flow INSIDE the wrapper: the sticky, the width and
     the gutter offset now belong to the wrapper, so nothing is applied twice. */
  .cnsh-toc{
    display:block;
    position:static;
    top:auto;
    float:none;
    width:auto;
    max-width:none;
    margin:0;
    padding:16px 18px;
  }
}

/* ⚠️ STICKY NEEDS UNCLIPPED ANCESTORS. `.post`, `.container` and `section` are all
   `overflow: visible` and carry no `transform` or `filter`; this makes the requirement
   explicit so a future rule cannot break pinning silently. */
body:has(.post > p) .post,
body:has(.post > p) .container,
body:has(.post > p) section{overflow:visible;transform:none;filter:none}

/* ==========================================================================
   Batch 74 (task #81 — the incremental rebuild) · PART 1 OF 3
   The signed article: the byline · the FAQ block · back-and-next.
   --------------------------------------------------------------------------
   ⚠️ WHY THIS IS A SECOND BLOCK AND NOT AN EDIT. The Batch 73 stylesheet block was
   truncated as the half-revert — the loader had been reverted and the sheet had not — so
   the components were then rebuilt into a stylesheet carrying NO rules for them. This is
   APPENDED, which keeps the file append-only and every earlier step reversible: the
   property the half-revert existed to restore.
   ⚠️ COLOUR: palette only — the nine site values plus #C83E4D. No new value, no gold.
   ⚠️ TYPE: Inter only. No new face, no new font request.
   ⚠️ SPECIFICITY: every article rule is prefixed `body:has(.post > p)`, so it cannot lose
   to the reading layer's `.post > p:not(...)` rules — and cannot reach any other page.
   ⚠️ THE READING SPACING IS NOT TOUCHED HERE: no rule below sets a margin or padding on a
   bare `p` or `h2` that the Batch 51/57 blocks own.
   ========================================================================== */

/* ---- 1 · THE BYLINE. Date and read time, and a name only if one is set. ---- */
body:has(.post > p) .post > .cnsh-byline{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  margin:0 0 28px;padding:0 0 16px;
  border-bottom:1px solid #D9E2EC;
  font-size:14px;line-height:1.4;color:#627D98;letter-spacing:.01em;
}
body:has(.post > p) .post > .cnsh-byline .cnsh-byline__name{color:#243B53;font-weight:600}
body:has(.post > p) .post > .cnsh-byline .cnsh-byline__rt{color:#627D98}
body:has(.post > p) .post > .cnsh-byline .cnsh-byline__sep{color:#D9E2EC}

/* ---- 2 · THE FAQ BLOCK. Styled from the same headings the schema is built from. ---- */
body:has(.post > p) .post .cnsh-faq{margin:48px 0 0;padding:26px 0 0;border-top:1px solid #D9E2EC}
body:has(.post > p) .post .cnsh-faq > h2{margin:0 0 6px}
body:has(.post > p) .post .cnsh-faq .cnsh-faq__body h3{
  margin:26px 0 8px;font-size:18px;line-height:1.35;font-weight:700;color:#102A43;letter-spacing:-.005em;
}
body:has(.post > p) .post .cnsh-faq .cnsh-faq__body p{margin:0 0 14px}
body:has(.post > p) .post .cnsh-faq .cnsh-faq__body p:last-child{margin-bottom:0}

/* ---- 3 · BACK AND NEXT. Degrades to back-only, never to a broken link. ---- */
body:has(.post > p) .post > .cnsh-nextprev{
  display:flex;justify-content:space-between;align-items:baseline;gap:24px;flex-wrap:wrap;
  margin:52px 0 0;padding:22px 0 0;border-top:1px solid #D9E2EC;font-size:15px;line-height:1.5;
}
body:has(.post > p) .post > .cnsh-nextprev a{
  color:#C83E4D;text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px;
}
body:has(.post > p) .post > .cnsh-nextprev a:hover{color:#102A43}
body:has(.post > p) .post > .cnsh-nextprev .cnsh-nextprev__next{text-align:right;font-weight:600;color:#243B53}
body:has(.post > p) .post > .cnsh-nextprev a:focus-visible{
  outline:2px solid #C83E4D;outline-offset:3px;border-radius:2px;
}

/* ==========================================================================
   Batch 74 (task #81) · PART 2 OF 3
   The closing band at the foot of the article, and THE FULL-WIDTH SUBMIT.
   --------------------------------------------------------------------------
   ⚠️ INERT UNTIL THE BLOCK RENDERS. `cnsh_enquiry_html()` returns nothing while
   `cnsh_form_shortcode` is unset or Contact Form 7 is absent, so these rules have nothing
   to match today. They are appended with the markup so the pair is complete and the block
   cannot be switched on half-styled — and the moment it renders, the band and its submit
   are already the right shape.
   ⚠️ SCOPED TO THIS BLOCK ONLY. The contact and services forms are other surfaces and are
   reported rather than reached into: every selector below sits inside `.cnsh-enquiry`.
   ========================================================================== */

/* ---- 5 · THE ENQUIRY FORM AT THE FOOT. ---- */
body:has(.post > p) .post > .cnsh-enquiry{
  margin:48px 0 8px;padding:26px 24px;background:#FFFFFF;
  border:1px solid #D9E2EC;border-radius:14px;
}
body:has(.post > p) .post > .cnsh-enquiry .cnsh-enquiry__title{
  margin:0 0 6px;font-size:22px;font-weight:700;letter-spacing:-.01em;color:#102A43;
}
/* ⚠️ THE FULL-WIDTH SUBMIT BUTTON — the lowest-cost item on the whole list, and the action
   that must not be missable. Scoped to the enquiry block this layer renders; the contact
   and services forms are other surfaces and are reported rather than reached into. */
body:has(.post > p) .post > .cnsh-enquiry input[type="submit"],
body:has(.post > p) .post > .cnsh-enquiry button[type="submit"],
body:has(.post > p) .post > .cnsh-enquiry .wpcf7-submit{
  display:block;width:100%;margin:18px 0 0;padding:15px 18px;
  font-size:16px;font-weight:600;letter-spacing:.01em;cursor:pointer;
}
body:has(.post > p) .post > .cnsh-enquiry input[type="submit"]:focus-visible,
body:has(.post > p) .post > .cnsh-enquiry button[type="submit"]:focus-visible,
body:has(.post > p) .post > .cnsh-enquiry .wpcf7-submit:focus-visible{
  outline:2px solid #C83E4D;outline-offset:3px;
}
/* The form's own fields follow the page's existing field treatment. */
body:has(.post > p) .post > .cnsh-enquiry input[type="text"],
body:has(.post > p) .post > .cnsh-enquiry input[type="email"],
body:has(.post > p) .post > .cnsh-enquiry input[type="tel"],
body:has(.post > p) .post > .cnsh-enquiry textarea{
  width:100%;border:1px solid #D9E2EC;border-radius:8px;padding:12px 14px;
  font:inherit;color:#243B53;background:#FFFFFF;
}

/* ==========================================================================
   Batch 74 (task #81) · PART 3 OF 3
   The proof band, and the small-screen stacking for everything above.
   --------------------------------------------------------------------------
   ⚠️ INERT UNTIL THE STRINGS EXIST. `cnsh_proof_band_html()` returns nothing until
   `cnsh_proof_claims` carries at least three claims, which is deliberate — a band with
   three invented claims would be exactly the borrowed-credibility move the client-logo
   band was refused for. The rules are appended with the markup so the pair is complete.
   ========================================================================== */

/* ---- 4 · THE PROOF BAND. Same position and weight as the logo band we refused.
       Renders nothing at all until the content owner's strings exist. ---- */
body:has(.post > p) .post > .cnsh-proof{
  margin:48px 0 0;padding:30px 0;background:#F5F8FA;
  border-top:1px solid #D9E2EC;border-bottom:1px solid #D9E2EC;
}
body:has(.post > p) .post > .cnsh-proof .cnsh-proof__title{
  margin:0 0 20px;font-size:20px;font-weight:700;letter-spacing:-.01em;color:#102A43;
}
body:has(.post > p) .post > .cnsh-proof .cnsh-proof__list{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:18px;
  list-style:none;margin:0;padding:0;
}
body:has(.post > p) .post > .cnsh-proof .cnsh-proof__list li{
  border-top:2px solid #C83E4D;padding-top:12px;font-size:15px;line-height:1.5;color:#243B53;
}

/* ---- 6 · NO NAME IN THE BYLINE, SO NOTHING TO HIDE AT 390; the blocks stack cleanly. ---- */
@media (max-width:640px){
  body:has(.post > p) .post > .cnsh-nextprev{flex-direction:column;align-items:flex-start;gap:12px}
  body:has(.post > p) .post > .cnsh-nextprev .cnsh-nextprev__next{text-align:left}
  body:has(.post > p) .post > .cnsh-proof{padding:24px 0}
  body:has(.post > p) .post > .cnsh-enquiry{padding:22px 18px}
}

/* ==================================================================
   R167 - RETIRE THE OFF-PALETTE GOLD TOKEN (--cnsh-gold)
   ------------------------------------------------------------------
   --cnsh-gold is still declared as #C9952E (OFF PALETTE) in the first
   .cnsh-page token block (near line 830). That declaration is inert
   today ONLY because a later .cnsh-page block (near line 1193)
   re-points the same token to the palette red #C83E4D. It is a latent
   defect: if that later override is ever removed, reordered, or
   superseded, the gold resolves again - and no check would catch it,
   because nothing renders the token today.

   This block is APPENDED at the very END of the file. The stylesheet
   is append-only by design (every earlier rollback depends on earlier
   bytes never moving), so the retirement lives at the end: a
   declaration at the end of the file wins the cascade for the
   selectors below, which is the only position guaranteed to out-rank
   an earlier rule and any single-class rule added later. The original
   #C9952E declaration above is deliberately NOT deleted or edited -
   the append is the fix, not a rewrite.

   Palette value chosen: #C83E4D (the site's single accent red),
   matching the existing inert override so nothing changes where it
   would render.
   ================================================================== */
:root, .cnsh-page, .cnsh-page.cnsh-page { --cnsh-gold: #C83E4D; }

/* ==========================================================================
   Batch 86 (task #95) — THE BLOCK SYSTEM.
   --------------------------------------------------------------------------
   ⚠️ THE TREATMENT LANGUAGE, STATED BEFORE IT IS APPLIED:

   Four devices are shared by every block in the reading layer — a 3px edge rule,
   a pale fill (#F5F8FA), a type step off the 17px body, and block padding — and each
   block takes exactly ONE OR TWO of them, told apart by WHICH it takes and never by
   taking more; the key box and the pull quote set the ceiling at two.

   ⇒ AND THAT IS THE POINT, in one consequence: no block carries more devices than the
   key box, so the key box stops being the single loud element on an otherwise plain page.
   The type scale carries HIERARCHY (h2 → h3 → body); the edge rule and the fill carry
   IDENTITY (which kind of block is this). The two never trade places.

   ⚠️ THE TWO MODELS ARE NOT TOUCHED AT ALL — not restated, not "improved". The key box
   (4px ink left rule + 1px muted top + pale fill, 18/22 padding) and the pull quote
   (2px top rule + 1.35x, 600) already define the ceiling, and leaving them literally
   unmodified is the only guarantee against regressing them.

   ⚠️ WHAT THIS BLOCK DOES NOT TOUCH, deliberately: the measure (544px), the paragraph and
   heading MARGINS, the palette, and the typeface. No rule below sets a margin on a bare
   `p`, `h2` or `h3` — the reading spacing belongs to the earlier blocks.
   ========================================================================== */

/* ---- 1 · THE STANDFIRST. Type step only, at the top of the ladder's middle rung. ----
   ⚠️ 1.18x WAS NOT ENOUGH, AND THE REASON IS ARITHMETIC RATHER THAN TASTE. At a 17px body,
   1.18x is a 3.06px step — under 0.2 of a line, and inside the range a reader's eye absorbs
   as "the same size". The earlier reading that the standfirst "reads at body weight" was
   wrong about the mechanism and right about the experience: 20.06px against 17px is a step
   nobody notices, so the opener reads as prose and the article starts flat.
   ⇒ 1.22x (20.74px) plus ink at #243B53 rather than body grey. Still the SMALLEST step in
   the set — the pull quote is 1.35x — so the ladder stays ordered and nothing shouts. */
body:has(.post > p) .post > p.csh-lead{
  font-size:1.22em;color:#243B53;letter-spacing:-.004em;
}

/* ---- 2 · THE ASIDE. Edge rule alone — the quietest member of the set. ----
   It measured as "a paragraph with a line above it": a 1px top border and a 15.3px size, so
   it read as an accident between two paragraphs. It now takes the shared edge rule on the
   LEFT — the same device the definition list and the rail take — and drops its top line, so
   it is told apart by POSITION of rule rather than by being the only one with a line. */
body:has(.post > p) .post > p.csh-note{
  border-top:0;
  border-left:3px solid #D9E2EC;
  padding:2px 0 2px 18px;
}

/* ---- 3 · THE DEFINITION LIST. Rule + fill — the second-largest structure in the article,
   and it measured as IDENTICAL to body text: transparent, no border, no padding, 17px/400.
   It takes the muted rule and the pale fill, which is one device fewer than the key box, so
   it reads as a member of the same family rather than as a competitor to it. */
body:has(.post > p) .post dl.csh-dl{
  border-left:3px solid #D9E2EC;
  background:#F5F8FA;
  padding:18px 22px;
  margin:32px 0;
}
body:has(.post > p) .post dl.csh-dl dt{
  font-weight:600;color:#102A43;
  margin:0;
}
body:has(.post > p) .post dl.csh-dl dd{
  margin:0 0 14px 0;
}
body:has(.post > p) .post dl.csh-dl dd:last-child{margin-bottom:0}

/* ---- 4 · TABLES. Bordered top and bottom, header filled — rule + fill, like the list. ----
   Article 202 carries the only table on the site: 1 table, 4 th, 20 td. It had no treatment
   of its own, so it rendered as the platform default. */
body:has(.post > .cnsh-byline) .post table{
  width:100%;border-collapse:collapse;
  border-top:2px solid #102A43;border-bottom:1px solid #D9E2EC;
  margin:32px 0;font-size:15.5px;line-height:1.5;
}
body:has(.post > .cnsh-byline) .post table th{
  background:#F5F8FA;color:#102A43;font-weight:600;text-align:left;
  padding:12px 14px;border-bottom:1px solid #D9E2EC;
}
body:has(.post > .cnsh-byline) .post table td{
  padding:12px 14px;border-bottom:1px solid #D9E2EC;vertical-align:top;
}
body:has(.post > .cnsh-byline) .post table tr:last-child td{border-bottom:0}

/* ---- 5 · FIGURES. Rule alone, and only when one exists. ---- */
body:has(.post > .cnsh-byline) .post figure{
  border-top:3px solid #D9E2EC;padding-top:18px;margin:32px 0;
}
body:has(.post > .cnsh-byline) .post figure figcaption{
  font-size:14px;line-height:1.5;color:#627D98;margin-top:10px;
}

/* ---- 6 · THE FAQ'S INNER HEADINGS STEP DOWN ONCE, AND IT IS A DECLARED RULE. ----
   ⚠️ MEASURED AS AN INCONSISTENCY: an `h3` renders 18px inside `.cnsh-faq__body` and 20px in
   the article body. That difference is deliberate — the questions belong to the block, not to
   the article's outline — but an undeclared difference is indistinguishable from drift, which
   is what the user is objecting to. So the language names it: an inner heading may step DOWN
   one rung; it may never step UP. The declaration itself lives in the Batch 74 block; this is
   the rule's name. (No new rule needed — recorded so the difference is a decision, not a bug.) */

/* ---- 7 · ORPHAN CONTROL. Measured first: article 203 ends FIVE paragraphs on a single word
   ("do." · "assume." · "happens." · "engagement." · "start."); article 202 has none.
   ✅ `CSS.supports('text-wrap','pretty')` = TRUE and `('balance')` = TRUE on this site's Chrome,
   so `pretty` is the mechanism that actually applies — it is named here rather than described,
   and the measurement after the change says whether it took. `orphans`/`widows` are declared
   too, because they are the fallback for any engine without `pretty`, and a fallback that is
   not declared is not a fallback.
   ⚠️ `balance` is deliberately NOT used on paragraphs: it is capped at a handful of lines and
   would silently do nothing on long paragraphs, which is worse than not claiming it. */
body:has(.post > p) .post > p{
  text-wrap:pretty;orphans:2;widows:2;
}

/* ---- 8 · NO GLYPH HANGS. Measured: zero `hanging-punctuation` declarations, and no prose
   block's first character sits left of the column. Recorded as checked-and-correct rather
   than changed, because adding hanging punctuation now would OPEN a hole this column does
   not have. ---- */

/* ---- 9 · THE RAIL. Rule + type step, and its WIDTH made to work. ----
   ⚠️ THREE MEASURED FAULTS, and the third is the user's red rectangle:
     · it carries a 1px left border where every other block now carries 3px — so it reads as a
       different system rather than a member of this one;
     · its text is 17px, THE SAME SIZE AS BODY, which is why it competes with the article
       instead of serving it — size is the one device that makes a rail read as apparatus;
     · 9 of its 11 entries WRAP TO TWO LINES, and the wrap is a consequence of the rail being
       240px while its labels mirror headings it cannot shorten.
   ⇒ The width moves, not the labels. 240 → 268px, which is the cheapest rung that clears the
   longest single-line entry; the cost is 28px of the left margin, and the MEASURE IS NOT
   TOUCHED — the rail lives in the margin, not in the column. */
body:has(.post > p) .post .cnsh-tocwrap{width:268px}
body:has(.post > p) .post .cnsh-toc{
  border-left:3px solid #D9E2EC;
  padding-left:16px;
  font-size:14.5px;line-height:1.45;
}
body:has(.post > p) .post .cnsh-toc__title{
  font-size:11px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;
  color:#829AB1;margin:0 0 14px;
}
/* Even rhythm: ONE gap between entries, set on the `li` rather than inferred from line count,
   so a two-line entry is separated from its neighbour by the same distance as a one-line one. */
body:has(.post > p) .post .cnsh-toc li{margin:0 0 12px;padding:0}
body:has(.post > p) .post .cnsh-toc li:last-child{margin-bottom:0}
body:has(.post > p) .post .cnsh-toc a{
  display:block;color:#627D98;text-decoration:none;
}
body:has(.post > p) .post .cnsh-toc a:hover,body:has(.post > p) .post .cnsh-toc a:focus-visible{
  color:#102A43;text-decoration:underline;text-underline-offset:3px;
}

/* ---- 10 · THE CURRENT SECTION, WITHOUT JAVASCRIPT. ----
   ⚠️ AND THE HONEST LIMIT IS STATED RATHER THAN HIDDEN: a live "you are here" that follows the
   scroll needs scroll-spy JAVASCRIPT, and a reading page in this design carries no motion and
   no script. What CAN be done with zero JS is done here, and it is real: CSS knows which
   heading a fragment targeted, so the landing heading marks itself and the rail entry that
   points at it marks itself with it. The rail declares entries cnsh-h1…cnsh-h24 so the rule
   covers any article on the site, not only this one. */
body:has(.post > p) .post h2:target,
body:has(.post > p) .post h3:target{
  color:#102A43;
  box-shadow:-16px 0 0 -13px #C83E4D;
}
body:has(#cnsh-h1:target) .cnsh-toc a[href="#cnsh-h1"],
body:has(#cnsh-h2:target) .cnsh-toc a[href="#cnsh-h2"],
body:has(#cnsh-h3:target) .cnsh-toc a[href="#cnsh-h3"],
body:has(#cnsh-h4:target) .cnsh-toc a[href="#cnsh-h4"],
body:has(#cnsh-h5:target) .cnsh-toc a[href="#cnsh-h5"],
body:has(#cnsh-h6:target) .cnsh-toc a[href="#cnsh-h6"],
body:has(#cnsh-h7:target) .cnsh-toc a[href="#cnsh-h7"],
body:has(#cnsh-h8:target) .cnsh-toc a[href="#cnsh-h8"],
body:has(#cnsh-h9:target) .cnsh-toc a[href="#cnsh-h9"],
body:has(#cnsh-h10:target) .cnsh-toc a[href="#cnsh-h10"],
body:has(#cnsh-h11:target) .cnsh-toc a[href="#cnsh-h11"],
body:has(#cnsh-h12:target) .cnsh-toc a[href="#cnsh-h12"],
body:has(#cnsh-h13:target) .cnsh-toc a[href="#cnsh-h13"],
body:has(#cnsh-h14:target) .cnsh-toc a[href="#cnsh-h14"],
body:has(#cnsh-h15:target) .cnsh-toc a[href="#cnsh-h15"],
body:has(#cnsh-h16:target) .cnsh-toc a[href="#cnsh-h16"],
body:has(#cnsh-h17:target) .cnsh-toc a[href="#cnsh-h17"],
body:has(#cnsh-h18:target) .cnsh-toc a[href="#cnsh-h18"],
body:has(#cnsh-h19:target) .cnsh-toc a[href="#cnsh-h19"],
body:has(#cnsh-h20:target) .cnsh-toc a[href="#cnsh-h20"],
body:has(#cnsh-h21:target) .cnsh-toc a[href="#cnsh-h21"],
body:has(#cnsh-h22:target) .cnsh-toc a[href="#cnsh-h22"],
body:has(#cnsh-h23:target) .cnsh-toc a[href="#cnsh-h23"],
body:has(#cnsh-h24:target) .cnsh-toc a[href="#cnsh-h24"]{
  color:#102A43;font-weight:600;
}

/* ---- 10b · THE TABLE AT 390. The only table on the site carries five columns, so at 390 it
   can exceed the column and push the whole page sideways — the one way a table treatment can
   create a fault that is worse than the default it replaces. `display:block` + `overflow-x`
   lets the ROWS keep their table layout inside a scrollable box, so the page never overflows
   even when the table does. ---- */
@media (max-width:640px){
  body:has(.post > .cnsh-byline) .post table{
    display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;font-size:14.5px;
  }
}

/* ---- 11 · BELOW THE BREAKPOINT THE RAIL IS ALREADY GONE. ----
   Measured at 390: both `.cnsh-toc` and `.cnsh-tocwrap` compute to `display:none`, so nothing
   here needs to collapse — and the added width therefore cannot create a narrow-screen fault.
   Recorded as checked rather than assumed. ---- */

/* ==========================================================================
   Batch 86b (task #95) — CORRECTION to §9 of the block system.
   --------------------------------------------------------------------------
   ⚠️ WHY THIS EXISTS, AND IT IS AN HONEST FAILURE RATHER THAN A TIDY-UP: §9 declared
   `.cnsh-tocwrap{width:268px}` to stop the rail's labels wrapping — and the MEASUREMENT
   returned **240px, wraps unchanged at 9 of 11**. The declaration never took, because a
   `max-width:240px` on the same element, set in an earlier rail block, clamps it.

   ⇒ A width that does not take is worse than no width declared, because the record then says
   the raggedness was addressed when it was not. So the cap is raised here as well. Same
   specificity, later in the file, so this declaration wins — and nothing above it is edited,
   so the append-only property that makes every earlier step reversible still holds.

   ⚠️ THE MEASURE IS STILL NOT TOUCHED. The rail lives in the margin: its right edge was
   296.5 + 240 = 536.5 against a column that starts at 584.5, so there is 48px of clearance
   and a 28px growth cannot reach the text column. The check after this append is that
   `div.post` is still at left 584.5 / width 544.
   ========================================================================== */

body:has(.post > p) .post .cnsh-tocwrap{
  width:268px;
  max-width:268px;
}

/* ==========================================================================
   Batch 90 (task #97) — ONE FILL BACK ONTO THE PALETTE.
   --------------------------------------------------------------------------
   ⚠️ THE FIX IS ONE VALUE ONTO THE PALETTE, NOT TWO OFF-PALETTE VALUES AGREEING WITH EACH
   OTHER. Measured: `div.csh-key` computes `rgb(245,248,251)` while the definition list and
   the table header compute `rgb(245,248,250)` — and 245,248,250 IS the palette's #F5F8FA.
   So the key box is the one sitting a step outside the identity, and it is the key box that
   moves. *The earlier reasoning had it backwards: moving the two correct blocks to meet the
   odd one would have widened a one-value drift into a three-value one.*

   ⚠️ THIS IS NOT A RE-DESIGN, AND THE BRIEF'S OWN CONSTRAINT IS HONOURED LITERALLY: no size,
   no spacing, no border, no radius, no type, no colour other than the ONE background value
   that was already meant to be the palette's.

   ⚠️ It wins on the cascade rather than on `!important` — later in the file, with a more
   specific selector than the model's own rule — so nothing above it is edited and the
   append-only property that makes every earlier step reversible still holds.
   ========================================================================== */

body:has(.post > p) .post div.csh-key,
body:has(.post > .cnsh-byline) .post div.csh-key{
  background:#F5F8FA;
}

/* ==========================================================================
   Batch 91 (task #99) — THE LAST TWO OFF-PALETTE VALUES, ONTO THE PALETTE.
   --------------------------------------------------------------------------
   ⚠️ ONTO THE PALETTE, NEVER BETWEEN VALUES. Both are the same class as the fill corrected
   in Batch 90, and both sit on the SAME TWO BLOCKS. `p.csh-note`'s text is 2/8/13 off
   `#627D98` — making it agree with anything other than the palette value would WIDEN the
   gap rather than close it.

   ⚠️ AND BOTH ARE INVISIBLE, WHICH IS EXACTLY WHY THEY ARE WORTH CLOSING. A drift nobody can
   see is a drift nobody will ever catch again — and the fill that was corrected in the same
   round was the same size of difference.

   ⚠️ THE KEY BOX'S DESIGN IS NOT TOUCHED, AND THAT INCLUDES ITS LEFT RULE. The 4px LEFT
   border is the block's identity and measures `rgb(16,42,67)` — the ink. **Only the three 1px
   sides move.** Setting the left rule's colour, even onto a palette value, would be a design
   decision dressed as a compliance fix; the drift is on the three 1px sides and it is the
   three 1px sides that change.

   ⚠️ COLOURS ONLY. No width, no style, no radius, no padding, no background, no type. The
   background corrected in Batch 90 is not restated here, so nothing can be silently undone.

   ⚠️ Later in the file than the model's own rule and one element selector more specific, so it
   wins on the cascade rather than on `!important` — nothing above it is edited and the
   append-only property still holds.
   ========================================================================== */

body:has(.post > p) .post div.csh-key,
body:has(.post > .cnsh-byline) .post div.csh-key{
  border-top-color:#D9E2EC;
  border-right-color:#D9E2EC;
  border-bottom-color:#D9E2EC;
}

body:has(.post > p) .post p.csh-note,
body:has(.post > .cnsh-byline) .post p.csh-note{
  color:#627D98;
}

/* ==========================================================================
   Batch 92 (task #100) — THE PALETTE COMPLETION: SPLIT CLOSED & CONTACT HERO.
   --------------------------------------------------------------------------
   1. The one-step split: `p.csh-pull` borders and `dl.csh-dl` row hairlines (`dt`, `dd`)
      moved from `#DDE5ED` (`rgb(221,229,237)`) onto palette `#D9E2EC` (`rgb(217,226,236)`).
   2. Pull quote width (2px), type size (22.95px), padding (22.95px 0), and device
      language remain 100% UNTOUCHED — colour only.
   3. The contact hero overlay moved from off-palette `#0A2463` (`rgba(10,36,99,0.85)`)
      onto identity navy `#102A43` (`rgba(16,42,67,0.85)`).
   ========================================================================== */

body:has(.post > p) .post p.csh-pull,
body:has(.post > .cnsh-byline) .post p.csh-pull{
  border-top-color:#D9E2EC;
  border-bottom-color:#D9E2EC;
}

body:has(.post > p) .post dl.csh-dl dt,
body:has(.post > .cnsh-byline) .post dl.csh-dl dt,
body:has(.post > p) .post dl.csh-dl dd,
body:has(.post > .cnsh-byline) .post dl.csh-dl dd{
  border-top-color:#D9E2EC;
}

section.hero-dark > div:first-child{
  background:rgba(16,42,67,0.85);
}
